12cc2df49SGarrett Wollman /* 22cc2df49SGarrett Wollman * Copyright 1998 Massachusetts Institute of Technology 32cc2df49SGarrett Wollman * 42cc2df49SGarrett Wollman * Permission to use, copy, modify, and distribute this software and 52cc2df49SGarrett Wollman * its documentation for any purpose and without fee is hereby 62cc2df49SGarrett Wollman * granted, provided that both the above copyright notice and this 72cc2df49SGarrett Wollman * permission notice appear in all copies, that both the above 82cc2df49SGarrett Wollman * copyright notice and this permission notice appear in all 92cc2df49SGarrett Wollman * supporting documentation, and that the name of M.I.T. not be used 102cc2df49SGarrett Wollman * in advertising or publicity pertaining to distribution of the 112cc2df49SGarrett Wollman * software without specific, written prior permission. M.I.T. makes 122cc2df49SGarrett Wollman * no representations about the suitability of this software for any 132cc2df49SGarrett Wollman * purpose. It is provided "as is" without express or implied 142cc2df49SGarrett Wollman * warranty. 152cc2df49SGarrett Wollman * 162cc2df49SGarrett Wollman * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 172cc2df49SGarrett Wollman * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 182cc2df49SGarrett Wollman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 192cc2df49SGarrett Wollman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 202cc2df49SGarrett Wollman * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212cc2df49SGarrett Wollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222cc2df49SGarrett Wollman * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 232cc2df49SGarrett Wollman * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 242cc2df49SGarrett Wollman * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 252cc2df49SGarrett Wollman * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 262cc2df49SGarrett Wollman * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 272cc2df49SGarrett Wollman * SUCH DAMAGE. 282cc2df49SGarrett Wollman * 29cfe8b629SGarrett Wollman * $Id: if_vlan.c,v 1.2 1998/05/15 20:02:47 wollman Exp $ 302cc2df49SGarrett Wollman */ 312cc2df49SGarrett Wollman 322cc2df49SGarrett Wollman /* 332cc2df49SGarrett Wollman * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 342cc2df49SGarrett Wollman * Might be extended some day to also handle IEEE 802.1p priority 352cc2df49SGarrett Wollman * tagging. This is sort of sneaky in the implementation, since 362cc2df49SGarrett Wollman * we need to pretend to be enough of an Ethernet implementation 372cc2df49SGarrett Wollman * to make arp work. The way we do this is by telling everyone 382cc2df49SGarrett Wollman * that we are an Ethernet, and then catch the packets that 392cc2df49SGarrett Wollman * ether_output() left on our output queue queue when it calls 402cc2df49SGarrett Wollman * if_start(), rewrite them for use by the real outgoing interface, 412cc2df49SGarrett Wollman * and ask it to send them. 422cc2df49SGarrett Wollman */ 432cc2df49SGarrett Wollman 442cc2df49SGarrett Wollman #include "vlan.h" 452cc2df49SGarrett Wollman #if NVLAN > 0 462cc2df49SGarrett Wollman #include "opt_inet.h" 472cc2df49SGarrett Wollman #include "bpfilter.h" 482cc2df49SGarrett Wollman 492cc2df49SGarrett Wollman #include <sys/param.h> 502cc2df49SGarrett Wollman #include <sys/kernel.h> 512cc2df49SGarrett Wollman #include <sys/mbuf.h> 522cc2df49SGarrett Wollman #include <sys/socket.h> 532cc2df49SGarrett Wollman #include <sys/sockio.h> 542cc2df49SGarrett Wollman #include <sys/sysctl.h> 552cc2df49SGarrett Wollman #include <sys/systm.h> 562cc2df49SGarrett Wollman 572cc2df49SGarrett Wollman #if NBPFILTER > 0 582cc2df49SGarrett Wollman #include <net/bpf.h> 592cc2df49SGarrett Wollman #endif 602cc2df49SGarrett Wollman #include <net/ethernet.h> 612cc2df49SGarrett Wollman #include <net/if.h> 622cc2df49SGarrett Wollman #include <net/if_arp.h> 632cc2df49SGarrett Wollman #include <net/if_dl.h> 642cc2df49SGarrett Wollman #include <net/if_types.h> 652cc2df49SGarrett Wollman #include <net/if_vlan_var.h> 662cc2df49SGarrett Wollman 672cc2df49SGarrett Wollman #ifdef INET 682cc2df49SGarrett Wollman #include <netinet/in.h> 692cc2df49SGarrett Wollman #include <netinet/if_ether.h> 702cc2df49SGarrett Wollman #endif 712cc2df49SGarrett Wollman 722cc2df49SGarrett Wollman SYSCTL_NODE(_net_link, IFT_8021_VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 732cc2df49SGarrett Wollman SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 742cc2df49SGarrett Wollman 752cc2df49SGarrett Wollman u_int vlan_proto = ETHERTYPE_VLAN; 762cc2df49SGarrett Wollman SYSCTL_INT(_net_link_vlan_link, VLANCTL_PROTO, proto, CTLFLAG_RW, &vlan_proto, 772cc2df49SGarrett Wollman 0, "Ethernet protocol used for VLAN encapsulation"); 782cc2df49SGarrett Wollman 792cc2df49SGarrett Wollman static struct ifvlan ifv_softc[NVLAN]; 802cc2df49SGarrett Wollman 812cc2df49SGarrett Wollman static void vlan_start(struct ifnet *ifp); 822cc2df49SGarrett Wollman static void vlan_ifinit(void *foo); 83cfe8b629SGarrett Wollman static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 842cc2df49SGarrett Wollman 852cc2df49SGarrett Wollman static void 862cc2df49SGarrett Wollman vlaninit(void *dummy) 872cc2df49SGarrett Wollman { 882cc2df49SGarrett Wollman int i; 892cc2df49SGarrett Wollman 902cc2df49SGarrett Wollman for (i = 0; i < NVLAN; i++) { 912cc2df49SGarrett Wollman struct ifnet *ifp = &ifv_softc[i].ifv_if; 922cc2df49SGarrett Wollman 932cc2df49SGarrett Wollman ifp->if_softc = &ifv_softc[i]; 942cc2df49SGarrett Wollman ifp->if_name = "vlan"; 952cc2df49SGarrett Wollman ifp->if_unit = i; 962cc2df49SGarrett Wollman /* NB: flags are not set here */ 972cc2df49SGarrett Wollman ifp->if_linkmib = &ifv_softc[i].ifv_mib; 982cc2df49SGarrett Wollman ifp->if_linkmiblen = sizeof ifv_softc[i].ifv_mib; 992cc2df49SGarrett Wollman /* NB: mtu is not set here */ 1002cc2df49SGarrett Wollman 1012cc2df49SGarrett Wollman ifp->if_init = vlan_ifinit; 1022cc2df49SGarrett Wollman ifp->if_start = vlan_start; 1032cc2df49SGarrett Wollman ifp->if_ioctl = vlan_ioctl; 1042cc2df49SGarrett Wollman ifp->if_output = ether_output; 1052cc2df49SGarrett Wollman if_attach(ifp); 1062cc2df49SGarrett Wollman ether_ifattach(ifp); 1072cc2df49SGarrett Wollman #if NBPFILTER > 0 1082cc2df49SGarrett Wollman bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 1092cc2df49SGarrett Wollman #endif 1102cc2df49SGarrett Wollman /* Now undo some of the damage... */ 1112cc2df49SGarrett Wollman ifp->if_data.ifi_type = IFT_8021_VLAN; 1122cc2df49SGarrett Wollman ifp->if_data.ifi_hdrlen = EVL_ENCAPLEN; 1132cc2df49SGarrett Wollman ifp->if_resolvemulti = 0; 1142cc2df49SGarrett Wollman } 1152cc2df49SGarrett Wollman } 1162cc2df49SGarrett Wollman PSEUDO_SET(vlaninit, if_vlan); 1172cc2df49SGarrett Wollman 1182cc2df49SGarrett Wollman static void 1192cc2df49SGarrett Wollman vlan_ifinit(void *foo) 1202cc2df49SGarrett Wollman { 1212cc2df49SGarrett Wollman ; 1222cc2df49SGarrett Wollman } 1232cc2df49SGarrett Wollman 1242cc2df49SGarrett Wollman static void 1252cc2df49SGarrett Wollman vlan_start(struct ifnet *ifp) 1262cc2df49SGarrett Wollman { 1272cc2df49SGarrett Wollman struct ifvlan *ifv; 1282cc2df49SGarrett Wollman struct ifnet *p; 1292cc2df49SGarrett Wollman struct ether_vlan_header *evl; 1302cc2df49SGarrett Wollman struct mbuf *m; 1312cc2df49SGarrett Wollman 1322cc2df49SGarrett Wollman ifv = ifp->if_softc; 1332cc2df49SGarrett Wollman p = ifv->ifv_p; 1342cc2df49SGarrett Wollman 1352cc2df49SGarrett Wollman ifp->if_flags |= IFF_OACTIVE; 1362cc2df49SGarrett Wollman for (;;) { 1372cc2df49SGarrett Wollman IF_DEQUEUE(&ifp->if_snd, m); 1382cc2df49SGarrett Wollman if (m == 0) 1392cc2df49SGarrett Wollman break; 1402cc2df49SGarrett Wollman #if NBPFILTER > 0 1412cc2df49SGarrett Wollman if (ifp->if_bpf) 142eb92a347SGarrett Wollman bpf_mtap(ifp, m); 1432cc2df49SGarrett Wollman #endif /* NBPFILTER > 0 */ 1442cc2df49SGarrett Wollman 1452cc2df49SGarrett Wollman M_PREPEND(m, EVL_ENCAPLEN, M_DONTWAIT); 1462cc2df49SGarrett Wollman if (m == 0) 1472cc2df49SGarrett Wollman continue; 1482cc2df49SGarrett Wollman /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ 1492cc2df49SGarrett Wollman 1502cc2df49SGarrett Wollman /* 1512cc2df49SGarrett Wollman * Transform the Ethernet header into an Ethernet header 1522cc2df49SGarrett Wollman * with 802.1Q encapsulation. 1532cc2df49SGarrett Wollman */ 1542cc2df49SGarrett Wollman bcopy(mtod(m, char *) + EVL_ENCAPLEN, mtod(m, char *), 1552cc2df49SGarrett Wollman sizeof(struct ether_header)); 1562cc2df49SGarrett Wollman evl = mtod(m, struct ether_vlan_header *); 1572cc2df49SGarrett Wollman evl->evl_proto = evl->evl_encap_proto; 1582cc2df49SGarrett Wollman evl->evl_encap_proto = htons(vlan_proto); 1592cc2df49SGarrett Wollman evl->evl_tag = htons(ifv->ifv_tag); 1602cc2df49SGarrett Wollman printf("vlan_start: %*D\n", sizeof *evl, (char *)evl, ":"); 1612cc2df49SGarrett Wollman 1622cc2df49SGarrett Wollman /* 1632cc2df49SGarrett Wollman * Send it, precisely as ether_output() would have. 1642cc2df49SGarrett Wollman * We are already running at splimp. 1652cc2df49SGarrett Wollman */ 1662cc2df49SGarrett Wollman if (IF_QFULL(&p->if_snd)) { 1672cc2df49SGarrett Wollman IF_DROP(&p->if_snd); 1682cc2df49SGarrett Wollman /* XXX stats */ 1692cc2df49SGarrett Wollman } 1702cc2df49SGarrett Wollman IF_ENQUEUE(&p->if_snd, m); 1712cc2df49SGarrett Wollman if ((p->if_flags & IFF_OACTIVE) == 0) 1722cc2df49SGarrett Wollman p->if_start(p); 1732cc2df49SGarrett Wollman } 1742cc2df49SGarrett Wollman ifp->if_flags &= ~IFF_OACTIVE; 1752cc2df49SGarrett Wollman } 1762cc2df49SGarrett Wollman 1772cc2df49SGarrett Wollman int 1782cc2df49SGarrett Wollman vlan_input(struct ether_header *eh, struct mbuf *m) 1792cc2df49SGarrett Wollman { 1802cc2df49SGarrett Wollman int i; 1812cc2df49SGarrett Wollman struct ifvlan *ifv; 1822cc2df49SGarrett Wollman 1832cc2df49SGarrett Wollman for (i = 0; i < NVLAN; i++) { 1842cc2df49SGarrett Wollman ifv = &ifv_softc[i]; 1852cc2df49SGarrett Wollman if (m->m_pkthdr.rcvif == ifv->ifv_p 1862cc2df49SGarrett Wollman && (EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *))) 1872cc2df49SGarrett Wollman == ifv->ifv_tag)) 1882cc2df49SGarrett Wollman break; 1892cc2df49SGarrett Wollman } 1902cc2df49SGarrett Wollman 1912cc2df49SGarrett Wollman if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) { 1922cc2df49SGarrett Wollman m_freem(m); 1932cc2df49SGarrett Wollman return -1; /* so ether_input can take note */ 1942cc2df49SGarrett Wollman } 1952cc2df49SGarrett Wollman 1962cc2df49SGarrett Wollman /* 1972cc2df49SGarrett Wollman * Having found a valid vlan interface corresponding to 1982cc2df49SGarrett Wollman * the given source interface and vlan tag, remove the 1992cc2df49SGarrett Wollman * encapsulation, and run the real packet through 2002cc2df49SGarrett Wollman * ether_input() a second time (it had better be 2012cc2df49SGarrett Wollman * reentrant!). 2022cc2df49SGarrett Wollman */ 2032cc2df49SGarrett Wollman m->m_pkthdr.rcvif = &ifv->ifv_if; 2042cc2df49SGarrett Wollman eh->ether_type = mtod(m, u_int16_t *)[1]; 2052cc2df49SGarrett Wollman m->m_data += EVL_ENCAPLEN; 2062cc2df49SGarrett Wollman m->m_len -= EVL_ENCAPLEN; 2072cc2df49SGarrett Wollman m->m_pkthdr.len -= EVL_ENCAPLEN; 2082cc2df49SGarrett Wollman 2092cc2df49SGarrett Wollman #if NBPFILTER > 0 2102cc2df49SGarrett Wollman if (ifv->ifv_if.if_bpf) { 2112cc2df49SGarrett Wollman /* 2122cc2df49SGarrett Wollman * Do the usual BPF fakery. Note that we don't support 2132cc2df49SGarrett Wollman * promiscuous mode here, since it would require the 2142cc2df49SGarrett Wollman * drivers to know about VLANs and we're not ready for 2152cc2df49SGarrett Wollman * that yet. 2162cc2df49SGarrett Wollman */ 2172cc2df49SGarrett Wollman struct mbuf m0; 2182cc2df49SGarrett Wollman m0.m_next = m; 2192cc2df49SGarrett Wollman m0.m_len = sizeof(struct ether_header); 2202cc2df49SGarrett Wollman m0.m_data = (char *)eh; 2212cc2df49SGarrett Wollman bpf_mtap(&ifv->ifv_if, &m0); 2222cc2df49SGarrett Wollman } 2232cc2df49SGarrett Wollman #endif 2242cc2df49SGarrett Wollman ether_input(&ifv->ifv_if, eh, m); 2252cc2df49SGarrett Wollman return 0; 2262cc2df49SGarrett Wollman } 2272cc2df49SGarrett Wollman 2282cc2df49SGarrett Wollman static int 2292cc2df49SGarrett Wollman vlan_config(struct ifvlan *ifv, struct ifnet *p) 2302cc2df49SGarrett Wollman { 2312cc2df49SGarrett Wollman struct ifaddr *ifa1, *ifa2; 2322cc2df49SGarrett Wollman struct sockaddr_dl *sdl1, *sdl2; 2332cc2df49SGarrett Wollman 2342cc2df49SGarrett Wollman if (p->if_data.ifi_type != IFT_ETHER) 2352cc2df49SGarrett Wollman return EPROTONOSUPPORT; 2362cc2df49SGarrett Wollman if (ifv->ifv_p) 2372cc2df49SGarrett Wollman return EBUSY; 2382cc2df49SGarrett Wollman ifv->ifv_p = p; 2392cc2df49SGarrett Wollman if (p->if_data.ifi_hdrlen == sizeof(struct ether_vlan_header)) 2402cc2df49SGarrett Wollman ifv->ifv_if.if_mtu = p->if_mtu; 2412cc2df49SGarrett Wollman else 2422cc2df49SGarrett Wollman ifv->ifv_if.if_mtu = p->if_data.ifi_mtu - EVL_ENCAPLEN; 2432cc2df49SGarrett Wollman 2442cc2df49SGarrett Wollman /* 2452cc2df49SGarrett Wollman * NB: we don't support multicast at this point. 2462cc2df49SGarrett Wollman */ 2472cc2df49SGarrett Wollman ifv->ifv_if.if_flags = (p->if_flags & ~IFF_MULTICAST); /* XXX */ 2482cc2df49SGarrett Wollman 2492cc2df49SGarrett Wollman /* 2502cc2df49SGarrett Wollman * Set up our ``Ethernet address'' to reflect the underlying 2512cc2df49SGarrett Wollman * physical interface's. 2522cc2df49SGarrett Wollman */ 2532cc2df49SGarrett Wollman ifa1 = ifnet_addrs[ifv->ifv_if.if_index - 1]; 2542cc2df49SGarrett Wollman ifa2 = ifnet_addrs[p->if_index - 1]; 2552cc2df49SGarrett Wollman sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr; 2562cc2df49SGarrett Wollman sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr; 2572cc2df49SGarrett Wollman sdl1->sdl_type = IFT_ETHER; 2582cc2df49SGarrett Wollman sdl1->sdl_alen = ETHER_ADDR_LEN; 2592cc2df49SGarrett Wollman bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN); 2602cc2df49SGarrett Wollman bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN); 2612cc2df49SGarrett Wollman return 0; 2622cc2df49SGarrett Wollman } 2632cc2df49SGarrett Wollman 2642cc2df49SGarrett Wollman static int 265cfe8b629SGarrett Wollman vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2662cc2df49SGarrett Wollman { 2672cc2df49SGarrett Wollman struct ifaddr *ifa; 2682cc2df49SGarrett Wollman struct ifnet *p; 2692cc2df49SGarrett Wollman struct ifreq *ifr; 2702cc2df49SGarrett Wollman struct ifvlan *ifv; 2712cc2df49SGarrett Wollman struct vlanreq vlr; 2722cc2df49SGarrett Wollman int error = 0; 2732cc2df49SGarrett Wollman 2742cc2df49SGarrett Wollman ifr = (struct ifreq *)data; 2752cc2df49SGarrett Wollman ifa = (struct ifaddr *)data; 2762cc2df49SGarrett Wollman ifv = ifp->if_softc; 2772cc2df49SGarrett Wollman 2782cc2df49SGarrett Wollman switch (cmd) { 2792cc2df49SGarrett Wollman case SIOCSIFADDR: 2802cc2df49SGarrett Wollman ifp->if_flags |= IFF_UP; 2812cc2df49SGarrett Wollman 2822cc2df49SGarrett Wollman switch (ifa->ifa_addr->sa_family) { 2832cc2df49SGarrett Wollman #ifdef INET 2842cc2df49SGarrett Wollman case AF_INET: 2852cc2df49SGarrett Wollman arp_ifinit(&ifv->ifv_ac, ifa); 2862cc2df49SGarrett Wollman break; 2872cc2df49SGarrett Wollman #endif 2882cc2df49SGarrett Wollman default: 2892cc2df49SGarrett Wollman break; 2902cc2df49SGarrett Wollman } 2912cc2df49SGarrett Wollman break; 2922cc2df49SGarrett Wollman 2932cc2df49SGarrett Wollman case SIOCGIFADDR: 2942cc2df49SGarrett Wollman { 2952cc2df49SGarrett Wollman struct sockaddr *sa; 2962cc2df49SGarrett Wollman 2972cc2df49SGarrett Wollman sa = (struct sockaddr *) &ifr->ifr_data; 2982cc2df49SGarrett Wollman bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 2992cc2df49SGarrett Wollman (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 3002cc2df49SGarrett Wollman } 3012cc2df49SGarrett Wollman break; 3022cc2df49SGarrett Wollman 3032cc2df49SGarrett Wollman case SIOCSIFMTU: 3042cc2df49SGarrett Wollman /* 3052cc2df49SGarrett Wollman * Set the interface MTU. 3062cc2df49SGarrett Wollman */ 3072cc2df49SGarrett Wollman if (ifr->ifr_mtu > ETHERMTU) { 3082cc2df49SGarrett Wollman error = EINVAL; 3092cc2df49SGarrett Wollman } else { 3102cc2df49SGarrett Wollman ifp->if_mtu = ifr->ifr_mtu; 3112cc2df49SGarrett Wollman } 3122cc2df49SGarrett Wollman break; 3132cc2df49SGarrett Wollman 3142cc2df49SGarrett Wollman case SIOCSETVLAN: 3152cc2df49SGarrett Wollman error = copyin(ifr->ifr_data, &vlr, sizeof vlr); 3162cc2df49SGarrett Wollman if (error) 3172cc2df49SGarrett Wollman break; 3182cc2df49SGarrett Wollman if (vlr.vlr_parent[0] == '\0') { 3192cc2df49SGarrett Wollman ifv->ifv_p = 0; 3202cc2df49SGarrett Wollman if_down(ifp); 3212cc2df49SGarrett Wollman break; 3222cc2df49SGarrett Wollman } 3232cc2df49SGarrett Wollman p = ifunit(vlr.vlr_parent); 3242cc2df49SGarrett Wollman if (p == 0) { 3252cc2df49SGarrett Wollman error = ENOENT; 3262cc2df49SGarrett Wollman break; 3272cc2df49SGarrett Wollman } 3282cc2df49SGarrett Wollman error = vlan_config(ifv, p); 3292cc2df49SGarrett Wollman if (error) 3302cc2df49SGarrett Wollman break; 3312cc2df49SGarrett Wollman ifv->ifv_tag = vlr.vlr_tag; 3322cc2df49SGarrett Wollman break; 3332cc2df49SGarrett Wollman 3342cc2df49SGarrett Wollman case SIOCGETVLAN: 3352cc2df49SGarrett Wollman bzero(&vlr, sizeof vlr); 3362cc2df49SGarrett Wollman if (ifv->ifv_p) { 3372cc2df49SGarrett Wollman sprintf(vlr.vlr_parent, "%s%d", ifv->ifv_p->if_name, 3382cc2df49SGarrett Wollman ifv->ifv_p->if_unit); 3392cc2df49SGarrett Wollman vlr.vlr_tag = ifv->ifv_tag; 3402cc2df49SGarrett Wollman } 3412cc2df49SGarrett Wollman error = copyout(&vlr, ifr->ifr_data, sizeof vlr); 3422cc2df49SGarrett Wollman break; 3432cc2df49SGarrett Wollman 3442cc2df49SGarrett Wollman case SIOCSIFFLAGS: 3452cc2df49SGarrett Wollman /* 3462cc2df49SGarrett Wollman * We don't support all-multicast or promiscuous modes 3472cc2df49SGarrett Wollman * right now because it would require help from the 3482cc2df49SGarrett Wollman * underlying drivers, which hasn't been implemented. 3492cc2df49SGarrett Wollman */ 3502cc2df49SGarrett Wollman if (ifr->ifr_flags & (IFF_PROMISC|IFF_ALLMULTI)) { 3512cc2df49SGarrett Wollman ifp->if_flags &= ~(IFF_PROMISC|IFF_ALLMULTI); 3522cc2df49SGarrett Wollman error = EINVAL; 3532cc2df49SGarrett Wollman } 3542cc2df49SGarrett Wollman break; 3552cc2df49SGarrett Wollman 3562cc2df49SGarrett Wollman /* NB: this will reject multicast state changes */ 3572cc2df49SGarrett Wollman default: 3582cc2df49SGarrett Wollman error = EINVAL; 3592cc2df49SGarrett Wollman } 3602cc2df49SGarrett Wollman return error; 3612cc2df49SGarrett Wollman } 3622cc2df49SGarrett Wollman 3632cc2df49SGarrett Wollman #endif /* NVLAN > 0 */ 364