diff options
author | David S. Miller <davem@davemloft.net> | 2010-06-17 17:19:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-17 17:19:06 -0400 |
commit | bb9c03d8a6893517737b16fdbeb54be3c73b3023 (patch) | |
tree | 35fa0d1defaaf94641963a49126d7bb475ffa4c6 /net/mac80211/rx.c | |
parent | 4de57826810fd2cfeb2ab5c7d003ff9116b8f7ee (diff) | |
parent | abf52f86aa0a49a7377350cafa8f218c4cd227e7 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 137 |
1 files changed, 87 insertions, 50 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6a15632e7ec..a8aa0f2411a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -719,16 +719,13 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
719 | 719 | ||
720 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 720 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
721 | 721 | ||
722 | spin_lock(&sta->lock); | 722 | tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); |
723 | 723 | if (!tid_agg_rx) | |
724 | if (!sta->ampdu_mlme.tid_active_rx[tid]) | 724 | goto dont_reorder; |
725 | goto dont_reorder_unlock; | ||
726 | |||
727 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | ||
728 | 725 | ||
729 | /* qos null data frames are excluded */ | 726 | /* qos null data frames are excluded */ |
730 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) | 727 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) |
731 | goto dont_reorder_unlock; | 728 | goto dont_reorder; |
732 | 729 | ||
733 | /* new, potentially un-ordered, ampdu frame - process it */ | 730 | /* new, potentially un-ordered, ampdu frame - process it */ |
734 | 731 | ||
@@ -740,20 +737,22 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
740 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 737 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
741 | sc = le16_to_cpu(hdr->seq_ctrl); | 738 | sc = le16_to_cpu(hdr->seq_ctrl); |
742 | if (sc & IEEE80211_SCTL_FRAG) { | 739 | if (sc & IEEE80211_SCTL_FRAG) { |
743 | spin_unlock(&sta->lock); | 740 | skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; |
744 | __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, | 741 | skb_queue_tail(&rx->sdata->skb_queue, skb); |
745 | WLAN_REASON_QSTA_REQUIRE_SETUP); | 742 | ieee80211_queue_work(&local->hw, &rx->sdata->work); |
746 | dev_kfree_skb(skb); | ||
747 | return; | 743 | return; |
748 | } | 744 | } |
749 | 745 | ||
750 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) { | 746 | /* |
751 | spin_unlock(&sta->lock); | 747 | * No locking needed -- we will only ever process one |
748 | * RX packet at a time, and thus own tid_agg_rx. All | ||
749 | * other code manipulating it needs to (and does) make | ||
750 | * sure that we cannot get to it any more before doing | ||
751 | * anything with it. | ||
752 | */ | ||
753 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) | ||
752 | return; | 754 | return; |
753 | } | ||
754 | 755 | ||
755 | dont_reorder_unlock: | ||
756 | spin_unlock(&sta->lock); | ||
757 | dont_reorder: | 756 | dont_reorder: |
758 | __skb_queue_tail(frames, skb); | 757 | __skb_queue_tail(frames, skb); |
759 | } | 758 | } |
@@ -1268,11 +1267,13 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1268 | rx->queue, &(rx->skb)); | 1267 | rx->queue, &(rx->skb)); |
1269 | if (rx->key && rx->key->conf.alg == ALG_CCMP && | 1268 | if (rx->key && rx->key->conf.alg == ALG_CCMP && |
1270 | ieee80211_has_protected(fc)) { | 1269 | ieee80211_has_protected(fc)) { |
1270 | int queue = ieee80211_is_mgmt(fc) ? | ||
1271 | NUM_RX_DATA_QUEUES : rx->queue; | ||
1271 | /* Store CCMP PN so that we can verify that the next | 1272 | /* Store CCMP PN so that we can verify that the next |
1272 | * fragment has a sequential PN value. */ | 1273 | * fragment has a sequential PN value. */ |
1273 | entry->ccmp = 1; | 1274 | entry->ccmp = 1; |
1274 | memcpy(entry->last_pn, | 1275 | memcpy(entry->last_pn, |
1275 | rx->key->u.ccmp.rx_pn[rx->queue], | 1276 | rx->key->u.ccmp.rx_pn[queue], |
1276 | CCMP_PN_LEN); | 1277 | CCMP_PN_LEN); |
1277 | } | 1278 | } |
1278 | return RX_QUEUED; | 1279 | return RX_QUEUED; |
@@ -1292,6 +1293,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1292 | if (entry->ccmp) { | 1293 | if (entry->ccmp) { |
1293 | int i; | 1294 | int i; |
1294 | u8 pn[CCMP_PN_LEN], *rpn; | 1295 | u8 pn[CCMP_PN_LEN], *rpn; |
1296 | int queue; | ||
1295 | if (!rx->key || rx->key->conf.alg != ALG_CCMP) | 1297 | if (!rx->key || rx->key->conf.alg != ALG_CCMP) |
1296 | return RX_DROP_UNUSABLE; | 1298 | return RX_DROP_UNUSABLE; |
1297 | memcpy(pn, entry->last_pn, CCMP_PN_LEN); | 1299 | memcpy(pn, entry->last_pn, CCMP_PN_LEN); |
@@ -1300,7 +1302,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1300 | if (pn[i]) | 1302 | if (pn[i]) |
1301 | break; | 1303 | break; |
1302 | } | 1304 | } |
1303 | rpn = rx->key->u.ccmp.rx_pn[rx->queue]; | 1305 | queue = ieee80211_is_mgmt(fc) ? |
1306 | NUM_RX_DATA_QUEUES : rx->queue; | ||
1307 | rpn = rx->key->u.ccmp.rx_pn[queue]; | ||
1304 | if (memcmp(pn, rpn, CCMP_PN_LEN)) | 1308 | if (memcmp(pn, rpn, CCMP_PN_LEN)) |
1305 | return RX_DROP_UNUSABLE; | 1309 | return RX_DROP_UNUSABLE; |
1306 | memcpy(entry->last_pn, pn, CCMP_PN_LEN); | 1310 | memcpy(entry->last_pn, pn, CCMP_PN_LEN); |
@@ -1830,13 +1834,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1830 | &bar_data, sizeof(bar_data))) | 1834 | &bar_data, sizeof(bar_data))) |
1831 | return RX_DROP_MONITOR; | 1835 | return RX_DROP_MONITOR; |
1832 | 1836 | ||
1833 | spin_lock(&rx->sta->lock); | ||
1834 | tid = le16_to_cpu(bar_data.control) >> 12; | 1837 | tid = le16_to_cpu(bar_data.control) >> 12; |
1835 | if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) { | 1838 | |
1836 | spin_unlock(&rx->sta->lock); | 1839 | tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); |
1840 | if (!tid_agg_rx) | ||
1837 | return RX_DROP_MONITOR; | 1841 | return RX_DROP_MONITOR; |
1838 | } | ||
1839 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; | ||
1840 | 1842 | ||
1841 | start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; | 1843 | start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; |
1842 | 1844 | ||
@@ -1849,7 +1851,6 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1849 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, | 1851 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, |
1850 | frames); | 1852 | frames); |
1851 | kfree_skb(skb); | 1853 | kfree_skb(skb); |
1852 | spin_unlock(&rx->sta->lock); | ||
1853 | return RX_QUEUED; | 1854 | return RX_QUEUED; |
1854 | } | 1855 | } |
1855 | 1856 | ||
@@ -1950,30 +1951,27 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1950 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 1951 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
1951 | break; | 1952 | break; |
1952 | 1953 | ||
1953 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
1954 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); | ||
1955 | |||
1956 | switch (mgmt->u.action.u.addba_req.action_code) { | 1954 | switch (mgmt->u.action.u.addba_req.action_code) { |
1957 | case WLAN_ACTION_ADDBA_REQ: | 1955 | case WLAN_ACTION_ADDBA_REQ: |
1958 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1956 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
1959 | sizeof(mgmt->u.action.u.addba_req))) | 1957 | sizeof(mgmt->u.action.u.addba_req))) |
1960 | return RX_DROP_MONITOR; | 1958 | goto invalid; |
1961 | ieee80211_process_addba_request(local, rx->sta, mgmt, len); | 1959 | break; |
1962 | goto handled; | ||
1963 | case WLAN_ACTION_ADDBA_RESP: | 1960 | case WLAN_ACTION_ADDBA_RESP: |
1964 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1961 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
1965 | sizeof(mgmt->u.action.u.addba_resp))) | 1962 | sizeof(mgmt->u.action.u.addba_resp))) |
1966 | break; | 1963 | goto invalid; |
1967 | ieee80211_process_addba_resp(local, rx->sta, mgmt, len); | 1964 | break; |
1968 | goto handled; | ||
1969 | case WLAN_ACTION_DELBA: | 1965 | case WLAN_ACTION_DELBA: |
1970 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1966 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
1971 | sizeof(mgmt->u.action.u.delba))) | 1967 | sizeof(mgmt->u.action.u.delba))) |
1972 | break; | 1968 | goto invalid; |
1973 | ieee80211_process_delba(sdata, rx->sta, mgmt, len); | 1969 | break; |
1974 | goto handled; | 1970 | default: |
1971 | goto invalid; | ||
1975 | } | 1972 | } |
1976 | break; | 1973 | |
1974 | goto queue; | ||
1977 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 1975 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
1978 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | 1976 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) |
1979 | break; | 1977 | break; |
@@ -2003,7 +2001,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2003 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) | 2001 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
2004 | break; | 2002 | break; |
2005 | 2003 | ||
2006 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); | 2004 | goto queue; |
2007 | } | 2005 | } |
2008 | break; | 2006 | break; |
2009 | case WLAN_CATEGORY_SA_QUERY: | 2007 | case WLAN_CATEGORY_SA_QUERY: |
@@ -2021,11 +2019,12 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2021 | break; | 2019 | break; |
2022 | case WLAN_CATEGORY_MESH_PLINK: | 2020 | case WLAN_CATEGORY_MESH_PLINK: |
2023 | case WLAN_CATEGORY_MESH_PATH_SEL: | 2021 | case WLAN_CATEGORY_MESH_PATH_SEL: |
2024 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2022 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2025 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); | 2023 | break; |
2026 | break; | 2024 | goto queue; |
2027 | } | 2025 | } |
2028 | 2026 | ||
2027 | invalid: | ||
2029 | /* | 2028 | /* |
2030 | * For AP mode, hostapd is responsible for handling any action | 2029 | * For AP mode, hostapd is responsible for handling any action |
2031 | * frames that we didn't handle, including returning unknown | 2030 | * frames that we didn't handle, including returning unknown |
@@ -2045,8 +2044,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2045 | */ | 2044 | */ |
2046 | status = IEEE80211_SKB_RXCB(rx->skb); | 2045 | status = IEEE80211_SKB_RXCB(rx->skb); |
2047 | 2046 | ||
2048 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 2047 | if (cfg80211_rx_action(rx->sdata->dev, status->freq, |
2049 | cfg80211_rx_action(rx->sdata->dev, status->freq, | ||
2050 | rx->skb->data, rx->skb->len, | 2048 | rx->skb->data, rx->skb->len, |
2051 | GFP_ATOMIC)) | 2049 | GFP_ATOMIC)) |
2052 | goto handled; | 2050 | goto handled; |
@@ -2074,6 +2072,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2074 | rx->sta->rx_packets++; | 2072 | rx->sta->rx_packets++; |
2075 | dev_kfree_skb(rx->skb); | 2073 | dev_kfree_skb(rx->skb); |
2076 | return RX_QUEUED; | 2074 | return RX_QUEUED; |
2075 | |||
2076 | queue: | ||
2077 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
2078 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2079 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
2080 | if (rx->sta) | ||
2081 | rx->sta->rx_packets++; | ||
2082 | return RX_QUEUED; | ||
2077 | } | 2083 | } |
2078 | 2084 | ||
2079 | static ieee80211_rx_result debug_noinline | 2085 | static ieee80211_rx_result debug_noinline |
@@ -2081,10 +2087,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2081 | { | 2087 | { |
2082 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2088 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
2083 | ieee80211_rx_result rxs; | 2089 | ieee80211_rx_result rxs; |
2090 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; | ||
2091 | __le16 stype; | ||
2084 | 2092 | ||
2085 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 2093 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
2086 | return RX_DROP_MONITOR; | 2094 | return RX_DROP_MONITOR; |
2087 | 2095 | ||
2096 | if (rx->skb->len < 24) | ||
2097 | return RX_DROP_MONITOR; | ||
2098 | |||
2088 | if (ieee80211_drop_unencrypted_mgmt(rx)) | 2099 | if (ieee80211_drop_unencrypted_mgmt(rx)) |
2089 | return RX_DROP_UNUSABLE; | 2100 | return RX_DROP_UNUSABLE; |
2090 | 2101 | ||
@@ -2092,16 +2103,42 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2092 | if (rxs != RX_CONTINUE) | 2103 | if (rxs != RX_CONTINUE) |
2093 | return rxs; | 2104 | return rxs; |
2094 | 2105 | ||
2095 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2106 | stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); |
2096 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); | ||
2097 | 2107 | ||
2098 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 2108 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
2099 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb); | 2109 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2110 | sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2111 | return RX_DROP_MONITOR; | ||
2112 | |||
2113 | switch (stype) { | ||
2114 | case cpu_to_le16(IEEE80211_STYPE_BEACON): | ||
2115 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): | ||
2116 | /* process for all: mesh, mlme, ibss */ | ||
2117 | break; | ||
2118 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | ||
2119 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): | ||
2120 | /* process only for station */ | ||
2121 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2122 | return RX_DROP_MONITOR; | ||
2123 | break; | ||
2124 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | ||
2125 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | ||
2126 | /* process only for ibss */ | ||
2127 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2128 | return RX_DROP_MONITOR; | ||
2129 | break; | ||
2130 | default: | ||
2131 | return RX_DROP_MONITOR; | ||
2132 | } | ||
2100 | 2133 | ||
2101 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 2134 | /* queue up frame and kick off work to process it */ |
2102 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); | 2135 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; |
2136 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2137 | ieee80211_queue_work(&rx->local->hw, &sdata->work); | ||
2138 | if (rx->sta) | ||
2139 | rx->sta->rx_packets++; | ||
2103 | 2140 | ||
2104 | return RX_DROP_MONITOR; | 2141 | return RX_QUEUED; |
2105 | } | 2142 | } |
2106 | 2143 | ||
2107 | static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, | 2144 | static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, |