iPXE
Functions
802.11 helper functions

Functions

static void net80211_add_channels (struct net80211_device *dev, int start, int len, int txpower)
 Add channels to 802.11 device.
static void net80211_filter_hw_channels (struct net80211_device *dev)
 Filter 802.11 device channels for hardware capabilities.
static void net80211_set_rtscts_rate (struct net80211_device *dev)
 Pick TX rate for RTS/CTS packets based on data rate.
static int net80211_process_capab (struct net80211_device *dev, u16 capab)
 Update 802.11 device state to reflect received capabilities field.
static int net80211_process_ie (struct net80211_device *dev, union ieee80211_ie *ie, void *ie_end)
 Update 802.11 device state to reflect received information elements.
static union ieee80211_ienet80211_marshal_request_info (struct net80211_device *dev, union ieee80211_ie *ie)
 Create information elements for outgoing probe or association packet.

Function Documentation

static void net80211_add_channels ( struct net80211_device dev,
int  start,
int  len,
int  txpower 
) [static]

Add channels to 802.11 device.

Parameters:
dev802.11 device
startFirst channel number to add
lenNumber of channels to add
txpowerTX power (dBm) to allow on added channels

To replace the current list of channels instead of adding to it, set the nr_channels field of the 802.11 device to 0 before calling this function.

Definition at line 917 of file net80211.c.

References net80211_channel::band, net80211_channel::center_freq, net80211_channel::channel_nr, net80211_device::channels, net80211_channel::hw_value, net80211_channel::maxpower, NET80211_BAND_2GHZ, NET80211_BAND_5GHZ, NET80211_MAX_CHANNELS, net80211_device::nr_channels, and start.

Referenced by net80211_prepare_probe(), and net80211_process_ie().

{
        int i, chan = start;

        for ( i = dev->nr_channels; len-- && i < NET80211_MAX_CHANNELS; i++ ) {
                dev->channels[i].channel_nr = chan;
                dev->channels[i].maxpower = txpower;
                dev->channels[i].hw_value = 0;

                if ( chan >= 1 && chan <= 14 ) {
                        dev->channels[i].band = NET80211_BAND_2GHZ;
                        if ( chan == 14 )
                                dev->channels[i].center_freq = 2484;
                        else
                                dev->channels[i].center_freq = 2407 + 5 * chan;
                        chan++;
                } else {
                        dev->channels[i].band = NET80211_BAND_5GHZ;
                        dev->channels[i].center_freq = 5000 + 5 * chan;
                        chan += 4;
                }
        }

        dev->nr_channels = i;
}
static void net80211_filter_hw_channels ( struct net80211_device dev) [static]

Filter 802.11 device channels for hardware capabilities.

Parameters:
dev802.11 device

Hardware may support fewer channels than regulatory restrictions allow; this function filters out channels in dev->channels that are not supported by the hardware list in dev->hwinfo. It also copies over the net80211_channel::hw_value and limits maximum TX power appropriately.

Channels are matched based on center frequency, ignoring band and channel number.

If the driver specifies no supported channels, the effect will be as though all were supported.

Definition at line 961 of file net80211.c.

References net80211_channel::center_freq, net80211_device::channel, net80211_hw_info::channels, channels, net80211_device::channels, net80211_device_operations::config, net80211_device::hw, net80211_channel::hw_value, net80211_channel::maxpower, NET80211_CFG_CHANNEL, net80211_hw_info::nr_channels, net80211_device::nr_channels, ok, and net80211_device::op.

Referenced by net80211_prepare_probe(), and net80211_process_ie().

{
        int delta = 0, i = 0;
        int old_freq = dev->channels[dev->channel].center_freq;
        struct net80211_channel *chan, *hwchan;

        if ( ! dev->hw->nr_channels )
                return;

        dev->channel = 0;
        for ( chan = dev->channels; chan < dev->channels + dev->nr_channels;
              chan++, i++ ) {
                int ok = 0;
                for ( hwchan = dev->hw->channels;
                      hwchan < dev->hw->channels + dev->hw->nr_channels;
                      hwchan++ ) {
                        if ( hwchan->center_freq == chan->center_freq ) {
                                ok = 1;
                                break;
                        }
                }

                if ( ! ok )
                        delta++;
                else {
                        chan->hw_value = hwchan->hw_value;
                        if ( hwchan->maxpower != 0 &&
                             chan->maxpower > hwchan->maxpower )
                                chan->maxpower = hwchan->maxpower;
                        if ( old_freq == chan->center_freq )
                                dev->channel = i - delta;
                        if ( delta )
                                chan[-delta] = *chan;
                }
        }

        dev->nr_channels -= delta;

        if ( dev->channels[dev->channel].center_freq != old_freq )
                dev->op->config ( dev, NET80211_CFG_CHANNEL );
}
static void net80211_set_rtscts_rate ( struct net80211_device dev) [static]

