mac80211: reject unhandled action frames
802.11-2007 7.3.1.11 mandates that we need to reject action frames we don't handle by setting the 0x80 bit in the category and returning them to the sender, so do that. In AP mode, hostapd is responsible for this. Additionally, drop completely malformed action frames or ones that should've been encrypted as unusable, userspace shouldn't see those. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
de1ebdceb6
commit
8404080568
|
@ -2,7 +2,7 @@
|
||||||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* 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
|
* 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
|
* 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_local *local = rx->local;
|
||||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
|
||||||
|
struct sk_buff *nskb;
|
||||||
int len = rx->skb->len;
|
int len = rx->skb->len;
|
||||||
|
|
||||||
if (!ieee80211_is_action(mgmt->frame_control))
|
if (!ieee80211_is_action(mgmt->frame_control))
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
|
|
||||||
if (!rx->sta)
|
if (!rx->sta)
|
||||||
return RX_DROP_MONITOR;
|
return RX_DROP_UNUSABLE;
|
||||||
|
|
||||||
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
||||||
return RX_DROP_MONITOR;
|
return RX_DROP_UNUSABLE;
|
||||||
|
|
||||||
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
|
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)
|
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
|
||||||
return RX_DROP_MONITOR;
|
goto return_frame;
|
||||||
|
|
||||||
switch (mgmt->u.action.category) {
|
switch (mgmt->u.action.category) {
|
||||||
case WLAN_CATEGORY_BACK:
|
case WLAN_CATEGORY_BACK:
|
||||||
|
@ -1884,7 +1889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||||
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
switch (mgmt->u.action.u.addba_req.action_code) {
|
switch (mgmt->u.action.u.addba_req.action_code) {
|
||||||
case WLAN_ACTION_ADDBA_REQ:
|
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)))
|
sizeof(mgmt->u.action.u.addba_req)))
|
||||||
return RX_DROP_MONITOR;
|
return RX_DROP_MONITOR;
|
||||||
ieee80211_process_addba_request(local, rx->sta, mgmt, len);
|
ieee80211_process_addba_request(local, rx->sta, mgmt, len);
|
||||||
break;
|
goto handled;
|
||||||
case WLAN_ACTION_ADDBA_RESP:
|
case WLAN_ACTION_ADDBA_RESP:
|
||||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||||
sizeof(mgmt->u.action.u.addba_resp)))
|
sizeof(mgmt->u.action.u.addba_resp)))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
|
ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
|
||||||
break;
|
goto handled;
|
||||||
case WLAN_ACTION_DELBA:
|
case WLAN_ACTION_DELBA:
|
||||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||||
sizeof(mgmt->u.action.u.delba)))
|
sizeof(mgmt->u.action.u.delba)))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
ieee80211_process_delba(sdata, rx->sta, mgmt, len);
|
ieee80211_process_delba(sdata, rx->sta, mgmt, len);
|
||||||
break;
|
goto handled;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WLAN_CATEGORY_SPECTRUM_MGMT:
|
case WLAN_CATEGORY_SPECTRUM_MGMT:
|
||||||
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
|
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
switch (mgmt->u.action.u.measurement.action_code) {
|
switch (mgmt->u.action.u.measurement.action_code) {
|
||||||
case WLAN_ACTION_SPCT_MSR_REQ:
|
case WLAN_ACTION_SPCT_MSR_REQ:
|
||||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||||
sizeof(mgmt->u.action.u.measurement)))
|
sizeof(mgmt->u.action.u.measurement)))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
ieee80211_process_measurement_req(sdata, mgmt, len);
|
ieee80211_process_measurement_req(sdata, mgmt, len);
|
||||||
break;
|
goto handled;
|
||||||
case WLAN_ACTION_SPCT_CHL_SWITCH:
|
case WLAN_ACTION_SPCT_CHL_SWITCH:
|
||||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||||
sizeof(mgmt->u.action.u.chan_switch)))
|
sizeof(mgmt->u.action.u.chan_switch)))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
|
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
return ieee80211_sta_rx_mgmt(sdata, rx->skb);
|
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:
|
case WLAN_CATEGORY_SA_QUERY:
|
||||||
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||||||
sizeof(mgmt->u.action.u.sa_query)))
|
sizeof(mgmt->u.action.u.sa_query)))
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
|
|
||||||
switch (mgmt->u.action.u.sa_query.action) {
|
switch (mgmt->u.action.u.sa_query.action) {
|
||||||
case WLAN_ACTION_SA_QUERY_REQUEST:
|
case WLAN_ACTION_SA_QUERY_REQUEST:
|
||||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||||
return RX_DROP_MONITOR;
|
break;
|
||||||
ieee80211_process_sa_query_req(sdata, mgmt, len);
|
ieee80211_process_sa_query_req(sdata, mgmt, len);
|
||||||
break;
|
goto handled;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
/* do not process rejected action frames */
|
return_frame:
|
||||||
if (mgmt->u.action.category & 0x80)
|
/*
|
||||||
return RX_DROP_MONITOR;
|
* 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++;
|
rx->sta->rx_packets++;
|
||||||
dev_kfree_skb(rx->skb);
|
dev_kfree_skb(rx->skb);
|
||||||
return RX_QUEUED;
|
return RX_QUEUED;
|
||||||
|
|
Loading…
Reference in a new issue