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