From 74079fdce472a2b16d502fe39e06b135ef06c69b Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 13 Sep 2005 17:35:21 -0500 Subject: [PATCH] ieee80211 Added wireless spy support Added wireless spy support to Rx code path. Signed-off-by: James Ketrenos NOTE: Looks like scripts/Lindent generated output different than the Lindented version already in-kernel, hence all the whitespace deltas... *sigh* Signed-off-by: Jeff Garzik --- include/net/ieee80211_crypt.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index b58a3bcc0dc0..93bf91fda82e 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -31,10 +31,10 @@ 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) (int keyidx); /* deinitialize crypto context and free allocated private data */ - void (*deinit)(void *priv); + void (*deinit) (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 @@ -42,21 +42,21 @@ struct ieee80211_crypto_ops { * encryption; if not, error will be returned; these functions are * called for all MPDUs (i.e., fragments). */ - int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); /* These functions are called for full MSDUs, i.e. full frames. * These can be NULL if full MSDU operations are not needed. */ - int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, - void *priv); + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); - int (*set_key)(void *key, int len, u8 *seq, void *priv); - int (*get_key)(void *key, int len, u8 *seq, void *priv); + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); /* procfs handler for printing out key information and possible * statistics */ - char * (*print_stats)(char *p, void *priv); + char *(*print_stats) (char *p, void *priv); /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and @@ -69,7 +69,7 @@ struct ieee80211_crypto_ops { }; struct ieee80211_crypt_data { - struct list_head list; /* delayed deletion list */ + struct list_head list; /* delayed deletion list */ struct ieee80211_crypto_ops *ops; void *priv; atomic_t refcnt; @@ -77,7 +77,7 @@ struct ieee80211_crypt_data { int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); -struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name); void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); void ieee80211_crypt_deinit_handler(unsigned long); void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, -- cgit v1.2.3 From 20d64713ae71c0b0aa06084acbef2244021baaca Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:53:43 -0500 Subject: [PATCH] ieee80211: Fixed a kernel oops on module unload tree 367069f24fc38b4aa910e86ff40094d2078d8aa7 parent a33a1982012e9070736e3717231714dc9892303b author James Ketrenos 1124430800 -0500 committer James Ketrenos 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 Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 + include/net/ieee80211_crypt.h | 2 +- net/ieee80211/ieee80211_crypt.c | 9 +++++---- net/ieee80211/ieee80211_crypt_ccmp.c | 2 +- net/ieee80211/ieee80211_crypt_tkip.c | 31 ++++++++++++++++++++++++++++--- net/ieee80211/ieee80211_crypt_wep.c | 2 +- net/ieee80211/ieee80211_rx.c | 11 ----------- net/ieee80211/ieee80211_tx.c | 14 -------------- net/ieee80211/ieee80211_wx.c | 6 +++--- 9 files changed, 40 insertions(+), 38 deletions(-) (limited to 'include/net/ieee80211_crypt.h') 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; #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) 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 { /* 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); 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) { 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; } 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, 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; 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 { /* 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))) { 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 { 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; 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, 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); 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, 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) */ 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, 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); -- cgit v1.2.3 From 0ad0c3c64484b1458b51167bd3e614d8d9d070f8 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:15 -0500 Subject: [PATCH] ieee80211: Fix kernel Oops when module unload tree b69e983266840983183a00f5ac02c66d5270ca47 parent cdd6372949b76694622ed74fe36e1dd17a92eb71 author Zhu Yi 1124435425 -0500 committer James Ketrenos 1127312421 -0500 Fix kernel Oops when module unload. Export a new function ieee80211_crypt_quiescing from ieee80211. Device drivers call it to make the host crypto stack enter the quiescence state, which means "process existing requests, but don't accept new ones". This is usually called during a driver's host crypto data structure free (module unload) path. Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 + include/net/ieee80211_crypt.h | 1 + net/ieee80211/ieee80211_crypt.c | 33 +++++++++++++++++++++++++++------ net/ieee80211/ieee80211_module.c | 2 ++ 4 files changed, 31 insertions(+), 6 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index fa14360dbc9d..6cc0674e5606 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -684,6 +684,7 @@ struct ieee80211_device { struct ieee80211_crypt_data *crypt[WEP_KEYS]; int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ struct timer_list crypt_deinit_timer; + int crypt_quiesced; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index e2064edb957d..536e9a9e6718 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -82,5 +82,6 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); void ieee80211_crypt_deinit_handler(unsigned long); void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, struct ieee80211_crypt_data **crypt); +void ieee80211_crypt_quiescing(struct ieee80211_device *ieee); #endif diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 0c366299db0f..60d3166facce 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -44,6 +44,10 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) unsigned long flags; spin_lock_irqsave(&ieee->lock, flags); + + if (list_empty(&ieee->crypt_deinit_list)) + goto unlock; + 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); @@ -59,21 +63,35 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) } kfree(entry); } + unlock: + spin_unlock_irqrestore(&ieee->lock, flags); +} + +/* After this, crypt_deinit_list won't accept new members */ +void ieee80211_crypt_quiescing(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + ieee->crypt_quiesced = 1; 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; ieee80211_crypt_deinit_entries(ieee, 0); - if (!list_empty(&ieee->crypt_deinit_list)) { + + spin_lock_irqsave(&ieee->lock, flags); + if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) { printk(KERN_DEBUG "%s: entries remaining in delayed crypt " "deletion list\n", ieee->dev->name); ieee->crypt_deinit_timer.expires = jiffies + HZ; add_timer(&ieee->crypt_deinit_timer); } - + spin_unlock_irqrestore(&ieee->lock, flags); } void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, @@ -93,10 +111,12 @@ void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, * locking. */ spin_lock_irqsave(&ieee->lock, flags); - list_add(&tmp->list, &ieee->crypt_deinit_list); - if (!timer_pending(&ieee->crypt_deinit_timer)) { - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); + if (!ieee->crypt_quiesced) { + list_add(&tmp->list, &ieee->crypt_deinit_list); + if (!timer_pending(&ieee->crypt_deinit_timer)) { + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } } spin_unlock_irqrestore(&ieee->lock, flags); } @@ -250,6 +270,7 @@ static void __exit ieee80211_crypto_deinit(void) EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); +EXPORT_SYMBOL(ieee80211_crypt_quiescing); EXPORT_SYMBOL(ieee80211_register_crypto_ops); EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 4b43ae1235f9..82a4fd713b28 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -138,6 +138,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) init_timer(&ieee->crypt_deinit_timer); ieee->crypt_deinit_timer.data = (unsigned long)ieee; ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; + ieee->crypt_quiesced = 0; spin_lock_init(&ieee->lock); @@ -161,6 +162,7 @@ void free_ieee80211(struct net_device *dev) int i; + ieee80211_crypt_quiescing(ieee); del_timer_sync(&ieee->crypt_deinit_timer); ieee80211_crypt_deinit_entries(ieee, 1); -- cgit v1.2.3 From 1264fc0498e1e20f97b1ab690e523e7a7fc50eab Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:54:53 -0500 Subject: [PATCH] ieee80211: Fix TKIP, repeated fragmentation problem, and payload_size reporting tree 8428e9f510e6ad6c77baec89cb57374842abf733 parent d78bfd3ddae9c422dd350159110f9c4d7cfc50de author Liu Hong 1124446520 -0500 committer James Ketrenos 1127313183 -0500 Fix TKIP, repeated fragmentation problem, and payload_size reporting 1. TKIP encryption Originally, TKIP encryption issues msdu + mpdu encryption on every fragment. Change the behavior to msdu encryption on the whole packet, then mpdu encryption on every fragment. 2. Avoid repeated fragmentation when !host_encrypt. We only need do fragmentation when using host encryption. Otherwise we only need pass the whole packet to driver, letting driver do the fragmentation. 3. change the txb->payload_size to correct value FW will use this value to determine whether to do fragmentation. If we pass the wrong value, fw may cut on the wrong bound which will make decryption fail when we do host encryption. NOTE: This requires changing drivers (hostap) that have extra_prefix_len used within them (structure member name change). Signed-off-by: Hong Liu Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 2 + include/net/ieee80211_crypt.h | 3 +- net/ieee80211/ieee80211_crypt.c | 4 +- net/ieee80211/ieee80211_crypt_ccmp.c | 4 +- net/ieee80211/ieee80211_crypt_tkip.c | 5 +- net/ieee80211/ieee80211_crypt_wep.c | 4 +- net/ieee80211/ieee80211_module.c | 7 +- net/ieee80211/ieee80211_tx.c | 148 ++++++++++++++++++++--------------- 8 files changed, 102 insertions(+), 75 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 43cf2e577191..46466f5a2b45 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -724,7 +724,9 @@ struct ieee80211_device { /* If the host performs {en,de}cryption, then set to 1 */ int host_encrypt; + int host_encrypt_msdu; int host_decrypt; + int host_open_frag; int ieee802_1x; /* is IEEE 802.1X used */ /* WPA data */ diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 536e9a9e6718..24e4912a263a 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -63,7 +63,8 @@ struct ieee80211_crypto_ops { * extra_postfix_len; encrypt need not use all this space, but * the result must start at the beginning of the buffer and correct * length must be returned */ - int extra_prefix_len, extra_postfix_len; + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; struct module *owner; }; diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index 60d3166facce..e26bcc918032 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -221,8 +221,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_null = { .decrypt_msdu = NULL, .set_key = NULL, .get_key = NULL, - .extra_prefix_len = 0, - .extra_postfix_len = 0, + .extra_mpdu_prefix_len = 0, + .extra_mpdu_postfix_len = 0, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index d3b5cdee69ef..a3dc5712b98b 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -436,8 +436,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { .set_key = ieee80211_ccmp_set_key, .get_key = ieee80211_ccmp_get_key, .print_stats = ieee80211_ccmp_print_stats, - .extra_prefix_len = CCMP_HDR_LEN, - .extra_postfix_len = CCMP_MIC_LEN, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index f091aacd4297..f973d6cb8248 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -690,8 +690,9 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { .set_key = ieee80211_tkip_set_key, .get_key = ieee80211_tkip_get_key, .print_stats = ieee80211_tkip_print_stats, - .extra_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 63e783fa5173..2aaeac1e02d7 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -239,8 +239,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = { .set_key = prism2_wep_set_key, .get_key = prism2_wep_get_key, .print_stats = prism2_wep_print_stats, - .extra_prefix_len = 4, /* IV */ - .extra_postfix_len = 4, /* ICV */ + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 67d6bdd2e3f2..dddc61647390 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -133,6 +133,12 @@ struct net_device *alloc_ieee80211(int sizeof_priv) /* Default to enabling full open WEP with host based encrypt/decrypt */ ieee->host_encrypt = 1; ieee->host_decrypt = 1; + /* Host fragementation in Open mode. Default is enabled. + * Note: host fragmentation is always enabled if host encryption + * is enabled. For cards can do hardware encryption, they must do + * hardware fragmentation as well. So we don't need a variable + * like host_enc_frag. */ + ieee->host_open_frag = 1; ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ INIT_LIST_HEAD(&ieee->crypt_deinit_list); @@ -147,7 +153,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->tkip_countermeasures = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; - ieee->ieee802_1x = 1; return dev; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index f505aa127e21..23a1f88de7cb 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -128,7 +128,7 @@ payload of each frame is reduced to 492 bytes. static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -static inline int ieee80211_put_snap(u8 * data, u16 h_proto) +static inline int ieee80211_copy_snap(u8 * data, u16 h_proto) { struct ieee80211_snap_hdr *snap; u8 *oui; @@ -159,15 +159,9 @@ static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, /* To encrypt, frame format is: * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ - - // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. */ atomic_inc(&crypt->refcnt); res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) + if (crypt->ops->encrypt_mpdu) res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); atomic_dec(&crypt->refcnt); @@ -222,7 +216,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -/* Incoming skb is converted to a txb which consist of +/* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -233,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; + int ether_type, encrypt, host_encrypt, host_encrypt_msdu; int bytes, fc, hdr_len; struct sk_buff *skb_frag; struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ @@ -241,8 +235,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) .seq_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt; + int snapped = 0; spin_lock_irqsave(&ieee->lock, flags); @@ -266,6 +260,7 @@ 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; if (!encrypt && ieee->ieee802_1x && ieee->drop_unencrypted && ether_type != ETH_P_PAE) { @@ -291,14 +286,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (ieee->iw_mode == IW_MODE_INFRA) { fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, - Addr3 = DA */ + /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ memcpy(header.addr1, ieee->bssid, ETH_ALEN); memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, dest, ETH_ALEN); } else if (ieee->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, - Addr3 = BSSID */ + /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ memcpy(header.addr1, dest, ETH_ALEN); memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN); @@ -306,42 +299,75 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) header.frame_ctl = cpu_to_le16(fc); hdr_len = IEEE80211_3ADDR_LEN; - /* Determine fragmentation size based on destination (multicast - * and broadcast are not fragmented) */ - if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) - frag_size = MAX_FRAG_THRESHOLD; - else - frag_size = ieee->fts; + /* Encrypt msdu first on the whole data packet. */ + if ((host_encrypt || host_encrypt_msdu) && + crypt && crypt->ops && crypt->ops->encrypt_msdu) { + int res = 0; + 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; + ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), + ether_type); + memcpy(skb_put(skb_new, skb->len), skb->data, skb->len); + res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); + if (res < 0) { + IEEE80211_ERROR("msdu encryption failed\n"); + dev_kfree_skb_any(skb_new); + goto failed; + } + dev_kfree_skb_any(skb); + skb = skb_new; + bytes += crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + skb_pull(skb, hdr_len); + } - /* Determine amount of payload per fragment. Regardless of if - * this stack is providing the full 802.11 header, one will - * eventually be affixed to this fragment -- so we must account for - * it when determining the amount of payload space. */ - bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; + if (host_encrypt || ieee->host_open_frag) { + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ + if (is_multicast_ether_addr(dest)) + frag_size = MAX_FRAG_THRESHOLD; + else + frag_size = ieee->fts; + + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account + * for it when determining the amount of payload space. */ + bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; - /* Each fragment may need to have room for encryptiong pre/postfix */ - if (host_encrypt) - bytes_per_frag -= crypt->ops->extra_prefix_len + - crypt->ops->extra_postfix_len; - - /* Number of fragments is the total bytes_per_frag / - * payload_per_fragment */ - nr_frags = bytes / bytes_per_frag; - bytes_last_frag = bytes % bytes_per_frag; - if (bytes_last_frag) - nr_frags++; - else - bytes_last_frag = bytes_per_frag; + /* Each fragment may need to have room for encryptiong + * pre/postfix */ + if (host_encrypt) + bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_mpdu_postfix_len; + + /* Number of fragments is the total + * bytes_per_frag / payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + } else { + nr_frags = 1; + bytes_per_frag = bytes_last_frag = bytes; + frag_size = bytes + IEEE80211_3ADDR_LEN; + } rts_required = (frag_size > ieee->rts && ieee->config & CFG_IEEE80211_RTS); if (rts_required) nr_frags++; - else - bytes_last_frag = bytes_per_frag; /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, @@ -353,7 +379,11 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) goto failed; } txb->encrypted = encrypt; - txb->payload_size = bytes; + if (host_encrypt) + txb->payload_size = frag_size * (nr_frags - 1) + + bytes_last_frag; + else + txb->payload_size = bytes; if (rts_required) { skb_frag = txb->fragments[0]; @@ -385,7 +415,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag = txb->fragments[i]; if (host_encrypt) - skb_reserve(skb_frag, crypt->ops->extra_prefix_len); + skb_reserve(skb_frag, + crypt->ops->extra_mpdu_prefix_len); frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); @@ -402,11 +433,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) bytes = bytes_last_frag; } - /* Put a SNAP header on the first fragment */ - if (i == 0) { - ieee80211_put_snap(skb_put - (skb_frag, SNAP_SIZE + sizeof(u16)), - ether_type); + if (i == 0 && !snapped) { + ieee80211_copy_snap(skb_put + (skb_frag, SNAP_SIZE + sizeof(u16)), + ether_type); bytes -= SNAP_SIZE + sizeof(u16); } @@ -420,19 +450,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) 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); @@ -444,7 +461,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); if (txb) { - if ((*ieee->hard_start_xmit) (txb, dev) == 0) { + int ret = (*ieee->hard_start_xmit) (txb, dev); + if (ret == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; return 0; -- cgit v1.2.3 From 31b59eaee8f8ec29d8cb6ac0c8eed086689d8030 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 21 Sep 2005 11:58:49 -0500 Subject: [PATCH] ieee80211: Added handle_deauth() callback, enhanced tkip/ccmp support of varying hw/sw offload tree de81b55e78e85997642c651ea677078d0554a14f parent c8030da8c159f8b82712172a6748a42523aea83a author James Ketrenos 1127104380 -0500 committer James Ketrenos 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 --- include/net/ieee80211.h | 5 ++- include/net/ieee80211_crypt.h | 2 ++ net/ieee80211/ieee80211_crypt_ccmp.c | 41 ++++++++++++++++-------- net/ieee80211/ieee80211_crypt_tkip.c | 60 +++++++++++++++++++++++++----------- net/ieee80211/ieee80211_rx.c | 6 ++++ net/ieee80211/ieee80211_tx.c | 18 +++++++++-- 6 files changed, 99 insertions(+), 33 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4a1340b8341c..220a9e3c91fa 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -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, diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 24e4912a263a..daf3b2c6b038 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -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 diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index a3dc5712b98b..081d8575dbb1 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -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, diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 21022f195bab..e0733050ae71 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -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); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 256d5524445c..fcf05bf677b8 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -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 diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 24ade5f68e02..8d87897d7eb7 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -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)) -- cgit v1.2.3 From 6eb6edf04acd09e3cea09456913e8da59323b89e Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 22 Sep 2005 10:34:15 +0000 Subject: [PATCH] ieee80211: in-tree driver updates to sync with latest ieee80211 series Changed crypto method from requiring a struct ieee80211_device reference to the init handler. Instead we now have a get/set flags method for each crypto component. Setting of TKIP countermeasures can now be done via set_flags(IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) Signed-off-by: James Ketrenos Signed-off-by: Jeff Garzik --- include/net/ieee80211.h | 1 - include/net/ieee80211_crypt.h | 10 +++++++++- net/ieee80211/ieee80211_crypt.c | 3 +-- net/ieee80211/ieee80211_crypt_ccmp.c | 2 +- net/ieee80211/ieee80211_crypt_tkip.c | 34 ++++++++++++++++++++++++---------- net/ieee80211/ieee80211_crypt_wep.c | 2 +- net/ieee80211/ieee80211_module.c | 1 - net/ieee80211/ieee80211_wx.c | 4 ++-- 8 files changed, 38 insertions(+), 19 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4a381a074fdd..4851756202c5 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -876,7 +876,6 @@ struct ieee80211_device { /* WPA data */ int wpa_enabled; int drop_unencrypted; - int tkip_countermeasures; int privacy_invoked; size_t wpa_ie_len; u8 *wpa_ie; diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index daf3b2c6b038..0c9d859d912e 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -25,13 +25,17 @@ #include +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1<<0), +}; + struct ieee80211_crypto_ops { const char *name; /* 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) (struct ieee80211_device * ieee, int keyidx); + void *(*init) (int keyidx); /* deinitialize crypto context and free allocated private data */ void (*deinit) (void *priv); @@ -60,6 +64,10 @@ struct ieee80211_crypto_ops { * statistics */ char *(*print_stats) (char *p, void *priv); + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags)(void *priv); + unsigned long (*set_flags)(unsigned long flags, void *priv); + /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and * extra_postfix_len; encrypt need not use all this space, but diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index e26bcc918032..f3b6aa3be638 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -202,8 +202,7 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) return NULL; } -static void *ieee80211_crypt_null_init(struct ieee80211_device *ieee, - int keyidx) +static void *ieee80211_crypt_null_init(int keyidx) { return (void *)1; } diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 081d8575dbb1..05a853c13012 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, crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); } -static void *ieee80211_ccmp_init(struct ieee80211_device *ieee, int key_idx) +static void *ieee80211_ccmp_init(int key_idx) { struct ieee80211_ccmp_data *priv; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index e0733050ae71..2e34f29b7956 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -60,10 +60,24 @@ struct ieee80211_tkip_data { /* scratch buffers for virt_to_page() (crypto API) */ u8 rx_hdr[16], tx_hdr[16]; - struct ieee80211_device *ieee; + unsigned long flags; }; -static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx) +static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; + unsigned long old_flags = _priv->flags; + _priv->flags = flags; + return old_flags; +} + +static unsigned long ieee80211_tkip_get_flags(void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; + return _priv->flags; +} + +static void *ieee80211_tkip_init(int key_idx) { struct ieee80211_tkip_data *priv; @@ -72,8 +86,6 @@ static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx) goto fail; memset(priv, 0, sizeof(*priv)); - priv->ieee = ieee; - priv->key_idx = key_idx; priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); @@ -315,13 +327,13 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 *pos; struct scatterlist sg; - if (tkey->ieee->tkip_countermeasures) { + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + printk(KERN_DEBUG "TKIP countermeasures: dropped " "TX packet to " MAC_FMT "\n", - tkey->ieee->dev->name, MAC_ARG(hdr->addr1)); + MAC_ARG(hdr->addr1)); } return -1; } @@ -366,11 +378,11 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) hdr = (struct ieee80211_hdr_4addr *)skb->data; - if (tkey->ieee->tkip_countermeasures) { + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + printk(KERN_DEBUG "TKIP countermeasures: dropped " "received packet from " MAC_FMT "\n", - tkey->ieee->dev->name, MAC_ARG(hdr->addr2)); + MAC_ARG(hdr->addr2)); } return -1; } @@ -694,6 +706,8 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ .extra_mpdu_postfix_len = 4, /* ICV */ .extra_msdu_postfix_len = 8, /* MIC */ + .get_flags = ieee80211_tkip_get_flags, + .set_flags = ieee80211_tkip_set_flags, .owner = THIS_MODULE, }; diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 2aaeac1e02d7..7c08ed2f2628 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -37,7 +37,7 @@ struct prism2_wep_data { struct crypto_tfm *tfm; }; -static void *prism2_wep_init(struct ieee80211_device *ieee, int keyidx) +static void *prism2_wep_init(int keyidx) { struct prism2_wep_data *priv; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 319312564167..5714692e82b4 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -155,7 +155,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) spin_lock_init(&ieee->lock); ieee->wpa_enabled = 0; - ieee->tkip_countermeasures = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 3dd2bbae0c24..ee7a70a13250 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -355,7 +355,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(ieee, key); + new_crypt->priv = new_crypt->ops->init(key); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); @@ -598,7 +598,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); new_crypt->ops = ops; if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(ieee, idx); + new_crypt->priv = new_crypt->ops->init(idx); if (new_crypt->priv == NULL) { kfree(new_crypt); ret = -EINVAL; -- cgit v1.2.3 From ff0037b259e8b47843176142131844bc80fd2887 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Mon, 3 Oct 2005 10:23:42 -0500 Subject: Lindent and trailing whitespace script executed ieee80211 subsystem Signed-off-by: James Ketrenos --- include/net/ieee80211_crypt.h | 6 +++--- net/ieee80211/ieee80211_rx.c | 35 +++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'include/net/ieee80211_crypt.h') diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 0c9d859d912e..0a1c2d82ca4b 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -26,7 +26,7 @@ #include enum { - IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1<<0), + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), }; struct ieee80211_crypto_ops { @@ -65,8 +65,8 @@ struct ieee80211_crypto_ops { char *(*print_stats) (char *p, void *priv); /* Crypto specific flag get/set for configuration settings */ - unsigned long (*get_flags)(void *priv); - unsigned long (*set_flags)(unsigned long flags, void *priv); + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); /* maximum number of bytes added by encryption; encrypt buf is * allocated with extra_prefix_len bytes, copy of in_buf, and diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 8d87d66c2a34..6b005cb0caa0 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -917,8 +917,9 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element return rc; } -static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, - u16 length, struct ieee80211_network *network) +static int ieee80211_parse_info_param(struct ieee80211_info_element + *info_element, u16 length, + struct ieee80211_network *network) { u8 i; #ifdef CONFIG_IEEE80211_DEBUG @@ -929,11 +930,11 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen while (length >= sizeof(*info_element)) { if (sizeof(*info_element) + info_element->len > length) { IEEE80211_DEBUG_MGMT("Info elem: parse failed: " - "info_element->len + 2 > left : " - "info_element->len+2=%zd left=%d, id=%d.\n", - info_element->len + - sizeof(*info_element), - length, info_element->id); + "info_element->len + 2 > left : " + "info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(*info_element), + length, info_element->id); return 1; } @@ -954,7 +955,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen IW_ESSID_MAX_SIZE - network->ssid_len); IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); + network->ssid, network->ssid_len); break; case MFIE_TYPE_RATES: @@ -1074,17 +1075,20 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_elemen break; case MFIE_TYPE_QOS_PARAMETER: - printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n"); + printk(KERN_ERR + "QoS Error need to parse QOS_PARAMETER IE\n"); break; default: IEEE80211_DEBUG_MGMT("unsupported IE %d\n", - info_element->id); + info_element->id); break; } length -= sizeof(*info_element) + info_element->len; - info_element = (struct ieee80211_info_element *) &info_element->data[info_element->len]; + info_element = + (struct ieee80211_info_element *)&info_element-> + data[info_element->len]; } return 0; @@ -1112,7 +1116,8 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->rates_len = network->rates_ex_len = 0; network->last_associate = 0; network->ssid_len = 0; - network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; + network->erp_value = + (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; if (stats->freq == IEEE80211_52GHZ_BAND) { /* for A band (No DS info) */ @@ -1123,7 +1128,8 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if(ieee80211_parse_info_param(frame->info_element, stats->len - sizeof(*frame), network)) + if (ieee80211_parse_info_param + (frame->info_element, stats->len - sizeof(*frame), network)) return 1; network->mode = 0; @@ -1185,7 +1191,8 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if(ieee80211_parse_info_param(beacon->info_element, stats->len - sizeof(*beacon), network)) + if (ieee80211_parse_info_param + (beacon->info_element, stats->len - sizeof(*beacon), network)) return 1; network->mode = 0; -- cgit v1.2.3