aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-08-28 17:01:53 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:48:44 -0400
commit3017b80bf0c4d6a44ccf0d35db9dadf01092b54e (patch)
treec08a6688469f857276d59bf69ef19d1d37440245 /net/mac80211
parent82f716056fb1c214289fe6c284b0316858c1b70c (diff)
[MAC80211]: fix software decryption
When doing key selection for software decryption, mac80211 gets a few things wrong: it always uses pairwise keys if configured, even if the frame is addressed to a multicast address. Also, it doesn't allow using a key index of zero if a pairwise key has also been found. This patch changes the key selection code to be (more) in line with the 802.11 specification. I have confirmed that with this, multicast frames are correctly decrypted and I've tested with WEP as well. While at it, I've cleaned up the semantics of the hardware flags IEEE80211_HW_WEP_INCLUDE_IV and IEEE80211_HW_DEVICE_HIDES_WEP and clarified them in the mac80211.h header; it is also now allowed to set the IEEE80211_HW_DEVICE_HIDES_WEP option even if it only applies to frames that have been decrypted by the hw, unencrypted frames must be dropped but encrypted frames that the hardware couldn't handle can be passed up unmodified. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/rx.c113
-rw-r--r--net/mac80211/wpa.c7
2 files changed, 74 insertions, 46 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b0959c249869..08ca066246b9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -310,52 +310,77 @@ static ieee80211_txrx_result
310ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) 310ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
311{ 311{
312 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; 312 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
313 int always_sta_key; 313 int keyidx;
314 int hdrlen;
314 315
315 if (rx->sdata->type == IEEE80211_IF_TYPE_STA) 316 /*
316 always_sta_key = 0; 317 * Key selection 101
317 else 318 *
318 always_sta_key = 1; 319 * There are three types of keys:
320 * - GTK (group keys)
321 * - PTK (pairwise keys)
322 * - STK (station-to-station pairwise keys)
323 *
324 * When selecting a key, we have to distinguish between multicast
325 * (including broadcast) and unicast frames, the latter can only
326 * use PTKs and STKs while the former always use GTKs. Unless, of
327 * course, actual WEP keys ("pre-RSNA") are used, then unicast
328 * frames can also use key indizes like GTKs. Hence, if we don't
329 * have a PTK/STK we check the key index for a WEP key.
330 *
331 * There is also a slight problem in IBSS mode: GTKs are negotiated
332 * with each station, that is something we don't currently handle.
333 */
334
335 if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
336 return TXRX_CONTINUE;
319 337
320 if (rx->sta && rx->sta->key && always_sta_key) { 338 /*
339 * No point in finding a key if the frame is neither
340 * addressed to us nor a multicast frame.
341 */
342 if (!rx->u.rx.ra_match)
343 return TXRX_CONTINUE;
344
345 if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) {
321 rx->key = rx->sta->key; 346 rx->key = rx->sta->key;
322 } else { 347 } else {
323 if (rx->sta && rx->sta->key) 348 /*
324 rx->key = rx->sta->key; 349 * The device doesn't give us the IV so we won't be
325 else 350 * able to look up the key. That's ok though, we
326 rx->key = rx->sdata->default_key; 351 * don't need to decrypt the frame, we just won't
352 * be able to keep statistics accurate.
353 * Except for key threshold notifications, should
354 * we somehow allow the driver to tell us which key
355 * the hardware used if this flag is set?
356 */
357 if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
358 return TXRX_CONTINUE;
327 359
328 if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && 360 hdrlen = ieee80211_get_hdrlen(rx->fc);
329 rx->fc & IEEE80211_FCTL_PROTECTED) {
330 int keyidx = ieee80211_wep_get_keyidx(rx->skb);
331 361
332 if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS && 362 if (rx->skb->len < 8 + hdrlen)
333 (!rx->sta || !rx->sta->key || keyidx > 0)) 363 return TXRX_DROP; /* TODO: count this? */
334 rx->key = rx->sdata->keys[keyidx];
335 364
336 if (!rx->key) { 365 /*
337 if (!rx->u.rx.ra_match) 366 * no need to call ieee80211_wep_get_keyidx,
338 return TXRX_DROP; 367 * it verifies a bunch of things we've done already
339 if (net_ratelimit()) 368 */
340 printk(KERN_DEBUG "%s: RX WEP frame " 369 keyidx = rx->skb->data[hdrlen + 3] >> 6;
341 "with unknown keyidx %d " 370
342 "(A1=" MAC_FMT 371 rx->key = rx->sdata->keys[keyidx];
343 " A2=" MAC_FMT 372
344 " A3=" MAC_FMT ")\n", 373 /*
345 rx->dev->name, keyidx, 374 * RSNA-protected unicast frames should always be sent with
346 MAC_ARG(hdr->addr1), 375 * pairwise or station-to-station keys, but for WEP we allow
347 MAC_ARG(hdr->addr2), 376 * using a key index as well.
348 MAC_ARG(hdr->addr3)); 377 */
349 /* 378 if (rx->key && rx->key->alg != ALG_WEP &&
350 * TODO: notify userspace about this 379 !is_multicast_ether_addr(hdr->addr1))
351 * via cfg/nl80211 380 rx->key = NULL;
352 */
353 return TXRX_DROP;
354 }
355 }
356 } 381 }
357 382
358 if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) { 383 if (rx->key) {
359 rx->key->tx_rx_count++; 384 rx->key->tx_rx_count++;
360 if (unlikely(rx->local->key_tx_rx_threshold && 385 if (unlikely(rx->local->key_tx_rx_threshold &&
361 rx->key->tx_rx_count > 386 rx->key->tx_rx_count >
@@ -516,10 +541,6 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
516static ieee80211_txrx_result 541static ieee80211_txrx_result
517ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) 542ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
518{ 543{
519 /* If the device handles decryption totally, skip this test */
520 if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
521 return TXRX_CONTINUE;
522
523 if ((rx->key && rx->key->alg != ALG_WEP) || 544 if ((rx->key && rx->key->alg != ALG_WEP) ||
524 !(rx->fc & IEEE80211_FCTL_PROTECTED) || 545 !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
525 ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && 546 ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
@@ -871,8 +892,14 @@ ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
871static ieee80211_txrx_result 892static ieee80211_txrx_result
872ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) 893ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
873{ 894{
874 /* If the device handles decryption totally, skip this test */ 895 /*
875 if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) 896 * Pass through unencrypted frames if the hardware might have
897 * decrypted them already without telling us, but that can only
898 * be true if we either didn't find a key or the found key is
899 * uploaded to the hardware.
900 */
901 if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) &&
902 (!rx->key || !rx->key->force_sw_encrypt))
876 return TXRX_CONTINUE; 903 return TXRX_CONTINUE;
877 904
878 /* Drop unencrypted frames if key is set. */ 905 /* Drop unencrypted frames if key is set. */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 783af32c6911..f5723ea15aae 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -137,9 +137,10 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
137 137
138 fc = rx->fc; 138 fc = rx->fc;
139 139
140 /* If device handles decryption totally, skip this check */ 140 /*
141 if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) || 141 * No way to verify the MIC if the hardware stripped it
142 (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC)) 142 */
143 if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC)
143 return TXRX_CONTINUE; 144 return TXRX_CONTINUE;
144 145
145 if (!rx->key || rx->key->alg != ALG_TKIP || 146 if (!rx->key || rx->key->alg != ALG_TKIP ||