/*
 * DF-5493 PoC harness — BRANCH A (see ue_guard_b.c for branch B).
 *
 * Target: sys/bus/u4b/net/usb_ethernet.c uether_ifdetach() (:267-305),
 * which validates NOTHING about the usb_ether handed to it.
 *
 * BRANCH A state = what any of the 8 sibling drivers (cdce/aue/axge/
 * urndis/mos/udav/kue/cue — DF-5334/5384/5395/5397/5399/5411/5453/5486)
 * leave in the softc when attach() fails BEFORE the ue_* fields are
 * assigned, e.g. if_cue.c:405-410:
 *
 *      error = usbd_transfer_setup(...);   :405
 *      if (error) { goto detach; }         :407-410
 *      ...
 *      ue->ue_sc/ue_dev/ue_udev/ue_lock/ue_methods = ...;  :412-416 (AFTER)
 *      ...
 * detach:
 *      cue_detach(dev);                    :425-426
 *          -> usbd_transfer_unsetup(...);  :436   (safe on zeroed array)
 *          -> uether_ifdetach(ue);         :437
 *
 * with ue->ue_lock still NULL, uether_ifdetach():
 *      usb_proc_drain(&ue->ue_tq);         :273  no-op (up_lock == NULL,
 *                                               usb_process.c:409)
 *      ifp = uether_getifp(ue);            :276  embedded arpcom, NOT NULL
 *      if (ifp != NULL) {                  :278  dead guard, always true
 *          UE_LOCK(ue);                    :281  lockmgr(NULL, LK_EXCLUSIVE)
 *                                        ==> Fatal trap 12, fault VA 0x0
 *
 * This KLD replays the exact state (zeroed usb_ether) + the single
 * production call uether_ifdetach() exported by the stock uether.ko.
 */

#include <sys/stdint.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>

#include <bus/u4b/usb.h>
#include <bus/u4b/usbdi.h>
#include <bus/u4b/usb_process.h>

#include <bus/u4b/net/usb_ethernet.h>

static struct usb_ether *poc_ue;

static int
ue_guard_a_modevent(module_t mod, int type, void *arg)
{
	switch (type) {
	case MOD_LOAD:
		poc_ue = kmalloc(sizeof(*poc_ue), M_TEMP, M_WAITOK | M_ZERO);
		if (poc_ue == NULL)
			return (ENOMEM);
		kprintf("ue_guard_a: branch A state: zeroed usb_ether, "
		    "ue_lock=NULL (8-sibling attach-fail state, e.g. "
		    "if_cue.c:405-410)\n");
		kprintf("ue_guard_a: ue=%p ue_lock=%p ue_tq.up_lock=%p "
		    "(all must be 0/NULL)\n", poc_ue, poc_ue->ue_lock,
		    poc_ue->ue_tq.up_lock);
		kprintf("ue_guard_a: calling production uether_ifdetach() "
		    "(usb_ethernet.c:267) -> UE_LOCK -> lockmgr(NULL)\n");
		uether_ifdetach(poc_ue);
		kprintf("ue_guard_a: SURVIVED uether_ifdetach() (UNEXPECTED "
		    "-- guard present?)\n");
		kfree(poc_ue, M_TEMP);
		return (0);
	default:
		return (0);
	}
}

static moduledata_t ue_guard_a_mod = { "ue_guard_a", ue_guard_a_modevent, NULL };
DECLARE_MODULE(ue_guard_a, ue_guard_a_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
MODULE_DEPEND(ue_guard_a, uether, 1, 1, 1);
