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