2 * Copyright 1998 Massachusetts Institute of Technology
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all
9 * supporting documentation, and that the name of M.I.T. not be used
10 * in advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission. M.I.T. makes
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied
16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/sys/net/if_vlan.c,v 1.15.2.13 2003/02/14 22:25:58 fenner Exp $
30 * $DragonFly: src/sys/net/vlan/if_vlan.c,v 1.26 2008/01/11 11:59:41 sephe Exp $
34 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
35 * Might be extended some day to also handle IEEE 802.1p priority
36 * tagging. This is sort of sneaky in the implementation, since
37 * we need to pretend to be enough of an Ethernet implementation
38 * to make arp work. The way we do this is by telling everyone
39 * that we are an Ethernet, and then catch the packets that
40 * ether_output() left on our output queue queue when it calls
41 * if_start(), rewrite them for use by the real outgoing interface,
42 * and ask it to send them.
45 * XXX It's incorrect to assume that we must always kludge up
46 * headers on the physical device's behalf: some devices support
47 * VLAN tag insertion and extraction in firmware. For these cases,
48 * one can change the behavior of the vlan interface by setting
49 * the LINK0 flag on it (that is setting the vlan interface's LINK0
50 * flag, _not_ the parent's LINK0 flag; we try to leave the parent
51 * alone). If the interface has the LINK0 flag set, then it will
52 * not modify the ethernet header on output, because the parent
53 * can do that for itself. On input, the parent can call vlan_input_tag()
54 * directly in order to supply us with an incoming mbuf and the vlan
55 * tag value that goes with it.
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
68 #include <sys/module.h>
69 #include <sys/queue.h>
70 #include <sys/socket.h>
71 #include <sys/sockio.h>
72 #include <sys/sysctl.h>
74 #include <sys/thread2.h>
77 #include <net/ethernet.h>
79 #include <net/if_arp.h>
80 #include <net/if_dl.h>
81 #include <net/if_types.h>
82 #include <net/ifq_var.h>
83 #include <net/if_clone.h>
84 #include "if_vlan_var.h"
87 #include <netinet/in.h>
88 #include <netinet/if_ether.h>
91 #define VLANNAME "vlan"
93 SYSCTL_DECL(_net_link
);
94 SYSCTL_NODE(_net_link
, IFT_L2VLAN
, vlan
, CTLFLAG_RW
, 0, "IEEE 802.1Q VLAN");
95 SYSCTL_NODE(_net_link_vlan
, PF_LINK
, link
, CTLFLAG_RW
, 0, "for consistency");
97 static MALLOC_DEFINE(M_VLAN
, "vlan", "802.1Q Virtual LAN Interface");
98 static LIST_HEAD(, ifvlan
) ifv_list
;
100 static int vlan_clone_create(struct if_clone
*, int);
101 static void vlan_clone_destroy(struct ifnet
*);
102 static void vlan_start(struct ifnet
*ifp
);
103 static void vlan_ifinit(void *foo
);
104 static int vlan_input(const struct ether_header
*eh
, struct mbuf
*m
);
105 static int vlan_input_tag(struct mbuf
*m
, uint16_t t
);
106 static int vlan_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t addr
,
108 static int vlan_setmulti(struct ifnet
*ifp
);
109 static int vlan_unconfig(struct ifnet
*ifp
);
110 static int vlan_config(struct ifvlan
*ifv
, struct ifnet
*p
);
112 struct if_clone vlan_cloner
= IF_CLONE_INITIALIZER("vlan", vlan_clone_create
,
113 vlan_clone_destroy
, NVLAN
, IF_MAXUNIT
);
116 * Program our multicast filter. What we're actually doing is
117 * programming the multicast filter of the parent. This has the
118 * side effect of causing the parent interface to receive multicast
119 * traffic that it doesn't really want, which ends up being discarded
120 * later by the upper protocol layers. Unfortunately, there's no way
121 * to avoid this: there really is only one physical interface.
124 vlan_setmulti(struct ifnet
*ifp
)
127 struct ifmultiaddr
*ifma
, *rifma
= NULL
;
129 struct vlan_mc_entry
*mc
= NULL
;
130 struct sockaddr_dl sdl
;
133 /* Find the parent. */
138 * If we don't have a parent, just remember the membership for
144 bzero((char *)&sdl
, sizeof sdl
);
145 sdl
.sdl_len
= sizeof sdl
;
146 sdl
.sdl_family
= AF_LINK
;
147 sdl
.sdl_index
= ifp_p
->if_index
;
148 sdl
.sdl_type
= IFT_ETHER
;
149 sdl
.sdl_alen
= ETHER_ADDR_LEN
;
151 /* First, remove any existing filter entries. */
152 while(SLIST_FIRST(&sc
->vlan_mc_listhead
) != NULL
) {
153 mc
= SLIST_FIRST(&sc
->vlan_mc_listhead
);
154 bcopy((char *)&mc
->mc_addr
, LLADDR(&sdl
), ETHER_ADDR_LEN
);
155 error
= if_delmulti(ifp_p
, (struct sockaddr
*)&sdl
);
158 SLIST_REMOVE_HEAD(&sc
->vlan_mc_listhead
, mc_entries
);
162 /* Now program new ones. */
163 LIST_FOREACH(ifma
, &ifp
->if_multiaddrs
, ifma_link
) {
164 if (ifma
->ifma_addr
->sa_family
!= AF_LINK
)
166 mc
= kmalloc(sizeof(struct vlan_mc_entry
), M_VLAN
, M_WAITOK
);
167 bcopy(LLADDR((struct sockaddr_dl
*)ifma
->ifma_addr
),
168 (char *)&mc
->mc_addr
, ETHER_ADDR_LEN
);
169 SLIST_INSERT_HEAD(&sc
->vlan_mc_listhead
, mc
, mc_entries
);
170 bcopy(LLADDR((struct sockaddr_dl
*)ifma
->ifma_addr
),
171 LLADDR(&sdl
), ETHER_ADDR_LEN
);
172 error
= if_addmulti(ifp_p
, (struct sockaddr
*)&sdl
, &rifma
);
181 vlan_modevent(module_t mod
, int type
, void *data
)
186 LIST_INIT(&ifv_list
);
187 vlan_input_p
= vlan_input
;
188 vlan_input_tag_p
= vlan_input_tag
;
189 if_clone_attach(&vlan_cloner
);
192 if_clone_detach(&vlan_cloner
);
194 vlan_input_tag_p
= NULL
;
195 while (!LIST_EMPTY(&ifv_list
))
196 vlan_clone_destroy(&LIST_FIRST(&ifv_list
)->ifv_if
);
202 static moduledata_t vlan_mod
= {
208 DECLARE_MODULE(if_vlan
, vlan_mod
, SI_SUB_PSEUDO
, SI_ORDER_ANY
);
211 vlan_clone_create(struct if_clone
*ifc
, int unit
)
216 ifv
= kmalloc(sizeof(struct ifvlan
), M_VLAN
, M_WAITOK
| M_ZERO
);
218 SLIST_INIT(&ifv
->vlan_mc_listhead
);
221 LIST_INSERT_HEAD(&ifv_list
, ifv
, ifv_list
);
225 if_initname(ifp
, "vlan", unit
);
226 /* NB: flags are not set here */
227 ifp
->if_linkmib
= &ifv
->ifv_mib
;
228 ifp
->if_linkmiblen
= sizeof ifv
->ifv_mib
;
229 /* NB: mtu is not set here */
231 ifp
->if_init
= vlan_ifinit
;
232 ifp
->if_start
= vlan_start
;
233 ifp
->if_ioctl
= vlan_ioctl
;
234 ifq_set_maxlen(&ifp
->if_snd
, ifqmaxlen
);
235 ifq_set_ready(&ifp
->if_snd
);
236 ether_ifattach(ifp
, ifv
->ifv_ac
.ac_enaddr
, NULL
);
237 /* Now undo some of the damage... */
238 ifp
->if_data
.ifi_type
= IFT_L2VLAN
;
239 ifp
->if_data
.ifi_hdrlen
= EVL_ENCAPLEN
;
245 vlan_clone_destroy(struct ifnet
*ifp
)
247 struct ifvlan
*ifv
= ifp
->if_softc
;
251 LIST_REMOVE(ifv
, ifv_list
);
261 vlan_ifinit(void *foo
)
267 vlan_start(struct ifnet
*ifp
)
271 struct ether_vlan_header
*evl
;
274 struct altq_pktattr pktattr
;
279 ifp
->if_flags
|= IFF_OACTIVE
;
281 m
= ifq_dequeue(&ifp
->if_snd
, NULL
);
287 * Do not run parent's if_start() if the parent is not up,
288 * or parent's driver will cause a system crash.
290 if ((p
->if_flags
& (IFF_UP
| IFF_RUNNING
)) !=
291 (IFF_UP
| IFF_RUNNING
)) {
293 ifp
->if_data
.ifi_collisions
++;
298 * If ALTQ is enabled on the parent interface, do
299 * classification; the queueing discipline might
300 * not require classification, but might require
301 * the address family/header pointer in the pktattr.
303 if (ifq_is_enabled(&p
->if_snd
))
304 altq_etherclassify(&p
->if_snd
, m
, &pktattr
);
307 * If underlying interface can do VLAN tag insertion itself,
308 * just pass the packet along. However, we need some way to
309 * tell the interface where the packet came from so that it
310 * knows how to find the VLAN tag to use, so we set the rcvif
311 * in the mbuf header to our ifnet.
313 * Note: we also set the M_PROTO1 flag in the mbuf to let
314 * the parent driver know that the rcvif pointer is really
315 * valid. We need to do this because sometimes mbufs will
316 * be allocated by other parts of the system that contain
317 * garbage in the rcvif pointer. Using the M_PROTO1 flag
318 * lets the driver perform a proper sanity check and avoid
319 * following potentially bogus rcvif pointers off into
322 if (p
->if_capenable
& IFCAP_VLAN_HWTAGGING
) {
323 m
->m_pkthdr
.rcvif
= ifp
;
324 m
->m_flags
|= M_PROTO1
;
326 M_PREPEND(m
, EVL_ENCAPLEN
, MB_DONTWAIT
);
328 kprintf("%s: M_PREPEND failed", ifp
->if_xname
);
332 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
334 m
= m_pullup(m
, ETHER_HDR_LEN
+ EVL_ENCAPLEN
);
336 kprintf("%s: m_pullup failed", ifp
->if_xname
);
342 * Transform the Ethernet header into an Ethernet header
343 * with 802.1Q encapsulation.
345 bcopy(mtod(m
, char *) + EVL_ENCAPLEN
, mtod(m
, char *),
346 sizeof(struct ether_header
));
347 evl
= mtod(m
, struct ether_vlan_header
*);
348 evl
->evl_proto
= evl
->evl_encap_proto
;
349 evl
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
350 evl
->evl_tag
= htons(ifv
->ifv_tag
);
352 kprintf("vlan_start: %*D\n", sizeof *evl
,
353 (unsigned char *)evl
, ":");
358 * Send it, precisely as ether_output() would have.
359 * We are already running at splimp.
361 lwkt_serialize_exit(ifp
->if_serializer
);
362 lwkt_serialize_enter(p
->if_serializer
);
363 error
= ifq_handoff(p
, m
, &pktattr
);
364 lwkt_serialize_exit(p
->if_serializer
);
365 lwkt_serialize_enter(ifp
->if_serializer
);
371 ifp
->if_flags
&= ~IFF_OACTIVE
;
377 vlan_input_tag( struct mbuf
*m
, uint16_t t
)
383 rcvif
= m
->m_pkthdr
.rcvif
;
385 ASSERT_SERIALIZED(rcvif
->if_serializer
);
388 * Fake up a header and send the packet to the physical interface's
391 if ((bif
= rcvif
->if_bpf
) != NULL
) {
392 struct ether_header
*eh
;
393 struct ether_vlan_header evh
;
395 eh
= mtod(m
, struct ether_header
*);
396 m_adj(m
, ETHER_HDR_LEN
);
397 bcopy(eh
, &evh
, 2*ETHER_ADDR_LEN
);
398 evh
.evl_encap_proto
= htons(ETHERTYPE_VLAN
);
399 evh
.evl_tag
= htons(t
);
400 evh
.evl_proto
= eh
->ether_type
;
401 bpf_ptap(bif
, m
, &evh
, ETHER_HDR_LEN
+ EVL_ENCAPLEN
);
402 /* XXX assumes data was left intact */
403 M_PREPEND(m
, ETHER_HDR_LEN
, MB_WAIT
);
406 for (ifv
= LIST_FIRST(&ifv_list
); ifv
!= NULL
;
407 ifv
= LIST_NEXT(ifv
, ifv_list
)) {
408 if (rcvif
== ifv
->ifv_p
&& ifv
->ifv_tag
== t
)
412 if (ifv
== NULL
|| (ifv
->ifv_if
.if_flags
& IFF_UP
) == 0) {
414 return -1; /* So the parent can take note */
418 * Having found a valid vlan interface corresponding to
419 * the given source interface and vlan tag, run the
420 * the real packet through ether_input().
422 m
->m_pkthdr
.rcvif
= &ifv
->ifv_if
;
424 ifv
->ifv_if
.if_ipackets
++;
425 lwkt_serialize_exit(rcvif
->if_serializer
);
426 lwkt_serialize_enter(ifv
->ifv_if
.if_serializer
);
427 ether_input(&ifv
->ifv_if
, m
);
428 lwkt_serialize_exit(ifv
->ifv_if
.if_serializer
);
429 lwkt_serialize_enter(rcvif
->if_serializer
);
434 vlan_input(const struct ether_header
*eh
, struct mbuf
*m
)
438 struct ether_header eh_copy
;
440 rcvif
= m
->m_pkthdr
.rcvif
;
441 ASSERT_SERIALIZED(rcvif
->if_serializer
);
443 for (ifv
= LIST_FIRST(&ifv_list
); ifv
!= NULL
;
444 ifv
= LIST_NEXT(ifv
, ifv_list
)) {
445 if (rcvif
== ifv
->ifv_p
446 && (EVL_VLANOFTAG(ntohs(*mtod(m
, u_int16_t
*)))
451 if (ifv
== NULL
|| (ifv
->ifv_if
.if_flags
& IFF_UP
) == 0) {
454 return -1; /* so ether_input can take note */
458 * Having found a valid vlan interface corresponding to
459 * the given source interface and vlan tag, remove the
460 * remaining encapsulation (ether_vlan_header minus the ether_header
461 * that had already been removed) and run the real packet
462 * through ether_input() a second time (it had better be
466 eh_copy
.ether_type
= mtod(m
, u_int16_t
*)[1]; /* evl_proto */
467 m
->m_pkthdr
.rcvif
= &ifv
->ifv_if
;
468 m_adj(m
, EVL_ENCAPLEN
);
469 M_PREPEND(m
, ETHER_HDR_LEN
, MB_WAIT
);
470 *(struct ether_header
*)mtod(m
, void *) = eh_copy
;
472 ifv
->ifv_if
.if_ipackets
++;
473 lwkt_serialize_exit(rcvif
->if_serializer
);
474 lwkt_serialize_enter(ifv
->ifv_if
.if_serializer
);
475 ether_input(&ifv
->ifv_if
, m
);
476 lwkt_serialize_exit(ifv
->ifv_if
.if_serializer
);
477 lwkt_serialize_enter(rcvif
->if_serializer
);
482 vlan_config(struct ifvlan
*ifv
, struct ifnet
*p
)
484 struct sockaddr_dl
*sdl1
, *sdl2
;
486 if (p
->if_data
.ifi_type
!= IFT_ETHER
)
487 return EPROTONOSUPPORT
;
491 if (p
->if_capenable
& IFCAP_VLAN_MTU
)
492 ifv
->ifv_if
.if_mtu
= p
->if_mtu
;
494 ifv
->ifv_if
.if_mtu
= p
->if_data
.ifi_mtu
- EVL_ENCAPLEN
;
497 * Copy only a selected subset of flags from the parent.
498 * Other flags are none of our business.
500 ifv
->ifv_if
.if_flags
= (p
->if_flags
&
501 (IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
| IFF_POINTOPOINT
));
504 * Set up our ``Ethernet address'' to reflect the underlying
505 * physical interface's.
507 sdl1
= IF_LLSOCKADDR(&ifv
->ifv_if
);
508 sdl2
= IF_LLSOCKADDR(p
);
509 sdl1
->sdl_type
= IFT_ETHER
;
510 sdl1
->sdl_alen
= ETHER_ADDR_LEN
;
511 bcopy(LLADDR(sdl2
), LLADDR(sdl1
), ETHER_ADDR_LEN
);
512 bcopy(LLADDR(sdl2
), ifv
->ifv_ac
.ac_enaddr
, ETHER_ADDR_LEN
);
515 * Configure multicast addresses that may already be
516 * joined on the vlan device.
518 vlan_setmulti(&ifv
->ifv_if
);
524 vlan_unconfig(struct ifnet
*ifp
)
526 struct sockaddr_dl
*sdl
;
527 struct vlan_mc_entry
*mc
;
536 struct sockaddr_dl sdl
;
539 * Since the interface is being unconfigured, we need to
540 * empty the list of multicast groups that we may have joined
541 * while we were alive from the parent's list.
543 bzero((char *)&sdl
, sizeof sdl
);
544 sdl
.sdl_len
= sizeof sdl
;
545 sdl
.sdl_family
= AF_LINK
;
546 sdl
.sdl_index
= p
->if_index
;
547 sdl
.sdl_type
= IFT_ETHER
;
548 sdl
.sdl_alen
= ETHER_ADDR_LEN
;
550 while(SLIST_FIRST(&ifv
->vlan_mc_listhead
) != NULL
) {
551 mc
= SLIST_FIRST(&ifv
->vlan_mc_listhead
);
552 bcopy((char *)&mc
->mc_addr
, LLADDR(&sdl
), ETHER_ADDR_LEN
);
553 error
= if_delmulti(p
, (struct sockaddr
*)&sdl
);
556 SLIST_REMOVE_HEAD(&ifv
->vlan_mc_listhead
, mc_entries
);
561 /* Disconnect from parent. */
563 ifv
->ifv_if
.if_mtu
= ETHERMTU
;
565 /* Clear our MAC address. */
566 sdl
= IF_LLSOCKADDR(&ifv
->ifv_if
);
567 sdl
->sdl_type
= IFT_ETHER
;
568 sdl
->sdl_alen
= ETHER_ADDR_LEN
;
569 bzero(LLADDR(sdl
), ETHER_ADDR_LEN
);
570 bzero(ifv
->ifv_ac
.ac_enaddr
, ETHER_ADDR_LEN
);
576 vlan_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
, struct ucred
*cr
)
585 ifr
= (struct ifreq
*)data
;
586 ifa
= (struct ifaddr
*)data
;
589 ASSERT_SERIALIZED(ifp
->if_serializer
);
594 ifp
->if_flags
|= IFF_UP
;
596 switch (ifa
->ifa_addr
->sa_family
) {
599 arp_ifinit(&ifv
->ifv_if
, ifa
);
611 sa
= (struct sockaddr
*) &ifr
->ifr_data
;
612 bcopy(((struct arpcom
*)ifp
->if_softc
)->ac_enaddr
,
613 (caddr_t
) sa
->sa_data
, ETHER_ADDR_LEN
);
618 if (ifv
->ifv_p
!= NULL
) {
619 lwkt_serialize_exit(ifp
->if_serializer
);
620 lwkt_serialize_enter(ifv
->ifv_p
->if_serializer
);
621 error
= ifv
->ifv_p
->if_ioctl(ifv
->ifv_p
,
622 SIOCGIFMEDIA
, data
, cr
);
623 lwkt_serialize_exit(ifv
->ifv_p
->if_serializer
);
624 lwkt_serialize_enter(ifp
->if_serializer
);
625 /* Limit the result to the parent's current config. */
627 struct ifmediareq
*ifmr
;
629 ifmr
= (struct ifmediareq
*) data
;
630 if (ifmr
->ifm_count
>= 1 && ifmr
->ifm_ulist
) {
632 error
= copyout(&ifmr
->ifm_current
,
647 * Set the interface MTU.
648 * This is bogus. The underlying interface might support
651 if (ifr
->ifr_mtu
> ETHERMTU
) {
654 ifp
->if_mtu
= ifr
->ifr_mtu
;
659 error
= copyin(ifr
->ifr_data
, &vlr
, sizeof vlr
);
662 if (vlr
.vlr_parent
[0] == '\0') {
664 if (ifp
->if_flags
& IFF_UP
)
666 ifp
->if_flags
&= ~IFF_RUNNING
;
669 p
= ifunit(vlr
.vlr_parent
);
674 error
= vlan_config(ifv
, p
);
677 ifv
->ifv_tag
= vlr
.vlr_tag
;
678 ifp
->if_flags
|= IFF_RUNNING
;
682 bzero(&vlr
, sizeof vlr
);
684 strlcpy(vlr
.vlr_parent
, ifv
->ifv_p
->if_xname
,
685 sizeof(vlr
.vlr_parent
));
686 vlr
.vlr_tag
= ifv
->ifv_tag
;
688 error
= copyout(&vlr
, ifr
->ifr_data
, sizeof vlr
);
693 * We don't support promiscuous mode
694 * right now because it would require help from the
695 * underlying drivers, which hasn't been implemented.
697 if (ifr
->ifr_flags
& (IFF_PROMISC
)) {
698 ifp
->if_flags
&= ~(IFF_PROMISC
);
704 error
= vlan_setmulti(ifp
);