diff options
Diffstat (limited to 'freebsd/sys/netinet6/in6_ifattach.c')
-rw-r--r-- | freebsd/sys/netinet6/in6_ifattach.c | 75 |
1 files changed, 37 insertions, 38 deletions
diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c index 6af4b557..560b4255 100644 --- a/freebsd/sys/netinet6/in6_ifattach.c +++ b/freebsd/sys/netinet6/in6_ifattach.c @@ -246,6 +246,7 @@ generate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) int in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) { + struct epoch_tracker et; struct ifaddr *ifa; struct sockaddr_dl *sdl; u_int8_t *addr; @@ -254,7 +255,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - IF_ADDR_RLOCK(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; @@ -266,7 +267,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) goto found; } - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; @@ -289,7 +290,7 @@ found: /* look at IEEE802/EUI64 only */ if (addrlen != 8 && addrlen != 6) { - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } @@ -299,11 +300,11 @@ found: * card insertion. */ if (bcmp(addr, allzero, addrlen) == 0) { - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } if (bcmp(addr, allone, addrlen) == 0) { - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } @@ -330,17 +331,25 @@ found: * identifier source (can be renumbered). * we don't do this. */ - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; + case IFT_INFINIBAND: + if (addrlen != 20) { + NET_EPOCH_EXIT(et); + return -1; + } + bcopy(addr + 12, &in6->s6_addr[8], 8); + break; + default: - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } /* sanity check: g bit must not indicate "group" */ if (EUI64_GROUP(in6)) { - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } @@ -353,11 +362,11 @@ found: */ if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && bcmp(&in6->s6_addr[9], allzero, 7) == 0) { - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return -1; } - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return 0; } @@ -372,6 +381,7 @@ static int get_ifid(struct ifnet *ifp0, struct ifnet *altifp, struct in6_addr *in6) { + struct epoch_tracker et; struct ifnet *ifp; /* first, try to get it from the interface itself */ @@ -389,7 +399,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, } /* next, try to get it from some other hardware interface */ - IFNET_RLOCK_NOSLEEP(); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp == ifp0) continue; @@ -404,11 +414,11 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, nd6log((LOG_DEBUG, "%s: borrow interface identifier from %s\n", if_name(ifp0), if_name(ifp))); - IFNET_RUNLOCK_NOSLEEP(); + NET_EPOCH_EXIT(et); goto success; } } - IFNET_RUNLOCK_NOSLEEP(); + NET_EPOCH_EXIT(et); /* last resort: get from random number source */ if (get_rand_ifid(ifp, in6) == 0) { @@ -700,6 +710,7 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp) * it is rather harmful to have one. */ ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; + ND_IFINFO(ifp)->flags |= ND6_IFF_NO_DAD; break; default: break; @@ -773,9 +784,11 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp) in6_purgeaddr(ifa); } if (purgeulp) { + IN6_MULTI_LOCK(); in6_pcbpurgeif0(&V_udbinfo, ifp); in6_pcbpurgeif0(&V_ulitecbinfo, ifp); in6_pcbpurgeif0(&V_ripcbinfo, ifp); + IN6_MULTI_UNLOCK(); } /* leave from all multicast groups joined */ in6_purgemaddrs(ifp); @@ -862,36 +875,22 @@ in6_tmpaddrtimer(void *arg) static void in6_purgemaddrs(struct ifnet *ifp) { - struct in6_multi_head purgeinms; - struct in6_multi *inm; - struct ifmultiaddr *ifma, *next; + struct in6_multi_head inmh; - SLIST_INIT(&purgeinms); + SLIST_INIT(&inmh); IN6_MULTI_LOCK(); IN6_MULTI_LIST_LOCK(); - IF_ADDR_WLOCK(ifp); - /* - * Extract list of in6_multi associated with the detaching ifp - * which the PF_INET6 layer is about to release. - */ - restart: - CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { - if (ifma->ifma_addr->sa_family != AF_INET6 || - ifma->ifma_protospec == NULL) - continue; - inm = (struct in6_multi *)ifma->ifma_protospec; - in6m_disconnect(inm); - in6m_rele_locked(&purgeinms, inm); - if (__predict_false(ifma6_restart)) { - ifma6_restart = false; - goto restart; - } - } - IF_ADDR_WUNLOCK(ifp); - mld_ifdetach(ifp); + mld_ifdetach(ifp, &inmh); IN6_MULTI_LIST_UNLOCK(); IN6_MULTI_UNLOCK(); - in6m_release_list_deferred(&purgeinms); + in6m_release_list_deferred(&inmh); + + /* + * Make sure all multicast deletions invoking if_ioctl() are + * completed before returning. Else we risk accessing a freed + * ifnet structure pointer. + */ + in6m_release_wait(); } void |