summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/in.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/in.c')
-rw-r--r--freebsd/sys/netinet/in.c179
1 files changed, 87 insertions, 92 deletions
diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c
index 28c257aa..7233f9a2 100644
--- a/freebsd/sys/netinet/in.c
+++ b/freebsd/sys/netinet/in.c
@@ -104,7 +104,7 @@ in_localaddr(struct in_addr in)
struct in_ifaddr *ia;
IN_IFADDR_RLOCK(&in_ifa_tracker);
- TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
if ((i & ia->ia_subnetmask) == ia->ia_subnet) {
IN_IFADDR_RUNLOCK(&in_ifa_tracker);
return (1);
@@ -145,7 +145,7 @@ in_ifhasaddr(struct ifnet *ifp, struct in_addr in)
struct in_ifaddr *ia;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
ia = (struct in_ifaddr *)ifa;
@@ -282,7 +282,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
* first one on the interface, if possible.
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
ia = (struct in_ifaddr *)ifa;
@@ -290,7 +290,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
break;
}
if (ifa == NULL)
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_INET) {
ia = (struct in_ifaddr *)ifa;
if (prison_check_ip4(td->td_ucred,
@@ -381,7 +381,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
iaIsFirst = true;
ia = NULL;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct in_ifaddr *it;
if (ifa->ifa_addr->sa_family != AF_INET)
@@ -459,12 +459,12 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
/* if_addrhead is already referenced by ifa_alloc() */
IF_ADDR_WLOCK(ifp);
- TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
+ CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_ref(ifa); /* in_ifaddrhead */
IN_IFADDR_WLOCK();
- TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link);
+ CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link);
LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash);
IN_IFADDR_WUNLOCK();
@@ -537,12 +537,12 @@ fail1:
(*carp_detach_p)(&ia->ia_ifa, false);
IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_free(&ia->ia_ifa); /* if_addrhead */
IN_IFADDR_WLOCK();
- TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
+ CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link);
LIST_REMOVE(ia, ia_hash);
IN_IFADDR_WUNLOCK();
ifa_free(&ia->ia_ifa); /* in_ifaddrhead */
@@ -576,7 +576,7 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
iaIsLast = true;
ia = NULL;
IF_ADDR_WLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct in_ifaddr *it;
if (ifa->ifa_addr->sa_family != AF_INET)
@@ -601,12 +601,12 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
return (EADDRNOTAVAIL);
}
- TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_free(&ia->ia_ifa); /* if_addrhead */
IN_IFADDR_WLOCK();
- TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
+ CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link);
LIST_REMOVE(ia, ia_hash);
IN_IFADDR_WUNLOCK();
@@ -636,12 +636,10 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
struct in_ifinfo *ii;
ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
- IN_MULTI_LOCK();
if (ii->ii_allhosts) {
- (void)in_leavegroup_locked(ii->ii_allhosts, NULL);
+ (void)in_leavegroup(ii->ii_allhosts, NULL);
ii->ii_allhosts = NULL;
}
- IN_MULTI_UNLOCK();
}
IF_ADDR_WLOCK(ifp);
@@ -682,7 +680,7 @@ in_addprefix(struct in_ifaddr *target, int flags)
IN_IFADDR_RLOCK(&in_ifa_tracker);
/* Look for an existing address with the same prefix, mask, and fib */
- TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
if (rtinitflags(ia)) {
p = ia->ia_dstaddr.sin_addr;
@@ -842,7 +840,7 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
}
IN_IFADDR_RLOCK(&in_ifa_tracker);
- TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+ CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
if (rtinitflags(ia)) {
p = ia->ia_dstaddr.sin_addr;
@@ -918,10 +916,10 @@ in_ifscrub_all(void)
struct ifaliasreq ifr;
IFNET_RLOCK();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
/* Cannot lock here - lock recursion. */
/* IF_ADDR_RLOCK(ifp); */
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
+ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
@@ -982,7 +980,7 @@ in_broadcast(struct in_addr in, struct ifnet *ifp)
* with a broadcast address.
*/
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_INET &&
in_ifaddr_broadcast(in, (struct in_ifaddr *)ifa)) {
found = 1;
@@ -998,11 +996,12 @@ in_broadcast(struct in_addr in, struct ifnet *ifp)
void
in_ifdetach(struct ifnet *ifp)
{
-
+ IN_MULTI_LOCK();
in_pcbpurgeif0(&V_ripcbinfo, ifp);
in_pcbpurgeif0(&V_udbinfo, ifp);
in_pcbpurgeif0(&V_ulitecbinfo, ifp);
in_purgemaddrs(ifp);
+ IN_MULTI_UNLOCK();
}
/*
@@ -1015,12 +1014,12 @@ in_ifdetach(struct ifnet *ifp)
static void
in_purgemaddrs(struct ifnet *ifp)
{
- LIST_HEAD(,in_multi) purgeinms;
- struct in_multi *inm, *tinm;
- struct ifmultiaddr *ifma;
+ struct in_multi_head purgeinms;
+ struct in_multi *inm;
+ struct ifmultiaddr *ifma, *next;
- LIST_INIT(&purgeinms);
- IN_MULTI_LOCK();
+ SLIST_INIT(&purgeinms);
+ IN_MULTI_LIST_LOCK();
/*
* Extract list of in_multi associated with the detaching ifp
@@ -1028,27 +1027,24 @@ in_purgemaddrs(struct ifnet *ifp)
* We need to do this as IF_ADDR_LOCK() may be re-acquired
* by code further down.
*/
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ IF_ADDR_WLOCK(ifp);
+ restart:
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) {
if (ifma->ifma_addr->sa_family != AF_INET ||
ifma->ifma_protospec == NULL)
continue;
-#if 0
- KASSERT(ifma->ifma_protospec != NULL,
- ("%s: ifma_protospec is NULL", __func__));
-#endif
inm = (struct in_multi *)ifma->ifma_protospec;
- LIST_INSERT_HEAD(&purgeinms, inm, inm_link);
+ inm_rele_locked(&purgeinms, inm);
+ if (__predict_false(ifma_restart)) {
+ ifma_restart = true;
+ goto restart;
+ }
}
- IF_ADDR_RUNLOCK(ifp);
+ IF_ADDR_WUNLOCK(ifp);
- LIST_FOREACH_SAFE(inm, &purgeinms, inm_link, tinm) {
- LIST_REMOVE(inm, inm_link);
- inm_release_locked(inm);
- }
+ inm_release_list_deferred(&purgeinms);
igmp_ifdetach(ifp);
-
- IN_MULTI_UNLOCK();
+ IN_MULTI_LIST_UNLOCK();
}
struct in_llentry {
@@ -1063,9 +1059,11 @@ struct in_llentry {
* Do actual deallocation of @lle.
*/
static void
-in_lltable_destroy_lle_unlocked(struct llentry *lle)
+in_lltable_destroy_lle_unlocked(epoch_context_t ctx)
{
+ struct llentry *lle;
+ lle = __containerof(ctx, struct llentry, lle_epoch_ctx);
LLE_LOCK_DESTROY(lle);
LLE_REQ_DESTROY(lle);
free(lle, M_LLTABLE);
@@ -1093,7 +1091,7 @@ in_lltable_destroy_lle(struct llentry *lle)
{
LLE_WUNLOCK(lle);
- in_lltable_destroy_lle_unlocked(lle);
+ epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked);
}
static struct llentry *
@@ -1160,7 +1158,6 @@ in_lltable_match_prefix(const struct sockaddr *saddr,
static void
in_lltable_free_entry(struct lltable *llt, struct llentry *lle)
{
- struct ifnet *ifp;
size_t pkts_dropped;
LLE_WLOCK_ASSERT(lle);
@@ -1168,8 +1165,7 @@ in_lltable_free_entry(struct lltable *llt, struct llentry *lle)
/* Unlink entry from table if not already */
if ((lle->la_flags & LLE_LINKED) != 0) {
- ifp = llt->llt_ifp;
- IF_AFDATA_WLOCK_ASSERT(ifp);
+ IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
lltable_unlink_entry(llt, lle);
}
@@ -1304,7 +1300,7 @@ in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
hashidx = in_lltable_hash_dst(dst, llt->llt_hsize);
lleh = &llt->lle_head[hashidx];
- LIST_FOREACH(lle, lleh, lle_next) {
+ CK_LIST_FOREACH(lle, lleh, lle_next) {
if (lle->la_flags & LLE_DELETED)
continue;
if (lle->r_l3addr.addr4.s_addr == dst.s_addr)
@@ -1360,7 +1356,7 @@ in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr
linkhdrsize = LLE_MAX_LINKHDR;
if (lltable_calc_llheader(ifp, AF_INET, IF_LLADDR(ifp),
linkhdr, &linkhdrsize, &lladdr_off) != 0) {
- in_lltable_destroy_lle_unlocked(lle);
+ epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked);
return (NULL);
}
lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
@@ -1420,52 +1416,51 @@ in_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
int error;
bzero(&arpc, sizeof(arpc));
- /* skip deleted entries */
- if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
- return (0);
- /* Skip if jailed and not a valid IP of the prison. */
- lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin);
- if (prison_if(wr->td->td_ucred,
- (struct sockaddr *)&arpc.sin) != 0)
- return (0);
- /*
- * produce a msg made of:
- * struct rt_msghdr;
- * struct sockaddr_in; (IPv4)
- * struct sockaddr_dl;
- */
- arpc.rtm.rtm_msglen = sizeof(arpc);
- arpc.rtm.rtm_version = RTM_VERSION;
- arpc.rtm.rtm_type = RTM_GET;
- arpc.rtm.rtm_flags = RTF_UP;
- arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
-
- /* publish */
- if (lle->la_flags & LLE_PUB)
- arpc.rtm.rtm_flags |= RTF_ANNOUNCE;
-
- sdl = &arpc.sdl;
- sdl->sdl_family = AF_LINK;
- sdl->sdl_len = sizeof(*sdl);
- sdl->sdl_index = ifp->if_index;
- sdl->sdl_type = ifp->if_type;
- if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
- sdl->sdl_alen = ifp->if_addrlen;
- bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
- } else {
- sdl->sdl_alen = 0;
- bzero(LLADDR(sdl), ifp->if_addrlen);
- }
+ /* skip deleted entries */
+ if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
+ return (0);
+ /* Skip if jailed and not a valid IP of the prison. */
+ lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin);
+ if (prison_if(wr->td->td_ucred, (struct sockaddr *)&arpc.sin) != 0)
+ return (0);
+ /*
+ * produce a msg made of:
+ * struct rt_msghdr;
+ * struct sockaddr_in; (IPv4)
+ * struct sockaddr_dl;
+ */
+ arpc.rtm.rtm_msglen = sizeof(arpc);
+ arpc.rtm.rtm_version = RTM_VERSION;
+ arpc.rtm.rtm_type = RTM_GET;
+ arpc.rtm.rtm_flags = RTF_UP;
+ arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
+
+ /* publish */
+ if (lle->la_flags & LLE_PUB)
+ arpc.rtm.rtm_flags |= RTF_ANNOUNCE;
+
+ sdl = &arpc.sdl;
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_len = sizeof(*sdl);
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = ifp->if_type;
+ if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
+ sdl->sdl_alen = ifp->if_addrlen;
+ bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ } else {
+ sdl->sdl_alen = 0;
+ bzero(LLADDR(sdl), ifp->if_addrlen);
+ }
- arpc.rtm.rtm_rmx.rmx_expire =
- lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
- arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
- if (lle->la_flags & LLE_STATIC)
- arpc.rtm.rtm_flags |= RTF_STATIC;
- if (lle->la_flags & LLE_IFADDR)
- arpc.rtm.rtm_flags |= RTF_PINNED;
- arpc.rtm.rtm_index = ifp->if_index;
- error = SYSCTL_OUT(wr, &arpc, sizeof(arpc));
+ arpc.rtm.rtm_rmx.rmx_expire =
+ lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
+ arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA);
+ if (lle->la_flags & LLE_STATIC)
+ arpc.rtm.rtm_flags |= RTF_STATIC;
+ if (lle->la_flags & LLE_IFADDR)
+ arpc.rtm.rtm_flags |= RTF_PINNED;
+ arpc.rtm.rtm_index = ifp->if_index;
+ error = SYSCTL_OUT(wr, &arpc, sizeof(arpc));
return (error);
}