@ -2,7 +2,7 @@
* Copyright 2002 - 2005 , Instant802 Networks , Inc .
* Copyright 2005 - 2006 , Devicescape Software , Inc .
* Copyright 2006 - 2007 Jiri Benc < jbenc @ suse . cz >
* Copyright 2007 Johannes Berg < johannes @ sipsolutions . net >
* Copyright 2007 - 2010 Johannes Berg < johannes @ sipsolutions . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
@ -1855,23 +1855,28 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
struct ieee80211_local * local = rx - > local ;
struct ieee80211_sub_if_data * sdata = rx - > sdata ;
struct ieee80211_mgmt * mgmt = ( struct ieee80211_mgmt * ) rx - > skb - > data ;
struct sk_buff * nskb ;
int len = rx - > skb - > len ;
if ( ! ieee80211_is_action ( mgmt - > frame_control ) )
return RX_CONTINUE ;
if ( ! rx - > sta )
return RX_DROP_MONITOR ;
return RX_DROP_UNUSABLE ;
if ( ! ( rx - > flags & IEEE80211_RX_RA_MATCH ) )
return RX_DROP_MONITOR ;
return RX_DROP_UNUSABLE ;
if ( ieee80211_drop_unencrypted ( rx , mgmt - > frame_control ) )
return RX_DROP_MONITOR ;
return RX_DROP_UNUSABLE ;
/* all categories we currently handle have action_code */
/* drop too small frames */
if ( len < IEEE80211_MIN_ACTION_SIZE )
return RX_DROP_UNUSABLE ;
/* return action frames that have *only* category */
if ( len < IEEE80211_MIN_ACTION_SIZE + 1 )
return RX_DROP_MONITOR ;
goto return_frame ;
switch ( mgmt - > u . action . category ) {
case WLAN_CATEGORY_BACK :
@ -1884,7 +1889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if ( sdata - > vif . type ! = NL80211_IFTYPE_STATION & &
sdata - > vif . type ! = NL80211_IFTYPE_AP_VLAN & &
sdata - > vif . type ! = NL80211_IFTYPE_AP )
return RX_DROP_MONITOR ;
break ;
switch ( mgmt - > u . action . u . addba_req . action_code ) {
case WLAN_ACTION_ADDBA_REQ :
@ -1892,45 +1897,45 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sizeof ( mgmt - > u . action . u . addba_req ) ) )
return RX_DROP_MONITOR ;
ieee80211_process_addba_request ( local , rx - > sta , mgmt , len ) ;
break ;
goto handled ;
case WLAN_ACTION_ADDBA_RESP :
if ( len < ( IEEE80211_MIN_ACTION_SIZE +
sizeof ( mgmt - > u . action . u . addba_resp ) ) )
return RX_DROP_MONITOR ;
break ;
ieee80211_process_addba_resp ( local , rx - > sta , mgmt , len ) ;
break ;
goto handled ;
case WLAN_ACTION_DELBA :
if ( len < ( IEEE80211_MIN_ACTION_SIZE +
sizeof ( mgmt - > u . action . u . delba ) ) )
return RX_DROP_MONITOR ;
break ;
ieee80211_process_delba ( sdata , rx - > sta , mgmt , len ) ;
break ;
goto handled ;
}
break ;
case WLAN_CATEGORY_SPECTRUM_MGMT :
if ( local - > hw . conf . channel - > band ! = IEEE80211_BAND_5GHZ )
return RX_DROP_MONITOR ;
break ;
if ( sdata - > vif . type ! = NL80211_IFTYPE_STATION )
return RX_DROP_MONITOR ;
break ;
switch ( mgmt - > u . action . u . measurement . action_code ) {
case WLAN_ACTION_SPCT_MSR_REQ :
if ( len < ( IEEE80211_MIN_ACTION_SIZE +
sizeof ( mgmt - > u . action . u . measurement ) ) )
return RX_DROP_MONITOR ;
break ;
ieee80211_process_measurement_req ( sdata , mgmt , len ) ;
break ;
goto handled ;
case WLAN_ACTION_SPCT_CHL_SWITCH :
if ( len < ( IEEE80211_MIN_ACTION_SIZE +
sizeof ( mgmt - > u . action . u . chan_switch ) ) )
return RX_DROP_MONITOR ;
break ;
if ( sdata - > vif . type ! = NL80211_IFTYPE_STATION )
return RX_DROP_MONITOR ;
break ;
if ( memcmp ( mgmt - > bssid , sdata - > u . mgd . bssid , ETH_ALEN ) )
return RX_DROP_MONITOR ;
break ;
return ieee80211_sta_rx_mgmt ( sdata , rx - > skb ) ;
}
@ -1938,29 +1943,48 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
case WLAN_CATEGORY_SA_QUERY :
if ( len < ( IEEE80211_MIN_ACTION_SIZE +
sizeof ( mgmt - > u . action . u . sa_query ) ) )
return RX_DROP_MONITOR ;
break ;
switch ( mgmt - > u . action . u . sa_query . action ) {
case WLAN_ACTION_SA_QUERY_REQUEST :
if ( sdata - > vif . type ! = NL80211_IFTYPE_STATION )
return RX_DROP_MONITOR ;
break ;
ieee80211_process_sa_query_req ( sdata , mgmt , len ) ;
break ;
case WLAN_ACTION_SA_QUERY_RESPONSE :
/*
* SA Query response is currently only used in AP mode
* and it is processed in user space .
*/
return RX_CONTINUE ;
goto handled ;
}
break ;
default :
/* do not process rejected action frames */
if ( mgmt - > u . action . category & 0x80 )
return RX_DROP_MONITOR ;
}
return_frame :
/*
* For AP mode , hostapd is responsible for handling any action
* frames that we didn ' t handle , including returning unknown
* ones . For all other modes we will return them to the sender ,
* setting the 0x80 bit in the action category , as required by
* 802.11 - 2007 7.3 .1 .11 .
*/
if ( sdata - > vif . type = = NL80211_IFTYPE_AP | |
sdata - > vif . type = = NL80211_IFTYPE_AP_VLAN )
return RX_DROP_MONITOR ;
return RX_CONTINUE ;
/* do not return rejected action frames */
if ( mgmt - > u . action . category & 0x80 )
return RX_DROP_UNUSABLE ;
nskb = skb_copy_expand ( rx - > skb , local - > hw . extra_tx_headroom , 0 ,
GFP_ATOMIC ) ;
if ( nskb ) {
struct ieee80211_mgmt * mgmt = ( void * ) nskb - > data ;
mgmt - > u . action . category | = 0x80 ;
memcpy ( mgmt - > da , mgmt - > sa , ETH_ALEN ) ;
memcpy ( mgmt - > sa , rx - > sdata - > vif . addr , ETH_ALEN ) ;
memset ( nskb - > cb , 0 , sizeof ( nskb - > cb ) ) ;
ieee80211_tx_skb ( rx - > sdata , nskb ) ;
}
handled :
rx - > sta - > rx_packets + + ;
dev_kfree_skb ( rx - > skb ) ;
return RX_QUEUED ;