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