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