2007-02-10 12:25:27 -02:00
/* Copyright (C) 2006, Red Hat, Inc. */
2008-09-24 18:13:14 -04:00
# include <linux/types.h>
2007-05-25 17:28:30 -04:00
# include <linux/etherdevice.h>
2008-09-24 18:13:14 -04:00
# include <net/lib80211.h>
2007-02-10 12:25:27 -02:00
# include "assoc.h"
# include "decl.h"
# include "host.h"
2008-04-02 16:27:42 +02:00
# include "scan.h"
2007-12-11 16:54:15 -05:00
# include "cmd.h"
2007-02-10 12:25:27 -02:00
2008-08-21 21:46:59 -04:00
static int lbs_adhoc_post ( struct lbs_private * priv , struct cmd_header * resp ) ;
2007-02-10 12:25:27 -02:00
2008-01-25 14:15:00 +01:00
static const u8 bssid_any [ ETH_ALEN ] __attribute__ ( ( aligned ( 2 ) ) ) =
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
static const u8 bssid_off [ ETH_ALEN ] __attribute__ ( ( aligned ( 2 ) ) ) =
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2007-02-10 12:25:27 -02:00
2008-04-02 16:27:10 +02:00
/* The firmware needs certain bits masked out of the beacon-derviced capability
* field when associating / joining to BSSs .
*/
# define CAPINFO_MASK (~(0xda00))
2008-08-21 21:46:59 -04:00
/**
* @ brief This function finds common rates between rates and card rates .
*
* It will fill common rates in rates as output if found .
*
* NOTE : Setting the MSB of the basic rates need to be taken
* care , either before or after calling this function
*
* @ param priv A pointer to struct lbs_private structure
* @ param rates the buffer which keeps input and output
* @ param rates_size the size of rate1 buffer ; new size of buffer on return
*
* @ return 0 on success , or - 1 on error
*/
static int get_common_rates ( struct lbs_private * priv ,
u8 * rates ,
u16 * rates_size )
{
u8 * card_rates = lbs_bg_rates ;
size_t num_card_rates = sizeof ( lbs_bg_rates ) ;
int ret = 0 , i , j ;
u8 tmp [ 30 ] ;
size_t tmp_size = 0 ;
/* For each rate in card_rates that exists in rate1, copy to tmp */
for ( i = 0 ; card_rates [ i ] & & ( i < num_card_rates ) ; i + + ) {
for ( j = 0 ; rates [ j ] & & ( j < * rates_size ) ; j + + ) {
if ( rates [ j ] = = card_rates [ i ] )
tmp [ tmp_size + + ] = card_rates [ i ] ;
}
}
lbs_deb_hex ( LBS_DEB_JOIN , " AP rates " , rates , * rates_size ) ;
lbs_deb_hex ( LBS_DEB_JOIN , " card rates " , card_rates , num_card_rates ) ;
lbs_deb_hex ( LBS_DEB_JOIN , " common rates " , tmp , tmp_size ) ;
lbs_deb_join ( " TX data rate 0x%02x \n " , priv - > cur_rate ) ;
if ( ! priv - > enablehwauto ) {
for ( i = 0 ; i < tmp_size ; i + + ) {
if ( tmp [ i ] = = priv - > cur_rate )
goto done ;
}
lbs_pr_alert ( " Previously set fixed data rate %#x isn't "
" compatible with the network. \n " , priv - > cur_rate ) ;
ret = - 1 ;
goto done ;
}
ret = 0 ;
done :
memset ( rates , 0 , * rates_size ) ;
* rates_size = min_t ( int , tmp_size , * rates_size ) ;
memcpy ( rates , tmp , * rates_size ) ;
return ret ;
}
/**
* @ brief Sets the MSB on basic rates as the firmware requires
*
* Scan through an array and set the MSB for basic data rates .
*
* @ param rates buffer of data rates
* @ param len size of buffer
*/
static void lbs_set_basic_rate_flags ( u8 * rates , size_t len )
{
int i ;
for ( i = 0 ; i < len ; i + + ) {
if ( rates [ i ] = = 0x02 | | rates [ i ] = = 0x04 | |
rates [ i ] = = 0x0b | | rates [ i ] = = 0x16 )
rates [ i ] | = 0x80 ;
}
}
2008-04-02 16:27:10 +02:00
/**
* @ brief Associate to a specific BSS discovered in a scan
*
* @ param priv A pointer to struct lbs_private structure
2008-08-21 17:51:07 -04:00
* @ param assoc_req The association request describing the BSS to associate with
2008-04-02 16:27:10 +02:00
*
* @ return 0 - success , otherwise fail
*/
static int lbs_associate ( struct lbs_private * priv ,
struct assoc_request * assoc_req )
{
int ret ;
2008-08-21 17:51:07 -04:00
u8 preamble = RADIO_PREAMBLE_LONG ;
2008-04-02 16:27:10 +02:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_AUTHENTICATE ,
0 , CMD_OPTION_WAITFORRSP ,
0 , assoc_req - > bss . bssid ) ;
if ( ret )
2008-08-21 17:51:07 -04:00
goto out ;
2008-04-02 16:27:10 +02:00
2008-08-21 17:51:07 -04:00
/* Use short preamble only when both the BSS and firmware support it */
2008-04-02 16:27:10 +02:00
if ( ( priv - > capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) & &
( assoc_req - > bss . capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) )
2008-08-21 17:51:07 -04:00
preamble = RADIO_PREAMBLE_SHORT ;
2008-04-02 16:27:10 +02:00
2008-08-21 17:51:07 -04:00
ret = lbs_set_radio ( priv , preamble , 1 ) ;
if ( ret )
goto out ;
2008-04-02 16:27:10 +02:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_ASSOCIATE ,
0 , CMD_OPTION_WAITFORRSP , 0 , assoc_req ) ;
2008-08-21 17:51:07 -04:00
out :
2008-04-02 16:27:10 +02:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
}
/**
* @ brief Join an adhoc network found in a previous scan
*
* @ param priv A pointer to struct lbs_private structure
2008-08-21 17:51:07 -04:00
* @ param assoc_req The association request describing the BSS to join
2008-04-02 16:27:10 +02:00
*
2008-08-21 21:46:59 -04:00
* @ return 0 on success , error on failure
2008-04-02 16:27:10 +02:00
*/
2008-08-21 21:46:59 -04:00
static int lbs_adhoc_join ( struct lbs_private * priv ,
2008-04-02 16:27:10 +02:00
struct assoc_request * assoc_req )
{
2008-08-21 21:46:59 -04:00
struct cmd_ds_802_11_ad_hoc_join cmd ;
2008-04-02 16:27:10 +02:00
struct bss_descriptor * bss = & assoc_req - > bss ;
2008-08-21 17:51:07 -04:00
u8 preamble = RADIO_PREAMBLE_LONG ;
2008-08-21 21:46:59 -04:00
u16 ratesize = 0 ;
int ret = 0 ;
2008-08-21 17:51:07 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2008-04-02 16:27:10 +02:00
lbs_deb_join ( " current SSID '%s', ssid length %u \n " ,
2008-09-24 18:13:14 -04:00
escape_ssid ( priv - > curbssparams . ssid ,
2008-04-02 16:27:10 +02:00
priv - > curbssparams . ssid_len ) ,
priv - > curbssparams . ssid_len ) ;
lbs_deb_join ( " requested ssid '%s', ssid length %u \n " ,
2008-09-24 18:13:14 -04:00
escape_ssid ( bss - > ssid , bss - > ssid_len ) ,
2008-04-02 16:27:10 +02:00
bss - > ssid_len ) ;
/* check if the requested SSID is already joined */
if ( priv - > curbssparams . ssid_len & &
! lbs_ssid_cmp ( priv - > curbssparams . ssid ,
priv - > curbssparams . ssid_len ,
bss - > ssid , bss - > ssid_len ) & &
( priv - > mode = = IW_MODE_ADHOC ) & &
( priv - > connect_status = = LBS_CONNECTED ) ) {
union iwreq_data wrqu ;
lbs_deb_join ( " ADHOC_J_CMD: New ad-hoc SSID is the same as "
" current, not attempting to re-join " ) ;
/* Send the re-association event though, because the association
* request really was successful , even if just a null - op .
*/
memset ( & wrqu , 0 , sizeof ( wrqu ) ) ;
memcpy ( wrqu . ap_addr . sa_data , priv - > curbssparams . bssid ,
ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > dev , SIOCGIWAP , & wrqu , NULL ) ;
goto out ;
}
2008-08-21 17:51:07 -04:00
/* Use short preamble only when both the BSS and firmware support it */
if ( ( priv - > capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) & &
( bss - > capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) ) {
2008-04-02 16:27:10 +02:00
lbs_deb_join ( " AdhocJoin: Short preamble \n " ) ;
2008-08-21 17:51:07 -04:00
preamble = RADIO_PREAMBLE_SHORT ;
2008-04-02 16:27:10 +02:00
}
2008-08-21 17:51:07 -04:00
ret = lbs_set_radio ( priv , preamble , 1 ) ;
if ( ret )
goto out ;
2008-04-02 16:27:10 +02:00
lbs_deb_join ( " AdhocJoin: channel = %d \n " , assoc_req - > channel ) ;
lbs_deb_join ( " AdhocJoin: band = %c \n " , assoc_req - > band ) ;
priv - > adhoccreate = 0 ;
2008-08-21 21:46:59 -04:00
priv - > curbssparams . channel = bss - > channel ;
2008-04-02 16:27:10 +02:00
2008-08-21 21:46:59 -04:00
/* Build the join command */
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . bss . type = CMD_BSS_TYPE_IBSS ;
cmd . bss . beaconperiod = cpu_to_le16 ( bss - > beaconperiod ) ;
memcpy ( & cmd . bss . bssid , & bss - > bssid , ETH_ALEN ) ;
memcpy ( & cmd . bss . ssid , & bss - > ssid , bss - > ssid_len ) ;
memcpy ( & cmd . bss . phyparamset , & bss - > phyparamset ,
sizeof ( union ieeetypes_phyparamset ) ) ;
memcpy ( & cmd . bss . ssparamset , & bss - > ssparamset ,
sizeof ( union IEEEtypes_ssparamset ) ) ;
cmd . bss . capability = cpu_to_le16 ( bss - > capability & CAPINFO_MASK ) ;
lbs_deb_join ( " ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X \n " ,
bss - > capability , CAPINFO_MASK ) ;
/* information on BSSID descriptor passed to FW */
2008-10-27 15:59:26 -07:00
lbs_deb_join ( " ADHOC_J_CMD: BSSID = %pM, SSID = '%s' \n " ,
cmd . bss . bssid , cmd . bss . ssid ) ;
2008-08-21 21:46:59 -04:00
/* Only v8 and below support setting these */
if ( priv - > fwrelease < 0x09000000 ) {
/* failtimeout */
cmd . failtimeout = cpu_to_le16 ( MRVDRV_ASSOCIATION_TIME_OUT ) ;
/* probedelay */
cmd . probedelay = cpu_to_le16 ( CMD_SCAN_PROBE_DELAY_TIME ) ;
}
/* Copy Data rates from the rates recorded in scan response */
memset ( cmd . bss . rates , 0 , sizeof ( cmd . bss . rates ) ) ;
ratesize = min_t ( u16 , sizeof ( cmd . bss . rates ) , MAX_RATES ) ;
memcpy ( cmd . bss . rates , bss - > rates , ratesize ) ;
if ( get_common_rates ( priv , cmd . bss . rates , & ratesize ) ) {
lbs_deb_join ( " ADHOC_JOIN: get_common_rates returned error. \n " ) ;
ret = - 1 ;
goto out ;
}
/* Copy the ad-hoc creation rates into Current BSS state structure */
memset ( & priv - > curbssparams . rates , 0 , sizeof ( priv - > curbssparams . rates ) ) ;
memcpy ( & priv - > curbssparams . rates , cmd . bss . rates , ratesize ) ;
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates .
*/
lbs_set_basic_rate_flags ( cmd . bss . rates , ratesize ) ;
cmd . bss . ssparamset . ibssparamset . atimwindow = cpu_to_le16 ( bss - > atimwindow ) ;
if ( assoc_req - > secinfo . wep_enabled ) {
u16 tmp = le16_to_cpu ( cmd . bss . capability ) ;
tmp | = WLAN_CAPABILITY_PRIVACY ;
cmd . bss . capability = cpu_to_le16 ( tmp ) ;
}
if ( priv - > psmode = = LBS802_11POWERMODEMAX_PSP ) {
__le32 local_ps_mode = cpu_to_le32 ( LBS802_11POWERMODECAM ) ;
/* wake up first */
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_PS_MODE ,
CMD_ACT_SET , 0 , 0 ,
& local_ps_mode ) ;
if ( ret ) {
ret = - 1 ;
goto out ;
}
}
if ( lbs_parse_dnld_countryinfo_11d ( priv , bss ) ) {
ret = - 1 ;
goto out ;
}
ret = lbs_cmd_with_response ( priv , CMD_802_11_AD_HOC_JOIN , & cmd ) ;
if ( ret = = 0 )
ret = lbs_adhoc_post ( priv , ( struct cmd_header * ) & cmd ) ;
2008-04-02 16:27:10 +02:00
out :
2008-08-21 17:51:07 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2008-04-02 16:27:10 +02:00
return ret ;
}
/**
* @ brief Start an Adhoc Network
*
* @ param priv A pointer to struct lbs_private structure
2008-08-21 17:51:07 -04:00
* @ param assoc_req The association request describing the BSS to start
2008-08-21 21:46:59 -04:00
*
* @ return 0 on success , error on failure
2008-04-02 16:27:10 +02:00
*/
2008-08-21 21:46:59 -04:00
static int lbs_adhoc_start ( struct lbs_private * priv ,
2008-04-02 16:27:10 +02:00
struct assoc_request * assoc_req )
{
2008-08-21 21:46:59 -04:00
struct cmd_ds_802_11_ad_hoc_start cmd ;
2008-08-21 17:51:07 -04:00
u8 preamble = RADIO_PREAMBLE_LONG ;
2008-08-21 21:46:59 -04:00
size_t ratesize = 0 ;
u16 tmpcap = 0 ;
int ret = 0 ;
2008-08-21 17:51:07 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2008-04-02 16:27:10 +02:00
if ( priv - > capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) {
2008-08-21 21:46:59 -04:00
lbs_deb_join ( " ADHOC_START: Will use short preamble \n " ) ;
2008-08-21 17:51:07 -04:00
preamble = RADIO_PREAMBLE_SHORT ;
2008-04-02 16:27:10 +02:00
}
2008-08-21 17:51:07 -04:00
ret = lbs_set_radio ( priv , preamble , 1 ) ;
if ( ret )
goto out ;
2008-04-02 16:27:10 +02:00
2008-08-21 21:46:59 -04:00
/* Build the start command */
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
2008-04-02 16:27:10 +02:00
2008-08-21 21:46:59 -04:00
memcpy ( cmd . ssid , assoc_req - > ssid , assoc_req - > ssid_len ) ;
lbs_deb_join ( " ADHOC_START: SSID '%s', ssid length %u \n " ,
2008-09-24 18:13:14 -04:00
escape_ssid ( assoc_req - > ssid , assoc_req - > ssid_len ) ,
2008-08-21 21:46:59 -04:00
assoc_req - > ssid_len ) ;
cmd . bsstype = CMD_BSS_TYPE_IBSS ;
if ( priv - > beacon_period = = 0 )
priv - > beacon_period = MRVDRV_BEACON_INTERVAL ;
cmd . beaconperiod = cpu_to_le16 ( priv - > beacon_period ) ;
WARN_ON ( ! assoc_req - > channel ) ;
/* set Physical parameter set */
cmd . phyparamset . dsparamset . elementid = MFIE_TYPE_DS_SET ;
cmd . phyparamset . dsparamset . len = 1 ;
cmd . phyparamset . dsparamset . currentchan = assoc_req - > channel ;
/* set IBSS parameter set */
cmd . ssparamset . ibssparamset . elementid = MFIE_TYPE_IBSS_SET ;
cmd . ssparamset . ibssparamset . len = 2 ;
cmd . ssparamset . ibssparamset . atimwindow = 0 ;
/* set capability info */
tmpcap = WLAN_CAPABILITY_IBSS ;
if ( assoc_req - > secinfo . wep_enabled ) {
lbs_deb_join ( " ADHOC_START: WEP enabled, setting privacy on \n " ) ;
tmpcap | = WLAN_CAPABILITY_PRIVACY ;
} else
lbs_deb_join ( " ADHOC_START: WEP disabled, setting privacy off \n " ) ;
cmd . capability = cpu_to_le16 ( tmpcap ) ;
/* Only v8 and below support setting probe delay */
if ( priv - > fwrelease < 0x09000000 )
cmd . probedelay = cpu_to_le16 ( CMD_SCAN_PROBE_DELAY_TIME ) ;
ratesize = min ( sizeof ( cmd . rates ) , sizeof ( lbs_bg_rates ) ) ;
memcpy ( cmd . rates , lbs_bg_rates , ratesize ) ;
/* Copy the ad-hoc creating rates into Current BSS state structure */
memset ( & priv - > curbssparams . rates , 0 , sizeof ( priv - > curbssparams . rates ) ) ;
memcpy ( & priv - > curbssparams . rates , & cmd . rates , ratesize ) ;
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates .
*/
lbs_set_basic_rate_flags ( cmd . rates , ratesize ) ;
lbs_deb_join ( " ADHOC_START: rates=%02x %02x %02x %02x \n " ,
cmd . rates [ 0 ] , cmd . rates [ 1 ] , cmd . rates [ 2 ] , cmd . rates [ 3 ] ) ;
if ( lbs_create_dnld_countryinfo_11d ( priv ) ) {
lbs_deb_join ( " ADHOC_START: dnld_countryinfo_11d failed \n " ) ;
ret = - 1 ;
goto out ;
}
lbs_deb_join ( " ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d \n " ,
assoc_req - > channel , assoc_req - > band ) ;
priv - > adhoccreate = 1 ;
priv - > mode = IW_MODE_ADHOC ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_AD_HOC_START , & cmd ) ;
if ( ret = = 0 )
ret = lbs_adhoc_post ( priv , ( struct cmd_header * ) & cmd ) ;
2008-04-02 16:27:10 +02:00
2008-08-21 17:51:07 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2008-04-02 16:27:10 +02:00
return ret ;
}
2008-08-21 21:46:59 -04:00
/**
* @ brief Stop and Ad - Hoc network and exit Ad - Hoc mode
*
* @ param priv A pointer to struct lbs_private structure
* @ return 0 on success , or an error
*/
int lbs_adhoc_stop ( struct lbs_private * priv )
2008-04-02 16:27:10 +02:00
{
2008-08-21 21:46:59 -04:00
struct cmd_ds_802_11_ad_hoc_stop cmd ;
int ret ;
lbs_deb_enter ( LBS_DEB_JOIN ) ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_AD_HOC_STOP , & cmd ) ;
/* Clean up everything even if there was an error */
lbs_mac_event_disconnected ( priv ) ;
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
2008-04-02 16:27:10 +02:00
}
2007-05-25 17:09:41 -04:00
2008-04-02 16:27:42 +02:00
static inline int match_bss_no_security ( struct lbs_802_11_security * secinfo ,
struct bss_descriptor * match_bss )
{
if ( ! secinfo - > wep_enabled & & ! secinfo - > WPAenabled
& & ! secinfo - > WPA2enabled
& & match_bss - > wpa_ie [ 0 ] ! = MFIE_TYPE_GENERIC
& & match_bss - > rsn_ie [ 0 ] ! = MFIE_TYPE_RSN
& & ! ( match_bss - > capability & WLAN_CAPABILITY_PRIVACY ) )
return 1 ;
else
return 0 ;
}
static inline int match_bss_static_wep ( struct lbs_802_11_security * secinfo ,
struct bss_descriptor * match_bss )
{
if ( secinfo - > wep_enabled & & ! secinfo - > WPAenabled
& & ! secinfo - > WPA2enabled
& & ( match_bss - > capability & WLAN_CAPABILITY_PRIVACY ) )
return 1 ;
else
return 0 ;
}
static inline int match_bss_wpa ( struct lbs_802_11_security * secinfo ,
struct bss_descriptor * match_bss )
{
if ( ! secinfo - > wep_enabled & & secinfo - > WPAenabled
& & ( match_bss - > wpa_ie [ 0 ] = = MFIE_TYPE_GENERIC )
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
& & ( match_bss - > capability & WLAN_CAPABILITY_PRIVACY ) */
)
return 1 ;
else
return 0 ;
}
static inline int match_bss_wpa2 ( struct lbs_802_11_security * secinfo ,
struct bss_descriptor * match_bss )
{
if ( ! secinfo - > wep_enabled & & secinfo - > WPA2enabled & &
( match_bss - > rsn_ie [ 0 ] = = MFIE_TYPE_RSN )
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
( match_bss - > capability & WLAN_CAPABILITY_PRIVACY ) */
)
return 1 ;
else
return 0 ;
}
static inline int match_bss_dynamic_wep ( struct lbs_802_11_security * secinfo ,
struct bss_descriptor * match_bss )
{
if ( ! secinfo - > wep_enabled & & ! secinfo - > WPAenabled
& & ! secinfo - > WPA2enabled
& & ( match_bss - > wpa_ie [ 0 ] ! = MFIE_TYPE_GENERIC )
& & ( match_bss - > rsn_ie [ 0 ] ! = MFIE_TYPE_RSN )
& & ( match_bss - > capability & WLAN_CAPABILITY_PRIVACY ) )
return 1 ;
else
return 0 ;
}
/**
* @ brief Check if a scanned network compatible with the driver settings
*
* WEP WPA WPA2 ad - hoc encrypt Network
* enabled enabled enabled AES mode privacy WPA WPA2 Compatible
* 0 0 0 0 NONE 0 0 0 yes No security
* 1 0 0 0 NONE 1 0 0 yes Static WEP
* 0 1 0 0 x 1 x 1 x yes WPA
* 0 0 1 0 x 1 x x 1 yes WPA2
* 0 0 0 1 NONE 1 0 0 yes Ad - hoc AES
* 0 0 0 0 ! = NONE 1 0 0 yes Dynamic WEP
*
*
* @ param priv A pointer to struct lbs_private
* @ param index Index in scantable to check against current driver settings
* @ param mode Network mode : Infrastructure or IBSS
*
* @ return Index in scantable , or error code if negative
*/
static int is_network_compatible ( struct lbs_private * priv ,
struct bss_descriptor * bss , uint8_t mode )
{
int matched = 0 ;
lbs_deb_enter ( LBS_DEB_SCAN ) ;
if ( bss - > mode ! = mode )
goto done ;
matched = match_bss_no_security ( & priv - > secinfo , bss ) ;
if ( matched )
goto done ;
matched = match_bss_static_wep ( & priv - > secinfo , bss ) ;
if ( matched )
goto done ;
matched = match_bss_wpa ( & priv - > secinfo , bss ) ;
if ( matched ) {
lbs_deb_scan ( " is_network_compatible() WPA: wpa_ie 0x%x "
" wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
" privacy 0x%x \n " , bss - > wpa_ie [ 0 ] , bss - > rsn_ie [ 0 ] ,
priv - > secinfo . wep_enabled ? " e " : " d " ,
priv - > secinfo . WPAenabled ? " e " : " d " ,
priv - > secinfo . WPA2enabled ? " e " : " d " ,
( bss - > capability & WLAN_CAPABILITY_PRIVACY ) ) ;
goto done ;
}
matched = match_bss_wpa2 ( & priv - > secinfo , bss ) ;
if ( matched ) {
lbs_deb_scan ( " is_network_compatible() WPA2: wpa_ie 0x%x "
" wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
" privacy 0x%x \n " , bss - > wpa_ie [ 0 ] , bss - > rsn_ie [ 0 ] ,
priv - > secinfo . wep_enabled ? " e " : " d " ,
priv - > secinfo . WPAenabled ? " e " : " d " ,
priv - > secinfo . WPA2enabled ? " e " : " d " ,
( bss - > capability & WLAN_CAPABILITY_PRIVACY ) ) ;
goto done ;
}
matched = match_bss_dynamic_wep ( & priv - > secinfo , bss ) ;
if ( matched ) {
lbs_deb_scan ( " is_network_compatible() dynamic WEP: "
" wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x \n " ,
bss - > wpa_ie [ 0 ] , bss - > rsn_ie [ 0 ] ,
( bss - > capability & WLAN_CAPABILITY_PRIVACY ) ) ;
goto done ;
}
/* bss security settings don't match those configured on card */
lbs_deb_scan ( " is_network_compatible() FAILED: wpa_ie 0x%x "
" wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x \n " ,
bss - > wpa_ie [ 0 ] , bss - > rsn_ie [ 0 ] ,
priv - > secinfo . wep_enabled ? " e " : " d " ,
priv - > secinfo . WPAenabled ? " e " : " d " ,
priv - > secinfo . WPA2enabled ? " e " : " d " ,
( bss - > capability & WLAN_CAPABILITY_PRIVACY ) ) ;
done :
lbs_deb_leave_args ( LBS_DEB_SCAN , " matched: %d " , matched ) ;
return matched ;
}
/**
* @ brief This function finds a specific compatible BSSID in the scan list
*
* Used in association code
*
* @ param priv A pointer to struct lbs_private
* @ param bssid BSSID to find in the scan list
* @ param mode Network mode : Infrastructure or IBSS
*
* @ return index in BSSID list , or error return code ( < 0 )
*/
static struct bss_descriptor * lbs_find_bssid_in_list ( struct lbs_private * priv ,
uint8_t * bssid , uint8_t mode )
{
struct bss_descriptor * iter_bss ;
struct bss_descriptor * found_bss = NULL ;
lbs_deb_enter ( LBS_DEB_SCAN ) ;
if ( ! bssid )
goto out ;
lbs_deb_hex ( LBS_DEB_SCAN , " looking for " , bssid , ETH_ALEN ) ;
/* Look through the scan table for a compatible match. The loop will
* continue past a matched bssid that is not compatible in case there
* is an AP with multiple SSIDs assigned to the same BSSID
*/
mutex_lock ( & priv - > lock ) ;
list_for_each_entry ( iter_bss , & priv - > network_list , list ) {
if ( compare_ether_addr ( iter_bss - > bssid , bssid ) )
continue ; /* bssid doesn't match */
switch ( mode ) {
case IW_MODE_INFRA :
case IW_MODE_ADHOC :
if ( ! is_network_compatible ( priv , iter_bss , mode ) )
break ;
found_bss = iter_bss ;
break ;
default :
found_bss = iter_bss ;
break ;
}
}
mutex_unlock ( & priv - > lock ) ;
out :
lbs_deb_leave_args ( LBS_DEB_SCAN , " found_bss %p " , found_bss ) ;
return found_bss ;
}
/**
* @ brief This function finds ssid in ssid list .
*
* Used in association code
*
* @ param priv A pointer to struct lbs_private
* @ param ssid SSID to find in the list
* @ param bssid BSSID to qualify the SSID selection ( if provided )
* @ param mode Network mode : Infrastructure or IBSS
*
* @ return index in BSSID list
*/
static struct bss_descriptor * lbs_find_ssid_in_list ( struct lbs_private * priv ,
uint8_t * ssid , uint8_t ssid_len ,
uint8_t * bssid , uint8_t mode ,
int channel )
{
u32 bestrssi = 0 ;
struct bss_descriptor * iter_bss = NULL ;
struct bss_descriptor * found_bss = NULL ;
struct bss_descriptor * tmp_oldest = NULL ;
lbs_deb_enter ( LBS_DEB_SCAN ) ;
mutex_lock ( & priv - > lock ) ;
list_for_each_entry ( iter_bss , & priv - > network_list , list ) {
if ( ! tmp_oldest | |
( iter_bss - > last_scanned < tmp_oldest - > last_scanned ) )
tmp_oldest = iter_bss ;
if ( lbs_ssid_cmp ( iter_bss - > ssid , iter_bss - > ssid_len ,
ssid , ssid_len ) ! = 0 )
continue ; /* ssid doesn't match */
if ( bssid & & compare_ether_addr ( iter_bss - > bssid , bssid ) ! = 0 )
continue ; /* bssid doesn't match */
if ( ( channel > 0 ) & & ( iter_bss - > channel ! = channel ) )
continue ; /* channel doesn't match */
switch ( mode ) {
case IW_MODE_INFRA :
case IW_MODE_ADHOC :
if ( ! is_network_compatible ( priv , iter_bss , mode ) )
break ;
if ( bssid ) {
/* Found requested BSSID */
found_bss = iter_bss ;
goto out ;
}
if ( SCAN_RSSI ( iter_bss - > rssi ) > bestrssi ) {
bestrssi = SCAN_RSSI ( iter_bss - > rssi ) ;
found_bss = iter_bss ;
}
break ;
case IW_MODE_AUTO :
default :
if ( SCAN_RSSI ( iter_bss - > rssi ) > bestrssi ) {
bestrssi = SCAN_RSSI ( iter_bss - > rssi ) ;
found_bss = iter_bss ;
}
break ;
}
}
out :
mutex_unlock ( & priv - > lock ) ;
lbs_deb_leave_args ( LBS_DEB_SCAN , " found_bss %p " , found_bss ) ;
return found_bss ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_essid ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
2007-05-25 16:15:56 -04:00
struct bss_descriptor * bss ;
2007-05-25 22:30:48 -04:00
int channel = - 1 ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 16:46:33 -04:00
/* FIXME: take channel into account when picking SSIDs if a channel
* is set .
*/
2007-05-25 22:30:48 -04:00
if ( test_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) )
channel = assoc_req - > channel ;
2007-10-15 12:55:56 +02:00
lbs_deb_assoc ( " SSID '%s' requested \n " ,
2008-09-24 18:13:14 -04:00
escape_ssid ( assoc_req - > ssid , assoc_req - > ssid_len ) ) ;
2007-05-10 22:58:02 -04:00
if ( assoc_req - > mode = = IW_MODE_INFRA ) {
2007-11-15 18:05:47 -05:00
lbs_send_specific_ssid_scan ( priv , assoc_req - > ssid ,
2008-03-05 07:05:32 +01:00
assoc_req - > ssid_len ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
bss = lbs_find_ssid_in_list ( priv , assoc_req - > ssid ,
2007-05-28 23:54:55 -04:00
assoc_req - > ssid_len , NULL , IW_MODE_INFRA , channel ) ;
2007-05-25 16:15:56 -04:00
if ( bss ! = NULL ) {
2007-05-25 17:09:41 -04:00
memcpy ( & assoc_req - > bss , bss , sizeof ( struct bss_descriptor ) ) ;
2007-11-15 18:05:47 -05:00
ret = lbs_associate ( priv , assoc_req ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-05-28 23:54:55 -04:00
lbs_deb_assoc ( " SSID not found; cannot associate \n " ) ;
2007-02-10 12:25:27 -02:00
}
2007-05-10 22:58:02 -04:00
} else if ( assoc_req - > mode = = IW_MODE_ADHOC ) {
2007-02-10 12:25:27 -02:00
/* Scan for the network, do not save previous results. Stale
* scan data will cause us to join a non - existant adhoc network
*/
2007-11-15 18:05:47 -05:00
lbs_send_specific_ssid_scan ( priv , assoc_req - > ssid ,
2008-03-05 07:05:32 +01:00
assoc_req - > ssid_len ) ;
2007-02-10 12:25:27 -02:00
/* Search for the requested SSID in the scan table */
2007-12-08 20:04:36 +00:00
bss = lbs_find_ssid_in_list ( priv , assoc_req - > ssid ,
2007-05-28 23:54:55 -04:00
assoc_req - > ssid_len , NULL , IW_MODE_ADHOC , channel ) ;
2007-05-25 16:15:56 -04:00
if ( bss ! = NULL ) {
2007-05-28 23:54:55 -04:00
lbs_deb_assoc ( " SSID found, will join \n " ) ;
2007-05-25 17:09:41 -04:00
memcpy ( & assoc_req - > bss , bss , sizeof ( struct bss_descriptor ) ) ;
2008-08-21 21:46:59 -04:00
lbs_adhoc_join ( priv , assoc_req ) ;
2007-02-10 12:25:27 -02:00
} else {
/* else send START command */
2007-05-28 23:54:55 -04:00
lbs_deb_assoc ( " SSID not found, creating adhoc network \n " ) ;
2007-05-25 17:09:41 -04:00
memcpy ( & assoc_req - > bss . ssid , & assoc_req - > ssid ,
2007-05-28 23:54:55 -04:00
IW_ESSID_MAX_SIZE ) ;
assoc_req - > bss . ssid_len = assoc_req - > ssid_len ;
2008-08-21 21:46:59 -04:00
lbs_adhoc_start ( priv , assoc_req ) ;
2007-02-10 12:25:27 -02:00
}
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_bssid ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
2007-05-25 16:15:56 -04:00
int ret = 0 ;
struct bss_descriptor * bss ;
2007-02-10 12:25:27 -02:00
2008-10-27 15:59:26 -07:00
lbs_deb_enter_args ( LBS_DEB_ASSOC , " BSSID %pM " , assoc_req - > bssid ) ;
2007-02-10 12:25:27 -02:00
/* Search for index position in list for requested MAC */
2007-12-08 20:04:36 +00:00
bss = lbs_find_bssid_in_list ( priv , assoc_req - > bssid ,
2007-02-10 12:25:27 -02:00
assoc_req - > mode ) ;
2007-05-25 16:15:56 -04:00
if ( bss = = NULL ) {
2008-10-27 15:59:26 -07:00
lbs_deb_assoc ( " ASSOC: WAP: BSSID %pM not found, "
" cannot associate. \n " , assoc_req - > bssid ) ;
2007-02-10 12:25:27 -02:00
goto out ;
}
2007-05-25 17:09:41 -04:00
memcpy ( & assoc_req - > bss , bss , sizeof ( struct bss_descriptor ) ) ;
2007-05-10 22:58:02 -04:00
if ( assoc_req - > mode = = IW_MODE_INFRA ) {
2007-11-15 18:05:47 -05:00
ret = lbs_associate ( priv , assoc_req ) ;
lbs_deb_assoc ( " ASSOC: lbs_associate(bssid) returned %d \n " , ret ) ;
2007-05-10 22:58:02 -04:00
} else if ( assoc_req - > mode = = IW_MODE_ADHOC ) {
2008-08-21 21:46:59 -04:00
lbs_adhoc_join ( priv , assoc_req ) ;
2007-02-10 12:25:27 -02:00
}
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_associate ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 , done = 0 ;
2007-10-15 12:55:56 +02:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
/* If we're given and 'any' BSSID, try associating based on SSID */
if ( test_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags ) ) {
2007-05-25 17:28:30 -04:00
if ( compare_ether_addr ( bssid_any , assoc_req - > bssid )
& & compare_ether_addr ( bssid_off , assoc_req - > bssid ) ) {
2007-02-10 12:25:27 -02:00
ret = assoc_helper_bssid ( priv , assoc_req ) ;
done = 1 ;
}
}
if ( ! done & & test_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ) {
ret = assoc_helper_essid ( priv , assoc_req ) ;
}
2007-10-15 12:55:56 +02:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_mode ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
if ( assoc_req - > mode = = priv - > mode )
2007-05-25 11:27:16 -04:00
goto done ;
2007-02-10 12:25:27 -02:00
2007-05-10 22:58:02 -04:00
if ( assoc_req - > mode = = IW_MODE_INFRA ) {
2007-12-08 20:04:36 +00:00
if ( priv - > psstate ! = PS_STATE_FULL_POWER )
2007-11-15 18:05:47 -05:00
lbs_ps_wakeup ( priv , CMD_OPTION_WAITFORRSP ) ;
2007-12-08 20:04:36 +00:00
priv - > psmode = LBS802_11POWERMODECAM ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
priv - > mode = assoc_req - > mode ;
2008-09-10 12:49:00 -04:00
ret = lbs_set_snmp_mib ( priv , SNMP_MIB_OID_BSS_TYPE , assoc_req - > mode ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
done :
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_channel ( struct lbs_private * priv ,
2007-05-25 16:46:33 -04:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-12-12 22:50:21 -05:00
ret = lbs_update_channel ( priv ) ;
2007-12-16 17:21:00 -05:00
if ( ret ) {
2007-12-12 00:14:21 -05:00
lbs_deb_assoc ( " ASSOC: channel: error getting channel. \n " ) ;
2007-12-16 17:21:00 -05:00
goto done ;
2007-05-25 16:46:33 -04:00
}
2007-12-08 20:04:36 +00:00
if ( assoc_req - > channel = = priv - > curbssparams . channel )
2007-05-25 16:46:33 -04:00
goto done ;
2007-12-11 20:03:01 -05:00
if ( priv - > mesh_dev ) {
2007-12-13 00:32:36 -05:00
/* Change mesh channel first; 21.p21 firmware won't let
you change channel otherwise ( even though it ' ll return
an error to this */
2008-05-17 00:55:10 -07:00
lbs_mesh_config ( priv , CMD_ACT_MESH_CONFIG_STOP ,
assoc_req - > channel ) ;
2007-12-11 20:03:01 -05:00
}
2007-05-25 16:46:33 -04:00
lbs_deb_assoc ( " ASSOC: channel: %d -> %d \n " ,
2007-12-13 00:32:36 -05:00
priv - > curbssparams . channel , assoc_req - > channel ) ;
2007-05-25 16:46:33 -04:00
2007-12-11 16:54:15 -05:00
ret = lbs_set_channel ( priv , assoc_req - > channel ) ;
if ( ret < 0 )
2007-12-12 00:14:21 -05:00
lbs_deb_assoc ( " ASSOC: channel: error setting channel. \n " ) ;
2007-05-25 16:46:33 -04:00
2007-12-11 16:54:15 -05:00
/* FIXME: shouldn't need to grab the channel _again_ after setting
* it since the firmware is supposed to return the new channel , but
* whatever . . . */
2007-12-12 22:50:21 -05:00
ret = lbs_update_channel ( priv ) ;
2007-12-16 17:21:00 -05:00
if ( ret ) {
2007-12-12 00:14:21 -05:00
lbs_deb_assoc ( " ASSOC: channel: error getting channel. \n " ) ;
2007-12-16 17:21:00 -05:00
goto done ;
}
2007-05-25 16:46:33 -04:00
2007-12-08 20:04:36 +00:00
if ( assoc_req - > channel ! = priv - > curbssparams . channel ) {
2007-12-11 19:57:05 -05:00
lbs_deb_assoc ( " ASSOC: channel: failed to update channel to %d \n " ,
2007-05-25 16:46:33 -04:00
assoc_req - > channel ) ;
2007-12-11 20:03:01 -05:00
goto restore_mesh ;
2007-05-25 16:46:33 -04:00
}
if ( assoc_req - > secinfo . wep_enabled
& & ( assoc_req - > wep_keys [ 0 ] . len
| | assoc_req - > wep_keys [ 1 ] . len
| | assoc_req - > wep_keys [ 2 ] . len
| | assoc_req - > wep_keys [ 3 ] . len ) ) {
/* Make sure WEP keys are re-sent to firmware */
set_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags ) ;
}
/* Must restart/rejoin adhoc networks after channel change */
2007-12-12 00:14:21 -05:00
set_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ;
2007-05-25 16:46:33 -04:00
2007-12-11 20:03:01 -05:00
restore_mesh :
if ( priv - > mesh_dev )
2008-05-17 00:55:10 -07:00
lbs_mesh_config ( priv , CMD_ACT_MESH_CONFIG_START ,
priv - > curbssparams . channel ) ;
2007-12-11 20:03:01 -05:00
done :
2007-05-25 16:46:33 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_wep_keys ( struct lbs_private * priv ,
2007-12-18 00:18:05 -05:00
struct assoc_request * assoc_req )
2007-02-10 12:25:27 -02:00
{
int i ;
int ret = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
/* Set or remove WEP keys */
2007-12-18 00:18:05 -05:00
if ( assoc_req - > wep_keys [ 0 ] . len | | assoc_req - > wep_keys [ 1 ] . len | |
assoc_req - > wep_keys [ 2 ] . len | | assoc_req - > wep_keys [ 3 ] . len )
ret = lbs_cmd_802_11_set_wep ( priv , CMD_ACT_ADD , assoc_req ) ;
else
ret = lbs_cmd_802_11_set_wep ( priv , CMD_ACT_REMOVE , assoc_req ) ;
2007-02-10 12:25:27 -02:00
if ( ret )
goto out ;
/* enable/disable the MAC's WEP packet filter */
2007-05-10 22:57:23 -04:00
if ( assoc_req - > secinfo . wep_enabled )
2008-03-12 16:06:43 +01:00
priv - > mac_control | = CMD_ACT_MAC_WEP_ENABLE ;
2007-02-10 12:25:27 -02:00
else
2008-03-12 16:06:43 +01:00
priv - > mac_control & = ~ CMD_ACT_MAC_WEP_ENABLE ;
2007-12-18 00:18:05 -05:00
2008-03-18 11:20:21 +01:00
lbs_set_mac_control ( priv ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
mutex_lock ( & priv - > lock ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
/* Copy WEP keys into priv wep key fields */
2007-02-10 12:25:27 -02:00
for ( i = 0 ; i < 4 ; i + + ) {
2007-12-08 20:04:36 +00:00
memcpy ( & priv - > wep_keys [ i ] , & assoc_req - > wep_keys [ i ] ,
2007-12-18 00:18:05 -05:00
sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
priv - > wep_tx_keyidx = assoc_req - > wep_tx_keyidx ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
mutex_unlock ( & priv - > lock ) ;
2007-02-10 12:25:27 -02:00
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_secinfo ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
2007-12-18 00:47:17 -05:00
uint16_t do_wpa ;
uint16_t rsn = 0 ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
memcpy ( & priv - > secinfo , & assoc_req - > secinfo ,
2007-11-15 18:05:47 -05:00
sizeof ( struct lbs_802_11_security ) ) ;
2007-02-10 12:25:27 -02:00
2008-03-18 11:20:21 +01:00
lbs_set_mac_control ( priv ) ;
2007-02-10 12:25:27 -02:00
2007-06-18 12:01:12 -04:00
/* If RSN is already enabled, don't try to enable it again, since
* ENABLE_RSN resets internal state machines and will clobber the
* 4 - way WPA handshake .
*/
/* Get RSN enabled/disabled */
2007-12-18 00:47:17 -05:00
ret = lbs_cmd_802_11_enable_rsn ( priv , CMD_ACT_GET , & rsn ) ;
2007-06-18 12:01:12 -04:00
if ( ret ) {
2007-12-12 00:14:21 -05:00
lbs_deb_assoc ( " Failed to get RSN status: %d \n " , ret ) ;
2007-06-18 12:01:12 -04:00
goto out ;
}
/* Don't re-enable RSN if it's already enabled */
2007-12-18 00:47:17 -05:00
do_wpa = assoc_req - > secinfo . WPAenabled | | assoc_req - > secinfo . WPA2enabled ;
2007-06-18 12:01:12 -04:00
if ( do_wpa = = rsn )
goto out ;
/* Set RSN enabled/disabled */
2007-12-18 00:47:17 -05:00
ret = lbs_cmd_802_11_enable_rsn ( priv , CMD_ACT_SET , & do_wpa ) ;
2007-05-25 23:01:24 -04:00
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_wpa_keys ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
2007-10-03 10:37:45 -04:00
unsigned int flags = assoc_req - > flags ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
2007-10-03 10:37:45 -04:00
/* Work around older firmware bug where WPA unicast and multicast
* keys must be set independently . Seen in SDIO parts with firmware
* version 5.0 .11 p0 .
*/
2007-02-10 12:25:27 -02:00
2007-10-03 10:37:45 -04:00
if ( test_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ) {
clear_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags ) ;
2008-03-03 12:15:39 +01:00
ret = lbs_cmd_802_11_key_material ( priv , CMD_ACT_SET , assoc_req ) ;
2007-10-03 10:37:45 -04:00
assoc_req - > flags = flags ;
}
if ( ret )
goto out ;
if ( test_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags ) ) {
clear_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ;
2008-03-03 12:15:39 +01:00
ret = lbs_cmd_802_11_key_material ( priv , CMD_ACT_SET , assoc_req ) ;
2007-10-03 10:37:45 -04:00
assoc_req - > flags = flags ;
}
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-23 15:43:44 +01:00
static int assoc_helper_wpa_ie ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
int ret = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
if ( assoc_req - > secinfo . WPAenabled | | assoc_req - > secinfo . WPA2enabled ) {
2007-12-08 20:04:36 +00:00
memcpy ( & priv - > wpa_ie , & assoc_req - > wpa_ie , assoc_req - > wpa_ie_len ) ;
priv - > wpa_ie_len = assoc_req - > wpa_ie_len ;
2007-02-10 12:25:27 -02:00
} else {
2007-12-08 20:04:36 +00:00
memset ( & priv - > wpa_ie , 0 , MAX_WPA_IE_LEN ) ;
priv - > wpa_ie_len = 0 ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-12-08 20:04:36 +00:00
static int should_deauth_infrastructure ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
2007-10-15 12:55:56 +02:00
int ret = 0 ;
2007-12-08 20:04:36 +00:00
if ( priv - > connect_status ! = LBS_CONNECTED )
2007-02-10 12:25:27 -02:00
return 0 ;
2008-01-28 17:25:53 +01:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
if ( test_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ) {
2007-10-15 12:55:56 +02:00
lbs_deb_assoc ( " Deauthenticating due to new SSID \n " ) ;
ret = 1 ;
goto out ;
2007-02-10 12:25:27 -02:00
}
if ( test_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
if ( priv - > secinfo . auth_mode ! = assoc_req - > secinfo . auth_mode ) {
2007-10-15 12:55:56 +02:00
lbs_deb_assoc ( " Deauthenticating due to new security \n " ) ;
ret = 1 ;
goto out ;
2007-02-10 12:25:27 -02:00
}
}
if ( test_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags ) ) {
2007-10-15 12:55:56 +02:00
lbs_deb_assoc ( " Deauthenticating due to new BSSID \n " ) ;
ret = 1 ;
goto out ;
2007-02-10 12:25:27 -02:00
}
2007-05-30 12:16:13 -04:00
if ( test_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) ) {
2007-10-15 12:55:56 +02:00
lbs_deb_assoc ( " Deauthenticating due to channel switch \n " ) ;
ret = 1 ;
goto out ;
2007-05-30 12:16:13 -04:00
}
2007-02-10 12:25:27 -02:00
/* FIXME: deal with 'auto' mode somehow */
if ( test_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) ) {
2007-10-15 12:55:56 +02:00
if ( assoc_req - > mode ! = IW_MODE_INFRA ) {
lbs_deb_assoc ( " Deauthenticating due to leaving "
" infra mode \n " ) ;
ret = 1 ;
goto out ;
}
2007-02-10 12:25:27 -02:00
}
2007-10-15 12:55:56 +02:00
out :
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
2008-01-28 17:25:53 +01:00
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
static int should_stop_adhoc ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req )
{
2007-10-15 12:55:56 +02:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-12-08 20:04:36 +00:00
if ( priv - > connect_status ! = LBS_CONNECTED )
2007-02-10 12:25:27 -02:00
return 0 ;
2007-12-08 20:04:36 +00:00
if ( lbs_ssid_cmp ( priv - > curbssparams . ssid ,
priv - > curbssparams . ssid_len ,
2007-05-28 23:54:55 -04:00
assoc_req - > ssid , assoc_req - > ssid_len ) ! = 0 )
2007-02-10 12:25:27 -02:00
return 1 ;
/* FIXME: deal with 'auto' mode somehow */
if ( test_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) ) {
2007-05-10 22:58:02 -04:00
if ( assoc_req - > mode ! = IW_MODE_ADHOC )
2007-02-10 12:25:27 -02:00
return 1 ;
}
2007-05-25 16:46:33 -04:00
if ( test_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
if ( assoc_req - > channel ! = priv - > curbssparams . channel )
2007-05-25 16:46:33 -04:00
return 1 ;
}
2007-10-15 12:55:56 +02:00
lbs_deb_leave ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2008-04-02 16:27:42 +02:00
/**
* @ brief This function finds the best SSID in the Scan List
*
* Search the scan table for the best SSID that also matches the current
* adapter network preference ( infrastructure or adhoc )
*
* @ param priv A pointer to struct lbs_private
*
* @ return index in BSSID list
*/
static struct bss_descriptor * lbs_find_best_ssid_in_list (
struct lbs_private * priv , uint8_t mode )
{
uint8_t bestrssi = 0 ;
struct bss_descriptor * iter_bss ;
struct bss_descriptor * best_bss = NULL ;
lbs_deb_enter ( LBS_DEB_SCAN ) ;
mutex_lock ( & priv - > lock ) ;
list_for_each_entry ( iter_bss , & priv - > network_list , list ) {
switch ( mode ) {
case IW_MODE_INFRA :
case IW_MODE_ADHOC :
if ( ! is_network_compatible ( priv , iter_bss , mode ) )
break ;
if ( SCAN_RSSI ( iter_bss - > rssi ) < = bestrssi )
break ;
bestrssi = SCAN_RSSI ( iter_bss - > rssi ) ;
best_bss = iter_bss ;
break ;
case IW_MODE_AUTO :
default :
if ( SCAN_RSSI ( iter_bss - > rssi ) < = bestrssi )
break ;
bestrssi = SCAN_RSSI ( iter_bss - > rssi ) ;
best_bss = iter_bss ;
break ;
}
}
mutex_unlock ( & priv - > lock ) ;
lbs_deb_leave_args ( LBS_DEB_SCAN , " best_bss %p " , best_bss ) ;
return best_bss ;
}
/**
* @ brief Find the best AP
*
* Used from association worker .
*
* @ param priv A pointer to struct lbs_private structure
* @ param pSSID A pointer to AP ' s ssid
*
* @ return 0 - - success , otherwise - - fail
*/
static int lbs_find_best_network_ssid ( struct lbs_private * priv ,
uint8_t * out_ssid , uint8_t * out_ssid_len , uint8_t preferred_mode ,
uint8_t * out_mode )
{
int ret = - 1 ;
struct bss_descriptor * found ;
lbs_deb_enter ( LBS_DEB_SCAN ) ;
priv - > scan_ssid_len = 0 ;
lbs_scan_networks ( priv , 1 ) ;
if ( priv - > surpriseremoved )
goto out ;
found = lbs_find_best_ssid_in_list ( priv , preferred_mode ) ;
if ( found & & ( found - > ssid_len > 0 ) ) {
memcpy ( out_ssid , & found - > ssid , IW_ESSID_MAX_SIZE ) ;
* out_ssid_len = found - > ssid_len ;
* out_mode = found - > mode ;
ret = 0 ;
}
out :
lbs_deb_leave_args ( LBS_DEB_SCAN , " ret %d " , ret ) ;
return ret ;
}
2007-11-15 18:05:47 -05:00
void lbs_association_worker ( struct work_struct * work )
2007-02-10 12:25:27 -02:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = container_of ( work , struct lbs_private ,
assoc_work . work ) ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req = NULL ;
int ret = 0 ;
int find_any_ssid = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
mutex_lock ( & priv - > lock ) ;
assoc_req = priv - > pending_assoc_req ;
priv - > pending_assoc_req = NULL ;
priv - > in_progress_assoc_req = assoc_req ;
mutex_unlock ( & priv - > lock ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
if ( ! assoc_req )
goto done ;
2007-02-10 12:25:27 -02:00
2007-10-15 12:55:56 +02:00
lbs_deb_assoc (
" Association Request: \n "
" flags: 0x%08lx \n "
" SSID: '%s' \n "
" chann: %d \n "
" band: %d \n "
" mode: %d \n "
2008-10-27 15:59:26 -07:00
" BSSID: %pM \n "
2007-10-15 12:55:56 +02:00
" secinfo: %s%s%s \n "
" auth_mode: %d \n " ,
assoc_req - > flags ,
2008-09-24 18:13:14 -04:00
escape_ssid ( assoc_req - > ssid , assoc_req - > ssid_len ) ,
2007-10-15 12:55:56 +02:00
assoc_req - > channel , assoc_req - > band , assoc_req - > mode ,
2008-10-27 15:59:26 -07:00
assoc_req - > bssid ,
2007-10-15 12:55:56 +02:00
assoc_req - > secinfo . WPAenabled ? " WPA " : " " ,
assoc_req - > secinfo . WPA2enabled ? " WPA2 " : " " ,
assoc_req - > secinfo . wep_enabled ? " WEP " : " " ,
assoc_req - > secinfo . auth_mode ) ;
2007-02-10 12:25:27 -02:00
/* If 'any' SSID was specified, find an SSID to associate with */
if ( test_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags )
2007-05-28 23:54:55 -04:00
& & ! assoc_req - > ssid_len )
2007-02-10 12:25:27 -02:00
find_any_ssid = 1 ;
/* But don't use 'any' SSID if there's a valid locked BSSID to use */
if ( test_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags ) ) {
2007-05-25 17:28:30 -04:00
if ( compare_ether_addr ( assoc_req - > bssid , bssid_any )
& & compare_ether_addr ( assoc_req - > bssid , bssid_off ) )
2007-02-10 12:25:27 -02:00
find_any_ssid = 0 ;
}
if ( find_any_ssid ) {
2008-04-02 16:34:51 +02:00
u8 new_mode = assoc_req - > mode ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
ret = lbs_find_best_network_ssid ( priv , assoc_req - > ssid ,
2007-05-28 23:54:55 -04:00
& assoc_req - > ssid_len , assoc_req - > mode , & new_mode ) ;
2007-02-10 12:25:27 -02:00
if ( ret ) {
2007-05-25 11:27:16 -04:00
lbs_deb_assoc ( " Could not find best network \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - ENETUNREACH ;
goto out ;
}
/* Ensure we switch to the mode of the AP */
2007-05-10 22:58:02 -04:00
if ( assoc_req - > mode = = IW_MODE_AUTO ) {
2007-02-10 12:25:27 -02:00
set_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) ;
assoc_req - > mode = new_mode ;
}
}
/*
* Check if the attributes being changing require deauthentication
* from the currently associated infrastructure access point .
*/
2007-12-08 20:04:36 +00:00
if ( priv - > mode = = IW_MODE_INFRA ) {
if ( should_deauth_infrastructure ( priv , assoc_req ) ) {
2008-08-21 17:46:18 -04:00
ret = lbs_cmd_80211_deauthenticate ( priv ,
priv - > curbssparams . bssid ,
WLAN_REASON_DEAUTH_LEAVING ) ;
2007-02-10 12:25:27 -02:00
if ( ret ) {
2007-05-25 11:27:16 -04:00
lbs_deb_assoc ( " Deauthentication due to new "
2007-02-10 12:25:27 -02:00
" configuration request failed: %d \n " ,
ret ) ;
}
}
2007-12-08 20:04:36 +00:00
} else if ( priv - > mode = = IW_MODE_ADHOC ) {
if ( should_stop_adhoc ( priv , assoc_req ) ) {
2008-08-21 21:46:59 -04:00
ret = lbs_adhoc_stop ( priv ) ;
2007-02-10 12:25:27 -02:00
if ( ret ) {
2007-05-25 11:27:16 -04:00
lbs_deb_assoc ( " Teardown of AdHoc network due to "
2007-02-10 12:25:27 -02:00
" new configuration request failed: %d \n " ,
ret ) ;
}
}
}
/* Send the various configuration bits to the firmware */
if ( test_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) ) {
ret = assoc_helper_mode ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-02-10 12:25:27 -02:00
goto out ;
}
2007-05-25 16:46:33 -04:00
if ( test_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) ) {
ret = assoc_helper_channel ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-05-25 16:46:33 -04:00
goto out ;
}
2007-02-10 12:25:27 -02:00
if ( test_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags )
| | test_bit ( ASSOC_FLAG_WEP_TX_KEYIDX , & assoc_req - > flags ) ) {
ret = assoc_helper_wep_keys ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-02-10 12:25:27 -02:00
goto out ;
}
if ( test_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ) {
ret = assoc_helper_secinfo ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-02-10 12:25:27 -02:00
goto out ;
}
if ( test_bit ( ASSOC_FLAG_WPA_IE , & assoc_req - > flags ) ) {
ret = assoc_helper_wpa_ie ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-02-10 12:25:27 -02:00
goto out ;
}
if ( test_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags )
| | test_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ) {
ret = assoc_helper_wpa_keys ( priv , assoc_req ) ;
2007-10-15 12:55:56 +02:00
if ( ret )
2007-02-10 12:25:27 -02:00
goto out ;
}
/* SSID/BSSID should be the _last_ config option set, because they
* trigger the association attempt .
*/
if ( test_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags )
| | test_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ) {
int success = 1 ;
ret = assoc_helper_associate ( priv , assoc_req ) ;
if ( ret ) {
2007-11-28 14:05:02 +01:00
lbs_deb_assoc ( " ASSOC: association unsuccessful: %d \n " ,
2007-02-10 12:25:27 -02:00
ret ) ;
success = 0 ;
}
2007-12-08 20:04:36 +00:00
if ( priv - > connect_status ! = LBS_CONNECTED ) {
2007-11-28 14:05:02 +01:00
lbs_deb_assoc ( " ASSOC: association unsuccessful, "
" not connected \n " ) ;
2007-02-10 12:25:27 -02:00
success = 0 ;
}
if ( success ) {
2008-10-27 15:59:26 -07:00
lbs_deb_assoc ( " associated to %pM \n " ,
priv - > curbssparams . bssid ) ;
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_RSSI ,
0 , CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
} else {
ret = - 1 ;
}
}
out :
if ( ret ) {
2007-05-25 11:27:16 -04:00
lbs_deb_assoc ( " ASSOC: reconfiguration attempt unsuccessful: %d \n " ,
2007-02-10 12:25:27 -02:00
ret ) ;
}
2007-05-25 17:09:41 -04:00
2007-12-08 20:04:36 +00:00
mutex_lock ( & priv - > lock ) ;
priv - > in_progress_assoc_req = NULL ;
mutex_unlock ( & priv - > lock ) ;
2007-02-10 12:25:27 -02:00
kfree ( assoc_req ) ;
2007-05-25 11:27:16 -04:00
done :
lbs_deb_leave ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
}
/*
* Caller MUST hold any necessary locks
*/
2007-12-08 20:04:36 +00:00
struct assoc_request * lbs_get_association_request ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
struct assoc_request * assoc_req ;
2007-10-15 12:55:56 +02:00
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
2007-12-08 20:04:36 +00:00
if ( ! priv - > pending_assoc_req ) {
priv - > pending_assoc_req = kzalloc ( sizeof ( struct assoc_request ) ,
2007-05-25 17:09:41 -04:00
GFP_KERNEL ) ;
2007-12-08 20:04:36 +00:00
if ( ! priv - > pending_assoc_req ) {
2007-02-10 12:25:27 -02:00
lbs_pr_info ( " Not enough memory to allocate association "
" request! \n " ) ;
return NULL ;
}
}
/* Copy current configuration attributes to the association request,
* but don ' t overwrite any that are already set .
*/
2007-12-08 20:04:36 +00:00
assoc_req = priv - > pending_assoc_req ;
2007-02-10 12:25:27 -02:00
if ( ! test_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > ssid , & priv - > curbssparams . ssid ,
2007-05-28 23:54:55 -04:00
IW_ESSID_MAX_SIZE ) ;
2007-12-08 20:04:36 +00:00
assoc_req - > ssid_len = priv - > curbssparams . ssid_len ;
2007-02-10 12:25:27 -02:00
}
if ( ! test_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) )
2007-12-08 20:04:36 +00:00
assoc_req - > channel = priv - > curbssparams . channel ;
2007-02-10 12:25:27 -02:00
2007-05-25 17:09:41 -04:00
if ( ! test_bit ( ASSOC_FLAG_BAND , & assoc_req - > flags ) )
2007-12-08 20:04:36 +00:00
assoc_req - > band = priv - > curbssparams . band ;
2007-05-25 17:09:41 -04:00
2007-02-10 12:25:27 -02:00
if ( ! test_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) )
2007-12-08 20:04:36 +00:00
assoc_req - > mode = priv - > mode ;
2007-02-10 12:25:27 -02:00
if ( ! test_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > bssid , priv - > curbssparams . bssid ,
2007-02-10 12:25:27 -02:00
ETH_ALEN ) ;
}
if ( ! test_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags ) ) {
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > wep_keys [ i ] , & priv - > wep_keys [ i ] ,
2007-08-02 10:45:55 -04:00
sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
}
}
if ( ! test_bit ( ASSOC_FLAG_WEP_TX_KEYIDX , & assoc_req - > flags ) )
2007-12-08 20:04:36 +00:00
assoc_req - > wep_tx_keyidx = priv - > wep_tx_keyidx ;
2007-02-10 12:25:27 -02:00
if ( ! test_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > wpa_mcast_key , & priv - > wpa_mcast_key ,
2007-08-02 10:45:55 -04:00
sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
}
if ( ! test_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > wpa_unicast_key , & priv - > wpa_unicast_key ,
2007-08-02 10:45:55 -04:00
sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
}
if ( ! test_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > secinfo , & priv - > secinfo ,
2007-11-15 18:05:47 -05:00
sizeof ( struct lbs_802_11_security ) ) ;
2007-02-10 12:25:27 -02:00
}
if ( ! test_bit ( ASSOC_FLAG_WPA_IE , & assoc_req - > flags ) ) {
2007-12-08 20:04:36 +00:00
memcpy ( & assoc_req - > wpa_ie , & priv - > wpa_ie ,
2007-02-10 12:25:27 -02:00
MAX_WPA_IE_LEN ) ;
2007-12-08 20:04:36 +00:00
assoc_req - > wpa_ie_len = priv - > wpa_ie_len ;
2007-02-10 12:25:27 -02:00
}
2007-10-15 12:55:56 +02:00
lbs_deb_leave ( LBS_DEB_ASSOC ) ;
2007-02-10 12:25:27 -02:00
return assoc_req ;
}
2008-04-02 16:27:10 +02:00
/**
* @ brief This function prepares command of authenticate .
*
* @ param priv A pointer to struct lbs_private structure
* @ param cmd A pointer to cmd_ds_command structure
* @ param pdata_buf Void cast of pointer to a BSSID to authenticate with
*
* @ return 0 or - 1
*/
int lbs_cmd_80211_authenticate ( struct lbs_private * priv ,
struct cmd_ds_command * cmd ,
void * pdata_buf )
{
struct cmd_ds_802_11_authenticate * pauthenticate = & cmd - > params . auth ;
int ret = - 1 ;
u8 * bssid = pdata_buf ;
lbs_deb_enter ( LBS_DEB_JOIN ) ;
cmd - > command = cpu_to_le16 ( CMD_802_11_AUTHENTICATE ) ;
cmd - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_authenticate )
+ S_DS_GEN ) ;
/* translate auth mode to 802.11 defined wire value */
switch ( priv - > secinfo . auth_mode ) {
case IW_AUTH_ALG_OPEN_SYSTEM :
pauthenticate - > authtype = 0x00 ;
break ;
case IW_AUTH_ALG_SHARED_KEY :
pauthenticate - > authtype = 0x01 ;
break ;
case IW_AUTH_ALG_LEAP :
pauthenticate - > authtype = 0x80 ;
break ;
default :
lbs_deb_join ( " AUTH_CMD: invalid auth alg 0x%X \n " ,
priv - > secinfo . auth_mode ) ;
goto out ;
}
memcpy ( pauthenticate - > macaddr , bssid , ETH_ALEN ) ;
2008-10-27 15:59:26 -07:00
lbs_deb_join ( " AUTH_CMD: BSSID %pM, auth 0x%x \n " ,
bssid , pauthenticate - > authtype ) ;
2008-04-02 16:27:10 +02:00
ret = 0 ;
out :
lbs_deb_leave_args ( LBS_DEB_JOIN , " ret %d " , ret ) ;
return ret ;
}
2008-08-21 17:46:18 -04:00
/**
* @ brief Deauthenticate from a specific BSS
*
* @ param priv A pointer to struct lbs_private structure
* @ param bssid The specific BSS to deauthenticate from
* @ param reason The 802.11 sec . 7.3 .1 .7 Reason Code for deauthenticating
*
* @ return 0 on success , error on failure
*/
int lbs_cmd_80211_deauthenticate ( struct lbs_private * priv , u8 bssid [ ETH_ALEN ] ,
u16 reason )
2008-04-02 16:27:10 +02:00
{
2008-08-21 17:46:18 -04:00
struct cmd_ds_802_11_deauthenticate cmd ;
int ret ;
2008-04-02 16:27:10 +02:00
lbs_deb_enter ( LBS_DEB_JOIN ) ;
2008-08-21 17:46:18 -04:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
memcpy ( cmd . macaddr , & bssid [ 0 ] , ETH_ALEN ) ;
cmd . reasoncode = cpu_to_le16 ( reason ) ;
2008-04-02 16:27:10 +02:00
2008-08-21 17:46:18 -04:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_DEAUTHENTICATE , & cmd ) ;
2008-04-02 16:27:10 +02:00
2008-08-21 17:46:18 -04:00
/* Clean up everything even if there was an error; can't assume that
* we ' re still authenticated to the AP after trying to deauth .
*/
lbs_mac_event_disconnected ( priv ) ;
2008-04-02 16:27:10 +02:00
lbs_deb_leave ( LBS_DEB_JOIN ) ;
2008-08-21 17:46:18 -04:00
return ret ;
2008-04-02 16:27:10 +02:00
}
int lbs_cmd_80211_associate ( struct lbs_private * priv ,
struct cmd_ds_command * cmd , void * pdata_buf )
{
struct cmd_ds_802_11_associate * passo = & cmd - > params . associate ;
int ret = 0 ;
struct assoc_request * assoc_req = pdata_buf ;
struct bss_descriptor * bss = & assoc_req - > bss ;
u8 * pos ;
u16 tmpcap , tmplen ;
struct mrvlietypes_ssidparamset * ssid ;
struct mrvlietypes_phyparamset * phy ;
struct mrvlietypes_ssparamset * ss ;
struct mrvlietypes_ratesparamset * rates ;
struct mrvlietypes_rsnparamset * rsn ;
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
pos = ( u8 * ) passo ;
if ( ! priv ) {
ret = - 1 ;
goto done ;
}
cmd - > command = cpu_to_le16 ( CMD_802_11_ASSOCIATE ) ;
memcpy ( passo - > peerstaaddr , bss - > bssid , sizeof ( passo - > peerstaaddr ) ) ;
pos + = sizeof ( passo - > peerstaaddr ) ;
/* set the listen interval */
passo - > listeninterval = cpu_to_le16 ( MRVDRV_DEFAULT_LISTEN_INTERVAL ) ;
pos + = sizeof ( passo - > capability ) ;
pos + = sizeof ( passo - > listeninterval ) ;
pos + = sizeof ( passo - > bcnperiod ) ;
pos + = sizeof ( passo - > dtimperiod ) ;
ssid = ( struct mrvlietypes_ssidparamset * ) pos ;
ssid - > header . type = cpu_to_le16 ( TLV_TYPE_SSID ) ;
tmplen = bss - > ssid_len ;
ssid - > header . len = cpu_to_le16 ( tmplen ) ;
memcpy ( ssid - > ssid , bss - > ssid , tmplen ) ;
pos + = sizeof ( ssid - > header ) + tmplen ;
phy = ( struct mrvlietypes_phyparamset * ) pos ;
phy - > header . type = cpu_to_le16 ( TLV_TYPE_PHY_DS ) ;
tmplen = sizeof ( phy - > fh_ds . dsparamset ) ;
phy - > header . len = cpu_to_le16 ( tmplen ) ;
memcpy ( & phy - > fh_ds . dsparamset ,
& bss - > phyparamset . dsparamset . currentchan ,
tmplen ) ;
pos + = sizeof ( phy - > header ) + tmplen ;
ss = ( struct mrvlietypes_ssparamset * ) pos ;
ss - > header . type = cpu_to_le16 ( TLV_TYPE_CF ) ;
tmplen = sizeof ( ss - > cf_ibss . cfparamset ) ;
ss - > header . len = cpu_to_le16 ( tmplen ) ;
pos + = sizeof ( ss - > header ) + tmplen ;
rates = ( struct mrvlietypes_ratesparamset * ) pos ;
rates - > header . type = cpu_to_le16 ( TLV_TYPE_RATES ) ;
memcpy ( & rates - > rates , & bss - > rates , MAX_RATES ) ;
tmplen = MAX_RATES ;
if ( get_common_rates ( priv , rates - > rates , & tmplen ) ) {
ret = - 1 ;
goto done ;
}
pos + = sizeof ( rates - > header ) + tmplen ;
rates - > header . len = cpu_to_le16 ( tmplen ) ;
lbs_deb_assoc ( " ASSOC_CMD: num rates %u \n " , tmplen ) ;
/* Copy the infra. association rates into Current BSS state structure */
memset ( & priv - > curbssparams . rates , 0 , sizeof ( priv - > curbssparams . rates ) ) ;
memcpy ( & priv - > curbssparams . rates , & rates - > rates , tmplen ) ;
/* Set MSB on basic rates as the firmware requires, but _after_
* copying to current bss rates .
*/
lbs_set_basic_rate_flags ( rates - > rates , tmplen ) ;
if ( assoc_req - > secinfo . WPAenabled | | assoc_req - > secinfo . WPA2enabled ) {
rsn = ( struct mrvlietypes_rsnparamset * ) pos ;
/* WPA_IE or WPA2_IE */
rsn - > header . type = cpu_to_le16 ( ( u16 ) assoc_req - > wpa_ie [ 0 ] ) ;
tmplen = ( u16 ) assoc_req - > wpa_ie [ 1 ] ;
rsn - > header . len = cpu_to_le16 ( tmplen ) ;
memcpy ( rsn - > rsnie , & assoc_req - > wpa_ie [ 2 ] , tmplen ) ;
lbs_deb_hex ( LBS_DEB_JOIN , " ASSOC_CMD: RSN IE " , ( u8 * ) rsn ,
sizeof ( rsn - > header ) + tmplen ) ;
pos + = sizeof ( rsn - > header ) + tmplen ;
}
/* update curbssparams */
priv - > curbssparams . channel = bss - > phyparamset . dsparamset . currentchan ;
if ( lbs_parse_dnld_countryinfo_11d ( priv , bss ) ) {
ret = - 1 ;
goto done ;
}
cmd - > size = cpu_to_le16 ( ( u16 ) ( pos - ( u8 * ) passo ) + S_DS_GEN ) ;
/* set the capability info */
tmpcap = ( bss - > capability & CAPINFO_MASK ) ;
if ( bss - > mode = = IW_MODE_INFRA )
tmpcap | = WLAN_CAPABILITY_ESS ;
passo - > capability = cpu_to_le16 ( tmpcap ) ;
lbs_deb_assoc ( " ASSOC_CMD: capability 0x%04x \n " , tmpcap ) ;
done :
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
}
int lbs_ret_80211_associate ( struct lbs_private * priv ,
struct cmd_ds_command * resp )
{
int ret = 0 ;
union iwreq_data wrqu ;
struct ieeetypes_assocrsp * passocrsp ;
struct bss_descriptor * bss ;
u16 status_code ;
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
if ( ! priv - > in_progress_assoc_req ) {
lbs_deb_assoc ( " ASSOC_RESP: no in-progress assoc request \n " ) ;
ret = - 1 ;
goto done ;
}
bss = & priv - > in_progress_assoc_req - > bss ;
passocrsp = ( struct ieeetypes_assocrsp * ) & resp - > params ;
/*
* Older FW versions map the IEEE 802.11 Status Code in the association
* response to the following values returned in passocrsp - > statuscode :
*
* IEEE Status Code Marvell Status Code
* 0 - > 0x0000 ASSOC_RESULT_SUCCESS
* 13 - > 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 14 - > 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 15 - > 0x0004 ASSOC_RESULT_AUTH_REFUSED
* 16 - > 0x0004 ASSOC_RESULT_AUTH_REFUSED
* others - > 0x0003 ASSOC_RESULT_REFUSED
*
* Other response codes :
* 0x0001 - > ASSOC_RESULT_INVALID_PARAMETERS ( unused )
* 0x0002 - > ASSOC_RESULT_TIMEOUT ( internal timer expired waiting for
* association response from the AP )
*/
status_code = le16_to_cpu ( passocrsp - > statuscode ) ;
switch ( status_code ) {
case 0x00 :
break ;
case 0x01 :
lbs_deb_assoc ( " ASSOC_RESP: invalid parameters \n " ) ;
break ;
case 0x02 :
lbs_deb_assoc ( " ASSOC_RESP: internal timer "
" expired while waiting for the AP \n " ) ;
break ;
case 0x03 :
lbs_deb_assoc ( " ASSOC_RESP: association "
" refused by AP \n " ) ;
break ;
case 0x04 :
lbs_deb_assoc ( " ASSOC_RESP: authentication "
" refused by AP \n " ) ;
break ;
default :
lbs_deb_assoc ( " ASSOC_RESP: failure reason 0x%02x "
" unknown \n " , status_code ) ;
break ;
}
if ( status_code ) {
lbs_mac_event_disconnected ( priv ) ;
ret = - 1 ;
goto done ;
}
lbs_deb_hex ( LBS_DEB_ASSOC , " ASSOC_RESP " , ( void * ) & resp - > params ,
le16_to_cpu ( resp - > size ) - S_DS_GEN ) ;
/* Send a Media Connected event, according to the Spec */
priv - > connect_status = LBS_CONNECTED ;
/* Update current SSID and BSSID */
memcpy ( & priv - > curbssparams . ssid , & bss - > ssid , IW_ESSID_MAX_SIZE ) ;
priv - > curbssparams . ssid_len = bss - > ssid_len ;
memcpy ( priv - > curbssparams . bssid , bss - > bssid , ETH_ALEN ) ;
priv - > SNR [ TYPE_RXPD ] [ TYPE_AVG ] = 0 ;
priv - > NF [ TYPE_RXPD ] [ TYPE_AVG ] = 0 ;
memset ( priv - > rawSNR , 0x00 , sizeof ( priv - > rawSNR ) ) ;
memset ( priv - > rawNF , 0x00 , sizeof ( priv - > rawNF ) ) ;
priv - > nextSNRNF = 0 ;
priv - > numSNRNF = 0 ;
netif_carrier_on ( priv - > dev ) ;
if ( ! priv - > tx_pending_len )
netif_wake_queue ( priv - > dev ) ;
memcpy ( wrqu . ap_addr . sa_data , priv - > curbssparams . bssid , ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > dev , SIOCGIWAP , & wrqu , NULL ) ;
done :
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
}
2008-08-21 21:46:59 -04:00
static int lbs_adhoc_post ( struct lbs_private * priv , struct cmd_header * resp )
2008-04-02 16:27:10 +02:00
{
int ret = 0 ;
u16 command = le16_to_cpu ( resp - > command ) ;
u16 result = le16_to_cpu ( resp - > result ) ;
2008-08-21 21:46:59 -04:00
struct cmd_ds_802_11_ad_hoc_result * adhoc_resp ;
2008-04-02 16:27:10 +02:00
union iwreq_data wrqu ;
struct bss_descriptor * bss ;
lbs_deb_enter ( LBS_DEB_JOIN ) ;
2008-08-21 21:46:59 -04:00
adhoc_resp = ( struct cmd_ds_802_11_ad_hoc_result * ) resp ;
2008-04-02 16:27:10 +02:00
if ( ! priv - > in_progress_assoc_req ) {
lbs_deb_join ( " ADHOC_RESP: no in-progress association "
" request \n " ) ;
ret = - 1 ;
goto done ;
}
bss = & priv - > in_progress_assoc_req - > bss ;
/*
* Join result code 0 - - > SUCCESS
*/
if ( result ) {
2008-08-21 21:46:59 -04:00
lbs_deb_join ( " ADHOC_RESP: failed (result 0x%X) \n " , result ) ;
2008-04-02 16:27:10 +02:00
if ( priv - > connect_status = = LBS_CONNECTED )
lbs_mac_event_disconnected ( priv ) ;
ret = - 1 ;
goto done ;
}
/* Send a Media Connected event, according to the Spec */
priv - > connect_status = LBS_CONNECTED ;
if ( command = = CMD_RET ( CMD_802_11_AD_HOC_START ) ) {
/* Update the created network descriptor with the new BSSID */
2008-08-21 21:46:59 -04:00
memcpy ( bss - > bssid , adhoc_resp - > bssid , ETH_ALEN ) ;
2008-04-02 16:27:10 +02:00
}
/* Set the BSSID from the joined/started descriptor */
memcpy ( & priv - > curbssparams . bssid , bss - > bssid , ETH_ALEN ) ;
/* Set the new SSID to current SSID */
memcpy ( & priv - > curbssparams . ssid , & bss - > ssid , IW_ESSID_MAX_SIZE ) ;
priv - > curbssparams . ssid_len = bss - > ssid_len ;
netif_carrier_on ( priv - > dev ) ;
if ( ! priv - > tx_pending_len )
netif_wake_queue ( priv - > dev ) ;
memset ( & wrqu , 0 , sizeof ( wrqu ) ) ;
memcpy ( wrqu . ap_addr . sa_data , priv - > curbssparams . bssid , ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > dev , SIOCGIWAP , & wrqu , NULL ) ;
2008-10-27 15:59:26 -07:00
lbs_deb_join ( " ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d \n " ,
2008-09-24 18:13:14 -04:00
escape_ssid ( bss - > ssid , bss - > ssid_len ) ,
2008-10-27 15:59:26 -07:00
priv - > curbssparams . bssid ,
2008-08-21 21:46:59 -04:00
priv - > curbssparams . channel ) ;
2008-04-02 16:27:10 +02:00
done :
lbs_deb_leave_args ( LBS_DEB_JOIN , " ret %d " , ret ) ;
return ret ;
}