Annotation of XNU/bsd/net/if_vlan.c, revision 1.1.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.