if_vlan.c revision 152209
1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/net/if_vlan.c 152209 2005-11-08 20:08:34Z thompsa $ 30 */ 31 32/* 33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 34 * Might be extended some day to also handle IEEE 802.1p priority 35 * tagging. This is sort of sneaky in the implementation, since 36 * we need to pretend to be enough of an Ethernet implementation 37 * to make arp work. The way we do this is by telling everyone 38 * that we are an Ethernet, and then catch the packets that 39 * ether_output() left on our output queue when it calls 40 * if_start(), rewrite them for use by the real outgoing interface, 41 * and ask it to send them. 42 */ 43 44#include "opt_inet.h" 45 46#include <sys/param.h> 47#include <sys/kernel.h> 48#include <sys/malloc.h> 49#include <sys/mbuf.h> 50#include <sys/module.h> 51#include <sys/queue.h> 52#include <sys/socket.h> 53#include <sys/sockio.h> 54#include <sys/sysctl.h> 55#include <sys/systm.h> 56 57#include <net/bpf.h> 58#include <net/ethernet.h> 59#include <net/if.h> 60#include <net/if_clone.h> 61#include <net/if_arp.h> 62#include <net/if_dl.h> 63#include <net/if_types.h> 64#include <net/if_vlan_var.h> 65 66#ifdef INET 67#include <netinet/in.h> 68#include <netinet/if_ether.h> 69#endif 70 71#define VLANNAME "vlan" 72 73struct vlan_mc_entry { 74 struct ether_addr mc_addr; 75 SLIST_ENTRY(vlan_mc_entry) mc_entries; 76}; 77 78struct ifvlan { 79 struct ifnet *ifv_ifp; 80 struct ifnet *ifv_p; /* parent inteface of this vlan */ 81 int ifv_pflags; /* special flags we have set on parent */ 82 struct ifv_linkmib { 83 int ifvm_parent; 84 int ifvm_encaplen; /* encapsulation length */ 85 int ifvm_mtufudge; /* MTU fudged by this much */ 86 int ifvm_mintu; /* min transmission unit */ 87 u_int16_t ifvm_proto; /* encapsulation ethertype */ 88 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */ 89 } ifv_mib; 90 SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead; 91 LIST_ENTRY(ifvlan) ifv_list; 92}; 93#define ifv_tag ifv_mib.ifvm_tag 94#define ifv_encaplen ifv_mib.ifvm_encaplen 95#define ifv_mtufudge ifv_mib.ifvm_mtufudge 96#define ifv_mintu ifv_mib.ifvm_mintu 97 98/* Special flags we should propagate to parent */ 99static struct { 100 int flag; 101 int (*func)(struct ifnet *, int); 102} vlan_pflags[] = { 103 {IFF_PROMISC, ifpromisc}, 104 {IFF_ALLMULTI, if_allmulti}, 105 {0, NULL} 106}; 107 108SYSCTL_DECL(_net_link); 109SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 110SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 111 112static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); 113static LIST_HEAD(, ifvlan) ifv_list; 114 115/* 116 * Locking: one lock is used to guard both the ifv_list and modification 117 * to vlan data structures. We are rather conservative here; probably 118 * more than necessary. 119 */ 120static struct mtx ifv_mtx; 121#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF) 122#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx) 123#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED) 124#define VLAN_LOCK() mtx_lock(&ifv_mtx) 125#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx) 126 127static void vlan_start(struct ifnet *ifp); 128static void vlan_ifinit(void *foo); 129static void vlan_input(struct ifnet *ifp, struct mbuf *m); 130static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 131static int vlan_setflag(struct ifnet *ifp, int flag, int status, 132 int (*func)(struct ifnet *, int)); 133static int vlan_setflags(struct ifnet *ifp, int status); 134static int vlan_setmulti(struct ifnet *ifp); 135static int vlan_unconfig(struct ifnet *ifp); 136static int vlan_config(struct ifvlan *ifv, struct ifnet *p); 137static void vlan_link_state(struct ifnet *ifp, int link); 138 139static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, 140 const char *, int *); 141static int vlan_clone_match(struct if_clone *, const char *); 142static int vlan_clone_create(struct if_clone *, char *, size_t); 143static int vlan_clone_destroy(struct if_clone *, struct ifnet *); 144 145static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, 146 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy); 147 148/* 149 * Program our multicast filter. What we're actually doing is 150 * programming the multicast filter of the parent. This has the 151 * side effect of causing the parent interface to receive multicast 152 * traffic that it doesn't really want, which ends up being discarded 153 * later by the upper protocol layers. Unfortunately, there's no way 154 * to avoid this: there really is only one physical interface. 155 * 156 * XXX: There is a possible race here if more than one thread is 157 * modifying the multicast state of the vlan interface at the same time. 158 */ 159static int 160vlan_setmulti(struct ifnet *ifp) 161{ 162 struct ifnet *ifp_p; 163 struct ifmultiaddr *ifma, *rifma = NULL; 164 struct ifvlan *sc; 165 struct vlan_mc_entry *mc = NULL; 166 struct sockaddr_dl sdl; 167 int error; 168 169 /*VLAN_LOCK_ASSERT();*/ 170 171 /* Find the parent. */ 172 sc = ifp->if_softc; 173 ifp_p = sc->ifv_p; 174 175 /* 176 * If we don't have a parent, just remember the membership for 177 * when we do. 178 */ 179 if (ifp_p == NULL) 180 return (0); 181 182 bzero((char *)&sdl, sizeof(sdl)); 183 sdl.sdl_len = sizeof(sdl); 184 sdl.sdl_family = AF_LINK; 185 sdl.sdl_index = ifp_p->if_index; 186 sdl.sdl_type = IFT_ETHER; 187 sdl.sdl_alen = ETHER_ADDR_LEN; 188 189 /* First, remove any existing filter entries. */ 190 while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) { 191 mc = SLIST_FIRST(&sc->vlan_mc_listhead); 192 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN); 193 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl); 194 if (error) 195 return (error); 196 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); 197 free(mc, M_VLAN); 198 } 199 200 /* Now program new ones. */ 201 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 202 if (ifma->ifma_addr->sa_family != AF_LINK) 203 continue; 204 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT); 205 if (mc == NULL) 206 return (ENOMEM); 207 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 208 (char *)&mc->mc_addr, ETHER_ADDR_LEN); 209 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); 210 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 211 LLADDR(&sdl), ETHER_ADDR_LEN); 212 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma); 213 if (error) 214 return (error); 215 } 216 217 return (0); 218} 219 220/* 221 * VLAN support can be loaded as a module. The only place in the 222 * system that's intimately aware of this is ether_input. We hook 223 * into this code through vlan_input_p which is defined there and 224 * set here. Noone else in the system should be aware of this so 225 * we use an explicit reference here. 226 * 227 * NB: Noone should ever need to check if vlan_input_p is null or 228 * not. This is because interfaces have a count of the number 229 * of active vlans (if_nvlans) and this should never be bumped 230 * except by vlan_config--which is in this module so therefore 231 * the module must be loaded and vlan_input_p must be non-NULL. 232 */ 233extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); 234 235/* For if_link_state_change() eyes only... */ 236extern void (*vlan_link_state_p)(struct ifnet *, int); 237 238static int 239vlan_modevent(module_t mod, int type, void *data) 240{ 241 242 switch (type) { 243 case MOD_LOAD: 244 LIST_INIT(&ifv_list); 245 VLAN_LOCK_INIT(); 246 vlan_input_p = vlan_input; 247 vlan_link_state_p = vlan_link_state; 248 if_clone_attach(&vlan_cloner); 249 break; 250 case MOD_UNLOAD: 251 if_clone_detach(&vlan_cloner); 252 vlan_input_p = NULL; 253 vlan_link_state_p = NULL; 254 VLAN_LOCK_DESTROY(); 255 break; 256 default: 257 return (EOPNOTSUPP); 258 } 259 return (0); 260} 261 262static moduledata_t vlan_mod = { 263 "if_vlan", 264 vlan_modevent, 265 0 266}; 267 268DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 269MODULE_DEPEND(if_vlan, miibus, 1, 1, 1); 270 271static struct ifnet * 272vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag) 273{ 274 const char *cp; 275 struct ifnet *ifp; 276 int t = 0; 277 278 /* Check for <etherif>.<vlan> style interface names. */ 279 IFNET_RLOCK(); 280 TAILQ_FOREACH(ifp, &ifnet, if_link) { 281 if (ifp->if_type != IFT_ETHER) 282 continue; 283 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0) 284 continue; 285 cp = name + strlen(ifp->if_xname); 286 if (*cp != '.') 287 continue; 288 for(; *cp != '\0'; cp++) { 289 if (*cp < '0' || *cp > '9') 290 continue; 291 t = (t * 10) + (*cp - '0'); 292 } 293 if (tag != NULL) 294 *tag = t; 295 break; 296 } 297 IFNET_RUNLOCK(); 298 299 return (ifp); 300} 301 302static int 303vlan_clone_match(struct if_clone *ifc, const char *name) 304{ 305 const char *cp; 306 307 if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL) 308 return (1); 309 310 if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0) 311 return (0); 312 for (cp = name + 4; *cp != '\0'; cp++) { 313 if (*cp < '0' || *cp > '9') 314 return (0); 315 } 316 317 return (1); 318} 319 320static int 321vlan_clone_create(struct if_clone *ifc, char *name, size_t len) 322{ 323 char *dp; 324 int wildcard; 325 int unit; 326 int error; 327 int tag; 328 int ethertag; 329 struct ifvlan *ifv; 330 struct ifnet *ifp; 331 struct ifnet *p; 332 u_char eaddr[6] = {0,0,0,0,0,0}; 333 334 if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) { 335 ethertag = 1; 336 unit = -1; 337 wildcard = 0; 338 339 /* 340 * Don't let the caller set up a VLAN tag with 341 * anything except VLID bits. 342 */ 343 if (tag & ~EVL_VLID_MASK) 344 return (EINVAL); 345 } else { 346 ethertag = 0; 347 348 error = ifc_name2unit(name, &unit); 349 if (error != 0) 350 return (error); 351 352 wildcard = (unit < 0); 353 } 354 355 error = ifc_alloc_unit(ifc, &unit); 356 if (error != 0) 357 return (error); 358 359 /* In the wildcard case, we need to update the name. */ 360 if (wildcard) { 361 for (dp = name; *dp != '\0'; dp++); 362 if (snprintf(dp, len - (dp-name), "%d", unit) > 363 len - (dp-name) - 1) { 364 panic("%s: interface name too long", __func__); 365 } 366 } 367 368 ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO); 369 ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER); 370 if (ifp == NULL) { 371 ifc_free_unit(ifc, unit); 372 free(ifv, M_VLAN); 373 return (ENOSPC); 374 } 375 SLIST_INIT(&ifv->vlan_mc_listhead); 376 377 ifp->if_softc = ifv; 378 /* 379 * Set the name manually rather than using if_initname because 380 * we don't conform to the default naming convention for interfaces. 381 */ 382 strlcpy(ifp->if_xname, name, IFNAMSIZ); 383 ifp->if_dname = ifc->ifc_name; 384 ifp->if_dunit = unit; 385 /* NB: flags are not set here */ 386 ifp->if_linkmib = &ifv->ifv_mib; 387 ifp->if_linkmiblen = sizeof(ifv->ifv_mib); 388 /* NB: mtu is not set here */ 389 390 ifp->if_init = vlan_ifinit; 391 ifp->if_start = vlan_start; 392 ifp->if_ioctl = vlan_ioctl; 393 ifp->if_snd.ifq_maxlen = ifqmaxlen; 394 ether_ifattach(ifp, eaddr); 395 /* Now undo some of the damage... */ 396 ifp->if_baudrate = 0; 397 ifp->if_type = IFT_L2VLAN; 398 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN; 399 400 VLAN_LOCK(); 401 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list); 402 VLAN_UNLOCK(); 403 404 if (ethertag) { 405 VLAN_LOCK(); 406 error = vlan_config(ifv, p); 407 if (error != 0) { 408 /* 409 * Since we've partialy failed, we need to back 410 * out all the way, otherwise userland could get 411 * confused. Thus, we destroy the interface. 412 */ 413 LIST_REMOVE(ifv, ifv_list); 414 vlan_unconfig(ifp); 415 VLAN_UNLOCK(); 416 ether_ifdetach(ifp); 417 if_free_type(ifp, IFT_ETHER); 418 free(ifv, M_VLAN); 419 420 return (error); 421 } 422 ifv->ifv_tag = tag; 423 ifp->if_drv_flags |= IFF_DRV_RUNNING; 424 VLAN_UNLOCK(); 425 426 /* Update flags on the parent, if necessary. */ 427 vlan_setflags(ifp, 1); 428 } 429 430 return (0); 431} 432 433static int 434vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 435{ 436 int unit; 437 struct ifvlan *ifv = ifp->if_softc; 438 439 unit = ifp->if_dunit; 440 441 VLAN_LOCK(); 442 LIST_REMOVE(ifv, ifv_list); 443 vlan_unconfig(ifp); 444 VLAN_UNLOCK(); 445 446 ether_ifdetach(ifp); 447 if_free_type(ifp, IFT_ETHER); 448 449 free(ifv, M_VLAN); 450 451 ifc_free_unit(ifc, unit); 452 453 return (0); 454} 455 456/* 457 * The ifp->if_init entry point for vlan(4) is a no-op. 458 */ 459static void 460vlan_ifinit(void *foo) 461{ 462 463} 464 465/* 466 * The if_start method for vlan(4) interface. It doesn't 467 * raises the IFF_DRV_OACTIVE flag, since it is called 468 * only from IFQ_HANDOFF() macro in ether_output_frame(). 469 * If the interface queue is full, and vlan_start() is 470 * not called, the queue would never get emptied and 471 * interface would stall forever. 472 */ 473static void 474vlan_start(struct ifnet *ifp) 475{ 476 struct ifvlan *ifv; 477 struct ifnet *p; 478 struct ether_vlan_header *evl; 479 struct mbuf *m; 480 int error; 481 482 ifv = ifp->if_softc; 483 p = ifv->ifv_p; 484 485 for (;;) { 486 IF_DEQUEUE(&ifp->if_snd, m); 487 if (m == 0) 488 break; 489 BPF_MTAP(ifp, m); 490 491 /* 492 * Do not run parent's if_start() if the parent is not up, 493 * or parent's driver will cause a system crash. 494 */ 495 if (!((p->if_flags & IFF_UP) && 496 (p->if_drv_flags & IFF_DRV_RUNNING))) { 497 m_freem(m); 498 ifp->if_collisions++; 499 continue; 500 } 501 502 /* 503 * If underlying interface can do VLAN tag insertion itself, 504 * just pass the packet along. However, we need some way to 505 * tell the interface where the packet came from so that it 506 * knows how to find the VLAN tag to use, so we attach a 507 * packet tag that holds it. 508 */ 509 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { 510 struct m_tag *mtag = m_tag_alloc(MTAG_VLAN, 511 MTAG_VLAN_TAG, 512 sizeof(u_int), 513 M_NOWAIT); 514 if (mtag == NULL) { 515 ifp->if_oerrors++; 516 m_freem(m); 517 continue; 518 } 519 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag; 520 m_tag_prepend(m, mtag); 521 m->m_flags |= M_VLANTAG; 522 } else { 523 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 524 if (m == NULL) { 525 if_printf(ifp, 526 "unable to prepend VLAN header\n"); 527 ifp->if_oerrors++; 528 continue; 529 } 530 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ 531 532 if (m->m_len < sizeof(*evl)) { 533 m = m_pullup(m, sizeof(*evl)); 534 if (m == NULL) { 535 if_printf(ifp, 536 "cannot pullup VLAN header\n"); 537 ifp->if_oerrors++; 538 continue; 539 } 540 } 541 542 /* 543 * Transform the Ethernet header into an Ethernet header 544 * with 802.1Q encapsulation. 545 */ 546 bcopy(mtod(m, char *) + ifv->ifv_encaplen, 547 mtod(m, char *), ETHER_HDR_LEN); 548 evl = mtod(m, struct ether_vlan_header *); 549 evl->evl_proto = evl->evl_encap_proto; 550 evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 551 evl->evl_tag = htons(ifv->ifv_tag); 552#ifdef DEBUG 553 printf("%s: %*D\n", __func__, (int)sizeof(*evl), 554 (unsigned char *)evl, ":"); 555#endif 556 } 557 558 /* 559 * Send it, precisely as ether_output() would have. 560 * We are already running at splimp. 561 */ 562 IFQ_HANDOFF(p, m, error); 563 if (!error) 564 ifp->if_opackets++; 565 else 566 ifp->if_oerrors++; 567 } 568} 569 570static void 571vlan_input(struct ifnet *ifp, struct mbuf *m) 572{ 573 struct ether_vlan_header *evl; 574 struct ifvlan *ifv; 575 struct m_tag *mtag; 576 u_int tag; 577 578 if (m->m_flags & M_VLANTAG) { 579 /* 580 * Packet is tagged, but m contains a normal 581 * Ethernet frame; the tag is stored out-of-band. 582 */ 583 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL); 584 KASSERT(mtag != NULL, 585 ("%s: M_VLANTAG without m_tag", __func__)); 586 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)); 587 m_tag_delete(m, mtag); 588 m->m_flags &= ~M_VLANTAG; 589 } else { 590 /* 591 * Packet is tagged in-band as specified by 802.1q. 592 */ 593 mtag = NULL; 594 switch (ifp->if_type) { 595 case IFT_ETHER: 596 if (m->m_len < sizeof(*evl) && 597 (m = m_pullup(m, sizeof(*evl))) == NULL) { 598 if_printf(ifp, "cannot pullup VLAN header\n"); 599 return; 600 } 601 evl = mtod(m, struct ether_vlan_header *); 602 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN, 603 ("%s: bad encapsulation protocol (%u)", 604 __func__, ntohs(evl->evl_encap_proto))); 605 606 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag)); 607 608 /* 609 * Restore the original ethertype. We'll remove 610 * the encapsulation after we've found the vlan 611 * interface corresponding to the tag. 612 */ 613 evl->evl_encap_proto = evl->evl_proto; 614 break; 615 default: 616 tag = (u_int) -1; 617#ifdef INVARIANTS 618 panic("%s: unsupported if_type (%u)", 619 __func__, ifp->if_type); 620#endif 621 break; 622 } 623 } 624 625 VLAN_LOCK(); 626 LIST_FOREACH(ifv, &ifv_list, ifv_list) 627 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag) 628 break; 629 630 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { 631 VLAN_UNLOCK(); 632 m_freem(m); 633 ifp->if_noproto++; 634#ifdef DEBUG 635 printf("%s: tag %d, no interface\n", __func__, tag); 636#endif 637 return; 638 } 639 VLAN_UNLOCK(); /* XXX extend below? */ 640#ifdef DEBUG 641 printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname); 642#endif 643 644 if (mtag == NULL) { 645 /* 646 * Packet had an in-line encapsulation header; 647 * remove it. The original header has already 648 * been fixed up above. 649 */ 650 bcopy(mtod(m, caddr_t), 651 mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN, 652 ETHER_HDR_LEN); 653 m_adj(m, ETHER_VLAN_ENCAP_LEN); 654 } 655 656 m->m_pkthdr.rcvif = ifv->ifv_ifp; 657 ifv->ifv_ifp->if_ipackets++; 658 659 /* Pass it back through the parent's input routine. */ 660 (*ifp->if_input)(ifv->ifv_ifp, m); 661} 662 663static int 664vlan_config(struct ifvlan *ifv, struct ifnet *p) 665{ 666 struct ifaddr *ifa1, *ifa2; 667 struct ifnet *ifp; 668 struct sockaddr_dl *sdl1, *sdl2; 669 670 VLAN_LOCK_ASSERT(); 671 672 if (p->if_type != IFT_ETHER) 673 return (EPROTONOSUPPORT); 674 if (ifv->ifv_p) 675 return (EBUSY); 676 677 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 678 ifv->ifv_mintu = ETHERMIN; 679 ifv->ifv_pflags = 0; 680 681 /* 682 * The active VLAN counter on the parent is used 683 * at various places to see if there is a vlan(4) 684 * attached to this physical interface. 685 */ 686 p->if_nvlans++; 687 688 /* 689 * If the parent supports the VLAN_MTU capability, 690 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 691 * use it. 692 */ 693 if (p->if_capenable & IFCAP_VLAN_MTU) { 694 /* 695 * No need to fudge the MTU since the parent can 696 * handle extended frames. 697 */ 698 ifv->ifv_mtufudge = 0; 699 } else { 700 /* 701 * Fudge the MTU by the encapsulation size. This 702 * makes us incompatible with strictly compliant 703 * 802.1Q implementations, but allows us to use 704 * the feature with other NetBSD implementations, 705 * which might still be useful. 706 */ 707 ifv->ifv_mtufudge = ifv->ifv_encaplen; 708 } 709 710 ifv->ifv_p = p; 711 ifp = ifv->ifv_ifp; 712 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge; 713 /* 714 * Copy only a selected subset of flags from the parent. 715 * Other flags are none of our business. 716 */ 717#define VLAN_COPY_FLAGS \ 718 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT) 719 ifp->if_flags &= ~VLAN_COPY_FLAGS; 720 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; 721#undef VLAN_COPY_FLAGS 722 723 ifp->if_link_state = p->if_link_state; 724 725#if 0 726 /* 727 * Not ready yet. We need notification from the parent 728 * when hw checksumming flags in its if_capenable change. 729 * Flags set in if_capabilities only are useless. 730 */ 731 /* 732 * If the parent interface can do hardware-assisted 733 * VLAN encapsulation, then propagate its hardware- 734 * assisted checksumming flags. 735 */ 736 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 737 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM; 738#endif 739 740 /* 741 * Set up our ``Ethernet address'' to reflect the underlying 742 * physical interface's. 743 */ 744 ifa1 = ifaddr_byindex(ifp->if_index); 745 ifa2 = ifaddr_byindex(p->if_index); 746 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 747 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 748 sdl1->sdl_type = IFT_ETHER; 749 sdl1->sdl_alen = ETHER_ADDR_LEN; 750 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 751 bcopy(LLADDR(sdl2), IFP2ENADDR(ifp), ETHER_ADDR_LEN); 752 753 /* 754 * Configure multicast addresses that may already be 755 * joined on the vlan device. 756 */ 757 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ 758 759 return (0); 760} 761 762static int 763vlan_unconfig(struct ifnet *ifp) 764{ 765 struct ifaddr *ifa; 766 struct sockaddr_dl *sdl; 767 struct vlan_mc_entry *mc; 768 struct ifvlan *ifv; 769 struct ifnet *p; 770 int error; 771 772 VLAN_LOCK_ASSERT(); 773 774 ifv = ifp->if_softc; 775 p = ifv->ifv_p; 776 777 if (p) { 778 struct sockaddr_dl sdl; 779 780 /* 781 * Since the interface is being unconfigured, we need to 782 * empty the list of multicast groups that we may have joined 783 * while we were alive from the parent's list. 784 */ 785 bzero((char *)&sdl, sizeof(sdl)); 786 sdl.sdl_len = sizeof(sdl); 787 sdl.sdl_family = AF_LINK; 788 sdl.sdl_index = p->if_index; 789 sdl.sdl_type = IFT_ETHER; 790 sdl.sdl_alen = ETHER_ADDR_LEN; 791 792 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) { 793 mc = SLIST_FIRST(&ifv->vlan_mc_listhead); 794 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), 795 ETHER_ADDR_LEN); 796 error = if_delmulti(p, (struct sockaddr *)&sdl); 797 if (error) 798 return (error); 799 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 800 free(mc, M_VLAN); 801 } 802 803 vlan_setflags(ifp, 0); /* clear special flags on parent */ 804 p->if_nvlans--; 805 } 806 807 /* Disconnect from parent. */ 808 if (ifv->ifv_pflags) 809 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__); 810 ifv->ifv_p = NULL; 811 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */ 812 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN; 813 814 /* Clear our MAC address. */ 815 ifa = ifaddr_byindex(ifv->ifv_ifp->if_index); 816 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 817 sdl->sdl_type = IFT_ETHER; 818 sdl->sdl_alen = ETHER_ADDR_LEN; 819 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 820 bzero(IFP2ENADDR(ifv->ifv_ifp), ETHER_ADDR_LEN); 821 822 return (0); 823} 824 825/* Handle a reference counted flag that should be set on the parent as well */ 826static int 827vlan_setflag(struct ifnet *ifp, int flag, int status, 828 int (*func)(struct ifnet *, int)) 829{ 830 struct ifvlan *ifv; 831 int error; 832 833 /* XXX VLAN_LOCK_ASSERT(); */ 834 835 ifv = ifp->if_softc; 836 status = status ? (ifp->if_flags & flag) : 0; 837 /* Now "status" contains the flag value or 0 */ 838 839 /* 840 * See if recorded parent's status is different from what 841 * we want it to be. If it is, flip it. We record parent's 842 * status in ifv_pflags so that we won't clear parent's flag 843 * we haven't set. In fact, we don't clear or set parent's 844 * flags directly, but get or release references to them. 845 * That's why we can be sure that recorded flags still are 846 * in accord with actual parent's flags. 847 */ 848 if (status != (ifv->ifv_pflags & flag)) { 849 error = (*func)(ifv->ifv_p, status); 850 if (error) 851 return (error); 852 ifv->ifv_pflags &= ~flag; 853 ifv->ifv_pflags |= status; 854 } 855 return (0); 856} 857 858/* 859 * Handle IFF_* flags that require certain changes on the parent: 860 * if "status" is true, update parent's flags respective to our if_flags; 861 * if "status" is false, forcedly clear the flags set on parent. 862 */ 863static int 864vlan_setflags(struct ifnet *ifp, int status) 865{ 866 int error, i; 867 868 for (i = 0; vlan_pflags[i].flag; i++) { 869 error = vlan_setflag(ifp, vlan_pflags[i].flag, 870 status, vlan_pflags[i].func); 871 if (error) 872 return (error); 873 } 874 return (0); 875} 876 877/* Inform all vlans that their parent has changed link state */ 878static void 879vlan_link_state(struct ifnet *ifp, int link) 880{ 881 struct ifvlan *ifv; 882 883 VLAN_LOCK(); 884 LIST_FOREACH(ifv, &ifv_list, ifv_list) { 885 if (ifv->ifv_p == ifp) 886 if_link_state_change(ifv->ifv_ifp, 887 ifv->ifv_p->if_link_state); 888 } 889 VLAN_UNLOCK(); 890} 891 892static int 893vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 894{ 895 struct ifaddr *ifa; 896 struct ifnet *p; 897 struct ifreq *ifr; 898 struct ifvlan *ifv; 899 struct vlanreq vlr; 900 int error = 0; 901 902 ifr = (struct ifreq *)data; 903 ifa = (struct ifaddr *)data; 904 ifv = ifp->if_softc; 905 906 switch (cmd) { 907 case SIOCSIFADDR: 908 ifp->if_flags |= IFF_UP; 909 910 switch (ifa->ifa_addr->sa_family) { 911#ifdef INET 912 case AF_INET: 913 arp_ifinit(ifv->ifv_ifp, ifa); 914 break; 915#endif 916 default: 917 break; 918 } 919 break; 920 921 case SIOCGIFADDR: 922 { 923 struct sockaddr *sa; 924 925 sa = (struct sockaddr *) &ifr->ifr_data; 926 bcopy(IFP2ENADDR(ifp), (caddr_t)sa->sa_data, 927 ETHER_ADDR_LEN); 928 } 929 break; 930 931 case SIOCGIFMEDIA: 932 VLAN_LOCK(); 933 if (ifv->ifv_p != NULL) { 934 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, 935 SIOCGIFMEDIA, data); 936 VLAN_UNLOCK(); 937 /* Limit the result to the parent's current config. */ 938 if (error == 0) { 939 struct ifmediareq *ifmr; 940 941 ifmr = (struct ifmediareq *)data; 942 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { 943 ifmr->ifm_count = 1; 944 error = copyout(&ifmr->ifm_current, 945 ifmr->ifm_ulist, 946 sizeof(int)); 947 } 948 } 949 } else { 950 VLAN_UNLOCK(); 951 error = EINVAL; 952 } 953 break; 954 955 case SIOCSIFMEDIA: 956 error = EINVAL; 957 break; 958 959 case SIOCSIFMTU: 960 /* 961 * Set the interface MTU. 962 */ 963 VLAN_LOCK(); 964 if (ifv->ifv_p != NULL) { 965 if (ifr->ifr_mtu > 966 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) || 967 ifr->ifr_mtu < 968 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 969 error = EINVAL; 970 else 971 ifp->if_mtu = ifr->ifr_mtu; 972 } else 973 error = EINVAL; 974 VLAN_UNLOCK(); 975 break; 976 977 case SIOCSETVLAN: 978 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); 979 if (error) 980 break; 981 if (vlr.vlr_parent[0] == '\0') { 982 VLAN_LOCK(); 983 vlan_unconfig(ifp); 984 if (ifp->if_flags & IFF_UP) 985 if_down(ifp); 986 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 987 VLAN_UNLOCK(); 988 break; 989 } 990 p = ifunit(vlr.vlr_parent); 991 if (p == 0) { 992 error = ENOENT; 993 break; 994 } 995 /* 996 * Don't let the caller set up a VLAN tag with 997 * anything except VLID bits. 998 */ 999 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 1000 error = EINVAL; 1001 break; 1002 } 1003 VLAN_LOCK(); 1004 error = vlan_config(ifv, p); 1005 if (error) { 1006 VLAN_UNLOCK(); 1007 break; 1008 } 1009 ifv->ifv_tag = vlr.vlr_tag; 1010 ifp->if_drv_flags |= IFF_DRV_RUNNING; 1011 VLAN_UNLOCK(); 1012 1013 /* Update flags on the parent, if necessary. */ 1014 vlan_setflags(ifp, 1); 1015 break; 1016 1017 case SIOCGETVLAN: 1018 bzero(&vlr, sizeof(vlr)); 1019 VLAN_LOCK(); 1020 if (ifv->ifv_p) { 1021 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname, 1022 sizeof(vlr.vlr_parent)); 1023 vlr.vlr_tag = ifv->ifv_tag; 1024 } 1025 VLAN_UNLOCK(); 1026 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 1027 break; 1028 1029 case SIOCSIFFLAGS: 1030 /* 1031 * We should propagate selected flags to the parent, 1032 * e.g., promiscuous mode. 1033 */ 1034 if (ifv->ifv_p != NULL) 1035 error = vlan_setflags(ifp, 1); 1036 break; 1037 1038 case SIOCADDMULTI: 1039 case SIOCDELMULTI: 1040 /*VLAN_LOCK();*/ 1041 error = vlan_setmulti(ifp); 1042 /*VLAN_UNLOCK();*/ 1043 break; 1044 default: 1045 error = EINVAL; 1046 } 1047 1048 return (error); 1049} 1050