Pick TX rate for RTS/CTS packets based on data rate.

Parameters:
dev802.11 device

The RTS/CTS rate is the fastest TX rate marked as "basic" that is not faster than the data rate.

Definition at line 1967 of file net80211.c.

References net80211_device::basic_rates, net80211_device::nr_rates, net80211_device::rate, net80211_device::rates, and net80211_device::rtscts_rate.

Referenced by net80211_process_ie(), and net80211_set_rate_idx().

{
        u16 datarate = dev->rates[dev->rate];
        u16 rtsrate = 0;
        int rts_idx = -1;
        int i;

        for ( i = 0; i < dev->nr_rates; i++ ) {
                u16 rate = dev->rates[i];

                if ( ! ( dev->basic_rates & ( 1 << i ) ) || rate > datarate )
                        continue;

                if ( rate > rtsrate ) {
                        rtsrate = rate;
                        rts_idx = i;
                }
        }

        /* If this is in initialization, we might not have any basic
           rates; just use the first data rate in that case. */
        if ( rts_idx < 0 )
                rts_idx = 0;

        dev->rtscts_rate = rts_idx;
}
static int net80211_process_capab ( struct net80211_device dev,
u16  capab 
) [static]

Update 802.11 device state to reflect received capabilities field.

Parameters:
dev802.11 device
capabCapabilities field in beacon, probe, or association frame
Return values:
rcReturn status code

Definition at line 1010 of file net80211.c.

References net80211_device_operations::config, DBGC, ENOSYS, IEEE80211_CAPAB_ADHOC, IEEE80211_CAPAB_MANAGED, IEEE80211_CAPAB_SHORT_PMBL, IEEE80211_CAPAB_SHORT_SLOT, NET80211_CFG_PHY_PARAMS, NET80211_PHY_USE_SHORT_PREAMBLE, NET80211_PHY_USE_SHORT_SLOT, net80211_device::op, and net80211_device::phy_flags.

Referenced by net80211_handle_assoc_reply(), and net80211_prepare_assoc().

{
        u16 old_phy = dev->phy_flags;

        if ( ( capab & ( IEEE80211_CAPAB_MANAGED | IEEE80211_CAPAB_ADHOC ) ) !=
             IEEE80211_CAPAB_MANAGED ) {
                DBGC ( dev, "802.11 %p cannot handle IBSS network\n", dev );
                return -ENOSYS;
        }

        dev->phy_flags &= ~( NET80211_PHY_USE_SHORT_PREAMBLE |
                             NET80211_PHY_USE_SHORT_SLOT );

        if ( capab & IEEE80211_CAPAB_SHORT_PMBL )
                dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;

        if ( capab & IEEE80211_CAPAB_SHORT_SLOT )
                dev->phy_flags |= NET80211_PHY_USE_SHORT_SLOT;

        if ( old_phy != dev->phy_flags )
                dev->op->config ( dev, NET80211_CFG_PHY_PARAMS );

        return 0;
}
static int net80211_process_ie ( struct net80211_device dev,
union ieee80211_ie ie,
void *  ie_end 
) [static]

Update 802.11 device state to reflect received information elements.

Parameters:
dev802.11 device
iePointer to first information element
ie_endPointer to tail of packet I/O buffer
Return values:
rcReturn status code

Definition at line 1044 of file net80211.c.

