iPXE
Functions
802.11 network location API

Functions

int net80211_prepare_probe (struct net80211_device *dev, int band, int active)
 Prepare 802.11 device channel and rate set for scanning.
struct net80211_probe_ctxnet80211_probe_start (struct net80211_device *dev, const char *essid, int active)
 Begin probe of 802.11 networks.
int net80211_probe_step (struct net80211_probe_ctx *ctx)
 Continue probe of 802.11 networks.
struct net80211_wlannet80211_probe_finish_best (struct net80211_probe_ctx *ctx)
 Finish probe of 802.11 networks, returning best-signal network found.
struct list_headnet80211_probe_finish_all (struct net80211_probe_ctx *ctx)
 Finish probe of 802.11 networks, returning all networks found.
void net80211_free_wlan (struct net80211_wlan *wlan)
 Free WLAN structure.
void net80211_free_wlanlist (struct list_head *list)
 Free list of WLAN structures.

Function Documentation

int net80211_prepare_probe ( struct net80211_device dev,
int  band,
int  active 
)

Prepare 802.11 device channel and rate set for scanning.

Parameters:
dev802.11 device
bandRF band(s) on which to prepare for scanning
activeWhether the scanning will be active
Return values:
rcReturn status code

Definition at line 2051 of file net80211.c.

References assert, net80211_channel::band, net80211_device::channel, net80211_device::channels, net80211_device_operations::config, DBGC, EINVAL_ACTIVE_SCAN, net80211_device::hw, net80211_add_channels(), NET80211_BAND_BIT_2GHZ, NET80211_BAND_BIT_5GHZ, NET80211_CFG_CHANNEL, NET80211_CFG_RATE, net80211_filter_hw_channels(), NET80211_REG_TXPOWER, net80211_device::netdev, netdev_is_open(), net80211_device::nr_channels, net80211_device::nr_rates, net80211_device::op, net80211_device::rate, net80211_hw_info::rates, and net80211_device::rates.

Referenced by iwlist(), and net80211_step_associate().

{
        assert ( netdev_is_open ( dev->netdev ) );

        if ( active && ( band & NET80211_BAND_BIT_5GHZ ) ) {
                DBGC ( dev, "802.11 %p cannot perform active scanning on "
                       "5GHz band\n", dev );
                return -EINVAL_ACTIVE_SCAN;
        }

        if ( band == 0 ) {
                /* This can happen for a 5GHz-only card with 5GHz
                   scanning masked out by an active request. */
                DBGC ( dev, "802.11 %p asked to prepare for scanning nothing\n",
                       dev );
                return -EINVAL_ACTIVE_SCAN;
        }

        dev->nr_channels = 0;

        if ( active )
                net80211_add_channels ( dev, 1, 11, NET80211_REG_TXPOWER );
        else {
                if ( band & NET80211_BAND_BIT_2GHZ )
                        net80211_add_channels ( dev, 1, 14,
                                                NET80211_REG_TXPOWER );
                if ( band & NET80211_BAND_BIT_5GHZ )
                        net80211_add_channels ( dev, 36, 8,
                                                NET80211_REG_TXPOWER );
        }

        net80211_filter_hw_channels ( dev );

        /* Use channel 1 for now */
        dev->channel = 0;
        dev->op->config ( dev, NET80211_CFG_CHANNEL );

        /* Always do active probes at lowest (presumably first) speed */
        dev->rate = 0;
        dev->nr_rates = 1;
        dev->rates[0] = dev->hw->rates[dev->channels[0].band][0];
        dev->op->config ( dev, NET80211_CFG_RATE );

        return 0;
}
struct net80211_probe_ctx* net80211_probe_start ( struct net80211_device dev,
const char *  essid,
int  active 
) [read]

Begin probe of 802.11 networks.

Parameters:
dev802.11 device
essidSSID to probe for, or "" to accept any (may not be NULL)
activeWhether to use active scanning
Return values:
ctxProbe context

