Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_vlan.c
/*- | /*- | ||||
* Copyright 1998 Massachusetts Institute of Technology | * Copyright 1998 Massachusetts Institute of Technology | ||||
* Copyright 2012 ADARA Networks, Inc. | |||||
* | * | ||||
* Portions of this software were developed by Robert N. M. Watson under | |||||
* contract to ADARA Networks, Inc. | |||||
* | |||||
* Permission to use, copy, modify, and distribute this software and | * Permission to use, copy, modify, and distribute this software and | ||||
* its documentation for any purpose and without fee is hereby | * its documentation for any purpose and without fee is hereby | ||||
* granted, provided that both the above copyright notice and this | * granted, provided that both the above copyright notice and this | ||||
* permission notice appear in all copies, that both the above | * permission notice appear in all copies, that both the above | ||||
* copyright notice and this permission notice appear in all | * copyright notice and this permission notice appear in all | ||||
* supporting documentation, and that the name of M.I.T. not be used | * supporting documentation, and that the name of M.I.T. not be used | ||||
* in advertising or publicity pertaining to distribution of the | * in advertising or publicity pertaining to distribution of the | ||||
* software without specific, written prior permission. M.I.T. makes | * software without specific, written prior permission. M.I.T. makes | ||||
Show All 12 Lines | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
/* | /* | ||||
* if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. | * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. | ||||
* Might be extended some day to also handle IEEE 802.1p priority | * This is sort of sneaky in the implementation, since | ||||
* tagging. This is sort of sneaky in the implementation, since | |||||
* we need to pretend to be enough of an Ethernet implementation | * we need to pretend to be enough of an Ethernet implementation | ||||
* to make arp work. The way we do this is by telling everyone | * to make arp work. The way we do this is by telling everyone | ||||
* that we are an Ethernet, and then catch the packets that | * that we are an Ethernet, and then catch the packets that | ||||
* ether_output() sends to us via if_transmit(), rewrite them for | * ether_output() sends to us via if_transmit(), rewrite them for | ||||
* use by the real outgoing interface, and ask it to send them. | * use by the real outgoing interface, and ask it to send them. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_vlan.h" | #include "opt_vlan.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/rmlock.h> | #include <sys/rmlock.h> | ||||
#include <sys/priv.h> | |||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <net/bpf.h> | #include <net/bpf.h> | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | #define PARENT(ifv) ((ifv)->ifv_trunk->parent) | ||||
void *ifv_cookie; | void *ifv_cookie; | ||||
int ifv_pflags; /* special flags we have set on parent */ | int ifv_pflags; /* special flags we have set on parent */ | ||||
struct ifv_linkmib { | struct ifv_linkmib { | ||||
int ifvm_encaplen; /* encapsulation length */ | int ifvm_encaplen; /* encapsulation length */ | ||||
int ifvm_mtufudge; /* MTU fudged by this much */ | int ifvm_mtufudge; /* MTU fudged by this much */ | ||||
int ifvm_mintu; /* min transmission unit */ | int ifvm_mintu; /* min transmission unit */ | ||||
uint16_t ifvm_proto; /* encapsulation ethertype */ | uint16_t ifvm_proto; /* encapsulation ethertype */ | ||||
uint16_t ifvm_tag; /* tag to apply on packets leaving if */ | uint16_t ifvm_tag; /* tag to apply on packets leaving if */ | ||||
uint16_t ifvm_vid; /* VLAN ID */ | |||||
uint8_t ifvm_pcp; /* Priority Code Point (PCP). */ | |||||
} ifv_mib; | } ifv_mib; | ||||
SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; | SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; | ||||
#ifndef VLAN_ARRAY | #ifndef VLAN_ARRAY | ||||
LIST_ENTRY(ifvlan) ifv_list; | LIST_ENTRY(ifvlan) ifv_list; | ||||
#endif | #endif | ||||
}; | }; | ||||
#define ifv_proto ifv_mib.ifvm_proto | #define ifv_proto ifv_mib.ifvm_proto | ||||
#define ifv_vid ifv_mib.ifvm_tag | #define ifv_tag ifv_mib.ifvm_tag | ||||
#define ifv_vid ifv_mib.ifvm_vid | |||||
#define ifv_pcp ifv_mib.ifvm_pcp | |||||
#define ifv_encaplen ifv_mib.ifvm_encaplen | #define ifv_encaplen ifv_mib.ifvm_encaplen | ||||
loos: Another cosmetic fix, alignment. | |||||
#define ifv_mtufudge ifv_mib.ifvm_mtufudge | #define ifv_mtufudge ifv_mib.ifvm_mtufudge | ||||
#define ifv_mintu ifv_mib.ifvm_mintu | #define ifv_mintu ifv_mib.ifvm_mintu | ||||
/* Special flags we should propagate to parent. */ | /* Special flags we should propagate to parent. */ | ||||
static struct { | static struct { | ||||
int flag; | int flag; | ||||
int (*func)(struct ifnet *, int); | int (*func)(struct ifnet *, int); | ||||
} vlan_pflags[] = { | } vlan_pflags[] = { | ||||
{IFF_PROMISC, ifpromisc}, | {IFF_PROMISC, ifpromisc}, | ||||
{IFF_ALLMULTI, if_allmulti}, | {IFF_ALLMULTI, if_allmulti}, | ||||
{0, NULL} | {0, NULL} | ||||
}; | }; | ||||
SYSCTL_DECL(_net_link); | SYSCTL_DECL(_net_link); | ||||
static SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, | static SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, | ||||
"IEEE 802.1Q VLAN"); | "IEEE 802.1Q VLAN"); | ||||
static SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, | static SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, | ||||
"for consistency"); | "for consistency"); | ||||
static VNET_DEFINE(int, soft_pad); | static VNET_DEFINE(int, soft_pad); | ||||
#define V_soft_pad VNET(soft_pad) | #define V_soft_pad VNET(soft_pad) | ||||
SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW | CTLFLAG_VNET, | SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW | CTLFLAG_VNET, | ||||
&VNET_NAME(soft_pad), 0, "pad short frames before tagging"); | &VNET_NAME(soft_pad), 0, "pad short frames before tagging"); | ||||
/* | |||||
* For now, make preserving PCP via an mbuf tag optional, as it increases | |||||
* per-packet memory allocations and frees. In the future, it would be | |||||
* preferable to reuse ether_vtag for this, or similar. | |||||
*/ | |||||
static int vlan_mtag_pcp = 0; | |||||
SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW, &vlan_mtag_pcp, 0, | |||||
"Retain VLAN PCP information as packets are passed up the stack"); | |||||
static const char vlanname[] = "vlan"; | static const char vlanname[] = "vlan"; | ||||
static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface"); | static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface"); | ||||
static eventhandler_tag ifdetach_tag; | static eventhandler_tag ifdetach_tag; | ||||
static eventhandler_tag iflladdr_tag; | static eventhandler_tag iflladdr_tag; | ||||
/* | /* | ||||
* We have a global mutex, that is used to serialize configuration | * We have a global mutex, that is used to serialize configuration | ||||
▲ Show 20 Lines • Show All 534 Lines • ▼ Show 20 Lines | vlan_devat(struct ifnet *ifp, uint16_t vid) | ||||
ifv = vlan_gethash(trunk, vid); | ifv = vlan_gethash(trunk, vid); | ||||
if (ifv) | if (ifv) | ||||
ifp = ifv->ifv_ifp; | ifp = ifv->ifv_ifp; | ||||
TRUNK_RUNLOCK(trunk); | TRUNK_RUNLOCK(trunk); | ||||
return (ifp); | return (ifp); | ||||
} | } | ||||
/* | /* | ||||
* Recalculate the cached VLAN tag exposed via the MIB. | |||||
*/ | |||||
static void | |||||
vlan_tag_recalculate(struct ifvlan *ifv) | |||||
{ | |||||
ifv->ifv_tag = EVL_MAKETAG(ifv->ifv_vid, ifv->ifv_pcp, 0); | |||||
} | |||||
/* | |||||
* VLAN support can be loaded as a module. The only place in the | * VLAN support can be loaded as a module. The only place in the | ||||
* system that's intimately aware of this is ether_input. We hook | * system that's intimately aware of this is ether_input. We hook | ||||
* into this code through vlan_input_p which is defined there and | * into this code through vlan_input_p which is defined there and | ||||
* set here. Noone else in the system should be aware of this so | * set here. Noone else in the system should be aware of this so | ||||
* we use an explicit reference here. | * we use an explicit reference here. | ||||
*/ | */ | ||||
extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); | extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); | ||||
▲ Show 20 Lines • Show All 296 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 ifvlan *ifv; | struct ifvlan *ifv; | ||||
struct ifnet *p; | struct ifnet *p; | ||||
struct m_tag *mtag; | |||||
uint16_t tag; | |||||
int error, len, mcast; | int error, len, mcast; | ||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
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); | ||||
Show All 39 Lines | vlan_transmit(struct ifnet *ifp, struct mbuf *m) | ||||
/* | /* | ||||
* If underlying interface can do VLAN tag insertion itself, | * If underlying interface can do VLAN tag insertion itself, | ||||
* just pass the packet along. However, we need some way to | * just pass the packet along. However, we need some way to | ||||
* tell the interface where the packet came from so that it | * tell the interface where the packet came from so that it | ||||
* knows how to find the VLAN tag to use, so we attach a | * knows how to find the VLAN tag to use, so we attach a | ||||
* packet tag that holds it. | * packet tag that holds it. | ||||
*/ | */ | ||||
if (vlan_mtag_pcp && (mtag = m_tag_locate(m, MTAG_8021Q, | |||||
MTAG_8021Q_PCP_OUT, NULL)) != NULL) | |||||
tag = EVL_MAKETAG(ifv->ifv_vid, *(uint8_t *)(mtag + 1), 0); | |||||
else | |||||
tag = ifv->ifv_tag; | |||||
if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { | if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { | ||||
m->m_pkthdr.ether_vtag = ifv->ifv_vid; | m->m_pkthdr.ether_vtag = tag; | ||||
m->m_flags |= M_VLANTAG; | m->m_flags |= M_VLANTAG; | ||||
} else { | } else { | ||||
m = ether_vlanencap(m, ifv->ifv_vid); | m = ether_vlanencap(m, tag); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
if_printf(ifp, "unable to prepend VLAN header\n"); | if_printf(ifp, "unable to prepend VLAN header\n"); | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
Show All 18 Lines | |||||
} | } | ||||
static void | static void | ||||
vlan_input(struct ifnet *ifp, struct mbuf *m) | vlan_input(struct ifnet *ifp, struct mbuf *m) | ||||
{ | { | ||||
struct ifvlantrunk *trunk = ifp->if_vlantrunk; | struct ifvlantrunk *trunk = ifp->if_vlantrunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
TRUNK_LOCK_READER; | TRUNK_LOCK_READER; | ||||
uint16_t vid; | struct m_tag *mtag; | ||||
uint16_t vid, tag; | |||||
KASSERT(trunk != NULL, ("%s: no trunk", __func__)); | KASSERT(trunk != NULL, ("%s: no trunk", __func__)); | ||||
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. | ||||
*/ | */ | ||||
vid = EVL_VLANOFTAG(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"); | ||||
return; | return; | ||||
} | } | ||||
evl = mtod(m, struct ether_vlan_header *); | evl = mtod(m, struct ether_vlan_header *); | ||||
vid = EVL_VLANOFTAG(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 | ||||
m_freem(m); | m_freem(m); | ||||
if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
vid = EVL_VLANOFTAG(tag); | |||||
TRUNK_RLOCK(trunk); | TRUNK_RLOCK(trunk); | ||||
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)) { | ||||
TRUNK_RUNLOCK(trunk); | TRUNK_RUNLOCK(trunk); | ||||
m_freem(m); | m_freem(m); | ||||
if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); | ||||
return; | return; | ||||
} | } | ||||
TRUNK_RUNLOCK(trunk); | TRUNK_RUNLOCK(trunk); | ||||
if (vlan_mtag_pcp) { | |||||
/* | |||||
* While uncommon, it is possible that we will find a 802.1q | |||||
* packet encapsulated inside another packet that also had an | |||||
* 802.1q header. For example, ethernet tunneled over IPSEC | |||||
* arriving over ethernet. In that case, we replace the | |||||
* existing 802.1q PCP m_tag value. | |||||
*/ | |||||
mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL); | |||||
if (mtag == NULL) { | |||||
mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN, | |||||
sizeof(uint8_t), M_NOWAIT); | |||||
if (mtag == NULL) { | |||||
m_freem(m); | |||||
ifp->if_ierrors++; | |||||
return; | |||||
} | |||||
m_tag_prepend(m, mtag); | |||||
} | |||||
*(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); | ||||
/* Pass it back through the parent's input routine. */ | /* Pass it back through the parent's input routine. */ | ||||
(*ifp->if_input)(ifv->ifv_ifp, m); | (*ifp->if_input)(ifv->ifv_ifp, m); | ||||
} | } | ||||
static int | static int | ||||
Show All 23 Lines | if (ifv->ifv_trunk) | ||||
return (EBUSY); | return (EBUSY); | ||||
if (p->if_vlantrunk == NULL) { | if (p->if_vlantrunk == NULL) { | ||||
trunk = malloc(sizeof(struct ifvlantrunk), | trunk = malloc(sizeof(struct ifvlantrunk), | ||||
M_VLAN, M_WAITOK | M_ZERO); | M_VLAN, M_WAITOK | M_ZERO); | ||||
vlan_inithash(trunk); | vlan_inithash(trunk); | ||||
VLAN_LOCK(); | VLAN_LOCK(); | ||||
if (p->if_vlantrunk != NULL) { | if (p->if_vlantrunk != NULL) { | ||||
/* A race that that is very unlikely to be hit. */ | /* A race that is very unlikely to be hit. */ | ||||
vlan_freehash(trunk); | vlan_freehash(trunk); | ||||
free(trunk, M_VLAN); | free(trunk, M_VLAN); | ||||
goto exists; | goto exists; | ||||
} | } | ||||
TRUNK_LOCK_INIT(trunk); | TRUNK_LOCK_INIT(trunk); | ||||
TRUNK_LOCK(trunk); | TRUNK_LOCK(trunk); | ||||
p->if_vlantrunk = trunk; | p->if_vlantrunk = trunk; | ||||
trunk->parent = p; | trunk->parent = p; | ||||
} else { | } else { | ||||
VLAN_LOCK(); | VLAN_LOCK(); | ||||
exists: | exists: | ||||
trunk = p->if_vlantrunk; | trunk = p->if_vlantrunk; | ||||
TRUNK_LOCK(trunk); | TRUNK_LOCK(trunk); | ||||
} | } | ||||
ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ | ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ | ||||
ifv->ifv_pcp = 0; /* Default: best effort delivery. */ | |||||
vlan_tag_recalculate(ifv); | |||||
error = vlan_inshash(trunk, ifv); | error = vlan_inshash(trunk, ifv); | ||||
if (error) | if (error) | ||||
goto done; | goto done; | ||||
ifv->ifv_proto = ETHERTYPE_VLAN; | ifv->ifv_proto = ETHERTYPE_VLAN; | ||||
ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; | ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; | ||||
ifv->ifv_mintu = ETHERMIN; | ifv->ifv_mintu = ETHERMIN; | ||||
ifv->ifv_pflags = 0; | ifv->ifv_pflags = 0; | ||||
▲ Show 20 Lines • Show All 469 Lines • ▼ Show 20 Lines | case SIOCDELMULTI: | ||||
* when we do. | * when we do. | ||||
*/ | */ | ||||
trunk = TRUNK(ifv); | trunk = TRUNK(ifv); | ||||
if (trunk != NULL) { | if (trunk != NULL) { | ||||
TRUNK_LOCK(trunk); | TRUNK_LOCK(trunk); | ||||
error = vlan_setmulti(ifp); | error = vlan_setmulti(ifp); | ||||
TRUNK_UNLOCK(trunk); | TRUNK_UNLOCK(trunk); | ||||
} | } | ||||
break; | |||||
case SIOCGVLANPCP: | |||||
#ifdef VIMAGE | |||||
if (ifp->if_vnet != ifp->if_home_vnet) { | |||||
error = EPERM; | |||||
break; | |||||
} | |||||
#endif | |||||
ifr->ifr_vlan_pcp = ifv->ifv_pcp; | |||||
break; | |||||
case SIOCSVLANPCP: | |||||
#ifdef VIMAGE | |||||
if (ifp->if_vnet != ifp->if_home_vnet) { | |||||
error = EPERM; | |||||
break; | |||||
} | |||||
#endif | |||||
error = priv_check(curthread, PRIV_NET_SETVLANPCP); | |||||
if (error) | |||||
break; | |||||
if (ifr->ifr_vlan_pcp > 7) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
ifv->ifv_pcp = ifr->ifr_vlan_pcp; | |||||
vlan_tag_recalculate(ifv); | |||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } |
Another cosmetic fix, alignment.