2010-12-08 11:12:31 -06:00
/******************************************************************************
*
2012-01-07 20:46:42 -06:00
* Copyright ( c ) 2009 - 2012 Realtek Corporation .
2010-12-08 11:12:31 -06:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 , USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE .
*
* Contact Information :
* wlanfae < wlanfae @ realtek . com >
* Realtek Corporation , No . 2 , Innovation Road II , Hsinchu Science Park ,
* Hsinchu 300 , Taiwan .
*
* Larry Finger < Larry . Finger @ lwfinger . net >
2011-04-25 13:23:10 -05:00
*
2010-12-08 11:12:31 -06:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "wifi.h"
# include "core.h"
# include "cam.h"
# include "base.h"
# include "ps.h"
/*mutex for start & stop is must here. */
static int rtl_op_start ( struct ieee80211_hw * hw )
{
2011-03-27 16:19:57 -05:00
int err ;
2010-12-08 11:12:31 -06:00
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
if ( ! is_hal_stop ( rtlhal ) )
return 0 ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
return 0 ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
err = rtlpriv - > intf_ops - > adapter_start ( hw ) ;
2011-03-27 16:19:57 -05:00
if ( ! err )
rtl_watch_dog_timer_callback ( ( unsigned long ) hw ) ;
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
return err ;
}
static void rtl_op_stop ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
if ( is_hal_stop ( rtlhal ) )
return ;
if ( unlikely ( ppsc - > rfpwr_state = = ERFOFF ) ) {
rtl_ips_nic_on ( hw ) ;
mdelay ( 1 ) ;
}
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
2011-04-25 13:23:10 -05:00
mac - > vendor = PEER_UNKNOWN ;
2010-12-08 11:12:31 -06:00
/*reset sec info */
rtl_cam_reset_sec_info ( hw ) ;
rtl_deinit_deferred_work ( hw ) ;
rtlpriv - > intf_ops - > adapter_stop ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
2011-02-24 14:42:06 +01:00
static void rtl_op_tx ( struct ieee80211_hw * hw , struct sk_buff * skb )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
2011-04-25 13:23:10 -05:00
struct rtl_tcb_desc tcb_desc ;
memset ( & tcb_desc , 0 , sizeof ( struct rtl_tcb_desc ) ) ;
2010-12-08 11:12:31 -06:00
if ( unlikely ( is_hal_stop ( rtlhal ) | | ppsc - > rfpwr_state ! = ERFON ) )
goto err_free ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
goto err_free ;
2011-04-25 13:23:10 -05:00
if ( ! rtlpriv - > intf_ops - > waitq_insert ( hw , skb ) )
rtlpriv - > intf_ops - > adapter_tx ( hw , skb , & tcb_desc ) ;
2010-12-08 11:12:31 -06:00
2011-02-24 14:42:06 +01:00
return ;
2010-12-08 11:12:31 -06:00
err_free :
dev_kfree_skb_any ( skb ) ;
}
static int rtl_op_add_interface ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
int err = 0 ;
2012-01-19 09:29:57 +01:00
vif - > driver_flags | = IEEE80211_VIF_BEACON_FILTER ;
2010-12-08 11:12:31 -06:00
if ( mac - > vif ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
2012-01-04 19:40:41 -08:00
" vif has been set!! mac->vif = 0x%p \n " , mac - > vif ) ;
2010-12-08 11:12:31 -06:00
return - EOPNOTSUPP ;
}
rtl_ips_nic_on ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
switch ( vif - > type ) {
case NL80211_IFTYPE_STATION :
if ( mac - > beacon_enabled = = 1 ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" NL80211_IFTYPE_STATION \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > beacon_enabled = 0 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw , 0 ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ) ;
}
break ;
case NL80211_IFTYPE_ADHOC :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" NL80211_IFTYPE_ADHOC \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > link_state = MAC80211_LINKED ;
rtlpriv - > cfg - > ops - > set_bcn_reg ( hw ) ;
2011-04-25 13:23:10 -05:00
if ( rtlpriv - > rtlhal . current_bandtype = = BAND_ON_2_4G )
mac - > basic_rates = 0xfff ;
else
mac - > basic_rates = 0xff0 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BASIC_RATE ,
( u8 * ) ( & mac - > basic_rates ) ) ;
2010-12-08 11:12:31 -06:00
break ;
case NL80211_IFTYPE_AP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" NL80211_IFTYPE_AP \n " ) ;
2011-04-25 13:23:10 -05:00
mac - > link_state = MAC80211_LINKED ;
rtlpriv - > cfg - > ops - > set_bcn_reg ( hw ) ;
if ( rtlpriv - > rtlhal . current_bandtype = = BAND_ON_2_4G )
mac - > basic_rates = 0xfff ;
else
mac - > basic_rates = 0xff0 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BASIC_RATE ,
( u8 * ) ( & mac - > basic_rates ) ) ;
2010-12-08 11:12:31 -06:00
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
2012-01-04 19:40:41 -08:00
" operation mode %d is not supported! \n " , vif - > type ) ;
2010-12-08 11:12:31 -06:00
err = - EOPNOTSUPP ;
goto out ;
}
mac - > vif = vif ;
mac - > opmode = vif - > type ;
rtlpriv - > cfg - > ops - > set_network_type ( hw , vif - > type ) ;
memcpy ( mac - > mac_addr , vif - > addr , ETH_ALEN ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_ETHER_ADDR , mac - > mac_addr ) ;
out :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
return err ;
}
static void rtl_op_remove_interface ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/* Free beacon resources */
if ( ( mac - > opmode = = NL80211_IFTYPE_AP ) | |
( mac - > opmode = = NL80211_IFTYPE_ADHOC ) | |
( mac - > opmode = = NL80211_IFTYPE_MESH_POINT ) ) {
if ( mac - > beacon_enabled = = 1 ) {
mac - > beacon_enabled = 0 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw , 0 ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ) ;
}
}
/*
* Note : We assume NL80211_IFTYPE_UNSPECIFIED as
* NO LINK for our hardware .
*/
mac - > vif = NULL ;
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
2011-04-25 13:23:10 -05:00
mac - > vendor = PEER_UNKNOWN ;
2010-12-08 11:12:31 -06:00
mac - > opmode = NL80211_IFTYPE_UNSPECIFIED ;
rtlpriv - > cfg - > ops - > set_network_type ( hw , mac - > opmode ) ;
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
static int rtl_op_config ( struct ieee80211_hw * hw , u32 changed )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_phy * rtlphy = & ( rtlpriv - > phy ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
struct ieee80211_conf * conf = & hw - > conf ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
if ( changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL ) { /*BIT(2)*/
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" IEEE80211_CONF_CHANGE_LISTEN_INTERVAL \n " ) ;
2010-12-08 11:12:31 -06:00
}
/*For IPS */
if ( changed & IEEE80211_CONF_CHANGE_IDLE ) {
if ( hw - > conf . flags & IEEE80211_CONF_IDLE )
rtl_ips_nic_off ( hw ) ;
else
rtl_ips_nic_on ( hw ) ;
} else {
/*
* although rfoff may not cause by ips , but we will
* check the reason in set_rf_power_state function
*/
if ( unlikely ( ppsc - > rfpwr_state = = ERFOFF ) )
rtl_ips_nic_on ( hw ) ;
}
/*For LPS */
if ( changed & IEEE80211_CONF_CHANGE_PS ) {
2011-04-25 13:23:10 -05:00
cancel_delayed_work ( & rtlpriv - > works . ps_work ) ;
cancel_delayed_work ( & rtlpriv - > works . ps_rfon_wq ) ;
if ( conf - > flags & IEEE80211_CONF_PS ) {
rtlpriv - > psc . sw_ps_enabled = true ;
/* sleep here is must, or we may recv the beacon and
* cause mac80211 into wrong ps state , this will cause
* power save nullfunc send fail , and further cause
* pkt loss , So sleep must quickly but not immediatly
* because that will cause nullfunc send by mac80211
* fail , and cause pkt loss , we have tested that 5 mA
* is worked very well */
if ( ! rtlpriv - > psc . multi_buffered )
queue_delayed_work ( rtlpriv - > works . rtl_wq ,
& rtlpriv - > works . ps_work ,
MSECS ( 5 ) ) ;
} else {
rtl_swlps_rf_awake ( hw ) ;
rtlpriv - > psc . sw_ps_enabled = false ;
}
2010-12-08 11:12:31 -06:00
}
if ( changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" IEEE80211_CONF_CHANGE_RETRY_LIMITS %x \n " ,
hw - > conf . long_frame_max_tx_count ) ;
2010-12-08 11:12:31 -06:00
mac - > retry_long = hw - > conf . long_frame_max_tx_count ;
mac - > retry_short = hw - > conf . long_frame_max_tx_count ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_RETRY_LIMIT ,
( u8 * ) ( & hw - > conf .
long_frame_max_tx_count ) ) ;
}
if ( changed & IEEE80211_CONF_CHANGE_CHANNEL ) {
struct ieee80211_channel * channel = hw - > conf . channel ;
u8 wide_chan = ( u8 ) channel - > hw_value ;
/*
* because we should back channel to
* current_network . chan in in scanning ,
* So if set_chan = = current_network . chan
* we should set it .
* because mac80211 tell us wrong bw40
* info for cisco1253 bw20 , so we modify
* it here based on UPPER & LOWER
*/
switch ( hw - > conf . channel_type ) {
case NL80211_CHAN_HT20 :
case NL80211_CHAN_NO_HT :
/* SC */
mac - > cur_40_prime_sc =
2011-04-25 13:23:10 -05:00
PRIME_CHNL_OFFSET_DONT_CARE ;
2010-12-08 11:12:31 -06:00
rtlphy - > current_chan_bw = HT_CHANNEL_WIDTH_20 ;
mac - > bw_40 = false ;
break ;
case NL80211_CHAN_HT40MINUS :
/* SC */
mac - > cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER ;
rtlphy - > current_chan_bw =
2011-04-25 13:23:10 -05:00
HT_CHANNEL_WIDTH_20_40 ;
2010-12-08 11:12:31 -06:00
mac - > bw_40 = true ;
/*wide channel */
wide_chan - = 2 ;
break ;
case NL80211_CHAN_HT40PLUS :
/* SC */
mac - > cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER ;
rtlphy - > current_chan_bw =
2011-04-25 13:23:10 -05:00
HT_CHANNEL_WIDTH_20_40 ;
2010-12-08 11:12:31 -06:00
mac - > bw_40 = true ;
/*wide channel */
wide_chan + = 2 ;
break ;
default :
mac - > bw_40 = false ;
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
2012-01-04 19:40:41 -08:00
" switch case not processed \n " ) ;
2010-12-08 11:12:31 -06:00
break ;
}
if ( wide_chan < = 0 )
wide_chan = 1 ;
2011-04-25 13:23:10 -05:00
/* In scanning, before we go offchannel we may send a ps=1 null
* to AP , and then we may send a ps = 0 null to AP quickly , but
* first null may have caused AP to put lots of packet to hw tx
* buffer . These packets must be tx ' d before we go off channel
* so we must delay more time to let AP flush these packets
* before going offchannel , or dis - association or delete BA will
* happen by AP
*/
2011-06-20 10:44:58 +09:00
if ( rtlpriv - > mac80211 . offchan_delay ) {
rtlpriv - > mac80211 . offchan_delay = false ;
2011-04-25 13:23:10 -05:00
mdelay ( 50 ) ;
}
2010-12-08 11:12:31 -06:00
rtlphy - > current_channel = wide_chan ;
rtlpriv - > cfg - > ops - > switch_channel ( hw ) ;
2011-04-25 13:23:10 -05:00
rtlpriv - > cfg - > ops - > set_channel_access ( hw ) ;
2010-12-08 11:12:31 -06:00
rtlpriv - > cfg - > ops - > set_bw_mode ( hw ,
hw - > conf . channel_type ) ;
}
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
return 0 ;
}
static void rtl_op_configure_filter ( struct ieee80211_hw * hw ,
unsigned int changed_flags ,
unsigned int * new_flags , u64 multicast )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
* new_flags & = RTL_SUPPORTED_FILTERS ;
if ( ! changed_flags )
return ;
/*TODO: we disable broadcase now, so enable here */
if ( changed_flags & FIF_ALLMULTI ) {
if ( * new_flags & FIF_ALLMULTI ) {
mac - > rx_conf | = rtlpriv - > cfg - > maps [ MAC_RCR_AM ] |
rtlpriv - > cfg - > maps [ MAC_RCR_AB ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Enable receive multicast frame \n " ) ;
2010-12-08 11:12:31 -06:00
} else {
mac - > rx_conf & = ~ ( rtlpriv - > cfg - > maps [ MAC_RCR_AM ] |
rtlpriv - > cfg - > maps [ MAC_RCR_AB ] ) ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Disable receive multicast frame \n " ) ;
2010-12-08 11:12:31 -06:00
}
}
if ( changed_flags & FIF_FCSFAIL ) {
if ( * new_flags & FIF_FCSFAIL ) {
mac - > rx_conf | = rtlpriv - > cfg - > maps [ MAC_RCR_ACRC32 ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Enable receive FCS error frame \n " ) ;
2010-12-08 11:12:31 -06:00
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_ACRC32 ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Disable receive FCS error frame \n " ) ;
2010-12-08 11:12:31 -06:00
}
}
2011-04-25 13:23:10 -05:00
/* if ssid not set to hw don't check bssid
* here just used for linked scanning , & linked
* and nolink check bssid is set in set network_type */
if ( ( changed_flags & FIF_BCN_PRBRESP_PROMISC ) & &
( mac - > link_state > = MAC80211_LINKED ) ) {
if ( mac - > opmode ! = NL80211_IFTYPE_AP ) {
if ( * new_flags & FIF_BCN_PRBRESP_PROMISC ) {
rtlpriv - > cfg - > ops - > set_chk_bssid ( hw , false ) ;
} else {
rtlpriv - > cfg - > ops - > set_chk_bssid ( hw , true ) ;
}
}
2010-12-08 11:12:31 -06:00
}
if ( changed_flags & FIF_CONTROL ) {
if ( * new_flags & FIF_CONTROL ) {
mac - > rx_conf | = rtlpriv - > cfg - > maps [ MAC_RCR_ACF ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Enable receive control frame \n " ) ;
2010-12-08 11:12:31 -06:00
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_ACF ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Disable receive control frame \n " ) ;
2010-12-08 11:12:31 -06:00
}
}
if ( changed_flags & FIF_OTHER_BSS ) {
if ( * new_flags & FIF_OTHER_BSS ) {
mac - > rx_conf | = rtlpriv - > cfg - > maps [ MAC_RCR_AAP ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Enable receive other BSS's frame \n " ) ;
2010-12-08 11:12:31 -06:00
} else {
mac - > rx_conf & = ~ rtlpriv - > cfg - > maps [ MAC_RCR_AAP ] ;
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" Disable receive other BSS's frame \n " ) ;
2010-12-08 11:12:31 -06:00
}
}
}
2011-04-25 13:23:10 -05:00
static int rtl_op_sta_add ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_hal * rtlhal = rtl_hal ( rtl_priv ( hw ) ) ;
struct rtl_sta_info * sta_entry ;
if ( sta ) {
sta_entry = ( struct rtl_sta_info * ) sta - > drv_priv ;
if ( rtlhal - > current_bandtype = = BAND_ON_2_4G ) {
sta_entry - > wireless_mode = WIRELESS_MODE_G ;
if ( sta - > supp_rates [ 0 ] < = 0xf )
sta_entry - > wireless_mode = WIRELESS_MODE_B ;
2011-06-20 10:47:51 +09:00
if ( sta - > ht_cap . ht_supported )
2011-04-25 13:23:10 -05:00
sta_entry - > wireless_mode = WIRELESS_MODE_N_24G ;
} else if ( rtlhal - > current_bandtype = = BAND_ON_5G ) {
sta_entry - > wireless_mode = WIRELESS_MODE_A ;
2011-06-20 10:47:51 +09:00
if ( sta - > ht_cap . ht_supported )
2011-04-25 13:23:10 -05:00
sta_entry - > wireless_mode = WIRELESS_MODE_N_24G ;
}
/* I found some times mac80211 give wrong supp_rates for adhoc*/
if ( rtlpriv - > mac80211 . opmode = = NL80211_IFTYPE_ADHOC )
sta_entry - > wireless_mode = WIRELESS_MODE_G ;
2010-12-08 11:12:31 -06:00
2011-04-25 13:23:10 -05:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" Add sta addr is %pM \n " , sta - > addr ) ;
2011-04-25 13:23:10 -05:00
rtlpriv - > cfg - > ops - > update_rate_tbl ( hw , sta , 0 ) ;
}
return 0 ;
}
static int rtl_op_sta_remove ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_sta * sta )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_sta_info * sta_entry ;
if ( sta ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" Remove sta addr is %pM \n " , sta - > addr ) ;
2011-04-25 13:23:10 -05:00
sta_entry = ( struct rtl_sta_info * ) sta - > drv_priv ;
sta_entry - > wireless_mode = 0 ;
sta_entry - > ratr_index = 0 ;
}
return 0 ;
}
2010-12-08 11:12:31 -06:00
static int _rtl_get_hal_qnum ( u16 queue )
{
int qnum ;
switch ( queue ) {
case 0 :
qnum = AC3_VO ;
break ;
case 1 :
qnum = AC2_VI ;
break ;
case 2 :
qnum = AC0_BE ;
break ;
case 3 :
qnum = AC1_BK ;
break ;
default :
qnum = AC0_BE ;
break ;
}
return qnum ;
}
/*
* for mac80211 VO = 0 , VI = 1 , BE = 2 , BK = 3
* for rtl819x BE = 0 , BK = 1 , VI = 2 , VO = 3
*/
2011-10-02 10:15:52 +02:00
static int rtl_op_conf_tx ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif , u16 queue ,
2010-12-08 11:12:31 -06:00
const struct ieee80211_tx_queue_params * param )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
int aci ;
if ( queue > = AC_MAX ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
2012-01-04 19:40:41 -08:00
" queue number %d is incorrect! \n " , queue ) ;
2010-12-08 11:12:31 -06:00
return - EINVAL ;
}
aci = _rtl_get_hal_qnum ( queue ) ;
mac - > ac [ aci ] . aifs = param - > aifs ;
2011-02-19 16:29:57 -06:00
mac - > ac [ aci ] . cw_min = cpu_to_le16 ( param - > cw_min ) ;
mac - > ac [ aci ] . cw_max = cpu_to_le16 ( param - > cw_max ) ;
mac - > ac [ aci ] . tx_op = cpu_to_le16 ( param - > txop ) ;
2010-12-08 11:12:31 -06:00
memcpy ( & mac - > edca_param [ aci ] , param , sizeof ( * param ) ) ;
rtlpriv - > cfg - > ops - > set_qos ( hw , aci ) ;
return 0 ;
}
static void rtl_op_bss_info_changed ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
struct ieee80211_bss_conf * bss_conf , u32 changed )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
2011-04-25 13:23:10 -05:00
struct rtl_hal * rtlhal = rtl_hal ( rtlpriv ) ;
2010-12-08 11:12:31 -06:00
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
struct rtl_ps_ctl * ppsc = rtl_psc ( rtl_priv ( hw ) ) ;
2011-04-25 13:23:10 -05:00
struct ieee80211_sta * sta = NULL ;
2010-12-08 11:12:31 -06:00
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
if ( ( vif - > type = = NL80211_IFTYPE_ADHOC ) | |
( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_MESH_POINT ) ) {
if ( ( changed & BSS_CHANGED_BEACON ) | |
( changed & BSS_CHANGED_BEACON_ENABLED & &
bss_conf - > enable_beacon ) ) {
if ( mac - > beacon_enabled = = 0 ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_BEACON_ENABLED \n " ) ;
2010-12-08 11:12:31 -06:00
/*start hw beacon interrupt. */
/*rtlpriv->cfg->ops->set_bcn_reg(hw); */
mac - > beacon_enabled = 1 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ,
0 ) ;
2011-04-25 13:23:10 -05:00
if ( rtlpriv - > cfg - > ops - > linked_set_reg )
rtlpriv - > cfg - > ops - > linked_set_reg ( hw ) ;
2010-12-08 11:12:31 -06:00
}
2011-04-25 13:23:10 -05:00
}
if ( ( changed & BSS_CHANGED_BEACON_ENABLED & &
! bss_conf - > enable_beacon ) ) {
2010-12-08 11:12:31 -06:00
if ( mac - > beacon_enabled = = 1 ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" ADHOC DISABLE BEACON \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > beacon_enabled = 0 ;
rtlpriv - > cfg - > ops - > update_interrupt_mask ( hw , 0 ,
rtlpriv - > cfg - > maps
[ RTL_IBSS_INT_MASKS ] ) ;
}
}
if ( changed & BSS_CHANGED_BEACON_INT ) {
RT_TRACE ( rtlpriv , COMP_BEACON , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_BEACON_INT \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > beacon_interval = bss_conf - > beacon_int ;
rtlpriv - > cfg - > ops - > set_bcn_intv ( hw ) ;
}
}
/*TODO: reference to enum ieee80211_bss_change */
if ( changed & BSS_CHANGED_ASSOC ) {
if ( bss_conf - > assoc ) {
2011-04-25 13:23:10 -05:00
/* we should reset all sec info & cam
* before set cam after linked , we should not
* reset in disassoc , that will cause tkip - > wep
* fail because some flag will be wrong */
/* reset sec info */
rtl_cam_reset_sec_info ( hw ) ;
/* reset cam to fix wep fail issue
* when change from wpa to wep */
rtl_cam_reset_all_entry ( hw ) ;
2010-12-08 11:12:31 -06:00
mac - > link_state = MAC80211_LINKED ;
mac - > cnt_after_linked = 0 ;
mac - > assoc_id = bss_conf - > aid ;
memcpy ( mac - > bssid , bss_conf - > bssid , 6 ) ;
2011-04-25 13:23:10 -05:00
if ( rtlpriv - > cfg - > ops - > linked_set_reg )
rtlpriv - > cfg - > ops - > linked_set_reg ( hw ) ;
if ( mac - > opmode = = NL80211_IFTYPE_STATION & & sta )
rtlpriv - > cfg - > ops - > update_rate_tbl ( hw , sta , 0 ) ;
2010-12-08 11:12:31 -06:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_ASSOC \n " ) ;
2010-12-08 11:12:31 -06:00
} else {
if ( mac - > link_state = = MAC80211_LINKED )
rtl_lps_leave ( hw ) ;
mac - > link_state = MAC80211_NOLINK ;
memset ( mac - > bssid , 0 , 6 ) ;
2011-09-03 10:58:48 -05:00
/* reset sec info */
rtl_cam_reset_sec_info ( hw ) ;
rtl_cam_reset_all_entry ( hw ) ;
2011-04-25 13:23:10 -05:00
mac - > vendor = PEER_UNKNOWN ;
2010-12-08 11:12:31 -06:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_UN_ASSOC \n " ) ;
2010-12-08 11:12:31 -06:00
}
}
if ( changed & BSS_CHANGED_ERP_CTS_PROT ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_ERP_CTS_PROT \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > use_cts_protect = bss_conf - > use_cts_prot ;
}
if ( changed & BSS_CHANGED_ERP_PREAMBLE ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_ERP_PREAMBLE use short preamble:%x \n " ,
bss_conf - > use_short_preamble ) ;
2010-12-08 11:12:31 -06:00
mac - > short_preamble = bss_conf - > use_short_preamble ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_ACK_PREAMBLE ,
( u8 * ) ( & mac - > short_preamble ) ) ;
}
if ( changed & BSS_CHANGED_ERP_SLOT ) {
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" BSS_CHANGED_ERP_SLOT \n " ) ;
2010-12-08 11:12:31 -06:00
if ( bss_conf - > use_short_slot )
mac - > slot_time = RTL_SLOT_TIME_9 ;
else
mac - > slot_time = RTL_SLOT_TIME_20 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_SLOT_TIME ,
( u8 * ) ( & mac - > slot_time ) ) ;
}
if ( changed & BSS_CHANGED_HT ) {
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE , " BSS_CHANGED_HT \n " ) ;
2011-02-28 18:46:44 +01:00
rcu_read_lock ( ) ;
2011-06-10 11:05:23 -05:00
sta = get_sta ( hw , vif , bss_conf - > bssid ) ;
2010-12-08 11:12:31 -06:00
if ( sta ) {
if ( sta - > ht_cap . ampdu_density >
mac - > current_ampdu_density )
mac - > current_ampdu_density =
sta - > ht_cap . ampdu_density ;
if ( sta - > ht_cap . ampdu_factor <
mac - > current_ampdu_factor )
mac - > current_ampdu_factor =
sta - > ht_cap . ampdu_factor ;
}
2011-02-28 18:46:44 +01:00
rcu_read_unlock ( ) ;
2010-12-08 11:12:31 -06:00
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_SHORTGI_DENSITY ,
( u8 * ) ( & mac - > max_mss_density ) ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_AMPDU_FACTOR ,
& mac - > current_ampdu_factor ) ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_AMPDU_MIN_SPACE ,
& mac - > current_ampdu_density ) ;
}
if ( changed & BSS_CHANGED_BSSID ) {
u32 basic_rates ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BSSID ,
( u8 * ) bss_conf - > bssid ) ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_DMESG , " %pM \n " ,
bss_conf - > bssid ) ;
2010-12-08 11:12:31 -06:00
2011-04-25 13:23:10 -05:00
mac - > vendor = PEER_UNKNOWN ;
2010-12-08 11:12:31 -06:00
memcpy ( mac - > bssid , bss_conf - > bssid , 6 ) ;
2011-04-25 13:23:10 -05:00
rtlpriv - > cfg - > ops - > set_network_type ( hw , vif - > type ) ;
2010-12-08 11:12:31 -06:00
2011-02-28 18:46:44 +01:00
rcu_read_lock ( ) ;
2011-06-10 11:05:23 -05:00
sta = get_sta ( hw , vif , bss_conf - > bssid ) ;
2011-04-25 13:23:10 -05:00
if ( ! sta ) {
rcu_read_unlock ( ) ;
goto out ;
}
2010-12-08 11:12:31 -06:00
2011-04-25 13:23:10 -05:00
if ( rtlhal - > current_bandtype = = BAND_ON_5G ) {
mac - > mode = WIRELESS_MODE_A ;
} else {
if ( sta - > supp_rates [ 0 ] < = 0xf )
mac - > mode = WIRELESS_MODE_B ;
else
mac - > mode = WIRELESS_MODE_G ;
}
if ( sta - > ht_cap . ht_supported ) {
if ( rtlhal - > current_bandtype = = BAND_ON_2_4G )
2010-12-08 11:12:31 -06:00
mac - > mode = WIRELESS_MODE_N_24G ;
2011-04-25 13:23:10 -05:00
else
mac - > mode = WIRELESS_MODE_N_5G ;
}
2010-12-08 11:12:31 -06:00
2011-04-25 13:23:10 -05:00
/* just station need it, because ibss & ap mode will
* set in sta_add , and will be NULL here */
if ( mac - > opmode = = NL80211_IFTYPE_STATION ) {
struct rtl_sta_info * sta_entry ;
sta_entry = ( struct rtl_sta_info * ) sta - > drv_priv ;
sta_entry - > wireless_mode = mac - > mode ;
}
if ( sta - > ht_cap . ht_supported ) {
mac - > ht_enable = true ;
/*
* for cisco 1252 bw20 it ' s wrong
* if ( ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ) {
* mac - > bw_40 = true ;
* }
* */
2010-12-08 11:12:31 -06:00
}
if ( changed & BSS_CHANGED_BASIC_RATES ) {
2011-04-25 13:23:10 -05:00
/* for 5G must << RATE_6M_INDEX=4,
* because 5 G have no cck rate */
if ( rtlhal - > current_bandtype = = BAND_ON_5G )
basic_rates = sta - > supp_rates [ 1 ] < < 4 ;
2010-12-08 11:12:31 -06:00
else
2011-04-25 13:23:10 -05:00
basic_rates = sta - > supp_rates [ 0 ] ;
2010-12-08 11:12:31 -06:00
mac - > basic_rates = basic_rates ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_BASIC_RATE ,
( u8 * ) ( & basic_rates ) ) ;
}
2011-04-25 13:23:10 -05:00
rcu_read_unlock ( ) ;
2010-12-08 11:12:31 -06:00
}
/*
* For FW LPS :
* To tell firmware we have connected
* to an AP . For 92 SE / CE power save v2 .
*/
if ( changed & BSS_CHANGED_ASSOC ) {
if ( bss_conf - > assoc ) {
2011-02-19 16:28:57 -06:00
if ( ppsc - > fwctrl_lps ) {
2010-12-08 11:12:31 -06:00
u8 mstatus = RT_MEDIA_CONNECT ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw ,
HW_VAR_H2C_FW_JOINBSSRPT ,
( u8 * ) ( & mstatus ) ) ;
ppsc - > report_linked = true ;
}
} else {
2011-02-19 16:28:57 -06:00
if ( ppsc - > fwctrl_lps ) {
2010-12-08 11:12:31 -06:00
u8 mstatus = RT_MEDIA_DISCONNECT ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw ,
HW_VAR_H2C_FW_JOINBSSRPT ,
( u8 * ) ( & mstatus ) ) ;
ppsc - > report_linked = false ;
}
}
}
out :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
2011-09-21 14:06:11 +03:00
static u64 rtl_op_get_tsf ( struct ieee80211_hw * hw , struct ieee80211_vif * vif )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u64 tsf ;
rtlpriv - > cfg - > ops - > get_hw_reg ( hw , HW_VAR_CORRECT_TSF , ( u8 * ) ( & tsf ) ) ;
return tsf ;
}
2011-09-21 14:06:11 +03:00
static void rtl_op_set_tsf ( struct ieee80211_hw * hw , struct ieee80211_vif * vif ,
u64 tsf )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
2011-04-08 19:49:08 -07:00
u8 bibss = ( mac - > opmode = = NL80211_IFTYPE_ADHOC ) ? 1 : 0 ;
2010-12-08 11:12:31 -06:00
mac - > tsf = tsf ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_CORRECT_TSF , ( u8 * ) ( & bibss ) ) ;
}
2011-09-21 14:06:11 +03:00
static void rtl_op_reset_tsf ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u8 tmp = 0 ;
rtlpriv - > cfg - > ops - > set_hw_reg ( hw , HW_VAR_DUAL_TSF_RST , ( u8 * ) ( & tmp ) ) ;
}
static void rtl_op_sta_notify ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
enum sta_notify_cmd cmd ,
struct ieee80211_sta * sta )
{
switch ( cmd ) {
case STA_NOTIFY_SLEEP :
break ;
case STA_NOTIFY_AWAKE :
break ;
default :
break ;
}
}
static int rtl_op_ampdu_action ( struct ieee80211_hw * hw ,
struct ieee80211_vif * vif ,
enum ieee80211_ampdu_mlme_action action ,
2011-01-18 13:51:05 +01:00
struct ieee80211_sta * sta , u16 tid , u16 * ssn ,
u8 buf_size )
2010-12-08 11:12:31 -06:00
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
switch ( action ) {
case IEEE80211_AMPDU_TX_START :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_TX_START: TID:%d \n " , tid ) ;
2011-04-25 13:23:10 -05:00
return rtl_tx_agg_start ( hw , sta , tid , ssn ) ;
2010-12-08 11:12:31 -06:00
break ;
case IEEE80211_AMPDU_TX_STOP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_TX_STOP: TID:%d \n " , tid ) ;
2011-04-25 13:23:10 -05:00
return rtl_tx_agg_stop ( hw , sta , tid ) ;
2010-12-08 11:12:31 -06:00
break ;
case IEEE80211_AMPDU_TX_OPERATIONAL :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d \n " , tid ) ;
2011-04-25 13:23:10 -05:00
rtl_tx_agg_oper ( hw , sta , tid ) ;
2010-12-08 11:12:31 -06:00
break ;
case IEEE80211_AMPDU_RX_START :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_RX_START:TID:%d \n " , tid ) ;
2010-12-08 11:12:31 -06:00
break ;
case IEEE80211_AMPDU_RX_STOP :
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_TRACE ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_RX_STOP:TID:%d \n " , tid ) ;
2010-12-08 11:12:31 -06:00
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
2012-01-04 19:40:41 -08:00
" IEEE80211_AMPDU_ERR!!!!: \n " ) ;
2010-12-08 11:12:31 -06:00
return - EOPNOTSUPP ;
}
return 0 ;
}
static void rtl_op_sw_scan_start ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
mac - > act_scanning = true ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD , " \n " ) ;
2010-12-08 11:12:31 -06:00
if ( mac - > link_state = = MAC80211_LINKED ) {
rtl_lps_leave ( hw ) ;
mac - > link_state = MAC80211_LINKED_SCANNING ;
2011-04-25 13:23:10 -05:00
} else {
2010-12-08 11:12:31 -06:00
rtl_ips_nic_on ( hw ) ;
2011-04-25 13:23:10 -05:00
}
/* Dual mac */
rtlpriv - > rtlhal . load_imrandiqk_setting_for2g = false ;
2010-12-08 11:12:31 -06:00
rtlpriv - > cfg - > ops - > led_control ( hw , LED_CTL_SITE_SURVEY ) ;
rtlpriv - > cfg - > ops - > scan_operation_backup ( hw , SCAN_OPT_BACKUP ) ;
}
static void rtl_op_sw_scan_complete ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_MAC80211 , DBG_LOUD , " \n " ) ;
2010-12-08 11:12:31 -06:00
mac - > act_scanning = false ;
2011-04-25 13:23:10 -05:00
/* Dual mac */
rtlpriv - > rtlhal . load_imrandiqk_setting_for2g = false ;
2010-12-08 11:12:31 -06:00
if ( mac - > link_state = = MAC80211_LINKED_SCANNING ) {
mac - > link_state = MAC80211_LINKED ;
2011-04-25 13:23:10 -05:00
if ( mac - > opmode = = NL80211_IFTYPE_STATION ) {
/* fix fwlps issue */
rtlpriv - > cfg - > ops - > set_network_type ( hw , mac - > opmode ) ;
}
2010-12-08 11:12:31 -06:00
}
2011-04-25 13:23:10 -05:00
rtlpriv - > cfg - > ops - > scan_operation_backup ( hw , SCAN_OPT_RESTORE ) ;
2010-12-08 11:12:31 -06:00
}
static int rtl_op_set_key ( struct ieee80211_hw * hw , enum set_key_cmd cmd ,
struct ieee80211_vif * vif , struct ieee80211_sta * sta ,
struct ieee80211_key_conf * key )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
struct rtl_mac * mac = rtl_mac ( rtl_priv ( hw ) ) ;
u8 key_type = NO_ENCRYPTION ;
u8 key_idx ;
bool group_key = false ;
bool wep_only = false ;
int err = 0 ;
u8 mac_addr [ ETH_ALEN ] ;
u8 bcast_addr [ ETH_ALEN ] = { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ;
u8 zero_addr [ ETH_ALEN ] = { 0 } ;
if ( rtlpriv - > cfg - > mod_params - > sw_crypto | | rtlpriv - > sec . use_sw_sec ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
2012-01-04 19:40:41 -08:00
" not open hw encryption \n " ) ;
2010-12-08 11:12:31 -06:00
return - ENOSPC ; /*User disabled HW-crypto */
}
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" %s hardware based encryption for keyidx: %d, mac: %pM \n " ,
cmd = = SET_KEY ? " Using " : " Disabling " , key - > keyidx ,
sta ? sta - > addr : bcast_addr ) ;
2010-12-08 11:12:31 -06:00
rtlpriv - > sec . being_setkey = true ;
rtl_ips_nic_on ( hw ) ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/* <1> get encryption alg */
2011-04-25 13:23:10 -05:00
2010-12-08 11:12:31 -06:00
switch ( key - > cipher ) {
case WLAN_CIPHER_SUITE_WEP40 :
key_type = WEP40_ENCRYPTION ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " alg:WEP40 \n " ) ;
2010-12-08 11:12:31 -06:00
break ;
case WLAN_CIPHER_SUITE_WEP104 :
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " alg:WEP104 \n " ) ;
2010-12-08 11:12:31 -06:00
key_type = WEP104_ENCRYPTION ;
break ;
case WLAN_CIPHER_SUITE_TKIP :
key_type = TKIP_ENCRYPTION ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " alg:TKIP \n " ) ;
2010-12-08 11:12:31 -06:00
break ;
case WLAN_CIPHER_SUITE_CCMP :
key_type = AESCCMP_ENCRYPTION ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " alg:CCMP \n " ) ;
2010-12-08 11:12:31 -06:00
break ;
default :
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG , " alg_err:%x!!!! \n " ,
key - > cipher ) ;
2010-12-08 11:12:31 -06:00
goto out_unlock ;
}
2011-04-25 13:23:10 -05:00
if ( key_type = = WEP40_ENCRYPTION | |
key_type = = WEP104_ENCRYPTION | |
mac - > opmode = = NL80211_IFTYPE_ADHOC )
rtlpriv - > sec . use_defaultkey = true ;
2010-12-08 11:12:31 -06:00
/* <2> get key_idx */
key_idx = ( u8 ) ( key - > keyidx ) ;
if ( key_idx > 3 )
goto out_unlock ;
/* <3> if pairwise key enable_hw_sec */
group_key = ! ( key - > flags & IEEE80211_KEY_FLAG_PAIRWISE ) ;
2011-04-25 13:23:10 -05:00
/* wep always be group key, but there are two conditions:
* 1 ) wep only : is just for wep enc , in this condition
* rtlpriv - > sec . pairwise_enc_algorithm = = NO_ENCRYPTION
* will be true & enable_hw_sec will be set when wep
* ke setting .
* 2 ) wep ( group ) + AES ( pairwise ) : some AP like cisco
* may use it , in this condition enable_hw_sec will not
* be set when wep key setting */
/* we must reset sec_info after lingked before set key,
* or some flag will be wrong */
if ( mac - > opmode = = NL80211_IFTYPE_AP ) {
if ( ! group_key | | key_type = = WEP40_ENCRYPTION | |
key_type = = WEP104_ENCRYPTION ) {
if ( group_key )
wep_only = true ;
rtlpriv - > cfg - > ops - > enable_hw_sec ( hw ) ;
}
} else {
if ( ( ! group_key ) | | ( mac - > opmode = = NL80211_IFTYPE_ADHOC ) | |
rtlpriv - > sec . pairwise_enc_algorithm = = NO_ENCRYPTION ) {
if ( rtlpriv - > sec . pairwise_enc_algorithm = =
NO_ENCRYPTION & &
( key_type = = WEP40_ENCRYPTION | |
key_type = = WEP104_ENCRYPTION ) )
wep_only = true ;
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5) \n " ,
key_type ) ;
2011-04-25 13:23:10 -05:00
rtlpriv - > cfg - > ops - > enable_hw_sec ( hw ) ;
}
2010-12-08 11:12:31 -06:00
}
/* <4> set key based on cmd */
switch ( cmd ) {
case SET_KEY :
if ( wep_only ) {
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" set WEP(group/pairwise) key \n " ) ;
2010-12-08 11:12:31 -06:00
/* Pairwise key with an assigned MAC address. */
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
rtlpriv - > sec . group_enc_algorithm = key_type ;
/*set local buf about wep key. */
memcpy ( rtlpriv - > sec . key_buf [ key_idx ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = key - > keylen ;
memcpy ( mac_addr , zero_addr , ETH_ALEN ) ;
} else if ( group_key ) { /* group key */
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" set group key \n " ) ;
2010-12-08 11:12:31 -06:00
/* group key */
rtlpriv - > sec . group_enc_algorithm = key_type ;
/*set local buf about group key. */
memcpy ( rtlpriv - > sec . key_buf [ key_idx ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = key - > keylen ;
memcpy ( mac_addr , bcast_addr , ETH_ALEN ) ;
} else { /* pairwise key */
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" set pairwise key \n " ) ;
2010-12-08 11:12:31 -06:00
if ( ! sta ) {
2012-01-04 19:40:43 -08:00
RT_ASSERT ( false ,
" pairwise key without mac_addr \n " ) ;
2011-04-25 13:23:10 -05:00
2010-12-08 11:12:31 -06:00
err = - EOPNOTSUPP ;
goto out_unlock ;
}
/* Pairwise key with an assigned MAC address. */
rtlpriv - > sec . pairwise_enc_algorithm = key_type ;
/*set local buf about pairwise key. */
memcpy ( rtlpriv - > sec . key_buf [ PAIRWISE_KEYIDX ] ,
key - > key , key - > keylen ) ;
rtlpriv - > sec . key_len [ PAIRWISE_KEYIDX ] = key - > keylen ;
rtlpriv - > sec . pairwise_key =
rtlpriv - > sec . key_buf [ PAIRWISE_KEYIDX ] ;
memcpy ( mac_addr , sta - > addr , ETH_ALEN ) ;
}
rtlpriv - > cfg - > ops - > set_key ( hw , key_idx , mac_addr ,
group_key , key_type , wep_only ,
false ) ;
/* <5> tell mac80211 do something: */
/*must use sw generate IV, or can not work !!!!. */
key - > flags | = IEEE80211_KEY_FLAG_GENERATE_IV ;
key - > hw_key_idx = key_idx ;
if ( key_type = = TKIP_ENCRYPTION )
key - > flags | = IEEE80211_KEY_FLAG_GENERATE_MMIC ;
break ;
case DISABLE_KEY :
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" disable key delete one entry \n " ) ;
2010-12-08 11:12:31 -06:00
/*set local buf about wep key. */
2011-04-25 13:23:10 -05:00
if ( mac - > opmode = = NL80211_IFTYPE_AP ) {
if ( sta )
rtl_cam_del_entry ( hw , sta - > addr ) ;
}
2010-12-08 11:12:31 -06:00
memset ( rtlpriv - > sec . key_buf [ key_idx ] , 0 , key - > keylen ) ;
rtlpriv - > sec . key_len [ key_idx ] = 0 ;
memcpy ( mac_addr , zero_addr , ETH_ALEN ) ;
/*
* mac80211 will delete entrys one by one ,
* so don ' t use rtl_cam_reset_all_entry
* or clear all entry here .
*/
rtl_cam_delete_one_entry ( hw , mac_addr , key_idx ) ;
2011-09-03 10:58:48 -05:00
rtl_cam_reset_sec_info ( hw ) ;
2010-12-08 11:12:31 -06:00
break ;
default :
RT_TRACE ( rtlpriv , COMP_ERR , DBG_EMERG ,
2012-01-04 19:40:41 -08:00
" cmd_err:%x!!!! \n " , cmd ) ;
2010-12-08 11:12:31 -06:00
}
out_unlock :
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
rtlpriv - > sec . being_setkey = false ;
return err ;
}
static void rtl_op_rfkill_poll ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
bool radio_state ;
bool blocked ;
u8 valid = 0 ;
if ( ! test_bit ( RTL_STATUS_INTERFACE_START , & rtlpriv - > status ) )
return ;
2010-12-16 11:13:57 -06:00
mutex_lock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
/*if Radio On return true here */
radio_state = rtlpriv - > cfg - > ops - > radio_onoff_checking ( hw , & valid ) ;
if ( valid ) {
if ( unlikely ( radio_state ! = rtlpriv - > rfkill . rfkill_state ) ) {
rtlpriv - > rfkill . rfkill_state = radio_state ;
RT_TRACE ( rtlpriv , COMP_RF , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" wireless radio switch turned %s \n " ,
radio_state ? " on " : " off " ) ;
2010-12-08 11:12:31 -06:00
blocked = ( rtlpriv - > rfkill . rfkill_state = = 1 ) ? 0 : 1 ;
wiphy_rfkill_set_hw_state ( hw - > wiphy , blocked ) ;
}
}
2010-12-16 11:13:57 -06:00
mutex_unlock ( & rtlpriv - > locks . conf_mutex ) ;
2010-12-08 11:12:31 -06:00
}
2011-04-25 13:23:10 -05:00
/* this function is called by mac80211 to flush tx buffer
* before switch channle or power save , or tx buffer packet
* maybe send after offchannel or rf sleep , this may cause
* dis - association by AP */
static void rtl_op_flush ( struct ieee80211_hw * hw , bool drop )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
if ( rtlpriv - > intf_ops - > flush )
rtlpriv - > intf_ops - > flush ( hw , drop ) ;
}
2010-12-08 11:12:31 -06:00
const struct ieee80211_ops rtl_ops = {
. start = rtl_op_start ,
. stop = rtl_op_stop ,
. tx = rtl_op_tx ,
. add_interface = rtl_op_add_interface ,
. remove_interface = rtl_op_remove_interface ,
. config = rtl_op_config ,
. configure_filter = rtl_op_configure_filter ,
2011-04-25 13:23:10 -05:00
. sta_add = rtl_op_sta_add ,
. sta_remove = rtl_op_sta_remove ,
2010-12-08 11:12:31 -06:00
. set_key = rtl_op_set_key ,
. conf_tx = rtl_op_conf_tx ,
. bss_info_changed = rtl_op_bss_info_changed ,
. get_tsf = rtl_op_get_tsf ,
. set_tsf = rtl_op_set_tsf ,
. reset_tsf = rtl_op_reset_tsf ,
. sta_notify = rtl_op_sta_notify ,
. ampdu_action = rtl_op_ampdu_action ,
. sw_scan_start = rtl_op_sw_scan_start ,
. sw_scan_complete = rtl_op_sw_scan_complete ,
. rfkill_poll = rtl_op_rfkill_poll ,
2011-04-25 13:23:10 -05:00
. flush = rtl_op_flush ,
2010-12-08 11:12:31 -06:00
} ;