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? :-)