Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_ethersubr.c
Show First 20 Lines • Show All 435 Lines • ▼ Show 20 Lines | bad: if (m != NULL) | ||||
/* Continue with link-layer output */ | /* Continue with link-layer output */ | ||||
return ether_output_frame(ifp, m); | return ether_output_frame(ifp, m); | ||||
} | } | ||||
static bool | static bool | ||||
ether_set_pcp(struct mbuf **mp, struct ifnet *ifp, uint8_t pcp) | ether_set_pcp(struct mbuf **mp, struct ifnet *ifp, uint8_t pcp) | ||||
{ | { | ||||
struct ether_8021q_tag qtag; | |||||
struct ether_header *eh; | struct ether_header *eh; | ||||
eh = mtod(*mp, struct ether_header *); | eh = mtod(*mp, struct ether_header *); | ||||
if (ntohs(eh->ether_type) == ETHERTYPE_VLAN || | if (ntohs(eh->ether_type) == ETHERTYPE_VLAN || | ||||
ether_8021q_frame(mp, ifp, ifp, 0, pcp)) | ntohs(eh->ether_type) == ETHERTYPE_QINQ) | ||||
return (true); | return (true); | ||||
qtag.vid = 0; | |||||
qtag.pcp = pcp; | |||||
qtag.proto = ETHERTYPE_VLAN; | |||||
if (ether_8021q_frame(mp, ifp, ifp, &qtag)) | |||||
return (true); | |||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
return (false); | return (false); | ||||
} | } | ||||
/* | /* | ||||
* Ethernet link layer output routine to send a raw frame to the device. | * Ethernet link layer output routine to send a raw frame to the device. | ||||
* | * | ||||
* This assumes that the 14 byte Ethernet header is present and contiguous | * This assumes that the 14 byte Ethernet header is present and contiguous | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | else { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If the hardware did not process an 802.1Q tag, do this now, | * If the hardware did not process an 802.1Q tag, do this now, | ||||
* to allow 802.1P priority frames to be passed to the main input | * to allow 802.1P priority frames to be passed to the main input | ||||
* path correctly. | * path correctly. | ||||
* TODO: Deal with Q-in-Q frames, but not arbitrary nesting levels. | * TODO: Deal with Q-in-Q frames, but not arbitrary nesting levels. | ||||
melifaro: Is it done now? :-) | |||||
*/ | */ | ||||
if ((m->m_flags & M_VLANTAG) == 0 && etype == ETHERTYPE_VLAN) { | if ((m->m_flags & M_VLANTAG) == 0 && | ||||
((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ))) { | |||||
struct ether_vlan_header *evl; | struct ether_vlan_header *evl; | ||||
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) { | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
if_printf(ifp, "cannot pullup VLAN header\n"); | if_printf(ifp, "cannot pullup VLAN header\n"); | ||||
#endif | #endif | ||||
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); | ||||
▲ Show 20 Lines • Show All 668 Lines • ▼ Show 20 Lines | if (data != NULL) { | ||||
bpf_mtap(bp, &mb); | bpf_mtap(bp, &mb); | ||||
} else | } else | ||||
bpf_mtap2(bp, &vlan, sizeof(vlan), m); | bpf_mtap2(bp, &vlan, sizeof(vlan), m); | ||||
m->m_len += sizeof(struct ether_header); | m->m_len += sizeof(struct ether_header); | ||||
m->m_data -= sizeof(struct ether_header); | m->m_data -= sizeof(struct ether_header); | ||||
} | } | ||||
struct mbuf * | struct mbuf * | ||||
ether_vlanencap(struct mbuf *m, uint16_t tag) | ether_vlanencap_proto(struct mbuf *m, uint16_t tag, uint16_t proto) | ||||
{ | { | ||||
struct ether_vlan_header *evl; | struct ether_vlan_header *evl; | ||||
M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_NOWAIT); | M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_NOWAIT); | ||||
if (m == NULL) | if (m == NULL) | ||||
return (NULL); | return (NULL); | ||||
/* M_PREPEND takes care of m_len, m_pkthdr.len for us */ | /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ | ||||
if (m->m_len < sizeof(*evl)) { | if (m->m_len < sizeof(*evl)) { | ||||
m = m_pullup(m, sizeof(*evl)); | m = m_pullup(m, sizeof(*evl)); | ||||
if (m == NULL) | if (m == NULL) | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* Transform the Ethernet header into an Ethernet header | * Transform the Ethernet header into an Ethernet header | ||||
* with 802.1Q encapsulation. | * with 802.1Q encapsulation. | ||||
*/ | */ | ||||
evl = mtod(m, struct ether_vlan_header *); | evl = mtod(m, struct ether_vlan_header *); | ||||
bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, | bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, | ||||
(char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); | (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); | ||||
evl->evl_encap_proto = htons(ETHERTYPE_VLAN); | evl->evl_encap_proto = htons(proto); | ||||
evl->evl_tag = htons(tag); | evl->evl_tag = htons(tag); | ||||
return (m); | return (m); | ||||
} | } | ||||
static SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
"IEEE 802.1Q VLAN"); | "IEEE 802.1Q VLAN"); | ||||
static SYSCTL_NODE(_net_link_vlan, PF_LINK, link, | static SYSCTL_NODE(_net_link_vlan, PF_LINK, link, | ||||
CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
Show All 12 Lines | |||||
*/ | */ | ||||
int vlan_mtag_pcp = 0; | int vlan_mtag_pcp = 0; | ||||
SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW, | SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW, | ||||
&vlan_mtag_pcp, 0, | &vlan_mtag_pcp, 0, | ||||
"Retain VLAN PCP information as packets are passed up the stack"); | "Retain VLAN PCP information as packets are passed up the stack"); | ||||
bool | bool | ||||
ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, | ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, | ||||
uint16_t vid, uint8_t pcp) | struct ether_8021q_tag *qtag) | ||||
{ | { | ||||
struct m_tag *mtag; | struct m_tag *mtag; | ||||
int n; | int n; | ||||
uint16_t tag; | uint16_t tag; | ||||
static const char pad[8]; /* just zeros */ | static const char pad[8]; /* just zeros */ | ||||
/* | /* | ||||
* Pad the frame to the minimum size allowed if told to. | * Pad the frame to the minimum size allowed if told to. | ||||
Show All 25 Lines | ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, | ||||
* 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(*mp, MTAG_8021Q, | if (vlan_mtag_pcp && (mtag = m_tag_locate(*mp, MTAG_8021Q, | ||||
MTAG_8021Q_PCP_OUT, NULL)) != NULL) | MTAG_8021Q_PCP_OUT, NULL)) != NULL) | ||||
tag = EVL_MAKETAG(vid, *(uint8_t *)(mtag + 1), 0); | tag = EVL_MAKETAG(qtag->vid, *(uint8_t *)(mtag + 1), 0); | ||||
else | else | ||||
tag = EVL_MAKETAG(vid, pcp, 0); | tag = EVL_MAKETAG(qtag->vid, qtag->pcp, 0); | ||||
if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { | if ((p->if_capenable & IFCAP_VLAN_HWTAGGING) && | ||||
(qtag->proto == ETHERTYPE_VLAN)) { | |||||
(*mp)->m_pkthdr.ether_vtag = tag; | (*mp)->m_pkthdr.ether_vtag = tag; | ||||
(*mp)->m_flags |= M_VLANTAG; | (*mp)->m_flags |= M_VLANTAG; | ||||
} else { | } else { | ||||
*mp = ether_vlanencap(*mp, tag); | *mp = ether_vlanencap_proto(*mp, tag, qtag->proto); | ||||
if (*mp == NULL) { | if (*mp == NULL) { | ||||
if_printf(ife, "unable to prepend 802.1Q header"); | if_printf(ife, "unable to prepend 802.1Q header"); | ||||
return (false); | return (false); | ||||
} | } | ||||
} | } | ||||
return (true); | return (true); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 47 Lines • Show Last 20 Lines |
Is it done now? :-)