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