/* Return all AF_INET addresses of all interfaces */
ifnet_lock();
TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
- struct ifaddr_container *ifac;
+ struct ifaddr_container *ifac, *ifac_mark;
+ struct ifaddr_marker mark;
+ struct ifaddrhead *head;
if (uio.uio_resid <= 0)
break;
else
strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
- /* Walk the address list */
- TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
+ /*
+ * Walk the address list
+ *
+ * Add a marker, since uiomove() could block and during that
+ * period the list could be changed. Inserting the marker to
+ * the header of the list will not cause trouble for the code
+ * assuming that the first element of the list is AF_LINK; the
+ * marker will be moved to the next position w/o blocking.
+ */
+ ifa_marker_init(&mark, ifp);
+ ifac_mark = &mark.ifac;
+ head = &ifp->if_addrheads[mycpuid];
+
+ TAILQ_INSERT_HEAD(head, ifac_mark, ifa_link);
+ while ((ifac = TAILQ_NEXT(ifac_mark, ifa_link)) != NULL) {
struct ifaddr *ifa = ifac->ifa;
struct sockaddr *sa = ifa->ifa_addr;
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
+ TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
+
if (uio.uio_resid <= 0)
break;
error = uiomove((caddr_t)&ifr, sizeof ifr,
&uio);
if (error != 0) {
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
ifnet_unlock();
return (error);
}
}
}
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
}
ifnet_unlock();
/*
* Purge all addresses whose type is _not_ AF_LINK
*/
-void
-if_purgeaddrs_nolink(struct ifnet *ifp)
+static void
+if_purgeaddrs_nolink_dispatch(netmsg_t nmsg)
{
+ struct lwkt_msg *lmsg = &nmsg->lmsg;
+ struct ifnet *ifp = lmsg->u.ms_resultp;
struct ifaddr_container *ifac, *next;
+ KASSERT(&curthread->td_msgport == netisr_cpuport(0),
+ ("not in netisr0"));
+
+ /*
+ * The ifaddr processing in the following loop will block,
+ * however, this function is called in netisr0, in which
+ * ifaddr list changes happen, so we don't care about the
+ * blockness of the ifaddr processing here.
+ */
TAILQ_FOREACH_MUTABLE(ifac, &ifp->if_addrheads[mycpuid],
ifa_link, next) {
struct ifaddr *ifa = ifac->ifa;
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
/* Leave link ifaddr as it is */
if (ifa->ifa_addr->sa_family == AF_LINK)
continue;
ifa_ifunlink(ifa, ifp);
ifa_destroy(ifa);
}
+
+ lwkt_replymsg(lmsg, 0);
+}
+
+void
+if_purgeaddrs_nolink(struct ifnet *ifp)
+{
+ struct netmsg_base nmsg;
+ struct lwkt_msg *lmsg = &nmsg.lmsg;
+
+ ASSERT_CANDOMSG_NETISR0(curthread);
+
+ netmsg_init(&nmsg, NULL, &curthread->td_msgport, 0,
+ if_purgeaddrs_nolink_dispatch);
+ lmsg->u.ms_resultp = ifp;
+ lwkt_domsg(netisr_cpuport(0), lmsg, 0);
}
static void
}
}
+struct netmsg_ifroute {
+ struct netmsg_base base;
+ struct ifnet *ifp;
+ int flag;
+ int fam;
+};
+
/*
- * Mark an interface down and notify protocols of
- * the transition.
- * NOTE: must be called at splnet or eqivalent.
+ * Mark an interface down and notify protocols of the transition.
*/
-void
-if_unroute(struct ifnet *ifp, int flag, int fam)
+static void
+if_unroute_dispatch(netmsg_t nmsg)
{
+ struct netmsg_ifroute *msg = (struct netmsg_ifroute *)nmsg;
+ struct ifnet *ifp = msg->ifp;
+ int flag = msg->flag, fam = msg->fam;
struct ifaddr_container *ifac;
ifp->if_flags &= ~flag;
getmicrotime(&ifp->if_lastchange);
+ /*
+ * The ifaddr processing in the following loop will block,
+ * however, this function is called in netisr0, in which
+ * ifaddr list changes happen, so we don't care about the
+ * blockness of the ifaddr processing here.
+ */
TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
struct ifaddr *ifa = ifac->ifa;
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
kpfctlinput(PRC_IFDOWN, ifa->ifa_addr);
}
ifq_purge_all(&ifp->if_snd);
rt_ifmsg(ifp);
+
+ lwkt_replymsg(&nmsg->lmsg, 0);
+}
+
+void
+if_unroute(struct ifnet *ifp, int flag, int fam)
+{
+ struct netmsg_ifroute msg;
+
+ ASSERT_CANDOMSG_NETISR0(curthread);
+
+ netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0,
+ if_unroute_dispatch);
+ msg.ifp = ifp;
+ msg.flag = flag;
+ msg.fam = fam;
+ lwkt_domsg(netisr_cpuport(0), &msg.base.lmsg, 0);
}
/*
- * Mark an interface up and notify protocols of
- * the transition.
- * NOTE: must be called at splnet or eqivalent.
+ * Mark an interface up and notify protocols of the transition.
*/
-void
-if_route(struct ifnet *ifp, int flag, int fam)
+static void
+if_route_dispatch(netmsg_t nmsg)
{
+ struct netmsg_ifroute *msg = (struct netmsg_ifroute *)nmsg;
+ struct ifnet *ifp = msg->ifp;
+ int flag = msg->flag, fam = msg->fam;
struct ifaddr_container *ifac;
ifq_purge_all(&ifp->if_snd);
ifp->if_flags |= flag;
getmicrotime(&ifp->if_lastchange);
+ /*
+ * The ifaddr processing in the following loop will block,
+ * however, this function is called in netisr0, in which
+ * ifaddr list changes happen, so we don't care about the
+ * blockness of the ifaddr processing here.
+ */
TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
struct ifaddr *ifa = ifac->ifa;
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
kpfctlinput(PRC_IFUP, ifa->ifa_addr);
}
#ifdef INET6
in6_if_up(ifp);
#endif
+
+ lwkt_replymsg(&nmsg->lmsg, 0);
+}
+
+void
+if_route(struct ifnet *ifp, int flag, int fam)
+{
+ struct netmsg_ifroute msg;
+
+ ASSERT_CANDOMSG_NETISR0(curthread);
+
+ netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0,
+ if_route_dispatch);
+ msg.ifp = ifp;
+ msg.flag = flag;
+ msg.fam = fam;
+ lwkt_domsg(netisr_cpuport(0), &msg.base.lmsg, 0);
}
/*
strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
ifa = TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa;
- /* XXX IFA_LOCK(ifa); */
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
namelen = strlen(new_name);
onamelen = sdl->sdl_nlen;
bzero(sdl->sdl_data, onamelen);
while (namelen != 0)
sdl->sdl_data[--namelen] = 0xff;
- /* XXX IFA_UNLOCK(ifa) */
EVENTHANDLER_INVOKE(ifnet_attach_event, ifp);
ifnet_lock();
TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
- struct ifaddr_container *ifac;
+ struct ifaddr_container *ifac, *ifac_mark;
+ struct ifaddr_marker mark;
+ struct ifaddrhead *head;
int addrs;
if (space <= sizeof ifr)
break;
}
+ /*
+ * Add a marker, since copyout() could block and during that
+ * period the list could be changed. Inserting the marker to
+ * the header of the list will not cause trouble for the code
+ * assuming that the first element of the list is AF_LINK; the
+ * marker will be moved to the next position w/o blocking.
+ */
+ ifa_marker_init(&mark, ifp);
+ ifac_mark = &mark.ifac;
+ head = &ifp->if_addrheads[mycpuid];
+
addrs = 0;
- TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
+ TAILQ_INSERT_HEAD(head, ifac_mark, ifa_link);
+ while ((ifac = TAILQ_NEXT(ifac_mark, ifa_link)) != NULL) {
struct ifaddr *ifa = ifac->ifa;
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
+ TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
+
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (space <= sizeof ifr)
break;
sa = ifa->ifa_addr;
prison_if(cred, sa))
continue;
addrs++;
+ /*
+ * Keep a reference on this ifaddr, so that it will
+ * not be destroyed when its address is copied to
+ * the userland, which could block.
+ */
+ IFAREF(ifa);
#ifdef COMPAT_43
if (cmd == OSIOCGIFCONF) {
struct osockaddr *osa =
ifrp++;
} else {
if (space < (sizeof ifr) + sa->sa_len -
- sizeof(*sa))
+ sizeof(*sa)) {
+ IFAFREE(ifa);
break;
+ }
space -= sa->sa_len - sizeof(*sa);
error = copyout(&ifr, ifrp,
sizeof ifr.ifr_name);
ifrp = (struct ifreq *)
(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
}
+ IFAFREE(ifa);
if (error)
break;
space -= sizeof ifr;
}
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
if (error)
break;
if (!addrs) {
else
return 0;
}
+
+void
+ifa_marker_init(struct ifaddr_marker *mark, struct ifnet *ifp)
+{
+ struct ifaddr *ifa;
+
+ memset(mark, 0, sizeof(*mark));
+ ifa = &mark->ifa;
+
+ mark->ifac.ifa = ifa;
+
+ ifa->ifa_addr = &mark->addr;
+ ifa->ifa_dstaddr = &mark->dstaddr;
+ ifa->ifa_netmask = &mark->netmask;
+ ifa->ifa_ifp = ifp;
+}
#ifdef _KERNEL
+struct ifaddr_marker {
+ struct ifaddr ifa;
+ struct ifaddr_container ifac;
+ struct sockaddr addr;
+ struct sockaddr netmask;
+ struct sockaddr dstaddr;
+};
+
/*
* ifaddr statistics update macro
*/
void ifa_destroy(struct ifaddr *);
void ifa_iflink(struct ifaddr *, struct ifnet *, int);
void ifa_ifunlink(struct ifaddr *, struct ifnet *);
+void ifa_marker_init(struct ifaddr_marker *, struct ifnet *);
struct ifmultiaddr *ifmaof_ifpforaddr(struct sockaddr *, struct ifnet *);
int if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen);
#include <sys/mbuf.h>
#include <sys/eventhandler.h>
#include <sys/filio.h>
+#include <sys/msgport2.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <net/if.h>
#include <net/if_types.h>
+#include <net/netisr2.h>
+#include <net/netmsg2.h>
#include <net/route.h>
#include <netinet/in.h>
"into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
}
-void
-pfi_instance_add(struct ifnet *ifp, int net, int flags)
+struct netmsg_pfiadd {
+ struct netmsg_base base;
+ struct ifnet *ifp;
+ int net;
+ int flags;
+};
+
+static void
+pfi_instance_add_dispatch(netmsg_t nmsg)
{
+ struct netmsg_pfiadd *msg = (struct netmsg_pfiadd *)nmsg;
struct ifaddr_container *ifac;
int got4 = 0, got6 = 0;
int net2, af;
+ struct ifnet *ifp = msg->ifp;
+ int net = msg->net, flags = msg->flags;
if (ifp == NULL)
- return;
+ goto done;
+ /*
+ * The ifaddr processing in the following loop will block,
+ * however, this function is called in netisr0, in which
+ * ifaddr list changes happen, so we don't care about the
+ * blockness of the ifaddr processing here.
+ */
TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
struct ifaddr *ia = ifac->ifa;
else
pfi_address_add(ia->ifa_addr, af, net2);
}
+done:
+ lwkt_replymsg(&nmsg->lmsg, 0);
+}
+
+void
+pfi_instance_add(struct ifnet *ifp, int net, int flags)
+{
+ struct netmsg_pfiadd msg;
+
+ ASSERT_CANDOMSG_NETISR0(curthread);
+
+ netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0,
+ pfi_instance_add_dispatch);
+ msg.ifp = ifp;
+ msg.net = net;
+ msg.flags = flags;
+ lwkt_domsg(netisr_cpuport(0), &msg.base.lmsg, 0);
}
void
ifnet_lock();
TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
- struct ifaddr_container *ifac;
+ struct ifaddr_container *ifac, *ifac_mark;
+ struct ifaddr_marker mark;
+ struct ifaddrhead *head;
struct ifaddr *ifa;
if (w->w_arg && w->w_arg != ifp->if_index)
continue;
- ifac = TAILQ_FIRST(&ifp->if_addrheads[mycpuid]);
+ head = &ifp->if_addrheads[mycpuid];
+ /*
+ * There is no need to reference the first ifaddr
+ * even if the following resizewalkarg() blocks,
+ * since the first ifaddr will not be destroyed
+ * when the ifnet lock is held.
+ */
+ ifac = TAILQ_FIRST(head);
ifa = ifac->ifa;
rtinfo.rti_ifpaddr = ifa->ifa_addr;
msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
return (error);
}
}
- while ((ifac = TAILQ_NEXT(ifac, ifa_link)) != NULL) {
+ /*
+ * Add a marker, since SYSCTL_OUT() could block and during
+ * that period the list could be changed.
+ */
+ ifa_marker_init(&mark, ifp);
+ ifac_mark = &mark.ifac;
+ TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
+ while ((ifac = TAILQ_NEXT(ifac_mark, ifa_link)) != NULL) {
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
+ TAILQ_INSERT_AFTER(head, ifac, ifac_mark, ifa_link);
+
ifa = ifac->ifa;
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (af && af != ifa->ifa_addr->sa_family)
continue;
if (curproc->p_ucred->cr_prison &&
rtinfo.rti_netmask = ifa->ifa_netmask;
rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
+ /*
+ * Keep a reference on this ifaddr, so that it will
+ * not be destroyed if the following resizewalkarg()
+ * blocks.
+ */
+ IFAREF(ifa);
if (w->w_tmemsize < msglen &&
resizewalkarg(w, msglen) != 0) {
+ IFAFREE(ifa);
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
ifnet_unlock();
return (ENOMEM);
}
ifam->ifam_addrs = rtinfo.rti_addrs;
error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
if (error) {
+ IFAFREE(ifa);
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
ifnet_unlock();
return (error);
}
}
+ IFAFREE(ifa);
}
+ TAILQ_REMOVE(head, ifac_mark, ifa_link);
rtinfo.rti_netmask = NULL;
rtinfo.rti_ifaaddr = NULL;
rtinfo.rti_bcastaddr = NULL;
/* Determine size of response and allocate it */
buflen = 0;
TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
- ifa_link)
+ ifa_link) {
+ /* Ignore marker */
+ if (ifac->ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
buflen += SA_SIZE(ifac->ifa->ifa_addr);
+ }
NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
struct ifaddr *ifa = ifac->ifa;
const int len = SA_SIZE(ifa->ifa_addr);
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (buflen < len) {
log(LOG_ERR, "%s: len changed?\n",
ifp->if_xname);
/* Determine size of response and allocate it */
buflen = 0;
TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
- ifa_link)
+ ifa_link) {
+ /* Ignore marker */
+ if (ifac->ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
buflen += SA_SIZE(ifac->ifa->ifa_addr);
+ }
NG_MKRESPONSE(resp, msg, buflen, M_WAITOK | M_NULLOK);
if (resp == NULL) {
error = ENOMEM;
struct ifaddr *ifa = ifac->ifa;
const int len = SA_SIZE(ifa->ifa_addr);
+ /* Ignore marker */
+ if (ifa->ifa_addr->sa_family == AF_UNSPEC)
+ continue;
+
if (buflen < len) {
log(LOG_ERR, "%s: len changed?\n",
ifp->if_xname);
--- /dev/null
+WARNS= 6
+PROG= ifconf
+BINDIR= /usr/local/bin
+NOMAN=
+
+.include <bsd.prog.mk>
--- /dev/null
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NADDRS 128
+
+/* XXX _SIZEOF_ADDR_IFREQ should accept ptr */
+#define _SIZEOF_ADDR_IFREQ1(ifr) \
+ ((ifr)->ifr_addr.sa_len > sizeof(struct sockaddr) ? \
+ (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
+ (ifr)->ifr_addr.sa_len) : sizeof(struct ifreq))
+
+static void
+usage(const char *cmd)
+{
+ fprintf(stderr, "%s [-n naddrs]\n", cmd);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ caddr_t pos;
+ int s, naddrs, opt;
+
+ naddrs = NADDRS;
+
+ while ((opt = getopt(argc, argv, "n:")) != -1) {
+ switch (opt) {
+ case 'n':
+ naddrs = strtol(optarg, NULL, 10);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+ if (naddrs <= 0)
+ usage(argv[0]);
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(2, "socket failed");
+
+ memset(&ifc, 0, sizeof(ifc));
+ ifc.ifc_len = sizeof(struct sockaddr_storage) * naddrs;
+ ifc.ifc_buf = malloc(ifc.ifc_len);
+ if (ifc.ifc_buf == NULL)
+ err(2, "malloc failed");
+
+ if (ioctl(s, SIOCGIFCONF, &ifc, sizeof(ifc)) < 0)
+ err(2, "ioctl failed");
+
+ pos = ifc.ifc_buf;
+ while (ifc.ifc_len >= (int)sizeof(*ifr)) {
+ int len;
+
+ ifr = (struct ifreq *)pos;
+ len = _SIZEOF_ADDR_IFREQ1(ifr);
+ if (ifc.ifc_len < len)
+ err(2, "invalid ifc.ifc_len");
+
+ if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
+ printf("%s: no address\n", ifr->ifr_name);
+ } else if (ifr->ifr_addr.sa_family == AF_INET ||
+ ifr->ifr_addr.sa_family == AF_INET6) {
+ char addr_str[INET6_ADDRSTRLEN];
+ const void *src;
+ const char *ret;
+
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)&ifr->ifr_addr;
+ src = &in->sin_addr;
+ } else {
+ const struct sockaddr_in6 *in6 =
+ (const struct sockaddr_in6 *)&ifr->ifr_addr;
+ src = &in6->sin6_addr;
+ }
+
+ ret = inet_ntop(ifr->ifr_addr.sa_family, src,
+ addr_str, sizeof(addr_str));
+ if (ret == NULL)
+ err(2, "inet_ntop failed");
+ printf("%s: inet%c %s\n", ifr->ifr_name,
+ ifr->ifr_addr.sa_family == AF_INET ? '4' : '6',
+ ret);
+ } else if (ifr->ifr_addr.sa_family == AF_LINK) {
+ const struct sockaddr_dl *dl =
+ (const struct sockaddr_dl *)&ifr->ifr_addr;
+
+ printf("%s: link%d\n", ifr->ifr_name, dl->sdl_index);
+ } else {
+ printf("%s: unknown family %d\n", ifr->ifr_name,
+ ifr->ifr_addr.sa_family);
+ }
+
+ ifc.ifc_len -= len;
+ pos += len;
+ }
+ if (ifc.ifc_len != 0)
+ printf("ifc_len left %d\n", ifc.ifc_len);
+
+ exit(0);
+}