[PATCH] ieee80211: Fixed a kernel oops on module unload
authorJames Ketrenos <jketreno@linux.intel.com>
Wed, 21 Sep 2005 16:53:43 +0000 (11:53 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 22 Sep 2005 03:01:52 +0000 (23:01 -0400)
tree 367069f24fc38b4aa910e86ff40094d2078d8aa7
parent a33a1982012e9070736e3717231714dc9892303b
author James Ketrenos <jketreno@linux.intel.com> 1124430800 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127310571 -0500

Fixed a kernel oops on module unload by adding spin lock protection to
ieee80211's crypt handlers (thanks to Zhu Yi)

Modified scan result logic to report WPA and RSN IEs if set (vs.being
based on wpa_enabled)

Added ieee80211_device as the first parameter to the crypt init()
method.  TKIP modified to use that structure for determining whether to
countermeasures are active.

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

index 2d9c679cf6b6a1b275497df8fb2863703f31697c..ed06a9454edcebdeba3a71eb2b0f8199106171e0 100644 (file)
@@ -434,6 +434,7 @@ struct ieee80211_device;
 #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)
index 93bf91fda82e13f7d2cbe592e0ce16a1713c5929..e2064edb957d7d6d76d8b1df94627b9a4c61bc52 100644 (file)
@@ -31,7 +31,7 @@ struct ieee80211_crypto_ops {
        /* init new crypto context (e.g., allocate private data space,
         * select IV, etc.); returns NULL on failure or pointer to allocated
         * private data on success */
-       void *(*init) (int keyidx);
+       void *(*init) (struct ieee80211_device * ieee, int keyidx);
 
        /* deinitialize crypto context and free allocated private data */
        void (*deinit) (void *priv);
index dc835f68edd3b54a271ed008d98992117e3409ed..0c366299db0f7c72ec3e95bf71af86d875b48f59 100644 (file)
@@ -41,7 +41,9 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
 {
        struct list_head *ptr, *n;
        struct ieee80211_crypt_data *entry;
+       unsigned long flags;
 
+       spin_lock_irqsave(&ieee->lock, flags);
        for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
             ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
                entry = list_entry(ptr, struct ieee80211_crypt_data, list);
@@ -57,14 +59,13 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
                }
                kfree(entry);
        }
+       spin_unlock_irqrestore(&ieee->lock, flags);
 }
 
 void ieee80211_crypt_deinit_handler(unsigned long data)
 {
        struct ieee80211_device *ieee = (struct ieee80211_device *)data;
-       unsigned long flags;
 
-       spin_lock_irqsave(&ieee->lock, flags);
        ieee80211_crypt_deinit_entries(ieee, 0);
        if (!list_empty(&ieee->crypt_deinit_list)) {
                printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
@@ -72,7 +73,6 @@ void ieee80211_crypt_deinit_handler(unsigned long data)
                ieee->crypt_deinit_timer.expires = jiffies + HZ;
                add_timer(&ieee->crypt_deinit_timer);
        }
-       spin_unlock_irqrestore(&ieee->lock, flags);
 
 }
 
@@ -182,7 +182,8 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
                return NULL;
 }
 
-static void *ieee80211_crypt_null_init(int keyidx)
+static void *ieee80211_crypt_null_init(struct ieee80211_device *ieee,
+                                      int keyidx)
 {
        return (void *)1;
 }
index 7b6290885e7d71e972f24d03da40508a1d15aa5a..1e6644b133dc2bab430807862662f5ea610607c8 100644 (file)
@@ -74,7 +74,7 @@ static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
        crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
 }
 
