|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright 1998 Massachusetts Institute of Technology ! 24: * ! 25: * Permission to use, copy, modify, and distribute this software and ! 26: * its documentation for any purpose and without fee is hereby ! 27: * granted, provided that both the above copyright notice and this ! 28: * permission notice appear in all copies, that both the above ! 29: * copyright notice and this permission notice appear in all ! 30: * supporting documentation, and that the name of M.I.T. not be used ! 31: * in advertising or publicity pertaining to distribution of the ! 32: * software without specific, written prior permission. M.I.T. makes ! 33: * no representations about the suitability of this software for any ! 34: * purpose. It is provided "as is" without express or implied ! 35: * warranty. ! 36: * ! 37: * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS ! 38: * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, ! 39: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ! 40: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT ! 41: * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ! 42: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ! 43: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ! 44: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ! 45: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! 46: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ! 47: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 48: * SUCH DAMAGE. ! 49: * ! 50: */ ! 51: ! 52: /* ! 53: * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. ! 54: * Might be extended some day to also handle IEEE 802.1p priority ! 55: * tagging. This is sort of sneaky in the implementation, since ! 56: * we need to pretend to be enough of an Ethernet implementation ! 57: * to make arp work. The way we do this is by telling everyone ! 58: * that we are an Ethernet, and then catch the packets that ! 59: * ether_output() left on our output queue queue when it calls ! 60: * if_start(), rewrite them for use by the real outgoing interface, ! 61: * and ask it to send them. ! 62: * ! 63: * ! 64: * XXX It's incorrect to assume that we must always kludge up ! 65: * headers on the physical device's behalf: some devices support ! 66: * VLAN tag insersion and extraction in firmware. For these cases, ! 67: * one can change the behavior of the vlan interface by setting ! 68: * the LINK0 flag on it (that is setting the vlan interface's LINK0 ! 69: * flag, _not_ the parent's LINK0 flag; we try to leave the parent ! 70: * alone). If the interface as the LINK0 flag set, then it will ! 71: * not modify the ethernet header on output because the parent ! 72: * can do that for itself. On input, the parent can call vlan_input_tag() ! 73: * directly in order to supply us with an incoming mbuf and the vlan ! 74: * tag value that goes with it. ! 75: */ ! 76: ! 77: #include "vlan.h" ! 78: #if NVLAN > 0 ! 79: #include "opt_inet.h" ! 80: #include "bpfilter.h" ! 81: ! 82: #include <sys/param.h> ! 83: #include <sys/kernel.h> ! 84: #include <sys/mbuf.h> ! 85: #include <sys/socket.h> ! 86: #include <sys/sockio.h> ! 87: #include <sys/sysctl.h> ! 88: #include <sys/systm.h> ! 89: ! 90: #if NBPFILTER > 0 ! 91: #include <net/bpf.h> ! 92: #endif ! 93: #include <net/ethernet.h> ! 94: #include <net/if.h> ! 95: #include <net/if_arp.h> ! 96: #include <net/if_dl.h> ! 97: #include <net/if_types.h> ! 98: #include <net/if_vlan_var.h> ! 99: ! 100: #if INET ! 101: #include <netinet/in.h> ! 102: #include <netinet/if_ether.h> ! 103: #endif ! 104: ! 105: SYSCTL_DECL(_net_link); ! 106: SYSCTL_NODE(_net_link, IFT_8021_VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); ! 107: SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); ! 108: ! 109: u_int vlan_proto = ETHERTYPE_VLAN; ! 110: SYSCTL_INT(_net_link_vlan_link, VLANCTL_PROTO, proto, CTLFLAG_RW, &vlan_proto, ! 111: 0, "Ethernet protocol used for VLAN encapsulation"); ! 112: ! 113: static struct ifvlan ifv_softc[NVLAN]; ! 114: ! 115: static void vlan_start(struct ifnet *ifp); ! 116: static void vlan_ifinit(void *foo); ! 117: static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); ! 118: static int vlan_setmulti(struct ifnet *ifp); ! 119: static int vlan_unconfig(struct ifnet *ifp); ! 120: static int vlan_config(struct ifvlan *ifv, struct ifnet *p); ! 121: ! 122: /* ! 123: * Program our multicast filter. What we're actually doing is ! 124: * programming the multicast filter of the parent. This has the ! 125: * side effect of causing the parent interface to receive multicast ! 126: * traffic that it doesn't really want, which ends up being discarded ! 127: * later by the upper protocol layers. Unfortunately, there's no way ! 128: * to avoid this: there really is only one physical interface. ! 129: */ ! 130: static int vlan_setmulti(struct ifnet *ifp) ! 131: { ! 132: struct ifnet *ifp_p; ! 133: struct ifmultiaddr *ifma, *rifma = NULL; ! 134: struct ifvlan *sc; ! 135: struct vlan_mc_entry *mc = NULL; ! 136: struct sockaddr_dl sdl; ! 137: int error; ! 138: ! 139: /* Find the parent. */ ! 140: sc = ifp->if_softc; ! 141: ifp_p = sc->ifv_p; ! 142: ! 143: sdl.sdl_len = ETHER_ADDR_LEN; ! 144: sdl.sdl_family = AF_LINK; ! 145: ! 146: /* First, remove any existing filter entries. */ ! 147: while(sc->vlan_mc_listhead.slh_first != NULL) { ! 148: mc = sc->vlan_mc_listhead.slh_first; ! 149: bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN); ! 150: error = if_delmulti(ifp_p, (struct sockaddr *)&sdl); ! 151: if (error) ! 152: return(error); ! 153: SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); ! 154: FREE(mc, M_DEVBUF); ! 155: } ! 156: ! 157: /* Now program new ones. */ ! 158: for (ifma = ifp->if_multiaddrs.lh_first; ! 159: ifma != NULL;ifma = ifma->ifma_link.le_next) { ! 160: if (ifma->ifma_addr->sa_family != AF_LINK) ! 161: continue; ! 162: mc = _MALLOC(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT); ! 163: bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ! 164: (char *)&mc->mc_addr, ETHER_ADDR_LEN); ! 165: SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); ! 166: error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma); ! 167: if (error) ! 168: return(error); ! 169: } ! 170: ! 171: return(0); ! 172: } ! 173: ! 174: static void ! 175: vlaninit(void *dummy) ! 176: { ! 177: int i; ! 178: ! 179: for (i = 0; i < NVLAN; i++) { ! 180: struct ifnet *ifp = &ifv_softc[i].ifv_if; ! 181: ! 182: ifp->if_softc = &ifv_softc[i]; ! 183: ifp->if_name = "vlan"; ! 184: ifp->if_family = APPLE_IF_FAM_VLAN; ! 185: ifp->if_unit = i; ! 186: /* NB: flags are not set here */ ! 187: ifp->if_linkmib = &ifv_softc[i].ifv_mib; ! 188: ifp->if_linkmiblen = sizeof ifv_softc[i].ifv_mib; ! 189: /* NB: mtu is not set here */ ! 190: ! 191: ifp->if_init = vlan_ifinit; ! 192: ifp->if_start = vlan_start; ! 193: ifp->if_ioctl = vlan_ioctl; ! 194: ifp->if_output = ether_output; ! 195: ifp->if_snd.ifq_maxlen = ifqmaxlen; ! 196: if_attach(ifp); ! 197: ether_ifattach(ifp); ! 198: #if NBPFILTER > 0 ! 199: bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); ! 200: #endif ! 201: /* Now undo some of the damage... */ ! 202: ifp->if_data.ifi_type = IFT_8021_VLAN; ! 203: ifp->if_data.ifi_hdrlen = EVL_ENCAPLEN; ! 204: ifp->if_resolvemulti = 0; ! 205: } ! 206: } ! 207: PSEUDO_SET(vlaninit, if_vlan); ! 208: ! 209: static void ! 210: vlan_ifinit(void *foo) ! 211: { ! 212: return; ! 213: } ! 214: ! 215: static void ! 216: vlan_start(struct ifnet *ifp) ! 217: { ! 218: struct ifvlan *ifv; ! 219: struct ifnet *p; ! 220: struct ether_vlan_header *evl; ! 221: struct mbuf *m; ! 222: ! 223: ifv = ifp->if_softc; ! 224: p = ifv->ifv_p; ! 225: ! 226: ifp->if_flags |= IFF_OACTIVE; ! 227: for (;;) { ! 228: IF_DEQUEUE(&ifp->if_snd, m); ! 229: if (m == 0) ! 230: break; ! 231: #if NBPFILTER > 0 ! 232: if (ifp->if_bpf) ! 233: bpf_mtap(ifp, m); ! 234: #endif /* NBPFILTER > 0 */ ! 235: ! 236: /* ! 237: * If the LINK0 flag is set, it means the underlying interface ! 238: * can do VLAN tag insertion itself and doesn't require us to ! 239: * create a special header for it. In this case, we just pass ! 240: * the packet along. However, we need some way to tell the ! 241: * interface where the packet came from so that it knows how ! 242: * to find the VLAN tag to use, so we set the rcvif in the ! 243: * mbuf header to our ifnet. ! 244: * ! 245: * Note: we also set the M_PROTO1 flag in the mbuf to let ! 246: * the parent driver know that the rcvif pointer is really ! 247: * valid. We need to do this because sometimes mbufs will ! 248: * be allocated by other parts of the system that contain ! 249: * garbage in the rcvif pointer. Using the M_PROTO1 flag ! 250: * lets the driver perform a proper sanity check and avoid ! 251: * following potentially bogus rcvif pointers off into ! 252: * never-never land. ! 253: */ ! 254: if (ifp->if_flags & IFF_LINK0) { ! 255: m->m_pkthdr.rcvif = ifp; ! 256: m->m_flags |= M_PROTO1; ! 257: } else { ! 258: M_PREPEND(m, EVL_ENCAPLEN, M_DONTWAIT); ! 259: if (m == 0) ! 260: continue; ! 261: /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ ! 262: ! 263: /* ! 264: * Transform the Ethernet header into an Ethernet header ! 265: * with 802.1Q encapsulation. ! 266: */ ! 267: bcopy(mtod(m, char *) + EVL_ENCAPLEN, mtod(m, char *), ! 268: sizeof(struct ether_header)); ! 269: evl = mtod(m, struct ether_vlan_header *); ! 270: evl->evl_proto = evl->evl_encap_proto; ! 271: evl->evl_encap_proto = htons(vlan_proto); ! 272: evl->evl_tag = htons(ifv->ifv_tag); ! 273: #ifdef DEBUG ! 274: printf("vlan_start: %*D\n", sizeof *evl, ! 275: (char *)evl, ":"); ! 276: #endif ! 277: } ! 278: ! 279: /* ! 280: * Send it, precisely as ether_output() would have. ! 281: * We are already running at splimp. ! 282: */ ! 283: if (IF_QFULL(&p->if_snd)) { ! 284: IF_DROP(&p->if_snd); ! 285: /* XXX stats */ ! 286: ifp->if_oerrors++; ! 287: m_freem(m); ! 288: continue; ! 289: } ! 290: IF_ENQUEUE(&p->if_snd, m); ! 291: if ((p->if_flags & IFF_OACTIVE) == 0) { ! 292: p->if_start(p); ! 293: ifp->if_opackets++; ! 294: } ! 295: } ! 296: ifp->if_flags &= ~IFF_OACTIVE; ! 297: ! 298: return; ! 299: } ! 300: ! 301: void ! 302: vlan_input_tag(struct ether_header *eh, struct mbuf *m, u_int16_t t) ! 303: { ! 304: int i; ! 305: struct ifvlan *ifv; ! 306: ! 307: for (i = 0; i < NVLAN; i++) { ! 308: ifv = &ifv_softc[i]; ! 309: if (ifv->ifv_tag == t) ! 310: break; ! 311: } ! 312: ! 313: if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) { ! 314: m_freem(m); ! 315: ifv->ifv_p->if_data.ifi_noproto++; ! 316: return; ! 317: } ! 318: ! 319: /* ! 320: * Having found a valid vlan interface corresponding to ! 321: * the given source interface and vlan tag, run the ! 322: * the real packet through ethert_input(). ! 323: */ ! 324: m->m_pkthdr.rcvif = &ifv->ifv_if; ! 325: ! 326: #if NBPFILTER > 0 ! 327: if (ifv->ifv_if.if_bpf) { ! 328: /* ! 329: * Do the usual BPF fakery. Note that we don't support ! 330: * promiscuous mode here, since it would require the ! 331: * drivers to know about VLANs and we're not ready for ! 332: * that yet. ! 333: */ ! 334: struct mbuf m0; ! 335: m0.m_next = m; ! 336: m0.m_len = sizeof(struct ether_header); ! 337: m0.m_data = (char *)eh; ! 338: bpf_mtap(&ifv->ifv_if, &m0); ! 339: } ! 340: #endif ! 341: ifv->ifv_if.if_ipackets++; ! 342: ether_input(&ifv->ifv_if, eh, m); ! 343: return; ! 344: } ! 345: ! 346: int ! 347: vlan_input(struct ether_header *eh, struct mbuf *m) ! 348: { ! 349: int i; ! 350: struct ifvlan *ifv; ! 351: ! 352: for (i = 0; i < NVLAN; i++) { ! 353: ifv = &ifv_softc[i]; ! 354: if (m->m_pkthdr.rcvif == ifv->ifv_p ! 355: && (EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *))) ! 356: == ifv->ifv_tag)) ! 357: break; ! 358: } ! 359: ! 360: if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) { ! 361: m_freem(m); ! 362: return -1; /* so ether_input can take note */ ! 363: } ! 364: ! 365: /* ! 366: * Having found a valid vlan interface corresponding to ! 367: * the given source interface and vlan tag, remove the ! 368: * encapsulation, and run the real packet through ! 369: * ether_input() a second time (it had better be ! 370: * reentrant!). ! 371: */ ! 372: m->m_pkthdr.rcvif = &ifv->ifv_if; ! 373: eh->ether_type = mtod(m, u_int16_t *)[1]; ! 374: m->m_data += EVL_ENCAPLEN; ! 375: m->m_len -= EVL_ENCAPLEN; ! 376: m->m_pkthdr.len -= EVL_ENCAPLEN; ! 377: ! 378: #if NBPFILTER > 0 ! 379: if (ifv->ifv_if.if_bpf) { ! 380: /* ! 381: * Do the usual BPF fakery. Note that we don't support ! 382: * promiscuous mode here, since it would require the ! 383: * drivers to know about VLANs and we're not ready for ! 384: * that yet. ! 385: */ ! 386: struct mbuf m0; ! 387: m0.m_next = m; ! 388: m0.m_len = sizeof(struct ether_header); ! 389: m0.m_data = (char *)eh; ! 390: bpf_mtap(&ifv->ifv_if, &m0); ! 391: } ! 392: #endif ! 393: ifv->ifv_if.if_ipackets++; ! 394: ether_input(&ifv->ifv_if, eh, m); ! 395: return 0; ! 396: } ! 397: ! 398: static int ! 399: vlan_config(struct ifvlan *ifv, struct ifnet *p) ! 400: { ! 401: struct ifaddr *ifa1, *ifa2; ! 402: struct sockaddr_dl *sdl1, *sdl2; ! 403: ! 404: if (p->if_data.ifi_type != IFT_ETHER) ! 405: return EPROTONOSUPPORT; ! 406: if (ifv->ifv_p) ! 407: return EBUSY; ! 408: ifv->ifv_p = p; ! 409: if (p->if_data.ifi_hdrlen == sizeof(struct ether_vlan_header)) ! 410: ifv->ifv_if.if_mtu = p->if_mtu; ! 411: else ! 412: ifv->ifv_if.if_mtu = p->if_data.ifi_mtu - EVL_ENCAPLEN; ! 413: ! 414: /* ! 415: * Preserve the state of the LINK0 flag for ourselves. ! 416: */ ! 417: ifv->ifv_if.if_flags = (p->if_flags & ~(IFF_LINK0)); ! 418: ! 419: /* ! 420: * Set up our ``Ethernet address'' to reflect the underlying ! 421: * physical interface's. ! 422: */ ! 423: ifa1 = ifnet_addrs[ifv->ifv_if.if_index - 1]; ! 424: ifa2 = ifnet_addrs[p->if_index - 1]; ! 425: sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; ! 426: sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; ! 427: sdl1->sdl_type = IFT_ETHER; ! 428: sdl1->sdl_alen = ETHER_ADDR_LEN; ! 429: bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); ! 430: bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); ! 431: return 0; ! 432: } ! 433: ! 434: static int ! 435: vlan_unconfig(struct ifnet *ifp) ! 436: { ! 437: struct ifaddr *ifa; ! 438: struct sockaddr_dl *sdl; ! 439: struct vlan_mc_entry *mc; ! 440: struct ifvlan *ifv; ! 441: struct ifnet *p; ! 442: int error; ! 443: ! 444: ifv = ifp->if_softc; ! 445: p = ifv->ifv_p; ! 446: ! 447: /* ! 448: * Since the interface is being unconfigured, we need to ! 449: * empty the list of multicast groups that we may have joined ! 450: * while we were alive and remove them from the parent's list ! 451: * as well. ! 452: */ ! 453: while(ifv->vlan_mc_listhead.slh_first != NULL) { ! 454: struct sockaddr_dl sdl; ! 455: ! 456: sdl.sdl_len = ETHER_ADDR_LEN; ! 457: sdl.sdl_family = AF_LINK; ! 458: mc = ifv->vlan_mc_listhead.slh_first; ! 459: bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN); ! 460: error = if_delmulti(p, (struct sockaddr *)&sdl); ! 461: error = if_delmulti(ifp, (struct sockaddr *)&sdl); ! 462: if (error) ! 463: return(error); ! 464: SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); ! 465: FREE(mc, M_DEVBUF); ! 466: } ! 467: ! 468: /* Disconnect from parent. */ ! 469: ifv->ifv_p = NULL; ! 470: ifv->ifv_if.if_mtu = ETHERMTU; ! 471: ! 472: /* Clear our MAC address. */ ! 473: ifa = ifnet_addrs[ifv->ifv_if.if_index - 1]; ! 474: sdl = (struct sockaddr_dl *)ifa->ifa_addr; ! 475: sdl->sdl_type = IFT_ETHER; ! 476: sdl->sdl_alen = ETHER_ADDR_LEN; ! 477: bzero(LLADDR(sdl), ETHER_ADDR_LEN); ! 478: bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); ! 479: ! 480: return 0; ! 481: } ! 482: ! 483: static int ! 484: vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ! 485: { ! 486: struct ifaddr *ifa; ! 487: struct ifnet *p; ! 488: struct ifreq *ifr; ! 489: struct ifvlan *ifv; ! 490: struct vlanreq vlr; ! 491: int error = 0; ! 492: ! 493: ifr = (struct ifreq *)data; ! 494: ifa = (struct ifaddr *)data; ! 495: ifv = ifp->if_softc; ! 496: ! 497: switch (cmd) { ! 498: case SIOCSIFADDR: ! 499: ifp->if_flags |= IFF_UP; ! 500: ! 501: switch (ifa->ifa_addr->sa_family) { ! 502: #if INET ! 503: case AF_INET: ! 504: arp_ifinit(&ifv->ifv_ac, ifa); ! 505: break; ! 506: #endif ! 507: default: ! 508: break; ! 509: } ! 510: break; ! 511: ! 512: case SIOCGIFADDR: ! 513: { ! 514: struct sockaddr *sa; ! 515: ! 516: sa = (struct sockaddr *) &ifr->ifr_data; ! 517: bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, ! 518: (caddr_t) sa->sa_data, ETHER_ADDR_LEN); ! 519: } ! 520: break; ! 521: ! 522: case SIOCSIFMTU: ! 523: /* ! 524: * Set the interface MTU. ! 525: * This is bogus. The underlying interface might support ! 526: * jumbo frames. ! 527: */ ! 528: if (ifr->ifr_mtu > ETHERMTU) { ! 529: error = EINVAL; ! 530: } else { ! 531: ifp->if_mtu = ifr->ifr_mtu; ! 532: } ! 533: break; ! 534: ! 535: case SIOCSETVLAN: ! 536: error = copyin(ifr->ifr_data, &vlr, sizeof vlr); ! 537: if (error) ! 538: break; ! 539: if (vlr.vlr_parent[0] == '\0') { ! 540: vlan_unconfig(ifp); ! 541: if_down(ifp); ! 542: ifp->if_flags = 0; ! 543: break; ! 544: } ! 545: p = ifunit(vlr.vlr_parent); ! 546: if (p == 0) { ! 547: error = ENOENT; ! 548: break; ! 549: } ! 550: error = vlan_config(ifv, p); ! 551: if (error) ! 552: break; ! 553: ifv->ifv_tag = vlr.vlr_tag; ! 554: break; ! 555: ! 556: case SIOCGETVLAN: ! 557: bzero(&vlr, sizeof vlr); ! 558: if (ifv->ifv_p) { ! 559: snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), ! 560: "%s%d", ifv->ifv_p->if_name, ifv->ifv_p->if_unit); ! 561: vlr.vlr_tag = ifv->ifv_tag; ! 562: } ! 563: error = copyout(&vlr, ifr->ifr_data, sizeof vlr); ! 564: break; ! 565: ! 566: case SIOCSIFFLAGS: ! 567: /* ! 568: * We don't support promiscuous mode ! 569: * right now because it would require help from the ! 570: * underlying drivers, which hasn't been implemented. ! 571: */ ! 572: if (ifr->ifr_flags & (IFF_PROMISC)) { ! 573: ifp->if_flags &= ~(IFF_PROMISC); ! 574: error = EINVAL; ! 575: } ! 576: break; ! 577: case SIOCADDMULTI: ! 578: case SIOCDELMULTI: ! 579: error = vlan_setmulti(ifp); ! 580: break; ! 581: default: ! 582: error = EINVAL; ! 583: } ! 584: return error; ! 585: } ! 586: ! 587: #endif /* NVLAN > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.