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