]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_vlan.c
957865e651bdb6d0795658be89d692f9c25aa4f0
[apple/xnu.git] / bsd / net / if_vlan.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright 1998 Massachusetts Institute of Technology
30 *
31 * Permission to use, copy, modify, and distribute this software and
32 * its documentation for any purpose and without fee is hereby
33 * granted, provided that both the above copyright notice and this
34 * permission notice appear in all copies, that both the above
35 * copyright notice and this permission notice appear in all
36 * supporting documentation, and that the name of M.I.T. not be used
37 * in advertising or publicity pertaining to distribution of the
38 * software without specific, written prior permission. M.I.T. makes
39 * no representations about the suitability of this software for any
40 * purpose. It is provided "as is" without express or implied
41 * warranty.
42 *
43 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
44 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
45 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
46 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
47 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
50 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
51 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 *
56 * $FreeBSD: src/sys/net/if_vlan.c,v 1.54 2003/10/31 18:32:08 brooks Exp $
57 */
58
59 /*
60 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
61 * Might be extended some day to also handle IEEE 802.1p priority
62 * tagging. This is sort of sneaky in the implementation, since
63 * we need to pretend to be enough of an Ethernet implementation
64 * to make arp work. The way we do this is by telling everyone
65 * that we are an Ethernet, and then catch the packets that
66 * ether_output() left on our output queue when it calls
67 * if_start(), rewrite them for use by the real outgoing interface,
68 * and ask it to send them.
69 */
70
71
72 #include <sys/param.h>
73 #include <sys/kernel.h>
74 #include <sys/malloc.h>
75 #include <sys/mbuf.h>
76 #include <sys/queue.h>
77 #include <sys/socket.h>
78 #include <sys/sockio.h>
79 #include <sys/sysctl.h>
80 #include <sys/systm.h>
81 #include <sys/kern_event.h>
82
83 #include <net/bpf.h>
84 #include <net/ethernet.h>
85 #include <net/if.h>
86 #include <net/if_arp.h>
87 #include <net/if_dl.h>
88 #include <net/if_ether.h>
89 #include <net/if_types.h>
90 #include <net/if_vlan_var.h>
91 #include <libkern/OSAtomic.h>
92
93 #include <net/dlil.h>
94
95 #include <kern/locks.h>
96
97 #ifdef INET
98 #include <netinet/in.h>
99 #include <netinet/if_ether.h>
100 #endif
101
102 #include <net/if_media.h>
103 #include <net/multicast_list.h>
104
105 #define IF_MAXUNIT 0x7fff /* historical value */
106
107 #define VLANNAME "vlan"
108
109 typedef int (bpf_callback_func)(struct ifnet *, struct mbuf *);
110 typedef int (if_set_bpf_tap_func)(struct ifnet *ifp, int mode, bpf_callback_func * func);
111
112 /**
113 ** vlan locks
114 **/
115 static __inline__ lck_grp_t *
116 my_lck_grp_alloc_init(const char * grp_name)
117 {
118 lck_grp_t * grp;
119 lck_grp_attr_t * grp_attrs;
120
121 grp_attrs = lck_grp_attr_alloc_init();
122 grp = lck_grp_alloc_init(grp_name, grp_attrs);
123 lck_grp_attr_free(grp_attrs);
124 return (grp);
125 }
126
127 static __inline__ lck_mtx_t *
128 my_lck_mtx_alloc_init(lck_grp_t * lck_grp)
129 {
130 lck_attr_t * lck_attrs;
131 lck_mtx_t * lck_mtx;
132
133 lck_attrs = lck_attr_alloc_init();
134 lck_mtx = lck_mtx_alloc_init(lck_grp, lck_attrs);
135 lck_attr_free(lck_attrs);
136 return (lck_mtx);
137 }
138
139 static lck_mtx_t * vlan_lck_mtx;
140
141 static __inline__ void
142 vlan_lock_init(void)
143 {
144 lck_grp_t * vlan_lck_grp;
145
146 vlan_lck_grp = my_lck_grp_alloc_init("if_vlan");
147 vlan_lck_mtx = my_lck_mtx_alloc_init(vlan_lck_grp);
148 }
149
150 static __inline__ void
151 vlan_assert_lock_held(void)
152 {
153 lck_mtx_assert(vlan_lck_mtx, LCK_MTX_ASSERT_OWNED);
154 return;
155 }
156
157 static __inline__ void
158 vlan_assert_lock_not_held(void)
159 {
160 lck_mtx_assert(vlan_lck_mtx, LCK_MTX_ASSERT_NOTOWNED);
161 return;
162 }
163
164 static __inline__ void
165 vlan_lock(void)
166 {
167 lck_mtx_lock(vlan_lck_mtx);
168 return;
169 }
170
171 static __inline__ void
172 vlan_unlock(void)
173 {
174 lck_mtx_unlock(vlan_lck_mtx);
175 return;
176 }
177
178 /**
179 ** vlan structures, types
180 **/
181 struct vlan_parent;
182 LIST_HEAD(vlan_parent_list, vlan_parent);
183 struct ifvlan;
184 LIST_HEAD(ifvlan_list, ifvlan);
185
186 typedef struct vlan_parent {
187 LIST_ENTRY(vlan_parent) vlp_parent_list;/* list of parents */
188 struct ifnet * vlp_ifp; /* interface */
189 struct ifvlan_list vlp_vlan_list; /* list of VLAN's */
190 #define VLPF_SUPPORTS_VLAN_MTU 0x1
191 #define VLPF_CHANGE_IN_PROGRESS 0x2
192 #define VLPF_DETACHING 0x4
193 u_int32_t vlp_flags;
194 struct ifdevmtu vlp_devmtu;
195 UInt32 vlp_retain_count;
196 } vlan_parent, * vlan_parent_ref;
197
198 struct ifvlan {
199 LIST_ENTRY(ifvlan) ifv_vlan_list;
200 char ifv_name[IFNAMSIZ]; /* our unique id */
201 struct ifnet * ifv_ifp; /* our interface */
202 vlan_parent_ref ifv_vlp; /* parent information */
203 struct ifv_linkmib {
204 u_int16_t ifvm_encaplen;/* encapsulation length */
205 u_int16_t ifvm_mtufudge;/* MTU fudged by this much */
206 u_int16_t ifvm_proto; /* encapsulation ethertype */
207 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
208 } ifv_mib;
209 struct multicast_list ifv_multicast;
210 #define IFVF_PROMISC 0x1 /* promiscuous mode enabled */
211 #define IFVF_DETACHING 0x2 /* interface is detaching */
212 #define IFVF_READY 0x4 /* interface is ready */
213 u_int32_t ifv_flags;
214 bpf_packet_func ifv_bpf_input;
215 bpf_packet_func ifv_bpf_output;
216 };
217
218 typedef struct ifvlan * ifvlan_ref;
219
220 typedef struct vlan_globals_s {
221 struct vlan_parent_list parent_list;
222 int verbose;
223 } * vlan_globals_ref;
224
225 static vlan_globals_ref g_vlan;
226
227 #define ifv_tag ifv_mib.ifvm_tag
228 #define ifv_encaplen ifv_mib.ifvm_encaplen
229 #define ifv_mtufudge ifv_mib.ifvm_mtufudge
230
231
232 /**
233 ** vlan_parent_ref vlp_flags in-lines
234 **/
235 static __inline__ int
236 vlan_parent_flags_supports_vlan_mtu(vlan_parent_ref vlp)
237 {
238 return ((vlp->vlp_flags & VLPF_SUPPORTS_VLAN_MTU) != 0);
239 }
240
241 static __inline__ void
242 vlan_parent_flags_set_supports_vlan_mtu(vlan_parent_ref vlp)
243 {
244 vlp->vlp_flags |= VLPF_SUPPORTS_VLAN_MTU;
245 return;
246 }
247
248 static __inline__ void
249 vlan_parent_flags_clear_supports_vlan_mtu(vlan_parent_ref vlp)
250 {
251 vlp->vlp_flags &= ~VLPF_SUPPORTS_VLAN_MTU;
252 return;
253 }
254
255 static __inline__ int
256 vlan_parent_flags_change_in_progress(vlan_parent_ref vlp)
257 {
258 return ((vlp->vlp_flags & VLPF_CHANGE_IN_PROGRESS) != 0);
259 }
260
261 static __inline__ void
262 vlan_parent_flags_set_change_in_progress(vlan_parent_ref vlp)
263 {
264 vlp->vlp_flags |= VLPF_CHANGE_IN_PROGRESS;
265 return;
266 }
267
268 static __inline__ void
269 vlan_parent_flags_clear_change_in_progress(vlan_parent_ref vlp)
270 {
271 vlp->vlp_flags &= ~VLPF_CHANGE_IN_PROGRESS;
272 return;
273 }
274
275 static __inline__ int
276 vlan_parent_flags_detaching(struct vlan_parent * vlp)
277 {
278 return ((vlp->vlp_flags & VLPF_DETACHING) != 0);
279 }
280
281 static __inline__ void
282 vlan_parent_flags_set_detaching(struct vlan_parent * vlp)
283 {
284 vlp->vlp_flags |= VLPF_DETACHING;
285 return;
286 }
287
288
289 /**
290 ** ifvlan_flags in-lines routines
291 **/
292 static __inline__ int
293 ifvlan_flags_promisc(ifvlan_ref ifv)
294 {
295 return ((ifv->ifv_flags & IFVF_PROMISC) != 0);
296 }
297
298 static __inline__ void
299 ifvlan_flags_set_promisc(ifvlan_ref ifv)
300 {
301 ifv->ifv_flags |= IFVF_PROMISC;
302 return;
303 }
304
305 static __inline__ void
306 ifvlan_flags_clear_promisc(ifvlan_ref ifv)
307 {
308 ifv->ifv_flags &= ~IFVF_PROMISC;
309 return;
310 }
311
312 static __inline__ int
313 ifvlan_flags_ready(ifvlan_ref ifv)
314 {
315 return ((ifv->ifv_flags & IFVF_READY) != 0);
316 }
317
318 static __inline__ void
319 ifvlan_flags_set_ready(ifvlan_ref ifv)
320 {
321 ifv->ifv_flags |= IFVF_READY;
322 return;
323 }
324
325 static __inline__ void
326 ifvlan_flags_clear_ready(ifvlan_ref ifv)
327 {
328 ifv->ifv_flags &= ~IFVF_READY;
329 return;
330 }
331
332 static __inline__ int
333 ifvlan_flags_detaching(ifvlan_ref ifv)
334 {
335 return ((ifv->ifv_flags & IFVF_DETACHING) != 0);
336 }
337
338 static __inline__ void
339 ifvlan_flags_set_detaching(ifvlan_ref ifv)
340 {
341 ifv->ifv_flags |= IFVF_DETACHING;
342 return;
343 }
344
345 #if 0
346 SYSCTL_DECL(_net_link);
347 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
348 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
349 #endif 0
350
351 #define M_VLAN M_DEVBUF
352
353 static int vlan_clone_create(struct if_clone *, int);
354 static void vlan_clone_destroy(struct ifnet *);
355 static int vlan_input(struct mbuf *m, char *frame_header, struct ifnet *ifp,
356 u_long protocol_family, int sync_ok);
357 static int vlan_output(struct ifnet *ifp, struct mbuf *m);
358 static int vlan_ioctl(ifnet_t ifp, u_int32_t cmd, void * addr);
359 static int vlan_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode,
360 bpf_packet_func func);
361 static int vlan_attach_protocol(struct ifnet *ifp);
362 static int vlan_detach_protocol(struct ifnet *ifp);
363 static int vlan_setmulti(struct ifnet *ifp);
364 static int vlan_unconfig(struct ifnet *ifp);
365 static int vlan_config(struct ifnet * ifp, struct ifnet * p, int tag);
366 static void vlan_if_free(struct ifnet * ifp);
367 static void vlan_remove(ifvlan_ref ifv);
368 static void vlan_if_detach(struct ifnet * ifp);
369 static int vlan_new_mtu(struct ifnet * ifp, int mtu);
370
371 static struct if_clone vlan_cloner = IF_CLONE_INITIALIZER(VLANNAME,
372 vlan_clone_create,
373 vlan_clone_destroy,
374 0,
375 IF_MAXUNIT);
376 static void interface_link_event(struct ifnet * ifp, u_long event_code);
377 static void vlan_parent_link_event(vlan_parent_ref vlp,
378 u_long event_code);
379 extern int dlil_input_packet(struct ifnet *ifp, struct mbuf *m, char *frame_header);
380
381 static int
382 vlan_globals_init(void)
383 {
384 vlan_globals_ref v;
385
386 vlan_assert_lock_not_held();
387
388 if (g_vlan != NULL) {
389 return (0);
390 }
391 v = _MALLOC(sizeof(*v), M_VLAN, M_WAITOK);
392 if (v != NULL) {
393 LIST_INIT(&v->parent_list);
394 v->verbose = 0;
395 }
396 vlan_lock();
397 if (g_vlan != NULL) {
398 vlan_unlock();
399 if (v != NULL) {
400 _FREE(v, M_VLAN);
401 }
402 return (0);
403 }
404 g_vlan = v;
405 vlan_unlock();
406 if (v == NULL) {
407 return (ENOMEM);
408 }
409 return (0);
410 }
411
412 static int
413 siocgifdevmtu(struct ifnet * ifp, struct ifdevmtu * ifdm_p)
414 {
415 struct ifreq ifr;
416 int error;
417
418 bzero(&ifr, sizeof(ifr));
419 error = dlil_ioctl(0, ifp, SIOCGIFDEVMTU, (caddr_t)&ifr);
420 if (error == 0) {
421 *ifdm_p = ifr.ifr_devmtu;
422 }
423 return (error);
424 }
425
426 static int
427 siocsifaltmtu(struct ifnet * ifp, int mtu)
428 {
429 struct ifreq ifr;
430
431 bzero(&ifr, sizeof(ifr));
432 ifr.ifr_mtu = mtu;
433 return (dlil_ioctl(0, ifp, SIOCSIFALTMTU, (caddr_t)&ifr));
434 }
435
436 static __inline__ void
437 vlan_bpf_output(struct ifnet * ifp, struct mbuf * m,
438 bpf_packet_func func)
439 {
440 if (func != NULL) {
441 (*func)(ifp, m);
442 }
443 return;
444 }
445
446 static __inline__ void
447 vlan_bpf_input(struct ifnet * ifp, struct mbuf * m,
448 bpf_packet_func func, char * frame_header,
449 int frame_header_len, int encap_len)
450 {
451 if (func != NULL) {
452 if (encap_len > 0) {
453 /* present the right header to bpf */
454 bcopy(frame_header, frame_header + encap_len, frame_header_len);
455 }
456 m->m_data -= frame_header_len;
457 m->m_len += frame_header_len;
458 (*func)(ifp, m);
459 m->m_data += frame_header_len;
460 m->m_len -= frame_header_len;
461 if (encap_len > 0) {
462 /* restore the header */
463 bcopy(frame_header + encap_len, frame_header, frame_header_len);
464 }
465 }
466 return;
467 }
468
469 static struct ifaddr *
470 ifaddr_byindex(int i)
471 {
472 if (i > if_index || i == 0) {
473 return (NULL);
474 }
475 return (ifnet_addrs[i - 1]);
476 }
477
478 /**
479 ** vlan_parent synchronization routines
480 **/
481 static __inline__ void
482 vlan_parent_retain(vlan_parent_ref vlp)
483 {
484 OSIncrementAtomic(&vlp->vlp_retain_count);
485 }
486
487 static __inline__ void
488 vlan_parent_release(vlan_parent_ref vlp)
489 {
490 UInt32 old_retain_count;
491
492 old_retain_count = OSDecrementAtomic(&vlp->vlp_retain_count);
493 switch (old_retain_count) {
494 case 0:
495 panic("vlan_parent_release: retain count is 0\n");
496 break;
497 case 1:
498 if (g_vlan->verbose) {
499 struct ifnet * ifp = vlp->vlp_ifp;
500 printf("vlan_parent_release(%s%d)\n", ifp->if_name,
501 ifp->if_unit);
502 }
503 FREE(vlp, M_VLAN);
504 break;
505 default:
506 break;
507 }
508 return;
509 }
510
511 /*
512 * Function: vlan_parent_wait
513 * Purpose:
514 * Allows a single thread to gain exclusive access to the vlan_parent
515 * data structure. Some operations take a long time to complete,
516 * and some have side-effects that we can't predict. Holding the
517 * vlan_lock() across such operations is not possible.
518 *
519 * Notes:
520 * Before calling, you must be holding the vlan_lock and have taken
521 * a reference on the vlan_parent_ref.
522 */
523 static void
524 vlan_parent_wait(vlan_parent_ref vlp, const char * msg)
525 {
526 int waited = 0;
527
528 /* other add/remove/multicast-change in progress */
529 while (vlan_parent_flags_change_in_progress(vlp)) {
530 if (g_vlan->verbose) {
531 struct ifnet * ifp = vlp->vlp_ifp;
532
533 printf("%s%d: %s msleep\n", ifp->if_name, ifp->if_unit, msg);
534 }
535 waited = 1;
536 (void)msleep(vlp, vlan_lck_mtx, PZERO, msg, 0);
537 }
538 /* prevent other vlan parent remove/add from taking place */
539 vlan_parent_flags_set_change_in_progress(vlp);
540 if (g_vlan->verbose && waited) {
541 struct ifnet * ifp = vlp->vlp_ifp;
542
543 printf("%s: %s woke up\n", ifp->if_name, ifp->if_unit, msg);
544 }
545 return;
546 }
547
548 /*
549 * Function: vlan_parent_signal
550 * Purpose:
551 * Allows the thread that previously invoked vlan_parent_wait() to
552 * give up exclusive access to the vlan_parent data structure, and wake up
553 * any other threads waiting to access
554 * Notes:
555 * Before calling, you must be holding the vlan_lock and have taken
556 * a reference on the vlan_parent_ref.
557 */
558 static void
559 vlan_parent_signal(vlan_parent_ref vlp, const char * msg)
560 {
561 vlan_parent_flags_clear_change_in_progress(vlp);
562 wakeup((caddr_t)vlp);
563 if (g_vlan->verbose) {
564 struct ifnet * ifp = vlp->vlp_ifp;
565
566 printf("%s%d: %s wakeup\n", ifp->if_name, ifp->if_unit, msg);
567 }
568 return;
569 }
570
571
572 /*
573 * Program our multicast filter. What we're actually doing is
574 * programming the multicast filter of the parent. This has the
575 * side effect of causing the parent interface to receive multicast
576 * traffic that it doesn't really want, which ends up being discarded
577 * later by the upper protocol layers. Unfortunately, there's no way
578 * to avoid this: there really is only one physical interface.
579 */
580 static int
581 vlan_setmulti(struct ifnet * ifp)
582 {
583 int error = 0;
584 ifvlan_ref ifv;
585 struct ifnet * p;
586 vlan_parent_ref vlp;
587
588 vlan_lock();
589 ifv = (ifvlan_ref)ifp->if_private;
590 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
591 goto unlock_done;
592 }
593 vlp = ifv->ifv_vlp;
594 if (vlp == NULL) {
595 /* no parent, no need to program the multicast filter */
596 goto unlock_done;
597 }
598 if (vlan_parent_flags_detaching(vlp)) {
599 goto unlock_done;
600 }
601 vlan_parent_retain(vlp);
602 vlan_parent_wait(vlp, "vlan_setmulti");
603
604 /* check again, things could have changed */
605 ifv = (ifvlan_ref)ifp->if_private;
606 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
607 goto signal_done;
608 }
609 if (ifv->ifv_vlp != vlp) {
610 /* vlan parent changed */
611 goto signal_done;
612 }
613 if (vlp == NULL) {
614 /* no parent, no need to program the multicast filter */
615 goto signal_done;
616 }
617 p = vlp->vlp_ifp;
618 vlan_unlock();
619
620 /* update parent interface with our multicast addresses */
621 error = multicast_list_program(&ifv->ifv_multicast, ifp, p);
622
623 vlan_lock();
624
625 signal_done:
626 vlan_parent_signal(vlp, "vlan_setmulti");
627
628 unlock_done:
629 vlan_unlock();
630 return (error);
631 }
632
633 /**
634 ** vlan_parent list manipulation/lookup routines
635 **/
636 static vlan_parent_ref
637 parent_list_lookup(struct ifnet * p)
638 {
639 vlan_parent_ref vlp;
640
641 LIST_FOREACH(vlp, &g_vlan->parent_list, vlp_parent_list) {
642 if (vlp->vlp_ifp == p) {
643 return (vlp);
644 }
645 }
646 return (NULL);
647 }
648
649 static ifvlan_ref
650 vlan_parent_lookup_tag(vlan_parent_ref vlp, int tag)
651 {
652 ifvlan_ref ifv;
653
654 LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
655 if (tag == ifv->ifv_tag) {
656 return (ifv);
657 }
658 }
659 return (NULL);
660 }
661
662 static ifvlan_ref
663 vlan_lookup_parent_and_tag(struct ifnet * p, int tag)
664 {
665 vlan_parent_ref vlp;
666
667 vlp = parent_list_lookup(p);
668 if (vlp != NULL) {
669 return (vlan_parent_lookup_tag(vlp, tag));
670 }
671 return (NULL);
672 }
673
674 static int
675 vlan_parent_find_max_mtu(vlan_parent_ref vlp, ifvlan_ref exclude_ifv)
676 {
677 int max_mtu = 0;
678 ifvlan_ref ifv;
679
680 LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
681 int req_mtu;
682
683 if (exclude_ifv == ifv) {
684 continue;
685 }
686 req_mtu = ifv->ifv_ifp->if_mtu + ifv->ifv_mtufudge;
687 if (req_mtu > max_mtu) {
688 max_mtu = req_mtu;
689 }
690 }
691 return (max_mtu);
692 }
693
694 /*
695 * Function: vlan_parent_create
696 * Purpose:
697 * Create a vlan_parent structure to hold the VLAN's for the given
698 * interface. Add it to the list of VLAN parents.
699 */
700 static int
701 vlan_parent_create(struct ifnet * p, vlan_parent_ref * ret_vlp)
702 {
703 int error;
704 vlan_parent_ref vlp;
705
706 *ret_vlp = NULL;
707 vlp = _MALLOC(sizeof(*vlp), M_VLAN, M_WAITOK);
708 if (vlp == NULL) {
709 return (ENOMEM);
710 }
711 bzero(vlp, sizeof(*vlp));
712 error = siocgifdevmtu(p, &vlp->vlp_devmtu);
713 if (error != 0) {
714 printf("vlan_parent_create (%s%d): siocgifdevmtu failed, %d\n",
715 p->if_name, p->if_unit, error);
716 FREE(vlp, M_VLAN);
717 return (error);
718 }
719 LIST_INIT(&vlp->vlp_vlan_list);
720 vlp->vlp_ifp = p;
721 vlan_parent_retain(vlp);
722 if (p->if_hwassist
723 & (IF_HWASSIST_VLAN_MTU | IF_HWASSIST_VLAN_TAGGING)) {
724 vlan_parent_flags_set_supports_vlan_mtu(vlp);
725 }
726 *ret_vlp = vlp;
727 return (0);
728 }
729
730 static void
731 vlan_parent_remove_all_vlans(vlan_parent_ref vlp)
732 {
733 ifvlan_ref ifv;
734 struct ifnet * p;
735
736 vlan_assert_lock_held();
737
738 while ((ifv = LIST_FIRST(&vlp->vlp_vlan_list)) != NULL) {
739 vlan_remove(ifv);
740 vlan_unlock();
741 vlan_if_detach(ifv->ifv_ifp);
742 vlan_lock();
743 }
744
745 /* the vlan parent has no more VLAN's */
746 p = vlp->vlp_ifp;
747 ifnet_lock_exclusive(p);
748 p->if_eflags &= ~IFEF_VLAN;
749 ifnet_lock_done(p);
750 LIST_REMOVE(vlp, vlp_parent_list);
751 vlan_unlock();
752 vlan_parent_release(vlp);
753 vlan_lock();
754
755 return;
756 }
757
758 static __inline__ int
759 vlan_parent_no_vlans(vlan_parent_ref vlp)
760 {
761 return (LIST_EMPTY(&vlp->vlp_vlan_list));
762 }
763
764 static void
765 vlan_parent_add_vlan(vlan_parent_ref vlp, ifvlan_ref ifv, int tag)
766 {
767 LIST_INSERT_HEAD(&vlp->vlp_vlan_list, ifv, ifv_vlan_list);
768 ifv->ifv_vlp = vlp;
769 ifv->ifv_tag = tag;
770 return;
771 }
772
773 static void
774 vlan_parent_remove_vlan(__unused vlan_parent_ref vlp, ifvlan_ref ifv)
775 {
776 ifv->ifv_vlp = NULL;
777 LIST_REMOVE(ifv, ifv_vlan_list);
778 return;
779 }
780
781 static void
782 vlan_clone_attach(void)
783 {
784 if_clone_attach(&vlan_cloner);
785 vlan_lock_init();
786 return;
787 }
788
789 static int
790 vlan_clone_create(struct if_clone *ifc, int unit)
791 {
792 int error;
793 ifvlan_ref ifv;
794 struct ifnet * ifp;
795
796 error = vlan_globals_init();
797 if (error != 0) {
798 return (error);
799 }
800 ifv = _MALLOC(sizeof(struct ifvlan), M_VLAN, M_WAITOK);
801 bzero(ifv, sizeof(struct ifvlan));
802 multicast_list_init(&ifv->ifv_multicast);
803
804 /* use the interface name as the unique id for ifp recycle */
805 if ((unsigned int)snprintf(ifv->ifv_name, sizeof(ifv->ifv_name), "%s%d",
806 ifc->ifc_name, unit) >= sizeof(ifv->ifv_name)) {
807 FREE(ifv, M_VLAN);
808 return (EINVAL);
809 }
810 error = dlil_if_acquire(APPLE_IF_FAM_VLAN,
811 ifv->ifv_name,
812 strlen(ifv->ifv_name),
813 &ifp);
814 if (error) {
815 FREE(ifv, M_VLAN);
816 return (error);
817 }
818 ifp->if_name = ifc->ifc_name;
819 ifp->if_unit = unit;
820 ifp->if_family = APPLE_IF_FAM_VLAN;
821
822 #if 0
823 /* NB: flags are not set here */
824 ifp->if_linkmib = &ifv->ifv_mib;
825 ifp->if_linkmiblen = sizeof ifv->ifv_mib;
826 /* NB: mtu is not set here */
827 #endif 0
828
829 ifp->if_ioctl = vlan_ioctl;
830 ifp->if_set_bpf_tap = vlan_set_bpf_tap;
831 ifp->if_free = vlan_if_free;
832 ifp->if_output = vlan_output;
833 ifp->if_hwassist = 0;
834 ifp->if_addrlen = ETHER_ADDR_LEN; /* XXX ethernet specific */
835 ifp->if_baudrate = 0;
836 ifp->if_type = IFT_L2VLAN;
837 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
838
839 /* XXX ethernet specific */
840 ifp->if_broadcast.length = ETHER_ADDR_LEN;
841 bcopy(etherbroadcastaddr, ifp->if_broadcast.u.buffer, ETHER_ADDR_LEN);
842
843 error = dlil_if_attach(ifp);
844 if (error) {
845 dlil_if_release(ifp);
846 FREE(ifv, M_VLAN);
847 return (error);
848 }
849 ifp->if_private = ifv;
850 ifv->ifv_ifp = ifp;
851
852 /* attach as ethernet */
853 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
854 return (0);
855 }
856
857 static void
858 vlan_remove(ifvlan_ref ifv)
859 {
860 vlan_assert_lock_held();
861 ifvlan_flags_set_detaching(ifv);
862 vlan_unconfig(ifv->ifv_ifp);
863 return;
864 }
865
866 static void
867 vlan_if_detach(struct ifnet * ifp)
868 {
869 if (dlil_if_detach(ifp) != DLIL_WAIT_FOR_FREE) {
870 vlan_if_free(ifp);
871 }
872 return;
873 }
874
875 static void
876 vlan_clone_destroy(struct ifnet *ifp)
877 {
878 ifvlan_ref ifv;
879
880 vlan_lock();
881 ifv = ifp->if_private;
882 if (ifv == NULL || ifp->if_type != IFT_L2VLAN) {
883 vlan_unlock();
884 return;
885 }
886 if (ifvlan_flags_detaching(ifv)) {
887 vlan_unlock();
888 return;
889 }
890 vlan_remove(ifv);
891 vlan_unlock();
892 vlan_if_detach(ifp);
893 return;
894 }
895
896 static int
897 vlan_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, bpf_packet_func func)
898 {
899 ifvlan_ref ifv;
900
901 vlan_lock();
902 ifv = ifp->if_private;
903 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
904 vlan_unlock();
905 return (ENODEV);
906 }
907 switch (mode) {
908 case BPF_TAP_DISABLE:
909 ifv->ifv_bpf_input = ifv->ifv_bpf_output = NULL;
910 break;
911
912 case BPF_TAP_INPUT:
913 ifv->ifv_bpf_input = func;
914 break;
915
916 case BPF_TAP_OUTPUT:
917 ifv->ifv_bpf_output = func;
918 break;
919
920 case BPF_TAP_INPUT_OUTPUT:
921 ifv->ifv_bpf_input = ifv->ifv_bpf_output = func;
922 break;
923 default:
924 break;
925 }
926 vlan_unlock();
927 return 0;
928 }
929
930 static int
931 vlan_output(struct ifnet * ifp, struct mbuf * m)
932 {
933 bpf_packet_func bpf_func;
934 struct ether_vlan_header * evl;
935 int encaplen;
936 ifvlan_ref ifv;
937 struct ifnet * p;
938 int soft_vlan;
939 u_short tag;
940 vlan_parent_ref vlp;
941
942 if (m == 0) {
943 return (0);
944 }
945 if ((m->m_flags & M_PKTHDR) == 0) {
946 m_freem_list(m);
947 return (0);
948 }
949 vlan_lock();
950 ifv = (ifvlan_ref)ifp->if_private;
951 if (ifv == NULL || ifvlan_flags_detaching(ifv)
952 || ifvlan_flags_ready(ifv) == 0) {
953 vlan_unlock();
954 m_freem_list(m);
955 return (0);
956 }
957 vlp = ifv->ifv_vlp;
958 if (vlp == NULL) {
959 vlan_unlock();
960 m_freem_list(m);
961 return (0);
962 }
963 p = vlp->vlp_ifp;
964 (void)ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
965 soft_vlan = (p->if_hwassist & IF_HWASSIST_VLAN_TAGGING) == 0;
966 bpf_func = ifv->ifv_bpf_output;
967 tag = ifv->ifv_tag;
968 encaplen = ifv->ifv_encaplen;
969 vlan_unlock();
970 vlan_bpf_output(ifp, m, bpf_func);
971
972 /* do not run parent's if_output() if the parent is not up */
973 if ((p->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) {
974 m_freem(m);
975 ifp->if_collisions++;
976 return (0);
977 }
978 /*
979 * If underlying interface can do VLAN tag insertion itself,
980 * just pass the packet along. However, we need some way to
981 * tell the interface where the packet came from so that it
982 * knows how to find the VLAN tag to use. We use a field in
983 * the mbuf header to store the VLAN tag, and a bit in the
984 * csum_flags field to mark the field as valid.
985 */
986 if (soft_vlan == 0) {
987 m->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
988 m->m_pkthdr.vlan_tag = tag;
989 } else {
990 M_PREPEND(m, encaplen, M_DONTWAIT);
991 if (m == NULL) {
992 printf("%s%d: unable to prepend VLAN header\n", ifp->if_name,
993 ifp->if_unit);
994 ifp->if_oerrors++;
995 return (0);
996 }
997 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
998 if (m->m_len < (int)sizeof(*evl)) {
999 m = m_pullup(m, sizeof(*evl));
1000 if (m == NULL) {
1001 printf("%s%d: unable to pullup VLAN header\n", ifp->if_name,
1002 ifp->if_unit);
1003 ifp->if_oerrors++;
1004 return (0);
1005 }
1006 }
1007
1008 /*
1009 * Transform the Ethernet header into an Ethernet header
1010 * with 802.1Q encapsulation.
1011 */
1012 bcopy(mtod(m, char *) + encaplen,
1013 mtod(m, char *), ETHER_HDR_LEN);
1014 evl = mtod(m, struct ether_vlan_header *);
1015 evl->evl_proto = evl->evl_encap_proto;
1016 evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
1017 evl->evl_tag = htons(tag);
1018 }
1019 return dlil_output(p, 0, m, NULL, NULL, 1);
1020 }
1021
1022 static int
1023 vlan_input(struct mbuf * m, char * frame_header, struct ifnet * p,
1024 __unused u_long protocol_family, __unused int sync_ok)
1025 {
1026 bpf_packet_func bpf_func = NULL;
1027 struct ether_vlan_header * evl;
1028 struct ifnet * ifp = NULL;
1029 int soft_vlan = 0;
1030 u_int tag = 0;
1031
1032 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1033 /*
1034 * Packet is tagged, m contains a normal
1035 * Ethernet frame; the tag is stored out-of-band.
1036 */
1037 m->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
1038 tag = EVL_VLANOFTAG(m->m_pkthdr.vlan_tag);
1039 m->m_pkthdr.vlan_tag = 0;
1040 } else {
1041 soft_vlan = 1;
1042 switch (p->if_type) {
1043 case IFT_ETHER:
1044 if (m->m_len < ETHER_VLAN_ENCAP_LEN) {
1045 m_freem(m);
1046 return 0;
1047 }
1048 evl = (struct ether_vlan_header *)frame_header;
1049 if (ntohs(evl->evl_proto) == ETHERTYPE_VLAN) {
1050 /* don't allow VLAN within VLAN */
1051 m_freem(m);
1052 return (0);
1053 }
1054 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
1055
1056 /*
1057 * Restore the original ethertype. We'll remove
1058 * the encapsulation after we've found the vlan
1059 * interface corresponding to the tag.
1060 */
1061 evl->evl_encap_proto = evl->evl_proto;
1062 break;
1063 default:
1064 printf("vlan_demux: unsupported if type %u",
1065 p->if_type);
1066 m_freem(m);
1067 return 0;
1068 break;
1069 }
1070 }
1071 if (tag != 0) {
1072 ifvlan_ref ifv;
1073
1074 if ((p->if_eflags & IFEF_VLAN) == 0) {
1075 /* don't bother looking through the VLAN list */
1076 m_freem(m);
1077 return 0;
1078 }
1079 vlan_lock();
1080 ifv = vlan_lookup_parent_and_tag(p, tag);
1081 if (ifv != NULL) {
1082 ifp = ifv->ifv_ifp;
1083 }
1084 if (ifv == NULL
1085 || ifvlan_flags_ready(ifv) == 0
1086 || (ifp->if_flags & IFF_UP) == 0) {
1087 vlan_unlock();
1088 m_freem(m);
1089 return 0;
1090 }
1091 bpf_func = ifv->ifv_bpf_input;
1092 vlan_unlock();
1093 }
1094 if (soft_vlan) {
1095 /*
1096 * Packet had an in-line encapsulation header;
1097 * remove it. The original header has already
1098 * been fixed up above.
1099 */
1100 m->m_len -= ETHER_VLAN_ENCAP_LEN;
1101 m->m_data += ETHER_VLAN_ENCAP_LEN;
1102 m->m_pkthdr.len -= ETHER_VLAN_ENCAP_LEN;
1103 m->m_pkthdr.csum_flags = 0; /* can't trust hardware checksum */
1104 }
1105 if (tag != 0) {
1106 m->m_pkthdr.rcvif = ifp;
1107 (void)ifnet_stat_increment_in(ifp, 1,
1108 m->m_pkthdr.len + ETHER_HDR_LEN, 0);
1109 vlan_bpf_input(ifp, m, bpf_func, frame_header, ETHER_HDR_LEN,
1110 soft_vlan ? ETHER_VLAN_ENCAP_LEN : 0);
1111 /* We found a vlan interface, inject on that interface. */
1112 dlil_input_packet(ifp, m, frame_header);
1113 } else {
1114 /* Send priority-tagged packet up through the parent */
1115 dlil_input_packet(p, m, frame_header);
1116 }
1117 return 0;
1118 }
1119
1120 #define VLAN_CONFIG_PROGRESS_VLP_RETAINED 0x1
1121 #define VLAN_CONFIG_PROGRESS_IN_LIST 0x2
1122
1123 static int
1124 vlan_config(struct ifnet * ifp, struct ifnet * p, int tag)
1125 {
1126 int error;
1127 int first_vlan = 0;
1128 ifvlan_ref ifv = NULL;
1129 struct ifaddr * ifa1;
1130 struct ifaddr * ifa2;
1131 vlan_parent_ref new_vlp = NULL;
1132 int need_vlp_release = 0;
1133 u_int32_t progress = 0;
1134 struct sockaddr_dl *sdl1;
1135 struct sockaddr_dl *sdl2;
1136 vlan_parent_ref vlp = NULL;
1137
1138 /* pre-allocate space for vlan_parent, in case we're first */
1139 error = vlan_parent_create(p, &new_vlp);
1140 if (error != 0) {
1141 return (error);
1142 }
1143
1144 vlan_lock();
1145 ifv = (ifvlan_ref)ifp->if_private;
1146 if (ifv != NULL && ifv->ifv_vlp != NULL) {
1147 vlan_unlock();
1148 vlan_parent_release(new_vlp);
1149 return (EBUSY);
1150 }
1151 vlp = parent_list_lookup(p);
1152 if (vlp != NULL) {
1153 if (vlan_parent_lookup_tag(vlp, tag) != NULL) {
1154 /* already a VLAN with that tag on this interface */
1155 error = EADDRINUSE;
1156 goto unlock_done;
1157 }
1158 }
1159 else {
1160 /* we're the first VLAN on this interface */
1161 LIST_INSERT_HEAD(&g_vlan->parent_list, new_vlp, vlp_parent_list);
1162 vlp = new_vlp;
1163 }
1164
1165 /* need to wait to ensure no one else is trying to add/remove */
1166 vlan_parent_retain(vlp);
1167 progress |= VLAN_CONFIG_PROGRESS_VLP_RETAINED;
1168 vlan_parent_wait(vlp, "vlan_config");
1169
1170 ifv = (ifvlan_ref)ifp->if_private;
1171 if (ifv == NULL) {
1172 error = EOPNOTSUPP;
1173 goto signal_done;
1174 }
1175 if (vlan_parent_flags_detaching(vlp)
1176 || ifvlan_flags_detaching(ifv) || ifv->ifv_vlp != NULL) {
1177 error = EBUSY;
1178 goto signal_done;
1179 }
1180
1181 /* check again because someone might have gotten in */
1182 if (vlan_parent_lookup_tag(vlp, tag) != NULL) {
1183 /* already a VLAN with that tag on this interface */
1184 error = EADDRINUSE;
1185 goto signal_done;
1186 }
1187
1188 if (vlan_parent_no_vlans(vlp)) {
1189 first_vlan = 1;
1190 }
1191 vlan_parent_add_vlan(vlp, ifv, tag);
1192 progress |= VLAN_CONFIG_PROGRESS_IN_LIST;
1193
1194 /* check whether bond interface is using parent interface */
1195 ifnet_lock_exclusive(p);
1196 if ((p->if_eflags & IFEF_BOND) != 0) {
1197 ifnet_lock_done(p);
1198 /* don't allow VLAN over interface that's already part of a bond */
1199 error = EBUSY;
1200 goto signal_done;
1201 }
1202 /* prevent BOND interface from using it */
1203 p->if_eflags |= IFEF_VLAN;
1204 ifnet_lock_done(p);
1205 vlan_unlock();
1206
1207 if (first_vlan) {
1208 /* attach our VLAN "protocol" to the interface */
1209 error = vlan_attach_protocol(p);
1210 if (error) {
1211 vlan_lock();
1212 goto signal_done;
1213 }
1214 /* mark the parent interface up */
1215 ifnet_lock_exclusive(p);
1216 p->if_flags |= IFF_UP;
1217 ifnet_lock_done(p);
1218 (void)dlil_ioctl(0, p, SIOCSIFFLAGS, (caddr_t)NULL);
1219 }
1220
1221 /* configure parent to receive our multicast addresses */
1222 error = multicast_list_program(&ifv->ifv_multicast, ifp, p);
1223 if (error != 0) {
1224 if (first_vlan) {
1225 (void)vlan_detach_protocol(p);
1226 }
1227 vlan_lock();
1228 goto signal_done;
1229 }
1230
1231 /* no failures past this point */
1232 vlan_lock();
1233
1234 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
1235 ifv->ifv_flags = 0;
1236 if (vlan_parent_flags_supports_vlan_mtu(vlp)) {
1237 ifv->ifv_mtufudge = 0;
1238 } else {
1239 /*
1240 * Fudge the MTU by the encapsulation size. This
1241 * makes us incompatible with strictly compliant
1242 * 802.1Q implementations, but allows us to use
1243 * the feature with other NetBSD implementations,
1244 * which might still be useful.
1245 */
1246 ifv->ifv_mtufudge = ifv->ifv_encaplen;
1247 }
1248 ifp->if_mtu = ETHERMTU - ifv->ifv_mtufudge;
1249
1250 /*
1251 * Copy only a selected subset of flags from the parent.
1252 * Other flags are none of our business.
1253 */
1254 ifp->if_flags |= (p->if_flags &
1255 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX));
1256 /*
1257 * If the parent interface can do hardware-assisted
1258 * VLAN encapsulation, then propagate its hardware-
1259 * assisted checksumming flags.
1260 */
1261 if (p->if_hwassist & IF_HWASSIST_VLAN_TAGGING) {
1262 ifp->if_hwassist |= IF_HWASSIST_CSUM_FLAGS(p->if_hwassist);
1263 }
1264
1265 /* set our ethernet address to that of the parent */
1266 ifa1 = ifaddr_byindex(ifp->if_index);
1267 ifa2 = ifaddr_byindex(p->if_index);
1268 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
1269 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
1270 sdl1->sdl_type = IFT_ETHER;
1271 sdl1->sdl_alen = ETHER_ADDR_LEN;
1272 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
1273
1274 ifp->if_flags |= IFF_RUNNING;
1275 ifvlan_flags_set_ready(ifv);
1276 vlan_parent_signal(vlp, "vlan_config");
1277 vlan_unlock();
1278 if (new_vlp != vlp) {
1279 /* throw it away, it wasn't needed */
1280 vlan_parent_release(new_vlp);
1281 }
1282 return 0;
1283
1284 signal_done:
1285 vlan_assert_lock_held();
1286 vlan_parent_signal(vlp, "vlan_config");
1287
1288 unlock_done:
1289 if ((progress & VLAN_CONFIG_PROGRESS_IN_LIST) != 0) {
1290 vlan_parent_remove_vlan(vlp, ifv);
1291 }
1292 if (!vlan_parent_flags_detaching(vlp) && vlan_parent_no_vlans(vlp)) {
1293 /* the vlan parent has no more VLAN's */
1294 ifnet_lock_exclusive(p);
1295 p->if_eflags &= ~IFEF_VLAN;
1296 ifnet_lock_done(p);
1297 LIST_REMOVE(vlp, vlp_parent_list);
1298 /* release outside of the lock below */
1299 need_vlp_release = 1;
1300 }
1301 vlan_unlock();
1302
1303 if ((progress & VLAN_CONFIG_PROGRESS_VLP_RETAINED) != 0) {
1304 vlan_parent_release(vlp);
1305 }
1306 if (need_vlp_release) {
1307 vlan_parent_release(vlp);
1308 }
1309 if (new_vlp != vlp) {
1310 vlan_parent_release(new_vlp);
1311 }
1312 return (error);
1313 }
1314
1315 static void
1316 vlan_link_event(struct ifnet * ifp, struct ifnet * p)
1317 {
1318 struct ifmediareq ifmr;
1319
1320 /* generate a link event based on the state of the underlying interface */
1321 bzero(&ifmr, sizeof(ifmr));
1322 snprintf(ifmr.ifm_name, sizeof(ifmr.ifm_name),
1323 "%s%d", p->if_name, p->if_unit);
1324 if ((*p->if_ioctl)(p, SIOCGIFMEDIA, (caddr_t)&ifmr) == 0
1325 && ifmr.ifm_count > 0 && ifmr.ifm_status & IFM_AVALID) {
1326 u_long event;
1327
1328 event = (ifmr.ifm_status & IFM_ACTIVE)
1329 ? KEV_DL_LINK_ON : KEV_DL_LINK_OFF;
1330 interface_link_event(ifp, event);
1331 }
1332 return;
1333 }
1334
1335 static int
1336 vlan_unconfig(struct ifnet * ifp)
1337 {
1338 int error = 0;
1339 struct ifaddr * ifa;
1340 ifvlan_ref ifv;
1341 int last_vlan = 0;
1342 int need_vlp_release = 0;
1343 struct ifnet * p;
1344 struct sockaddr_dl *sdl;
1345 vlan_parent_ref vlp;
1346
1347 vlan_assert_lock_held();
1348 ifv = (ifvlan_ref)ifp->if_private;
1349 if (ifv == NULL) {
1350 return (0);
1351 }
1352 vlp = ifv->ifv_vlp;
1353 if (vlp == NULL) {
1354 return (0);
1355 }
1356 vlan_parent_retain(vlp);
1357 vlan_parent_wait(vlp, "vlan_unconfig");
1358
1359 /* check again because another thread could be in vlan_unconfig */
1360 ifv = (ifvlan_ref)ifp->if_private;
1361 if (ifv == NULL) {
1362 goto signal_done;
1363 }
1364 if (ifv->ifv_vlp != vlp) {
1365 /* vlan parent changed */
1366 goto signal_done;
1367 }
1368 need_vlp_release++;
1369 p = vlp->vlp_ifp;
1370
1371 /* remember whether we're the last VLAN on the parent */
1372 if (LIST_NEXT(LIST_FIRST(&vlp->vlp_vlan_list), ifv_vlan_list) == NULL) {
1373 if (g_vlan->verbose) {
1374 printf("vlan_unconfig: last vlan on %s%d\n",
1375 p->if_name, p->if_unit);
1376 }
1377 last_vlan = 1;
1378 }
1379
1380 /* back-out any effect our mtu might have had on the parent */
1381 (void)vlan_new_mtu(ifp, ETHERMTU - ifv->ifv_mtufudge);
1382
1383 vlan_unlock();
1384
1385 /* detach VLAN "protocol" */
1386 if (last_vlan) {
1387 (void)vlan_detach_protocol(p);
1388 }
1389
1390 /* un-join multicast on parent interface */
1391 (void)multicast_list_remove(&ifv->ifv_multicast);
1392
1393 vlan_lock();
1394
1395 /* Disconnect from parent. */
1396 vlan_parent_remove_vlan(vlp, ifv);
1397
1398 /* return to the state we were in before SIFVLAN */
1399 ifp->if_mtu = 0;
1400 ifp->if_flags &= ~(IFF_BROADCAST | IFF_MULTICAST
1401 | IFF_SIMPLEX | IFF_RUNNING);
1402 ifp->if_hwassist = 0;
1403 ifv->ifv_flags = 0;
1404 ifv->ifv_mtufudge = 0;
1405
1406 /* Clear our MAC address. */
1407 ifa = ifaddr_byindex(ifp->if_index);
1408 sdl = (struct sockaddr_dl *)(ifa->ifa_addr);
1409 sdl->sdl_type = IFT_L2VLAN;
1410 sdl->sdl_alen = 0;
1411 bzero(LLADDR(sdl), ETHER_ADDR_LEN);
1412
1413 if (!vlan_parent_flags_detaching(vlp) && vlan_parent_no_vlans(vlp)) {
1414 /* the vlan parent has no more VLAN's */
1415 ifnet_lock_exclusive(p);
1416 p->if_eflags &= ~IFEF_VLAN;
1417 ifnet_lock_done(p);
1418 LIST_REMOVE(vlp, vlp_parent_list);
1419 /* release outside of the lock below */
1420 need_vlp_release++;
1421 }
1422
1423 signal_done:
1424 vlan_parent_signal(vlp, "vlan_unconfig");
1425 vlan_unlock();
1426 vlan_parent_release(vlp); /* one because we waited */
1427
1428 while (need_vlp_release--) {
1429 vlan_parent_release(vlp);
1430 }
1431 vlan_lock();
1432 return (error);
1433 }
1434
1435 static int
1436 vlan_set_promisc(struct ifnet * ifp)
1437 {
1438 int error = 0;
1439 ifvlan_ref ifv;
1440 vlan_parent_ref vlp;
1441
1442 vlan_lock();
1443 ifv = (ifvlan_ref)ifp->if_private;
1444 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1445 error = (ifv == NULL) ? EOPNOTSUPP : EBUSY;
1446 goto done;
1447 }
1448
1449 vlp = ifv->ifv_vlp;
1450 if (vlp == NULL) {
1451 goto done;
1452 }
1453 if ((ifp->if_flags & IFF_PROMISC) != 0) {
1454 if (!ifvlan_flags_promisc(ifv)) {
1455 error = ifnet_set_promiscuous(vlp->vlp_ifp, 1);
1456 if (error == 0) {
1457 ifvlan_flags_set_promisc(ifv);
1458 }
1459 }
1460 } else {
1461 if (ifvlan_flags_promisc(ifv)) {
1462 error = ifnet_set_promiscuous(vlp->vlp_ifp, 0);
1463 if (error == 0) {
1464 ifvlan_flags_clear_promisc(ifv);
1465 }
1466 }
1467 }
1468 done:
1469 vlan_unlock();
1470 return (error);
1471 }
1472
1473 static int
1474 vlan_new_mtu(struct ifnet * ifp, int mtu)
1475 {
1476 struct ifdevmtu * devmtu_p;
1477 int error = 0;
1478 ifvlan_ref ifv;
1479 int max_mtu;
1480 int new_mtu = 0;
1481 int req_mtu;
1482 vlan_parent_ref vlp;
1483
1484 vlan_assert_lock_held();
1485 ifv = (ifvlan_ref)ifp->if_private;
1486 vlp = ifv->ifv_vlp;
1487 devmtu_p = &vlp->vlp_devmtu;
1488 req_mtu = mtu + ifv->ifv_mtufudge;
1489 if (req_mtu > devmtu_p->ifdm_max || req_mtu < devmtu_p->ifdm_min) {
1490 return (EINVAL);
1491 }
1492 max_mtu = vlan_parent_find_max_mtu(vlp, ifv);
1493 if (req_mtu > max_mtu) {
1494 new_mtu = req_mtu;
1495 }
1496 else if (max_mtu < devmtu_p->ifdm_current) {
1497 new_mtu = max_mtu;
1498 }
1499 if (new_mtu != 0) {
1500 struct ifnet * p = vlp->vlp_ifp;
1501 vlan_unlock();
1502 error = siocsifaltmtu(p, new_mtu);
1503 vlan_lock();
1504 }
1505 if (error == 0) {
1506 if (new_mtu != 0) {
1507 devmtu_p->ifdm_current = new_mtu;
1508 }
1509 ifp->if_mtu = mtu;
1510 }
1511 return (error);
1512 }
1513
1514 static int
1515 vlan_set_mtu(struct ifnet * ifp, int mtu)
1516 {
1517 int error = 0;
1518 ifvlan_ref ifv;
1519 vlan_parent_ref vlp;
1520
1521 if (mtu < IF_MINMTU) {
1522 return (EINVAL);
1523 }
1524 vlan_lock();
1525 ifv = (ifvlan_ref)ifp->if_private;
1526 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1527 vlan_unlock();
1528 return ((ifv == NULL) ? EOPNOTSUPP : EBUSY);
1529 }
1530 vlp = ifv->ifv_vlp;
1531 if (vlp == NULL || vlan_parent_flags_detaching(vlp)) {
1532 vlan_unlock();
1533 if (mtu != 0) {
1534 return (EINVAL);
1535 }
1536 return (0);
1537 }
1538 vlan_parent_retain(vlp);
1539 vlan_parent_wait(vlp, "vlan_set_mtu");
1540
1541 /* check again, something might have changed */
1542 ifv = (ifvlan_ref)ifp->if_private;
1543 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1544 error = (ifv == NULL) ? EOPNOTSUPP : EBUSY;
1545 goto signal_done;
1546 }
1547 if (ifv->ifv_vlp != vlp) {
1548 /* vlan parent changed */
1549 goto signal_done;
1550 }
1551 if (vlp == NULL || vlan_parent_flags_detaching(vlp)) {
1552 if (mtu != 0) {
1553 error = EINVAL;
1554 }
1555 goto signal_done;
1556 }
1557 error = vlan_new_mtu(ifp, mtu);
1558
1559 signal_done:
1560 vlan_parent_signal(vlp, "vlan_set_mtu");
1561 vlan_unlock();
1562 vlan_parent_release(vlp);
1563
1564 return (error);
1565 }
1566
1567 static int
1568 vlan_ioctl(ifnet_t ifp, u_int32_t cmd, void * data)
1569 {
1570 struct ifdevmtu * devmtu_p;
1571 int error = 0;
1572 struct ifaddr * ifa;
1573 struct ifmediareq64 * ifmr;
1574 struct ifreq * ifr;
1575 ifvlan_ref ifv;
1576 struct ifnet * p;
1577 u_short tag;
1578 user_addr_t user_addr;
1579 vlan_parent_ref vlp;
1580 struct vlanreq vlr;
1581
1582 if (ifp->if_type != IFT_L2VLAN) {
1583 return (EOPNOTSUPP);
1584 }
1585 ifr = (struct ifreq *)data;
1586 ifa = (struct ifaddr *)data;
1587
1588 switch (cmd) {
1589 case SIOCSIFADDR:
1590 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
1591 break;
1592
1593 case SIOCGIFMEDIA64:
1594 case SIOCGIFMEDIA:
1595 vlan_lock();
1596 ifv = (ifvlan_ref)ifp->if_private;
1597 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1598 vlan_unlock();
1599 return (ifv == NULL ? EOPNOTSUPP : EBUSY);
1600 }
1601 p = (ifv->ifv_vlp == NULL) ? NULL : ifv->ifv_vlp->vlp_ifp;
1602 vlan_unlock();
1603 ifmr = (struct ifmediareq64 *)data;
1604 user_addr = (cmd == SIOCGIFMEDIA64)
1605 ? ifmr->ifm_ifmu.ifmu_ulist64
1606 : CAST_USER_ADDR_T(ifmr->ifm_ifmu.ifmu_ulist32);
1607 if (p != NULL) {
1608 struct ifmediareq64 p_ifmr;
1609
1610 bzero(&p_ifmr, sizeof(p_ifmr));
1611 error = dlil_ioctl(0, p, SIOCGIFMEDIA, (caddr_t)&p_ifmr);
1612 if (error == 0) {
1613 ifmr->ifm_active = p_ifmr.ifm_active;
1614 ifmr->ifm_current = p_ifmr.ifm_current;
1615 ifmr->ifm_mask = p_ifmr.ifm_mask;
1616 ifmr->ifm_status = p_ifmr.ifm_status;
1617 ifmr->ifm_count = p_ifmr.ifm_count;
1618 /* Limit the result to the parent's current config. */
1619 if (ifmr->ifm_count >= 1 && user_addr != USER_ADDR_NULL) {
1620 ifmr->ifm_count = 1;
1621 error = copyout(&ifmr->ifm_current, user_addr,
1622 sizeof(int));
1623 }
1624 }
1625 } else {
1626 ifmr->ifm_active = ifmr->ifm_current = IFM_NONE;
1627 ifmr->ifm_mask = 0;
1628 ifmr->ifm_status = IFM_AVALID;
1629 ifmr->ifm_count = 1;
1630 if (user_addr != USER_ADDR_NULL) {
1631 error = copyout(&ifmr->ifm_current, user_addr, sizeof(int));
1632 }
1633 }
1634 break;
1635
1636 case SIOCSIFMEDIA:
1637 error = EOPNOTSUPP;
1638 break;
1639
1640 case SIOCGIFDEVMTU:
1641 vlan_lock();
1642 ifv = (ifvlan_ref)ifp->if_private;
1643 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1644 vlan_unlock();
1645 return (ifv == NULL ? EOPNOTSUPP : EBUSY);
1646 }
1647 vlp = ifv->ifv_vlp;
1648 if (vlp != NULL) {
1649 int min_mtu = vlp->vlp_devmtu.ifdm_min - ifv->ifv_mtufudge;
1650 devmtu_p = &ifr->ifr_devmtu;
1651 devmtu_p->ifdm_current = ifp->if_mtu;
1652 devmtu_p->ifdm_min = max(min_mtu, IF_MINMTU);
1653 devmtu_p->ifdm_max = vlp->vlp_devmtu.ifdm_max - ifv->ifv_mtufudge;
1654 }
1655 else {
1656 devmtu_p = &ifr->ifr_devmtu;
1657 devmtu_p->ifdm_current = 0;
1658 devmtu_p->ifdm_min = 0;
1659 devmtu_p->ifdm_max = 0;
1660 }
1661 vlan_unlock();
1662 break;
1663
1664 case SIOCSIFMTU:
1665 error = vlan_set_mtu(ifp, ifr->ifr_mtu);
1666 break;
1667
1668 case SIOCSIFVLAN:
1669 user_addr = proc_is64bit(current_proc())
1670 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
1671 error = copyin(user_addr, &vlr, sizeof(vlr));
1672 if (error) {
1673 break;
1674 }
1675 p = NULL;
1676 if (vlr.vlr_parent[0] != '\0') {
1677 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
1678 /*
1679 * Don't let the caller set up a VLAN tag with
1680 * anything except VLID bits.
1681 */
1682 error = EINVAL;
1683 break;
1684 }
1685 p = ifunit(vlr.vlr_parent);
1686 if (p == NULL) {
1687 error = ENXIO;
1688 break;
1689 }
1690 /* can't do VLAN over anything but ethernet or ethernet aggregate */
1691 if (p->if_type != IFT_ETHER && p->if_type != IFT_IEEE8023ADLAG) {
1692 error = EPROTONOSUPPORT;
1693 break;
1694 }
1695 error = vlan_config(ifp, p, vlr.vlr_tag);
1696 if (error) {
1697 break;
1698 }
1699
1700 /* Update promiscuous mode, if necessary. */
1701 (void)vlan_set_promisc(ifp);
1702
1703 /* generate a link event based on the state of the parent */
1704 vlan_link_event(ifp, p);
1705 } else {
1706 vlan_lock();
1707 ifv = (ifvlan_ref)ifp->if_private;
1708 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1709 vlan_unlock();
1710 error = (ifv == NULL ? EOPNOTSUPP : EBUSY);
1711 break;
1712 }
1713 error = vlan_unconfig(ifp);
1714 vlan_unlock();
1715 if (error == 0) {
1716 interface_link_event(ifp, KEV_DL_LINK_OFF);
1717 }
1718 }
1719 break;
1720
1721 case SIOCGIFVLAN:
1722 bzero(&vlr, sizeof vlr);
1723 vlan_lock();
1724 ifv = (ifvlan_ref)ifp->if_private;
1725 if (ifv == NULL || ifvlan_flags_detaching(ifv)) {
1726 vlan_unlock();
1727 return (ifv == NULL ? EOPNOTSUPP : EBUSY);
1728 }
1729 p = (ifv->ifv_vlp == NULL) ? NULL : ifv->ifv_vlp->vlp_ifp;
1730 tag = ifv->ifv_tag;
1731 vlan_unlock();
1732 if (p != NULL) {
1733 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
1734 "%s%d", p->if_name, p->if_unit);
1735 vlr.vlr_tag = tag;
1736 }
1737 user_addr = proc_is64bit(current_proc())
1738 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
1739 error = copyout(&vlr, user_addr, sizeof(vlr));
1740 break;
1741
1742 case SIOCSIFFLAGS:
1743 /*
1744 * For promiscuous mode, we enable promiscuous mode on
1745 * the parent if we need promiscuous on the VLAN interface.
1746 */
1747 error = vlan_set_promisc(ifp);
1748 break;
1749
1750 case SIOCADDMULTI:
1751 case SIOCDELMULTI:
1752 error = vlan_setmulti(ifp);
1753 break;
1754 default:
1755 error = EOPNOTSUPP;
1756 }
1757 return error;
1758 }
1759
1760 static void
1761 vlan_if_free(struct ifnet * ifp)
1762 {
1763 ifvlan_ref ifv;
1764
1765 if (ifp == NULL) {
1766 return;
1767 }
1768 vlan_lock();
1769 ifv = (ifvlan_ref)ifp->if_private;
1770 if (ifv == NULL) {
1771 vlan_unlock();
1772 return;
1773 }
1774 ifp->if_private = NULL;
1775 vlan_unlock();
1776 dlil_if_release(ifp);
1777 FREE(ifv, M_VLAN);
1778 }
1779
1780 static void
1781 vlan_event(struct ifnet * p, struct kev_msg * event)
1782 {
1783 vlan_parent_ref vlp;
1784
1785 /* Check if the interface we are attached to is being detached */
1786 if (event->vendor_code != KEV_VENDOR_APPLE
1787 || event->kev_class != KEV_NETWORK_CLASS
1788 || event->kev_subclass != KEV_DL_SUBCLASS) {
1789 return;
1790 }
1791 switch (event->event_code) {
1792 case KEV_DL_IF_DETACHING:
1793 case KEV_DL_LINK_OFF:
1794 case KEV_DL_LINK_ON:
1795 break;
1796 default:
1797 return;
1798 }
1799 vlan_lock();
1800 if ((p->if_eflags & IFEF_VLAN) == 0) {
1801 vlan_unlock();
1802 /* no VLAN's */
1803 return;
1804 }
1805 vlp = parent_list_lookup(p);
1806 if (vlp == NULL) {
1807 /* no VLAN's */
1808 vlan_unlock();
1809 return;
1810 }
1811 switch (event->event_code) {
1812 case KEV_DL_IF_DETACHING:
1813 vlan_parent_flags_set_detaching(vlp);
1814 vlan_parent_remove_all_vlans(vlp);
1815 break;
1816
1817 case KEV_DL_LINK_OFF:
1818 case KEV_DL_LINK_ON:
1819 vlan_parent_link_event(vlp, event->event_code);
1820 break;
1821 default:
1822 break;
1823 }
1824 vlan_unlock();
1825 return;
1826 }
1827
1828 static void
1829 interface_link_event(struct ifnet * ifp, u_long event_code)
1830 {
1831 struct {
1832 struct kern_event_msg header;
1833 u_long unit;
1834 char if_name[IFNAMSIZ];
1835 } event;
1836
1837 event.header.total_size = sizeof(event);
1838 event.header.vendor_code = KEV_VENDOR_APPLE;
1839 event.header.kev_class = KEV_NETWORK_CLASS;
1840 event.header.kev_subclass = KEV_DL_SUBCLASS;
1841 event.header.event_code = event_code;
1842 event.header.event_data[0] = ifp->if_family;
1843 event.unit = (u_long) ifp->if_unit;
1844 strncpy(event.if_name, ifp->if_name, IFNAMSIZ);
1845 dlil_event(ifp, &event.header);
1846 return;
1847 }
1848
1849 static void
1850 vlan_parent_link_event(vlan_parent_ref vlp, u_long event_code)
1851 {
1852 ifvlan_ref ifv;
1853
1854 LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
1855 interface_link_event(ifv->ifv_ifp, event_code);
1856 }
1857 return;
1858
1859 }
1860
1861 /*
1862 * Function: vlan_attach_protocol
1863 * Purpose:
1864 * Attach a DLIL protocol to the interface, using the ETHERTYPE_VLAN
1865 * demux ether type.
1866 *
1867 * The ethernet demux actually special cases VLAN to support hardware.
1868 * The demux here isn't used. The demux will return PF_VLAN for the
1869 * appropriate packets and our vlan_input function will be called.
1870 */
1871 static int
1872 vlan_attach_protocol(struct ifnet *ifp)
1873 {
1874 int error;
1875 struct dlil_proto_reg_str reg;
1876
1877 bzero(&reg, sizeof(reg));
1878 TAILQ_INIT(&reg.demux_desc_head);
1879 reg.interface_family = ifp->if_family;
1880 reg.unit_number = ifp->if_unit;
1881 reg.input = vlan_input;
1882 reg.event = vlan_event;
1883 reg.protocol_family = PF_VLAN;
1884 error = dlil_attach_protocol(&reg);
1885 if (error) {
1886 printf("vlan_proto_attach(%s%d) dlil_attach_protocol failed, %d\n",
1887 ifp->if_name, ifp->if_unit, error);
1888 }
1889 return (error);
1890 }
1891
1892 /*
1893 * Function: vlan_detach_protocol
1894 * Purpose:
1895 * Detach our DLIL protocol from an interface
1896 */
1897 static int
1898 vlan_detach_protocol(struct ifnet *ifp)
1899 {
1900 int error;
1901
1902 error = dlil_detach_protocol(ifp, PF_VLAN);
1903 if (error) {
1904 printf("vlan_proto_detach(%s%d) dlil_detach_protocol failed, %d\n",
1905 ifp->if_name, ifp->if_unit, error);
1906 }
1907
1908 return (error);
1909 }
1910
1911 /*
1912 * DLIL interface family functions
1913 * We use the ethernet dlil functions, since that's all we support.
1914 * If we wanted to handle multiple LAN types (tokenring, etc.), we'd
1915 * call the appropriate routines for that LAN type instead of hard-coding
1916 * ethernet.
1917 */
1918 extern int ether_add_if(struct ifnet *ifp);
1919 extern int ether_del_if(struct ifnet *ifp);
1920 extern int ether_init_if(struct ifnet *ifp);
1921 extern int ether_add_proto_old(struct ifnet *ifp, u_long protocol_family,
1922 struct ddesc_head_str *desc_head);
1923
1924 extern int ether_attach_inet(struct ifnet *ifp, u_long protocol_family);
1925 extern int ether_detach_inet(struct ifnet *ifp, u_long protocol_family);
1926 extern int ether_attach_inet6(struct ifnet *ifp, u_long protocol_family);
1927 extern int ether_detach_inet6(struct ifnet *ifp, u_long protocol_family);
1928
1929 static int
1930 vlan_attach_inet(struct ifnet *ifp, u_long protocol_family)
1931 {
1932 return (ether_attach_inet(ifp, protocol_family));
1933 }
1934
1935 static int
1936 vlan_detach_inet(struct ifnet *ifp, u_long protocol_family)
1937 {
1938 return (ether_detach_inet(ifp, protocol_family));
1939 }
1940
1941 static int
1942 vlan_attach_inet6(struct ifnet *ifp, u_long protocol_family)
1943 {
1944 return (ether_attach_inet6(ifp, protocol_family));
1945 }
1946
1947 static int
1948 vlan_detach_inet6(struct ifnet *ifp, u_long protocol_family)
1949 {
1950 return (ether_detach_inet6(ifp, protocol_family));
1951 }
1952
1953 static int
1954 vlan_add_if(struct ifnet *ifp)
1955 {
1956 return (ether_add_if(ifp));
1957 }
1958
1959 static int
1960 vlan_del_if(struct ifnet *ifp)
1961 {
1962 return (ether_del_if(ifp));
1963 }
1964
1965
1966 __private_extern__ int
1967 vlan_family_init(void)
1968 {
1969 int error=0;
1970 struct dlil_ifmod_reg_str ifmod_reg;
1971
1972 bzero(&ifmod_reg, sizeof(ifmod_reg));
1973 ifmod_reg.add_if = vlan_add_if;
1974 ifmod_reg.del_if = vlan_del_if;
1975 ifmod_reg.init_if = NULL;
1976 ifmod_reg.add_proto = ether_add_proto_old;
1977 ifmod_reg.del_proto = ether_del_proto;
1978 ifmod_reg.ifmod_ioctl = ether_ioctl;
1979 ifmod_reg.shutdown = NULL;
1980
1981 if (dlil_reg_if_modules(APPLE_IF_FAM_VLAN, &ifmod_reg)) {
1982 printf("WARNING: vlan_family_init -- "
1983 "Can't register if family modules\n");
1984 error = EIO;
1985 goto done;
1986 }
1987
1988 error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_VLAN,
1989 vlan_attach_inet, vlan_detach_inet);
1990 if (error != 0) {
1991 printf("dlil_reg_proto_module failed for AF_INET error=%d\n",
1992 error);
1993 goto done;
1994 }
1995 error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_VLAN,
1996 vlan_attach_inet6, vlan_detach_inet6);
1997 if (error != 0) {
1998 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n",
1999 error);
2000 goto done;
2001 }
2002 vlan_clone_attach();
2003
2004 done:
2005 return (error);
2006 }