summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c4
-rw-r--r--sys/net/if_spppsubr.c2
-rw-r--r--sys/net/if_stf.c6
-rw-r--r--sys/netinet/if_ether.c12
-rw-r--r--sys/netinet/in.c61
-rw-r--r--sys/netinet/in_gif.c8
-rw-r--r--sys/netinet/in_mcast.c2
-rw-r--r--sys/netinet/in_pcb.c21
-rw-r--r--sys/netinet/in_var.h11
-rw-r--r--sys/netinet/ip_carp.c19
-rw-r--r--sys/netinet/ip_icmp.c4
-rw-r--r--sys/netinet/ip_input.c6
-rw-r--r--sys/netinet/raw_ip.c14
-rw-r--r--sys/netipsec/key.c3
-rw-r--r--sys/nfsclient/nfs_vnops.c4
15 files changed, 149 insertions, 28 deletions
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 3c47552..f69be4d 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 3e82866..1e7adb4 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 d463ff6..12ce174 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 9c80ea0..97ea108 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 2b6fd18..b9db746 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 ce45672..11e32c3 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 a856676..5c299af 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 574ce63..958e6b6 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 dbacbfa..e00ea5c 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 edeec2a..8c7bd0c 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 3cd6530..f3ef175 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 81b8f8f3..53c07fc 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 0157afb..00ec423 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 0ab2eb0..08547a8 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 3623fab..bc6936d 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);
OpenPOWER on IntegriCloud