Annotation of qemu/roms/ipxe/src/net/vlan.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2010 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stdint.h>
        !            22: #include <string.h>
        !            23: #include <stdio.h>
        !            24: #include <errno.h>
        !            25: #include <byteswap.h>
        !            26: #include <ipxe/features.h>
        !            27: #include <ipxe/if_ether.h>
        !            28: #include <ipxe/ethernet.h>
        !            29: #include <ipxe/netdevice.h>
        !            30: #include <ipxe/iobuf.h>
        !            31: #include <ipxe/vlan.h>
        !            32: 
        !            33: /** @file
        !            34:  *
        !            35:  * Virtual LANs
        !            36:  *
        !            37:  */
        !            38: 
        !            39: FEATURE ( FEATURE_PROTOCOL, "VLAN", DHCP_EB_FEATURE_VLAN, 1 );
        !            40: 
        !            41: struct net_protocol vlan_protocol __net_protocol;
        !            42: 
        !            43: /** VLAN device private data */
        !            44: struct vlan_device {
        !            45:        /** Trunk network device */
        !            46:        struct net_device *trunk;
        !            47:        /** VLAN tag */
        !            48:        unsigned int tag;
        !            49:        /** Default priority */
        !            50:        unsigned int priority;
        !            51: };
        !            52: 
        !            53: /**
        !            54:  * Open VLAN device
        !            55:  *
        !            56:  * @v netdev           Network device
        !            57:  * @ret rc             Return status code
        !            58:  */
        !            59: static int vlan_open ( struct net_device *netdev ) {
        !            60:        struct vlan_device *vlan = netdev->priv;
        !            61: 
        !            62:        return netdev_open ( vlan->trunk );
        !            63: }
        !            64: 
        !            65: /**
        !            66:  * Close VLAN device
        !            67:  *
        !            68:  * @v netdev           Network device
        !            69:  */
        !            70: static void vlan_close ( struct net_device *netdev ) {
        !            71:        struct vlan_device *vlan = netdev->priv;
        !            72: 
        !            73:        netdev_close ( vlan->trunk );
        !            74: }
        !            75: 
        !            76: /**
        !            77:  * Transmit packet on VLAN device
        !            78:  *
        !            79:  * @v netdev           Network device
        !            80:  * @v iobuf            I/O buffer
        !            81:  * @ret rc             Return status code
        !            82:  */
        !            83: static int vlan_transmit ( struct net_device *netdev,
        !            84:                           struct io_buffer *iobuf ) {
        !            85:        struct vlan_device *vlan = netdev->priv;
        !            86:        struct net_device *trunk = vlan->trunk;
        !            87:        struct ll_protocol *ll_protocol;
        !            88:        struct vlan_header *vlanhdr;
        !            89:        uint8_t ll_dest_copy[ETH_ALEN];
        !            90:        uint8_t ll_source_copy[ETH_ALEN];
        !            91:        const void *ll_dest;
        !            92:        const void *ll_source;
        !            93:        uint16_t net_proto;
        !            94:        int rc;
        !            95: 
        !            96:        /* Strip link-layer header and preserve link-layer header fields */
        !            97:        ll_protocol = netdev->ll_protocol;
        !            98:        if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
        !            99:                                        &net_proto ) ) != 0 ) {
        !           100:                DBGC ( netdev, "VLAN %s could not parse link-layer header: "
        !           101:                       "%s\n", netdev->name, strerror ( rc ) );
        !           102:                return rc;
        !           103:        }
        !           104:        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
        !           105:        memcpy ( ll_source_copy, ll_source, ETH_ALEN );
        !           106: 
        !           107:        /* Construct VLAN header */
        !           108:        vlanhdr = iob_push ( iobuf, sizeof ( *vlanhdr ) );
        !           109:        vlanhdr->tci = htons ( VLAN_TCI ( vlan->tag, vlan->priority ) );
        !           110:        vlanhdr->net_proto = net_proto;
        !           111: 
        !           112:        /* Reclaim I/O buffer from VLAN device's TX queue */
        !           113:        list_del ( &iobuf->list );
        !           114: 
        !           115:        /* Transmit packet on trunk device */
        !           116:        if ( ( rc = net_tx ( iob_disown ( iobuf ), trunk, &vlan_protocol,
        !           117:                             ll_dest_copy, ll_source_copy ) ) != 0 ) {
        !           118:                DBGC ( netdev, "VLAN %s could not transmit: %s\n",
        !           119:                       netdev->name, strerror ( rc ) );
        !           120:                /* Cannot return an error status, since that would
        !           121:                 * cause the I/O buffer to be double-freed.
        !           122:                 */
        !           123:                return 0;
        !           124:        }
        !           125: 
        !           126:        return 0;
        !           127: }
        !           128: 
        !           129: /**
        !           130:  * Poll VLAN device
        !           131:  *
        !           132:  * @v netdev           Network device
        !           133:  */
        !           134: static void vlan_poll ( struct net_device *netdev ) {
        !           135:        struct vlan_device *vlan = netdev->priv;
        !           136: 
        !           137:        /* Poll trunk device */
        !           138:        netdev_poll ( vlan->trunk );
        !           139: }
        !           140: 
        !           141: /**
        !           142:  * Enable/disable interrupts on VLAN device
        !           143:  *
        !           144:  * @v netdev           Network device
        !           145:  * @v enable           Interrupts should be enabled
        !           146:  */
        !           147: static void vlan_irq ( struct net_device *netdev, int enable ) {
        !           148:        struct vlan_device *vlan = netdev->priv;
        !           149: 
        !           150:        /* Enable/disable interrupts on trunk device.  This is not at
        !           151:         * all robust, but there is no sensible course of action
        !           152:         * available.
        !           153:         */
        !           154:        netdev_irq ( vlan->trunk, enable );
        !           155: }
        !           156: 
        !           157: /** VLAN device operations */
        !           158: static struct net_device_operations vlan_operations = {
        !           159:        .open           = vlan_open,
        !           160:        .close          = vlan_close,
        !           161:        .transmit       = vlan_transmit,
        !           162:        .poll           = vlan_poll,
        !           163:        .irq            = vlan_irq,
        !           164: };
        !           165: 
        !           166: /**
        !           167:  * Synchronise VLAN device
        !           168:  *
        !           169:  * @v netdev           Network device
        !           170:  */
        !           171: static void vlan_sync ( struct net_device *netdev ) {
        !           172:        struct vlan_device *vlan = netdev->priv;
        !           173:        struct net_device *trunk = vlan->trunk;
        !           174: 
        !           175:        /* Synchronise link status */
        !           176:        if ( netdev->link_rc != trunk->link_rc )
        !           177:                netdev_link_err ( netdev, trunk->link_rc );
        !           178: 
        !           179:        /* Synchronise open/closed status */
        !           180:        if ( netdev_is_open ( trunk ) ) {
        !           181:                if ( ! netdev_is_open ( netdev ) )
        !           182:                        netdev_open ( netdev );
        !           183:        } else {
        !           184:                if ( netdev_is_open ( netdev ) )
        !           185:                        netdev_close ( netdev );
        !           186:        }
        !           187: }
        !           188: 
        !           189: /**
        !           190:  * Identify VLAN device
        !           191:  *
        !           192:  * @v trunk            Trunk network device
        !           193:  * @v tag              VLAN tag
        !           194:  * @ret netdev         VLAN device, if any
        !           195:  */
        !           196: struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
        !           197:        struct net_device *netdev;
        !           198:        struct vlan_device *vlan;
        !           199: 
        !           200:        for_each_netdev ( netdev ) {
        !           201:                if ( netdev->op != &vlan_operations )
        !           202:                        continue;
        !           203:                vlan = netdev->priv;
        !           204:                if ( ( vlan->trunk == trunk ) && ( vlan->tag == tag ) )
        !           205:                        return netdev;
        !           206:        }
        !           207:        return NULL;
        !           208: }
        !           209: 
        !           210: /**
        !           211:  * Process incoming VLAN packet
        !           212:  *
        !           213:  * @v iobuf            I/O buffer
        !           214:  * @v trunk            Trunk network device
        !           215:  * @v ll_dest          Link-layer destination address
        !           216:  * @v ll_source                Link-layer source address
        !           217:  * @ret rc             Return status code
        !           218:  */
        !           219: static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
        !           220:                     const void *ll_dest, const void *ll_source ) {
        !           221:        struct vlan_header *vlanhdr = iobuf->data;
        !           222:        struct net_device *netdev;
        !           223:        struct ll_protocol *ll_protocol;
        !           224:        uint8_t ll_dest_copy[ETH_ALEN];
        !           225:        uint8_t ll_source_copy[ETH_ALEN];
        !           226:        uint16_t tag;
        !           227:        int rc;
        !           228: 
        !           229:        /* Sanity check */
        !           230:        if ( iob_len ( iobuf ) < sizeof ( *vlanhdr ) ) {
        !           231:                DBGC ( trunk, "VLAN %s received underlength packet (%zd "
        !           232:                       "bytes)\n", trunk->name, iob_len ( iobuf ) );
        !           233:                rc = -EINVAL;
        !           234:                goto err_sanity;
        !           235:        }
        !           236: 
        !           237:        /* Identify VLAN device */
        !           238:        tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) );
        !           239:        netdev = vlan_find ( trunk, tag );
        !           240:        if ( ! netdev ) {
        !           241:                DBGC2 ( trunk, "VLAN %s received packet for unknown VLAN "
        !           242:                        "%d\n", trunk->name, tag );
        !           243:                rc = -EPIPE;
        !           244:                goto err_no_vlan;
        !           245:        }
        !           246: 
        !           247:        /* Strip VLAN header and preserve original link-layer header fields */
        !           248:        iob_pull ( iobuf, sizeof ( *vlanhdr ) );
        !           249:        ll_protocol = trunk->ll_protocol;
        !           250:        memcpy ( ll_dest_copy, ll_dest, ETH_ALEN );
        !           251:        memcpy ( ll_source_copy, ll_source, ETH_ALEN );
        !           252: 
        !           253:        /* Reconstruct link-layer header for VLAN device */
        !           254:        ll_protocol = netdev->ll_protocol;
        !           255:        if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest_copy,
        !           256:                                        ll_source_copy,
        !           257:                                        vlanhdr->net_proto ) ) != 0 ) {
        !           258:                DBGC ( netdev, "VLAN %s could not reconstruct link-layer "
        !           259:                       "header: %s\n", netdev->name, strerror ( rc ) );
        !           260:                goto err_ll_push;
        !           261:        }
        !           262: 
        !           263:        /* Enqueue packet on VLAN device */
        !           264:        netdev_rx ( netdev, iob_disown ( iobuf ) );
        !           265:        return 0;
        !           266: 
        !           267:  err_ll_push:
        !           268:  err_no_vlan:
        !           269:  err_sanity:
        !           270:        free_iob ( iobuf );
        !           271:        return rc;
        !           272: }
        !           273: 
        !           274: /** VLAN protocol */
        !           275: struct net_protocol vlan_protocol __net_protocol = {
        !           276:        .name = "VLAN",
        !           277:        .net_proto = htons ( ETH_P_8021Q ),
        !           278:        .rx = vlan_rx,
        !           279: };
        !           280: 
        !           281: /**
        !           282:  * Check if network device can be used as a VLAN trunk device
        !           283:  *
        !           284:  * @v trunk            Trunk network device
        !           285:  * @ret is_ok          Trunk network device is usable
        !           286:  *
        !           287:  * VLAN devices will be created as Ethernet devices.  (We cannot
        !           288:  * simply clone the link layer of the trunk network device, because
        !           289:  * this link layer may expect the network device structure to contain
        !           290:  * some link-layer-private data.)  The trunk network device must
        !           291:  * therefore have a link layer that is in some sense 'compatible' with
        !           292:  * Ethernet; specifically, it must have link-layer addresses that are
        !           293:  * the same length as Ethernet link-layer addresses.
        !           294:  *
        !           295:  * As an additional check, and primarily to assist with the sanity of
        !           296:  * the FCoE code, we refuse to allow nested VLANs.
        !           297:  */
        !           298: int vlan_can_be_trunk ( struct net_device *trunk ) {
        !           299: 
        !           300:        return ( ( trunk->ll_protocol->ll_addr_len == ETH_ALEN ) &&
        !           301:                 ( trunk->op != &vlan_operations ) );
        !           302: }
        !           303: 
        !           304: /**
        !           305:  * Create VLAN device
        !           306:  *
        !           307:  * @v trunk            Trunk network device
        !           308:  * @v tag              VLAN tag
        !           309:  * @v priority         Default VLAN priority
        !           310:  * @ret rc             Return status code
        !           311:  */
        !           312: int vlan_create ( struct net_device *trunk, unsigned int tag,
        !           313:                  unsigned int priority ) {
        !           314:        struct net_device *netdev;
        !           315:        struct vlan_device *vlan;
        !           316:        int rc;
        !           317: 
        !           318:        /* If VLAN already exists, just update the priority */
        !           319:        if ( ( netdev = vlan_find ( trunk, tag ) ) != NULL ) {
        !           320:                vlan = netdev->priv;
        !           321:                if ( priority != vlan->priority ) {
        !           322:                        DBGC ( netdev, "VLAN %s priority changed from %d to "
        !           323:                               "%d\n", netdev->name, vlan->priority, priority );
        !           324:                }
        !           325:                vlan->priority = priority;
        !           326:                return 0;
        !           327:        }
        !           328: 
        !           329:        /* Sanity checks */
        !           330:        if ( ! vlan_can_be_trunk ( trunk ) ) {
        !           331:                DBGC ( trunk, "VLAN %s cannot create VLAN on non-trunk "
        !           332:                       "device\n", trunk->name );
        !           333:                rc = -ENOTTY;
        !           334:                goto err_sanity;
        !           335:        }
        !           336:        if ( ! VLAN_TAG_IS_VALID ( tag ) ) {
        !           337:                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid tag "
        !           338:                       "%d\n", trunk->name, tag );
        !           339:                rc = -EINVAL;
        !           340:                goto err_sanity;
        !           341:        }
        !           342:        if ( ! VLAN_PRIORITY_IS_VALID ( priority ) ) {
        !           343:                DBGC ( trunk, "VLAN %s cannot create VLAN with invalid "
        !           344:                       "priority %d\n", trunk->name, priority );
        !           345:                rc = -EINVAL;
        !           346:                goto err_sanity;
        !           347:        }
        !           348: 
        !           349:        /* Allocate and initialise structure */
        !           350:        netdev = alloc_etherdev ( sizeof ( *vlan ) );
        !           351:        if ( ! netdev ) {
        !           352:                rc = -ENOMEM;
        !           353:                goto err_alloc_etherdev;
        !           354:        }
        !           355:        netdev_init ( netdev, &vlan_operations );
        !           356:        netdev->dev = trunk->dev;
        !           357:        memcpy ( netdev->hw_addr, trunk->ll_addr, ETH_ALEN );
        !           358:        vlan = netdev->priv;
        !           359:        vlan->trunk = netdev_get ( trunk );
        !           360:        vlan->tag = tag;
        !           361:        vlan->priority = priority;
        !           362: 
        !           363:        /* Construct VLAN device name */
        !           364:        snprintf ( netdev->name, sizeof ( netdev->name ), "%s-%d",
        !           365:                   trunk->name, vlan->tag );
        !           366: 
        !           367:        /* Register VLAN device */
        !           368:        if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
        !           369:                DBGC ( netdev, "VLAN %s could not register: %s\n",
        !           370:                       netdev->name, strerror ( rc ) );
        !           371:                goto err_register;
        !           372:        }
        !           373: 
        !           374:        /* Synchronise with trunk device */
        !           375:        vlan_sync ( netdev );
        !           376: 
        !           377:        DBGC ( netdev, "VLAN %s created with tag %d and priority %d\n",
        !           378:               netdev->name, vlan->tag, vlan->priority );
        !           379: 
        !           380:        return 0;
        !           381: 
        !           382:        unregister_netdev ( netdev );
        !           383:  err_register:
        !           384:        netdev_nullify ( netdev );
        !           385:        netdev_put ( netdev );
        !           386:        netdev_put ( trunk );
        !           387:  err_alloc_etherdev:
        !           388:  err_sanity:
        !           389:        return rc;
        !           390: }
        !           391: 
        !           392: /**
        !           393:  * Destroy VLAN device
        !           394:  *
        !           395:  * @v netdev           Network device
        !           396:  * @ret rc             Return status code
        !           397:  */
        !           398: int vlan_destroy ( struct net_device *netdev ) {
        !           399:        struct vlan_device *vlan = netdev->priv;
        !           400:        struct net_device *trunk;
        !           401: 
        !           402:        /* Sanity check */
        !           403:        if ( netdev->op != &vlan_operations ) {
        !           404:                DBGC ( netdev, "VLAN %s cannot destroy non-VLAN device\n",
        !           405:                       netdev->name );
        !           406:                return -ENOTTY;
        !           407:        }
        !           408: 
        !           409:        DBGC ( netdev, "VLAN %s destroyed\n", netdev->name );
        !           410: 
        !           411:        /* Remove VLAN device */
        !           412:        unregister_netdev ( netdev );
        !           413:        trunk = vlan->trunk;
        !           414:        netdev_nullify ( netdev );
        !           415:        netdev_put ( netdev );
        !           416:        netdev_put ( trunk );
        !           417: 
        !           418:        return 0;
        !           419: }
        !           420: 
        !           421: /**
        !           422:  * Do nothing
        !           423:  *
        !           424:  * @v trunk            Trunk network device
        !           425:  * @ret rc             Return status code
        !           426:  */
        !           427: static int vlan_probe ( struct net_device *trunk __unused ) {
        !           428:        return 0;
        !           429: }
        !           430: 
        !           431: /**
        !           432:  * Handle trunk network device link state change
        !           433:  *
        !           434:  * @v trunk            Trunk network device
        !           435:  */
        !           436: static void vlan_notify ( struct net_device *trunk ) {
        !           437:        struct net_device *netdev;
        !           438:        struct vlan_device *vlan;
        !           439: 
        !           440:        for_each_netdev ( netdev ) {
        !           441:                if ( netdev->op != &vlan_operations )
        !           442:                        continue;
        !           443:                vlan = netdev->priv;
        !           444:                if ( vlan->trunk == trunk )
        !           445:                        vlan_sync ( netdev );
        !           446:        }
        !           447: }
        !           448: 
        !           449: /**
        !           450:  * Destroy first VLAN device for a given trunk
        !           451:  *
        !           452:  * @v trunk            Trunk network device
        !           453:  * @ret found          A VLAN device was found
        !           454:  */
        !           455: static int vlan_remove_first ( struct net_device *trunk ) {
        !           456:        struct net_device *netdev;
        !           457:        struct vlan_device *vlan;
        !           458: 
        !           459:        for_each_netdev ( netdev ) {
        !           460:                if ( netdev->op != &vlan_operations )
        !           461:                        continue;
        !           462:                vlan = netdev->priv;
        !           463:                if ( vlan->trunk == trunk ) {
        !           464:                        vlan_destroy ( netdev );
        !           465:                        return 1;
        !           466:                }
        !           467:        }
        !           468:        return 0;
        !           469: }
        !           470: 
        !           471: /**
        !           472:  * Destroy all VLAN devices for a given trunk
        !           473:  *
        !           474:  * @v trunk            Trunk network device
        !           475:  */
        !           476: static void vlan_remove ( struct net_device *trunk ) {
        !           477: 
        !           478:        /* Remove all VLAN devices attached to this trunk, safe
        !           479:         * against arbitrary net device removal.
        !           480:         */
        !           481:        while ( vlan_remove_first ( trunk ) ) {}
        !           482: }
        !           483: 
        !           484: /** VLAN driver */
        !           485: struct net_driver vlan_driver __net_driver = {
        !           486:        .name = "VLAN",
        !           487:        .probe = vlan_probe,
        !           488:        .notify = vlan_notify,
        !           489:        .remove = vlan_remove,
        !           490: };

unix.superglobalmegacorp.com

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