[PATCH] ieee80211: Added handle_deauth() callback, enhanced tkip/ccmp support of...
authorJames Ketrenos <jketreno@linux.intel.com>
Wed, 21 Sep 2005 16:58:49 +0000 (11:58 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 22 Sep 2005 19:39:41 +0000 (15:39 -0400)
tree de81b55e78e85997642c651ea677078d0554a14f
parent c8030da8c159f8b82712172a6748a42523aea83a
author James Ketrenos <jketreno@linux.intel.com> 1127104380 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127315225 -0500

Added handle_deauth() callback.
Enhanced crypt_{tkip,ccmp} to support varying splits of HW/SW offload.
Changed channel freq to u32 from u16.
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
include/net/ieee80211.h
include/net/ieee80211_crypt.h
net/ieee80211/ieee80211_crypt_ccmp.c
net/ieee80211/ieee80211_crypt_tkip.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_tx.c

index 4a1340b8341ce1c24f601f085aecf6b97e58cd14..220a9e3c91fa83ba7bd07fbb132d8c3125557777 100644 (file)
@@ -808,7 +808,7 @@ enum {
 };
 
 struct ieee80211_channel {
-       u16 freq;
+       u32 freq;
        u8 channel;
        u8 flags;
        u8 max_power;
@@ -862,6 +862,7 @@ struct ieee80211_device {
        int host_mc_decrypt;
 
        int host_open_frag;
+       int host_build_iv;
        int ieee802_1x;         /* is IEEE 802.1X used */
 
        /* WPA data */
@@ -914,6 +915,8 @@ struct ieee80211_device {
        /* Typical STA methods */
        int (*handle_auth) (struct net_device * dev,
                            struct ieee80211_auth * auth);
+       int (*handle_deauth) (struct net_device * dev,
+                             struct ieee80211_auth * auth);
        int (*handle_disassoc) (struct net_device * dev,
                                struct ieee80211_disassoc * assoc);
        int (*handle_beacon) (struct net_device * dev,
index 24e4912a263aa284fb6508f77b5845f6cacd891e..daf3b2c6b038d9b7038b10243d5218d1bbcbc209 100644 (file)
@@ -36,6 +36,8 @@ struct ieee80211_crypto_ops {
        /* deinitialize crypto context and free allocated private data */
        void (*deinit) (void *priv);
 
+       int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv);
+
        /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
         * value from decrypt_mpdu is passed as the keyidx value for
         * decrypt_msdu. skb must have enough head and tail room for the
index a3dc5712b98b36ae4b307f27af602ac22f95e49e..081d8575dbb180bd54dcc1ab5ad358e380545199 100644 (file)
@@ -191,26 +191,18 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
        ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
 }
 
-static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv)
 {
        struct ieee80211_ccmp_data *key = priv;
-       int data_len, i, blocks, last, len;
-       u8 *pos, *mic;
-       struct ieee80211_hdr_4addr *hdr;
-       u8 *b0 = key->tx_b0;
-       u8 *b = key->tx_b;
-       u8 *e = key->tx_e;
-       u8 *s0 = key->tx_s0;
+       int i;
+       u8 *pos;
 
-       if (skb_headroom(skb) < CCMP_HDR_LEN ||
-           skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
+       if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
                return -1;
 
-       data_len = skb->len - hdr_len;
        pos = skb_push(skb, CCMP_HDR_LEN);
        memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
        pos += hdr_len;
-       mic = skb_put(skb, CCMP_MIC_LEN);
 
        i = CCMP_PN_LEN - 1;
        while (i >= 0) {
@@ -229,6 +221,30 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        *pos++ = key->tx_pn[1];
        *pos++ = key->tx_pn[0];
 
+       return CCMP_HDR_LEN;
+}
+
+static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_ccmp_data *key = priv;
+       int data_len, i, blocks, last, len;
+       u8 *pos, *mic;
+       struct ieee80211_hdr_4addr *hdr;
+       u8 *b0 = key->tx_b0;
+       u8 *b = key->tx_b;
+       u8 *e = key->tx_e;
+       u8 *s0 = key->tx_s0;
+
+       if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len)
+               return -1;
+
+       data_len = skb->len - hdr_len;
+       len = ieee80211_ccmp_hdr(skb, hdr_len, priv);
+       if (len < 0)
+               return -1;
+
+       pos = skb->data + hdr_len + CCMP_HDR_LEN;
+       mic = skb_put(skb, CCMP_MIC_LEN);
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
        ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
 
@@ -429,6 +445,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
        .name = "CCMP",
        .init = ieee80211_ccmp_init,
        .deinit = ieee80211_ccmp_deinit,
+       .build_iv = ieee80211_ccmp_hdr,
        .encrypt_mpdu = ieee80211_ccmp_encrypt,
        .decrypt_mpdu = ieee80211_ccmp_decrypt,
        .encrypt_msdu = NULL,
index 21022f195bab6f4df898d61590ce59b13d2bc43a..e0733050ae7179d859342905e24317e34230af48 100644 (file)
@@ -260,35 +260,27 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
 #endif
 }
 
-static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
 {
        struct ieee80211_tkip_data *tkey = priv;
        int len;
-       u8 rc4key[16], *pos, *icv;
+       u8 *rc4key, *pos, *icv;
        struct ieee80211_hdr_4addr *hdr;
        u32 crc;
-       struct scatterlist sg;
 
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
 
-       if (tkey->ieee->tkip_countermeasures) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-                              "TX packet to " MAC_FMT "\n",
-                              tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
-               }
-               return -1;
-       }
-
-       if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
-           skb->len < hdr_len)
-               return -1;
+       if (skb_headroom(skb) < 8 || skb->len < hdr_len)
+               return NULL;
 
        if (!tkey->tx_phase1_done) {
                tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
                                   tkey->tx_iv32);
                tkey->tx_phase1_done = 1;
        }
