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:
dev 802.11 device
start First channel number to add
len Number of channels to add
txpower TX 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 925 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, and net80211_device::nr_channels.

Referenced by net80211_prepare_probe(), and net80211_process_ie().

00927 {
00928         int i, chan = start;
00929 
00930         for ( i = dev->nr_channels; len-- && i < NET80211_MAX_CHANNELS; i++ ) {
00931                 dev->channels[i].channel_nr = chan;
00932                 dev->channels[i].maxpower = txpower;
00933                 dev->channels[i].hw_value = 0;
00934 
00935                 if ( chan >= 1 && chan <= 14 ) {
00936                         dev->channels[i].band = NET80211_BAND_2GHZ;
00937                         if ( chan == 14 )
00938                                 dev->channels[i].center_freq = 2484;
00939                         else
00940                                 dev->channels[i].center_freq = 2407 + 5 * chan;
00941                         chan++;
00942                 } else {
00943                         dev->channels[i].band = NET80211_BAND_5GHZ;
00944                         dev->channels[i].center_freq = 5000 + 5 * chan;
00945                         chan += 4;
00946                 }
00947         }
00948 
00949         dev->nr_channels = i;
00950 }

static void net80211_filter_hw_channels ( struct net80211_device dev  )  [static]

Filter 802.11 device channels for hardware capabilities.

Parameters:
dev 802.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 969 of file net80211.c.

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

Referenced by net80211_prepare_probe(), and net80211_process_ie().

00970 {
00971         int delta = 0, i = 0;
00972         int old_freq = dev->channels[dev->channel].center_freq;
00973         struct net80211_channel *chan, *hwchan;
00974 
00975         if ( ! dev->hw->nr_channels )
00976                 return;
00977 
00978         dev->channel = 0;
00979         for ( chan = dev->channels; chan < dev->channels + dev->nr_channels;
00980               chan++, i++ ) {
00981                 int ok = 0;
00982                 for ( hwchan = dev->hw->channels;
00983                       hwchan < dev->hw->channels + dev->hw->nr_channels;
00984                       hwchan++ ) {
00985                         if ( hwchan->center_freq == chan->center_freq ) {
00986                                 ok = 1;
00987                                 break;
00988                         }
00989                 }
00990 
00991                 if ( ! ok )
00992                         delta++;
00993                 else {
00994                         chan->hw_value = hwchan->hw_value;
00995                         if ( hwchan->maxpower != 0 &&
00996                              chan->maxpower > hwchan->maxpower )
00997                                 chan->maxpower = hwchan->maxpower;
00998                         if ( old_freq == chan->center_freq )
00999                                 dev->channel = i - delta;
01000                         if ( delta )
01001                                 chan[-delta] = *chan;
01002                 }
01003         }
01004 
01005         dev->nr_channels -= delta;
01006 
01007         if ( dev->channels[dev->channel].center_freq != old_freq )
01008                 dev->op->config ( dev, NET80211_CFG_CHANNEL );
01009 }

static void net80211_set_rtscts_rate ( struct net80211_device dev  )  [static]

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

Parameters:
dev 802.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 1980 of file net80211.c.

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

Referenced by net80211_process_ie(), and net80211_set_rate_idx().

01981 {
01982         u16 datarate = dev->rates[dev->rate];
01983         u16 rtsrate = 0;
01984         int rts_idx = -1;
01985         int i;
01986 
01987         for ( i = 0; i < dev->nr_rates; i++ ) {
01988                 u16 rate = dev->rates[i];
01989 
01990                 if ( ! ( dev->basic_rates & ( 1 << i ) ) || rate > datarate )
01991                         continue;
01992 
01993                 if ( rate > rtsrate ) {
01994                         rtsrate = rate;
01995                         rts_idx = i;
01996                 }
01997         }
01998 
01999         /* If this is in initialization, we might not have any basic
02000            rates; just use the first data rate in that case. */
02001         if ( rts_idx < 0 )
02002                 rts_idx = 0;
02003 
02004         dev->rtscts_rate = rts_idx;
02005 }

static int net80211_process_capab ( struct net80211_device dev,
u16  capab 
) [static]

Update 802.11 device state to reflect received capabilities field.

Parameters:
dev 802.11 device
capab Capabilities field in beacon, probe, or association frame
Return values:
rc Return status code

Definition at line 1018 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, net80211_device::phy_flags, and u16.

Referenced by net80211_handle_assoc_reply(), and net80211_prepare_assoc().

