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 | |
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>
-rw-r--r-- | net/mac80211/ieee80211_i.h | 17 | ||||
-rw-r--r-- | net/mac80211/key.h | 2 | ||||
-rw-r--r-- | net/mac80211/rx.c | 33 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 3 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 9 |
5 files changed, 44 insertions, 20 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4f2e424e8b1b..4c7a831e7d1e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -202,7 +202,22 @@ struct ieee80211_rx_data { | |||
202 | struct ieee80211_key *key; | 202 | struct ieee80211_key *key; |
203 | 203 | ||
204 | unsigned int flags; | 204 | unsigned int flags; |
205 | int queue; | 205 | |
206 | /* | ||
207 | * Index into sequence numbers array, 0..16 | ||
208 | * since the last (16) is used for non-QoS, | ||
209 | * will be 16 on non-QoS frames. | ||
210 | */ | ||
211 | int seqno_idx; | ||
212 | |||
213 | /* | ||
214 | * Index into the security IV/PN arrays, 0..16 | ||
215 | * since the last (16) is used for CCMP-encrypted | ||
216 | * management frames, will be set to 16 on mgmt | ||
217 | * frames and 0 on non-QoS frames. | ||
218 | */ | ||
219 | int security_idx; | ||
220 | |||
206 | u32 tkip_iv32; | 221 | u32 tkip_iv32; |
207 | u16 tkip_iv16; | 222 | u16 tkip_iv16; |
208 | }; | 223 | }; |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 05abab05b0aa..beb9c20ff48c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define TKIP_IV_LEN 8 | 29 | #define TKIP_IV_LEN 8 |
30 | #define TKIP_ICV_LEN 4 | 30 | #define TKIP_ICV_LEN 4 |
31 | 31 | ||
32 | #define NUM_RX_DATA_QUEUES 17 | 32 | #define NUM_RX_DATA_QUEUES 16 |
33 | 33 | ||
34 | struct ieee80211_local; | 34 | struct ieee80211_local; |
35 | struct ieee80211_sub_if_data; | 35 | struct ieee80211_sub_if_data; |
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; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a06d64ebc177..28beb78e601e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -287,7 +287,8 @@ struct sta_info { | |||
287 | unsigned long rx_dropped; | 287 | unsigned long rx_dropped; |
288 | int last_signal; | 288 | int last_signal; |
289 | struct ewma avg_signal; | 289 | struct ewma avg_signal; |
290 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; | 290 | /* Plus 1 for non-QoS frames */ |
291 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; | ||
291 | 292 | ||
292 | /* Updated from TX status path only, no locking requirements */ | 293 | /* Updated from TX status path only, no locking requirements */ |
293 | unsigned long tx_filtered_count; | 294 | unsigned long tx_filtered_count; |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 01684234b704..7bc8702808fa 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -149,8 +149,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
149 | 149 | ||
150 | update_iv: | 150 | update_iv: |
151 | /* update IV in key information to be able to detect replays */ | 151 | /* update IV in key information to be able to detect replays */ |
152 | rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; | 152 | rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; |
153 | rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; | 153 | rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; |
154 | 154 | ||
155 | return RX_CONTINUE; | 155 | return RX_CONTINUE; |
156 | 156 | ||
@@ -263,7 +263,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
263 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, | 263 | res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, |
264 | key, skb->data + hdrlen, | 264 | key, skb->data + hdrlen, |
265 | skb->len - hdrlen, rx->sta->sta.addr, | 265 | skb->len - hdrlen, rx->sta->sta.addr, |
266 | hdr->addr1, hwaccel, rx->queue, | 266 | hdr->addr1, hwaccel, rx->security_idx, |
267 | &rx->tkip_iv32, | 267 | &rx->tkip_iv32, |
268 | &rx->tkip_iv16); | 268 | &rx->tkip_iv16); |
269 | if (res != TKIP_DECRYPT_OK) | 269 | if (res != TKIP_DECRYPT_OK) |
@@ -478,8 +478,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
478 | 478 | ||
479 | ccmp_hdr2pn(pn, skb->data + hdrlen); | 479 | ccmp_hdr2pn(pn, skb->data + hdrlen); |
480 | 480 | ||
481 | queue = ieee80211_is_mgmt(hdr->frame_control) ? | 481 | queue = rx->security_idx; |
482 | NUM_RX_DATA_QUEUES : rx->queue; | ||
483 | 482 | ||
484 | if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) { | 483 | if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) { |
485 | key->u.ccmp.replays++; | 484 | key->u.ccmp.replays++; |