References net80211_channel::band, ieee80211_ie_country_triplet::band, net80211_device::basic_rates, net80211_device::channel, net80211_channel::channel_nr, net80211_device::channels, net80211_device_operations::config, ieee80211_ie::country, ieee80211_ie_ds_param::current_channel, DBGC, ieee80211_ie::ds_param, ieee80211_ie::erp_info, net80211_device::essid, ieee80211_ie_country_triplet::first, ieee80211_ie_country_band_triplet::first_channel, net80211_hw_info::flags, net80211_device::hw, ieee80211_ie::id, IEEE80211_ERP_BARKER_LONG, IEEE80211_ERP_USE_PROTECTION, ieee80211_ie_bound(), IEEE80211_IE_COUNTRY, IEEE80211_IE_DS_PARAM, IEEE80211_IE_ERP_INFO, IEEE80211_IE_EXT_RATES, IEEE80211_IE_RATES, IEEE80211_IE_SSID, ieee80211_next_ie(), ieee80211_ie::len, ieee80211_ie_country_band_triplet::max_txpower, memcpy(), ieee80211_ie_country::name, net80211_add_channels(), NET80211_CFG_PHY_PARAMS, NET80211_CFG_RATE, net80211_change_channel(), net80211_filter_hw_channels(), NET80211_MAX_RATES, NET80211_PHY_USE_PROTECTION, NET80211_PHY_USE_SHORT_PREAMBLE, NET80211_PHY_USE_SHORT_SLOT, net80211_set_rtscts_rate(), ieee80211_ie_country_band_triplet::nr_channels, net80211_device::nr_channels, net80211_hw_info::nr_rates, net80211_device::nr_rates, ok, net80211_device::op, net80211_device::phy_flags, net80211_device::rate, net80211_hw_info::rates, net80211_device::rates, ieee80211_ie::rates, ieee80211_ie::ssid, and ieee80211_ie_country::triplet.

Referenced by net80211_handle_assoc_reply(), and net80211_prepare_assoc().

{
        u16 old_rate = dev->rates[dev->rate];
        u16 old_phy = dev->phy_flags;
        int have_rates = 0, i;
        int ds_channel = 0;
        int changed = 0;
        int band = dev->channels[dev->channel].band;

        if ( ! ieee80211_ie_bound ( ie, ie_end ) )
                return 0;

        for ( ; ie; ie = ieee80211_next_ie ( ie, ie_end ) ) {
                switch ( ie->id ) {
                case IEEE80211_IE_SSID:
                        if ( ie->len <= 32 ) {
                                memcpy ( dev->essid, ie->ssid, ie->len );
                                dev->essid[ie->len] = 0;
                        }
                        break;

                case IEEE80211_IE_RATES:
                case IEEE80211_IE_EXT_RATES:
                        if ( ! have_rates ) {
                                dev->nr_rates = 0;
                                dev->basic_rates = 0;
                                have_rates = 1;
                        }
                        for ( i = 0; i < ie->len &&
                              dev->nr_rates < NET80211_MAX_RATES; i++ ) {
                                u8 rid = ie->rates[i];
                                u16 rate = ( rid & 0x7f ) * 5;

                                if ( rid & 0x80 )
                                        dev->basic_rates |=
                                                ( 1 << dev->nr_rates );

                                dev->rates[dev->nr_rates++] = rate;
                        }

                        break;

                case IEEE80211_IE_DS_PARAM:
                        if ( dev->channel < dev->nr_channels && ds_channel ==
                             dev->channels[dev->channel].channel_nr )
                                break;
                        ds_channel = ie->ds_param.current_channel;
                        net80211_change_channel ( dev, ds_channel );
                        break;

                case IEEE80211_IE_COUNTRY:
                        dev->nr_channels = 0;

                        DBGC ( dev, "802.11 %p setting country regulations "
                               "for %c%c\n", dev, ie->country.name[0],
                               ie->country.name[1] );
                        for ( i = 0; i < ( ie->len - 3 ) / 3; i++ ) {
                                union ieee80211_ie_country_triplet *t =
                                        &ie->country.triplet[i];
                                if ( t->first > 200 ) {
                                        DBGC ( dev, "802.11 %p ignoring regulatory "
                                               "extension information\n", dev );
                                } else {
                                        net80211_add_channels ( dev,
                                                        t->band.first_channel,
                                                        t->band.nr_channels,
                                                        t->band.max_txpower );
                                }
                        }
                        net80211_filter_hw_channels ( dev );
                        break;

                case IEEE80211_IE_ERP_INFO:
                        dev->phy_flags &= ~( NET80211_PHY_USE_PROTECTION |
                                             NET80211_PHY_USE_SHORT_PREAMBLE );
                        if ( ie->erp_info & IEEE80211_ERP_USE_PROTECTION )
                                dev->phy_flags |= NET80211_PHY_USE_PROTECTION;
                        if ( ! ( ie->erp_info & IEEE80211_ERP_BARKER_LONG ) )
                                dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
                        break;
                }
        }

        if ( have_rates ) {
                /* Allow only those rates that are also supported by
                   the hardware. */
                int delta = 0, j;

                dev->rate = 0;
                for ( i = 0; i < dev->nr_rates; i++ ) {
                        int ok = 0;
                        for ( j = 0; j < dev->hw->nr_rates[band]; j++ ) {
                                if ( dev->hw->rates[band][j] == dev->rates[i] ){
                                        ok = 1;
                                        break;
                                }
                        }

                        if ( ! ok )
                                delta++;
                        else {
                                dev->rates[i - delta] = dev->rates[i];
                                if ( old_rate == dev->rates[i] )
                                        dev->rate = i - delta;
                        }
                }

                dev->nr_rates -= delta;

                /* Sort available rates - sorted subclumps tend to already
                   exist, so insertion sort works well. */
                for ( i = 1; i < dev->nr_rates; i++ ) {
                        u16 rate = dev->rates[i];
                        u32 tmp, br, mask;

                        for ( j = i - 1; j >= 0 && dev->rates[j] >= rate; j-- )
                                dev->rates[j + 1] = dev->rates[j];
                        dev->rates[j + 1] = rate;

                        /* Adjust basic_rates to match by rotating the
                           bits from bit j+1 to bit i left one position. */
                        mask = ( ( 1 << i ) - 1 ) & ~( ( 1 << ( j + 1 ) ) - 1 );
                        br = dev->basic_rates;
                        tmp = br & ( 1 << i );
                        br = ( br & ~( mask | tmp ) ) | ( ( br & mask ) << 1 );
                        br |= ( tmp >> ( i - j - 1 ) );
                        dev->basic_rates = br;
                }

                net80211_set_rtscts_rate ( dev );

                if ( dev->rates[dev->rate] != old_rate )
                        changed |= NET80211_CFG_RATE;
        }

        if ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE )
                dev->phy_flags &= ~NET80211_PHY_USE_SHORT_PREAMBLE;
        if ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT )
                dev->phy_flags &= ~NET80211_PHY_USE_SHORT_SLOT;

        if ( old_phy != dev->phy_flags )
                changed |= NET80211_CFG_PHY_PARAMS;

        if ( changed )
                dev->op->config ( dev, changed );

        return 0;
}
static union ieee80211_ie * net80211_marshal_request_info ( struct net80211_device dev,
union ieee80211_ie ie 
) [static, write]

