summaryrefslogtreecommitdiff
path: root/sys/net/if_vlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/if_vlan.c')
-rw-r--r--sys/net/if_vlan.c107
1 files changed, 47 insertions, 60 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index e3dd261e746..632ace29c6d 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan.c,v 1.127 2015/05/27 12:23:44 dlg Exp $ */
+/* $OpenBSD: if_vlan.c,v 1.128 2015/06/08 13:44:08 mpi Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -47,9 +47,6 @@
* will not modify the ethernet header.
*/
-#include "bridge.h"
-#include "vlan.h"
-
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@@ -59,11 +56,6 @@
#include <sys/sockio.h>
#include <sys/systm.h>
-#include "bpfilter.h"
-#if NBPFILTER > 0
-#include <net/bpf.h>
-#endif
-
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
@@ -73,6 +65,16 @@
#include <net/if_vlan_var.h>
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include "bridge.h"
+#if NBRIDGE > 0
+#include <net/if_bridge.h>
+#endif
+
u_long vlan_tagmask, svlan_tagmask;
#define TAG_HASH_SIZE 32
@@ -81,8 +83,6 @@ LIST_HEAD(vlan_taghash, ifvlan) *vlan_tagh, *svlan_tagh;
int vlan_input(struct mbuf *);
-int vlan_output(struct ifnet *, struct mbuf *, struct sockaddr *,
- struct rtentry *);
void vlan_start(struct ifnet *ifp);
int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
int vlan_unconfig(struct ifnet *ifp, struct ifnet *newp);
@@ -152,7 +152,6 @@ vlan_clone_create(struct if_clone *ifc, int unit)
if_attach(ifp);
ether_ifattach(ifp);
ifp->if_hdrlen = EVL_ENCAPLEN;
- ifp->if_output = vlan_output;
return (0);
}
@@ -176,24 +175,13 @@ vlan_ifdetach(void *ptr)
vlan_clone_destroy(&ifv->ifv_if);
}
-int
-vlan_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
- struct rtentry *rt)
-{
- /*
- * we have to use a custom output function because ether_output
- * can't figure out ifp is a vlan in a reasonable way
- */
- m->m_flags |= M_VLANTAG;
- return (ether_output(ifp, m, dst, rt));
-}
-
void
vlan_start(struct ifnet *ifp)
{
- struct ifvlan *ifv;
+ struct ifvlan *ifv;
struct ifnet *p;
struct mbuf *m;
+ uint8_t prio;
ifv = ifp->if_softc;
p = ifv->ifv_p;
@@ -203,6 +191,11 @@ vlan_start(struct ifnet *ifp)
if (m == NULL)
break;
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER > 0 */
+
if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
(IFF_UP|IFF_RUNNING)) {
IF_DROP(&p->if_snd);
@@ -211,43 +204,37 @@ vlan_start(struct ifnet *ifp)
continue;
}
-#if NBPFILTER > 0
- if (ifp->if_bpf) {
- if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
- (ifv->ifv_type == ETHERTYPE_VLAN))
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
- else {
- struct mbuf *m0;
- u_int off;
- struct m_hdr mh;
- struct {
- uint8_t dst[ETHER_ADDR_LEN];
- uint8_t src[ETHER_ADDR_LEN];
- } hdr;
-
- /* copy the ether addresses off the front */
- m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-
- /* find the ethertype after the vlan subhdr*/
- m0 = m_getptr(m,
- offsetof(struct ether_vlan_header,
- evl_proto), &off);
- KASSERT(m0 != NULL);
-
- /* pretend the vlan subhdr isnt there */
- mh.mh_flags = 0;
- mh.mh_data = mtod(m0, caddr_t) + off;
- mh.mh_len = m0->m_len - off;
- mh.mh_next = m0->m_next;
-
- /* dst+src + ethertype == ethernet header */
- bpf_mtap_hdr(ifp->if_bpf,
- (caddr_t)&hdr, sizeof(hdr),
- (struct mbuf *)&mh, BPF_DIRECTION_OUT,
- NULL);
+ /* IEEE 802.1p has prio 0 and 1 swapped */
+ prio = m->m_pkthdr.pf.prio;
+ if (prio <= 1)
+ prio = !prio;
+
+ /*
+ * If the underlying interface cannot do VLAN tag insertion
+ * itself, create an encapsulation header.
+ */
+ if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
+ (ifv->ifv_type == ETHERTYPE_VLAN)) {
+ m->m_pkthdr.ether_vtag = ifv->ifv_tag +
+ (prio << EVL_PRIO_BITS);
+ m->m_flags |= M_VLANTAG;
+ } else {
+ struct ether_vlan_header evh;
+
+ m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
+ evh.evl_proto = evh.evl_encap_proto;
+ evh.evl_encap_proto = htons(ifv->ifv_type);
+ evh.evl_tag = htons(ifv->ifv_tag +
+ (prio << EVL_PRIO_BITS));
+ m_adj(m, ETHER_HDR_LEN);
+ M_PREPEND(m, sizeof(evh), M_DONTWAIT);
+ if (m == NULL) {
+ ifp->if_oerrors++;
+ continue;
}
+ m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
+ m->m_flags &= ~M_VLANTAG;
}
-#endif /* NBPFILTER > 0 */
if (if_output(p, m)) {
ifp->if_oerrors++;