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