diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a177472adc13..a6080d8d72bb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1856,28 +1856,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
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 | struct sk_buff *nskb; |
1859 | struct ieee80211_rx_status *status; | ||
1859 | int len = rx->skb->len; | 1860 | int len = rx->skb->len; |
1860 | 1861 | ||
1861 | if (!ieee80211_is_action(mgmt->frame_control)) | 1862 | if (!ieee80211_is_action(mgmt->frame_control)) |
1862 | return RX_CONTINUE; | 1863 | return RX_CONTINUE; |
1863 | 1864 | ||
1864 | if (!rx->sta) | 1865 | /* drop too small frames */ |
1866 | if (len < IEEE80211_MIN_ACTION_SIZE) | ||
1865 | return RX_DROP_UNUSABLE; | 1867 | return RX_DROP_UNUSABLE; |
1866 | 1868 | ||
1867 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1869 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) |
1868 | return RX_DROP_UNUSABLE; | 1870 | return RX_DROP_UNUSABLE; |
1869 | 1871 | ||
1870 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | 1872 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
1871 | return RX_DROP_UNUSABLE; | 1873 | return RX_DROP_UNUSABLE; |
1872 | 1874 | ||
1873 | /* drop too small frames */ | 1875 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) |
1874 | if (len < IEEE80211_MIN_ACTION_SIZE) | ||
1875 | return RX_DROP_UNUSABLE; | 1876 | return RX_DROP_UNUSABLE; |
1876 | 1877 | ||
1877 | /* return action frames that have *only* category */ | ||
1878 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
1879 | goto return_frame; | ||
1880 | |||
1881 | switch (mgmt->u.action.category) { | 1878 | switch (mgmt->u.action.category) { |
1882 | case WLAN_CATEGORY_BACK: | 1879 | case WLAN_CATEGORY_BACK: |
1883 | /* | 1880 | /* |
@@ -1891,6 +1888,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1891 | sdata->vif.type != NL80211_IFTYPE_AP) | 1888 | sdata->vif.type != NL80211_IFTYPE_AP) |
1892 | break; | 1889 | break; |
1893 | 1890 | ||
1891 | /* verify action_code is present */ | ||
1892 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
1893 | break; | ||
1894 | |||
1894 | switch (mgmt->u.action.u.addba_req.action_code) { | 1895 | switch (mgmt->u.action.u.addba_req.action_code) { |
1895 | case WLAN_ACTION_ADDBA_REQ: | 1896 | case WLAN_ACTION_ADDBA_REQ: |
1896 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1897 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
@@ -1919,6 +1920,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1919 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1920 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1920 | break; | 1921 | break; |
1921 | 1922 | ||
1923 | /* verify action_code is present */ | ||
1924 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
1925 | break; | ||
1926 | |||
1922 | switch (mgmt->u.action.u.measurement.action_code) { | 1927 | switch (mgmt->u.action.u.measurement.action_code) { |
1923 | case WLAN_ACTION_SPCT_MSR_REQ: | 1928 | case WLAN_ACTION_SPCT_MSR_REQ: |
1924 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1929 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
@@ -1954,7 +1959,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1954 | } | 1959 | } |
1955 | break; | 1960 | break; |
1956 | } | 1961 | } |
1957 | return_frame: | 1962 | |
1958 | /* | 1963 | /* |
1959 | * For AP mode, hostapd is responsible for handling any action | 1964 | * For AP mode, hostapd is responsible for handling any action |
1960 | * frames that we didn't handle, including returning unknown | 1965 | * frames that we didn't handle, including returning unknown |
@@ -1966,6 +1971,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1966 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1971 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1967 | return RX_DROP_MONITOR; | 1972 | return RX_DROP_MONITOR; |
1968 | 1973 | ||
1974 | /* | ||
1975 | * Getting here means the kernel doesn't know how to handle | ||
1976 | * it, but maybe userspace does ... include returned frames | ||
1977 | * so userspace can register for those to know whether ones | ||
1978 | * it transmitted were processed or returned. | ||
1979 | */ | ||
1980 | status = IEEE80211_SKB_RXCB(rx->skb); | ||
1981 | |||
1982 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
1983 | cfg80211_rx_action(rx->sdata->dev, status->freq, | ||
1984 | rx->skb->data, rx->skb->len, | ||
1985 | GFP_ATOMIC)) | ||
1986 | goto handled; | ||
1987 | |||
1969 | /* do not return rejected action frames */ | 1988 | /* do not return rejected action frames */ |
1970 | if (mgmt->u.action.category & 0x80) | 1989 | if (mgmt->u.action.category & 0x80) |
1971 | return RX_DROP_UNUSABLE; | 1990 | return RX_DROP_UNUSABLE; |
@@ -1985,7 +2004,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1985 | } | 2004 | } |
1986 | 2005 | ||
1987 | handled: | 2006 | handled: |
1988 | rx->sta->rx_packets++; | 2007 | if (rx->sta) |
2008 | rx->sta->rx_packets++; | ||
1989 | dev_kfree_skb(rx->skb); | 2009 | dev_kfree_skb(rx->skb); |
1990 | return RX_QUEUED; | 2010 | return RX_QUEUED; |
1991 | } | 2011 | } |