Skip to content

Commit 8404080

Browse files
jmberglinvjw
authored andcommitted
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>
1 parent de1ebdc commit 8404080

File tree

1 file changed

+57
-33
lines changed

1 file changed

+57
-33
lines changed

net/mac80211/rx.c

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2002-2005, Instant802 Networks, Inc.
33
* Copyright 2005-2006, Devicescape Software, Inc.
44
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
5-
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
5+
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* 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)
18551855
struct ieee80211_local *local = rx->local;
18561856
struct ieee80211_sub_if_data *sdata = rx->sdata;
18571857
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1858+
struct sk_buff *nskb;
18581859
int len = rx->skb->len;
18591860

18601861
if (!ieee80211_is_action(mgmt->frame_control))
18611862
return RX_CONTINUE;
18621863

18631864
if (!rx->sta)
1864-
return RX_DROP_MONITOR;
1865+
return RX_DROP_UNUSABLE;
18651866

18661867
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1867-
return RX_DROP_MONITOR;
1868+
return RX_DROP_UNUSABLE;
18681869

18691870
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
1870-
return RX_DROP_MONITOR;
1871+
return RX_DROP_UNUSABLE;
18711872

1872-
/* all categories we currently handle have action_code */
1873+
/* drop too small frames */
1874+
if (len < IEEE80211_MIN_ACTION_SIZE)
1875+
return RX_DROP_UNUSABLE;
1876+
1877+
/* return action frames that have *only* category */
18731878
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1874-
return RX_DROP_MONITOR;
1879+
goto return_frame;
18751880

18761881
switch (mgmt->u.action.category) {
18771882
case WLAN_CATEGORY_BACK:
@@ -1884,83 +1889,102 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
18841889
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
18851890
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
18861891
sdata->vif.type != NL80211_IFTYPE_AP)
1887-
return RX_DROP_MONITOR;
1892+
break;
18881893

18891894
switch (mgmt->u.action.u.addba_req.action_code) {
18901895
case WLAN_ACTION_ADDBA_REQ:
18911896
if (len < (IEEE80211_MIN_ACTION_SIZE +
18921897
sizeof(mgmt->u.action.u.addba_req)))
18931898
return RX_DROP_MONITOR;
18941899
ieee80211_process_addba_request(local, rx->sta, mgmt, len);
1895-
break;
1900+
goto handled;
18961901
case WLAN_ACTION_ADDBA_RESP:
18971902
if (len < (IEEE80211_MIN_ACTION_SIZE +
18981903
sizeof(mgmt->u.action.u.addba_resp)))
1899-
return RX_DROP_MONITOR;
1904+
break;
19001905
ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
1901-
break;
1906+
goto handled;
19021907
case WLAN_ACTION_DELBA:
19031908
if (len < (IEEE80211_MIN_ACTION_SIZE +
19041909
sizeof(mgmt->u.action.u.delba)))
1905-
return RX_DROP_MONITOR;
1910+
break;
19061911
ieee80211_process_delba(sdata, rx->sta, mgmt, len);
1907-
break;
1912+
goto handled;
19081913
}
19091914
break;
19101915
case WLAN_CATEGORY_SPECTRUM_MGMT:
19111916
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
1912-
return RX_DROP_MONITOR;
1917+
break;
19131918

19141919
if (sdata->vif.type != NL80211_IFTYPE_STATION)
1915-
return RX_DROP_MONITOR;
1920+
break;
19161921

19171922
switch (mgmt->u.action.u.measurement.action_code) {
19181923
case WLAN_ACTION_SPCT_MSR_REQ:
19191924
if (len < (IEEE80211_MIN_ACTION_SIZE +
19201925
sizeof(mgmt->u.action.u.measurement)))
1921-
return RX_DROP_MONITOR;
1926+
break;
19221927
ieee80211_process_measurement_req(sdata, mgmt, len);
1923-
break;
1928+
goto handled;
19241929
case WLAN_ACTION_SPCT_CHL_SWITCH:
19251930
if (len < (IEEE80211_MIN_ACTION_SIZE +
19261931
sizeof(mgmt->u.action.u.chan_switch)))
1927-
return RX_DROP_MONITOR;
1932+
break;
19281933

19291934
if (sdata->vif.type != NL80211_IFTYPE_STATION)
1930-
return RX_DROP_MONITOR;
1935+
break;
19311936

19321937
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
1933-
return RX_DROP_MONITOR;
1938+
break;
19341939

19351940
return ieee80211_sta_rx_mgmt(sdata, rx->skb);
19361941
}
19371942
break;
19381943
case WLAN_CATEGORY_SA_QUERY:
19391944
if (len < (IEEE80211_MIN_ACTION_SIZE +
19401945
sizeof(mgmt->u.action.u.sa_query)))
1941-
return RX_DROP_MONITOR;
1946+
break;
1947+
19421948
switch (mgmt->u.action.u.sa_query.action) {
19431949
case WLAN_ACTION_SA_QUERY_REQUEST:
19441950
if (sdata->vif.type != NL80211_IFTYPE_STATION)
1945-
return RX_DROP_MONITOR;
1951+
break;
19461952
ieee80211_process_sa_query_req(sdata, mgmt, len);
1947-
break;
1948-
case WLAN_ACTION_SA_QUERY_RESPONSE:
1949-
/*
1950-
* SA Query response is currently only used in AP mode
1951-
* and it is processed in user space.
1952-
*/
1953-
return RX_CONTINUE;
1953+
goto handled;
19541954
}
19551955
break;
1956-
default:
1957-
/* do not process rejected action frames */
1958-
if (mgmt->u.action.category & 0x80)
1959-
return RX_DROP_MONITOR;
1956+
}
1957+
return_frame:
1958+
/*
1959+
* For AP mode, hostapd is responsible for handling any action
1960+
* frames that we didn't handle, including returning unknown
1961+
* ones. For all other modes we will return them to the sender,
1962+
* setting the 0x80 bit in the action category, as required by
1963+
* 802.11-2007 7.3.1.11.
1964+
*/
1965+
if (sdata->vif.type == NL80211_IFTYPE_AP ||
1966+
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1967+
return RX_DROP_MONITOR;
19601968

1961-
return RX_CONTINUE;
1969+
/* do not return rejected action frames */
1970+
if (mgmt->u.action.category & 0x80)
1971+
return RX_DROP_UNUSABLE;
1972+
1973+
nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
1974+
GFP_ATOMIC);
1975+
if (nskb) {
1976+
struct ieee80211_mgmt *mgmt = (void *)nskb->data;
1977+
1978+
mgmt->u.action.category |= 0x80;
1979+
memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
1980+
memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
1981+
1982+
memset(nskb->cb, 0, sizeof(nskb->cb));
1983+
1984+
ieee80211_tx_skb(rx->sdata, nskb);
19621985
}
19631986

1987+
handled:
19641988
rx->sta->rx_packets++;
19651989
dev_kfree_skb(rx->skb);
19661990
return RX_QUEUED;

0 commit comments

Comments
 (0)