2007-07-27 17:43:23 +04:00
/*
* Copyright 2002 - 2005 , Instant802 Networks , Inc .
* Copyright 2005 - 2006 , Devicescape Software , Inc .
* Copyright 2006 - 2007 Jiri Benc < jbenc @ suse . cz >
* Copyright 2007 Johannes Berg < johannes @ sipsolutions . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* utilities for mac80211
*/
# include <net/mac80211.h>
# include <linux/netdevice.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/skbuff.h>
# include <linux/etherdevice.h>
# include <linux/if_arp.h>
# include <linux/wireless.h>
# include <linux/bitmap.h>
2007-09-17 22:56:21 +04:00
# include <net/net_namespace.h>
2007-07-27 17:43:23 +04:00
# include <net/cfg80211.h>
2007-11-09 03:57:29 +03:00
# include <net/rtnetlink.h>
2007-07-27 17:43:23 +04:00
# include "ieee80211_i.h"
2008-04-08 23:14:40 +04:00
# include "rate.h"
2008-02-23 17:17:11 +03:00
# include "mesh.h"
2007-07-27 17:43:23 +04:00
# include "wme.h"
/* privid for wiphys to determine whether they belong to us or not */
void * mac80211_wiphy_privid = & mac80211_wiphy_privid ;
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
2008-05-28 21:45:32 +04:00
const unsigned char rfc1042_header [ ] __aligned ( 2 ) =
2007-07-27 17:43:23 +04:00
{ 0xaa , 0xaa , 0x03 , 0x00 , 0x00 , 0x00 } ;
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
2008-05-28 21:45:32 +04:00
const unsigned char bridge_tunnel_header [ ] __aligned ( 2 ) =
2007-07-27 17:43:23 +04:00
{ 0xaa , 0xaa , 0x03 , 0x00 , 0x00 , 0xf8 } ;
2007-12-25 18:00:36 +03:00
u8 * ieee80211_get_bssid ( struct ieee80211_hdr * hdr , size_t len ,
2008-09-11 02:01:58 +04:00
enum nl80211_iftype type )
2007-07-27 17:43:23 +04:00
{
2008-06-12 01:21:58 +04:00
__le16 fc = hdr - > frame_control ;
2007-07-27 17:43:23 +04:00
2007-12-18 18:23:53 +03:00
/* drop ACK/CTS frames and incorrect hdr len (ctrl) */
if ( len < 16 )
2007-07-27 17:43:23 +04:00
return NULL ;
2008-06-12 01:21:58 +04:00
if ( ieee80211_is_data ( fc ) ) {
2007-12-18 18:23:53 +03:00
if ( len < 24 ) /* drop incorrect hdr len (data) */
return NULL ;
2008-06-12 01:21:58 +04:00
if ( ieee80211_has_a4 ( fc ) )
2007-07-27 17:43:23 +04:00
return NULL ;
2008-06-12 01:21:58 +04:00
if ( ieee80211_has_tods ( fc ) )
return hdr - > addr1 ;
if ( ieee80211_has_fromds ( fc ) )
2007-07-27 17:43:23 +04:00
return hdr - > addr2 ;
2008-06-12 01:21:58 +04:00
return hdr - > addr3 ;
}
if ( ieee80211_is_mgmt ( fc ) ) {
2007-12-18 18:23:53 +03:00
if ( len < 24 ) /* drop incorrect hdr len (mgmt) */
return NULL ;
2007-07-27 17:43:23 +04:00
return hdr - > addr3 ;
2008-06-12 01:21:58 +04:00
}
if ( ieee80211_is_ctl ( fc ) ) {
if ( ieee80211_is_pspoll ( fc ) )
2007-07-27 17:43:23 +04:00
return hdr - > addr1 ;
2008-06-12 01:21:58 +04:00
if ( ieee80211_is_back_req ( fc ) ) {
2007-12-25 18:00:36 +03:00
switch ( type ) {
2008-09-11 02:01:58 +04:00
case NL80211_IFTYPE_STATION :
2007-12-25 18:00:36 +03:00
return hdr - > addr2 ;
2008-09-11 02:01:58 +04:00
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_AP_VLAN :
2007-12-25 18:00:36 +03:00
return hdr - > addr1 ;
default :
2008-06-12 01:21:58 +04:00
break ; /* fall through to the return */
2007-12-25 18:00:36 +03:00
}
}
2007-07-27 17:43:23 +04:00
}
return NULL ;
}
2008-06-12 01:21:57 +04:00
unsigned int ieee80211_hdrlen ( __le16 fc )
{
unsigned int hdrlen = 24 ;
if ( ieee80211_is_data ( fc ) ) {
if ( ieee80211_has_a4 ( fc ) )
hdrlen = 30 ;
if ( ieee80211_is_data_qos ( fc ) )
hdrlen + = IEEE80211_QOS_CTL_LEN ;
goto out ;
}
if ( ieee80211_is_ctl ( fc ) ) {
/*
* ACK and CTS are 10 bytes , all others 16. To see how
* to get this condition consider
* subtype mask : 0 b0000000011110000 ( 0x00F0 )
* ACK subtype : 0 b0000000011010000 ( 0x00D0 )
* CTS subtype : 0 b0000000011000000 ( 0x00C0 )
* bits that matter : ^ ^ ^ ( 0x00E0 )
* value of those : 0 b0000000011000000 ( 0x00C0 )
*/
if ( ( fc & cpu_to_le16 ( 0x00E0 ) ) = = cpu_to_le16 ( 0x00C0 ) )
hdrlen = 10 ;
else
hdrlen = 16 ;
}
out :
return hdrlen ;
}
EXPORT_SYMBOL ( ieee80211_hdrlen ) ;
2008-06-12 01:21:57 +04:00
unsigned int ieee80211_get_hdrlen_from_skb ( const struct sk_buff * skb )
2007-07-27 17:43:23 +04:00
{
2008-06-12 01:21:57 +04:00
const struct ieee80211_hdr * hdr = ( const struct ieee80211_hdr * ) skb - > data ;
unsigned int hdrlen ;
2007-07-27 17:43:23 +04:00
if ( unlikely ( skb - > len < 10 ) )
return 0 ;
2008-06-12 01:21:57 +04:00
hdrlen = ieee80211_hdrlen ( hdr - > frame_control ) ;
2007-07-27 17:43:23 +04:00
if ( unlikely ( hdrlen > skb - > len ) )
return 0 ;
return hdrlen ;
}
EXPORT_SYMBOL ( ieee80211_get_hdrlen_from_skb ) ;
2008-02-23 17:17:11 +03:00
int ieee80211_get_mesh_hdrlen ( struct ieee80211s_hdr * meshhdr )
{
int ae = meshhdr - > flags & IEEE80211S_FLAGS_AE ;
/* 7.1.3.5a.2 */
switch ( ae ) {
case 0 :
2008-05-05 23:02:35 +04:00
return 6 ;
2008-02-23 17:17:11 +03:00
case 1 :
2008-05-05 23:02:35 +04:00
return 12 ;
2008-02-23 17:17:11 +03:00
case 2 :
2008-05-05 23:02:35 +04:00
return 18 ;
2008-02-23 17:17:11 +03:00
case 3 :
2008-05-05 23:02:35 +04:00
return 24 ;
2008-02-23 17:17:11 +03:00
default :
2008-05-05 23:02:35 +04:00
return 6 ;
2008-02-23 17:17:11 +03:00
}
}
2008-02-25 18:27:43 +03:00
void ieee80211_tx_set_protected ( struct ieee80211_tx_data * tx )
2007-07-27 17:43:23 +04:00
{
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) tx - > skb - > data ;
hdr - > frame_control | = cpu_to_le16 ( IEEE80211_FCTL_PROTECTED ) ;
2008-02-25 18:27:43 +03:00
if ( tx - > extra_frag ) {
2007-07-27 17:43:23 +04:00
struct ieee80211_hdr * fhdr ;
int i ;
2008-02-25 18:27:43 +03:00
for ( i = 0 ; i < tx - > num_extra_frag ; i + + ) {
2007-07-27 17:43:23 +04:00
fhdr = ( struct ieee80211_hdr * )
2008-02-25 18:27:43 +03:00
tx - > extra_frag [ i ] - > data ;
2007-07-27 17:43:23 +04:00
fhdr - > frame_control | = cpu_to_le16 ( IEEE80211_FCTL_PROTECTED ) ;
}
}
}
int ieee80211_frame_duration ( struct ieee80211_local * local , size_t len ,
int rate , int erp , int short_preamble )
{
int dur ;
/* calculate duration (in microseconds, rounded up to next higher
* integer if it includes a fractional microsecond ) to send frame of
* len bytes ( does not include FCS ) at the given rate . Duration will
* also include SIFS .
*
* rate is in 100 kbps , so divident is multiplied by 10 in the
* DIV_ROUND_UP ( ) operations .
*/
2008-01-24 21:38:38 +03:00
if ( local - > hw . conf . channel - > band = = IEEE80211_BAND_5GHZ | | erp ) {
2007-07-27 17:43:23 +04:00
/*
* OFDM :
*
* N_DBPS = DATARATE x 4
* N_SYM = Ceiling ( ( 16 + 8 xLENGTH + 6 ) / N_DBPS )
* ( 16 = SIGNAL time , 6 = tail bits )
* TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
*
* T_SYM = 4 usec
* 802.11 a - 17.5 .2 : aSIFSTime = 16 usec
* 802.11 g - 19.8 .4 : aSIFSTime = 10 usec +
* signal ext = 6 usec
*/
dur = 16 ; /* SIFS + signal ext */
dur + = 16 ; /* 17.3.2.3: T_PREAMBLE = 16 usec */
dur + = 4 ; /* 17.3.2.3: T_SIGNAL = 4 usec */
dur + = 4 * DIV_ROUND_UP ( ( 16 + 8 * ( len + 4 ) + 6 ) * 10 ,
4 * rate ) ; /* T_SYM x N_SYM */
} else {
/*
* 802.11 b or 802.11 g with 802.11 b compatibility :
* 18.3 .4 : TXTIME = PreambleLength + PLCPHeaderTime +
* Ceiling ( ( ( LENGTH + PBCC ) x8 ) / DATARATE ) . PBCC = 0.
*
* 802.11 ( DS ) : 15.3 .3 , 802.11 b : 18.3 .4
* aSIFSTime = 10 usec
* aPreambleLength = 144 usec or 72 usec with short preamble
* aPLCPHeaderLength = 48 usec or 24 usec with short preamble
*/
dur = 10 ; /* aSIFSTime = 10 usec */
dur + = short_preamble ? ( 72 + 24 ) : ( 144 + 48 ) ;
dur + = DIV_ROUND_UP ( 8 * ( len + 4 ) * 10 , rate ) ;
}
return dur ;
}
/* Exported duration function for driver use */
2007-12-19 03:31:26 +03:00
__le16 ieee80211_generic_frame_duration ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
2008-01-24 21:38:38 +03:00
size_t frame_len ,
struct ieee80211_rate * rate )
2007-07-27 17:43:23 +04:00
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
2008-09-13 00:52:47 +04:00
struct ieee80211_sub_if_data * sdata ;
2007-07-27 17:43:23 +04:00
u16 dur ;
int erp ;
2008-09-13 00:52:47 +04:00
bool short_preamble = false ;
2007-07-27 17:43:23 +04:00
2008-01-24 21:38:38 +03:00
erp = 0 ;
2008-09-13 00:52:47 +04:00
if ( vif ) {
sdata = vif_to_sdata ( vif ) ;
short_preamble = sdata - > bss_conf . use_short_preamble ;
if ( sdata - > flags & IEEE80211_SDATA_OPERATING_GMODE )
erp = rate - > flags & IEEE80211_RATE_ERP_G ;
}
2008-01-24 21:38:38 +03:00
dur = ieee80211_frame_duration ( local , frame_len , rate - > bitrate , erp ,
2008-09-13 00:52:47 +04:00
short_preamble ) ;
2007-07-27 17:43:23 +04:00
return cpu_to_le16 ( dur ) ;
}
EXPORT_SYMBOL ( ieee80211_generic_frame_duration ) ;
2007-12-19 03:31:26 +03:00
__le16 ieee80211_rts_duration ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif , size_t frame_len ,
2008-05-15 14:55:29 +04:00
const struct ieee80211_tx_info * frame_txctl )
2007-07-27 17:43:23 +04:00
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_rate * rate ;
2008-09-13 00:52:47 +04:00
struct ieee80211_sub_if_data * sdata ;
2007-12-28 16:32:58 +03:00
bool short_preamble ;
2007-07-27 17:43:23 +04:00
int erp ;
u16 dur ;
2008-05-15 14:55:27 +04:00
struct ieee80211_supported_band * sband ;
sband = local - > hw . wiphy - > bands [ local - > hw . conf . channel - > band ] ;
2007-07-27 17:43:23 +04:00
2008-09-13 00:52:47 +04:00
short_preamble = false ;
2007-07-27 17:43:24 +04:00
2008-05-15 14:55:29 +04:00
rate = & sband - > bitrates [ frame_txctl - > control . rts_cts_rate_idx ] ;
2008-01-24 21:38:38 +03:00
erp = 0 ;
2008-09-13 00:52:47 +04:00
if ( vif ) {
sdata = vif_to_sdata ( vif ) ;
short_preamble = sdata - > bss_conf . use_short_preamble ;
if ( sdata - > flags & IEEE80211_SDATA_OPERATING_GMODE )
erp = rate - > flags & IEEE80211_RATE_ERP_G ;
}
2007-07-27 17:43:23 +04:00
/* CTS duration */
2008-01-24 21:38:38 +03:00
dur = ieee80211_frame_duration ( local , 10 , rate - > bitrate ,
2007-07-27 17:43:23 +04:00
erp , short_preamble ) ;
/* Data frame duration */
2008-01-24 21:38:38 +03:00
dur + = ieee80211_frame_duration ( local , frame_len , rate - > bitrate ,
2007-07-27 17:43:23 +04:00
erp , short_preamble ) ;
/* ACK duration */
2008-01-24 21:38:38 +03:00
dur + = ieee80211_frame_duration ( local , 10 , rate - > bitrate ,
2007-07-27 17:43:23 +04:00
erp , short_preamble ) ;
return cpu_to_le16 ( dur ) ;
}
EXPORT_SYMBOL ( ieee80211_rts_duration ) ;
2007-12-19 03:31:26 +03:00
__le16 ieee80211_ctstoself_duration ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
2007-07-27 17:43:23 +04:00
size_t frame_len ,
2008-05-15 14:55:29 +04:00
const struct ieee80211_tx_info * frame_txctl )
2007-07-27 17:43:23 +04:00
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_rate * rate ;
2008-09-13 00:52:47 +04:00
struct ieee80211_sub_if_data * sdata ;
2007-12-28 16:32:58 +03:00
bool short_preamble ;
2007-07-27 17:43:23 +04:00
int erp ;
u16 dur ;
2008-05-15 14:55:27 +04:00
struct ieee80211_supported_band * sband ;
sband = local - > hw . wiphy - > bands [ local - > hw . conf . channel - > band ] ;
2007-07-27 17:43:23 +04:00
2008-09-13 00:52:47 +04:00
short_preamble = false ;
2007-07-27 17:43:24 +04:00
2008-05-15 14:55:29 +04:00
rate = & sband - > bitrates [ frame_txctl - > control . rts_cts_rate_idx ] ;
2008-01-24 21:38:38 +03:00
erp = 0 ;
2008-09-13 00:52:47 +04:00
if ( vif ) {
sdata = vif_to_sdata ( vif ) ;
short_preamble = sdata - > bss_conf . use_short_preamble ;
if ( sdata - > flags & IEEE80211_SDATA_OPERATING_GMODE )
erp = rate - > flags & IEEE80211_RATE_ERP_G ;
}
2007-07-27 17:43:23 +04:00
/* Data frame duration */
2008-01-24 21:38:38 +03:00
dur = ieee80211_frame_duration ( local , frame_len , rate - > bitrate ,
2007-07-27 17:43:23 +04:00
erp , short_preamble ) ;
2008-05-15 14:55:29 +04:00
if ( ! ( frame_txctl - > flags & IEEE80211_TX_CTL_NO_ACK ) ) {
2007-07-27 17:43:23 +04:00
/* ACK duration */
2008-01-24 21:38:38 +03:00
dur + = ieee80211_frame_duration ( local , 10 , rate - > bitrate ,
2007-07-27 17:43:23 +04:00
erp , short_preamble ) ;
}
return cpu_to_le16 ( dur ) ;
}
EXPORT_SYMBOL ( ieee80211_ctstoself_duration ) ;
void ieee80211_wake_queue ( struct ieee80211_hw * hw , int queue )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
2008-05-17 02:57:14 +04:00
if ( test_bit ( queue , local - > queues_pending ) ) {
2008-07-24 19:46:44 +04:00
set_bit ( queue , local - > queues_pending_run ) ;
2008-05-17 02:57:14 +04:00
tasklet_schedule ( & local - > tx_pending_tasklet ) ;
} else {
2008-07-15 14:34:57 +04:00
netif_wake_subqueue ( local - > mdev , queue ) ;
2007-07-27 17:43:23 +04:00
}
}
EXPORT_SYMBOL ( ieee80211_wake_queue ) ;
void ieee80211_stop_queue ( struct ieee80211_hw * hw , int queue )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
2008-07-15 14:34:57 +04:00
netif_stop_subqueue ( local - > mdev , queue ) ;
2007-07-27 17:43:23 +04:00
}
EXPORT_SYMBOL ( ieee80211_stop_queue ) ;
void ieee80211_stop_queues ( struct ieee80211_hw * hw )
{
int i ;
2008-05-17 02:57:14 +04:00
for ( i = 0 ; i < ieee80211_num_queues ( hw ) ; i + + )
2007-07-27 17:43:23 +04:00
ieee80211_stop_queue ( hw , i ) ;
}
EXPORT_SYMBOL ( ieee80211_stop_queues ) ;
2008-07-24 22:02:04 +04:00
int ieee80211_queue_stopped ( struct ieee80211_hw * hw , int queue )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
return __netif_subqueue_stopped ( local - > mdev , queue ) ;
}
EXPORT_SYMBOL ( ieee80211_queue_stopped ) ;
2007-07-27 17:43:23 +04:00
void ieee80211_wake_queues ( struct ieee80211_hw * hw )
{
int i ;
2008-05-15 14:55:25 +04:00
for ( i = 0 ; i < hw - > queues + hw - > ampdu_queues ; i + + )
2007-07-27 17:43:23 +04:00
ieee80211_wake_queue ( hw , i ) ;
}
EXPORT_SYMBOL ( ieee80211_wake_queues ) ;
2007-11-09 03:57:29 +03:00
2007-12-19 03:31:26 +03:00
void ieee80211_iterate_active_interfaces (
struct ieee80211_hw * hw ,
void ( * iterator ) ( void * data , u8 * mac ,
struct ieee80211_vif * vif ) ,
void * data )
2007-11-09 03:57:29 +03:00
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_sub_if_data * sdata ;
2008-05-10 15:40:49 +04:00
rtnl_lock ( ) ;
list_for_each_entry ( sdata , & local - > interfaces , list ) {
switch ( sdata - > vif . type ) {
2008-09-11 02:01:58 +04:00
case __NL80211_IFTYPE_AFTER_LAST :
case NL80211_IFTYPE_UNSPECIFIED :
case NL80211_IFTYPE_MONITOR :
case NL80211_IFTYPE_AP_VLAN :
2008-05-10 15:40:49 +04:00
continue ;
2008-09-11 02:01:58 +04:00
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_ADHOC :
case NL80211_IFTYPE_WDS :
case NL80211_IFTYPE_MESH_POINT :
2008-05-10 15:40:49 +04:00
break ;
}
if ( netif_running ( sdata - > dev ) )
iterator ( data , sdata - > dev - > dev_addr ,
& sdata - > vif ) ;
}
rtnl_unlock ( ) ;
}
EXPORT_SYMBOL_GPL ( ieee80211_iterate_active_interfaces ) ;
void ieee80211_iterate_active_interfaces_atomic (
struct ieee80211_hw * hw ,
void ( * iterator ) ( void * data , u8 * mac ,
struct ieee80211_vif * vif ) ,
void * data )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_sub_if_data * sdata ;
2007-11-28 12:55:32 +03:00
rcu_read_lock ( ) ;
2007-11-09 03:57:29 +03:00
2007-11-28 12:55:32 +03:00
list_for_each_entry_rcu ( sdata , & local - > interfaces , list ) {
2007-12-19 03:31:27 +03:00
switch ( sdata - > vif . type ) {
2008-09-11 02:01:58 +04:00
case __NL80211_IFTYPE_AFTER_LAST :
case NL80211_IFTYPE_UNSPECIFIED :
case NL80211_IFTYPE_MONITOR :
case NL80211_IFTYPE_AP_VLAN :
2007-11-09 03:57:29 +03:00
continue ;
2008-09-11 02:01:58 +04:00
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_ADHOC :
case NL80211_IFTYPE_WDS :
case NL80211_IFTYPE_MESH_POINT :
2007-11-09 03:57:29 +03:00
break ;
}
if ( netif_running ( sdata - > dev ) )
iterator ( data , sdata - > dev - > dev_addr ,
2007-12-19 03:31:26 +03:00
& sdata - > vif ) ;
2007-11-09 03:57:29 +03:00
}
2007-11-28 12:55:32 +03:00
rcu_read_unlock ( ) ;
2007-11-09 03:57:29 +03:00
}
2008-05-10 15:40:49 +04:00
EXPORT_SYMBOL_GPL ( ieee80211_iterate_active_interfaces_atomic ) ;
2008-09-08 18:40:36 +04:00
void ieee802_11_parse_elems ( u8 * start , size_t len ,
struct ieee802_11_elems * elems )
{
size_t left = len ;
u8 * pos = start ;
memset ( elems , 0 , sizeof ( * elems ) ) ;
elems - > ie_start = start ;
elems - > total_len = len ;
while ( left > = 2 ) {
u8 id , elen ;
id = * pos + + ;
elen = * pos + + ;
left - = 2 ;
if ( elen > left )
return ;
switch ( id ) {
case WLAN_EID_SSID :
elems - > ssid = pos ;
elems - > ssid_len = elen ;
break ;
case WLAN_EID_SUPP_RATES :
elems - > supp_rates = pos ;
elems - > supp_rates_len = elen ;
break ;
case WLAN_EID_FH_PARAMS :
elems - > fh_params = pos ;
elems - > fh_params_len = elen ;
break ;
case WLAN_EID_DS_PARAMS :
elems - > ds_params = pos ;
elems - > ds_params_len = elen ;
break ;
case WLAN_EID_CF_PARAMS :
elems - > cf_params = pos ;
elems - > cf_params_len = elen ;
break ;
case WLAN_EID_TIM :
elems - > tim = pos ;
elems - > tim_len = elen ;
break ;
case WLAN_EID_IBSS_PARAMS :
elems - > ibss_params = pos ;
elems - > ibss_params_len = elen ;
break ;
case WLAN_EID_CHALLENGE :
elems - > challenge = pos ;
elems - > challenge_len = elen ;
break ;
case WLAN_EID_WPA :
if ( elen > = 4 & & pos [ 0 ] = = 0x00 & & pos [ 1 ] = = 0x50 & &
pos [ 2 ] = = 0xf2 ) {
/* Microsoft OUI (00:50:F2) */
if ( pos [ 3 ] = = 1 ) {
/* OUI Type 1 - WPA IE */
elems - > wpa = pos ;
elems - > wpa_len = elen ;
} else if ( elen > = 5 & & pos [ 3 ] = = 2 ) {
if ( pos [ 4 ] = = 0 ) {
elems - > wmm_info = pos ;
elems - > wmm_info_len = elen ;
} else if ( pos [ 4 ] = = 1 ) {
elems - > wmm_param = pos ;
elems - > wmm_param_len = elen ;
}
}
}
break ;
case WLAN_EID_RSN :
elems - > rsn = pos ;
elems - > rsn_len = elen ;
break ;
case WLAN_EID_ERP_INFO :
elems - > erp_info = pos ;
elems - > erp_info_len = elen ;
break ;
case WLAN_EID_EXT_SUPP_RATES :
elems - > ext_supp_rates = pos ;
elems - > ext_supp_rates_len = elen ;
break ;
case WLAN_EID_HT_CAPABILITY :
2008-10-07 21:31:17 +04:00
if ( elen > = sizeof ( struct ieee80211_ht_cap ) )
elems - > ht_cap_elem = ( void * ) pos ;
2008-09-08 18:40:36 +04:00
break ;
2008-10-09 14:13:49 +04:00
case WLAN_EID_HT_INFORMATION :
if ( elen > = sizeof ( struct ieee80211_ht_info ) )
2008-10-07 21:31:17 +04:00
elems - > ht_info_elem = ( void * ) pos ;
2008-09-08 18:40:36 +04:00
break ;
case WLAN_EID_MESH_ID :
elems - > mesh_id = pos ;
elems - > mesh_id_len = elen ;
break ;
case WLAN_EID_MESH_CONFIG :
elems - > mesh_config = pos ;
elems - > mesh_config_len = elen ;
break ;
case WLAN_EID_PEER_LINK :
elems - > peer_link = pos ;
elems - > peer_link_len = elen ;
break ;
case WLAN_EID_PREQ :
elems - > preq = pos ;
elems - > preq_len = elen ;
break ;
case WLAN_EID_PREP :
elems - > prep = pos ;
elems - > prep_len = elen ;
break ;
case WLAN_EID_PERR :
elems - > perr = pos ;
elems - > perr_len = elen ;
break ;
case WLAN_EID_CHANNEL_SWITCH :
elems - > ch_switch_elem = pos ;
elems - > ch_switch_elem_len = elen ;
break ;
case WLAN_EID_QUIET :
if ( ! elems - > quiet_elem ) {
elems - > quiet_elem = pos ;
elems - > quiet_elem_len = elen ;
}
elems - > num_of_quiet_elem + + ;
break ;
case WLAN_EID_COUNTRY :
elems - > country_elem = pos ;
elems - > country_elem_len = elen ;
break ;
case WLAN_EID_PWR_CONSTRAINT :
elems - > pwr_constr_elem = pos ;
elems - > pwr_constr_elem_len = elen ;
break ;
default :
break ;
}
left - = elen ;
pos + = elen ;
}
}
2008-09-09 14:56:01 +04:00
void ieee80211_set_wmm_default ( struct ieee80211_sub_if_data * sdata )
{
struct ieee80211_local * local = sdata - > local ;
struct ieee80211_tx_queue_params qparam ;
int i ;
if ( ! local - > ops - > conf_tx )
return ;
memset ( & qparam , 0 , sizeof ( qparam ) ) ;
qparam . aifs = 2 ;
if ( local - > hw . conf . channel - > band = = IEEE80211_BAND_2GHZ & &
! ( sdata - > flags & IEEE80211_SDATA_OPERATING_GMODE ) )
qparam . cw_min = 31 ;
else
qparam . cw_min = 15 ;
qparam . cw_max = 1023 ;
qparam . txop = 0 ;
for ( i = 0 ; i < local_to_hw ( local ) - > queues ; i + + )
local - > ops - > conf_tx ( local_to_hw ( local ) , i , & qparam ) ;
}
2008-09-09 17:07:09 +04:00
void ieee80211_tx_skb ( struct ieee80211_sub_if_data * sdata , struct sk_buff * skb ,
int encrypt )
{
skb - > dev = sdata - > local - > mdev ;
skb_set_mac_header ( skb , 0 ) ;
skb_set_network_header ( skb , 0 ) ;
skb_set_transport_header ( skb , 0 ) ;
skb - > iif = sdata - > dev - > ifindex ;
skb - > do_not_encrypt = ! encrypt ;
dev_queue_xmit ( skb ) ;
}
2008-09-11 02:01:53 +04:00
int ieee80211_set_freq ( struct ieee80211_sub_if_data * sdata , int freqMHz )
{
int ret = - EINVAL ;
struct ieee80211_channel * chan ;
struct ieee80211_local * local = sdata - > local ;
chan = ieee80211_get_channel ( local - > hw . wiphy , freqMHz ) ;
if ( chan & & ! ( chan - > flags & IEEE80211_CHAN_DISABLED ) ) {
2008-09-11 02:01:58 +04:00
if ( sdata - > vif . type = = NL80211_IFTYPE_ADHOC & &
2008-10-07 14:04:34 +04:00
chan - > flags & IEEE80211_CHAN_NO_IBSS )
2008-09-11 02:01:53 +04:00
return ret ;
local - > oper_channel = chan ;
2008-09-11 02:01:55 +04:00
if ( local - > sw_scanning | | local - > hw_scanning )
2008-09-11 02:01:53 +04:00
ret = 0 ;
else
2008-10-09 14:18:51 +04:00
ret = ieee80211_hw_config (
local , IEEE80211_CONF_CHANGE_CHANNEL ) ;
2008-09-11 02:01:53 +04:00
rate_control_clear ( local ) ;
}
return ret ;
}
2008-09-11 02:01:57 +04:00
u64 ieee80211_mandatory_rates ( struct ieee80211_local * local ,
enum ieee80211_band band )
{
struct ieee80211_supported_band * sband ;
struct ieee80211_rate * bitrates ;
u64 mandatory_rates ;
enum ieee80211_rate_flags mandatory_flag ;
int i ;
sband = local - > hw . wiphy - > bands [ band ] ;
if ( ! sband ) {
WARN_ON ( 1 ) ;
sband = local - > hw . wiphy - > bands [ local - > hw . conf . channel - > band ] ;
}
if ( band = = IEEE80211_BAND_2GHZ )
mandatory_flag = IEEE80211_RATE_MANDATORY_B ;
else
mandatory_flag = IEEE80211_RATE_MANDATORY_A ;
bitrates = sband - > bitrates ;
mandatory_rates = 0 ;
for ( i = 0 ; i < sband - > n_bitrates ; i + + )
if ( bitrates [ i ] . flags & mandatory_flag )
mandatory_rates | = BIT ( i ) ;
return mandatory_rates ;
}