[PATCH] ieee80211: Hardware crypto and fragmentation offload support
authorJames Ketrenos <jketreno@linux.intel.com>
Wed, 21 Sep 2005 16:53:54 +0000 (11:53 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 22 Sep 2005 03:01:52 +0000 (23:01 -0400)
tree 5322d496af90d03ffbec27292dc1a6268a746ede
parent 6c9364386ccb786e4a84427ab3ad712f0b7b8904
author James Ketrenos <jketreno@linux.intel.com> 1124432367 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127311810 -0500

Hardware crypto and fragmentation offload support added (Zhu Yi)

Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
include/net/ieee80211.h
net/ieee80211/ieee80211_tx.c
net/ieee80211/ieee80211_wx.c

index ed06a94..fa14360 100644 (file)
@@ -430,31 +430,34 @@ struct ieee80211_device;
 
 #include "ieee80211_crypt.h"
 
-#define SEC_KEY_1         (1<<0)
-#define SEC_KEY_2         (1<<1)
-#define SEC_KEY_3         (1<<2)
-#define SEC_KEY_4         (1<<3)
-#define SEC_KEY_MASK      (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4)
-#define SEC_ACTIVE_KEY    (1<<4)
-#define SEC_AUTH_MODE     (1<<5)
-#define SEC_UNICAST_GROUP (1<<6)
-#define SEC_LEVEL         (1<<7)
-#define SEC_ENABLED       (1<<8)
-
-#define SEC_LEVEL_0      0     /* None */
-#define SEC_LEVEL_1      1     /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2      2     /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3     /* Level 1 + CKIP */
-#define SEC_LEVEL_3      4     /* Level 2 + CCMP */
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
+#define SEC_KEY_1              (1<<0)
+#define SEC_KEY_2              (1<<1)
+#define SEC_KEY_3              (1<<2)
+#define SEC_KEY_4              (1<<3)
+#define SEC_ACTIVE_KEY         (1<<4)
+#define SEC_AUTH_MODE          (1<<5)
+#define SEC_UNICAST_GROUP      (1<<6)
+#define SEC_LEVEL              (1<<7)
+#define SEC_ENABLED            (1<<8)
+#define SEC_TGI_KEY_RESET      (1<<9)
+
+#define SEC_LEVEL_0            0       /* None */
+#define SEC_LEVEL_1            1       /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2            2       /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP       3       /* Level 1 + CKIP */
+#define SEC_LEVEL_3            4       /* Level 2 + CCMP */
+
+#define WEP_KEYS               4
+#define WEP_KEY_LEN            13
+#define SCM_KEY_LEN            32
+#define SCM_TEMPORAL_KEY_LENGTH        16
 
 struct ieee80211_security {
        u16 active_key:2,
-           enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1;
+           enabled:1,
+           auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
        u8 key_sizes[WEP_KEYS];
-       u8 keys[WEP_KEYS][WEP_KEY_LEN];
+       u8 keys[WEP_KEYS][SCM_KEY_LEN];
        u8 level;
        u16 flags;
 } __attribute__ ((packed));
@@ -636,6 +639,7 @@ enum ieee80211_state {
 
 struct ieee80211_device {
        struct net_device *dev;
+       struct ieee80211_security sec;
 
        /* Bookkeeping structures */
        struct net_device_stats stats;
index 435ef5a..785e76f 100644 (file)
@@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
        unsigned long flags;
        struct net_device_stats *stats = &ieee->stats;
-       int ether_type, encrypt;
+       int ether_type, encrypt, host_encrypt;
        int bytes, fc, hdr_len;
        struct sk_buff *skb_frag;
        struct ieee80211_hdr header = { /* Ensure zero initialized */
@@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        crypt = ieee->crypt[ieee->tx_keyidx];
 
        encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
-           ieee->host_encrypt && crypt && crypt->ops;
+           ieee->sec.encrypt;
+       host_encrypt = ieee->host_encrypt && encrypt;
 
        if (!encrypt && ieee->ieee802_1x &&
            ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Determine total amount of storage required for TXB packets */
        bytes = skb->len + SNAP_SIZE + sizeof(u16);
 
-       if (encrypt)
+       if (host_encrypt)
                fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
                    IEEE80211_FCTL_PROTECTED;
        else
@@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                bytes_per_frag -= IEEE80211_FCS_LEN;
 
        /* Each fragment may need to have room for encryptiong pre/postfix */
-       if (encrypt)
+       if (host_encrypt)
                bytes_per_frag -= crypt->ops->extra_prefix_len +
                    crypt->ops->extra_postfix_len;
 
@@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        for (i = 0; i < nr_frags; i++) {
                skb_frag = txb->fragments[i];
 
-               if (encrypt)
+               if (host_encrypt)
                        skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
 
                frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
@@ -380,8 +381,22 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* Encryption routine will move the header forward in order
                 * to insert the IV between the header and the payload */
-               if (encrypt)
+               if (host_encrypt)
                        ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+
+               /* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */
+               if (!ieee->host_encrypt && encrypt &&
+                   (ieee->sec.level == SEC_LEVEL_2) &&
+                   crypt && crypt->ops && crypt->ops->encrypt_msdu) {
+                       int res = 0;
+                       res = crypt->ops->encrypt_msdu(skb_frag, hdr_len,
+                                                      crypt->priv);
+                       if (res < 0) {
+                               IEEE80211_ERROR("TKIP MIC encryption failed\n");
+                               goto failed;
+                       }
+               }
+
                if (ieee->config &
                    (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
                        skb_put(skb_frag, 4);
index fc4e137..f88c811 100644 (file)
@@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
        };
        int i, key, key_provided, len;
        struct ieee80211_crypt_data **crypt;
+       int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
 
        IEEE80211_DEBUG_WX("SET_ENCODE\n");
 
@@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
 
                if (i == WEP_KEYS) {
                        sec.enabled = 0;
+                       sec.encrypt = 0;
                        sec.level = SEC_LEVEL_0;
                        sec.flags |= SEC_ENABLED | SEC_LEVEL;
                }
@@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
        }
 
        sec.enabled = 1;
+       sec.encrypt = 1;
        sec.flags |= SEC_ENABLED;
 
        if (*crypt != NULL && (*crypt)->ops != NULL &&
@@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
                ieee80211_crypt_delayed_deinit(ieee, crypt);
        }
 
-       if (*crypt == NULL) {
+       if (*crypt == NULL && host_crypto) {
                struct ieee80211_crypt_data *new_crypt;
 
                /* take WEP into use */
@@ -375,31 +378,34 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
                                   key, escape_essid(sec.keys[key], len),
                                   erq->length, len);
                sec.key_sizes[key] = len;
-               (*crypt)->ops->set_key(sec.keys[key], len, NULL,
-                                      (*crypt)->priv);
+               if (*crypt)
+                       (*crypt)->ops->set_key(sec.keys[key], len, NULL,
+                                              (*crypt)->priv);
                sec.flags |= (1 << key);
                /* This ensures a key will be activated if no key is
                 * explicitely set */
                if (key == sec.active_key)
                        sec.flags |= SEC_ACTIVE_KEY;
+
        } else {
-               len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
-                                            NULL, (*crypt)->priv);
-               if (len == 0) {
-                       /* Set a default key of all 0 */
-                       IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
-                                          key);
-                       memset(sec.keys[key], 0, 13);
-                       (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
-                                              (*crypt)->priv);
-                       sec.key_sizes[key] = 13;
-                       sec.flags |= (1 << key);
+               if (host_crypto) {
+                       len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
+                                                    NULL, (*crypt)->priv);
+                       if (len == 0) {
+                               /* Set a default key of all 0 */
+                               IEEE80211_DEBUG_WX("Setting key %d to all "
+                                                  "zero.\n", key);
+                               memset(sec.keys[key], 0, 13);
+                               (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
+                                                      (*crypt)->priv);
+                               sec.key_sizes[key] = 13;
+                               sec.flags |= (1 << key);
+                       }
                }
-
                /* No key data - just set the default TX key index */
                if (key_provided) {
-                       IEEE80211_DEBUG_WX
-                           ("Setting key %d to default Tx key.\n", key);
+                       IEEE80211_DEBUG_WX("Setting key %d to default Tx "
+                                          "key.\n", key);
                        ieee->tx_keyidx = key;
                        sec.active_key = key;
                        sec.flags |= SEC_ACTIVE_KEY;
@@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
        struct iw_point *erq = &(wrqu->encoding);
        int len, key;
        struct ieee80211_crypt_data *crypt;
+       struct ieee80211_security *sec = &ieee->sec;
 
        IEEE80211_DEBUG_WX("GET_ENCODE\n");
 
@@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
        crypt = ieee->crypt[key];
        erq->flags = key + 1;
 
-       if (crypt == NULL || crypt->ops == NULL) {
+       if (!sec->enabled) {
                erq->length = 0;
                erq->flags |= IW_ENCODE_DISABLED;
                return 0;
        }
 
-       if (strcmp(crypt->ops->name, "WEP") != 0) {
+       if (sec->level != SEC_LEVEL_1) {
                /* only WEP is supported with wireless extensions, so just
                 * report that encryption is used */
                erq->length = 0;
@@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
                return 0;
        }
 
-       len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
-       erq->length = (len >= 0 ? len : 0);
+       len = sec->key_sizes[key];
+       memcpy(keybuf, sec->keys[key], len);
 
+       erq->length = (len >= 0 ? len : 0);
        erq->flags |= IW_ENCODE_ENABLED;
 
        if (ieee->open_wep)