if_vlan.c revision 1.32.2.1 1 /* $NetBSD: if_vlan.c,v 1.32.2.1 2002/01/10 20:02:17 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2000, 2001 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 <sys/cdefs.h>
88 __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.32.2.1 2002/01/10 20:02:17 thorpej Exp $");
89
90 #include "opt_inet.h"
91 #include "bpfilter.h"
92
93 #include <sys/param.h>
94 #include <sys/kernel.h>
95 #include <sys/mbuf.h>
96 #include <sys/queue.h>
97 #include <sys/socket.h>
98 #include <sys/sockio.h>
99 #include <sys/systm.h>
100 #include <sys/proc.h>
101
102 #if NBPFILTER > 0
103 #include <net/bpf.h>
104 #endif
105 #include <net/if.h>
106 #include <net/if_dl.h>
107 #include <net/if_types.h>
108 #include <net/if_ether.h>
109 #include <net/if_vlanvar.h>
110
111 #ifdef INET
112 #include <netinet/in.h>
113 #include <netinet/if_inarp.h>
114 #endif
115
116 struct vlan_mc_entry {
117 LIST_ENTRY(vlan_mc_entry) mc_entries;
118 /*
119 * A key to identify this entry. The mc_addr below can't be
120 * used since multiple sockaddr may mapped into the same
121 * ether_multi (e.g., AF_UNSPEC).
122 */
123 union {
124 struct ether_multi *mcu_enm;
125 } mc_u;
126 struct sockaddr_storage mc_addr;
127 };
128
129 #define mc_enm mc_u.mcu_enm
130
131 struct ifvlan {
132 union {
133 struct ethercom ifvu_ec;
134 } ifv_u;
135 struct ifnet *ifv_p; /* parent interface of this vlan */
136 struct ifv_linkmib {
137 const struct vlan_multisw *ifvm_msw;
138 int ifvm_encaplen; /* encapsulation length */
139 int ifvm_mtufudge; /* MTU fudged by this much */
140 int ifvm_mintu; /* min transmission unit */
141 u_int16_t ifvm_proto; /* encapsulation ethertype */
142 u_int16_t ifvm_tag; /* tag to apply on packets */
143 } ifv_mib;
144 LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
145 LIST_ENTRY(ifvlan) ifv_list;
146 int ifv_flags;
147 };
148
149 #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
150
151 #define ifv_ec ifv_u.ifvu_ec
152
153 #define ifv_if ifv_ec.ec_if
154
155 #define ifv_msw ifv_mib.ifvm_msw
156 #define ifv_encaplen ifv_mib.ifvm_encaplen
157 #define ifv_mtufudge ifv_mib.ifvm_mtufudge
158 #define ifv_mintu ifv_mib.ifvm_mintu
159 #define ifv_tag ifv_mib.ifvm_tag
160
161 struct vlan_multisw {
162 int (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
163 int (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
164 void (*vmsw_purgemulti)(struct ifvlan *);
165 };
166
167 static int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
168 static int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
169 static void vlan_ether_purgemulti(struct ifvlan *);
170
171 const struct vlan_multisw vlan_ether_multisw = {
172 vlan_ether_addmulti,
173 vlan_ether_delmulti,
174 vlan_ether_purgemulti,
175 };
176
177 static int vlan_clone_create(struct if_clone *, int);
178 static void vlan_clone_destroy(struct ifnet *);
179 static int vlan_config(struct ifvlan *, struct ifnet *);
180 static int vlan_ioctl(struct ifnet *, u_long, caddr_t);
181 static void vlan_start(struct ifnet *);
182 static void vlan_unconfig(struct ifnet *);
183
184 void vlanattach(int);
185
186 /* XXX This should be a hash table with the tag as the basis of the key. */
187 static LIST_HEAD(, ifvlan) ifv_list;
188
189 struct if_clone vlan_cloner =
190 IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
191
192 void
193 vlanattach(int n)
194 {
195
196 LIST_INIT(&ifv_list);
197 if_clone_attach(&vlan_cloner);
198 }
199
200 static void
201 vlan_reset_linkname(struct ifnet *ifp)
202 {
203
204 /*
205 * We start out with a "802.1Q VLAN" type and zero-length
206 * addresses. When we attach to a parent interface, we
207 * inherit its type, address length, address, and data link
208 * type.
209 */
210
211 ifp->if_type = IFT_L2VLAN;
212 ifp->if_addrlen = 0;
213 ifp->if_dlt = DLT_NULL;
214 if_alloc_sadl(ifp);
215 }
216
217 static int
218 vlan_clone_create(struct if_clone *ifc, int unit)
219 {
220 struct ifvlan *ifv;
221 struct ifnet *ifp;
222 int s;
223
224 ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK);
225 memset(ifv, 0, sizeof(struct ifvlan));
226 ifp = &ifv->ifv_if;
227 LIST_INIT(&ifv->ifv_mc_listhead);
228
229 s = splnet();
230 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
231 splx(s);
232
233 sprintf(ifp->if_xname, "%s%d", ifc->ifc_name, unit);
234 ifp->if_softc = ifv;
235 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236 ifp->if_start = vlan_start;
237 ifp->if_ioctl = vlan_ioctl;
238 IFQ_SET_READY(&ifp->if_snd);
239
240 if_attach(ifp);
241 vlan_reset_linkname(ifp);
242
243 return (0);
244 }
245
246 static void
247 vlan_clone_destroy(struct ifnet *ifp)
248 {
249 struct ifvlan *ifv = ifp->if_softc;
250 int s;
251
252 s = splnet();
253 LIST_REMOVE(ifv, ifv_list);
254 vlan_unconfig(ifp);
255 splx(s);
256
257 if_detach(ifp);
258 free(ifv, M_DEVBUF);
259 }
260
261 /*
262 * Configure a VLAN interface. Must be called at splnet().
263 */
264 static int
265 vlan_config(struct ifvlan *ifv, struct ifnet *p)
266 {
267 struct ifnet *ifp = &ifv->ifv_if;
268 int error;
269
270 if (ifv->ifv_p != NULL)
271 return (EBUSY);
272
273 switch (p->if_type) {
274 case IFT_ETHER:
275 {
276 struct ethercom *ec = (void *) p;
277
278 ifv->ifv_msw = &vlan_ether_multisw;
279 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
280 ifv->ifv_mintu = ETHERMIN;
281
282 /*
283 * If the parent supports the VLAN_MTU capability,
284 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
285 * enable it.
286 */
287 if (ec->ec_nvlans++ == 0 &&
288 (ec->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
289 /*
290 * Enable Tx/Rx of VLAN-sized frames.
291 */
292 ec->ec_capenable |= ETHERCAP_VLAN_MTU;
293 if (p->if_flags & IFF_UP) {
294 struct ifreq ifr;
295
296 ifr.ifr_flags = p->if_flags;
297 error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
298 (caddr_t) &ifr);
299 if (error) {
300 if (ec->ec_nvlans-- == 1)
301 ec->ec_capenable &=
302 ~ETHERCAP_VLAN_MTU;
303 return (error);
304 }
305 }
306 ifv->ifv_mtufudge = 0;
307 } else if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) {
308 /*
309 * Fudge the MTU by the encapsulation size. This
310 * makes us incompatible with strictly compliant
311 * 802.1Q implementations, but allows us to use
312 * the feature with other NetBSD implementations,
313 * which might still be useful.
314 */
315 ifv->ifv_mtufudge = ifv->ifv_encaplen;
316 }
317
318 /*
319 * If the parent interface can do hardware-assisted
320 * VLAN encapsulation, then propagate its hardware-
321 * assisted checksumming flags.
322 */
323 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING)
324 ifp->if_capabilities = p->if_capabilities &
325 (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4|
326 IFCAP_CSUM_UDPv4|IFCAP_CSUM_TCPv6|
327 IFCAP_CSUM_UDPv6);
328
329 /*
330 * We inherit the parent's Ethernet address.
331 */
332 ether_ifattach(ifp, LLADDR(p->if_sadl));
333 ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
334 break;
335 }
336
337 default:
338 return (EPROTONOSUPPORT);
339 }
340
341 ifv->ifv_p = p;
342 ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
343 ifv->ifv_if.if_flags = p->if_flags &
344 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
345
346 /*
347 * Inherit the if_type from the parent. This allows us
348 * to participate in bridges of that type.
349 */
350 ifv->ifv_if.if_type = p->if_type;
351
352 return (0);
353 }
354
355 /*
356 * Unconfigure a VLAN interface. Must be called at splnet().
357 */
358 static void
359 vlan_unconfig(struct ifnet *ifp)
360 {
361 struct ifvlan *ifv = ifp->if_softc;
362
363 if (ifv->ifv_p == NULL)
364 return;
365
366 /*
367 * Since the interface is being unconfigured, we need to empty the
368 * list of multicast groups that we may have joined while we were
369 * alive and remove them from the parent's list also.
370 */
371 (*ifv->ifv_msw->vmsw_purgemulti)(ifv);
372
373 /* Disconnect from parent. */
374 switch (ifv->ifv_p->if_type) {
375 case IFT_ETHER:
376 {
377 struct ethercom *ec = (void *) ifv->ifv_p;
378
379 if (ec->ec_nvlans-- == 1) {
380 /*
381 * Disable Tx/Rx of VLAN-sized frames.
382 */
383 ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
384 if (ifv->ifv_p->if_flags & IFF_UP) {
385 struct ifreq ifr;
386
387 ifr.ifr_flags = ifv->ifv_p->if_flags;
388 (void) (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
389 SIOCSIFFLAGS, (caddr_t) &ifr);
390 }
391 }
392
393 ether_ifdetach(ifp);
394 vlan_reset_linkname(ifp);
395 break;
396 }
397
398 #ifdef DIAGNOSTIC
399 default:
400 panic("vlan_unconfig: impossible");
401 #endif
402 }
403
404 ifv->ifv_p = NULL;
405 ifv->ifv_if.if_mtu = 0;
406 ifv->ifv_flags = 0;
407
408 if_down(ifp);
409 ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
410 ifp->if_capabilities = 0;
411 }
412
413 /*
414 * Called when a parent interface is detaching; destroy any VLAN
415 * configuration for the parent interface.
416 */
417 void
418 vlan_ifdetach(struct ifnet *p)
419 {
420 struct ifvlan *ifv;
421 int s;
422
423 s = splnet();
424
425 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
426 ifv = LIST_NEXT(ifv, ifv_list)) {
427 if (ifv->ifv_p == p)
428 vlan_unconfig(&ifv->ifv_if);
429 }
430
431 splx(s);
432 }
433
434 static int
435 vlan_set_promisc(struct ifnet *ifp)
436 {
437 struct ifvlan *ifv = ifp->if_softc;
438 int error = 0;
439
440 if ((ifp->if_flags & IFF_PROMISC) != 0) {
441 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
442 error = ifpromisc(ifv->ifv_p, 1);
443 if (error == 0)
444 ifv->ifv_flags |= IFVF_PROMISC;
445 }
446 } else {
447 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
448 error = ifpromisc(ifv->ifv_p, 0);
449 if (error == 0)
450 ifv->ifv_flags &= ~IFVF_PROMISC;
451 }
452 }
453
454 return (error);
455 }
456
457 static int
458 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
459 {
460 struct proc *p = curproc; /* XXX */
461 struct ifvlan *ifv = ifp->if_softc;
462 struct ifaddr *ifa = (struct ifaddr *) data;
463 struct ifreq *ifr = (struct ifreq *) data;
464 struct ifnet *pr;
465 struct vlanreq vlr;
466 struct sockaddr *sa;
467 int s, error = 0;
468
469 s = splnet();
470
471 switch (cmd) {
472 case SIOCSIFADDR:
473 if (ifv->ifv_p != NULL) {
474 ifp->if_flags |= IFF_UP;
475
476 switch (ifa->ifa_addr->sa_family) {
477 #ifdef INET
478 case AF_INET:
479 arp_ifinit(ifp, ifa);
480 break;
481 #endif
482 default:
483 break;
484 }
485 } else {
486 error = EINVAL;
487 }
488 break;
489
490 case SIOCGIFADDR:
491 sa = (struct sockaddr *)&ifr->ifr_data;
492 memcpy(sa->sa_data, LLADDR(ifp->if_sadl), ifp->if_addrlen);
493 break;
494
495 case SIOCSIFMTU:
496 if (ifv->ifv_p != NULL) {
497 if (ifr->ifr_mtu >
498 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
499 ifr->ifr_mtu <
500 (ifv->ifv_mintu - ifv->ifv_mtufudge))
501 error = EINVAL;
502 else
503 ifp->if_mtu = ifr->ifr_mtu;
504 } else
505 error = EINVAL;
506 break;
507
508 case SIOCSETVLAN:
509 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
510 break;
511 if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
512 break;
513 if (vlr.vlr_parent[0] == '\0') {
514 vlan_unconfig(ifp);
515 break;
516 }
517 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
518 error = EINVAL; /* check for valid tag */
519 break;
520 }
521 if ((pr = ifunit(vlr.vlr_parent)) == 0) {
522 error = ENOENT;
523 break;
524 }
525 if ((error = vlan_config(ifv, pr)) != 0)
526 break;
527 ifv->ifv_tag = vlr.vlr_tag;
528 ifp->if_flags |= IFF_RUNNING;
529
530 /* Update promiscuous mode, if necessary. */
531 vlan_set_promisc(ifp);
532 break;
533
534 case SIOCGETVLAN:
535 memset(&vlr, 0, sizeof(vlr));
536 if (ifv->ifv_p != NULL) {
537 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
538 ifv->ifv_p->if_xname);
539 vlr.vlr_tag = ifv->ifv_tag;
540 }
541 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
542 break;
543
544 case SIOCSIFFLAGS:
545 /*
546 * For promiscuous mode, we enable promiscuous mode on
547 * the parent if we need promiscuous on the VLAN interface.
548 */
549 if (ifv->ifv_p != NULL)
550 error = vlan_set_promisc(ifp);
551 break;
552
553 case SIOCADDMULTI:
554 error = (ifv->ifv_p != NULL) ?
555 (*ifv->ifv_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
556 break;
557
558 case SIOCDELMULTI:
559 error = (ifv->ifv_p != NULL) ?
560 (*ifv->ifv_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
561 break;
562
563 default:
564 error = EINVAL;
565 }
566
567 splx(s);
568
569 return (error);
570 }
571
572 static int
573 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
574 {
575 struct vlan_mc_entry *mc;
576 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
577 int error;
578
579 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
580 return (EINVAL);
581
582 error = ether_addmulti(ifr, &ifv->ifv_ec);
583 if (error != ENETRESET)
584 return (error);
585
586 /*
587 * This is new multicast address. We have to tell parent
588 * about it. Also, remember this multicast address so that
589 * we can delete them on unconfigure.
590 */
591 MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
592 M_DEVBUF, M_NOWAIT);
593 if (mc == NULL) {
594 error = ENOMEM;
595 goto alloc_failed;
596 }
597
598 /*
599 * As ether_addmulti() returns ENETRESET, following two
600 * statement shouldn't fail.
601 */
602 (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
603 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm);
604 memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
605 LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
606
607 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCADDMULTI,
608 (caddr_t)ifr);
609 if (error != 0)
610 goto ioctl_failed;
611 return (error);
612
613 ioctl_failed:
614 LIST_REMOVE(mc, mc_entries);
615 FREE(mc, M_DEVBUF);
616 alloc_failed:
617 (void)ether_delmulti(ifr, &ifv->ifv_ec);
618 return (error);
619 }
620
621 static int
622 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
623 {
624 struct ether_multi *enm;
625 struct vlan_mc_entry *mc;
626 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
627 int error;
628
629 /*
630 * Find a key to lookup vlan_mc_entry. We have to do this
631 * before calling ether_delmulti for obvious reason.
632 */
633 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
634 return (error);
635 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm);
636
637 error = ether_delmulti(ifr, &ifv->ifv_ec);
638 if (error != ENETRESET)
639 return (error);
640
641 /* We no longer use this multicast address. Tell parent so. */
642 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCDELMULTI,
643 (caddr_t)ifr);
644 if (error == 0) {
645 /* And forget about this address. */
646 for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL;
647 mc = LIST_NEXT(mc, mc_entries)) {
648 if (mc->mc_enm == enm) {
649 LIST_REMOVE(mc, mc_entries);
650 FREE(mc, M_DEVBUF);
651 break;
652 }
653 }
654 KASSERT(mc != NULL);
655 } else
656 (void)ether_addmulti(ifr, &ifv->ifv_ec);
657 return (error);
658 }
659
660 /*
661 * Delete any multicast address we have asked to add form parent
662 * interface. Called when the vlan is being unconfigured.
663 */
664 static void
665 vlan_ether_purgemulti(struct ifvlan *ifv)
666 {
667 struct ifnet *ifp = ifv->ifv_p; /* Parent. */
668 struct vlan_mc_entry *mc;
669 union {
670 struct ifreq ifreq;
671 struct {
672 char ifr_name[IFNAMSIZ];
673 struct sockaddr_storage ifr_ss;
674 } ifreq_storage;
675 } ifreq;
676 struct ifreq *ifr = &ifreq.ifreq;
677
678 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
679 while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
680 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
681 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
682 LIST_REMOVE(mc, mc_entries);
683 FREE(mc, M_DEVBUF);
684 }
685 }
686
687 static void
688 vlan_start(struct ifnet *ifp)
689 {
690 struct ifvlan *ifv = ifp->if_softc;
691 struct ifnet *p = ifv->ifv_p;
692 struct ethercom *ec = (void *) ifv->ifv_p;
693 struct mbuf *m;
694 int error;
695 ALTQ_DECL(struct altq_pktattr pktattr;)
696
697 ifp->if_flags |= IFF_OACTIVE;
698
699 for (;;) {
700 IFQ_DEQUEUE(&ifp->if_snd, m);
701 if (m == NULL)
702 break;
703
704 #ifdef ALTQ
705 /*
706 * If ALTQ is enabled on the parent interface, do
707 * classification; the queueing discipline might
708 * not require classification, but might require
709 * the address family/header pointer in the pktattr.
710 */
711 if (ALTQ_IS_ENABLED(&p->if_snd)) {
712 switch (p->if_type) {
713 case IFT_ETHER:
714 altq_etherclassify(&p->if_snd, m, &pktattr);
715 break;
716 #ifdef DIAGNOSTIC
717 default:
718 panic("vlan_start: impossible (altq)");
719 #endif
720 }
721 }
722 #endif /* ALTQ */
723
724 #if NBPFILTER > 0
725 if (ifp->if_bpf)
726 bpf_mtap(ifp->if_bpf, m);
727 #endif
728 /*
729 * If the parent can insert the tag itself, just mark
730 * the tag in the mbuf header.
731 */
732 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
733 struct mbuf *n;
734 n = m_aux_add(m, AF_LINK, ETHERTYPE_VLAN);
735 if (n == NULL) {
736 ifp->if_oerrors++;
737 m_freem(m);
738 continue;
739 }
740 *mtod(n, int *) = ifv->ifv_tag;
741 n->m_len = sizeof(int);
742 } else {
743 /*
744 * insert the tag ourselve
745 */
746 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
747 if (m == NULL) {
748 printf("%s: unable to prepend encap header",
749 ifv->ifv_p->if_xname);
750 ifp->if_oerrors++;
751 continue;
752 }
753
754 switch (p->if_type) {
755 case IFT_ETHER:
756 {
757 struct ether_vlan_header *evl;
758
759 if (m->m_len < sizeof(struct ether_vlan_header))
760 m = m_pullup(m,
761 sizeof(struct ether_vlan_header));
762 if (m == NULL) {
763 printf("%s: unable to pullup encap "
764 "header", ifv->ifv_p->if_xname);
765 ifp->if_oerrors++;
766 continue;
767 }
768
769 /*
770 * Transform the Ethernet header into an
771 * Ethernet header with 802.1Q encapsulation.
772 */
773 memmove(mtod(m, caddr_t),
774 mtod(m, caddr_t) + ifv->ifv_encaplen,
775 sizeof(struct ether_header));
776 evl = mtod(m, struct ether_vlan_header *);
777 evl->evl_proto = evl->evl_encap_proto;
778 evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
779 evl->evl_tag = htons(ifv->ifv_tag);
780 break;
781 }
782
783 #ifdef DIAGNOSTIC
784 default:
785 panic("vlan_start: impossible");
786 #endif
787 }
788 }
789
790 /*
791 * Send it, precisely as the parent's output routine
792 * would have. We are already running at splimp.
793 */
794 IFQ_ENQUEUE(&p->if_snd, m, &pktattr, error);
795 if (error) {
796 /* mbuf is already freed */
797 ifp->if_oerrors++;
798 continue;
799 }
800
801 ifp->if_opackets++;
802 if ((p->if_flags & IFF_OACTIVE) == 0)
803 (*p->if_start)(p);
804 }
805
806 ifp->if_flags &= ~IFF_OACTIVE;
807 }
808
809 /*
810 * Given an Ethernet frame, find a valid vlan interface corresponding to the
811 * given source interface and tag, then run the the real packet through
812 * the parent's input routine.
813 */
814 void
815 vlan_input(struct ifnet *ifp, struct mbuf *m)
816 {
817 struct ifvlan *ifv;
818 u_int tag;
819 struct mbuf *n;
820
821 n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
822 if (n) {
823 /* m contains a normal ethernet frame, the tag is in m_aux */
824 tag = *mtod(n, int *);
825 m_aux_delete(m, n);
826 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
827 ifv = LIST_NEXT(ifv, ifv_list))
828 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
829 break;
830 } else {
831 switch (ifp->if_type) {
832 case IFT_ETHER:
833 {
834 struct ether_vlan_header *evl;
835
836 if (m->m_len < sizeof(struct ether_vlan_header) &&
837 (m = m_pullup(m,
838 sizeof(struct ether_vlan_header))) == NULL) {
839 printf("%s: no memory for VLAN header, "
840 "dropping packet.\n", ifp->if_xname);
841 return;
842 }
843 evl = mtod(m, struct ether_vlan_header *);
844 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
845
846 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
847
848 /*
849 * Restore the original ethertype. We'll remove
850 * the encapsulation after we've found the vlan
851 * interface corresponding to the tag.
852 */
853 evl->evl_encap_proto = evl->evl_proto;
854 break;
855 }
856
857 default:
858 tag = (u_int) -1; /* XXX GCC */
859 #ifdef DIAGNOSTIC
860 panic("vlan_input: impossible");
861 #endif
862 }
863
864 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
865 ifv = LIST_NEXT(ifv, ifv_list))
866 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
867 break;
868
869
870 /*
871 * Now, remove the encapsulation header. The original
872 * header has already been fixed up above.
873 */
874 if (ifv) {
875 memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
876 mtod(m, caddr_t), sizeof(struct ether_header));
877 m_adj(m, ifv->ifv_encaplen);
878 }
879 }
880
881 if (ifv == NULL ||
882 (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
883 (IFF_UP|IFF_RUNNING)) {
884 m_free(m);
885 ifp->if_noproto++;
886 return;
887 }
888 m->m_pkthdr.rcvif = &ifv->ifv_if;
889 ifv->ifv_if.if_ipackets++;
890
891 #if NBPFILTER > 0
892 if (ifv->ifv_if.if_bpf)
893 bpf_mtap(ifv->ifv_if.if_bpf, m);
894 #endif
895
896 /* Pass it back through the parent's input routine. */
897 (*ifp->if_input)(&ifv->ifv_if, m);
898 }
899