--- a/sys/net/dummynet3/ip_dummynet3.c +++ b/sys/net/dummynet3/ip_dummynet3.c @@ -2009,29 +2009,51 @@ static void ip_dn_stop_dispatch(netmsg_t msg) { + int error; + crit_enter(); + /* + * DF-3449: ip_fw3_unregister_module() returns 1 while any ipfw3 + * rule still references the dummynet module (pipe/queue actions). + * It must run before the module text goes away: it clears + * filter_funcs[MODULE_DUMMYNET_ID][] -- which check_body() calls + * through without a NULL check -- and drops the module + * registration so no new pipe/queue rules can be compiled after + * the unload. Every sibling module (ipfw3_basic/nat/layer2/ + * layer4) already does this; dummynet3 was the only one that + * did not. + */ + error = ip_fw3_unregister_module(MODULE_DUMMYNET_ID); + if (error) { + error = EBUSY; + goto back; + } + dummynet_flush(); ip_dn_ctl_ptr = NULL; ip_dn_io_ptr = NULL; systimer_del(&dn_clock); - +back: crit_exit(); - lwkt_replymsg(&msg->lmsg, 0); + lwkt_replymsg(&msg->lmsg, error); } -static void +static int ip_dn_stop(void) { struct netmsg_base smsg; + int error; netmsg_init(&smsg, NULL, &curthread->td_msgport, 0, ip_dn_stop_dispatch); lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0); + error = smsg.lmsg.ms_error; netmsg_service_sync(); + return error; } #endif /* KLD_MODULE */ @@ -2048,7 +2070,11 @@ kprintf("dummynet statically compiled, cannot unload\n"); return EINVAL; #else - ip_dn_stop(); + { + int error = ip_dn_stop(); + if (error) + return error; + } #endif break;