1 /* $OpenBSD: if_vlan.c,v 1.25 2001/08/03 23:21:19 chris Exp $ */ 2 /* 3 * Copyright 1998 Massachusetts Institute of Technology 4 * 5 * Permission to use, copy, modify, and distribute this software and 6 * its documentation for any purpose and without fee is hereby 7 * granted, provided that both the above copyright notice and this 8 * permission notice appear in all copies, that both the above 9 * copyright notice and this permission notice appear in all 10 * supporting documentation, and that the name of M.I.T. not be used 11 * in advertising or publicity pertaining to distribution of the 12 * software without specific, written prior permission. M.I.T. makes 13 * no representations about the suitability of this software for any 14 * purpose. It is provided "as is" without express or implied 15 * warranty. 16 * 17 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 18 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 21 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: src/sys/net/if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp $ 31 */ 32 33 /* 34 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 35 * Might be extended some day to also handle IEEE 802.1p priority 36 * tagging. This is sort of sneaky in the implementation, since 37 * we need to pretend to be enough of an Ethernet implementation 38 * to make arp work. The way we do this is by telling everyone 39 * that we are an Ethernet, and then catch the packets that 40 * ether_output() left on our output queue when it calls 41 * if_start(), rewrite them for use by the real outgoing interface, 42 * and ask it to send them. 43 * 44 * Some devices support 802.1Q tag insertion and extraction in firmware. 45 * The vlan interface behavior changes when the IFCAP_VLAN_HWTAGGING 46 * capability is set on the parent. In this case, vlan_start() will not 47 * modify the ethernet header. On input, the parent can call vlan_input_tag() 48 * directly in order to supply us with an incoming mbuf and the vlan 49 * tag value that goes with it. 50 */ 51 52 #include "vlan.h" 53 #if NVLAN > 0 54 55 #include <sys/param.h> 56 #include <sys/kernel.h> 57 #include <sys/malloc.h> 58 #include <sys/mbuf.h> 59 #include <sys/queue.h> 60 #include <sys/socket.h> 61 #include <sys/sockio.h> 62 #include <sys/sysctl.h> 63 #include <sys/systm.h> 64 #include <sys/proc.h> 65 66 #include "bpfilter.h" 67 #if NBPFILTER > 0 68 #include <net/bpf.h> 69 #endif 70 71 #include <net/if.h> 72 #include <net/if_dl.h> 73 #include <net/if_types.h> 74 75 #ifdef INET 76 #include <netinet/in.h> 77 #include <netinet/if_ether.h> 78 #endif 79 80 #include <net/if_vlan_var.h> 81 82 struct ifaddr **ifnet_addrs; 83 84 struct ifvlan ifv_softc[NVLAN]; 85 86 extern int ifqmaxlen; 87 88 void vlan_start (struct ifnet *ifp); 89 int vlan_ioctl (struct ifnet *ifp, u_long cmd, caddr_t addr); 90 int vlan_setmulti (struct ifnet *ifp); 91 int vlan_unconfig (struct ifnet *ifp); 92 int vlan_config (struct ifvlan *ifv, struct ifnet *p); 93 void vlanattach (void *dummy); 94 int vlan_set_promisc (struct ifnet *ifp); 95 96 /* 97 * Program our multicast filter. What we're actually doing is 98 * programming the multicast filter of the parent. This has the 99 * side effect of causing the parent interface to receive multicast 100 * traffic that it doesn't really want, which ends up being discarded 101 * later by the upper protocol layers. Unfortunately, there's no way 102 * to avoid this: there really is only one physical interface. 103 */ 104 105 int vlan_setmulti(struct ifnet *ifp) 106 { 107 struct ifreq *ifr_p; 108 struct ether_multi *enm; 109 struct ether_multistep step; 110 struct ifvlan *sc; 111 struct vlan_mc_entry *mc = NULL; 112 int error; 113 114 /* Find the parent. */ 115 sc = ifp->if_softc; 116 ifr_p = (struct ifreq *)&sc->ifv_p->if_data; 117 118 /* First, remove any existing filter entries. */ 119 while(sc->vlan_mc_listhead.slh_first != NULL) { 120 mc = sc->vlan_mc_listhead.slh_first; 121 error = ether_delmulti(ifr_p, &sc->ifv_ac); 122 if (error) 123 return(error); 124 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); 125 free(mc, M_DEVBUF); 126 } 127 128 /* Now program new ones. */ 129 ETHER_FIRST_MULTI(step, &sc->ifv_ac, enm); 130 while (enm != NULL) { 131 mc = malloc(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT); 132 bcopy(enm->enm_addrlo, 133 (void *) &mc->mc_addr, ETHER_ADDR_LEN); 134 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); 135 error = ether_addmulti(ifr_p, &sc->ifv_ac); 136 if (error) 137 return(error); 138 ETHER_NEXT_MULTI(step, enm); 139 } 140 141 return(0); 142 } 143 144 void 145 vlanattach(void *dummy) 146 { 147 struct ifnet *ifp; 148 int i; 149 150 bzero(ifv_softc, sizeof(ifv_softc)); 151 152 for (i = 0; i < NVLAN; i++) { 153 ifp = &ifv_softc[i].ifv_if; 154 ifp->if_softc = &ifv_softc[i]; 155 sprintf(ifp->if_xname, "vlan%d", i); 156 /* NB: flags are not set here */ 157 /* NB: mtu is not set here */ 158 159 ifp->if_start = vlan_start; 160 ifp->if_ioctl = vlan_ioctl; 161 ifp->if_output = ether_output; 162 IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 163 IFQ_SET_READY(&ifp->if_snd); 164 if_attach(ifp); 165 ether_ifattach(ifp); 166 167 /* Now undo some of the damage... */ 168 ifp->if_type = IFT_8021_VLAN; 169 ifp->if_hdrlen = EVL_ENCAPLEN; 170 } 171 } 172 173 void 174 vlan_start(struct ifnet *ifp) 175 { 176 struct ifvlan *ifv; 177 struct ifnet *p; 178 struct ether_vlan_header *evl; 179 struct mbuf *m, *m0; 180 int error; 181 ALTQ_DECL(struct altq_pktattr pktattr;) 182 183 ifv = ifp->if_softc; 184 p = ifv->ifv_p; 185 186 ifp->if_flags |= IFF_OACTIVE; 187 for (;;) { 188 IFQ_DEQUEUE(&ifp->if_snd, m); 189 if (m == NULL) 190 break; 191 192 if ((p->if_flags & (IFF_UP|IFF_RUNNING)) != 193 (IFF_UP|IFF_RUNNING)) { 194 IF_DROP(&p->if_snd); 195 /* XXX stats */ 196 ifp->if_oerrors++; 197 m_freem(m); 198 continue; 199 } 200 201 #ifdef ALTQ 202 /* 203 * If ALTQ is enabled on the parent interface, do 204 * classification; the queueing discipline might 205 * not require classification, but might require 206 * the address family/header pointer in the pktattr. 207 */ 208 if (ALTQ_IS_ENABLED(&p->if_snd)) { 209 switch (p->if_type) { 210 case IFT_ETHER: 211 altq_etherclassify(&p->if_snd, m, &pktattr); 212 break; 213 #ifdef DIAGNOSTIC 214 default: 215 panic("vlan_start: impossible (altq)"); 216 #endif 217 } 218 } 219 #endif /* ALTQ */ 220 221 #if NBPFILTER > 0 222 if (ifp->if_bpf) 223 bpf_mtap(ifp->if_bpf, m); 224 #endif 225 226 /* 227 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent, 228 * it can do VLAN tag insertion itself and doesn't require us 229 * to create a special header for it. In this case, we just pass 230 * the packet along. However, we need some way to tell the 231 * interface where the packet came from so that it knows how 232 * to find the VLAN tag to use, so we set the rcvif in the 233 * mbuf header to our ifnet. 234 * 235 * Note: we also set the M_PROTO1 flag in the mbuf to let 236 * the parent driver know that the rcvif pointer is really 237 * valid. We need to do this because sometimes mbufs will 238 * be allocated by other parts of the system that contain 239 * garbage in the rcvif pointer. Using the M_PROTO1 flag 240 * lets the driver perform a proper sanity check and avoid 241 * following potentially bogus rcvif pointers off into 242 * never-never land. 243 */ 244 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) { 245 m->m_pkthdr.rcvif = ifp; 246 m->m_flags |= M_PROTO1; 247 } else { 248 if (m->m_len < sizeof(struct ether_header) && 249 (m = m_pullup(m, sizeof(struct ether_header))) 250 == NULL) { 251 ifp->if_ierrors++; 252 continue; 253 } 254 255 if (m->m_flags & M_PKTHDR) { 256 MGETHDR(m0, MT_DATA, M_DONTWAIT); 257 } else { 258 MGET(m0, MT_DATA, M_DONTWAIT); 259 } 260 261 if (m0 == NULL) { 262 ifp->if_ierrors++; 263 m_freem(m); 264 continue; 265 } 266 267 if (m0->m_flags & M_PKTHDR) 268 M_MOVE_PKTHDR(m0, m); 269 270 m0->m_flags &= ~M_PROTO1; 271 m0->m_next = m; 272 m0->m_len = sizeof(struct ether_vlan_header); 273 274 evl = mtod(m0, struct ether_vlan_header *); 275 bcopy(mtod(m, char *), 276 evl, sizeof(struct ether_header)); 277 evl->evl_proto = evl->evl_encap_proto; 278 evl->evl_encap_proto = htons(ETHERTYPE_8021Q); 279 evl->evl_tag = htons(ifv->ifv_tag); 280 281 m->m_len -= sizeof(struct ether_header); 282 m->m_data += sizeof(struct ether_header); 283 284 m = m0; 285 } 286 287 /* 288 * Send it, precisely as ether_output() would have. 289 * We are already running at splimp. 290 */ 291 p->if_obytes += m->m_pkthdr.len; 292 if (m->m_flags & M_MCAST) 293 p->if_omcasts++; 294 IFQ_ENQUEUE(&p->if_snd, m, &pktattr, error); 295 if (error) { 296 /* mbuf is already freed */ 297 ifp->if_oerrors++; 298 continue; 299 } 300 301 ifp->if_opackets++; 302 if ((p->if_flags & IFF_OACTIVE) == 0) 303 p->if_start(p); 304 } 305 ifp->if_flags &= ~IFF_OACTIVE; 306 307 return; 308 } 309 310 int 311 vlan_input_tag(struct mbuf *m, u_int16_t t) 312 { 313 int i; 314 struct ifvlan *ifv; 315 struct ether_vlan_header vh; 316 317 for (i = 0; i < NVLAN; i++) { 318 ifv = &ifv_softc[i]; 319 if (m->m_pkthdr.rcvif == ifv->ifv_p && t == ifv->ifv_tag) 320 break; 321 } 322 323 if (i >= NVLAN) { 324 if (m->m_pkthdr.len < sizeof(struct ether_header)) 325 return (-1); 326 m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&vh); 327 vh.evl_proto = vh.evl_encap_proto; 328 vh.evl_tag = htons(t); 329 vh.evl_encap_proto = htons(ETHERTYPE_8021Q); 330 M_PREPEND(m, EVL_ENCAPLEN, M_DONTWAIT); 331 if (m == NULL) 332 return (-1); 333 m_copyback(m, 0, sizeof(struct ether_vlan_header), (caddr_t)&vh); 334 ether_input_mbuf(m->m_pkthdr.rcvif, m); 335 return (-1); 336 } 337 338 if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 339 (IFF_UP|IFF_RUNNING)) { 340 m_freem(m); 341 return (-1); 342 } 343 344 /* 345 * Having found a valid vlan interface corresponding to 346 * the given source interface and vlan tag, run the 347 * the real packet through ether_input(). 348 */ 349 m->m_pkthdr.rcvif = &ifv->ifv_if; 350 351 #if NBPFILTER > 0 352 if (ifv->ifv_if.if_bpf) { 353 /* 354 * Do the usual BPF fakery. Note that we don't support 355 * promiscuous mode here, since it would require the 356 * drivers to know about VLANs and we're not ready for 357 * that yet. 358 */ 359 bpf_mtap(ifv->ifv_if.if_bpf, m); 360 } 361 #endif 362 ifv->ifv_if.if_ipackets++; 363 ether_input_mbuf(&ifv->ifv_if, m); 364 return 0; 365 } 366 367 int 368 vlan_input(eh, m) 369 struct ether_header *eh; 370 struct mbuf *m; 371 { 372 int i; 373 struct ifvlan *ifv; 374 u_int tag; 375 376 if (m->m_len < EVL_ENCAPLEN && 377 (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) { 378 m->m_pkthdr.rcvif->if_ierrors++; 379 return (0); 380 } 381 382 tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *))); 383 384 for (i = 0; i < NVLAN; i++) { 385 ifv = &ifv_softc[i]; 386 if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag) 387 break; 388 } 389 390 if (i >= NVLAN || (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 391 (IFF_UP|IFF_RUNNING)) { 392 m_freem(m); 393 return -1; /* so ether_input can take note */ 394 } 395 396 /* 397 * Having found a valid vlan interface corresponding to 398 * the given source interface and vlan tag, remove the 399 * encapsulation, and run the real packet through 400 * ether_input() a second time (it had better be 401 * reentrant!). 402 */ 403 m->m_pkthdr.rcvif = &ifv->ifv_if; 404 eh->ether_type = mtod(m, u_int16_t *)[1]; 405 m->m_len -= EVL_ENCAPLEN; 406 m->m_data += EVL_ENCAPLEN; 407 m->m_pkthdr.len -= EVL_ENCAPLEN; 408 409 #if NBPFILTER > 0 410 if (ifv->ifv_if.if_bpf) { 411 /* 412 * Do the usual BPF fakery. Note that we don't support 413 * promiscuous mode here, since it would require the 414 * drivers to know about VLANs and we're not ready for 415 * that yet. 416 */ 417 struct mbuf m0; 418 m0.m_next = m; 419 m0.m_len = sizeof(struct ether_header); 420 m0.m_data = (char *)eh; 421 bpf_mtap(ifv->ifv_if.if_bpf, &m0); 422 } 423 #endif 424 ifv->ifv_if.if_ipackets++; 425 ether_input(&ifv->ifv_if, eh, m); 426 427 return 0; 428 } 429 430 int 431 vlan_config(struct ifvlan *ifv, struct ifnet *p) 432 { 433 struct ifaddr *ifa1, *ifa2; 434 struct sockaddr_dl *sdl1, *sdl2; 435 436 if (p->if_type != IFT_ETHER) 437 return EPROTONOSUPPORT; 438 if (ifv->ifv_p) 439 return EBUSY; 440 ifv->ifv_p = p; 441 442 if (p->if_capabilities & IFCAP_VLAN_MTU) 443 ifv->ifv_if.if_mtu = p->if_mtu; 444 else { 445 /* 446 * This will be incompatible with strict 447 * 802.1Q implementations 448 */ 449 ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN; 450 #ifdef DIAGNOSTIC 451 printf("%s: initialized with non-standard mtu %d (parent %s)\n", 452 ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu, 453 ifv->ifv_p->if_xname); 454 #endif 455 } 456 457 ifv->ifv_if.if_flags = p->if_flags & 458 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 459 460 /* 461 * Inherit the if_type from the parent. This allows us to 462 * participate in bridges of that type. 463 */ 464 ifv->ifv_if.if_type = p->if_type; 465 466 /* 467 * If the parent interface can do hardware-assisted 468 * VLAN encapsulation, then propagate its hardware- 469 * assisted checksumming flags. 470 * 471 * If the card cannot handle hardware tagging, it cannot 472 * possibly compute the correct checksums for tagged packets. 473 * 474 * This brings up another possibility, do cards exist which 475 * have all of these capabilities but cannot utilize them together? 476 */ 477 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 478 ifv->ifv_if.if_capabilities = p->if_capabilities & 479 (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| 480 IFCAP_CSUM_UDPv4); 481 /* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */ 482 483 /* 484 * Set up our ``Ethernet address'' to reflect the underlying 485 * physical interface's. 486 */ 487 ifa1 = ifnet_addrs[ifv->ifv_if.if_index]; 488 ifa2 = ifnet_addrs[p->if_index]; 489 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 490 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 491 sdl1->sdl_type = IFT_ETHER; 492 sdl1->sdl_alen = ETHER_ADDR_LEN; 493 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 494 bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 495 return 0; 496 } 497 498 int 499 vlan_unconfig(struct ifnet *ifp) 500 { 501 struct ifaddr *ifa; 502 struct sockaddr_dl *sdl; 503 struct ifvlan *ifv; 504 struct ifnet *p; 505 struct ifreq *ifr, *ifr_p; 506 struct vlan_mc_entry *mc; 507 int error; 508 509 ifv = ifp->if_softc; 510 p = ifv->ifv_p; 511 ifr = (struct ifreq *)&ifp->if_data; 512 ifr_p = (struct ifreq *)&ifv->ifv_p->if_data; 513 514 /* 515 * Since the interface is being unconfigured, we need to 516 * empty the list of multicast groups that we may have joined 517 * while we were alive and remove them from the parent's list 518 * as well. 519 */ 520 while(ifv->vlan_mc_listhead.slh_first != NULL) { 521 522 mc = ifv->vlan_mc_listhead.slh_first; 523 error = ether_delmulti(ifr_p, &ifv->ifv_ac); 524 error = ether_delmulti(ifr, &ifv->ifv_ac); 525 if (error) 526 return(error); 527 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 528 free(mc, M_DEVBUF); 529 } 530 531 /* Disconnect from parent. */ 532 ifv->ifv_p = NULL; 533 ifv->ifv_if.if_mtu = ETHERMTU; 534 535 /* Clear our MAC address. */ 536 ifa = ifnet_addrs[ifv->ifv_if.if_index]; 537 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 538 sdl->sdl_type = IFT_ETHER; 539 sdl->sdl_alen = ETHER_ADDR_LEN; 540 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 541 bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 542 543 return 0; 544 } 545 546 int 547 vlan_set_promisc(struct ifnet *ifp) 548 { 549 struct ifvlan *ifv = ifp->if_softc; 550 int error = 0; 551 552 if ((ifp->if_flags & IFF_PROMISC) != 0) { 553 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) { 554 error = ifpromisc(ifv->ifv_p, 1); 555 if (error == 0) 556 ifv->ifv_flags |= IFVF_PROMISC; 557 } 558 } else { 559 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) { 560 error = ifpromisc(ifv->ifv_p, 0); 561 if (error == 0) 562 ifv->ifv_flags &= ~IFVF_PROMISC; 563 } 564 } 565 566 return (0); 567 } 568 569 int 570 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 571 { 572 struct proc *p = curproc; /* XXX */ 573 struct ifaddr *ifa; 574 struct ifnet *pr; 575 struct ifreq *ifr; 576 struct ifvlan *ifv; 577 struct vlanreq vlr; 578 int error = 0, p_mtu = 0; 579 580 ifr = (struct ifreq *)data; 581 ifa = (struct ifaddr *)data; 582 ifv = ifp->if_softc; 583 584 switch (cmd) { 585 case SIOCSIFADDR: 586 if (ifv->ifv_p != NULL) { 587 ifp->if_flags |= IFF_UP; 588 589 switch (ifa->ifa_addr->sa_family) { 590 #ifdef INET 591 case AF_INET: 592 arp_ifinit(&ifv->ifv_ac, ifa); 593 break; 594 #endif 595 default: 596 break; 597 } 598 } else { 599 error = EINVAL; 600 } 601 break; 602 603 case SIOCGIFADDR: 604 { 605 struct sockaddr *sa; 606 607 sa = (struct sockaddr *) &ifr->ifr_data; 608 bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 609 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 610 } 611 break; 612 613 case SIOCSIFMTU: 614 if (ifv->ifv_p != NULL) { 615 if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU) 616 p_mtu = ifv->ifv_p->if_mtu; 617 else 618 p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN; 619 620 if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN) 621 error = EINVAL; 622 else 623 ifp->if_mtu = ifr->ifr_mtu; 624 } else 625 error = EINVAL; 626 627 break; 628 629 case SIOCSETVLAN: 630 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 631 break; 632 if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr))) 633 break; 634 if (vlr.vlr_parent[0] == '\0') { 635 vlan_unconfig(ifp); 636 if_down(ifp); 637 ifp->if_flags &= ~(IFF_UP|IFF_RUNNING); 638 break; 639 } 640 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) { 641 error = EINVAL; /* check for valid tag */ 642 break; 643 } 644 pr = ifunit(vlr.vlr_parent); 645 if (pr == NULL) { 646 error = ENOENT; 647 break; 648 } 649 error = vlan_config(ifv, pr); 650 if (error) 651 break; 652 ifv->ifv_tag = vlr.vlr_tag; 653 ifp->if_flags |= IFF_RUNNING; 654 655 /* Update promiscuous mode, if necessary. */ 656 vlan_set_promisc(ifp); 657 break; 658 659 case SIOCGETVLAN: 660 bzero(&vlr, sizeof vlr); 661 if (ifv->ifv_p) { 662 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), 663 "%s", ifv->ifv_p->if_xname); 664 vlr.vlr_tag = ifv->ifv_tag; 665 } 666 error = copyout(&vlr, ifr->ifr_data, sizeof vlr); 667 break; 668 669 case SIOCSIFFLAGS: 670 /* 671 * For promiscuous mode, we enable promiscuous mode on 672 * the parent if we need promiscuous on the VLAN interface. 673 */ 674 if (ifv->ifv_p != NULL) 675 error = vlan_set_promisc(ifp); 676 break; 677 case SIOCADDMULTI: 678 case SIOCDELMULTI: 679 if (ifv->ifv_p != NULL) { 680 error = vlan_setmulti(ifp); 681 } else { 682 error = EINVAL; 683 } 684 break; 685 default: 686 error = EINVAL; 687 } 688 return error; 689 } 690 691 #endif /* NVLAN > 0 */ 692