if_vlan.c revision 1.30 1 /* $NetBSD: if_vlan.c,v 1.30 2001/01/29 01:51:05 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran, and by Jason R. Thorpe of Zembu Labs, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright 1998 Massachusetts Institute of Technology
41 *
42 * Permission to use, copy, modify, and distribute this software and
43 * its documentation for any purpose and without fee is hereby
44 * granted, provided that both the above copyright notice and this
45 * permission notice appear in all copies, that both the above
46 * copyright notice and this permission notice appear in all
47 * supporting documentation, and that the name of M.I.T. not be used
48 * in advertising or publicity pertaining to distribution of the
49 * software without specific, written prior permission. M.I.T. makes
50 * no representations about the suitability of this software for any
51 * purpose. It is provided "as is" without express or implied
52 * warranty.
53 *
54 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
55 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
56 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
57 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
58 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
61 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
63 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
64 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 *
67 * from FreeBSD: if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp
68 * via OpenBSD: if_vlan.c,v 1.4 2000/05/15 19:15:00 chris Exp
69 */
70
71 /*
72 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. Might be
73 * extended some day to also handle IEEE 802.1P priority tagging. This is
74 * sort of sneaky in the implementation, since we need to pretend to be
75 * enough of an Ethernet implementation to make ARP work. The way we do
76 * this is by telling everyone that we are an Ethernet interface, and then
77 * catch the packets that ether_output() left on our output queue when it
78 * calls if_start(), rewrite them for use by the real outgoing interface,
79 * and ask it to send them.
80 *
81 * TODO:
82 *
83 * - Need some way to notify vlan interfaces when the parent
84 * interface changes MTU.
85 */
86
87 #include "opt_inet.h"
88 #include "bpfilter.h"
89
90 #include <sys/param.h>
91 #include <sys/kernel.h>
92 #include <sys/mbuf.h>
93 #include <sys/queue.h>
94 #include <sys/socket.h>
95 #include <sys/sockio.h>
96 #include <sys/systm.h>
97 #include <sys/proc.h>
98
99 #if NBPFILTER > 0
100 #include <net/bpf.h>
101 #endif
102 #include <net/if.h>
103 #include <net/if_dl.h>
104 #include <net/if_types.h>
105 #include <net/if_ether.h>
106 #include <net/if_vlanvar.h>
107
108 #ifdef INET
109 #include <netinet/in.h>
110 #include <netinet/if_inarp.h>
111 #endif
112
113 struct vlan_mc_entry {
114 LIST_ENTRY(vlan_mc_entry) mc_entries;
115 /*
116 * A key to identify this entry. The mc_addr below can't be
117 * used since multiple sockaddr may mapped into the same
118 * ether_multi (e.g., AF_UNSPEC).
119 */
120 union {
121 struct ether_multi *mcu_enm;
122 } mc_u;
123 struct sockaddr_storage mc_addr;
124 };
125
126 #define mc_enm mc_u.mcu_enm
127
128 struct ifvlan {
129 union {
130 struct ethercom ifvu_ec;
131 } ifv_u;
132 struct ifnet *ifv_p; /* parent interface of this vlan */
133 struct ifv_linkmib {
134 const struct vlan_multisw *ifvm_msw;
135 int ifvm_encaplen; /* encapsulation length */
136 int ifvm_mtufudge; /* MTU fudged by this much */
137 int ifvm_mintu; /* min transmission unit */
138 u_int16_t ifvm_proto; /* encapsulation ethertype */
139 u_int16_t ifvm_tag; /* tag to apply on packets */
140 } ifv_mib;
141 LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
142 LIST_ENTRY(ifvlan) ifv_list;
143 int ifv_flags;
144 };
145
146 #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
147
148 #define ifv_ec ifv_u.ifvu_ec
149
150 #define ifv_if ifv_ec.ec_if
151
152 #define ifv_msw ifv_mib.ifvm_msw
153 #define ifv_encaplen ifv_mib.ifvm_encaplen
154 #define ifv_mtufudge ifv_mib.ifvm_mtufudge
155 #define ifv_mintu ifv_mib.ifvm_mintu
156 #define ifv_tag ifv_mib.ifvm_tag
157
158 struct vlan_multisw {
159 int (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
160 int (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
161 void (*vmsw_purgemulti)(struct ifvlan *);
162 };
163
164 static int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
165 static int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
166 static void vlan_ether_purgemulti(struct ifvlan *);
167
168 const struct vlan_multisw vlan_ether_multisw = {
169 vlan_ether_addmulti,
170 vlan_ether_delmulti,
171 vlan_ether_purgemulti,
172 };
173
174 static int vlan_clone_create(struct if_clone *, int);
175 static void vlan_clone_destroy(struct ifnet *);
176 static int vlan_config(struct ifvlan *, struct ifnet *);
177 static int vlan_ioctl(struct ifnet *, u_long, caddr_t);
178 static void vlan_start(struct ifnet *);
179 static void vlan_unconfig(struct ifnet *);
180
181 void vlanattach(int);
182
183 /* XXX This should be a hash table with the tag as the basis of the key. */
184 static LIST_HEAD(, ifvlan) ifv_list;
185
186 struct if_clone vlan_cloner =
187 IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
188
189 void
190 vlanattach(int n)
191 {
192
193 LIST_INIT(&ifv_list);
194 if_clone_attach(&vlan_cloner);
195 }
196
197 static void
198 vlan_reset_linkname(struct ifnet *ifp)
199 {
200
201 /*
202 * We start out with a "802.1Q VLAN" type and zero-length
203 * addresses. When we attach to a parent interface, we
204 * inherit its type, address length, address, and data link
205 * type.
206 */
207
208 ifp->if_type = IFT_L2VLAN;
209 ifp->if_addrlen = 0;
210 ifp->if_dlt = DLT_NULL;
211 if_alloc_sadl(ifp);
212 }
213
214 static int
215 vlan_clone_create(struct if_clone *ifc, int unit)
216 {
217 struct ifvlan *ifv;
218 struct ifnet *ifp;
219 int s;
220
221 ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK);
222 memset(ifv, 0, sizeof(struct ifvlan));
223 ifp = &ifv->ifv_if;
224 LIST_INIT(&ifv->ifv_mc_listhead);
225
226 s = splnet();
227 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
228 splx(s);
229
230 sprintf(ifp->if_xname, "%s%d", ifc->ifc_name, unit);
231 ifp->if_softc = ifv;
232 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
233 ifp->if_start = vlan_start;
234 ifp->if_ioctl = vlan_ioctl;
235
236 if_attach(ifp);
237 vlan_reset_linkname(ifp);
238
239 return (0);
240 }
241
242 static void
243 vlan_clone_destroy(struct ifnet *ifp)
244 {
245 struct ifvlan *ifv = ifp->if_softc;
246 int s;
247
248 s = splnet();
249 LIST_REMOVE(ifv, ifv_list);
250 vlan_unconfig(ifp);
251 splx(s);
252
253 if_detach(ifp);
254 free(ifv, M_DEVBUF);
255 }
256
257 /*
258 * Configure a VLAN interface. Must be called at splnet().
259 */
260 static int
261 vlan_config(struct ifvlan *ifv, struct ifnet *p)
262 {
263 struct ifnet *ifp = &ifv->ifv_if;
264 int error;
265
266 if (ifv->ifv_p != NULL)
267 return (EBUSY);
268
269 switch (p->if_type) {
270 case IFT_ETHER:
271 {
272 struct ethercom *ec = (void *) p;
273
274 ifv->ifv_msw = &vlan_ether_multisw;
275 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
276 ifv->ifv_mintu = ETHERMIN;
277
278 /*
279 * If the parent supports the VLAN_MTU capability,
280 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
281 * enable it.
282 */
283 if (ec->ec_nvlans++ == 0 &&
284 (ec->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
285 /*
286 * Enable Tx/Rx of VLAN-sized frames.
287 */
288 ec->ec_capenable |= ETHERCAP_VLAN_MTU;
289 if (p->if_flags & IFF_UP) {
290 struct ifreq ifr;
291
292 ifr.ifr_flags = p->if_flags;
293 error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
294 (caddr_t) &ifr);
295 if (error) {
296 if (ec->ec_nvlans-- == 1)
297 ec->ec_capenable &=
298 ~ETHERCAP_VLAN_MTU;
299 return (error);
300 }
301 }
302 ifv->ifv_mtufudge = 0;
303 } else if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) {
304 /*
305 * Fudge the MTU by the encapsulation size. This
306 * makes us incompatible with strictly compliant
307 * 802.1Q implementations, but allows us to use
308 * the feature with other NetBSD implementations,
309 * which might still be useful.
310 */
311 ifv->ifv_mtufudge = ifv->ifv_encaplen;
312 }
313
314 /*
315 * We inherit the parent's Ethernet address.
316 */
317 ether_ifattach(ifp, LLADDR(p->if_sadl));
318 ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
319 break;
320 }
321
322 default:
323 return (EPROTONOSUPPORT);
324 }
325
326 ifv->ifv_p = p;
327 ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
328 ifv->ifv_if.if_flags = p->if_flags &
329 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
330
331 /*
332 * Inherit the if_type from the parent. This allows us
333 * to participate in bridges of that type.
334 */
335 ifv->ifv_if.if_type = p->if_type;
336
337 return (0);
338 }
339
340 /*
341 * Unconfigure a VLAN interface. Must be called at splnet().
342 */
343 static void
344 vlan_unconfig(struct ifnet *ifp)
345 {
346 struct ifvlan *ifv = ifp->if_softc;
347
348 if (ifv->ifv_p == NULL)
349 return;
350
351 /*
352 * Since the interface is being unconfigured, we need to empty the
353 * list of multicast groups that we may have joined while we were
354 * alive and remove them from the parent's list also.
355 */
356 (*ifv->ifv_msw->vmsw_purgemulti)(ifv);
357
358 /* Disconnect from parent. */
359 switch (ifv->ifv_p->if_type) {
360 case IFT_ETHER:
361 {
362 struct ethercom *ec = (void *) ifv->ifv_p;
363
364 if (ec->ec_nvlans-- == 1) {
365 /*
366 * Disable Tx/Rx of VLAN-sized frames.
367 */
368 ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
369 if (ifv->ifv_p->if_flags & IFF_UP) {
370 struct ifreq ifr;
371
372 ifr.ifr_flags = ifv->ifv_p->if_flags;
373 (void) (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
374 SIOCSIFFLAGS, (caddr_t) &ifr);
375 }
376 }
377
378 ether_ifdetach(ifp);
379 vlan_reset_linkname(ifp);
380 break;
381 }
382
383 #ifdef DIAGNOSTIC
384 default:
385 panic("vlan_unconfig: impossible");
386 #endif
387 }
388
389 ifv->ifv_p = NULL;
390 ifv->ifv_if.if_mtu = 0;
391 ifv->ifv_flags = 0;
392
393 if_down(ifp);
394 ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
395 }
396
397 /*
398 * Called when a parent interface is detaching; destroy any VLAN
399 * configuration for the parent interface.
400 */
401 void
402 vlan_ifdetach(struct ifnet *p)
403 {
404 struct ifvlan *ifv;
405 int s;
406
407 s = splnet();
408
409 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
410 ifv = LIST_NEXT(ifv, ifv_list)) {
411 if (ifv->ifv_p == p)
412 vlan_unconfig(&ifv->ifv_if);
413 }
414
415 splx(s);
416 }
417
418 static int
419 vlan_set_promisc(struct ifnet *ifp)
420 {
421 struct ifvlan *ifv = ifp->if_softc;
422 int error = 0;
423
424 if ((ifp->if_flags & IFF_PROMISC) != 0) {
425 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
426 error = ifpromisc(ifv->ifv_p, 1);
427 if (error == 0)
428 ifv->ifv_flags |= IFVF_PROMISC;
429 }
430 } else {
431 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
432 error = ifpromisc(ifv->ifv_p, 0);
433 if (error == 0)
434 ifv->ifv_flags &= ~IFVF_PROMISC;
435 }
436 }
437
438 return (error);
439 }
440
441 static int
442 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
443 {
444 struct proc *p = curproc; /* XXX */
445 struct ifvlan *ifv = ifp->if_softc;
446 struct ifaddr *ifa = (struct ifaddr *) data;
447 struct ifreq *ifr = (struct ifreq *) data;
448 struct ifnet *pr;
449 struct vlanreq vlr;
450 struct sockaddr *sa;
451 int s, error = 0;
452
453 s = splnet();
454
455 switch (cmd) {
456 case SIOCSIFADDR:
457 if (ifv->ifv_p != NULL) {
458 ifp->if_flags |= IFF_UP;
459
460 switch (ifa->ifa_addr->sa_family) {
461 #ifdef INET
462 case AF_INET:
463 arp_ifinit(ifp, ifa);
464 break;
465 #endif
466 default:
467 break;
468 }
469 } else {
470 error = EINVAL;
471 }
472 break;
473
474 case SIOCGIFADDR:
475 sa = (struct sockaddr *)&ifr->ifr_data;
476 memcpy(sa->sa_data, LLADDR(ifp->if_sadl), ifp->if_addrlen);
477 break;
478
479 case SIOCSIFMTU:
480 if (ifv->ifv_p != NULL) {
481 if (ifr->ifr_mtu >
482 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
483 ifr->ifr_mtu <
484 (ifv->ifv_mintu - ifv->ifv_mtufudge))
485 error = EINVAL;
486 else
487 ifp->if_mtu = ifr->ifr_mtu;
488 } else
489 error = EINVAL;
490 break;
491
492 case SIOCSETVLAN:
493 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
494 break;
495 if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
496 break;
497 if (vlr.vlr_parent[0] == '\0') {
498 vlan_unconfig(ifp);
499 break;
500 }
501 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
502 error = EINVAL; /* check for valid tag */
503 break;
504 }
505 if ((pr = ifunit(vlr.vlr_parent)) == 0) {
506 error = ENOENT;
507 break;
508 }
509 if ((error = vlan_config(ifv, pr)) != 0)
510 break;
511 ifv->ifv_tag = vlr.vlr_tag;
512 ifp->if_flags |= IFF_RUNNING;
513
514 /* Update promiscuous mode, if necessary. */
515 vlan_set_promisc(ifp);
516 break;
517
518 case SIOCGETVLAN:
519 memset(&vlr, 0, sizeof(vlr));
520 if (ifv->ifv_p != NULL) {
521 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
522 ifv->ifv_p->if_xname);
523 vlr.vlr_tag = ifv->ifv_tag;
524 }
525 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
526 break;
527
528 case SIOCSIFFLAGS:
529 /*
530 * For promiscuous mode, we enable promiscuous mode on
531 * the parent if we need promiscuous on the VLAN interface.
532 */
533 if (ifv->ifv_p != NULL)
534 error = vlan_set_promisc(ifp);
535 break;
536
537 case SIOCADDMULTI:
538 error = (ifv->ifv_p != NULL) ?
539 (*ifv->ifv_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
540 break;
541
542 case SIOCDELMULTI:
543 error = (ifv->ifv_p != NULL) ?
544 (*ifv->ifv_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
545 break;
546
547 default:
548 error = EINVAL;
549 }
550
551 splx(s);
552
553 return (error);
554 }
555
556 static int
557 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
558 {
559 struct vlan_mc_entry *mc;
560 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
561 int error;
562
563 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
564 return (EINVAL);
565
566 error = ether_addmulti(ifr, &ifv->ifv_ec);
567 if (error != ENETRESET)
568 return (error);
569
570 /*
571 * This is new multicast address. We have to tell parent
572 * about it. Also, remember this multicast address so that
573 * we can delete them on unconfigure.
574 */
575 MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
576 M_DEVBUF, M_NOWAIT);
577 if (mc == NULL) {
578 error = ENOMEM;
579 goto alloc_failed;
580 }
581
582 /*
583 * As ether_addmulti() returns ENETRESET, following two
584 * statement shouldn't fail.
585 */
586 (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
587 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm);
588 memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
589 LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
590
591 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCADDMULTI,
592 (caddr_t)ifr);
593 if (error != 0)
594 goto ioctl_failed;
595 return (error);
596
597 ioctl_failed:
598 LIST_REMOVE(mc, mc_entries);
599 FREE(mc, M_DEVBUF);
600 alloc_failed:
601 (void)ether_delmulti(ifr, &ifv->ifv_ec);
602 return (error);
603 }
604
605 static int
606 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
607 {
608 struct ether_multi *enm;
609 struct vlan_mc_entry *mc;
610 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
611 int error;
612
613 /*
614 * Find a key to lookup vlan_mc_entry. We have to do this
615 * before calling ether_delmulti for obvious reason.
616 */
617 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
618 return (error);
619 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm);
620
621 error = ether_delmulti(ifr, &ifv->ifv_ec);
622 if (error != ENETRESET)
623 return (error);
624
625 /* We no longer use this multicast address. Tell parent so. */
626 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCDELMULTI,
627 (caddr_t)ifr);
628 if (error == 0) {
629 /* And forget about this address. */
630 for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL;
631 mc = LIST_NEXT(mc, mc_entries)) {
632 if (mc->mc_enm == enm) {
633 LIST_REMOVE(mc, mc_entries);
634 FREE(mc, M_DEVBUF);
635 break;
636 }
637 }
638 KASSERT(mc != NULL);
639 } else
640 (void)ether_addmulti(ifr, &ifv->ifv_ec);
641 return (error);
642 }
643
644 /*
645 * Delete any multicast address we have asked to add form parent
646 * interface. Called when the vlan is being unconfigured.
647 */
648 static void
649 vlan_ether_purgemulti(struct ifvlan *ifv)
650 {
651 struct ifnet *ifp = ifv->ifv_p; /* Parent. */
652 struct vlan_mc_entry *mc;
653 union {
654 struct ifreq ifreq;
655 struct {
656 char ifr_name[IFNAMSIZ];
657 struct sockaddr_storage ifr_ss;
658 } ifreq_storage;
659 } ifreq;
660 struct ifreq *ifr = &ifreq.ifreq;
661
662 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
663 while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
664 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
665 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
666 LIST_REMOVE(mc, mc_entries);
667 FREE(mc, M_DEVBUF);
668 }
669 }
670
671 static void
672 vlan_start(struct ifnet *ifp)
673 {
674 struct ifvlan *ifv = ifp->if_softc;
675 struct ifnet *p = ifv->ifv_p;
676 struct ethercom *ec = (void *) ifv->ifv_p;
677 struct mbuf *m;
678
679 ifp->if_flags |= IFF_OACTIVE;
680
681 for (;;) {
682 IF_DEQUEUE(&ifp->if_snd, m);
683 if (m == NULL)
684 break;
685
686 #if NBPFILTER > 0
687 if (ifp->if_bpf)
688 bpf_mtap(ifp->if_bpf, m);
689 #endif
690 /*
691 * If the parent can insert the tag itself, just mark
692 * the tag in the mbuf header.
693 */
694 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
695 struct mbuf *n;
696 n = m_aux_add(m, AF_LINK, ETHERTYPE_VLAN);
697 if (n == NULL) {
698 ifp->if_oerrors++;
699 m_freem(m);
700 continue;
701 }
702 *mtod(n, int *) = ifv->ifv_tag;
703 n->m_len = sizeof(int);
704 } else {
705 /*
706 * insert the tag ourselve
707 */
708 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
709 if (m == NULL) {
710 printf("%s: unable to prepend encap header",
711 ifv->ifv_p->if_xname);
712 ifp->if_oerrors++;
713 continue;
714 }
715
716 switch (p->if_type) {
717 case IFT_ETHER:
718 {
719 struct ether_vlan_header *evl;
720
721 if (m->m_len < sizeof(struct ether_vlan_header))
722 m = m_pullup(m,
723 sizeof(struct ether_vlan_header));
724 if (m == NULL) {
725 printf("%s: unable to pullup encap "
726 "header", ifv->ifv_p->if_xname);
727 ifp->if_oerrors++;
728 continue;
729 }
730
731 /*
732 * Transform the Ethernet header into an
733 * Ethernet header with 802.1Q encapsulation.
734 */
735 memmove(mtod(m, caddr_t),
736 mtod(m, caddr_t) + ifv->ifv_encaplen,
737 sizeof(struct ether_header));
738 evl = mtod(m, struct ether_vlan_header *);
739 evl->evl_proto = evl->evl_encap_proto;
740 evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
741 evl->evl_tag = htons(ifv->ifv_tag);
742 break;
743 }
744
745 #ifdef DIAGNOSTIC
746 default:
747 panic("vlan_start: impossible");
748 #endif
749 }
750 }
751
752 /*
753 * Send it, precisely as the parent's output routine
754 * would have. We are already running at splimp.
755 */
756 if (IF_QFULL(&p->if_snd)) {
757 IF_DROP(&p->if_snd);
758 /* XXX stats */
759 ifp->if_oerrors++;
760 m_freem(m);
761 continue;
762 }
763
764 IF_ENQUEUE(&p->if_snd, m);
765 ifp->if_opackets++;
766 if ((p->if_flags & IFF_OACTIVE) == 0) {
767 (*p->if_start)(p);
768 }
769 }
770
771 ifp->if_flags &= ~IFF_OACTIVE;
772 }
773
774 /*
775 * Given an Ethernet frame, find a valid vlan interface corresponding to the
776 * given source interface and tag, then run the the real packet through
777 * the parent's input routine.
778 */
779 void
780 vlan_input(struct ifnet *ifp, struct mbuf *m)
781 {
782 struct ifvlan *ifv;
783 u_int tag;
784 struct mbuf *n;
785
786 n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
787 if (n) {
788 /* m contains a normal ethernet frame, the tag is in m_aux */
789 tag = *mtod(n, int *);
790 m_aux_delete(m, n);
791 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
792 ifv = LIST_NEXT(ifv, ifv_list))
793 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
794 break;
795 } else {
796 switch (ifp->if_type) {
797 case IFT_ETHER:
798 {
799 struct ether_vlan_header *evl;
800
801 if (m->m_len < sizeof(struct ether_vlan_header) &&
802 (m = m_pullup(m,
803 sizeof(struct ether_vlan_header))) == NULL) {
804 printf("%s: no memory for VLAN header, "
805 "dropping packet.\n", ifp->if_xname);
806 return;
807 }
808 evl = mtod(m, struct ether_vlan_header *);
809 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
810
811 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
812
813 /*
814 * Restore the original ethertype. We'll remove
815 * the encapsulation after we've found the vlan
816 * interface corresponding to the tag.
817 */
818 evl->evl_encap_proto = evl->evl_proto;
819 break;
820 }
821
822 default:
823 tag = (u_int) -1; /* XXX GCC */
824 #ifdef DIAGNOSTIC
825 panic("vlan_input: impossible");
826 #endif
827 }
828
829 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
830 ifv = LIST_NEXT(ifv, ifv_list))
831 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
832 break;
833
834
835 /*
836 * Now, remove the encapsulation header. The original
837 * header has already been fixed up above.
838 */
839 if (ifv) {
840 memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
841 mtod(m, caddr_t), sizeof(struct ether_header));
842 m_adj(m, ifv->ifv_encaplen);
843 }
844 }
845
846 if (ifv == NULL ||
847 (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
848 (IFF_UP|IFF_RUNNING)) {
849 m_free(m);
850 ifp->if_noproto++;
851 return;
852 }
853 m->m_pkthdr.rcvif = &ifv->ifv_if;
854 ifv->ifv_if.if_ipackets++;
855
856 #if NBPFILTER > 0
857 if (ifv->ifv_if.if_bpf)
858 bpf_mtap(ifv->ifv_if.if_bpf, m);
859 #endif
860
861 /* Pass it back through the parent's input routine. */
862 (*ifp->if_input)(&ifv->ifv_if, m);
863 }
864