-static void *ieee80211_ccmp_init(int key_idx)
+static void *ieee80211_ccmp_init(struct ieee80211_device *ieee, int key_idx)
 {
        struct ieee80211_ccmp_data *priv;
 
index dca380e574542a4921f4a5772e4e0aaa9d17ce27..0c495f07e718ec3e5e23d2269c725fc9f4b913cc 100644 (file)
@@ -59,9 +59,11 @@ struct ieee80211_tkip_data {
 
        /* scratch buffers for virt_to_page() (crypto API) */
        u8 rx_hdr[16], tx_hdr[16];
+
+       struct ieee80211_device *ieee;
 };
 
-static void *ieee80211_tkip_init(int key_idx)
+static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx)
 {
        struct ieee80211_tkip_data *priv;
 
@@ -69,6 +71,9 @@ static void *ieee80211_tkip_init(int key_idx)
        if (priv == NULL)
                goto fail;
        memset(priv, 0, sizeof(*priv));
+
+       priv->ieee = ieee;
+
        priv->key_idx = key_idx;
 
        priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
@@ -264,11 +269,21 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        u32 crc;
        struct scatterlist sg;
 
+       hdr = (struct ieee80211_hdr *)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;
 
-       hdr = (struct ieee80211_hdr *)skb->data;
        if (!tkey->tx_phase1_done) {
                tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
                                   tkey->tx_iv32);
@@ -325,10 +340,20 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        struct scatterlist sg;
        int plen;
 
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (tkey->ieee->tkip_countermeasures) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+                              "received packet from " MAC_FMT "\n",
+                              tkey->ieee->dev->name, MAC_ARG(hdr->addr2));
+               }
+               return -1;
+       }
+
        if (skb->len < hdr_len + 8 + 4)
                return -1;
 
-       hdr = (struct ieee80211_hdr *)skb->data;
        pos = skb->data + hdr_len;
        keyidx = pos[3];
        if (!(keyidx & (1 << 5))) {
index ebe16155e7929b735691aab48510926ebf49e4ad..63e783fa5173d89abbd51bf76c029fed6a236dc3 100644 (file)
@@ -37,7 +37,7 @@ struct prism2_wep_data {
        struct crypto_tfm *tfm;
 };
 
-static void *prism2_wep_init(int keyidx)
+static void *prism2_wep_init(struct ieee80211_device *ieee, int keyidx)
 {
        struct prism2_wep_data *priv;
 
index e0337c8fcde85075bef9f24a27fa7d81233faac8..9a125d45289a36434ba9a69193026b27215e87b5 100644 (file)
@@ -280,17 +280,6 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
        hdr = (struct ieee80211_hdr *)skb->data;
        hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
 
-#ifdef CONFIG_IEEE80211_CRYPT_TKIP
-       if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-                              "received packet from " MAC_FMT "\n",
-                              ieee->dev->name, MAC_ARG(hdr->addr2));
-               }
-               return -1;
-       }
-#endif
-
        atomic_inc(&crypt->refcnt);
        res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
        atomic_dec(&crypt->refcnt);
index 1a09448016ed7f69504039362cadc54c52c08f9d..435ef5a73d75b224d8636d5a74d297a20a94a732 100644 (file)
@@ -157,20 +157,6 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
        struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
        int res;
 
-#ifdef CONFIG_IEEE80211_CRYPT_TKIP
-       struct ieee80211_hdr *header;
-
-       if (ieee->tkip_countermeasures &&
-           crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
-               header = (struct ieee80211_hdr *)frag->data;
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-                              "TX packet to " MAC_FMT "\n",
-                              ieee->dev->name, MAC_ARG(header->addr1));
-               }
-               return -1;
-       }
-#endif
        /* To encrypt, frame format is:
         * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
 
index 04f0897b065364a153fd1211d81b0feec09bc775..fc4e1377aba7f8e6600c32e5f62c5eec8325b2cc 100644 (file)
@@ -182,7 +182,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
        if (iwe.u.data.length)
                start = iwe_stream_add_point(start, stop, &iwe, custom);
 
-       if (ieee->wpa_enabled && network->wpa_ie_len) {
+       if (network->wpa_ie_len) {
                char buf[MAX_WPA_IE_LEN * 2 + 30];
 
                u8 *p = buf;
@@ -197,7 +197,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
                start = iwe_stream_add_point(start, stop, &iwe, buf);
        }
 
-       if (ieee->wpa_enabled && network->rsn_ie_len) {
+       if (network->rsn_ie_len) {
                char buf[MAX_WPA_IE_LEN * 2 + 30];
 
                u8 *p = buf;
@@ -351,7 +351,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
                }
 
                if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
-                       new_crypt->priv = new_crypt->ops->init(key);
+                       new_crypt->priv = new_crypt->ops->init(ieee, key);
 
                if (!new_crypt->ops || !new_crypt->priv) {
                        kfree(new_crypt);