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 .
*
* 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 .
*
2011-04-25 13:23:05 -05:00
* Larry Finger < Larry . Finger @ lwfinger . net >
*
2010-12-08 11:12:31 -06:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "wifi.h"
# include "cam.h"
2014-09-22 09:39:22 -05:00
# include <linux/export.h>
2010-12-08 11:12:31 -06:00
void rtl_cam_reset_sec_info ( struct ieee80211_hw * hw )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
rtlpriv - > sec . use_defaultkey = false ;
rtlpriv - > sec . pairwise_enc_algorithm = NO_ENCRYPTION ;
rtlpriv - > sec . group_enc_algorithm = NO_ENCRYPTION ;
memset ( rtlpriv - > sec . key_buf , 0 , KEY_BUF_SIZE * MAX_KEY_LEN ) ;
memset ( rtlpriv - > sec . key_len , 0 , KEY_BUF_SIZE ) ;
rtlpriv - > sec . pairwise_key = NULL ;
}
static void rtl_cam_program_entry ( struct ieee80211_hw * hw , u32 entry_no ,
u8 * mac_addr , u8 * key_cont_128 , u16 us_config )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u32 target_command ;
u32 target_content = 0 ;
u8 entry_i ;
2014-09-22 09:39:22 -05:00
RT_PRINT_DATA ( rtlpriv , COMP_SEC , DBG_DMESG , " Key content : " ,
key_cont_128 , 16 ) ;
2010-12-08 11:12:31 -06:00
for ( entry_i = 0 ; entry_i < CAM_CONTENT_COUNT ; entry_i + + ) {
target_command = entry_i + CAM_CONTENT_COUNT * entry_no ;
target_command = target_command | BIT ( 31 ) | BIT ( 16 ) ;
if ( entry_i = = 0 ) {
target_content = ( u32 ) ( * ( mac_addr + 0 ) ) < < 16 |
( u32 ) ( * ( mac_addr + 1 ) ) < < 24 | ( u32 ) us_config ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] ,
target_content ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] ,
target_command ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE %x: %x \n " ,
2012-01-04 19:40:41 -08:00
rtlpriv - > cfg - > maps [ WCAMI ] , target_content ) ;
2011-04-25 13:23:05 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" The Key ID is %d \n " , entry_no ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE %x: %x \n " ,
2012-01-04 19:40:41 -08:00
rtlpriv - > cfg - > maps [ RWCAM ] , target_command ) ;
2010-12-08 11:12:31 -06:00
} else if ( entry_i = = 1 ) {
target_content = ( u32 ) ( * ( mac_addr + 5 ) ) < < 24 |
( u32 ) ( * ( mac_addr + 4 ) ) < < 16 |
( u32 ) ( * ( mac_addr + 3 ) ) < < 8 |
( u32 ) ( * ( mac_addr + 2 ) ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] ,
target_content ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] ,
target_command ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE A4: %x \n " , target_content ) ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE A0: %x \n " , target_command ) ;
2010-12-08 11:12:31 -06:00
} else {
target_content =
( u32 ) ( * ( key_cont_128 + ( entry_i * 4 - 8 ) + 3 ) ) < <
24 | ( u32 ) ( * ( key_cont_128 + ( entry_i * 4 - 8 ) + 2 ) )
< < 16 |
( u32 ) ( * ( key_cont_128 + ( entry_i * 4 - 8 ) + 1 ) ) < < 8
| ( u32 ) ( * ( key_cont_128 + ( entry_i * 4 - 8 ) + 0 ) ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] ,
target_content ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] ,
target_command ) ;
udelay ( 100 ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE A4: %x \n " , target_content ) ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" WRITE A0: %x \n " , target_command ) ;
2010-12-08 11:12:31 -06:00
}
}
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
" after set key, usconfig:%x \n " , us_config ) ;
2010-12-08 11:12:31 -06:00
}
u8 rtl_cam_add_one_entry ( struct ieee80211_hw * hw , u8 * mac_addr ,
u32 ul_key_id , u32 ul_entry_idx , u32 ul_enc_alg ,
u32 ul_default_key , u8 * key_content )
{
u32 us_config ;
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM \n " ,
ul_entry_idx , ul_key_id , ul_enc_alg ,
ul_default_key , mac_addr ) ;
2010-12-08 11:12:31 -06:00
if ( ul_key_id = = TOTAL_CAM_ENTRY ) {
RT_TRACE ( rtlpriv , COMP_ERR , DBG_WARNING ,
2014-09-22 09:39:22 -05:00
" ulKeyId exceed! \n " ) ;
2010-12-08 11:12:31 -06:00
return 0 ;
}
2014-09-22 09:39:22 -05:00
if ( ul_default_key = = 1 )
2010-12-08 11:12:31 -06:00
us_config = CFG_VALID | ( ( u16 ) ( ul_enc_alg ) < < 2 ) ;
2014-09-22 09:39:22 -05:00
else
2010-12-08 11:12:31 -06:00
us_config = CFG_VALID | ( ( ul_enc_alg ) < < 2 ) | ul_key_id ;
rtl_cam_program_entry ( hw , ul_entry_idx , mac_addr ,
2014-09-22 09:39:22 -05:00
( u8 * ) key_content , us_config ) ;
2010-12-08 11:12:31 -06:00
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " end \n " ) ;
2010-12-08 11:12:31 -06:00
return 1 ;
}
EXPORT_SYMBOL ( rtl_cam_add_one_entry ) ;
int rtl_cam_delete_one_entry ( struct ieee80211_hw * hw ,
u8 * mac_addr , u32 ul_key_id )
{
u32 ul_command ;
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
2012-01-04 19:40:41 -08:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG , " key_idx:%d \n " , ul_key_id ) ;
2010-12-08 11:12:31 -06:00
ul_command = ul_key_id * CAM_CONTENT_COUNT ;
ul_command = ul_command | BIT ( 31 ) | BIT ( 16 ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] , 0 ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] , ul_command ) ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" rtl_cam_delete_one_entry(): WRITE A4: %x \n " , 0 ) ;
2010-12-08 11:12:31 -06:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" rtl_cam_delete_one_entry(): WRITE A0: %x \n " , ul_command ) ;
2010-12-08 11:12:31 -06:00
return 0 ;
}
EXPORT_SYMBOL ( rtl_cam_delete_one_entry ) ;
void rtl_cam_reset_all_entry ( struct ieee80211_hw * hw )
{
u32 ul_command ;
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
ul_command = BIT ( 31 ) | BIT ( 30 ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] , ul_command ) ;
}
EXPORT_SYMBOL ( rtl_cam_reset_all_entry ) ;
void rtl_cam_mark_invalid ( struct ieee80211_hw * hw , u8 uc_index )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u32 ul_command ;
u32 ul_content ;
u32 ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
switch ( rtlpriv - > sec . pairwise_enc_algorithm ) {
case WEP40_ENCRYPTION :
ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_WEP40 ] ;
break ;
case WEP104_ENCRYPTION :
ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_WEP104 ] ;
break ;
case TKIP_ENCRYPTION :
ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_TKIP ] ;
break ;
case AESCCMP_ENCRYPTION :
ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
break ;
default :
ul_enc_algo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
}
ul_content = ( uc_index & 3 ) | ( ( u16 ) ( ul_enc_algo ) < < 2 ) ;
ul_content | = BIT ( 15 ) ;
ul_command = CAM_CONTENT_COUNT * uc_index ;
ul_command = ul_command | BIT ( 31 ) | BIT ( 16 ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] , ul_content ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] , ul_command ) ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" rtl_cam_mark_invalid(): WRITE A4: %x \n " , ul_content ) ;
2010-12-08 11:12:31 -06:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
2012-01-04 19:40:41 -08:00
" rtl_cam_mark_invalid(): WRITE A0: %x \n " , ul_command ) ;
2010-12-08 11:12:31 -06:00
}
EXPORT_SYMBOL ( rtl_cam_mark_invalid ) ;
void rtl_cam_empty_entry ( struct ieee80211_hw * hw , u8 uc_index )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u32 ul_command ;
u32 ul_content ;
u32 ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
u8 entry_i ;
switch ( rtlpriv - > sec . pairwise_enc_algorithm ) {
case WEP40_ENCRYPTION :
ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_WEP40 ] ;
break ;
case WEP104_ENCRYPTION :
ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_WEP104 ] ;
break ;
case TKIP_ENCRYPTION :
ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_TKIP ] ;
break ;
case AESCCMP_ENCRYPTION :
ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
break ;
default :
ul_encalgo = rtlpriv - > cfg - > maps [ SEC_CAM_AES ] ;
}
for ( entry_i = 0 ; entry_i < CAM_CONTENT_COUNT ; entry_i + + ) {
if ( entry_i = = 0 ) {
ul_content =
( uc_index & 0x03 ) | ( ( u16 ) ( ul_encalgo ) < < 2 ) ;
ul_content | = BIT ( 15 ) ;
} else {
ul_content = 0 ;
}
ul_command = CAM_CONTENT_COUNT * uc_index + entry_i ;
ul_command = ul_command | BIT ( 31 ) | BIT ( 16 ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ WCAMI ] , ul_content ) ;
rtl_write_dword ( rtlpriv , rtlpriv - > cfg - > maps [ RWCAM ] , ul_command ) ;
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" rtl_cam_empty_entry(): WRITE A4: %x \n " ,
ul_content ) ;
2010-12-08 11:12:31 -06:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_LOUD ,
2012-01-04 19:40:41 -08:00
" rtl_cam_empty_entry(): WRITE A0: %x \n " ,
ul_command ) ;
2010-12-08 11:12:31 -06:00
}
}
EXPORT_SYMBOL ( rtl_cam_empty_entry ) ;
2011-04-25 13:23:05 -05:00
u8 rtl_cam_get_free_entry ( struct ieee80211_hw * hw , u8 * sta_addr )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u32 bitmap = ( rtlpriv - > sec . hwsec_cam_bitmap ) > > 4 ;
u8 entry_idx = 0 ;
u8 i , * addr ;
if ( NULL = = sta_addr ) {
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_EMERG ,
" sta_addr is NULL. \n " ) ;
2011-04-25 13:23:05 -05:00
return TOTAL_CAM_ENTRY ;
}
/* Does STA already exist? */
for ( i = 4 ; i < TOTAL_CAM_ENTRY ; i + + ) {
addr = rtlpriv - > sec . hwsec_cam_sta_addr [ i ] ;
2013-12-26 19:41:30 +08:00
if ( ether_addr_equal_unaligned ( addr , sta_addr ) )
2011-04-25 13:23:05 -05:00
return i ;
}
/* Get a free CAM entry. */
for ( entry_idx = 4 ; entry_idx < TOTAL_CAM_ENTRY ; entry_idx + + ) {
if ( ( bitmap & BIT ( 0 ) ) = = 0 ) {
RT_TRACE ( rtlpriv , COMP_SEC , DBG_EMERG ,
2012-01-04 19:40:41 -08:00
" -----hwsec_cam_bitmap: 0x%x entry_idx=%d \n " ,
rtlpriv - > sec . hwsec_cam_bitmap , entry_idx ) ;
2011-04-25 13:23:05 -05:00
rtlpriv - > sec . hwsec_cam_bitmap | = BIT ( 0 ) < < entry_idx ;
memcpy ( rtlpriv - > sec . hwsec_cam_sta_addr [ entry_idx ] ,
sta_addr , ETH_ALEN ) ;
return entry_idx ;
}
bitmap = bitmap > > 1 ;
}
return TOTAL_CAM_ENTRY ;
}
EXPORT_SYMBOL ( rtl_cam_get_free_entry ) ;
void rtl_cam_del_entry ( struct ieee80211_hw * hw , u8 * sta_addr )
{
struct rtl_priv * rtlpriv = rtl_priv ( hw ) ;
u32 bitmap ;
u8 i , * addr ;
if ( NULL = = sta_addr ) {
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_EMERG ,
" sta_addr is NULL. \n " ) ;
return ;
2011-04-25 13:23:05 -05:00
}
2012-03-17 12:13:30 -07:00
if ( is_zero_ether_addr ( sta_addr ) ) {
2011-04-25 13:23:05 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_EMERG ,
2012-03-17 12:13:30 -07:00
" sta_addr is %pM \n " , sta_addr ) ;
2011-04-25 13:23:05 -05:00
return ;
}
/* Does STA already exist? */
for ( i = 4 ; i < TOTAL_CAM_ENTRY ; i + + ) {
addr = rtlpriv - > sec . hwsec_cam_sta_addr [ i ] ;
bitmap = ( rtlpriv - > sec . hwsec_cam_bitmap ) > > i ;
if ( ( ( bitmap & BIT ( 0 ) ) = = BIT ( 0 ) ) & &
2013-12-26 19:41:30 +08:00
( ether_addr_equal_unaligned ( addr , sta_addr ) ) ) {
2011-04-25 13:23:05 -05:00
/* Remove from HW Security CAM */
2012-11-15 21:24:57 +08:00
eth_zero_addr ( rtlpriv - > sec . hwsec_cam_sta_addr [ i ] ) ;
2011-04-25 13:23:05 -05:00
rtlpriv - > sec . hwsec_cam_bitmap & = ~ ( BIT ( 0 ) < < i ) ;
2014-09-22 09:39:22 -05:00
RT_TRACE ( rtlpriv , COMP_SEC , DBG_DMESG ,
" &&&&&&&&&del entry %d \n " , i ) ;
2011-04-25 13:23:05 -05:00
}
}
return ;
}
EXPORT_SYMBOL ( rtl_cam_del_entry ) ;