1 /* $OpenBSD: if_vlan.c,v 1.41 2003/08/15 20:32:19 tedu 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 54 #include <sys/param.h> 55 #include <sys/kernel.h> 56 #include <sys/malloc.h> 57 #include <sys/mbuf.h> 58 #include <sys/queue.h> 59 #include <sys/socket.h> 60 #include <sys/sockio.h> 61 #include <sys/sysctl.h> 62 #include <sys/systm.h> 63 #include <sys/proc.h> 64 65 #include "bpfilter.h" 66 #if NBPFILTER > 0 67 #include <net/bpf.h> 68 #endif 69 70 #include <net/if.h> 71 #include <net/if_dl.h> 72 #include <net/if_types.h> 73 74 #ifdef INET 75 #include <netinet/in.h> 76 #include <netinet/if_ether.h> 77 #endif 78 79 #include <net/if_vlan_var.h> 80 81 extern struct ifaddr **ifnet_addrs; 82 83 struct ifvlan *ifv_softc; 84 int nifvlan; 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 (int count); 94 int vlan_set_promisc (struct ifnet *ifp); 95 int vlan_ether_addmulti(struct ifvlan *, struct ifreq *); 96 int vlan_ether_delmulti(struct ifvlan *, struct ifreq *); 97 void vlan_ether_purgemulti(struct ifvlan *); 98 99 void 100 vlanattach(int count) 101 { 102 struct ifnet *ifp; 103 int i; 104 105 MALLOC(ifv_softc, struct ifvlan *, count * sizeof(struct ifvlan), 106 M_DEVBUF, M_NOWAIT); 107 if (ifv_softc == NULL) 108 panic("vlanattach: MALLOC failed"); 109 nifvlan = count; 110 bzero(ifv_softc, nifvlan * sizeof(struct ifvlan)); 111 112 for (i = 0; i < nifvlan; i++) { 113 LIST_INIT(&ifv_softc[i].vlan_mc_listhead); 114 ifp = &ifv_softc[i].ifv_if; 115 ifp->if_softc = &ifv_softc[i]; 116 snprintf(ifp->if_xname, sizeof ifp->if_xname, "vlan%d", i); 117 /* NB: flags are not set here */ 118 /* NB: mtu is not set here */ 119 120 ifp->if_start = vlan_start; 121 ifp->if_ioctl = vlan_ioctl; 122 ifp->if_output = ether_output; 123 IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 124 IFQ_SET_READY(&ifp->if_snd); 125 if_attach(ifp); 126 ether_ifattach(ifp); 127 128 /* Now undo some of the damage... */ 129 ifp->if_type = IFT_8021_VLAN; 130 ifp->if_hdrlen = EVL_ENCAPLEN; 131 } 132 } 133 134 void 135 vlan_start(struct ifnet *ifp) 136 { 137 struct ifvlan *ifv; 138 struct ifnet *p; 139 struct mbuf *m, *m0; 140 int error; 141 142 ifv = ifp->if_softc; 143 p = ifv->ifv_p; 144 145 ifp->if_flags |= IFF_OACTIVE; 146 for (;;) { 147 IFQ_DEQUEUE(&ifp->if_snd, m); 148 if (m == NULL) 149 break; 150 151 if ((p->if_flags & (IFF_UP|IFF_RUNNING)) != 152 (IFF_UP|IFF_RUNNING)) { 153 IF_DROP(&p->if_snd); 154 /* XXX stats */ 155 ifp->if_oerrors++; 156 m_freem(m); 157 continue; 158 } 159 160 #if NBPFILTER > 0 161 if (ifp->if_bpf) 162 bpf_mtap(ifp->if_bpf, m); 163 #endif 164 165 /* 166 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent, 167 * it can do VLAN tag insertion itself and doesn't require us 168 * to create a special header for it. In this case, we just pass 169 * the packet along. However, we need some way to tell the 170 * interface where the packet came from so that it knows how 171 * to find the VLAN tag to use, so we set the rcvif in the 172 * mbuf header to our ifnet. 173 * 174 * Note: we also set the M_PROTO1 flag in the mbuf to let 175 * the parent driver know that the rcvif pointer is really 176 * valid. We need to do this because sometimes mbufs will 177 * be allocated by other parts of the system that contain 178 * garbage in the rcvif pointer. Using the M_PROTO1 flag 179 * lets the driver perform a proper sanity check and avoid 180 * following potentially bogus rcvif pointers off into 181 * never-never land. 182 */ 183 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) { 184 m->m_pkthdr.rcvif = ifp; 185 m->m_flags |= M_PROTO1; 186 } else { 187 struct ether_vlan_header evh; 188 189 m_copydata(m, 0, sizeof(struct ether_header), 190 (caddr_t)&evh); 191 evh.evl_proto = evh.evl_encap_proto; 192 evh.evl_encap_proto = htons(ETHERTYPE_8021Q); 193 evh.evl_tag = htons(ifv->ifv_tag); 194 m_adj(m, sizeof(struct ether_header)); 195 196 m0 = m_prepend(m, sizeof(struct ether_vlan_header), 197 M_DONTWAIT); 198 if (m0 == NULL) { 199 ifp->if_ierrors++; 200 continue; 201 } 202 203 /* m_prepend() doesn't adjust m_pkthdr.len */ 204 if (m0->m_flags & M_PKTHDR) 205 m0->m_pkthdr.len += 206 sizeof(struct ether_vlan_header); 207 208 m_copyback(m0, 0, sizeof(struct ether_vlan_header), 209 &evh); 210 211 m = m0; 212 } 213 214 /* 215 * Send it, precisely as ether_output() would have. 216 * We are already running at splimp. 217 */ 218 p->if_obytes += m->m_pkthdr.len; 219 if (m->m_flags & M_MCAST) 220 p->if_omcasts++; 221 IFQ_ENQUEUE(&p->if_snd, m, NULL, error); 222 if (error) { 223 /* mbuf is already freed */ 224 ifp->if_oerrors++; 225 continue; 226 } 227 228 ifp->if_opackets++; 229 if ((p->if_flags & IFF_OACTIVE) == 0) 230 p->if_start(p); 231 } 232 ifp->if_flags &= ~IFF_OACTIVE; 233 234 return; 235 } 236 237 int 238 vlan_input_tag(struct mbuf *m, u_int16_t t) 239 { 240 int i; 241 struct ifvlan *ifv; 242 struct ether_vlan_header vh; 243 244 t = EVL_VLANOFTAG(t); 245 for (i = 0; i < nifvlan; i++) { 246 ifv = &ifv_softc[i]; 247 if (m->m_pkthdr.rcvif == ifv->ifv_p && t == ifv->ifv_tag) 248 break; 249 } 250 251 if (i >= nifvlan) { 252 if (m->m_pkthdr.len < sizeof(struct ether_header)) { 253 m_freem(m); 254 return (-1); 255 } 256 m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&vh); 257 vh.evl_proto = vh.evl_encap_proto; 258 vh.evl_tag = htons(t); 259 vh.evl_encap_proto = htons(ETHERTYPE_8021Q); 260 m_adj(m, sizeof(struct ether_header)); 261 m = m_prepend(m, sizeof(struct ether_vlan_header), M_DONTWAIT); 262 if (m == NULL) 263 return (-1); 264 m->m_pkthdr.len += sizeof(struct ether_vlan_header); 265 if (m->m_len < sizeof(struct ether_vlan_header) && 266 (m = m_pullup(m, sizeof(struct ether_vlan_header))) == NULL) 267 return (-1); 268 m_copyback(m, 0, sizeof(struct ether_vlan_header), &vh); 269 ether_input_mbuf(m->m_pkthdr.rcvif, m); 270 return (-1); 271 } 272 273 if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 274 (IFF_UP|IFF_RUNNING)) { 275 m_freem(m); 276 return (-1); 277 } 278 279 /* 280 * Having found a valid vlan interface corresponding to 281 * the given source interface and vlan tag, run the 282 * the real packet through ether_input(). 283 */ 284 m->m_pkthdr.rcvif = &ifv->ifv_if; 285 286 #if NBPFILTER > 0 287 if (ifv->ifv_if.if_bpf) { 288 /* 289 * Do the usual BPF fakery. Note that we don't support 290 * promiscuous mode here, since it would require the 291 * drivers to know about VLANs and we're not ready for 292 * that yet. 293 */ 294 bpf_mtap(ifv->ifv_if.if_bpf, m); 295 } 296 #endif 297 ifv->ifv_if.if_ipackets++; 298 ether_input_mbuf(&ifv->ifv_if, m); 299 return 0; 300 } 301 302 int 303 vlan_input(eh, m) 304 struct ether_header *eh; 305 struct mbuf *m; 306 { 307 int i; 308 struct ifvlan *ifv; 309 u_int tag; 310 struct ifnet *ifp = m->m_pkthdr.rcvif; 311 312 if (m->m_len < EVL_ENCAPLEN && 313 (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) { 314 ifp->if_ierrors++; 315 return (0); 316 } 317 318 tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *))); 319 320 for (i = 0; i < nifvlan; i++) { 321 ifv = &ifv_softc[i]; 322 if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag) 323 break; 324 } 325 326 if (i >= nifvlan || (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) != 327 (IFF_UP|IFF_RUNNING)) { 328 m_freem(m); 329 return -1; /* so ether_input can take note */ 330 } 331 332 /* 333 * Having found a valid vlan interface corresponding to 334 * the given source interface and vlan tag, remove the 335 * encapsulation, and run the real packet through 336 * ether_input() a second time (it had better be 337 * reentrant!). 338 */ 339 m->m_pkthdr.rcvif = &ifv->ifv_if; 340 eh->ether_type = mtod(m, u_int16_t *)[1]; 341 m->m_len -= EVL_ENCAPLEN; 342 m->m_data += EVL_ENCAPLEN; 343 m->m_pkthdr.len -= EVL_ENCAPLEN; 344 345 #if NBPFILTER > 0 346 if (ifv->ifv_if.if_bpf) { 347 /* 348 * Do the usual BPF fakery. Note that we don't support 349 * promiscuous mode here, since it would require the 350 * drivers to know about VLANs and we're not ready for 351 * that yet. 352 */ 353 struct mbuf m0; 354 355 m0.m_flags = 0; 356 m0.m_next = m; 357 m0.m_len = sizeof(struct ether_header); 358 m0.m_data = (char *)eh; 359 bpf_mtap(ifv->ifv_if.if_bpf, &m0); 360 } 361 #endif 362 ifv->ifv_if.if_ipackets++; 363 ether_input(&ifv->ifv_if, eh, m); 364 365 return 0; 366 } 367 368 int 369 vlan_config(struct ifvlan *ifv, struct ifnet *p) 370 { 371 struct ifaddr *ifa1, *ifa2; 372 struct sockaddr_dl *sdl1, *sdl2; 373 374 if (p->if_type != IFT_ETHER) 375 return EPROTONOSUPPORT; 376 if (ifv->ifv_p) 377 return EBUSY; 378 ifv->ifv_p = p; 379 380 if (p->if_capabilities & IFCAP_VLAN_MTU) 381 ifv->ifv_if.if_mtu = p->if_mtu; 382 else { 383 /* 384 * This will be incompatible with strict 385 * 802.1Q implementations 386 */ 387 ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN; 388 #ifdef DIAGNOSTIC 389 printf("%s: initialized with non-standard mtu %lu (parent %s)\n", 390 ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu, 391 ifv->ifv_p->if_xname); 392 #endif 393 } 394 395 ifv->ifv_if.if_flags = p->if_flags & 396 (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 397 398 /* 399 * Inherit the if_type from the parent. This allows us to 400 * participate in bridges of that type. 401 */ 402 ifv->ifv_if.if_type = p->if_type; 403 404 /* 405 * Inherit baudrate from the parent. An SNMP agent would use this 406 * information. 407 */ 408 ifv->ifv_if.if_baudrate = p->if_baudrate; 409 410 /* 411 * If the parent interface can do hardware-assisted 412 * VLAN encapsulation, then propagate its hardware- 413 * assisted checksumming flags. 414 * 415 * If the card cannot handle hardware tagging, it cannot 416 * possibly compute the correct checksums for tagged packets. 417 * 418 * This brings up another possibility, do cards exist which 419 * have all of these capabilities but cannot utilize them together? 420 */ 421 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) 422 ifv->ifv_if.if_capabilities = p->if_capabilities & 423 (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| 424 IFCAP_CSUM_UDPv4); 425 /* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */ 426 427 /* 428 * Set up our ``Ethernet address'' to reflect the underlying 429 * physical interface's. 430 */ 431 ifa1 = ifnet_addrs[ifv->ifv_if.if_index]; 432 ifa2 = ifnet_addrs[p->if_index]; 433 sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 434 sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 435 sdl1->sdl_type = IFT_ETHER; 436 sdl1->sdl_alen = ETHER_ADDR_LEN; 437 bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 438 bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 439 return 0; 440 } 441 442 int 443 vlan_unconfig(struct ifnet *ifp) 444 { 445 struct ifaddr *ifa; 446 struct sockaddr_dl *sdl; 447 struct ifvlan *ifv; 448 struct ifnet *p; 449 struct ifreq *ifr, *ifr_p; 450 451 ifv = ifp->if_softc; 452 p = ifv->ifv_p; 453 ifr = (struct ifreq *)&ifp->if_data; 454 ifr_p = (struct ifreq *)&ifv->ifv_p->if_data; 455 456 if (p == NULL) 457 return 0; 458 459 /* 460 * Since the interface is being unconfigured, we need to 461 * empty the list of multicast groups that we may have joined 462 * while we were alive and remove them from the parent's list 463 * as well. 464 */ 465 vlan_ether_purgemulti(ifv); 466 467 /* Disconnect from parent. */ 468 ifv->ifv_p = NULL; 469 ifv->ifv_if.if_mtu = ETHERMTU; 470 471 /* Clear our MAC address. */ 472 ifa = ifnet_addrs[ifv->ifv_if.if_index]; 473 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 474 sdl->sdl_type = IFT_ETHER; 475 sdl->sdl_alen = ETHER_ADDR_LEN; 476 bzero(LLADDR(sdl), ETHER_ADDR_LEN); 477 bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 478 479 return 0; 480 } 481 482 int 483 vlan_set_promisc(struct ifnet *ifp) 484 { 485 struct ifvlan *ifv = ifp->if_softc; 486 int error = 0; 487 488 if ((ifp->if_flags & IFF_PROMISC) != 0) { 489 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) { 490 error = ifpromisc(ifv->ifv_p, 1); 491 if (error == 0) 492 ifv->ifv_flags |= IFVF_PROMISC; 493 } 494 } else { 495 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) { 496 error = ifpromisc(ifv->ifv_p, 0); 497 if (error == 0) 498 ifv->ifv_flags &= ~IFVF_PROMISC; 499 } 500 } 501 502 return (0); 503 } 504 505 int 506 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 507 { 508 struct proc *p = curproc; /* XXX */ 509 struct ifaddr *ifa; 510 struct ifnet *pr; 511 struct ifreq *ifr; 512 struct ifvlan *ifv; 513 struct vlanreq vlr; 514 int error = 0, p_mtu = 0; 515 516 ifr = (struct ifreq *)data; 517 ifa = (struct ifaddr *)data; 518 ifv = ifp->if_softc; 519 520 switch (cmd) { 521 case SIOCSIFADDR: 522 if (ifv->ifv_p != NULL) { 523 ifp->if_flags |= IFF_UP; 524 525 switch (ifa->ifa_addr->sa_family) { 526 #ifdef INET 527 case AF_INET: 528 arp_ifinit(&ifv->ifv_ac, ifa); 529 break; 530 #endif 531 default: 532 break; 533 } 534 } else { 535 error = EINVAL; 536 } 537 break; 538 539 case SIOCGIFADDR: 540 { 541 struct sockaddr *sa; 542 543 sa = (struct sockaddr *) &ifr->ifr_data; 544 bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 545 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 546 } 547 break; 548 549 case SIOCSIFMTU: 550 if (ifv->ifv_p != NULL) { 551 if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU) 552 p_mtu = ifv->ifv_p->if_mtu; 553 else 554 p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN; 555 556 if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN) 557 error = EINVAL; 558 else 559 ifp->if_mtu = ifr->ifr_mtu; 560 } else 561 error = EINVAL; 562 563 break; 564 565 case SIOCSETVLAN: 566 if ((error = suser(p, 0)) != 0) 567 break; 568 if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr))) 569 break; 570 if (vlr.vlr_parent[0] == '\0') { 571 vlan_unconfig(ifp); 572 if_down(ifp); 573 ifp->if_flags &= ~(IFF_UP|IFF_RUNNING); 574 break; 575 } 576 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) { 577 error = EINVAL; /* check for valid tag */ 578 break; 579 } 580 pr = ifunit(vlr.vlr_parent); 581 if (pr == NULL) { 582 error = ENOENT; 583 break; 584 } 585 error = vlan_config(ifv, pr); 586 if (error) 587 break; 588 ifv->ifv_tag = vlr.vlr_tag; 589 ifp->if_flags |= IFF_RUNNING; 590 591 /* Update promiscuous mode, if necessary. */ 592 vlan_set_promisc(ifp); 593 break; 594 595 case SIOCGETVLAN: 596 bzero(&vlr, sizeof vlr); 597 if (ifv->ifv_p) { 598 snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), 599 "%s", ifv->ifv_p->if_xname); 600 vlr.vlr_tag = ifv->ifv_tag; 601 } 602 error = copyout(&vlr, ifr->ifr_data, sizeof vlr); 603 break; 604 605 case SIOCSIFFLAGS: 606 /* 607 * For promiscuous mode, we enable promiscuous mode on 608 * the parent if we need promiscuous on the VLAN interface. 609 */ 610 if (ifv->ifv_p != NULL) 611 error = vlan_set_promisc(ifp); 612 break; 613 case SIOCADDMULTI: 614 error = (ifv->ifv_p != NULL) ? 615 vlan_ether_addmulti(ifv, ifr) : EINVAL; 616 break; 617 618 case SIOCDELMULTI: 619 error = (ifv->ifv_p != NULL) ? 620 vlan_ether_delmulti(ifv, ifr) : EINVAL; 621 break; 622 default: 623 error = EINVAL; 624 } 625 return error; 626 } 627 628 629 int 630 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr) 631 { 632 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 633 struct vlan_mc_entry *mc; 634 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 635 int error; 636 637 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage)) 638 return (EINVAL); 639 640 error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 641 if (error != ENETRESET) 642 return (error); 643 644 /* 645 * This is new multicast address. We have to tell parent 646 * about it. Also, remember this multicast address so that 647 * we can delete them on unconfigure. 648 */ 649 MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry), 650 M_DEVBUF, M_NOWAIT); 651 if (mc == NULL) { 652 error = ENOMEM; 653 goto alloc_failed; 654 } 655 656 /* 657 * As ether_addmulti() returns ENETRESET, following two 658 * statement shouldn't fail. 659 */ 660 (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 661 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm); 662 memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len); 663 LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries); 664 665 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr); 666 if (error != 0) 667 goto ioctl_failed; 668 669 return (error); 670 671 ioctl_failed: 672 LIST_REMOVE(mc, mc_entries); 673 FREE(mc, M_DEVBUF); 674 alloc_failed: 675 (void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 676 677 return (error); 678 } 679 680 int 681 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr) 682 { 683 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 684 struct ether_multi *enm; 685 struct vlan_mc_entry *mc; 686 u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 687 int error; 688 689 /* 690 * Find a key to lookup vlan_mc_entry. We have to do this 691 * before calling ether_delmulti for obvious reason. 692 */ 693 if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0) 694 return (error); 695 ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm); 696 697 error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 698 if (error != ENETRESET) 699 return (error); 700 701 /* We no longer use this multicast address. Tell parent so. */ 702 error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 703 if (error == 0) { 704 /* And forget about this address. */ 705 for (mc = LIST_FIRST(&ifv->vlan_mc_listhead); mc != NULL; 706 mc = LIST_NEXT(mc, mc_entries)) { 707 if (mc->mc_enm == enm) { 708 LIST_REMOVE(mc, mc_entries); 709 FREE(mc, M_DEVBUF); 710 break; 711 } 712 } 713 KASSERT(mc != NULL); 714 } else 715 (void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac); 716 return (error); 717 } 718 719 /* 720 * Delete any multicast address we have asked to add from parent 721 * interface. Called when the vlan is being unconfigured. 722 */ 723 void 724 vlan_ether_purgemulti(struct ifvlan *ifv) 725 { 726 struct ifnet *ifp = ifv->ifv_p; /* Parent. */ 727 struct vlan_mc_entry *mc; 728 union { 729 struct ifreq ifreq; 730 struct { 731 char ifr_name[IFNAMSIZ]; 732 struct sockaddr_storage ifr_ss; 733 } ifreq_storage; 734 } ifreq; 735 struct ifreq *ifr = &ifreq.ifreq; 736 737 memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ); 738 while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { 739 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len); 740 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr); 741 LIST_REMOVE(mc, mc_entries); 742 FREE(mc, M_DEVBUF); 743 } 744 } 745