diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-07-07 12:45:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-08 11:42:21 -0400 |
commit | 9e26297a56453315ae6829aec609b5a6309af7b4 (patch) | |
tree | 9152708917200d9b4f0ecc027c13c5da836f22e7 /net/mac80211/rx.c | |
parent | 1d738e64f3d957d56c1b51e64ebdef986a8760e3 (diff) |
mac80211: simplify RX PN/IV handling
The current rx->queue value is slightly confusing.
It is set to 16 on non-QoS frames, including data,
and then used for sequence number and PN/IV checks.
Until recently, we had a TKIP IV checking bug that
had been introduced in 2008 to fix a seqno issue.
Before that, we always used TID 0 for checking the
PN or IV on non-QoS packets.
Go back to the old status for PN/IV checks using
the TID 0 counter for non-QoS by splitting up the
rx->queue value into "seqno_idx" and "security_idx"
in order to avoid confusion in the future. They
each have special rules on the value used for non-
QoS data frames.
Since the handling is now unified, also revert the
special TKIP handling from my patch
"mac80211: fix TKIP replay vulnerability".
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5493ecd1e93..e6dccc70931d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -331,7 +331,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
331 | { | 331 | { |
332 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 332 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
333 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 333 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
334 | int tid; | 334 | int tid, seqno_idx, security_idx; |
335 | 335 | ||
336 | /* does the frame have a qos control field? */ | 336 | /* does the frame have a qos control field? */ |
337 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 337 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
@@ -340,6 +340,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
340 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 340 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
341 | if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) | 341 | if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) |
342 | status->rx_flags |= IEEE80211_RX_AMSDU; | 342 | status->rx_flags |= IEEE80211_RX_AMSDU; |
343 | |||
344 | seqno_idx = tid; | ||
345 | security_idx = tid; | ||
343 | } else { | 346 | } else { |
344 | /* | 347 | /* |
345 | * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): | 348 | * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): |
@@ -352,10 +355,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
352 | * | 355 | * |
353 | * We also use that counter for non-QoS STAs. | 356 | * We also use that counter for non-QoS STAs. |
354 | */ | 357 | */ |
355 | tid = NUM_RX_DATA_QUEUES - 1; | 358 | seqno_idx = NUM_RX_DATA_QUEUES; |
359 | security_idx = 0; | ||
360 | if (ieee80211_is_mgmt(hdr->frame_control)) | ||
361 | security_idx = NUM_RX_DATA_QUEUES; | ||
362 | tid = 0; | ||
356 | } | 363 | } |
357 | 364 | ||
358 | rx->queue = tid; | 365 | rx->seqno_idx = seqno_idx; |
366 | rx->security_idx = security_idx; | ||
359 | /* Set skb->priority to 1d tag if highest order bit of TID is not set. | 367 | /* Set skb->priority to 1d tag if highest order bit of TID is not set. |
360 | * For now, set skb->priority to 0 for other cases. */ | 368 | * For now, set skb->priority to 0 for other cases. */ |
361 | rx->skb->priority = (tid > 7) ? 0 : tid; | 369 | rx->skb->priority = (tid > 7) ? 0 : tid; |
@@ -810,7 +818,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
810 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ | 818 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ |
811 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { | 819 | if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { |
812 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | 820 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && |
813 | rx->sta->last_seq_ctrl[rx->queue] == | 821 | rx->sta->last_seq_ctrl[rx->seqno_idx] == |
814 | hdr->seq_ctrl)) { | 822 | hdr->seq_ctrl)) { |
815 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) { | 823 | if (status->rx_flags & IEEE80211_RX_RA_MATCH) { |
816 | rx->local->dot11FrameDuplicateCount++; | 824 | rx->local->dot11FrameDuplicateCount++; |
@@ -818,7 +826,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
818 | } | 826 | } |
819 | return RX_DROP_UNUSABLE; | 827 | return RX_DROP_UNUSABLE; |
820 | } else | 828 | } else |
821 | rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; | 829 | rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; |
822 | } | 830 | } |
823 | 831 | ||
824 | if (unlikely(rx->skb->len < 16)) { | 832 | if (unlikely(rx->skb->len < 16)) { |
@@ -1374,11 +1382,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1374 | if (frag == 0) { | 1382 | if (frag == 0) { |
1375 | /* This is the first fragment of a new frame. */ | 1383 | /* This is the first fragment of a new frame. */ |
1376 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, | 1384 | entry = ieee80211_reassemble_add(rx->sdata, frag, seq, |
1377 | rx->queue, &(rx->skb)); | 1385 | rx->seqno_idx, &(rx->skb)); |
1378 | if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP && | 1386 | if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP && |
1379 | ieee80211_has_protected(fc)) { | 1387 | ieee80211_has_protected(fc)) { |
1380 | int queue = ieee80211_is_mgmt(fc) ? | 1388 | int queue = rx->security_idx; |
1381 | NUM_RX_DATA_QUEUES : rx->queue; | ||
1382 | /* Store CCMP PN so that we can verify that the next | 1389 | /* Store CCMP PN so that we can verify that the next |
1383 | * fragment has a sequential PN value. */ | 1390 | * fragment has a sequential PN value. */ |
1384 | entry->ccmp = 1; | 1391 | entry->ccmp = 1; |
@@ -1392,7 +1399,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1392 | /* This is a fragment for a frame that should already be pending in | 1399 | /* This is a fragment for a frame that should already be pending in |
1393 | * fragment cache. Add this fragment to the end of the pending entry. | 1400 | * fragment cache. Add this fragment to the end of the pending entry. |
1394 | */ | 1401 | */ |
1395 | entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr); | 1402 | entry = ieee80211_reassemble_find(rx->sdata, frag, seq, |
1403 | rx->seqno_idx, hdr); | ||
1396 | if (!entry) { | 1404 | if (!entry) { |
1397 | I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); | 1405 | I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); |
1398 | return RX_DROP_MONITOR; | 1406 | return RX_DROP_MONITOR; |
@@ -1412,8 +1420,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1412 | if (pn[i]) | 1420 | if (pn[i]) |
1413 | break; | 1421 | break; |
1414 | } | 1422 | } |
1415 | queue = ieee80211_is_mgmt(fc) ? | 1423 | queue = rx->security_idx; |
1416 | NUM_RX_DATA_QUEUES : rx->queue; | ||
1417 | rpn = rx->key->u.ccmp.rx_pn[queue]; | 1424 | rpn = rx->key->u.ccmp.rx_pn[queue]; |
1418 | if (memcmp(pn, rpn, CCMP_PN_LEN)) | 1425 | if (memcmp(pn, rpn, CCMP_PN_LEN)) |
1419 | return RX_DROP_UNUSABLE; | 1426 | return RX_DROP_UNUSABLE; |
@@ -2590,7 +2597,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | |||
2590 | .sta = sta, | 2597 | .sta = sta, |
2591 | .sdata = sta->sdata, | 2598 | .sdata = sta->sdata, |
2592 | .local = sta->local, | 2599 | .local = sta->local, |
2593 | .queue = tid, | 2600 | /* This is OK -- must be QoS data frame */ |
2601 | .security_idx = tid, | ||
2602 | .seqno_idx = tid, | ||
2594 | .flags = 0, | 2603 | .flags = 0, |
2595 | }; | 2604 | }; |
2596 | struct tid_ampdu_rx *tid_agg_rx; | 2605 | struct tid_ampdu_rx *tid_agg_rx; |