1 /* $NetBSD: if_vlan.c,v 1.34 2002/06/11 06:00:57 pooka 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.34 2002/06/11 06:00:57 pooka 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 from 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 ourselves 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 splnet. 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