/*
 * df735_fixed.c - DF-0735 fix-validation harness.
 *
 * Same trigger pattern as df735_trigger.c, but instead of calling ip_input(m)
 * directly from the sysctl-handler thread (which trips ASSERT_NETISR_NCPUS),
 * it routes the mbuf through netisr_queue(NETISR_IP, m) -- exactly the fix
 * applied in fix.diff to sys/netgraph7/ng_ipfw.c:248. The mbuf is then
 * dispatched to a netisr thread and ip_input runs there, so the assertion
 * holds and no panic occurs.
 *
 * Trigger:   sysctl debug.df735_fixed=1     (as root)
 *
 * If the fix concept is correct, this sysctl should NOT panic the kernel --
 * a deliberate contrast with the buggy df735_trigger.ko, which panics
 * every time on default-GENERIC.
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/types.h>

#include <net/netisr.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>

/* See note in df735_trigger.c. */
extern void ip_input(struct mbuf *);

static int df735_fixed(SYSCTL_HANDLER_ARGS);

SYSCTL_PROC(_debug, OID_AUTO, df735_fixed, CTLTYPE_INT | CTLFLAG_RW,
    NULL, 0, df735_fixed, "I",
    "DF-0735 fix validation: write 1 to dispatch mbuf via netisr_queue");

static int
df735_fixed(SYSCTL_HANDLER_ARGS)
{
	int error, val = 0;

	error = sysctl_handle_int(oidp, &val, 0, req);
	if (error != 0 || req->newptr == NULL)
		return (error);

	if (val) {
		struct mbuf *m;
		m = m_gethdr(M_WAITOK, MT_DATA);
		if (m == NULL)
			return (ENOMEM);
		m->m_pkthdr.len = m->m_len = 0;
		/* DF-0735 fix pattern (mirrors ng_ip_input.c:122-125):
		 * hand the mbuf to NETISR_IP, do not call ip_input directly. */
		m->m_flags &= ~M_HASH;
		netisr_queue(NETISR_IP, m);
		/* ip_input() will be called from the NETISR_IP thread, where
		 * ASSERT_NETISR_NCPUS holds. The mbuf is malformed (zero
		 * length) so it will be dropped inside ip_input -- but the
		 * important property is that NO panic occurs. */
	}

	return (0);
}
