@ -93,6 +93,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
might_sleep ( ) ;
if ( key - > flags & KEY_FLAG_TAINTED )
return - EINVAL ;
if ( ! key - > local - > ops - > set_key )
goto out_unsupported ;
@ -455,6 +458,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data * sdata ,
struct sta_info * sta )
{
struct ieee80211_local * local = sdata - > local ;
struct ieee80211_key * old_key ;
int idx , ret ;
bool pairwise ;
@ -484,10 +488,13 @@ int ieee80211_key_link(struct ieee80211_key *key,
ieee80211_debugfs_key_add ( key ) ;
ret = ieee80211_key_enable_hw_accel ( key ) ;
if ( ret )
ieee80211_key_free ( key , true ) ;
if ( ! local - > wowlan ) {
ret = ieee80211_key_enable_hw_accel ( key ) ;
if ( ret )
ieee80211_key_free ( key , true ) ;
} else {
ret = 0 ;
}
mutex_unlock ( & sdata - > local - > key_mtx ) ;
@ -540,7 +547,7 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
void * iter_data )
{
struct ieee80211_local * local = hw_to_local ( hw ) ;
struct ieee80211_key * key ;
struct ieee80211_key * key , * tmp ;
struct ieee80211_sub_if_data * sdata ;
ASSERT_RTNL ( ) ;
@ -548,13 +555,14 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
mutex_lock ( & local - > key_mtx ) ;
if ( vif ) {
sdata = vif_to_sdata ( vif ) ;
list_for_each_entry ( key , & sdata - > key_list , list )
list_for_each_entry_safe ( key , tmp , & sdata - > key_list , list )
iter ( hw , & sdata - > vif ,
key - > sta ? & key - > sta - > sta : NULL ,
& key - > conf , iter_data ) ;
} else {
list_for_each_entry ( sdata , & local - > interfaces , list )
list_for_each_entry ( key , & sdata - > key_list , list )
list_for_each_entry_safe ( key , tmp ,
& sdata - > key_list , list )
iter ( hw , & sdata - > vif ,
key - > sta ? & key - > sta - > sta : NULL ,
& key - > conf , iter_data ) ;
@ -751,3 +759,135 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
}
}
EXPORT_SYMBOL ( ieee80211_get_key_rx_seq ) ;
void ieee80211_set_key_tx_seq ( struct ieee80211_key_conf * keyconf ,
struct ieee80211_key_seq * seq )
{
struct ieee80211_key * key ;
u64 pn64 ;
key = container_of ( keyconf , struct ieee80211_key , conf ) ;
switch ( key - > conf . cipher ) {
case WLAN_CIPHER_SUITE_TKIP :
key - > u . tkip . tx . iv32 = seq - > tkip . iv32 ;
key - > u . tkip . tx . iv16 = seq - > tkip . iv16 ;
break ;
case WLAN_CIPHER_SUITE_CCMP :
pn64 = ( u64 ) seq - > ccmp . pn [ 5 ] |
( ( u64 ) seq - > ccmp . pn [ 4 ] < < 8 ) |
( ( u64 ) seq - > ccmp . pn [ 3 ] < < 16 ) |
( ( u64 ) seq - > ccmp . pn [ 2 ] < < 24 ) |
( ( u64 ) seq - > ccmp . pn [ 1 ] < < 32 ) |
( ( u64 ) seq - > ccmp . pn [ 0 ] < < 40 ) ;
atomic64_set ( & key - > u . ccmp . tx_pn , pn64 ) ;
break ;
case WLAN_CIPHER_SUITE_AES_CMAC :
pn64 = ( u64 ) seq - > aes_cmac . pn [ 5 ] |
( ( u64 ) seq - > aes_cmac . pn [ 4 ] < < 8 ) |
( ( u64 ) seq - > aes_cmac . pn [ 3 ] < < 16 ) |
( ( u64 ) seq - > aes_cmac . pn [ 2 ] < < 24 ) |
( ( u64 ) seq - > aes_cmac . pn [ 1 ] < < 32 ) |
( ( u64 ) seq - > aes_cmac . pn [ 0 ] < < 40 ) ;
atomic64_set ( & key - > u . aes_cmac . tx_pn , pn64 ) ;
break ;
default :
WARN_ON ( 1 ) ;
break ;
}
}
EXPORT_SYMBOL_GPL ( ieee80211_set_key_tx_seq ) ;
void ieee80211_set_key_rx_seq ( struct ieee80211_key_conf * keyconf ,
int tid , struct ieee80211_key_seq * seq )
{
struct ieee80211_key * key ;
u8 * pn ;
key = container_of ( keyconf , struct ieee80211_key , conf ) ;
switch ( key - > conf . cipher ) {
case WLAN_CIPHER_SUITE_TKIP :
if ( WARN_ON ( tid < 0 | | tid > = IEEE80211_NUM_TIDS ) )
return ;
key - > u . tkip . rx [ tid ] . iv32 = seq - > tkip . iv32 ;
key - > u . tkip . rx [ tid ] . iv16 = seq - > tkip . iv16 ;
break ;
case WLAN_CIPHER_SUITE_CCMP :
if ( WARN_ON ( tid < - 1 | | tid > = IEEE80211_NUM_TIDS ) )
return ;
if ( tid < 0 )
pn = key - > u . ccmp . rx_pn [ IEEE80211_NUM_TIDS ] ;
else
pn = key - > u . ccmp . rx_pn [ tid ] ;
memcpy ( pn , seq - > ccmp . pn , IEEE80211_CCMP_PN_LEN ) ;
break ;
case WLAN_CIPHER_SUITE_AES_CMAC :
if ( WARN_ON ( tid ! = 0 ) )
return ;
pn = key - > u . aes_cmac . rx_pn ;
memcpy ( pn , seq - > aes_cmac . pn , IEEE80211_CMAC_PN_LEN ) ;
break ;
default :
WARN_ON ( 1 ) ;
break ;
}
}
EXPORT_SYMBOL_GPL ( ieee80211_set_key_rx_seq ) ;
void ieee80211_remove_key ( struct ieee80211_key_conf * keyconf )
{
struct ieee80211_key * key ;
key = container_of ( keyconf , struct ieee80211_key , conf ) ;
assert_key_lock ( key - > local ) ;
/*
* if key was uploaded , we assume the driver will / has remove ( d )
* it , so adjust bookkeeping accordingly
*/
if ( key - > flags & KEY_FLAG_UPLOADED_TO_HARDWARE ) {
key - > flags & = ~ KEY_FLAG_UPLOADED_TO_HARDWARE ;
if ( ! ( ( key - > conf . flags & IEEE80211_KEY_FLAG_GENERATE_MMIC ) | |
( key - > conf . flags & IEEE80211_KEY_FLAG_GENERATE_IV ) | |
( key - > conf . flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE ) ) )
increment_tailroom_need_count ( key - > sdata ) ;
}
ieee80211_key_free ( key , false ) ;
}
EXPORT_SYMBOL_GPL ( ieee80211_remove_key ) ;
struct ieee80211_key_conf *
ieee80211_gtk_rekey_add ( struct ieee80211_vif * vif ,
struct ieee80211_key_conf * keyconf )
{
struct ieee80211_sub_if_data * sdata = vif_to_sdata ( vif ) ;
struct ieee80211_local * local = sdata - > local ;
struct ieee80211_key * key ;
int err ;
if ( WARN_ON ( ! local - > wowlan ) )
return ERR_PTR ( - EINVAL ) ;
if ( WARN_ON ( vif - > type ! = NL80211_IFTYPE_STATION ) )
return ERR_PTR ( - EINVAL ) ;
key = ieee80211_key_alloc ( keyconf - > cipher , keyconf - > keyidx ,
keyconf - > keylen , keyconf - > key ,
0 , NULL ) ;
if ( IS_ERR ( key ) )
return ERR_PTR ( PTR_ERR ( key ) ) ;
if ( sdata - > u . mgd . mfp ! = IEEE80211_MFP_DISABLED )
key - > conf . flags | = IEEE80211_KEY_FLAG_RX_MGMT ;
err = ieee80211_key_link ( key , sdata , NULL ) ;
if ( err )
return ERR_PTR ( err ) ;
return & key - > conf ;
}
EXPORT_SYMBOL_GPL ( ieee80211_gtk_rekey_add ) ;