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