summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/in6_ifattach.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/in6_ifattach.c')
-rw-r--r--freebsd/sys/netinet6/in6_ifattach.c75
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