aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-02-15 05:46:39 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-02-15 16:14:13 -0500
commit8404080568613d93ad7cf0a16dfb68459b42a264 (patch)
treef09409846d4d2a81f750618082ea65c34854bcd9 /net
parentde1ebdceb6a4fe1b7073b81d273285b7c8bed312 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/rx.c90
1 files changed, 57 insertions, 33 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c9755f3d986c..a177472adc13 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2,7 +2,7 @@
2 * Copyright 2002-2005, Instant802 Networks, Inc. 2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc. 3 * Copyright 2005-2006, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 4 * 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>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * 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)
1855 struct ieee80211_local *local = rx->local; 1855 struct ieee80211_local *local = rx->local;
1856 struct ieee80211_sub_if_data *sdata = rx->sdata; 1856 struct ieee80211_sub_if_data *sdata = rx->sdata;
1857 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 1857 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1858 struct sk_buff *nskb;
1858 int len = rx->skb->len; 1859 int len = rx->skb->len;
1859 1860
1860 if (!ieee80211_is_action(mgmt->frame_control)) 1861 if (!ieee80211_is_action(mgmt->frame_control))
1861 return RX_CONTINUE; 1862 return RX_CONTINUE;
1862 1863
1863 if (!rx->sta) 1864 if (!rx->sta)
1864 return RX_DROP_MONITOR; 1865 return RX_DROP_UNUSABLE;
1865 1866
1866 if (!(rx->flags & IEEE80211_RX_RA_MATCH)) 1867 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1867 return RX_DROP_MONITOR; 1868 return RX_DROP_UNUSABLE;
1868 1869
1869 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) 1870 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
1870 return RX_DROP_MONITOR; 1871 return RX_DROP_UNUSABLE;
1871 1872
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 */
1873 if (len < IEEE80211_MIN_ACTION_SIZE + 1) 1878 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1874 return RX_DROP_MONITOR; 1879 goto return_frame;
1875 1880
1876 switch (mgmt->u.action.category) { 1881 switch (mgmt->u.action.category) {
1877 case WLAN_CATEGORY_BACK: 1882 case WLAN_CATEGORY_BACK:
@@ -1884,7 +1889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1884 if (sdata->vif.type != NL80211_IFTYPE_STATION && 1889 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
1885 sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1890 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1886 sdata->vif.type != NL80211_IFTYPE_AP) 1891 sdata->vif.type != NL80211_IFTYPE_AP)
1887 return RX_DROP_MONITOR; 1892 break;
1888 1893
1889 switch (mgmt->u.action.u.addba_req.action_code) { 1894 switch (mgmt->u.action.u.addba_req.action_code) {
1890 case WLAN_ACTION_ADDBA_REQ: 1895 case WLAN_ACTION_ADDBA_REQ:
@@ -1892,45 +1897,45 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1892 sizeof(mgmt->u.action.u.addba_req))) 1897 sizeof(mgmt->u.action.u.addba_req)))
1893 return RX_DROP_MONITOR; 1898 return RX_DROP_MONITOR;
1894 ieee80211_process_addba_request(local, rx->sta, mgmt, len); 1899 ieee80211_process_addba_request(local, rx->sta, mgmt, len);
1895 break; 1900 goto handled;
1896 case WLAN_ACTION_ADDBA_RESP: 1901 case WLAN_ACTION_ADDBA_RESP:
1897 if (len < (IEEE80211_MIN_ACTION_SIZE + 1902 if (len < (IEEE80211_MIN_ACTION_SIZE +
1898 sizeof(mgmt->u.action.u.addba_resp))) 1903 sizeof(mgmt->u.action.u.addba_resp)))
1899 return RX_DROP_MONITOR; 1904 break;
1900 ieee80211_process_addba_resp(local, rx->sta, mgmt, len); 1905 ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
1901 break; 1906 goto handled;
1902 case WLAN_ACTION_DELBA: 1907 case WLAN_ACTION_DELBA:
1903 if (len < (IEEE80211_MIN_ACTION_SIZE + 1908 if (len < (IEEE80211_MIN_ACTION_SIZE +
1904 sizeof(mgmt->u.action.u.delba))) 1909 sizeof(mgmt->u.action.u.delba)))
1905 return RX_DROP_MONITOR; 1910 break;
1906 ieee80211_process_delba(sdata, rx->sta, mgmt, len); 1911 ieee80211_process_delba(sdata, rx->sta, mgmt, len);
1907 break; 1912 goto handled;
1908 } 1913 }
1909 break; 1914 break;
1910 case WLAN_CATEGORY_SPECTRUM_MGMT: 1915 case WLAN_CATEGORY_SPECTRUM_MGMT:
1911 if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) 1916 if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
1912 return RX_DROP_MONITOR; 1917 break;
1913 1918
1914 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1919 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1915 return RX_DROP_MONITOR; 1920 break;
1916 1921
1917 switch (mgmt->u.action.u.measurement.action_code) { 1922 switch (mgmt->u.action.u.measurement.action_code) {
1918 case WLAN_ACTION_SPCT_MSR_REQ: 1923 case WLAN_ACTION_SPCT_MSR_REQ:
1919 if (len < (IEEE80211_MIN_ACTION_SIZE + 1924 if (len < (IEEE80211_MIN_ACTION_SIZE +
1920 sizeof(mgmt->u.action.u.measurement))) 1925 sizeof(mgmt->u.action.u.measurement)))
1921 return RX_DROP_MONITOR; 1926 break;
1922 ieee80211_process_measurement_req(sdata, mgmt, len); 1927 ieee80211_process_measurement_req(sdata, mgmt, len);
1923 break; 1928 goto handled;
1924 case WLAN_ACTION_SPCT_CHL_SWITCH: 1929 case WLAN_ACTION_SPCT_CHL_SWITCH:
1925 if (len < (IEEE80211_MIN_ACTION_SIZE + 1930 if (len < (IEEE80211_MIN_ACTION_SIZE +
1926 sizeof(mgmt->u.action.u.chan_switch))) 1931 sizeof(mgmt->u.action.u.chan_switch)))
1927 return RX_DROP_MONITOR; 1932 break;
1928 1933
1929 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1934 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1930 return RX_DROP_MONITOR; 1935 break;
1931 1936
1932 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) 1937 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
1933 return RX_DROP_MONITOR; 1938 break;
1934 1939
1935 return ieee80211_sta_rx_mgmt(sdata, rx->skb); 1940 return ieee80211_sta_rx_mgmt(sdata, rx->skb);
1936 } 1941 }
@@ -1938,29 +1943,48 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1938 case WLAN_CATEGORY_SA_QUERY: 1943 case WLAN_CATEGORY_SA_QUERY:
1939 if (len < (IEEE80211_MIN_ACTION_SIZE + 1944 if (len < (IEEE80211_MIN_ACTION_SIZE +
1940 sizeof(mgmt->u.action.u.sa_query))) 1945 sizeof(mgmt->u.action.u.sa_query)))
1941 return RX_DROP_MONITOR; 1946 break;
1947
1942 switch (mgmt->u.action.u.sa_query.action) { 1948 switch (mgmt->u.action.u.sa_query.action) {
1943 case WLAN_ACTION_SA_QUERY_REQUEST: 1949 case WLAN_ACTION_SA_QUERY_REQUEST:
1944 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1950 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1945 return RX_DROP_MONITOR; 1951 break;
1946 ieee80211_process_sa_query_req(sdata, mgmt, len); 1952 ieee80211_process_sa_query_req(sdata, mgmt, len);
1947 break; 1953 goto handled;
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;
1954 } 1954 }
1955 break; 1955 break;
1956 default: 1956 }
1957 /* do not process rejected action frames */ 1957 return_frame:
1958 if (mgmt->u.action.category & 0x80) 1958 /*
1959 return RX_DROP_MONITOR; 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;
1960 1968
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);
1962 } 1985 }
1963 1986
1987 handled:
1964 rx->sta->rx_packets++; 1988 rx->sta->rx_packets++;
1965 dev_kfree_skb(rx->skb); 1989 dev_kfree_skb(rx->skb);
1966 return RX_QUEUED; 1990 return RX_QUEUED;