01020 {
01021         u16 old_phy = dev->phy_flags;
01022 
01023         if ( ( capab & ( IEEE80211_CAPAB_MANAGED | IEEE80211_CAPAB_ADHOC ) ) !=
01024              IEEE80211_CAPAB_MANAGED ) {
01025                 DBGC ( dev, "802.11 %p cannot handle IBSS network\n", dev );
01026                 return -ENOSYS;
01027         }
01028 
01029         dev->phy_flags &= ~( NET80211_PHY_USE_SHORT_PREAMBLE |
01030                              NET80211_PHY_USE_SHORT_SLOT );
01031 
01032         if ( capab & IEEE80211_CAPAB_SHORT_PMBL )
01033                 dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
01034 
01035         if ( capab & IEEE80211_CAPAB_SHORT_SLOT )
01036                 dev->phy_flags |= NET80211_PHY_USE_SHORT_SLOT;
01037 
01038         if ( old_phy != dev->phy_flags )
01039                 dev->op->config ( dev, NET80211_CFG_PHY_PARAMS );
01040 
01041         return 0;
01042 }

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:
dev 802.11 device
ie Pointer to first information element
ie_end Pointer to tail of packet I/O buffer
Return values:
rc Return status code

Definition at line 1052 of file net80211.c.

References ieee80211_ie_country_triplet::band, net80211_channel::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, net80211_device::op, net80211_device::phy_flags, net80211_device::rate, net80211_hw_info::rates, ieee80211_ie::rates, net80211_device::rates, ieee80211_ie::ssid, ieee80211_ie_country::triplet, u16, u32, and u8.

Referenced by net80211_handle_assoc_reply(), and net80211_prepare_assoc().

01054 {
01055         u16 old_rate = dev->rates[dev->rate];
01056         u16 old_phy = dev->phy_flags;
01057         int have_rates = 0, i;
01058         int ds_channel = 0;
01059         int changed = 0;
01060         int band = dev->channels[dev->channel].band;
01061 
01062         if ( ! ieee80211_ie_bound ( ie, ie_end ) )
01063                 return 0;
01064 
01065         for ( ; ie; ie = ieee80211_next_ie ( ie, ie_end ) ) {
01066                 switch ( ie->id ) {
01067                 case IEEE80211_IE_SSID:
01068                         if ( ie->len <= 32 ) {
01069                                 memcpy ( dev->essid, ie->ssid, ie->len );
01070                                 dev->essid[ie->len] = 0;
01071                         }
01072                         break;
01073 
01074                 case IEEE80211_IE_RATES:
01075                 case IEEE80211_IE_EXT_RATES:
01076                         if ( ! have_rates ) {
01077                                 dev->nr_rates = 0;
01078                                 dev->basic_rates = 0;
01079                                 have_rates = 1;
01080                         }
01081                         for ( i = 0; i < ie->len &&
01082                               dev->nr_rates < NET80211_MAX_RATES; i++ ) {
01083                                 u8 rid = ie->rates[i];
01084                                 u16 rate = ( rid & 0x7f ) * 5;
01085 
01086                                 if ( rid & 0x80 )
01087                                         dev->basic_rates |=
01088                                                 ( 1 << dev->nr_rates );
01089 
01090                                 dev->rates[dev->nr_rates++] = rate;
01091                         }
01092 
01093                         break;
01094 
01095                 case IEEE80211_IE_DS_PARAM:
01096                         if ( dev->channel < dev->nr_channels && ds_channel ==
01097                              dev->channels[dev->channel].channel_nr )
01098                                 break;
01099                         ds_channel = ie->ds_param.current_channel;
01100                         net80211_change_channel ( dev, ds_channel );
01101                         break;
01102 
01103                 case IEEE80211_IE_COUNTRY:
01104                         dev->nr_channels = 0;
01105 
01106                         DBGC ( dev, "802.11 %p setting country regulations "
01107                                "for %c%c\n", dev, ie->country.name[0],
01108                                ie->country.name[1] );
01109                         for ( i = 0; i < ( ie->len - 3 ) / 3; i++ ) {
01110                                 union ieee80211_ie_country_triplet *t =
01111                                         &ie->country.triplet[i];
01112                                 if ( t->first > 200 ) {
01113                                         DBGC ( dev, "802.11 %p ignoring regulatory "
01114                                                "extension information\n", dev );
01115                                 } else {
01116                                         net80211_add_channels ( dev,
01117                                                         t->band.first_channel,
01118                                                         t->band.nr_channels,
01119                                                         t->band.max_txpower );
01120                                 }
01121                         }
01122                         net80211_filter_hw_channels ( dev );
01123                         break;
01124 
01125                 case IEEE80211_IE_ERP_INFO:
01126                         dev->phy_flags &= ~( NET80211_PHY_USE_PROTECTION |
01127                                              NET80211_PHY_USE_SHORT_PREAMBLE );
01128                         if ( ie->erp_info & IEEE80211_ERP_USE_PROTECTION )
01129                                 dev->phy_flags |= NET80211_PHY_USE_PROTECTION;
01130                         if ( ! ( ie->erp_info & IEEE80211_ERP_BARKER_LONG ) )
01131                                 dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
01132                         break;
01133                 }
01134         }
01135 
01136         if ( have_rates ) {
01137                 /* Allow only those rates that are also supported by
01138                    the hardware. */
01139                 int delta = 0, j;
01140 
01141                 dev->rate = 0;
01142                 for ( i = 0; i < dev->nr_rates; i++ ) {
01143                         int ok = 0;
01144                         for ( j = 0; j < dev->hw->nr_rates[band]; j++ ) {
01145                                 if ( dev->hw->rates[band][j] == dev->rates[i] ){
01146                                         ok = 1;
01147                                         break;
01148                                 }
01149                         }
01150 
01151                         if ( ! ok )
01152                                 delta++;
01153                         else {
01154                                 dev->rates[i - delta] = dev->rates[i];
01155                                 if ( old_rate == dev->rates[i] )
01156                                         dev->rate = i - delta;
01157                         }
01158                 }
01159 
01160                 dev->nr_rates -= delta;
01161 
01162                 /* Sort available rates - sorted subclumps tend to already
01163                    exist, so insertion sort works well. */
01164                 for ( i = 1; i < dev->nr_rates; i++ ) {
01165                         u16 rate = dev->rates[i];
01166                         u32 tmp, br, mask;
01167 
01168                         for ( j = i - 1; j >= 0 && dev->rates[j] >= rate; j-- )
01169                                 dev->rates[j + 1] = dev->rates[j];
01170                         dev->rates[j + 1] = rate;
01171 
01172                         /* Adjust basic_rates to match by rotating the
01173                            bits from bit j+1 to bit i left one position. */
01174                         mask = ( ( 1 << i ) - 1 ) & ~( ( 1 << ( j + 1 ) ) - 1 );
01175                         br = dev->basic_rates;
01176                         tmp = br & ( 1 << i );
01177                         br = ( br & ~( mask | tmp ) ) | ( ( br & mask ) << 1 );
01178                         br |= ( tmp >> ( i - j - 1 ) );
01179                         dev->basic_rates = br;
01180                 }
01181 
01182                 net80211_set_rtscts_rate ( dev );
01183 
01184                 if ( dev->rates[dev->rate] != old_rate )
01185                         changed |= NET80211_CFG_RATE;
01186         }
01187 
01188         if ( dev->hw->flags & NET80211_HW_NO_SHORT_PREAMBLE )
01189                 dev->phy_flags &= ~NET80211_PHY_USE_SHORT_PREAMBLE;
01190         if ( dev->hw->flags & NET80211_HW_NO_SHORT_SLOT )
01191                 dev->phy_flags &= ~NET80211_PHY_USE_SHORT_SLOT;
01192 
01193         if ( old_phy != dev->phy_flags )
01194                 changed |= NET80211_CFG_PHY_PARAMS;
01195 
01196         if ( changed )
01197                 dev->op->config ( dev, changed );
01198 
01199         return 0;
01200 }

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:
dev 802.11 device
ie Pointer to start of information element area
Return values:
next_ie Pointer to first byte after added information elements

