#!/usr/bin/env python3
"""Generate findings/poc/DF-5455/umoscom_prod_guarded.c from the production
sys/bus/u4b/serial/umoscom.c with exactly ONE guard hunk (and emit
prod_guard.diff documenting it).  Everything else -- including the
DRIVER_MODULE registration, inert without hardware -- stays
byte-identical."""
import difflib, os

SRC = "sys/bus/u4b/serial/umoscom.c"
DST = "findings/poc/DF-5455/umoscom_prod_guarded.c"

orig = open(SRC).read()

guard1_anchor = "#include <bus/u4b/serial/usb_serial.h>\n"
assert orig.count(guard1_anchor) == 1
guard1 = guard1_anchor + """
#ifdef UMOSCOM_HARNESS
/*
 * DF-5455 HARNESS GUARD, the ONLY change to production (see
 * prod_guard.diff): reroute
 * the EP0 control-request macro to a shim that reproduces the traced
 * usbd_do_request_flags() failure semantics (usb_request.c:642-650 timeout
 * breaks out BEFORE the usbd_copy_out at :680-681; a zero-length data
 * stage copies nothing at :666-683) so the caller's buffer stays
 * untouched, exactly like a silent/stalling/short-replying evil MCS7703.
 * All production call sites stay byte-identical.
 */
void\t\tmo_shim_request(struct usb_device_request *, void *, int);
#undef\tucom_cfg_do_request
#define\tucom_cfg_do_request(udev, com, req, ptr, flags, timo)\t\\
\tmo_shim_request((req), (ptr), (timo))
#endif
"""

pre = """static device_method_t umoscom_methods[] = {
	DEVMETHOD(device_probe, umoscom_probe),
	DEVMETHOD(device_attach, umoscom_attach),
	DEVMETHOD(device_detach, umoscom_detach),
	DEVMETHOD_END
};

static devclass_t umoscom_devclass;

static driver_t umoscom_driver = {
	.name = "umoscom",
	.methods = umoscom_methods,
	.size = sizeof(struct umoscom_softc),
};

"""
devs = """static const STRUCT_USB_HOST_ID umoscom_devs[] = {
	{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)}
};

"""
post = """DRIVER_MODULE(umoscom, uhub, umoscom_driver, umoscom_devclass, NULL, NULL);
MODULE_DEPEND(umoscom, ucom, 1, 1, 1);
MODULE_DEPEND(umoscom, usb, 1, 1, 1);
MODULE_VERSION(umoscom, 1);"""
assert orig.count(pre + devs + post) == 1
guard2 = """/*
 * DF-5455 HARNESS GUARD #2 of 2 (see prod_guard.diff): the driver
 * registration machinery is compiled out -- no uhub probing happens; the
 * harness calls the production cfg helpers directly.  umoscom_devs stays
 * (between the two guarded regions): umoscom_probe() references it and
 * remains compiled verbatim.
 */
#ifndef UMOSCOM_HARNESS
""" + pre + """#endif

""" + devs + """#ifndef UMOSCOM_HARNESS
""" + post + """
#endif"""

mod = orig.replace(guard1_anchor, guard1, 1)
os.makedirs(os.path.dirname(DST), exist_ok=True)
open(DST, "w").write(mod)

diff = list(difflib.unified_diff(
    orig.splitlines(True), mod.splitlines(True),
    fromfile="a/sys/bus/u4b/serial/umoscom.c (production, verbatim)",
    tofile="b/umoscom_prod_guarded.c (harness copy)"))
open("findings/poc/DF-5455/prod_guard.diff", "w").write("".join(diff))
print("wrote", DST, "and prod_guard.diff;",
      sum(1 for l in diff if l.startswith('+') and not l.startswith('+++')),
      "added lines")
