if_vlan.c revision 152296
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 152296 2005-11-11 07:36:14Z ru $ 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 ifnet *ifp; 667 668 VLAN_LOCK_ASSERT(); 669 670 if (p->if_type != IFT_ETHER) 671 return (EPROTONOSUPPORT); 672 if (ifv->ifv_p) 673 return (EBUSY); 674 675 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 676 ifv->ifv_mintu = ETHERMIN; 677 ifv->ifv_pflags = 0; 678 679 /* 680 * The active VLAN counter on the parent is used 681 * at various places to see if there is a vlan(4) 682 * attached to this physical interface. 683 */ 684 p->if_nvlans++; 685 686 /* 687 * If the parent supports the VLAN_MTU capability, 688 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 689 * use it. 690 */ 691 if (p->if_capenable & IFCAP_VLAN_MTU) { 692 /* 693 * No need to fudge the MTU since the parent can 694 * handle extended frames. 695 */ 696 ifv->ifv_mtufudge = 0; 697 } else { 698 /* 699 * Fudge the MTU by the encapsulation size. This 700 * makes us incompatible with strictly compliant 701 * 802.1Q implementations, but allows us to use 702 * the feature with other NetBSD implementations, 703 * which might still be useful. 704 */ 705 ifv->ifv_mtufudge = ifv->ifv_encaplen; 706 } 707 708 ifv->ifv_p = p; 709 ifp = ifv->ifv_ifp; 710 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge; 711 /* 712 * Copy only a selected subset of flags from the parent. 713 * Other flags are none of our business. 714 */ 715#define VLAN_COPY_FLAGS \ 716 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT) 717 ifp->if_flags &= ~VLAN_COPY_FLAGS; 718 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; 719#undef VLAN_COPY_FLAGS 720 721 ifp->if_link_state = p->if_link_state; 722 723#if 0 724 /* 725 * Not ready yet. We need notification from the parent 726 * when hw checksumming flags in its if_capenable change. 727 * Flags set in if_capabilities only are useless. 728 */ 729 /* 730 * If the parent interface can do hardware-assisted 731 * VLAN encapsulation, then propagate its hardware- 732 * assisted checksumming flags. 733 */ 734 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 735 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM; 736#endif 737 738 /* 739 * Set up our ``Ethernet address'' to reflect the underlying 740 * physical interface's. 741 */ 742 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN); 743 744 /* 745 * Configure multicast addresses that may already be 746 * joined on the vlan device. 747 */ 748 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ 749 750 return (0); 751} 752 753static int 754vlan_unconfig(struct ifnet *ifp) 755{ 756 struct vlan_mc_entry *mc; 757 struct ifvlan *ifv; 758 struct ifnet *p; 759 int error; 760 761 VLAN_LOCK_ASSERT(); 762 763 ifv = ifp->if_softc; 764 p = ifv->ifv_p; 765 766 if (p) { 767 struct sockaddr_dl sdl; 768 769 /* 770 * Since the interface is being unconfigured, we need to 771 * empty the list of multicast groups that we may have joined 772 * while we were alive from the parent's list. 773 */ 774 bzero((char *)&sdl, sizeof(sdl)); 775 sdl.sdl_len = sizeof(sdl); 776 sdl.sdl_family = AF_LINK; 777 sdl.sdl_index = p->if_index; 778 sdl.sdl_type = IFT_ETHER; 779 sdl.sdl_alen = ETHER_ADDR_LEN; 780 781 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) { 782 mc = SLIST_FIRST(&ifv->vlan_mc_listhead); 783 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), 784 ETHER_ADDR_LEN); 785 error = if_delmulti(p, (struct sockaddr *)&sdl); 786 if (error) 787 return (error); 788 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 789 free(mc, M_VLAN); 790 } 791 792 vlan_setflags(ifp, 0); /* clear special flags on parent */ 793 p->if_nvlans--; 794 } 795 796 /* Disconnect from parent. */ 797 if (ifv->ifv_pflags) 798 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__); 799 ifv->ifv_p = NULL; 800 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */ 801 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN; 802 803 /* Clear our MAC address. */ 804 bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN); 805 806 return (0); 807} 808 809/* Handle a reference counted flag that should be set on the parent as well */ 810static int 811vlan_setflag(struct ifnet *ifp, int flag, int status, 812 int (*func)(struct ifnet *, int)) 813{ 814 struct ifvlan *ifv; 815 int error; 816 817 /* XXX VLAN_LOCK_ASSERT(); */ 818 819 ifv = ifp->if_softc; 820 status = status ? (ifp->if_flags & flag) : 0; 821 /* Now "status" contains the flag value or 0 */ 822 823 /* 824 * See if recorded parent's status is different from what 825 * we want it to be. If it is, flip it. We record parent's 826 * status in ifv_pflags so that we won't clear parent's flag 827 * we haven't set. In fact, we don't clear or set parent's 828 * flags directly, but get or release references to them. 829 * That's why we can be sure that recorded flags still are 830 * in accord with actual parent's flags. 831 */ 832 if (status != (ifv->ifv_pflags & flag)) { 833 error = (*func)(ifv->ifv_p, status); 834 if (error) 835 return (error); 836 ifv->ifv_pflags &= ~flag; 837 ifv->ifv_pflags |= status; 838 } 839 return (0); 840} 841 842/* 843 * Handle IFF_* flags that require certain changes on the parent: 844 * if "status" is true, update parent's flags respective to our if_flags; 845 * if "status" is false, forcedly clear the flags set on parent. 846 */ 847static int 848vlan_setflags(struct ifnet *ifp, int status) 849{ 850 int error, i; 851 852 for (i = 0; vlan_pflags[i].flag; i++) { 853 error = vlan_setflag(ifp, vlan_pflags[i].flag, 854 status, vlan_pflags[i].func); 855 if (error) 856 return (error); 857 } 858 return (0); 859} 860 861/* Inform all vlans that their parent has changed link state */ 862static void 863vlan_link_state(struct ifnet *ifp, int link) 864{ 865 struct ifvlan *ifv; 866 867 VLAN_LOCK(); 868 LIST_FOREACH(ifv, &ifv_list, ifv_list) { 869 if (ifv->ifv_p == ifp) 870 if_link_state_change(ifv->ifv_ifp, 871 ifv->ifv_p->if_link_state); 872 } 873 VLAN_UNLOCK(); 874} 875 876static int 877vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 878{ 879 struct ifaddr *ifa; 880 struct ifnet *p; 881 struct ifreq *ifr; 882 struct ifvlan *ifv; 883 struct vlanreq vlr; 884 int error = 0; 885 886 ifr = (struct ifreq *)data; 887 ifa = (struct ifaddr *)data; 888 ifv = ifp->if_softc; 889 890 switch (cmd) { 891 case SIOCSIFADDR: 892 ifp->if_flags |= IFF_UP; 893 894 switch (ifa->ifa_addr->sa_family) { 895#ifdef INET 896 case AF_INET: 897 arp_ifinit(ifv->ifv_ifp, ifa); 898 break; 899#endif 900 default: 901 break; 902 } 903 break; 904 905 case SIOCGIFADDR: 906 { 907 struct sockaddr *sa; 908 909 sa = (struct sockaddr *) &ifr->ifr_data; 910 bcopy(IFP2ENADDR(ifp), (caddr_t)sa->sa_data, 911 ETHER_ADDR_LEN); 912 } 913 break; 914 915 case SIOCGIFMEDIA: 916 VLAN_LOCK(); 917 if (ifv->ifv_p != NULL) { 918 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, 919 SIOCGIFMEDIA, data); 920 VLAN_UNLOCK(); 921 /* Limit the result to the parent's current config. */ 922 if (error == 0) { 923 struct ifmediareq *ifmr; 924 925 ifmr = (struct ifmediareq *)data; 926 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { 927 ifmr->ifm_count = 1; 928 error = copyout(&ifmr->ifm_current, 929 ifmr->ifm_ulist, 930 sizeof(int)); 931 } 932 } 933 } else { 934 VLAN_UNLOCK(); 935 error = EINVAL; 936 } 937 break; 938 939 case SIOCSIFMEDIA: 940 error = EINVAL; 941 break; 942 943 case SIOCSIFMTU: 944 /* 945 * Set the interface MTU. 946 */ 947 VLAN_LOCK(); 948 if (ifv->ifv_p != NULL) { 949 if (ifr->ifr_mtu > 950 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) || 951 ifr->ifr_mtu < 952 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 953 error = EINVAL; 954 else 955 ifp->if_mtu = ifr->ifr_mtu; 956 } else 957 error = EINVAL; 958 VLAN_UNLOCK(); 959 break; 960 961 case SIOCSETVLAN: 962 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); 963 if (error) 964 break; 965 if (vlr.vlr_parent[0] == '\0') { 966 VLAN_LOCK(); 967 vlan_unconfig(ifp); 968 if (ifp->if_flags & IFF_UP) 969 if_down(ifp); 970 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 971 VLAN_UNLOCK(); 972 break; 973 } 974 p = ifunit(vlr.vlr_parent); 975 if (p == 0) { 976 error = ENOENT; 977 break; 978 } 979 /* 980 * Don't let the caller set up a VLAN tag with 981 * anything except VLID bits. 982 */ 983 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 984 error = EINVAL; 985 break; 986 } 987 VLAN_LOCK(); 988 error = vlan_config(ifv, p); 989 if (error) { 990 VLAN_UNLOCK(); 991 break; 992 } 993 ifv->ifv_tag = vlr.vlr_tag; 994 ifp->if_drv_flags |= IFF_DRV_RUNNING; 995 VLAN_UNLOCK(); 996 997 /* Update flags on the parent, if necessary. */ 998 vlan_setflags(ifp, 1); 999 break; 1000 1001 case SIOCGETVLAN: 1002 bzero(&vlr, sizeof(vlr)); 1003 VLAN_LOCK(); 1004 if (ifv->ifv_p) { 1005 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname, 1006 sizeof(vlr.vlr_parent)); 1007 vlr.vlr_tag = ifv->ifv_tag; 1008 } 1009 VLAN_UNLOCK(); 1010 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 1011 break; 1012 1013 case SIOCSIFFLAGS: 1014 /* 1015 * We should propagate selected flags to the parent, 1016 * e.g., promiscuous mode. 1017 */ 1018 if (ifv->ifv_p != NULL) 1019 error = vlan_setflags(ifp, 1); 1020 break; 1021 1022 case SIOCADDMULTI: 1023 case SIOCDELMULTI: 1024 /*VLAN_LOCK();*/ 1025 error = vlan_setmulti(ifp); 1026 /*VLAN_UNLOCK();*/ 1027 break; 1028 default: 1029 error = EINVAL; 1030 } 1031 1032 return (error); 1033} 1034