version 1.394, 2017/06/01 02:45:14 |
version 1.394.2.18, 2019/09/24 18:27:09 |
Line 95 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 95 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#if defined(_KERNEL_OPT) |
#if defined(_KERNEL_OPT) |
#include "opt_inet.h" |
#include "opt_inet.h" |
#include "opt_ipsec.h" |
#include "opt_ipsec.h" |
|
|
#include "opt_atalk.h" |
#include "opt_atalk.h" |
#include "opt_natm.h" |
#include "opt_natm.h" |
#include "opt_wlan.h" |
#include "opt_wlan.h" |
#include "opt_net_mpsafe.h" |
#include "opt_net_mpsafe.h" |
|
#include "opt_mrouting.h" |
#endif |
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
Line 209 static int if_transmit(struct ifnet *, s |
|
Line 209 static int if_transmit(struct ifnet *, s |
|
static int if_clone_create(const char *); |
static int if_clone_create(const char *); |
static int if_clone_destroy(const char *); |
static int if_clone_destroy(const char *); |
static void if_link_state_change_si(void *); |
static void if_link_state_change_si(void *); |
|
static void if_up_locked(struct ifnet *); |
|
static void _if_down(struct ifnet *); |
|
static void if_down_deactivated(struct ifnet *); |
|
|
struct if_percpuq { |
struct if_percpuq { |
struct ifnet *ipq_ifp; |
struct ifnet *ipq_ifp; |
|
|
ifinit(void) |
ifinit(void) |
{ |
{ |
|
|
if_sysctl_setup(NULL); |
|
|
|
#if (defined(INET) || defined(INET6)) |
#if (defined(INET) || defined(INET6)) |
encapinit(); |
encapinit(); |
#endif |
#endif |
|
|
void |
void |
ifinit1(void) |
ifinit1(void) |
{ |
{ |
|
|
|
#ifdef NET_MPSAFE |
|
printf("NET_MPSAFE enabled\n"); |
|
#endif |
|
|
mutex_init(&if_clone_mtx, MUTEX_DEFAULT, IPL_NONE); |
mutex_init(&if_clone_mtx, MUTEX_DEFAULT, IPL_NONE); |
|
|
TAILQ_INIT(&ifnet_list); |
TAILQ_INIT(&ifnet_list); |
|
|
#endif |
#endif |
} |
} |
|
|
|
/* XXX must be after domaininit() */ |
|
void |
|
ifinit_post(void) |
|
{ |
|
|
|
if_sysctl_setup(NULL); |
|
} |
|
|
ifnet_t * |
ifnet_t * |
if_alloc(u_char type) |
if_alloc(u_char type) |
{ |
{ |
Line 447 if_dl_create(const struct ifnet *ifp, co |
|
Line 461 if_dl_create(const struct ifnet *ifp, co |
|
addrlen = ifp->if_addrlen; |
addrlen = ifp->if_addrlen; |
socksize = roundup(sockaddr_dl_measure(namelen, addrlen), sizeof(long)); |
socksize = roundup(sockaddr_dl_measure(namelen, addrlen), sizeof(long)); |
ifasize = sizeof(*ifa) + 2 * socksize; |
ifasize = sizeof(*ifa) + 2 * socksize; |
ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK|M_ZERO); |
ifa = malloc(ifasize, M_IFADDR, M_WAITOK|M_ZERO); |
|
|
sdl = (struct sockaddr_dl *)(ifa + 1); |
sdl = (struct sockaddr_dl *)(ifa + 1); |
mask = (struct sockaddr_dl *)(socksize + (char *)sdl); |
mask = (struct sockaddr_dl *)(socksize + (char *)sdl); |
|
|
sockaddr_dl_init(sdl, socksize, ifp->if_index, ifp->if_type, |
sockaddr_dl_init(sdl, socksize, ifp->if_index, ifp->if_type, |
ifp->if_xname, namelen, NULL, addrlen); |
ifp->if_xname, namelen, NULL, addrlen); |
|
mask->sdl_family = AF_LINK; |
mask->sdl_len = sockaddr_dl_measure(namelen, 0); |
mask->sdl_len = sockaddr_dl_measure(namelen, 0); |
memset(&mask->sdl_data[0], 0xff, namelen); |
memset(&mask->sdl_data[0], 0xff, namelen); |
ifa->ifa_rtrequest = link_rtrequest; |
ifa->ifa_rtrequest = link_rtrequest; |
|
|
* ether_ifattach(ifp, enaddr); |
* ether_ifattach(ifp, enaddr); |
* if_register(ifp); |
* if_register(ifp); |
*/ |
*/ |
void |
int |
if_initialize(ifnet_t *ifp) |
if_initialize(ifnet_t *ifp) |
{ |
{ |
|
int rv = 0; |
|
|
KASSERT(if_indexlim > 0); |
KASSERT(if_indexlim > 0); |
TAILQ_INIT(&ifp->if_addrlist); |
TAILQ_INIT(&ifp->if_addrlist); |
|
|
Line 709 if_initialize(ifnet_t *ifp) |
|
Line 726 if_initialize(ifnet_t *ifp) |
|
IF_AFDATA_LOCK_INIT(ifp); |
IF_AFDATA_LOCK_INIT(ifp); |
|
|
if (if_is_link_state_changeable(ifp)) { |
if (if_is_link_state_changeable(ifp)) { |
ifp->if_link_si = softint_establish(SOFTINT_NET, |
u_int flags = SOFTINT_NET; |
|
flags |= if_is_mpsafe(ifp) ? SOFTINT_MPSAFE : 0; |
|
ifp->if_link_si = softint_establish(flags, |
if_link_state_change_si, ifp); |
if_link_state_change_si, ifp); |
if (ifp->if_link_si == NULL) |
if (ifp->if_link_si == NULL) { |
panic("%s: softint_establish() failed", __func__); |
rv = ENOMEM; |
|
goto fail; |
|
} |
} |
} |
|
|
PSLIST_ENTRY_INIT(ifp, if_pslist_entry); |
PSLIST_ENTRY_INIT(ifp, if_pslist_entry); |
Line 721 if_initialize(ifnet_t *ifp) |
|
Line 742 if_initialize(ifnet_t *ifp) |
|
ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
LIST_INIT(&ifp->if_multiaddrs); |
LIST_INIT(&ifp->if_multiaddrs); |
|
|
IFNET_LOCK(); |
IFNET_GLOBAL_LOCK(); |
if_getindex(ifp); |
if_getindex(ifp); |
IFNET_UNLOCK(); |
IFNET_GLOBAL_UNLOCK(); |
|
|
|
return 0; |
|
|
|
fail: |
|
IF_AFDATA_LOCK_DESTROY(ifp); |
|
|
|
pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp); |
|
(void)pfil_head_destroy(ifp->if_pfil); |
|
|
|
IFQ_LOCK_DESTROY(&ifp->if_snd); |
|
|
|
return rv; |
} |
} |
|
|
/* |
/* |
Line 758 if_register(ifnet_t *ifp) |
|
Line 791 if_register(ifnet_t *ifp) |
|
if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) |
if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) |
ifp->if_transmit = if_transmit; |
ifp->if_transmit = if_transmit; |
|
|
IFNET_LOCK(); |
IFNET_GLOBAL_LOCK(); |
TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); |
TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); |
IFNET_WRITER_INSERT_TAIL(ifp); |
IFNET_WRITER_INSERT_TAIL(ifp); |
IFNET_UNLOCK(); |
IFNET_GLOBAL_UNLOCK(); |
} |
} |
|
|
/* |
/* |
Line 811 struct if_percpuq * |
|
Line 844 struct if_percpuq * |
|
if_percpuq_create(struct ifnet *ifp) |
if_percpuq_create(struct ifnet *ifp) |
{ |
{ |
struct if_percpuq *ipq; |
struct if_percpuq *ipq; |
|
u_int flags = SOFTINT_NET; |
|
|
|
flags |= if_is_mpsafe(ifp) ? SOFTINT_MPSAFE : 0; |
|
|
ipq = kmem_zalloc(sizeof(*ipq), KM_SLEEP); |
ipq = kmem_zalloc(sizeof(*ipq), KM_SLEEP); |
ipq->ipq_ifp = ifp; |
ipq->ipq_ifp = ifp; |
ipq->ipq_si = softint_establish(SOFTINT_NET|SOFTINT_MPSAFE, |
ipq->ipq_si = softint_establish(flags, if_percpuq_softint, ipq); |
if_percpuq_softint, ipq); |
|
ipq->ipq_ifqs = percpu_alloc(sizeof(struct ifqueue)); |
ipq->ipq_ifqs = percpu_alloc(sizeof(struct ifqueue)); |
percpu_foreach(ipq->ipq_ifqs, &if_percpuq_init_ifq, NULL); |
percpu_foreach(ipq->ipq_ifqs, &if_percpuq_init_ifq, NULL); |
|
|
|
|
if_deferred_start_init(struct ifnet *ifp, void (*func)(struct ifnet *)) |
if_deferred_start_init(struct ifnet *ifp, void (*func)(struct ifnet *)) |
{ |
{ |
struct if_deferred_start *ids; |
struct if_deferred_start *ids; |
|
u_int flags = SOFTINT_NET; |
|
|
|
flags |= if_is_mpsafe(ifp) ? SOFTINT_MPSAFE : 0; |
|
|
ids = kmem_zalloc(sizeof(*ids), KM_SLEEP); |
ids = kmem_zalloc(sizeof(*ids), KM_SLEEP); |
ids->ids_ifp = ifp; |
ids->ids_ifp = ifp; |
ids->ids_si = softint_establish(SOFTINT_NET|SOFTINT_MPSAFE, |
ids->ids_si = softint_establish(flags, if_deferred_start_softint, ids); |
if_deferred_start_softint, ids); |
|
if (func != NULL) |
if (func != NULL) |
ids->ids_if_start = func; |
ids->ids_if_start = func; |
else |
else |
Line 1094 if_input(struct ifnet *ifp, struct mbuf |
|
Line 1131 if_input(struct ifnet *ifp, struct mbuf |
|
* migrate softint-based if_input without much changes. If you don't |
* migrate softint-based if_input without much changes. If you don't |
* want to enable it, use if_initialize instead. |
* want to enable it, use if_initialize instead. |
*/ |
*/ |
void |
int |
if_attach(ifnet_t *ifp) |
if_attach(ifnet_t *ifp) |
{ |
{ |
|
int rv; |
|
|
|
rv = if_initialize(ifp); |
|
if (rv != 0) |
|
return rv; |
|
|
if_initialize(ifp); |
|
ifp->if_percpuq = if_percpuq_create(ifp); |
ifp->if_percpuq = if_percpuq_create(ifp); |
if_register(ifp); |
if_register(ifp); |
|
|
|
return 0; |
} |
} |
|
|
void |
void |
Line 1284 if_detach(struct ifnet *ifp) |
|
Line 1327 if_detach(struct ifnet *ifp) |
|
s = splnet(); |
s = splnet(); |
|
|
sysctl_teardown(&ifp->if_sysctl_log); |
sysctl_teardown(&ifp->if_sysctl_log); |
mutex_enter(ifp->if_ioctl_lock); |
IFNET_LOCK(ifp); |
if_deactivate(ifp); |
if_deactivate(ifp); |
mutex_exit(ifp->if_ioctl_lock); |
IFNET_UNLOCK(ifp); |
|
|
IFNET_LOCK(); |
|
ifindex2ifnet[ifp->if_index] = NULL; |
|
TAILQ_REMOVE(&ifnet_list, ifp, if_list); |
|
IFNET_WRITER_REMOVE(ifp); |
|
pserialize_perform(ifnet_psz); |
|
IFNET_UNLOCK(); |
|
|
|
/* Wait for all readers to drain before freeing. */ |
|
psref_target_destroy(&ifp->if_psref, ifnet_psref_class); |
|
PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry); |
|
|
|
mutex_obj_free(ifp->if_ioctl_lock); |
|
ifp->if_ioctl_lock = NULL; |
|
|
|
if (ifp->if_slowtimo != NULL && ifp->if_slowtimo_ch != NULL) { |
if (ifp->if_slowtimo != NULL && ifp->if_slowtimo_ch != NULL) { |
ifp->if_slowtimo = NULL; |
ifp->if_slowtimo = NULL; |
Line 1313 if_detach(struct ifnet *ifp) |
|
Line 1342 if_detach(struct ifnet *ifp) |
|
/* |
/* |
* Do an if_down() to give protocols a chance to do something. |
* Do an if_down() to give protocols a chance to do something. |
*/ |
*/ |
if_down(ifp); |
if_down_deactivated(ifp); |
|
|
#ifdef ALTQ |
#ifdef ALTQ |
if (ALTQ_IS_ENABLED(&ifp->if_snd)) |
if (ALTQ_IS_ENABLED(&ifp->if_snd)) |
Line 1322 if_detach(struct ifnet *ifp) |
|
Line 1351 if_detach(struct ifnet *ifp) |
|
altq_detach(&ifp->if_snd); |
altq_detach(&ifp->if_snd); |
#endif |
#endif |
|
|
mutex_obj_free(ifp->if_snd.ifq_lock); |
|
|
|
#if NCARP > 0 |
#if NCARP > 0 |
/* Remove the interface from any carp group it is a part of. */ |
/* Remove the interface from any carp group it is a part of. */ |
if (ifp->if_carp != NULL && ifp->if_type != IFT_CARP) |
if (ifp->if_carp != NULL && ifp->if_type != IFT_CARP) |
Line 1346 if_detach(struct ifnet *ifp) |
|
Line 1373 if_detach(struct ifnet *ifp) |
|
again: |
again: |
/* |
/* |
* At this point, no other one tries to remove ifa in the list, |
* At this point, no other one tries to remove ifa in the list, |
* so we don't need to take a lock or psref. |
* so we don't need to take a lock or psref. Avoid using |
|
* IFADDR_READER_FOREACH to pass over an inspection of contract |
|
* violations of pserialize. |
*/ |
*/ |
IFADDR_READER_FOREACH(ifa, ifp) { |
IFADDR_WRITER_FOREACH(ifa, ifp) { |
family = ifa->ifa_addr->sa_family; |
family = ifa->ifa_addr->sa_family; |
#ifdef IFAREF_DEBUG |
#ifdef IFAREF_DEBUG |
printf("if_detach: ifaddr %p, family %d, refcnt %d\n", |
printf("if_detach: ifaddr %p, family %d, refcnt %d\n", |
|
|
} |
} |
} |
} |
|
|
|
/* Wait for all readers to drain before freeing. */ |
|
IFNET_GLOBAL_LOCK(); |
|
ifindex2ifnet[ifp->if_index] = NULL; |
|
TAILQ_REMOVE(&ifnet_list, ifp, if_list); |
|
IFNET_WRITER_REMOVE(ifp); |
|
pserialize_perform(ifnet_psz); |
|
IFNET_GLOBAL_UNLOCK(); |
|
|
|
psref_target_destroy(&ifp->if_psref, ifnet_psref_class); |
|
PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry); |
|
|
pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp); |
pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp); |
(void)pfil_head_destroy(ifp->if_pfil); |
(void)pfil_head_destroy(ifp->if_pfil); |
|
|
|
|
ifp->if_percpuq = NULL; |
ifp->if_percpuq = NULL; |
} |
} |
|
|
|
mutex_obj_free(ifp->if_ioctl_lock); |
|
ifp->if_ioctl_lock = NULL; |
|
mutex_obj_free(ifp->if_snd.ifq_lock); |
|
|
splx(s); |
splx(s); |
|
|
#ifdef IFAREF_DEBUG |
#ifdef IFAREF_DEBUG |
Line 1557 if_clone_destroy(const char *name) |
|
Line 1601 if_clone_destroy(const char *name) |
|
struct if_clone *ifc; |
struct if_clone *ifc; |
struct ifnet *ifp; |
struct ifnet *ifp; |
struct psref psref; |
struct psref psref; |
|
int error; |
|
int (*if_ioctl)(struct ifnet *, u_long, void *); |
|
|
KASSERT(mutex_owned(&if_clone_mtx)); |
KASSERT(mutex_owned(&if_clone_mtx)); |
|
|
Line 1572 if_clone_destroy(const char *name) |
|
Line 1618 if_clone_destroy(const char *name) |
|
return ENXIO; |
return ENXIO; |
|
|
/* We have to disable ioctls here */ |
/* We have to disable ioctls here */ |
mutex_enter(ifp->if_ioctl_lock); |
IFNET_LOCK(ifp); |
|
if_ioctl = ifp->if_ioctl; |
ifp->if_ioctl = if_nullioctl; |
ifp->if_ioctl = if_nullioctl; |
mutex_exit(ifp->if_ioctl_lock); |
IFNET_UNLOCK(ifp); |
|
|
/* |
/* |
* We cannot call ifc_destroy with holding ifp. |
* We cannot call ifc_destroy with holding ifp. |
Line 1582 if_clone_destroy(const char *name) |
|
Line 1629 if_clone_destroy(const char *name) |
|
*/ |
*/ |
if_put(ifp, &psref); |
if_put(ifp, &psref); |
|
|
return (*ifc->ifc_destroy)(ifp); |
error = (*ifc->ifc_destroy)(ifp); |
|
|
|
if (error != 0) { |
|
/* We have to restore if_ioctl on error */ |
|
IFNET_LOCK(ifp); |
|
ifp->if_ioctl = if_ioctl; |
|
IFNET_UNLOCK(ifp); |
|
} |
|
|
|
return error; |
} |
} |
|
|
static bool |
static bool |
Line 1733 ifa_psref_init(struct ifaddr *ifa) |
|
Line 1789 ifa_psref_init(struct ifaddr *ifa) |
|
void |
void |
ifaref(struct ifaddr *ifa) |
ifaref(struct ifaddr *ifa) |
{ |
{ |
KASSERT(!ISSET(ifa->ifa_flags, IFA_DESTROYING)); |
|
ifa->ifa_refcnt++; |
atomic_inc_uint(&ifa->ifa_refcnt); |
} |
} |
|
|
void |
void |
Line 1743 ifafree(struct ifaddr *ifa) |
|
Line 1799 ifafree(struct ifaddr *ifa) |
|
KASSERT(ifa != NULL); |
KASSERT(ifa != NULL); |
KASSERT(ifa->ifa_refcnt > 0); |
KASSERT(ifa->ifa_refcnt > 0); |
|
|
if (--ifa->ifa_refcnt == 0) { |
if (atomic_dec_uint_nv(&ifa->ifa_refcnt) == 0) { |
free(ifa, M_IFADDR); |
free(ifa, M_IFADDR); |
} |
} |
} |
} |
Line 1761 ifa_insert(struct ifnet *ifp, struct ifa |
|
Line 1817 ifa_insert(struct ifnet *ifp, struct ifa |
|
|
|
ifa->ifa_ifp = ifp; |
ifa->ifa_ifp = ifp; |
|
|
IFNET_LOCK(); |
/* |
|
* Check MP-safety for IFEF_MPSAFE drivers. |
|
* Check !IFF_RUNNING for initialization routines that normally don't |
|
* take IFNET_LOCK but it's safe because there is no competitor. |
|
* XXX there are false positive cases because IFF_RUNNING can be off on |
|
* if_stop. |
|
*/ |
|
KASSERT(!if_is_mpsafe(ifp) || !ISSET(ifp->if_flags, IFF_RUNNING) || |
|
IFNET_LOCKED(ifp)); |
|
|
TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list); |
TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list); |
IFADDR_ENTRY_INIT(ifa); |
IFADDR_ENTRY_INIT(ifa); |
IFADDR_WRITER_INSERT_TAIL(ifp, ifa); |
IFADDR_WRITER_INSERT_TAIL(ifp, ifa); |
IFNET_UNLOCK(); |
|
|
|
ifaref(ifa); |
ifaref(ifa); |
} |
} |
Line 1775 ifa_remove(struct ifnet *ifp, struct ifa |
|
Line 1839 ifa_remove(struct ifnet *ifp, struct ifa |
|
{ |
{ |
|
|
KASSERT(ifa->ifa_ifp == ifp); |
KASSERT(ifa->ifa_ifp == ifp); |
|
/* |
|
* Check MP-safety for IFEF_MPSAFE drivers. |
|
* if_is_deactivated indicates ifa_remove is called form if_detach |
|
* where is safe even if IFNET_LOCK isn't held. |
|
*/ |
|
KASSERT(!if_is_mpsafe(ifp) || if_is_deactivated(ifp) || IFNET_LOCKED(ifp)); |
|
|
IFNET_LOCK(); |
|
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list); |
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list); |
IFADDR_WRITER_REMOVE(ifa); |
IFADDR_WRITER_REMOVE(ifa); |
#ifdef NET_MPSAFE |
#ifdef NET_MPSAFE |
|
IFNET_GLOBAL_LOCK(); |
pserialize_perform(ifnet_psz); |
pserialize_perform(ifnet_psz); |
|
IFNET_GLOBAL_UNLOCK(); |
#endif |
#endif |
IFNET_UNLOCK(); |
|
|
|
#ifdef NET_MPSAFE |
#ifdef NET_MPSAFE |
psref_target_destroy(&ifa->ifa_psref, ifa_psref_class); |
psref_target_destroy(&ifa->ifa_psref, ifa_psref_class); |
Line 2119 link_rtrequest(int cmd, struct rtentry * |
|
Line 2189 link_rtrequest(int cmd, struct rtentry * |
|
struct psref psref; |
struct psref psref; |
|
|
if (cmd != RTM_ADD || (ifa = rt->rt_ifa) == NULL || |
if (cmd != RTM_ADD || (ifa = rt->rt_ifa) == NULL || |
(ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL) |
(ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL || |
|
ISSET(info->rti_flags, RTF_DONTCHANGEIFA)) |
return; |
return; |
if ((ifa = ifaof_ifpforaddr_psref(dst, ifp, &psref)) != NULL) { |
if ((ifa = ifaof_ifpforaddr_psref(dst, ifp, &psref)) != NULL) { |
rt_replace_ifa(rt, ifa); |
rt_replace_ifa(rt, ifa); |
Line 2162 link_rtrequest(int cmd, struct rtentry * |
|
Line 2233 link_rtrequest(int cmd, struct rtentry * |
|
if (LQ_ITEM((q), (i)) == LINK_STATE_UNSET) \ |
if (LQ_ITEM((q), (i)) == LINK_STATE_UNSET) \ |
break; \ |
break; \ |
} |
} |
|
|
|
/* |
|
* XXX reusing (ifp)->if_snd->ifq_lock rather than having another spin mutex |
|
* for each ifnet. It doesn't matter because: |
|
* - if IFEF_MPSAFE is enabled, if_snd isn't used and lock contentions on |
|
* ifq_lock don't happen |
|
* - if IFEF_MPSAFE is disabled, there is no lock contention on ifq_lock |
|
* because if_snd, if_link_state_change and if_link_state_change_softint |
|
* are all called with KERNEL_LOCK |
|
*/ |
|
#define IF_LINK_STATE_CHANGE_LOCK(ifp) \ |
|
mutex_enter((ifp)->if_snd.ifq_lock) |
|
#define IF_LINK_STATE_CHANGE_UNLOCK(ifp) \ |
|
mutex_exit((ifp)->if_snd.ifq_lock) |
|
|
/* |
/* |
* Handle a change in the interface link state and |
* Handle a change in the interface link state and |
* queue notifications. |
* queue notifications. |
Line 2169 link_rtrequest(int cmd, struct rtentry * |
|
Line 2255 link_rtrequest(int cmd, struct rtentry * |
|
void |
void |
if_link_state_change(struct ifnet *ifp, int link_state) |
if_link_state_change(struct ifnet *ifp, int link_state) |
{ |
{ |
int s, idx; |
int idx; |
|
|
KASSERTMSG(if_is_link_state_changeable(ifp), |
KASSERTMSG(if_is_link_state_changeable(ifp), |
"%s: IFEF_NO_LINK_STATE_CHANGE must not be set, but if_extflags=0x%x", |
"%s: IFEF_NO_LINK_STATE_CHANGE must not be set, but if_extflags=0x%x", |
Line 2189 if_link_state_change(struct ifnet *ifp, |
|
Line 2275 if_link_state_change(struct ifnet *ifp, |
|
return; |
return; |
} |
} |
|
|
s = splnet(); |
IF_LINK_STATE_CHANGE_LOCK(ifp); |
|
|
/* Find the last unset event in the queue. */ |
/* Find the last unset event in the queue. */ |
LQ_FIND_UNSET(ifp->if_link_queue, idx); |
LQ_FIND_UNSET(ifp->if_link_queue, idx); |
Line 2233 if_link_state_change(struct ifnet *ifp, |
|
Line 2319 if_link_state_change(struct ifnet *ifp, |
|
softint_schedule(ifp->if_link_si); |
softint_schedule(ifp->if_link_si); |
|
|
out: |
out: |
splx(s); |
IF_LINK_STATE_CHANGE_UNLOCK(ifp); |
} |
} |
|
|
/* |
/* |
Line 2244 if_link_state_change_softint(struct ifne |
|
Line 2330 if_link_state_change_softint(struct ifne |
|
{ |
{ |
struct domain *dp; |
struct domain *dp; |
int s = splnet(); |
int s = splnet(); |
|
bool notify; |
|
|
KASSERT(!cpu_intr_p()); |
KASSERT(!cpu_intr_p()); |
|
|
|
IF_LINK_STATE_CHANGE_LOCK(ifp); |
|
|
/* Ensure the change is still valid. */ |
/* Ensure the change is still valid. */ |
if (ifp->if_link_state == link_state) { |
if (ifp->if_link_state == link_state) { |
|
IF_LINK_STATE_CHANGE_UNLOCK(ifp); |
splx(s); |
splx(s); |
return; |
return; |
} |
} |
Line 2272 if_link_state_change_softint(struct ifne |
|
Line 2362 if_link_state_change_softint(struct ifne |
|
* listeners would have an address and expect it to work right |
* listeners would have an address and expect it to work right |
* away. |
* away. |
*/ |
*/ |
if (link_state == LINK_STATE_UP && |
notify = (link_state == LINK_STATE_UP && |
ifp->if_link_state == LINK_STATE_UNKNOWN) |
ifp->if_link_state == LINK_STATE_UNKNOWN); |
{ |
ifp->if_link_state = link_state; |
|
/* The following routines may sleep so release the spin mutex */ |
|
IF_LINK_STATE_CHANGE_UNLOCK(ifp); |
|
|
|
KERNEL_LOCK_UNLESS_NET_MPSAFE(); |
|
if (notify) { |
DOMAIN_FOREACH(dp) { |
DOMAIN_FOREACH(dp) { |
if (dp->dom_if_link_state_change != NULL) |
if (dp->dom_if_link_state_change != NULL) |
dp->dom_if_link_state_change(ifp, |
dp->dom_if_link_state_change(ifp, |
Line 2282 if_link_state_change_softint(struct ifne |
|
Line 2377 if_link_state_change_softint(struct ifne |
|
} |
} |
} |
} |
|
|
ifp->if_link_state = link_state; |
|
|
|
/* Notify that the link state has changed. */ |
/* Notify that the link state has changed. */ |
rt_ifmsg(ifp); |
rt_ifmsg(ifp); |
|
|
Line 2296 if_link_state_change_softint(struct ifne |
|
Line 2389 if_link_state_change_softint(struct ifne |
|
if (dp->dom_if_link_state_change != NULL) |
if (dp->dom_if_link_state_change != NULL) |
dp->dom_if_link_state_change(ifp, link_state); |
dp->dom_if_link_state_change(ifp, link_state); |
} |
} |
|
KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); |
splx(s); |
splx(s); |
} |
} |
|
|
Line 2308 if_link_state_change_si(void *arg) |
|
Line 2402 if_link_state_change_si(void *arg) |
|
struct ifnet *ifp = arg; |
struct ifnet *ifp = arg; |
int s; |
int s; |
uint8_t state; |
uint8_t state; |
|
bool schedule; |
|
|
#ifndef NET_MPSAFE |
SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); |
mutex_enter(softnet_lock); |
|
KERNEL_LOCK(1, NULL); |
|
#endif |
|
s = splnet(); |
s = splnet(); |
|
|
/* Pop a link state change from the queue and process it. */ |
/* Pop a link state change from the queue and process it. */ |
|
IF_LINK_STATE_CHANGE_LOCK(ifp); |
LQ_POP(ifp->if_link_queue, state); |
LQ_POP(ifp->if_link_queue, state); |
|
IF_LINK_STATE_CHANGE_UNLOCK(ifp); |
|
|
if_link_state_change_softint(ifp, state); |
if_link_state_change_softint(ifp, state); |
|
|
/* If there is a link state change to come, schedule it. */ |
/* If there is a link state change to come, schedule it. */ |
if (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET) |
IF_LINK_STATE_CHANGE_LOCK(ifp); |
|
schedule = (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET); |
|
IF_LINK_STATE_CHANGE_UNLOCK(ifp); |
|
if (schedule) |
softint_schedule(ifp->if_link_si); |
softint_schedule(ifp->if_link_si); |
|
|
splx(s); |
splx(s); |
#ifndef NET_MPSAFE |
SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); |
KERNEL_UNLOCK_ONE(NULL); |
|
mutex_exit(softnet_lock); |
|
#endif |
|
} |
} |
|
|
/* |
/* |
Line 2349 p2p_rtrequest(int req, struct rtentry *r |
|
Line 2444 p2p_rtrequest(int req, struct rtentry *r |
|
|
|
rt->rt_ifp = lo0ifp; |
rt->rt_ifp = lo0ifp; |
|
|
|
if (ISSET(info->rti_flags, RTF_DONTCHANGEIFA)) |
|
break; |
|
|
IFADDR_READER_FOREACH(ifa, ifp) { |
IFADDR_READER_FOREACH(ifa, ifp) { |
if (equal(rt_getkey(rt), ifa->ifa_addr)) |
if (equal(rt_getkey(rt), ifa->ifa_addr)) |
break; |
break; |
Line 2382 p2p_rtrequest(int req, struct rtentry *r |
|
Line 2480 p2p_rtrequest(int req, struct rtentry *r |
|
pserialize_read_exit(s); |
pserialize_read_exit(s); |
} |
} |
|
|
/* |
static void |
* Mark an interface down and notify protocols of |
_if_down(struct ifnet *ifp) |
* the transition. |
|
* NOTE: must be called at splsoftnet or equivalent. |
|
*/ |
|
void |
|
if_down(struct ifnet *ifp) |
|
{ |
{ |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
struct domain *dp; |
struct domain *dp; |
Line 2424 if_down(struct ifnet *ifp) |
|
Line 2517 if_down(struct ifnet *ifp) |
|
} |
} |
} |
} |
|
|
|
static void |
|
if_down_deactivated(struct ifnet *ifp) |
|
{ |
|
|
|
KASSERT(if_is_deactivated(ifp)); |
|
_if_down(ifp); |
|
} |
|
|
|
void |
|
if_down_locked(struct ifnet *ifp) |
|
{ |
|
|
|
KASSERT(IFNET_LOCKED(ifp)); |
|
_if_down(ifp); |
|
} |
|
|
/* |
/* |
* Mark an interface up and notify protocols of |
* Mark an interface down and notify protocols of |
* the transition. |
* the transition. |
* NOTE: must be called at splsoftnet or equivalent. |
* NOTE: must be called at splsoftnet or equivalent. |
*/ |
*/ |
void |
void |
if_up(struct ifnet *ifp) |
if_down(struct ifnet *ifp) |
|
{ |
|
|
|
IFNET_LOCK(ifp); |
|
if_down_locked(ifp); |
|
IFNET_UNLOCK(ifp); |
|
} |
|
|
|
/* |
|
* Must be called with holding if_ioctl_lock. |
|
*/ |
|
static void |
|
if_up_locked(struct ifnet *ifp) |
{ |
{ |
#ifdef notyet |
#ifdef notyet |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
#endif |
#endif |
struct domain *dp; |
struct domain *dp; |
|
|
|
KASSERT(IFNET_LOCKED(ifp)); |
|
|
|
KASSERT(!if_is_deactivated(ifp)); |
ifp->if_flags |= IFF_UP; |
ifp->if_flags |= IFF_UP; |
nanotime(&ifp->if_lastchange); |
nanotime(&ifp->if_lastchange); |
#ifdef notyet |
#ifdef notyet |
Line 2482 if_slowtimo(void *arg) |
|
Line 2606 if_slowtimo(void *arg) |
|
} |
} |
|
|
/* |
/* |
|
* Mark an interface up and notify protocols of |
|
* the transition. |
|
* NOTE: must be called at splsoftnet or equivalent. |
|
*/ |
|
void |
|
if_up(struct ifnet *ifp) |
|
{ |
|
|
|
IFNET_LOCK(ifp); |
|
if_up_locked(ifp); |
|
IFNET_UNLOCK(ifp); |
|
} |
|
|
|
/* |
* Set/clear promiscuous mode on interface ifp based on the truth value |
* Set/clear promiscuous mode on interface ifp based on the truth value |
* of pswitch. The calls are reference counted so that only the first |
* of pswitch. The calls are reference counted so that only the first |
* "on" request actually has an effect, as does the final "off" request. |
* "on" request actually has an effect, as does the final "off" request. |
* Results are undefined if the "off" and "on" requests are not matched. |
* Results are undefined if the "off" and "on" requests are not matched. |
*/ |
*/ |
int |
int |
ifpromisc(struct ifnet *ifp, int pswitch) |
ifpromisc_locked(struct ifnet *ifp, int pswitch) |
{ |
{ |
int pcount, ret; |
int pcount, ret = 0; |
short nflags; |
short nflags; |
|
|
|
KASSERT(IFNET_LOCKED(ifp)); |
|
|
pcount = ifp->if_pcount; |
pcount = ifp->if_pcount; |
if (pswitch) { |
if (pswitch) { |
/* |
/* |
Line 2501 ifpromisc(struct ifnet *ifp, int pswitch |
|
Line 2641 ifpromisc(struct ifnet *ifp, int pswitch |
|
* consult IFF_PROMISC when it is brought up. |
* consult IFF_PROMISC when it is brought up. |
*/ |
*/ |
if (ifp->if_pcount++ != 0) |
if (ifp->if_pcount++ != 0) |
return 0; |
goto out; |
nflags = ifp->if_flags | IFF_PROMISC; |
nflags = ifp->if_flags | IFF_PROMISC; |
} else { |
} else { |
if (--ifp->if_pcount > 0) |
if (--ifp->if_pcount > 0) |
return 0; |
goto out; |
nflags = ifp->if_flags & ~IFF_PROMISC; |
nflags = ifp->if_flags & ~IFF_PROMISC; |
} |
} |
ret = if_flags_set(ifp, nflags); |
ret = if_flags_set(ifp, nflags); |
Line 2513 ifpromisc(struct ifnet *ifp, int pswitch |
|
Line 2653 ifpromisc(struct ifnet *ifp, int pswitch |
|
if (ret != 0) { |
if (ret != 0) { |
ifp->if_pcount = pcount; |
ifp->if_pcount = pcount; |
} |
} |
|
out: |
return ret; |
return ret; |
} |
} |
|
|
|
int |
|
ifpromisc(struct ifnet *ifp, int pswitch) |
|
{ |
|
int e; |
|
|
|
IFNET_LOCK(ifp); |
|
e = ifpromisc_locked(ifp, pswitch); |
|
IFNET_UNLOCK(ifp); |
|
|
|
return e; |
|
} |
|
|
/* |
/* |
* Map interface name to |
* Map interface name to |
* interface structure pointer. |
* interface structure pointer. |
|
|
} |
} |
|
|
/* |
/* |
* Release a reference of an ifnet object given by if_get or |
* Release a reference of an ifnet object given by if_get, if_get_byindex |
* if_get_byindex. |
* or if_get_bylla. |
*/ |
*/ |
void |
void |
if_put(const struct ifnet *ifp, struct psref *psref) |
if_put(const struct ifnet *ifp, struct psref *psref) |
Line 2612 if_put(const struct ifnet *ifp, struct p |
|
Line 2765 if_put(const struct ifnet *ifp, struct p |
|
psref_release(psref, &ifp->if_psref, ifnet_psref_class); |
psref_release(psref, &ifp->if_psref, ifnet_psref_class); |
} |
} |
|
|
|
/* |
|
* Return ifp having idx. Return NULL if not found. Normally if_byindex |
|
* should be used. |
|
*/ |
|
ifnet_t * |
|
_if_byindex(u_int idx) |
|
{ |
|
|
|
return (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL; |
|
} |
|
|
|
/* |
|
* Return ifp having idx. Return NULL if not found or the found ifp is |
|
* already deactivated. |
|
*/ |
ifnet_t * |
ifnet_t * |
if_byindex(u_int idx) |
if_byindex(u_int idx) |
{ |
{ |
ifnet_t *ifp; |
ifnet_t *ifp; |
|
|
ifp = (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL; |
ifp = _if_byindex(idx); |
if (ifp != NULL && if_is_deactivated(ifp)) |
if (ifp != NULL && if_is_deactivated(ifp)) |
ifp = NULL; |
ifp = NULL; |
return ifp; |
return ifp; |
Line 2643 if_get_byindex(u_int idx, struct psref * |
|
Line 2811 if_get_byindex(u_int idx, struct psref * |
|
return ifp; |
return ifp; |
} |
} |
|
|
|
ifnet_t * |
|
if_get_bylla(const void *lla, unsigned char lla_len, struct psref *psref) |
|
{ |
|
ifnet_t *ifp; |
|
int s; |
|
|
|
s = pserialize_read_enter(); |
|
IFNET_READER_FOREACH(ifp) { |
|
if (if_is_deactivated(ifp)) |
|
continue; |
|
if (ifp->if_addrlen != lla_len) |
|
continue; |
|
if (memcmp(lla, CLLADDR(ifp->if_sadl), lla_len) == 0) { |
|
psref_acquire(psref, &ifp->if_psref, |
|
ifnet_psref_class); |
|
break; |
|
} |
|
} |
|
pserialize_read_exit(s); |
|
|
|
return ifp; |
|
} |
|
|
/* |
/* |
* Note that it's safe only if the passed ifp is guaranteed to not be freed, |
* Note that it's safe only if the passed ifp is guaranteed to not be freed, |
* for example using pserialize or the ifp is already held or some other |
* for example using pserialize or the ifp is already held or some other |
Line 2663 if_held(struct ifnet *ifp) |
|
Line 2854 if_held(struct ifnet *ifp) |
|
return psref_held(&ifp->if_psref, ifnet_psref_class); |
return psref_held(&ifp->if_psref, ifnet_psref_class); |
} |
} |
|
|
|
/* |
|
* Some tunnel interfaces can nest, e.g. IPv4 over IPv4 gif(4) tunnel over IPv4. |
|
* Check the tunnel nesting count. |
|
* Return > 0, if tunnel nesting count is more than limit. |
|
* Return 0, if tunnel nesting count is equal or less than limit. |
|
*/ |
|
int |
|
if_tunnel_check_nesting(struct ifnet *ifp, struct mbuf *m, int limit) |
|
{ |
|
struct m_tag *mtag; |
|
int *count; |
|
|
|
mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL); |
|
if (mtag != NULL) { |
|
count = (int *)(mtag + 1); |
|
if (++(*count) > limit) { |
|
log(LOG_NOTICE, |
|
"%s: recursively called too many times(%d)\n", |
|
ifp->if_xname, *count); |
|
return EIO; |
|
} |
|
} else { |
|
mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count), |
|
M_NOWAIT); |
|
if (mtag != NULL) { |
|
m_tag_prepend(m, mtag); |
|
count = (int *)(mtag + 1); |
|
*count = 0; |
|
} else { |
|
log(LOG_DEBUG, |
|
"%s: m_tag_get() failed, recursion calls are not prevented.\n", |
|
ifp->if_xname); |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static void |
|
if_tunnel_ro_init_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) |
|
{ |
|
struct tunnel_ro *tro = p; |
|
|
|
tro->tr_ro = kmem_zalloc(sizeof(*tro->tr_ro), KM_SLEEP); |
|
tro->tr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
|
} |
|
|
|
percpu_t * |
|
if_tunnel_alloc_ro_percpu(void) |
|
{ |
|
percpu_t *ro_percpu; |
|
|
|
ro_percpu = percpu_alloc(sizeof(struct tunnel_ro)); |
|
percpu_foreach(ro_percpu, if_tunnel_ro_init_pc, NULL); |
|
|
|
return ro_percpu; |
|
} |
|
|
|
static void |
|
if_tunnel_ro_fini_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) |
|
{ |
|
struct tunnel_ro *tro = p; |
|
|
|
rtcache_free(tro->tr_ro); |
|
kmem_free(tro->tr_ro, sizeof(*tro->tr_ro)); |
|
|
|
mutex_obj_free(tro->tr_lock); |
|
} |
|
|
|
void |
|
if_tunnel_free_ro_percpu(percpu_t *ro_percpu) |
|
{ |
|
|
|
percpu_foreach(ro_percpu, if_tunnel_ro_fini_pc, NULL); |
|
percpu_free(ro_percpu, sizeof(struct tunnel_ro)); |
|
} |
|
|
|
|
|
static void |
|
if_tunnel_rtcache_free_pc(void *p, void *arg __unused, struct cpu_info *ci __unused) |
|
{ |
|
struct tunnel_ro *tro = p; |
|
|
|
mutex_enter(tro->tr_lock); |
|
rtcache_free(tro->tr_ro); |
|
mutex_exit(tro->tr_lock); |
|
} |
|
|
|
void if_tunnel_ro_percpu_rtcache_free(percpu_t *ro_percpu) |
|
{ |
|
|
|
percpu_foreach(ro_percpu, if_tunnel_rtcache_free_pc, NULL); |
|
} |
|
|
|
|
/* common */ |
/* common */ |
int |
int |
Line 2726 ifioctl_common(struct ifnet *ifp, u_long |
|
Line 3011 ifioctl_common(struct ifnet *ifp, u_long |
|
return 0; |
return 0; |
case SIOCSIFFLAGS: |
case SIOCSIFFLAGS: |
ifr = data; |
ifr = data; |
|
/* |
|
* If if_is_mpsafe(ifp), KERNEL_LOCK isn't held here, but if_up |
|
* and if_down aren't MP-safe yet, so we must hold the lock. |
|
*/ |
|
KERNEL_LOCK_IF_IFP_MPSAFE(ifp); |
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { |
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { |
s = splsoftnet(); |
s = splsoftnet(); |
if_down(ifp); |
if_down_locked(ifp); |
splx(s); |
splx(s); |
} |
} |
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { |
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { |
s = splsoftnet(); |
s = splsoftnet(); |
if_up(ifp); |
if_up_locked(ifp); |
splx(s); |
splx(s); |
} |
} |
|
KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp); |
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | |
(ifr->ifr_flags &~ IFF_CANTCHANGE); |
(ifr->ifr_flags &~ IFF_CANTCHANGE); |
break; |
break; |
Line 2807 ifioctl_common(struct ifnet *ifp, u_long |
|
Line 3098 ifioctl_common(struct ifnet *ifp, u_long |
|
* If the link MTU changed, do network layer specific procedure. |
* If the link MTU changed, do network layer specific procedure. |
*/ |
*/ |
#ifdef INET6 |
#ifdef INET6 |
|
KERNEL_LOCK_UNLESS_NET_MPSAFE(); |
if (in6_present) |
if (in6_present) |
nd6_setmtu(ifp); |
nd6_setmtu(ifp); |
|
KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); |
#endif |
#endif |
return ENETRESET; |
return ENETRESET; |
default: |
default: |
Line 2952 doifioctl(struct socket *so, u_long cmd, |
|
Line 3245 doifioctl(struct socket *so, u_long cmd, |
|
return error; |
return error; |
} |
} |
} |
} |
|
KERNEL_LOCK_UNLESS_NET_MPSAFE(); |
mutex_enter(&if_clone_mtx); |
mutex_enter(&if_clone_mtx); |
r = (cmd == SIOCIFCREATE) ? |
r = (cmd == SIOCIFCREATE) ? |
if_clone_create(ifr->ifr_name) : |
if_clone_create(ifr->ifr_name) : |
if_clone_destroy(ifr->ifr_name); |
if_clone_destroy(ifr->ifr_name); |
mutex_exit(&if_clone_mtx); |
mutex_exit(&if_clone_mtx); |
|
KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); |
curlwp_bindx(bound); |
curlwp_bindx(bound); |
return r; |
return r; |
|
|
Line 3014 doifioctl(struct socket *so, u_long cmd, |
|
Line 3309 doifioctl(struct socket *so, u_long cmd, |
|
|
|
oif_flags = ifp->if_flags; |
oif_flags = ifp->if_flags; |
|
|
mutex_enter(ifp->if_ioctl_lock); |
KERNEL_LOCK_UNLESS_IFP_MPSAFE(ifp); |
|
IFNET_LOCK(ifp); |
|
|
error = (*ifp->if_ioctl)(ifp, cmd, data); |
error = (*ifp->if_ioctl)(ifp, cmd, data); |
if (error != ENOTTY) |
if (error != ENOTTY) |
Line 3022 doifioctl(struct socket *so, u_long cmd, |
|
Line 3318 doifioctl(struct socket *so, u_long cmd, |
|
else if (so->so_proto == NULL) |
else if (so->so_proto == NULL) |
error = EOPNOTSUPP; |
error = EOPNOTSUPP; |
else { |
else { |
|
KERNEL_LOCK_IF_IFP_MPSAFE(ifp); |
#ifdef COMPAT_OSOCK |
#ifdef COMPAT_OSOCK |
if (vec_compat_ifioctl != NULL) |
if (vec_compat_ifioctl != NULL) |
error = (*vec_compat_ifioctl)(so, ocmd, cmd, data, l); |
error = (*vec_compat_ifioctl)(so, ocmd, cmd, data, l); |
Line 3029 doifioctl(struct socket *so, u_long cmd, |
|
Line 3326 doifioctl(struct socket *so, u_long cmd, |
|
#endif |
#endif |
error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so, |
error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so, |
cmd, data, ifp); |
cmd, data, ifp); |
|
KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp); |
} |
} |
|
|
if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) { |
if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) { |
if ((ifp->if_flags & IFF_UP) != 0) { |
if ((ifp->if_flags & IFF_UP) != 0) { |
int s = splsoftnet(); |
int s = splsoftnet(); |
if_up(ifp); |
if_up_locked(ifp); |
splx(s); |
splx(s); |
} |
} |
} |
} |
Line 3043 doifioctl(struct socket *so, u_long cmd, |
|
Line 3341 doifioctl(struct socket *so, u_long cmd, |
|
ifreqn2o(oifr, ifr); |
ifreqn2o(oifr, ifr); |
#endif |
#endif |
|
|
mutex_exit(ifp->if_ioctl_lock); |
IFNET_UNLOCK(ifp); |
|
KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(ifp); |
out: |
out: |
if_put(ifp, &psref); |
if_put(ifp, &psref); |
curlwp_bindx(bound); |
curlwp_bindx(bound); |
Line 3093 ifconf(u_long cmd, void *data) |
|
Line 3392 ifconf(u_long cmd, void *data) |
|
int bound; |
int bound; |
struct psref psref; |
struct psref psref; |
|
|
|
memset(&ifr, 0, sizeof(ifr)); |
if (docopy) { |
if (docopy) { |
space = ifc->ifc_len; |
space = ifc->ifc_len; |
ifrp = ifc->ifc_req; |
ifrp = ifc->ifc_req; |
Line 3115 ifconf(u_long cmd, void *data) |
|
Line 3415 ifconf(u_long cmd, void *data) |
|
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); |
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); |
if (!docopy) { |
if (!docopy) { |
space += sz; |
space += sz; |
continue; |
goto next; |
} |
} |
if (space >= sz) { |
if (space >= sz) { |
error = copyout(&ifr, ifrp, sz); |
error = copyout(&ifr, ifrp, sz); |
Line 3126 ifconf(u_long cmd, void *data) |
|
Line 3426 ifconf(u_long cmd, void *data) |
|
} |
} |
} |
} |
|
|
|
s = pserialize_read_enter(); |
IFADDR_READER_FOREACH(ifa, ifp) { |
IFADDR_READER_FOREACH(ifa, ifp) { |
struct sockaddr *sa = ifa->ifa_addr; |
struct sockaddr *sa = ifa->ifa_addr; |
/* all sockaddrs must fit in sockaddr_storage */ |
/* all sockaddrs must fit in sockaddr_storage */ |
Line 3136 ifconf(u_long cmd, void *data) |
|
Line 3437 ifconf(u_long cmd, void *data) |
|
continue; |
continue; |
} |
} |
memcpy(&ifr.ifr_space, sa, sa->sa_len); |
memcpy(&ifr.ifr_space, sa, sa->sa_len); |
|
pserialize_read_exit(s); |
|
|
if (space >= sz) { |
if (space >= sz) { |
error = copyout(&ifr, ifrp, sz); |
error = copyout(&ifr, ifrp, sz); |
if (error != 0) |
if (error != 0) |
goto release_exit; |
goto release_exit; |
ifrp++; space -= sz; |
ifrp++; space -= sz; |
} |
} |
|
s = pserialize_read_enter(); |
} |
} |
|
pserialize_read_exit(s); |
|
|
|
next: |
s = pserialize_read_enter(); |
s = pserialize_read_enter(); |
psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
} |
} |
Line 3294 if_addr_init(ifnet_t *ifp, struct ifaddr |
|
Line 3600 if_addr_init(ifnet_t *ifp, struct ifaddr |
|
{ |
{ |
int rc; |
int rc; |
|
|
|
KASSERT(IFNET_LOCKED(ifp)); |
if (ifp->if_initaddr != NULL) |
if (ifp->if_initaddr != NULL) |
rc = (*ifp->if_initaddr)(ifp, ifa, src); |
rc = (*ifp->if_initaddr)(ifp, ifa, src); |
else if (src || |
else if (src || |
/* FIXME: may not hold if_ioctl_lock */ |
|
(rc = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY) |
(rc = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY) |
rc = (*ifp->if_ioctl)(ifp, SIOCINITIFADDR, ifa); |
rc = (*ifp->if_ioctl)(ifp, SIOCINITIFADDR, ifa); |
|
|
Line 3342 if_flags_set(ifnet_t *ifp, const short f |
|
Line 3648 if_flags_set(ifnet_t *ifp, const short f |
|
{ |
{ |
int rc; |
int rc; |
|
|
|
KASSERT(IFNET_LOCKED(ifp)); |
|
|
if (ifp->if_setflags != NULL) |
if (ifp->if_setflags != NULL) |
rc = (*ifp->if_setflags)(ifp, flags); |
rc = (*ifp->if_setflags)(ifp, flags); |
else { |
else { |
Line 3364 if_flags_set(ifnet_t *ifp, const short f |
|
Line 3672 if_flags_set(ifnet_t *ifp, const short f |
|
memset(&ifr, 0, sizeof(ifr)); |
memset(&ifr, 0, sizeof(ifr)); |
|
|
ifr.ifr_flags = flags & ~IFF_CANTCHANGE; |
ifr.ifr_flags = flags & ~IFF_CANTCHANGE; |
/* FIXME: may not hold if_ioctl_lock */ |
|
rc = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr); |
rc = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr); |
|
|
if (rc != 0 && cantflags != 0) |
if (rc != 0 && cantflags != 0) |
Line 3380 if_mcast_op(ifnet_t *ifp, const unsigned |
|
Line 3687 if_mcast_op(ifnet_t *ifp, const unsigned |
|
int rc; |
int rc; |
struct ifreq ifr; |
struct ifreq ifr; |
|
|
|
/* There remain some paths that don't hold IFNET_LOCK yet */ |
|
#ifdef NET_MPSAFE |
|
/* CARP and MROUTING still don't deal with the lock yet */ |
|
#if (!defined(NCARP) || (NCARP == 0)) && !defined(MROUTING) |
|
KASSERT(IFNET_LOCKED(ifp)); |
|
#endif |
|
#endif |
if (ifp->if_mcastop != NULL) |
if (ifp->if_mcastop != NULL) |
rc = (*ifp->if_mcastop)(ifp, cmd, sa); |
rc = (*ifp->if_mcastop)(ifp, cmd, sa); |
else { |
else { |