Create information elements for outgoing probe or association packet.

Parameters:
dev802.11 device
iePointer to start of information element area
Return values:
next_iePointer to first byte after added information elements

Definition at line 1202 of file net80211.c.

References net80211_device::basic_rates, net80211_device::essid, ieee80211_ie::id, IEEE80211_IE_EXT_RATES, IEEE80211_IE_RATES, IEEE80211_IE_RSN, IEEE80211_IE_SSID, IEEE80211_IE_VENDOR, ieee80211_next_ie(), ieee80211_ie::len, memcpy(), net80211_device::nr_rates, NULL, net80211_device::rates, ieee80211_ie::rates, net80211_device::rsn_ie, ieee80211_ie::ssid, and strlen().

Referenced by net80211_probe_start(), and net80211_send_assoc().

{
        int i;

        ie->id = IEEE80211_IE_SSID;
        ie->len = strlen ( dev->essid );
        memcpy ( ie->ssid, dev->essid, ie->len );

        ie = ieee80211_next_ie ( ie, NULL );

        ie->id = IEEE80211_IE_RATES;
        ie->len = dev->nr_rates;
        if ( ie->len > 8 )
                ie->len = 8;

        for ( i = 0; i < ie->len; i++ ) {
                ie->rates[i] = dev->rates[i] / 5;
                if ( dev->basic_rates & ( 1 << i ) )
                        ie->rates[i] |= 0x80;
        }

        ie = ieee80211_next_ie ( ie, NULL );

        if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_RSN ) {
                memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
                ie = ieee80211_next_ie ( ie, NULL );
        }

        if ( dev->nr_rates > 8 ) {
                /* 802.11 requires we use an Extended Basic Rates IE
                   for the rates beyond the eighth. */

                ie->id = IEEE80211_IE_EXT_RATES;
                ie->len = dev->nr_rates - 8;

                for ( ; i < dev->nr_rates; i++ ) {
                        ie->rates[i - 8] = dev->rates[i] / 5;
                        if ( dev->basic_rates & ( 1 << i ) )
                                ie->rates[i - 8] |= 0x80;
                }

                ie = ieee80211_next_ie ( ie, NULL );
        }

        if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_VENDOR ) {
                memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
                ie = ieee80211_next_ie ( ie, NULL );
        }

        return ie;
}