diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-03-12 08:49:14 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-03-13 14:54:17 -0400 |
commit | a8286911881948c7a2ecc63ee4224c258cce2da3 (patch) | |
tree | a35566503b81c654db55857f42fe9664d0aab3af /net | |
parent | 617bbde878604adfcd557fc2a8952f77ab4ebd95 (diff) |
mac80211: linearize SKBs as needed for crypto
Not linearizing every SKB will help actually pass
non-linear SKBs all the way up when on an encrypted
connection. For now, linearize TKIP completely as
it is lower performance and I don't quite grok all
the details.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/wep.c | 11 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 22 |
3 files changed, 31 insertions, 8 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b38da13e2a88..53c88d145472 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1063,10 +1063,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1063 | return RX_DROP_MONITOR; | 1063 | return RX_DROP_MONITOR; |
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | if (skb_linearize(rx->skb)) | ||
1067 | return RX_DROP_UNUSABLE; | ||
1068 | /* the hdr variable is invalid now! */ | ||
1069 | |||
1070 | switch (rx->key->conf.cipher) { | 1066 | switch (rx->key->conf.cipher) { |
1071 | case WLAN_CIPHER_SUITE_WEP40: | 1067 | case WLAN_CIPHER_SUITE_WEP40: |
1072 | case WLAN_CIPHER_SUITE_WEP104: | 1068 | case WLAN_CIPHER_SUITE_WEP104: |
@@ -1089,6 +1085,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1089 | return RX_DROP_UNUSABLE; | 1085 | return RX_DROP_UNUSABLE; |
1090 | } | 1086 | } |
1091 | 1087 | ||
1088 | /* the hdr variable is invalid after the decrypt handlers */ | ||
1089 | |||
1092 | /* either the frame has been decrypted or will be dropped */ | 1090 | /* either the frame has been decrypted or will be dropped */ |
1093 | status->flag |= RX_FLAG_DECRYPTED; | 1091 | status->flag |= RX_FLAG_DECRYPTED; |
1094 | 1092 | ||
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 5cd87ba11bb7..7aa31bbfaa3b 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -284,22 +284,27 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | |||
284 | struct sk_buff *skb = rx->skb; | 284 | struct sk_buff *skb = rx->skb; |
285 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 285 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
286 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 286 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
287 | __le16 fc = hdr->frame_control; | ||
287 | 288 | ||
288 | if (!ieee80211_is_data(hdr->frame_control) && | 289 | if (!ieee80211_is_data(fc) && !ieee80211_is_auth(fc)) |
289 | !ieee80211_is_auth(hdr->frame_control)) | ||
290 | return RX_CONTINUE; | 290 | return RX_CONTINUE; |
291 | 291 | ||
292 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | 292 | if (!(status->flag & RX_FLAG_DECRYPTED)) { |
293 | if (skb_linearize(rx->skb)) | ||
294 | return RX_DROP_UNUSABLE; | ||
293 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | 295 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) |
294 | rx->sta->wep_weak_iv_count++; | 296 | rx->sta->wep_weak_iv_count++; |
295 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) | 297 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) |
296 | return RX_DROP_UNUSABLE; | 298 | return RX_DROP_UNUSABLE; |
297 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { | 299 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { |
300 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + WEP_IV_LEN)) | ||
301 | return RX_DROP_UNUSABLE; | ||
298 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | 302 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) |
299 | rx->sta->wep_weak_iv_count++; | 303 | rx->sta->wep_weak_iv_count++; |
300 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); | 304 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); |
301 | /* remove ICV */ | 305 | /* remove ICV */ |
302 | skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN); | 306 | if (pskb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN)) |
307 | return RX_DROP_UNUSABLE; | ||
303 | } | 308 | } |
304 | 309 | ||
305 | return RX_CONTINUE; | 310 | return RX_CONTINUE; |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b758350919ff..0ae23c60968c 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -138,6 +138,10 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
138 | if (skb->len < hdrlen + MICHAEL_MIC_LEN) | 138 | if (skb->len < hdrlen + MICHAEL_MIC_LEN) |
139 | return RX_DROP_UNUSABLE; | 139 | return RX_DROP_UNUSABLE; |
140 | 140 | ||
141 | if (skb_linearize(rx->skb)) | ||
142 | return RX_DROP_UNUSABLE; | ||
143 | hdr = (void *)skb->data; | ||
144 | |||
141 | data = skb->data + hdrlen; | 145 | data = skb->data + hdrlen; |
142 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; | 146 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; |
143 | key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; | 147 | key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; |
@@ -253,6 +257,11 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
253 | if (!rx->sta || skb->len - hdrlen < 12) | 257 | if (!rx->sta || skb->len - hdrlen < 12) |
254 | return RX_DROP_UNUSABLE; | 258 | return RX_DROP_UNUSABLE; |
255 | 259 | ||
260 | /* it may be possible to optimize this a bit more */ | ||
261 | if (skb_linearize(rx->skb)) | ||
262 | return RX_DROP_UNUSABLE; | ||
263 | hdr = (void *)skb->data; | ||
264 | |||
256 | /* | 265 | /* |
257 | * Let TKIP code verify IV, but skip decryption. | 266 | * Let TKIP code verify IV, but skip decryption. |
258 | * In the case where hardware checks the IV as well, | 267 | * In the case where hardware checks the IV as well, |
@@ -484,6 +493,14 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
484 | if (!rx->sta || data_len < 0) | 493 | if (!rx->sta || data_len < 0) |
485 | return RX_DROP_UNUSABLE; | 494 | return RX_DROP_UNUSABLE; |
486 | 495 | ||
496 | if (status->flag & RX_FLAG_DECRYPTED) { | ||
497 | if (!pskb_may_pull(rx->skb, hdrlen + CCMP_HDR_LEN)) | ||
498 | return RX_DROP_UNUSABLE; | ||
499 | } else { | ||
500 | if (skb_linearize(rx->skb)) | ||
501 | return RX_DROP_UNUSABLE; | ||
502 | } | ||
503 | |||
487 | ccmp_hdr2pn(pn, skb->data + hdrlen); | 504 | ccmp_hdr2pn(pn, skb->data + hdrlen); |
488 | 505 | ||
489 | queue = rx->security_idx; | 506 | queue = rx->security_idx; |
@@ -509,7 +526,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
509 | memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN); | 526 | memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN); |
510 | 527 | ||
511 | /* Remove CCMP header and MIC */ | 528 | /* Remove CCMP header and MIC */ |
512 | skb_trim(skb, skb->len - CCMP_MIC_LEN); | 529 | if (pskb_trim(skb, skb->len - CCMP_MIC_LEN)) |
530 | return RX_DROP_UNUSABLE; | ||
513 | memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); | 531 | memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); |
514 | skb_pull(skb, CCMP_HDR_LEN); | 532 | skb_pull(skb, CCMP_HDR_LEN); |
515 | 533 | ||
@@ -609,6 +627,8 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | |||
609 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 627 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
610 | return RX_CONTINUE; | 628 | return RX_CONTINUE; |
611 | 629 | ||
630 | /* management frames are already linear */ | ||
631 | |||
612 | if (skb->len < 24 + sizeof(*mmie)) | 632 | if (skb->len < 24 + sizeof(*mmie)) |
613 | return RX_DROP_UNUSABLE; | 633 | return RX_DROP_UNUSABLE; |
614 | 634 | ||