aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ketrenos <jketreno@linux.intel.com>2005-09-21 12:53:43 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-21 23:01:52 -0400
commit20d64713ae71c0b0aa06084acbef2244021baaca (patch)
treef9af562b0bc70f7f75d0195aacf155fd3ec6628a
parent4ca5253d573d7b3785dbb2f123f948fdca6ee235 (diff)
[PATCH] ieee80211: Fixed a kernel oops on module unload
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>
-rw-r--r--include/net/ieee80211.h1
-rw-r--r--include/net/ieee80211_crypt.h2
-rw-r--r--net/ieee80211/ieee80211_crypt.c9
-rw-r--r--net/ieee80211/ieee80211_crypt_ccmp.c2
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c31
-rw-r--r--net/ieee80211/ieee80211_crypt_wep.c2
-rw-r--r--net/ieee80211/ieee80211_rx.c11
-rw-r--r--net/ieee80211/ieee80211_tx.c14
-rw-r--r--net/ieee80211/ieee80211_wx.c6
9 files changed, 40 insertions, 38 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 2d9c679cf6b6..ed06a9454edc 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -434,6 +434,7 @@ struct ieee80211_device;
434#define SEC_KEY_2 (1<<1) 434#define SEC_KEY_2 (1<<1)
435#define SEC_KEY_3 (1<<2) 435#define SEC_KEY_3 (1<<2)
436#define SEC_KEY_4 (1<<3) 436#define SEC_KEY_4 (1<<3)
437#define SEC_KEY_MASK (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4)
437#define SEC_ACTIVE_KEY (1<<4) 438#define SEC_ACTIVE_KEY (1<<4)
438#define SEC_AUTH_MODE (1<<5) 439#define SEC_AUTH_MODE (1<<5)
439#define SEC_UNICAST_GROUP (1<<6) 440#define SEC_UNICAST_GROUP (1<<6)
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index 93bf91fda82e..e2064edb957d 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -31,7 +31,7 @@ struct ieee80211_crypto_ops {
31 /* init new crypto context (e.g., allocate private data space, 31 /* init new crypto context (e.g., allocate private data space,
32 * select IV, etc.); returns NULL on failure or pointer to allocated 32 * select IV, etc.); returns NULL on failure or pointer to allocated
33 * private data on success */ 33 * private data on success */
34 void *(*init) (int keyidx); 34 void *(*init) (struct ieee80211_device * ieee, int keyidx);
35 35
36 /* deinitialize crypto context and free allocated private data */ 36 /* deinitialize crypto context and free allocated private data */
37 void (*deinit) (void *priv); 37 void (*deinit) (void *priv);
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index dc835f68edd3..0c366299db0f 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -41,7 +41,9 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
41{ 41{
42 struct list_head *ptr, *n; 42 struct list_head *ptr, *n;
43 struct ieee80211_crypt_data *entry; 43 struct ieee80211_crypt_data *entry;
44 unsigned long flags;
44 45
46 spin_lock_irqsave(&ieee->lock, flags);
45 for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; 47 for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
46 ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { 48 ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
47 entry = list_entry(ptr, struct ieee80211_crypt_data, list); 49 entry = list_entry(ptr, struct ieee80211_crypt_data, list);
@@ -57,14 +59,13 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
57 } 59 }
58 kfree(entry); 60 kfree(entry);
59 } 61 }
62 spin_unlock_irqrestore(&ieee->lock, flags);
60} 63}
61 64
62void ieee80211_crypt_deinit_handler(unsigned long data) 65void ieee80211_crypt_deinit_handler(unsigned long data)
63{ 66{
64 struct ieee80211_device *ieee = (struct ieee80211_device *)data; 67 struct ieee80211_device *ieee = (struct ieee80211_device *)data;
65 unsigned long flags;
66 68
67 spin_lock_irqsave(&ieee->lock, flags);
68 ieee80211_crypt_deinit_entries(ieee, 0); 69 ieee80211_crypt_deinit_entries(ieee, 0);
69 if (!list_empty(&ieee->crypt_deinit_list)) { 70 if (!list_empty(&ieee->crypt_deinit_list)) {
70 printk(KERN_DEBUG "%s: entries remaining in delayed crypt " 71 printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
@@ -72,7 +73,6 @@ void ieee80211_crypt_deinit_handler(unsigned long data)
72 ieee->crypt_deinit_timer.expires = jiffies + HZ; 73 ieee->crypt_deinit_timer.expires = jiffies + HZ;
73 add_timer(&ieee->crypt_deinit_timer); 74 add_timer(&ieee->crypt_deinit_timer);
74 } 75 }
75 spin_unlock_irqrestore(&ieee->lock, flags);
76 76
77} 77}
78 78
@@ -182,7 +182,8 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
182 return NULL; 182 return NULL;
183} 183}
184 184
185static void *ieee80211_crypt_null_init(int keyidx) 185static void *ieee80211_crypt_null_init(struct ieee80211_device *ieee,
186 int keyidx)
186{ 187{
187 return (void *)1; 188 return (void *)1;
188} 189}
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index 7b6290885e7d..1e6644b133dc 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -74,7 +74,7 @@ static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
74 crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); 74 crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
75} 75}
76 76
77static void *ieee80211_ccmp_init(int key_idx) 77static void *ieee80211_ccmp_init(struct ieee80211_device *ieee, int key_idx)
78{ 78{
79 struct ieee80211_ccmp_data *priv; 79 struct ieee80211_ccmp_data *priv;
80 80
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index dca380e57454..0c495f07e718 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -59,9 +59,11 @@ struct ieee80211_tkip_data {
59 59
60 /* scratch buffers for virt_to_page() (crypto API) */ 60 /* scratch buffers for virt_to_page() (crypto API) */
61 u8 rx_hdr[16], tx_hdr[16]; 61 u8 rx_hdr[16], tx_hdr[16];
62
63 struct ieee80211_device *ieee;
62}; 64};
63 65
64static void *ieee80211_tkip_init(int key_idx) 66static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx)
65{ 67{
66 struct ieee80211_tkip_data *priv; 68 struct ieee80211_tkip_data *priv;
67 69
@@ -69,6 +71,9 @@ static void *ieee80211_tkip_init(int key_idx)
69 if (priv == NULL) 71 if (priv == NULL)
70 goto fail; 72 goto fail;
71 memset(priv, 0, sizeof(*priv)); 73 memset(priv, 0, sizeof(*priv));
74
75 priv->ieee = ieee;
76
72 priv->key_idx = key_idx; 77 priv->key_idx = key_idx;
73 78
74 priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); 79 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)
264 u32 crc; 269 u32 crc;
265 struct scatterlist sg; 270 struct scatterlist sg;
266 271
272 hdr = (struct ieee80211_hdr *)skb->data;
273
274 if (tkey->ieee->tkip_countermeasures) {
275 if (net_ratelimit()) {
276 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
277 "TX packet to " MAC_FMT "\n",
278 tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
279 }
280 return -1;
281 }
282
267 if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || 283 if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
268 skb->len < hdr_len) 284 skb->len < hdr_len)
269 return -1; 285 return -1;
270 286
271 hdr = (struct ieee80211_hdr *)skb->data;
272 if (!tkey->tx_phase1_done) { 287 if (!tkey->tx_phase1_done) {
273 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, 288 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
274 tkey->tx_iv32); 289 tkey->tx_iv32);
@@ -325,10 +340,20 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
325 struct scatterlist sg; 340 struct scatterlist sg;
326 int plen; 341 int plen;
327 342
343 hdr = (struct ieee80211_hdr *)skb->data;
344
345 if (tkey->ieee->tkip_countermeasures) {
346 if (net_ratelimit()) {
347 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
348 "received packet from " MAC_FMT "\n",
349 tkey->ieee->dev->name, MAC_ARG(hdr->addr2));
350 }
351 return -1;
352 }
353
328 if (skb->len < hdr_len + 8 + 4) 354 if (skb->len < hdr_len + 8 + 4)
329 return -1; 355 return -1;
330 356
331 hdr = (struct ieee80211_hdr *)skb->data;
332 pos = skb->data + hdr_len; 357 pos = skb->data + hdr_len;
333 keyidx = pos[3]; 358 keyidx = pos[3];
334 if (!(keyidx & (1 << 5))) { 359 if (!(keyidx & (1 << 5))) {
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index ebe16155e792..63e783fa5173 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -37,7 +37,7 @@ struct prism2_wep_data {
37 struct crypto_tfm *tfm; 37 struct crypto_tfm *tfm;
38}; 38};
39 39
40static void *prism2_wep_init(int keyidx) 40static void *prism2_wep_init(struct ieee80211_device *ieee, int keyidx)
41{ 41{
42 struct prism2_wep_data *priv; 42 struct prism2_wep_data *priv;
43 43
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index e0337c8fcde8..9a125d45289a 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -280,17 +280,6 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
280 hdr = (struct ieee80211_hdr *)skb->data; 280 hdr = (struct ieee80211_hdr *)skb->data;
281 hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); 281 hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
282 282
283#ifdef CONFIG_IEEE80211_CRYPT_TKIP
284 if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) {
285 if (net_ratelimit()) {
286 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
287 "received packet from " MAC_FMT "\n",
288 ieee->dev->name, MAC_ARG(hdr->addr2));
289 }
290 return -1;
291 }
292#endif
293
294 atomic_inc(&crypt->refcnt); 283 atomic_inc(&crypt->refcnt);
295 res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); 284 res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
296 atomic_dec(&crypt->refcnt); 285 atomic_dec(&crypt->refcnt);
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 1a09448016ed..435ef5a73d75 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -157,20 +157,6 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
157 struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; 157 struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
158 int res; 158 int res;
159 159
160#ifdef CONFIG_IEEE80211_CRYPT_TKIP
161 struct ieee80211_hdr *header;
162
163 if (ieee->tkip_countermeasures &&
164 crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
165 header = (struct ieee80211_hdr *)frag->data;
166 if (net_ratelimit()) {
167 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
168 "TX packet to " MAC_FMT "\n",
169 ieee->dev->name, MAC_ARG(header->addr1));
170 }
171 return -1;
172 }
173#endif
174 /* To encrypt, frame format is: 160 /* To encrypt, frame format is:
175 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ 161 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
176 162
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 04f0897b0653..fc4e1377aba7 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -182,7 +182,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
182 if (iwe.u.data.length) 182 if (iwe.u.data.length)
183 start = iwe_stream_add_point(start, stop, &iwe, custom); 183 start = iwe_stream_add_point(start, stop, &iwe, custom);
184 184
185 if (ieee->wpa_enabled && network->wpa_ie_len) { 185 if (network->wpa_ie_len) {
186 char buf[MAX_WPA_IE_LEN * 2 + 30]; 186 char buf[MAX_WPA_IE_LEN * 2 + 30];
187 187
188 u8 *p = buf; 188 u8 *p = buf;
@@ -197,7 +197,7 @@ static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
197 start = iwe_stream_add_point(start, stop, &iwe, buf); 197 start = iwe_stream_add_point(start, stop, &iwe, buf);
198 } 198 }
199 199
200 if (ieee->wpa_enabled && network->rsn_ie_len) { 200 if (network->rsn_ie_len) {
201 char buf[MAX_WPA_IE_LEN * 2 + 30]; 201 char buf[MAX_WPA_IE_LEN * 2 + 30];
202 202
203 u8 *p = buf; 203 u8 *p = buf;
@@ -351,7 +351,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
351 } 351 }
352 352
353 if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) 353 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
354 new_crypt->priv = new_crypt->ops->init(key); 354 new_crypt->priv = new_crypt->ops->init(ieee, key);
355 355
356 if (!new_crypt->ops || !new_crypt->priv) { 356 if (!new_crypt->ops || !new_crypt->priv) {
357 kfree(new_crypt); 357 kfree(new_crypt);