Active scanning may only be used on channels 1-11 in the 2.4GHz band, due to iPXE's lack of a complete regulatory database. If active scanning is used, probe packets will be sent on each channel; this can allow association with hidden-SSID networks if the SSID is properly specified.

A NULL return indicates an out-of-memory condition.

The returned context must be periodically passed to net80211_probe_step() until that function returns zero.

Definition at line 1290 of file net80211.c.

References alloc_iob(), assert, net80211_probe_ctx::beacons, net80211_device::channel, net80211_device_operations::config, ctx, currticks(), io_buffer::data, net80211_probe_ctx::dev, net80211_probe_ctx::essid, net80211_device::essid, net80211_probe_ctx::hop_step, net80211_probe_ctx::hop_time, IEEE80211_TYP_FRAME_HEADER_LEN, ieee80211_probe_req::info_element, INIT_LIST_HEAD, iob_put, iob_reserve, malloc(), NET80211_CFG_CHANNEL, net80211_keep_mgmt(), net80211_marshal_request_info(), net80211_device::netdev, netdev_is_open(), net80211_device::nr_channels, NULL, net80211_probe_ctx::old_keep_mgmt, net80211_device::op, net80211_probe_ctx::probe, strcpy(), net80211_probe_ctx::ticks_beacon, net80211_probe_ctx::ticks_channel, TICKS_PER_SEC, net80211_probe_ctx::ticks_start, and zalloc().

Referenced by iwlist(), and net80211_step_associate().

{
        struct net80211_probe_ctx *ctx = zalloc ( sizeof ( *ctx ) );

        if ( ! ctx )
                return NULL;

        assert ( netdev_is_open ( dev->netdev ) );

        ctx->dev = dev;
        ctx->old_keep_mgmt = net80211_keep_mgmt ( dev, 1 );
        ctx->essid = essid;
        if ( dev->essid != ctx->essid )
                strcpy ( dev->essid, ctx->essid );

        if ( active ) {
                struct ieee80211_probe_req *probe_req;
                union ieee80211_ie *ie;

                ctx->probe = alloc_iob ( 128 );
                iob_reserve ( ctx->probe, IEEE80211_TYP_FRAME_HEADER_LEN );
                probe_req = ctx->probe->data;

                ie = net80211_marshal_request_info ( dev,
                                                     probe_req->info_element );

                iob_put ( ctx->probe, ( void * ) ie - ctx->probe->data );
        }

        ctx->ticks_start = currticks();
        ctx->ticks_beacon = 0;
        ctx->ticks_channel = currticks();
        ctx->hop_time = TICKS_PER_SEC / ( active ? 2 : 6 );

        /*
         * Channels on 2.4GHz overlap, and the most commonly used
         * are 1, 6, and 11. We'll get a result faster if we check
         * every 5 channels, but in order to hit all of them the
         * number of channels must be relatively prime to 5. If it's
         * not, tweak the hop.
         */
        ctx->hop_step = 5;
        while ( dev->nr_channels % ctx->hop_step == 0 && ctx->hop_step > 1 )
                ctx->hop_step--;

        ctx->beacons = malloc ( sizeof ( *ctx->beacons ) );
        INIT_LIST_HEAD ( ctx->beacons );

        dev->channel = 0;
        dev->op->config ( dev, NET80211_CFG_CHANNEL );

        return ctx;
}
int net80211_probe_step ( struct net80211_probe_ctx ctx)

Continue probe of 802.11 networks.

Parameters:
ctxProbe context returned by net80211_probe_start()
Return values:
rcProbe status

The return code will be 0 if the probe is still going on (and this function should be called again), a positive number if the probe completed successfully, or a negative error code if the probe failed for that reason.

Whether the probe succeeded or failed, you must call net80211_probe_finish_all() or net80211_probe_finish_best() (depending on whether you want information on all networks or just the best-signal one) in order to release the probe context. A failed probe may still have acquired some valid data.

Definition at line 1363 of file net80211.c.