Definition at line 1210 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().

01212 {
01213         int i;
01214 
01215         ie->id = IEEE80211_IE_SSID;
01216         ie->len = strlen ( dev->essid );
01217         memcpy ( ie->ssid, dev->essid, ie->len );
01218 
01219         ie = ieee80211_next_ie ( ie, NULL );
01220 
01221         ie->id = IEEE80211_IE_RATES;
01222         ie->len = dev->nr_rates;
01223         if ( ie->len > 8 )
01224                 ie->len = 8;
01225 
01226         for ( i = 0; i < ie->len; i++ ) {
01227                 ie->rates[i] = dev->rates[i] / 5;
01228                 if ( dev->basic_rates & ( 1 << i ) )
01229                         ie->rates[i] |= 0x80;
01230         }
01231 
01232         ie = ieee80211_next_ie ( ie, NULL );
01233 
01234         if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_RSN ) {
01235                 memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
01236                 ie = ieee80211_next_ie ( ie, NULL );
01237         }
01238 
01239         if ( dev->nr_rates > 8 ) {
01240                 /* 802.11 requires we use an Extended Basic Rates IE
01241                    for the rates beyond the eighth. */
01242 
01243                 ie->id = IEEE80211_IE_EXT_RATES;
01244                 ie->len = dev->nr_rates - 8;
01245 
01246                 for ( ; i < dev->nr_rates; i++ ) {
01247                         ie->rates[i - 8] = dev->rates[i] / 5;
01248                         if ( dev->basic_rates & ( 1 << i ) )
01249                                 ie->rates[i - 8] |= 0x80;
01250                 }
01251 
01252                 ie = ieee80211_next_ie ( ie, NULL );
01253         }
01254 
01255         if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_VENDOR ) {
01256                 memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
01257                 ie = ieee80211_next_ie ( ie, NULL );
01258         }
01259 
01260         return ie;
01261 }


Generated on Tue Apr 6 20:01:57 2010 for gPXE by  doxygen 1.5.7.1