Merge from vendor branch OPENSSH:
[dragonfly.git] / sys / net / vlan / 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: src/sys/net/if_vlan.c,v 1.15.2.13 2003/02/14 22:25:58 fenner Exp $
30  * $DragonFly: src/sys/net/vlan/if_vlan.c,v 1.31 2008/03/18 14:12:45 sephe Exp $
31  */
32
33 /*
34  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
35  * Might be extended some day to also handle IEEE 802.1p priority
36  * tagging.  This is sort of sneaky in the implementation, since
37  * we need to pretend to be enough of an Ethernet implementation
38  * to make arp work.  The way we do this is by telling everyone
39  * that we are an Ethernet, and then catch the packets that
40  * ether_output() left on our output queue queue when it calls
41  * if_start(), rewrite them for use by the real outgoing interface,
42  * and ask it to send them.
43  *
44  *
45  * XXX It's incorrect to assume that we must always kludge up
46  * headers on the physical device's behalf: some devices support
47  * VLAN tag insertion and extraction in firmware. For these cases,
48  * one can change the behavior of the vlan interface by setting
49  * the LINK0 flag on it (that is setting the vlan interface's LINK0
50  * flag, _not_ the parent's LINK0 flag; we try to leave the parent
51  * alone). If the interface has the LINK0 flag set, then it will
52  * not modify the ethernet header on output, because the parent
53  * can do that for itself. On input, the parent can call vlan_input_tag()
54  * directly in order to supply us with an incoming mbuf and the vlan
55  * tag value that goes with it.
56  */
57
58 #ifndef NVLAN
59 #include "use_vlan.h"
60 #endif
61 #include "opt_inet.h"
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 #include <sys/mbuf.h>
68 #include <sys/module.h>
69 #include <sys/queue.h>
70 #include <sys/socket.h>
71 #include <sys/sockio.h>
72 #include <sys/sysctl.h>
73 #include <sys/bus.h>
74 #include <sys/thread2.h>
75
76 #include <net/bpf.h>
77 #include <net/ethernet.h>
78 #include <net/if.h>
79 #include <net/if_arp.h>
80 #include <net/if_dl.h>
81 #include <net/if_types.h>
82 #include <net/ifq_var.h>
83 #include <net/if_clone.h>
84 #include <net/netmsg2.h>
85
86 #ifdef INET
87 #include <netinet/in.h>
88 #include <netinet/if_ether.h>
89 #endif
90
91 #include <net/vlan/if_vlan_var.h>
92 #include <net/vlan/if_vlan_ether.h>
93
94 struct ifvlan;
95
96 struct vlan_mc_entry {
97         struct ether_addr               mc_addr;
98         SLIST_ENTRY(vlan_mc_entry)      mc_entries;
99 };
100
101 struct vlan_entry {
102         struct ifvlan           *ifv;
103         LIST_ENTRY(vlan_entry)  ifv_link;
104 };
105
106 struct  ifvlan {
107         struct  arpcom ifv_ac;  /* make this an interface */
108         struct  ifnet *ifv_p;   /* parent inteface of this vlan */
109         struct  ifv_linkmib {
110                 int     ifvm_parent;
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_mc_entry) vlan_mc_listhead;
115         LIST_ENTRY(ifvlan) ifv_list;
116         struct vlan_entry ifv_entries[1];
117 };
118 #define ifv_if  ifv_ac.ac_if
119 #define ifv_tag ifv_mib.ifvm_tag
120
121 struct vlan_trunk {
122         LIST_HEAD(, vlan_entry) vlan_list;
123 };
124
125 struct netmsg_vlan {
126         struct netmsg   nv_nmsg;
127         struct ifvlan   *nv_ifv;
128         struct ifnet    *nv_ifp_p;
129         const char      *nv_parent_name;
130         uint16_t        nv_vlantag;
131 };
132
133 #define VLANNAME        "vlan"
134
135 SYSCTL_DECL(_net_link);
136 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
137 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
138
139 static MALLOC_DEFINE(M_VLAN, "vlan", "802.1Q Virtual LAN Interface");
140 static LIST_HEAD(, ifvlan) ifv_list;
141
142 static int      vlan_clone_create(struct if_clone *, int);
143 static void     vlan_clone_destroy(struct ifnet *);
144 static void     vlan_ifdetach(void *, struct ifnet *);
145
146 static void     vlan_init(void *);
147 static void     vlan_start(struct ifnet *);
148 static int      vlan_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
149
150 static int      vlan_input(const struct ether_header *eh, struct mbuf *m);
151 static int      vlan_input_tag(struct mbuf *m, uint16_t t);
152
153 static void     vlan_clrmulti(struct ifvlan *, struct ifnet *);
154 static int      vlan_setmulti(struct ifvlan *, struct ifnet *);
155 static int      vlan_config_multi(struct ifvlan *);
156 static int      vlan_config(struct ifvlan *, const char *, uint16_t);
157 static int      vlan_unconfig(struct ifvlan *);
158 static void     vlan_link(struct ifvlan *, struct ifnet *);
159 static void     vlan_unlink(struct ifvlan *, struct ifnet *);
160
161 static void     vlan_config_dispatch(struct netmsg *);
162 static void     vlan_unconfig_dispatch(struct netmsg *);
163 static void     vlan_link_dispatch(struct netmsg *);
164 static void     vlan_unlink_dispatch(struct netmsg *);
165 static void     vlan_multi_dispatch(struct netmsg *);
166 static void     vlan_ifdetach_dispatch(struct netmsg *);
167
168 static eventhandler_tag vlan_ifdetach_cookie;
169 static struct if_clone vlan_cloner =
170         IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy,
171                              NVLAN, IF_MAXUNIT);
172
173 static __inline void
174 vlan_forwardmsg(struct lwkt_msg *lmsg, int next_cpu)
175 {
176         if (next_cpu < ncpus)
177                 lwkt_forwardmsg(ifa_portfn(next_cpu), lmsg);
178         else
179                 lwkt_replymsg(lmsg, 0);
180 }
181
182 /*
183  * Program our multicast filter. What we're actually doing is
184  * programming the multicast filter of the parent. This has the
185  * side effect of causing the parent interface to receive multicast
186  * traffic that it doesn't really want, which ends up being discarded
187  * later by the upper protocol layers. Unfortunately, there's no way
188  * to avoid this: there really is only one physical interface.
189  */
190 static int
191 vlan_setmulti(struct ifvlan *ifv, struct ifnet *ifp_p)
192 {
193         struct ifmultiaddr *ifma, *rifma = NULL;
194         struct vlan_mc_entry *mc = NULL;
195         struct sockaddr_dl sdl;
196         struct ifnet *ifp = &ifv->ifv_if;
197
198         ASSERT_NOT_SERIALIZED(ifp->if_serializer);
199
200         /*
201          * First, remove any existing filter entries.
202          */
203         vlan_clrmulti(ifv, ifp_p);
204
205         /*
206          * Now program new ones.
207          */
208         bzero(&sdl, sizeof(sdl));
209         sdl.sdl_len = sizeof(sdl);
210         sdl.sdl_family = AF_LINK;
211         sdl.sdl_index = ifp_p->if_index;
212         sdl.sdl_type = IFT_ETHER;
213         sdl.sdl_alen = ETHER_ADDR_LEN;
214
215         LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
216                 int error;
217
218                 if (ifma->ifma_addr->sa_family != AF_LINK)
219                         continue;
220
221                 /* Save a copy */
222                 mc = kmalloc(sizeof(struct vlan_mc_entry), M_VLAN, M_WAITOK);
223                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
224                       &mc->mc_addr, ETHER_ADDR_LEN);
225                 SLIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
226
227                 /* Program the parent multicast filter */
228                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
229                       LLADDR(&sdl), ETHER_ADDR_LEN);
230                 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
231                 if (error)
232                         return error;
233         }
234         return 0;
235 }
236
237 static void
238 vlan_clrmulti(struct ifvlan *ifv, struct ifnet *ifp_p)
239 {
240         struct vlan_mc_entry *mc;
241         struct sockaddr_dl sdl;
242
243         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
244
245         bzero(&sdl, sizeof(sdl));
246         sdl.sdl_len = sizeof(sdl);
247         sdl.sdl_family = AF_LINK;
248         sdl.sdl_index = ifp_p->if_index;
249         sdl.sdl_type = IFT_ETHER;
250         sdl.sdl_alen = ETHER_ADDR_LEN;
251
252         while ((mc = SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
253                 bcopy(&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
254                 if_delmulti(ifp_p, (struct sockaddr *)&sdl); /* ignore error */
255
256                 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
257                 kfree(mc, M_VLAN);
258         }
259 }
260
261 static int
262 vlan_modevent(module_t mod, int type, void *data)
263 {
264         switch (type) {
265         case MOD_LOAD:
266                 LIST_INIT(&ifv_list);
267                 vlan_input_p = vlan_input;
268                 vlan_input_tag_p = vlan_input_tag;
269                 vlan_ifdetach_cookie =
270                 EVENTHANDLER_REGISTER(ifnet_detach_event,
271                                       vlan_ifdetach, NULL,
272                                       EVENTHANDLER_PRI_ANY);
273                 if_clone_attach(&vlan_cloner);
274                 break;
275
276         case MOD_UNLOAD:
277                 if_clone_detach(&vlan_cloner);
278                 vlan_input_p = NULL;
279                 vlan_input_tag_p = NULL;
280                 EVENTHANDLER_DEREGISTER(ifnet_detach_event,
281                                         vlan_ifdetach_cookie);
282                 while (!LIST_EMPTY(&ifv_list))
283                         vlan_clone_destroy(&LIST_FIRST(&ifv_list)->ifv_if);
284                 break;
285         }
286         return 0;
287 }
288
289 static moduledata_t vlan_mod = {
290         "if_vlan",
291         vlan_modevent,
292         0
293 };
294
295 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
296
297 static void
298 vlan_ifdetach_dispatch(struct netmsg *nmsg)
299 {
300         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
301         struct ifnet *ifp_p = vmsg->nv_ifp_p;
302         struct vlan_trunk *vlantrunks, *trunk;
303         struct vlan_entry *ifve;
304
305         vlantrunks = ifp_p->if_vlantrunks;
306         if (vlantrunks == NULL)
307                 goto reply;
308         trunk = &vlantrunks[mycpuid];
309
310         while (ifp_p->if_vlantrunks &&
311                (ifve = LIST_FIRST(&trunk->vlan_list)) != NULL)
312                 vlan_unconfig(ifve->ifv);
313 reply:
314         lwkt_replymsg(&nmsg->nm_lmsg, 0);
315 }
316
317 static void
318 vlan_ifdetach(void *arg __unused, struct ifnet *ifp)
319 {
320         struct netmsg_vlan vmsg;
321         struct netmsg *nmsg;
322
323         ASSERT_NOT_SERIALIZED(ifp->if_serializer);
324
325         bzero(&vmsg, sizeof(vmsg));
326         nmsg = &vmsg.nv_nmsg;
327
328         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_ifdetach_dispatch);
329         vmsg.nv_ifp_p = ifp;
330
331         lwkt_domsg(cpu_portfn(0), &nmsg->nm_lmsg, 0);
332 }
333
334 static int
335 vlan_clone_create(struct if_clone *ifc, int unit)
336 {
337         struct ifvlan *ifv;
338         struct ifnet *ifp;
339         int vlan_size, i;
340
341         vlan_size = sizeof(struct ifvlan)
342                   + ((ncpus - 1) * sizeof(struct vlan_entry));
343         ifv = kmalloc(vlan_size, M_VLAN, M_WAITOK | M_ZERO);
344         SLIST_INIT(&ifv->vlan_mc_listhead);
345         for (i = 0; i < ncpus; ++i)
346                 ifv->ifv_entries[i].ifv = ifv;
347
348         crit_enter();   /* XXX not MP safe */
349         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
350         crit_exit();
351
352         ifp = &ifv->ifv_if;
353         ifp->if_softc = ifv;
354         if_initname(ifp, "vlan", unit);
355         /* NB: flags are not set here */
356         ifp->if_linkmib = &ifv->ifv_mib;
357         ifp->if_linkmiblen = sizeof ifv->ifv_mib;
358         /* NB: mtu is not set here */
359
360         ifp->if_init = vlan_init;
361         ifp->if_start = vlan_start;
362         ifp->if_ioctl = vlan_ioctl;
363         ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
364         ifq_set_ready(&ifp->if_snd);
365         ether_ifattach(ifp, ifv->ifv_ac.ac_enaddr, NULL);
366         /* Now undo some of the damage... */
367         ifp->if_data.ifi_type = IFT_L2VLAN;
368         ifp->if_data.ifi_hdrlen = EVL_ENCAPLEN;
369
370         return (0);
371 }
372
373 static void
374 vlan_clone_destroy(struct ifnet *ifp)
375 {
376         struct ifvlan *ifv = ifp->if_softc;
377
378         crit_enter();   /* XXX not MP safe */
379         LIST_REMOVE(ifv, ifv_list);
380         crit_exit();
381
382         vlan_unconfig(ifv);
383         ether_ifdetach(ifp);
384
385         kfree(ifv, M_VLAN);
386 }
387
388 static void
389 vlan_init(void *xsc)
390 {
391         struct ifvlan *ifv = xsc;
392         struct ifnet *ifp = &ifv->ifv_if;
393
394         ASSERT_SERIALIZED(ifp->if_serializer);
395
396         if (ifv->ifv_p != NULL)
397                 ifp->if_flags |= IFF_RUNNING;
398 }
399
400 static void
401 vlan_start(struct ifnet *ifp)
402 {
403         struct ifvlan *ifv = ifp->if_softc;
404         struct ifnet *ifp_p = ifv->ifv_p;
405         struct mbuf *m;
406
407         ASSERT_SERIALIZED(ifp->if_serializer);
408
409         if ((ifp->if_flags & IFF_RUNNING) == 0 || ifp_p == NULL)
410                 return;
411
412         ifp->if_flags |= IFF_OACTIVE;
413         for (;;) {
414                 struct netmsg_packet *nmp;
415                 struct netmsg *nmsg;
416                 struct lwkt_port *port;
417
418                 m = ifq_dequeue(&ifp->if_snd, NULL);
419                 if (m == NULL)
420                         break;
421                 BPF_MTAP(ifp, m);
422
423                 /*
424                  * Do not run parent's if_start() if the parent is not up,
425                  * or parent's driver will cause a system crash.
426                  */
427                 if ((ifp_p->if_flags & (IFF_UP | IFF_RUNNING)) !=
428                     (IFF_UP | IFF_RUNNING)) {
429                         m_freem(m);
430                         ifp->if_data.ifi_collisions++;
431                         continue;
432                 }
433
434                 /*
435                  * We need some way to tell the interface where the packet
436                  * came from so that it knows how to find the VLAN tag to
437                  * use, so we set the ether_vlantag in the mbuf packet header
438                  * to our vlan tag.  We also set the M_VLANTAG flag in the
439                  * mbuf to let the parent driver know that the ether_vlantag
440                  * is really valid.
441                  */
442                 m->m_pkthdr.ether_vlantag = ifv->ifv_tag;
443                 m->m_flags |= M_VLANTAG;
444
445                 nmp = &m->m_hdr.mh_netmsg;
446                 nmsg = &nmp->nm_netmsg;
447
448                 netmsg_init(nmsg, &netisr_apanic_rport, 0, vlan_start_dispatch);
449                 nmp->nm_packet = m;
450                 nmsg->nm_lmsg.u.ms_resultp = ifp_p;
451
452                 port = cpu_portfn(ifp_p->if_index % ncpus /* XXX */);
453                 lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
454                 ifp->if_opackets++;
455         }
456         ifp->if_flags &= ~IFF_OACTIVE;
457 }
458
459 static int
460 vlan_input_tag(struct mbuf *m, uint16_t t)
461 {
462         struct bpf_if *bif;
463         struct ifvlan *ifv;
464         struct ifnet *rcvif;
465
466         rcvif = m->m_pkthdr.rcvif;
467
468         ASSERT_SERIALIZED(rcvif->if_serializer);
469
470         /*
471          * Fake up a header and send the packet to the physical interface's
472          * bpf tap if active.
473          */
474         if ((bif = rcvif->if_bpf) != NULL)
475                 vlan_ether_ptap(bif, m, t);
476
477         for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
478             ifv = LIST_NEXT(ifv, ifv_list)) {
479                 if (rcvif == ifv->ifv_p && ifv->ifv_tag == t)
480                         break;
481         }
482
483         if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
484                 m_freem(m);
485                 return -1;      /* So the parent can take note */
486         }
487
488         /*
489          * Having found a valid vlan interface corresponding to
490          * the given source interface and vlan tag, run the
491          * the real packet through ether_input().
492          */
493         m->m_pkthdr.rcvif = &ifv->ifv_if;
494
495         ifv->ifv_if.if_ipackets++;
496         lwkt_serialize_exit(rcvif->if_serializer);
497         lwkt_serialize_enter(ifv->ifv_if.if_serializer);
498         ether_input(&ifv->ifv_if, m);
499         lwkt_serialize_exit(ifv->ifv_if.if_serializer);
500         lwkt_serialize_enter(rcvif->if_serializer);
501         return 0;
502 }
503
504 static int
505 vlan_input(const struct ether_header *eh, struct mbuf *m)
506 {
507         struct ifvlan *ifv;
508         struct ifnet *rcvif;
509         struct ether_header eh_copy;
510
511         rcvif = m->m_pkthdr.rcvif;
512         ASSERT_SERIALIZED(rcvif->if_serializer);
513
514         for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
515             ifv = LIST_NEXT(ifv, ifv_list)) {
516                 if (rcvif == ifv->ifv_p
517                     && (EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)))
518                         == ifv->ifv_tag))
519                         break;
520         }
521
522         if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
523                 rcvif->if_noproto++;
524                 m_freem(m);
525                 return -1;      /* so ether_input can take note */
526         }
527
528         /*
529          * Having found a valid vlan interface corresponding to
530          * the given source interface and vlan tag, remove the
531          * remaining encapsulation (ether_vlan_header minus the ether_header
532          * that had already been removed) and run the real packet
533          * through ether_input() a second time (it had better be
534          * reentrant!).
535          */
536         eh_copy = *eh;
537         eh_copy.ether_type = mtod(m, u_int16_t *)[1];   /* evl_proto */
538         m->m_pkthdr.rcvif = &ifv->ifv_if;
539         m_adj(m, EVL_ENCAPLEN);
540         M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT); 
541         *(struct ether_header *)mtod(m, void *) = eh_copy;
542
543         ifv->ifv_if.if_ipackets++;
544         lwkt_serialize_exit(rcvif->if_serializer);
545         lwkt_serialize_enter(ifv->ifv_if.if_serializer);
546         ether_input(&ifv->ifv_if, m);
547         lwkt_serialize_exit(ifv->ifv_if.if_serializer);
548         lwkt_serialize_enter(rcvif->if_serializer);
549         return 0;
550 }
551
552 static void
553 vlan_link_dispatch(struct netmsg *nmsg)
554 {
555         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
556         struct ifvlan *ifv = vmsg->nv_ifv;
557         struct ifnet *ifp_p = vmsg->nv_ifp_p;
558         struct vlan_entry *entry;
559         struct vlan_trunk *vlantrunks, *trunk;
560         int cpu = mycpuid;
561
562         vlantrunks = ifp_p->if_vlantrunks;
563         KASSERT(vlantrunks != NULL,
564                 ("vlan trunk has not been initialized yet\n"));
565
566         entry = &ifv->ifv_entries[cpu];
567         trunk = &vlantrunks[cpu];
568
569         crit_enter();
570         LIST_INSERT_HEAD(&trunk->vlan_list, entry, ifv_link);
571         crit_exit();
572
573         vlan_forwardmsg(&nmsg->nm_lmsg, cpu + 1);
574 }
575
576 static void
577 vlan_link(struct ifvlan *ifv, struct ifnet *ifp_p)
578 {
579         struct netmsg_vlan vmsg;
580         struct netmsg *nmsg;
581
582         /* Assert in netisr0 */
583         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
584
585         if (ifp_p->if_vlantrunks == NULL) {
586                 struct vlan_trunk *vlantrunks;
587                 int i;
588
589                 vlantrunks = kmalloc(sizeof(*vlantrunks) * ncpus, M_VLAN,
590                                      M_WAITOK | M_ZERO);
591                 for (i = 0; i < ncpus; ++i)
592                         LIST_INIT(&vlantrunks[i].vlan_list);
593
594                 ifp_p->if_vlantrunks = vlantrunks;
595         }
596
597         bzero(&vmsg, sizeof(vmsg));
598         nmsg = &vmsg.nv_nmsg;
599
600         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_link_dispatch);
601         vmsg.nv_ifv = ifv;
602         vmsg.nv_ifp_p = ifp_p;
603
604         lwkt_domsg(ifa_portfn(0), &nmsg->nm_lmsg, 0);
605 }
606
607 static void
608 vlan_config_dispatch(struct netmsg *nmsg)
609 {
610         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
611         struct ifvlan *ifv;
612         struct ifnet *ifp_p, *ifp;
613         struct sockaddr_dl *sdl1, *sdl2;
614         int error;
615
616         /* Assert in netisr0 */
617
618         ifp_p = ifunit(vmsg->nv_parent_name);
619         if (ifp_p == NULL) {
620                 error = ENOENT;
621                 goto reply;
622         }
623
624         if (ifp_p->if_data.ifi_type != IFT_ETHER) {
625                 error = EPROTONOSUPPORT;
626                 goto reply;
627         }
628
629         ifv = vmsg->nv_ifv;
630         ifp = &ifv->ifv_if;
631
632         if (ifv->ifv_p) {
633                 error = EBUSY;
634                 goto reply;
635         }
636
637         /* Link vlan into parent's vlantrunk */
638         vlan_link(ifv, ifp_p);
639
640         lwkt_serialize_enter(ifp->if_serializer);
641
642         ifv->ifv_tag = vmsg->nv_vlantag;
643         if (ifp_p->if_capenable & IFCAP_VLAN_MTU)
644                 ifp->if_mtu = ifp_p->if_mtu;
645         else
646                 ifp->if_mtu = ifp_p->if_data.ifi_mtu - EVL_ENCAPLEN;
647
648         /*
649          * Copy only a selected subset of flags from the parent.
650          * Other flags are none of our business.
651          */
652         ifp->if_flags = (ifp_p->if_flags &
653             (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT));
654
655         /*
656          * Set up our ``Ethernet address'' to reflect the underlying
657          * physical interface's.
658          */
659         sdl1 = IF_LLSOCKADDR(ifp);
660         sdl2 = IF_LLSOCKADDR(ifp_p);
661         sdl1->sdl_type = IFT_ETHER;
662         sdl1->sdl_alen = ETHER_ADDR_LEN;
663         bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
664         bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
665
666         /*
667          * Release vlan's serializer before reprogramming parent's
668          * multicast filter to avoid possible dead lock.
669          */
670         lwkt_serialize_exit(ifp->if_serializer);
671
672         /*
673          * Configure multicast addresses that may already be
674          * joined on the vlan device.
675          */
676         vlan_setmulti(ifv, ifp_p);
677
678         /*
679          * Connect to parent after everything have been set up,
680          * so input/output could know that vlan is ready to go
681          */
682         ifv->ifv_p = ifp_p;
683         error = 0;
684 reply:
685         lwkt_replymsg(&nmsg->nm_lmsg, error);
686 }
687
688 static int
689 vlan_config(struct ifvlan *ifv, const char *parent_name, uint16_t vlantag)
690 {
691         struct netmsg_vlan vmsg;
692         struct netmsg *nmsg;
693
694         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
695
696         bzero(&vmsg, sizeof(vmsg));
697         nmsg = &vmsg.nv_nmsg;
698
699         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_config_dispatch);
700         vmsg.nv_ifv = ifv;
701         vmsg.nv_parent_name = parent_name;
702         vmsg.nv_vlantag = vlantag;
703
704         return lwkt_domsg(cpu_portfn(0), &nmsg->nm_lmsg, 0);
705 }
706
707 static void
708 vlan_unlink_dispatch(struct netmsg *nmsg)
709 {
710         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
711         struct ifvlan *ifv = vmsg->nv_ifv;
712         struct vlan_entry *entry;
713         int cpu = mycpuid;
714
715         KASSERT(vmsg->nv_ifp_p->if_vlantrunks != NULL,
716                 ("vlan trunk has not been initialized yet\n"));
717         entry = &ifv->ifv_entries[cpu];
718
719         crit_enter();
720         LIST_REMOVE(entry, ifv_link);
721         crit_exit();
722
723         vlan_forwardmsg(&nmsg->nm_lmsg, cpu + 1);
724 }
725
726 static void
727 vlan_unlink(struct ifvlan *ifv, struct ifnet *ifp_p)
728 {
729         struct vlan_trunk *vlantrunks = ifp_p->if_vlantrunks;
730         struct netmsg_vlan vmsg;
731         struct netmsg *nmsg;
732
733         /* Assert in netisr0 */
734         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
735
736         KASSERT(ifp_p->if_vlantrunks != NULL,
737                 ("vlan trunk has not been initialized yet\n"));
738
739         bzero(&vmsg, sizeof(vmsg));
740         nmsg = &vmsg.nv_nmsg;
741
742         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_unlink_dispatch);
743         vmsg.nv_ifv = ifv;
744         vmsg.nv_ifp_p = ifp_p;
745
746         lwkt_domsg(ifa_portfn(0), &nmsg->nm_lmsg, 0);
747
748         crit_enter();
749         if (LIST_EMPTY(&vlantrunks[mycpuid].vlan_list)) {
750 #ifdef notyet
751                 ifp_p->if_vlantrunks = NULL;
752                 netmsg_service_sync();
753                 kfree(vlantrunks, M_VLAN);
754 #else
755                 lwkt_serialize_enter(ifp_p->if_serializer);
756                 kfree(ifp_p->if_vlantrunks, M_VLAN);
757                 ifp_p->if_vlantrunks = NULL;
758                 lwkt_serialize_exit(ifp_p->if_serializer);
759 #endif
760         }
761         crit_exit();
762 }
763
764 static void
765 vlan_unconfig_dispatch(struct netmsg *nmsg)
766 {
767         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
768         struct sockaddr_dl *sdl;
769         struct ifvlan *ifv;
770         struct ifnet *ifp_p, *ifp;
771         int error;
772
773         /* Assert in netisr0 */
774
775         ifv = vmsg->nv_ifv;
776         ifp = &ifv->ifv_if;
777
778         if (ifp->if_flags & IFF_UP)
779                 if_down(ifp);
780
781         lwkt_serialize_enter(ifp->if_serializer);
782
783         ifp->if_flags &= ~IFF_RUNNING;
784
785         /*
786          * Save parent ifnet pointer and disconnect from parent.
787          *
788          * This is done early in this function, so input/output could
789          * know that we are disconnecting.
790          */
791         ifp_p = ifv->ifv_p;
792         ifv->ifv_p = NULL;
793
794         /*
795          * Release vlan's serializer before reprogramming parent's
796          * multicast filter to avoid possible dead lock.
797          */
798         lwkt_serialize_exit(ifp->if_serializer);
799
800         if (ifp_p) {
801                 /*
802                  * Since the interface is being unconfigured, we need to
803                  * empty the list of multicast groups that we may have joined
804                  * while we were alive from the parent's list.
805                  */
806                 vlan_clrmulti(ifv, ifp_p);
807         }
808
809         lwkt_serialize_enter(ifp->if_serializer);
810
811         ifp->if_mtu = ETHERMTU;
812
813         /* Clear our MAC address. */
814         sdl = IF_LLSOCKADDR(ifp);
815         sdl->sdl_type = IFT_ETHER;
816         sdl->sdl_alen = ETHER_ADDR_LEN;
817         bzero(LLADDR(sdl), ETHER_ADDR_LEN);
818         bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
819
820         lwkt_serialize_exit(ifp->if_serializer);
821
822         /* Unlink vlan from parent's vlantrunk */
823         if (ifp_p != NULL && ifp_p->if_vlantrunks != NULL)
824                 vlan_unlink(ifv, ifp_p);
825
826         error = 0;
827         lwkt_replymsg(&nmsg->nm_lmsg, error);
828 }
829
830 static int
831 vlan_unconfig(struct ifvlan *ifv)
832 {
833         struct netmsg_vlan vmsg;
834         struct netmsg *nmsg;
835
836         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
837
838         bzero(&vmsg, sizeof(vmsg));
839         nmsg = &vmsg.nv_nmsg;
840
841         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_unconfig_dispatch);
842         vmsg.nv_ifv = ifv;
843
844         return lwkt_domsg(cpu_portfn(0), &nmsg->nm_lmsg, 0);
845 }
846
847 static int
848 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
849 {
850         struct ifvlan *ifv = ifp->if_softc;
851         struct ifreq *ifr = (struct ifreq *)data;
852         struct ifnet *ifp_p;
853         struct vlanreq vlr;
854         int error = 0;
855
856         ASSERT_SERIALIZED(ifp->if_serializer);
857
858         switch (cmd) {
859         case SIOCGIFMEDIA:
860                 ifp_p = ifv->ifv_p;
861                 if (ifp_p != NULL) {
862                         lwkt_serialize_exit(ifp->if_serializer);
863
864                         lwkt_serialize_enter(ifp_p->if_serializer);
865                         error = ifp_p->if_ioctl(ifp_p, SIOCGIFMEDIA, data, cr);
866                         lwkt_serialize_exit(ifp_p->if_serializer);
867
868                         lwkt_serialize_enter(ifp->if_serializer);
869                         /* Limit the result to the parent's current config. */
870                         if (error == 0) {
871                                 struct ifmediareq *ifmr;
872
873                                 ifmr = (struct ifmediareq *) data;
874                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
875                                         ifmr->ifm_count = 1;
876                                         error = copyout(&ifmr->ifm_current,
877                                                 ifmr->ifm_ulist, 
878                                                 sizeof(int));
879                                 }
880                         }
881                 } else {
882                         error = EINVAL;
883                 }
884                 break;
885
886         case SIOCSIFMEDIA:
887                 error = EINVAL;
888                 break;
889
890         case SIOCSETVLAN:
891                 error = copyin(ifr->ifr_data, &vlr, sizeof vlr);
892                 if (error)
893                         break;
894
895                 lwkt_serialize_exit(ifp->if_serializer);
896                 if (vlr.vlr_parent[0] == '\0')
897                         error = vlan_unconfig(ifv);
898                 else
899                         error = vlan_config(ifv, vlr.vlr_parent, vlr.vlr_tag);
900                 lwkt_serialize_enter(ifp->if_serializer);
901                 break;
902
903         case SIOCGETVLAN:
904                 bzero(&vlr, sizeof(vlr));
905                 if (ifv->ifv_p) {
906                         strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
907                             sizeof(vlr.vlr_parent));
908                         vlr.vlr_tag = ifv->ifv_tag;
909                 }
910                 error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
911                 break;
912                 
913         case SIOCSIFFLAGS:
914                 if (ifp->if_flags & IFF_UP)
915                         ifp->if_init(ifp);
916                 else
917                         ifp->if_flags &= ~IFF_RUNNING;
918
919                 /*
920                  * We don't support promiscuous mode
921                  * right now because it would require help from the
922                  * underlying drivers, which hasn't been implemented.
923                  */
924                 if (ifr->ifr_flags & IFF_PROMISC) {
925                         ifp->if_flags &= ~IFF_PROMISC;
926                         error = EINVAL;
927                 }
928                 break;
929
930         case SIOCADDMULTI:
931         case SIOCDELMULTI:
932                 lwkt_serialize_exit(ifp->if_serializer);
933                 error = vlan_config_multi(ifv);
934                 lwkt_serialize_enter(ifp->if_serializer);
935                 break;
936
937         default:
938                 error = ether_ioctl(ifp, cmd, data);
939                 break;
940         }
941         return error;
942 }
943
944 static void
945 vlan_multi_dispatch(struct netmsg *nmsg)
946 {
947         struct netmsg_vlan *vmsg = (struct netmsg_vlan *)nmsg;
948         struct ifvlan *ifv = vmsg->nv_ifv;
949         int error = 0;
950
951         /*
952          * If we don't have a parent, just remember the membership for
953          * when we do.
954          */
955         if (ifv->ifv_p != NULL)
956                 error = vlan_setmulti(ifv, ifv->ifv_p);
957         lwkt_replymsg(&nmsg->nm_lmsg, error);
958 }
959
960 static int
961 vlan_config_multi(struct ifvlan *ifv)
962 {
963         struct netmsg_vlan vmsg;
964         struct netmsg *nmsg;
965
966         ASSERT_NOT_SERIALIZED(ifv->ifv_if.if_serializer);
967
968         bzero(&vmsg, sizeof(vmsg));
969         nmsg = &vmsg.nv_nmsg;
970
971         netmsg_init(nmsg, &curthread->td_msgport, 0, vlan_multi_dispatch);
972         vmsg.nv_ifv = ifv;
973
974         return lwkt_domsg(cpu_portfn(0), &nmsg->nm_lmsg, 0);
975 }