References ieee80211_frame::addr3, alloc_iob(), net80211_wlan::beacon, net80211_probe_ctx::beacons, net80211_wlan::bssid, net80211_device::channel, net80211_wlan::channel, net80211_hw_info::channel_change_time, net80211_channel::channel_nr, net80211_device::channels, net80211_device_operations::config, net80211_wlan::crypto, currticks(), io_buffer::data, ieee80211_frame::data, DBG, DBGC, DBGC2, net80211_probe_ctx::dev, ENOTSUP, net80211_probe_ctx::essid, net80211_wlan::essid, ETH_ALEN, eth_broadcast, eth_ntoa(), ETIMEDOUT, ieee80211_frame::fc, fill, free_iob(), net80211_wlan::handshaking, hdr, io_buffer::head, net80211_probe_ctx::hop_step, net80211_probe_ctx::hop_time, net80211_device::hw, ieee80211_ie::id, ieee80211_beacon, IEEE80211_CAPAB_PRIVACY, IEEE80211_FC_SUBTYPE, ieee80211_ie_bound(), IEEE80211_IE_SSID, IEEE80211_MAX_SSID_LEN, ieee80211_next_ie(), IEEE80211_STYPE_BEACON, IEEE80211_STYPE_PROBE_REQ, IEEE80211_STYPE_PROBE_RESP, iob_disown, iob_headroom(), iob_len(), iob_put, iob_reserve, ieee80211_ie::len, net80211_wlan::list, list_add_tail, list_empty, list_for_each_entry, memcpy(), NET80211_CFG_CHANNEL, NET80211_CRYPT_NONE, NET80211_CRYPT_UNKNOWN, net80211_mgmt_dequeue(), NET80211_PROBE_GATHER, NET80211_PROBE_GATHER_ALL, NET80211_PROBE_TIMEOUT, NET80211_SECPROT_NONE, NET80211_SECPROT_UNKNOWN, net80211_tx_mgmt(), net80211_device::nr_channels, NULL, net80211_device::op, net80211_probe_ctx::probe, rc, sec80211_detect(), net80211_wlan::signal, ssid, ieee80211_ie::ssid, strcmp(), strcpy(), strerror(), io_buffer::tail, net80211_probe_ctx::ticks_beacon, net80211_probe_ctx::ticks_channel, TICKS_PER_SEC, net80211_probe_ctx::ticks_start, type, udelay(), and zalloc().

Referenced by iwlist(), and net80211_step_associate().

