DF-3306 / fix.diff
--- /home/maxx/dfbsd/dfbsd/sys/net/ip_mroute/ip_mroute.c 2026-07-18 00:45:16.868076229 +0000 +++ fixed_ip_mroute.c 2026-09-10 09:20:53.482370450 +0000 @@ -905,6 +905,13 @@ reg_vif_num = VIFI_INVALID; #endif + /* + * The tbf reprocess callout may be armed with this vif as its + * argument; stop it before the vif is cleared, or it will fire + * with a zeroed vif (v_tbf == NULL) and panic. + */ + callout_stop(&tbf_reprocess_q_ch); + bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf))); bzero((caddr_t)vifp, sizeof (*vifp)); @@ -973,6 +980,7 @@ struct rtdetq *rte; u_short nstl; + lwkt_gettoken(&mroute_token); rt = mfc_find(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); /* If an entry already exists, just update the fields */ @@ -983,7 +991,6 @@ (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent); - lwkt_gettoken(&mroute_token); update_mfc_params(rt, mfccp); lwkt_reltoken(&mroute_token); return 0; @@ -992,7 +999,6 @@ /* * Find the entry for which the upcall was made and update */ - lwkt_gettoken(&mroute_token); hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) { @@ -1108,15 +1114,16 @@ *nptr = rt->mfc_next; /* - * free the bw_meter entries + * free the bw_meter entries (must be done while holding + * mroute_token: unschedule_bw_meter() mutates bw_meter_timers[]) */ list = rt->mfc_bw_meter; rt->mfc_bw_meter = NULL; - lwkt_reltoken(&mroute_token); kfree(rt, M_MRTABLE); free_bw_list(list); + lwkt_reltoken(&mroute_token); return 0; } @@ -1424,6 +1431,7 @@ struct bw_meter *x = mfc->mfc_bw_meter; mfc->mfc_bw_meter = x->bm_mfc_next; + unschedule_bw_meter(x); kfree(x, M_BWMETER); } @@ -1875,7 +1883,7 @@ { struct vif *vifp = xvifp; - if (ip_mrouter == NULL) + if (ip_mrouter == NULL || vifp == NULL || vifp->v_tbf == NULL) return; tbf_update_tokens(vifp); tbf_process_q(vifp); @@ -2364,8 +2372,10 @@ list = mfc->mfc_bw_meter; mfc->mfc_bw_meter = NULL; - lwkt_reltoken(&mroute_token); + /* free_bw_list() calls unschedule_bw_meter() which walks + * bw_meter_timers[]: must hold mroute_token. */ free_bw_list(list); + lwkt_reltoken(&mroute_token); return 0; } else { /* Delete a single bw_meter entry */ struct bw_meter *prev; @@ -2823,7 +2833,7 @@ mm = m_pullup(mm, sizeof(struct ip)); if (mm != NULL) { ip = mtod(mm, struct ip *); - if ((mrt_api_config & MRT_MFC_RP) && + if (rt != NULL && (mrt_api_config & MRT_MFC_RP) && (rt->mfc_rp.s_addr != INADDR_ANY)) { pim_register_send_rp(ip, vifp, mm, rt); } else { |