if_vlan.c revision 131580
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 131580 2004-07-04 16:43:24Z bms $ 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#include <net/route.h> 66 67#ifdef INET 68#include <netinet/in.h> 69#include <netinet/if_ether.h> 70#endif 71 72#define VLANNAME "vlan" 73 74struct vlan_mc_entry { 75 struct ether_addr mc_addr; 76 SLIST_ENTRY(vlan_mc_entry) mc_entries; 77}; 78 79struct ifvlan { 80 struct arpcom ifv_ac; /* make this an interface */ 81 struct ifnet *ifv_p; /* parent inteface of this vlan */ 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 int ifv_flags; 93}; 94#define ifv_if ifv_ac.ac_if 95#define ifv_tag ifv_mib.ifvm_tag 96#define ifv_encaplen ifv_mib.ifvm_encaplen 97#define ifv_mtufudge ifv_mib.ifvm_mtufudge 98#define ifv_mintu ifv_mib.ifvm_mintu 99 100#define IFVF_PROMISC 0x01 /* promiscuous mode enabled */ 101 102SYSCTL_DECL(_net_link); 103SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 104SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 105 106static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); 107static LIST_HEAD(, ifvlan) ifv_list; 108 109/* 110 * Locking: one lock is used to guard both the ifv_list and modification 111 * to vlan data structures. We are rather conservative here; probably 112 * more than necessary. 113 */ 114static struct mtx ifv_mtx; 115#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF) 116#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx) 117#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED) 118#define VLAN_LOCK() mtx_lock(&ifv_mtx) 119#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx) 120 121static void vlan_start(struct ifnet *ifp); 122static void vlan_ifinit(void *foo); 123static void vlan_input(struct ifnet *ifp, struct mbuf *m); 124static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 125static int vlan_setmulti(struct ifnet *ifp); 126static int vlan_unconfig(struct ifnet *ifp); 127static int vlan_config(struct ifvlan *ifv, struct ifnet *p); 128static void vlan_link_state(struct ifnet *ifp, int link); 129static int vlan_set_promisc(struct ifnet *ifp); 130 131static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, 132 const char *, int *); 133static int vlan_clone_match(struct if_clone *, const char *); 134static int vlan_clone_create(struct if_clone *, char *, size_t); 135static int vlan_clone_destroy(struct if_clone *, struct ifnet *); 136 137struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, IF_MAXUNIT, 138 NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy); 139 140/* 141 * Program our multicast filter. What we're actually doing is 142 * programming the multicast filter of the parent. This has the 143 * side effect of causing the parent interface to receive multicast 144 * traffic that it doesn't really want, which ends up being discarded 145 * later by the upper protocol layers. Unfortunately, there's no way 146 * to avoid this: there really is only one physical interface. 147 */ 148static int 149vlan_setmulti(struct ifnet *ifp) 150{ 151 struct ifnet *ifp_p; 152 struct ifmultiaddr *ifma, *rifma = NULL; 153 struct ifvlan *sc; 154 struct vlan_mc_entry *mc = NULL; 155 struct sockaddr_dl sdl; 156 int error; 157 158 /* Find the parent. */ 159 sc = ifp->if_softc; 160 ifp_p = sc->ifv_p; 161 162 /* 163 * If we don't have a parent, just remember the membership for 164 * when we do. 165 */ 166 if (ifp_p == NULL) 167 return (0); 168 169 bzero((char *)&sdl, sizeof(sdl)); 170 sdl.sdl_len = sizeof(sdl); 171 sdl.sdl_family = AF_LINK; 172 sdl.sdl_index = ifp_p->if_index; 173 sdl.sdl_type = IFT_ETHER; 174 sdl.sdl_alen = ETHER_ADDR_LEN; 175 176 /* First, remove any existing filter entries. */ 177 while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) { 178 mc = SLIST_FIRST(&sc->vlan_mc_listhead); 179 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN); 180 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl); 181 if (error) 182 return (error); 183 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); 184 free(mc, M_VLAN); 185 } 186 187 /* Now program new ones. */ 188 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 189 if (ifma->ifma_addr->sa_family != AF_LINK) 190 continue; 191 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_WAITOK); 192 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 193 (char *)&mc->mc_addr, ETHER_ADDR_LEN); 194 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); 195 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 196 LLADDR(&sdl), ETHER_ADDR_LEN); 197 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma); 198 if (error) 199 return (error); 200 } 201 202 return (0); 203} 204 205/* 206 * VLAN support can be loaded as a module. The only place in the 207 * system that's intimately aware of this is ether_input. We hook 208 * into this code through vlan_input_p which is defined there and 209 * set here. Noone else in the system should be aware of this so 210 * we use an explicit reference here. 211 * 212 * NB: Noone should ever need to check if vlan_input_p is null or 213 * not. This is because interfaces have a count of the number 214 * of active vlans (if_nvlans) and this should never be bumped 215 * except by vlan_config--which is in this module so therefore 216 * the module must be loaded and vlan_input_p must be non-NULL. 217 */ 218extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); 219 220/* For MII eyes only... */ 221extern void (*vlan_link_state_p)(struct ifnet *, int); 222 223static int 224vlan_modevent(module_t mod, int type, void *data) 225{ 226 227 switch (type) { 228 case MOD_LOAD: 229 LIST_INIT(&ifv_list); 230 VLAN_LOCK_INIT(); 231 vlan_input_p = vlan_input; 232 vlan_link_state_p = vlan_link_state; 233 if_clone_attach(&vlan_cloner); 234 break; 235 case MOD_UNLOAD: 236 if_clone_detach(&vlan_cloner); 237 vlan_input_p = NULL; 238 vlan_link_state_p = NULL; 239 while (!LIST_EMPTY(&ifv_list)) 240 vlan_clone_destroy(&vlan_cloner, 241 &LIST_FIRST(&ifv_list)->ifv_if); 242 VLAN_LOCK_DESTROY(); 243 break; 244 } 245 return (0); 246} 247 248static moduledata_t vlan_mod = { 249 "if_vlan", 250 vlan_modevent, 251 0 252}; 253 254DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 255MODULE_DEPEND(if_vlan, miibus, 1, 1, 1); 256 257static struct ifnet * 258vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag) 259{ 260 const char *cp; 261 struct ifnet *ifp; 262 int t = 0; 263 264 /* Check for <etherif>.<vlan> style interface names. */ 265 IFNET_RLOCK(); 266 TAILQ_FOREACH(ifp, &ifnet, if_link) { 267 if (ifp->if_type != IFT_ETHER) 268 continue; 269 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0) 270 continue; 271 cp = name + strlen(ifp->if_xname); 272 if (*cp != '.') 273 continue; 274 for(; *cp != '\0'; cp++) { 275 if (*cp < '0' || *cp > '9') 276 continue; 277 t = (t * 10) + (*cp - '0'); 278 } 279 if (tag != NULL) 280 *tag = t; 281 break; 282 } 283 IFNET_RUNLOCK(); 284 285 return (ifp); 286} 287 288static int 289vlan_clone_match(struct if_clone *ifc, const char *name) 290{ 291 const char *cp; 292 293 if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL) 294 return (1); 295 296 if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0) 297 return (0); 298 for (cp = name + 4; *cp != '\0'; cp++) { 299 if (*cp < '0' || *cp > '9') 300 return (0); 301 } 302 303 return (1); 304} 305 306static int 307vlan_clone_create(struct if_clone *ifc, char *name, size_t len) 308{ 309 char *dp; 310 int wildcard; 311 int unit; 312 int error; 313 int tag; 314 int ethertag; 315 struct ifvlan *ifv; 316 struct ifnet *ifp; 317 struct ifnet *p; 318 319 if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) { 320 ethertag = 1; 321 unit = -1; 322 wildcard = 0; 323 324 /* 325 * Don't let the caller set up a VLAN tag with 326 * anything except VLID bits. 327 */ 328 if (tag & ~EVL_VLID_MASK) 329 return (EINVAL); 330 } else { 331 ethertag = 0; 332 333 error = ifc_name2unit(name, &unit); 334 if (error != 0) 335 return (error); 336 337 wildcard = (unit < 0); 338 } 339 340 error = ifc_alloc_unit(ifc, &unit); 341 if (error != 0) 342 return (error); 343 344 /* In the wildcard case, we need to update the name. */ 345 if (wildcard) { 346 for (dp = name; *dp != '\0'; dp++); 347 if (snprintf(dp, len - (dp-name), "%d", unit) > 348 len - (dp-name) - 1) { 349 panic("%s: interface name too long", __func__); 350 } 351 } 352 353 ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO); 354 ifp = &ifv->ifv_if; 355 SLIST_INIT(&ifv->vlan_mc_listhead); 356 357 ifp->if_softc = ifv; 358 /* 359 * Set the name manually rather then using if_initname because 360 * we don't conform to the default naming convention for interfaces. 361 */ 362 strlcpy(ifp->if_xname, name, IFNAMSIZ); 363 ifp->if_dname = ifc->ifc_name; 364 ifp->if_dunit = unit; 365 /* NB: flags are not set here */ 366 ifp->if_linkmib = &ifv->ifv_mib; 367 ifp->if_linkmiblen = sizeof(ifv->ifv_mib); 368 /* NB: mtu is not set here */ 369 370 ifp->if_init = vlan_ifinit; 371 ifp->if_start = vlan_start; 372 ifp->if_ioctl = vlan_ioctl; 373 ifp->if_snd.ifq_maxlen = ifqmaxlen; 374 ether_ifattach(ifp, ifv->ifv_ac.ac_enaddr); 375 /* Now undo some of the damage... */ 376 ifp->if_baudrate = 0; 377 ifp->if_type = IFT_L2VLAN; 378 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN; 379 380 VLAN_LOCK(); 381 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list); 382 VLAN_UNLOCK(); 383 384 if (ethertag) { 385 VLAN_LOCK(); 386 error = vlan_config(ifv, p); 387 if (error != 0) { 388 /* 389 * Since we've partialy failed, we need to back 390 * out all the way, otherwise userland could get 391 * confused. Thus, we destroy the interface. 392 */ 393 LIST_REMOVE(ifv, ifv_list); 394 vlan_unconfig(ifp); 395 VLAN_UNLOCK(); 396 ether_ifdetach(ifp); 397 free(ifv, M_VLAN); 398 399 return (error); 400 } 401 ifv->ifv_tag = tag; 402 ifp->if_flags |= IFF_RUNNING; 403 VLAN_UNLOCK(); 404 405 /* Update promiscuous mode, if necessary. */ 406 vlan_set_promisc(ifp); 407 } 408 409 return (0); 410} 411 412static int 413vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 414{ 415 struct ifvlan *ifv = ifp->if_softc; 416 417 VLAN_LOCK(); 418 LIST_REMOVE(ifv, ifv_list); 419 vlan_unconfig(ifp); 420 VLAN_UNLOCK(); 421 422 ether_ifdetach(ifp); 423 424 free(ifv, M_VLAN); 425 426 return (0); 427} 428 429/* 430 * The ifp->if_init entry point for vlan(4) is a no-op. 431 */ 432static void 433vlan_ifinit(void *foo) 434{ 435 436} 437 438static void 439vlan_start(struct ifnet *ifp) 440{ 441 struct ifvlan *ifv; 442 struct ifnet *p; 443 struct ether_vlan_header *evl; 444 struct mbuf *m; 445 int error; 446 447 ifv = ifp->if_softc; 448 p = ifv->ifv_p; 449 450 ifp->if_flags |= IFF_OACTIVE; 451 for (;;) { 452 IF_DEQUEUE(&ifp->if_snd, m); 453 if (m == 0) 454 break; 455 BPF_MTAP(ifp, m); 456 457 /* 458 * Do not run parent's if_start() if the parent is not up, 459 * or parent's driver will cause a system crash. 460 */ 461 if ((p->if_flags & (IFF_UP | IFF_RUNNING)) != 462 (IFF_UP | IFF_RUNNING)) { 463 m_freem(m); 464 ifp->if_collisions++; 465 continue; 466 } 467 468 /* 469 * If underlying interface can do VLAN tag insertion itself, 470 * just pass the packet along. However, we need some way to 471 * tell the interface where the packet came from so that it 472 * knows how to find the VLAN tag to use, so we attach a 473 * packet tag that holds it. 474 */ 475 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { 476 struct m_tag *mtag = m_tag_alloc(MTAG_VLAN, 477 MTAG_VLAN_TAG, 478 sizeof(u_int), 479 M_NOWAIT); 480 if (mtag == NULL) { 481 ifp->if_oerrors++; 482 m_freem(m); 483 continue; 484 } 485 *(u_int*)(mtag + 1) = ifv->ifv_tag; 486 m_tag_prepend(m, mtag); 487 } else { 488 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 489 if (m == NULL) { 490 if_printf(ifp, 491 "unable to prepend VLAN header\n"); 492 ifp->if_oerrors++; 493 continue; 494 } 495 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ 496 497 if (m->m_len < sizeof(*evl)) { 498 m = m_pullup(m, sizeof(*evl)); 499 if (m == NULL) { 500 if_printf(ifp, 501 "cannot pullup VLAN header\n"); 502 ifp->if_oerrors++; 503 continue; 504 } 505 } 506 507 /* 508 * Transform the Ethernet header into an Ethernet header 509 * with 802.1Q encapsulation. 510 */ 511 bcopy(mtod(m, char *) + ifv->ifv_encaplen, 512 mtod(m, char *), ETHER_HDR_LEN); 513 evl = mtod(m, struct ether_vlan_header *); 514 evl->evl_proto = evl->evl_encap_proto; 515 evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 516 evl->evl_tag = htons(ifv->ifv_tag); 517#ifdef DEBUG 518 printf("vlan_start: %*D\n", (int)sizeof(*evl), 519 (unsigned char *)evl, ":"); 520#endif 521 } 522 523 /* 524 * Send it, precisely as ether_output() would have. 525 * We are already running at splimp. 526 */ 527 IFQ_HANDOFF(p, m, error); 528 if (!error) 529 ifp->if_opackets++; 530 else 531 ifp->if_oerrors++; 532 } 533 ifp->if_flags &= ~IFF_OACTIVE; 534} 535 536static void 537vlan_input(struct ifnet *ifp, struct mbuf *m) 538{ 539 struct ether_vlan_header *evl; 540 struct ifvlan *ifv; 541 struct m_tag *mtag; 542 u_int tag; 543 544 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL); 545 if (mtag != NULL) { 546 /* 547 * Packet is tagged, m contains a normal 548 * Ethernet frame; the tag is stored out-of-band. 549 */ 550 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)); 551 m_tag_delete(m, mtag); 552 } else { 553 switch (ifp->if_type) { 554 case IFT_ETHER: 555 if (m->m_len < sizeof(*evl) && 556 (m = m_pullup(m, sizeof(*evl))) == NULL) { 557 if_printf(ifp, "cannot pullup VLAN header\n"); 558 return; 559 } 560 evl = mtod(m, struct ether_vlan_header *); 561 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN, 562 ("vlan_input: bad encapsulated protocols (%u)", 563 ntohs(evl->evl_encap_proto))); 564 565 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag)); 566 567 /* 568 * Restore the original ethertype. We'll remove 569 * the encapsulation after we've found the vlan 570 * interface corresponding to the tag. 571 */ 572 evl->evl_encap_proto = evl->evl_proto; 573 break; 574 default: 575 tag = (u_int) -1; 576#ifdef DIAGNOSTIC 577 panic("vlan_input: unsupported if type %u", 578 ifp->if_type); 579#endif 580 break; 581 } 582 } 583 584 VLAN_LOCK(); 585 LIST_FOREACH(ifv, &ifv_list, ifv_list) 586 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag) 587 break; 588 589 if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) { 590 VLAN_UNLOCK(); 591 m_freem(m); 592 ifp->if_noproto++; 593#ifdef DEBUG 594 printf("vlan_input: tag %d, no interface\n", tag); 595#endif 596 return; 597 } 598 VLAN_UNLOCK(); /* XXX extend below? */ 599#ifdef DEBUG 600 printf("vlan_input: tag %d, parent %s\n", tag, ifv->ifv_p->if_xname); 601#endif 602 603 if (mtag == NULL) { 604 /* 605 * Packet had an in-line encapsulation header; 606 * remove it. The original header has already 607 * been fixed up above. 608 */ 609 bcopy(mtod(m, caddr_t), 610 mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN, 611 ETHER_HDR_LEN); 612 m_adj(m, ETHER_VLAN_ENCAP_LEN); 613 } 614 615 m->m_pkthdr.rcvif = &ifv->ifv_if; 616 ifv->ifv_if.if_ipackets++; 617 618 /* Pass it back through the parent's input routine. */ 619 (*ifp->if_input)(&ifv->ifv_if, m); 620} 621 622static int 623vlan_config(struct ifvlan *ifv, struct ifnet *p) 624{ 625 struct ifaddr *ifa1, *ifa2; 626 struct sockaddr_dl *sdl1, *sdl2; 627 628 VLAN_LOCK_ASSERT(); 629 630 if (p->if_data.ifi_type != IFT_ETHER) 631 return (EPROTONOSUPPORT); 632 if (ifv->ifv_p) 633 return (EBUSY); 634 635 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 636 ifv->ifv_mintu = ETHERMIN; 637 ifv->ifv_flags = 0; 638 639 /* 640 * If the parent supports the VLAN_MTU capability, 641 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 642 * use it. 643 * First of all, enable Tx/Rx of such extended frames on the 644 * parent if it's disabled and we're the first to attach. 645 */ 646 p->if_nvlans++; 647 if (p->if_nvlans == 1 && 648 (p->if_capabilities & IFCAP_VLAN_MTU) && 649 (p->if_capenable & IFCAP_VLAN_MTU) == 0) { 650 struct ifreq ifr; 651 int error; 652 653 ifr.ifr_reqcap = p->if_capenable | IFCAP_VLAN_MTU; 654 error = (*p->if_ioctl)(p, SIOCSIFCAP, (caddr_t) &ifr); 655 if (error) { 656 p->if_nvlans--; 657 return (error); 658 } 659 } 660 if (p->if_capenable & IFCAP_VLAN_MTU) { 661 /* 662 * No need to fudge the MTU since the parent can 663 * handle extended frames. 664 */ 665 ifv->ifv_mtufudge = 0; 666 } else { 667 /* 668 * Fudge the MTU by the encapsulation size. This 669 * makes us incompatible with strictly compliant 670 * 802.1Q implementations, but allows us to use 671 * the feature with other NetBSD implementations, 672 * which might still be useful. 673 */ 674 ifv->ifv_mtufudge = ifv->ifv_encaplen; 675 } 676 677 ifv->ifv_p = p; 678 ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge; 679 /* 680 * Copy only a selected subset of flags from the parent. 681 * Other flags are none of our business. 682 */ 683 ifv->ifv_if.if_flags = (p->if_flags & 684 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT)); 685 ifv->ifv_if.if_link_state = p->if_link_state; 686 687#if 0 688 /* 689 * Not ready yet. We need notification from the parent 690 * when hw checksumming flags in its if_capenable change. 691 * Flags set in if_capabilities only are useless. 692 */ 693 /* 694 * If the parent interface can do hardware-assisted 695 * VLAN encapsulation, then propagate its hardware- 696 * assisted checksumming flags. 697 */ 698 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 699 ifv->ifv_if.if_capabilities |= p->if_capabilities & IFCAP_HWCSUM; 700#endif 701 702 /* 703 * Set up our ``Ethernet address'' to reflect the underlying 704 * physical interface's. 705 */ 706 ifa1 = ifaddr_byindex(ifv->ifv_if.if_index); 707 ifa2 = ifaddr_byindex(p->if_index); 708 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 709 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 710 sdl1->sdl_type = IFT_ETHER; 711 sdl1->sdl_alen = ETHER_ADDR_LEN; 712 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 713 bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 714 715 /* 716 * Configure multicast addresses that may already be 717 * joined on the vlan device. 718 */ 719 (void)vlan_setmulti(&ifv->ifv_if); 720 721 return (0); 722} 723 724static int 725vlan_unconfig(struct ifnet *ifp) 726{ 727 struct ifaddr *ifa; 728 struct sockaddr_dl *sdl; 729 struct vlan_mc_entry *mc; 730 struct ifvlan *ifv; 731 struct ifnet *p; 732 int error; 733 734 VLAN_LOCK_ASSERT(); 735 736 ifv = ifp->if_softc; 737 p = ifv->ifv_p; 738 739 if (p) { 740 struct sockaddr_dl sdl; 741 742 /* 743 * Since the interface is being unconfigured, we need to 744 * empty the list of multicast groups that we may have joined 745 * while we were alive from the parent's list. 746 */ 747 bzero((char *)&sdl, sizeof(sdl)); 748 sdl.sdl_len = sizeof(sdl); 749 sdl.sdl_family = AF_LINK; 750 sdl.sdl_index = p->if_index; 751 sdl.sdl_type = IFT_ETHER; 752 sdl.sdl_alen = ETHER_ADDR_LEN; 753 754 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) { 755 mc = SLIST_FIRST(&ifv->vlan_mc_listhead); 756 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), 757 ETHER_ADDR_LEN); 758 error = if_delmulti(p, (struct sockaddr *)&sdl); 759 if (error) 760 return (error); 761 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 762 free(mc, M_VLAN); 763 } 764 765 p->if_nvlans--; 766 if (p->if_nvlans == 0) { 767 struct ifreq ifr; 768 769 /* 770 * Try to disable Tx/Rx of VLAN-sized frames. 771 * This may have no effect for some interfaces, 772 * but only the parent driver knows that. 773 */ 774 ifr.ifr_reqcap = p->if_capenable & ~IFCAP_VLAN_MTU; 775 (*p->if_ioctl)(p, SIOCSIFCAP, (caddr_t) &ifr); 776 } 777 } 778 779 /* Disconnect from parent. */ 780 ifv->ifv_p = NULL; 781 ifv->ifv_if.if_mtu = ETHERMTU; /* XXX why not 0? */ 782 ifv->ifv_flags = 0; 783 ifv->ifv_if.if_link_state = LINK_STATE_UNKNOWN; 784 785 /* Clear our MAC address. */ 786 ifa = ifaddr_byindex(ifv->ifv_if.if_index); 787 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 788 sdl->sdl_type = IFT_ETHER; 789 sdl->sdl_alen = ETHER_ADDR_LEN; 790 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 791 bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 792 793 return (0); 794} 795 796static int 797vlan_set_promisc(struct ifnet *ifp) 798{ 799 struct ifvlan *ifv = ifp->if_softc; 800 int error = 0; 801 802 if ((ifp->if_flags & IFF_PROMISC) != 0) { 803 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) { 804 error = ifpromisc(ifv->ifv_p, 1); 805 if (error == 0) 806 ifv->ifv_flags |= IFVF_PROMISC; 807 } 808 } else { 809 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) { 810 error = ifpromisc(ifv->ifv_p, 0); 811 if (error == 0) 812 ifv->ifv_flags &= ~IFVF_PROMISC; 813 } 814 } 815 816 return (error); 817} 818 819/* Inform all vlans that their parent has changed link state */ 820static void 821vlan_link_state(struct ifnet *ifp, int link) 822{ 823 struct ifvlan *ifv; 824 825 VLAN_LOCK(); 826 LIST_FOREACH(ifv, &ifv_list, ifv_list) { 827 if (ifv->ifv_p == ifp) { 828 ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state; 829 rt_ifmsg(&(ifv->ifv_if)); 830 KNOTE(&ifp->if_klist, link); 831 } 832 } 833 VLAN_UNLOCK(); 834} 835 836static int 837vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 838{ 839 struct ifaddr *ifa; 840 struct ifnet *p; 841 struct ifreq *ifr; 842 struct ifvlan *ifv; 843 struct vlanreq vlr; 844 int error = 0; 845 846 ifr = (struct ifreq *)data; 847 ifa = (struct ifaddr *)data; 848 ifv = ifp->if_softc; 849 850 switch (cmd) { 851 case SIOCSIFADDR: 852 ifp->if_flags |= IFF_UP; 853 854 switch (ifa->ifa_addr->sa_family) { 855#ifdef INET 856 case AF_INET: 857 arp_ifinit(&ifv->ifv_if, ifa); 858 break; 859#endif 860 default: 861 break; 862 } 863 break; 864 865 case SIOCGIFADDR: 866 { 867 struct sockaddr *sa; 868 869 sa = (struct sockaddr *) &ifr->ifr_data; 870 bcopy(IFP2AC(ifp)->ac_enaddr, (caddr_t)sa->sa_data, 871 ETHER_ADDR_LEN); 872 } 873 break; 874 875 case SIOCGIFMEDIA: 876 VLAN_LOCK(); 877 if (ifv->ifv_p != NULL) { 878 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, 879 SIOCGIFMEDIA, data); 880 VLAN_UNLOCK(); 881 /* Limit the result to the parent's current config. */ 882 if (error == 0) { 883 struct ifmediareq *ifmr; 884 885 ifmr = (struct ifmediareq *)data; 886 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { 887 ifmr->ifm_count = 1; 888 error = copyout(&ifmr->ifm_current, 889 ifmr->ifm_ulist, 890 sizeof(int)); 891 } 892 } 893 } else { 894 VLAN_UNLOCK(); 895 error = EINVAL; 896 } 897 break; 898 899 case SIOCSIFMEDIA: 900 error = EINVAL; 901 break; 902 903 case SIOCSIFMTU: 904 /* 905 * Set the interface MTU. 906 */ 907 VLAN_LOCK(); 908 if (ifv->ifv_p != NULL) { 909 if (ifr->ifr_mtu > 910 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) || 911 ifr->ifr_mtu < 912 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 913 error = EINVAL; 914 else 915 ifp->if_mtu = ifr->ifr_mtu; 916 } else 917 error = EINVAL; 918 VLAN_UNLOCK(); 919 break; 920 921 case SIOCSETVLAN: 922 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); 923 if (error) 924 break; 925 if (vlr.vlr_parent[0] == '\0') { 926 VLAN_LOCK(); 927 vlan_unconfig(ifp); 928 if (ifp->if_flags & IFF_UP) 929 if_down(ifp); 930 ifp->if_flags &= ~IFF_RUNNING; 931 VLAN_UNLOCK(); 932 break; 933 } 934 p = ifunit(vlr.vlr_parent); 935 if (p == 0) { 936 error = ENOENT; 937 break; 938 } 939 /* 940 * Don't let the caller set up a VLAN tag with 941 * anything except VLID bits. 942 */ 943 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 944 error = EINVAL; 945 break; 946 } 947 VLAN_LOCK(); 948 error = vlan_config(ifv, p); 949 if (error) { 950 VLAN_UNLOCK(); 951 break; 952 } 953 ifv->ifv_tag = vlr.vlr_tag; 954 ifp->if_flags |= IFF_RUNNING; 955 VLAN_UNLOCK(); 956 957 /* Update promiscuous mode, if necessary. */ 958 vlan_set_promisc(ifp); 959 break; 960 961 case SIOCGETVLAN: 962 bzero(&vlr, sizeof(vlr)); 963 VLAN_LOCK(); 964 if (ifv->ifv_p) { 965 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname, 966 sizeof(vlr.vlr_parent)); 967 vlr.vlr_tag = ifv->ifv_tag; 968 } 969 VLAN_UNLOCK(); 970 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 971 break; 972 973 case SIOCSIFFLAGS: 974 /* 975 * For promiscuous mode, we enable promiscuous mode on 976 * the parent if we need promiscuous on the VLAN interface. 977 */ 978 if (ifv->ifv_p != NULL) 979 error = vlan_set_promisc(ifp); 980 break; 981 982 case SIOCADDMULTI: 983 case SIOCDELMULTI: 984 error = vlan_setmulti(ifp); 985 break; 986 default: 987 error = EINVAL; 988 } 989 990 return (error); 991} 992