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