/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/syslog.h>
#include <sys/sysctl.h>
+#include <machine/endian.h>
+
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
/*XXX*/
#include <netinet/in.h>
#include <netinet/in_var.h>
+#include <netinet/ip_var.h>
#if INET6
#include <netinet6/in6_var.h>
#include <netinet6/in6_ifattach.h>
#endif
#endif
-extern u_long route_generation;
-extern int use_routegenid;
extern int dlil_multithreaded_input;
extern struct dlil_threading_info *dlil_lo_thread_ptr;
#include <security/mac_framework.h>
#endif
+
/*
* System initialization
*/
static int if_rtmtu(struct radix_node *, void *);
static void if_rtmtu_update(struct ifnet *);
-static struct if_clone *if_clone_lookup(const char *, int *);
-#ifdef IF_CLONE_LIST
+#if IF_CLONE_LIST
static int if_clone_list(int count, int * total, user_addr_t dst);
-#endif
+#endif /* IF_CLONE_LIST */
MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
static int if_cloners_count;
LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
+static struct ifaddr *ifa_ifwithnet_common(const struct sockaddr *,
+ unsigned int);
+
#if INET6
/*
* XXX: declare here to avoid to include many inet6 related files..
extern void nd6_setmtu(struct ifnet *);
#endif
-#define M_CLONE M_IFADDR
/*
* Network interface utility routines.
struct ifaddr *ifa)
{
ifnet_lock_assert(ifp, LCK_MTX_ASSERT_OWNED);
- if (ifa->ifa_debug & IFA_ATTACHED) {
+ if (ifa->ifa_debug & IFD_ATTACHED) {
panic("if_attach_ifa: Attempted to attach address that's already attached!\n");
}
ifaref(ifa);
- ifa->ifa_debug |= IFA_ATTACHED;
+ ifa->ifa_debug |= IFD_ATTACHED;
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
}
ifnet_lock_assert(ifp, LCK_MTX_ASSERT_OWNED);
#if 1
/* Debugging code */
- if ((ifa->ifa_debug & IFA_ATTACHED) == 0) {
- printf("if_detach_ifa: ifa is not attached to any interface! flags=%lu\n", ifa->ifa_debug);
+ if ((ifa->ifa_debug & IFD_ATTACHED) == 0) {
+ printf("if_detach_ifa: ifa is not attached to any interface! flags=%u\n", ifa->ifa_debug);
return;
}
else {
}
#endif
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
- ifa->ifa_debug &= ~IFA_ATTACHED;
+ ifa->ifa_debug &= ~IFD_ATTACHED;
ifafree(ifa);
}
/* allocate space for the larger arrays */
n = (2 * new_if_indexlim + 1) * sizeof(caddr_t);
new_ifnet_addrs = _MALLOC(n, M_IFADDR, M_WAITOK);
+ if (new_ifnet_addrs == NULL) {
+ --if_index;
+ return -1;
+ }
+
new_ifindex2ifnet = new_ifnet_addrs
+ new_if_indexlim * sizeof(caddr_t);
bzero(new_ifnet_addrs, n);
* Create a clone network interface.
*/
static int
-if_clone_create(char *name, int len)
+if_clone_create(char *name, int len, void *params)
{
struct if_clone *ifc;
char *dp;
- int wildcard, bytoff, bitoff;
- int unit;
+ int wildcard;
+ u_int32_t bytoff, bitoff;
+ u_int32_t unit;
int err;
ifc = if_clone_lookup(name, &unit);
return (EEXIST);
bytoff = bitoff = 0;
- wildcard = (unit < 0);
+ wildcard = (unit == UINT32_MAX);
/*
* Find a free unit if none was given.
*/
if (unit > ifc->ifc_maxunit)
return (ENXIO);
- err = (*ifc->ifc_create)(ifc, unit);
+ err = (*ifc->ifc_create)(ifc, unit, params);
if (err != 0)
return (err);
struct if_clone *ifc;
struct ifnet *ifp;
int bytoff, bitoff;
- int unit;
+ u_int32_t unit;
ifc = if_clone_lookup(name, &unit);
if (ifc == NULL)
* Look up a network interface cloner.
*/
-static struct if_clone *
-if_clone_lookup(const char *name, int *unitp)
+__private_extern__ struct if_clone *
+if_clone_lookup(const char *name, u_int32_t *unitp)
{
struct if_clone *ifc;
const char *cp;
found_name:
if (*cp == '\0') {
- i = -1;
+ i = 0xffff;
} else {
for (i = 0; *cp != '\0'; cp++) {
if (*cp < '0' || *cp > '9') {
/*
* Register a network interface cloner.
*/
-void
+int
if_clone_attach(struct if_clone *ifc)
{
int bytoff, bitoff;
int err;
int len, maxclone;
- int unit;
+ u_int32_t unit;
KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
("%s: %s requested more units then allowed (%d > %d)",
if ((len << 3) < maxclone)
len++;
ifc->ifc_units = _MALLOC(len, M_CLONE, M_WAITOK | M_ZERO);
+ if (ifc->ifc_units == NULL)
+ return ENOBUFS;
bzero(ifc->ifc_units, len);
ifc->ifc_bmlen = len;
if_cloners_count++;
for (unit = 0; unit < ifc->ifc_minifs; unit++) {
- err = (*ifc->ifc_create)(ifc, unit);
+ err = (*ifc->ifc_create)(ifc, unit, NULL);
KASSERT(err == 0,
("%s: failed to create required interface %s%d",
__func__, ifc->ifc_name, unit));
bitoff = unit - (bytoff << 3);
ifc->ifc_units[bytoff] |= (1 << bitoff);
}
+
+ return 0;
}
/*
if_cloners_count--;
}
-#ifdef IF_CLONE_LIST
+#if IF_CLONE_LIST
/*
* Provide list of interface cloners to userspace.
*/
return (error);
}
-#endif IF_CLONE_LIST
+#endif /* IF_CLONE_LIST */
-__private_extern__ int
-ifa_foraddr(
- unsigned int addr)
+/*
+ * Similar to ifa_ifwithaddr, except that this is IPv4 specific
+ * and that it matches only the local (not broadcast) address.
+ */
+__private_extern__ struct in_ifaddr *
+ifa_foraddr(unsigned int addr)
{
- struct ifnet *ifp;
- struct ifaddr *ifa;
- unsigned int addr2;
- int result = 0;
-
- ifnet_head_lock_shared();
- for (ifp = ifnet_head.tqh_first; ifp && !result; ifp = ifp->if_link.tqe_next) {
- ifnet_lock_shared(ifp);
- for (ifa = ifp->if_addrhead.tqh_first; ifa;
- ifa = ifa->ifa_link.tqe_next) {
- if (ifa->ifa_addr->sa_family != AF_INET)
- continue;
- addr2 = IA_SIN(ifa)->sin_addr.s_addr;
-
- if (addr == addr2) {
- result = 1;
- break;
- }
- }
- ifnet_lock_done(ifp);
+ return (ifa_foraddr_scoped(addr, IFSCOPE_NONE));
+}
+
+/*
+ * Similar to ifa_foraddr, except with the added interface scope
+ * constraint (unless the caller passes in IFSCOPE_NONE in which
+ * case there is no scope restriction).
+ */
+__private_extern__ struct in_ifaddr *
+ifa_foraddr_scoped(unsigned int addr, unsigned int scope)
+{
+ struct in_ifaddr *ia = NULL;
+
+ lck_rw_lock_shared(in_ifaddr_rwlock);
+ TAILQ_FOREACH(ia, INADDR_HASH(addr), ia_hash) {
+ if (ia->ia_addr.sin_addr.s_addr == addr &&
+ (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope))
+ break;
}
- ifnet_head_done();
-
- return result;
+ if (ia != NULL)
+ ifaref(&ia->ia_ifa);
+ lck_rw_done(in_ifaddr_rwlock);
+ return (ia);
}
/*
return result;
}
+/*
+ * Locate the source address of an interface based on a complete address.
+ */
+struct ifaddr *
+ifa_ifwithaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
+{
+ struct ifaddr *result = NULL;
+ struct ifnet *ifp;
+
+ if (ifscope == IFSCOPE_NONE)
+ return (ifa_ifwithaddr(addr));
+
+ ifnet_head_lock_shared();
+ if (ifscope > (unsigned int)if_index) {
+ ifnet_head_done();
+ return (NULL);
+ }
+
+ ifp = ifindex2ifnet[ifscope];
+ if (ifp != NULL) {
+ struct ifaddr *ifa = NULL;
+
+ /*
+ * This is suboptimal; there should be a better way
+ * to search for a given address of an interface
+ * for any given address family.
+ */
+ ifnet_lock_shared(ifp);
+ for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL;
+ ifa = ifa->ifa_link.tqe_next) {
+ if (ifa->ifa_addr->sa_family != addr->sa_family)
+ continue;
+ if (equal(addr, ifa->ifa_addr)) {
+ result = ifa;
+ break;
+ }
+ if ((ifp->if_flags & IFF_BROADCAST) &&
+ ifa->ifa_broadaddr != NULL &&
+ /* IP6 doesn't have broadcast */
+ ifa->ifa_broadaddr->sa_len != 0 &&
+ equal(ifa->ifa_broadaddr, addr)) {
+ result = ifa;
+ break;
+ }
+ }
+ if (result != NULL)
+ ifaref(result);
+ ifnet_lock_done(ifp);
+ }
+ ifnet_head_done();
+
+ return (result);
+}
+
+struct ifaddr *
+ifa_ifwithnet(const struct sockaddr *addr)
+{
+ return (ifa_ifwithnet_common(addr, IFSCOPE_NONE));
+}
+
+struct ifaddr *
+ifa_ifwithnet_scoped(const struct sockaddr *addr, unsigned int ifscope)
+{
+ return (ifa_ifwithnet_common(addr, ifscope));
+}
+
/*
* Find an interface on a specific network. If many, choice
* is most specific found.
*/
-struct ifaddr *
-ifa_ifwithnet(
- const struct sockaddr *addr)
+static struct ifaddr *
+ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
{
struct ifnet *ifp;
struct ifaddr *ifa = NULL;
u_int af = addr->sa_family;
const char *addr_data = addr->sa_data, *cplim;
+ if (!ip_doscopedroute || addr->sa_family != AF_INET)
+ ifscope = IFSCOPE_NONE;
+
ifnet_head_lock_shared();
/*
* AF_LINK addresses can be looked up directly by their index number,
#endif /* __APPLE__*/
{
/*
- * if we have a special address handler,
- * then use it instead of the generic one.
+ * If we're looking up with a scope,
+ * find using a matching interface.
*/
- if (ifa->ifa_claim_addr) {
- if (ifa->ifa_claim_addr(ifa, addr)) {
- break;
- } else {
- continue;
- }
- }
+ if (ifscope != IFSCOPE_NONE &&
+ ifp->if_index != ifscope)
+ continue;
/*
* Scan all the bits in the ifa's address.
continue;
}
if (ifp->if_flags & IFF_POINTOPOINT) {
- if (equal(addr, ifa->ifa_dstaddr))
+ if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
break;
} else {
if (equal(addr, ifa->ifa_addr)) {
struct sockaddr *dst;
struct ifnet *ifp;
+ lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
+ RT_LOCK_ASSERT_HELD(rt);
+
if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
return;
struct net_event_data ev_data;
switch (cmd) {
- case SIOCGIFCONF:
- case OSIOCGIFCONF:
+ case OSIOCGIFCONF32:
+ case SIOCGIFCONF32: {
+ struct ifconf32 *ifc = (struct ifconf32 *)data;
+ return (ifconf(cmd, CAST_USER_ADDR_T(ifc->ifc_req),
+ &ifc->ifc_len));
+ /* NOTREACHED */
+ }
case SIOCGIFCONF64:
- {
- struct ifconf64 * ifc = (struct ifconf64 *)data;
- user_addr_t user_addr;
-
- user_addr = proc_is64bit(p)
- ? ifc->ifc_req64 : CAST_USER_ADDR_T(ifc->ifc_req);
- return (ifconf(cmd, user_addr, &ifc->ifc_len));
- }
- break;
+ case OSIOCGIFCONF64: {
+ struct ifconf64 *ifc = (struct ifconf64 *)data;
+ return (ifconf(cmd, ifc->ifc_req, &ifc->ifc_len));
+ /* NOTREACHED */
+ }
}
ifr = (struct ifreq *)data;
switch (cmd) {
case SIOCIFCREATE:
+ case SIOCIFCREATE2:
+ error = proc_suser(p);
+ if (error)
+ return (error);
+ return if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name),
+ cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL);
case SIOCIFDESTROY:
error = proc_suser(p);
if (error)
return (error);
- return ((cmd == SIOCIFCREATE) ?
- if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
- if_clone_destroy(ifr->ifr_name));
+ return if_clone_destroy(ifr->ifr_name);
#if IF_CLONE_LIST
- case SIOCIFGCLONERS:
- case SIOCIFGCLONERS64:
- {
- struct if_clonereq64 * ifcr = (struct if_clonereq64 *)data;
- user_addr = proc_is64bit(p)
- ? ifcr->ifcr_ifcru.ifcru_buffer64
- : CAST_USER_ADDR_T(ifcr->ifcr_ifcru.ifcru_buffer32);
+ case SIOCIFGCLONERS32: {
+ struct if_clonereq32 *ifcr = (struct if_clonereq32 *)data;
return (if_clone_list(ifcr->ifcr_count, &ifcr->ifcr_total,
- user_data));
+ CAST_USER_ADDR_T(ifcr->ifcru_buffer)));
+ /* NOTREACHED */
+
+ }
+ case SIOCIFGCLONERS64: {
+ struct if_clonereq64 *ifcr = (struct if_clonereq64 *)data;
+ return (if_clone_list(ifcr->ifcr_count, &ifcr->ifcr_total,
+ ifcr->ifcru_buffer));
+ /* NOTREACHED */
}
-#endif IF_CLONE_LIST
+#endif /* IF_CLONE_LIST */
}
ifp = ifunit(ifr->ifr_name);
error = ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family,
cmd, data);
- if (error == 0) {
- ev_msg.vendor_code = KEV_VENDOR_APPLE;
- ev_msg.kev_class = KEV_NETWORK_CLASS;
- ev_msg.kev_subclass = KEV_DL_SUBCLASS;
-
- ev_msg.event_code = KEV_DL_SIFFLAGS;
- strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
- ev_data.if_family = ifp->if_family;
- ev_data.if_unit = (unsigned long) ifp->if_unit;
- ev_msg.dv[0].data_length = sizeof(struct net_event_data);
- ev_msg.dv[0].data_ptr = &ev_data;
- ev_msg.dv[1].data_length = 0;
- kev_post_msg(&ev_msg);
- }
+ /* Send the event even upon error from the driver because we changed the flags */
+ ev_msg.vendor_code = KEV_VENDOR_APPLE;
+ ev_msg.kev_class = KEV_NETWORK_CLASS;
+ ev_msg.kev_subclass = KEV_DL_SUBCLASS;
+
+ ev_msg.event_code = KEV_DL_SIFFLAGS;
+ strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
+ ev_data.if_family = ifp->if_family;
+ ev_data.if_unit = (u_int32_t) ifp->if_unit;
+ ev_msg.dv[0].data_length = sizeof(struct net_event_data);
+ ev_msg.dv[0].data_ptr = &ev_data;
+ ev_msg.dv[1].data_length = 0;
+ kev_post_msg(&ev_msg);
+
ifnet_touch_lastchange(ifp);
break;
ev_msg.event_code = KEV_DL_SIFMETRICS;
strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
ev_data.if_family = ifp->if_family;
- ev_data.if_unit = (unsigned long) ifp->if_unit;
+ ev_data.if_unit = (u_int32_t) ifp->if_unit;
ev_msg.dv[0].data_length = sizeof(struct net_event_data);
ev_msg.dv[0].data_ptr = &ev_data;
ev_msg.event_code = KEV_DL_SIFPHYS;
strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
ev_data.if_family = ifp->if_family;
- ev_data.if_unit = (unsigned long) ifp->if_unit;
+ ev_data.if_unit = (u_int32_t) ifp->if_unit;
ev_msg.dv[0].data_length = sizeof(struct net_event_data);
ev_msg.dv[0].data_ptr = &ev_data;
ev_msg.dv[1].data_length = 0;
case SIOCSIFMTU:
{
- u_long oldmtu = ifp->if_mtu;
+ u_int32_t oldmtu = ifp->if_mtu;
error = proc_suser(p);
if (error)
ev_msg.event_code = KEV_DL_SIFMTU;
strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
ev_data.if_family = ifp->if_family;
- ev_data.if_unit = (unsigned long) ifp->if_unit;
+ ev_data.if_unit = (u_int32_t) ifp->if_unit;
ev_msg.dv[0].data_length = sizeof(struct net_event_data);
ev_msg.dv[0].data_ptr = &ev_data;
ev_msg.dv[1].data_length = 0;
strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
ev_data.if_family = ifp->if_family;
- ev_data.if_unit = (unsigned long) ifp->if_unit;
+ ev_data.if_unit = (u_int32_t) ifp->if_unit;
ev_msg.dv[0].data_length = sizeof(struct net_event_data);
ev_msg.dv[0].data_ptr = &ev_data;
ev_msg.dv[1].data_length = 0;
case SIOCSIFPHYADDR:
case SIOCDIFPHYADDR:
#if INET6
- case SIOCSIFPHYADDR_IN6:
+ case SIOCSIFPHYADDR_IN6_32:
+ case SIOCSIFPHYADDR_IN6_64:
#endif
case SIOCSLIFPHYADDR:
case SIOCSIFMEDIA:
case SIOCGIFPSRCADDR:
case SIOCGIFPDSTADDR:
case SIOCGLIFPHYADDR:
- case SIOCGIFMEDIA:
+ case SIOCGIFMEDIA32:
+ case SIOCGIFMEDIA64:
case SIOCGIFGENERIC:
case SIOCGIFDEVMTU:
return ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family,
return ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family,
cmd, data);
+ case SIOCGIFWAKEFLAGS:
+ ifnet_lock_shared(ifp);
+ ifr->ifr_wake_flags = ifnet_get_wake_flags(ifp);
+ ifnet_lock_done(ifp);
+ break;
+
+ case SIOCGIFGETRTREFCNT:
+#if IFNET_ROUTE_REFCNT
+ ifnet_lock_shared(ifp);
+ ifr->ifr_route_refcnt = ifp->if_route_refcnt;
+ ifnet_lock_done(ifp);
+ break;
+#else
+ return (EOPNOTSUPP);
+#endif /* IFNET_ROUTE_REFCNT */
+
default:
oif_flags = ifp->if_flags;
if (so->so_proto == 0)
continue;
#endif
addrs++;
- if (cmd == OSIOCGIFCONF) {
+ if (cmd == OSIOCGIFCONF32 || cmd == OSIOCGIFCONF64) {
struct osockaddr *osa =
(struct osockaddr *)&ifr.ifr_addr;
ifr.ifr_addr = *sa;
ifma_reference(
struct ifmultiaddr *ifma)
{
- if (OSIncrementAtomic((SInt32 *)&ifma->ifma_refcount) <= 0)
+ if (OSIncrementAtomic(&ifma->ifma_refcount) <= 0)
panic("ifma_reference: ifma already released or invalid\n");
}
{
while (ifma) {
struct ifmultiaddr *next;
- int32_t prevValue = OSDecrementAtomic((SInt32 *)&ifma->ifma_refcount);
+ int32_t prevValue = OSDecrementAtomic(&ifma->ifma_refcount);
if (prevValue < 1)
panic("ifma_release: ifma already released or invalid\n");
if (prevValue != 1)
*
*/
static int
-if_rtdel(
- struct radix_node *rn,
- void *arg)
+if_rtdel(struct radix_node *rn, void *arg)
{
struct rtentry *rt = (struct rtentry *)rn;
struct ifnet *ifp = arg;
int err;
- if (rt != NULL && rt->rt_ifp == ifp) {
-
+ if (rt == NULL)
+ return (0);
+ /*
+ * Checking against RTF_UP protects against walktree
+ * recursion problems with cloned routes.
+ */
+ RT_LOCK(rt);
+ if (rt->rt_ifp == ifp && (rt->rt_flags & RTF_UP)) {
/*
- * Protect (sorta) against walktree recursion problems
- * with cloned routes
+ * Safe to drop rt_lock and use rt_key, rt_gateway,
+ * since holding rnh_lock here prevents another thread
+ * from calling rt_setgate() on this route.
*/
- if ((rt->rt_flags & RTF_UP) == 0)
- return (0);
-
+ RT_UNLOCK(rt);
err = rtrequest_locked(RTM_DELETE, rt_key(rt), rt->rt_gateway,
- rt_mask(rt), rt->rt_flags,
- (struct rtentry **) NULL);
+ rt_mask(rt), rt->rt_flags, NULL);
if (err) {
log(LOG_WARNING, "if_rtdel: error %d\n", err);
}
+ } else {
+ RT_UNLOCK(rt);
}
-
return (0);
}
/*
- * Removes routing table reference to a given interfacei
+ * Removes routing table reference to a given interface
* for a given protocol family
*/
-void if_rtproto_del(struct ifnet *ifp, int protocol)
+void
+if_rtproto_del(struct ifnet *ifp, int protocol)
{
struct radix_node_head *rnh;
- if (use_routegenid)
- route_generation++;
+
+ if (use_routegenid)
+ routegenid_update();
if ((protocol <= AF_MAX) && (protocol >= 0) &&
((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL)) {
- lck_mtx_lock(rt_mtx);
+ lck_mtx_lock(rnh_lock);
(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
- lck_mtx_unlock(rt_mtx);
+ lck_mtx_unlock(rnh_lock);
}
}
struct rtentry *rt = (struct rtentry *)rn;
struct ifnet *ifp = arg;
+ RT_LOCK(rt);
if (rt->rt_ifp == ifp) {
/*
* Update the MTU of this entry only if the MTU
if (!(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_rmx.rmx_mtu)
rt->rt_rmx.rmx_mtu = ifp->if_mtu;
}
+ RT_UNLOCK(rt);
return (0);
}
if ((rnh = rt_tables[p]) == NULL)
continue;
- lck_mtx_lock(rt_mtx);
+ lck_mtx_lock(rnh_lock);
(void) rnh->rnh_walktree(rnh, if_rtmtu, ifp);
- lck_mtx_unlock(rt_mtx);
+ lck_mtx_unlock(rnh_lock);
}
if (use_routegenid)
- route_generation++;
+ routegenid_update();
}
__private_extern__ void
COPYFIELD32(ifi_noproto);
COPYFIELD32(ifi_recvtiming);
COPYFIELD32(ifi_xmittiming);
- COPYFIELD(ifi_lastchange);
+ if_data->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+ if_data->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
lck_mtx_unlock(thread->input_lck);
#if IF_LASTCHANGEUPTIME
COPYFIELD(ifi_noproto);
COPYFIELD(ifi_recvtiming);
COPYFIELD(ifi_xmittiming);
- COPYFIELD(ifi_lastchange);
+ if_data64->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+ if_data64->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
lck_mtx_unlock(thread->input_lck);
#if IF_LASTCHANGEUPTIME
#undef COPYFIELD
}
+
+void
+ifafree(struct ifaddr *ifa)
+{
+ int oldval;
+
+ oldval = OSAddAtomic(-1, &ifa->ifa_refcnt);
+ if (oldval >= 1 && ifa->ifa_trace != NULL)
+ (*ifa->ifa_trace)(ifa, FALSE);
+ if (oldval == 0) {
+ panic("%s: ifa %p negative refcnt\n", __func__, ifa);
+ } else if (oldval == 1) {
+ if (ifa->ifa_debug & IFD_ATTACHED)
+ panic("ifa %p attached to ifp is being freed\n", ifa);
+ /*
+ * Some interface addresses are allocated either statically
+ * or carved out of a larger block; e.g. AppleTalk addresses.
+ * Only free it if it was allocated via MALLOC or via the
+ * corresponding per-address family allocator. Otherwise,
+ * leave it alone.
+ */
+ if (ifa->ifa_debug & IFD_ALLOC) {
+ if (ifa->ifa_free == NULL)
+ FREE(ifa, M_IFADDR);
+ else
+ (*ifa->ifa_free)(ifa);
+ }
+ }
+}
+
+void
+ifaref(struct ifaddr *ifa)
+{
+ int oldval;
+
+ oldval = OSAddAtomic(1, &ifa->ifa_refcnt);
+ if (oldval < 0)
+ panic("%s: ifa %p negative refcnt\n", __func__, ifa);
+ else if (ifa->ifa_trace != NULL)
+ (*ifa->ifa_trace)(ifa, TRUE);
+}