{
        struct net80211_device *dev = ctx->dev;
        u32 start_timeout = NET80211_PROBE_TIMEOUT * TICKS_PER_SEC;
        u32 gather_timeout = TICKS_PER_SEC;
        u32 now = currticks();
        struct io_buffer *iob;
        int signal;
        int rc;
        char ssid[IEEE80211_MAX_SSID_LEN + 1];

        gather_timeout *= ( ctx->essid[0] ? NET80211_PROBE_GATHER :
                            NET80211_PROBE_GATHER_ALL );

        /* Time out if necessary */
        if ( now >= ctx->ticks_start + start_timeout )
                return list_empty ( ctx->beacons ) ? -ETIMEDOUT : +1;

        if ( ctx->ticks_beacon > 0 && now >= ctx->ticks_start + gather_timeout )
                return +1;

        /* Change channels if necessary */
        if ( now >= ctx->ticks_channel + ctx->hop_time ) {
                dev->channel = ( dev->channel + ctx->hop_step )
                        % dev->nr_channels;
                dev->op->config ( dev, NET80211_CFG_CHANNEL );
                udelay ( dev->hw->channel_change_time );

                ctx->ticks_channel = now;

                if ( ctx->probe ) {
                        struct io_buffer *siob = ctx->probe; /* to send */

                        /* make a copy for future use */
                        iob = alloc_iob ( siob->tail - siob->head );
                        iob_reserve ( iob, iob_headroom ( siob ) );
                        memcpy ( iob_put ( iob, iob_len ( siob ) ),
                                 siob->data, iob_len ( siob ) );

                        ctx->probe = iob;
                        rc = net80211_tx_mgmt ( dev, IEEE80211_STYPE_PROBE_REQ,
                                                eth_broadcast,
                                                iob_disown ( siob ) );
                        if ( rc ) {
                                DBGC ( dev, "802.11 %p send probe failed: "
                                       "%s\n", dev, strerror ( rc ) );
                                return rc;
                        }
                }
        }

        /* Check for new management packets */
        while ( ( iob = net80211_mgmt_dequeue ( dev, &signal ) ) != NULL ) {
                struct ieee80211_frame *hdr;
                struct ieee80211_beacon *beacon;
                union ieee80211_ie *ie;
                struct net80211_wlan *wlan;
                u16 type;

                hdr = iob->data;
                type = hdr->fc & IEEE80211_FC_SUBTYPE;
                beacon = ( struct ieee80211_beacon * ) hdr->data;

                if ( type != IEEE80211_STYPE_BEACON &&
                     type != IEEE80211_STYPE_PROBE_RESP ) {
                        DBGC2 ( dev, "802.11 %p probe: non-beacon\n", dev );
                        goto drop;
                }

                if ( ( void * ) beacon->info_element >= iob->tail ) {
                        DBGC ( dev, "802.11 %p probe: beacon with no IEs\n",
                               dev );
                        goto drop;
                }

                ie = beacon->info_element;

                if ( ! ieee80211_ie_bound ( ie, iob->tail ) )
                        ie = NULL;

                while ( ie && ie->id != IEEE80211_IE_SSID )
                        ie = ieee80211_next_ie ( ie, iob->tail );

                if ( ! ie ) {
                        DBGC ( dev, "802.11 %p probe: beacon with no SSID\n",
                               dev );
                        goto drop;
                }

                memcpy ( ssid, ie->ssid, ie->len );
                ssid[ie->len] = 0;

                if ( ctx->essid[0] && strcmp ( ctx->essid, ssid ) != 0 ) {
                        DBGC2 ( dev, "802.11 %p probe: beacon with wrong SSID "
                                "(%s)\n", dev, ssid );
                        goto drop;
                }

                /* See if we've got an entry for this network */
                list_for_each_entry ( wlan, ctx->beacons, list ) {
                        if ( strcmp ( wlan->essid, ssid ) != 0 )
                                continue;

                        if ( signal < wlan->signal ) {
                                DBGC2 ( dev, "802.11 %p probe: beacon for %s "
                                        "(%s) with weaker signal %d\n", dev,
                                        ssid, eth_ntoa ( hdr->addr3 ), signal );
                                goto drop;
                        }

                        goto fill;
                }

                /* No entry yet - make one */
                wlan = zalloc ( sizeof ( *wlan ) );
                strcpy ( wlan->essid, ssid );
                list_add_tail ( &wlan->list, ctx->beacons );

                /* Whether we're using an old entry or a new one, fill
                   it with new data. */
        fill:
                memcpy ( wlan->bssid, hdr->addr3, ETH_ALEN );
                wlan->signal = signal;
                wlan->channel = dev->channels[dev->channel].channel_nr;

                /* Copy this I/O buffer into a new wlan->beacon; the
                 * iob we've got probably came from the device driver
                 * and may have the full 2.4k allocation, which we
                 * don't want to keep around wasting memory.
                 */
                free_iob ( wlan->beacon );
                wlan->beacon = alloc_iob ( iob_len ( iob ) );
                memcpy ( iob_put ( wlan->beacon, iob_len ( iob ) ),
                         iob->data, iob_len ( iob ) );

                if ( ( rc = sec80211_detect ( wlan->beacon, &wlan->handshaking,
                                              &wlan->crypto ) ) == -ENOTSUP ) {
                        struct ieee80211_beacon *beacon =
                                ( struct ieee80211_beacon * ) hdr->data;

                        if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) {
                                DBG ( "802.11 %p probe: secured network %s but "
                                      "encryption support not compiled in\n",
                                      dev, wlan->essid );
                                wlan->handshaking = NET80211_SECPROT_UNKNOWN;
                                wlan->crypto = NET80211_CRYPT_UNKNOWN;
                        } else {
                                wlan->handshaking = NET80211_SECPROT_NONE;
                                wlan->crypto = NET80211_CRYPT_NONE;
                        }
                } else if ( rc != 0 ) {
                        DBGC ( dev, "802.11 %p probe warning: network "
                               "%s with unidentifiable security "
                               "settings: %s\n", dev, wlan->essid,
                               strerror ( rc ) );
                }

                ctx->ticks_beacon = now;

                DBGC2 ( dev, "802.11 %p probe: good beacon for %s (%s)\n",
                        dev, wlan->essid, eth_ntoa ( wlan->bssid ) );

        drop:
                free_iob ( iob );
        }

        return 0;
}

