diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 90 |
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; |