diff options
Diffstat (limited to 'freebsd/sys/netinet6/in6_pcb.c')
-rw-r--r-- | freebsd/sys/netinet6/in6_pcb.c | 50 |
1 files changed, 26 insertions, 24 deletions
diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c index a6beba43..b66aa8a4 100644 --- a/freebsd/sys/netinet6/in6_pcb.c +++ b/freebsd/sys/netinet6/in6_pcb.c @@ -186,14 +186,15 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, (SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + struct epoch_tracker et; struct ifaddr *ifa; sin6->sin6_port = 0; /* yech... */ - NET_EPOCH_ENTER(); + NET_EPOCH_ENTER(et); if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) == NULL && (inp->inp_flags & INP_BINDANY) == 0) { - NET_EPOCH_EXIT(); + NET_EPOCH_EXIT(et); return (EADDRNOTAVAIL); } @@ -206,10 +207,10 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, if (ifa != NULL && ((struct in6_ifaddr *)ifa)->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { - NET_EPOCH_EXIT(); + NET_EPOCH_EXIT(et); return (EADDRNOTAVAIL); } - NET_EPOCH_EXIT(); + NET_EPOCH_EXIT(et); } if (lport) { struct inpcb *t; @@ -814,19 +815,20 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr, void in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { - struct inpcb *in6p; + struct inpcb *inp; + struct in6_multi *inm; + struct in6_mfilter *imf; struct ip6_moptions *im6o; - int i, gap; INP_INFO_WLOCK(pcbinfo); - CK_LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) { - INP_WLOCK(in6p); - if (__predict_false(in6p->inp_flags2 & INP_FREED)) { - INP_WUNLOCK(in6p); + CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { + INP_WLOCK(inp); + if (__predict_false(inp->inp_flags2 & INP_FREED)) { + INP_WUNLOCK(inp); continue; } - im6o = in6p->in6p_moptions; - if ((in6p->inp_vflag & INP_IPV6) && im6o != NULL) { + im6o = inp->in6p_moptions; + if ((inp->inp_vflag & INP_IPV6) && im6o != NULL) { /* * Unselect the outgoing ifp for multicast if it * is being detached. @@ -837,20 +839,20 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) * Drop multicast group membership if we joined * through the interface being detached. */ - gap = 0; - for (i = 0; i < im6o->im6o_num_memberships; i++) { - if (im6o->im6o_membership[i]->in6m_ifp == - ifp) { - in6_leavegroup(im6o->im6o_membership[i], NULL); - gap++; - } else if (gap != 0) { - im6o->im6o_membership[i - gap] = - im6o->im6o_membership[i]; - } +restart: + IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { + if ((inm = imf->im6f_in6m) == NULL) + continue; + if (inm->in6m_ifp != ifp) + continue; + ip6_mfilter_remove(&im6o->im6o_head, imf); + IN6_MULTI_LOCK_ASSERT(); + in6_leavegroup_locked(inm, NULL); + ip6_mfilter_free(imf); + goto restart; } - im6o->im6o_num_memberships -= gap; } - INP_WUNLOCK(in6p); + INP_WUNLOCK(inp); } INP_INFO_WUNLOCK(pcbinfo); } |