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