1 /* $OpenBSD: if_vlan.c,v 1.88 2011/08/20 06:21:32 mcbride Exp $ */ 2 3 /* 4 * Copyright 1998 Massachusetts Institute of Technology 5 * 6 * Permission to use, copy, modify, and distribute this software and 7 * its documentation for any purpose and without fee is hereby 8 * granted, provided that both the above copyright notice and this 9 * permission notice appear in all copies, that both the above 10 * copyright notice and this permission notice appear in all 11 * supporting documentation, and that the name of M.I.T. not be used 12 * in advertising or publicity pertaining to distribution of the 13 * software without specific, written prior permission. M.I.T. makes 14 * no representations about the suitability of this software for any 15 * purpose. It is provided "as is" without express or implied 16 * warranty. 17 * 18 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 19 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 22 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 25 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD: src/sys/net/if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp $ 32 */ 33 34 /* 35 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 36 * Might be extended some day to also handle IEEE 802.1p priority 37 * tagging. This is sort of sneaky in the implementation, since 38 * we need to pretend to be enough of an Ethernet implementation 39 * to make arp work. The way we do this is by telling everyone 40 * that we are an Ethernet, and then catch the packets that 41 * ether_output() left on our output queue when it calls 42 * if_start(), rewrite them for use by the real outgoing interface, 43 * and ask it to send them. 44 * 45 * Some devices support 802.1Q tag insertion in firmware. The 46 * vlan interface behavior changes when the IFCAP_VLAN_HWTAGGING 47 * capability is set on the parent. In this case, vlan_start() 48 * will not modify the ethernet header. 49 */ 50 51 #include "vlan.h" 52 53 #include <sys/param.h> 54 #include <sys/kernel.h> 55 #include <sys/malloc.h> 56 #include <sys/mbuf.h> 57 #include <sys/queue.h> 58 #include <sys/socket.h> 59 #include <sys/sockio.h> 60 #include <sys/systm.h> 61 #include <sys/proc.h> 62 63 #include "bpfilter.h" 64 #if NBPFILTER > 0 65 #include <net/bpf.h> 66 #endif 67 68 #include <net/if.h> 69 #include <net/if_dl.h> 70 #include <net/if_types.h> 71 72 #ifdef INET 73 #include <netinet/in.h> 74 #include <netinet/if_ether.h> 75 #endif 76 77 #include <net/if_vlan_var.h> 78 79 extern struct ifaddr **ifnet_addrs; 80 u_long vlan_tagmask, svlan_tagmask; 81 82 #define TAG_HASH_SIZE 32 83 #define TAG_HASH(tag) (tag & vlan_tagmask) 84 LIST_HEAD(vlan_taghash, ifvlan) *vlan_tagh, *svlan_tagh; 85 86 void vlan_start(struct ifnet *ifp); 87 int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 88 int vlan_unconfig(struct ifnet *ifp, struct ifnet *newp); 89 int vlan_config(struct ifvlan *, struct ifnet *, u_int16_t); 90 void vlan_vlandev_state(void *); 91 void vlanattach(int count); 92 int vlan_set_promisc(struct ifnet *ifp); 93 int vlan_ether_addmulti(struct ifvlan *, struct ifreq *); 94 int vlan_ether_delmulti(struct ifvlan *, struct ifreq *); 95 void vlan_ether_purgemulti(struct ifvlan *); 96 void vlan_ether_resetmulti(struct ifvlan *, struct ifnet *); 97 int vlan_clone_create(struct if_clone *, int); 98 int vlan_clone_destroy(struct ifnet *); 99 void vlan_ifdetach(void *); 100 101 struct if_clone vlan_cloner = 102 IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy); 103 struct if_clone svlan_cloner = 104 IF_CLONE_INITIALIZER("svlan", vlan_clone_create, vlan_clone_destroy); 105 106 /* ARGSUSED */ 107 void 108 vlanattach(int count) 109 { 110 /* Normal VLAN */ 111 vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, 112 &vlan_tagmask); 113 if (vlan_tagh == NULL) 114 panic("vlanattach: hashinit"); 115 if_clone_attach(&vlan_cloner); 116 117 /* Service-VLAN for QinQ/802.1ad provider bridges */ 118 svlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, 119 &svlan_tagmask); 120 if (svlan_tagh == NULL) 121 panic("vlanattach: hashinit"); 122 if_clone_attach(&svlan_cloner); 123 } 124 125 int 126 vlan_clone_create(struct if_clone *ifc, int unit) 127 { 128 struct ifvlan *ifv; 129 struct ifnet *ifp; 130 131 ifv = malloc(sizeof(*ifv), M_DEVBUF, M_NOWAIT|M_ZERO); 132 if (!ifv) 133 return (ENOMEM); 134 135 LIST_INIT(&ifv->vlan_mc_listhead); 136 ifp = &ifv->ifv_if; 137 ifp->if_softc = ifv; 138 snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name, 139 unit); 140 /* NB: flags are not set here */ 141 /* NB: mtu is not set here */ 142 143 /* Special handling for the IEEE 802.1ad QinQ variant */ 144 if (strcmp("svlan", ifc->ifc_name) == 0) 145 ifv->ifv_type = ETHERTYPE_QINQ; 146 else 147 ifv->ifv_type = ETHERTYPE_VLAN; 148 149 ifp->if_start = vlan_start; 150 ifp->if_ioctl = vlan_ioctl; 151 IFQ_SET_MAXLEN(&ifp->if_snd, 1); 152 IFQ_SET_READY(&ifp->if_snd); 153 if_attach(ifp); 154 ether_ifattach(ifp); 155 /* Now undo some of the damage... */ 156 ifp->if_type = IFT_L2VLAN; 157 ifp->if_hdrlen = EVL_ENCAPLEN; 158 159 return (0); 160 } 161 162 int 163 vlan_clone_destroy(struct ifnet *ifp) 164 { 165 struct ifvlan *ifv = ifp->if_softc; 166 167 vlan_unconfig(ifp, NULL); 168 ether_ifdetach(ifp); 169 if_detach(ifp); 170 171 free(ifv, M_DEVBUF); 172 return (0); 173 } 174 175 void 176 vlan_ifdetach(void *ptr) 177 { 178 struct ifvlan *ifv = (struct ifvlan *)ptr; 179 /* 180 * Destroy the vlan interface because the parent has been 181 * detached. Set the dh_cookie to NULL because we're running 182 * inside of dohooks which is told to disestablish the hook 183 * for us (otherwise we would kill the TAILQ element...). 184 */ 185 ifv->dh_cookie = NULL; 186 vlan_clone_destroy(&ifv->ifv_if); 187 } 188 189 void 190 vlan_start(struct ifnet *ifp) 191 { 192 struct ifvlan *ifv; 193 struct ifnet *p; 194 struct mbuf *m; 195 int error; 196 197 ifv = ifp->if_softc; 198 p = ifv->ifv_p; 199 200 ifp->if_flags |= IFF_OACTIVE; 201 for (;;) { 202 IFQ_DEQUEUE(&ifp->if_snd, m); 203 if (m == NULL) 204 break; 205 206 if ((p->if_flags & (IFF_UP|IFF_RUNNING)) != 207 (IFF_UP|IFF_RUNNING)) { 208 IF_DROP(&p->if_snd); 209 /* XXX stats */ 210 ifp->if_oerrors++; 211 m_freem(m); 212 continue; 213 } 214 215 #if NBPFILTER > 0 216 if (ifp->if_bpf) 217 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 218 #endif 219 220 /* 221 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent, 222 * it can do VLAN tag insertion itself and doesn't require us 223 * to create a special header for it. In this case, we just pass 224 * the packet along. 225 */ 226 if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) && 227 (ifv->ifv_type == ETHERTYPE_VLAN)) { 228 m->m_pkthdr.ether_vtag = ifv->ifv_tag + 229 (ifv->ifv_prio << EVL_PRIO_BITS); 230 m->m_flags |= M_VLANTAG; 231 } else { 232 struct ether_vlan_header evh; 233 234 m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh); 235 evh.evl_proto = evh.evl_encap_proto; 236 evh.evl_encap_proto = htons(ifv->ifv_type); 237 evh.evl_tag = htons(ifv->ifv_tag + 238 (ifv->ifv_prio << EVL_PRIO_BITS)); 239 240 m_adj(m, ETHER_HDR_LEN); 241 M_PREPEND(m, sizeof(evh), M_DONTWAIT); 242 if (m == NULL) { 243 ifp->if_oerrors++; 244 continue; 245 } 246 247 m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT); 248 } 249 250 /* 251 * Send it, precisely as ether_output() would have. 252 * We are already running at splnet. 253 */ 254 IFQ_ENQUEUE(&p->if_snd, m, NULL, error); 255 if (error) { 256 /* mbuf is already freed */ 257 ifp->if_oerrors++; 258 continue; 259 } 260 p->if_obytes += m->m_pkthdr.len; 261 if (m->m_flags & M_MCAST) 262 p->if_omcasts++; 263 264 ifp->if_opackets++; 265 if_start(p); 266 } 267 ifp->if_flags &= ~IFF_OACTIVE; 268 269 return; 270 } 271 272 /* 273 * vlan_input() returns 0 if it has consumed the packet, 1 otherwise. 274 */ 275 int 276 vlan_input(struct ether_header *eh, struct mbuf *m) 277 { 278 struct ifvlan *ifv; 279 struct ifnet *ifp = m->m_pkthdr.rcvif; 280 struct vlan_taghash *tagh; 281 u_int tag; 282 u_int16_t etype; 283 284 if (m->m_flags & M_VLANTAG) { 285 etype = ETHERTYPE_VLAN; 286 tagh = vlan_tagh; 287 tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 288 } else { 289 if (m->m_len < EVL_ENCAPLEN && 290 (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) { 291 ifp->if_ierrors++; 292 return (0); 293 } 294 295 etype = ntohs(eh->ether_type); 296 tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; 297 tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *))); 298 } 299 300 LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) { 301 if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag && 302 etype == ifv->ifv_type) 303 break; 304 } 305 if (ifv == NULL) 306 return (1); 307 308 if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 309 (IFF_UP|IFF_RUNNING)) { 310 m_freem(m); 311 return (0); 312 } 313 314 /* 315 * Having found a valid vlan interface corresponding to 316 * the given source interface and vlan tag, remove the 317 * encapsulation, and run the real packet through 318 * ether_input() a second time (it had better be 319 * reentrant!). 320 */ 321 m->m_pkthdr.rcvif = &ifv->ifv_if; 322 if (m->m_flags & M_VLANTAG) { 323 m->m_flags &= ~M_VLANTAG; 324 } else { 325 eh->ether_type = mtod(m, u_int16_t *)[1]; 326 m->m_len -= EVL_ENCAPLEN; 327 m->m_data += EVL_ENCAPLEN; 328 m->m_pkthdr.len -= EVL_ENCAPLEN; 329 } 330 331 #if NBPFILTER > 0 332 if (ifv->ifv_if.if_bpf) 333 bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh, ETHER_HDR_LEN, 334 m, BPF_DIRECTION_IN); 335 #endif 336 337 /* 338 * Drop promiscuously received packets if we are not in 339 * promiscuous mode. 340 */ 341 if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 && 342 (ifp->if_flags & IFF_PROMISC) && 343 (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) { 344 struct arpcom *ac = &ifv->ifv_ac; 345 if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN)) { 346 m_freem(m); 347 return (0); 348 } 349 } 350 351 ifv->ifv_if.if_ipackets++; 352 ether_input(&ifv->ifv_if, eh, m); 353 354 return (0); 355 } 356 357 int 358 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) 359 { 360 struct ifaddr *ifa1, *ifa2; 361 struct sockaddr_dl *sdl1, *sdl2; 362 struct vlan_taghash *tagh; 363 u_int flags; 364 int s; 365 366 if (p->if_type != IFT_ETHER) 367 return EPROTONOSUPPORT; 368 if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */ 369 return (0); 370 371 /* Remember existing interface flags and reset the interface */ 372 flags = ifv->ifv_flags; 373 vlan_unconfig(&ifv->ifv_if, p); 374 375 ifv->ifv_p = p; 376 377 if (p->if_capabilities & IFCAP_VLAN_MTU) 378 ifv->ifv_if.if_mtu = p->if_mtu; 379 else { 380 /* 381 * This will be incompatible with strict 382 * 802.1Q implementations 383 */ 384 ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN; 385 #ifdef DIAGNOSTIC 386 printf("%s: initialized with non-standard mtu %lu (parent %s)\n", 387 ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu, 388 ifv->ifv_p->if_xname); 389 #endif 390 } 391 392 ifv->ifv_if.if_flags = p->if_flags & 393 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 394 395 /* Reset promisc mode on the interface and its parent */ 396 if (flags & IFVF_PROMISC) { 397 ifv->ifv_if.if_flags |= IFF_PROMISC; 398 vlan_set_promisc(&ifv->ifv_if); 399 } 400 401 /* 402 * Inherit the if_type from the parent. This allows us to 403 * participate in bridges of that type. 404 */ 405 ifv->ifv_if.if_type = p->if_type; 406 407 /* 408 * Inherit baudrate from the parent. An SNMP agent would use this 409 * information. 410 */ 411 ifv->ifv_if.if_baudrate = p->if_baudrate; 412 413 /* 414 * If the parent interface can do hardware-assisted 415 * VLAN encapsulation, then propagate its hardware- 416 * assisted checksumming flags. 417 * 418 * If the card cannot handle hardware tagging, it cannot 419 * possibly compute the correct checksums for tagged packets. 420 * 421 * This brings up another possibility, do cards exist which 422 * have all of these capabilities but cannot utilize them together? 423 */ 424 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 425 ifv->ifv_if.if_capabilities = p->if_capabilities & 426 (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| 427 IFCAP_CSUM_UDPv4); 428 /* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */ 429 430 /* 431 * Hardware VLAN tagging only works with the default VLAN 432 * ethernet type (0x8100). 433 */ 434 if (ifv->ifv_type != ETHERTYPE_VLAN) 435 ifv->ifv_if.if_capabilities &= ~IFCAP_VLAN_HWTAGGING; 436 437 /* 438 * Set up our ``Ethernet address'' to reflect the underlying 439 * physical interface's. 440 */ 441 ifa1 = ifnet_addrs[ifv->ifv_if.if_index]; 442 ifa2 = ifnet_addrs[p->if_index]; 443 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 444 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 445 sdl1->sdl_type = IFT_ETHER; 446 sdl1->sdl_alen = ETHER_ADDR_LEN; 447 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 448 bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 449 450 ifv->ifv_tag = tag; 451 s = splnet(); 452 tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; 453 LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list); 454 455 /* Register callback for physical link state changes */ 456 ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1, 457 vlan_vlandev_state, ifv); 458 459 /* Register callback if parent wants to unregister */ 460 ifv->dh_cookie = hook_establish(p->if_detachhooks, 1, 461 vlan_ifdetach, ifv); 462 463 vlan_vlandev_state(ifv); 464 splx(s); 465 466 return 0; 467 } 468 469 int 470 vlan_unconfig(struct ifnet *ifp, struct ifnet *newp) 471 { 472 struct ifaddr *ifa; 473 struct sockaddr_dl *sdl; 474 struct ifvlan *ifv; 475 struct ifnet *p; 476 int s; 477 478 ifv = ifp->if_softc; 479 p = ifv->ifv_p; 480 if (p == NULL) 481 return 0; 482 483 /* Unset promisc mode on the interface and its parent */ 484 if (ifv->ifv_flags & IFVF_PROMISC) { 485 ifp->if_flags &= ~IFF_PROMISC; 486 vlan_set_promisc(ifp); 487 } 488 489 s = splnet(); 490 LIST_REMOVE(ifv, ifv_list); 491 if (ifv->lh_cookie != NULL) 492 hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie); 493 /* The cookie is NULL if disestablished externally */ 494 if (ifv->dh_cookie != NULL) 495 hook_disestablish(p->if_detachhooks, ifv->dh_cookie); 496 /* Reset link state */ 497 if (newp != NULL) { 498 ifp->if_link_state = LINK_STATE_INVALID; 499 if_link_state_change(ifp); 500 } 501 splx(s); 502 503 /* 504 * Since the interface is being unconfigured, we need to 505 * empty the list of multicast groups that we may have joined 506 * while we were alive and remove them from the parent's list 507 * as well. 508 */ 509 vlan_ether_resetmulti(ifv, newp); 510 511 /* Disconnect from parent. */ 512 ifv->ifv_p = NULL; 513 ifv->ifv_if.if_mtu = ETHERMTU; 514 ifv->ifv_flags = 0; 515 516 /* Clear our MAC address. */ 517 ifa = ifnet_addrs[ifv->ifv_if.if_index]; 518 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 519 sdl->sdl_type = IFT_ETHER; 520 sdl->sdl_alen = ETHER_ADDR_LEN; 521 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 522 bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 523 524 return 0; 525 } 526 527 void 528 vlan_vlandev_state(void *v) 529 { 530 struct ifvlan *ifv = v; 531 532 if (ifv->ifv_if.if_link_state == ifv->ifv_p->if_link_state) 533 return; 534 535 ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state; 536 ifv->ifv_if.if_baudrate = ifv->ifv_p->if_baudrate; 537 if_link_state_change(&ifv->ifv_if); 538 } 539 540 int 541 vlan_set_promisc(struct ifnet *ifp) 542 { 543 struct ifvlan *ifv = ifp->if_softc; 544 int error = 0; 545 546 if ((ifp->if_flags & IFF_PROMISC) != 0) { 547 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) { 548 error = ifpromisc(ifv->ifv_p, 1); 549 if (error == 0) 550 ifv->ifv_flags |= IFVF_PROMISC; 551 } 552 } else { 553 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) { 554 error = ifpromisc(ifv->ifv_p, 0); 555 if (error == 0) 556 ifv->ifv_flags &= ~IFVF_PROMISC; 557 } 558 } 559 560 return (0); 561 } 562 563 int 564 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 565 { 566 struct proc *p = curproc; /* XXX */ 567 struct ifaddr *ifa; 568 struct ifnet *pr; 569 struct ifreq *ifr; 570 struct ifvlan *ifv; 571 struct vlanreq vlr; 572 int error = 0, p_mtu = 0, s; 573 574 ifr = (struct ifreq *)data; 575 ifa = (struct ifaddr *)data; 576 ifv = ifp->if_softc; 577 578 switch (cmd) { 579 case SIOCSIFADDR: 580 if (ifv->ifv_p != NULL) { 581 ifp->if_flags |= IFF_UP; 582 583 switch (ifa->ifa_addr->sa_family) { 584 #ifdef INET 585 case AF_INET: 586 arp_ifinit(&ifv->ifv_ac, ifa); 587 break; 588 #endif 589 default: 590 break; 591 } 592 } else { 593 error = EINVAL; 594 } 595 break; 596 597 case SIOCGIFADDR: 598 { 599 struct sockaddr *sa; 600 601 sa = (struct sockaddr *) &ifr->ifr_data; 602 bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 603 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 604 } 605 break; 606 607 case SIOCSIFMTU: 608 if (ifv->ifv_p != NULL) { 609 if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU) 610 p_mtu = ifv->ifv_p->if_mtu; 611 else 612 p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN; 613 614 if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN) 615 error = EINVAL; 616 else 617 ifp->if_mtu = ifr->ifr_mtu; 618 } else 619 error = EINVAL; 620 621 break; 622 623 case SIOCSETVLAN: 624 if ((error = suser(p, 0)) != 0) 625 break; 626 if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr))) 627 break; 628 if (vlr.vlr_parent[0] == '\0') { 629 s = splnet(); 630 vlan_unconfig(ifp, NULL); 631 if (ifp->if_flags & IFF_UP) 632 if_down(ifp); 633 ifp->if_flags &= ~IFF_RUNNING; 634 splx(s); 635 break; 636 } 637 pr = ifunit(vlr.vlr_parent); 638 if (pr == NULL) { 639 error = ENOENT; 640 break; 641 } 642 /* 643 * Don't let the caller set up a VLAN tag with 644 * anything except VLID bits. 645 */ 646 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 647 error = EINVAL; 648 break; 649 } 650 error = vlan_config(ifv, pr, vlr.vlr_tag); 651 if (error) 652 break; 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 case SIOCSETVLANPRIO: 669 if ((error = suser(p, 0)) != 0) 670 break; 671 if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr))) 672 break; 673 /* 674 * Don't let the caller set up a VLAN priority 675 * outside the range 0-7 676 */ 677 if (vlr.vlr_tag > EVL_PRIO_MAX) { 678 error = EINVAL; 679 break; 680 } 681 ifv->ifv_prio = vlr.vlr_tag; 682 break; 683 case SIOCGETVLANPRIO: 684 bzero(&vlr, sizeof vlr); 685 if (ifv->ifv_p) 686 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname, 687 sizeof(vlr.vlr_parent)); 688 vlr.vlr_tag = ifv->ifv_prio; 689 error = copyout(&vlr, ifr->ifr_data, sizeof vlr); 690 break; 691 case SIOCSIFFLAGS: 692 /* 693 * For promiscuous mode, we enable promiscuous mode on 694 * the parent if we need promiscuous on the VLAN interface. 695 */ 696 if (ifv->ifv_p != NULL) 697 error = vlan_set_promisc(ifp); 698 break; 699 700 case SIOCADDMULTI: 701 error = (ifv->ifv_p != NULL) ? 702 vlan_ether_addmulti(ifv, ifr) : EINVAL; 703 break; 704 705 case SIOCDELMULTI: 706 error = (ifv->ifv_p != NULL) ? 707 vlan_ether_delmulti(ifv, ifr) : EINVAL; 708 break; 709 default: 710 error = ENOTTY; 711 } 712 return error; 713 } 714 715 716 int 717 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr) 718 { 719 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 720 struct vlan_mc_entry *mc; 721 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 722 int error; 723 724 /* XXX: sa_len is too small for such comparison 725 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage)) 726 return (EINVAL); 727 */ 728 729 error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 730 if (error != ENETRESET) 731 return (error); 732 733 /* 734 * This is new multicast address. We have to tell parent 735 * about it. Also, remember this multicast address so that 736 * we can delete them on unconfigure. 737 */ 738 mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT); 739 if (mc == NULL) { 740 error = ENOMEM; 741 goto alloc_failed; 742 } 743 744 /* 745 * As ether_addmulti() returns ENETRESET, following two 746 * statement shouldn't fail. 747 */ 748 (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 749 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm); 750 memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len); 751 LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries); 752 753 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr); 754 if (error != 0) 755 goto ioctl_failed; 756 757 return (error); 758 759 ioctl_failed: 760 LIST_REMOVE(mc, mc_entries); 761 free(mc, M_DEVBUF); 762 alloc_failed: 763 (void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 764 765 return (error); 766 } 767 768 int 769 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr) 770 { 771 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 772 struct ether_multi *enm; 773 struct vlan_mc_entry *mc; 774 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 775 int error; 776 777 /* 778 * Find a key to lookup vlan_mc_entry. We have to do this 779 * before calling ether_delmulti for obvious reason. 780 */ 781 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 782 return (error); 783 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm); 784 if (enm == NULL) 785 return (EINVAL); 786 787 LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) 788 if (mc->mc_enm == enm) 789 break; 790 791 /* We won't delete entries we didn't add */ 792 if (mc == NULL) 793 return (EINVAL); 794 795 error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 796 if (error != ENETRESET) 797 return (error); 798 799 /* We no longer use this multicast address. Tell parent so. */ 800 error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 801 if (error == 0) { 802 /* And forget about this address. */ 803 LIST_REMOVE(mc, mc_entries); 804 free(mc, M_DEVBUF); 805 } else 806 (void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 807 return (error); 808 } 809 810 /* 811 * Delete any multicast address we have asked to add from parent 812 * interface. Called when the vlan is being unconfigured. 813 */ 814 void 815 vlan_ether_purgemulti(struct ifvlan *ifv) 816 { 817 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 818 struct vlan_mc_entry *mc; 819 union { 820 struct ifreq ifreq; 821 struct { 822 char ifr_name[IFNAMSIZ]; 823 struct sockaddr_storage ifr_ss; 824 } ifreq_storage; 825 } ifreq; 826 struct ifreq *ifr = &ifreq.ifreq; 827 828 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 829 while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { 830 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len); 831 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 832 LIST_REMOVE(mc, mc_entries); 833 free(mc, M_DEVBUF); 834 } 835 } 836 837 void 838 vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *p) 839 { 840 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 841 struct vlan_mc_entry *mc; 842 union { 843 struct ifreq ifreq; 844 struct { 845 char ifr_name[IFNAMSIZ]; 846 struct sockaddr_storage ifr_ss; 847 } ifreq_storage; 848 } ifreq; 849 struct ifreq *ifr = &ifreq.ifreq; 850 851 if (p == NULL) { 852 vlan_ether_purgemulti(ifv); 853 return; 854 } else if (ifp == p) 855 return; 856 857 LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) { 858 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len); 859 860 /* Remove from the old parent */ 861 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 862 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 863 864 /* Try to add to the new parent */ 865 memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ); 866 (void)(*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr); 867 } 868 } 869