diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 3c47552d3214..f69be4d22137 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1400,11 +1400,15 @@ again: CURVNET_SET(P_TO_VNET(&proc0)); #ifdef INET INIT_VNET_INET(curvnet); + IN_IFADDR_RLOCK(); if (!TAILQ_EMPTY(&V_in_ifaddrhead)) cverf.lval[0] = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr.s_addr; else #endif cverf.lval[0] = create_verf; +#ifdef INET + IN_IFADDR_RUNLOCK(); +#endif cverf.lval[1] = ++create_verf; CURVNET_RESTORE(); error = nfsrpc_create(dvp, cnp->cn_nameptr, cnp->cn_namelen, diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 3e82866842ef..1e7adb4afd24 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -4973,8 +4973,10 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) /* set new address */ si->sin_addr.s_addr = htonl(src); ia = ifatoia(ifa); + IN_IFADDR_WLOCK(); LIST_REMOVE(ia, ia_hash); LIST_INSERT_HEAD(INADDR_HASH(si->sin_addr.s_addr), ia, ia_hash); + IN_IFADDR_WUNLOCK(); /* add new route */ error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index d463ff63485b..12ce174f09d8 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -620,15 +620,19 @@ stf_checkaddr4(sc, in, inifp) /* * reject packets with broadcast */ + IN_IFADDR_RLOCK(); for (ia4 = TAILQ_FIRST(&V_in_ifaddrhead); ia4; ia4 = TAILQ_NEXT(ia4, ia_link)) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; - if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { + IN_IFADDR_RUNLOCK(); return -1; + } } + IN_IFADDR_RUNLOCK(); /* * perform ingress filter diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 9c80ea0a4e39..97ea1085bfdf 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -509,11 +509,13 @@ in_arpinput(struct mbuf *m) * request for the virtual host ip. * XXX: This is really ugly! */ + IN_IFADDR_RLOCK(); LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { if (((bridged && ia->ia_ifp->if_bridge != NULL) || ia->ia_ifp == ifp) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); goto match; } #ifdef DEV_CARP @@ -522,6 +524,7 @@ in_arpinput(struct mbuf *m) itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { carp_match = 1; ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); goto match; } #endif @@ -531,6 +534,7 @@ in_arpinput(struct mbuf *m) ia->ia_ifp == ifp) && isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); goto match; } @@ -549,11 +553,13 @@ in_arpinput(struct mbuf *m) if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) { ifa_ref(&ia->ia_ifa); ifp = ia->ia_ifp; + IN_IFADDR_RUNLOCK(); goto match; } } } #undef BDG_MEMBER_MATCHES_ARP + IN_IFADDR_RUNLOCK(); /* * No match, use the first inet address on the receive interface @@ -572,9 +578,13 @@ in_arpinput(struct mbuf *m) /* * If bridging, fall back to using any inet address. */ - if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) + IN_IFADDR_RLOCK(); + if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) { + IN_IFADDR_RUNLOCK(); goto drop; + } ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); match: if (!enaddr) enaddr = (u_int8_t *)IF_LLADDR(ifp); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 2b6fd185eed5..b9db746591e8 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -100,15 +100,23 @@ in_localaddr(struct in_addr in) register u_long i = ntohl(in.s_addr); register struct in_ifaddr *ia; + IN_IFADDR_RLOCK(); if (V_subnetsarelocal) { - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) - if ((i & ia->ia_netmask) == ia->ia_net) + TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + if ((i & ia->ia_netmask) == ia->ia_net) { + IN_IFADDR_RUNLOCK(); return (1); + } + } } else { - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) - if ((i & ia->ia_subnetmask) == ia->ia_subnet) + TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + if ((i & ia->ia_subnetmask) == ia->ia_subnet) { + IN_IFADDR_RUNLOCK(); return (1); + } + } } + IN_IFADDR_RUNLOCK(); return (0); } @@ -122,10 +130,14 @@ in_localip(struct in_addr in) INIT_VNET_INET(curvnet); struct in_ifaddr *ia; + IN_IFADDR_RLOCK(); LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) { - if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) + if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) { + IN_IFADDR_RUNLOCK(); return (1); + } } + IN_IFADDR_RUNLOCK(); return (0); } @@ -222,7 +234,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct in_ifinfo *ii; struct in_aliasreq *ifra = (struct in_aliasreq *)data; struct sockaddr_in oldaddr; - int error, hostIsNew, iaIsNew, maskIsNew, s; + int error, hostIsNew, iaIsNew, maskIsNew; int iaIsFirst; ia = NULL; @@ -313,6 +325,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * first one on the interface, if possible. */ dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; + IN_IFADDR_RLOCK(); LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) { if (iap->ia_ifp == ifp && iap->ia_addr.sin_addr.s_addr == dst.s_addr) { @@ -324,6 +337,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, } if (ia != NULL) ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); if (ia == NULL) { IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { @@ -351,6 +365,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, if (ifra->ifra_addr.sin_family == AF_INET) { struct in_ifaddr *oia; + IN_IFADDR_RLOCK(); for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { if (ia->ia_ifp == ifp && ia->ia_addr.sin_addr.s_addr == @@ -361,6 +376,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, ifa_ref(&ia->ia_ifa); if (oia != NULL && ia != oia) ifa_free(&oia->ia_ifa); + IN_IFADDR_RUNLOCK(); if ((ifp->if_flags & IFF_POINTOPOINT) && (cmd == SIOCAIFADDR) && (ifra->ifra_dstaddr.sin_addr.s_addr @@ -405,9 +421,9 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); IF_ADDR_UNLOCK(ifp); ifa_ref(ifa); /* in_ifaddrhead */ - s = splnet(); + IN_IFADDR_WLOCK(); TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); - splx(s); + IN_IFADDR_WUNLOCK(); iaIsNew = 1; } break; @@ -578,13 +594,14 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); IF_ADDR_UNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ - s = splnet(); + + IN_IFADDR_WLOCK(); TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); - ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ if (ia->ia_addr.sin_family == AF_INET) { struct in_ifaddr *if_ia; LIST_REMOVE(ia, ia_hash); + IN_IFADDR_WUNLOCK(); /* * If this is the last IPv4 address configured on this * interface, leave the all-hosts group. @@ -603,8 +620,9 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, IN_MULTI_UNLOCK(); } else ifa_free(&if_ia->ia_ifa); - } - splx(s); + } else + IN_IFADDR_WUNLOCK(); + ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ out: if (ia != NULL) ifa_free(&ia->ia_ifa); @@ -811,9 +829,12 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, if (oldaddr.sin_family == AF_INET) LIST_REMOVE(ia, ia_hash); ia->ia_addr = *sin; - if (ia->ia_addr.sin_family == AF_INET) + if (ia->ia_addr.sin_family == AF_INET) { + IN_IFADDR_WLOCK(); LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); + IN_IFADDR_WUNLOCK(); + } /* * Give the interface a chance to initialize * if this is its first address, @@ -825,6 +846,7 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, splx(s); /* LIST_REMOVE(ia, ia_hash) is done in in_control */ ia->ia_addr = oldaddr; + IN_IFADDR_WLOCK(); if (ia->ia_addr.sin_family == AF_INET) LIST_INSERT_HEAD(INADDR_HASH( ia->ia_addr.sin_addr.s_addr), ia, ia_hash); @@ -836,6 +858,7 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, * with bogus ia entries in hash */ LIST_REMOVE(ia, ia_hash); + IN_IFADDR_WUNLOCK(); return (error); } } @@ -943,6 +966,7 @@ in_addprefix(struct in_ifaddr *target, int flags) prefix.s_addr &= mask.s_addr; } + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { p = ia->ia_addr.sin_addr; @@ -966,12 +990,16 @@ in_addprefix(struct in_ifaddr *target, int flags) if (ia->ia_flags & IFA_ROUTE) { if (V_sameprefixcarponly && target->ia_ifp->if_type != IFT_CARP && - ia->ia_ifp->if_type != IFT_CARP) + ia->ia_ifp->if_type != IFT_CARP) { + IN_IFADDR_RUNLOCK(); return (EEXIST); - else + } else { + IN_IFADDR_RUNLOCK(); return (0); + } } } + IN_IFADDR_RUNLOCK(); /* * No-one seem to have this prefix route, so we try to insert it. @@ -1031,6 +1059,7 @@ in_scrubprefix(struct in_ifaddr *target) arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr); } + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) p = ia->ia_dstaddr.sin_addr; @@ -1054,6 +1083,7 @@ in_scrubprefix(struct in_ifaddr *target) && (ia->ia_ifp->if_type != IFT_CARP) #endif ) { + IN_IFADDR_RUNLOCK(); rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); target->ia_flags &= ~IFA_ROUTE; @@ -1065,6 +1095,7 @@ in_scrubprefix(struct in_ifaddr *target) return (error); } } + IN_IFADDR_RUNLOCK(); /* * remove all L2 entries on the given prefix diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index ce45672fcfc3..11e32c356408 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -387,13 +387,19 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) case 0: case 127: case 255: return 0; } + /* reject packets with broadcast on source */ + /* XXXRW: should use hash lists? */ + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; - if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) + if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { + IN_IFADDR_RUNLOCK(); return 0; + } } + IN_IFADDR_RUNLOCK(); /* ingress filters on outer source */ if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index a856676cdc00..5c299af6a6e1 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -1834,6 +1834,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, struct ifnet *mifp; mifp = NULL; + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { mifp = ia->ia_ifp; if (!(mifp->if_flags & IFF_LOOPBACK) && @@ -1842,6 +1843,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, break; } } + IN_IFADDR_RUNLOCK(); } } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 574ce63a03f9..958e6b6ab313 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -813,16 +813,21 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, * choose the broadcast address for that interface. */ if (faddr.s_addr == INADDR_ANY) { + IN_IFADDR_RLOCK(); faddr = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; + IN_IFADDR_RUNLOCK(); if (cred != NULL && (error = prison_get_ip4(cred, &faddr)) != 0) return (error); - } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && - (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & - IFF_BROADCAST)) - faddr = satosin(&TAILQ_FIRST( - &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; + } else if (faddr.s_addr == (u_long)INADDR_BROADCAST) { + IN_IFADDR_RLOCK(); + if (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & + IFF_BROADCAST) + faddr = satosin(&TAILQ_FIRST( + &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; + IN_IFADDR_RUNLOCK(); + } } if (laddr.s_addr == INADDR_ANY) { error = in_pcbladdr(inp, &faddr, &laddr, cred); @@ -842,12 +847,16 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) if (ia->ia_ifp == ifp) break; - if (ia == NULL) + if (ia == NULL) { + IN_IFADDR_RUNLOCK(); return (EADDRNOTAVAIL); + } laddr = ia->ia_addr.sin_addr; + IN_IFADDR_RUNLOCK(); } } } diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index dbacbface287..e00ea5cb1e22 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -114,6 +114,17 @@ extern u_long in_ifaddrhmask; /* mask for hash table */ #define INADDR_HASH(x) \ (&V_in_ifaddrhashtbl[INADDR_HASHVAL(x) & V_in_ifaddrhmask]) +extern struct rwlock in_ifaddr_lock; + +#define IN_IFADDR_LOCK_INIT() rw_init(&in_ifaddr_lock, "in_ifaddr_lock") +#define IN_IFADDR_LOCK_ASSERT() rw_assert(&in_ifaddr_lock, RA_LOCKED) +#define IN_IFADDR_RLOCK() rw_rlock(&in_ifaddr_lock) +#define IN_IFADDR_RLOCK_ASSERT() rw_assert(&in_ifaddr_lock, RA_RLOCKED) +#define IN_IFADDR_RUNLOCK() rw_runlock(&in_ifaddr_lock) +#define IN_IFADDR_WLOCK() rw_wlock(&in_ifaddr_lock) +#define IN_IFADDR_WLOCK_ASSERT() rw_assert(&in_ifaddr_lock, RA_WLOCKED) +#define IN_IFADDR_WUNLOCK() rw_wunlock(&in_ifaddr_lock) + /* * Macro for finding the internet address structure (in_ifaddr) * corresponding to one of our IP addresses (in_addr). diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index edeec2afec56..8c7bd0cab5b2 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1500,6 +1500,7 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) /* we have to do it by hands to check we won't match on us */ ia_if = NULL; own = 0; + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { /* and, yeah, we need a multicast-capable iface too */ if (ia->ia_ifp != SC2IFP(sc) && @@ -1513,20 +1514,30 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) } } - if (!ia_if) + if (!ia_if) { + IN_IFADDR_RUNLOCK(); return (EADDRNOTAVAIL); + } ia = ia_if; + ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); + ifp = ia->ia_ifp; if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 || - (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp)) + (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp)) { + ifa_free(&ia->ia_ifa); return (EADDRNOTAVAIL); + } if (imo->imo_num_memberships == 0) { addr.s_addr = htonl(INADDR_CARP_GROUP); - if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == NULL) + if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == + NULL) { + ifa_free(&ia->ia_ifa); return (ENOBUFS); + } imo->imo_num_memberships++; imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; @@ -1601,11 +1612,13 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) carp_setrun(sc, 0); CARP_UNLOCK(cif); + ifa_free(&ia->ia_ifa); /* XXXRW: should hold reference for softc. */ return (0); cleanup: in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); + ifa_free(&ia->ia_ifa); return (error); } diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 3cd6530b41fd..f3ef17524470 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -675,12 +675,16 @@ icmp_reflect(struct mbuf *m) * If the incoming packet was addressed directly to one of our * own addresses, use dst as the src for the reply. */ + IN_IFADDR_RLOCK(); LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash) { if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) { t = IA_SIN(ia)->sin_addr; + IN_IFADDR_RUNLOCK(); goto match; } } + IN_IFADDR_RUNLOCK(); + /* * If the incoming packet was addressed to one of our broadcast * addresses, use the first non-broadcast address which corresponds diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 81b8f8f355ed..53c07fc5f2b4 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -117,6 +117,7 @@ static int maxfragsperpacket; int ipstealth; static int nipq; /* Total # of reass queues */ #endif +struct rwlock in_ifaddr_lock; SYSCTL_V_INT(V_NET, vnet_inet, _net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, ipforwarding, 0, @@ -325,6 +326,7 @@ ip_init(void) TAILQ_INIT(&V_in_ifaddrhead); V_in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &V_in_ifaddrhmask); + IN_IFADDR_LOCK_INIT(); /* Initialize IP reassembly queue. */ for (i = 0; i < IPREASS_NHASH; i++) @@ -615,6 +617,7 @@ passin: /* * Check for exact addresses in the hash bucket. */ + /* IN_IFADDR_RLOCK(); */ LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) { /* * If the address matches, verify that the packet @@ -624,9 +627,12 @@ passin: if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr && (!checkif || ia->ia_ifp == ifp)) { ifa_ref(&ia->ia_ifa); + /* IN_IFADDR_RUNLOCK(); */ goto ours; } } + /* IN_IFADDR_RUNLOCK(); */ + /* * Check for broadcast addresses. * diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 0157afbe250b..00ec4231988b 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -678,9 +678,12 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) switch (cmd) { case PRC_IFDOWN: + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (ia->ia_ifa.ifa_addr == sa && (ia->ia_flags & IFA_ROUTE)) { + ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); /* * in_ifscrub kills the interface route. */ @@ -692,18 +695,26 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) * routing process they will come back. */ in_ifadown(&ia->ia_ifa, 0); + ifa_free(&ia->ia_ifa); break; } } + if (ia == NULL) /* If ia matched, already unlocked. */ + IN_IFADDR_RUNLOCK(); break; case PRC_IFUP: + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (ia->ia_ifa.ifa_addr == sa) break; } - if (ia == 0 || (ia->ia_flags & IFA_ROUTE)) + if (ia == NULL || (ia->ia_flags & IFA_ROUTE)) { + IN_IFADDR_RUNLOCK(); return; + } + ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); flags = RTF_UP; ifp = ia->ia_ifa.ifa_ifp; @@ -714,6 +725,7 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) err = rtinit(&ia->ia_ifa, RTM_ADD, flags); if (err == 0) ia->ia_flags |= IFA_ROUTE; + ifa_free(&ia->ia_ifa); break; } } diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index 0ab2eb00b0f4..08547a8d58d2 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -3939,6 +3939,7 @@ key_ismyaddr(sa) #ifdef INET case AF_INET: sin = (struct sockaddr_in *)sa; + IN_IFADDR_RLOCK(); for (ia = V_in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { @@ -3946,9 +3947,11 @@ key_ismyaddr(sa) sin->sin_len == ia->ia_addr.sin_len && sin->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) { + IN_IFADDR_RUNLOCK(); return 1; } } + IN_IFADDR_RUNLOCK(); break; #endif #ifdef INET6 diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index 3623fab6c325..bc6936d45984 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -1553,11 +1553,15 @@ again: tl = nfsm_build(u_int32_t *, NFSX_V3CREATEVERF); #ifdef INET INIT_VNET_INET(curvnet); + IN_IFADDR_RLOCK(); if (!TAILQ_EMPTY(&V_in_ifaddrhead)) *tl++ = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr.s_addr; else #endif *tl++ = create_verf; +#ifdef INET + IN_IFADDR_RUNLOCK(); +#endif *tl = ++create_verf; } else { *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);