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