+       rc4key = kmalloc(16, GFP_ATOMIC);
+       if (!rc4key)
+               return NULL;
        tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
 
        len = skb->len - hdr_len;
@@ -297,9 +289,9 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pos += hdr_len;
        icv = skb_put(skb, 4);
 
-       *pos++ = rc4key[0];
-       *pos++ = rc4key[1];
-       *pos++ = rc4key[2];
+       *pos++ = *rc4key;
+       *pos++ = *(rc4key + 1);
+       *pos++ = *(rc4key + 2);
        *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
        *pos++ = tkey->tx_iv32 & 0xff;
        *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
@@ -312,6 +304,38 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        icv[2] = crc >> 16;
        icv[3] = crc >> 24;
 
+       return rc4key;
+}
+
+static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+{
+       struct ieee80211_tkip_data *tkey = priv;
+       int len;
+       const u8 *rc4key;
+       u8 *pos;
+       struct scatterlist sg;
+
+       if (tkey->ieee->tkip_countermeasures) {
+               if (net_ratelimit()) {
+                       struct ieee80211_hdr_4addr *hdr =
+                           (struct ieee80211_hdr_4addr *)skb->data;
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "TX packet to " MAC_FMT "\n",
+                              tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
+               }
+               return -1;
+       }
+
+       if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
+               return -1;
+
+       len = skb->len - hdr_len;
+       pos = skb->data + hdr_len;
+
+       rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv);
+       if (!rc4key)
+               return -1;
+
        crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
        sg.page = virt_to_page(pos);
        sg.offset = offset_in_page(pos);
index 256d5524445c6001646e70beb496cae5860bdee0..fcf05bf677b8983c75868f2b0249c77f896b4038 100644 (file)
@@ -1534,6 +1534,12 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                                              header);
                break;
 
+       case IEEE80211_STYPE_DEAUTH:
+               printk("DEAUTH from AP\n");
+               if (ieee->handle_deauth != NULL)
+                       ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
+                                           header);
+               break;
        default:
                IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
index 24ade5f68e0259293801b61b9b2a6e9138e7a493..8d87897d7eb7ef218d483a90bb64606cdc557e91 100644 (file)
@@ -227,7 +227,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
            rts_required;
        unsigned long flags;
        struct net_device_stats *stats = &ieee->stats;
-       int ether_type, encrypt, host_encrypt, host_encrypt_msdu;
+       int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
        int bytes, fc, hdr_len;
        struct sk_buff *skb_frag;
        struct ieee80211_hdr_3addr header = {   /* Ensure zero initialized */
@@ -263,8 +263,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 
        encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
            ieee->sec.encrypt;
+
        host_encrypt = ieee->host_encrypt && encrypt;
        host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt;
+       host_build_iv = ieee->host_build_iv && encrypt;
 
        if (!encrypt && ieee->ieee802_1x &&
            ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -310,8 +312,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
                    crypt->ops->extra_msdu_postfix_len;
                struct sk_buff *skb_new = dev_alloc_skb(len);
+
                if (unlikely(!skb_new))
                        goto failed;
+
                skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
                memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
                snapped = 1;
@@ -418,7 +422,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        for (; i < nr_frags; i++) {
                skb_frag = txb->fragments[i];
 
-               if (host_encrypt)
+               if (host_encrypt || host_build_iv)
                        skb_reserve(skb_frag,
                                    crypt->ops->extra_mpdu_prefix_len);
 
@@ -453,6 +457,16 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                 * to insert the IV between the header and the payload */
                if (host_encrypt)
                        ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+               else if (host_build_iv) {
+                       struct ieee80211_crypt_data *crypt;
+
+                       crypt = ieee->crypt[ieee->tx_keyidx];
+                       atomic_inc(&crypt->refcnt);
+                       if (crypt->ops->build_iv)
+                               crypt->ops->build_iv(skb_frag, hdr_len,
+                                                    crypt->priv);
+                       atomic_dec(&crypt->refcnt);
+               }
 
                if (ieee->config &
                    (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))