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

1.1     ! root        1: /*
        !             2:  * The iPXE 802.11 MAC layer.
        !             3:  *
        !             4:  * Copyright (c) 2009 Joshua Oreman <[email protected]>.
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or
        !             7:  * modify it under the terms of the GNU General Public License as
        !             8:  * published by the Free Software Foundation; either version 2 of the
        !             9:  * License, or any later version.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14:  * General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU General Public License
        !            17:  * along with this program; if not, write to the Free Software
        !            18:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            19:  */
        !            20: 
        !            21: FILE_LICENCE ( GPL2_OR_LATER );
        !            22: 
        !            23: #include <string.h>
        !            24: #include <byteswap.h>
        !            25: #include <stdlib.h>
        !            26: #include <unistd.h>
        !            27: #include <errno.h>
        !            28: #include <ipxe/settings.h>
        !            29: #include <ipxe/if_arp.h>
        !            30: #include <ipxe/ethernet.h>
        !            31: #include <ipxe/ieee80211.h>
        !            32: #include <ipxe/netdevice.h>
        !            33: #include <ipxe/net80211.h>
        !            34: #include <ipxe/sec80211.h>
        !            35: #include <ipxe/timer.h>
        !            36: #include <ipxe/nap.h>
        !            37: #include <ipxe/errortab.h>
        !            38: #include <ipxe/net80211_err.h>
        !            39: 
        !            40: /** @file
        !            41:  *
        !            42:  * 802.11 device management
        !            43:  */
        !            44: 
        !            45: /** List of 802.11 devices */
        !            46: static struct list_head net80211_devices = LIST_HEAD_INIT ( net80211_devices );
        !            47: 
        !            48: /** Set of device operations that does nothing */
        !            49: static struct net80211_device_operations net80211_null_ops;
        !            50: 
        !            51: /** Information associated with a received management packet
        !            52:  *
        !            53:  * This is used to keep beacon signal strengths in a parallel queue to
        !            54:  * the beacons themselves.
        !            55:  */
        !            56: struct net80211_rx_info {
        !            57:        int signal;
        !            58:        struct list_head list;
        !            59: };
        !            60: 
        !            61: /** Context for a probe operation */
        !            62: struct net80211_probe_ctx {
        !            63:        /** 802.11 device to probe on */
        !            64:        struct net80211_device *dev;
        !            65: 
        !            66:        /** Value of keep_mgmt before probe was started */
        !            67:        int old_keep_mgmt;
        !            68: 
        !            69:        /** If scanning actively, pointer to probe packet to send */
        !            70:        struct io_buffer *probe;
        !            71: 
        !            72:        /** If non-"", the ESSID to limit ourselves to */
        !            73:        const char *essid;
        !            74: 
        !            75:        /** Time probe was started */
        !            76:        u32 ticks_start;
        !            77: 
        !            78:        /** Time last useful beacon was received */
        !            79:        u32 ticks_beacon;
        !            80: 
        !            81:        /** Time channel was last changed */
        !            82:        u32 ticks_channel;
        !            83: 
        !            84:        /** Time to stay on each channel */
        !            85:        u32 hop_time;
        !            86: 
        !            87:        /** Channels to hop by when changing channel */
        !            88:        int hop_step;
        !            89: 
        !            90:        /** List of best beacons for each network found so far */
        !            91:        struct list_head *beacons;
        !            92: };
        !            93: 
        !            94: /** Context for the association task */
        !            95: struct net80211_assoc_ctx {
        !            96:        /** Next authentication method to try using */
        !            97:        int method;
        !            98: 
        !            99:        /** Time (in ticks) of the last sent association-related packet */
        !           100:        int last_packet;
        !           101: 
        !           102:        /** Number of times we have tried sending it */
        !           103:        int times_tried;
        !           104: };
        !           105: 
        !           106: /**
        !           107:  * Detect secure 802.11 network when security support is not available
        !           108:  *
        !           109:  * @return -ENOTSUP, always.
        !           110:  */
        !           111: __weak int sec80211_detect ( struct io_buffer *iob __unused,
        !           112:                             enum net80211_security_proto *secprot __unused,
        !           113:                             enum net80211_crypto_alg *crypt __unused ) {
        !           114:        return -ENOTSUP;
        !           115: }
        !           116: 
        !           117: /**
        !           118:  * @defgroup net80211_netdev Network device interface functions
        !           119:  * @{
        !           120:  */
        !           121: static int net80211_netdev_open ( struct net_device *netdev );
        !           122: static void net80211_netdev_close ( struct net_device *netdev );
        !           123: static int net80211_netdev_transmit ( struct net_device *netdev,
        !           124:                                      struct io_buffer *iobuf );
        !           125: static void net80211_netdev_poll ( struct net_device *netdev );
        !           126: static void net80211_netdev_irq ( struct net_device *netdev, int enable );
        !           127: /** @} */
        !           128: 
        !           129: /**
        !           130:  * @defgroup net80211_linklayer 802.11 link-layer protocol functions
        !           131:  * @{
        !           132:  */
        !           133: static int net80211_ll_push ( struct net_device *netdev,
        !           134:                              struct io_buffer *iobuf, const void *ll_dest,
        !           135:                              const void *ll_source, uint16_t net_proto );
        !           136: static int net80211_ll_pull ( struct net_device *netdev,
        !           137:                              struct io_buffer *iobuf, const void **ll_dest,
        !           138:                              const void **ll_source, uint16_t * net_proto );
        !           139: /** @} */
        !           140: 
        !           141: /**
        !           142:  * @defgroup net80211_help 802.11 helper functions
        !           143:  * @{
        !           144:  */
        !           145: static void net80211_add_channels ( struct net80211_device *dev, int start,
        !           146:                                    int len, int txpower );
        !           147: static void net80211_filter_hw_channels ( struct net80211_device *dev );
        !           148: static void net80211_set_rtscts_rate ( struct net80211_device *dev );
        !           149: static int net80211_process_capab ( struct net80211_device *dev,
        !           150:                                    u16 capab );
        !           151: static int net80211_process_ie ( struct net80211_device *dev,
        !           152:                                 union ieee80211_ie *ie, void *ie_end );
        !           153: static union ieee80211_ie *
        !           154: net80211_marshal_request_info ( struct net80211_device *dev,
        !           155:                                union ieee80211_ie *ie );
        !           156: /** @} */
        !           157: 
        !           158: /**
        !           159:  * @defgroup net80211_assoc_ll 802.11 association handling functions
        !           160:  * @{
        !           161:  */
        !           162: static void net80211_step_associate ( struct process *proc );
        !           163: static void net80211_handle_auth ( struct net80211_device *dev,
        !           164:                                   struct io_buffer *iob );
        !           165: static void net80211_handle_assoc_reply ( struct net80211_device *dev,
        !           166:                                          struct io_buffer *iob );
        !           167: static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
        !           168:                                    int deauth );
        !           169: static void net80211_handle_mgmt ( struct net80211_device *dev,
        !           170:                                   struct io_buffer *iob, int signal );
        !           171: /** @} */
        !           172: 
        !           173: /**
        !           174:  * @defgroup net80211_frag 802.11 fragment handling functions
        !           175:  * @{
        !           176:  */
        !           177: static void net80211_free_frags ( struct net80211_device *dev, int fcid );
        !           178: static struct io_buffer *net80211_accum_frags ( struct net80211_device *dev,
        !           179:                                                int fcid, int nfrags, int size );
        !           180: static void net80211_rx_frag ( struct net80211_device *dev,
        !           181:                               struct io_buffer *iob, int signal );
        !           182: /** @} */
        !           183: 
        !           184: /**
        !           185:  * @defgroup net80211_settings 802.11 settings handlers
        !           186:  * @{
        !           187:  */
        !           188: static int net80211_check_settings_update ( void );
        !           189: 
        !           190: /** 802.11 settings applicator
        !           191:  *
        !           192:  * When the SSID is changed, this will cause any open devices to
        !           193:  * re-associate; when the encryption key is changed, we similarly
        !           194:  * update their state.
        !           195:  */
        !           196: struct settings_applicator net80211_applicator __settings_applicator = {
        !           197:        .apply = net80211_check_settings_update,
        !           198: };
        !           199: 
        !           200: /** The network name to associate with
        !           201:  *
        !           202:  * If this is blank, we scan for all networks and use the one with the
        !           203:  * greatest signal strength.
        !           204:  */
        !           205: struct setting net80211_ssid_setting __setting ( SETTING_NETDEV_EXTRA ) = {
        !           206:        .name = "ssid",
        !           207:        .description = "Wireless SSID",
        !           208:        .type = &setting_type_string,
        !           209:        .tag = NET80211_SETTING_TAG_SSID,
        !           210: };
        !           211: 
        !           212: /** Whether to use active scanning
        !           213:  *
        !           214:  * In order to associate with a hidden SSID, it's necessary to use an
        !           215:  * active scan (send probe packets). If this setting is nonzero, an
        !           216:  * active scan on the 2.4GHz band will be used to associate.
        !           217:  */
        !           218: struct setting net80211_active_setting __setting ( SETTING_NETDEV_EXTRA ) = {
        !           219:        .name = "active-scan",
        !           220:        .description = "Actively scan for wireless networks",
        !           221:        .type = &setting_type_int8,
        !           222:        .tag = NET80211_SETTING_TAG_ACTIVE_SCAN,
        !           223: };
        !           224: 
        !           225: /** The cryptographic key to use
        !           226:  *
        !           227:  * For hex WEP keys, as is common, this must be entered using the
        !           228:  * normal iPXE method for entering hex settings; an ASCII string of
        !           229:  * hex characters will not behave as expected.
        !           230:  */
        !           231: struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA ) = {
        !           232:        .name = "key",
        !           233:        .description = "Wireless encryption key",
        !           234:        .type = &setting_type_string,
        !           235:        .tag = NET80211_SETTING_TAG_KEY,
        !           236: };
        !           237: 
        !           238: /** @} */
        !           239: 
        !           240: 
        !           241: /* ---------- net_device wrapper ---------- */
        !           242: 
        !           243: /**
        !           244:  * Open 802.11 device and start association
        !           245:  *
        !           246:  * @v netdev   Wrapping network device
        !           247:  * @ret rc     Return status code
        !           248:  *
        !           249:  * This sets up a default conservative set of channels for probing,
        !           250:  * and starts the auto-association task unless the @c
        !           251:  * NET80211_NO_ASSOC flag is set in the wrapped 802.11 device's @c
        !           252:  * state field.
        !           253:  */
        !           254: static int net80211_netdev_open ( struct net_device *netdev )
        !           255: {
        !           256:        struct net80211_device *dev = netdev->priv;
        !           257:        int rc = 0;
        !           258: 
        !           259:        if ( dev->op == &net80211_null_ops )
        !           260:                return -EFAULT;
        !           261: 
        !           262:        if ( dev->op->open )
        !           263:                rc = dev->op->open ( dev );
        !           264: 
        !           265:        if ( rc < 0 )
        !           266:                return rc;
        !           267: 
        !           268:        if ( ! ( dev->state & NET80211_NO_ASSOC ) )
        !           269:                net80211_autoassociate ( dev );
        !           270: 
        !           271:        return 0;
        !           272: }
        !           273: 
        !           274: /**
        !           275:  * Close 802.11 device
        !           276:  *
        !           277:  * @v netdev   Wrapping network device.
        !           278:  *
        !           279:  * If the association task is running, this will stop it.
        !           280:  */
        !           281: static void net80211_netdev_close ( struct net_device *netdev )
        !           282: {
        !           283:        struct net80211_device *dev = netdev->priv;
        !           284: 
        !           285:        if ( dev->state & NET80211_WORKING )
        !           286:                process_del ( &dev->proc_assoc );
        !           287: 
        !           288:        /* Send disassociation frame to AP, to be polite */
        !           289:        if ( dev->state & NET80211_ASSOCIATED )
        !           290:                net80211_send_disassoc ( dev, IEEE80211_REASON_LEAVING, 0 );
        !           291: 
        !           292:        if ( dev->handshaker && dev->handshaker->stop &&
        !           293:             dev->handshaker->started )
        !           294:                dev->handshaker->stop ( dev );
        !           295: 
        !           296:        free ( dev->crypto );
        !           297:        free ( dev->handshaker );
        !           298:        dev->crypto = NULL;
        !           299:        dev->handshaker = NULL;
        !           300: 
        !           301:        netdev_link_down ( netdev );
        !           302:        dev->state = 0;
        !           303: 
        !           304:        if ( dev->op->close )
        !           305:                dev->op->close ( dev );
        !           306: }
        !           307: 
        !           308: /**
        !           309:  * Transmit packet on 802.11 device
        !           310:  *
        !           311:  * @v netdev   Wrapping network device
        !           312:  * @v iobuf    I/O buffer
        !           313:  * @ret rc     Return status code
        !           314:  *
        !           315:  * If encryption is enabled for the currently associated network, the
        !           316:  * packet will be encrypted prior to transmission.
        !           317:  */
        !           318: static int net80211_netdev_transmit ( struct net_device *netdev,
        !           319:                                      struct io_buffer *iobuf )
        !           320: {
        !           321:        struct net80211_device *dev = netdev->priv;
        !           322:        struct ieee80211_frame *hdr = iobuf->data;
        !           323:        int rc = -ENOSYS;
        !           324: 
        !           325:        if ( dev->crypto && ! ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
        !           326:             ( ( hdr->fc & IEEE80211_FC_TYPE ) == IEEE80211_TYPE_DATA ) ) {
        !           327:                struct io_buffer *niob = dev->crypto->encrypt ( dev->crypto,
        !           328:                                                                iobuf );
        !           329:                if ( ! niob )
        !           330:                        return -ENOMEM; /* only reason encryption could fail */
        !           331: 
        !           332:                /* Free the non-encrypted iob */
        !           333:                netdev_tx_complete ( netdev, iobuf );
        !           334: 
        !           335:                /* Transmit the encrypted iob; the Protected flag is
        !           336:                   set, so we won't recurse into here again */
        !           337:                netdev_tx ( netdev, niob );
        !           338: 
        !           339:                /* Don't transmit the freed packet */
        !           340:                return 0;
        !           341:        }
        !           342: 
        !           343:        if ( dev->op->transmit )
        !           344:                rc = dev->op->transmit ( dev, iobuf );
        !           345: 
        !           346:        return rc;
        !           347: }
        !           348: 
        !           349: /**
        !           350:  * Poll 802.11 device for received packets and completed transmissions
        !           351:  *
        !           352:  * @v netdev   Wrapping network device
        !           353:  */
        !           354: static void net80211_netdev_poll ( struct net_device *netdev )
        !           355: {
        !           356:        struct net80211_device *dev = netdev->priv;
        !           357: 
        !           358:        if ( dev->op->poll )
        !           359:                dev->op->poll ( dev );
        !           360: }
        !           361: 
        !           362: /**
        !           363:  * Enable or disable interrupts for 802.11 device
        !           364:  *
        !           365:  * @v netdev   Wrapping network device
        !           366:  * @v enable   Whether to enable interrupts
        !           367:  */
        !           368: static void net80211_netdev_irq ( struct net_device *netdev, int enable )
        !           369: {
        !           370:        struct net80211_device *dev = netdev->priv;
        !           371: 
        !           372:        if ( dev->op->irq )
        !           373:                dev->op->irq ( dev, enable );
        !           374: }
        !           375: 
        !           376: /** Network device operations for a wrapped 802.11 device */
        !           377: static struct net_device_operations net80211_netdev_ops = {
        !           378:        .open = net80211_netdev_open,
        !           379:        .close = net80211_netdev_close,
        !           380:        .transmit = net80211_netdev_transmit,
        !           381:        .poll = net80211_netdev_poll,
        !           382:        .irq = net80211_netdev_irq,
        !           383: };
        !           384: 
        !           385: 
        !           386: /* ---------- 802.11 link-layer protocol ---------- */
        !           387: 
        !           388: /** 802.11 broadcast MAC address */
        !           389: static u8 net80211_ll_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        !           390: 
        !           391: /**
        !           392:  * Determine whether a transmission rate uses ERP/OFDM
        !           393:  *
        !           394:  * @v rate     Rate in 100 kbps units
        !           395:  * @ret is_erp TRUE if the rate is an ERP/OFDM rate
        !           396:  *
        !           397:  * 802.11b supports rates of 1.0, 2.0, 5.5, and 11.0 Mbps; any other
        !           398:  * rate than these on the 2.4GHz spectrum is an ERP (802.11g) rate.
        !           399:  */
        !           400: static inline int net80211_rate_is_erp ( u16 rate )
        !           401: {
        !           402:        if ( rate == 10 || rate == 20 || rate == 55 || rate == 110 )
        !           403:                return 0;
        !           404:        return 1;
        !           405: }
        !           406: 
        !           407: 
        !           408: /**
        !           409:  * Calculate one frame's contribution to 802.11 duration field
        !           410:  *
        !           411:  * @v dev      802.11 device
        !           412:  * @v bytes    Amount of data to calculate duration for
        !           413:  * @ret dur    Duration field in microseconds
        !           414:  *
        !           415:  * To avoid multiple stations attempting to transmit at once, 802.11
        !           416:  * provides that every packet shall include a duration field
        !           417:  * specifying a length of time for which the wireless medium will be
        !           418:  * reserved after it is transmitted. The duration is measured in
        !           419:  * microseconds and is calculated with respect to the current
        !           420:  * physical-layer parameters of the 802.11 device.
        !           421:  *
        !           422:  * For an unfragmented data or management frame, or the last fragment
        !           423:  * of a fragmented frame, the duration captures only the 10 data bytes
        !           424:  * of one ACK; call once with bytes = 10.
        !           425:  *
        !           426:  * For a fragment of a data or management rame that will be followed
        !           427:  * by more fragments, the duration captures an ACK, the following
        !           428:  * fragment, and its ACK; add the results of three calls, two with
        !           429:  * bytes = 10 and one with bytes set to the next fragment's size.
        !           430:  *
        !           431:  * For an RTS control frame, the duration captures the responding CTS,
        !           432:  * the frame being sent, and its ACK; add the results of three calls,
        !           433:  * two with bytes = 10 and one with bytes set to the next frame's size
        !           434:  * (assuming unfragmented).
        !           435:  *
        !           436:  * For a CTS-to-self control frame, the duration captures the frame
        !           437:  * being protected and its ACK; add the results of two calls, one with
        !           438:  * bytes = 10 and one with bytes set to the next frame's size.
        !           439:  *
        !           440:  * No other frame types are currently supported by iPXE.
        !           441:  */
        !           442: u16 net80211_duration ( struct net80211_device *dev, int bytes, u16 rate )
        !           443: {
        !           444:        struct net80211_channel *chan = &dev->channels[dev->channel];
        !           445:        u32 kbps = rate * 100;
        !           446: 
        !           447:        if ( chan->band == NET80211_BAND_5GHZ || net80211_rate_is_erp ( rate ) ) {
        !           448:                /* OFDM encoding (802.11a/g) */
        !           449:                int bits_per_symbol = ( kbps * 4 ) / 1000;      /* 4us/symbol */
        !           450:                int bits = 22 + ( bytes << 3 ); /* 22-bit PLCP */
        !           451:                int symbols = ( bits + bits_per_symbol - 1 ) / bits_per_symbol;
        !           452: 
        !           453:                return 16 + 20 + ( symbols * 4 ); /* 16us SIFS, 20us preamble */
        !           454:        } else {
        !           455:                /* CCK encoding (802.11b) */
        !           456:                int phy_time = 144 + 48;        /* preamble + PLCP */
        !           457:                int bits = bytes << 3;
        !           458:                int data_time = ( bits * 1000 + kbps - 1 ) / kbps;
        !           459: 
        !           460:                if ( dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE )
        !           461:                        phy_time >>= 1;
        !           462: 
        !           463:                return 10 + phy_time + data_time; /* 10us SIFS */
        !           464:        }
        !           465: }
        !           466: 
        !           467: /**
        !           468:  * Add 802.11 link-layer header
        !           469:  *
        !           470:  * @v netdev           Wrapping network device
        !           471:  * @v iobuf            I/O buffer
        !           472:  * @v ll_dest          Link-layer destination address
        !           473:  * @v ll_source                Link-layer source address
        !           474:  * @v net_proto                Network-layer protocol, in network byte order
        !           475:  * @ret rc             Return status code
        !           476:  *
        !           477:  * This adds both the 802.11 frame header and the 802.2 LLC/SNAP
        !           478:  * header used on data packets.
        !           479:  *
        !           480:  * We also check here for state of the link that would make it invalid
        !           481:  * to send a data packet; every data packet must pass through here,
        !           482:  * and no non-data packet (e.g. management frame) should.
        !           483:  */
        !           484: static int net80211_ll_push ( struct net_device *netdev,
        !           485:                              struct io_buffer *iobuf, const void *ll_dest,
        !           486:                              const void *ll_source, uint16_t net_proto )
        !           487: {
        !           488:        struct net80211_device *dev = netdev->priv;
        !           489:        struct ieee80211_frame *hdr = iob_push ( iobuf,
        !           490:                                                 IEEE80211_LLC_HEADER_LEN +
        !           491:                                                 IEEE80211_TYP_FRAME_HEADER_LEN );
        !           492:        struct ieee80211_llc_snap_header *lhdr =
        !           493:                ( void * ) hdr + IEEE80211_TYP_FRAME_HEADER_LEN;
        !           494: 
        !           495:        /* We can't send data packets if we're not associated. */
        !           496:        if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
        !           497:                if ( dev->assoc_rc )
        !           498:                        return dev->assoc_rc;
        !           499:                return -ENETUNREACH;
        !           500:        }
        !           501: 
        !           502:        hdr->fc = IEEE80211_THIS_VERSION | IEEE80211_TYPE_DATA |
        !           503:            IEEE80211_STYPE_DATA | IEEE80211_FC_TODS;
        !           504: 
        !           505:        /* We don't send fragmented frames, so duration is the time
        !           506:           for an SIFS + 10-byte ACK. */
        !           507:        hdr->duration = net80211_duration ( dev, 10, dev->rates[dev->rate] );
        !           508: 
        !           509:        memcpy ( hdr->addr1, dev->bssid, ETH_ALEN );
        !           510:        memcpy ( hdr->addr2, ll_source, ETH_ALEN );
        !           511:        memcpy ( hdr->addr3, ll_dest, ETH_ALEN );
        !           512: 
        !           513:        hdr->seq = IEEE80211_MAKESEQ ( ++dev->last_tx_seqnr, 0 );
        !           514: 
        !           515:        lhdr->dsap = IEEE80211_LLC_DSAP;
        !           516:        lhdr->ssap = IEEE80211_LLC_SSAP;
        !           517:        lhdr->ctrl = IEEE80211_LLC_CTRL;
        !           518:        memset ( lhdr->oui, 0x00, 3 );
        !           519:        lhdr->ethertype = net_proto;
        !           520: 
        !           521:        return 0;
        !           522: }
        !           523: 
        !           524: /**
        !           525:  * Remove 802.11 link-layer header
        !           526:  *
        !           527:  * @v netdev           Wrapping network device
        !           528:  * @v iobuf            I/O buffer
        !           529:  * @ret ll_dest                Link-layer destination address
        !           530:  * @ret ll_source      Link-layer source
        !           531:  * @ret net_proto      Network-layer protocol, in network byte order
        !           532:  * @ret rc             Return status code
        !           533:  *
        !           534:  * This expects and removes both the 802.11 frame header and the 802.2
        !           535:  * LLC/SNAP header that are used on data packets.
        !           536:  */
        !           537: static int net80211_ll_pull ( struct net_device *netdev __unused,
        !           538:                              struct io_buffer *iobuf,
        !           539:                              const void **ll_dest, const void **ll_source,
        !           540:                              uint16_t * net_proto )
        !           541: {
        !           542:        struct ieee80211_frame *hdr = iobuf->data;
        !           543:        struct ieee80211_llc_snap_header *lhdr =
        !           544:                ( void * ) hdr + IEEE80211_TYP_FRAME_HEADER_LEN;
        !           545: 
        !           546:        /* Bunch of sanity checks */
        !           547:        if ( iob_len ( iobuf ) < IEEE80211_TYP_FRAME_HEADER_LEN +
        !           548:             IEEE80211_LLC_HEADER_LEN ) {
        !           549:                DBGC ( netdev->priv, "802.11 %p packet too short (%zd bytes)\n",
        !           550:                       netdev->priv, iob_len ( iobuf ) );
        !           551:                return -EINVAL_PKT_TOO_SHORT;
        !           552:        }
        !           553: 
        !           554:        if ( ( hdr->fc & IEEE80211_FC_VERSION ) != IEEE80211_THIS_VERSION ) {
        !           555:                DBGC ( netdev->priv, "802.11 %p packet invalid version %04x\n",
        !           556:                       netdev->priv, hdr->fc & IEEE80211_FC_VERSION );
        !           557:                return -EINVAL_PKT_VERSION;
        !           558:        }
        !           559: 
        !           560:        if ( ( hdr->fc & IEEE80211_FC_TYPE ) != IEEE80211_TYPE_DATA ||
        !           561:             ( hdr->fc & IEEE80211_FC_SUBTYPE ) != IEEE80211_STYPE_DATA ) {
        !           562:                DBGC ( netdev->priv, "802.11 %p packet not data/data (fc=%04x)\n",
        !           563:                       netdev->priv, hdr->fc );
        !           564:                return -EINVAL_PKT_NOT_DATA;
        !           565:        }
        !           566: 
        !           567:        if ( ( hdr->fc & ( IEEE80211_FC_TODS | IEEE80211_FC_FROMDS ) ) !=
        !           568:             IEEE80211_FC_FROMDS ) {
        !           569:                DBGC ( netdev->priv, "802.11 %p packet not from DS (fc=%04x)\n",
        !           570:                       netdev->priv, hdr->fc );
        !           571:                return -EINVAL_PKT_NOT_FROMDS;
        !           572:        }
        !           573: 
        !           574:        if ( lhdr->dsap != IEEE80211_LLC_DSAP || lhdr->ssap != IEEE80211_LLC_SSAP ||
        !           575:             lhdr->ctrl != IEEE80211_LLC_CTRL || lhdr->oui[0] || lhdr->oui[1] ||
        !           576:             lhdr->oui[2] ) {
        !           577:                DBGC ( netdev->priv, "802.11 %p LLC header is not plain EtherType "
        !           578:                       "encapsulator: %02x->%02x [%02x] %02x:%02x:%02x %04x\n",
        !           579:                       netdev->priv, lhdr->dsap, lhdr->ssap, lhdr->ctrl,
        !           580:                       lhdr->oui[0], lhdr->oui[1], lhdr->oui[2], lhdr->ethertype );
        !           581:                return -EINVAL_PKT_LLC_HEADER;
        !           582:        }
        !           583: 
        !           584:        iob_pull ( iobuf, sizeof ( *hdr ) + sizeof ( *lhdr ) );
        !           585: 
        !           586:        *ll_dest = hdr->addr1;
        !           587:        *ll_source = hdr->addr3;
        !           588:        *net_proto = lhdr->ethertype;
        !           589:        return 0;
        !           590: }
        !           591: 
        !           592: /** 802.11 link-layer protocol */
        !           593: static struct ll_protocol net80211_ll_protocol __ll_protocol = {
        !           594:        .name = "802.11",
        !           595:        .push = net80211_ll_push,
        !           596:        .pull = net80211_ll_pull,
        !           597:        .init_addr = eth_init_addr,
        !           598:        .ntoa = eth_ntoa,
        !           599:        .mc_hash = eth_mc_hash,
        !           600:        .eth_addr = eth_eth_addr,
        !           601:        .ll_proto = htons ( ARPHRD_ETHER ),     /* "encapsulated Ethernet" */
        !           602:        .hw_addr_len = ETH_ALEN,
        !           603:        .ll_addr_len = ETH_ALEN,
        !           604:        .ll_header_len = IEEE80211_TYP_FRAME_HEADER_LEN +
        !           605:                                IEEE80211_LLC_HEADER_LEN,
        !           606: };
        !           607: 
        !           608: 
        !           609: /* ---------- 802.11 network management API ---------- */
        !           610: 
        !           611: /**
        !           612:  * Get 802.11 device from wrapping network device
        !           613:  *
        !           614:  * @v netdev   Wrapping network device
        !           615:  * @ret dev    802.11 device wrapped by network device, or NULL
        !           616:  *
        !           617:  * Returns NULL if the network device does not wrap an 802.11 device.
        !           618:  */
        !           619: struct net80211_device * net80211_get ( struct net_device *netdev )
        !           620: {
        !           621:        struct net80211_device *dev;
        !           622: 
        !           623:        list_for_each_entry ( dev, &net80211_devices, list ) {
        !           624:                if ( netdev->priv == dev )
        !           625:                        return netdev->priv;
        !           626:        }
        !           627: 
        !           628:        return NULL;
        !           629: }
        !           630: 
        !           631: /**
        !           632:  * Set state of 802.11 device keeping management frames
        !           633:  *
        !           634:  * @v dev      802.11 device
        !           635:  * @v enable   Whether to keep management frames
        !           636:  * @ret oldenab        Whether management frames were enabled before this call
        !           637:  *
        !           638:  * If enable is TRUE, beacon, probe, and action frames will be kept
        !           639:  * and may be retrieved by calling net80211_mgmt_dequeue().
        !           640:  */
        !           641: int net80211_keep_mgmt ( struct net80211_device *dev, int enable )
        !           642: {
        !           643:        int oldenab = dev->keep_mgmt;
        !           644: 
        !           645:        dev->keep_mgmt = enable;
        !           646:        return oldenab;
        !           647: }
        !           648: 
        !           649: /**
        !           650:  * Get 802.11 management frame
        !           651:  *
        !           652:  * @v dev      802.11 device
        !           653:  * @ret signal Signal strength of returned management frame
        !           654:  * @ret iob    I/O buffer, or NULL if no management frame is queued
        !           655:  *
        !           656:  * Frames will only be returned by this function if
        !           657:  * net80211_keep_mgmt() has been previously called with enable set to
        !           658:  * TRUE.
        !           659:  *
        !           660:  * The calling function takes ownership of the returned I/O buffer.
        !           661:  */
        !           662: struct io_buffer * net80211_mgmt_dequeue ( struct net80211_device *dev,
        !           663:                                           int *signal )
        !           664: {
        !           665:        struct io_buffer *iobuf;
        !           666:        struct net80211_rx_info *rxi;
        !           667: 
        !           668:        list_for_each_entry ( rxi, &dev->mgmt_info_queue, list ) {
        !           669:                list_del ( &rxi->list );
        !           670:                if ( signal )
        !           671:                        *signal = rxi->signal;
        !           672:                free ( rxi );
        !           673: 
        !           674:                assert ( ! list_empty ( &dev->mgmt_queue ) );
        !           675:                iobuf = list_first_entry ( &dev->mgmt_queue, struct io_buffer,
        !           676:                                           list );
        !           677:                list_del ( &iobuf->list );
        !           678:                return iobuf;
        !           679:        }
        !           680: 
        !           681:        return NULL;
        !           682: }
        !           683: 
        !           684: /**
        !           685:  * Transmit 802.11 management frame
        !           686:  *
        !           687:  * @v dev      802.11 device
        !           688:  * @v fc       Frame Control flags for management frame
        !           689:  * @v dest     Destination access point
        !           690:  * @v iob      I/O buffer
        !           691:  * @ret rc     Return status code
        !           692:  *
        !           693:  * The @a fc argument must contain at least an IEEE 802.11 management
        !           694:  * subtype number (e.g. IEEE80211_STYPE_PROBE_REQ). If it contains
        !           695:  * IEEE80211_FC_PROTECTED, the frame will be encrypted prior to
        !           696:  * transmission.
        !           697:  *
        !           698:  * It is required that @a iob have at least 24 bytes of headroom
        !           699:  * reserved before its data start.
        !           700:  */
        !           701: int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc, u8 dest[6],
        !           702:                       struct io_buffer *iob )
        !           703: {
        !           704:        struct ieee80211_frame *hdr = iob_push ( iob,
        !           705:                                                 IEEE80211_TYP_FRAME_HEADER_LEN );
        !           706: 
        !           707:        hdr->fc = IEEE80211_THIS_VERSION | IEEE80211_TYPE_MGMT |
        !           708:            ( fc & ~IEEE80211_FC_PROTECTED );
        !           709:        hdr->duration = net80211_duration ( dev, 10, dev->rates[dev->rate] );
        !           710:        hdr->seq = IEEE80211_MAKESEQ ( ++dev->last_tx_seqnr, 0 );
        !           711: 
        !           712:        memcpy ( hdr->addr1, dest, ETH_ALEN );  /* DA = RA */
        !           713:        memcpy ( hdr->addr2, dev->netdev->ll_addr, ETH_ALEN );  /* SA = TA */
        !           714:        memcpy ( hdr->addr3, dest, ETH_ALEN );  /* BSSID */
        !           715: 
        !           716:        if ( fc & IEEE80211_FC_PROTECTED ) {
        !           717:                if ( ! dev->crypto )
        !           718:                        return -EINVAL_CRYPTO_REQUEST;
        !           719: 
        !           720:                struct io_buffer *eiob = dev->crypto->encrypt ( dev->crypto,
        !           721:                                                                iob );
        !           722:                free_iob ( iob );
        !           723:                iob = eiob;
        !           724:        }
        !           725: 
        !           726:        return netdev_tx ( dev->netdev, iob );
        !           727: }
        !           728: 
        !           729: 
        !           730: /* ---------- Driver API ---------- */
        !           731: 
        !           732: /**
        !           733:  * Allocate 802.11 device
        !           734:  *
        !           735:  * @v priv_size                Size of driver-private allocation area
        !           736:  * @ret dev            Newly allocated 802.11 device
        !           737:  *
        !           738:  * This function allocates a net_device with space in its private area
        !           739:  * for both the net80211_device it will wrap and the driver-private
        !           740:  * data space requested. It initializes the link-layer-specific parts
        !           741:  * of the net_device, and links the net80211_device to the net_device
        !           742:  * appropriately.
        !           743:  */
        !           744: struct net80211_device * net80211_alloc ( size_t priv_size )
        !           745: {
        !           746:        struct net80211_device *dev;
        !           747:        struct net_device *netdev =
        !           748:                alloc_netdev ( sizeof ( *dev ) + priv_size );
        !           749: 
        !           750:        if ( ! netdev )
        !           751:                return NULL;
        !           752: 
        !           753:        netdev->ll_protocol = &net80211_ll_protocol;
        !           754:        netdev->ll_broadcast = net80211_ll_broadcast;
        !           755:        netdev->max_pkt_len = IEEE80211_MAX_DATA_LEN;
        !           756:        netdev_init ( netdev, &net80211_netdev_ops );
        !           757: 
        !           758:        dev = netdev->priv;
        !           759:        dev->netdev = netdev;
        !           760:        dev->priv = ( u8 * ) dev + sizeof ( *dev );
        !           761:        dev->op = &net80211_null_ops;
        !           762: 
        !           763:        process_init_stopped ( &dev->proc_assoc, net80211_step_associate,
        !           764:                               &netdev->refcnt );
        !           765:        INIT_LIST_HEAD ( &dev->mgmt_queue );
        !           766:        INIT_LIST_HEAD ( &dev->mgmt_info_queue );
        !           767: 
        !           768:        return dev;
        !           769: }
        !           770: 
        !           771: /**
        !           772:  * Register 802.11 device with network stack
        !           773:  *
        !           774:  * @v dev      802.11 device
        !           775:  * @v ops      802.11 device operations
        !           776:  * @v hw       802.11 hardware information
        !           777:  *
        !           778:  * This also registers the wrapping net_device with the higher network
        !           779:  * layers.
        !           780:  */
        !           781: int net80211_register ( struct net80211_device *dev,
        !           782:                        struct net80211_device_operations *ops,
        !           783:                        struct net80211_hw_info *hw )
        !           784: {
        !           785:        dev->op = ops;
        !           786:        dev->hw = malloc ( sizeof ( *hw ) );
        !           787:        if ( ! dev->hw )
        !           788:                return -ENOMEM;
        !           789: 
        !           790:        memcpy ( dev->hw, hw, sizeof ( *hw ) );
        !           791:        memcpy ( dev->netdev->hw_addr, hw->hwaddr, ETH_ALEN );
        !           792: 
        !           793:        /* Set some sensible channel defaults for driver's open() function */
        !           794:        memcpy ( dev->channels, dev->hw->channels,
        !           795:                 NET80211_MAX_CHANNELS * sizeof ( dev->channels[0] ) );
        !           796:        dev->channel = 0;
        !           797: 
        !           798:        list_add_tail ( &dev->list, &net80211_devices );
        !           799:        return register_netdev ( dev->netdev );
        !           800: }
        !           801: 
        !           802: /**
        !           803:  * Unregister 802.11 device from network stack
        !           804:  *
        !           805:  * @v dev      802.11 device
        !           806:  *
        !           807:  * After this call, the device operations are cleared so that they
        !           808:  * will not be called.
        !           809:  */
        !           810: void net80211_unregister ( struct net80211_device *dev )
        !           811: {
        !           812:        unregister_netdev ( dev->netdev );
        !           813:        list_del ( &dev->list );
        !           814:        dev->op = &net80211_null_ops;
        !           815: }
        !           816: 
        !           817: /**
        !           818:  * Free 802.11 device
        !           819:  *
        !           820:  * @v dev      802.11 device
        !           821:  *
        !           822:  * The device should be unregistered before this function is called.
        !           823:  */
        !           824: void net80211_free ( struct net80211_device *dev )
        !           825: {
        !           826:        free ( dev->hw );
        !           827:        rc80211_free ( dev->rctl );
        !           828:        netdev_nullify ( dev->netdev );
        !           829:        netdev_put ( dev->netdev );
        !           830: }
        !           831: 
        !           832: 
        !           833: /* ---------- 802.11 network management workhorse code ---------- */
        !           834: 
        !           835: /**
        !           836:  * Set state of 802.11 device
        !           837:  *
        !           838:  * @v dev      802.11 device
        !           839:  * @v clear    Bitmask of flags to clear
        !           840:  * @v set      Bitmask of flags to set
        !           841:  * @v status   Status or reason code for most recent operation
        !           842:  *
        !           843:  * If @a status represents a reason code, it should be OR'ed with
        !           844:  * NET80211_IS_REASON.
        !           845:  *
        !           846:  * Clearing authentication also clears association; clearing
        !           847:  * association also clears security handshaking state. Clearing
        !           848:  * association removes the link-up flag from the wrapping net_device,
        !           849:  * but setting it does not automatically set the flag; that is left to
        !           850:  * the judgment of higher-level code.
        !           851:  */
        !           852: static inline void net80211_set_state ( struct net80211_device *dev,
        !           853:                                        short clear, short set,
        !           854:                                        u16 status )
        !           855: {
        !           856:        /* The conditions in this function are deliberately formulated
        !           857:           to be decidable at compile-time in most cases. Since clear
        !           858:           and set are generally passed as constants, the body of this
        !           859:           function can be reduced down to a few statements by the
        !           860:           compiler. */
        !           861: 
        !           862:        const int statmsk = NET80211_STATUS_MASK | NET80211_IS_REASON;
        !           863: 
        !           864:        if ( clear & NET80211_PROBED )
        !           865:                clear |= NET80211_AUTHENTICATED;
        !           866: 
        !           867:        if ( clear & NET80211_AUTHENTICATED )
        !           868:                clear |= NET80211_ASSOCIATED;
        !           869: 
        !           870:        if ( clear & NET80211_ASSOCIATED )
        !           871:                clear |= NET80211_CRYPTO_SYNCED;
        !           872: 
        !           873:        dev->state = ( dev->state & ~clear ) | set;
        !           874:        dev->state = ( dev->state & ~statmsk ) | ( status & statmsk );
        !           875: 
        !           876:        if ( clear & NET80211_ASSOCIATED )
        !           877:                netdev_link_down ( dev->netdev );
        !           878: 
        !           879:        if ( ( clear | set ) & NET80211_ASSOCIATED )
        !           880:                dev->op->config ( dev, NET80211_CFG_ASSOC );
        !           881: 
        !           882:        if ( status != 0 ) {
        !           883:                if ( status & NET80211_IS_REASON )
        !           884:                        dev->assoc_rc = -E80211_REASON ( status );
        !           885:                else
        !           886:                        dev->assoc_rc = -E80211_STATUS ( status );
        !           887:                netdev_link_err ( dev->netdev, dev->assoc_rc );
        !           888:        }
        !           889: }
        !           890: 
        !           891: /**
        !           892:  * Add channels to 802.11 device
        !           893:  *
        !           894:  * @v dev      802.11 device
        !           895:  * @v start    First channel number to add
        !           896:  * @v len      Number of channels to add
        !           897:  * @v txpower  TX power (dBm) to allow on added channels
        !           898:  *
        !           899:  * To replace the current list of channels instead of adding to it,
        !           900:  * set the nr_channels field of the 802.11 device to 0 before calling
        !           901:  * this function.
        !           902:  */
        !           903: static void net80211_add_channels ( struct net80211_device *dev, int start,
        !           904:                                    int len, int txpower )
        !           905: {
        !           906:        int i, chan = start;
        !           907: 
        !           908:        for ( i = dev->nr_channels; len-- && i < NET80211_MAX_CHANNELS; i++ ) {
        !           909:                dev->channels[i].channel_nr = chan;
        !           910:                dev->channels[i].maxpower = txpower;
        !           911:                dev->channels[i].hw_value = 0;
        !           912: 
        !           913:                if ( chan >= 1 && chan <= 14 ) {
        !           914:                        dev->channels[i].band = NET80211_BAND_2GHZ;
        !           915:                        if ( chan == 14 )
        !           916:                                dev->channels[i].center_freq = 2484;
        !           917:                        else
        !           918:                                dev->channels[i].center_freq = 2407 + 5 * chan;
        !           919:                        chan++;
        !           920:                } else {
        !           921:                        dev->channels[i].band = NET80211_BAND_5GHZ;
        !           922:                        dev->channels[i].center_freq = 5000 + 5 * chan;
        !           923:                        chan += 4;
        !           924:                }
        !           925:        }
        !           926: 
        !           927:        dev->nr_channels = i;
        !           928: }
        !           929: 
        !           930: /**
        !           931:  * Filter 802.11 device channels for hardware capabilities
        !           932:  *
        !           933:  * @v dev      802.11 device
        !           934:  *
        !           935:  * Hardware may support fewer channels than regulatory restrictions
        !           936:  * allow; this function filters out channels in dev->channels that are
        !           937:  * not supported by the hardware list in dev->hwinfo. It also copies
        !           938:  * over the net80211_channel::hw_value and limits maximum TX power
        !           939:  * appropriately.
        !           940:  *
        !           941:  * Channels are matched based on center frequency, ignoring band and
        !           942:  * channel number.
        !           943:  *
        !           944:  * If the driver specifies no supported channels, the effect will be
        !           945:  * as though all were supported.
        !           946:  */
        !           947: static void net80211_filter_hw_channels ( struct net80211_device *dev )
        !           948: {
        !           949:        int delta = 0, i = 0;
        !           950:        int old_freq = dev->channels[dev->channel].center_freq;
        !           951:        struct net80211_channel *chan, *hwchan;
        !           952: 
        !           953:        if ( ! dev->hw->nr_channels )
        !           954:                return;
        !           955: 
        !           956:        dev->channel = 0;
        !           957:        for ( chan = dev->channels; chan < dev->channels + dev->nr_channels;
        !           958:              chan++, i++ ) {
        !           959:                int ok = 0;
        !           960:                for ( hwchan = dev->hw->channels;
        !           961:                      hwchan < dev->hw->channels + dev->hw->nr_channels;
        !           962:                      hwchan++ ) {
        !           963:                        if ( hwchan->center_freq == chan->center_freq ) {
        !           964:                                ok = 1;
        !           965:                                break;
        !           966:                        }
        !           967:                }
        !           968: 
        !           969:                if ( ! ok )
        !           970:                        delta++;
        !           971:                else {
        !           972:                        chan->hw_value = hwchan->hw_value;
        !           973:                        if ( hwchan->maxpower != 0 &&
        !           974:                             chan->maxpower > hwchan->maxpower )
        !           975:                                chan->maxpower = hwchan->maxpower;
        !           976:                        if ( old_freq == chan->center_freq )
        !           977:                                dev->channel = i - delta;
        !           978:                        if ( delta )
        !           979:                                chan[-delta] = *chan;
        !           980:                }
        !           981:        }
        !           982: 
        !           983:        dev->nr_channels -= delta;
        !           984: 
        !           985:        if ( dev->channels[dev->channel].center_freq != old_freq )
        !           986:                dev->op->config ( dev, NET80211_CFG_CHANNEL );
        !           987: }
        !           988: 
        !           989: /**
        !           990:  * Update 802.11 device state to reflect received capabilities field
        !           991:  *
        !           992:  * @v dev      802.11 device
        !           993:  * @v capab    Capabilities field in beacon, probe, or association frame
        !           994:  * @ret rc     Return status code
        !           995:  */
        !           996: static int net80211_process_capab ( struct net80211_device *dev,
        !           997:                                    u16 capab )
        !           998: {
        !           999:        u16 old_phy = dev->phy_flags;
        !          1000: 
        !          1001:        if ( ( capab & ( IEEE80211_CAPAB_MANAGED | IEEE80211_CAPAB_ADHOC ) ) !=
        !          1002:             IEEE80211_CAPAB_MANAGED ) {
        !          1003:                DBGC ( dev, "802.11 %p cannot handle IBSS network\n", dev );
        !          1004:                return -ENOSYS;
        !          1005:        }
        !          1006: 
        !          1007:        dev->phy_flags &= ~( NET80211_PHY_USE_SHORT_PREAMBLE |
        !          1008:                             NET80211_PHY_USE_SHORT_SLOT );
        !          1009: 
        !          1010:        if ( capab & IEEE80211_CAPAB_SHORT_PMBL )
        !          1011:                dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
        !          1012: 
        !          1013:        if ( capab & IEEE80211_CAPAB_SHORT_SLOT )
        !          1014:                dev->phy_flags |= NET80211_PHY_USE_SHORT_SLOT;
        !          1015: 
        !          1016:        if ( old_phy != dev->phy_flags )
        !          1017:                dev->op->config ( dev, NET80211_CFG_PHY_PARAMS );
        !          1018: 
        !          1019:        return 0;
        !          1020: }
        !          1021: 
        !          1022: /**
        !          1023:  * Update 802.11 device state to reflect received information elements
        !          1024:  *
        !          1025:  * @v dev      802.11 device
        !          1026:  * @v ie       Pointer to first information element
        !          1027:  * @v ie_end   Pointer to tail of packet I/O buffer
        !          1028:  * @ret rc     Return status code
        !          1029:  */
        !          1030: static int net80211_process_ie ( struct net80211_device *dev,
        !          1031:                                 union ieee80211_ie *ie, void *ie_end )
        !          1032: {
        !          1033:        u16 old_rate = dev->rates[dev->rate];
        !          1034:        u16 old_phy = dev->phy_flags;
        !          1035:        int have_rates = 0, i;
        !          1036:        int ds_channel = 0;
        !          1037:        int changed = 0;
        !          1038:        int band = dev->channels[dev->channel].band;
        !          1039: 
        !          1040:        if ( ! ieee80211_ie_bound ( ie, ie_end ) )
        !          1041:                return 0;
        !          1042: 
        !          1043:        for ( ; ie; ie = ieee80211_next_ie ( ie, ie_end ) ) {
        !          1044:                switch ( ie->id ) {
        !          1045:                case IEEE80211_IE_SSID:
        !          1046:                        if ( ie->len <= 32 ) {
        !          1047:                                memcpy ( dev->essid, ie->ssid, ie->len );
        !          1048:                                dev->essid[ie->len] = 0;
        !          1049:                        }
        !          1050:                        break;
        !          1051: 
        !          1052:                case IEEE80211_IE_RATES:
        !          1053:                case IEEE80211_IE_EXT_RATES:
        !          1054:                        if ( ! have_rates ) {
        !          1055:                                dev->nr_rates = 0;
        !          1056:                                dev->basic_rates = 0;
        !          1057:                                have_rates = 1;
        !          1058:                        }
        !          1059:                        for ( i = 0; i < ie->len &&
        !          1060:                              dev->nr_rates < NET80211_MAX_RATES; i++ ) {
        !          1061:                                u8 rid = ie->rates[i];
        !          1062:                                u16 rate = ( rid & 0x7f ) * 5;
        !          1063: 
        !          1064:                                if ( rid & 0x80 )
        !          1065:                                        dev->basic_rates |=
        !          1066:                                                ( 1 << dev->nr_rates );
        !          1067: 
        !          1068:                                dev->rates[dev->nr_rates++] = rate;
        !          1069:                        }
        !          1070: 
        !          1071:                        break;
        !          1072: 
        !          1073:                case IEEE80211_IE_DS_PARAM:
        !          1074:                        if ( dev->channel < dev->nr_channels && ds_channel ==
        !          1075:                             dev->channels[dev->channel].channel_nr )
        !          1076:                                break;
        !          1077:                        ds_channel = ie->ds_param.current_channel;
        !          1078:                        net80211_change_channel ( dev, ds_channel );
        !          1079:                        break;
        !          1080: 
        !          1081:                case IEEE80211_IE_COUNTRY:
        !          1082:                        dev->nr_channels = 0;
        !          1083: 
        !          1084:                        DBGC ( dev, "802.11 %p setting country regulations "
        !          1085:                               "for %c%c\n", dev, ie->country.name[0],
        !          1086:                               ie->country.name[1] );
        !          1087:                        for ( i = 0; i < ( ie->len - 3 ) / 3; i++ ) {
        !          1088:                                union ieee80211_ie_country_triplet *t =
        !          1089:                                        &ie->country.triplet[i];
        !          1090:                                if ( t->first > 200 ) {
        !          1091:                                        DBGC ( dev, "802.11 %p ignoring regulatory "
        !          1092:                                               "extension information\n", dev );
        !          1093:                                } else {
        !          1094:                                        net80211_add_channels ( dev,
        !          1095:                                                        t->band.first_channel,
        !          1096:                                                        t->band.nr_channels,
        !          1097:                                                        t->band.max_txpower );
        !          1098:                                }
        !          1099:                        }
        !          1100:                        net80211_filter_hw_channels ( dev );
        !          1101:                        break;
        !          1102: 
        !          1103:                case IEEE80211_IE_ERP_INFO:
        !          1104:                        dev->phy_flags &= ~( NET80211_PHY_USE_PROTECTION |
        !          1105:                                             NET80211_PHY_USE_SHORT_PREAMBLE );
        !          1106:                        if ( ie->erp_info & IEEE80211_ERP_USE_PROTECTION )
        !          1107:                                dev->phy_flags |= NET80211_PHY_USE_PROTECTION;
        !          1108:                        if ( ! ( ie->erp_info & IEEE80211_ERP_BARKER_LONG ) )
        !          1109:                                dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
        !          1110:                        break;
        !          1111:                }
        !          1112:        }
        !          1113: 
        !          1114:        if ( have_rates ) {
        !          1115:                /* Allow only those rates that are also supported by
        !          1116:                   the hardware. */
        !          1117:                int delta = 0, j;
        !          1118: 
        !          1119:                dev->rate = 0;
        !          1120:                for ( i = 0; i < dev->nr_rates; i++ ) {
        !          1121:                        int ok = 0;
        !          1122:                        for ( j = 0; j < dev->hw->nr_rates[band]; j++ ) {
        !          1123:                                if ( dev->hw->rates[band][j] == dev->rates[i] ){
        !          1124:                                        ok = 1;
        !          1125:                                        break;
        !          1126:                                }
        !          1127:                        }
        !          1128: 
        !          1129:                        if ( ! ok )
        !          1130:                                delta++;
        !          1131:                        else {
        !          1132:                                dev->rates[i - delta] = dev->rates[i];
        !          1133:                                if ( old_rate == dev->rates[i] )
        !          1134:                                        dev->rate = i - delta;
        !          1135:                        }
        !          1136:                }
        !          1137: 
        !          1138:                dev->nr_rates -= delta;
        !          1139: 
        !          1140:                /* Sort available rates - sorted subclumps tend to already
        !          1141:                   exist, so insertion sort works well. */
        !          1142:                for ( i = 1; i < dev->nr_rates; i++ ) {
        !          1143:                        u16 rate = dev->rates[i];
        !          1144:                        u32 tmp, br, mask;
        !          1145: 
        !          1146:                        for ( j = i - 1; j >= 0 && dev->rates[j] >= rate; j-- )
        !          1147:                                dev->rates[j + 1] = dev->rates[j];
        !          1148:                        dev->rates[j + 1] = rate;
        !          1149: 
        !          1150:                        /* Adjust basic_rates to match by rotating the
        !          1151:                           bits from bit j+1 to bit i left one position. */
        !          1152:                        mask = ( ( 1 << i ) - 1 ) & ~( ( 1 << ( j + 1 ) ) - 1 );
        !          1153:                        br = dev->basic_rates;
        !          1154:                        tmp = br & ( 1 << i );
        !          1155:                        br = ( br & ~( mask | tmp ) ) | ( ( br & mask ) << 1 );
        !          1156:                        br |= ( tmp >> ( i - j - 1 ) );
        !          1157:                        dev->basic_rates = br;
        !          1158:                }
        !          1159: 
        !          1160:                net80211_set_rtscts_rate ( dev );
        !          1161: 
        !          1162:                if ( dev->rates[dev->rate] != old_rate )
        !          1163:                        changed |= NET80211_CFG_RATE;
        !          1164:        }
        !          1165: 
        !          1166:        if ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE )
        !          1167:                dev->phy_flags &= ~NET80211_PHY_USE_SHORT_PREAMBLE;
        !          1168:        if ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT )
        !          1169:                dev->phy_flags &= ~NET80211_PHY_USE_SHORT_SLOT;
        !          1170: 
        !          1171:        if ( old_phy != dev->phy_flags )
        !          1172:                changed |= NET80211_CFG_PHY_PARAMS;
        !          1173: 
        !          1174:        if ( changed )
        !          1175:                dev->op->config ( dev, changed );
        !          1176: 
        !          1177:        return 0;
        !          1178: }
        !          1179: 
        !          1180: /**
        !          1181:  * Create information elements for outgoing probe or association packet
        !          1182:  *
        !          1183:  * @v dev              802.11 device
        !          1184:  * @v ie               Pointer to start of information element area
        !          1185:  * @ret next_ie                Pointer to first byte after added information elements
        !          1186:  */
        !          1187: static union ieee80211_ie *
        !          1188: net80211_marshal_request_info ( struct net80211_device *dev,
        !          1189:                                union ieee80211_ie *ie )
        !          1190: {
        !          1191:        int i;
        !          1192: 
        !          1193:        ie->id = IEEE80211_IE_SSID;
        !          1194:        ie->len = strlen ( dev->essid );
        !          1195:        memcpy ( ie->ssid, dev->essid, ie->len );
        !          1196: 
        !          1197:        ie = ieee80211_next_ie ( ie, NULL );
        !          1198: 
        !          1199:        ie->id = IEEE80211_IE_RATES;
        !          1200:        ie->len = dev->nr_rates;
        !          1201:        if ( ie->len > 8 )
        !          1202:                ie->len = 8;
        !          1203: 
        !          1204:        for ( i = 0; i < ie->len; i++ ) {
        !          1205:                ie->rates[i] = dev->rates[i] / 5;
        !          1206:                if ( dev->basic_rates & ( 1 << i ) )
        !          1207:                        ie->rates[i] |= 0x80;
        !          1208:        }
        !          1209: 
        !          1210:        ie = ieee80211_next_ie ( ie, NULL );
        !          1211: 
        !          1212:        if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_RSN ) {
        !          1213:                memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
        !          1214:                ie = ieee80211_next_ie ( ie, NULL );
        !          1215:        }
        !          1216: 
        !          1217:        if ( dev->nr_rates > 8 ) {
        !          1218:                /* 802.11 requires we use an Extended Basic Rates IE
        !          1219:                   for the rates beyond the eighth. */
        !          1220: 
        !          1221:                ie->id = IEEE80211_IE_EXT_RATES;
        !          1222:                ie->len = dev->nr_rates - 8;
        !          1223: 
        !          1224:                for ( ; i < dev->nr_rates; i++ ) {
        !          1225:                        ie->rates[i - 8] = dev->rates[i] / 5;
        !          1226:                        if ( dev->basic_rates & ( 1 << i ) )
        !          1227:                                ie->rates[i - 8] |= 0x80;
        !          1228:                }
        !          1229: 
        !          1230:                ie = ieee80211_next_ie ( ie, NULL );
        !          1231:        }
        !          1232: 
        !          1233:        if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_VENDOR ) {
        !          1234:                memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
        !          1235:                ie = ieee80211_next_ie ( ie, NULL );
        !          1236:        }
        !          1237: 
        !          1238:        return ie;
        !          1239: }
        !          1240: 
        !          1241: /** Seconds to wait after finding a network, to possibly find better APs for it
        !          1242:  *
        !          1243:  * This is used when a specific SSID to scan for is specified.
        !          1244:  */
        !          1245: #define NET80211_PROBE_GATHER    1
        !          1246: 
        !          1247: /** Seconds to wait after finding a network, to possibly find other networks
        !          1248:  *
        !          1249:  * This is used when an empty SSID is specified, to scan for all
        !          1250:  * networks.
        !          1251:  */
        !          1252: #define NET80211_PROBE_GATHER_ALL 2
        !          1253: 
        !          1254: /** Seconds to allow a probe to take if no network has been found */
        !          1255: #define NET80211_PROBE_TIMEOUT   6
        !          1256: 
        !          1257: /**
        !          1258:  * Begin probe of 802.11 networks
        !          1259:  *
        !          1260:  * @v dev      802.11 device
        !          1261:  * @v essid    SSID to probe for, or "" to accept any (may not be NULL)
        !          1262:  * @v active   Whether to use active scanning
        !          1263:  * @ret ctx    Probe context
        !          1264:  *
        !          1265:  * Active scanning may only be used on channels 1-11 in the 2.4GHz
        !          1266:  * band, due to iPXE's lack of a complete regulatory database. If
        !          1267:  * active scanning is used, probe packets will be sent on each
        !          1268:  * channel; this can allow association with hidden-SSID networks if
        !          1269:  * the SSID is properly specified.
        !          1270:  *
        !          1271:  * A @c NULL return indicates an out-of-memory condition.
        !          1272:  *
        !          1273:  * The returned context must be periodically passed to
        !          1274:  * net80211_probe_step() until that function returns zero.
        !          1275:  */
        !          1276: struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
        !          1277:                                                   const char *essid,
        !          1278:                                                   int active )
        !          1279: {
        !          1280:        struct net80211_probe_ctx *ctx = zalloc ( sizeof ( *ctx ) );
        !          1281: 
        !          1282:        if ( ! ctx )
        !          1283:                return NULL;
        !          1284: 
        !          1285:        assert ( netdev_is_open ( dev->netdev ) );
        !          1286: 
        !          1287:        ctx->dev = dev;
        !          1288:        ctx->old_keep_mgmt = net80211_keep_mgmt ( dev, 1 );
        !          1289:        ctx->essid = essid;
        !          1290:        if ( dev->essid != ctx->essid )
        !          1291:                strcpy ( dev->essid, ctx->essid );
        !          1292: 
        !          1293:        if ( active ) {
        !          1294:                struct ieee80211_probe_req *probe_req;
        !          1295:                union ieee80211_ie *ie;
        !          1296: 
        !          1297:                ctx->probe = alloc_iob ( 128 );
        !          1298:                iob_reserve ( ctx->probe, IEEE80211_TYP_FRAME_HEADER_LEN );
        !          1299:                probe_req = ctx->probe->data;
        !          1300: 
        !          1301:                ie = net80211_marshal_request_info ( dev,
        !          1302:                                                     probe_req->info_element );
        !          1303: 
        !          1304:                iob_put ( ctx->probe, ( void * ) ie - ctx->probe->data );
        !          1305:        }
        !          1306: 
        !          1307:        ctx->ticks_start = currticks();
        !          1308:        ctx->ticks_beacon = 0;
        !          1309:        ctx->ticks_channel = currticks();
        !          1310:        ctx->hop_time = ticks_per_sec() / ( active ? 2 : 6 );
        !          1311: 
        !          1312:        /*
        !          1313:         * Channels on 2.4GHz overlap, and the most commonly used
        !          1314:         * are 1, 6, and 11. We'll get a result faster if we check
        !          1315:         * every 5 channels, but in order to hit all of them the
        !          1316:         * number of channels must be relatively prime to 5. If it's
        !          1317:         * not, tweak the hop.
        !          1318:         */
        !          1319:        ctx->hop_step = 5;
        !          1320:        while ( dev->nr_channels % ctx->hop_step == 0 && ctx->hop_step > 1 )
        !          1321:                ctx->hop_step--;
        !          1322: 
        !          1323:        ctx->beacons = malloc ( sizeof ( *ctx->beacons ) );
        !          1324:        INIT_LIST_HEAD ( ctx->beacons );
        !          1325: 
        !          1326:        dev->channel = 0;
        !          1327:        dev->op->config ( dev, NET80211_CFG_CHANNEL );
        !          1328: 
        !          1329:        return ctx;
        !          1330: }
        !          1331: 
        !          1332: /**
        !          1333:  * Continue probe of 802.11 networks
        !          1334:  *
        !          1335:  * @v ctx      Probe context returned by net80211_probe_start()
        !          1336:  * @ret rc     Probe status
        !          1337:  *
        !          1338:  * The return code will be 0 if the probe is still going on (and this
        !          1339:  * function should be called again), a positive number if the probe
        !          1340:  * completed successfully, or a negative error code if the probe
        !          1341:  * failed for that reason.
        !          1342:  *
        !          1343:  * Whether the probe succeeded or failed, you must call
        !          1344:  * net80211_probe_finish_all() or net80211_probe_finish_best()
        !          1345:  * (depending on whether you want information on all networks or just
        !          1346:  * the best-signal one) in order to release the probe context. A
        !          1347:  * failed probe may still have acquired some valid data.
        !          1348:  */
        !          1349: int net80211_probe_step ( struct net80211_probe_ctx *ctx )
        !          1350: {
        !          1351:        struct net80211_device *dev = ctx->dev;
        !          1352:        u32 start_timeout = NET80211_PROBE_TIMEOUT * ticks_per_sec();
        !          1353:        u32 gather_timeout = ticks_per_sec();
        !          1354:        u32 now = currticks();
        !          1355:        struct io_buffer *iob;
        !          1356:        int signal;
        !          1357:        int rc;
        !          1358:        char ssid[IEEE80211_MAX_SSID_LEN + 1];
        !          1359: 
        !          1360:        gather_timeout *= ( ctx->essid[0] ? NET80211_PROBE_GATHER :
        !          1361:                            NET80211_PROBE_GATHER_ALL );
        !          1362: 
        !          1363:        /* Time out if necessary */
        !          1364:        if ( now >= ctx->ticks_start + start_timeout )
        !          1365:                return list_empty ( ctx->beacons ) ? -ETIMEDOUT : +1;
        !          1366: 
        !          1367:        if ( ctx->ticks_beacon > 0 && now >= ctx->ticks_start + gather_timeout )
        !          1368:                return +1;
        !          1369: 
        !          1370:        /* Change channels if necessary */
        !          1371:        if ( now >= ctx->ticks_channel + ctx->hop_time ) {
        !          1372:                dev->channel = ( dev->channel + ctx->hop_step )
        !          1373:                        % dev->nr_channels;
        !          1374:                dev->op->config ( dev, NET80211_CFG_CHANNEL );
        !          1375:                udelay ( dev->hw->channel_change_time );
        !          1376: 
        !          1377:                ctx->ticks_channel = now;
        !          1378: 
        !          1379:                if ( ctx->probe ) {
        !          1380:                        struct io_buffer *siob = ctx->probe; /* to send */
        !          1381: 
        !          1382:                        /* make a copy for future use */
        !          1383:                        iob = alloc_iob ( siob->tail - siob->head );
        !          1384:                        iob_reserve ( iob, iob_headroom ( siob ) );
        !          1385:                        memcpy ( iob_put ( iob, iob_len ( siob ) ),
        !          1386:                                 siob->data, iob_len ( siob ) );
        !          1387: 
        !          1388:                        ctx->probe = iob;
        !          1389:                        rc = net80211_tx_mgmt ( dev, IEEE80211_STYPE_PROBE_REQ,
        !          1390:                                                net80211_ll_broadcast,
        !          1391:                                                iob_disown ( siob ) );
        !          1392:                        if ( rc ) {
        !          1393:                                DBGC ( dev, "802.11 %p send probe failed: "
        !          1394:                                       "%s\n", dev, strerror ( rc ) );
        !          1395:                                return rc;
        !          1396:                        }
        !          1397:                }
        !          1398:        }
        !          1399: 
        !          1400:        /* Check for new management packets */
        !          1401:        while ( ( iob = net80211_mgmt_dequeue ( dev, &signal ) ) != NULL ) {
        !          1402:                struct ieee80211_frame *hdr;
        !          1403:                struct ieee80211_beacon *beacon;
        !          1404:                union ieee80211_ie *ie;
        !          1405:                struct net80211_wlan *wlan;
        !          1406:                u16 type;
        !          1407: 
        !          1408:                hdr = iob->data;
        !          1409:                type = hdr->fc & IEEE80211_FC_SUBTYPE;
        !          1410:                beacon = ( struct ieee80211_beacon * ) hdr->data;
        !          1411: 
        !          1412:                if ( type != IEEE80211_STYPE_BEACON &&
        !          1413:                     type != IEEE80211_STYPE_PROBE_RESP ) {
        !          1414:                        DBGC2 ( dev, "802.11 %p probe: non-beacon\n", dev );
        !          1415:                        goto drop;
        !          1416:                }
        !          1417: 
        !          1418:                if ( ( void * ) beacon->info_element >= iob->tail ) {
        !          1419:                        DBGC ( dev, "802.11 %p probe: beacon with no IEs\n",
        !          1420:                               dev );
        !          1421:                        goto drop;
        !          1422:                }
        !          1423: 
        !          1424:                ie = beacon->info_element;
        !          1425: 
        !          1426:                if ( ! ieee80211_ie_bound ( ie, iob->tail ) )
        !          1427:                        ie = NULL;
        !          1428: 
        !          1429:                while ( ie && ie->id != IEEE80211_IE_SSID )
        !          1430:                        ie = ieee80211_next_ie ( ie, iob->tail );
        !          1431: 
        !          1432:                if ( ! ie ) {
        !          1433:                        DBGC ( dev, "802.11 %p probe: beacon with no SSID\n",
        !          1434:                               dev );
        !          1435:                        goto drop;
        !          1436:                }
        !          1437: 
        !          1438:                memcpy ( ssid, ie->ssid, ie->len );
        !          1439:                ssid[ie->len] = 0;
        !          1440: 
        !          1441:                if ( ctx->essid[0] && strcmp ( ctx->essid, ssid ) != 0 ) {
        !          1442:                        DBGC2 ( dev, "802.11 %p probe: beacon with wrong SSID "
        !          1443:                                "(%s)\n", dev, ssid );
        !          1444:                        goto drop;
        !          1445:                }
        !          1446: 
        !          1447:                /* See if we've got an entry for this network */
        !          1448:                list_for_each_entry ( wlan, ctx->beacons, list ) {
        !          1449:                        if ( strcmp ( wlan->essid, ssid ) != 0 )
        !          1450:                                continue;
        !          1451: 
        !          1452:                        if ( signal < wlan->signal ) {
        !          1453:                                DBGC2 ( dev, "802.11 %p probe: beacon for %s "
        !          1454:                                        "(%s) with weaker signal %d\n", dev,
        !          1455:                                        ssid, eth_ntoa ( hdr->addr3 ), signal );
        !          1456:                                goto drop;
        !          1457:                        }
        !          1458: 
        !          1459:                        goto fill;
        !          1460:                }
        !          1461: 
        !          1462:                /* No entry yet - make one */
        !          1463:                wlan = zalloc ( sizeof ( *wlan ) );
        !          1464:                strcpy ( wlan->essid, ssid );
        !          1465:                list_add_tail ( &wlan->list, ctx->beacons );
        !          1466: 
        !          1467:                /* Whether we're using an old entry or a new one, fill
        !          1468:                   it with new data. */
        !          1469:        fill:
        !          1470:                memcpy ( wlan->bssid, hdr->addr3, ETH_ALEN );
        !          1471:                wlan->signal = signal;
        !          1472:                wlan->channel = dev->channels[dev->channel].channel_nr;
        !          1473: 
        !          1474:                /* Copy this I/O buffer into a new wlan->beacon; the
        !          1475:                 * iob we've got probably came from the device driver
        !          1476:                 * and may have the full 2.4k allocation, which we
        !          1477:                 * don't want to keep around wasting memory.
        !          1478:                 */
        !          1479:                free_iob ( wlan->beacon );
        !          1480:                wlan->beacon = alloc_iob ( iob_len ( iob ) );
        !          1481:                memcpy ( iob_put ( wlan->beacon, iob_len ( iob ) ),
        !          1482:                         iob->data, iob_len ( iob ) );
        !          1483: 
        !          1484:                if ( ( rc = sec80211_detect ( wlan->beacon, &wlan->handshaking,
        !          1485:                                              &wlan->crypto ) ) == -ENOTSUP ) {
        !          1486:                        struct ieee80211_beacon *beacon =
        !          1487:                                ( struct ieee80211_beacon * ) hdr->data;
        !          1488: 
        !          1489:                        if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) {
        !          1490:                                DBG ( "802.11 %p probe: secured network %s but "
        !          1491:                                      "encryption support not compiled in\n",
        !          1492:                                      dev, wlan->essid );
        !          1493:                                wlan->handshaking = NET80211_SECPROT_UNKNOWN;
        !          1494:                                wlan->crypto = NET80211_CRYPT_UNKNOWN;
        !          1495:                        } else {
        !          1496:                                wlan->handshaking = NET80211_SECPROT_NONE;
        !          1497:                                wlan->crypto = NET80211_CRYPT_NONE;
        !          1498:                        }
        !          1499:                } else if ( rc != 0 ) {
        !          1500:                        DBGC ( dev, "802.11 %p probe warning: network "
        !          1501:                               "%s with unidentifiable security "
        !          1502:                               "settings: %s\n", dev, wlan->essid,
        !          1503:                               strerror ( rc ) );
        !          1504:                }
        !          1505: 
        !          1506:                ctx->ticks_beacon = now;
        !          1507: 
        !          1508:                DBGC2 ( dev, "802.11 %p probe: good beacon for %s (%s)\n",
        !          1509:                        dev, wlan->essid, eth_ntoa ( wlan->bssid ) );
        !          1510: 
        !          1511:        drop:
        !          1512:                free_iob ( iob );
        !          1513:        }
        !          1514: 
        !          1515:        return 0;
        !          1516: }
        !          1517: 
        !          1518: 
        !          1519: /**
        !          1520:  * Finish probe of 802.11 networks, returning best-signal network found
        !          1521:  *
        !          1522:  * @v ctx      Probe context
        !          1523:  * @ret wlan   Best-signal network found, or @c NULL if none were found
        !          1524:  *
        !          1525:  * If net80211_probe_start() was called with a particular SSID
        !          1526:  * parameter as filter, only a network with that SSID (matching
        !          1527:  * case-sensitively) can be returned from this function.
        !          1528:  */
        !          1529: struct net80211_wlan *
        !          1530: net80211_probe_finish_best ( struct net80211_probe_ctx *ctx )
        !          1531: {
        !          1532:        struct net80211_wlan *best = NULL, *wlan;
        !          1533: 
        !          1534:        if ( ! ctx )
        !          1535:                return NULL;
        !          1536: 
        !          1537:        list_for_each_entry ( wlan, ctx->beacons, list ) {
        !          1538:                if ( ! best || best->signal < wlan->signal )
        !          1539:                        best = wlan;
        !          1540:        }
        !          1541: 
        !          1542:        if ( best )
        !          1543:                list_del ( &best->list );
        !          1544:        else
        !          1545:                DBGC ( ctx->dev, "802.11 %p probe: found nothing for '%s'\n",
        !          1546:                       ctx->dev, ctx->essid );
        !          1547: 
        !          1548:        net80211_free_wlanlist ( ctx->beacons );
        !          1549: 
        !          1550:        net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );
        !          1551: 
        !          1552:        if ( ctx->probe )
        !          1553:                free_iob ( ctx->probe );
        !          1554: 
        !          1555:        free ( ctx );
        !          1556: 
        !          1557:        return best;
        !          1558: }
        !          1559: 
        !          1560: 
        !          1561: /**
        !          1562:  * Finish probe of 802.11 networks, returning all networks found
        !          1563:  *
        !          1564:  * @v ctx      Probe context
        !          1565:  * @ret list   List of net80211_wlan detailing networks found
        !          1566:  *
        !          1567:  * If net80211_probe_start() was called with a particular SSID
        !          1568:  * parameter as filter, this will always return either an empty or a
        !          1569:  * one-element list.
        !          1570:  */
        !          1571: struct list_head *net80211_probe_finish_all ( struct net80211_probe_ctx *ctx )
        !          1572: {
        !          1573:        struct list_head *beacons = ctx->beacons;
        !          1574: 
        !          1575:        if ( ! ctx )
        !          1576:                return NULL;
        !          1577: 
        !          1578:        net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );
        !          1579: 
        !          1580:        if ( ctx->probe )
        !          1581:                free_iob ( ctx->probe );
        !          1582: 
        !          1583:        free ( ctx );
        !          1584: 
        !          1585:        return beacons;
        !          1586: }
        !          1587: 
        !          1588: 
        !          1589: /**
        !          1590:  * Free WLAN structure
        !          1591:  *
        !          1592:  * @v wlan     WLAN structure to free
        !          1593:  */
        !          1594: void net80211_free_wlan ( struct net80211_wlan *wlan )
        !          1595: {
        !          1596:        if ( wlan ) {
        !          1597:                free_iob ( wlan->beacon );
        !          1598:                free ( wlan );
        !          1599:        }
        !          1600: }
        !          1601: 
        !          1602: 
        !          1603: /**
        !          1604:  * Free list of WLAN structures
        !          1605:  *
        !          1606:  * @v list     List of WLAN structures to free
        !          1607:  */
        !          1608: void net80211_free_wlanlist ( struct list_head *list )
        !          1609: {
        !          1610:        struct net80211_wlan *wlan, *tmp;
        !          1611: 
        !          1612:        if ( ! list )
        !          1613:                return;
        !          1614: 
        !          1615:        list_for_each_entry_safe ( wlan, tmp, list, list ) {
        !          1616:                list_del ( &wlan->list );
        !          1617:                net80211_free_wlan ( wlan );
        !          1618:        }
        !          1619: 
        !          1620:        free ( list );
        !          1621: }
        !          1622: 
        !          1623: 
        !          1624: /** Number of ticks to wait for replies to association management frames */
        !          1625: #define ASSOC_TIMEOUT  TICKS_PER_SEC
        !          1626: 
        !          1627: /** Number of times to try sending a particular association management frame */
        !          1628: #define ASSOC_RETRIES  2
        !          1629: 
        !          1630: /**
        !          1631:  * Step 802.11 association process
        !          1632:  *
        !          1633:  * @v proc     Association process
        !          1634:  */
        !          1635: static void net80211_step_associate ( struct process *proc )
        !          1636: {
        !          1637:        struct net80211_device *dev =
        !          1638:            container_of ( proc, struct net80211_device, proc_assoc );
        !          1639:        int rc = 0;
        !          1640:        int status = dev->state & NET80211_STATUS_MASK;
        !          1641: 
        !          1642:        /*
        !          1643:         * We use a sort of state machine implemented using bits in
        !          1644:         * the dev->state variable. At each call, we take the
        !          1645:         * logically first step that has not yet succeeded; either it
        !          1646:         * has not been tried yet, it's being retried, or it failed.
        !          1647:         * If it failed, we return an error indication; otherwise we
        !          1648:         * perform the step. If it succeeds, RX handling code will set
        !          1649:         * the appropriate status bit for us.
        !          1650:         *
        !          1651:         * Probe works a bit differently, since we have to step it
        !          1652:         * on every call instead of waiting for a packet to arrive
        !          1653:         * that will set the completion bit for us.
        !          1654:         */
        !          1655: 
        !          1656:        /* If we're waiting for a reply, check for timeout condition */
        !          1657:        if ( dev->state & NET80211_WAITING ) {
        !          1658:                /* Sanity check */
        !          1659:                if ( ! dev->associating )
        !          1660:                        return;
        !          1661: 
        !          1662:                if ( currticks() - dev->ctx.assoc->last_packet > ASSOC_TIMEOUT ) {
        !          1663:                        /* Timed out - fail if too many retries, or retry */
        !          1664:                        dev->ctx.assoc->times_tried++;
        !          1665:                        if ( ++dev->ctx.assoc->times_tried > ASSOC_RETRIES ) {
        !          1666:                                rc = -ETIMEDOUT;
        !          1667:                                goto fail;
        !          1668:                        }
        !          1669:                } else {
        !          1670:                        /* Didn't time out - let it keep going */
        !          1671:                        return;
        !          1672:                }
        !          1673:        } else {
        !          1674:                if ( dev->state & NET80211_PROBED )
        !          1675:                        dev->ctx.assoc->times_tried = 0;
        !          1676:        }
        !          1677: 
        !          1678:        if ( ! ( dev->state & NET80211_PROBED ) ) {
        !          1679:                /* state: probe */
        !          1680: 
        !          1681:                if ( ! dev->ctx.probe ) {
        !          1682:                        /* start probe */
        !          1683:                        int active = fetch_intz_setting ( NULL,
        !          1684:                                                &net80211_active_setting );
        !          1685:                        int band = dev->hw->bands;
        !          1686: 
        !          1687:                        if ( active )
        !          1688:                                band &= ~NET80211_BAND_BIT_5GHZ;
        !          1689: 
        !          1690:                        rc = net80211_prepare_probe ( dev, band, active );
        !          1691:                        if ( rc )
        !          1692:                                goto fail;
        !          1693: 
        !          1694:                        dev->ctx.probe = net80211_probe_start ( dev, dev->essid,
        !          1695:                                                                active );
        !          1696:                        if ( ! dev->ctx.probe ) {
        !          1697:                                dev->assoc_rc = -ENOMEM;
        !          1698:                                goto fail;
        !          1699:                        }
        !          1700:                }
        !          1701: 
        !          1702:                rc = net80211_probe_step ( dev->ctx.probe );
        !          1703:                if ( ! rc ) {
        !          1704:                        return; /* still going */
        !          1705:                }
        !          1706: 
        !          1707:                dev->associating = net80211_probe_finish_best ( dev->ctx.probe );
        !          1708:                dev->ctx.probe = NULL;
        !          1709:                if ( ! dev->associating ) {
        !          1710:                        if ( rc > 0 ) /* "successful" probe found nothing */
        !          1711:                                rc = -ETIMEDOUT;
        !          1712:                        goto fail;
        !          1713:                }
        !          1714: 
        !          1715:                /* If we probed using a broadcast SSID, record that
        !          1716:                   fact for the settings applicator before we clobber
        !          1717:                   it with the specific SSID we've chosen. */
        !          1718:                if ( ! dev->essid[0] )
        !          1719:                        dev->state |= NET80211_AUTO_SSID;
        !          1720: 
        !          1721:                DBGC ( dev, "802.11 %p found network %s (%s)\n", dev,
        !          1722:                       dev->associating->essid,
        !          1723:                       eth_ntoa ( dev->associating->bssid ) );
        !          1724: 
        !          1725:                dev->ctx.assoc = zalloc ( sizeof ( *dev->ctx.assoc ) );
        !          1726:                if ( ! dev->ctx.assoc ) {
        !          1727:                        rc = -ENOMEM;
        !          1728:                        goto fail;
        !          1729:                }
        !          1730: 
        !          1731:                dev->state |= NET80211_PROBED;
        !          1732:                dev->ctx.assoc->method = IEEE80211_AUTH_OPEN_SYSTEM;
        !          1733: 
        !          1734:                return;
        !          1735:        }
        !          1736: 
        !          1737:        /* Record time of sending the packet we're about to send, for timeout */
        !          1738:        dev->ctx.assoc->last_packet = currticks();
        !          1739: 
        !          1740:        if ( ! ( dev->state & NET80211_AUTHENTICATED ) ) {
        !          1741:                /* state: prepare and authenticate */
        !          1742: 
        !          1743:                if ( status != IEEE80211_STATUS_SUCCESS ) {
        !          1744:                        /* we tried authenticating already, but failed */
        !          1745:                        int method = dev->ctx.assoc->method;
        !          1746: 
        !          1747:                        if ( method == IEEE80211_AUTH_OPEN_SYSTEM &&
        !          1748:                             ( status == IEEE80211_STATUS_AUTH_CHALL_INVALID ||
        !          1749:                               status == IEEE80211_STATUS_AUTH_ALGO_UNSUPP ) ) {
        !          1750:                                /* Maybe this network uses Shared Key? */
        !          1751:                                dev->ctx.assoc->method =
        !          1752:                                        IEEE80211_AUTH_SHARED_KEY;
        !          1753:                        } else {
        !          1754:                                goto fail;
        !          1755:                        }
        !          1756:                }
        !          1757: 
        !          1758:                DBGC ( dev, "802.11 %p authenticating with method %d\n", dev,
        !          1759:                       dev->ctx.assoc->method );
        !          1760: 
        !          1761:                rc = net80211_prepare_assoc ( dev, dev->associating );
        !          1762:                if ( rc )
        !          1763:                        goto fail;
        !          1764: 
        !          1765:                rc = net80211_send_auth ( dev, dev->associating,
        !          1766:                                          dev->ctx.assoc->method );
        !          1767:                if ( rc )
        !          1768:                        goto fail;
        !          1769: 
        !          1770:                return;
        !          1771:        }
        !          1772: 
        !          1773:        if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
        !          1774:                /* state: associate */
        !          1775: 
        !          1776:                if ( status != IEEE80211_STATUS_SUCCESS )
        !          1777:                        goto fail;
        !          1778: 
        !          1779:                DBGC ( dev, "802.11 %p associating\n", dev );
        !          1780: 
        !          1781:                if ( dev->handshaker && dev->handshaker->start &&
        !          1782:                     ! dev->handshaker->started ) {
        !          1783:                        rc = dev->handshaker->start ( dev );
        !          1784:                        if ( rc < 0 )
        !          1785:                                goto fail;
        !          1786:                        dev->handshaker->started = 1;
        !          1787:                }
        !          1788: 
        !          1789:                rc = net80211_send_assoc ( dev, dev->associating );
        !          1790:                if ( rc )
        !          1791:                        goto fail;
        !          1792: 
        !          1793:                return;
        !          1794:        }
        !          1795: 
        !          1796:        if ( ! ( dev->state & NET80211_CRYPTO_SYNCED ) ) {
        !          1797:                /* state: crypto sync */
        !          1798:                DBGC ( dev, "802.11 %p security handshaking\n", dev );
        !          1799: 
        !          1800:                if ( ! dev->handshaker || ! dev->handshaker->step ) {
        !          1801:                        dev->state |= NET80211_CRYPTO_SYNCED;
        !          1802:                        return;
        !          1803:                }
        !          1804: 
        !          1805:                rc = dev->handshaker->step ( dev );
        !          1806: 
        !          1807:                if ( rc < 0 ) {
        !          1808:                        /* Only record the returned error if we're
        !          1809:                           still marked as associated, because an
        !          1810:                           asynchronous error will have already been
        !          1811:                           reported to net80211_deauthenticate() and
        !          1812:                           assoc_rc thereby set. */
        !          1813:                        if ( dev->state & NET80211_ASSOCIATED )
        !          1814:                                dev->assoc_rc = rc;
        !          1815:                        rc = 0;
        !          1816:                        goto fail;
        !          1817:                }
        !          1818: 
        !          1819:                if ( rc > 0 ) {
        !          1820:                        dev->assoc_rc = 0;
        !          1821:                        dev->state |= NET80211_CRYPTO_SYNCED;
        !          1822:                }
        !          1823:                return;
        !          1824:        }
        !          1825: 
        !          1826:        /* state: done! */
        !          1827:        netdev_link_up ( dev->netdev );
        !          1828:        dev->assoc_rc = 0;
        !          1829:        dev->state &= ~NET80211_WORKING;
        !          1830: 
        !          1831:        free ( dev->ctx.assoc );
        !          1832:        dev->ctx.assoc = NULL;
        !          1833: 
        !          1834:        net80211_free_wlan ( dev->associating );
        !          1835:        dev->associating = NULL;
        !          1836: 
        !          1837:        dev->rctl = rc80211_init ( dev );
        !          1838: 
        !          1839:        process_del ( proc );
        !          1840: 
        !          1841:        DBGC ( dev, "802.11 %p associated with %s (%s)\n", dev,
        !          1842:               dev->essid, eth_ntoa ( dev->bssid ) );
        !          1843: 
        !          1844:        return;
        !          1845: 
        !          1846:  fail:
        !          1847:        dev->state &= ~( NET80211_WORKING | NET80211_WAITING );
        !          1848:        if ( rc )
        !          1849:                dev->assoc_rc = rc;
        !          1850: 
        !          1851:        netdev_link_err ( dev->netdev, dev->assoc_rc );
        !          1852: 
        !          1853:        /* We never reach here from the middle of a probe, so we don't
        !          1854:           need to worry about freeing dev->ctx.probe. */
        !          1855: 
        !          1856:        if ( dev->state & NET80211_PROBED ) {
        !          1857:                free ( dev->ctx.assoc );
        !          1858:                dev->ctx.assoc = NULL;
        !          1859:        }
        !          1860: 
        !          1861:        net80211_free_wlan ( dev->associating );
        !          1862:        dev->associating = NULL;
        !          1863: 
        !          1864:        process_del ( proc );
        !          1865: 
        !          1866:        DBGC ( dev, "802.11 %p association failed (state=%04x): "
        !          1867:               "%s\n", dev, dev->state, strerror ( dev->assoc_rc ) );
        !          1868: 
        !          1869:        /* Try it again: */
        !          1870:        net80211_autoassociate ( dev );
        !          1871: }
        !          1872: 
        !          1873: /**
        !          1874:  * Check for 802.11 SSID or key updates
        !          1875:  *
        !          1876:  * This acts as a settings applicator; if the user changes netX/ssid,
        !          1877:  * and netX is currently open, the association task will be invoked
        !          1878:  * again. If the user changes the encryption key, the current security
        !          1879:  * handshaker will be asked to update its state to match; if that is
        !          1880:  * impossible without reassociation, we reassociate.
        !          1881:  */
        !          1882: static int net80211_check_settings_update ( void )
        !          1883: {
        !          1884:        struct net80211_device *dev;
        !          1885:        char ssid[IEEE80211_MAX_SSID_LEN + 1];
        !          1886:        int key_reassoc;
        !          1887: 
        !          1888:        list_for_each_entry ( dev, &net80211_devices, list ) {
        !          1889:                if ( ! netdev_is_open ( dev->netdev ) )
        !          1890:                        continue;
        !          1891: 
        !          1892:                key_reassoc = 0;
        !          1893:                if ( dev->handshaker && dev->handshaker->change_key &&
        !          1894:                     dev->handshaker->change_key ( dev ) < 0 )
        !          1895:                        key_reassoc = 1;
        !          1896: 
        !          1897:                fetch_string_setting ( netdev_settings ( dev->netdev ),
        !          1898:                                       &net80211_ssid_setting, ssid,
        !          1899:                                       IEEE80211_MAX_SSID_LEN + 1 );
        !          1900: 
        !          1901:                if ( key_reassoc ||
        !          1902:                     ( ! ( ! ssid[0] && ( dev->state & NET80211_AUTO_SSID ) ) &&
        !          1903:                       strcmp ( ssid, dev->essid ) != 0 ) ) {
        !          1904:                        DBGC ( dev, "802.11 %p updating association: "
        !          1905:                               "%s -> %s\n", dev, dev->essid, ssid );
        !          1906:                        net80211_autoassociate ( dev );
        !          1907:                }
        !          1908:        }
        !          1909: 
        !          1910:        return 0;
        !          1911: }
        !          1912: 
        !          1913: /**
        !          1914:  * Start 802.11 association process
        !          1915:  *
        !          1916:  * @v dev      802.11 device
        !          1917:  *
        !          1918:  * If the association process is running, it will be restarted.
        !          1919:  */
        !          1920: void net80211_autoassociate ( struct net80211_device *dev )
        !          1921: {
        !          1922:        if ( ! ( dev->state & NET80211_WORKING ) ) {
        !          1923:                DBGC2 ( dev, "802.11 %p spawning association process\n", dev );
        !          1924:                process_add ( &dev->proc_assoc );
        !          1925:        } else {
        !          1926:                DBGC2 ( dev, "802.11 %p restarting association\n", dev );
        !          1927:        }
        !          1928: 
        !          1929:        /* Clean up everything an earlier association process might
        !          1930:           have been in the middle of using */
        !          1931:        if ( dev->associating )
        !          1932:                net80211_free_wlan ( dev->associating );
        !          1933: 
        !          1934:        if ( ! ( dev->state & NET80211_PROBED ) )
        !          1935:                net80211_free_wlan (
        !          1936:                        net80211_probe_finish_best ( dev->ctx.probe ) );
        !          1937:        else
        !          1938:                free ( dev->ctx.assoc );
        !          1939: 
        !          1940:        /* Reset to a clean state */
        !          1941:        fetch_string_setting ( netdev_settings ( dev->netdev ),
        !          1942:                               &net80211_ssid_setting, dev->essid,
        !          1943:                               IEEE80211_MAX_SSID_LEN + 1 );
        !          1944:        dev->ctx.probe = NULL;
        !          1945:        dev->associating = NULL;
        !          1946:        dev->assoc_rc = 0;
        !          1947:        net80211_set_state ( dev, NET80211_PROBED, NET80211_WORKING, 0 );
        !          1948: }
        !          1949: 
        !          1950: /**
        !          1951:  * Pick TX rate for RTS/CTS packets based on data rate
        !          1952:  *
        !          1953:  * @v dev      802.11 device
        !          1954:  *
        !          1955:  * The RTS/CTS rate is the fastest TX rate marked as "basic" that is
        !          1956:  * not faster than the data rate.
        !          1957:  */
        !          1958: static void net80211_set_rtscts_rate ( struct net80211_device *dev )
        !          1959: {
        !          1960:        u16 datarate = dev->rates[dev->rate];
        !          1961:        u16 rtsrate = 0;
        !          1962:        int rts_idx = -1;
        !          1963:        int i;
        !          1964: 
        !          1965:        for ( i = 0; i < dev->nr_rates; i++ ) {
        !          1966:                u16 rate = dev->rates[i];
        !          1967: 
        !          1968:                if ( ! ( dev->basic_rates & ( 1 << i ) ) || rate > datarate )
        !          1969:                        continue;
        !          1970: 
        !          1971:                if ( rate > rtsrate ) {
        !          1972:                        rtsrate = rate;
        !          1973:                        rts_idx = i;
        !          1974:                }
        !          1975:        }
        !          1976: 
        !          1977:        /* If this is in initialization, we might not have any basic
        !          1978:           rates; just use the first data rate in that case. */
        !          1979:        if ( rts_idx < 0 )
        !          1980:                rts_idx = 0;
        !          1981: 
        !          1982:        dev->rtscts_rate = rts_idx;
        !          1983: }
        !          1984: 
        !          1985: /**
        !          1986:  * Set data transmission rate for 802.11 device
        !          1987:  *
        !          1988:  * @v dev      802.11 device
        !          1989:  * @v rate     Rate to set, as index into @c dev->rates array
        !          1990:  */
        !          1991: void net80211_set_rate_idx ( struct net80211_device *dev, int rate )
        !          1992: {
        !          1993:        assert ( netdev_is_open ( dev->netdev ) );
        !          1994: 
        !          1995:        if ( rate >= 0 && rate < dev->nr_rates && rate != dev->rate ) {
        !          1996:                DBGC2 ( dev, "802.11 %p changing rate from %d->%d Mbps\n",
        !          1997:                        dev, dev->rates[dev->rate] / 10,
        !          1998:                        dev->rates[rate] / 10 );
        !          1999: 
        !          2000:                dev->rate = rate;
        !          2001:                net80211_set_rtscts_rate ( dev );
        !          2002:                dev->op->config ( dev, NET80211_CFG_RATE );
        !          2003:        }
        !          2004: }
        !          2005: 
        !          2006: /**
        !          2007:  * Configure 802.11 device to transmit on a certain channel
        !          2008:  *
        !          2009:  * @v dev      802.11 device
        !          2010:  * @v channel  Channel number (1-11 for 2.4GHz) to transmit on
        !          2011:  */
        !          2012: int net80211_change_channel ( struct net80211_device *dev, int channel )
        !          2013: {
        !          2014:        int i, oldchan = dev->channel;
        !          2015: 
        !          2016:        assert ( netdev_is_open ( dev->netdev ) );
        !          2017: 
        !          2018:        for ( i = 0; i < dev->nr_channels; i++ ) {
        !          2019:                if ( dev->channels[i].channel_nr == channel ) {
        !          2020:                        dev->channel = i;
        !          2021:                        break;
        !          2022:                }
        !          2023:        }
        !          2024: 
        !          2025:        if ( i == dev->nr_channels )
        !          2026:                return -ENOENT;
        !          2027: 
        !          2028:        if ( i != oldchan )
        !          2029:                return dev->op->config ( dev, NET80211_CFG_CHANNEL );
        !          2030: 
        !          2031:        return 0;
        !          2032: }
        !          2033: 
        !          2034: /**
        !          2035:  * Prepare 802.11 device channel and rate set for scanning
        !          2036:  *
        !          2037:  * @v dev      802.11 device
        !          2038:  * @v band     RF band(s) on which to prepare for scanning
        !          2039:  * @v active   Whether the scanning will be active
        !          2040:  * @ret rc     Return status code
        !          2041:  */
        !          2042: int net80211_prepare_probe ( struct net80211_device *dev, int band,
        !          2043:                             int active )
        !          2044: {
        !          2045:        assert ( netdev_is_open ( dev->netdev ) );
        !          2046: 
        !          2047:        if ( active && ( band & NET80211_BAND_BIT_5GHZ ) ) {
        !          2048:                DBGC ( dev, "802.11 %p cannot perform active scanning on "
        !          2049:                       "5GHz band\n", dev );
        !          2050:                return -EINVAL_ACTIVE_SCAN;
        !          2051:        }
        !          2052: 
        !          2053:        if ( band == 0 ) {
        !          2054:                /* This can happen for a 5GHz-only card with 5GHz
        !          2055:                   scanning masked out by an active request. */
        !          2056:                DBGC ( dev, "802.11 %p asked to prepare for scanning nothing\n",
        !          2057:                       dev );
        !          2058:                return -EINVAL_ACTIVE_SCAN;
        !          2059:        }
        !          2060: 
        !          2061:        dev->nr_channels = 0;
        !          2062: 
        !          2063:        if ( active )
        !          2064:                net80211_add_channels ( dev, 1, 11, NET80211_REG_TXPOWER );
        !          2065:        else {
        !          2066:                if ( band & NET80211_BAND_BIT_2GHZ )
        !          2067:                        net80211_add_channels ( dev, 1, 14,
        !          2068:                                                NET80211_REG_TXPOWER );
        !          2069:                if ( band & NET80211_BAND_BIT_5GHZ )
        !          2070:                        net80211_add_channels ( dev, 36, 8,
        !          2071:                                                NET80211_REG_TXPOWER );
        !          2072:        }
        !          2073: 
        !          2074:        net80211_filter_hw_channels ( dev );
        !          2075: 
        !          2076:        /* Use channel 1 for now */
        !          2077:        dev->channel = 0;
        !          2078:        dev->op->config ( dev, NET80211_CFG_CHANNEL );
        !          2079: 
        !          2080:        /* Always do active probes at lowest (presumably first) speed */
        !          2081:        dev->rate = 0;
        !          2082:        dev->nr_rates = 1;
        !          2083:        dev->rates[0] = dev->hw->rates[dev->channels[0].band][0];
        !          2084:        dev->op->config ( dev, NET80211_CFG_RATE );
        !          2085: 
        !          2086:        return 0;
        !          2087: }
        !          2088: 
        !          2089: /**
        !          2090:  * Prepare 802.11 device channel and rate set for communication
        !          2091:  *
        !          2092:  * @v dev      802.11 device
        !          2093:  * @v wlan     WLAN to prepare for communication with
        !          2094:  * @ret rc     Return status code
        !          2095:  */
        !          2096: int net80211_prepare_assoc ( struct net80211_device *dev,
        !          2097:                             struct net80211_wlan *wlan )
        !          2098: {
        !          2099:        struct ieee80211_frame *hdr = wlan->beacon->data;
        !          2100:        struct ieee80211_beacon *beacon =
        !          2101:                ( struct ieee80211_beacon * ) hdr->data;
        !          2102:        struct net80211_handshaker *handshaker;
        !          2103:        int rc;
        !          2104: 
        !          2105:        assert ( netdev_is_open ( dev->netdev ) );
        !          2106: 
        !          2107:        net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
        !          2108:        memcpy ( dev->bssid, wlan->bssid, ETH_ALEN );
        !          2109:        strcpy ( dev->essid, wlan->essid );
        !          2110: 
        !          2111:        free ( dev->rsn_ie );
        !          2112:        dev->rsn_ie = NULL;
        !          2113: 
        !          2114:        dev->last_beacon_timestamp = beacon->timestamp;
        !          2115:        dev->tx_beacon_interval = 1024 * beacon->beacon_interval;
        !          2116: 
        !          2117:        /* Barring an IE that tells us the channel outright, assume
        !          2118:           the channel we heard this AP best on is the channel it's
        !          2119:           communicating on. */
        !          2120:        net80211_change_channel ( dev, wlan->channel );
        !          2121: 
        !          2122:        rc = net80211_process_capab ( dev, beacon->capability );
        !          2123:        if ( rc )
        !          2124:                return rc;
        !          2125: 
        !          2126:        rc = net80211_process_ie ( dev, beacon->info_element,
        !          2127:                                   wlan->beacon->tail );
        !          2128:        if ( rc )
        !          2129:                return rc;
        !          2130: 
        !          2131:        /* Associate at the lowest rate so we know it'll get through */
        !          2132:        dev->rate = 0;
        !          2133:        dev->op->config ( dev, NET80211_CFG_RATE );
        !          2134: 
        !          2135:        /* Free old handshaker and crypto, if they exist */
        !          2136:        if ( dev->handshaker && dev->handshaker->stop &&
        !          2137:             dev->handshaker->started )
        !          2138:                dev->handshaker->stop ( dev );
        !          2139:        free ( dev->handshaker );
        !          2140:        dev->handshaker = NULL;
        !          2141:        free ( dev->crypto );
        !          2142:        free ( dev->gcrypto );
        !          2143:        dev->crypto = dev->gcrypto = NULL;
        !          2144: 
        !          2145:        /* Find new security handshaker to use */
        !          2146:        for_each_table_entry ( handshaker, NET80211_HANDSHAKERS ) {
        !          2147:                if ( handshaker->protocol == wlan->handshaking ) {
        !          2148:                        dev->handshaker = zalloc ( sizeof ( *handshaker ) +
        !          2149:                                                   handshaker->priv_len );
        !          2150:                        if ( ! dev->handshaker )
        !          2151:                                return -ENOMEM;
        !          2152: 
        !          2153:                        memcpy ( dev->handshaker, handshaker,
        !          2154:                                 sizeof ( *handshaker ) );
        !          2155:                        dev->handshaker->priv = ( ( void * ) dev->handshaker +
        !          2156:                                                  sizeof ( *handshaker ) );
        !          2157:                        break;
        !          2158:                }
        !          2159:        }
        !          2160: 
        !          2161:        if ( ( wlan->handshaking != NET80211_SECPROT_NONE ) &&
        !          2162:             ! dev->handshaker ) {
        !          2163:                DBGC ( dev, "802.11 %p no support for handshaking scheme %d\n",
        !          2164:                       dev, wlan->handshaking );
        !          2165:                return -( ENOTSUP | ( wlan->handshaking << 8 ) );
        !          2166:        }
        !          2167: 
        !          2168:        /* Initialize security handshaker */
        !          2169:        if ( dev->handshaker ) {
        !          2170:                rc = dev->handshaker->init ( dev );
        !          2171:                if ( rc < 0 )
        !          2172:                        return rc;
        !          2173:        }
        !          2174: 
        !          2175:        return 0;
        !          2176: }
        !          2177: 
        !          2178: /**
        !          2179:  * Send 802.11 initial authentication frame
        !          2180:  *
        !          2181:  * @v dev      802.11 device
        !          2182:  * @v wlan     WLAN to authenticate with
        !          2183:  * @v method   Authentication method
        !          2184:  * @ret rc     Return status code
        !          2185:  *
        !          2186:  * @a method may be 0 for Open System authentication or 1 for Shared
        !          2187:  * Key authentication. Open System provides no security in association
        !          2188:  * whatsoever, relying on encryption for confidentiality, but Shared
        !          2189:  * Key actively introduces security problems and is very rarely used.
        !          2190:  */
        !          2191: int net80211_send_auth ( struct net80211_device *dev,
        !          2192:                         struct net80211_wlan *wlan, int method )
        !          2193: {
        !          2194:        struct io_buffer *iob = alloc_iob ( 64 );
        !          2195:        struct ieee80211_auth *auth;
        !          2196: 
        !          2197:        net80211_set_state ( dev, 0, NET80211_WAITING, 0 );
        !          2198:        iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
        !          2199:        auth = iob_put ( iob, sizeof ( *auth ) );
        !          2200:        auth->algorithm = method;
        !          2201:        auth->tx_seq = 1;
        !          2202:        auth->status = 0;
        !          2203: 
        !          2204:        return net80211_tx_mgmt ( dev, IEEE80211_STYPE_AUTH, wlan->bssid, iob );
        !          2205: }
        !          2206: 
        !          2207: /**
        !          2208:  * Handle receipt of 802.11 authentication frame
        !          2209:  *
        !          2210:  * @v dev      802.11 device
        !          2211:  * @v iob      I/O buffer
        !          2212:  *
        !          2213:  * If the authentication method being used is Shared Key, and the
        !          2214:  * frame that was received included challenge text, the frame is
        !          2215:  * encrypted using the cryptosystem currently in effect and sent back
        !          2216:  * to the AP to complete the authentication.
        !          2217:  */
        !          2218: static void net80211_handle_auth ( struct net80211_device *dev,
        !          2219:                                   struct io_buffer *iob )
        !          2220: {
        !          2221:        struct ieee80211_frame *hdr = iob->data;
        !          2222:        struct ieee80211_auth *auth =
        !          2223:            ( struct ieee80211_auth * ) hdr->data;
        !          2224: 
        !          2225:        if ( auth->tx_seq & 1 ) {
        !          2226:                DBGC ( dev, "802.11 %p authentication received improperly "
        !          2227:                       "directed frame (seq. %d)\n", dev, auth->tx_seq );
        !          2228:                net80211_set_state ( dev, NET80211_WAITING, 0,
        !          2229:                                     IEEE80211_STATUS_FAILURE );
        !          2230:                return;
        !          2231:        }
        !          2232: 
        !          2233:        if ( auth->status != IEEE80211_STATUS_SUCCESS ) {
        !          2234:                DBGC ( dev, "802.11 %p authentication failed: status %d\n",
        !          2235:                       dev, auth->status );
        !          2236:                net80211_set_state ( dev, NET80211_WAITING, 0,
        !          2237:                                     auth->status );
        !          2238:                return;
        !          2239:        }
        !          2240: 
        !          2241:        if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY && ! dev->crypto ) {
        !          2242:                DBGC ( dev, "802.11 %p can't perform shared-key authentication "
        !          2243:                       "without a cryptosystem\n", dev );
        !          2244:                net80211_set_state ( dev, NET80211_WAITING, 0,
        !          2245:                                     IEEE80211_STATUS_FAILURE );
        !          2246:                return;
        !          2247:        }
        !          2248: 
        !          2249:        if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY &&
        !          2250:             auth->tx_seq == 2 ) {
        !          2251:                /* Since the iob we got is going to be freed as soon
        !          2252:                   as we return, we can do some in-place
        !          2253:                   modification. */
        !          2254:                auth->tx_seq = 3;
        !          2255:                auth->status = 0;
        !          2256: 
        !          2257:                memcpy ( hdr->addr2, hdr->addr1, ETH_ALEN );
        !          2258:                memcpy ( hdr->addr1, hdr->addr3, ETH_ALEN );
        !          2259: 
        !          2260:                netdev_tx ( dev->netdev,
        !          2261:                            dev->crypto->encrypt ( dev->crypto, iob ) );
        !          2262:                return;
        !          2263:        }
        !          2264: 
        !          2265:        net80211_set_state ( dev, NET80211_WAITING, NET80211_AUTHENTICATED,
        !          2266:                             IEEE80211_STATUS_SUCCESS );
        !          2267: 
        !          2268:        return;
        !          2269: }
        !          2270: 
        !          2271: /**
        !          2272:  * Send 802.11 association frame
        !          2273:  *
        !          2274:  * @v dev      802.11 device
        !          2275:  * @v wlan     WLAN to associate with
        !          2276:  * @ret rc     Return status code
        !          2277:  */
        !          2278: int net80211_send_assoc ( struct net80211_device *dev,
        !          2279:                          struct net80211_wlan *wlan )
        !          2280: {
        !          2281:        struct io_buffer *iob = alloc_iob ( 128 );
        !          2282:        struct ieee80211_assoc_req *assoc;
        !          2283:        union ieee80211_ie *ie;
        !          2284: 
        !          2285:        net80211_set_state ( dev, 0, NET80211_WAITING, 0 );
        !          2286: 
        !          2287:        iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
        !          2288:        assoc = iob->data;
        !          2289: 
        !          2290:        assoc->capability = IEEE80211_CAPAB_MANAGED;
        !          2291:        if ( ! ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE ) )
        !          2292:                assoc->capability |= IEEE80211_CAPAB_SHORT_PMBL;
        !          2293:        if ( ! ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT ) )
        !          2294:                assoc->capability |= IEEE80211_CAPAB_SHORT_SLOT;
        !          2295:        if ( wlan->crypto )
        !          2296:                assoc->capability |= IEEE80211_CAPAB_PRIVACY;
        !          2297: 
        !          2298:        assoc->listen_interval = 1;
        !          2299: 
        !          2300:        ie = net80211_marshal_request_info ( dev, assoc->info_element );
        !          2301: 
        !          2302:        DBGP ( "802.11 %p about to send association request:\n", dev );
        !          2303:        DBGP_HD ( iob->data, ( void * ) ie - iob->data );
        !          2304: 
        !          2305:        iob_put ( iob, ( void * ) ie - iob->data );
        !          2306: 
        !          2307:        return net80211_tx_mgmt ( dev, IEEE80211_STYPE_ASSOC_REQ,
        !          2308:                                  wlan->bssid, iob );
        !          2309: }
        !          2310: 
        !          2311: /**
        !          2312:  * Handle receipt of 802.11 association reply frame
        !          2313:  *
        !          2314:  * @v dev      802.11 device
        !          2315:  * @v iob      I/O buffer
        !          2316:  */
        !          2317: static void net80211_handle_assoc_reply ( struct net80211_device *dev,
        !          2318:                                          struct io_buffer *iob )
        !          2319: {
        !          2320:        struct ieee80211_frame *hdr = iob->data;
        !          2321:        struct ieee80211_assoc_resp *assoc =
        !          2322:                ( struct ieee80211_assoc_resp * ) hdr->data;
        !          2323: 
        !          2324:        net80211_process_capab ( dev, assoc->capability );
        !          2325:        net80211_process_ie ( dev, assoc->info_element, iob->tail );
        !          2326: 
        !          2327:        if ( assoc->status != IEEE80211_STATUS_SUCCESS ) {
        !          2328:                DBGC ( dev, "802.11 %p association failed: status %d\n",
        !          2329:                       dev, assoc->status );
        !          2330:                net80211_set_state ( dev, NET80211_WAITING, 0,
        !          2331:                                     assoc->status );
        !          2332:                return;
        !          2333:        }
        !          2334: 
        !          2335:        /* ESSID was filled before the association request was sent */
        !          2336:        memcpy ( dev->bssid, hdr->addr3, ETH_ALEN );
        !          2337:        dev->aid = assoc->aid;
        !          2338: 
        !          2339:        net80211_set_state ( dev, NET80211_WAITING, NET80211_ASSOCIATED,
        !          2340:                             IEEE80211_STATUS_SUCCESS );
        !          2341: }
        !          2342: 
        !          2343: 
        !          2344: /**
        !          2345:  * Send 802.11 disassociation frame
        !          2346:  *
        !          2347:  * @v dev      802.11 device
        !          2348:  * @v reason   Reason for disassociation
        !          2349:  * @v deauth   If TRUE, send deauthentication instead of disassociation
        !          2350:  * @ret rc     Return status code
        !          2351:  */
        !          2352: static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
        !          2353:                                    int deauth )
        !          2354: {
        !          2355:        struct io_buffer *iob = alloc_iob ( 64 );
        !          2356:        struct ieee80211_disassoc *disassoc;
        !          2357: 
        !          2358:        if ( ! ( dev->state & NET80211_ASSOCIATED ) )
        !          2359:                return -EINVAL;
        !          2360: 
        !          2361:        net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
        !          2362:        iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
        !          2363:        disassoc = iob_put ( iob, sizeof ( *disassoc ) );
        !          2364:        disassoc->reason = reason;
        !          2365: 
        !          2366:        return net80211_tx_mgmt ( dev, deauth ? IEEE80211_STYPE_DEAUTH :
        !          2367:                                  IEEE80211_STYPE_DISASSOC, dev->bssid, iob );
        !          2368: }
        !          2369: 
        !          2370: 
        !          2371: /**
        !          2372:  * Deauthenticate from current network and try again
        !          2373:  *
        !          2374:  * @v dev      802.11 device
        !          2375:  * @v rc       Return status code indicating reason
        !          2376:  *
        !          2377:  * The deauthentication will be sent using an 802.11 "unspecified
        !          2378:  * reason", as is common, but @a rc will be set as a link-up
        !          2379:  * error to aid the user in debugging.
        !          2380:  */
        !          2381: void net80211_deauthenticate ( struct net80211_device *dev, int rc )
        !          2382: {
        !          2383:        net80211_send_disassoc ( dev, IEEE80211_REASON_UNSPECIFIED, 1 );
        !          2384:        dev->assoc_rc = rc;
        !          2385:        netdev_link_err ( dev->netdev, rc );
        !          2386: 
        !          2387:        net80211_autoassociate ( dev );
        !          2388: }
        !          2389: 
        !          2390: 
        !          2391: /** Smoothing factor (1-7) for link quality calculation */
        !          2392: #define LQ_SMOOTH      7
        !          2393: 
        !          2394: /**
        !          2395:  * Update link quality information based on received beacon
        !          2396:  *
        !          2397:  * @v dev      802.11 device
        !          2398:  * @v iob      I/O buffer containing beacon
        !          2399:  * @ret rc     Return status code
        !          2400:  */
        !          2401: static void net80211_update_link_quality ( struct net80211_device *dev,
        !          2402:                                           struct io_buffer *iob )
        !          2403: {
        !          2404:        struct ieee80211_frame *hdr = iob->data;
        !          2405:        struct ieee80211_beacon *beacon;
        !          2406:        u32 dt, rxi;
        !          2407: 
        !          2408:        if ( ! ( dev->state & NET80211_ASSOCIATED ) )
        !          2409:                return;
        !          2410: 
        !          2411:        beacon = ( struct ieee80211_beacon * ) hdr->data;
        !          2412:        dt = ( u32 ) ( beacon->timestamp - dev->last_beacon_timestamp );
        !          2413:        rxi = dev->rx_beacon_interval;
        !          2414: 
        !          2415:        rxi = ( LQ_SMOOTH * rxi ) + ( ( 8 - LQ_SMOOTH ) * dt );
        !          2416:        dev->rx_beacon_interval = rxi >> 3;
        !          2417: 
        !          2418:        dev->last_beacon_timestamp = beacon->timestamp;
        !          2419: }
        !          2420: 
        !          2421: 
        !          2422: /**
        !          2423:  * Handle receipt of 802.11 management frame
        !          2424:  *
        !          2425:  * @v dev      802.11 device
        !          2426:  * @v iob      I/O buffer
        !          2427:  * @v signal   Signal strength of received frame
        !          2428:  */
        !          2429: static void net80211_handle_mgmt ( struct net80211_device *dev,
        !          2430:                                   struct io_buffer *iob, int signal )
        !          2431: {
        !          2432:        struct ieee80211_frame *hdr = iob->data;
        !          2433:        struct ieee80211_disassoc *disassoc;
        !          2434:        u16 stype = hdr->fc & IEEE80211_FC_SUBTYPE;
        !          2435:        int keep = 0;
        !          2436:        int is_deauth = ( stype == IEEE80211_STYPE_DEAUTH );
        !          2437: 
        !          2438:        if ( ( hdr->fc & IEEE80211_FC_TYPE ) != IEEE80211_TYPE_MGMT ) {
        !          2439:                free_iob ( iob );
        !          2440:                return;         /* only handle management frames */
        !          2441:        }
        !          2442: 
        !          2443:        switch ( stype ) {
        !          2444:                /* We reconnect on deauthentication and disassociation. */
        !          2445:        case IEEE80211_STYPE_DEAUTH:
        !          2446:        case IEEE80211_STYPE_DISASSOC:
        !          2447:                disassoc = ( struct ieee80211_disassoc * ) hdr->data;
        !          2448:                net80211_set_state ( dev, is_deauth ? NET80211_AUTHENTICATED :
        !          2449:                                     NET80211_ASSOCIATED, 0,
        !          2450:                                     NET80211_IS_REASON | disassoc->reason );
        !          2451:                DBGC ( dev, "802.11 %p %s: reason %d\n",
        !          2452:                       dev, is_deauth ? "deauthenticated" : "disassociated",
        !          2453:                       disassoc->reason );
        !          2454: 
        !          2455:                /* Try to reassociate, in case it's transient. */
        !          2456:                net80211_autoassociate ( dev );
        !          2457: 
        !          2458:                break;
        !          2459: 
        !          2460:                /* We handle authentication and association. */
        !          2461:        case IEEE80211_STYPE_AUTH:
        !          2462:                if ( ! ( dev->state & NET80211_AUTHENTICATED ) )
        !          2463:                        net80211_handle_auth ( dev, iob );
        !          2464:                break;
        !          2465: 
        !          2466:        case IEEE80211_STYPE_ASSOC_RESP:
        !          2467:        case IEEE80211_STYPE_REASSOC_RESP:
        !          2468:                if ( ! ( dev->state & NET80211_ASSOCIATED ) )
        !          2469:                        net80211_handle_assoc_reply ( dev, iob );
        !          2470:                break;
        !          2471: 
        !          2472:                /* We pass probes and beacons onto network scanning
        !          2473:                   code. Pass actions for future extensibility. */
        !          2474:        case IEEE80211_STYPE_BEACON:
        !          2475:                net80211_update_link_quality ( dev, iob );
        !          2476:                /* fall through */
        !          2477:        case IEEE80211_STYPE_PROBE_RESP:
        !          2478:        case IEEE80211_STYPE_ACTION:
        !          2479:                if ( dev->keep_mgmt ) {
        !          2480:                        struct net80211_rx_info *rxinf;
        !          2481:                        rxinf = zalloc ( sizeof ( *rxinf ) );
        !          2482:                        if ( ! rxinf ) {
        !          2483:                                DBGC ( dev, "802.11 %p out of memory\n", dev );
        !          2484:                                break;
        !          2485:                        }
        !          2486:                        rxinf->signal = signal;
        !          2487:                        list_add_tail ( &iob->list, &dev->mgmt_queue );
        !          2488:                        list_add_tail ( &rxinf->list, &dev->mgmt_info_queue );
        !          2489:                        keep = 1;
        !          2490:                }
        !          2491:                break;
        !          2492: 
        !          2493:        case IEEE80211_STYPE_PROBE_REQ:
        !          2494:                /* Some nodes send these broadcast. Ignore them. */
        !          2495:                break;
        !          2496: 
        !          2497:        case IEEE80211_STYPE_ASSOC_REQ:
        !          2498:        case IEEE80211_STYPE_REASSOC_REQ:
        !          2499:                /* We should never receive these, only send them. */
        !          2500:                DBGC ( dev, "802.11 %p received strange management request "
        !          2501:                       "(%04x)\n", dev, stype );
        !          2502:                break;
        !          2503: 
        !          2504:        default:
        !          2505:                DBGC ( dev, "802.11 %p received unimplemented management "
        !          2506:                       "packet (%04x)\n", dev, stype );
        !          2507:                break;
        !          2508:        }
        !          2509: 
        !          2510:        if ( ! keep )
        !          2511:                free_iob ( iob );
        !          2512: }
        !          2513: 
        !          2514: /* ---------- Packet handling functions ---------- */
        !          2515: 
        !          2516: /**
        !          2517:  * Free buffers used by 802.11 fragment cache entry
        !          2518:  *
        !          2519:  * @v dev      802.11 device
        !          2520:  * @v fcid     Fragment cache entry index
        !          2521:  *
        !          2522:  * After this function, the referenced entry will be marked unused.
        !          2523:  */
        !          2524: static void net80211_free_frags ( struct net80211_device *dev, int fcid )
        !          2525: {
        !          2526:        int j;
        !          2527:        struct net80211_frag_cache *frag = &dev->frags[fcid];
        !          2528: 
        !          2529:        for ( j = 0; j < 16; j++ ) {
        !          2530:                if ( frag->iob[j] ) {
        !          2531:                        free_iob ( frag->iob[j] );
        !          2532:                        frag->iob[j] = NULL;
        !          2533:                }
        !          2534:        }
        !          2535: 
        !          2536:        frag->seqnr = 0;
        !          2537:        frag->start_ticks = 0;
        !          2538:        frag->in_use = 0;
        !          2539: }
        !          2540: 
        !          2541: /**
        !          2542:  * Accumulate 802.11 fragments into one I/O buffer
        !          2543:  *
        !          2544:  * @v dev      802.11 device
        !          2545:  * @v fcid     Fragment cache entry index
        !          2546:  * @v nfrags   Number of fragments received
        !          2547:  * @v size     Sum of sizes of all fragments, including headers
        !          2548:  * @ret iob    I/O buffer containing reassembled packet
        !          2549:  *
        !          2550:  * This function does not free the fragment buffers.
        !          2551:  */
        !          2552: static struct io_buffer *net80211_accum_frags ( struct net80211_device *dev,
        !          2553:                                                int fcid, int nfrags, int size )
        !          2554: {
        !          2555:        struct net80211_frag_cache *frag = &dev->frags[fcid];
        !          2556:        int hdrsize = IEEE80211_TYP_FRAME_HEADER_LEN;
        !          2557:        int nsize = size - hdrsize * ( nfrags - 1 );
        !          2558:        int i;
        !          2559: 
        !          2560:        struct io_buffer *niob = alloc_iob ( nsize );
        !          2561:        struct ieee80211_frame *hdr;
        !          2562: 
        !          2563:        /* Add the header from the first one... */
        !          2564:        memcpy ( iob_put ( niob, hdrsize ), frag->iob[0]->data, hdrsize );
        !          2565: 
        !          2566:        /* ... and all the data from all of them. */
        !          2567:        for ( i = 0; i < nfrags; i++ ) {
        !          2568:                int len = iob_len ( frag->iob[i] ) - hdrsize;
        !          2569:                memcpy ( iob_put ( niob, len ),
        !          2570:                         frag->iob[i]->data + hdrsize, len );
        !          2571:        }
        !          2572: 
        !          2573:        /* Turn off the fragment bit. */
        !          2574:        hdr = niob->data;
        !          2575:        hdr->fc &= ~IEEE80211_FC_MORE_FRAG;
        !          2576: 
        !          2577:        return niob;
        !          2578: }
        !          2579: 
        !          2580: /**
        !          2581:  * Handle receipt of 802.11 fragment
        !          2582:  *
        !          2583:  * @v dev      802.11 device
        !          2584:  * @v iob      I/O buffer containing fragment
        !          2585:  * @v signal   Signal strength with which fragment was received
        !          2586:  */
        !          2587: static void net80211_rx_frag ( struct net80211_device *dev,
        !          2588:                               struct io_buffer *iob, int signal )
        !          2589: {
        !          2590:        struct ieee80211_frame *hdr = iob->data;
        !          2591:        int fragnr = IEEE80211_FRAG ( hdr->seq );
        !          2592: 
        !          2593:        if ( fragnr == 0 && ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
        !          2594:                /* start a frag cache entry */
        !          2595:                int i, newest = -1;
        !          2596:                u32 curr_ticks = currticks(), newest_ticks = 0;
        !          2597:                u32 timeout = ticks_per_sec() * NET80211_FRAG_TIMEOUT;
        !          2598: 
        !          2599:                for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
        !          2600:                        if ( dev->frags[i].in_use == 0 )
        !          2601:                                break;
        !          2602: 
        !          2603:                        if ( dev->frags[i].start_ticks + timeout >=
        !          2604:                             curr_ticks ) {
        !          2605:                                net80211_free_frags ( dev, i );
        !          2606:                                break;
        !          2607:                        }
        !          2608: 
        !          2609:                        if ( dev->frags[i].start_ticks > newest_ticks ) {
        !          2610:                                newest = i;
        !          2611:                                newest_ticks = dev->frags[i].start_ticks;
        !          2612:                        }
        !          2613:                }
        !          2614: 
        !          2615:                /* If we're being sent more concurrent fragmented
        !          2616:                   packets than we can handle, drop the newest so the
        !          2617:                   older ones have time to complete. */
        !          2618:                if ( i == NET80211_NR_CONCURRENT_FRAGS ) {
        !          2619:                        i = newest;
        !          2620:                        net80211_free_frags ( dev, i );
        !          2621:                }
        !          2622: 
        !          2623:                dev->frags[i].in_use = 1;
        !          2624:                dev->frags[i].seqnr = IEEE80211_SEQNR ( hdr->seq );
        !          2625:                dev->frags[i].start_ticks = currticks();
        !          2626:                dev->frags[i].iob[0] = iob;
        !          2627:                return;
        !          2628:        } else {
        !          2629:                int i;
        !          2630:                for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
        !          2631:                        if ( dev->frags[i].in_use && dev->frags[i].seqnr ==
        !          2632:                             IEEE80211_SEQNR ( hdr->seq ) )
        !          2633:                                break;
        !          2634:                }
        !          2635:                if ( i == NET80211_NR_CONCURRENT_FRAGS ) {
        !          2636:                        /* Drop non-first not-in-cache fragments */
        !          2637:                        DBGC ( dev, "802.11 %p dropped fragment fc=%04x "
        !          2638:                               "seq=%04x\n", dev, hdr->fc, hdr->seq );
        !          2639:                        free_iob ( iob );
        !          2640:                        return;
        !          2641:                }
        !          2642: 
        !          2643:                dev->frags[i].iob[fragnr] = iob;
        !          2644: 
        !          2645:                if ( ! ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
        !          2646:                        int j, size = 0;
        !          2647:                        for ( j = 0; j < fragnr; j++ ) {
        !          2648:                                size += iob_len ( dev->frags[i].iob[j] );
        !          2649:                                if ( dev->frags[i].iob[j] == NULL )
        !          2650:                                        break;
        !          2651:                        }
        !          2652:                        if ( j == fragnr ) {
        !          2653:                                /* We've got everything */
        !          2654:                                struct io_buffer *niob =
        !          2655:                                    net80211_accum_frags ( dev, i, fragnr,
        !          2656:                                                           size );
        !          2657:                                net80211_free_frags ( dev, i );
        !          2658:                                net80211_rx ( dev, niob, signal, 0 );
        !          2659:                        } else {
        !          2660:                                DBGC ( dev, "802.11 %p dropping fragmented "
        !          2661:                                       "packet due to out-of-order arrival, "
        !          2662:                                       "fc=%04x seq=%04x\n", dev, hdr->fc,
        !          2663:                                       hdr->seq );
        !          2664:                                net80211_free_frags ( dev, i );
        !          2665:                        }
        !          2666:                }
        !          2667:        }
        !          2668: }
        !          2669: 
        !          2670: /**
        !          2671:  * Handle receipt of 802.11 frame
        !          2672:  *
        !          2673:  * @v dev      802.11 device
        !          2674:  * @v iob      I/O buffer
        !          2675:  * @v signal   Received signal strength
        !          2676:  * @v rate     Bitrate at which frame was received, in 100 kbps units
        !          2677:  *
        !          2678:  * If the rate or signal is unknown, 0 should be passed.
        !          2679:  */
        !          2680: void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
        !          2681:                   int signal, u16 rate )
        !          2682: {
        !          2683:        struct ieee80211_frame *hdr = iob->data;
        !          2684:        u16 type = hdr->fc & IEEE80211_FC_TYPE;
        !          2685:        if ( ( hdr->fc & IEEE80211_FC_VERSION ) != IEEE80211_THIS_VERSION )
        !          2686:                goto drop;      /* drop invalid-version packets */
        !          2687: 
        !          2688:        if ( type == IEEE80211_TYPE_CTRL )
        !          2689:                goto drop;      /* we don't handle control packets,
        !          2690:                                   the hardware does */
        !          2691: 
        !          2692:        if ( dev->last_rx_seq == hdr->seq )
        !          2693:                goto drop;      /* avoid duplicate packet */
        !          2694:        dev->last_rx_seq = hdr->seq;
        !          2695: 
        !          2696:        if ( dev->hw->flags & NET80211_HW_RX_HAS_FCS ) {
        !          2697:                /* discard the FCS */
        !          2698:                iob_unput ( iob, 4 );
        !          2699:        }
        !          2700: 
        !          2701:        /* Only decrypt packets from our BSSID, to avoid spurious errors */
        !          2702:        if ( ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
        !          2703:             ! memcmp ( hdr->addr2, dev->bssid, ETH_ALEN ) ) {
        !          2704:                /* Decrypt packet; record and drop if it fails */
        !          2705:                struct io_buffer *niob;
        !          2706:                struct net80211_crypto *crypto = dev->crypto;
        !          2707: 
        !          2708:                if ( ! dev->crypto ) {
        !          2709:                        DBGC ( dev, "802.11 %p cannot decrypt packet "
        !          2710:                               "without a cryptosystem\n", dev );
        !          2711:                        goto drop_crypt;
        !          2712:                }
        !          2713: 
        !          2714:                if ( ( hdr->addr1[0] & 1 ) && dev->gcrypto ) {
        !          2715:                        /* Use group decryption if needed */
        !          2716:                        crypto = dev->gcrypto;
        !          2717:                }
        !          2718: 
        !          2719:                niob = crypto->decrypt ( crypto, iob );
        !          2720:                if ( ! niob ) {
        !          2721:                        DBGC ( dev, "802.11 %p decryption error\n", dev );
        !          2722:                        goto drop_crypt;
        !          2723:                }
        !          2724:                free_iob ( iob );
        !          2725:                iob = niob;
        !          2726:                hdr = iob->data;
        !          2727:        }
        !          2728: 
        !          2729:        dev->last_signal = signal;
        !          2730: 
        !          2731:        /* Fragments go into the frag cache or get dropped. */
        !          2732:        if ( IEEE80211_FRAG ( hdr->seq ) != 0
        !          2733:             || ( hdr->fc & IEEE80211_FC_MORE_FRAG ) ) {
        !          2734:                net80211_rx_frag ( dev, iob, signal );
        !          2735:                return;
        !          2736:        }
        !          2737: 
        !          2738:        /* Management frames get handled, enqueued, or dropped. */
        !          2739:        if ( type == IEEE80211_TYPE_MGMT ) {
        !          2740:                net80211_handle_mgmt ( dev, iob, signal );
        !          2741:                return;
        !          2742:        }
        !          2743: 
        !          2744:        /* Data frames get dropped or sent to the net_device. */
        !          2745:        if ( ( hdr->fc & IEEE80211_FC_SUBTYPE ) != IEEE80211_STYPE_DATA )
        !          2746:                goto drop;      /* drop QoS, CFP, or null data packets */
        !          2747: 
        !          2748:        /* Update rate-control algorithm */
        !          2749:        if ( dev->rctl )
        !          2750:                rc80211_update_rx ( dev, hdr->fc & IEEE80211_FC_RETRY, rate );
        !          2751: 
        !          2752:        /* Pass packet onward */
        !          2753:        if ( dev->state & NET80211_ASSOCIATED ) {
        !          2754:                netdev_rx ( dev->netdev, iob );
        !          2755:                return;
        !          2756:        }
        !          2757: 
        !          2758:        /* No association? Drop it. */
        !          2759:        goto drop;
        !          2760: 
        !          2761:  drop_crypt:
        !          2762:        netdev_rx_err ( dev->netdev, NULL, EINVAL_CRYPTO_REQUEST );
        !          2763:  drop:
        !          2764:        DBGC2 ( dev, "802.11 %p dropped packet fc=%04x seq=%04x\n", dev,
        !          2765:                hdr->fc, hdr->seq );
        !          2766:        free_iob ( iob );
        !          2767:        return;
        !          2768: }
        !          2769: 
        !          2770: /** Indicate an error in receiving a packet
        !          2771:  *
        !          2772:  * @v dev      802.11 device
        !          2773:  * @v iob      I/O buffer with received packet, or NULL
        !          2774:  * @v rc       Error code
        !          2775:  *
        !          2776:  * This logs the error with the wrapping net_device, and frees iob if
        !          2777:  * it is passed.
        !          2778:  */
        !          2779: void net80211_rx_err ( struct net80211_device *dev,
        !          2780:                       struct io_buffer *iob, int rc )
        !          2781: {
        !          2782:        netdev_rx_err ( dev->netdev, iob, rc );
        !          2783: }
        !          2784: 
        !          2785: /** Indicate the completed transmission of a packet
        !          2786:  *
        !          2787:  * @v dev      802.11 device
        !          2788:  * @v iob      I/O buffer of transmitted packet
        !          2789:  * @v retries  Number of times this packet was retransmitted
        !          2790:  * @v rc       Error code, or 0 for success
        !          2791:  *
        !          2792:  * This logs an error with the wrapping net_device if one occurred,
        !          2793:  * and removes and frees the I/O buffer from its TX queue. The
        !          2794:  * provided retry information is used to tune our transmission rate.
        !          2795:  *
        !          2796:  * If the packet did not need to be retransmitted because it was
        !          2797:  * properly ACKed the first time, @a retries should be 0.
        !          2798:  */
        !          2799: void net80211_tx_complete ( struct net80211_device *dev,
        !          2800:                            struct io_buffer *iob, int retries, int rc )
        !          2801: {
        !          2802:        /* Update rate-control algorithm */
        !          2803:        if ( dev->rctl )
        !          2804:                rc80211_update_tx ( dev, retries, rc );
        !          2805: 
        !          2806:        /* Pass completion onward */
        !          2807:        netdev_tx_complete_err ( dev->netdev, iob, rc );
        !          2808: }
        !          2809: 
        !          2810: /** Common 802.11 errors */
        !          2811: struct errortab common_wireless_errors[] __errortab = {
        !          2812:        __einfo_errortab ( EINFO_EINVAL_CRYPTO_REQUEST ),
        !          2813:        __einfo_errortab ( EINFO_ECONNRESET_UNSPECIFIED ),
        !          2814:        __einfo_errortab ( EINFO_ECONNRESET_INACTIVITY ),
        !          2815:        __einfo_errortab ( EINFO_ECONNRESET_4WAY_TIMEOUT ),
        !          2816:        __einfo_errortab ( EINFO_ECONNRESET_8021X_FAILURE ),
        !          2817:        __einfo_errortab ( EINFO_ECONNREFUSED_FAILURE ),
        !          2818:        __einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_DENIED ),
        !          2819:        __einfo_errortab ( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP ),
        !          2820: };

unix.superglobalmegacorp.com

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