diff options
Diffstat (limited to 'sys/netinet/in.c')
-rw-r--r-- | sys/netinet/in.c | 61 |
1 files changed, 46 insertions, 15 deletions
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 |