1 /* $NetBSD: if_vlan.c,v 1.57 2008/02/20 17:05:53 matt 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.57 2008/02/20 17:05:53 matt 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 uint16_t ifvm_proto; /* encapsulation ethertype */ 143 uint16_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, void *); 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 (void *) &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, CLLADDR(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, (void *) &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, void *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, CLLADDR(ifp->if_sadl), ifp->if_addrlen); 502 break; 503 504 case SIOCSIFMTU: 505 if (ifv->ifv_p == NULL) 506 error = EINVAL; 507 else if ( 508 ifr->ifr_mtu > (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) || 509 ifr->ifr_mtu < (ifv->ifv_mintu - ifv->ifv_mtufudge)) 510 error = EINVAL; 511 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 512 error = 0; 513 break; 514 515 case SIOCSETVLAN: 516 if ((error = kauth_authorize_network(l->l_cred, 517 KAUTH_NETWORK_INTERFACE, 518 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 519 NULL)) != 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 const struct sockaddr *sa = ifreq_getaddr(SIOCADDMULTI, ifr); 586 struct vlan_mc_entry *mc; 587 uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 588 int error; 589 590 if (sa->sa_len > sizeof(struct sockaddr_storage)) 591 return (EINVAL); 592 593 error = ether_addmulti(sa, &ifv->ifv_ec); 594 if (error != ENETRESET) 595 return (error); 596 597 /* 598 * This is new multicast address. We have to tell parent 599 * about it. Also, remember this multicast address so that 600 * we can delete them on unconfigure. 601 */ 602 MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry), 603 M_DEVBUF, M_NOWAIT); 604 if (mc == NULL) { 605 error = ENOMEM; 606 goto alloc_failed; 607 } 608 609 /* 610 * As ether_addmulti() returns ENETRESET, following two 611 * statement shouldn't fail. 612 */ 613 (void)ether_multiaddr(sa, addrlo, addrhi); 614 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm); 615 memcpy(&mc->mc_addr, sa, sa->sa_len); 616 LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries); 617 618 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCADDMULTI, 619 (void *)ifr); 620 if (error != 0) 621 goto ioctl_failed; 622 return (error); 623 624 ioctl_failed: 625 LIST_REMOVE(mc, mc_entries); 626 FREE(mc, M_DEVBUF); 627 alloc_failed: 628 (void)ether_delmulti(sa, &ifv->ifv_ec); 629 return (error); 630 } 631 632 static int 633 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr) 634 { 635 const struct sockaddr *sa = ifreq_getaddr(SIOCDELMULTI, ifr); 636 struct ether_multi *enm; 637 struct vlan_mc_entry *mc; 638 uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 639 int error; 640 641 /* 642 * Find a key to lookup vlan_mc_entry. We have to do this 643 * before calling ether_delmulti for obvious reason. 644 */ 645 if ((error = ether_multiaddr(sa, addrlo, addrhi)) != 0) 646 return (error); 647 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm); 648 649 error = ether_delmulti(sa, &ifv->ifv_ec); 650 if (error != ENETRESET) 651 return (error); 652 653 /* We no longer use this multicast address. Tell parent so. */ 654 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCDELMULTI, 655 (void *)ifr); 656 if (error == 0) { 657 /* And forget about this address. */ 658 for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL; 659 mc = LIST_NEXT(mc, mc_entries)) { 660 if (mc->mc_enm == enm) { 661 LIST_REMOVE(mc, mc_entries); 662 FREE(mc, M_DEVBUF); 663 break; 664 } 665 } 666 KASSERT(mc != NULL); 667 } else 668 (void)ether_addmulti(sa, &ifv->ifv_ec); 669 return (error); 670 } 671 672 /* 673 * Delete any multicast address we have asked to add from parent 674 * interface. Called when the vlan is being unconfigured. 675 */ 676 static void 677 vlan_ether_purgemulti(struct ifvlan *ifv) 678 { 679 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 680 struct vlan_mc_entry *mc; 681 union { 682 struct ifreq ifreq; 683 struct { 684 char ifr_name[IFNAMSIZ]; 685 struct sockaddr_storage ifr_ss; 686 } ifreq_storage; 687 } ifreq; 688 struct ifreq *ifr = &ifreq.ifreq; 689 690 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 691 while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) { 692 ifreq_setaddr(SIOCDELMULTI, ifr, 693 (const struct sockaddr *)&mc->mc_addr); 694 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (void *)ifr); 695 LIST_REMOVE(mc, mc_entries); 696 FREE(mc, M_DEVBUF); 697 } 698 } 699 700 static void 701 vlan_start(struct ifnet *ifp) 702 { 703 struct ifvlan *ifv = ifp->if_softc; 704 struct ifnet *p = ifv->ifv_p; 705 struct ethercom *ec = (void *) ifv->ifv_p; 706 struct mbuf *m; 707 int error; 708 ALTQ_DECL(struct altq_pktattr pktattr;) 709 710 ifp->if_flags |= IFF_OACTIVE; 711 712 for (;;) { 713 IFQ_DEQUEUE(&ifp->if_snd, m); 714 if (m == NULL) 715 break; 716 717 #ifdef ALTQ 718 /* 719 * If ALTQ is enabled on the parent interface, do 720 * classification; the queueing discipline might 721 * not require classification, but might require 722 * the address family/header pointer in the pktattr. 723 */ 724 if (ALTQ_IS_ENABLED(&p->if_snd)) { 725 switch (p->if_type) { 726 case IFT_ETHER: 727 altq_etherclassify(&p->if_snd, m, &pktattr); 728 break; 729 #ifdef DIAGNOSTIC 730 default: 731 panic("vlan_start: impossible (altq)"); 732 #endif 733 } 734 } 735 #endif /* ALTQ */ 736 737 #if NBPFILTER > 0 738 if (ifp->if_bpf) 739 bpf_mtap(ifp->if_bpf, m); 740 #endif 741 /* 742 * If the parent can insert the tag itself, just mark 743 * the tag in the mbuf header. 744 */ 745 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) { 746 struct m_tag *mtag; 747 748 mtag = m_tag_get(PACKET_TAG_VLAN, sizeof(u_int), 749 M_NOWAIT); 750 if (mtag == NULL) { 751 ifp->if_oerrors++; 752 m_freem(m); 753 continue; 754 } 755 *(u_int *)(mtag + 1) = ifv->ifv_tag; 756 m_tag_prepend(m, mtag); 757 } else { 758 /* 759 * insert the tag ourselves 760 */ 761 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 762 if (m == NULL) { 763 printf("%s: unable to prepend encap header", 764 ifv->ifv_p->if_xname); 765 ifp->if_oerrors++; 766 continue; 767 } 768 769 switch (p->if_type) { 770 case IFT_ETHER: 771 { 772 struct ether_vlan_header *evl; 773 774 if (m->m_len < sizeof(struct ether_vlan_header)) 775 m = m_pullup(m, 776 sizeof(struct ether_vlan_header)); 777 if (m == NULL) { 778 printf("%s: unable to pullup encap " 779 "header", ifv->ifv_p->if_xname); 780 ifp->if_oerrors++; 781 continue; 782 } 783 784 /* 785 * Transform the Ethernet header into an 786 * Ethernet header with 802.1Q encapsulation. 787 */ 788 memmove(mtod(m, void *), 789 mtod(m, char *) + ifv->ifv_encaplen, 790 sizeof(struct ether_header)); 791 evl = mtod(m, struct ether_vlan_header *); 792 evl->evl_proto = evl->evl_encap_proto; 793 evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 794 evl->evl_tag = htons(ifv->ifv_tag); 795 796 /* 797 * To cater for VLAN-aware layer 2 ethernet 798 * switches which may need to strip the tag 799 * before forwarding the packet, make sure 800 * the packet+tag is at least 68 bytes long. 801 * This is necessary because our parent will 802 * only pad to 64 bytes (ETHER_MIN_LEN) and 803 * some switches will not pad by themselves 804 * after deleting a tag. 805 */ 806 if (m->m_pkthdr.len < 807 (ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN)) { 808 m_copyback(m, m->m_pkthdr.len, 809 (ETHER_MIN_LEN + 810 ETHER_VLAN_ENCAP_LEN) - 811 m->m_pkthdr.len, 812 vlan_zero_pad_buff); 813 } 814 break; 815 } 816 817 #ifdef DIAGNOSTIC 818 default: 819 panic("vlan_start: impossible"); 820 #endif 821 } 822 } 823 824 /* 825 * Send it, precisely as the parent's output routine 826 * would have. We are already running at splnet. 827 */ 828 IFQ_ENQUEUE(&p->if_snd, m, &pktattr, error); 829 if (error) { 830 /* mbuf is already freed */ 831 ifp->if_oerrors++; 832 continue; 833 } 834 835 ifp->if_opackets++; 836 if ((p->if_flags & (IFF_RUNNING|IFF_OACTIVE)) == IFF_RUNNING) 837 (*p->if_start)(p); 838 } 839 840 ifp->if_flags &= ~IFF_OACTIVE; 841 } 842 843 /* 844 * Given an Ethernet frame, find a valid vlan interface corresponding to the 845 * given source interface and tag, then run the real packet through the 846 * parent's input routine. 847 */ 848 void 849 vlan_input(struct ifnet *ifp, struct mbuf *m) 850 { 851 struct ifvlan *ifv; 852 u_int tag; 853 struct m_tag *mtag; 854 855 mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL); 856 if (mtag != NULL) { 857 /* m contains a normal ethernet frame, the tag is in mtag */ 858 tag = EVL_VLANOFTAG(*(u_int *)(mtag + 1)); 859 m_tag_delete(m, mtag); 860 } else { 861 switch (ifp->if_type) { 862 case IFT_ETHER: 863 { 864 struct ether_vlan_header *evl; 865 866 if (m->m_len < sizeof(struct ether_vlan_header) && 867 (m = m_pullup(m, 868 sizeof(struct ether_vlan_header))) == NULL) { 869 printf("%s: no memory for VLAN header, " 870 "dropping packet.\n", ifp->if_xname); 871 return; 872 } 873 evl = mtod(m, struct ether_vlan_header *); 874 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN); 875 876 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag)); 877 878 /* 879 * Restore the original ethertype. We'll remove 880 * the encapsulation after we've found the vlan 881 * interface corresponding to the tag. 882 */ 883 evl->evl_encap_proto = evl->evl_proto; 884 break; 885 } 886 887 default: 888 tag = (u_int) -1; /* XXX GCC */ 889 #ifdef DIAGNOSTIC 890 panic("vlan_input: impossible"); 891 #endif 892 } 893 } 894 895 for (ifv = LIST_FIRST(&ifv_list); ifv != NULL; 896 ifv = LIST_NEXT(ifv, ifv_list)) 897 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag) 898 break; 899 900 if (ifv == NULL || 901 (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 902 (IFF_UP|IFF_RUNNING)) { 903 m_freem(m); 904 ifp->if_noproto++; 905 return; 906 } 907 908 /* 909 * Now, remove the encapsulation header. The original 910 * header has already been fixed up above. 911 */ 912 if (mtag == NULL) { 913 memmove(mtod(m, char *) + ifv->ifv_encaplen, 914 mtod(m, void *), sizeof(struct ether_header)); 915 m_adj(m, ifv->ifv_encaplen); 916 } 917 918 m->m_pkthdr.rcvif = &ifv->ifv_if; 919 ifv->ifv_if.if_ipackets++; 920 921 #if NBPFILTER > 0 922 if (ifv->ifv_if.if_bpf) 923 bpf_mtap(ifv->ifv_if.if_bpf, m); 924 #endif 925 926 /* Pass it back through the parent's input routine. */ 927 (*ifp->if_input)(&ifv->ifv_if, m); 928 } 929