]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_vlan.c
m_dup () packet not m_copypacket () since we will modify it. For more
[FreeBSD/FreeBSD.git] / sys / net / if_vlan.c
1 /*-
2  * Copyright 1998 Massachusetts Institute of Technology
3  *
4  * Permission to use, copy, modify, and distribute this software and
5  * its documentation for any purpose and without fee is hereby
6  * granted, provided that both the above copyright notice and this
7  * permission notice appear in all copies, that both the above
8  * copyright notice and this permission notice appear in all
9  * supporting documentation, and that the name of M.I.T. not be used
10  * in advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.  M.I.T. makes
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied
14  * warranty.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
34  * Might be extended some day to also handle IEEE 802.1p priority
35  * tagging.  This is sort of sneaky in the implementation, since
36  * we need to pretend to be enough of an Ethernet implementation
37  * to make arp work.  The way we do this is by telling everyone
38  * that we are an Ethernet, and then catch the packets that
39  * ether_output() left on our output queue when it calls
40  * if_start(), rewrite them for use by the real outgoing interface,
41  * and ask it to send them.
42  */
43
44 #include "opt_inet.h"
45 #include "opt_vlan.h"
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/lock.h>
50 #include <sys/malloc.h>
51 #include <sys/mbuf.h>
52 #include <sys/module.h>
53 #include <sys/rwlock.h>
54 #include <sys/queue.h>
55 #include <sys/socket.h>
56 #include <sys/sockio.h>
57 #include <sys/sysctl.h>
58 #include <sys/systm.h>
59
60 #include <net/bpf.h>
61 #include <net/ethernet.h>
62 #include <net/if.h>
63 #include <net/if_clone.h>
64 #include <net/if_arp.h>
65 #include <net/if_dl.h>
66 #include <net/if_types.h>
67 #include <net/if_vlan_var.h>
68
69 #ifdef INET
70 #include <netinet/in.h>
71 #include <netinet/if_ether.h>
72 #endif
73
74 #define VLANNAME        "vlan"
75 #define VLAN_DEF_HWIDTH 4
76 #define VLAN_IFFLAGS    (IFF_BROADCAST | IFF_MULTICAST)
77
78 LIST_HEAD(ifvlanhead, ifvlan);
79
80 struct ifvlantrunk {
81         struct  ifnet   *parent;        /* parent interface of this trunk */
82         struct  rwlock  rw;
83 #ifdef VLAN_ARRAY
84         struct  ifvlan  *vlans[EVL_VLID_MASK+1]; /* static table */
85 #else
86         struct  ifvlanhead *hash;       /* dynamic hash-list table */
87         uint16_t        hmask;
88         uint16_t        hwidth;
89 #endif
90         int             refcnt;
91         LIST_ENTRY(ifvlantrunk) trunk_entry;
92 };
93 static LIST_HEAD(, ifvlantrunk) trunk_list;
94
95 struct vlan_mc_entry {
96         struct ether_addr               mc_addr;
97         SLIST_ENTRY(vlan_mc_entry)      mc_entries;
98 };
99
100 struct  ifvlan {
101         struct  ifvlantrunk *ifv_trunk;
102         struct  ifnet *ifv_ifp;
103 #define TRUNK(ifv)      ((ifv)->ifv_trunk)
104 #define PARENT(ifv)     ((ifv)->ifv_trunk->parent)
105         int     ifv_pflags;     /* special flags we have set on parent */
106         struct  ifv_linkmib {
107                 int     ifvm_parent;
108                 int     ifvm_encaplen;  /* encapsulation length */
109                 int     ifvm_mtufudge;  /* MTU fudged by this much */
110                 int     ifvm_mintu;     /* min transmission unit */
111                 uint16_t ifvm_proto;    /* encapsulation ethertype */
112                 uint16_t ifvm_tag;      /* tag to apply on packets leaving if */
113         }       ifv_mib;
114         SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead;
115         LIST_ENTRY(ifvlan) ifv_list;
116 };
117 #define ifv_tag ifv_mib.ifvm_tag
118 #define ifv_encaplen    ifv_mib.ifvm_encaplen
119 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
120 #define ifv_mintu       ifv_mib.ifvm_mintu
121
122 /* Special flags we should propagate to parent. */
123 static struct {
124         int flag;
125         int (*func)(struct ifnet *, int);
126 } vlan_pflags[] = {
127         {IFF_PROMISC, ifpromisc},
128         {IFF_ALLMULTI, if_allmulti},
129         {0, NULL}
130 };
131
132 SYSCTL_DECL(_net_link);
133 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
134 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
135
136 static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
137
138 /*
139  * We have a global mutex, that is used to serialize configuration
140  * changes and isn't used in normal packet delivery.
141  *
142  * We also have a per-trunk rwlock, that is locked shared on packet
143  * processing and exclusive when configuration is changed.
144  *
145  * The VLAN_ARRAY substitutes the dynamic hash with a static array
146  * with 4096 entries. In theory this can give a boots in processing,
147  * however on practice it does not. Probably this is because array
148  * is too big to fit into CPU cache.
149  */
150 static struct mtx ifv_mtx;
151 #define VLAN_LOCK_INIT()        mtx_init(&ifv_mtx, "vlan_global", NULL, MTX_DEF)
152 #define VLAN_LOCK_DESTROY()     mtx_destroy(&ifv_mtx)
153 #define VLAN_LOCK_ASSERT()      mtx_assert(&ifv_mtx, MA_OWNED)
154 #define VLAN_LOCK()             mtx_lock(&ifv_mtx)
155 #define VLAN_UNLOCK()           mtx_unlock(&ifv_mtx)
156 #define TRUNK_LOCK_INIT(trunk)  rw_init(&(trunk)->rw, VLANNAME)
157 #define TRUNK_LOCK_DESTROY(trunk) rw_destroy(&(trunk)->rw)
158 #define TRUNK_LOCK(trunk)       rw_wlock(&(trunk)->rw)
159 #define TRUNK_UNLOCK(trunk)     rw_wunlock(&(trunk)->rw)
160 #define TRUNK_LOCK_ASSERT(trunk) rw_assert(&(trunk)->rw, RA_WLOCKED)
161 #define TRUNK_RLOCK(trunk)      rw_rlock(&(trunk)->rw)
162 #define TRUNK_RUNLOCK(trunk)    rw_runlock(&(trunk)->rw)
163 #define TRUNK_LOCK_RASSERT(trunk) rw_assert(&(trunk)->rw, RA_RLOCKED)
164
165 #ifndef VLAN_ARRAY
166 static  void vlan_inithash(struct ifvlantrunk *trunk);
167 static  void vlan_freehash(struct ifvlantrunk *trunk);
168 static  int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
169 static  int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
170 static  void vlan_growhash(struct ifvlantrunk *trunk, int howmuch);
171 static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk,
172         uint16_t tag);
173 #endif
174 static  void trunk_destroy(struct ifvlantrunk *trunk);
175
176 static  void vlan_start(struct ifnet *ifp);
177 static  void vlan_ifinit(void *foo);
178 static  void vlan_input(struct ifnet *ifp, struct mbuf *m);
179 static  int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
180 static  int vlan_setflag(struct ifnet *ifp, int flag, int status,
181     int (*func)(struct ifnet *, int));
182 static  int vlan_setflags(struct ifnet *ifp, int status);
183 static  int vlan_setmulti(struct ifnet *ifp);
184 static  int vlan_unconfig(struct ifnet *ifp);
185 static  int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
186 static  void vlan_link_state(struct ifnet *ifp, int link);
187 static  void vlan_capabilities(struct ifvlan *ifv);
188 static  void vlan_trunk_capabilities(struct ifnet *ifp);
189
190 static  struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
191     const char *, int *);
192 static  int vlan_clone_match(struct if_clone *, const char *);
193 static  int vlan_clone_create(struct if_clone *, char *, size_t);
194 static  int vlan_clone_destroy(struct if_clone *, struct ifnet *);
195
196 static  struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
197     IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
198
199 #ifndef VLAN_ARRAY
200 #define HASH(n, m)      ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m))
201 static void
202 vlan_inithash(struct ifvlantrunk *trunk)
203 {
204         int i, n;
205         
206         /*
207          * The trunk must not be locked here since we call malloc(M_WAITOK).
208          * It is OK in case this function is called before the trunk struct
209          * gets hooked up and becomes visible from other threads.
210          */
211
212         KASSERT(trunk->hwidth == 0 && trunk->hash == NULL,
213             ("%s: hash already initialized", __func__));
214
215         trunk->hwidth = VLAN_DEF_HWIDTH;
216         n = 1 << trunk->hwidth;
217         trunk->hmask = n - 1;
218         trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK);
219         for (i = 0; i < n; i++)
220                 LIST_INIT(&trunk->hash[i]);
221 }
222
223 static void
224 vlan_freehash(struct ifvlantrunk *trunk)
225 {
226 #ifdef INVARIANTS
227         int i;
228
229         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
230         for (i = 0; i < (1 << trunk->hwidth); i++)
231                 KASSERT(LIST_EMPTY(&trunk->hash[i]),
232                     ("%s: hash table not empty", __func__));
233 #endif
234         free(trunk->hash, M_VLAN);
235         trunk->hash = NULL;
236         trunk->hwidth = trunk->hmask = 0;
237 }
238
239 static int
240 vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
241 {
242         int i, b;
243         struct ifvlan *ifv2;
244
245         TRUNK_LOCK_ASSERT(trunk);
246         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
247
248         b = 1 << trunk->hwidth;
249         i = HASH(ifv->ifv_tag, trunk->hmask);
250         LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
251                 if (ifv->ifv_tag == ifv2->ifv_tag)
252                         return (EEXIST);
253
254         /*
255          * Grow the hash when the number of vlans exceeds half of the number of
256          * hash buckets squared. This will make the average linked-list length
257          * buckets/2.
258          */
259         if (trunk->refcnt > (b * b) / 2) {
260                 vlan_growhash(trunk, 1);
261                 i = HASH(ifv->ifv_tag, trunk->hmask);
262         }
263         LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list);
264         trunk->refcnt++;
265
266         return (0);
267 }
268
269 static int
270 vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
271 {
272         int i, b;
273         struct ifvlan *ifv2;
274
275         TRUNK_LOCK_ASSERT(trunk);
276         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
277         
278         b = 1 << trunk->hwidth;
279         i = HASH(ifv->ifv_tag, trunk->hmask);
280         LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
281                 if (ifv2 == ifv) {
282                         trunk->refcnt--;
283                         LIST_REMOVE(ifv2, ifv_list);
284                         if (trunk->refcnt < (b * b) / 2)
285                                 vlan_growhash(trunk, -1);
286                         return (0);
287                 }
288
289         panic("%s: vlan not found\n", __func__);
290         return (ENOENT); /*NOTREACHED*/
291 }
292
293 /*
294  * Grow the hash larger or smaller if memory permits.
295  */
296 static void
297 vlan_growhash(struct ifvlantrunk *trunk, int howmuch)
298 {
299
300         struct ifvlan *ifv;
301         struct ifvlanhead *hash2;
302         int hwidth2, i, j, n, n2;
303
304         TRUNK_LOCK_ASSERT(trunk);
305         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
306
307         if (howmuch == 0) {
308                 /* Harmless yet obvious coding error */
309                 printf("%s: howmuch is 0\n", __func__);
310                 return;
311         }
312
313         hwidth2 = trunk->hwidth + howmuch;
314         n = 1 << trunk->hwidth;
315         n2 = 1 << hwidth2;
316         /* Do not shrink the table below the default */
317         if (hwidth2 < VLAN_DEF_HWIDTH)
318                 return;
319
320         /* M_NOWAIT because we're called with trunk mutex held */
321         hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT);
322         if (hash2 == NULL) {
323                 printf("%s: out of memory -- hash size not changed\n",
324                     __func__);
325                 return;         /* We can live with the old hash table */
326         }
327         for (j = 0; j < n2; j++)
328                 LIST_INIT(&hash2[j]);
329         for (i = 0; i < n; i++)
330                 while (!LIST_EMPTY(&trunk->hash[i])) {
331                         ifv = LIST_FIRST(&trunk->hash[i]);
332                         LIST_REMOVE(ifv, ifv_list);
333                         j = HASH(ifv->ifv_tag, n2 - 1);
334                         LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list);
335                 }
336         free(trunk->hash, M_VLAN);
337         trunk->hash = hash2;
338         trunk->hwidth = hwidth2;
339         trunk->hmask = n2 - 1;
340 }
341
342 static __inline struct ifvlan *
343 vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag)
344 {
345         struct ifvlan *ifv;
346
347         TRUNK_LOCK_RASSERT(trunk);
348
349         LIST_FOREACH(ifv, &trunk->hash[HASH(tag, trunk->hmask)], ifv_list)
350                 if (ifv->ifv_tag == tag)
351                         return (ifv);
352         return (NULL);
353 }
354
355 #if 0
356 /* Debugging code to view the hashtables. */
357 static void
358 vlan_dumphash(struct ifvlantrunk *trunk)
359 {
360         int i;
361         struct ifvlan *ifv;
362
363         for (i = 0; i < (1 << trunk->hwidth); i++) {
364                 printf("%d: ", i);
365                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
366                         printf("%s ", ifv->ifv_ifp->if_xname);
367                 printf("\n");
368         }
369 }
370 #endif /* 0 */
371 #endif /* !VLAN_ARRAY */
372
373 static void
374 trunk_destroy(struct ifvlantrunk *trunk)
375 {
376         VLAN_LOCK_ASSERT();
377
378         TRUNK_LOCK(trunk);
379 #ifndef VLAN_ARRAY
380         vlan_freehash(trunk);
381 #endif
382         trunk->parent->if_vlantrunk = NULL;
383         LIST_REMOVE(trunk, trunk_entry);
384         TRUNK_UNLOCK(trunk);
385         TRUNK_LOCK_DESTROY(trunk);
386         free(trunk, M_VLAN);
387 }
388
389 /*
390  * Program our multicast filter. What we're actually doing is
391  * programming the multicast filter of the parent. This has the
392  * side effect of causing the parent interface to receive multicast
393  * traffic that it doesn't really want, which ends up being discarded
394  * later by the upper protocol layers. Unfortunately, there's no way
395  * to avoid this: there really is only one physical interface.
396  *
397  * XXX: There is a possible race here if more than one thread is
398  *      modifying the multicast state of the vlan interface at the same time.
399  */
400 static int
401 vlan_setmulti(struct ifnet *ifp)
402 {
403         struct ifnet            *ifp_p;
404         struct ifmultiaddr      *ifma, *rifma = NULL;
405         struct ifvlan           *sc;
406         struct vlan_mc_entry    *mc = NULL;
407         struct sockaddr_dl      sdl;
408         int                     error;
409
410         /*VLAN_LOCK_ASSERT();*/
411
412         /* Find the parent. */
413         sc = ifp->if_softc;
414         ifp_p = PARENT(sc);
415
416         bzero((char *)&sdl, sizeof(sdl));
417         sdl.sdl_len = sizeof(sdl);
418         sdl.sdl_family = AF_LINK;
419         sdl.sdl_index = ifp_p->if_index;
420         sdl.sdl_type = IFT_ETHER;
421         sdl.sdl_alen = ETHER_ADDR_LEN;
422
423         /* First, remove any existing filter entries. */
424         while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) {
425                 mc = SLIST_FIRST(&sc->vlan_mc_listhead);
426                 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
427                 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
428                 if (error)
429                         return (error);
430                 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
431                 free(mc, M_VLAN);
432         }
433
434         /* Now program new ones. */
435         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
436                 if (ifma->ifma_addr->sa_family != AF_LINK)
437                         continue;
438                 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
439                 if (mc == NULL)
440                         return (ENOMEM);
441                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
442                     (char *)&mc->mc_addr, ETHER_ADDR_LEN);
443                 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
444                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
445                     LLADDR(&sdl), ETHER_ADDR_LEN);
446                 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
447                 if (error)
448                         return (error);
449         }
450
451         return (0);
452 }
453
454 /*
455  * VLAN support can be loaded as a module.  The only place in the
456  * system that's intimately aware of this is ether_input.  We hook
457  * into this code through vlan_input_p which is defined there and
458  * set here.  Noone else in the system should be aware of this so
459  * we use an explicit reference here.
460  */
461 extern  void (*vlan_input_p)(struct ifnet *, struct mbuf *);
462
463 /* For if_link_state_change() eyes only... */
464 extern  void (*vlan_link_state_p)(struct ifnet *, int);
465
466 static int
467 vlan_modevent(module_t mod, int type, void *data)
468 {
469
470         switch (type) {
471         case MOD_LOAD:
472                 LIST_INIT(&trunk_list);
473                 VLAN_LOCK_INIT();
474                 vlan_input_p = vlan_input;
475                 vlan_link_state_p = vlan_link_state;
476                 vlan_trunk_cap_p = vlan_trunk_capabilities;
477                 if_clone_attach(&vlan_cloner);
478                 break;
479         case MOD_UNLOAD:
480             {
481                 struct ifvlantrunk *trunk, *trunk1;
482
483                 if_clone_detach(&vlan_cloner);
484                 vlan_input_p = NULL;
485                 vlan_link_state_p = NULL;
486                 vlan_trunk_cap_p = NULL;
487                 VLAN_LOCK();
488                 LIST_FOREACH_SAFE(trunk, &trunk_list, trunk_entry, trunk1)
489                         trunk_destroy(trunk);
490                 VLAN_UNLOCK();
491                 VLAN_LOCK_DESTROY();
492                 break;
493             }
494         default:
495                 return (EOPNOTSUPP);
496         }
497         return (0);
498 }
499
500 static moduledata_t vlan_mod = {
501         "if_vlan",
502         vlan_modevent,
503         0
504 };
505
506 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
507 MODULE_VERSION(if_vlan, 3);
508 MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
509
510 static struct ifnet *
511 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
512 {
513         const char *cp;
514         struct ifnet *ifp;
515         int t = 0;
516
517         /* Check for <etherif>.<vlan> style interface names. */
518         IFNET_RLOCK();
519         TAILQ_FOREACH(ifp, &ifnet, if_link) {
520                 if (ifp->if_type != IFT_ETHER)
521                         continue;
522                 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
523                         continue;
524                 cp = name + strlen(ifp->if_xname);
525                 if (*cp != '.')
526                         continue;
527                 for(; *cp != '\0'; cp++) {
528                         if (*cp < '0' || *cp > '9')
529                                 continue;
530                         t = (t * 10) + (*cp - '0');
531                 }
532                 if (tag != NULL)
533                         *tag = t;
534                 break;
535         }
536         IFNET_RUNLOCK();
537
538         return (ifp);
539 }
540
541 static int
542 vlan_clone_match(struct if_clone *ifc, const char *name)
543 {
544         const char *cp;
545
546         if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
547                 return (1);
548
549         if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
550                 return (0);
551         for (cp = name + 4; *cp != '\0'; cp++) {
552                 if (*cp < '0' || *cp > '9')
553                         return (0);
554         }
555
556         return (1);
557 }
558
559 static int
560 vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
561 {
562         char *dp;
563         int wildcard;
564         int unit;
565         int error;
566         int tag;
567         int ethertag;
568         struct ifvlan *ifv;
569         struct ifnet *ifp;
570         struct ifnet *p;
571         u_char eaddr[6] = {0,0,0,0,0,0};
572
573         if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
574                 ethertag = 1;
575                 unit = -1;
576                 wildcard = 0;
577
578                 /*
579                  * Don't let the caller set up a VLAN tag with
580                  * anything except VLID bits.
581                  */
582                 if (tag & ~EVL_VLID_MASK)
583                         return (EINVAL);
584         } else {
585                 ethertag = 0;
586
587                 error = ifc_name2unit(name, &unit);
588                 if (error != 0)
589                         return (error);
590
591                 wildcard = (unit < 0);
592         }
593
594         error = ifc_alloc_unit(ifc, &unit);
595         if (error != 0)
596                 return (error);
597
598         /* In the wildcard case, we need to update the name. */
599         if (wildcard) {
600                 for (dp = name; *dp != '\0'; dp++);
601                 if (snprintf(dp, len - (dp-name), "%d", unit) >
602                     len - (dp-name) - 1) {
603                         panic("%s: interface name too long", __func__);
604                 }
605         }
606
607         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
608         ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
609         if (ifp == NULL) {
610                 ifc_free_unit(ifc, unit);
611                 free(ifv, M_VLAN);
612                 return (ENOSPC);
613         }
614         SLIST_INIT(&ifv->vlan_mc_listhead);
615
616         ifp->if_softc = ifv;
617         /*
618          * Set the name manually rather than using if_initname because
619          * we don't conform to the default naming convention for interfaces.
620          */
621         strlcpy(ifp->if_xname, name, IFNAMSIZ);
622         ifp->if_dname = ifc->ifc_name;
623         ifp->if_dunit = unit;
624         /* NB: flags are not set here */
625         ifp->if_linkmib = &ifv->ifv_mib;
626         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
627         /* NB: mtu is not set here */
628
629         ifp->if_init = vlan_ifinit;
630         ifp->if_start = vlan_start;
631         ifp->if_ioctl = vlan_ioctl;
632         ifp->if_snd.ifq_maxlen = ifqmaxlen;
633         ifp->if_flags = VLAN_IFFLAGS;
634         ether_ifattach(ifp, eaddr);
635         /* Now undo some of the damage... */
636         ifp->if_baudrate = 0;
637         ifp->if_type = IFT_L2VLAN;
638         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
639
640         if (ethertag) {
641                 error = vlan_config(ifv, p, tag);
642                 if (error != 0) {
643                         /*
644                          * Since we've partialy failed, we need to back
645                          * out all the way, otherwise userland could get
646                          * confused.  Thus, we destroy the interface.
647                          */
648                         vlan_unconfig(ifp);
649                         ether_ifdetach(ifp);
650                         if_free_type(ifp, IFT_ETHER);
651                         free(ifv, M_VLAN);
652
653                         return (error);
654                 }
655                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
656
657                 /* Update flags on the parent, if necessary. */
658                 vlan_setflags(ifp, 1);
659         }
660
661         return (0);
662 }
663
664 static int
665 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
666 {
667         int unit;
668         struct ifvlan *ifv = ifp->if_softc;
669
670         unit = ifp->if_dunit;
671
672         vlan_unconfig(ifp);
673
674         ether_ifdetach(ifp);
675         if_free_type(ifp, IFT_ETHER);
676
677         free(ifv, M_VLAN);
678
679         ifc_free_unit(ifc, unit);
680
681         return (0);
682 }
683
684 /*
685  * The ifp->if_init entry point for vlan(4) is a no-op.
686  */
687 static void
688 vlan_ifinit(void *foo)
689 {
690
691 }
692
693 /*
694  * The if_start method for vlan(4) interface. It doesn't
695  * raises the IFF_DRV_OACTIVE flag, since it is called
696  * only from IFQ_HANDOFF() macro in ether_output_frame().
697  * If the interface queue is full, and vlan_start() is
698  * not called, the queue would never get emptied and
699  * interface would stall forever.
700  */
701 static void
702 vlan_start(struct ifnet *ifp)
703 {
704         struct ifvlan *ifv;
705         struct ifnet *p;
706         struct mbuf *m;
707         int error;
708
709         ifv = ifp->if_softc;
710         p = PARENT(ifv);
711
712         for (;;) {
713                 IF_DEQUEUE(&ifp->if_snd, m);
714                 if (m == 0)
715                         break;
716                 BPF_MTAP(ifp, m);
717
718                 /*
719                  * Do not run parent's if_start() if the parent is not up,
720                  * or parent's driver will cause a system crash.
721                  */
722                 if (!((p->if_flags & IFF_UP) &&
723                     (p->if_drv_flags & IFF_DRV_RUNNING))) {
724                         m_freem(m);
725                         ifp->if_collisions++;
726                         continue;
727                 }
728
729                 /*
730                  * If underlying interface can do VLAN tag insertion itself,
731                  * just pass the packet along. However, we need some way to
732                  * tell the interface where the packet came from so that it
733                  * knows how to find the VLAN tag to use, so we attach a
734                  * packet tag that holds it.
735                  */
736                 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
737                         struct m_tag *mtag = (struct m_tag *)
738                             uma_zalloc(zone_mtag_vlan, M_NOWAIT);
739                         if (mtag == NULL) {
740                                 ifp->if_oerrors++;
741                                 m_freem(m);
742                                 continue;
743                         }
744                         VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
745                         m_tag_prepend(m, mtag);
746                         m->m_flags |= M_VLANTAG;
747                 } else {
748                         struct ether_vlan_header *evl;
749
750                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
751                         if (m == NULL) {
752                                 if_printf(ifp,
753                                     "unable to prepend VLAN header\n");
754                                 ifp->if_oerrors++;
755                                 continue;
756                         }
757                         /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
758
759                         if (m->m_len < sizeof(*evl)) {
760                                 m = m_pullup(m, sizeof(*evl));
761                                 if (m == NULL) {
762                                         if_printf(ifp,
763                                             "cannot pullup VLAN header\n");
764                                         ifp->if_oerrors++;
765                                         continue;
766                                 }
767                         }
768
769                         /*
770                          * Transform the Ethernet header into an Ethernet header
771                          * with 802.1Q encapsulation.
772                          */
773                         bcopy(mtod(m, char *) + ifv->ifv_encaplen,
774                               mtod(m, char *), ETHER_HDR_LEN);
775                         evl = mtod(m, struct ether_vlan_header *);
776                         evl->evl_proto = evl->evl_encap_proto;
777                         evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
778                         evl->evl_tag = htons(ifv->ifv_tag);
779 #ifdef DEBUG
780                         printf("%s: %*D\n", __func__, (int)sizeof(*evl),
781                             (unsigned char *)evl, ":");
782 #endif
783                 }
784
785                 /*
786                  * Send it, precisely as ether_output() would have.
787                  * We are already running at splimp.
788                  */
789                 IFQ_HANDOFF(p, m, error);
790                 if (!error)
791                         ifp->if_opackets++;
792                 else
793                         ifp->if_oerrors++;
794         }
795 }
796
797 static void
798 vlan_input(struct ifnet *ifp, struct mbuf *m)
799 {
800         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
801         struct ifvlan *ifv;
802         struct m_tag *mtag;
803         uint16_t tag;
804
805         KASSERT(trunk != NULL, ("%s: no trunk", __func__));
806
807         if (m->m_flags & M_VLANTAG) {
808                 /*
809                  * Packet is tagged, but m contains a normal
810                  * Ethernet frame; the tag is stored out-of-band.
811                  */
812                 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
813                 KASSERT(mtag != NULL,
814                         ("%s: M_VLANTAG without m_tag", __func__));
815                 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
816                 m_tag_delete(m, mtag);
817                 m->m_flags &= ~M_VLANTAG;
818         } else {
819                 struct ether_vlan_header *evl;
820
821                 /*
822                  * Packet is tagged in-band as specified by 802.1q.
823                  */
824                 mtag = NULL;
825                 switch (ifp->if_type) {
826                 case IFT_ETHER:
827                         if (m->m_len < sizeof(*evl) &&
828                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
829                                 if_printf(ifp, "cannot pullup VLAN header\n");
830                                 return;
831                         }
832                         evl = mtod(m, struct ether_vlan_header *);
833                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
834                                 ("%s: bad encapsulation protocol (%u)",
835                                  __func__, ntohs(evl->evl_encap_proto)));
836
837                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
838
839                         /*
840                          * Restore the original ethertype.  We'll remove
841                          * the encapsulation after we've found the vlan
842                          * interface corresponding to the tag.
843                          */
844                         evl->evl_encap_proto = evl->evl_proto;
845                         break;
846                 default:
847                         tag = (uint16_t) -1;
848 #ifdef INVARIANTS
849                         panic("%s: unsupported if_type (%u)",
850                               __func__, ifp->if_type);
851 #endif
852                         break;
853                 }
854         }
855
856         /*
857          * In VLAN_ARRAY case we proceed completely lockless.
858          */
859 #ifdef VLAN_ARRAY
860         ifv = trunk->vlans[tag];
861         if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
862                 m_freem(m);
863                 ifp->if_noproto++;
864                 return;
865         }
866 #else
867         TRUNK_RLOCK(trunk);
868         ifv = vlan_gethash(trunk, tag);
869         if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
870                 TRUNK_RUNLOCK(trunk);
871                 m_freem(m);
872                 ifp->if_noproto++;
873                 return;
874         }
875         TRUNK_RUNLOCK(trunk);
876 #endif
877
878         if (mtag == NULL) {
879                 /*
880                  * Packet had an in-line encapsulation header;
881                  * remove it.  The original header has already
882                  * been fixed up above.
883                  */
884                 bcopy(mtod(m, caddr_t),
885                       mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
886                       ETHER_HDR_LEN);
887                 m_adj(m, ETHER_VLAN_ENCAP_LEN);
888         }
889
890         m->m_pkthdr.rcvif = ifv->ifv_ifp;
891         ifv->ifv_ifp->if_ipackets++;
892
893         /* Pass it back through the parent's input routine. */
894         (*ifp->if_input)(ifv->ifv_ifp, m);
895 }
896
897 static int
898 vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
899 {
900         struct ifvlantrunk *trunk;
901         struct ifnet *ifp;
902         int error = 0;
903
904         /* VID numbers 0x0 and 0xFFF are reserved */
905         if (tag == 0 || tag == 0xFFF)
906                 return (EINVAL);
907         if (p->if_type != IFT_ETHER)
908                 return (EPROTONOSUPPORT);
909         if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
910                 return (EPROTONOSUPPORT);
911         if (ifv->ifv_trunk)
912                 return (EBUSY);
913
914         if (p->if_vlantrunk == NULL) {
915                 trunk = malloc(sizeof(struct ifvlantrunk),
916                     M_VLAN, M_WAITOK | M_ZERO);
917 #ifndef VLAN_ARRAY
918                 vlan_inithash(trunk);
919 #endif
920                 VLAN_LOCK();
921                 if (p->if_vlantrunk != NULL) {
922                         /* A race that that is very unlikely to be hit. */
923 #ifndef VLAN_ARRAY
924                         vlan_freehash(trunk);
925 #endif
926                         free(trunk, M_VLAN);
927                         goto exists;
928                 }
929                 TRUNK_LOCK_INIT(trunk);
930                 LIST_INSERT_HEAD(&trunk_list, trunk, trunk_entry);
931                 TRUNK_LOCK(trunk);
932                 p->if_vlantrunk = trunk;
933                 trunk->parent = p;
934         } else {
935                 VLAN_LOCK();
936 exists:
937                 trunk = p->if_vlantrunk;
938                 TRUNK_LOCK(trunk);
939         }
940
941         ifv->ifv_tag = tag;
942 #ifdef VLAN_ARRAY
943         if (trunk->vlans[tag] != NULL)
944                 error = EEXIST;
945 #else
946         error = vlan_inshash(trunk, ifv);
947 #endif
948         if (error)
949                 goto done;
950
951         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
952         ifv->ifv_mintu = ETHERMIN;
953         ifv->ifv_pflags = 0;
954
955         /*
956          * If the parent supports the VLAN_MTU capability,
957          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
958          * use it.
959          */
960         if (p->if_capenable & IFCAP_VLAN_MTU) {
961                 /*
962                  * No need to fudge the MTU since the parent can
963                  * handle extended frames.
964                  */
965                 ifv->ifv_mtufudge = 0;
966         } else {
967                 /*
968                  * Fudge the MTU by the encapsulation size.  This
969                  * makes us incompatible with strictly compliant
970                  * 802.1Q implementations, but allows us to use
971                  * the feature with other NetBSD implementations,
972                  * which might still be useful.
973                  */
974                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
975         }
976
977         ifv->ifv_trunk = trunk;
978         ifp = ifv->ifv_ifp;
979         ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
980         ifp->if_baudrate = p->if_baudrate;
981         /*
982          * Copy only a selected subset of flags from the parent.
983          * Other flags are none of our business.
984          */
985 #define VLAN_COPY_FLAGS (IFF_SIMPLEX)
986         ifp->if_flags &= ~VLAN_COPY_FLAGS;
987         ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
988 #undef VLAN_COPY_FLAGS
989
990         ifp->if_link_state = p->if_link_state;
991
992         vlan_capabilities(ifv);
993
994         /*
995          * Set up our ``Ethernet address'' to reflect the underlying
996          * physical interface's.
997          */
998         bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN);
999
1000         /*
1001          * Configure multicast addresses that may already be
1002          * joined on the vlan device.
1003          */
1004         (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
1005
1006 #ifdef VLAN_ARRAY
1007         atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[tag], (uintptr_t)ifv);
1008         trunk->refcnt++;
1009 #endif
1010 done:
1011         TRUNK_UNLOCK(trunk);
1012         VLAN_UNLOCK();
1013
1014         return (error);
1015 }
1016
1017 static int
1018 vlan_unconfig(struct ifnet *ifp)
1019 {
1020         struct ifvlantrunk *trunk;
1021         struct vlan_mc_entry *mc;
1022         struct ifvlan *ifv;
1023         int error;
1024
1025         VLAN_LOCK();
1026
1027         ifv = ifp->if_softc;
1028         trunk = ifv->ifv_trunk;
1029
1030         if (trunk) {
1031                 struct sockaddr_dl sdl;
1032                 struct ifnet *p = trunk->parent;
1033
1034                 TRUNK_LOCK(trunk);
1035 #ifdef VLAN_ARRAY
1036                 atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[ifv->ifv_tag],
1037                     (uintptr_t)NULL);
1038                 trunk->refcnt--;
1039 #endif
1040
1041                 /*
1042                  * Since the interface is being unconfigured, we need to
1043                  * empty the list of multicast groups that we may have joined
1044                  * while we were alive from the parent's list.
1045                  */
1046                 bzero((char *)&sdl, sizeof(sdl));
1047                 sdl.sdl_len = sizeof(sdl);
1048                 sdl.sdl_family = AF_LINK;
1049                 sdl.sdl_index = p->if_index;
1050                 sdl.sdl_type = IFT_ETHER;
1051                 sdl.sdl_alen = ETHER_ADDR_LEN;
1052
1053                 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
1054                         mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
1055                         bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
1056                             ETHER_ADDR_LEN);
1057                         error = if_delmulti(p, (struct sockaddr *)&sdl);
1058                         if (error)
1059                                 return (error);
1060                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
1061                         free(mc, M_VLAN);
1062                 }
1063
1064                 vlan_setflags(ifp, 0); /* clear special flags on parent */
1065 #ifndef VLAN_ARRAY
1066                 vlan_remhash(trunk, ifv);
1067 #endif
1068                 ifv->ifv_trunk = NULL;
1069
1070                 /*
1071                  * Check if we were the last.
1072                  */
1073                 if (trunk->refcnt == 0) {
1074                         atomic_store_rel_ptr((uintptr_t *)
1075                             &trunk->parent->if_vlantrunk,
1076                             (uintptr_t)NULL);
1077                         /*
1078                          * XXXGL: If some ithread has already entered
1079                          * vlan_input() and is now blocked on the trunk
1080                          * lock, then it should preempt us right after
1081                          * unlock and finish its work. Then we will acquire
1082                          * lock again in trunk_destroy().
1083                          * XXX: not true in case of VLAN_ARRAY
1084                          */
1085                         TRUNK_UNLOCK(trunk);
1086                         trunk_destroy(trunk);
1087                 } else
1088                         TRUNK_UNLOCK(trunk);
1089         }
1090
1091         /* Disconnect from parent. */
1092         if (ifv->ifv_pflags)
1093                 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
1094         ifv->ifv_ifp->if_mtu = ETHERMTU;                /* XXX why not 0? */
1095         ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
1096
1097         /* Clear our MAC address. */
1098         bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
1099
1100         VLAN_UNLOCK();
1101
1102         return (0);
1103 }
1104
1105 /* Handle a reference counted flag that should be set on the parent as well */
1106 static int
1107 vlan_setflag(struct ifnet *ifp, int flag, int status,
1108              int (*func)(struct ifnet *, int))
1109 {
1110         struct ifvlan *ifv;
1111         int error;
1112
1113         /* XXX VLAN_LOCK_ASSERT(); */
1114
1115         ifv = ifp->if_softc;
1116         status = status ? (ifp->if_flags & flag) : 0;
1117         /* Now "status" contains the flag value or 0 */
1118
1119         /*
1120          * See if recorded parent's status is different from what
1121          * we want it to be.  If it is, flip it.  We record parent's
1122          * status in ifv_pflags so that we won't clear parent's flag
1123          * we haven't set.  In fact, we don't clear or set parent's
1124          * flags directly, but get or release references to them.
1125          * That's why we can be sure that recorded flags still are
1126          * in accord with actual parent's flags.
1127          */
1128         if (status != (ifv->ifv_pflags & flag)) {
1129                 error = (*func)(PARENT(ifv), status);
1130                 if (error)
1131                         return (error);
1132                 ifv->ifv_pflags &= ~flag;
1133                 ifv->ifv_pflags |= status;
1134         }
1135         return (0);
1136 }
1137
1138 /*
1139  * Handle IFF_* flags that require certain changes on the parent:
1140  * if "status" is true, update parent's flags respective to our if_flags;
1141  * if "status" is false, forcedly clear the flags set on parent.
1142  */
1143 static int
1144 vlan_setflags(struct ifnet *ifp, int status)
1145 {
1146         int error, i;
1147         
1148         for (i = 0; vlan_pflags[i].flag; i++) {
1149                 error = vlan_setflag(ifp, vlan_pflags[i].flag,
1150                                      status, vlan_pflags[i].func);
1151                 if (error)
1152                         return (error);
1153         }
1154         return (0);
1155 }
1156
1157 /* Inform all vlans that their parent has changed link state */
1158 static void
1159 vlan_link_state(struct ifnet *ifp, int link)
1160 {
1161         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
1162         struct ifvlan *ifv;
1163         int i;
1164
1165         TRUNK_LOCK(trunk);
1166 #ifdef VLAN_ARRAY
1167         for (i = 0; i < EVL_VLID_MASK+1; i++)
1168                 if (trunk->vlans[i] != NULL) {
1169                         ifv = trunk->vlans[i];
1170 #else
1171         for (i = 0; i < (1 << trunk->hwidth); i++) {
1172                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
1173 #endif
1174                         if_link_state_change(ifv->ifv_ifp,
1175                             trunk->parent->if_link_state);
1176         }
1177         TRUNK_UNLOCK(trunk);
1178 }
1179
1180 static void
1181 vlan_capabilities(struct ifvlan *ifv)
1182 {
1183         struct ifnet *p = PARENT(ifv);
1184         struct ifnet *ifp = ifv->ifv_ifp;
1185
1186         TRUNK_LOCK_ASSERT(TRUNK(ifv));
1187
1188         /*
1189          * If the parent interface can do checksum offloading
1190          * on VLANs, then propagate its hardware-assisted
1191          * checksumming flags. Also assert that checksum
1192          * offloading requires hardware VLAN tagging.
1193          */
1194         if (p->if_capabilities & IFCAP_VLAN_HWCSUM)
1195                 ifp->if_capabilities = p->if_capabilities & IFCAP_HWCSUM;
1196
1197         if (p->if_capenable & IFCAP_VLAN_HWCSUM &&
1198             p->if_capenable & IFCAP_VLAN_HWTAGGING) {
1199                 ifp->if_capenable = p->if_capenable & IFCAP_HWCSUM;
1200                 ifp->if_hwassist = p->if_hwassist;
1201         } else {
1202                 ifp->if_capenable = 0;
1203                 ifp->if_hwassist = 0;
1204         }
1205 }
1206
1207 static void
1208 vlan_trunk_capabilities(struct ifnet *ifp)
1209 {
1210         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
1211         struct ifvlan *ifv;
1212         int i;
1213
1214         TRUNK_LOCK(trunk);
1215 #ifdef VLAN_ARRAY
1216         for (i = 0; i < EVL_VLID_MASK+1; i++)
1217                 if (trunk->vlans[i] != NULL) {
1218                         ifv = trunk->vlans[i];
1219 #else
1220         for (i = 0; i < (1 << trunk->hwidth); i++) {
1221                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
1222 #endif
1223                         vlan_capabilities(ifv);
1224         }
1225         TRUNK_UNLOCK(trunk);
1226 }
1227
1228 static int
1229 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1230 {
1231         struct ifaddr *ifa;
1232         struct ifnet *p;
1233         struct ifreq *ifr;
1234         struct ifvlan *ifv;
1235         struct vlanreq vlr;
1236         int error = 0;
1237
1238         ifr = (struct ifreq *)data;
1239         ifa = (struct ifaddr *)data;
1240         ifv = ifp->if_softc;
1241
1242         switch (cmd) {
1243         case SIOCSIFADDR:
1244                 ifp->if_flags |= IFF_UP;
1245
1246                 switch (ifa->ifa_addr->sa_family) {
1247 #ifdef INET
1248                 case AF_INET:
1249                         arp_ifinit(ifv->ifv_ifp, ifa);
1250                         break;
1251 #endif
1252                 default:
1253                         break;
1254                 }
1255                 break;
1256
1257         case SIOCGIFADDR:
1258                 {
1259                         struct sockaddr *sa;
1260
1261                         sa = (struct sockaddr *) &ifr->ifr_data;
1262                         bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data,
1263                             ETHER_ADDR_LEN);
1264                 }
1265                 break;
1266
1267         case SIOCGIFMEDIA:
1268                 VLAN_LOCK();
1269                 if (TRUNK(ifv) != NULL) {
1270                         error = (*PARENT(ifv)->if_ioctl)(PARENT(ifv),
1271                                         SIOCGIFMEDIA, data);
1272                         VLAN_UNLOCK();
1273                         /* Limit the result to the parent's current config. */
1274                         if (error == 0) {
1275                                 struct ifmediareq *ifmr;
1276
1277                                 ifmr = (struct ifmediareq *)data;
1278                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
1279                                         ifmr->ifm_count = 1;
1280                                         error = copyout(&ifmr->ifm_current,
1281                                                 ifmr->ifm_ulist,
1282                                                 sizeof(int));
1283                                 }
1284                         }
1285                 } else {
1286                         VLAN_UNLOCK();
1287                         error = EINVAL;
1288                 }
1289                 break;
1290
1291         case SIOCSIFMEDIA:
1292                 error = EINVAL;
1293                 break;
1294
1295         case SIOCSIFMTU:
1296                 /*
1297                  * Set the interface MTU.
1298                  */
1299                 VLAN_LOCK();
1300                 if (TRUNK(ifv) != NULL) {
1301                         if (ifr->ifr_mtu >
1302                              (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) ||
1303                             ifr->ifr_mtu <
1304                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
1305                                 error = EINVAL;
1306                         else
1307                                 ifp->if_mtu = ifr->ifr_mtu;
1308                 } else
1309                         error = EINVAL;
1310                 VLAN_UNLOCK();
1311                 break;
1312
1313         case SIOCSETVLAN:
1314                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
1315                 if (error)
1316                         break;
1317                 if (vlr.vlr_parent[0] == '\0') {
1318                         vlan_unconfig(ifp);
1319                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1320                         break;
1321                 }
1322                 p = ifunit(vlr.vlr_parent);
1323                 if (p == 0) {
1324                         error = ENOENT;
1325                         break;
1326                 }
1327                 /*
1328                  * Don't let the caller set up a VLAN tag with
1329                  * anything except VLID bits.
1330                  */
1331                 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
1332                         error = EINVAL;
1333                         break;
1334                 }
1335                 error = vlan_config(ifv, p, vlr.vlr_tag);
1336                 if (error)
1337                         break;
1338                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
1339
1340                 /* Update flags on the parent, if necessary. */
1341                 vlan_setflags(ifp, 1);
1342                 break;
1343
1344         case SIOCGETVLAN:
1345                 bzero(&vlr, sizeof(vlr));
1346                 VLAN_LOCK();
1347                 if (TRUNK(ifv) != NULL) {
1348                         strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname,
1349                             sizeof(vlr.vlr_parent));
1350                         vlr.vlr_tag = ifv->ifv_tag;
1351                 }
1352                 VLAN_UNLOCK();
1353                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
1354                 break;
1355                 
1356         case SIOCSIFFLAGS:
1357                 /*
1358                  * We should propagate selected flags to the parent,
1359                  * e.g., promiscuous mode.
1360                  */
1361                 if (TRUNK(ifv) != NULL)
1362                         error = vlan_setflags(ifp, 1);
1363                 break;
1364
1365         case SIOCADDMULTI:
1366         case SIOCDELMULTI:
1367                 /*
1368                  * If we don't have a parent, just remember the membership for
1369                  * when we do.
1370                  */
1371                 if (TRUNK(ifv) != NULL)
1372                         error = vlan_setmulti(ifp);
1373                 break;
1374
1375         default:
1376                 error = EINVAL;
1377         }
1378
1379         return (error);
1380 }