aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2006-09-26 22:50:31 -0400
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:11:56 -0500
commitc9308b06c049a107edfbd4e5271771564eb6024d (patch)
treea065438a0f279a96988c3730a4d644ce2b94061d
parentf2423723d70298e04179f934ff17346c3e06f408 (diff)
[PATCH] ieee80211: Move IV/ICV stripping into ieee80211_rx
This patch adds a host_strip_iv_icv flag to ieee80211 which indicates that ieee80211_rx should strip the IV/ICV/other security features from the payload. This saves on some memmove() calls in the driver and seems like something that belongs in the stack as it can be used by bcm43xx, ipw2200, and zd1211rw I will submit the ipw2200 patch separately as it needs testing. This patch also adds some sensible variable reuse (idx vs keyidx) in ieee80211_rx Signed-off-by: Daniel Drake <dsd@gentoo.org> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c19
-rw-r--r--include/net/ieee80211.h4
-rw-r--r--net/ieee80211/ieee80211_rx.c56
4 files changed, 55 insertions, 25 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 12043f8be1bf..a659442b9c15 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -690,6 +690,7 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
690 bcm->ieee->host_encrypt = !!on; 690 bcm->ieee->host_encrypt = !!on;
691 bcm->ieee->host_decrypt = !!on; 691 bcm->ieee->host_decrypt = !!on;
692 bcm->ieee->host_build_iv = !on; 692 bcm->ieee->host_build_iv = !on;
693 bcm->ieee->host_strip_iv_icv = !on;
693 spin_unlock_irqrestore(&bcm->irq_lock, flags); 694 spin_unlock_irqrestore(&bcm->irq_lock, flags);
694 mutex_unlock(&bcm->mutex); 695 mutex_unlock(&bcm->mutex);
695 696
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index 0159e4e93201..a957bc861382 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -543,25 +543,6 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
543 break; 543 break;
544 } 544 }
545 545
546 frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
547 if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
548 frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
549 wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
550 /* trim IV and ICV */
551 /* FIXME: this must be done only for WEP encrypted packets */
552 if (skb->len < 32) {
553 dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
554 "set and length < 32)\n");
555 return -EINVAL;
556 } else {
557 memmove(skb->data + 4, skb->data, 24);
558 skb_pull(skb, 4);
559 skb_trim(skb, skb->len - 4);
560 stats.len -= 8;
561 }
562 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
563 }
564
565 switch (WLAN_FC_GET_TYPE(frame_ctl)) { 546 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
566 case IEEE80211_FTYPE_MGMT: 547 case IEEE80211_FTYPE_MGMT:
567 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); 548 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index b174ebb277a9..cb255432e4e4 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1037,6 +1037,10 @@ struct ieee80211_device {
1037 /* host performs multicast decryption */ 1037 /* host performs multicast decryption */
1038 int host_mc_decrypt; 1038 int host_mc_decrypt;
1039 1039
1040 /* host should strip IV and ICV from protected frames */
1041 /* meaningful only when hardware decryption is being used */
1042 int host_strip_iv_icv;
1043
1040 int host_open_frag; 1044 int host_open_frag;
1041 int host_build_iv; 1045 int host_build_iv;
1042 int ieee802_1x; /* is IEEE 802.1X used */ 1046 int ieee802_1x; /* is IEEE 802.1X used */
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 2759312a4204..d9265195656d 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -415,17 +415,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
415 ieee->host_mc_decrypt : ieee->host_decrypt; 415 ieee->host_mc_decrypt : ieee->host_decrypt;
416 416
417 if (can_be_decrypted) { 417 if (can_be_decrypted) {
418 int idx = 0;
419 if (skb->len >= hdrlen + 3) { 418 if (skb->len >= hdrlen + 3) {
420 /* Top two-bits of byte 3 are the key index */ 419 /* Top two-bits of byte 3 are the key index */
421 idx = skb->data[hdrlen + 3] >> 6; 420 keyidx = skb->data[hdrlen + 3] >> 6;
422 } 421 }
423 422
424 /* ieee->crypt[] is WEP_KEY (4) in length. Given that idx 423 /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
425 * is only allowed 2-bits of storage, no value of idx can 424 * is only allowed 2-bits of storage, no value of keyidx can
426 * be provided via above code that would result in idx 425 * be provided via above code that would result in keyidx
427 * being out of range */ 426 * being out of range */
428 crypt = ieee->crypt[idx]; 427 crypt = ieee->crypt[keyidx];
429 428
430#ifdef NOT_YET 429#ifdef NOT_YET
431 sta = NULL; 430 sta = NULL;
@@ -655,6 +654,51 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
655 goto rx_dropped; 654 goto rx_dropped;
656 } 655 }
657 656
657 /* If the frame was decrypted in hardware, we may need to strip off
658 * any security data (IV, ICV, etc) that was left behind */
659 if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
660 ieee->host_strip_iv_icv) {
661 int trimlen = 0;
662
663 /* Top two-bits of byte 3 are the key index */
664 if (skb->len >= hdrlen + 3)
665 keyidx = skb->data[hdrlen + 3] >> 6;
666
667 /* To strip off any security data which appears before the
668 * payload, we simply increase hdrlen (as the header gets
669 * chopped off immediately below). For the security data which
670 * appears after the payload, we use skb_trim. */
671
672 switch (ieee->sec.encode_alg[keyidx]) {
673 case SEC_ALG_WEP:
674 /* 4 byte IV */
675 hdrlen += 4;
676 /* 4 byte ICV */
677 trimlen = 4;
678 break;
679 case SEC_ALG_TKIP:
680 /* 4 byte IV, 4 byte ExtIV */
681 hdrlen += 8;
682 /* 8 byte MIC, 4 byte ICV */
683 trimlen = 12;
684 break;
685 case SEC_ALG_CCMP:
686 /* 8 byte CCMP header */
687 hdrlen += 8;
688 /* 8 byte MIC */
689 trimlen = 8;
690 break;
691 }
692
693 if (skb->len < trimlen)
694 goto rx_dropped;
695
696 __skb_trim(skb, skb->len - trimlen);
697
698 if (skb->len < hdrlen)
699 goto rx_dropped;
700 }
701
658 /* skb: hdr + (possible reassembled) full plaintext payload */ 702 /* skb: hdr + (possible reassembled) full plaintext payload */
659 703
660 payload = skb->data + hdrlen; 704 payload = skb->data + hdrlen;