Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_vlan.c
Show First 20 Lines • Show All 226 Lines • ▼ Show 20 Lines | |||||
#define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) | #define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) | ||||
#define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) | #define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) | ||||
#define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) | #define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) | ||||
#define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) | #define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) | ||||
#define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) | #define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) | ||||
#define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) | #define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) | ||||
#define VLAN_SXLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_LOCKED) | #define VLAN_SXLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_LOCKED) | ||||
/* | /* | ||||
* We also have a per-trunk mutex that should be acquired when changing | * We also have a per-trunk mutex that should be acquired when changing | ||||
* its state. | * its state. | ||||
*/ | */ | ||||
#define TRUNK_LOCK_INIT(trunk) mtx_init(&(trunk)->lock, vlanname, NULL, MTX_DEF) | #define TRUNK_LOCK_INIT(trunk) mtx_init(&(trunk)->lock, vlanname, NULL, MTX_DEF) | ||||
#define TRUNK_LOCK_DESTROY(trunk) mtx_destroy(&(trunk)->lock) | #define TRUNK_LOCK_DESTROY(trunk) mtx_destroy(&(trunk)->lock) | ||||
#define TRUNK_WLOCK(trunk) mtx_lock(&(trunk)->lock) | #define TRUNK_WLOCK(trunk) mtx_lock(&(trunk)->lock) | ||||
#define TRUNK_WUNLOCK(trunk) mtx_unlock(&(trunk)->lock) | #define TRUNK_WUNLOCK(trunk) mtx_unlock(&(trunk)->lock) | ||||
#define TRUNK_LOCK_ASSERT(trunk) MPASS(in_epoch(net_epoch_preempt) || mtx_owned(&(trunk)->lock)) | |||||
#define TRUNK_WLOCK_ASSERT(trunk) mtx_assert(&(trunk)->lock, MA_OWNED); | #define TRUNK_WLOCK_ASSERT(trunk) mtx_assert(&(trunk)->lock, MA_OWNED); | ||||
/* | /* | ||||
* The VLAN_ARRAY substitutes the dynamic hash with a static array | * The VLAN_ARRAY substitutes the dynamic hash with a static array | ||||
* with 4096 entries. In theory this can give a boost in processing, | * with 4096 entries. In theory this can give a boost in processing, | ||||
* however in practice it does not. Probably this is because the array | * however in practice it does not. Probably this is because the array | ||||
* is too big to fit into CPU cache. | * is too big to fit into CPU cache. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 426 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Return the trunk device for a virtual interface. | * Return the trunk device for a virtual interface. | ||||
*/ | */ | ||||
static struct ifnet * | static struct ifnet * | ||||
vlan_trunkdev(struct ifnet *ifp) | vlan_trunkdev(struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
NET_EPOCH_ASSERT(); | |||||
if (ifp->if_type != IFT_L2VLAN) | if (ifp->if_type != IFT_L2VLAN) | ||||
return (NULL); | return (NULL); | ||||
NET_EPOCH_ENTER(et); | |||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
ifp = NULL; | ifp = NULL; | ||||
if (ifv->ifv_trunk) | if (ifv->ifv_trunk) | ||||
ifp = PARENT(ifv); | ifp = PARENT(ifv); | ||||
NET_EPOCH_EXIT(et); | |||||
return (ifp); | return (ifp); | ||||
} | } | ||||
/* | /* | ||||
* Return the 12-bit VLAN VID for this interface, for use by external | * Return the 12-bit VLAN VID for this interface, for use by external | ||||
* components such as Infiniband. | * components such as Infiniband. | ||||
* | * | ||||
* XXXRW: Note that the function name here is historical; it should be named | * XXXRW: Note that the function name here is historical; it should be named | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Return the vlan device present at the specific VID. | * Return the vlan device present at the specific VID. | ||||
*/ | */ | ||||
static struct ifnet * | static struct ifnet * | ||||
vlan_devat(struct ifnet *ifp, uint16_t vid) | vlan_devat(struct ifnet *ifp, uint16_t vid) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ASSERT(); | ||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) | ||||
NET_EPOCH_EXIT(et); | |||||
return (NULL); | return (NULL); | ||||
} | |||||
ifp = NULL; | ifp = NULL; | ||||
ifv = vlan_gethash(trunk, vid); | ifv = vlan_gethash(trunk, vid); | ||||
if (ifv) | if (ifv) | ||||
ifp = ifv->ifv_ifp; | ifp = ifv->ifv_ifp; | ||||
NET_EPOCH_EXIT(et); | |||||
return (ifp); | return (ifp); | ||||
} | } | ||||
/* | /* | ||||
* Recalculate the cached VLAN tag exposed via the MIB. | * Recalculate the cached VLAN tag exposed via the MIB. | ||||
*/ | */ | ||||
static void | static void | ||||
vlan_tag_recalculate(struct ifvlan *ifv) | vlan_tag_recalculate(struct ifvlan *ifv) | ||||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* The if_transmit method for vlan(4) interface. | * The if_transmit method for vlan(4) interface. | ||||
*/ | */ | ||||
static int | static int | ||||
vlan_transmit(struct ifnet *ifp, struct mbuf *m) | vlan_transmit(struct ifnet *ifp, struct mbuf *m) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
struct ifnet *p; | struct ifnet *p; | ||||
int error, len, mcast; | int error, len, mcast; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ASSERT(); | ||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
if (TRUNK(ifv) == NULL) { | if (TRUNK(ifv) == NULL) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
m_freem(m); | m_freem(m); | ||||
return (ENETDOWN); | return (ENETDOWN); | ||||
} | } | ||||
p = PARENT(ifv); | p = PARENT(ifv); | ||||
len = m->m_pkthdr.len; | len = m->m_pkthdr.len; | ||||
mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; | mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; | ||||
BPF_MTAP(ifp, m); | BPF_MTAP(ifp, m); | ||||
/* | /* | ||||
* Do not run parent's if_transmit() if the parent is not up, | * Do not run parent's if_transmit() if the parent is not up, | ||||
* or parent's driver will cause a system crash. | * or parent's driver will cause a system crash. | ||||
*/ | */ | ||||
if (!UP_AND_RUNNING(p)) { | if (!UP_AND_RUNNING(p)) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
m_freem(m); | m_freem(m); | ||||
return (ENETDOWN); | return (ENETDOWN); | ||||
} | } | ||||
if (!ether_8021q_frame(&m, ifp, p, ifv->ifv_vid, ifv->ifv_pcp)) { | if (!ether_8021q_frame(&m, ifp, p, ifv->ifv_vid, ifv->ifv_pcp)) { | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Send it, precisely as ether_output() would have. | * Send it, precisely as ether_output() would have. | ||||
*/ | */ | ||||
error = (p->if_transmit)(p, m); | error = (p->if_transmit)(p, m); | ||||
if (error == 0) { | if (error == 0) { | ||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); | ||||
if_inc_counter(ifp, IFCOUNTER_OBYTES, len); | if_inc_counter(ifp, IFCOUNTER_OBYTES, len); | ||||
if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast); | if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast); | ||||
} else | } else | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* The ifp->if_qflush entry point for vlan(4) is a no-op. | * The ifp->if_qflush entry point for vlan(4) is a no-op. | ||||
*/ | */ | ||||
static void | static void | ||||
vlan_qflush(struct ifnet *ifp __unused) | vlan_qflush(struct ifnet *ifp __unused) | ||||
{ | { | ||||
} | } | ||||
static void | static void | ||||
vlan_input(struct ifnet *ifp, struct mbuf *m) | vlan_input(struct ifnet *ifp, struct mbuf *m) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
struct m_tag *mtag; | struct m_tag *mtag; | ||||
uint16_t vid, tag; | uint16_t vid, tag; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ASSERT(); | ||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) { | ||||
NET_EPOCH_EXIT(et); | |||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
if (m->m_flags & M_VLANTAG) { | if (m->m_flags & M_VLANTAG) { | ||||
/* | /* | ||||
* Packet is tagged, but m contains a normal | * Packet is tagged, but m contains a normal | ||||
* Ethernet frame; the tag is stored out-of-band. | * Ethernet frame; the tag is stored out-of-band. | ||||
*/ | */ | ||||
tag = m->m_pkthdr.ether_vtag; | tag = m->m_pkthdr.ether_vtag; | ||||
m->m_flags &= ~M_VLANTAG; | m->m_flags &= ~M_VLANTAG; | ||||
} else { | } else { | ||||
struct ether_vlan_header *evl; | struct ether_vlan_header *evl; | ||||
/* | /* | ||||
* Packet is tagged in-band as specified by 802.1q. | * Packet is tagged in-band as specified by 802.1q. | ||||
*/ | */ | ||||
switch (ifp->if_type) { | switch (ifp->if_type) { | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
if (m->m_len < sizeof(*evl) && | if (m->m_len < sizeof(*evl) && | ||||
(m = m_pullup(m, sizeof(*evl))) == NULL) { | (m = m_pullup(m, sizeof(*evl))) == NULL) { | ||||
if_printf(ifp, "cannot pullup VLAN header\n"); | if_printf(ifp, "cannot pullup VLAN header\n"); | ||||
NET_EPOCH_EXIT(et); | |||||
return; | return; | ||||
} | } | ||||
evl = mtod(m, struct ether_vlan_header *); | evl = mtod(m, struct ether_vlan_header *); | ||||
tag = ntohs(evl->evl_tag); | tag = ntohs(evl->evl_tag); | ||||
/* | /* | ||||
* Remove the 802.1q header by copying the Ethernet | * Remove the 802.1q header by copying the Ethernet | ||||
* addresses over it and adjusting the beginning of | * addresses over it and adjusting the beginning of | ||||
* the data in the mbuf. The encapsulated Ethernet | * the data in the mbuf. The encapsulated Ethernet | ||||
* type field is already in place. | * type field is already in place. | ||||
*/ | */ | ||||
bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, | bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, | ||||
ETHER_HDR_LEN - ETHER_TYPE_LEN); | ETHER_HDR_LEN - ETHER_TYPE_LEN); | ||||
m_adj(m, ETHER_VLAN_ENCAP_LEN); | m_adj(m, ETHER_VLAN_ENCAP_LEN); | ||||
break; | break; | ||||
default: | default: | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
panic("%s: %s has unsupported if_type %u", | panic("%s: %s has unsupported if_type %u", | ||||
__func__, ifp->if_xname, ifp->if_type); | __func__, ifp->if_xname, ifp->if_type); | ||||
#endif | #endif | ||||
if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
vid = EVL_VLANOFTAG(tag); | vid = EVL_VLANOFTAG(tag); | ||||
ifv = vlan_gethash(trunk, vid); | ifv = vlan_gethash(trunk, vid); | ||||
if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { | if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { | ||||
NET_EPOCH_EXIT(et); | |||||
if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
if (vlan_mtag_pcp) { | if (vlan_mtag_pcp) { | ||||
/* | /* | ||||
* While uncommon, it is possible that we will find a 802.1q | * While uncommon, it is possible that we will find a 802.1q | ||||
* packet encapsulated inside another packet that also had an | * packet encapsulated inside another packet that also had an | ||||
* 802.1q header. For example, ethernet tunneled over IPSEC | * 802.1q header. For example, ethernet tunneled over IPSEC | ||||
* arriving over ethernet. In that case, we replace the | * arriving over ethernet. In that case, we replace the | ||||
* existing 802.1q PCP m_tag value. | * existing 802.1q PCP m_tag value. | ||||
*/ | */ | ||||
mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL); | mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL); | ||||
if (mtag == NULL) { | if (mtag == NULL) { | ||||
mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN, | mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN, | ||||
sizeof(uint8_t), M_NOWAIT); | sizeof(uint8_t), M_NOWAIT); | ||||
if (mtag == NULL) { | if (mtag == NULL) { | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
m_tag_prepend(m, mtag); | m_tag_prepend(m, mtag); | ||||
} | } | ||||
*(uint8_t *)(mtag + 1) = EVL_PRIOFTAG(tag); | *(uint8_t *)(mtag + 1) = EVL_PRIOFTAG(tag); | ||||
} | } | ||||
m->m_pkthdr.rcvif = ifv->ifv_ifp; | m->m_pkthdr.rcvif = ifv->ifv_ifp; | ||||
if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1); | ||||
NET_EPOCH_EXIT(et); | |||||
/* Pass it back through the parent's input routine. */ | /* Pass it back through the parent's input routine. */ | ||||
(*ifv->ifv_ifp->if_input)(ifv->ifv_ifp, m); | (*ifv->ifv_ifp->if_input)(ifv->ifv_ifp, m); | ||||
} | } | ||||
static void | static void | ||||
vlan_lladdr_fn(void *arg, int pending __unused) | vlan_lladdr_fn(void *arg, int pending __unused) | ||||
{ | { | ||||
Show All 9 Lines | vlan_lladdr_fn(void *arg, int pending __unused) | ||||
if_setlladdr(ifp, IF_LLADDR(ifp), ifp->if_addrlen); | if_setlladdr(ifp, IF_LLADDR(ifp), ifp->if_addrlen); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
static int | static int | ||||
vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) | vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
int error = 0; | int error = 0; | ||||
NET_EPOCH_ASSERT(); | |||||
/* | /* | ||||
* We can handle non-ethernet hardware types as long as | * We can handle non-ethernet hardware types as long as | ||||
* they handle the tagging and headers themselves. | * they handle the tagging and headers themselves. | ||||
*/ | */ | ||||
if (p->if_type != IFT_ETHER && | if (p->if_type != IFT_ETHER && | ||||
(p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) | (p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) | ||||
return (EPROTONOSUPPORT); | return (EPROTONOSUPPORT); | ||||
if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS) | if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS) | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) | ||||
*/ | */ | ||||
#define VLAN_COPY_FLAGS (IFF_SIMPLEX) | #define VLAN_COPY_FLAGS (IFF_SIMPLEX) | ||||
ifp->if_flags &= ~VLAN_COPY_FLAGS; | ifp->if_flags &= ~VLAN_COPY_FLAGS; | ||||
ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; | ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; | ||||
#undef VLAN_COPY_FLAGS | #undef VLAN_COPY_FLAGS | ||||
ifp->if_link_state = p->if_link_state; | ifp->if_link_state = p->if_link_state; | ||||
NET_EPOCH_ENTER(et); | |||||
vlan_capabilities(ifv); | vlan_capabilities(ifv); | ||||
NET_EPOCH_EXIT(et); | |||||
/* | /* | ||||
* Set up our interface address to reflect the underlying | * Set up our interface address to reflect the underlying | ||||
* physical interface's. | * physical interface's. | ||||
*/ | */ | ||||
bcopy(IF_LLADDR(p), IF_LLADDR(ifp), p->if_addrlen); | bcopy(IF_LLADDR(p), IF_LLADDR(ifp), p->if_addrlen); | ||||
((struct sockaddr_dl *)ifp->if_addr->ifa_addr)->sdl_alen = | ((struct sockaddr_dl *)ifp->if_addr->ifa_addr)->sdl_alen = | ||||
p->if_addrlen; | p->if_addrlen; | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | vlan_setflags(struct ifnet *ifp, int status) | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Inform all vlans that their parent has changed link state */ | /* Inform all vlans that their parent has changed link state */ | ||||
static void | static void | ||||
vlan_link_state(struct ifnet *ifp) | vlan_link_state(struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
/* Called from a taskqueue_swi task, so we cannot sleep. */ | NET_EPOCH_ASSERT(); | ||||
NET_EPOCH_ENTER(et); | |||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) | ||||
NET_EPOCH_EXIT(et); | |||||
return; | return; | ||||
} | |||||
TRUNK_WLOCK(trunk); | TRUNK_WLOCK(trunk); | ||||
VLAN_FOREACH(ifv, trunk) { | VLAN_FOREACH(ifv, trunk) { | ||||
ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; | ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; | ||||
if_link_state_change(ifv->ifv_ifp, | if_link_state_change(ifv->ifv_ifp, | ||||
trunk->parent->if_link_state); | trunk->parent->if_link_state); | ||||
} | } | ||||
TRUNK_WUNLOCK(trunk); | TRUNK_WUNLOCK(trunk); | ||||
NET_EPOCH_EXIT(et); | |||||
} | } | ||||
static void | static void | ||||
vlan_capabilities(struct ifvlan *ifv) | vlan_capabilities(struct ifvlan *ifv) | ||||
{ | { | ||||
struct ifnet *p; | struct ifnet *p; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ifnet_hw_tsomax hw_tsomax; | struct ifnet_hw_tsomax hw_tsomax; | ||||
int cap = 0, ena = 0, mena; | int cap = 0, ena = 0, mena; | ||||
u_long hwa = 0; | u_long hwa = 0; | ||||
VLAN_SXLOCK_ASSERT(); | |||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
VLAN_SXLOCK_ASSERT(); | |||||
p = PARENT(ifv); | p = PARENT(ifv); | ||||
ifp = ifv->ifv_ifp; | ifp = ifv->ifv_ifp; | ||||
/* Mask parent interface enabled capabilities disabled by user. */ | /* Mask parent interface enabled capabilities disabled by user. */ | ||||
mena = p->if_capenable & ifv->ifv_capenable; | mena = p->if_capenable & ifv->ifv_capenable; | ||||
/* | /* | ||||
* If the parent interface can do checksum offloading | * If the parent interface can do checksum offloading | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | #endif | ||||
ifp->if_capabilities = cap; | ifp->if_capabilities = cap; | ||||
ifp->if_capenable = ena; | ifp->if_capenable = ena; | ||||
ifp->if_hwassist = hwa; | ifp->if_hwassist = hwa; | ||||
} | } | ||||
static void | static void | ||||
vlan_trunk_capabilities(struct ifnet *ifp) | vlan_trunk_capabilities(struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
VLAN_SLOCK(); | VLAN_SLOCK(); | ||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) { | ||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
return; | return; | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | VLAN_FOREACH(ifv, trunk) | ||||
VLAN_FOREACH(ifv, trunk) { | |||||
vlan_capabilities(ifv); | vlan_capabilities(ifv); | ||||
} | |||||
NET_EPOCH_EXIT(et); | |||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
} | } | ||||
static int | static int | ||||
vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | ||||
{ | { | ||||
struct ifnet *p; | struct ifnet *p; | ||||
struct ifreq *ifr; | struct ifreq *ifr; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct vlanreq vlr; | struct vlanreq vlr; | ||||
int error = 0; | int error = 0; | ||||
NET_EPOCH_ASSERT(); | |||||
ifr = (struct ifreq *)data; | ifr = (struct ifreq *)data; | ||||
ifa = (struct ifaddr *) data; | ifa = (struct ifaddr *) data; | ||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
switch (cmd) { | switch (cmd) { | ||||
case SIOCSIFADDR: | case SIOCSIFADDR: | ||||
ifp->if_flags |= IFF_UP; | ifp->if_flags |= IFF_UP; | ||||
#ifdef INET | #ifdef INET | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | #endif | ||||
/* broadcast event about PCP change */ | /* broadcast event about PCP change */ | ||||
EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); | EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); | ||||
break; | break; | ||||
case SIOCSIFCAP: | case SIOCSIFCAP: | ||||
VLAN_SLOCK(); | VLAN_SLOCK(); | ||||
ifv->ifv_capenable = ifr->ifr_reqcap; | ifv->ifv_capenable = ifr->ifr_reqcap; | ||||
trunk = TRUNK(ifv); | trunk = TRUNK(ifv); | ||||
if (trunk != NULL) { | if (trunk != NULL) | ||||
struct epoch_tracker et; | |||||
NET_EPOCH_ENTER(et); | |||||
vlan_capabilities(ifv); | vlan_capabilities(ifv); | ||||
NET_EPOCH_EXIT(et); | |||||
} | |||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
Show All 24 Lines |