summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net/if.c')
-rw-r--r--freebsd/sys/net/if.c755
1 files changed, 470 insertions, 285 deletions
diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c
index bbf2ddd0..d4c18b46 100644
--- a/freebsd/sys/net/if.c
+++ b/freebsd/sys/net/if.c
@@ -34,7 +34,6 @@
* $FreeBSD$
*/
-#include <rtems/bsd/local/opt_compat.h>
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_inet.h>
@@ -44,6 +43,7 @@
#include <sys/malloc.h>
#include <sys/sbuf.h>
#include <sys/bus.h>
+#include <sys/epoch.h>
#include <sys/mbuf.h>
#include <sys/systm.h>
#include <sys/priv.h>
@@ -90,6 +90,7 @@
#include <netinet/ip_carp.h>
#ifdef INET
#include <netinet/if_ether.h>
+#include <netinet/netdump/netdump.h>
#endif /* INET */
#ifdef INET6
#include <netinet6/in6_var.h>
@@ -106,6 +107,13 @@
_Static_assert(sizeof(((struct ifreq *)0)->ifr_name) ==
offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru");
+#ifndef __rtems__
+__read_mostly epoch_t net_epoch_preempt;
+__read_mostly epoch_t net_epoch;
+#else /* __rtems__ */
+EPOCH_DEFINE(_bsd_net_epoch_preempt, EPOCH_PREEMPT);
+EPOCH_DEFINE(_bsd_net_epoch, 0);
+#endif /* __rtems__ */
#ifdef COMPAT_FREEBSD32
#include <sys/mount.h>
#include <compat/freebsd32/freebsd32.h>
@@ -144,7 +152,37 @@ struct ifreq32 {
CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32));
CTASSERT(__offsetof(struct ifreq, ifr_ifru) ==
__offsetof(struct ifreq32, ifr_ifru));
-#endif
+
+struct ifgroupreq32 {
+ char ifgr_name[IFNAMSIZ];
+ u_int ifgr_len;
+ union {
+ char ifgru_group[IFNAMSIZ];
+ uint32_t ifgru_groups;
+ } ifgr_ifgru;
+};
+
+struct ifmediareq32 {
+ char ifm_name[IFNAMSIZ];
+ int ifm_current;
+ int ifm_mask;
+ int ifm_status;
+ int ifm_active;
+ int ifm_count;
+ uint32_t ifm_ulist; /* (int *) */
+};
+#define SIOCGIFMEDIA32 _IOC_NEWTYPE(SIOCGIFMEDIA, struct ifmediareq32)
+#define SIOCGIFXMEDIA32 _IOC_NEWTYPE(SIOCGIFXMEDIA, struct ifmediareq32)
+
+#define _CASE_IOC_IFGROUPREQ_32(cmd) \
+ case _IOC_NEWTYPE((cmd), struct ifgroupreq32):
+#else /* !COMPAT_FREEBSD32 */
+#define _CASE_IOC_IFGROUPREQ_32(cmd)
+#endif /* !COMPAT_FREEBSD32 */
+
+#define CASE_IOC_IFGROUPREQ(cmd) \
+ _CASE_IOC_IFGROUPREQ_32(cmd) \
+ case (cmd)
union ifreq_union {
struct ifreq ifr;
@@ -153,6 +191,13 @@ union ifreq_union {
#endif
};
+union ifgroupreq_union {
+ struct ifgroupreq ifgr;
+#ifdef COMPAT_FREEBSD32
+ struct ifgroupreq32 ifgr32;
+#endif
+};
+
SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
@@ -185,7 +230,6 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions");
static struct sx ifdescr_sx;
SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
-void (*bridge_linkstate_p)(struct ifnet *ifp);
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
/* These are external hooks for CARP. */
@@ -219,8 +263,7 @@ struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
static void if_attachdomain(void *);
static void if_attachdomain1(struct ifnet *);
static int ifconf(u_long, caddr_t);
-static void if_freemulti(struct ifmultiaddr *);
-static void if_grow(void);
+static void *if_grow(void);
static void if_input_default(struct ifnet *, struct mbuf *);
static int if_requestencap_default(struct ifnet *, struct if_encap_req *);
static void if_route(struct ifnet *, int flag, int fam);
@@ -309,9 +352,7 @@ ifnet_byindex(u_short idx)
{
struct ifnet *ifp;
- IFNET_RLOCK_NOSLEEP();
ifp = ifnet_byindex_locked(idx);
- IFNET_RUNLOCK_NOSLEEP();
return (ifp);
}
@@ -336,12 +377,11 @@ ifnet_byindex_ref(u_short idx)
* failure.
*/
static u_short
-ifindex_alloc(void)
+ifindex_alloc(void **old)
{
u_short idx;
IFNET_WLOCK_ASSERT();
-retry:
/*
* Try to find an empty slot below V_if_index. If we fail, take the
* next slot.
@@ -353,8 +393,8 @@ retry:
/* Catch if_index overflow. */
if (idx >= V_if_indexlim) {
- if_grow();
- goto retry;
+ *old = if_grow();
+ return (USHRT_MAX);
}
if (idx > V_if_index)
V_if_index = idx;
@@ -383,21 +423,10 @@ ifindex_free(u_short idx)
}
static void
-ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp)
-{
-
- IFNET_WLOCK_ASSERT();
-
- V_ifindex_table[idx] = ifp;
-}
-
-static void
ifnet_setbyindex(u_short idx, struct ifnet *ifp)
{
- IFNET_WLOCK();
- ifnet_setbyindex_locked(idx, ifp);
- IFNET_WUNLOCK();
+ V_ifindex_table[idx] = ifp;
}
struct ifaddr *
@@ -424,12 +453,15 @@ ifaddr_byindex(u_short idx)
static void
vnet_if_init(const void *unused __unused)
{
+ void *old;
- TAILQ_INIT(&V_ifnet);
- TAILQ_INIT(&V_ifg_head);
+ CK_STAILQ_INIT(&V_ifnet);
+ CK_STAILQ_INIT(&V_ifg_head);
IFNET_WLOCK();
- if_grow(); /* create initial table */
+ old = if_grow(); /* create initial table */
IFNET_WUNLOCK();
+ epoch_wait_preempt(net_epoch_preempt);
+ free(old, M_IFNET);
vnet_if_clone_init();
}
VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init,
@@ -440,9 +472,9 @@ static void
vnet_if_uninit(const void *unused __unused)
{
- VNET_ASSERT(TAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p "
+ VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p "
"not empty", __func__, __LINE__, &V_ifnet));
- VNET_ASSERT(TAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p "
+ VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p "
"not empty", __func__, __LINE__, &V_ifg_head));
free((caddr_t)V_ifindex_table, M_IFNET);
@@ -456,7 +488,7 @@ vnet_if_return(const void *unused __unused)
struct ifnet *ifp, *nifp;
/* Return all inherited interfaces to their parent vnets. */
- TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
+ CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
if (ifp->if_home_vnet != ifp->if_vnet)
if_vmove(ifp, ifp->if_home_vnet);
}
@@ -465,13 +497,16 @@ VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY,
vnet_if_return, NULL);
#endif
-static void
+
+static void *
if_grow(void)
{
int oldlim;
u_int n;
struct ifnet **e;
+ void *old;
+ old = NULL;
IFNET_WLOCK_ASSERT();
oldlim = V_if_indexlim;
IFNET_WUNLOCK();
@@ -480,14 +515,15 @@ if_grow(void)
IFNET_WLOCK();
if (V_if_indexlim != oldlim) {
free(e, M_IFNET);
- return;
+ return (NULL);
}
if (V_ifindex_table != NULL) {
memcpy((caddr_t)e, (caddr_t)V_ifindex_table, n/2);
- free((caddr_t)V_ifindex_table, M_IFNET);
+ old = V_ifindex_table;
}
V_if_indexlim <<= 1;
V_ifindex_table = e;
+ return (old);
}
/*
@@ -500,11 +536,19 @@ if_alloc(u_char type)
{
struct ifnet *ifp;
u_short idx;
+ void *old;
ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO);
+ restart:
IFNET_WLOCK();
- idx = ifindex_alloc();
- ifnet_setbyindex_locked(idx, IFNET_HOLD);
+ idx = ifindex_alloc(&old);
+ if (__predict_false(idx == USHRT_MAX)) {
+ IFNET_WUNLOCK();
+ epoch_wait_preempt(net_epoch_preempt);
+ free(old, M_IFNET);
+ goto restart;
+ }
+ ifnet_setbyindex(idx, IFNET_HOLD);
IFNET_WUNLOCK();
ifp->if_index = idx;
ifp->if_type = type;
@@ -525,9 +569,9 @@ if_alloc(u_char type)
TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp);
ifp->if_afdata_initialized = 0;
IF_AFDATA_LOCK_INIT(ifp);
- TAILQ_INIT(&ifp->if_addrhead);
- TAILQ_INIT(&ifp->if_multiaddrs);
- TAILQ_INIT(&ifp->if_groups);
+ CK_STAILQ_INIT(&ifp->if_addrhead);
+ CK_STAILQ_INIT(&ifp->if_multiaddrs);
+ CK_STAILQ_INIT(&ifp->if_groups);
#ifdef MAC
mac_ifnet_init(ifp);
#endif
@@ -573,6 +617,15 @@ if_free_internal(struct ifnet *ifp)
free(ifp, M_IFNET);
}
+static void
+if_destroy(epoch_context_t ctx)
+{
+ struct ifnet *ifp;
+
+ ifp = __containerof(ctx, struct ifnet, if_epoch_ctx);
+ if_free_internal(ifp);
+}
+
/*
* Deregister an interface and free the associated storage.
*/
@@ -591,7 +644,7 @@ if_free(struct ifnet *ifp)
IFNET_WUNLOCK();
if (refcount_release(&ifp->if_refcount))
- if_free_internal(ifp);
+ epoch_call(net_epoch_preempt, &ifp->if_epoch_ctx, if_destroy);
CURVNET_RESTORE();
}
@@ -614,7 +667,7 @@ if_rele(struct ifnet *ifp)
if (!refcount_release(&ifp->if_refcount))
return;
- if_free_internal(ifp);
+ epoch_call(net_epoch_preempt, &ifp->if_epoch_ctx, if_destroy);
}
void
@@ -795,7 +848,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
sdl->sdl_len = masklen;
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
- TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
+ CK_STAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
/* Reliably crash if used uninitialized. */
ifp->if_broadcastaddr = NULL;
@@ -837,7 +890,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
* of the interface.
*/
for (ifa = ifp->if_addr; ifa != NULL;
- ifa = TAILQ_NEXT(ifa, ifa_link)) {
+ ifa = CK_STAILQ_NEXT(ifa, ifa_link)) {
if (ifa->ifa_addr->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
sdl->sdl_index = ifp->if_index;
@@ -847,7 +900,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
#endif
IFNET_WLOCK();
- TAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
+ CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
#ifdef VIMAGE
curvnet->vnet_ifcnt++;
#endif
@@ -864,12 +917,24 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
}
+#ifndef __rtems__
+static void
+if_epochalloc(void *dummy __unused)
+{
+
+ net_epoch_preempt = epoch_alloc(EPOCH_PREEMPT);
+ net_epoch = epoch_alloc(0);
+}
+SYSINIT(ifepochalloc, SI_SUB_TASKQ + 1, SI_ORDER_ANY,
+ if_epochalloc, NULL);
+#endif /* __rtems__ */
+
static void
if_attachdomain(void *dummy)
{
struct ifnet *ifp;
- TAILQ_FOREACH(ifp, &V_ifnet, if_link)
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link)
if_attachdomain1(ifp);
}
SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
@@ -911,8 +976,8 @@ if_purgeaddrs(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
- /* XXX cannot hold IF_ADDR_WLOCK over called functions. */
- TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
+ NET_EPOCH_ENTER();
+ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) {
if (ifa->ifa_addr->sa_family == AF_LINK)
continue;
#ifdef INET
@@ -937,10 +1002,11 @@ if_purgeaddrs(struct ifnet *ifp)
}
#endif /* INET6 */
IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+ CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_free(ifa);
}
+ NET_EPOCH_EXIT();
}
/*
@@ -951,11 +1017,13 @@ static void
if_purgemaddrs(struct ifnet *ifp)
{
struct ifmultiaddr *ifma;
- struct ifmultiaddr *next;
IF_ADDR_WLOCK(ifp);
- TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
+ while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) {
+ ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs);
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
if_delmulti_locked(ifp, ifma, 1);
+ }
IF_ADDR_WUNLOCK(ifp);
}
@@ -1002,9 +1070,9 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0;
#endif
IFNET_WLOCK();
- TAILQ_FOREACH(iter, &V_ifnet, if_link)
+ CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
if (iter == ifp) {
- TAILQ_REMOVE(&V_ifnet, ifp, if_link);
+ CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
found = 1;
break;
}
@@ -1032,7 +1100,7 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
#ifdef VIMAGE
curvnet->vnet_ifcnt--;
#endif
-
+ epoch_wait_preempt(net_epoch_preempt);
/*
* In any case (destroy or vmove) detach us from the groups
* and remove/wait for pending events on the taskq.
@@ -1125,9 +1193,9 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
/* We can now free link ifaddr. */
IF_ADDR_WLOCK(ifp);
- if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
- ifa = TAILQ_FIRST(&ifp->if_addrhead);
- TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+ if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) {
+ ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
+ CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
IF_ADDR_WUNLOCK(ifp);
ifa_free(ifa);
} else
@@ -1172,6 +1240,7 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
{
struct if_clone *ifc;
u_int bif_dlt, bif_hdrlen;
+ void *old;
int rc;
/*
@@ -1212,10 +1281,16 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
* Switch to the context of the target vnet.
*/
CURVNET_SET_QUIET(new_vnet);
-
+ restart:
IFNET_WLOCK();
- ifp->if_index = ifindex_alloc();
- ifnet_setbyindex_locked(ifp->if_index, ifp);
+ ifp->if_index = ifindex_alloc(&old);
+ if (__predict_false(ifp->if_index == USHRT_MAX)) {
+ IFNET_WUNLOCK();
+ epoch_wait_preempt(net_epoch_preempt);
+ free(old, M_IFNET);
+ goto restart;
+ }
+ ifnet_setbyindex(ifp->if_index, ifp);
IFNET_WUNLOCK();
if_attach_internal(ifp, 1, ifc);
@@ -1352,7 +1427,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
return (EINVAL);
IFNET_WLOCK();
- TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) {
IFNET_WUNLOCK();
return (EEXIST);
@@ -1371,7 +1446,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
return (ENOMEM);
}
- TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
+ CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
if (!strcmp(ifg->ifg_group, groupname))
break;
@@ -1385,8 +1460,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
}
strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
ifg->ifg_refcnt = 0;
- TAILQ_INIT(&ifg->ifg_members);
- TAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next);
+ CK_STAILQ_INIT(&ifg->ifg_members);
+ CK_STAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next);
new = 1;
}
@@ -1395,8 +1470,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname)
ifgm->ifgm_ifp = ifp;
IF_ADDR_WLOCK(ifp);
- TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
- TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
+ CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
+ CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
IF_ADDR_WUNLOCK(ifp);
IFNET_WUNLOCK();
@@ -1416,9 +1491,10 @@ if_delgroup(struct ifnet *ifp, const char *groupname)
{
struct ifg_list *ifgl;
struct ifg_member *ifgm;
+ int freeifgl;
IFNET_WLOCK();
- TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
break;
if (ifgl == NULL) {
@@ -1426,27 +1502,30 @@ if_delgroup(struct ifnet *ifp, const char *groupname)
return (ENOENT);
}
+ freeifgl = 0;
IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
+ CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next);
IF_ADDR_WUNLOCK(ifp);
- TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
+ CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
if (ifgm->ifgm_ifp == ifp)
break;
- if (ifgm != NULL) {
- TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next);
- free(ifgm, M_TEMP);
- }
+ if (ifgm != NULL)
+ CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifg_member, ifgm_next);
if (--ifgl->ifgl_group->ifg_refcnt == 0) {
- TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next);
- IFNET_WUNLOCK();
+ CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next);
+ freeifgl = 1;
+ }
+ IFNET_WUNLOCK();
+
+ epoch_wait_preempt(net_epoch_preempt);
+ if (freeifgl) {
EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group);
free(ifgl->ifgl_group, M_TEMP);
- } else
- IFNET_WUNLOCK();
-
+ }
+ free(ifgm, M_TEMP);
free(ifgl, M_TEMP);
EVENTHANDLER_INVOKE(group_change_event, groupname);
@@ -1463,38 +1542,39 @@ if_delgroups(struct ifnet *ifp)
struct ifg_list *ifgl;
struct ifg_member *ifgm;
char groupname[IFNAMSIZ];
+ int ifglfree;
IFNET_WLOCK();
- while (!TAILQ_EMPTY(&ifp->if_groups)) {
- ifgl = TAILQ_FIRST(&ifp->if_groups);
+ while (!CK_STAILQ_EMPTY(&ifp->if_groups)) {
+ ifgl = CK_STAILQ_FIRST(&ifp->if_groups);
strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ);
IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
+ CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next);
IF_ADDR_WUNLOCK(ifp);
- TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
+ CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
if (ifgm->ifgm_ifp == ifp)
break;
- if (ifgm != NULL) {
- TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm,
+ if (ifgm != NULL)
+ CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifg_member,
ifgm_next);
- free(ifgm, M_TEMP);
+ ifglfree = 0;
+ if (--ifgl->ifgl_group->ifg_refcnt == 0) {
+ CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next);
+ ifglfree = 1;
}
- if (--ifgl->ifgl_group->ifg_refcnt == 0) {
- TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next);
- IFNET_WUNLOCK();
+ IFNET_WUNLOCK();
+ epoch_wait_preempt(net_epoch_preempt);
+ free(ifgm, M_TEMP);
+ if (ifglfree) {
EVENTHANDLER_INVOKE(group_detach_event,
- ifgl->ifgl_group);
+ ifgl->ifgl_group);
free(ifgl->ifgl_group, M_TEMP);
- } else
- IFNET_WUNLOCK();
-
- free(ifgl, M_TEMP);
-
+ }
EVENTHANDLER_INVOKE(group_change_event, groupname);
IFNET_WLOCK();
@@ -1502,31 +1582,56 @@ if_delgroups(struct ifnet *ifp)
IFNET_WUNLOCK();
}
+static char *
+ifgr_group_get(void *ifgrp)
+{
+ union ifgroupreq_union *ifgrup;
+
+ ifgrup = ifgrp;
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32))
+ return (&ifgrup->ifgr32.ifgr_ifgru.ifgru_group[0]);
+#endif
+ return (&ifgrup->ifgr.ifgr_ifgru.ifgru_group[0]);
+}
+
+static struct ifg_req *
+ifgr_groups_get(void *ifgrp)
+{
+ union ifgroupreq_union *ifgrup;
+
+ ifgrup = ifgrp;
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32))
+ return ((struct ifg_req *)(uintptr_t)
+ ifgrup->ifgr32.ifgr_ifgru.ifgru_groups);
+#endif
+ return (ifgrup->ifgr.ifgr_ifgru.ifgru_groups);
+}
+
/*
- * Stores all groups from an interface in memory pointed
- * to by data
+ * Stores all groups from an interface in memory pointed to by ifgr.
*/
static int
-if_getgroup(struct ifgroupreq *data, struct ifnet *ifp)
+if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp)
{
int len, error;
struct ifg_list *ifgl;
struct ifg_req ifgrq, *ifgp;
- struct ifgroupreq *ifgr = data;
if (ifgr->ifgr_len == 0) {
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
ifgr->ifgr_len += sizeof(struct ifg_req);
IF_ADDR_RUNLOCK(ifp);
return (0);
}
len = ifgr->ifgr_len;
- ifgp = ifgr->ifgr_groups;
+ ifgp = ifgr_groups_get(ifgr);
/* XXX: wire */
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+ CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
if (len < sizeof(ifgrq)) {
IF_ADDR_RUNLOCK(ifp);
return (EINVAL);
@@ -1547,19 +1652,18 @@ if_getgroup(struct ifgroupreq *data, struct ifnet *ifp)
}
/*
- * Stores all members of a group in memory pointed to by data
+ * Stores all members of a group in memory pointed to by igfr
*/
static int
-if_getgroupmembers(struct ifgroupreq *data)
+if_getgroupmembers(struct ifgroupreq *ifgr)
{
- struct ifgroupreq *ifgr = data;
struct ifg_group *ifg;
struct ifg_member *ifgm;
struct ifg_req ifgrq, *ifgp;
int len, error;
IFNET_RLOCK();
- TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
+ CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
break;
if (ifg == NULL) {
@@ -1568,15 +1672,15 @@ if_getgroupmembers(struct ifgroupreq *data)
}
if (ifgr->ifgr_len == 0) {
- TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
+ CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
ifgr->ifgr_len += sizeof(ifgrq);
IFNET_RUNLOCK();
return (0);
}
len = ifgr->ifgr_len;
- ifgp = ifgr->ifgr_groups;
- TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
+ ifgp = ifgr_groups_get(ifgr);
+ CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
if (len < sizeof(ifgrq)) {
IFNET_RUNLOCK();
return (EINVAL);
@@ -1736,19 +1840,28 @@ ifa_ref(struct ifaddr *ifa)
refcount_acquire(&ifa->ifa_refcnt);
}
+static void
+ifa_destroy(epoch_context_t ctx)
+{
+ struct ifaddr *ifa;
+
+ ifa = __containerof(ctx, struct ifaddr, ifa_epoch_ctx);
+ counter_u64_free(ifa->ifa_opackets);
+ counter_u64_free(ifa->ifa_ipackets);
+ counter_u64_free(ifa->ifa_obytes);
+ counter_u64_free(ifa->ifa_ibytes);
+ free(ifa, M_IFADDR);
+}
+
void
ifa_free(struct ifaddr *ifa)
{
- if (refcount_release(&ifa->ifa_refcnt)) {
- counter_u64_free(ifa->ifa_opackets);
- counter_u64_free(ifa->ifa_ipackets);
- counter_u64_free(ifa->ifa_obytes);
- counter_u64_free(ifa->ifa_ibytes);
- free(ifa, M_IFADDR);
- }
+ if (refcount_release(&ifa->ifa_refcnt))
+ epoch_call(net_epoch_preempt, &ifa->ifa_epoch_ctx, ifa_destroy);
}
+
static int
ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa,
struct sockaddr *ia)
@@ -1770,9 +1883,10 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa,
error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib);
- if (error != 0)
- log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n",
- __func__, otype, if_name(ifp), error);
+ if (error != 0 &&
+ !(cmd == RTM_ADD && error == EEXIST) &&
+ !(cmd == RTM_DELETE && error == ENOENT))
+ if_printf(ifp, "%s failed: %d\n", otype, error);
return (error);
}
@@ -1815,22 +1929,18 @@ ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
* Locate an interface based on a complete address.
*/
/*ARGSUSED*/
-static struct ifaddr *
-ifa_ifwithaddr_internal(const struct sockaddr *addr, int getref)
+struct ifaddr *
+ifa_ifwithaddr(const struct sockaddr *addr)
{
struct ifnet *ifp;
struct ifaddr *ifa;
- IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ MPASS(in_epoch());
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
continue;
if (sa_equal(addr, ifa->ifa_addr)) {
- if (getref)
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
goto done;
}
/* IP6 doesn't have broadcast */
@@ -1838,32 +1948,24 @@ ifa_ifwithaddr_internal(const struct sockaddr *addr, int getref)
ifa->ifa_broadaddr &&
ifa->ifa_broadaddr->sa_len != 0 &&
sa_equal(ifa->ifa_broadaddr, addr)) {
- if (getref)
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
goto done;
}
}
- IF_ADDR_RUNLOCK(ifp);
}
ifa = NULL;
done:
- IFNET_RUNLOCK_NOSLEEP();
return (ifa);
}
-struct ifaddr *
-ifa_ifwithaddr(const struct sockaddr *addr)
-{
-
- return (ifa_ifwithaddr_internal(addr, 1));
-}
-
int
ifa_ifwithaddr_check(const struct sockaddr *addr)
{
+ int rc;
- return (ifa_ifwithaddr_internal(addr, 0) != NULL);
+ NET_EPOCH_ENTER();
+ rc = (ifa_ifwithaddr(addr) != NULL);
+ NET_EPOCH_EXIT();
+ return (rc);
}
/*
@@ -1876,28 +1978,23 @@ ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum)
struct ifnet *ifp;
struct ifaddr *ifa;
- IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ MPASS(in_epoch());
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
continue;
- 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 != addr->sa_family)
continue;
if ((ifp->if_flags & IFF_BROADCAST) &&
ifa->ifa_broadaddr &&
ifa->ifa_broadaddr->sa_len != 0 &&
sa_equal(ifa->ifa_broadaddr, addr)) {
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
goto done;
}
}
- IF_ADDR_RUNLOCK(ifp);
}
ifa = NULL;
done:
- IFNET_RUNLOCK_NOSLEEP();
return (ifa);
}
@@ -1911,28 +2008,23 @@ ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum)
struct ifnet *ifp;
struct ifaddr *ifa;
- IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ MPASS(in_epoch());
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
continue;
if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
continue;
- 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 != addr->sa_family)
continue;
if (ifa->ifa_dstaddr != NULL &&
sa_equal(addr, ifa->ifa_dstaddr)) {
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
goto done;
}
}
- IF_ADDR_RUNLOCK(ifp);
}
ifa = NULL;
done:
- IFNET_RUNLOCK_NOSLEEP();
return (ifa);
}
@@ -1949,6 +2041,7 @@ ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum)
u_int af = addr->sa_family;
const char *addr_data = addr->sa_data, *cplim;
+ MPASS(in_epoch());
/*
* AF_LINK addresses can be looked up directly by their index number,
* so do that if we can.
@@ -1965,12 +2058,10 @@ ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum)
* on ifa_maybe once we find one, as we release the IF_ADDR_RLOCK() that
* kept it stable when we move onto the next interface.
*/
- IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
continue;
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
const char *cp, *cp2, *cp3;
if (ifa->ifa_addr->sa_family != af)
@@ -1987,7 +2078,6 @@ next: continue;
*/
if (ifa->ifa_dstaddr != NULL &&
sa_equal(addr, ifa->ifa_dstaddr)) {
- ifa_ref(ifa);
IF_ADDR_RUNLOCK(ifp);
goto done;
}
@@ -2021,21 +2111,14 @@ next: continue;
ifa_preferred(ifa_maybe, ifa) ||
rn_refines((caddr_t)ifa->ifa_netmask,
(caddr_t)ifa_maybe->ifa_netmask)) {
- if (ifa_maybe != NULL)
- ifa_free(ifa_maybe);
ifa_maybe = ifa;
- ifa_ref(ifa_maybe);
}
}
}
- IF_ADDR_RUNLOCK(ifp);
}
ifa = ifa_maybe;
ifa_maybe = NULL;
done:
- IFNET_RUNLOCK_NOSLEEP();
- if (ifa_maybe != NULL)
- ifa_free(ifa_maybe);
return (ifa);
}
@@ -2054,8 +2137,8 @@ ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
if (af >= AF_MAX)
return (NULL);
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ MPASS(in_epoch());
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != af)
continue;
if (ifa_maybe == NULL)
@@ -2084,9 +2167,6 @@ ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
}
ifa = ifa_maybe;
done:
- if (ifa != NULL)
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
return (ifa);
}
@@ -2122,14 +2202,19 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == NULL) ||
((ifp = ifa->ifa_ifp) == NULL) || ((dst = rt_key(rt)) == NULL))
return;
+ NET_EPOCH_ENTER();
ifa = ifaof_ifpforaddr(dst, ifp);
if (ifa) {
oifa = rt->rt_ifa;
+ if (oifa != ifa) {
+ ifa_free(oifa);
+ ifa_ref(ifa);
+ }
rt->rt_ifa = ifa;
- ifa_free(oifa);
if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
ifa->ifa_rtrequest(cmd, rt, info);
}
+ NET_EPOCH_EXIT();
}
struct sockaddr_dl *
@@ -2177,7 +2262,7 @@ if_unroute(struct ifnet *ifp, int flag, int fam)
ifp->if_flags &= ~flag;
getmicrotime(&ifp->if_lastchange);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
ifp->if_qflush(ifp);
@@ -2200,7 +2285,7 @@ if_route(struct ifnet *ifp, int flag, int fam)
ifp->if_flags |= flag;
getmicrotime(&ifp->if_lastchange);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
pfctlinput(PRC_IFUP, ifa->ifa_addr);
if (ifp->if_carp)
@@ -2255,7 +2340,7 @@ do_link_state_change(void *arg, int pending)
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
if (ifp->if_bridge)
- (*bridge_linkstate_p)(ifp);
+ ifp->if_bridge_linkstate(ifp);
if (ifp->if_lagg)
(*lagg_linkstate_p)(ifp, link_state);
@@ -2266,7 +2351,7 @@ do_link_state_change(void *arg, int pending)
if (pending > 1)
if_printf(ifp, "%d link states coalesced\n", pending);
if (log_link_state_change)
- log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname,
+ if_printf(ifp, "link state changed to %s\n",
(link_state == LINK_STATE_UP) ? "UP" : "DOWN" );
EVENTHANDLER_INVOKE(ifnet_link_event, ifp, link_state);
CURVNET_RESTORE();
@@ -2332,7 +2417,7 @@ ifunit_ref(const char *name)
struct ifnet *ifp;
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 &&
!(ifp->if_flags & IFF_DYING))
break;
@@ -2349,7 +2434,7 @@ ifunit(const char *name)
struct ifnet *ifp;
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
break;
}
@@ -2358,13 +2443,13 @@ ifunit(const char *name)
}
static void *
-ifr_buffer_get_buffer(struct thread *td, void *data)
+ifr_buffer_get_buffer(void *data)
{
union ifreq_union *ifrup;
ifrup = data;
#ifdef COMPAT_FREEBSD32
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32))
+ if (SV_CURPROC_FLAG(SV_ILP32))
return ((void *)(uintptr_t)
ifrup->ifr32.ifr_ifru.ifru_buffer.buffer);
#endif
@@ -2372,13 +2457,13 @@ ifr_buffer_get_buffer(struct thread *td, void *data)
}
static void
-ifr_buffer_set_buffer_null(struct thread *td, void *data)
+ifr_buffer_set_buffer_null(void *data)
{
union ifreq_union *ifrup;
ifrup = data;
#ifdef COMPAT_FREEBSD32
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32))
+ if (SV_CURPROC_FLAG(SV_ILP32))
ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0;
else
#endif
@@ -2386,26 +2471,26 @@ ifr_buffer_set_buffer_null(struct thread *td, void *data)
}
static size_t
-ifr_buffer_get_length(struct thread *td, void *data)
+ifr_buffer_get_length(void *data)
{
union ifreq_union *ifrup;
ifrup = data;
#ifdef COMPAT_FREEBSD32
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32))
+ if (SV_CURPROC_FLAG(SV_ILP32))
return (ifrup->ifr32.ifr_ifru.ifru_buffer.length);
#endif
return (ifrup->ifr.ifr_ifru.ifru_buffer.length);
}
static void
-ifr_buffer_set_length(struct thread *td, void *data, size_t len)
+ifr_buffer_set_length(void *data, size_t len)
{
union ifreq_union *ifrup;
ifrup = data;
#ifdef COMPAT_FREEBSD32
- if (SV_PROC_FLAG(td->td_proc, SV_ILP32))
+ if (SV_CURPROC_FLAG(SV_ILP32))
ifrup->ifr32.ifr_ifru.ifru_buffer.length = len;
else
#endif
@@ -2486,12 +2571,12 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
else {
/* space for terminating nul */
descrlen = strlen(ifp->if_description) + 1;
- if (ifr_buffer_get_length(td, ifr) < descrlen)
- ifr_buffer_set_buffer_null(td, ifr);
+ if (ifr_buffer_get_length(ifr) < descrlen)
+ ifr_buffer_set_buffer_null(ifr);
else
error = copyout(ifp->if_description,
- ifr_buffer_get_buffer(td, ifr), descrlen);
- ifr_buffer_set_length(td, ifr, descrlen);
+ ifr_buffer_get_buffer(ifr), descrlen);
+ ifr_buffer_set_length(ifr, descrlen);
}
sx_sunlock(&ifdescr_sx);
break;
@@ -2507,15 +2592,15 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
* length parameter is supposed to count the
* terminating nul in.
*/
- if (ifr_buffer_get_length(td, ifr) > ifdescr_maxlen)
+ if (ifr_buffer_get_length(ifr) > ifdescr_maxlen)
return (ENAMETOOLONG);
- else if (ifr_buffer_get_length(td, ifr) == 0)
+ else if (ifr_buffer_get_length(ifr) == 0)
descrbuf = NULL;
else {
- descrbuf = malloc(ifr_buffer_get_length(td, ifr),
+ descrbuf = malloc(ifr_buffer_get_length(ifr),
M_IFDESCR, M_WAITOK | M_ZERO);
- error = copyin(ifr_buffer_get_buffer(td, ifr), descrbuf,
- ifr_buffer_get_length(td, ifr) - 1);
+ error = copyin(ifr_buffer_get_buffer(ifr), descrbuf,
+ ifr_buffer_get_length(ifr) - 1);
if (error) {
free(descrbuf, M_IFDESCR);
break;
@@ -2569,8 +2654,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
else if (ifp->if_pcount == 0)
ifp->if_flags &= ~IFF_PROMISC;
if (log_promisc_mode_change)
- log(LOG_INFO, "%s: permanently promiscuous mode %s\n",
- ifp->if_xname,
+ if_printf(ifp, "permanently promiscuous mode %s\n",
((new_flags & IFF_PPROMISC) ?
"enabled" : "disabled"));
}
@@ -2633,8 +2717,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
- log(LOG_INFO, "%s: changing name to '%s'\n",
- ifp->if_xname, new_name);
+ if_printf(ifp, "changing name to '%s'\n", new_name);
IF_ADDR_WLOCK(ifp);
strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
@@ -2709,6 +2792,9 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
if (error == 0) {
getmicrotime(&ifp->if_lastchange);
rt_ifmsg(ifp);
+#ifdef INET
+ NETDUMP_REINIT(ifp);
+#endif
}
/*
* If the link MTU changed, do network layer specific procedure.
@@ -2805,34 +2891,28 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
error = if_gethwaddr(ifp, ifr);
break;
- case SIOCAIFGROUP:
- {
- struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr;
-
+ CASE_IOC_IFGROUPREQ(SIOCAIFGROUP):
error = priv_check(td, PRIV_NET_ADDIFGROUP);
if (error)
return (error);
- if ((error = if_addgroup(ifp, ifgr->ifgr_group)))
+ if ((error = if_addgroup(ifp,
+ ifgr_group_get((struct ifgroupreq *)data))))
return (error);
break;
- }
- case SIOCGIFGROUP:
- if ((error = if_getgroup((struct ifgroupreq *)ifr, ifp)))
+ CASE_IOC_IFGROUPREQ(SIOCGIFGROUP):
+ if ((error = if_getgroup((struct ifgroupreq *)data, ifp)))
return (error);
break;
- case SIOCDIFGROUP:
- {
- struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr;
-
+ CASE_IOC_IFGROUPREQ(SIOCDIFGROUP):
error = priv_check(td, PRIV_NET_DELIFGROUP);
if (error)
return (error);
- if ((error = if_delgroup(ifp, ifgr->ifgr_group)))
+ if ((error = if_delgroup(ifp,
+ ifgr_group_get((struct ifgroupreq *)data))))
return (error);
break;
- }
#ifdef __rtems__
case RTEMS_SIOSIFINPUT:
@@ -2868,12 +2948,48 @@ struct ifconf32 {
#define SIOCGIFCONF32 _IOWR('i', 36, struct ifconf32)
#endif
+#ifdef COMPAT_FREEBSD32
+static void
+ifmr_init(struct ifmediareq *ifmr, caddr_t data)
+{
+ struct ifmediareq32 *ifmr32;
+
+ ifmr32 = (struct ifmediareq32 *)data;
+ memcpy(ifmr->ifm_name, ifmr32->ifm_name,
+ sizeof(ifmr->ifm_name));
+ ifmr->ifm_current = ifmr32->ifm_current;
+ ifmr->ifm_mask = ifmr32->ifm_mask;
+ ifmr->ifm_status = ifmr32->ifm_status;
+ ifmr->ifm_active = ifmr32->ifm_active;
+ ifmr->ifm_count = ifmr32->ifm_count;
+ ifmr->ifm_ulist = (int *)(uintptr_t)ifmr32->ifm_ulist;
+}
+
+static void
+ifmr_update(const struct ifmediareq *ifmr, caddr_t data)
+{
+ struct ifmediareq32 *ifmr32;
+
+ ifmr32 = (struct ifmediareq32 *)data;
+ ifmr32->ifm_current = ifmr->ifm_current;
+ ifmr32->ifm_mask = ifmr->ifm_mask;
+ ifmr32->ifm_status = ifmr->ifm_status;
+ ifmr32->ifm_active = ifmr->ifm_active;
+ ifmr32->ifm_count = ifmr->ifm_count;
+}
+#endif
+
/*
* Interface ioctls.
*/
int
ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
{
+#ifdef COMPAT_FREEBSD32
+ caddr_t saved_data = NULL;
+ struct ifmediareq ifmr;
+#endif
+ struct ifmediareq *ifmrp;
struct ifnet *ifp;
struct ifreq *ifr;
int error;
@@ -2918,8 +3034,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
}
#endif
}
- ifr = (struct ifreq *)data;
+ ifmrp = NULL;
+#ifdef COMPAT_FREEBSD32
+ switch (cmd) {
+ case SIOCGIFMEDIA32:
+ case SIOCGIFXMEDIA32:
+ ifmrp = &ifmr;
+ ifmr_init(ifmrp, data);
+ cmd = _IOC_NEWTYPE(cmd, struct ifmediareq);
+ saved_data = data;
+ data = (caddr_t)ifmrp;
+ }
+#endif
+
+ ifr = (struct ifreq *)data;
switch (cmd) {
#ifdef VIMAGE
case SIOCSIFRVNET:
@@ -2927,8 +3056,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
if (error == 0)
error = if_vmove_reclaim(td, ifr->ifr_name,
ifr->ifr_jid);
- CURVNET_RESTORE();
- return (error);
+ goto out_noref;
#endif
case SIOCIFCREATE:
case SIOCIFCREATE2:
@@ -2937,23 +3065,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
error = if_clone_create(ifr->ifr_name,
sizeof(ifr->ifr_name), cmd == SIOCIFCREATE2 ?
ifr_data_get_ptr(ifr) : NULL);
- CURVNET_RESTORE();
- return (error);
+ goto out_noref;
case SIOCIFDESTROY:
error = priv_check(td, PRIV_NET_IFDESTROY);
if (error == 0)
error = if_clone_destroy(ifr->ifr_name);
- CURVNET_RESTORE();
- return (error);
+ goto out_noref;
case SIOCIFGCLONERS:
error = if_clone_list((struct if_clonereq *)data);
- CURVNET_RESTORE();
- return (error);
- case SIOCGIFGMEMB:
+ goto out_noref;
+
+ CASE_IOC_IFGROUPREQ(SIOCGIFGMEMB):
error = if_getgroupmembers((struct ifgroupreq *)data);
- CURVNET_RESTORE();
- return (error);
+ goto out_noref;
+
#if defined(INET) || defined(INET6)
case SIOCSVH:
case SIOCGVH:
@@ -2961,29 +3087,24 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
error = EPROTONOSUPPORT;
else
error = (*carp_ioctl_p)(ifr, cmd, td);
- CURVNET_RESTORE();
- return (error);
+ goto out_noref;
#endif
}
ifp = ifunit_ref(ifr->ifr_name);
if (ifp == NULL) {
- CURVNET_RESTORE();
- return (ENXIO);
+ error = ENXIO;
+ goto out_noref;
}
error = ifhwioctl(cmd, ifp, data, td);
- if (error != ENOIOCTL) {
- if_rele(ifp);
- CURVNET_RESTORE();
- return (error);
- }
+ if (error != ENOIOCTL)
+ goto out_ref;
oif_flags = ifp->if_flags;
if (so->so_proto == NULL) {
- if_rele(ifp);
- CURVNET_RESTORE();
- return (EOPNOTSUPP);
+ error = EOPNOTSUPP;
+ goto out_ref;
}
/*
@@ -3008,7 +3129,19 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
in6_if_up(ifp);
#endif
}
+
+out_ref:
if_rele(ifp);
+out_noref:
+#ifdef COMPAT_FREEBSD32
+ if (ifmrp != NULL) {
+ KASSERT((cmd == SIOCGIFMEDIA || cmd == SIOCGIFXMEDIA),
+ ("ifmrp non-NULL, but cmd is not an ifmedia req 0x%lx",
+ cmd));
+ data = saved_data;
+ ifmr_update(ifmrp, data);
+ }
+#endif
CURVNET_RESTORE();
return (error);
}
@@ -3103,8 +3236,7 @@ ifpromisc(struct ifnet *ifp, int pswitch)
/* If promiscuous mode status has changed, log a message */
if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) &&
log_promisc_mode_change)
- log(LOG_INFO, "%s: promiscuous mode %s\n",
- ifp->if_xname,
+ if_printf(ifp, "promiscuous mode %s\n",
(ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
return (error);
}
@@ -3143,14 +3275,14 @@ again:
valid_len = 0;
IFNET_RLOCK();
- TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
int addrs;
/*
- * Zero the ifr_name buffer to make sure we don't
- * disclose the contents of the stack.
+ * Zero the ifr to make sure we don't disclose the contents
+ * of the stack.
*/
- memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name));
+ memset(&ifr, 0, sizeof(ifr));
if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
>= sizeof(ifr.ifr_name)) {
@@ -3161,14 +3293,20 @@ again:
addrs = 0;
IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
struct sockaddr *sa = ifa->ifa_addr;
if (prison_if(curthread->td_ucred, sa) != 0)
continue;
addrs++;
if (sa->sa_len <= sizeof(*sa)) {
- ifr.ifr_addr = *sa;
+ if (sa->sa_len < sizeof(*sa)) {
+ memset(&ifr.ifr_ifru.ifru_addr, 0,
+ sizeof(ifr.ifr_ifru.ifru_addr));
+ memcpy(&ifr.ifr_ifru.ifru_addr, sa,
+ sa->sa_len);
+ } else
+ ifr.ifr_ifru.ifru_addr = *sa;
sbuf_bcat(sb, &ifr, sizeof(ifr));
max_len += sizeof(ifr);
} else {
@@ -3184,7 +3322,6 @@ again:
}
IF_ADDR_RUNLOCK(ifp);
if (addrs == 0) {
- bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
sbuf_bcat(sb, &ifr, sizeof(ifr));
max_len += sizeof(ifr);
@@ -3228,7 +3365,7 @@ if_findmulti(struct ifnet *ifp, const struct sockaddr *sa)
IF_ADDR_LOCK_ASSERT(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (sa->sa_family == AF_LINK) {
if (sa_dl_equal(ifma->ifma_addr, sa))
break;
@@ -3295,8 +3432,11 @@ if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa,
* counting, notifying the driver, handling routing messages, and releasing
* any dependent link layer state.
*/
+#ifdef MCAST_VERBOSE
+extern void kdb_backtrace(void);
+#endif
static void
-if_freemulti(struct ifmultiaddr *ifma)
+if_freemulti_internal(struct ifmultiaddr *ifma)
{
KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
@@ -3304,10 +3444,33 @@ if_freemulti(struct ifmultiaddr *ifma)
if (ifma->ifma_lladdr != NULL)
free(ifma->ifma_lladdr, M_IFMADDR);
+#ifdef MCAST_VERBOSE
+ kdb_backtrace();
+ printf("%s freeing ifma: %p\n", __func__, ifma);
+#endif
free(ifma->ifma_addr, M_IFMADDR);
free(ifma, M_IFMADDR);
}
+static void
+if_destroymulti(epoch_context_t ctx)
+{
+ struct ifmultiaddr *ifma;
+
+ ifma = __containerof(ctx, struct ifmultiaddr, ifma_epoch_ctx);
+ if_freemulti_internal(ifma);
+}
+
+void
+if_freemulti(struct ifmultiaddr *ifma)
+{
+ KASSERT(ifma->ifma_refcount == 0, ("if_freemulti_epoch: refcount %d",
+ ifma->ifma_refcount));
+
+ epoch_call(net_epoch_preempt, &ifma->ifma_epoch_ctx, if_destroymulti);
+}
+
+
/*
* Register an additional multicast address with a network interface.
*
@@ -3335,6 +3498,12 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
struct sockaddr_dl sdl;
int error;
+#ifdef INET
+ IN_MULTI_LIST_UNLOCK_ASSERT();
+#endif
+#ifdef INET6
+ IN6_MULTI_LIST_UNLOCK_ASSERT();
+#endif
/*
* If the address is already present, return a new reference to it;
* otherwise, allocate storage and set up a new address.
@@ -3395,7 +3564,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
error = ENOMEM;
goto free_llsa_out;
}
- TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
+ CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
ifma_link);
} else
ll_ifma->ifma_refcount++;
@@ -3407,7 +3576,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
* referenced link layer address. Add the primary address to the
* ifnet address list.
*/
- TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
+ CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
if (retifma != NULL)
*retifma = ifma;
@@ -3459,7 +3628,7 @@ if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
struct ifnet *oifp;
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(oifp, &V_ifnet, if_link)
+ CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link)
if (ifp == oifp)
break;
if (ifp != oifp)
@@ -3499,11 +3668,17 @@ if_delallmulti(struct ifnet *ifp)
struct ifmultiaddr *next;
IF_ADDR_WLOCK(ifp);
- TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
+ CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
if_delmulti_locked(ifp, ifma, 0);
IF_ADDR_WUNLOCK(ifp);
}
+void
+if_delmulti_ifma(struct ifmultiaddr *ifma)
+{
+ if_delmulti_ifma_flags(ifma, 0);
+}
+
/*
* Delete a multicast group membership by group membership pointer.
* Network-layer protocol domains must use this routine.
@@ -3511,11 +3686,14 @@ if_delallmulti(struct ifnet *ifp)
* It is safe to call this routine if the ifp disappeared.
*/
void
-if_delmulti_ifma(struct ifmultiaddr *ifma)
+if_delmulti_ifma_flags(struct ifmultiaddr *ifma, int flags)
{
struct ifnet *ifp;
int lastref;
-
+ MCDPRINTF("%s freeing ifma: %p\n", __func__, ifma);
+#ifdef INET
+ IN_MULTI_LIST_UNLOCK_ASSERT();
+#endif
ifp = ifma->ifma_ifp;
#ifdef DIAGNOSTIC
if (ifp == NULL) {
@@ -3524,13 +3702,11 @@ if_delmulti_ifma(struct ifmultiaddr *ifma)
struct ifnet *oifp;
IFNET_RLOCK_NOSLEEP();
- TAILQ_FOREACH(oifp, &V_ifnet, if_link)
+ CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link)
if (ifp == oifp)
break;
- if (ifp != oifp) {
- printf("%s: ifnet %p disappeared\n", __func__, ifp);
+ if (ifp != oifp)
ifp = NULL;
- }
IFNET_RUNLOCK_NOSLEEP();
}
#endif
@@ -3540,7 +3716,7 @@ if_delmulti_ifma(struct ifmultiaddr *ifma)
if (ifp != NULL)
IF_ADDR_WLOCK(ifp);
- lastref = if_delmulti_locked(ifp, ifma, 0);
+ lastref = if_delmulti_locked(ifp, ifma, flags);
if (ifp != NULL) {
/*
@@ -3574,6 +3750,7 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
}
ifp = ifma->ifma_ifp;
+ MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : "");
/*
* If the ifnet is detaching, null out references to ifnet,
@@ -3599,6 +3776,9 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
if (--ifma->ifma_refcount > 0)
return 0;
+ if (ifp != NULL && detaching == 0)
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
+
/*
* If this ifma is a network-layer ifma, a link-layer ifma may
* have been associated with it. Release it first if so.
@@ -3611,18 +3791,21 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
ll_ifma->ifma_ifp = NULL; /* XXX */
if (--ll_ifma->ifma_refcount == 0) {
if (ifp != NULL) {
- TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma,
+ CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr,
ifma_link);
}
if_freemulti(ll_ifma);
}
}
+#ifdef INVARIANTS
+ if (ifp) {
+ struct ifmultiaddr *ifmatmp;
- if (ifp != NULL)
- TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
-
+ CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link)
+ MPASS(ifma != ifmatmp);
+ }
+#endif
if_freemulti(ifma);
-
/*
* The last reference to this instance of struct ifmultiaddr
* was released; the hardware should be notified of this change.
@@ -3644,38 +3827,36 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
struct sockaddr_dl *sdl;
struct ifaddr *ifa;
struct ifreq ifr;
+ int rc;
- IF_ADDR_RLOCK(ifp);
+ rc = 0;
+ NET_EPOCH_ENTER();
ifa = ifp->if_addr;
if (ifa == NULL) {
- IF_ADDR_RUNLOCK(ifp);
- return (EINVAL);
+ rc = EINVAL;
+ goto out;
}
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
+
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl == NULL) {
- ifa_free(ifa);
- return (EINVAL);
+ rc = EINVAL;
+ goto out;
}
if (len != sdl->sdl_alen) { /* don't allow length to change */
- ifa_free(ifa);
- return (EINVAL);
+ rc = EINVAL;
+ goto out;
}
switch (ifp->if_type) {
case IFT_ETHER:
- case IFT_FDDI:
case IFT_XETHER:
case IFT_L2VLAN:
case IFT_BRIDGE:
- case IFT_ARCNET:
case IFT_IEEE8023ADLAG:
bcopy(lladdr, LLADDR(sdl), len);
- ifa_free(ifa);
break;
default:
- ifa_free(ifa);
- return (ENODEV);
+ rc = ENODEV;
+ goto out;
}
/*
@@ -3683,6 +3864,7 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
* to re-init it in order to reprogram its
* address filter.
*/
+ NET_EPOCH_EXIT();
if ((ifp->if_flags & IFF_UP) != 0) {
if (ifp->if_ioctl) {
ifp->if_flags &= ~IFF_UP;
@@ -3697,6 +3879,9 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
}
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
return (0);
+ out:
+ NET_EPOCH_EXIT();
+ return (rc);
}
/*
@@ -3777,16 +3962,16 @@ if_initname(struct ifnet *ifp, const char *name, int unit)
}
int
-if_printf(struct ifnet *ifp, const char * fmt, ...)
+if_printf(struct ifnet *ifp, const char *fmt, ...)
{
+ char if_fmt[256];
va_list ap;
- int retval;
- retval = printf("%s: ", ifp->if_xname);
+ snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt);
va_start(ap, fmt);
- retval += vprintf(fmt, ap);
+ vlog(LOG_INFO, if_fmt, ap);
va_end(ap);
- return (retval);
+ return (0);
}
void
@@ -4149,7 +4334,7 @@ if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max)
uint8_t *lmta = (uint8_t *)mta;
int mcnt = 0;
- TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
@@ -4184,7 +4369,7 @@ if_multiaddr_count(if_t ifp, int max)
count = 0;
if_maddr_rlock(ifp);
- TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
+ CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
count++;
@@ -4202,7 +4387,7 @@ if_multi_apply(struct ifnet *ifp, int (*filter)(void *, struct ifmultiaddr *, in
int cnt = 0;
if_maddr_rlock(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
+ CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
cnt += filter(arg, ifma, cnt);
if_maddr_runlock(ifp);
return (cnt);