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