1 /* $OpenBSD: if_vlan.c,v 1.108 2014/07/12 18:44:22 tedu 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 int vlan_output(struct ifnet *, struct mbuf *, struct sockaddr *, 84 struct rtentry *); 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 if ((ifv = malloc(sizeof(*ifv), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 131 return (ENOMEM); 132 133 LIST_INIT(&ifv->vlan_mc_listhead); 134 ifp = &ifv->ifv_if; 135 ifp->if_softc = ifv; 136 snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name, 137 unit); 138 /* NB: flags are not set here */ 139 /* NB: mtu is not set here */ 140 141 /* Special handling for the IEEE 802.1ad QinQ variant */ 142 if (strcmp("svlan", ifc->ifc_name) == 0) 143 ifv->ifv_type = ETHERTYPE_QINQ; 144 else 145 ifv->ifv_type = ETHERTYPE_VLAN; 146 147 ifp->if_start = vlan_start; 148 ifp->if_ioctl = vlan_ioctl; 149 IFQ_SET_MAXLEN(&ifp->if_snd, 1); 150 IFQ_SET_READY(&ifp->if_snd); 151 if_attach(ifp); 152 ether_ifattach(ifp); 153 ifp->if_hdrlen = EVL_ENCAPLEN; 154 ifp->if_output = vlan_output; 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 free(ifv, M_DEVBUF, 0); 168 return (0); 169 } 170 171 void 172 vlan_ifdetach(void *ptr) 173 { 174 struct ifvlan *ifv = ptr; 175 vlan_clone_destroy(&ifv->ifv_if); 176 } 177 178 int 179 vlan_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 180 struct rtentry *rt) 181 { 182 /* 183 * we have to use a custom output function because ether_output 184 * can't figure out ifp is a vlan in a reasonable way 185 */ 186 m->m_flags |= M_VLANTAG; 187 return (ether_output(ifp, m, dst, rt)); 188 } 189 190 void 191 vlan_start(struct ifnet *ifp) 192 { 193 struct ifvlan *ifv; 194 struct ifnet *p; 195 struct mbuf *m; 196 int error; 197 198 ifv = ifp->if_softc; 199 p = ifv->ifv_p; 200 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 ifp->if_oerrors++; 210 m_freem(m); 211 continue; 212 } 213 214 #if NBPFILTER > 0 215 if (ifp->if_bpf) 216 bpf_mtap_stripvlan(ifp->if_bpf, m, BPF_DIRECTION_OUT); 217 #endif 218 219 /* 220 * Send it, precisely as ether_output() would have. 221 * We are already running at splnet. 222 */ 223 IFQ_ENQUEUE(&p->if_snd, m, NULL, error); 224 if (error) { 225 /* mbuf is already freed */ 226 ifp->if_oerrors++; 227 continue; 228 } 229 p->if_obytes += m->m_pkthdr.len; 230 if (m->m_flags & M_MCAST) 231 p->if_omcasts++; 232 233 ifp->if_opackets++; 234 if_start(p); 235 } 236 } 237 238 /* 239 * vlan_input() returns 0 if it has consumed the packet, 1 otherwise. 240 */ 241 int 242 vlan_input(struct ether_header *eh, struct mbuf *m) 243 { 244 struct ifvlan *ifv; 245 struct ifnet *ifp = m->m_pkthdr.rcvif; 246 struct vlan_taghash *tagh; 247 u_int tag; 248 u_int16_t etype; 249 250 if (m->m_flags & M_VLANTAG) { 251 etype = ETHERTYPE_VLAN; 252 tagh = vlan_tagh; 253 } else { 254 if (m->m_len < EVL_ENCAPLEN && 255 (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) { 256 ifp->if_ierrors++; 257 return (0); 258 } 259 260 etype = ntohs(eh->ether_type); 261 tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; 262 m->m_pkthdr.ether_vtag = ntohs(*mtod(m, u_int16_t *)); 263 } 264 /* From now on ether_vtag is fine */ 265 tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 266 m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag); 267 268 LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) { 269 if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag && 270 etype == ifv->ifv_type) 271 break; 272 } 273 if (ifv == NULL) 274 return (1); 275 276 if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 277 (IFF_UP|IFF_RUNNING)) { 278 m_freem(m); 279 return (0); 280 } 281 282 /* 283 * Having found a valid vlan interface corresponding to 284 * the given source interface and vlan tag, remove the 285 * encapsulation, and run the real packet through 286 * ether_input() a second time (it had better be 287 * reentrant!). 288 */ 289 m->m_pkthdr.rcvif = &ifv->ifv_if; 290 if (m->m_flags & M_VLANTAG) { 291 m->m_flags &= ~M_VLANTAG; 292 } else { 293 eh->ether_type = mtod(m, u_int16_t *)[1]; 294 m->m_len -= EVL_ENCAPLEN; 295 m->m_data += EVL_ENCAPLEN; 296 m->m_pkthdr.len -= EVL_ENCAPLEN; 297 } 298 299 #if NBPFILTER > 0 300 if (ifv->ifv_if.if_bpf) 301 bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh, ETHER_HDR_LEN, m, 302 BPF_DIRECTION_IN, NULL); 303 #endif 304 305 /* 306 * Drop promiscuously received packets if we are not in 307 * promiscuous mode. 308 */ 309 if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 && 310 (ifp->if_flags & IFF_PROMISC) && 311 (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) { 312 if (bcmp(&ifv->ifv_ac.ac_enaddr, eh->ether_dhost, 313 ETHER_ADDR_LEN)) { 314 m_freem(m); 315 return (0); 316 } 317 } 318 319 ifv->ifv_if.if_ipackets++; 320 ether_input(&ifv->ifv_if, eh, m); 321 322 return (0); 323 } 324 325 int 326 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) 327 { 328 struct sockaddr_dl *sdl1, *sdl2; 329 struct vlan_taghash *tagh; 330 u_int flags; 331 int s; 332 333 if (p->if_type != IFT_ETHER) 334 return EPROTONOSUPPORT; 335 if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */ 336 return (0); 337 338 /* Remember existing interface flags and reset the interface */ 339 flags = ifv->ifv_flags; 340 vlan_unconfig(&ifv->ifv_if, p); 341 ifv->ifv_p = p; 342 ifv->ifv_if.if_baudrate = p->if_baudrate; 343 344 if (p->if_capabilities & IFCAP_VLAN_MTU) 345 ifv->ifv_if.if_mtu = p->if_mtu; 346 else 347 ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN; 348 349 ifv->ifv_if.if_flags = p->if_flags & 350 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 351 352 /* Reset promisc mode on the interface and its parent */ 353 if (flags & IFVF_PROMISC) { 354 ifv->ifv_if.if_flags |= IFF_PROMISC; 355 vlan_set_promisc(&ifv->ifv_if); 356 } 357 358 /* 359 * If the parent interface can do hardware-assisted 360 * VLAN encapsulation, then propagate its hardware- 361 * assisted checksumming flags. 362 * 363 * If the card cannot handle hardware tagging, it cannot 364 * possibly compute the correct checksums for tagged packets. 365 */ 366 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 367 ifv->ifv_if.if_capabilities = p->if_capabilities & 368 IFCAP_CSUM_MASK; 369 370 /* 371 * Hardware VLAN tagging only works with the default VLAN 372 * ethernet type (0x8100). 373 */ 374 if (ifv->ifv_type != ETHERTYPE_VLAN) 375 ifv->ifv_if.if_capabilities &= ~IFCAP_VLAN_HWTAGGING; 376 377 /* 378 * Set up our ``Ethernet address'' to reflect the underlying 379 * physical interface's. 380 */ 381 sdl1 = ifv->ifv_if.if_sadl; 382 sdl2 = p->if_sadl; 383 sdl1->sdl_type = IFT_ETHER; 384 sdl1->sdl_alen = ETHER_ADDR_LEN; 385 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 386 bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 387 388 ifv->ifv_tag = tag; 389 s = splnet(); 390 tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; 391 LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list); 392 393 /* Register callback for physical link state changes */ 394 ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1, 395 vlan_vlandev_state, ifv); 396 397 /* Register callback if parent wants to unregister */ 398 ifv->dh_cookie = hook_establish(p->if_detachhooks, 0, 399 vlan_ifdetach, ifv); 400 401 vlan_vlandev_state(ifv); 402 splx(s); 403 404 return (0); 405 } 406 407 int 408 vlan_unconfig(struct ifnet *ifp, struct ifnet *newp) 409 { 410 struct sockaddr_dl *sdl; 411 struct ifvlan *ifv; 412 struct ifnet *p; 413 int s; 414 415 ifv = ifp->if_softc; 416 if ((p = ifv->ifv_p) == NULL) 417 return 0; 418 419 /* Unset promisc mode on the interface and its parent */ 420 if (ifv->ifv_flags & IFVF_PROMISC) { 421 ifp->if_flags &= ~IFF_PROMISC; 422 vlan_set_promisc(ifp); 423 } 424 425 s = splnet(); 426 LIST_REMOVE(ifv, ifv_list); 427 splx(s); 428 429 hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie); 430 hook_disestablish(p->if_detachhooks, ifv->dh_cookie); 431 /* Reset link state */ 432 if (newp != NULL) { 433 ifp->if_link_state = LINK_STATE_INVALID; 434 if_link_state_change(ifp); 435 } 436 437 /* 438 * Since the interface is being unconfigured, we need to 439 * empty the list of multicast groups that we may have joined 440 * while we were alive and remove them from the parent's list 441 * as well. 442 */ 443 vlan_ether_resetmulti(ifv, newp); 444 445 /* Disconnect from parent. */ 446 ifv->ifv_p = NULL; 447 ifv->ifv_if.if_mtu = ETHERMTU; 448 ifv->ifv_flags = 0; 449 450 /* Clear our MAC address. */ 451 sdl = ifv->ifv_if.if_sadl; 452 sdl->sdl_type = IFT_ETHER; 453 sdl->sdl_alen = ETHER_ADDR_LEN; 454 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 455 bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 456 457 return (0); 458 } 459 460 void 461 vlan_vlandev_state(void *v) 462 { 463 struct ifvlan *ifv = v; 464 465 if (ifv->ifv_if.if_link_state == ifv->ifv_p->if_link_state) 466 return; 467 468 ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state; 469 ifv->ifv_if.if_baudrate = ifv->ifv_p->if_baudrate; 470 if_link_state_change(&ifv->ifv_if); 471 } 472 473 int 474 vlan_set_promisc(struct ifnet *ifp) 475 { 476 struct ifvlan *ifv = ifp->if_softc; 477 int error = 0; 478 479 if ((ifp->if_flags & IFF_PROMISC) != 0) { 480 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) 481 if ((error = ifpromisc(ifv->ifv_p, 1)) == 0) 482 ifv->ifv_flags |= IFVF_PROMISC; 483 } else { 484 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) 485 if ((error = ifpromisc(ifv->ifv_p, 0)) == 0) 486 ifv->ifv_flags &= ~IFVF_PROMISC; 487 } 488 return (0); 489 } 490 491 int 492 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 493 { 494 struct proc *p = curproc; /* XXX */ 495 struct ifaddr *ifa; 496 struct ifnet *pr; 497 struct ifreq *ifr; 498 struct ifvlan *ifv; 499 struct vlanreq vlr; 500 int error = 0, p_mtu = 0, s; 501 502 ifr = (struct ifreq *)data; 503 ifa = (struct ifaddr *)data; 504 ifv = ifp->if_softc; 505 506 switch (cmd) { 507 case SIOCSIFADDR: 508 if (ifv->ifv_p != NULL) { 509 ifp->if_flags |= IFF_UP; 510 #ifdef INET 511 if (ifa->ifa_addr->sa_family == AF_INET) 512 arp_ifinit(&ifv->ifv_ac, ifa); 513 #endif 514 } else 515 error = EINVAL; 516 break; 517 518 case SIOCGIFADDR: 519 { 520 struct sockaddr *sa; 521 522 sa = (struct sockaddr *)&ifr->ifr_data; 523 bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 524 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 525 } 526 break; 527 528 case SIOCSIFMTU: 529 if (ifv->ifv_p != NULL) { 530 if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU) 531 p_mtu = ifv->ifv_p->if_mtu; 532 else 533 p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN; 534 535 if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN) 536 error = EINVAL; 537 else 538 ifp->if_mtu = ifr->ifr_mtu; 539 } else 540 error = EINVAL; 541 542 break; 543 544 case SIOCSETVLAN: 545 if ((error = suser(p, 0)) != 0) 546 break; 547 if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr))) 548 break; 549 if (vlr.vlr_parent[0] == '\0') { 550 s = splnet(); 551 vlan_unconfig(ifp, NULL); 552 if (ifp->if_flags & IFF_UP) 553 if_down(ifp); 554 ifp->if_flags &= ~IFF_RUNNING; 555 splx(s); 556 break; 557 } 558 pr = ifunit(vlr.vlr_parent); 559 if (pr == NULL) { 560 error = ENOENT; 561 break; 562 } 563 /* 564 * Don't let the caller set up a VLAN tag with 565 * anything except VLID bits. 566 */ 567 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 568 error = EINVAL; 569 break; 570 } 571 error = vlan_config(ifv, pr, vlr.vlr_tag); 572 if (error) 573 break; 574 ifp->if_flags |= IFF_RUNNING; 575 576 /* Update promiscuous mode, if necessary. */ 577 vlan_set_promisc(ifp); 578 break; 579 580 case SIOCGETVLAN: 581 bzero(&vlr, sizeof vlr); 582 if (ifv->ifv_p) { 583 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), 584 "%s", ifv->ifv_p->if_xname); 585 vlr.vlr_tag = ifv->ifv_tag; 586 } 587 error = copyout(&vlr, ifr->ifr_data, sizeof vlr); 588 break; 589 case SIOCSIFFLAGS: 590 /* 591 * For promiscuous mode, we enable promiscuous mode on 592 * the parent if we need promiscuous on the VLAN interface. 593 */ 594 if (ifv->ifv_p != NULL) 595 error = vlan_set_promisc(ifp); 596 break; 597 598 case SIOCADDMULTI: 599 error = (ifv->ifv_p != NULL) ? 600 vlan_ether_addmulti(ifv, ifr) : EINVAL; 601 break; 602 603 case SIOCDELMULTI: 604 error = (ifv->ifv_p != NULL) ? 605 vlan_ether_delmulti(ifv, ifr) : EINVAL; 606 break; 607 default: 608 error = ENOTTY; 609 } 610 return error; 611 } 612 613 614 int 615 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr) 616 { 617 struct ifnet *ifp = ifv->ifv_p; 618 struct vlan_mc_entry *mc; 619 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 620 int error; 621 622 error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 623 if (error != ENETRESET) 624 return (error); 625 626 /* 627 * This is new multicast address. We have to tell parent 628 * about it. Also, remember this multicast address so that 629 * we can delete them on unconfigure. 630 */ 631 if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) { 632 error = ENOMEM; 633 goto alloc_failed; 634 } 635 636 /* 637 * As ether_addmulti() returns ENETRESET, following two 638 * statement shouldn't fail. 639 */ 640 (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 641 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm); 642 memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len); 643 LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries); 644 645 if ((error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr)) != 0) 646 goto ioctl_failed; 647 648 return (error); 649 650 ioctl_failed: 651 LIST_REMOVE(mc, mc_entries); 652 free(mc, M_DEVBUF, 0); 653 alloc_failed: 654 (void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 655 656 return (error); 657 } 658 659 int 660 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr) 661 { 662 struct ifnet *ifp = ifv->ifv_p; 663 struct ether_multi *enm; 664 struct vlan_mc_entry *mc; 665 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 666 int error; 667 668 /* 669 * Find a key to lookup vlan_mc_entry. We have to do this 670 * before calling ether_delmulti for obvious reason. 671 */ 672 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 673 return (error); 674 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm); 675 if (enm == NULL) 676 return (EINVAL); 677 678 LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) 679 if (mc->mc_enm == enm) 680 break; 681 682 /* We won't delete entries we didn't add */ 683 if (mc == NULL) 684 return (EINVAL); 685 686 if ((error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac)) != 0) 687 return (error); 688 689 /* We no longer use this multicast address. Tell parent so. */ 690 if ((error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr)) != 0) { 691 /* And forget about this address. */ 692 LIST_REMOVE(mc, mc_entries); 693 free(mc, M_DEVBUF, 0); 694 } else 695 (void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 696 return (error); 697 } 698 699 /* 700 * Delete any multicast address we have asked to add from parent 701 * interface. Called when the vlan is being unconfigured. 702 */ 703 void 704 vlan_ether_purgemulti(struct ifvlan *ifv) 705 { 706 struct ifnet *ifp = ifv->ifv_p; 707 struct vlan_mc_entry *mc; 708 union { 709 struct ifreq ifreq; 710 struct { 711 char ifr_name[IFNAMSIZ]; 712 struct sockaddr_storage ifr_ss; 713 } ifreq_storage; 714 } ifreq; 715 struct ifreq *ifr = &ifreq.ifreq; 716 717 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 718 while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { 719 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len); 720 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 721 LIST_REMOVE(mc, mc_entries); 722 free(mc, M_DEVBUF, 0); 723 } 724 } 725 726 void 727 vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *p) 728 { 729 struct ifnet *ifp = ifv->ifv_p; 730 struct vlan_mc_entry *mc; 731 union { 732 struct ifreq ifreq; 733 struct { 734 char ifr_name[IFNAMSIZ]; 735 struct sockaddr_storage ifr_ss; 736 } ifreq_storage; 737 } ifreq; 738 struct ifreq *ifr = &ifreq.ifreq; 739 740 if (p == NULL) { 741 vlan_ether_purgemulti(ifv); 742 return; 743 } else if (ifp == p) 744 return; 745 746 LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) { 747 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len); 748 749 /* Remove from the old parent */ 750 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 751 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 752 753 /* Try to add to the new parent */ 754 memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ); 755 (void)(*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr); 756 } 757 } 758