Annotation of qemu/roms/ipxe/src/net/fcoe.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 <stddef.h>
        !            22: #include <stdlib.h>
        !            23: #include <errno.h>
        !            24: #include <byteswap.h>
        !            25: #include <ipxe/if_ether.h>
        !            26: #include <ipxe/if_arp.h>
        !            27: #include <ipxe/iobuf.h>
        !            28: #include <ipxe/interface.h>
        !            29: #include <ipxe/xfer.h>
        !            30: #include <ipxe/netdevice.h>
        !            31: #include <ipxe/ethernet.h>
        !            32: #include <ipxe/vlan.h>
        !            33: #include <ipxe/features.h>
        !            34: #include <ipxe/errortab.h>
        !            35: #include <ipxe/device.h>
        !            36: #include <ipxe/crc32.h>
        !            37: #include <ipxe/retry.h>
        !            38: #include <ipxe/timer.h>
        !            39: #include <ipxe/fc.h>
        !            40: #include <ipxe/fip.h>
        !            41: #include <ipxe/fcoe.h>
        !            42: 
        !            43: /** @file
        !            44:  *
        !            45:  * FCoE protocol
        !            46:  *
        !            47:  */
        !            48: 
        !            49: FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 );
        !            50: 
        !            51: /* Disambiguate the various error causes */
        !            52: #define EINVAL_UNDERLENGTH __einfo_error ( EINFO_EINVAL_UNDERLENGTH )
        !            53: #define EINFO_EINVAL_UNDERLENGTH \
        !            54:        __einfo_uniqify ( EINFO_EINVAL, 0x01, "Underlength packet" )
        !            55: #define EINVAL_SOF __einfo_error ( EINFO_EINVAL_SOF )
        !            56: #define EINFO_EINVAL_SOF \
        !            57:        __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid SoF delimiter" )
        !            58: #define EINVAL_CRC __einfo_error ( EINFO_EINVAL_CRC )
        !            59: #define EINFO_EINVAL_CRC \
        !            60:        __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid CRC (not stripped?)" )
        !            61: #define EINVAL_EOF __einfo_error ( EINFO_EINVAL_EOF )
        !            62: #define EINFO_EINVAL_EOF \
        !            63:        __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid EoF delimiter" )
        !            64: 
        !            65: /** An FCoE port */
        !            66: struct fcoe_port {
        !            67:        /** Reference count */
        !            68:        struct refcnt refcnt;
        !            69:        /** List of FCoE ports */
        !            70:        struct list_head list;
        !            71:        /** Transport interface */
        !            72:        struct interface transport;
        !            73:        /** Network device */
        !            74:        struct net_device *netdev;
        !            75: 
        !            76:        /** Node WWN */
        !            77:        union fcoe_name node_wwn;
        !            78:        /** Port WWN */
        !            79:        union fcoe_name port_wwn;
        !            80: 
        !            81:        /** FIP retransmission timer */
        !            82:        struct retry_timer timer;
        !            83:        /** FIP timeout counter */
        !            84:        unsigned int timeouts;
        !            85:        /** Flags */
        !            86:        unsigned int flags;
        !            87:        /** FCoE forwarder priority */
        !            88:        unsigned int priority;
        !            89:        /** Keepalive delay (in ms) */
        !            90:        unsigned int keepalive;
        !            91:        /** FCoE forwarder MAC address */
        !            92:        uint8_t fcf_mac[ETH_ALEN];
        !            93:        /** Local MAC address */
        !            94:        uint8_t local_mac[ETH_ALEN];
        !            95: };
        !            96: 
        !            97: /** FCoE flags */
        !            98: enum fcoe_flags {
        !            99:        /** Underlying network device is available */
        !           100:        FCOE_HAVE_NETWORK = 0x0001,
        !           101:        /** We have selected an FCoE forwarder to use */
        !           102:        FCOE_HAVE_FCF = 0x0002,
        !           103:        /** We have a FIP-capable FCoE forwarder available to be used */
        !           104:        FCOE_HAVE_FIP_FCF = 0x0004,
        !           105:        /** FCoE forwarder supports server-provided MAC addresses */
        !           106:        FCOE_FCF_ALLOWS_SPMA = 0x0008,
        !           107:        /** An alternative VLAN has been found */
        !           108:        FCOE_VLAN_FOUND = 0x0010,
        !           109:        /** VLAN discovery has timed out */
        !           110:        FCOE_VLAN_TIMED_OUT = 0x0020,
        !           111: };
        !           112: 
        !           113: struct net_protocol fcoe_protocol __net_protocol;
        !           114: struct net_protocol fip_protocol __net_protocol;
        !           115: 
        !           116: /** FCoE All-FCoE-MACs address */
        !           117: static uint8_t all_fcoe_macs[ETH_ALEN] =
        !           118:        { 0x01, 0x10, 0x18, 0x01, 0x00, 0x00 };
        !           119: 
        !           120: /** FCoE All-ENode-MACs address */
        !           121: static uint8_t all_enode_macs[ETH_ALEN] =
        !           122:        { 0x01, 0x10, 0x18, 0x01, 0x00, 0x01 };
        !           123: 
        !           124: /** FCoE All-FCF-MACs address */
        !           125: static uint8_t all_fcf_macs[ETH_ALEN] =
        !           126:        { 0x01, 0x10, 0x18, 0x01, 0x00, 0x02 };
        !           127: 
        !           128: /** Default FCoE forwarded MAC address */
        !           129: static uint8_t default_fcf_mac[ETH_ALEN] =
        !           130:        { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe };
        !           131: 
        !           132: /** Maximum number of VLAN requests before giving up on VLAN discovery */
        !           133: #define FCOE_MAX_VLAN_REQUESTS 2
        !           134: 
        !           135: /** Delay between retrying VLAN requests */
        !           136: #define FCOE_VLAN_RETRY_DELAY ( TICKS_PER_SEC )
        !           137: 
        !           138: /** Delay between retrying polling VLAN requests */
        !           139: #define FCOE_VLAN_POLL_DELAY ( 30 * TICKS_PER_SEC )
        !           140: 
        !           141: /** Maximum number of FIP solicitations before giving up on FIP */
        !           142: #define FCOE_MAX_FIP_SOLICITATIONS 2
        !           143: 
        !           144: /** Delay between retrying FIP solicitations */
        !           145: #define FCOE_FIP_RETRY_DELAY ( TICKS_PER_SEC )
        !           146: 
        !           147: /** Maximum number of missing discovery advertisements */
        !           148: #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4
        !           149: 
        !           150: /** List of FCoE ports */
        !           151: static LIST_HEAD ( fcoe_ports );
        !           152: 
        !           153: /******************************************************************************
        !           154:  *
        !           155:  * FCoE protocol
        !           156:  *
        !           157:  ******************************************************************************
        !           158:  */
        !           159: 
        !           160: /**
        !           161:  * Identify FCoE port by network device
        !           162:  *
        !           163:  * @v netdev           Network device
        !           164:  * @ret fcoe           FCoE port, or NULL
        !           165:  */
        !           166: static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) {
        !           167:        struct fcoe_port *fcoe;
        !           168: 
        !           169:        list_for_each_entry ( fcoe, &fcoe_ports, list ) {
        !           170:                if ( fcoe->netdev == netdev )
        !           171:                        return fcoe;
        !           172:        }
        !           173:        return NULL;
        !           174: }
        !           175: 
        !           176: /**
        !           177:  * Reset FCoE port
        !           178:  *
        !           179:  * @v fcoe             FCoE port
        !           180:  */
        !           181: static void fcoe_reset ( struct fcoe_port *fcoe ) {
        !           182: 
        !           183:        /* Detach FC port, if any */
        !           184:        intf_restart ( &fcoe->transport, -ECANCELED );
        !           185: 
        !           186:        /* Reset any FIP state */
        !           187:        stop_timer ( &fcoe->timer );
        !           188:        fcoe->timeouts = 0;
        !           189:        fcoe->flags = 0;
        !           190:        fcoe->priority = ( FIP_LOWEST_PRIORITY + 1 );
        !           191:        fcoe->keepalive = 0;
        !           192:        memcpy ( fcoe->fcf_mac, default_fcf_mac,
        !           193:                 sizeof ( fcoe->fcf_mac ) );
        !           194:        memcpy ( fcoe->local_mac, fcoe->netdev->ll_addr,
        !           195:                 sizeof ( fcoe->local_mac ) );
        !           196: 
        !           197:        /* Start FIP solicitation if network is available */
        !           198:        if ( netdev_is_open ( fcoe->netdev ) &&
        !           199:             netdev_link_ok ( fcoe->netdev ) ) {
        !           200:                fcoe->flags |= FCOE_HAVE_NETWORK;
        !           201:                start_timer_nodelay ( &fcoe->timer );
        !           202:                DBGC ( fcoe, "FCoE %s starting %s\n", fcoe->netdev->name,
        !           203:                       ( vlan_can_be_trunk ( fcoe->netdev ) ?
        !           204:                         "VLAN discovery" : "FIP solicitation" ) );
        !           205:        }
        !           206: 
        !           207:        /* Send notification of window change */
        !           208:        xfer_window_changed ( &fcoe->transport );
        !           209: }
        !           210: 
        !           211: /**
        !           212:  * Transmit FCoE packet
        !           213:  *
        !           214:  * @v fcoe             FCoE port
        !           215:  * @v iobuf            I/O buffer
        !           216:  * @v meta             Data transfer metadata
        !           217:  * @ret rc             Return status code
        !           218:  */
        !           219: static int fcoe_deliver ( struct fcoe_port *fcoe,
        !           220:                          struct io_buffer *iobuf,
        !           221:                          struct xfer_metadata *meta __unused ) {
        !           222:        struct fc_frame_header *fchdr = iobuf->data;
        !           223:        struct fc_els_frame_common *els = ( iobuf->data + sizeof ( *fchdr ) );
        !           224:        struct fcoe_header *fcoehdr;
        !           225:        struct fcoe_footer *fcoeftr;
        !           226:        struct fip_header *fiphdr;
        !           227:        struct fip_login *fipflogi;
        !           228:        struct fip_mac_address *fipmac;
        !           229:        uint32_t crc;
        !           230:        struct net_protocol *net_protocol;
        !           231:        void *ll_source;
        !           232:        int rc;
        !           233: 
        !           234:        /* Send as FIP or FCoE as appropriate */
        !           235:        if ( ( fchdr->r_ctl == ( FC_R_CTL_ELS | FC_R_CTL_UNSOL_CTRL ) ) &&
        !           236:             ( els->command == FC_ELS_FLOGI ) &&
        !           237:             ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) {
        !           238: 
        !           239:                /* Create FIP FLOGI descriptor */
        !           240:                fipflogi = iob_push ( iobuf,
        !           241:                                      offsetof ( typeof ( *fipflogi ), fc ) );
        !           242:                memset ( fipflogi, 0, offsetof ( typeof ( *fipflogi ), fc ) );
        !           243:                fipflogi->type = FIP_FLOGI;
        !           244:                fipflogi->len = ( iob_len ( iobuf ) / 4 );
        !           245: 
        !           246:                /* Create FIP MAC address descriptor */
        !           247:                fipmac = iob_put ( iobuf, sizeof ( *fipmac ) );
        !           248:                memset ( fipmac, 0, sizeof ( *fipmac ) );
        !           249:                fipmac->type = FIP_MAC_ADDRESS;
        !           250:                fipmac->len = ( sizeof ( *fipmac ) / 4 );
        !           251:                if ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) {
        !           252:                        memcpy ( fipmac->mac, fcoe->netdev->ll_addr,
        !           253:                                 sizeof ( fipmac->mac ) );
        !           254:                }
        !           255: 
        !           256:                /* Create FIP header */
        !           257:                fiphdr = iob_push ( iobuf, sizeof ( *fiphdr ) );
        !           258:                memset ( fiphdr, 0, sizeof ( *fiphdr ) );
        !           259:                fiphdr->version = FIP_VERSION;
        !           260:                fiphdr->code = htons ( FIP_CODE_ELS );
        !           261:                fiphdr->subcode = FIP_ELS_REQUEST;
        !           262:                fiphdr->len =
        !           263:                        htons ( ( iob_len ( iobuf ) - sizeof ( *fiphdr ) ) / 4);
        !           264:                fiphdr->flags = ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
        !           265:                                  htons ( FIP_SP ) : htons ( FIP_FP ) );
        !           266: 
        !           267:                /* Send as FIP packet from netdev's own MAC address */
        !           268:                net_protocol = &fip_protocol;
        !           269:                ll_source = fcoe->netdev->ll_addr;
        !           270: 
        !           271:        } else {
        !           272: 
        !           273:                /* Calculate CRC */
        !           274:                crc = crc32_le ( ~((uint32_t)0), iobuf->data,
        !           275:                                 iob_len ( iobuf ) );
        !           276: 
        !           277:                /* Create FCoE header */
        !           278:                fcoehdr = iob_push ( iobuf, sizeof ( *fcoehdr ) );
        !           279:                memset ( fcoehdr, 0, sizeof ( *fcoehdr ) );
        !           280:                fcoehdr->sof = ( ( fchdr->seq_cnt == ntohs ( 0 ) ) ?
        !           281:                                 FCOE_SOF_I3 : FCOE_SOF_N3 );
        !           282: 
        !           283:                /* Create FCoE footer */
        !           284:                fcoeftr = iob_put ( iobuf, sizeof ( *fcoeftr ) );
        !           285:                memset ( fcoeftr, 0, sizeof ( *fcoeftr ) );
        !           286:                fcoeftr->crc = cpu_to_le32 ( crc ^ ~((uint32_t)0) );
        !           287:                fcoeftr->eof = ( ( fchdr->f_ctl_es & FC_F_CTL_ES_END ) ?
        !           288:                                 FCOE_EOF_T : FCOE_EOF_N );
        !           289: 
        !           290:                /* Send as FCoE packet from FCoE MAC address */
        !           291:                net_protocol = &fcoe_protocol;
        !           292:                ll_source = fcoe->local_mac;
        !           293:        }
        !           294: 
        !           295:        /* Transmit packet */
        !           296:        if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev, net_protocol,
        !           297:                             fcoe->fcf_mac, ll_source ) ) != 0 ) {
        !           298:                DBGC ( fcoe, "FCoE %s could not transmit: %s\n",
        !           299:                       fcoe->netdev->name, strerror ( rc ) );
        !           300:                goto done;
        !           301:        }
        !           302: 
        !           303:  done:
        !           304:        free_iob ( iobuf );
        !           305:        return rc;
        !           306: }
        !           307: 
        !           308: /**
        !           309:  * Allocate FCoE I/O buffer
        !           310:  *
        !           311:  * @v len              Payload length
        !           312:  * @ret iobuf          I/O buffer, or NULL
        !           313:  */
        !           314: static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
        !           315:                                           size_t len ) {
        !           316:        struct io_buffer *iobuf;
        !           317: 
        !           318:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( struct fcoe_header ) +
        !           319:                            len + sizeof ( struct fcoe_footer ) );
        !           320:        if ( iobuf ) {
        !           321:                iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN +
        !           322:                                       sizeof ( struct fcoe_header ) ) );
        !           323:        }
        !           324:        return iobuf;
        !           325: }
        !           326: 
        !           327: /**
        !           328:  * Process incoming FCoE packets
        !           329:  *
        !           330:  * @v iobuf            I/O buffer
        !           331:  * @v netdev           Network device
        !           332:  * @v ll_dest          Link-layer destination address
        !           333:  * @v ll_source                Link-layer source address
        !           334:  * @ret rc             Return status code
        !           335:  */
        !           336: static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        !           337:                     const void *ll_dest, const void *ll_source ) {
        !           338:        struct fcoe_header *fcoehdr;
        !           339:        struct fcoe_footer *fcoeftr;
        !           340:        struct fcoe_port *fcoe;
        !           341:        int rc;
        !           342: 
        !           343:        /* Identify FCoE port */
        !           344:        if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
        !           345:                DBG ( "FCoE received frame for net device %s missing FCoE "
        !           346:                      "port\n", netdev->name );
        !           347:                rc = -ENOTCONN;
        !           348:                goto done;
        !           349:        }
        !           350: 
        !           351:        /* Discard packets not destined for us */
        !           352:        if ( ( memcmp ( fcoe->local_mac, ll_dest,
        !           353:                        sizeof ( fcoe->local_mac ) ) != 0 ) &&
        !           354:             ( memcmp ( default_fcf_mac, ll_dest,
        !           355:                        sizeof ( default_fcf_mac ) ) != 0 ) ) {
        !           356:                DBGC2 ( fcoe, "FCoE %s ignoring packet for %s\n",
        !           357:                        fcoe->netdev->name, eth_ntoa ( ll_dest ) );
        !           358:                rc = -ENOTCONN;
        !           359:                goto done;
        !           360:        }
        !           361: 
        !           362:        /* Sanity check */
        !           363:        if ( iob_len ( iobuf ) < ( sizeof ( *fcoehdr ) + sizeof ( *fcoeftr ) )){
        !           364:                DBGC ( fcoe, "FCoE %s received under-length frame (%zd "
        !           365:                       "bytes)\n", fcoe->netdev->name, iob_len ( iobuf ) );
        !           366:                rc = -EINVAL_UNDERLENGTH;
        !           367:                goto done;
        !           368:        }
        !           369: 
        !           370:        /* Strip header and footer */
        !           371:        fcoehdr = iobuf->data;
        !           372:        iob_pull ( iobuf, sizeof ( *fcoehdr ) );
        !           373:        fcoeftr = ( iobuf->data + iob_len ( iobuf ) - sizeof ( *fcoeftr ) );
        !           374:        iob_unput ( iobuf, sizeof ( *fcoeftr ) );
        !           375: 
        !           376:        /* Validity checks */
        !           377:        if ( fcoehdr->version != FCOE_FRAME_VER ) {
        !           378:                DBGC ( fcoe, "FCoE %s received unsupported frame version "
        !           379:                       "%02x\n", fcoe->netdev->name, fcoehdr->version );
        !           380:                rc = -EPROTONOSUPPORT;
        !           381:                goto done;
        !           382:        }
        !           383:        if ( ! ( ( fcoehdr->sof == FCOE_SOF_I3 ) ||
        !           384:                 ( fcoehdr->sof == FCOE_SOF_N3 ) ) ) {
        !           385:                DBGC ( fcoe, "FCoE %s received unsupported start-of-frame "
        !           386:                       "delimiter %02x\n", fcoe->netdev->name, fcoehdr->sof );
        !           387:                rc = -EINVAL_SOF;
        !           388:                goto done;
        !           389:        }
        !           390:        if ( ( le32_to_cpu ( fcoeftr->crc ) ^ ~((uint32_t)0) ) !=
        !           391:             crc32_le ( ~((uint32_t)0), iobuf->data, iob_len ( iobuf ) ) ) {
        !           392:                DBGC ( fcoe, "FCoE %s received invalid CRC\n",
        !           393:                       fcoe->netdev->name );
        !           394:                rc = -EINVAL_CRC;
        !           395:                goto done;
        !           396:        }
        !           397:        if ( ! ( ( fcoeftr->eof == FCOE_EOF_N ) ||
        !           398:                 ( fcoeftr->eof == FCOE_EOF_T ) ) ) {
        !           399:                DBGC ( fcoe, "FCoE %s received unsupported end-of-frame "
        !           400:                       "delimiter %02x\n", fcoe->netdev->name, fcoeftr->eof );
        !           401:                rc = -EINVAL_EOF;
        !           402:                goto done;
        !           403:        }
        !           404: 
        !           405:        /* Record FCF address if applicable */
        !           406:        if ( ( fcoe->flags & FCOE_HAVE_FCF ) &&
        !           407:             ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) ) {
        !           408:                memcpy ( &fcoe->fcf_mac, ll_source, sizeof ( fcoe->fcf_mac ) );
        !           409:        }
        !           410: 
        !           411:        /* Hand off via transport interface */
        !           412:        if ( ( rc = xfer_deliver_iob ( &fcoe->transport,
        !           413:                                       iob_disown ( iobuf ) ) ) != 0 ) {
        !           414:                DBGC ( fcoe, "FCoE %s could not deliver frame: %s\n",
        !           415:                       fcoe->netdev->name, strerror ( rc ) );
        !           416:                goto done;
        !           417:        }
        !           418: 
        !           419:  done:
        !           420:        free_iob ( iobuf );
        !           421:        return rc;
        !           422: }
        !           423: 
        !           424: /**
        !           425:  * Check FCoE flow control window
        !           426:  *
        !           427:  * @v fcoe             FCoE port
        !           428:  * @ret len            Length of window
        !           429:  */
        !           430: static size_t fcoe_window ( struct fcoe_port *fcoe ) {
        !           431:        return ( ( fcoe->flags & FCOE_HAVE_FCF ) ? ~( ( size_t ) 0 ) : 0 );
        !           432: }
        !           433: 
        !           434: /**
        !           435:  * Close FCoE port
        !           436:  *
        !           437:  * @v fcoe             FCoE port
        !           438:  * @v rc               Reason for close
        !           439:  */
        !           440: static void fcoe_close ( struct fcoe_port *fcoe, int rc ) {
        !           441: 
        !           442:        stop_timer ( &fcoe->timer );
        !           443:        intf_shutdown ( &fcoe->transport, rc );
        !           444:        netdev_put ( fcoe->netdev );
        !           445:        list_del ( &fcoe->list );
        !           446:        ref_put ( &fcoe->refcnt );
        !           447: }
        !           448: 
        !           449: /**
        !           450:  * Identify device underlying FCoE port
        !           451:  *
        !           452:  * @v fcoe             FCoE port
        !           453:  * @ret device         Underlying device
        !           454:  */
        !           455: static struct device * fcoe_identify_device ( struct fcoe_port *fcoe ) {
        !           456:        return fcoe->netdev->dev;
        !           457: }
        !           458: 
        !           459: /** FCoE transport interface operations */
        !           460: static struct interface_operation fcoe_transport_op[] = {
        !           461:        INTF_OP ( xfer_deliver, struct fcoe_port *, fcoe_deliver ),
        !           462:        INTF_OP ( xfer_alloc_iob, struct fcoe_port *, fcoe_alloc_iob ),
        !           463:        INTF_OP ( xfer_window, struct fcoe_port *, fcoe_window ),
        !           464:        INTF_OP ( intf_close, struct fcoe_port *, fcoe_close ),
        !           465:        INTF_OP ( identify_device, struct fcoe_port *,
        !           466:                  fcoe_identify_device ),
        !           467: };
        !           468: 
        !           469: /** FCoE transport interface descriptor */
        !           470: static struct interface_descriptor fcoe_transport_desc =
        !           471:        INTF_DESC ( struct fcoe_port, transport, fcoe_transport_op );
        !           472: 
        !           473: /******************************************************************************
        !           474:  *
        !           475:  * FIP protocol
        !           476:  *
        !           477:  ******************************************************************************
        !           478:  */
        !           479: 
        !           480: /**
        !           481:  * Parse FIP packet into descriptor set
        !           482:  *
        !           483:  * @v fcoe             FCoE port
        !           484:  * @v fiphdr           FIP header
        !           485:  * @v len              Length of FIP packet
        !           486:  * @v descs            Descriptor set to fill in
        !           487:  * @ret rc             Return status code
        !           488:  */
        !           489: static int fcoe_fip_parse ( struct fcoe_port *fcoe, struct fip_header *fiphdr,
        !           490:                            size_t len, struct fip_descriptors *descs ) {
        !           491:        union fip_descriptor *desc;
        !           492:        size_t descs_len;
        !           493:        size_t desc_len;
        !           494:        size_t desc_offset;
        !           495:        unsigned int desc_type;
        !           496: 
        !           497:        /* Check FIP version */
        !           498:        if ( fiphdr->version != FIP_VERSION ) {
        !           499:                DBGC ( fcoe, "FCoE %s received unsupported FIP version %02x\n",
        !           500:                       fcoe->netdev->name, fiphdr->version );
        !           501:                return -EINVAL;
        !           502:        }
        !           503: 
        !           504:        /* Check length */
        !           505:        descs_len = ( ntohs ( fiphdr->len ) * 4 );
        !           506:        if ( ( sizeof ( *fiphdr ) + descs_len ) > len ) {
        !           507:                DBGC ( fcoe, "FCoE %s received bad descriptor list length\n",
        !           508:                       fcoe->netdev->name );
        !           509:                return -EINVAL;
        !           510:        }
        !           511: 
        !           512:        /* Parse descriptor list */
        !           513:        memset ( descs, 0, sizeof ( *descs ) );
        !           514:        for ( desc_offset = 0 ;
        !           515:              desc_offset <= ( descs_len - sizeof ( desc->common ) ) ;
        !           516:              desc_offset += desc_len ) {
        !           517: 
        !           518:                /* Find descriptor and validate length */
        !           519:                desc = ( ( ( void * ) ( fiphdr + 1 ) ) + desc_offset );
        !           520:                desc_type = desc->common.type;
        !           521:                desc_len = ( desc->common.len * 4 );
        !           522:                if ( desc_len == 0 ) {
        !           523:                        DBGC ( fcoe, "FCoE %s received zero-length "
        !           524:                               "descriptor\n", fcoe->netdev->name );
        !           525:                        return -EINVAL;
        !           526:                }
        !           527:                if ( ( desc_offset + desc_len ) > descs_len ) {
        !           528:                        DBGC ( fcoe, "FCoE %s descriptor overrun\n",
        !           529:                               fcoe->netdev->name );
        !           530:                        return -EINVAL;
        !           531:                }
        !           532: 
        !           533:                /* Handle descriptors that we understand */
        !           534:                if ( ( desc_type > FIP_RESERVED ) &&
        !           535:                     ( desc_type < FIP_NUM_DESCRIPTOR_TYPES ) ) {
        !           536:                        /* Use only the first instance of a descriptor */
        !           537:                        if ( descs->desc[desc_type] == NULL )
        !           538:                                descs->desc[desc_type] = desc;
        !           539:                        continue;
        !           540:                }
        !           541: 
        !           542:                /* Abort if we cannot understand a critical descriptor */
        !           543:                if ( FIP_IS_CRITICAL ( desc_type ) ) {
        !           544:                        DBGC ( fcoe, "FCoE %s cannot understand critical "
        !           545:                               "descriptor type %02x\n",
        !           546:                               fcoe->netdev->name, desc_type );
        !           547:                        return -ENOTSUP;
        !           548:                }
        !           549: 
        !           550:                /* Ignore non-critical descriptors that we cannot understand */
        !           551:        }
        !           552: 
        !           553:        return 0;
        !           554: }
        !           555: 
        !           556: /**
        !           557:  * Send FIP VLAN request
        !           558:  *
        !           559:  * @v fcoe             FCoE port
        !           560:  * @ret rc             Return status code
        !           561:  */
        !           562: static int fcoe_fip_tx_vlan ( struct fcoe_port *fcoe ) {
        !           563:        struct io_buffer *iobuf;
        !           564:        struct {
        !           565:                struct fip_header hdr;
        !           566:                struct fip_mac_address mac_address;
        !           567:        } __attribute__ (( packed )) *request;
        !           568:        int rc;
        !           569: 
        !           570:        /* Allocate I/O buffer */
        !           571:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *request ) );
        !           572:        if ( ! iobuf )
        !           573:                return -ENOMEM;
        !           574:        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        !           575: 
        !           576:        /* Construct VLAN request */
        !           577:        request = iob_put ( iobuf, sizeof ( *request ) );
        !           578:        memset ( request, 0, sizeof ( *request ) );
        !           579:        request->hdr.version = FIP_VERSION;
        !           580:        request->hdr.code = htons ( FIP_CODE_VLAN );
        !           581:        request->hdr.subcode = FIP_VLAN_REQUEST;
        !           582:        request->hdr.len = htons ( ( sizeof ( *request ) -
        !           583:                                     sizeof ( request->hdr ) ) / 4 );
        !           584:        request->mac_address.type = FIP_MAC_ADDRESS;
        !           585:        request->mac_address.len =
        !           586:                ( sizeof ( request->mac_address ) / 4 );
        !           587:        memcpy ( request->mac_address.mac, fcoe->netdev->ll_addr,
        !           588:                 sizeof ( request->mac_address.mac ) );
        !           589: 
        !           590:        /* Send VLAN request */
        !           591:        if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
        !           592:                             &fip_protocol, all_fcf_macs,
        !           593:                             fcoe->netdev->ll_addr ) ) != 0 ) {
        !           594:                DBGC ( fcoe, "FCoE %s could not send VLAN request: "
        !           595:                       "%s\n", fcoe->netdev->name, strerror ( rc ) );
        !           596:                return rc;
        !           597:        }
        !           598: 
        !           599:        return 0;
        !           600: }
        !           601: 
        !           602: /**
        !           603:  * Handle received FIP VLAN notification
        !           604:  *
        !           605:  * @v fcoe             FCoE port
        !           606:  * @v descs            Descriptor list
        !           607:  * @v flags            Flags
        !           608:  * @ret rc             Return status code
        !           609:  */
        !           610: static int fcoe_fip_rx_vlan ( struct fcoe_port *fcoe,
        !           611:                              struct fip_descriptors *descs,
        !           612:                              unsigned int flags __unused ) {
        !           613:        struct fip_mac_address *mac_address = fip_mac_address ( descs );
        !           614:        struct fip_vlan *vlan = fip_vlan ( descs );
        !           615:        unsigned int tag;
        !           616:        int rc;
        !           617: 
        !           618:        /* Sanity checks */
        !           619:        if ( ! mac_address ) {
        !           620:                DBGC ( fcoe, "FCoE %s received VLAN notification missing MAC "
        !           621:                       "address\n", fcoe->netdev->name );
        !           622:                return -EINVAL;
        !           623:        }
        !           624:        if ( ! vlan ) {
        !           625:                DBGC ( fcoe, "FCoE %s received VLAN notification missing VLAN "
        !           626:                       "tag\n", fcoe->netdev->name );
        !           627:                return -EINVAL;
        !           628:        }
        !           629: 
        !           630:        /* Create VLAN */
        !           631:        tag = ntohs ( vlan->vlan );
        !           632:        DBGC ( fcoe, "FCoE %s creating VLAN %d for FCF %s\n",
        !           633:               fcoe->netdev->name, tag, eth_ntoa ( mac_address->mac ) );
        !           634:        if ( ( rc = vlan_create ( fcoe->netdev, tag,
        !           635:                                  FCOE_VLAN_PRIORITY ) ) != 0 ) {
        !           636:                DBGC ( fcoe, "FCoE %s could not create VLAN %d: %s\n",
        !           637:                       fcoe->netdev->name, tag, strerror ( rc ) );
        !           638:                return rc;
        !           639:        }
        !           640: 
        !           641:        /* Record that a VLAN was found.  This FCoE port will play no
        !           642:         * further active role; the real FCoE traffic will use the
        !           643:         * port automatically created for the new VLAN device.
        !           644:         */
        !           645:        fcoe->flags |= FCOE_VLAN_FOUND;
        !           646: 
        !           647:        return 0;
        !           648: }
        !           649: 
        !           650: /**
        !           651:  * Send FIP discovery solicitation
        !           652:  *
        !           653:  * @v fcoe             FCoE port
        !           654:  * @ret rc             Return status code
        !           655:  */
        !           656: static int fcoe_fip_tx_solicitation ( struct fcoe_port *fcoe ) {
        !           657:        struct io_buffer *iobuf;
        !           658:        struct {
        !           659:                struct fip_header hdr;
        !           660:                struct fip_mac_address mac_address;
        !           661:                struct fip_name_id name_id;
        !           662:                struct fip_max_fcoe_size max_fcoe_size;
        !           663:        } __attribute__ (( packed )) *solicitation;
        !           664:        int rc;
        !           665: 
        !           666:        /* Allocate I/O buffer */
        !           667:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *solicitation ) );
        !           668:        if ( ! iobuf )
        !           669:                return -ENOMEM;
        !           670:        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        !           671: 
        !           672:        /* Construct discovery solicitation */
        !           673:        solicitation = iob_put ( iobuf, sizeof ( *solicitation ) );
        !           674:        memset ( solicitation, 0, sizeof ( *solicitation ) );
        !           675:        solicitation->hdr.version = FIP_VERSION;
        !           676:        solicitation->hdr.code = htons ( FIP_CODE_DISCOVERY );
        !           677:        solicitation->hdr.subcode = FIP_DISCOVERY_SOLICIT;
        !           678:        solicitation->hdr.len = htons ( ( sizeof ( *solicitation ) -
        !           679:                                          sizeof ( solicitation->hdr ) ) / 4 );
        !           680:        solicitation->hdr.flags = htons ( FIP_FP | FIP_SP );
        !           681:        solicitation->mac_address.type = FIP_MAC_ADDRESS;
        !           682:        solicitation->mac_address.len =
        !           683:                ( sizeof ( solicitation->mac_address ) / 4 );
        !           684:        memcpy ( solicitation->mac_address.mac, fcoe->netdev->ll_addr,
        !           685:                 sizeof ( solicitation->mac_address.mac ) );
        !           686:        solicitation->name_id.type = FIP_NAME_ID;
        !           687:        solicitation->name_id.len = ( sizeof ( solicitation->name_id ) / 4 );
        !           688:        memcpy ( &solicitation->name_id.name, &fcoe->node_wwn.fc,
        !           689:                 sizeof ( solicitation->name_id.name ) );
        !           690:        solicitation->max_fcoe_size.type = FIP_MAX_FCOE_SIZE;
        !           691:        solicitation->max_fcoe_size.len =
        !           692:                ( sizeof ( solicitation->max_fcoe_size ) / 4 );
        !           693:        solicitation->max_fcoe_size.mtu =
        !           694:                htons ( ETH_MAX_MTU - sizeof ( struct fcoe_header ) -
        !           695:                        sizeof ( struct fcoe_footer ) );
        !           696: 
        !           697:        /* Send discovery solicitation */
        !           698:        if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
        !           699:                             &fip_protocol, all_fcf_macs,
        !           700:                             fcoe->netdev->ll_addr ) ) != 0 ) {
        !           701:                DBGC ( fcoe, "FCoE %s could not send discovery solicitation: "
        !           702:                       "%s\n", fcoe->netdev->name, strerror ( rc ) );
        !           703:                return rc;
        !           704:        }
        !           705: 
        !           706:        return 0;
        !           707: }
        !           708: 
        !           709: /**
        !           710:  * Handle received FIP discovery advertisement
        !           711:  *
        !           712:  * @v fcoe             FCoE port
        !           713:  * @v descs            Descriptor list
        !           714:  * @v flags            Flags
        !           715:  * @ret rc             Return status code
        !           716:  */
        !           717: static int fcoe_fip_rx_advertisement ( struct fcoe_port *fcoe,
        !           718:                                       struct fip_descriptors *descs,
        !           719:                                       unsigned int flags ) {
        !           720:        struct fip_priority *priority = fip_priority ( descs );
        !           721:        struct fip_mac_address *mac_address = fip_mac_address ( descs );
        !           722:        struct fip_fka_adv_p *fka_adv_p = fip_fka_adv_p ( descs );
        !           723: 
        !           724:        /* Sanity checks */
        !           725:        if ( ! priority ) {
        !           726:                DBGC ( fcoe, "FCoE %s received advertisement missing "
        !           727:                       "priority\n", fcoe->netdev->name );
        !           728:                return -EINVAL;
        !           729:        }
        !           730:        if ( ! mac_address ) {
        !           731:                DBGC ( fcoe, "FCoE %s received advertisement missing MAC "
        !           732:                       "address\n", fcoe->netdev->name );
        !           733:                return -EINVAL;
        !           734:        }
        !           735:        if ( ! fka_adv_p ) {
        !           736:                DBGC ( fcoe, "FCoE %s received advertisement missing FKA ADV "
        !           737:                       "period\n", fcoe->netdev->name );
        !           738:                return -EINVAL;
        !           739:        }
        !           740: 
        !           741:        if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
        !           742: 
        !           743:                /* We are soliciting for an FCF.  Store the highest
        !           744:                 * (i.e. lowest-valued) priority solicited
        !           745:                 * advertisement that we receive.
        !           746:                 */
        !           747:                if ( ( ( flags & ( FIP_A | FIP_S | FIP_F ) ) ==
        !           748:                       ( FIP_A | FIP_S | FIP_F ) ) &&
        !           749:                     ( priority->priority < fcoe->priority ) ) {
        !           750: 
        !           751:                        fcoe->flags |= FCOE_HAVE_FIP_FCF;
        !           752:                        fcoe->priority = priority->priority;
        !           753:                        if ( fka_adv_p->flags & FIP_NO_KEEPALIVE ) {
        !           754:                                fcoe->keepalive = 0;
        !           755:                        } else {
        !           756:                                fcoe->keepalive = ntohl ( fka_adv_p->period );
        !           757:                        }
        !           758:                        fcoe->flags &= ~FCOE_FCF_ALLOWS_SPMA;
        !           759:                        if ( flags & FIP_SP )
        !           760:                                fcoe->flags |= FCOE_FCF_ALLOWS_SPMA;
        !           761:                        memcpy ( fcoe->fcf_mac, mac_address->mac,
        !           762:                                 sizeof ( fcoe->fcf_mac ) );
        !           763:                        DBGC ( fcoe, "FCoE %s selected FCF %s (pri %d",
        !           764:                               fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ),
        !           765:                               fcoe->priority );
        !           766:                        if ( fcoe->keepalive ) {
        !           767:                                DBGC ( fcoe, ", FKA ADV %dms",
        !           768:                                       fcoe->keepalive );
        !           769:                        }
        !           770:                        DBGC ( fcoe, ", %cPMA)\n",
        !           771:                               ( ( fcoe->flags & FCOE_FCF_ALLOWS_SPMA ) ?
        !           772:                                 'S' : 'F' ) );
        !           773:                }
        !           774: 
        !           775:        } else if ( fcoe->flags & FCOE_HAVE_FIP_FCF ) {
        !           776: 
        !           777:                /* We are checking that the FCF remains alive.  Reset
        !           778:                 * the timeout counter if this is an advertisement
        !           779:                 * from our forwarder.
        !           780:                 */
        !           781:                if ( memcmp ( fcoe->fcf_mac, mac_address->mac,
        !           782:                              sizeof ( fcoe->fcf_mac ) ) == 0 ) {
        !           783:                        fcoe->timeouts = 0;
        !           784:                }
        !           785: 
        !           786:        } else {
        !           787: 
        !           788:                /* We are operating in non-FIP mode and have received
        !           789:                 * a FIP advertisement.  Reset the link in order to
        !           790:                 * attempt FIP.
        !           791:                 */
        !           792:                fcoe_reset ( fcoe );
        !           793: 
        !           794:        }
        !           795: 
        !           796:        return 0;
        !           797: }
        !           798: 
        !           799: /**
        !           800:  * Handle received FIP ELS response
        !           801:  *
        !           802:  * @v fcoe             FCoE port
        !           803:  * @v descs            Descriptor list
        !           804:  * @v flags            Flags
        !           805:  * @ret rc             Return status code
        !           806:  */
        !           807: static int fcoe_fip_rx_els_response ( struct fcoe_port *fcoe,
        !           808:                                      struct fip_descriptors *descs,
        !           809:                                      unsigned int flags __unused ) {
        !           810:        struct fip_els *flogi = fip_flogi ( descs );
        !           811:        struct fip_mac_address *mac_address = fip_mac_address ( descs );
        !           812:        void *frame;
        !           813:        size_t frame_len;
        !           814:        int rc;
        !           815: 
        !           816:        /* Sanity checks */
        !           817:        if ( ! flogi ) {
        !           818:                DBGC ( fcoe, "FCoE %s received ELS response missing FLOGI\n",
        !           819:                       fcoe->netdev->name );
        !           820:                return -EINVAL;
        !           821:        }
        !           822:        if ( ! mac_address ) {
        !           823:                DBGC ( fcoe, "FCoE %s received ELS response missing MAC "
        !           824:                       "address\n", fcoe->netdev->name );
        !           825:                return -EINVAL;
        !           826:        }
        !           827: 
        !           828:        /* Record local MAC address */
        !           829:        memcpy ( fcoe->local_mac, mac_address->mac, sizeof ( fcoe->local_mac ));
        !           830:        DBGC ( fcoe, "FCoE %s using local MAC %s\n",
        !           831:               fcoe->netdev->name, eth_ntoa ( fcoe->local_mac ) );
        !           832: 
        !           833:        /* Hand off via transport interface */
        !           834:        frame = &flogi->fc;
        !           835:        frame_len = ( ( flogi->len * 4 ) - offsetof ( typeof ( *flogi ), fc ) );
        !           836:        if ( ( rc = xfer_deliver_raw ( &fcoe->transport, frame,
        !           837:                                       frame_len ) ) != 0 ) {
        !           838:                DBGC ( fcoe, "FCoE %s could not deliver FIP FLOGI frame: %s\n",
        !           839:                       fcoe->netdev->name, strerror ( rc ) );
        !           840:                return rc;
        !           841:        }
        !           842: 
        !           843:        return 0;
        !           844: }
        !           845: 
        !           846: /**
        !           847:  * Send FIP keepalive
        !           848:  *
        !           849:  * @v fcoe             FCoE port
        !           850:  * @ret rc             Return status code
        !           851:  */
        !           852: static int fcoe_fip_tx_keepalive ( struct fcoe_port *fcoe ) {
        !           853:        struct io_buffer *iobuf;
        !           854:        struct {
        !           855:                struct fip_header hdr;
        !           856:                struct fip_mac_address mac_address;
        !           857:        } __attribute__ (( packed )) *keepalive;
        !           858:        int rc;
        !           859: 
        !           860:        /* Allocate I/O buffer */
        !           861:        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *keepalive ) );
        !           862:        if ( ! iobuf )
        !           863:                return -ENOMEM;
        !           864:        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        !           865: 
        !           866:        /* Construct keepalive */
        !           867:        keepalive = iob_put ( iobuf, sizeof ( *keepalive ) );
        !           868:        memset ( keepalive, 0, sizeof ( *keepalive ) );
        !           869:        keepalive->hdr.version = FIP_VERSION;
        !           870:        keepalive->hdr.code = htons ( FIP_CODE_MAINTAIN );
        !           871:        keepalive->hdr.subcode = FIP_MAINTAIN_KEEP_ALIVE;
        !           872:        keepalive->hdr.len =    htons ( ( sizeof ( *keepalive ) -
        !           873:                                          sizeof ( keepalive->hdr ) ) / 4 );
        !           874:        keepalive->mac_address.type = FIP_MAC_ADDRESS;
        !           875:        keepalive->mac_address.len =
        !           876:                ( sizeof ( keepalive->mac_address ) / 4 );
        !           877:        memcpy ( keepalive->mac_address.mac, fcoe->netdev->ll_addr,
        !           878:                 sizeof ( keepalive->mac_address.mac ) );
        !           879: 
        !           880:        /* Send keepalive */
        !           881:        if ( ( rc = net_tx ( iob_disown ( iobuf ), fcoe->netdev,
        !           882:                             &fip_protocol, fcoe->fcf_mac,
        !           883:                             fcoe->netdev->ll_addr ) ) != 0 ) {
        !           884:                DBGC ( fcoe, "FCoE %s could not send keepalive: %s\n",
        !           885:                       fcoe->netdev->name, strerror ( rc ) );
        !           886:                return rc;
        !           887:        }
        !           888: 
        !           889:        return 0;
        !           890: }
        !           891: 
        !           892: /** A FIP handler */
        !           893: struct fip_handler {
        !           894:        /** Protocol code */
        !           895:        uint16_t code;
        !           896:        /** Protocol subcode */
        !           897:        uint8_t subcode;
        !           898:        /**
        !           899:         * Receive FIP packet
        !           900:         *
        !           901:         * @v fcoe              FCoE port
        !           902:         * @v descs             Descriptor list
        !           903:         * @v flags             Flags
        !           904:         * @ret rc              Return status code
        !           905:         */
        !           906:        int ( * rx ) ( struct fcoe_port *fcoe, struct fip_descriptors *descs,
        !           907:                       unsigned int flags );
        !           908: };
        !           909: 
        !           910: /** FIP handlers */
        !           911: static struct fip_handler fip_handlers[] = {
        !           912:        { FIP_CODE_VLAN, FIP_VLAN_NOTIFY,
        !           913:          fcoe_fip_rx_vlan },
        !           914:        { FIP_CODE_DISCOVERY, FIP_DISCOVERY_ADVERTISE,
        !           915:          fcoe_fip_rx_advertisement },
        !           916:        { FIP_CODE_ELS, FIP_ELS_RESPONSE,
        !           917:          fcoe_fip_rx_els_response },
        !           918: };
        !           919: 
        !           920: /**
        !           921:  * Process incoming FIP packets
        !           922:  *
        !           923:  * @v iobuf            I/O buffer
        !           924:  * @v netdev           Network device
        !           925:  * @v ll_dest          Link-layer destination address
        !           926:  * @v ll_source                Link-layer source address
        !           927:  * @ret rc             Return status code
        !           928:  */
        !           929: static int fcoe_fip_rx ( struct io_buffer *iobuf,
        !           930:                         struct net_device *netdev,
        !           931:                         const void *ll_dest,
        !           932:                         const void *ll_source __unused ) {
        !           933:        struct fip_header *fiphdr = iobuf->data;
        !           934:        struct fip_descriptors descs;
        !           935:        struct fip_handler *handler;
        !           936:        struct fcoe_port *fcoe;
        !           937:        unsigned int i;
        !           938:        int rc;
        !           939: 
        !           940:        /* Identify FCoE port */
        !           941:        if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
        !           942:                DBG ( "FCoE received FIP frame for net device %s missing FCoE "
        !           943:                      "port\n", netdev->name );
        !           944:                rc = -ENOTCONN;
        !           945:                goto done;
        !           946:        }
        !           947: 
        !           948:        /* Discard packets not destined for us */
        !           949:        if ( ( memcmp ( fcoe->netdev->ll_addr, ll_dest, ETH_ALEN ) != 0 ) &&
        !           950:             ( memcmp ( all_fcoe_macs, ll_dest,
        !           951:                        sizeof ( all_fcoe_macs ) ) != 0 ) &&
        !           952:             ( memcmp ( all_enode_macs, ll_dest,
        !           953:                        sizeof ( all_enode_macs ) ) != 0 ) ) {
        !           954:                DBGC2 ( fcoe, "FCoE %s ignoring FIP packet for %s\n",
        !           955:                        fcoe->netdev->name, eth_ntoa ( ll_dest ) );
        !           956:                rc = -ENOTCONN;
        !           957:                goto done;
        !           958:        }
        !           959: 
        !           960:        /* Parse FIP packet */
        !           961:        if ( ( rc = fcoe_fip_parse ( fcoe, fiphdr, iob_len ( iobuf ),
        !           962:                                     &descs ) ) != 0 )
        !           963:                goto done;
        !           964: 
        !           965:        /* Find a suitable handler */
        !           966:        for ( i = 0 ; i < ( sizeof ( fip_handlers ) /
        !           967:                            sizeof ( fip_handlers[0] ) ) ; i++ ) {
        !           968:                handler = &fip_handlers[i];
        !           969:                if ( ( handler->code == ntohs ( fiphdr->code ) ) &&
        !           970:                     ( handler->subcode == fiphdr->subcode ) ) {
        !           971:                        rc = handler->rx ( fcoe, &descs,
        !           972:                                           ntohs ( fiphdr->flags ) );
        !           973:                        goto done;
        !           974:                }
        !           975:        }
        !           976:        DBGC ( fcoe, "FCoE %s received unsupported FIP code %04x.%02x\n",
        !           977:               fcoe->netdev->name, ntohs ( fiphdr->code ), fiphdr->subcode );
        !           978:        rc = -ENOTSUP;
        !           979: 
        !           980:  done:
        !           981:        free_iob ( iobuf );
        !           982:        return rc;
        !           983: }
        !           984: 
        !           985: /******************************************************************************
        !           986:  *
        !           987:  * FCoE ports
        !           988:  *
        !           989:  ******************************************************************************
        !           990:  */
        !           991: 
        !           992: /**
        !           993:  * Handle FCoE timer expiry
        !           994:  *
        !           995:  * @v timer            FIP timer
        !           996:  * @v over             Timer expired
        !           997:  */
        !           998: static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
        !           999:        struct fcoe_port *fcoe =
        !          1000:                container_of ( timer, struct fcoe_port, timer );
        !          1001:        int rc;
        !          1002: 
        !          1003:        /* Sanity check */
        !          1004:        assert ( fcoe->flags & FCOE_HAVE_NETWORK );
        !          1005: 
        !          1006:        /* Increment the timeout counter */
        !          1007:        fcoe->timeouts++;
        !          1008: 
        !          1009:        if ( vlan_can_be_trunk ( fcoe->netdev ) &
        !          1010:             ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) {
        !          1011: 
        !          1012:                /* If we have already found a VLAN, send infrequent
        !          1013:                 * VLAN requests, in case VLAN information changes.
        !          1014:                 */
        !          1015:                if ( fcoe->flags & FCOE_VLAN_FOUND ) {
        !          1016:                        fcoe->flags &= ~FCOE_VLAN_FOUND;
        !          1017:                        fcoe->timeouts = 0;
        !          1018:                        start_timer_fixed ( &fcoe->timer,
        !          1019:                                            FCOE_VLAN_POLL_DELAY );
        !          1020:                        fcoe_fip_tx_vlan ( fcoe );
        !          1021:                        return;
        !          1022:                }
        !          1023: 
        !          1024:                /* If we have not yet found a VLAN, and we have not
        !          1025:                 * yet timed out and given up on finding one, then
        !          1026:                 * send a VLAN request and wait.
        !          1027:                 */
        !          1028:                if ( fcoe->timeouts <= FCOE_MAX_VLAN_REQUESTS ) {
        !          1029:                        start_timer_fixed ( &fcoe->timer,
        !          1030:                                            FCOE_VLAN_RETRY_DELAY );
        !          1031:                        fcoe_fip_tx_vlan ( fcoe );
        !          1032:                        return;
        !          1033:                }
        !          1034: 
        !          1035:                /* We have timed out waiting for a VLAN; proceed to
        !          1036:                 * FIP discovery.
        !          1037:                 */
        !          1038:                fcoe->flags |= FCOE_VLAN_TIMED_OUT;
        !          1039:                fcoe->timeouts = 0;
        !          1040:                DBGC ( fcoe, "FCoE %s giving up on VLAN discovery\n",
        !          1041:                       fcoe->netdev->name );
        !          1042:                start_timer_nodelay ( &fcoe->timer );
        !          1043: 
        !          1044:        } else if ( ! ( fcoe->flags & FCOE_HAVE_FCF ) ) {
        !          1045: 
        !          1046:                /* If we have not yet found a FIP-capable forwarder,
        !          1047:                 * and we have not yet timed out and given up on
        !          1048:                 * finding one, then send a FIP solicitation and wait.
        !          1049:                 */
        !          1050:                start_timer_fixed ( &fcoe->timer, FCOE_FIP_RETRY_DELAY );
        !          1051:                if ( ( ! ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ) &&
        !          1052:                     ( fcoe->timeouts <= FCOE_MAX_FIP_SOLICITATIONS ) ) {
        !          1053:                        fcoe_fip_tx_solicitation ( fcoe );
        !          1054:                        return;
        !          1055:                }
        !          1056: 
        !          1057:                /* Attach Fibre Channel port */
        !          1058:                if ( ( rc = fc_port_open ( &fcoe->transport, &fcoe->node_wwn.fc,
        !          1059:                                           &fcoe->port_wwn.fc,
        !          1060:                                           fcoe->netdev->name ) ) != 0 ) {
        !          1061:                        DBGC ( fcoe, "FCoE %s could not create FC port: %s\n",
        !          1062:                               fcoe->netdev->name, strerror ( rc ) );
        !          1063:                        /* We will try again on the next timer expiry */
        !          1064:                        return;
        !          1065:                }
        !          1066:                stop_timer ( &fcoe->timer );
        !          1067: 
        !          1068:                /* Either we have found a FIP-capable forwarder, or we
        !          1069:                 * have timed out and will fall back to pre-FIP mode.
        !          1070:                 */
        !          1071:                fcoe->flags |= FCOE_HAVE_FCF;
        !          1072:                fcoe->timeouts = 0;
        !          1073:                DBGC ( fcoe, "FCoE %s using %sFIP FCF %s\n", fcoe->netdev->name,
        !          1074:                       ( ( fcoe->flags & FCOE_HAVE_FIP_FCF ) ? "" : "non-" ),
        !          1075:                       eth_ntoa ( fcoe->fcf_mac ) );
        !          1076: 
        !          1077:                /* Start sending keepalives if applicable */
        !          1078:                if ( fcoe->keepalive )
        !          1079:                        start_timer_nodelay ( &fcoe->timer );
        !          1080: 
        !          1081:                /* Send notification of window change */
        !          1082:                xfer_window_changed ( &fcoe->transport );
        !          1083: 
        !          1084:        } else {
        !          1085: 
        !          1086:                /* Send keepalive */
        !          1087:                start_timer_fixed ( &fcoe->timer,
        !          1088:                              ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
        !          1089:                fcoe_fip_tx_keepalive ( fcoe );
        !          1090: 
        !          1091:                /* Abandon FCF if we have not seen its advertisements */
        !          1092:                if ( fcoe->timeouts > FCOE_MAX_FIP_MISSING_KEEPALIVES ) {
        !          1093:                        DBGC ( fcoe, "FCoE %s abandoning FCF %s\n",
        !          1094:                               fcoe->netdev->name, eth_ntoa ( fcoe->fcf_mac ));
        !          1095:                        fcoe_reset ( fcoe );
        !          1096:                }
        !          1097:        }
        !          1098: }
        !          1099: 
        !          1100: /**
        !          1101:  * Create FCoE port
        !          1102:  *
        !          1103:  * @v netdev           Network device
        !          1104:  * @ret rc             Return status code
        !          1105:  */
        !          1106: static int fcoe_probe ( struct net_device *netdev ) {
        !          1107:        struct ll_protocol *ll_protocol = netdev->ll_protocol;
        !          1108:        struct fcoe_port *fcoe;
        !          1109:        int rc;
        !          1110: 
        !          1111:        /* Sanity check */
        !          1112:        if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) {
        !          1113:                /* Not an error; simply skip this net device */
        !          1114:                DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name );
        !          1115:                rc = 0;
        !          1116:                goto err_non_ethernet;
        !          1117:        }
        !          1118: 
        !          1119:        /* Allocate and initialise structure */
        !          1120:        fcoe = zalloc ( sizeof ( *fcoe ) );
        !          1121:        if ( ! fcoe ) {
        !          1122:                rc = -ENOMEM;
        !          1123:                goto err_zalloc;
        !          1124:        }
        !          1125:        ref_init ( &fcoe->refcnt, NULL );
        !          1126:        intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt );
        !          1127:        timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt );
        !          1128:        fcoe->netdev = netdev_get ( netdev );
        !          1129: 
        !          1130:        /* Construct node and port names */
        !          1131:        fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE );
        !          1132:        memcpy ( &fcoe->node_wwn.fcoe.mac, netdev->ll_addr,
        !          1133:                 sizeof ( fcoe->node_wwn.fcoe.mac ) );
        !          1134:        fcoe->port_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE_EXTENDED );
        !          1135:        memcpy ( &fcoe->port_wwn.fcoe.mac, netdev->ll_addr,
        !          1136:                 sizeof ( fcoe->port_wwn.fcoe.mac ) );
        !          1137: 
        !          1138:        DBGC ( fcoe, "FCoE %s is %s", fcoe->netdev->name,
        !          1139:               fc_ntoa ( &fcoe->node_wwn.fc ) );
        !          1140:        DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) );
        !          1141: 
        !          1142:        /* Transfer reference to port list */
        !          1143:        list_add ( &fcoe->list, &fcoe_ports );
        !          1144:        return 0;
        !          1145: 
        !          1146:        netdev_put ( fcoe->netdev );
        !          1147:  err_zalloc:
        !          1148:  err_non_ethernet:
        !          1149:        return rc;
        !          1150: }
        !          1151: 
        !          1152: /**
        !          1153:  * Handle FCoE port device or link state change
        !          1154:  *
        !          1155:  * @v netdev           Network device
        !          1156:  */
        !          1157: static void fcoe_notify ( struct net_device *netdev ) {
        !          1158:        struct fcoe_port *fcoe;
        !          1159: 
        !          1160:        /* Sanity check */
        !          1161:        if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
        !          1162:                DBG ( "FCoE notification for net device %s missing FCoE "
        !          1163:                      "port\n", netdev->name );
        !          1164:                return;
        !          1165:        }
        !          1166: 
        !          1167:        /* Reset the FCoE link if necessary */
        !          1168:        if ( ! ( netdev_is_open ( netdev ) &&
        !          1169:                 netdev_link_ok ( netdev ) &&
        !          1170:                 ( fcoe->flags & FCOE_HAVE_NETWORK ) ) ) {
        !          1171:                fcoe_reset ( fcoe );
        !          1172:        }
        !          1173: }
        !          1174: 
        !          1175: /**
        !          1176:  * Destroy FCoE port
        !          1177:  *
        !          1178:  * @v netdev           Network device
        !          1179:  */
        !          1180: static void fcoe_remove ( struct net_device *netdev ) {
        !          1181:        struct fcoe_port *fcoe;
        !          1182: 
        !          1183:        /* Sanity check */
        !          1184:        if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) {
        !          1185:                DBG ( "FCoE removal of net device %s missing FCoE port\n",
        !          1186:                      netdev->name );
        !          1187:                return;
        !          1188:        }
        !          1189: 
        !          1190:        /* Close FCoE device */
        !          1191:        fcoe_close ( fcoe, 0 );
        !          1192: }
        !          1193: 
        !          1194: /** FCoE driver */
        !          1195: struct net_driver fcoe_driver __net_driver = {
        !          1196:        .name = "FCoE",
        !          1197:        .probe = fcoe_probe,
        !          1198:        .notify = fcoe_notify,
        !          1199:        .remove = fcoe_remove,
        !          1200: };
        !          1201: 
        !          1202: /** FCoE protocol */
        !          1203: struct net_protocol fcoe_protocol __net_protocol = {
        !          1204:        .name = "FCoE",
        !          1205:        .net_proto = htons ( ETH_P_FCOE ),
        !          1206:        .rx = fcoe_rx,
        !          1207: };
        !          1208: 
        !          1209: /** FIP protocol */
        !          1210: struct net_protocol fip_protocol __net_protocol = {
        !          1211:        .name = "FIP",
        !          1212:        .net_proto = htons ( ETH_P_FIP ),
        !          1213:        .rx = fcoe_fip_rx,
        !          1214: };
        !          1215: 
        !          1216: /** Human-readable message for CRC errors
        !          1217:  *
        !          1218:  * It seems as though several drivers neglect to strip the Ethernet
        !          1219:  * CRC, which will cause the FCoE footer to be misplaced and result
        !          1220:  * (coincidentally) in an "invalid CRC" error from FCoE.
        !          1221:  */
        !          1222: struct errortab fcoe_errors[] __errortab = {
        !          1223:        __einfo_errortab ( EINFO_EINVAL_CRC ),
        !          1224: };

unix.superglobalmegacorp.com

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