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