git: 3a01a97d23a2 - main - mroute: partially sanitize the file
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 23 Feb 2023 13:38:43 UTC
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=3a01a97d23a27cb522b3e9de5d95b825f421cf9b commit 3a01a97d23a27cb522b3e9de5d95b825f421cf9b Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2023-02-17 11:23:35 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2023-02-23 13:35:44 +0000 mroute: partially sanitize the file There is rampant inconsistent formatting all around, make it mostly style(9)-conformant. While here: - drop malloc casts - rename a rw lock from mroute_mtx to mroute_lock - replace NOTREACHED comment with __assert_unreachable Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D38652 --- sys/netinet/ip_mroute.c | 2783 +++++++++++++++++++++++------------------------ 1 file changed, 1387 insertions(+), 1396 deletions(-) diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 6cabef8a1b16..15abe168e5c2 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -143,19 +143,19 @@ static MALLOC_DEFINE(M_MRTABLE, "mroutetbl", "multicast forwarding cache"); * structures. */ -static struct rwlock mrouter_mtx; -#define MRW_RLOCK() rw_rlock(&mrouter_mtx) -#define MRW_WLOCK() rw_wlock(&mrouter_mtx) -#define MRW_RUNLOCK() rw_runlock(&mrouter_mtx) -#define MRW_WUNLOCK() rw_wunlock(&mrouter_mtx) -#define MRW_UNLOCK() rw_unlock(&mrouter_mtx) -#define MRW_LOCK_ASSERT() rw_assert(&mrouter_mtx, RA_LOCKED) -#define MRW_WLOCK_ASSERT() rw_assert(&mrouter_mtx, RA_WLOCKED) -#define MRW_LOCK_TRY_UPGRADE() rw_try_upgrade(&mrouter_mtx) -#define MRW_WOWNED() rw_wowned(&mrouter_mtx) +static struct rwlock mrouter_lock; +#define MRW_RLOCK() rw_rlock(&mrouter_lock) +#define MRW_WLOCK() rw_wlock(&mrouter_lock) +#define MRW_RUNLOCK() rw_runlock(&mrouter_lock) +#define MRW_WUNLOCK() rw_wunlock(&mrouter_lock) +#define MRW_UNLOCK() rw_unlock(&mrouter_lock) +#define MRW_LOCK_ASSERT() rw_assert(&mrouter_lock, RA_LOCKED) +#define MRW_WLOCK_ASSERT() rw_assert(&mrouter_lock, RA_WLOCKED) +#define MRW_LOCK_TRY_UPGRADE() rw_try_upgrade(&mrouter_lock) +#define MRW_WOWNED() rw_wowned(&mrouter_lock) #define MRW_LOCK_INIT() \ - rw_init(&mrouter_mtx, "IPv4 multicast forwarding") -#define MRW_LOCK_DESTROY() rw_destroy(&mrouter_mtx) + rw_init(&mrouter_lock, "IPv4 multicast forwarding") +#define MRW_LOCK_DESTROY() rw_destroy(&mrouter_lock) static int ip_mrouter_cnt; /* # of vnets with active mrouters */ static int ip_mrouter_unloading; /* Allow no more V_ip_mrouter sockets */ @@ -392,7 +392,7 @@ static __inline struct mfc * mfc_alloc(void) { struct mfc *rt; - rt = (struct mfc*) malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT | M_ZERO); + rt = malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT | M_ZERO); if (rt == NULL) return rt; @@ -412,98 +412,94 @@ mfc_alloc(void) static int X_ip_mrouter_set(struct socket *so, struct sockopt *sopt) { - int error, optval; - vifi_t vifi; - struct vifctl vifc; - struct mfcctl2 mfc; - struct bw_upcall bw_upcall; - uint32_t i; - - if (so != V_ip_mrouter && sopt->sopt_name != MRT_INIT) - return EPERM; - - error = 0; - switch (sopt->sopt_name) { - case MRT_INIT: - error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); - if (error) - break; - error = ip_mrouter_init(so, optval); - break; + int error, optval; + vifi_t vifi; + struct vifctl vifc; + struct mfcctl2 mfc; + struct bw_upcall bw_upcall; + uint32_t i; + + if (so != V_ip_mrouter && sopt->sopt_name != MRT_INIT) + return EPERM; + + error = 0; + switch (sopt->sopt_name) { + case MRT_INIT: + error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); + if (error) + break; + error = ip_mrouter_init(so, optval); + break; + case MRT_DONE: + error = ip_mrouter_done(); + break; + case MRT_ADD_VIF: + error = sooptcopyin(sopt, &vifc, sizeof vifc, sizeof vifc); + if (error) + break; + error = add_vif(&vifc); + break; + case MRT_DEL_VIF: + error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi); + if (error) + break; + error = del_vif(vifi); + break; + case MRT_ADD_MFC: + case MRT_DEL_MFC: + /* + * select data size depending on API version. + */ + if (sopt->sopt_name == MRT_ADD_MFC && + V_mrt_api_config & MRT_API_FLAGS_ALL) { + error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl2), + sizeof(struct mfcctl2)); + } else { + error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl), + sizeof(struct mfcctl)); + bzero((caddr_t)&mfc + sizeof(struct mfcctl), + sizeof(mfc) - sizeof(struct mfcctl)); + } + if (error) + break; + if (sopt->sopt_name == MRT_ADD_MFC) + error = add_mfc(&mfc); + else + error = del_mfc(&mfc); + break; - case MRT_DONE: - error = ip_mrouter_done(); - break; + case MRT_ASSERT: + error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); + if (error) + break; + set_assert(optval); + break; - case MRT_ADD_VIF: - error = sooptcopyin(sopt, &vifc, sizeof vifc, sizeof vifc); - if (error) - break; - error = add_vif(&vifc); - break; + case MRT_API_CONFIG: + error = sooptcopyin(sopt, &i, sizeof i, sizeof i); + if (!error) + error = set_api_config(&i); + if (!error) + error = sooptcopyout(sopt, &i, sizeof i); + break; - case MRT_DEL_VIF: - error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi); - if (error) - break; - error = del_vif(vifi); - break; + case MRT_ADD_BW_UPCALL: + case MRT_DEL_BW_UPCALL: + error = sooptcopyin(sopt, &bw_upcall, sizeof bw_upcall, + sizeof bw_upcall); + if (error) + break; + if (sopt->sopt_name == MRT_ADD_BW_UPCALL) + error = add_bw_upcall(&bw_upcall); + else + error = del_bw_upcall(&bw_upcall); + break; - case MRT_ADD_MFC: - case MRT_DEL_MFC: - /* - * select data size depending on API version. - */ - if (sopt->sopt_name == MRT_ADD_MFC && - V_mrt_api_config & MRT_API_FLAGS_ALL) { - error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl2), - sizeof(struct mfcctl2)); - } else { - error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl), - sizeof(struct mfcctl)); - bzero((caddr_t)&mfc + sizeof(struct mfcctl), - sizeof(mfc) - sizeof(struct mfcctl)); + default: + error = EOPNOTSUPP; + break; } - if (error) - break; - if (sopt->sopt_name == MRT_ADD_MFC) - error = add_mfc(&mfc); - else - error = del_mfc(&mfc); - break; - - case MRT_ASSERT: - error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); - if (error) - break; - set_assert(optval); - break; - - case MRT_API_CONFIG: - error = sooptcopyin(sopt, &i, sizeof i, sizeof i); - if (!error) - error = set_api_config(&i); - if (!error) - error = sooptcopyout(sopt, &i, sizeof i); - break; - - case MRT_ADD_BW_UPCALL: - case MRT_DEL_BW_UPCALL: - error = sooptcopyin(sopt, &bw_upcall, sizeof bw_upcall, - sizeof bw_upcall); - if (error) - break; - if (sopt->sopt_name == MRT_ADD_BW_UPCALL) - error = add_bw_upcall(&bw_upcall); - else - error = del_bw_upcall(&bw_upcall); - break; - - default: - error = EOPNOTSUPP; - break; - } - return error; + return error; } /* @@ -512,31 +508,30 @@ X_ip_mrouter_set(struct socket *so, struct sockopt *sopt) static int X_ip_mrouter_get(struct socket *so, struct sockopt *sopt) { - int error; - - switch (sopt->sopt_name) { - case MRT_VERSION: - error = sooptcopyout(sopt, &mrt_api_version, sizeof mrt_api_version); - break; - - case MRT_ASSERT: - error = sooptcopyout(sopt, &V_pim_assert_enabled, - sizeof V_pim_assert_enabled); - break; - - case MRT_API_SUPPORT: - error = sooptcopyout(sopt, &mrt_api_support, sizeof mrt_api_support); - break; - - case MRT_API_CONFIG: - error = sooptcopyout(sopt, &V_mrt_api_config, sizeof V_mrt_api_config); - break; - - default: - error = EOPNOTSUPP; - break; - } - return error; + int error; + + switch (sopt->sopt_name) { + case MRT_VERSION: + error = sooptcopyout(sopt, &mrt_api_version, + sizeof mrt_api_version); + break; + case MRT_ASSERT: + error = sooptcopyout(sopt, &V_pim_assert_enabled, + sizeof V_pim_assert_enabled); + break; + case MRT_API_SUPPORT: + error = sooptcopyout(sopt, &mrt_api_support, + sizeof mrt_api_support); + break; + case MRT_API_CONFIG: + error = sooptcopyout(sopt, &V_mrt_api_config, + sizeof V_mrt_api_config); + break; + default: + error = EOPNOTSUPP; + break; + } + return error; } /* @@ -545,30 +540,30 @@ X_ip_mrouter_get(struct socket *so, struct sockopt *sopt) static int X_mrt_ioctl(u_long cmd, caddr_t data, int fibnum __unused) { - int error = 0; - - /* - * Currently the only function calling this ioctl routine is rtioctl_fib(). - * Typically, only root can create the raw socket in order to execute - * this ioctl method, however the request might be coming from a prison - */ - error = priv_check(curthread, PRIV_NETINET_MROUTE); - if (error) - return (error); - switch (cmd) { - case (SIOCGETVIFCNT): - error = get_vif_cnt((struct sioc_vif_req *)data); - break; - - case (SIOCGETSGCNT): - error = get_sg_cnt((struct sioc_sg_req *)data); - break; - - default: - error = EINVAL; - break; - } - return error; + int error; + + /* + * Currently the only function calling this ioctl routine is rtioctl_fib(). + * Typically, only root can create the raw socket in order to execute + * this ioctl method, however the request might be coming from a prison + */ + error = priv_check(curthread, PRIV_NETINET_MROUTE); + if (error) + return (error); + switch (cmd) { + case (SIOCGETVIFCNT): + error = get_vif_cnt((struct sioc_vif_req *)data); + break; + + case (SIOCGETSGCNT): + error = get_sg_cnt((struct sioc_sg_req *)data); + break; + + default: + error = EINVAL; + break; + } + return error; } /* @@ -577,20 +572,20 @@ X_mrt_ioctl(u_long cmd, caddr_t data, int fibnum __unused) static int get_sg_cnt(struct sioc_sg_req *req) { - struct mfc *rt; - - MRW_RLOCK(); - rt = mfc_find(&req->src, &req->grp); - if (rt == NULL) { - MRW_RUNLOCK(); - req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; - return EADDRNOTAVAIL; - } - req->pktcnt = rt->mfc_pkt_cnt; - req->bytecnt = rt->mfc_byte_cnt; - req->wrong_if = rt->mfc_wrong_if; - MRW_RUNLOCK(); - return 0; + struct mfc *rt; + + MRW_RLOCK(); + rt = mfc_find(&req->src, &req->grp); + if (rt == NULL) { + MRW_RUNLOCK(); + req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; + return EADDRNOTAVAIL; + } + req->pktcnt = rt->mfc_pkt_cnt; + req->bytecnt = rt->mfc_byte_cnt; + req->wrong_if = rt->mfc_wrong_if; + MRW_RUNLOCK(); + return 0; } /* @@ -599,73 +594,73 @@ get_sg_cnt(struct sioc_sg_req *req) static int get_vif_cnt(struct sioc_vif_req *req) { - vifi_t vifi = req->vifi; + vifi_t vifi = req->vifi; - MRW_RLOCK(); - if (vifi >= V_numvifs) { + MRW_RLOCK(); + if (vifi >= V_numvifs) { + MRW_RUNLOCK(); + return EINVAL; + } + + mtx_lock_spin(&V_viftable[vifi].v_spin); + req->icount = V_viftable[vifi].v_pkt_in; + req->ocount = V_viftable[vifi].v_pkt_out; + req->ibytes = V_viftable[vifi].v_bytes_in; + req->obytes = V_viftable[vifi].v_bytes_out; + mtx_unlock_spin(&V_viftable[vifi].v_spin); MRW_RUNLOCK(); - return EINVAL; - } - - mtx_lock_spin(&V_viftable[vifi].v_spin); - req->icount = V_viftable[vifi].v_pkt_in; - req->ocount = V_viftable[vifi].v_pkt_out; - req->ibytes = V_viftable[vifi].v_bytes_in; - req->obytes = V_viftable[vifi].v_bytes_out; - mtx_unlock_spin(&V_viftable[vifi].v_spin); - MRW_RUNLOCK(); - - return 0; + + return 0; } static void if_detached_event(void *arg __unused, struct ifnet *ifp) { - vifi_t vifi; - u_long i, vifi_cnt = 0; - struct ifnet *free_ptr; + vifi_t vifi; + u_long i, vifi_cnt = 0; + struct ifnet *free_ptr; - MRW_WLOCK(); + MRW_WLOCK(); - if (V_ip_mrouter == NULL) { - MRW_WUNLOCK(); - return; - } - - /* - * Tear down multicast forwarder state associated with this ifnet. - * 1. Walk the vif list, matching vifs against this ifnet. - * 2. Walk the multicast forwarding cache (mfc) looking for - * inner matches with this vif's index. - * 3. Expire any matching multicast forwarding cache entries. - * 4. Free vif state. This should disable ALLMULTI on the interface. - */ - for (vifi = 0; vifi < V_numvifs; vifi++) { - if (V_viftable[vifi].v_ifp != ifp) - continue; - for (i = 0; i < mfchashsize; i++) { - struct mfc *rt, *nrt; + if (V_ip_mrouter == NULL) { + MRW_WUNLOCK(); + return; + } - LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) { - if (rt->mfc_parent == vifi) { - expire_mfc(rt); + /* + * Tear down multicast forwarder state associated with this ifnet. + * 1. Walk the vif list, matching vifs against this ifnet. + * 2. Walk the multicast forwarding cache (mfc) looking for + * inner matches with this vif's index. + * 3. Expire any matching multicast forwarding cache entries. + * 4. Free vif state. This should disable ALLMULTI on the interface. + */ + for (vifi = 0; vifi < V_numvifs; vifi++) { + if (V_viftable[vifi].v_ifp != ifp) + continue; + for (i = 0; i < mfchashsize; i++) { + struct mfc *rt, *nrt; + + LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) { + if (rt->mfc_parent == vifi) { + expire_mfc(rt); + } } } + del_vif_locked(vifi, &free_ptr); + if (free_ptr != NULL) + vifi_cnt++; } - del_vif_locked(vifi, &free_ptr); - if (free_ptr != NULL) - vifi_cnt++; - } - MRW_WUNLOCK(); + MRW_WUNLOCK(); - /* - * Free IFP. We don't have to use free_ptr here as it is the same - * that ifp. Perform free as many times as required in case - * refcount is greater than 1. - */ - for (i = 0; i < vifi_cnt; i++) - if_free(ifp); + /* + * Free IFP. We don't have to use free_ptr here as it is the same + * that ifp. Perform free as many times as required in case + * refcount is greater than 1. + */ + for (i = 0; i < vifi_cnt; i++) + if_free(ifp); } static void @@ -687,55 +682,55 @@ static int ip_mrouter_init(struct socket *so, int version) { - CTR2(KTR_IPMF, "%s: so %p", __func__, so); + CTR2(KTR_IPMF, "%s: so %p", __func__, so); - if (version != 1) - return ENOPROTOOPT; + if (version != 1) + return ENOPROTOOPT; - MRW_WLOCK(); + MRW_WLOCK(); - if (ip_mrouter_unloading) { - MRW_WUNLOCK(); - return ENOPROTOOPT; - } + if (ip_mrouter_unloading) { + MRW_WUNLOCK(); + return ENOPROTOOPT; + } - if (V_ip_mrouter != NULL) { - MRW_WUNLOCK(); - return EADDRINUSE; - } + if (V_ip_mrouter != NULL) { + MRW_WUNLOCK(); + return EADDRINUSE; + } - V_mfchashtbl = hashinit_flags(mfchashsize, M_MRTABLE, &V_mfchash, - HASH_NOWAIT); + V_mfchashtbl = hashinit_flags(mfchashsize, M_MRTABLE, &V_mfchash, + HASH_NOWAIT); - /* Create upcall ring */ - mtx_init(&V_bw_upcalls_ring_mtx, "mroute upcall buf_ring mtx", NULL, MTX_DEF); - V_bw_upcalls_ring = buf_ring_alloc(BW_UPCALLS_MAX, M_MRTABLE, - M_NOWAIT, &V_bw_upcalls_ring_mtx); - if (!V_bw_upcalls_ring) { - MRW_WUNLOCK(); - return (ENOMEM); - } + /* Create upcall ring */ + mtx_init(&V_bw_upcalls_ring_mtx, "mroute upcall buf_ring mtx", NULL, MTX_DEF); + V_bw_upcalls_ring = buf_ring_alloc(BW_UPCALLS_MAX, M_MRTABLE, + M_NOWAIT, &V_bw_upcalls_ring_mtx); + if (!V_bw_upcalls_ring) { + MRW_WUNLOCK(); + return (ENOMEM); + } - TASK_INIT(&V_task, 0, ip_mrouter_upcall_thread, curvnet); - taskqueue_cancel(V_task_queue, &V_task, NULL); - taskqueue_unblock(V_task_queue); + TASK_INIT(&V_task, 0, ip_mrouter_upcall_thread, curvnet); + taskqueue_cancel(V_task_queue, &V_task, NULL); + taskqueue_unblock(V_task_queue); - callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, - curvnet); - callout_reset(&V_bw_upcalls_ch, BW_UPCALLS_PERIOD, expire_bw_upcalls_send, - curvnet); + callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, + curvnet); + callout_reset(&V_bw_upcalls_ch, BW_UPCALLS_PERIOD, expire_bw_upcalls_send, + curvnet); - V_ip_mrouter = so; - atomic_add_int(&ip_mrouter_cnt, 1); + V_ip_mrouter = so; + atomic_add_int(&ip_mrouter_cnt, 1); - /* This is a mutex required by buf_ring init, but not used internally */ - mtx_init(&V_buf_ring_mtx, "mroute buf_ring mtx", NULL, MTX_DEF); + /* This is a mutex required by buf_ring init, but not used internally */ + mtx_init(&V_buf_ring_mtx, "mroute buf_ring mtx", NULL, MTX_DEF); - MRW_WUNLOCK(); + MRW_WUNLOCK(); - CTR1(KTR_IPMF, "%s: done", __func__); + CTR1(KTR_IPMF, "%s: done", __func__); - return 0; + return 0; } /* @@ -744,100 +739,100 @@ ip_mrouter_init(struct socket *so, int version) static int X_ip_mrouter_done(void) { - struct ifnet **ifps; - int nifp; - u_long i; - vifi_t vifi; - struct bw_upcall *bu; - - if (V_ip_mrouter == NULL) - return (EINVAL); - - /* - * Detach/disable hooks to the reset of the system. - */ - V_ip_mrouter = NULL; - atomic_subtract_int(&ip_mrouter_cnt, 1); - V_mrt_api_config = 0; - - /* - * Wait for all epoch sections to complete to ensure - * V_ip_mrouter = NULL is visible to others. - */ - epoch_wait_preempt(net_epoch_preempt); - - /* Stop and drain task queue */ - taskqueue_block(V_task_queue); - while (taskqueue_cancel(V_task_queue, &V_task, NULL)) { - taskqueue_drain(V_task_queue, &V_task); - } - - ifps = malloc(MAXVIFS * sizeof(*ifps), M_TEMP, M_WAITOK); - - MRW_WLOCK(); - taskqueue_cancel(V_task_queue, &V_task, NULL); - - /* Destroy upcall ring */ - while ((bu = buf_ring_dequeue_mc(V_bw_upcalls_ring)) != NULL) { - free(bu, M_MRTABLE); - } - buf_ring_free(V_bw_upcalls_ring, M_MRTABLE); - mtx_destroy(&V_bw_upcalls_ring_mtx); - - /* - * For each phyint in use, prepare to disable promiscuous reception - * of all IP multicasts. Defer the actual call until the lock is released; - * just record the list of interfaces while locked. Some interfaces use - * sx locks in their ioctl routines, which is not allowed while holding - * a non-sleepable lock. - */ - KASSERT(V_numvifs <= MAXVIFS, ("More vifs than possible")); - for (vifi = 0, nifp = 0; vifi < V_numvifs; vifi++) { - if (!in_nullhost(V_viftable[vifi].v_lcl_addr) && - !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { - ifps[nifp++] = V_viftable[vifi].v_ifp; - } - } - bzero((caddr_t)V_viftable, sizeof(*V_viftable) * MAXVIFS); - V_numvifs = 0; - V_pim_assert_enabled = 0; - - callout_stop(&V_expire_upcalls_ch); - callout_stop(&V_bw_upcalls_ch); - - /* - * Free all multicast forwarding cache entries. - * Do not use hashdestroy(), as we must perform other cleanup. - */ - for (i = 0; i < mfchashsize; i++) { - struct mfc *rt, *nrt; - - LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) { - expire_mfc(rt); - } - } - free(V_mfchashtbl, M_MRTABLE); - V_mfchashtbl = NULL; - - bzero(V_nexpire, sizeof(V_nexpire[0]) * mfchashsize); - - V_reg_vif_num = VIFI_INVALID; - - mtx_destroy(&V_buf_ring_mtx); - - MRW_WUNLOCK(); - - /* - * Now drop our claim on promiscuous multicast on the interfaces recorded - * above. This is safe to do now because ALLMULTI is reference counted. - */ - for (vifi = 0; vifi < nifp; vifi++) - if_allmulti(ifps[vifi], 0); - free(ifps, M_TEMP); - - CTR1(KTR_IPMF, "%s: done", __func__); - - return 0; + struct ifnet **ifps; + int nifp; + u_long i; + vifi_t vifi; + struct bw_upcall *bu; + + if (V_ip_mrouter == NULL) + return (EINVAL); + + /* + * Detach/disable hooks to the reset of the system. + */ + V_ip_mrouter = NULL; + atomic_subtract_int(&ip_mrouter_cnt, 1); + V_mrt_api_config = 0; + + /* + * Wait for all epoch sections to complete to ensure + * V_ip_mrouter = NULL is visible to others. + */ + epoch_wait_preempt(net_epoch_preempt); + + /* Stop and drain task queue */ + taskqueue_block(V_task_queue); + while (taskqueue_cancel(V_task_queue, &V_task, NULL)) { + taskqueue_drain(V_task_queue, &V_task); + } + + ifps = malloc(MAXVIFS * sizeof(*ifps), M_TEMP, M_WAITOK); + + MRW_WLOCK(); + taskqueue_cancel(V_task_queue, &V_task, NULL); + + /* Destroy upcall ring */ + while ((bu = buf_ring_dequeue_mc(V_bw_upcalls_ring)) != NULL) { + free(bu, M_MRTABLE); + } + buf_ring_free(V_bw_upcalls_ring, M_MRTABLE); + mtx_destroy(&V_bw_upcalls_ring_mtx); + + /* + * For each phyint in use, prepare to disable promiscuous reception + * of all IP multicasts. Defer the actual call until the lock is released; + * just record the list of interfaces while locked. Some interfaces use + * sx locks in their ioctl routines, which is not allowed while holding + * a non-sleepable lock. + */ + KASSERT(V_numvifs <= MAXVIFS, ("More vifs than possible")); + for (vifi = 0, nifp = 0; vifi < V_numvifs; vifi++) { + if (!in_nullhost(V_viftable[vifi].v_lcl_addr) && + !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { + ifps[nifp++] = V_viftable[vifi].v_ifp; + } + } + bzero((caddr_t)V_viftable, sizeof(*V_viftable) * MAXVIFS); + V_numvifs = 0; + V_pim_assert_enabled = 0; + + callout_stop(&V_expire_upcalls_ch); + callout_stop(&V_bw_upcalls_ch); + + /* + * Free all multicast forwarding cache entries. + * Do not use hashdestroy(), as we must perform other cleanup. + */ + for (i = 0; i < mfchashsize; i++) { + struct mfc *rt, *nrt; + + LIST_FOREACH_SAFE(rt, &V_mfchashtbl[i], mfc_hash, nrt) { + expire_mfc(rt); + } + } + free(V_mfchashtbl, M_MRTABLE); + V_mfchashtbl = NULL; + + bzero(V_nexpire, sizeof(V_nexpire[0]) * mfchashsize); + + V_reg_vif_num = VIFI_INVALID; + + mtx_destroy(&V_buf_ring_mtx); + + MRW_WUNLOCK(); + + /* + * Now drop our claim on promiscuous multicast on the interfaces recorded + * above. This is safe to do now because ALLMULTI is reference counted. + */ + for (vifi = 0; vifi < nifp; vifi++) + if_allmulti(ifps[vifi], 0); + free(ifps, M_TEMP); + + CTR1(KTR_IPMF, "%s: done", __func__); + + return 0; } /* @@ -846,12 +841,12 @@ X_ip_mrouter_done(void) static int set_assert(int i) { - if ((i != 1) && (i != 0)) - return EINVAL; + if ((i != 1) && (i != 0)) + return EINVAL; - V_pim_assert_enabled = i; + V_pim_assert_enabled = i; - return 0; + return 0; } /* @@ -860,40 +855,40 @@ set_assert(int i) int set_api_config(uint32_t *apival) { - u_long i; - - /* - * We can set the API capabilities only if it is the first operation - * after MRT_INIT. I.e.: - * - there are no vifs installed - * - pim_assert is not enabled - * - the MFC table is empty - */ - if (V_numvifs > 0) { - *apival = 0; - return EPERM; - } - if (V_pim_assert_enabled) { - *apival = 0; - return EPERM; - } - - MRW_RLOCK(); - - for (i = 0; i < mfchashsize; i++) { - if (LIST_FIRST(&V_mfchashtbl[i]) != NULL) { - MRW_RUNLOCK(); - *apival = 0; - return EPERM; - } - } - - MRW_RUNLOCK(); - - V_mrt_api_config = *apival & mrt_api_support; - *apival = V_mrt_api_config; - - return 0; + u_long i; + + /* + * We can set the API capabilities only if it is the first operation + * after MRT_INIT. I.e.: + * - there are no vifs installed + * - pim_assert is not enabled + * - the MFC table is empty + */ + if (V_numvifs > 0) { + *apival = 0; + return EPERM; + } + if (V_pim_assert_enabled) { + *apival = 0; + return EPERM; + } + + MRW_RLOCK(); + + for (i = 0; i < mfchashsize; i++) { + if (LIST_FIRST(&V_mfchashtbl[i]) != NULL) { + MRW_RUNLOCK(); + *apival = 0; + return EPERM; + } + } + + MRW_RUNLOCK(); + + V_mrt_api_config = *apival & mrt_api_support; + *apival = V_mrt_api_config; + + return 0; } /* @@ -902,102 +897,101 @@ set_api_config(uint32_t *apival) static int add_vif(struct vifctl *vifcp) { - struct vif *vifp = V_viftable + vifcp->vifc_vifi; - struct sockaddr_in sin = {sizeof sin, AF_INET}; - struct ifaddr *ifa; - struct ifnet *ifp; - int error; - - - if (vifcp->vifc_vifi >= MAXVIFS) - return EINVAL; - /* rate limiting is no longer supported by this code */ - if (vifcp->vifc_rate_limit != 0) { - log(LOG_ERR, "rate limiting is no longer supported\n"); - return EINVAL; - } - - if (in_nullhost(vifcp->vifc_lcl_addr)) - return EADDRNOTAVAIL; - - /* Find the interface with an address in AF_INET family */ - if (vifcp->vifc_flags & VIFF_REGISTER) { - /* - * XXX: Because VIFF_REGISTER does not really need a valid - * local interface (e.g. it could be 127.0.0.2), we don't - * check its address. - */ - ifp = NULL; - } else { - struct epoch_tracker et; + struct vif *vifp = V_viftable + vifcp->vifc_vifi; + struct sockaddr_in sin = {sizeof sin, AF_INET}; + struct ifaddr *ifa; + struct ifnet *ifp; + int error; - sin.sin_addr = vifcp->vifc_lcl_addr; - NET_EPOCH_ENTER(et); - ifa = ifa_ifwithaddr((struct sockaddr *)&sin); - if (ifa == NULL) { - NET_EPOCH_EXIT(et); - return EADDRNOTAVAIL; + if (vifcp->vifc_vifi >= MAXVIFS) + return EINVAL; + /* rate limiting is no longer supported by this code */ + if (vifcp->vifc_rate_limit != 0) { + log(LOG_ERR, "rate limiting is no longer supported\n"); + return EINVAL; + } + + if (in_nullhost(vifcp->vifc_lcl_addr)) + return EADDRNOTAVAIL; + + /* Find the interface with an address in AF_INET family */ + if (vifcp->vifc_flags & VIFF_REGISTER) { + /* + * XXX: Because VIFF_REGISTER does not really need a valid + * local interface (e.g. it could be 127.0.0.2), we don't + * check its address. + */ + ifp = NULL; + } else { + struct epoch_tracker et; + + sin.sin_addr = vifcp->vifc_lcl_addr; + NET_EPOCH_ENTER(et); + ifa = ifa_ifwithaddr((struct sockaddr *)&sin); + if (ifa == NULL) { + NET_EPOCH_EXIT(et); + return EADDRNOTAVAIL; + } + ifp = ifa->ifa_ifp; + /* XXX FIXME we need to take a ref on ifp and cleanup properly! */ + NET_EPOCH_EXIT(et); + } + + if ((vifcp->vifc_flags & VIFF_TUNNEL) != 0) { + CTR1(KTR_IPMF, "%s: tunnels are no longer supported", __func__); + return EOPNOTSUPP; + } else if (vifcp->vifc_flags & VIFF_REGISTER) { + ifp = V_multicast_register_if = if_alloc(IFT_LOOP); *** 2270 LINES SKIPPED ***