2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright 1998 Massachusetts Institute of Technology
25 * Permission to use, copy, modify, and distribute this software and
26 * its documentation for any purpose and without fee is hereby
27 * granted, provided that both the above copyright notice and this
28 * permission notice appear in all copies, that both the above
29 * copyright notice and this permission notice appear in all
30 * supporting documentation, and that the name of M.I.T. not be used
31 * in advertising or publicity pertaining to distribution of the
32 * software without specific, written prior permission. M.I.T. makes
33 * no representations about the suitability of this software for any
34 * purpose. It is provided "as is" without express or implied
37 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
38 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
41 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * $FreeBSD: src/sys/net/if_vlan.c,v 1.54 2003/10/31 18:32:08 brooks Exp $
54 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
55 * Might be extended some day to also handle IEEE 802.1p priority
56 * tagging. This is sort of sneaky in the implementation, since
57 * we need to pretend to be enough of an Ethernet implementation
58 * to make arp work. The way we do this is by telling everyone
59 * that we are an Ethernet, and then catch the packets that
60 * ether_output() left on our output queue when it calls
61 * if_start(), rewrite them for use by the real outgoing interface,
62 * and ask it to send them.
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/malloc.h>
70 #include <sys/queue.h>
71 #include <sys/socket.h>
72 #include <sys/sockio.h>
73 #include <sys/sysctl.h>
74 #include <sys/systm.h>
75 #include <sys/kern_event.h>
78 #include <net/ethernet.h>
80 #include <net/if_arp.h>
81 #include <net/if_dl.h>
82 #include <net/if_types.h>
83 #include <net/if_vlan_var.h>
88 #include <netinet/in.h>
89 #include <netinet/if_ether.h>
92 #include <net/if_media.h>
94 #define ETHER_VLAN_ENCAP_LEN 4 /* len of 802.1Q VLAN encapsulation */
95 #define IF_MAXUNIT 0x7fff /* historical value */
97 #define IFP2AC(p) ((struct arpcom *)p)
99 #define VLAN_PROTO_FAMILY 0x766c616e /* 'vlan' */
101 #define VLANNAME "vlan"
103 typedef int (bpf_callback_func
)(struct ifnet
*, struct mbuf
*);
104 typedef int (if_set_bpf_tap_func
)(struct ifnet
*ifp
, int mode
, bpf_callback_func
* func
);
106 struct vlan_mc_entry
{
107 struct ether_addr mc_addr
;
108 SLIST_ENTRY(vlan_mc_entry
) mc_entries
;
112 char ifv_name
[IFNAMSIZ
]; /* our unique id */
113 struct ifnet
*ifv_ifp
; /* our interface */
114 struct ifnet
*ifv_p
; /* parent interface of this vlan */
117 int ifvm_encaplen
; /* encapsulation length */
118 int ifvm_mtufudge
; /* MTU fudged by this much */
119 int ifvm_mintu
; /* min transmission unit */
120 u_int16_t ifvm_proto
; /* encapsulation ethertype */
121 u_int16_t ifvm_tag
; /* tag to apply on packets leaving if */
123 SLIST_HEAD(__vlan_mchead
, vlan_mc_entry
) vlan_mc_listhead
;
124 LIST_ENTRY(ifvlan
) ifv_list
;
127 u_long ifv_filter_id
;
128 int ifv_filter_valid
;
129 bpf_callback_func
* ifv_bpf_input
;
130 bpf_callback_func
* ifv_bpf_output
;
133 #define ifv_tag ifv_mib.ifvm_tag
134 #define ifv_encaplen ifv_mib.ifvm_encaplen
135 #define ifv_mtufudge ifv_mib.ifvm_mtufudge
136 #define ifv_mintu ifv_mib.ifvm_mintu
138 #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
141 SYSCTL_DECL(_net_link
);
142 SYSCTL_NODE(_net_link
, IFT_L2VLAN
, vlan
, CTLFLAG_RW
, 0, "IEEE 802.1Q VLAN");
143 SYSCTL_NODE(_net_link_vlan
, PF_LINK
, link
, CTLFLAG_RW
, 0, "for consistency");
146 #define M_VLAN M_DEVBUF
148 MALLOC_DEFINE(M_VLAN
, VLANNAME
, "802.1Q Virtual LAN Interface");
150 static LIST_HEAD(, ifvlan
) ifv_list
;
154 * Locking: one lock is used to guard both the ifv_list and modification
155 * to vlan data structures. We are rather conservative here; probably
156 * more than necessary.
158 static struct mtx ifv_mtx
;
159 #define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
160 #define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx)
161 #define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED)
162 #define VLAN_LOCK() mtx_lock(&ifv_mtx)
163 #define VLAN_UNLOCK() mtx_unlock(&ifv_mtx)
165 #define VLAN_LOCK_INIT()
166 #define VLAN_LOCK_DESTROY()
167 #define VLAN_LOCK_ASSERT()
169 #define VLAN_UNLOCK()
172 static int vlan_clone_create(struct if_clone
*, int);
173 static void vlan_clone_destroy(struct ifnet
*);
174 static int vlan_output(struct ifnet
*ifp
, struct mbuf
*m
);
175 static void vlan_ifinit(void *foo
);
176 static int vlan_ioctl(struct ifnet
*ifp
, u_long cmd
, void * addr
);
177 static int vlan_set_bpf_tap(struct ifnet
* ifp
, int mode
,
178 bpf_callback_func
* func
);
179 static int vlan_attach_protocol(struct ifnet
*ifp
);
180 static int vlan_detach_protocol(struct ifnet
*ifp
);
181 static int vlan_attach_filter(struct ifnet
* ifp
, u_long
* filter_id
);
182 static int vlan_detach_filter(u_long filter_id
);
183 static int vlan_setmulti(struct ifnet
*ifp
);
184 static int vlan_unconfig(struct ifnet
*ifp
);
185 static int vlan_config(struct ifvlan
*ifv
, struct ifnet
*p
, int tag
);
186 static int vlan_if_free(struct ifnet
* ifp
);
188 static struct if_clone vlan_cloner
= IF_CLONE_INITIALIZER(VLANNAME
,
189 vlan_clone_create
, vlan_clone_destroy
, 0, IF_MAXUNIT
);
191 static if_set_bpf_tap_func nop_if_bpf
;
192 static int nop_if_free(struct ifnet
*);
193 static int nop_if_ioctl(struct ifnet
*, u_long
, void *);
194 static int nop_if_output(struct ifnet
* ifp
, struct mbuf
* m
);
196 static void interface_link_event(struct ifnet
* ifp
, u_long event_code
);
198 static __inline__
void
199 vlan_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
200 bpf_callback_func func
)
208 static __inline__
void
209 vlan_bpf_input(struct ifnet
* ifp
, struct mbuf
* m
,
210 bpf_callback_func func
, char * frame_header
,
211 int frame_header_len
, int encap_len
)
215 /* present the right header to bpf */
216 bcopy(frame_header
, frame_header
+ encap_len
, frame_header_len
);
218 m
->m_data
-= frame_header_len
;
219 m
->m_len
+= frame_header_len
;
221 m
->m_data
+= frame_header_len
;
222 m
->m_len
-= frame_header_len
;
224 /* restore the header */
225 bcopy(frame_header
+ encap_len
, frame_header
, frame_header_len
);
231 static struct ifaddr
*
232 ifaddr_byindex(unsigned int i
)
234 if (i
> if_index
|| i
== 0) {
237 return (ifnet_addrs
[i
- 1]);
241 * Program our multicast filter. What we're actually doing is
242 * programming the multicast filter of the parent. This has the
243 * side effect of causing the parent interface to receive multicast
244 * traffic that it doesn't really want, which ends up being discarded
245 * later by the upper protocol layers. Unfortunately, there's no way
246 * to avoid this: there really is only one physical interface.
249 vlan_setmulti(struct ifnet
*ifp
)
252 struct ifmultiaddr
*ifma
, *rifma
= NULL
;
254 struct vlan_mc_entry
*mc
= NULL
;
255 struct sockaddr_dl sdl
;
258 /* Find the parent. */
259 sc
= ifp
->if_private
;
262 /* no parent, so no need to program the multicast filter */
266 bzero((char *)&sdl
, sizeof sdl
);
267 sdl
.sdl_len
= sizeof sdl
;
268 sdl
.sdl_family
= AF_LINK
;
269 sdl
.sdl_index
= p
->if_index
;
270 sdl
.sdl_type
= IFT_ETHER
;
271 sdl
.sdl_alen
= ETHER_ADDR_LEN
;
273 /* First, remove any existing filter entries. */
274 while (SLIST_FIRST(&sc
->vlan_mc_listhead
) != NULL
) {
275 mc
= SLIST_FIRST(&sc
->vlan_mc_listhead
);
276 bcopy((char *)&mc
->mc_addr
, LLADDR(&sdl
), ETHER_ADDR_LEN
);
277 error
= if_delmulti(p
, (struct sockaddr
*)&sdl
);
280 SLIST_REMOVE_HEAD(&sc
->vlan_mc_listhead
, mc_entries
);
284 /* Now program new ones. */
285 LIST_FOREACH(ifma
, &ifp
->if_multiaddrs
, ifma_link
) {
286 if (ifma
->ifma_addr
->sa_family
!= AF_LINK
)
288 mc
= _MALLOC(sizeof(struct vlan_mc_entry
), M_VLAN
, M_WAITOK
);
289 bcopy(LLADDR((struct sockaddr_dl
*)ifma
->ifma_addr
),
290 (char *)&mc
->mc_addr
, ETHER_ADDR_LEN
);
291 SLIST_INSERT_HEAD(&sc
->vlan_mc_listhead
, mc
, mc_entries
);
292 bcopy(LLADDR((struct sockaddr_dl
*)ifma
->ifma_addr
),
293 LLADDR(&sdl
), ETHER_ADDR_LEN
);
294 error
= if_addmulti(p
, (struct sockaddr
*)&sdl
, &rifma
);
304 * VLAN support can be loaded as a module. The only place in the
305 * system that's intimately aware of this is ether_input. We hook
306 * into this code through vlan_input_p which is defined there and
307 * set here. Noone else in the system should be aware of this so
308 * we use an explicit reference here.
310 * NB: Noone should ever need to check if vlan_input_p is null or
311 * not. This is because interfaces have a count of the number
312 * of active vlans (if_nvlans) and this should never be bumped
313 * except by vlan_config--which is in this module so therefore
314 * the module must be loaded and vlan_input_p must be non-NULL.
316 extern void (*vlan_input_p
)(struct ifnet
*, struct mbuf
*);
319 vlan_modevent(module_t mod
, int type
, void *data
)
324 LIST_INIT(&ifv_list
);
326 vlan_input_p
= vlan_input
;
327 if_clone_attach(&vlan_cloner
);
330 if_clone_detach(&vlan_cloner
);
332 while (!LIST_EMPTY(&ifv_list
))
333 vlan_clone_destroy(LIST_FIRST(&ifv_list
)->ifv_ifp
);
340 static moduledata_t vlan_mod
= {
346 DECLARE_MODULE(if_vlan
, vlan_mod
, SI_SUB_PSEUDO
, SI_ORDER_ANY
);
350 static struct ifvlan
*
351 vlan_lookup_ifp_and_tag(struct ifnet
* ifp
, int tag
)
355 LIST_FOREACH(ifv
, &ifv_list
, ifv_list
) {
356 if (ifp
== ifv
->ifv_p
&& tag
== ifv
->ifv_tag
) {
363 static struct ifvlan
*
364 vlan_lookup_ifp(struct ifnet
* ifp
)
368 LIST_FOREACH(ifv
, &ifv_list
, ifv_list
) {
369 if (ifp
== ifv
->ifv_p
) {
377 vlan_clone_attach(void)
379 if_clone_attach(&vlan_cloner
);
384 vlan_clone_create(struct if_clone
*ifc
, int unit
)
390 ifv
= _MALLOC(sizeof(struct ifvlan
), M_VLAN
, M_WAITOK
);
391 bzero(ifv
, sizeof(struct ifvlan
));
392 SLIST_INIT(&ifv
->vlan_mc_listhead
);
394 /* use the interface name as the unique id for ifp recycle */
395 if (snprintf(ifv
->ifv_name
, sizeof(ifv
->ifv_name
), "%s%d",
396 ifc
->ifc_name
, unit
) >= sizeof(ifv
->ifv_name
)) {
400 error
= dlil_if_acquire(APPLE_IF_FAM_VLAN
,
402 strlen(ifv
->ifv_name
),
409 ifp
->if_private
= ifv
;
410 ifp
->if_name
= (char *)ifc
->ifc_name
;
412 ifp
->if_family
= APPLE_IF_FAM_VLAN
;
415 /* NB: flags are not set here */
416 ifp
->if_linkmib
= &ifv
->ifv_mib
;
417 ifp
->if_linkmiblen
= sizeof ifv
->ifv_mib
;
418 /* NB: mtu is not set here */
421 ifp
->if_ioctl
= vlan_ioctl
;
422 ifp
->if_set_bpf_tap
= vlan_set_bpf_tap
;
423 ifp
->if_free
= nop_if_free
;
424 ifp
->if_output
= nop_if_output
;
425 ifp
->if_hwassist
= 0;
426 ifp
->if_addrlen
= ETHER_ADDR_LEN
; /* XXX ethernet specific */
427 ifp
->if_baudrate
= 0;
428 ifp
->if_type
= IFT_L2VLAN
;
429 ifp
->if_hdrlen
= ETHER_VLAN_ENCAP_LEN
;
430 error
= dlil_if_attach(ifp
);
432 dlil_if_release(ifp
);
437 /* attach as ethernet */
438 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
441 LIST_INSERT_HEAD(&ifv_list
, ifv
, ifv_list
);
448 vlan_remove(struct ifvlan
* ifv
)
451 ifv
->ifv_detaching
= 1;
452 vlan_unconfig(ifv
->ifv_ifp
);
453 LIST_REMOVE(ifv
, ifv_list
);
458 vlan_if_detach(struct ifnet
* ifp
)
460 ifp
->if_output
= nop_if_output
;
461 ifp
->if_ioctl
= nop_if_ioctl
;
462 ifp
->if_set_bpf_tap
= &nop_if_bpf
;
463 if (dlil_if_detach(ifp
) == DLIL_WAIT_FOR_FREE
) {
464 ifp
->if_free
= vlan_if_free
;
472 vlan_clone_destroy(struct ifnet
*ifp
)
474 struct ifvlan
*ifv
= ifp
->if_private
;
476 if (ifv
== NULL
|| ifp
->if_type
!= IFT_L2VLAN
) {
480 if (ifv
->ifv_detaching
) {
491 vlan_set_bpf_tap(struct ifnet
* ifp
, int mode
, bpf_callback_func
* func
)
493 struct ifvlan
*ifv
= ifp
->if_private
;
496 case BPF_TAP_DISABLE
:
497 ifv
->ifv_bpf_input
= ifv
->ifv_bpf_output
= NULL
;
501 ifv
->ifv_bpf_input
= func
;
505 ifv
->ifv_bpf_output
= func
;
508 case BPF_TAP_INPUT_OUTPUT
:
509 ifv
->ifv_bpf_input
= ifv
->ifv_bpf_output
= func
;
518 vlan_ifinit(void *foo
)
524 vlan_output(struct ifnet
*ifp
, struct mbuf
*m
)
528 struct ether_vlan_header
*evl
;
531 ifv
= ifp
->if_private
;
534 return (nop_if_output(ifp
, m
));
537 printf("%s: NULL output mbuf\n", ifv
->ifv_name
);
540 if ((m
->m_flags
& M_PKTHDR
) == 0) {
541 printf("%s: M_PKTHDR bit not set\n", ifv
->ifv_name
);
545 ifp
->if_obytes
+= m
->m_pkthdr
.len
;
547 soft_vlan
= (p
->if_hwassist
& IF_HWASSIST_VLAN_TAGGING
) == 0;
548 vlan_bpf_output(ifp
, m
, ifv
->ifv_bpf_output
);
550 /* do not run parent's if_output() if the parent is not up */
551 if ((p
->if_flags
& (IFF_UP
| IFF_RUNNING
)) != (IFF_UP
| IFF_RUNNING
)) {
553 ifp
->if_collisions
++;
557 * If underlying interface can do VLAN tag insertion itself,
558 * just pass the packet along. However, we need some way to
559 * tell the interface where the packet came from so that it
560 * knows how to find the VLAN tag to use. We use a field in
561 * the mbuf header to store the VLAN tag, and a bit in the
562 * csum_flags field to mark the field as valid.
564 if (soft_vlan
== 0) {
565 m
->m_pkthdr
.csum_flags
|= CSUM_VLAN_TAG_VALID
;
566 m
->m_pkthdr
.vlan_tag
= ifv
->ifv_tag
;
568 M_PREPEND(m
, ifv
->ifv_encaplen
, M_DONTWAIT
);
570 printf("%s: unable to prepend VLAN header\n",
575 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
576 if (m
->m_len
< sizeof(*evl
)) {
577 m
= m_pullup(m
, sizeof(*evl
));
579 printf("%s: cannot pullup VLAN header\n",
587 * Transform the Ethernet header into an Ethernet header
588 * with 802.1Q encapsulation.
590 bcopy(mtod(m
, char *) + ifv
->ifv_encaplen
,
591 mtod(m
, char *), ETHER_HDR_LEN
);
592 evl
= mtod(m
, struct ether_vlan_header
*);
593 evl
->evl_proto
= evl
->evl_encap_proto
;
594 evl
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
595 evl
->evl_tag
= htons(ifv
->ifv_tag
);
596 m
->m_pkthdr
.len
+= ifv
->ifv_encaplen
;
600 * Send it, precisely as ether_output() would have.
601 * We are already running at splimp.
603 return ((*p
->if_output
)(p
, m
));
607 vlan_demux(struct ifnet
* ifp
, struct mbuf
* m
,
608 char * frame_header
, struct if_proto
* * proto
)
610 register struct ether_header
*eh
= (struct ether_header
*)frame_header
;
611 struct ether_vlan_header
*evl
;
612 struct ifvlan
*ifv
= NULL
;
616 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
618 * Packet is tagged, m contains a normal
619 * Ethernet frame; the tag is stored out-of-band.
621 m
->m_pkthdr
.csum_flags
&= ~CSUM_VLAN_TAG_VALID
;
622 tag
= EVL_VLANOFTAG(m
->m_pkthdr
.vlan_tag
);
623 m
->m_pkthdr
.vlan_tag
= 0;
627 switch (ifp
->if_type
) {
629 if (m
->m_len
< ETHER_VLAN_ENCAP_LEN
) {
631 return (EJUSTRETURN
);
633 evl
= (struct ether_vlan_header
*)frame_header
;
634 if (ntohs(evl
->evl_proto
) == ETHERTYPE_VLAN
) {
635 /* don't allow VLAN within VLAN */
637 return (EJUSTRETURN
);
639 tag
= EVL_VLANOFTAG(ntohs(evl
->evl_tag
));
642 * Restore the original ethertype. We'll remove
643 * the encapsulation after we've found the vlan
644 * interface corresponding to the tag.
646 evl
->evl_encap_proto
= evl
->evl_proto
;
649 printf("vlan_demux: unsupported if type %u",
652 return (EJUSTRETURN
);
657 if (ifp
->if_nvlans
== 0) {
658 /* don't bother looking through the VLAN list */
661 return (EJUSTRETURN
);
664 ifv
= vlan_lookup_ifp_and_tag(ifp
, tag
);
665 if (ifv
== NULL
|| (ifv
->ifv_ifp
->if_flags
& IFF_UP
) == 0) {
669 return (EJUSTRETURN
);
671 VLAN_UNLOCK(); /* XXX extend below? */
675 * Packet had an in-line encapsulation header;
676 * remove it. The original header has already
677 * been fixed up above.
679 m
->m_len
-= ETHER_VLAN_ENCAP_LEN
;
680 m
->m_data
+= ETHER_VLAN_ENCAP_LEN
;
681 m
->m_pkthdr
.len
-= ETHER_VLAN_ENCAP_LEN
;
682 m
->m_pkthdr
.csum_flags
= 0; /* can't trust hardware checksum */
685 /* we found a vlan interface above, so send it up */
686 m
->m_pkthdr
.rcvif
= ifv
->ifv_ifp
;
687 ifv
->ifv_ifp
->if_ipackets
++;
688 ifv
->ifv_ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
690 vlan_bpf_input(ifv
->ifv_ifp
, m
, ifv
->ifv_bpf_input
, frame_header
,
691 ETHER_HDR_LEN
, soft_vlan
? ETHER_VLAN_ENCAP_LEN
: 0);
693 /* Pass it back through the parent's demux routine. */
694 return ((*ifp
->if_demux
)(ifv
->ifv_ifp
, m
, frame_header
, proto
));
696 /* Pass it back through calling demux routine. */
697 return ((*ifp
->if_demux
)(ifp
, m
, frame_header
, proto
));
701 vlan_config(struct ifvlan
*ifv
, struct ifnet
*p
, int tag
)
704 struct ifaddr
*ifa1
, *ifa2
;
705 struct sockaddr_dl
*sdl1
, *sdl2
;
706 int supports_vlan_mtu
= 0;
709 if (p
->if_data
.ifi_type
!= IFT_ETHER
)
710 return EPROTONOSUPPORT
;
711 if (ifv
->ifv_p
!= NULL
|| ifv
->ifv_detaching
) {
714 if (vlan_lookup_ifp_and_tag(p
, tag
) != NULL
) {
715 /* already a VLAN with that tag on this interface */
719 ifv
->ifv_encaplen
= ETHER_VLAN_ENCAP_LEN
;
720 ifv
->ifv_mintu
= ETHERMIN
;
724 * If the parent supports the VLAN_MTU capability,
725 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
728 if (p
->if_hwassist
& (IF_HWASSIST_VLAN_MTU
| IF_HWASSIST_VLAN_TAGGING
)) {
729 supports_vlan_mtu
= 1;
731 if (p
->if_nvlans
== 0) {
736 /* attach our VLAN "interface filter" to the interface */
737 error
= vlan_attach_filter(p
, &filter_id
);
742 /* attach our VLAN "protocol" to the interface */
743 error
= vlan_attach_protocol(p
);
745 (void)vlan_detach_filter(filter_id
);
748 ifv
->ifv_filter_id
= filter_id
;
749 ifv
->ifv_filter_valid
= TRUE
;
751 if (supports_vlan_mtu
) {
753 * Enable Tx/Rx of VLAN-sized frames.
755 p
->if_capenable
|= IFCAP_VLAN_MTU
;
756 if (p
->if_flags
& IFF_UP
) {
760 ifr
.ifr_flags
= p
->if_flags
;
761 error
= (*p
->if_ioctl
)(p
, SIOCSIFFLAGS
,
764 if (p
->if_nvlans
== 0)
765 p
->if_capenable
&= ~IFCAP_VLAN_MTU
;
772 struct ifvlan
* other_ifv
;
774 other_ifv
= vlan_lookup_ifp(p
);
775 if (other_ifv
== NULL
) {
776 printf("vlan: other_ifv can't be NULL\n");
779 ifv
->ifv_filter_id
= other_ifv
->ifv_filter_id
;
780 ifv
->ifv_filter_valid
= TRUE
;
783 if (supports_vlan_mtu
) {
784 ifv
->ifv_mtufudge
= 0;
787 * Fudge the MTU by the encapsulation size. This
788 * makes us incompatible with strictly compliant
789 * 802.1Q implementations, but allows us to use
790 * the feature with other NetBSD implementations,
791 * which might still be useful.
793 ifv
->ifv_mtufudge
= ifv
->ifv_encaplen
;
797 ifp
->if_mtu
= p
->if_mtu
- ifv
->ifv_mtufudge
;
799 * Copy only a selected subset of flags from the parent.
800 * Other flags are none of our business.
802 ifp
->if_flags
|= (p
->if_flags
&
803 (IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
));
805 * If the parent interface can do hardware-assisted
806 * VLAN encapsulation, then propagate its hardware-
807 * assisted checksumming flags.
809 if (p
->if_hwassist
& IF_HWASSIST_VLAN_TAGGING
) {
810 ifp
->if_hwassist
|= IF_HWASSIST_CSUM_FLAGS(p
->if_hwassist
);
813 * Set up our ``Ethernet address'' to reflect the underlying
814 * physical interface's.
816 ifa1
= ifaddr_byindex(ifp
->if_index
);
817 ifa2
= ifaddr_byindex(p
->if_index
);
818 sdl1
= (struct sockaddr_dl
*)ifa1
->ifa_addr
;
819 sdl2
= (struct sockaddr_dl
*)ifa2
->ifa_addr
;
820 sdl1
->sdl_type
= IFT_ETHER
;
821 sdl1
->sdl_alen
= ETHER_ADDR_LEN
;
822 bcopy(LLADDR(sdl2
), LLADDR(sdl1
), ETHER_ADDR_LEN
);
823 bcopy(LLADDR(sdl2
), IFP2AC(ifp
)->ac_enaddr
, ETHER_ADDR_LEN
);
826 * Configure multicast addresses that may already be
827 * joined on the vlan device.
829 (void)vlan_setmulti(ifp
);
830 ifp
->if_output
= vlan_output
;
837 vlan_link_event(struct ifnet
* ifp
, struct ifnet
* p
)
839 struct ifmediareq ifmr
;
841 /* generate a link event based on the state of the underlying interface */
842 bzero(&ifmr
, sizeof(ifmr
));
843 snprintf(ifmr
.ifm_name
, sizeof(ifmr
.ifm_name
),
844 "%s%d", p
->if_name
, p
->if_unit
);
845 if ((*p
->if_ioctl
)(p
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == 0
846 && ifmr
.ifm_count
> 0 && ifmr
.ifm_status
& IFM_AVALID
) {
849 event
= (ifmr
.ifm_status
& IFM_ACTIVE
)
850 ? KEV_DL_LINK_ON
: KEV_DL_LINK_OFF
;
851 interface_link_event(ifp
, event
);
857 vlan_unconfig(struct ifnet
*ifp
)
860 struct sockaddr_dl
*sdl
;
861 struct vlan_mc_entry
*mc
;
868 ifv
= ifp
->if_private
;
870 /* Disconnect from parent. */
875 struct sockaddr_dl sdl
;
878 * Since the interface is being unconfigured, we need to
879 * empty the list of multicast groups that we may have joined
880 * while we were alive from the parent's list.
882 bzero((char *)&sdl
, sizeof sdl
);
883 sdl
.sdl_len
= sizeof sdl
;
884 sdl
.sdl_family
= AF_LINK
;
885 sdl
.sdl_index
= p
->if_index
;
886 sdl
.sdl_type
= IFT_ETHER
;
887 sdl
.sdl_alen
= ETHER_ADDR_LEN
;
889 while (SLIST_FIRST(&ifv
->vlan_mc_listhead
) != NULL
) {
890 mc
= SLIST_FIRST(&ifv
->vlan_mc_listhead
);
891 bcopy((char *)&mc
->mc_addr
, LLADDR(&sdl
), ETHER_ADDR_LEN
);
892 error
= if_delmulti(p
, (struct sockaddr
*)&sdl
);
894 printf("vlan_unconfig: if_delmulti %s failed, %d\n",
895 ifv
->ifv_name
, error
);
897 SLIST_REMOVE_HEAD(&ifv
->vlan_mc_listhead
, mc_entries
);
901 if (p
->if_nvlans
== 0) {
902 /* detach our VLAN "protocol" from the interface */
903 if (ifv
->ifv_filter_valid
) {
904 (void)vlan_detach_filter(ifv
->ifv_filter_id
);
906 (void)vlan_detach_protocol(p
);
909 * Disable Tx/Rx of VLAN-sized frames.
911 p
->if_capenable
&= ~IFCAP_VLAN_MTU
;
912 if (p
->if_flags
& IFF_UP
) {
915 ifr
.ifr_flags
= p
->if_flags
;
916 (*p
->if_ioctl
)(p
, SIOCSIFFLAGS
, (caddr_t
) &ifr
);
922 /* return to the state we were in before SETVLAN */
924 ifp
->if_flags
&= ~(IFF_BROADCAST
| IFF_MULTICAST
925 | IFF_SIMPLEX
| IFF_RUNNING
);
926 ifv
->ifv_ifp
->if_hwassist
= 0;
928 ifv
->ifv_ifp
->if_output
= nop_if_output
;
929 ifv
->ifv_mtufudge
= 0;
930 ifv
->ifv_filter_valid
= FALSE
;
932 /* Clear our MAC address. */
933 ifa
= ifaddr_byindex(ifv
->ifv_ifp
->if_index
);
934 sdl
= (struct sockaddr_dl
*)(ifa
->ifa_addr
);
935 sdl
->sdl_type
= IFT_L2VLAN
;
937 bzero(LLADDR(sdl
), ETHER_ADDR_LEN
);
938 bzero(IFP2AC(ifv
->ifv_ifp
)->ac_enaddr
, ETHER_ADDR_LEN
);
940 /* send a link down event */
942 interface_link_event(ifv
->ifv_ifp
, KEV_DL_LINK_OFF
);
948 vlan_set_promisc(struct ifnet
*ifp
)
950 struct ifvlan
*ifv
= ifp
->if_private
;
953 if ((ifp
->if_flags
& IFF_PROMISC
) != 0) {
954 if ((ifv
->ifv_flags
& IFVF_PROMISC
) == 0) {
955 error
= ifpromisc(ifv
->ifv_p
, 1);
957 ifv
->ifv_flags
|= IFVF_PROMISC
;
960 if ((ifv
->ifv_flags
& IFVF_PROMISC
) != 0) {
961 error
= ifpromisc(ifv
->ifv_p
, 0);
963 ifv
->ifv_flags
&= ~IFVF_PROMISC
;
971 vlan_ioctl(struct ifnet
*ifp
, u_long cmd
, void * data
)
980 ifr
= (struct ifreq
*)data
;
981 ifa
= (struct ifaddr
*)data
;
982 ifv
= (struct ifvlan
*)ifp
->if_private
;
986 ifp
->if_flags
|= IFF_UP
;
991 if (ifv
->ifv_p
!= NULL
) {
992 error
= (*ifv
->ifv_p
->if_ioctl
)(ifv
->ifv_p
,
995 /* Limit the result to the parent's current config. */
997 struct ifmediareq
*ifmr
;
999 ifmr
= (struct ifmediareq
*) data
;
1000 if (ifmr
->ifm_count
>= 1 && ifmr
->ifm_ulist
) {
1001 ifmr
->ifm_count
= 1;
1002 error
= copyout(&ifmr
->ifm_current
,
1008 struct ifmediareq
*ifmr
;
1011 ifmr
= (struct ifmediareq
*) data
;
1012 ifmr
->ifm_current
= 0;
1014 ifmr
->ifm_status
= IFM_AVALID
;
1015 ifmr
->ifm_active
= 0;
1016 ifmr
->ifm_count
= 1;
1017 if (ifmr
->ifm_ulist
) {
1018 error
= copyout(&ifmr
->ifm_current
,
1032 * Set the interface MTU.
1035 if (ifv
->ifv_p
!= NULL
) {
1036 if (ifr
->ifr_mtu
> (ifv
->ifv_p
->if_mtu
- ifv
->ifv_mtufudge
)
1037 || ifr
->ifr_mtu
< (ifv
->ifv_mintu
- ifv
->ifv_mtufudge
)) {
1040 ifp
->if_mtu
= ifr
->ifr_mtu
;
1049 error
= copyin(ifr
->ifr_data
, &vlr
, sizeof(vlr
));
1052 if (vlr
.vlr_parent
[0] == '\0') {
1056 if (ifp
->if_flags
& IFF_UP
)
1058 ifp
->if_flags
&= ~IFF_RUNNING
;
1063 p
= ifunit(vlr
.vlr_parent
);
1069 * Don't let the caller set up a VLAN tag with
1070 * anything except VLID bits.
1072 if (vlr
.vlr_tag
& ~EVL_VLID_MASK
) {
1077 error
= vlan_config(ifv
, p
, vlr
.vlr_tag
);
1082 ifp
->if_flags
|= IFF_RUNNING
;
1085 /* Update promiscuous mode, if necessary. */
1086 vlan_set_promisc(ifp
);
1088 /* generate a link event */
1089 vlan_link_event(ifp
, p
);
1093 bzero(&vlr
, sizeof vlr
);
1095 if (ifv
->ifv_p
!= NULL
) {
1096 snprintf(vlr
.vlr_parent
, sizeof(vlr
.vlr_parent
),
1097 "%s%d", ifv
->ifv_p
->if_name
,
1098 ifv
->ifv_p
->if_unit
);
1099 vlr
.vlr_tag
= ifv
->ifv_tag
;
1102 error
= copyout(&vlr
, ifr
->ifr_data
, sizeof vlr
);
1107 * For promiscuous mode, we enable promiscuous mode on
1108 * the parent if we need promiscuous on the VLAN interface.
1110 if (ifv
->ifv_p
!= NULL
)
1111 error
= vlan_set_promisc(ifp
);
1116 error
= vlan_setmulti(ifp
);
1125 nop_if_ioctl(struct ifnet
* ifp
, u_long cmd
, void * data
)
1131 nop_if_bpf(struct ifnet
*ifp
, int mode
, bpf_callback_func
* func
)
1137 nop_if_free(struct ifnet
* ifp
)
1143 nop_if_output(struct ifnet
* ifp
, struct mbuf
* m
)
1152 vlan_if_free(struct ifnet
* ifp
)
1159 ifv
= (struct ifvlan
*)ifp
->if_private
;
1163 ifp
->if_private
= NULL
;
1164 dlil_if_release(ifp
);
1170 * Function: vlan_if_filter_detach
1172 * Destroy all vlan interfaces that refer to the interface
1175 vlan_if_filter_detach(caddr_t cookie
)
1178 struct ifvlan
* ifv
;
1179 struct ifnet
* p
= (struct ifnet
*)cookie
;
1183 ifv
= vlan_lookup_ifp(p
);
1187 if (ifv
->ifv_detaching
) {
1190 /* make sure we don't invoke vlan_detach_filter */
1191 ifv
->ifv_filter_valid
= FALSE
;
1195 vlan_if_detach(ifp
);
1203 * Function: vlan_attach_filter
1205 * We attach an interface filter to detect when the underlying interface
1206 * goes away. We are forced to do that because dlil does not call our
1207 * protocol's dl_event function for KEV_DL_IF_DETACHING.
1211 vlan_attach_filter(struct ifnet
* ifp
, u_long
* filter_id
)
1214 struct dlil_if_flt_str filt
;
1216 bzero(&filt
, sizeof(filt
));
1217 filt
.filter_detach
= vlan_if_filter_detach
;
1218 filt
.cookie
= (caddr_t
)ifp
;
1219 error
= dlil_attach_interface_filter(ifp
, &filt
, filter_id
,
1222 printf("vlan: dlil_attach_interface_filter(%s%d) failed, %d\n",
1223 ifp
->if_name
, ifp
->if_unit
, error
);
1229 * Function: vlan_detach_filter
1231 * Remove our interface filter.
1234 vlan_detach_filter(u_long filter_id
)
1238 error
= dlil_detach_filter(filter_id
);
1240 printf("vlan: dlil_detach_filter failed, %d\n", error
);
1246 * Function: vlan_proto_input
1248 * This function is never called. We aren't allowed to leave the
1249 * function pointer NULL, so this function simply free's the mbuf.
1252 vlan_proto_input(m
, frame_header
, ifp
, dl_tag
, sync_ok
)
1260 return (EJUSTRETURN
);
1263 static struct ifnet
*
1264 find_if_name_unit(const char * if_name
, int unit
)
1268 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
1269 if (strcmp(if_name
, ifp
->if_name
) == 0 && unit
== ifp
->if_unit
) {
1277 interface_link_event(struct ifnet
* ifp
, u_long event_code
)
1280 struct kern_event_msg header
;
1282 char if_name
[IFNAMSIZ
];
1285 event
.header
.total_size
= sizeof(event
);
1286 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
1287 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
1288 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
1289 event
.header
.event_code
= event_code
;
1290 event
.header
.event_data
[0] = ifp
->if_family
;
1291 event
.unit
= (u_long
) ifp
->if_unit
;
1292 strncpy(event
.if_name
, ifp
->if_name
, IFNAMSIZ
);
1293 dlil_event(ifp
, &event
.header
);
1298 parent_link_event(struct ifnet
* p
, u_long event_code
)
1300 struct ifvlan
* ifv
;
1302 LIST_FOREACH(ifv
, &ifv_list
, ifv_list
) {
1303 if (p
== ifv
->ifv_p
) {
1304 interface_link_event(ifv
->ifv_ifp
, event_code
);
1312 * Function: vlan_dl_event
1314 * Process DLIL events that interest us. Currently, that is
1315 * just the interface UP and DOWN. Ideally, this would also
1316 * include the KEV_DL_IF_DETACH{ING} messages, which would eliminate
1317 * the need for an interface filter.
1320 vlan_dl_event(struct kern_event_msg
* event
, u_long dl_tag
)
1323 struct net_event_data
* net_event
;
1325 if (event
->vendor_code
!= KEV_VENDOR_APPLE
1326 || event
->kev_class
!= KEV_NETWORK_CLASS
1327 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
1330 net_event
= (struct net_event_data
*)(event
->event_data
);
1331 switch (event
->event_code
) {
1332 case KEV_DL_LINK_OFF
:
1333 case KEV_DL_LINK_ON
:
1334 p
= find_if_name_unit(net_event
->if_name
, net_event
->if_unit
);
1336 parent_link_event(p
, event
->event_code
);
1340 case KEV_DL_IF_DETACHING
:
1341 case KEV_DL_IF_DETACHED
:
1342 /* we don't get these, unfortunately */
1354 * Function: vlan_attach_protocol
1356 * Attach a DLIL protocol to the interface, using the ETHERTYPE_VLAN
1357 * demux ether type. We're not a real protocol, we'll never receive
1358 * any packets because they're intercepted by ether_demux before
1359 * our input routine would be called.
1361 * The reasons for attaching a protocol to the interface are:
1362 * 1) add a protocol reference to the interface so that the underlying
1363 * interface automatically gets marked up while we're attached
1364 * 2) receive link status events which we can propagate to our
1368 vlan_attach_protocol(struct ifnet
*ifp
)
1370 struct dlil_demux_desc desc
;
1372 u_short en_native
= ETHERTYPE_VLAN
;
1375 struct dlil_proto_reg_str reg
;
1377 TAILQ_INIT(®
.demux_desc_head
);
1378 desc
.type
= DLIL_DESC_RAW
;
1379 desc
.variants
.bitmask
.proto_id_length
= 0;
1380 desc
.variants
.bitmask
.proto_id
= 0;
1381 desc
.variants
.bitmask
.proto_id_mask
= 0;
1382 desc
.native_type
= (char *) &en_native
;
1383 TAILQ_INSERT_TAIL(®
.demux_desc_head
, &desc
, next
);
1384 reg
.interface_family
= ifp
->if_family
;
1385 reg
.unit_number
= ifp
->if_unit
;
1386 reg
.input
= vlan_proto_input
;
1388 reg
.event
= vlan_dl_event
;
1391 reg
.default_proto
= 0;
1392 reg
.protocol_family
= VLAN_PROTO_FAMILY
;
1394 error
= dlil_attach_protocol(®
, &dl_tag
);
1396 printf("vlan_proto_attach(%s%d) dlil_attach_protocol failed, %d\n",
1397 ifp
->if_name
, ifp
->if_unit
, error
);
1403 * Function: vlan_detach_protocol
1405 * Detach our DLIL protocol from an interface
1408 vlan_detach_protocol(struct ifnet
*ifp
)
1413 error
= dlil_find_dltag(ifp
->if_family
, ifp
->if_unit
,
1414 VLAN_PROTO_FAMILY
, &dl_tag
);
1416 printf("vlan_proto_detach(%s%d) dlil_find_dltag failed, %d\n",
1417 ifp
->if_name
, ifp
->if_unit
, error
);
1419 error
= dlil_detach_protocol(dl_tag
);
1421 printf("vlan_proto_detach(%s%d) dlil_detach_protocol failed, %d\n",
1422 ifp
->if_name
, ifp
->if_unit
, error
);
1429 * DLIL interface family functions
1430 * We use the ethernet dlil functions, since that's all we support.
1431 * If we wanted to handle multiple LAN types (tokenring, etc.), we'd
1432 * call the appropriate routines for that LAN type instead of hard-coding
1435 extern int ether_add_if(struct ifnet
*ifp
);
1436 extern int ether_del_if(struct ifnet
*ifp
);
1437 extern int ether_init_if(struct ifnet
*ifp
);
1438 extern int ether_add_proto(struct ddesc_head_str
*desc_head
,
1439 struct if_proto
*proto
, u_long dl_tag
);
1440 extern int ether_del_proto(struct if_proto
*proto
, u_long dl_tag
);
1441 extern int ether_ifmod_ioctl(struct ifnet
*ifp
, u_long command
,
1443 extern int ether_del_proto(struct if_proto
*proto
, u_long dl_tag
);
1444 extern int ether_add_proto(struct ddesc_head_str
*desc_head
, struct if_proto
*proto
, u_long dl_tag
);
1446 extern int ether_attach_inet(struct ifnet
*ifp
, u_long
*dl_tag
);
1447 extern int ether_detach_inet(struct ifnet
*ifp
, u_long dl_tag
);
1448 extern int ether_attach_inet6(struct ifnet
*ifp
, u_long
*dl_tag
);
1449 extern int ether_detach_inet6(struct ifnet
*ifp
, u_long dl_tag
);
1452 vlan_attach_inet(struct ifnet
*ifp
, u_long
*dl_tag
)
1454 return (ether_attach_inet(ifp
, dl_tag
));
1458 vlan_detach_inet(struct ifnet
*ifp
, u_long dl_tag
)
1460 return (ether_detach_inet(ifp
, dl_tag
));
1464 vlan_attach_inet6(struct ifnet
*ifp
, u_long
*dl_tag
)
1466 return (ether_attach_inet6(ifp
, dl_tag
));
1470 vlan_detach_inet6(struct ifnet
*ifp
, u_long dl_tag
)
1472 return (ether_detach_inet6(ifp
, dl_tag
));
1476 vlan_add_if(struct ifnet
*ifp
)
1478 return (ether_add_if(ifp
));
1482 vlan_del_if(struct ifnet
*ifp
)
1484 return (ether_del_if(ifp
));
1488 vlan_init_if(struct ifnet
*ifp
)
1499 __private_extern__
int
1503 struct dlil_ifmod_reg_str ifmod_reg
;
1504 struct dlil_protomod_reg_str vlan_protoreg
;
1507 /* VLAN family is built-in, called from ether_family_init */
1508 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
1511 bzero(&ifmod_reg
, sizeof(ifmod_reg
));
1512 ifmod_reg
.add_if
= vlan_add_if
;
1513 ifmod_reg
.del_if
= vlan_del_if
;
1514 ifmod_reg
.init_if
= vlan_init_if
;
1515 ifmod_reg
.add_proto
= ether_add_proto
;
1516 ifmod_reg
.del_proto
= ether_del_proto
;
1517 ifmod_reg
.ifmod_ioctl
= ether_ifmod_ioctl
;
1518 ifmod_reg
.shutdown
= vlan_shutdown
;
1520 if (dlil_reg_if_modules(APPLE_IF_FAM_VLAN
, &ifmod_reg
)) {
1521 printf("WARNING: vlan_family_init -- "
1522 "Can't register if family modules\n");
1527 /* Register protocol registration functions */
1528 bzero(&vlan_protoreg
, sizeof(vlan_protoreg
));
1529 vlan_protoreg
.attach_proto
= vlan_attach_inet
;
1530 vlan_protoreg
.detach_proto
= vlan_detach_inet
;
1532 if (error
= dlil_reg_proto_module(PF_INET
, APPLE_IF_FAM_VLAN
,
1533 &vlan_protoreg
) != 0) {
1534 kprintf("dlil_reg_proto_module failed for AF_INET6 error=%d\n",
1538 vlan_protoreg
.attach_proto
= vlan_attach_inet6
;
1539 vlan_protoreg
.detach_proto
= vlan_detach_inet6
;
1541 if (error
= dlil_reg_proto_module(PF_INET6
, APPLE_IF_FAM_VLAN
,
1542 &vlan_protoreg
) != 0) {
1543 kprintf("dlil_reg_proto_module failed for AF_INET6 error=%d\n",
1547 vlan_clone_attach();
1551 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);