Annotation of XNU/bsd/net/if_vlan.c, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.