]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_vlan.c
This commit was generated by cvs2svn to compensate for changes in r147021,
[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
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/module.h>
51 #include <sys/queue.h>
52 #include <sys/socket.h>
53 #include <sys/sockio.h>
54 #include <sys/sysctl.h>
55 #include <sys/systm.h>
56
57 #include <net/bpf.h>
58 #include <net/ethernet.h>
59 #include <net/if.h>
60 #include <net/if_clone.h>
61 #include <net/if_arp.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 #include <net/if_vlan_var.h>
65
66 #ifdef INET
67 #include <netinet/in.h>
68 #include <netinet/if_ether.h>
69 #endif
70
71 #define VLANNAME        "vlan"
72
73 struct vlan_mc_entry {
74         struct ether_addr               mc_addr;
75         SLIST_ENTRY(vlan_mc_entry)      mc_entries;
76 };
77
78 struct  ifvlan {
79         struct  arpcom ifv_ac;  /* make this an interface */
80         struct  ifnet *ifv_p;   /* parent inteface of this vlan */
81         struct  ifv_linkmib {
82                 int     ifvm_parent;
83                 int     ifvm_encaplen;  /* encapsulation length */
84                 int     ifvm_mtufudge;  /* MTU fudged by this much */
85                 int     ifvm_mintu;     /* min transmission unit */
86                 u_int16_t ifvm_proto; /* encapsulation ethertype */
87                 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
88         }       ifv_mib;
89         SLIST_HEAD(__vlan_mchead, vlan_mc_entry)        vlan_mc_listhead;
90         LIST_ENTRY(ifvlan) ifv_list;
91         int     ifv_flags;
92 };
93 #define ifv_if  ifv_ac.ac_if
94 #define ifv_tag ifv_mib.ifvm_tag
95 #define ifv_encaplen    ifv_mib.ifvm_encaplen
96 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
97 #define ifv_mintu       ifv_mib.ifvm_mintu
98
99 #define IFVF_PROMISC    0x01            /* promiscuous mode enabled */
100
101 SYSCTL_DECL(_net_link);
102 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
103 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
104
105 static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
106 static LIST_HEAD(, ifvlan) ifv_list;
107
108 /*
109  * Locking: one lock is used to guard both the ifv_list and modification
110  * to vlan data structures.  We are rather conservative here; probably
111  * more than necessary.
112  */
113 static struct mtx ifv_mtx;
114 #define VLAN_LOCK_INIT()        mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
115 #define VLAN_LOCK_DESTROY()     mtx_destroy(&ifv_mtx)
116 #define VLAN_LOCK_ASSERT()      mtx_assert(&ifv_mtx, MA_OWNED)
117 #define VLAN_LOCK()     mtx_lock(&ifv_mtx)
118 #define VLAN_UNLOCK()   mtx_unlock(&ifv_mtx)
119
120 static  void vlan_start(struct ifnet *ifp);
121 static  void vlan_ifinit(void *foo);
122 static  void vlan_input(struct ifnet *ifp, struct mbuf *m);
123 static  int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
124 static  int vlan_setmulti(struct ifnet *ifp);
125 static  int vlan_unconfig(struct ifnet *ifp);
126 static  int vlan_config(struct ifvlan *ifv, struct ifnet *p);
127 static  void vlan_link_state(struct ifnet *ifp, int link);
128 static  int vlan_set_promisc(struct ifnet *ifp);
129
130 static  struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
131     const char *, int *);
132 static  int vlan_clone_match(struct if_clone *, const char *);
133 static  int vlan_clone_create(struct if_clone *, char *, size_t);
134 static  int vlan_clone_destroy(struct if_clone *, struct ifnet *);
135
136 static  struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
137     IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
138
139 /*
140  * Program our multicast filter. What we're actually doing is
141  * programming the multicast filter of the parent. This has the
142  * side effect of causing the parent interface to receive multicast
143  * traffic that it doesn't really want, which ends up being discarded
144  * later by the upper protocol layers. Unfortunately, there's no way
145  * to avoid this: there really is only one physical interface.
146  *
147  * XXX: There is a possible race here if more than one thread is
148  *      modifying the multicast state of the vlan interface at the same time.
149  */
150 static int
151 vlan_setmulti(struct ifnet *ifp)
152 {
153         struct ifnet            *ifp_p;
154         struct ifmultiaddr      *ifma, *rifma = NULL;
155         struct ifvlan           *sc;
156         struct vlan_mc_entry    *mc = NULL;
157         struct sockaddr_dl      sdl;
158         int                     error;
159
160         /*VLAN_LOCK_ASSERT();*/
161
162         /* Find the parent. */
163         sc = ifp->if_softc;
164         ifp_p = sc->ifv_p;
165
166         /*
167          * If we don't have a parent, just remember the membership for
168          * when we do.
169          */
170         if (ifp_p == NULL)
171                 return (0);
172
173         bzero((char *)&sdl, sizeof(sdl));
174         sdl.sdl_len = sizeof(sdl);
175         sdl.sdl_family = AF_LINK;
176         sdl.sdl_index = ifp_p->if_index;
177         sdl.sdl_type = IFT_ETHER;
178         sdl.sdl_alen = ETHER_ADDR_LEN;
179
180         /* First, remove any existing filter entries. */
181         while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) {
182                 mc = SLIST_FIRST(&sc->vlan_mc_listhead);
183                 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
184                 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
185                 if (error)
186                         return (error);
187                 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
188                 free(mc, M_VLAN);
189         }
190
191         /* Now program new ones. */
192         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
193                 if (ifma->ifma_addr->sa_family != AF_LINK)
194                         continue;
195                 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
196                 if (mc == NULL)
197                         return (ENOMEM);
198                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
199                     (char *)&mc->mc_addr, ETHER_ADDR_LEN);
200                 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
201                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
202                     LLADDR(&sdl), ETHER_ADDR_LEN);
203                 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
204                 if (error)
205                         return (error);
206         }
207
208         return (0);
209 }
210
211 /*
212  * VLAN support can be loaded as a module.  The only place in the
213  * system that's intimately aware of this is ether_input.  We hook
214  * into this code through vlan_input_p which is defined there and
215  * set here.  Noone else in the system should be aware of this so
216  * we use an explicit reference here.
217  *
218  * NB: Noone should ever need to check if vlan_input_p is null or
219  *     not.  This is because interfaces have a count of the number
220  *     of active vlans (if_nvlans) and this should never be bumped
221  *     except by vlan_config--which is in this module so therefore
222  *     the module must be loaded and vlan_input_p must be non-NULL.
223  */
224 extern  void (*vlan_input_p)(struct ifnet *, struct mbuf *);
225
226 /* For if_link_state_change() eyes only... */
227 extern  void (*vlan_link_state_p)(struct ifnet *, int);
228
229 static int
230 vlan_modevent(module_t mod, int type, void *data)
231 {
232
233         switch (type) {
234         case MOD_LOAD:
235                 LIST_INIT(&ifv_list);
236                 VLAN_LOCK_INIT();
237                 vlan_input_p = vlan_input;
238                 vlan_link_state_p = vlan_link_state;
239                 if_clone_attach(&vlan_cloner);
240                 break;
241         case MOD_UNLOAD:
242                 if_clone_detach(&vlan_cloner);
243                 vlan_input_p = NULL;
244                 vlan_link_state_p = NULL;
245                 while (!LIST_EMPTY(&ifv_list))
246                         vlan_clone_destroy(&vlan_cloner,
247                             &LIST_FIRST(&ifv_list)->ifv_if);
248                 VLAN_LOCK_DESTROY();
249                 break;
250         default:
251                 return (EOPNOTSUPP);
252         }
253         return (0);
254 }
255
256 static moduledata_t vlan_mod = {
257         "if_vlan",
258         vlan_modevent,
259         0
260 };
261
262 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
263 MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
264
265 static struct ifnet *
266 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
267 {
268         const char *cp;
269         struct ifnet *ifp;
270         int t = 0;
271
272         /* Check for <etherif>.<vlan> style interface names. */
273         IFNET_RLOCK();
274         TAILQ_FOREACH(ifp, &ifnet, if_link) {
275                 if (ifp->if_type != IFT_ETHER)
276                         continue;
277                 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
278                         continue;
279                 cp = name + strlen(ifp->if_xname);
280                 if (*cp != '.')
281                         continue;
282                 for(; *cp != '\0'; cp++) {
283                         if (*cp < '0' || *cp > '9')
284                                 continue;
285                         t = (t * 10) + (*cp - '0');
286                 }
287                 if (tag != NULL)
288                         *tag = t;
289                 break;
290         }
291         IFNET_RUNLOCK();
292
293         return (ifp);
294 }
295
296 static int
297 vlan_clone_match(struct if_clone *ifc, const char *name)
298 {
299         const char *cp;
300
301         if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
302                 return (1);
303
304         if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
305                 return (0);
306         for (cp = name + 4; *cp != '\0'; cp++) {
307                 if (*cp < '0' || *cp > '9')
308                         return (0);
309         }
310
311         return (1);
312 }
313
314 static int
315 vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
316 {
317         char *dp;
318         int wildcard;
319         int unit;
320         int error;
321         int tag;
322         int ethertag;
323         struct ifvlan *ifv;
324         struct ifnet *ifp;
325         struct ifnet *p;
326
327         if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
328                 ethertag = 1;
329                 unit = -1;
330                 wildcard = 0;
331
332                 /*
333                  * Don't let the caller set up a VLAN tag with
334                  * anything except VLID bits.
335                  */
336                 if (tag & ~EVL_VLID_MASK)
337                         return (EINVAL);
338         } else {
339                 ethertag = 0;
340
341                 error = ifc_name2unit(name, &unit);
342                 if (error != 0)
343                         return (error);
344
345                 wildcard = (unit < 0);
346         }
347
348         error = ifc_alloc_unit(ifc, &unit);
349         if (error != 0)
350                 return (error);
351
352         /* In the wildcard case, we need to update the name. */
353         if (wildcard) {
354                 for (dp = name; *dp != '\0'; dp++);
355                 if (snprintf(dp, len - (dp-name), "%d", unit) >
356                     len - (dp-name) - 1) {
357                         panic("%s: interface name too long", __func__);
358                 }
359         }
360
361         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
362         ifp = &ifv->ifv_if;
363         SLIST_INIT(&ifv->vlan_mc_listhead);
364
365         ifp->if_softc = ifv;
366         /*
367          * Set the name manually rather than using if_initname because
368          * we don't conform to the default naming convention for interfaces.
369          */
370         strlcpy(ifp->if_xname, name, IFNAMSIZ);
371         ifp->if_dname = ifc->ifc_name;
372         ifp->if_dunit = unit;
373         /* NB: flags are not set here */
374         ifp->if_linkmib = &ifv->ifv_mib;
375         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
376         /* NB: mtu is not set here */
377
378         ifp->if_init = vlan_ifinit;
379         ifp->if_start = vlan_start;
380         ifp->if_ioctl = vlan_ioctl;
381         ifp->if_snd.ifq_maxlen = ifqmaxlen;
382         ether_ifattach(ifp, ifv->ifv_ac.ac_enaddr);
383         /* Now undo some of the damage... */
384         ifp->if_baudrate = 0;
385         ifp->if_type = IFT_L2VLAN;
386         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
387
388         VLAN_LOCK();
389         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
390         VLAN_UNLOCK();
391
392         if (ethertag) {
393                 VLAN_LOCK();
394                 error = vlan_config(ifv, p);
395                 if (error != 0) {
396                         /*
397                          * Since we've partialy failed, we need to back
398                          * out all the way, otherwise userland could get
399                          * confused.  Thus, we destroy the interface.
400                          */
401                         LIST_REMOVE(ifv, ifv_list);
402                         vlan_unconfig(ifp);
403                         VLAN_UNLOCK();
404                         ether_ifdetach(ifp);
405                         free(ifv, M_VLAN);
406
407                         return (error);
408                 }
409                 ifv->ifv_tag = tag;
410                 ifp->if_flags |= IFF_RUNNING;
411                 VLAN_UNLOCK();
412
413                 /* Update promiscuous mode, if necessary. */
414                 vlan_set_promisc(ifp);
415         }
416
417         return (0);
418 }
419
420 static int
421 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
422 {
423         int unit;
424         struct ifvlan *ifv = ifp->if_softc;
425
426         unit = ifp->if_dunit;
427
428         VLAN_LOCK();
429         LIST_REMOVE(ifv, ifv_list);
430         vlan_unconfig(ifp);
431         VLAN_UNLOCK();
432
433         ether_ifdetach(ifp);
434
435         free(ifv, M_VLAN);
436
437         ifc_free_unit(ifc, unit);
438
439         return (0);
440 }
441
442 /*
443  * The ifp->if_init entry point for vlan(4) is a no-op.
444  */
445 static void
446 vlan_ifinit(void *foo)
447 {
448
449 }
450
451 static void
452 vlan_start(struct ifnet *ifp)
453 {
454         struct ifvlan *ifv;
455         struct ifnet *p;
456         struct ether_vlan_header *evl;
457         struct mbuf *m;
458         int error;
459
460         ifv = ifp->if_softc;
461         p = ifv->ifv_p;
462
463         ifp->if_flags |= IFF_OACTIVE;
464         for (;;) {
465                 IF_DEQUEUE(&ifp->if_snd, m);
466                 if (m == 0)
467                         break;
468                 BPF_MTAP(ifp, m);
469
470                 /*
471                  * Do not run parent's if_start() if the parent is not up,
472                  * or parent's driver will cause a system crash.
473                  */
474                 if ((p->if_flags & (IFF_UP | IFF_RUNNING)) !=
475                                         (IFF_UP | IFF_RUNNING)) {
476                         m_freem(m);
477                         ifp->if_collisions++;
478                         continue;
479                 }
480
481                 /*
482                  * If underlying interface can do VLAN tag insertion itself,
483                  * just pass the packet along. However, we need some way to
484                  * tell the interface where the packet came from so that it
485                  * knows how to find the VLAN tag to use, so we attach a
486                  * packet tag that holds it.
487                  */
488                 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
489                         struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
490                                                          MTAG_VLAN_TAG,
491                                                          sizeof(u_int),
492                                                          M_NOWAIT);
493                         if (mtag == NULL) {
494                                 ifp->if_oerrors++;
495                                 m_freem(m);
496                                 continue;
497                         }
498                         *(u_int*)(mtag + 1) = ifv->ifv_tag;
499                         m_tag_prepend(m, mtag);
500                 } else {
501                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
502                         if (m == NULL) {
503                                 if_printf(ifp,
504                                     "unable to prepend VLAN header\n");
505                                 ifp->if_oerrors++;
506                                 continue;
507                         }
508                         /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
509
510                         if (m->m_len < sizeof(*evl)) {
511                                 m = m_pullup(m, sizeof(*evl));
512                                 if (m == NULL) {
513                                         if_printf(ifp,
514                                             "cannot pullup VLAN header\n");
515                                         ifp->if_oerrors++;
516                                         continue;
517                                 }
518                         }
519
520                         /*
521                          * Transform the Ethernet header into an Ethernet header
522                          * with 802.1Q encapsulation.
523                          */
524                         bcopy(mtod(m, char *) + ifv->ifv_encaplen,
525                               mtod(m, char *), ETHER_HDR_LEN);
526                         evl = mtod(m, struct ether_vlan_header *);
527                         evl->evl_proto = evl->evl_encap_proto;
528                         evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
529                         evl->evl_tag = htons(ifv->ifv_tag);
530 #ifdef DEBUG
531                         printf("vlan_start: %*D\n", (int)sizeof(*evl),
532                             (unsigned char *)evl, ":");
533 #endif
534                 }
535
536                 /*
537                  * Send it, precisely as ether_output() would have.
538                  * We are already running at splimp.
539                  */
540                 IFQ_HANDOFF(p, m, error);
541                 if (!error)
542                         ifp->if_opackets++;
543                 else
544                         ifp->if_oerrors++;
545         }
546         ifp->if_flags &= ~IFF_OACTIVE;
547 }
548
549 static void
550 vlan_input(struct ifnet *ifp, struct mbuf *m)
551 {
552         struct ether_vlan_header *evl;
553         struct ifvlan *ifv;
554         struct m_tag *mtag;
555         u_int tag;
556
557         mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
558         if (mtag != NULL) {
559                 /*
560                  * Packet is tagged, m contains a normal
561                  * Ethernet frame; the tag is stored out-of-band.
562                  */
563                 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
564                 m_tag_delete(m, mtag);
565                 m->m_flags &= ~M_VLANTAG;
566         } else {
567                 switch (ifp->if_type) {
568                 case IFT_ETHER:
569                         if (m->m_len < sizeof(*evl) &&
570                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
571                                 if_printf(ifp, "cannot pullup VLAN header\n");
572                                 return;
573                         }
574                         evl = mtod(m, struct ether_vlan_header *);
575                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
576                                 ("vlan_input: bad encapsulated protocols (%u)",
577                                  ntohs(evl->evl_encap_proto)));
578
579                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
580
581                         /*
582                          * Restore the original ethertype.  We'll remove
583                          * the encapsulation after we've found the vlan
584                          * interface corresponding to the tag.
585                          */
586                         evl->evl_encap_proto = evl->evl_proto;
587                         break;
588                 default:
589                         tag = (u_int) -1;
590 #ifdef DIAGNOSTIC
591                         panic("vlan_input: unsupported if type %u",
592                             ifp->if_type);
593 #endif
594                         break;
595                 }
596         }
597
598         VLAN_LOCK();
599         LIST_FOREACH(ifv, &ifv_list, ifv_list)
600                 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
601                         break;
602
603         if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
604                 VLAN_UNLOCK();
605                 m_freem(m);
606                 ifp->if_noproto++;
607 #ifdef DEBUG
608                 printf("vlan_input: tag %d, no interface\n", tag);
609 #endif
610                 return;
611         }
612         VLAN_UNLOCK();          /* XXX extend below? */
613 #ifdef DEBUG
614         printf("vlan_input: tag %d, parent %s\n", tag, ifv->ifv_p->if_xname);
615 #endif
616
617         if (mtag == NULL) {
618                 /*
619                  * Packet had an in-line encapsulation header;
620                  * remove it.  The original header has already
621                  * been fixed up above.
622                  */
623                 bcopy(mtod(m, caddr_t),
624                       mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
625                       ETHER_HDR_LEN);
626                 m_adj(m, ETHER_VLAN_ENCAP_LEN);
627         }
628
629         m->m_pkthdr.rcvif = &ifv->ifv_if;
630         ifv->ifv_if.if_ipackets++;
631
632         /* Pass it back through the parent's input routine. */
633         (*ifp->if_input)(&ifv->ifv_if, m);
634 }
635
636 static int
637 vlan_config(struct ifvlan *ifv, struct ifnet *p)
638 {
639         struct ifaddr *ifa1, *ifa2;
640         struct sockaddr_dl *sdl1, *sdl2;
641
642         VLAN_LOCK_ASSERT();
643
644         if (p->if_data.ifi_type != IFT_ETHER)
645                 return (EPROTONOSUPPORT);
646         if (ifv->ifv_p)
647                 return (EBUSY);
648
649         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
650         ifv->ifv_mintu = ETHERMIN;
651         ifv->ifv_flags = 0;
652
653         /*
654          * The active VLAN counter on the parent is used
655          * at various places to see if there is a vlan(4)
656          * attached to this physical interface.
657          */
658         p->if_nvlans++;
659
660         /*
661          * If the parent supports the VLAN_MTU capability,
662          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
663          * use it.
664          */
665         if (p->if_capenable & IFCAP_VLAN_MTU) {
666                 /*
667                  * No need to fudge the MTU since the parent can
668                  * handle extended frames.
669                  */
670                 ifv->ifv_mtufudge = 0;
671         } else {
672                 /*
673                  * Fudge the MTU by the encapsulation size.  This
674                  * makes us incompatible with strictly compliant
675                  * 802.1Q implementations, but allows us to use
676                  * the feature with other NetBSD implementations,
677                  * which might still be useful.
678                  */
679                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
680         }
681
682         ifv->ifv_p = p;
683         ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
684         /*
685          * Copy only a selected subset of flags from the parent.
686          * Other flags are none of our business.
687          */
688         ifv->ifv_if.if_flags = (p->if_flags &
689             (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT));
690         ifv->ifv_if.if_link_state = p->if_link_state;
691
692 #if 0
693         /*
694          * Not ready yet.  We need notification from the parent
695          * when hw checksumming flags in its if_capenable change.
696          * Flags set in if_capabilities only are useless.
697          */
698         /*
699          * If the parent interface can do hardware-assisted
700          * VLAN encapsulation, then propagate its hardware-
701          * assisted checksumming flags.
702          */
703         if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
704                 ifv->ifv_if.if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
705 #endif
706
707         /*
708          * Set up our ``Ethernet address'' to reflect the underlying
709          * physical interface's.
710          */
711         ifa1 = ifaddr_byindex(ifv->ifv_if.if_index);
712         ifa2 = ifaddr_byindex(p->if_index);
713         sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
714         sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
715         sdl1->sdl_type = IFT_ETHER;
716         sdl1->sdl_alen = ETHER_ADDR_LEN;
717         bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
718         bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
719
720         /*
721          * Configure multicast addresses that may already be
722          * joined on the vlan device.
723          */
724         (void)vlan_setmulti(&ifv->ifv_if); /* XXX: VLAN lock held */
725
726         return (0);
727 }
728
729 static int
730 vlan_unconfig(struct ifnet *ifp)
731 {
732         struct ifaddr *ifa;
733         struct sockaddr_dl *sdl;
734         struct vlan_mc_entry *mc;
735         struct ifvlan *ifv;
736         struct ifnet *p;
737         int error;
738
739         VLAN_LOCK_ASSERT();
740
741         ifv = ifp->if_softc;
742         p = ifv->ifv_p;
743
744         if (p) {
745                 struct sockaddr_dl sdl;
746
747                 /*
748                  * Since the interface is being unconfigured, we need to
749                  * empty the list of multicast groups that we may have joined
750                  * while we were alive from the parent's list.
751                  */
752                 bzero((char *)&sdl, sizeof(sdl));
753                 sdl.sdl_len = sizeof(sdl);
754                 sdl.sdl_family = AF_LINK;
755                 sdl.sdl_index = p->if_index;
756                 sdl.sdl_type = IFT_ETHER;
757                 sdl.sdl_alen = ETHER_ADDR_LEN;
758
759                 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
760                         mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
761                         bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
762                             ETHER_ADDR_LEN);
763                         error = if_delmulti(p, (struct sockaddr *)&sdl);
764                         if (error)
765                                 return (error);
766                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
767                         free(mc, M_VLAN);
768                 }
769
770                 p->if_nvlans--;
771         }
772
773         /* Disconnect from parent. */
774         ifv->ifv_p = NULL;
775         ifv->ifv_if.if_mtu = ETHERMTU;          /* XXX why not 0? */
776         ifv->ifv_flags = 0;
777         ifv->ifv_if.if_link_state = LINK_STATE_UNKNOWN;
778
779         /* Clear our MAC address. */
780         ifa = ifaddr_byindex(ifv->ifv_if.if_index);
781         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
782         sdl->sdl_type = IFT_ETHER;
783         sdl->sdl_alen = ETHER_ADDR_LEN;
784         bzero(LLADDR(sdl), ETHER_ADDR_LEN);
785         bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
786
787         return (0);
788 }
789
790 static int
791 vlan_set_promisc(struct ifnet *ifp)
792 {
793         struct ifvlan *ifv = ifp->if_softc;
794         int error = 0;
795
796         if ((ifp->if_flags & IFF_PROMISC) != 0) {
797                 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
798                         error = ifpromisc(ifv->ifv_p, 1);
799                         if (error == 0)
800                                 ifv->ifv_flags |= IFVF_PROMISC;
801                 }
802         } else {
803                 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
804                         error = ifpromisc(ifv->ifv_p, 0);
805                         if (error == 0)
806                                 ifv->ifv_flags &= ~IFVF_PROMISC;
807                 }
808         }
809
810         return (error);
811 }
812
813 /* Inform all vlans that their parent has changed link state */
814 static void
815 vlan_link_state(struct ifnet *ifp, int link)
816 {
817         struct ifvlan *ifv;
818
819         VLAN_LOCK();
820         LIST_FOREACH(ifv, &ifv_list, ifv_list) {
821                 if (ifv->ifv_p == ifp)
822                         if_link_state_change(&ifv->ifv_if,
823                             ifv->ifv_p->if_link_state);
824         }
825         VLAN_UNLOCK();
826 }
827
828 static int
829 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
830 {
831         struct ifaddr *ifa;
832         struct ifnet *p;
833         struct ifreq *ifr;
834         struct ifvlan *ifv;
835         struct vlanreq vlr;
836         int error = 0;
837
838         ifr = (struct ifreq *)data;
839         ifa = (struct ifaddr *)data;
840         ifv = ifp->if_softc;
841
842         switch (cmd) {
843         case SIOCSIFADDR:
844                 ifp->if_flags |= IFF_UP;
845
846                 switch (ifa->ifa_addr->sa_family) {
847 #ifdef INET
848                 case AF_INET:
849                         arp_ifinit(&ifv->ifv_if, ifa);
850                         break;
851 #endif
852                 default:
853                         break;
854                 }
855                 break;
856
857         case SIOCGIFADDR:
858                 {
859                         struct sockaddr *sa;
860
861                         sa = (struct sockaddr *) &ifr->ifr_data;
862                         bcopy(IFP2AC(ifp)->ac_enaddr, (caddr_t)sa->sa_data,
863                             ETHER_ADDR_LEN);
864                 }
865                 break;
866
867         case SIOCGIFMEDIA:
868                 VLAN_LOCK();
869                 if (ifv->ifv_p != NULL) {
870                         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
871                                         SIOCGIFMEDIA, data);
872                         VLAN_UNLOCK();
873                         /* Limit the result to the parent's current config. */
874                         if (error == 0) {
875                                 struct ifmediareq *ifmr;
876
877                                 ifmr = (struct ifmediareq *)data;
878                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
879                                         ifmr->ifm_count = 1;
880                                         error = copyout(&ifmr->ifm_current,
881                                                 ifmr->ifm_ulist,
882                                                 sizeof(int));
883                                 }
884                         }
885                 } else {
886                         VLAN_UNLOCK();
887                         error = EINVAL;
888                 }
889                 break;
890
891         case SIOCSIFMEDIA:
892                 error = EINVAL;
893                 break;
894
895         case SIOCSIFMTU:
896                 /*
897                  * Set the interface MTU.
898                  */
899                 VLAN_LOCK();
900                 if (ifv->ifv_p != NULL) {
901                         if (ifr->ifr_mtu >
902                              (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
903                             ifr->ifr_mtu <
904                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
905                                 error = EINVAL;
906                         else
907                                 ifp->if_mtu = ifr->ifr_mtu;
908                 } else
909                         error = EINVAL;
910                 VLAN_UNLOCK();
911                 break;
912
913         case SIOCSETVLAN:
914                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
915                 if (error)
916                         break;
917                 if (vlr.vlr_parent[0] == '\0') {
918                         VLAN_LOCK();
919                         vlan_unconfig(ifp);
920                         if (ifp->if_flags & IFF_UP)
921                                 if_down(ifp);
922                         ifp->if_flags &= ~IFF_RUNNING;
923                         VLAN_UNLOCK();
924                         break;
925                 }
926                 p = ifunit(vlr.vlr_parent);
927                 if (p == 0) {
928                         error = ENOENT;
929                         break;
930                 }
931                 /*
932                  * Don't let the caller set up a VLAN tag with
933                  * anything except VLID bits.
934                  */
935                 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
936                         error = EINVAL;
937                         break;
938                 }
939                 VLAN_LOCK();
940                 error = vlan_config(ifv, p);
941                 if (error) {
942                         VLAN_UNLOCK();
943                         break;
944                 }
945                 ifv->ifv_tag = vlr.vlr_tag;
946                 ifp->if_flags |= IFF_RUNNING;
947                 VLAN_UNLOCK();
948
949                 /* Update promiscuous mode, if necessary. */
950                 vlan_set_promisc(ifp);
951                 break;
952
953         case SIOCGETVLAN:
954                 bzero(&vlr, sizeof(vlr));
955                 VLAN_LOCK();
956                 if (ifv->ifv_p) {
957                         strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
958                             sizeof(vlr.vlr_parent));
959                         vlr.vlr_tag = ifv->ifv_tag;
960                 }
961                 VLAN_UNLOCK();
962                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
963                 break;
964                 
965         case SIOCSIFFLAGS:
966                 /*
967                  * For promiscuous mode, we enable promiscuous mode on
968                  * the parent if we need promiscuous on the VLAN interface.
969                  */
970                 if (ifv->ifv_p != NULL)
971                         error = vlan_set_promisc(ifp);
972                 break;
973
974         case SIOCADDMULTI:
975         case SIOCDELMULTI:
976                 /*VLAN_LOCK();*/
977                 error = vlan_setmulti(ifp);
978                 /*VLAN_UNLOCK();*/
979                 break;
980         default:
981                 error = EINVAL;
982         }
983
984         return (error);
985 }