2007-02-10 12:25:27 -02:00
/**
* This file contains ioctl functions
*/
# include <linux/ctype.h>
# include <linux/delay.h>
# include <linux/if.h>
# include <linux/if_arp.h>
# include <linux/wireless.h>
# include <linux/bitops.h>
# include <net/ieee80211.h>
# include <net/iw_handler.h>
# include "host.h"
# include "radiotap.h"
# include "decl.h"
# include "defs.h"
# include "dev.h"
# include "join.h"
# include "wext.h"
# include "assoc.h"
2007-11-23 15:43:44 +01:00
static inline void lbs_postpone_association_work ( struct lbs_private * priv )
2007-10-26 10:12:14 +02:00
{
if ( priv - > adapter - > surpriseremoved )
return ;
cancel_delayed_work ( & priv - > assoc_work ) ;
queue_delayed_work ( priv - > work_thread , & priv - > assoc_work , HZ / 2 ) ;
}
2007-11-23 15:43:44 +01:00
static inline void lbs_cancel_association_work ( struct lbs_private * priv )
2007-10-26 10:12:14 +02:00
{
cancel_delayed_work ( & priv - > assoc_work ) ;
2007-11-23 21:50:20 -05:00
kfree ( priv - > adapter - > pending_assoc_req ) ;
priv - > adapter - > pending_assoc_req = NULL ;
2007-10-26 10:12:14 +02:00
}
2007-02-10 12:25:27 -02:00
/**
* @ brief Find the channel frequency power info with specific channel
*
2007-11-23 15:43:44 +01:00
* @ param adapter A pointer to struct lbs_adapter structure
2007-02-10 12:25:27 -02:00
* @ param band it can be BAND_A , BAND_G or BAND_B
* @ param channel the channel for looking
* @ return A pointer to struct chan_freq_power structure or NULL if not find .
*/
2007-11-23 15:43:44 +01:00
struct chan_freq_power * lbs_find_cfp_by_band_and_channel (
struct lbs_adapter * adapter ,
u8 band ,
u16 channel )
2007-02-10 12:25:27 -02:00
{
struct chan_freq_power * cfp = NULL ;
struct region_channel * rc ;
int i , j ;
2007-10-18 10:16:33 +02:00
for ( j = 0 ; ! cfp & & ( j < ARRAY_SIZE ( adapter - > region_channel ) ) ; j + + ) {
2007-02-10 12:25:27 -02:00
rc = & adapter - > region_channel [ j ] ;
if ( adapter - > enable11d )
rc = & adapter - > universal_channel [ j ] ;
if ( ! rc - > valid | | ! rc - > CFP )
continue ;
if ( rc - > band ! = band )
continue ;
for ( i = 0 ; i < rc - > nrcfp ; i + + ) {
if ( rc - > CFP [ i ] . channel = = channel ) {
cfp = & rc - > CFP [ i ] ;
break ;
}
}
}
if ( ! cfp & & channel )
2007-11-15 18:05:47 -05:00
lbs_deb_wext ( " lbs_find_cfp_by_band_and_channel: can't find "
2007-05-25 11:27:16 -04:00
" cfp by band %d / channel %d \n " , band , channel ) ;
2007-02-10 12:25:27 -02:00
return cfp ;
}
/**
* @ brief Find the channel frequency power info with specific frequency
*
2007-11-23 15:43:44 +01:00
* @ param adapter A pointer to struct lbs_adapter structure
2007-02-10 12:25:27 -02:00
* @ param band it can be BAND_A , BAND_G or BAND_B
* @ param freq the frequency for looking
* @ return A pointer to struct chan_freq_power structure or NULL if not find .
*/
2007-11-23 15:43:44 +01:00
static struct chan_freq_power * find_cfp_by_band_and_freq (
struct lbs_adapter * adapter ,
u8 band ,
u32 freq )
2007-02-10 12:25:27 -02:00
{
struct chan_freq_power * cfp = NULL ;
struct region_channel * rc ;
int i , j ;
2007-10-18 10:16:33 +02:00
for ( j = 0 ; ! cfp & & ( j < ARRAY_SIZE ( adapter - > region_channel ) ) ; j + + ) {
2007-02-10 12:25:27 -02:00
rc = & adapter - > region_channel [ j ] ;
if ( adapter - > enable11d )
rc = & adapter - > universal_channel [ j ] ;
if ( ! rc - > valid | | ! rc - > CFP )
continue ;
if ( rc - > band ! = band )
continue ;
for ( i = 0 ; i < rc - > nrcfp ; i + + ) {
if ( rc - > CFP [ i ] . freq = = freq ) {
cfp = & rc - > CFP [ i ] ;
break ;
}
}
}
if ( ! cfp & & freq )
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " find_cfp_by_band_and_freql: can't find cfp by "
" band %d / freq %d \n " , band , freq ) ;
2007-02-10 12:25:27 -02:00
return cfp ;
}
/**
* @ brief Set Radio On / OFF
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ option Radio Option
* @ return 0 - - success , otherwise fail
*/
2007-11-23 15:43:44 +01:00
static int lbs_radio_ioctl ( struct lbs_private * priv , u8 option )
2007-02-10 12:25:27 -02:00
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( adapter - > radioon ! = option ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " switching radio %s \n " , option ? " on " : " off " ) ;
2007-02-10 12:25:27 -02:00
adapter - > radioon = option ;
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_RADIO_CONTROL ,
CMD_ACT_SET ,
CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
2007-08-02 11:40:45 -04:00
* @ brief Copy active data rates based on adapter mode and status
2007-02-10 12:25:27 -02:00
*
2007-11-23 15:43:44 +01:00
* @ param adapter A pointer to struct lbs_adapter structure
2007-02-10 12:25:27 -02:00
* @ param rate The buf to return the active rates
*/
2007-11-23 15:43:44 +01:00
static void copy_active_data_rates ( struct lbs_adapter * adapter , u8 * rates )
2007-02-10 12:25:27 -02:00
{
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-11-20 17:44:14 -05:00
if ( ( adapter - > connect_status ! = LBS_CONNECTED ) & &
( adapter - > mesh_connect_status ! = LBS_CONNECTED ) )
2007-11-15 18:05:47 -05:00
memcpy ( rates , lbs_bg_rates , MAX_RATES ) ;
2007-08-02 11:40:45 -04:00
else
memcpy ( rates , adapter - > curbssparams . rates , MAX_RATES ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:40:45 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_get_name ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
char * cwrq , char * extra )
{
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 13:16:30 -04:00
/* We could add support for 802.11n here as needed. Jean II */
snprintf ( cwrq , IFNAMSIZ , " IEEE 802.11b/g " ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_freq ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_freq * fwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct chan_freq_power * cfp ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
cfp = lbs_find_cfp_by_band_and_channel ( adapter , 0 ,
2007-02-10 12:25:27 -02:00
adapter - > curbssparams . channel ) ;
if ( ! cfp ) {
if ( adapter - > curbssparams . channel )
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " invalid channel %d \n " ,
2007-02-10 12:25:27 -02:00
adapter - > curbssparams . channel ) ;
return - EINVAL ;
}
fwrq - > m = ( long ) cfp - > freq * 100000 ;
fwrq - > e = 1 ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " freq %u \n " , fwrq - > m ) ;
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_wap ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct sockaddr * awrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
if ( adapter - > connect_status = = LBS_CONNECTED ) {
2007-02-10 12:25:27 -02:00
memcpy ( awrq - > sa_data , adapter - > curbssparams . bssid , ETH_ALEN ) ;
} else {
memset ( awrq - > sa_data , 0 , ETH_ALEN ) ;
}
awrq - > sa_family = ARPHRD_ETHER ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_nick ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_point * dwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/*
* Check the size of the string
*/
if ( dwrq - > length > 16 ) {
return - E2BIG ;
}
mutex_lock ( & adapter - > lock ) ;
memset ( adapter - > nodename , 0 , sizeof ( adapter - > nodename ) ) ;
memcpy ( adapter - > nodename , extra , dwrq - > length ) ;
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_nick ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_point * dwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-10-09 15:04:14 +02:00
dwrq - > length = strlen ( adapter - > nodename ) ;
memcpy ( extra , adapter - > nodename , dwrq - > length ) ;
extra [ dwrq - > length ] = ' \0 ' ;
2007-02-10 12:25:27 -02:00
2007-10-09 15:04:14 +02:00
dwrq - > flags = 1 ; /* active */
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-05-25 23:08:34 -04:00
static int mesh_get_nick ( struct net_device * dev , struct iw_request_info * info ,
struct iw_point * dwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-05-25 23:08:34 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
/* Use nickname to indicate that mesh is on */
2007-11-20 17:44:14 -05:00
if ( adapter - > mesh_connect_status = = LBS_CONNECTED ) {
2007-05-25 23:08:34 -04:00
strncpy ( extra , " Mesh " , 12 ) ;
extra [ 12 ] = ' \0 ' ;
2007-08-02 13:16:30 -04:00
dwrq - > length = strlen ( extra ) ;
2007-05-25 23:08:34 -04:00
}
else {
extra [ 0 ] = ' \0 ' ;
2007-08-02 13:16:30 -04:00
dwrq - > length = 0 ;
2007-05-25 23:08:34 -04:00
}
lbs_deb_leave ( LBS_DEB_WEXT ) ;
return 0 ;
}
2007-10-09 15:04:14 +02:00
2007-11-15 18:05:47 -05:00
static int lbs_set_rts ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-05-25 23:36:54 -04:00
u32 rthr = vwrq - > value ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( vwrq - > disabled ) {
adapter - > rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE ;
} else {
if ( rthr < MRVDRV_RTS_MIN_VALUE | | rthr > MRVDRV_RTS_MAX_VALUE )
return - EINVAL ;
adapter - > rtsthsd = rthr ;
}
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_SNMP_MIB ,
2007-08-02 11:31:18 -04:00
CMD_ACT_SET , CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_RTS_THRESHOLD , & rthr ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_rts ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
adapter - > rtsthsd = 0 ;
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_SNMP_MIB ,
2007-08-02 11:31:18 -04:00
CMD_ACT_GET , CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_RTS_THRESHOLD , NULL ) ;
2007-05-25 11:27:16 -04:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
vwrq - > value = adapter - > rtsthsd ;
vwrq - > disabled = ( ( vwrq - > value < MRVDRV_RTS_MIN_VALUE )
| | ( vwrq - > value > MRVDRV_RTS_MAX_VALUE ) ) ;
vwrq - > fixed = 1 ;
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_set_frag ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-05-25 23:36:54 -04:00
u32 fthr = vwrq - > value ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( vwrq - > disabled ) {
adapter - > fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE ;
} else {
if ( fthr < MRVDRV_FRAG_MIN_VALUE
| | fthr > MRVDRV_FRAG_MAX_VALUE )
return - EINVAL ;
adapter - > fragthsd = fthr ;
}
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_SNMP_MIB ,
2007-08-02 11:31:18 -04:00
CMD_ACT_SET , CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_FRAGMENTATION_THRESHOLD , & fthr ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_frag ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
adapter - > fragthsd = 0 ;
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_SNMP_MIB ,
CMD_ACT_GET , CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_FRAGMENTATION_THRESHOLD , NULL ) ;
2007-05-25 11:27:16 -04:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
vwrq - > value = adapter - > fragthsd ;
vwrq - > disabled = ( ( vwrq - > value < MRVDRV_FRAG_MIN_VALUE )
| | ( vwrq - > value > MRVDRV_FRAG_MAX_VALUE ) ) ;
vwrq - > fixed = 1 ;
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_mode ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info , u32 * uwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-05-10 22:58:02 -04:00
* uwrq = adapter - > mode ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-05-25 23:08:34 -04:00
static int mesh_wlan_get_mode ( struct net_device * dev ,
struct iw_request_info * info , u32 * uwrq ,
char * extra )
{
lbs_deb_enter ( LBS_DEB_WEXT ) ;
* uwrq = IW_MODE_REPEAT ;
lbs_deb_leave ( LBS_DEB_WEXT ) ;
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_txpow ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_RF_TX_POWER ,
CMD_ACT_TX_POWER_OPT_GET ,
CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " tx power level %d dbm \n " , adapter - > txpowerlevel ) ;
2007-02-10 12:25:27 -02:00
vwrq - > value = adapter - > txpowerlevel ;
vwrq - > fixed = 1 ;
if ( adapter - > radioon ) {
vwrq - > disabled = 0 ;
vwrq - > flags = IW_TXPOW_DBM ;
} else {
vwrq - > disabled = 1 ;
}
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_set_retry ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( vwrq - > flags = = IW_RETRY_LIMIT ) {
/* The MAC has a 4-bit Total_Tx_Count register
Total_Tx_Count = 1 + Tx_Retry_Count */
# define TX_RETRY_MIN 0
# define TX_RETRY_MAX 14
if ( vwrq - > value < TX_RETRY_MIN | | vwrq - > value > TX_RETRY_MAX )
return - EINVAL ;
/* Adding 1 to convert retry count to try count */
adapter - > txretrycount = vwrq - > value + 1 ;
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_SNMP_MIB ,
2007-08-02 11:31:18 -04:00
CMD_ACT_SET ,
CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_TX_RETRYCOUNT , NULL ) ;
2007-05-25 11:27:16 -04:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
} else {
return - EOPNOTSUPP ;
}
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_get_retry ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
int ret = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
adapter - > txretrycount = 0 ;
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_SNMP_MIB ,
CMD_ACT_GET , CMD_OPTION_WAITFORRSP ,
2007-02-10 12:25:27 -02:00
OID_802_11_TX_RETRYCOUNT , NULL ) ;
2007-05-25 11:27:16 -04:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
vwrq - > disabled = 0 ;
if ( ! vwrq - > flags ) {
vwrq - > flags = IW_RETRY_LIMIT ;
/* Subtract 1 to convert try count to retry count */
vwrq - > value = adapter - > txretrycount - 1 ;
}
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
static inline void sort_channels ( struct iw_freq * freq , int num )
{
int i , j ;
struct iw_freq temp ;
for ( i = 0 ; i < num ; i + + )
for ( j = i + 1 ; j < num ; j + + )
if ( freq [ i ] . i > freq [ j ] . i ) {
temp . i = freq [ i ] . i ;
temp . m = freq [ i ] . m ;
freq [ i ] . i = freq [ j ] . i ;
freq [ i ] . m = freq [ j ] . m ;
freq [ j ] . i = temp . i ;
freq [ j ] . m = temp . m ;
}
}
/* data rate listing
MULTI_BANDS :
abg a b b / g
Infra G ( 12 ) A ( 8 ) B ( 4 ) G ( 12 )
Adhoc A + B ( 12 ) A ( 8 ) B ( 4 ) B ( 4 )
non - MULTI_BANDS :
b b / g
Infra B ( 4 ) G ( 12 )
Adhoc B ( 4 ) B ( 4 )
*/
/**
* @ brief Get Range Info
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param vwrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_get_range ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_point * dwrq , char * extra )
{
int i , j ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct iw_range * range = ( struct iw_range * ) extra ;
struct chan_freq_power * cfp ;
2007-08-02 11:40:45 -04:00
u8 rates [ MAX_RATES + 1 ] ;
2007-02-10 12:25:27 -02:00
u8 flag = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
dwrq - > length = sizeof ( struct iw_range ) ;
memset ( range , 0 , sizeof ( struct iw_range ) ) ;
range - > min_nwid = 0 ;
range - > max_nwid = 0 ;
memset ( rates , 0 , sizeof ( rates ) ) ;
2007-08-02 11:40:45 -04:00
copy_active_data_rates ( adapter , rates ) ;
range - > num_bitrates = strnlen ( rates , IW_MAX_BITRATES ) ;
for ( i = 0 ; i < range - > num_bitrates ; i + + )
range - > bitrate [ i ] = rates [ i ] * 500000 ;
2007-02-10 12:25:27 -02:00
range - > num_bitrates = i ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " IW_MAX_BITRATES %d, num_bitrates %d \n " , IW_MAX_BITRATES ,
2007-02-10 12:25:27 -02:00
range - > num_bitrates ) ;
range - > num_frequency = 0 ;
if ( priv - > adapter - > enable11d & &
2007-11-20 17:44:14 -05:00
( adapter - > connect_status = = LBS_CONNECTED | |
adapter - > mesh_connect_status = = LBS_CONNECTED ) ) {
2007-02-10 12:25:27 -02:00
u8 chan_no ;
u8 band ;
struct parsed_region_chan_11d * parsed_region_chan =
& adapter - > parsed_region_chan ;
if ( parsed_region_chan = = NULL ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " 11d: parsed_region_chan is NULL \n " ) ;
goto out ;
2007-02-10 12:25:27 -02:00
}
band = parsed_region_chan - > band ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " band %d, nr_char %d \n " , band ,
2007-02-10 12:25:27 -02:00
parsed_region_chan - > nr_chan ) ;
for ( i = 0 ; ( range - > num_frequency < IW_MAX_FREQUENCIES )
& & ( i < parsed_region_chan - > nr_chan ) ; i + + ) {
chan_no = parsed_region_chan - > chanpwr [ i ] . chan ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " chan_no %d \n " , chan_no ) ;
2007-02-10 12:25:27 -02:00
range - > freq [ range - > num_frequency ] . i = ( long ) chan_no ;
range - > freq [ range - > num_frequency ] . m =
2007-11-15 18:05:47 -05:00
( long ) lbs_chan_2_freq ( chan_no , band ) * 100000 ;
2007-02-10 12:25:27 -02:00
range - > freq [ range - > num_frequency ] . e = 1 ;
range - > num_frequency + + ;
}
flag = 1 ;
}
if ( ! flag ) {
for ( j = 0 ; ( range - > num_frequency < IW_MAX_FREQUENCIES )
2007-10-18 10:16:33 +02:00
& & ( j < ARRAY_SIZE ( adapter - > region_channel ) ) ; j + + ) {
2007-02-10 12:25:27 -02:00
cfp = adapter - > region_channel [ j ] . CFP ;
for ( i = 0 ; ( range - > num_frequency < IW_MAX_FREQUENCIES )
& & adapter - > region_channel [ j ] . valid
& & cfp
& & ( i < adapter - > region_channel [ j ] . nrcfp ) ; i + + ) {
range - > freq [ range - > num_frequency ] . i =
( long ) cfp - > channel ;
range - > freq [ range - > num_frequency ] . m =
( long ) cfp - > freq * 100000 ;
range - > freq [ range - > num_frequency ] . e = 1 ;
cfp + + ;
range - > num_frequency + + ;
}
}
}
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " IW_MAX_FREQUENCIES %d, num_frequency %d \n " ,
2007-02-10 12:25:27 -02:00
IW_MAX_FREQUENCIES , range - > num_frequency ) ;
range - > num_channels = range - > num_frequency ;
sort_channels ( & range - > freq [ 0 ] , range - > num_frequency ) ;
/*
* Set an indication of the max TCP throughput in bit / s that we can
* expect using this interface
*/
if ( i > 2 )
range - > throughput = 5000 * 1000 ;
else
range - > throughput = 1500 * 1000 ;
range - > min_rts = MRVDRV_RTS_MIN_VALUE ;
range - > max_rts = MRVDRV_RTS_MAX_VALUE ;
range - > min_frag = MRVDRV_FRAG_MIN_VALUE ;
range - > max_frag = MRVDRV_FRAG_MAX_VALUE ;
range - > encoding_size [ 0 ] = 5 ;
range - > encoding_size [ 1 ] = 13 ;
range - > num_encoding_sizes = 2 ;
range - > max_encoding_tokens = 4 ;
range - > min_pmp = 1000000 ;
range - > max_pmp = 120000000 ;
range - > min_pmt = 1000 ;
range - > max_pmt = 1000000 ;
range - > pmp_flags = IW_POWER_PERIOD ;
range - > pmt_flags = IW_POWER_TIMEOUT ;
range - > pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R ;
/*
* Minimum version we recommend
*/
range - > we_version_source = 15 ;
/*
* Version we are compiled with
*/
range - > we_version_compiled = WIRELESS_EXT ;
range - > retry_capa = IW_RETRY_LIMIT ;
range - > retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX ;
range - > min_retry = TX_RETRY_MIN ;
range - > max_retry = TX_RETRY_MAX ;
/*
* Set the qual , level and noise range values
*/
range - > max_qual . qual = 100 ;
range - > max_qual . level = 0 ;
range - > max_qual . noise = 0 ;
range - > max_qual . updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM ;
range - > avg_qual . qual = 70 ;
/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range - > avg_qual . level = 0 ;
range - > avg_qual . noise = 0 ;
range - > avg_qual . updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM ;
range - > sensitivity = 0 ;
/*
* Setup the supported power level ranges
*/
memset ( range - > txpower , 0 , sizeof ( range - > txpower ) ) ;
range - > txpower [ 0 ] = 5 ;
range - > txpower [ 1 ] = 7 ;
range - > txpower [ 2 ] = 9 ;
range - > txpower [ 3 ] = 11 ;
range - > txpower [ 4 ] = 13 ;
range - > txpower [ 5 ] = 15 ;
range - > txpower [ 6 ] = 17 ;
range - > txpower [ 7 ] = 19 ;
range - > num_txpower = 8 ;
range - > txpower_capa = IW_TXPOW_DBM ;
range - > txpower_capa | = IW_TXPOW_RANGE ;
range - > event_capa [ 0 ] = ( IW_EVENT_CAPA_K_0 |
IW_EVENT_CAPA_MASK ( SIOCGIWAP ) |
IW_EVENT_CAPA_MASK ( SIOCGIWSCAN ) ) ;
range - > event_capa [ 1 ] = IW_EVENT_CAPA_K_1 ;
if ( adapter - > fwcapinfo & FW_CAPINFO_WPA ) {
range - > enc_capa = IW_ENC_CAPA_WPA
| IW_ENC_CAPA_WPA2
| IW_ENC_CAPA_CIPHER_TKIP
| IW_ENC_CAPA_CIPHER_CCMP ;
}
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_power ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/* PS is currently supported only in Infrastructure mode
* Remove this check if it is to be supported in IBSS mode also
*/
if ( vwrq - > disabled ) {
2007-11-15 18:05:47 -05:00
adapter - > psmode = LBS802_11POWERMODECAM ;
2007-02-10 12:25:27 -02:00
if ( adapter - > psstate ! = PS_STATE_FULL_POWER ) {
2007-11-15 18:05:47 -05:00
lbs_ps_wakeup ( priv , CMD_OPTION_WAITFORRSP ) ;
2007-02-10 12:25:27 -02:00
}
return 0 ;
}
if ( ( vwrq - > flags & IW_POWER_TYPE ) = = IW_POWER_TIMEOUT ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext (
" setting power timeout is not supported \n " ) ;
2007-02-10 12:25:27 -02:00
return - EINVAL ;
} else if ( ( vwrq - > flags & IW_POWER_TYPE ) = = IW_POWER_PERIOD ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " setting power period not supported \n " ) ;
2007-02-10 12:25:27 -02:00
return - EINVAL ;
}
2007-11-15 18:05:47 -05:00
if ( adapter - > psmode ! = LBS802_11POWERMODECAM ) {
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
adapter - > psmode = LBS802_11POWERMODEMAX_PSP ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
if ( adapter - > connect_status = = LBS_CONNECTED ) {
lbs_ps_sleep ( priv , CMD_OPTION_WAITFORRSP ) ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_power ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
int mode ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
mode = adapter - > psmode ;
2007-11-15 18:05:47 -05:00
if ( ( vwrq - > disabled = ( mode = = LBS802_11POWERMODECAM ) )
| | adapter - > connect_status = = LBS_DISCONNECTED )
2007-05-25 11:27:16 -04:00
{
goto out ;
2007-02-10 12:25:27 -02:00
}
vwrq - > value = 0 ;
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static struct iw_statistics * lbs_get_wireless_stats ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
enum {
POOR = 30 ,
FAIR = 60 ,
GOOD = 80 ,
VERY_GOOD = 90 ,
EXCELLENT = 95 ,
PERFECT = 100
} ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
u32 rssi_qual ;
u32 tx_qual ;
u32 quality = 0 ;
int stats_valid = 0 ;
u8 rssi ;
u32 tx_retries ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-05-10 22:58:02 -04:00
priv - > wstats . status = adapter - > mode ;
2007-02-10 12:25:27 -02:00
/* If we're not associated, all quality values are meaningless */
2007-11-20 17:44:14 -05:00
if ( ( adapter - > connect_status ! = LBS_CONNECTED ) & &
( adapter - > mesh_connect_status ! = LBS_CONNECTED ) )
2007-02-10 12:25:27 -02:00
goto out ;
/* Quality by RSSI */
priv - > wstats . qual . level =
CAL_RSSI ( adapter - > SNR [ TYPE_BEACON ] [ TYPE_NOAVG ] ,
adapter - > NF [ TYPE_BEACON ] [ TYPE_NOAVG ] ) ;
if ( adapter - > NF [ TYPE_BEACON ] [ TYPE_NOAVG ] = = 0 ) {
priv - > wstats . qual . noise = MRVDRV_NF_DEFAULT_SCAN_VALUE ;
} else {
priv - > wstats . qual . noise =
CAL_NF ( adapter - > NF [ TYPE_BEACON ] [ TYPE_NOAVG ] ) ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " signal level %#x \n " , priv - > wstats . qual . level ) ;
lbs_deb_wext ( " noise %#x \n " , priv - > wstats . qual . noise ) ;
2007-02-10 12:25:27 -02:00
rssi = priv - > wstats . qual . level - priv - > wstats . qual . noise ;
if ( rssi < 15 )
rssi_qual = rssi * POOR / 10 ;
else if ( rssi < 20 )
rssi_qual = ( rssi - 15 ) * ( FAIR - POOR ) / 5 + POOR ;
else if ( rssi < 30 )
rssi_qual = ( rssi - 20 ) * ( GOOD - FAIR ) / 5 + FAIR ;
else if ( rssi < 40 )
rssi_qual = ( rssi - 30 ) * ( VERY_GOOD - GOOD ) /
10 + GOOD ;
else
rssi_qual = ( rssi - 40 ) * ( PERFECT - VERY_GOOD ) /
10 + VERY_GOOD ;
quality = rssi_qual ;
/* Quality by TX errors */
priv - > wstats . discard . retries = priv - > stats . tx_errors ;
2007-08-03 09:40:55 -04:00
tx_retries = le32_to_cpu ( adapter - > logmsg . retry ) ;
2007-02-10 12:25:27 -02:00
if ( tx_retries > 75 )
tx_qual = ( 90 - tx_retries ) * POOR / 15 ;
else if ( tx_retries > 70 )
tx_qual = ( 75 - tx_retries ) * ( FAIR - POOR ) / 5 + POOR ;
else if ( tx_retries > 65 )
tx_qual = ( 70 - tx_retries ) * ( GOOD - FAIR ) / 5 + FAIR ;
else if ( tx_retries > 50 )
tx_qual = ( 65 - tx_retries ) * ( VERY_GOOD - GOOD ) /
15 + GOOD ;
else
tx_qual = ( 50 - tx_retries ) *
( PERFECT - VERY_GOOD ) / 50 + VERY_GOOD ;
quality = min ( quality , tx_qual ) ;
2007-08-03 09:40:55 -04:00
priv - > wstats . discard . code = le32_to_cpu ( adapter - > logmsg . wepundecryptable ) ;
priv - > wstats . discard . fragment = le32_to_cpu ( adapter - > logmsg . rxfrag ) ;
2007-02-10 12:25:27 -02:00
priv - > wstats . discard . retries = tx_retries ;
2007-08-03 09:40:55 -04:00
priv - > wstats . discard . misc = le32_to_cpu ( adapter - > logmsg . ackfailure ) ;
2007-02-10 12:25:27 -02:00
/* Calculate quality */
2007-08-02 13:07:15 -04:00
priv - > wstats . qual . qual = min_t ( u8 , quality , 100 ) ;
2007-02-10 12:25:27 -02:00
priv - > wstats . qual . updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM ;
stats_valid = 1 ;
/* update stats asynchronously for future calls */
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv , CMD_802_11_RSSI , 0 ,
2007-02-10 12:25:27 -02:00
0 , 0 , NULL ) ;
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv , CMD_802_11_GET_LOG , 0 ,
2007-02-10 12:25:27 -02:00
0 , 0 , NULL ) ;
out :
if ( ! stats_valid ) {
priv - > wstats . miss . beacon = 0 ;
priv - > wstats . discard . retries = 0 ;
priv - > wstats . qual . qual = 0 ;
priv - > wstats . qual . level = 0 ;
priv - > wstats . qual . noise = 0 ;
priv - > wstats . qual . updated = IW_QUAL_ALL_UPDATED ;
priv - > wstats . qual . updated | = IW_QUAL_NOISE_INVALID |
IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return & priv - > wstats ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_freq ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_freq * fwrq , char * extra )
{
2007-05-25 16:46:33 -04:00
int ret = - EINVAL ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct chan_freq_power * cfp ;
2007-05-25 16:46:33 -04:00
struct assoc_request * assoc_req ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 16:46:33 -04:00
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-05-25 16:46:33 -04:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
goto out ;
}
2007-02-10 12:25:27 -02:00
2007-05-25 16:46:33 -04:00
/* If setting by frequency, convert to a channel */
if ( fwrq - > e = = 1 ) {
2007-02-10 12:25:27 -02:00
long f = fwrq - > m / 100000 ;
cfp = find_cfp_by_band_and_freq ( adapter , 0 , f ) ;
if ( ! cfp ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " invalid freq %ld \n " , f ) ;
2007-05-25 16:46:33 -04:00
goto out ;
2007-02-10 12:25:27 -02:00
}
fwrq - > e = 0 ;
2007-05-25 16:46:33 -04:00
fwrq - > m = ( int ) cfp - > channel ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 16:46:33 -04:00
/* Setting by channel number */
2007-02-10 12:25:27 -02:00
if ( fwrq - > m > 1000 | | fwrq - > e > 0 ) {
2007-05-25 16:46:33 -04:00
goto out ;
}
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
cfp = lbs_find_cfp_by_band_and_channel ( adapter , 0 , fwrq - > m ) ;
2007-05-25 16:46:33 -04:00
if ( ! cfp ) {
goto out ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 16:46:33 -04:00
assoc_req - > channel = fwrq - > m ;
ret = 0 ;
2007-05-25 11:27:16 -04:00
out :
2007-05-25 16:46:33 -04:00
if ( ret = = 0 ) {
set_bit ( ASSOC_FLAG_CHANNEL , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-05-25 16:46:33 -04:00
} else {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-05-25 16:46:33 -04:00
}
mutex_unlock ( & adapter - > lock ) ;
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_set_rate ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-08-02 11:40:45 -04:00
u32 new_rate ;
2007-02-10 12:25:27 -02:00
u16 action ;
2007-08-02 11:40:45 -04:00
int ret = - EINVAL ;
u8 rates [ MAX_RATES + 1 ] ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
lbs_deb_wext ( " vwrq->value %d \n " , vwrq - > value ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:40:45 -04:00
/* Auto rate? */
2007-02-10 12:25:27 -02:00
if ( vwrq - > value = = - 1 ) {
2007-08-02 11:40:45 -04:00
action = CMD_ACT_SET_TX_AUTO ;
adapter - > auto_rate = 1 ;
adapter - > cur_rate = 0 ;
2007-02-10 12:25:27 -02:00
} else {
2007-08-02 11:40:45 -04:00
if ( vwrq - > value % 100000 )
goto out ;
2007-02-10 12:25:27 -02:00
memset ( rates , 0 , sizeof ( rates ) ) ;
2007-08-02 11:40:45 -04:00
copy_active_data_rates ( adapter , rates ) ;
new_rate = vwrq - > value / 500000 ;
if ( ! memchr ( rates , new_rate , sizeof ( rates ) ) ) {
lbs_pr_alert ( " fixed data rate 0x%X out of range \n " ,
new_rate ) ;
goto out ;
2007-02-10 12:25:27 -02:00
}
2007-08-02 11:40:45 -04:00
adapter - > cur_rate = new_rate ;
2007-08-02 11:35:46 -04:00
action = CMD_ACT_SET_TX_FIX_RATE ;
2007-08-02 11:40:45 -04:00
adapter - > auto_rate = 0 ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_DATA_RATE ,
2007-08-02 11:31:18 -04:00
action , CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:40:45 -04:00
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_rate ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
if ( adapter - > connect_status = = LBS_CONNECTED ) {
2007-08-02 11:40:45 -04:00
vwrq - > value = adapter - > cur_rate * 500000 ;
if ( adapter - > auto_rate )
vwrq - > fixed = 0 ;
else
vwrq - > fixed = 1 ;
2007-02-10 12:25:27 -02:00
} else {
2007-08-02 11:40:45 -04:00
vwrq - > fixed = 0 ;
vwrq - > value = 0 ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_mode ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info , u32 * uwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-05-10 22:58:02 -04:00
if ( ( * uwrq ! = IW_MODE_ADHOC )
& & ( * uwrq ! = IW_MODE_INFRA )
& & ( * uwrq ! = IW_MODE_AUTO ) ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " Invalid mode: 0x%x \n " , * uwrq ) ;
2007-05-10 22:58:02 -04:00
ret = - EINVAL ;
goto out ;
2007-02-10 12:25:27 -02:00
}
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-05-10 22:58:02 -04:00
assoc_req - > mode = * uwrq ;
2007-02-10 12:25:27 -02:00
set_bit ( ASSOC_FLAG_MODE , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " Switching to mode: 0x%x \n " , * uwrq ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-10 22:58:02 -04:00
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief Get Encryption key
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param vwrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_get_encode ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq , u8 * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
int index = ( dwrq - > flags & IW_ENCODE_INDEX ) - 1 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " flags 0x%x, index %d, length %d, wep_tx_keyidx %d \n " ,
2007-02-10 12:25:27 -02:00
dwrq - > flags , index , dwrq - > length , adapter - > wep_tx_keyidx ) ;
dwrq - > flags = 0 ;
/* Authentication method */
2007-05-10 22:56:42 -04:00
switch ( adapter - > secinfo . auth_mode ) {
case IW_AUTH_ALG_OPEN_SYSTEM :
2007-02-10 12:25:27 -02:00
dwrq - > flags = IW_ENCODE_OPEN ;
break ;
2007-05-10 22:56:42 -04:00
case IW_AUTH_ALG_SHARED_KEY :
case IW_AUTH_ALG_LEAP :
2007-02-10 12:25:27 -02:00
dwrq - > flags = IW_ENCODE_RESTRICTED ;
break ;
default :
dwrq - > flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN ;
break ;
}
2007-05-10 22:57:23 -04:00
if ( adapter - > secinfo . wep_enabled
| | adapter - > secinfo . WPAenabled
| | adapter - > secinfo . WPA2enabled ) {
2007-02-10 12:25:27 -02:00
dwrq - > flags & = ~ IW_ENCODE_DISABLED ;
} else {
dwrq - > flags | = IW_ENCODE_DISABLED ;
}
memset ( extra , 0 , 16 ) ;
mutex_lock ( & adapter - > lock ) ;
/* Default to returning current transmit key */
if ( index < 0 )
index = adapter - > wep_tx_keyidx ;
2007-05-10 22:57:23 -04:00
if ( ( adapter - > wep_keys [ index ] . len ) & & adapter - > secinfo . wep_enabled ) {
2007-02-10 12:25:27 -02:00
memcpy ( extra , adapter - > wep_keys [ index ] . key ,
adapter - > wep_keys [ index ] . len ) ;
dwrq - > length = adapter - > wep_keys [ index ] . len ;
dwrq - > flags | = ( index + 1 ) ;
/* Return WEP enabled */
dwrq - > flags & = ~ IW_ENCODE_DISABLED ;
} else if ( ( adapter - > secinfo . WPAenabled )
| | ( adapter - > secinfo . WPA2enabled ) ) {
/* return WPA enabled */
dwrq - > flags & = ~ IW_ENCODE_DISABLED ;
} else {
dwrq - > flags | = IW_ENCODE_DISABLED ;
}
mutex_unlock ( & adapter - > lock ) ;
dwrq - > flags | = IW_ENCODE_NOKEY ;
2007-10-03 17:59:30 -07:00
lbs_deb_wext ( " key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d \n " ,
2007-02-10 12:25:27 -02:00
extra [ 0 ] , extra [ 1 ] , extra [ 2 ] ,
extra [ 3 ] , extra [ 4 ] , extra [ 5 ] , dwrq - > length ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " return flags 0x%x \n " , dwrq - > flags ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
/**
* @ brief Set Encryption key ( internal )
*
* @ param priv A pointer to private card structure
* @ param key_material A pointer to key material
* @ param key_length length of key material
* @ param index key index to set
* @ param set_tx_key Force set TX key ( 1 = yes , 0 = no )
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_set_wep_key ( struct assoc_request * assoc_req ,
2007-02-10 12:25:27 -02:00
const char * key_material ,
u16 key_length ,
u16 index ,
int set_tx_key )
{
2007-05-25 11:27:16 -04:00
int ret = 0 ;
2007-08-02 10:45:55 -04:00
struct enc_key * pkey ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/* Paranoid validation of key index */
if ( index > 3 ) {
2007-05-25 11:27:16 -04:00
ret = - EINVAL ;
goto out ;
2007-02-10 12:25:27 -02:00
}
/* validate max key length */
if ( key_length > KEY_LEN_WEP_104 ) {
2007-05-25 11:27:16 -04:00
ret = - EINVAL ;
goto out ;
2007-02-10 12:25:27 -02:00
}
pkey = & assoc_req - > wep_keys [ index ] ;
if ( key_length > 0 ) {
2007-08-02 10:45:55 -04:00
memset ( pkey , 0 , sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
pkey - > type = KEY_TYPE_ID_WEP ;
/* Standardize the key length */
pkey - > len = ( key_length > KEY_LEN_WEP_40 ) ?
KEY_LEN_WEP_104 : KEY_LEN_WEP_40 ;
memcpy ( pkey - > key , key_material , key_length ) ;
}
if ( set_tx_key ) {
/* Ensure the chosen key is valid */
if ( ! pkey - > len ) {
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " key not set, so cannot enable it \n " ) ;
ret = - EINVAL ;
goto out ;
2007-02-10 12:25:27 -02:00
}
assoc_req - > wep_tx_keyidx = index ;
}
2007-05-10 22:57:23 -04:00
assoc_req - > secinfo . wep_enabled = 1 ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
static int validate_key_index ( u16 def_index , u16 raw_index ,
u16 * out_index , u16 * is_default )
{
if ( ! out_index | | ! is_default )
return - EINVAL ;
/* Verify index if present, otherwise use default TX key index */
if ( raw_index > 0 ) {
if ( raw_index > 4 )
return - EINVAL ;
* out_index = raw_index - 1 ;
} else {
* out_index = def_index ;
* is_default = 1 ;
}
return 0 ;
}
static void disable_wep ( struct assoc_request * assoc_req )
{
int i ;
2007-05-25 23:01:24 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/* Set Open System auth mode */
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
/* Clear WEP keys and mark WEP as disabled */
2007-05-10 22:57:23 -04:00
assoc_req - > secinfo . wep_enabled = 0 ;
2007-02-10 12:25:27 -02:00
for ( i = 0 ; i < 4 ; i + + )
assoc_req - > wep_keys [ i ] . len = 0 ;
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
set_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags ) ;
2007-05-25 23:01:24 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
}
static void disable_wpa ( struct assoc_request * assoc_req )
{
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-08-02 10:45:55 -04:00
memset ( & assoc_req - > wpa_mcast_key , 0 , sizeof ( struct enc_key ) ) ;
2007-05-25 23:01:24 -04:00
assoc_req - > wpa_mcast_key . flags = KEY_INFO_WPA_MCAST ;
set_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags ) ;
2007-08-02 10:45:55 -04:00
memset ( & assoc_req - > wpa_unicast_key , 0 , sizeof ( struct enc_key ) ) ;
2007-05-25 23:01:24 -04:00
assoc_req - > wpa_unicast_key . flags = KEY_INFO_WPA_UNICAST ;
set_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ;
assoc_req - > secinfo . WPAenabled = 0 ;
assoc_req - > secinfo . WPA2enabled = 0 ;
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief Set Encryption key
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param vwrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_set_encode ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req ;
u16 is_default = 0 , index = 0 , set_tx_key = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
goto out ;
}
if ( dwrq - > flags & IW_ENCODE_DISABLED ) {
disable_wep ( assoc_req ) ;
2007-05-25 23:01:24 -04:00
disable_wpa ( assoc_req ) ;
2007-02-10 12:25:27 -02:00
goto out ;
}
ret = validate_key_index ( assoc_req - > wep_tx_keyidx ,
( dwrq - > flags & IW_ENCODE_INDEX ) ,
& index , & is_default ) ;
if ( ret ) {
ret = - EINVAL ;
goto out ;
}
/* If WEP isn't enabled, or if there is no key data but a valid
* index , set the TX key .
*/
2007-05-10 22:57:23 -04:00
if ( ! assoc_req - > secinfo . wep_enabled | | ( dwrq - > length = = 0 & & ! is_default ) )
2007-02-10 12:25:27 -02:00
set_tx_key = 1 ;
2007-11-15 18:05:47 -05:00
ret = lbs_set_wep_key ( assoc_req , extra , dwrq - > length , index , set_tx_key ) ;
2007-02-10 12:25:27 -02:00
if ( ret )
goto out ;
if ( dwrq - > length )
set_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags ) ;
if ( set_tx_key )
set_bit ( ASSOC_FLAG_WEP_TX_KEYIDX , & assoc_req - > flags ) ;
if ( dwrq - > flags & IW_ENCODE_RESTRICTED ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_SHARED_KEY ;
2007-02-10 12:25:27 -02:00
} else if ( dwrq - > flags & IW_ENCODE_OPEN ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
}
out :
if ( ret = = 0 ) {
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief Get Extended Encryption key ( WPA / 802.1 x and WEP )
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param vwrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 on success , otherwise failure
*/
2007-11-15 18:05:47 -05:00
static int lbs_get_encodeext ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq ,
char * extra )
{
int ret = - EINVAL ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct iw_encode_ext * ext = ( struct iw_encode_ext * ) extra ;
int index , max_key_len ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
max_key_len = dwrq - > length - sizeof ( * ext ) ;
if ( max_key_len < 0 )
goto out ;
index = dwrq - > flags & IW_ENCODE_INDEX ;
if ( index ) {
if ( index < 1 | | index > 4 )
goto out ;
index - - ;
} else {
index = adapter - > wep_tx_keyidx ;
}
2007-10-26 21:51:26 +02:00
if ( ! ( ext - > ext_flags & IW_ENCODE_EXT_GROUP_KEY ) & &
2007-02-10 12:25:27 -02:00
ext - > alg ! = IW_ENCODE_ALG_WEP ) {
2007-05-10 22:58:02 -04:00
if ( index ! = 0 | | adapter - > mode ! = IW_MODE_INFRA )
2007-02-10 12:25:27 -02:00
goto out ;
}
dwrq - > flags = index + 1 ;
memset ( ext , 0 , sizeof ( * ext ) ) ;
2007-05-10 22:57:23 -04:00
if ( ! adapter - > secinfo . wep_enabled
& & ! adapter - > secinfo . WPAenabled
& & ! adapter - > secinfo . WPA2enabled ) {
2007-02-10 12:25:27 -02:00
ext - > alg = IW_ENCODE_ALG_NONE ;
ext - > key_len = 0 ;
dwrq - > flags | = IW_ENCODE_DISABLED ;
} else {
u8 * key = NULL ;
2007-05-10 22:57:23 -04:00
if ( adapter - > secinfo . wep_enabled
2007-02-10 12:25:27 -02:00
& & ! adapter - > secinfo . WPAenabled
& & ! adapter - > secinfo . WPA2enabled ) {
2007-05-25 23:01:24 -04:00
/* WEP */
2007-02-10 12:25:27 -02:00
ext - > alg = IW_ENCODE_ALG_WEP ;
ext - > key_len = adapter - > wep_keys [ index ] . len ;
key = & adapter - > wep_keys [ index ] . key [ 0 ] ;
2007-05-10 22:57:23 -04:00
} else if ( ! adapter - > secinfo . wep_enabled
& & ( adapter - > secinfo . WPAenabled | |
adapter - > secinfo . WPA2enabled ) ) {
2007-02-10 12:25:27 -02:00
/* WPA */
2007-08-02 10:45:55 -04:00
struct enc_key * pkey = NULL ;
2007-05-25 23:01:24 -04:00
if ( adapter - > wpa_mcast_key . len
& & ( adapter - > wpa_mcast_key . flags & KEY_INFO_WPA_ENABLED ) )
pkey = & adapter - > wpa_mcast_key ;
else if ( adapter - > wpa_unicast_key . len
& & ( adapter - > wpa_unicast_key . flags & KEY_INFO_WPA_ENABLED ) )
pkey = & adapter - > wpa_unicast_key ;
if ( pkey ) {
if ( pkey - > type = = KEY_TYPE_ID_AES ) {
ext - > alg = IW_ENCODE_ALG_CCMP ;
} else {
ext - > alg = IW_ENCODE_ALG_TKIP ;
}
ext - > key_len = pkey - > len ;
key = & pkey - > key [ 0 ] ;
} else {
ext - > alg = IW_ENCODE_ALG_TKIP ;
ext - > key_len = 0 ;
}
2007-02-10 12:25:27 -02:00
} else {
goto out ;
}
if ( ext - > key_len > max_key_len ) {
ret = - E2BIG ;
goto out ;
}
if ( ext - > key_len )
memcpy ( ext - > key , key , ext - > key_len ) ;
else
dwrq - > flags | = IW_ENCODE_NOKEY ;
dwrq - > flags | = IW_ENCODE_ENABLED ;
}
ret = 0 ;
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief Set Encryption key Extended ( WPA / 802.1 x and WEP )
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param vwrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_set_encodeext ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq ,
char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct iw_encode_ext * ext = ( struct iw_encode_ext * ) extra ;
int alg = ext - > alg ;
struct assoc_request * assoc_req ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
goto out ;
}
if ( ( alg = = IW_ENCODE_ALG_NONE ) | | ( dwrq - > flags & IW_ENCODE_DISABLED ) ) {
disable_wep ( assoc_req ) ;
2007-05-25 23:01:24 -04:00
disable_wpa ( assoc_req ) ;
2007-02-10 12:25:27 -02:00
} else if ( alg = = IW_ENCODE_ALG_WEP ) {
u16 is_default = 0 , index , set_tx_key = 0 ;
ret = validate_key_index ( assoc_req - > wep_tx_keyidx ,
( dwrq - > flags & IW_ENCODE_INDEX ) ,
& index , & is_default ) ;
if ( ret )
goto out ;
/* If WEP isn't enabled, or if there is no key data but a valid
* index , or if the set - TX - key flag was passed , set the TX key .
*/
2007-05-10 22:57:23 -04:00
if ( ! assoc_req - > secinfo . wep_enabled
2007-02-10 12:25:27 -02:00
| | ( dwrq - > length = = 0 & & ! is_default )
| | ( ext - > ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) )
set_tx_key = 1 ;
/* Copy key to driver */
2007-11-15 18:05:47 -05:00
ret = lbs_set_wep_key ( assoc_req , ext - > key , ext - > key_len , index ,
2007-02-10 12:25:27 -02:00
set_tx_key ) ;
if ( ret )
goto out ;
if ( dwrq - > flags & IW_ENCODE_RESTRICTED ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_SHARED_KEY ;
2007-02-10 12:25:27 -02:00
} else if ( dwrq - > flags & IW_ENCODE_OPEN ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
}
/* Mark the various WEP bits as modified */
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
if ( dwrq - > length )
set_bit ( ASSOC_FLAG_WEP_KEYS , & assoc_req - > flags ) ;
if ( set_tx_key )
set_bit ( ASSOC_FLAG_WEP_TX_KEYIDX , & assoc_req - > flags ) ;
} else if ( ( alg = = IW_ENCODE_ALG_TKIP ) | | ( alg = = IW_ENCODE_ALG_CCMP ) ) {
2007-08-02 10:45:55 -04:00
struct enc_key * pkey ;
2007-02-10 12:25:27 -02:00
/* validate key length */
if ( ( ( alg = = IW_ENCODE_ALG_TKIP )
& & ( ext - > key_len ! = KEY_LEN_WPA_TKIP ) )
| | ( ( alg = = IW_ENCODE_ALG_CCMP )
& & ( ext - > key_len ! = KEY_LEN_WPA_AES ) ) ) {
2007-11-19 17:48:27 -08:00
lbs_deb_wext ( " invalid size %d for key of alg "
2007-05-25 11:27:16 -04:00
" type %d \n " ,
2007-02-10 12:25:27 -02:00
ext - > key_len ,
alg ) ;
ret = - EINVAL ;
goto out ;
}
2007-05-25 23:01:24 -04:00
if ( ext - > ext_flags & IW_ENCODE_EXT_GROUP_KEY ) {
2007-02-10 12:25:27 -02:00
pkey = & assoc_req - > wpa_mcast_key ;
2007-05-25 23:01:24 -04:00
set_bit ( ASSOC_FLAG_WPA_MCAST_KEY , & assoc_req - > flags ) ;
} else {
2007-02-10 12:25:27 -02:00
pkey = & assoc_req - > wpa_unicast_key ;
2007-05-25 23:01:24 -04:00
set_bit ( ASSOC_FLAG_WPA_UCAST_KEY , & assoc_req - > flags ) ;
}
2007-02-10 12:25:27 -02:00
2007-08-02 10:45:55 -04:00
memset ( pkey , 0 , sizeof ( struct enc_key ) ) ;
2007-02-10 12:25:27 -02:00
memcpy ( pkey - > key , ext - > key , ext - > key_len ) ;
pkey - > len = ext - > key_len ;
2007-05-25 23:01:24 -04:00
if ( pkey - > len )
pkey - > flags | = KEY_INFO_WPA_ENABLED ;
2007-02-10 12:25:27 -02:00
2007-05-25 23:01:24 -04:00
/* Do this after zeroing key structure */
2007-02-10 12:25:27 -02:00
if ( ext - > ext_flags & IW_ENCODE_EXT_GROUP_KEY ) {
pkey - > flags | = KEY_INFO_WPA_MCAST ;
} else {
pkey - > flags | = KEY_INFO_WPA_UNICAST ;
}
2007-05-25 23:01:24 -04:00
if ( alg = = IW_ENCODE_ALG_TKIP ) {
2007-02-10 12:25:27 -02:00
pkey - > type = KEY_TYPE_ID_TKIP ;
2007-05-25 23:01:24 -04:00
} else if ( alg = = IW_ENCODE_ALG_CCMP ) {
2007-02-10 12:25:27 -02:00
pkey - > type = KEY_TYPE_ID_AES ;
2007-05-25 23:01:24 -04:00
}
2007-02-10 12:25:27 -02:00
/* If WPA isn't enabled yet, do that now */
if ( assoc_req - > secinfo . WPAenabled = = 0
& & assoc_req - > secinfo . WPA2enabled = = 0 ) {
assoc_req - > secinfo . WPAenabled = 1 ;
assoc_req - > secinfo . WPA2enabled = 1 ;
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
}
disable_wep ( assoc_req ) ;
}
out :
if ( ret = = 0 ) {
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_genie ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq ,
char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
int ret = 0 ;
struct assoc_request * assoc_req ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
goto out ;
}
if ( dwrq - > length > MAX_WPA_IE_LEN | |
( dwrq - > length & & extra = = NULL ) ) {
ret = - EINVAL ;
goto out ;
}
if ( dwrq - > length ) {
memcpy ( & assoc_req - > wpa_ie [ 0 ] , extra , dwrq - > length ) ;
assoc_req - > wpa_ie_len = dwrq - > length ;
} else {
memset ( & assoc_req - > wpa_ie [ 0 ] , 0 , sizeof ( adapter - > wpa_ie ) ) ;
assoc_req - > wpa_ie_len = 0 ;
}
out :
if ( ret = = 0 ) {
set_bit ( ASSOC_FLAG_WPA_IE , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_genie ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_point * dwrq ,
char * extra )
{
2007-05-25 11:27:16 -04:00
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( adapter - > wpa_ie_len = = 0 ) {
dwrq - > length = 0 ;
2007-05-25 11:27:16 -04:00
goto out ;
2007-02-10 12:25:27 -02:00
}
if ( dwrq - > length < adapter - > wpa_ie_len ) {
2007-05-25 11:27:16 -04:00
ret = - E2BIG ;
goto out ;
2007-02-10 12:25:27 -02:00
}
dwrq - > length = adapter - > wpa_ie_len ;
memcpy ( extra , & adapter - > wpa_ie [ 0 ] , adapter - > wpa_ie_len ) ;
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_set_auth ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_param * dwrq ,
char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req ;
int ret = 0 ;
int updated = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
mutex_lock ( & adapter - > lock ) ;
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
goto out ;
}
switch ( dwrq - > flags & IW_AUTH_INDEX ) {
case IW_AUTH_TKIP_COUNTERMEASURES :
case IW_AUTH_CIPHER_PAIRWISE :
case IW_AUTH_CIPHER_GROUP :
case IW_AUTH_KEY_MGMT :
2007-05-25 23:01:24 -04:00
case IW_AUTH_DROP_UNENCRYPTED :
2007-02-10 12:25:27 -02:00
/*
* libertas does not use these parameters
*/
break ;
case IW_AUTH_WPA_VERSION :
if ( dwrq - > value & IW_AUTH_WPA_VERSION_DISABLED ) {
assoc_req - > secinfo . WPAenabled = 0 ;
assoc_req - > secinfo . WPA2enabled = 0 ;
2007-05-25 23:01:24 -04:00
disable_wpa ( assoc_req ) ;
2007-02-10 12:25:27 -02:00
}
if ( dwrq - > value & IW_AUTH_WPA_VERSION_WPA ) {
assoc_req - > secinfo . WPAenabled = 1 ;
2007-05-10 22:57:23 -04:00
assoc_req - > secinfo . wep_enabled = 0 ;
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
}
if ( dwrq - > value & IW_AUTH_WPA_VERSION_WPA2 ) {
assoc_req - > secinfo . WPA2enabled = 1 ;
2007-05-10 22:57:23 -04:00
assoc_req - > secinfo . wep_enabled = 0 ;
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
}
updated = 1 ;
break ;
case IW_AUTH_80211_AUTH_ALG :
if ( dwrq - > value & IW_AUTH_ALG_SHARED_KEY ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_SHARED_KEY ;
2007-02-10 12:25:27 -02:00
} else if ( dwrq - > value & IW_AUTH_ALG_OPEN_SYSTEM ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
} else if ( dwrq - > value & IW_AUTH_ALG_LEAP ) {
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_LEAP ;
2007-02-10 12:25:27 -02:00
} else {
ret = - EINVAL ;
}
updated = 1 ;
break ;
case IW_AUTH_WPA_ENABLED :
if ( dwrq - > value ) {
if ( ! assoc_req - > secinfo . WPAenabled & &
! assoc_req - > secinfo . WPA2enabled ) {
assoc_req - > secinfo . WPAenabled = 1 ;
assoc_req - > secinfo . WPA2enabled = 1 ;
2007-05-10 22:57:23 -04:00
assoc_req - > secinfo . wep_enabled = 0 ;
2007-05-10 22:56:42 -04:00
assoc_req - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
2007-02-10 12:25:27 -02:00
}
} else {
assoc_req - > secinfo . WPAenabled = 0 ;
assoc_req - > secinfo . WPA2enabled = 0 ;
2007-05-25 23:01:24 -04:00
disable_wpa ( assoc_req ) ;
2007-02-10 12:25:27 -02:00
}
updated = 1 ;
break ;
default :
ret = - EOPNOTSUPP ;
break ;
}
out :
if ( ret = = 0 ) {
if ( updated )
set_bit ( ASSOC_FLAG_SECINFO , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
} else if ( ret ! = - EOPNOTSUPP ) {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_auth ( struct net_device * dev ,
2007-02-10 12:25:27 -02:00
struct iw_request_info * info ,
struct iw_param * dwrq ,
char * extra )
{
2007-05-25 11:27:16 -04:00
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
switch ( dwrq - > flags & IW_AUTH_INDEX ) {
case IW_AUTH_WPA_VERSION :
dwrq - > value = 0 ;
if ( adapter - > secinfo . WPAenabled )
dwrq - > value | = IW_AUTH_WPA_VERSION_WPA ;
if ( adapter - > secinfo . WPA2enabled )
dwrq - > value | = IW_AUTH_WPA_VERSION_WPA2 ;
if ( ! dwrq - > value )
dwrq - > value | = IW_AUTH_WPA_VERSION_DISABLED ;
break ;
case IW_AUTH_80211_AUTH_ALG :
2007-05-10 22:56:42 -04:00
dwrq - > value = adapter - > secinfo . auth_mode ;
2007-02-10 12:25:27 -02:00
break ;
case IW_AUTH_WPA_ENABLED :
if ( adapter - > secinfo . WPAenabled & & adapter - > secinfo . WPA2enabled )
dwrq - > value = 1 ;
break ;
default :
2007-05-25 11:27:16 -04:00
ret = - EOPNOTSUPP ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static int lbs_set_txpow ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_param * vwrq , char * extra )
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
u16 dbm ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( vwrq - > disabled ) {
2007-11-15 18:05:47 -05:00
lbs_radio_ioctl ( priv , RADIO_OFF ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-08-02 11:31:18 -04:00
adapter - > preamble = CMD_TYPE_AUTO_PREAMBLE ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
lbs_radio_ioctl ( priv , RADIO_ON ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 13:16:30 -04:00
/* Userspace check in iwrange if it should use dBm or mW,
* therefore this should never happen . . . Jean II */
2007-02-10 12:25:27 -02:00
if ( ( vwrq - > flags & IW_TXPOW_TYPE ) = = IW_TXPOW_MWATT ) {
2007-08-02 13:16:30 -04:00
return - EOPNOTSUPP ;
2007-02-10 12:25:27 -02:00
} else
dbm = ( u16 ) vwrq - > value ;
/* auto tx power control */
if ( vwrq - > fixed = = 0 )
dbm = 0xffff ;
2007-05-25 11:27:16 -04:00
lbs_deb_wext ( " txpower set %d dbm \n " , dbm ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_802_11_RF_TX_POWER ,
CMD_ACT_TX_POWER_OPT_SET_LOW ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & dbm ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-11-15 18:05:47 -05:00
static int lbs_get_essid ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_point * dwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/*
* Note : if dwrq - > flags ! = 0 , we should get the relevant SSID from
* the SSID list . . .
*/
/*
* Get the current SSID
*/
2007-11-15 18:05:47 -05:00
if ( adapter - > connect_status = = LBS_CONNECTED ) {
2007-05-28 23:54:55 -04:00
memcpy ( extra , adapter - > curbssparams . ssid ,
adapter - > curbssparams . ssid_len ) ;
extra [ adapter - > curbssparams . ssid_len ] = ' \0 ' ;
2007-02-10 12:25:27 -02:00
} else {
memset ( extra , 0 , 32 ) ;
2007-05-28 23:54:55 -04:00
extra [ adapter - > curbssparams . ssid_len ] = ' \0 ' ;
2007-02-10 12:25:27 -02:00
}
/*
* If none , we may want to get the one that was set
*/
2007-08-02 13:16:30 -04:00
dwrq - > length = adapter - > curbssparams . ssid_len ;
2007-02-10 12:25:27 -02:00
dwrq - > flags = 1 ; /* active */
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_essid ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct iw_point * dwrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
int ret = 0 ;
2007-05-28 23:54:55 -04:00
u8 ssid [ IW_ESSID_MAX_SIZE ] ;
u8 ssid_len = 0 ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req ;
2007-05-28 23:54:55 -04:00
int in_ssid_len = dwrq - > length ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
/* Check the size of the string */
2007-05-28 23:54:55 -04:00
if ( in_ssid_len > IW_ESSID_MAX_SIZE ) {
2007-02-10 12:25:27 -02:00
ret = - E2BIG ;
goto out ;
}
2007-05-28 23:54:55 -04:00
memset ( & ssid , 0 , sizeof ( ssid ) ) ;
2007-02-10 12:25:27 -02:00
2007-05-28 23:54:55 -04:00
if ( ! dwrq - > flags | | ! in_ssid_len ) {
2007-02-10 12:25:27 -02:00
/* "any" SSID requested; leave SSID blank */
} else {
/* Specific SSID requested */
2007-05-28 23:54:55 -04:00
memcpy ( & ssid , extra , in_ssid_len ) ;
ssid_len = in_ssid_len ;
2007-02-10 12:25:27 -02:00
}
2007-05-28 23:54:55 -04:00
if ( ! ssid_len ) {
lbs_deb_wext ( " requested any SSID \n " ) ;
} else {
lbs_deb_wext ( " requested SSID '%s' \n " ,
escape_essid ( ssid , ssid_len ) ) ;
}
2007-02-10 12:25:27 -02:00
out :
mutex_lock ( & adapter - > lock ) ;
if ( ret = = 0 ) {
/* Get or create the current association request */
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
ret = - ENOMEM ;
} else {
/* Copy the SSID to the association request */
2007-05-28 23:54:55 -04:00
memcpy ( & assoc_req - > ssid , & ssid , IW_ESSID_MAX_SIZE ) ;
assoc_req - > ssid_len = ssid_len ;
2007-02-10 12:25:27 -02:00
set_bit ( ASSOC_FLAG_SSID , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
}
/* Cancel the association request if there was an error */
if ( ret ! = 0 ) {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_WEXT , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief Connect to the AP or Ad - hoc Network with specific bssid
*
* @ param dev A pointer to net_device structure
* @ param info A pointer to iw_request_info structure
* @ param awrq A pointer to iw_param structure
* @ param extra A pointer to extra data buf
* @ return 0 - - success , otherwise fail
*/
2007-11-15 18:05:47 -05:00
static int lbs_set_wap ( struct net_device * dev , struct iw_request_info * info ,
2007-02-10 12:25:27 -02:00
struct sockaddr * awrq , char * extra )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
struct lbs_adapter * adapter = priv - > adapter ;
2007-02-10 12:25:27 -02:00
struct assoc_request * assoc_req ;
int ret = 0 ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_WEXT ) ;
2007-02-10 12:25:27 -02:00
if ( awrq - > sa_family ! = ARPHRD_ETHER )
return - EINVAL ;
2007-10-03 17:59:30 -07:00
lbs_deb_wext ( " ASSOC: WAP: sa_data %s \n " , print_mac ( mac , awrq - > sa_data ) ) ;
2007-02-10 12:25:27 -02:00
mutex_lock ( & adapter - > lock ) ;
/* Get or create the current association request */
2007-11-15 18:05:47 -05:00
assoc_req = lbs_get_association_request ( adapter ) ;
2007-02-10 12:25:27 -02:00
if ( ! assoc_req ) {
2007-11-15 18:05:47 -05:00
lbs_cancel_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
ret = - ENOMEM ;
} else {
/* Copy the BSSID to the association request */
memcpy ( & assoc_req - > bssid , awrq - > sa_data , ETH_ALEN ) ;
set_bit ( ASSOC_FLAG_BSSID , & assoc_req - > flags ) ;
2007-11-15 18:05:47 -05:00
lbs_postpone_association_work ( priv ) ;
2007-02-10 12:25:27 -02:00
}
mutex_unlock ( & adapter - > lock ) ;
return ret ;
}
2007-11-23 15:43:44 +01:00
void lbs_get_fwversion ( struct lbs_adapter * adapter , char * fwversion , int maxlen )
2007-02-10 12:25:27 -02:00
{
char fwver [ 32 ] ;
mutex_lock ( & adapter - > lock ) ;
2007-05-25 23:40:21 -04:00
if ( adapter - > fwreleasenumber [ 3 ] = = 0 )
sprintf ( fwver , " %u.%u.%u " ,
adapter - > fwreleasenumber [ 2 ] ,
adapter - > fwreleasenumber [ 1 ] ,
adapter - > fwreleasenumber [ 0 ] ) ;
2007-02-10 12:25:27 -02:00
else
sprintf ( fwver , " %u.%u.%u.p%u " ,
2007-05-25 23:40:21 -04:00
adapter - > fwreleasenumber [ 2 ] ,
adapter - > fwreleasenumber [ 1 ] ,
adapter - > fwreleasenumber [ 0 ] ,
adapter - > fwreleasenumber [ 3 ] ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 23:40:21 -04:00
mutex_unlock ( & adapter - > lock ) ;
2007-02-10 12:25:27 -02:00
snprintf ( fwversion , maxlen , fwver ) ;
}
/*
* iwconfig settable callbacks
*/
2007-11-15 18:05:47 -05:00
static const iw_handler lbs_handler [ ] = {
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWCOMMIT */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_get_name , /* SIOCGIWNAME */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWNWID */
( iw_handler ) NULL , /* SIOCGIWNWID */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_freq , /* SIOCSIWFREQ */
( iw_handler ) lbs_get_freq , /* SIOCGIWFREQ */
( iw_handler ) lbs_set_mode , /* SIOCSIWMODE */
( iw_handler ) lbs_get_mode , /* SIOCGIWMODE */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWSENS */
( iw_handler ) NULL , /* SIOCGIWSENS */
( iw_handler ) NULL , /* SIOCSIWRANGE */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_get_range , /* SIOCGIWRANGE */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWPRIV */
( iw_handler ) NULL , /* SIOCGIWPRIV */
( iw_handler ) NULL , /* SIOCSIWSTATS */
( iw_handler ) NULL , /* SIOCGIWSTATS */
iw_handler_set_spy , /* SIOCSIWSPY */
iw_handler_get_spy , /* SIOCGIWSPY */
iw_handler_set_thrspy , /* SIOCSIWTHRSPY */
iw_handler_get_thrspy , /* SIOCGIWTHRSPY */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_wap , /* SIOCSIWAP */
( iw_handler ) lbs_get_wap , /* SIOCGIWAP */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWMLME */
( iw_handler ) NULL , /* SIOCGIWAPLIST - deprecated */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_scan , /* SIOCSIWSCAN */
( iw_handler ) lbs_get_scan , /* SIOCGIWSCAN */
( iw_handler ) lbs_set_essid , /* SIOCSIWESSID */
( iw_handler ) lbs_get_essid , /* SIOCGIWESSID */
( iw_handler ) lbs_set_nick , /* SIOCSIWNICKN */
( iw_handler ) lbs_get_nick , /* SIOCGIWNICKN */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* -- hole -- */
( iw_handler ) NULL , /* -- hole -- */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_rate , /* SIOCSIWRATE */
( iw_handler ) lbs_get_rate , /* SIOCGIWRATE */
( iw_handler ) lbs_set_rts , /* SIOCSIWRTS */
( iw_handler ) lbs_get_rts , /* SIOCGIWRTS */
( iw_handler ) lbs_set_frag , /* SIOCSIWFRAG */
( iw_handler ) lbs_get_frag , /* SIOCGIWFRAG */
( iw_handler ) lbs_set_txpow , /* SIOCSIWTXPOW */
( iw_handler ) lbs_get_txpow , /* SIOCGIWTXPOW */
( iw_handler ) lbs_set_retry , /* SIOCSIWRETRY */
( iw_handler ) lbs_get_retry , /* SIOCGIWRETRY */
( iw_handler ) lbs_set_encode , /* SIOCSIWENCODE */
( iw_handler ) lbs_get_encode , /* SIOCGIWENCODE */
( iw_handler ) lbs_set_power , /* SIOCSIWPOWER */
( iw_handler ) lbs_get_power , /* SIOCGIWPOWER */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* -- hole -- */
( iw_handler ) NULL , /* -- hole -- */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_genie , /* SIOCSIWGENIE */
( iw_handler ) lbs_get_genie , /* SIOCGIWGENIE */
( iw_handler ) lbs_set_auth , /* SIOCSIWAUTH */
( iw_handler ) lbs_get_auth , /* SIOCGIWAUTH */
( iw_handler ) lbs_set_encodeext , /* SIOCSIWENCODEEXT */
( iw_handler ) lbs_get_encodeext , /* SIOCGIWENCODEEXT */
2007-02-10 12:25:27 -02:00
( iw_handler ) NULL , /* SIOCSIWPMKSA */
} ;
2007-05-25 23:08:34 -04:00
static const iw_handler mesh_wlan_handler [ ] = {
( iw_handler ) NULL , /* SIOCSIWCOMMIT */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_get_name , /* SIOCGIWNAME */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* SIOCSIWNWID */
( iw_handler ) NULL , /* SIOCGIWNWID */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_freq , /* SIOCSIWFREQ */
( iw_handler ) lbs_get_freq , /* SIOCGIWFREQ */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* SIOCSIWMODE */
( iw_handler ) mesh_wlan_get_mode , /* SIOCGIWMODE */
( iw_handler ) NULL , /* SIOCSIWSENS */
( iw_handler ) NULL , /* SIOCGIWSENS */
( iw_handler ) NULL , /* SIOCSIWRANGE */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_get_range , /* SIOCGIWRANGE */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* SIOCSIWPRIV */
( iw_handler ) NULL , /* SIOCGIWPRIV */
( iw_handler ) NULL , /* SIOCSIWSTATS */
( iw_handler ) NULL , /* SIOCGIWSTATS */
iw_handler_set_spy , /* SIOCSIWSPY */
iw_handler_get_spy , /* SIOCGIWSPY */
iw_handler_set_thrspy , /* SIOCSIWTHRSPY */
iw_handler_get_thrspy , /* SIOCGIWTHRSPY */
( iw_handler ) NULL , /* SIOCSIWAP */
( iw_handler ) NULL , /* SIOCGIWAP */
( iw_handler ) NULL , /* SIOCSIWMLME */
( iw_handler ) NULL , /* SIOCGIWAPLIST - deprecated */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_scan , /* SIOCSIWSCAN */
( iw_handler ) lbs_get_scan , /* SIOCGIWSCAN */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* SIOCSIWESSID */
( iw_handler ) NULL , /* SIOCGIWESSID */
( iw_handler ) NULL , /* SIOCSIWNICKN */
( iw_handler ) mesh_get_nick , /* SIOCGIWNICKN */
( iw_handler ) NULL , /* -- hole -- */
( iw_handler ) NULL , /* -- hole -- */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_rate , /* SIOCSIWRATE */
( iw_handler ) lbs_get_rate , /* SIOCGIWRATE */
( iw_handler ) lbs_set_rts , /* SIOCSIWRTS */
( iw_handler ) lbs_get_rts , /* SIOCGIWRTS */
( iw_handler ) lbs_set_frag , /* SIOCSIWFRAG */
( iw_handler ) lbs_get_frag , /* SIOCGIWFRAG */
( iw_handler ) lbs_set_txpow , /* SIOCSIWTXPOW */
( iw_handler ) lbs_get_txpow , /* SIOCGIWTXPOW */
( iw_handler ) lbs_set_retry , /* SIOCSIWRETRY */
( iw_handler ) lbs_get_retry , /* SIOCGIWRETRY */
( iw_handler ) lbs_set_encode , /* SIOCSIWENCODE */
( iw_handler ) lbs_get_encode , /* SIOCGIWENCODE */
( iw_handler ) lbs_set_power , /* SIOCSIWPOWER */
( iw_handler ) lbs_get_power , /* SIOCGIWPOWER */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* -- hole -- */
( iw_handler ) NULL , /* -- hole -- */
2007-11-15 18:05:47 -05:00
( iw_handler ) lbs_set_genie , /* SIOCSIWGENIE */
( iw_handler ) lbs_get_genie , /* SIOCGIWGENIE */
( iw_handler ) lbs_set_auth , /* SIOCSIWAUTH */
( iw_handler ) lbs_get_auth , /* SIOCGIWAUTH */
( iw_handler ) lbs_set_encodeext , /* SIOCSIWENCODEEXT */
( iw_handler ) lbs_get_encodeext , /* SIOCGIWENCODEEXT */
2007-05-25 23:08:34 -04:00
( iw_handler ) NULL , /* SIOCSIWPMKSA */
} ;
2007-11-15 18:05:47 -05:00
struct iw_handler_def lbs_handler_def = {
. num_standard = ARRAY_SIZE ( lbs_handler ) ,
. standard = ( iw_handler * ) lbs_handler ,
. get_wireless_stats = lbs_get_wireless_stats ,
2007-02-10 12:25:27 -02:00
} ;
2007-05-25 23:08:34 -04:00
struct iw_handler_def mesh_handler_def = {
2007-09-02 18:30:18 +08:00
. num_standard = ARRAY_SIZE ( mesh_wlan_handler ) ,
2007-05-25 23:08:34 -04:00
. standard = ( iw_handler * ) mesh_wlan_handler ,
2007-11-15 18:05:47 -05:00
. get_wireless_stats = lbs_get_wireless_stats ,
2007-05-25 23:08:34 -04:00
} ;