Finish probe of 802.11 networks, returning best-signal network found.

Parameters:
ctxProbe context
Return values:
wlanBest-signal network found, or NULL if none were found

If net80211_probe_start() was called with a particular SSID parameter as filter, only a network with that SSID (matching case-sensitively) can be returned from this function.

Definition at line 1544 of file net80211.c.

References net80211_probe_ctx::beacons, DBGC, net80211_probe_ctx::dev, net80211_probe_ctx::essid, free, free_iob(), net80211_wlan::list, list_del, list_for_each_entry, net80211_free_wlanlist(), net80211_keep_mgmt(), NULL, net80211_probe_ctx::old_keep_mgmt, net80211_probe_ctx::probe, and net80211_wlan::signal.

Referenced by net80211_autoassociate(), and net80211_step_associate().

{
        struct net80211_wlan *best = NULL, *wlan;

        if ( ! ctx )
                return NULL;

        list_for_each_entry ( wlan, ctx->beacons, list ) {
                if ( ! best || best->signal < wlan->signal )
                        best = wlan;
        }

        if ( best )
                list_del ( &best->list );
        else
                DBGC ( ctx->dev, "802.11 %p probe: found nothing for '%s'\n",
                       ctx->dev, ctx->essid );

        net80211_free_wlanlist ( ctx->beacons );

        net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );

        if ( ctx->probe )
                free_iob ( ctx->probe );

        free ( ctx );

        return best;
}
struct list_head* net80211_probe_finish_all ( struct net80211_probe_ctx ctx) [read]

Finish probe of 802.11 networks, returning all networks found.

Parameters:
ctxProbe context
Return values:
listList of net80211_wlan detailing networks found

If net80211_probe_start() was called with a particular SSID parameter as filter, this will always return either an empty or a one-element list.

Definition at line 1585 of file net80211.c.

References net80211_probe_ctx::beacons, net80211_probe_ctx::dev, free, free_iob(), net80211_keep_mgmt(), net80211_probe_ctx::old_keep_mgmt, and net80211_probe_ctx::probe.

Referenced by iwlist().

{
        struct list_head *beacons = ctx->beacons;

        net80211_keep_mgmt ( ctx->dev, ctx->old_keep_mgmt );

        if ( ctx->probe )
                free_iob ( ctx->probe );

        free ( ctx );

        return beacons;
}
void net80211_free_wlan ( struct net80211_wlan wlan)

Free WLAN structure.

Parameters:
wlanWLAN structure to free

Definition at line 1605 of file net80211.c.

References net80211_wlan::beacon, free, and free_iob().

Referenced by net80211_autoassociate(), net80211_free_wlanlist(), and net80211_step_associate().

{
        if ( wlan ) {
                free_iob ( wlan->beacon );
                free ( wlan );
        }
}
void net80211_free_wlanlist ( struct list_head list)

Free list of WLAN structures.

Parameters:
listList of WLAN structures to free

Definition at line 1619 of file net80211.c.

References free, net80211_wlan::list, list_del, list_for_each_entry_safe, and net80211_free_wlan().

Referenced by iwlist(), and net80211_probe_finish_best().

{
        struct net80211_wlan *wlan, *tmp;

        if ( ! list )
                return;

        list_for_each_entry_safe ( wlan, tmp, list, list ) {
                list_del ( &wlan->list );
                net80211_free_wlan ( wlan );
        }

        free ( list );
}