Commit 62fe7e37 authored by Jouni Malinen's avatar Jouni Malinen Committed by Jeff Garzik

[PATCH] hostap: Replace crypto code with net/ieee80211 version

Replace Host AP version of WEP, TKIP, CCMP implementation with
net/ieee80211 that has more or less identical implementation (since
it is based on the Host AP implementation). Remove Host AP specific
implementation and modules from drivers/net/wireless/hostap.
Signed-off-by: default avatarJouni Malinen <jkmaline@cc.hut.fi>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent ebed67d2
...@@ -7,9 +7,6 @@ config HOSTAP ...@@ -7,9 +7,6 @@ config HOSTAP
Host AP mode that allows the card to act as an IEEE 802.11 Host AP mode that allows the card to act as an IEEE 802.11
access point. access point.
In addition, this includes generic IEEE 802.11 code, e.g., for
WEP/TKIP/CCMP encryption that can be shared with other drivers.
See <http://hostap.epitest.fi/> for more information about the See <http://hostap.epitest.fi/> for more information about the
Host AP driver configuration and tools. This site includes Host AP driver configuration and tools. This site includes
information and tools (hostapd and wpa_supplicant) for WPA/WPA2 information and tools (hostapd and wpa_supplicant) for WPA/WPA2
...@@ -22,36 +19,6 @@ config HOSTAP ...@@ -22,36 +19,6 @@ config HOSTAP
The driver can be compiled as a module and it will be called The driver can be compiled as a module and it will be called
"hostap.ko". "hostap.ko".
config HOSTAP_WEP
tristate "IEEE 802.11 WEP encryption"
depends on HOSTAP
select CRYPTO
---help---
Software implementation of IEEE 802.11 WEP encryption.
This can be compiled as a modules and it will be called
"hostap_crypt_wep.ko".
config HOSTAP_TKIP
tristate "IEEE 802.11 TKIP encryption"
depends on HOSTAP
select CRYPTO
---help---
Software implementation of IEEE 802.11 TKIP encryption.
This can be compiled as a modules and it will be called
"hostap_crypt_tkip.ko".
config HOSTAP_CCMP
tristate "IEEE 802.11 CCMP encryption"
depends on HOSTAP
select CRYPTO
---help---
Software implementation of IEEE 802.11 CCMP encryption.
This can be compiled as a modules and it will be called
"hostap_crypt_ccmp.ko".
config HOSTAP_FIRMWARE config HOSTAP_FIRMWARE
bool "Support downloading firmware images with Host AP driver" bool "Support downloading firmware images with Host AP driver"
depends on HOSTAP depends on HOSTAP
......
obj-$(CONFIG_HOSTAP) += hostap.o obj-$(CONFIG_HOSTAP) += hostap.o
obj-$(CONFIG_HOSTAP_WEP) += hostap_crypt_wep.o
obj-$(CONFIG_HOSTAP_TKIP) += hostap_crypt_tkip.o
obj-$(CONFIG_HOSTAP_CCMP) += hostap_crypt_ccmp.o
obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi> * <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -34,16 +34,12 @@ ...@@ -34,16 +34,12 @@
#include "hostap_80211.h" #include "hostap_80211.h"
#include "hostap_ap.h" #include "hostap_ap.h"
#include "hostap.h" #include "hostap.h"
#include "hostap_crypt.h"
MODULE_AUTHOR("Jouni Malinen"); MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP common routines"); MODULE_DESCRIPTION("Host AP common routines");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(PRISM2_VERSION); MODULE_VERSION(PRISM2_VERSION);
/* Old hostap_crypt module is now part of hostap module. */
#include "hostap_crypt.c"
#define TX_TIMEOUT (2 * HZ) #define TX_TIMEOUT (2 * HZ)
#define PRISM2_MAX_FRAME_SIZE 2304 #define PRISM2_MAX_FRAME_SIZE 2304
...@@ -66,7 +62,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); ...@@ -66,7 +62,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer);
static int prism2_hostapd(struct ap_data *ap, static int prism2_hostapd(struct ap_data *ap,
struct prism2_hostapd_param *param); struct prism2_hostapd_param *param);
static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
struct prism2_crypt_data ***crypt); struct ieee80211_crypt_data ***crypt);
static void ap_control_kickall(struct ap_data *ap); static void ap_control_kickall(struct ap_data *ap);
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,
...@@ -1156,8 +1152,6 @@ struct proc_dir_entry *hostap_proc; ...@@ -1156,8 +1152,6 @@ struct proc_dir_entry *hostap_proc;
static int __init hostap_init(void) static int __init hostap_init(void)
{ {
hostap_crypto_init();
if (proc_net != NULL) { if (proc_net != NULL) {
hostap_proc = proc_mkdir("hostap", proc_net); hostap_proc = proc_mkdir("hostap", proc_net);
if (!hostap_proc) if (!hostap_proc)
...@@ -1176,8 +1170,6 @@ static void __exit hostap_exit(void) ...@@ -1176,8 +1170,6 @@ static void __exit hostap_exit(void)
hostap_proc = NULL; hostap_proc = NULL;
remove_proc_entry("hostap", proc_net); remove_proc_entry("hostap", proc_net);
} }
hostap_crypto_deinit();
} }
......
...@@ -101,7 +101,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); ...@@ -101,7 +101,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev);
int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
struct prism2_crypt_data *crypt); struct ieee80211_crypt_data *crypt);
int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
#endif /* HOSTAP_80211_H */ #endif /* HOSTAP_80211_H */
...@@ -613,7 +613,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) ...@@ -613,7 +613,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
/* Called only as a tasklet (software IRQ) */ /* Called only as a tasklet (software IRQ) */
static inline int static inline int
hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
struct prism2_crypt_data *crypt) struct ieee80211_crypt_data *crypt)
{ {
struct hostap_ieee80211_hdr *hdr; struct hostap_ieee80211_hdr *hdr;
int res, hdrlen; int res, hdrlen;
...@@ -652,7 +652,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, ...@@ -652,7 +652,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
/* Called only as a tasklet (software IRQ) */ /* Called only as a tasklet (software IRQ) */
static inline int static inline int
hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
int keyidx, struct prism2_crypt_data *crypt) int keyidx, struct ieee80211_crypt_data *crypt)
{ {
struct hostap_ieee80211_hdr *hdr; struct hostap_ieee80211_hdr *hdr;
int res, hdrlen; int res, hdrlen;
...@@ -698,7 +698,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, ...@@ -698,7 +698,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
int from_assoc_ap = 0; int from_assoc_ap = 0;
u8 dst[ETH_ALEN]; u8 dst[ETH_ALEN];
u8 src[ETH_ALEN]; u8 src[ETH_ALEN];
struct prism2_crypt_data *crypt = NULL; struct ieee80211_crypt_data *crypt = NULL;
void *sta = NULL; void *sta = NULL;
int keyidx = 0; int keyidx = 0;
......
...@@ -284,7 +284,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -284,7 +284,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Called only from software IRQ */ /* Called only from software IRQ */
struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
struct prism2_crypt_data *crypt) struct ieee80211_crypt_data *crypt)
{ {
struct hostap_interface *iface; struct hostap_interface *iface;
local_info_t *local; local_info_t *local;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Intersil Prism2 driver with Host AP (software access point) support * Intersil Prism2 driver with Host AP (software access point) support
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi> * <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
* *
* This file is to be included into hostap.c when S/W AP functionality is * This file is to be included into hostap.c when S/W AP functionality is
* compiled. * compiled.
...@@ -1206,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta) ...@@ -1206,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta)
static void ap_crypt_init(struct ap_data *ap) static void ap_crypt_init(struct ap_data *ap)
{ {
ap->crypt = hostap_get_crypto_ops("WEP"); ap->crypt = ieee80211_get_crypto_ops("WEP");
if (ap->crypt) { if (ap->crypt) {
if (ap->crypt->init) { if (ap->crypt->init) {
...@@ -1224,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap) ...@@ -1224,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap)
if (ap->crypt == NULL) { if (ap->crypt == NULL) {
printk(KERN_WARNING "AP could not initialize WEP: load module " printk(KERN_WARNING "AP could not initialize WEP: load module "
"hostap_crypt_wep.o\n"); "ieee80211_crypt_wep.ko\n");
} }
} }
...@@ -1293,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, ...@@ -1293,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
u16 auth_alg, auth_transaction, status_code, *pos; u16 auth_alg, auth_transaction, status_code, *pos;
u16 resp = WLAN_STATUS_SUCCESS, fc; u16 resp = WLAN_STATUS_SUCCESS, fc;
struct sta_info *sta = NULL; struct sta_info *sta = NULL;
struct prism2_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
char *txt = ""; char *txt = "";
len = skb->len - IEEE80211_MGMT_HDR_LEN; len = skb->len - IEEE80211_MGMT_HDR_LEN;
...@@ -3058,7 +3058,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, ...@@ -3058,7 +3058,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
/* Called only as a tasklet (software IRQ) */ /* Called only as a tasklet (software IRQ) */
int hostap_handle_sta_crypto(local_info_t *local, int hostap_handle_sta_crypto(local_info_t *local,
struct hostap_ieee80211_hdr *hdr, struct hostap_ieee80211_hdr *hdr,
struct prism2_crypt_data **crypt, void **sta_ptr) struct ieee80211_crypt_data **crypt,
void **sta_ptr)
{ {
struct sta_info *sta; struct sta_info *sta;
...@@ -3206,7 +3207,7 @@ void hostap_update_rates(local_info_t *local) ...@@ -3206,7 +3207,7 @@ void hostap_update_rates(local_info_t *local)
static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
struct prism2_crypt_data ***crypt) struct ieee80211_crypt_data ***crypt)
{ {
struct sta_info *sta; struct sta_info *sta;
......
...@@ -81,7 +81,7 @@ struct sta_info { ...@@ -81,7 +81,7 @@ struct sta_info {
u32 tx_since_last_failure; u32 tx_since_last_failure;
u32 tx_consecutive_exc; u32 tx_consecutive_exc;
struct prism2_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
int ap; /* whether this station is an AP */ int ap; /* whether this station is an AP */
...@@ -216,7 +216,7 @@ struct ap_data { ...@@ -216,7 +216,7 @@ struct ap_data {
/* WEP operations for generating challenges to be used with shared key /* WEP operations for generating challenges to be used with shared key
* authentication */ * authentication */
struct hostap_crypto_ops *crypt; struct ieee80211_crypto_ops *crypt;
void *crypt_priv; void *crypt_priv;
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
}; };
...@@ -236,7 +236,7 @@ typedef enum { ...@@ -236,7 +236,7 @@ typedef enum {
struct hostap_tx_data { struct hostap_tx_data {
struct sk_buff *skb; struct sk_buff *skb;
int host_encrypt; int host_encrypt;
struct prism2_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
void *sta_ptr; void *sta_ptr;
}; };
ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
...@@ -253,7 +253,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, ...@@ -253,7 +253,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
int wds); int wds);
int hostap_handle_sta_crypto(local_info_t *local, int hostap_handle_sta_crypto(local_info_t *local,
struct hostap_ieee80211_hdr *hdr, struct hostap_ieee80211_hdr *hdr,
struct prism2_crypt_data **crypt, void **sta_ptr); struct ieee80211_crypt_data **crypt,
void **sta_ptr);
int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
......
/*
* Host AP crypto routines
*
* Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
*/
struct hostap_crypto_alg {
struct list_head list;
struct hostap_crypto_ops *ops;
};
struct hostap_crypto {
struct list_head algs;
spinlock_t lock;
};
static struct hostap_crypto *hcrypt;
int hostap_register_crypto_ops(struct hostap_crypto_ops *ops)
{
unsigned long flags;
struct hostap_crypto_alg *alg;
if (hcrypt == NULL)
return -1;
alg = (struct hostap_crypto_alg *) kmalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL)
return -ENOMEM;
memset(alg, 0, sizeof(*alg));
alg->ops = ops;
spin_lock_irqsave(&hcrypt->lock, flags);
list_add(&alg->list, &hcrypt->algs);
spin_unlock_irqrestore(&hcrypt->lock, flags);
printk(KERN_DEBUG "hostap_crypt: registered algorithm '%s'\n",
ops->name);
return 0;
}
int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops)
{
unsigned long flags;
struct list_head *ptr;
struct hostap_crypto_alg *del_alg = NULL;
if (hcrypt == NULL)
return -1;
spin_lock_irqsave(&hcrypt->lock, flags);
for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
struct hostap_crypto_alg *alg =
(struct hostap_crypto_alg *) ptr;
if (alg->ops == ops) {
list_del(&alg->list);
del_alg = alg;
break;
}
}
spin_unlock_irqrestore(&hcrypt->lock, flags);
if (del_alg) {
printk(KERN_DEBUG "hostap_crypt: unregistered algorithm "
"'%s'\n", ops->name);
kfree(del_alg);
}
return del_alg ? 0 : -1;
}
struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name)
{
unsigned long flags;
struct list_head *ptr;
struct hostap_crypto_alg *found_alg = NULL;
if (hcrypt == NULL)
return NULL;
spin_lock_irqsave(&hcrypt->lock, flags);
for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) {
struct hostap_crypto_alg *alg =
(struct hostap_crypto_alg *) ptr;
if (strcmp(alg->ops->name, name) == 0) {
found_alg = alg;
break;
}
}
spin_unlock_irqrestore(&hcrypt->lock, flags);
if (found_alg)
return found_alg->ops;
else
return NULL;
}
static void * hostap_crypt_null_init(int keyidx) { return (void *) 1; }
static void hostap_crypt_null_deinit(void *priv) {}
static struct hostap_crypto_ops hostap_crypt_null = {
.name = "NULL",
.init = hostap_crypt_null_init,
.deinit = hostap_crypt_null_deinit,
.encrypt_mpdu = NULL,
.decrypt_mpdu = NULL,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
.set_key = NULL,
.get_key = NULL,
.extra_prefix_len = 0,
.extra_postfix_len = 0
};
static int __init hostap_crypto_init(void)
{
hcrypt = (struct hostap_crypto *) kmalloc(sizeof(*hcrypt), GFP_KERNEL);
if (hcrypt == NULL)
return -ENOMEM;
memset(hcrypt, 0, sizeof(*hcrypt));
INIT_LIST_HEAD(&hcrypt->algs);
spin_lock_init(&hcrypt->lock);
(void) hostap_register_crypto_ops(&hostap_crypt_null);
return 0;
}
static void __exit hostap_crypto_deinit(void)
{
struct list_head *ptr, *n;
if (hcrypt == NULL)
return;
for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
ptr = n, n = ptr->next) {
struct hostap_crypto_alg *alg =
(struct hostap_crypto_alg *) ptr;
list_del(ptr);
printk(KERN_DEBUG "hostap_crypt: unregistered algorithm "
"'%s' (deinit)\n", alg->ops->name);
kfree(alg);
}
kfree(hcrypt);
}
EXPORT_SYMBOL(hostap_register_crypto_ops);
EXPORT_SYMBOL(hostap_unregister_crypto_ops);
EXPORT_SYMBOL(hostap_get_crypto_ops);
#ifndef PRISM2_CRYPT_H
#define PRISM2_CRYPT_H
struct hostap_crypto_ops {
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)(int keyidx);
/* deinitialize crypto context and free allocated private data */
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
* decrypt_msdu. skb must have enough head and tail room for the
* 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);
/* 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 (*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);
/* 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
* the result must start at the beginning of the buffer and correct
* length must be returned */
int extra_prefix_len, extra_postfix_len;
};
int hostap_register_crypto_ops(struct hostap_crypto_ops *ops);
int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops);
struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name);
#endif /* PRISM2_CRYPT_H */
This diff is collapsed.
This diff is collapsed.
/*
* Host AP crypt: host-based WEP encryption implementation for Host AP driver
*
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <asm/string.h>
#include "hostap_crypt.h"
#include "hostap_config.h"
#ifndef CONFIG_CRYPTO
#error CONFIG_CRYPTO is required to build this module.
#endif
#include <linux/crypto.h>
#include <asm/scatterlist.h>
#include <linux/crc32.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: WEP");
MODULE_LICENSE("GPL");
MODULE_VERSION(PRISM2_VERSION);
struct prism2_wep_data {
u32 iv;
#define WEP_KEY_LEN 13
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
struct crypto_tfm *tfm;
};
static void * prism2_wep_init(int keyidx)
{
struct prism2_wep_data *priv;
if (!try_module_get(THIS_MODULE))
return NULL;
priv = (struct prism2_wep_data *) kmalloc(sizeof(*priv), GFP_ATOMIC);
if (priv == NULL)
goto fail;
memset(priv, 0, sizeof(*priv));
priv->key_idx = keyidx;
priv->tfm = crypto_alloc_tfm("arc4", 0);
if (priv->tfm == NULL) {
printk(KERN_DEBUG "hostap_crypt_wep: could not allocate "
"crypto API arc4\n");
goto fail;
}
/* start WEP IV from a random value */
get_random_bytes(&priv->iv, 4);
return priv;
fail:
if (priv) {
if (priv->tfm)
crypto_free_tfm(priv->tfm);
kfree(priv);
}
module_put(THIS_MODULE);
return NULL;
}
static void prism2_wep_deinit(void *priv)
{
struct prism2_wep_data *_priv = priv;
if (_priv && _priv->tfm)
crypto_free_tfm(_priv->tfm);
kfree(priv);
module_put(THIS_MODULE);
}
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
* for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
* so the payload length increases with 8 bytes.
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
u32 crc, klen, len;
u8 key[WEP_KEY_LEN + 3];
u8 *pos, *icv;
struct scatterlist sg;
if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
skb->len < hdr_len)
return -1;
len = skb->len - hdr_len;
pos = skb_push(skb, 4);
memmove(pos, pos + 4, hdr_len);
pos += hdr_len;
klen = 3 + wep->key_len;
wep->iv++;
/* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
* scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
* can be used to speedup attacks, so avoid using them. */
if ((wep->iv & 0xff00) == 0xff00) {
u8 B = (wep->iv >> 16) & 0xff;
if (B >= 3 && B < klen)
wep->iv += 0x0100;
}
/* Prepend 24-bit IV to RC4 key and TX frame */
*pos++ = key[0] = (wep->iv >> 16) & 0xff;
*pos++ = key[1] = (wep->iv >> 8) & 0xff;
*pos++ = key[2] = wep->iv & 0xff;
*pos++ = wep->key_idx << 6;
/* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len);
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
icv = skb_put(skb, 4);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
crypto_cipher_setkey(wep->tfm, key, klen);
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = len + 4;
crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
return 0;
}
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
* the frame: IV (4 bytes), encrypted payload (including SNAP header),
* ICV (4 bytes). len includes both IV and ICV.
*
* Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
* failure. If frame is OK, IV and ICV will be removed.
*/
static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
struct prism2_wep_data *wep = priv;
u32 crc, klen, plen;
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos, icv[4];
struct scatterlist sg;
if (skb->len < hdr_len + 8)
return -1;
pos = skb->data + hdr_len;
key[0] = *pos++;
key[1] = *pos++;
key[2] = *pos++;
keyidx = *pos++ >> 6;
if (keyidx != wep->key_idx)
return -1;
klen = 3 + wep->key_len;
/* Copy rest of the WEP key (the secret part) */
memcpy(key + 3, wep->key, wep->key_len);
/* Apply RC4 to data and compute CRC32 over decrypted data */
plen = skb->len - hdr_len - 8;
crypto_cipher_setkey(wep->tfm, key, klen);
sg.page = virt_to_page(pos);
sg.offset = offset_in_page(pos);
sg.length = plen + 4;
crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
crc = ~crc32_le(~0, pos, plen);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
if (memcmp(icv, pos + plen, 4) != 0) {
/* ICV mismatch - drop frame */
return -2;
}
/* Remove IV and ICV */
memmove(skb->data + 4, skb->data, hdr_len);
skb_pull(skb, 4);
skb_trim(skb, skb->len - 4);
return 0;
}
static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
if (len < 0 || len > WEP_KEY_LEN)
return -1;
memcpy(wep->key, key, len);
wep->key_len = len;
return 0;
}
static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
if (len < wep->key_len)
return -1;
memcpy(key, wep->key, wep->key_len);
return wep->key_len;
}
static char * prism2_wep_print_stats(char *p, void *priv)
{
struct prism2_wep_data *wep = priv;
p += sprintf(p, "key[%d] alg=WEP len=%d\n",
wep->key_idx, wep->key_len);
return p;
}
static struct hostap_crypto_ops hostap_crypt_wep = {
.name = "WEP",
.init = prism2_wep_init,
.deinit = prism2_wep_deinit,
.encrypt_mpdu = prism2_wep_encrypt,
.decrypt_mpdu = prism2_wep_decrypt,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
.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 */
};
static int __init hostap_crypto_wep_init(void)
{
if (hostap_register_crypto_ops(&hostap_crypt_wep) < 0)
return -1;
return 0;
}
static void __exit hostap_crypto_wep_exit(void)
{
hostap_unregister_crypto_ops(&hostap_crypt_wep);
}
module_init(hostap_crypto_wep_init);
module_exit(hostap_crypto_wep_exit);
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <jkmaline@cc.hut.fi> * <jkmaline@cc.hut.fi>
* Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -2967,11 +2967,11 @@ static void prism2_check_sta_fw_version(local_info_t *local) ...@@ -2967,11 +2967,11 @@ static void prism2_check_sta_fw_version(local_info_t *local)
static void prism2_crypt_deinit_entries(local_info_t *local, int force) static void prism2_crypt_deinit_entries(local_info_t *local, int force)
{ {
struct list_head *ptr, *n; struct list_head *ptr, *n;
struct prism2_crypt_data *entry; struct ieee80211_crypt_data *entry;
for (ptr = local->crypt_deinit_list.next, n = ptr->next; for (ptr = local->crypt_deinit_list.next, n = ptr->next;
ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) {
entry = list_entry(ptr, struct prism2_crypt_data, list); entry = list_entry(ptr, struct ieee80211_crypt_data, list);
if (atomic_read(&entry->refcnt) != 0 && !force) if (atomic_read(&entry->refcnt) != 0 && !force)
continue; continue;
...@@ -3531,7 +3531,7 @@ static void prism2_free_local_data(struct net_device *dev) ...@@ -3531,7 +3531,7 @@ static void prism2_free_local_data(struct net_device *dev)
prism2_callback(local, PRISM2_CALLBACK_DISABLE); prism2_callback(local, PRISM2_CALLBACK_DISABLE);
for (i = 0; i < WEP_KEYS; i++) { for (i = 0; i < WEP_KEYS; i++) {
struct prism2_crypt_data *crypt = local->crypt[i]; struct ieee80211_crypt_data *crypt = local->crypt[i];
if (crypt) { if (crypt) {
if (crypt->ops) if (crypt->ops)
crypt->ops->deinit(crypt->priv); crypt->ops->deinit(crypt->priv);
......
...@@ -115,9 +115,9 @@ static int prism2_get_name(struct net_device *dev, ...@@ -115,9 +115,9 @@ static int prism2_get_name(struct net_device *dev,
static void prism2_crypt_delayed_deinit(local_info_t *local, static void prism2_crypt_delayed_deinit(local_info_t *local,
struct prism2_crypt_data **crypt) struct ieee80211_crypt_data **crypt)
{ {
struct prism2_crypt_data *tmp; struct ieee80211_crypt_data *tmp;
unsigned long flags; unsigned long flags;
tmp = *crypt; tmp = *crypt;
...@@ -147,7 +147,7 @@ static int prism2_ioctl_siwencode(struct net_device *dev, ...@@ -147,7 +147,7 @@ static int prism2_ioctl_siwencode(struct net_device *dev,
struct hostap_interface *iface; struct hostap_interface *iface;
local_info_t *local; local_info_t *local;
int i; int i;
struct prism2_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
iface = netdev_priv(dev); iface = netdev_priv(dev);
local = iface->local; local = iface->local;
...@@ -175,18 +175,19 @@ static int prism2_ioctl_siwencode(struct net_device *dev, ...@@ -175,18 +175,19 @@ static int prism2_ioctl_siwencode(struct net_device *dev,
} }
if (*crypt == NULL) { if (*crypt == NULL) {
struct prism2_crypt_data *new_crypt; struct ieee80211_crypt_data *new_crypt;
/* take WEP into use */ /* take WEP into use */
new_crypt = (struct prism2_crypt_data *) new_crypt = (struct ieee80211_crypt_data *)
kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); kmalloc(sizeof(struct ieee80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL) if (new_crypt == NULL)
return -ENOMEM; return -ENOMEM;
memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = hostap_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
if (!new_crypt->ops) { if (!new_crypt->ops) {
request_module("hostap_crypt_wep"); request_module("ieee80211_crypt_wep");
new_crypt->ops = hostap_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
} }
if (new_crypt->ops) if (new_crypt->ops)
new_crypt->priv = new_crypt->ops->init(i); new_crypt->priv = new_crypt->ops->init(i);
...@@ -251,7 +252,7 @@ static int prism2_ioctl_giwencode(struct net_device *dev, ...@@ -251,7 +252,7 @@ static int prism2_ioctl_giwencode(struct net_device *dev,
local_info_t *local; local_info_t *local;
int i, len; int i, len;
u16 val; u16 val;
struct prism2_crypt_data *crypt; struct ieee80211_crypt_data *crypt;
iface = netdev_priv(dev); iface = netdev_priv(dev);
local = iface->local; local = iface->local;
...@@ -3259,8 +3260,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, ...@@ -3259,8 +3260,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
local_info_t *local = iface->local; local_info_t *local = iface->local;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
int i, ret = 0; int i, ret = 0;
struct hostap_crypto_ops *ops; struct ieee80211_crypto_ops *ops;
struct prism2_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
void *sta_ptr; void *sta_ptr;
u8 *addr; u8 *addr;
const char *alg, *module; const char *alg, *module;
...@@ -3308,15 +3309,15 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, ...@@ -3308,15 +3309,15 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
switch (ext->alg) { switch (ext->alg) {
case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_WEP:
alg = "WEP"; alg = "WEP";
module = "hostap_crypt_wep"; module = "ieee80211_crypt_wep";
break; break;
case IW_ENCODE_ALG_TKIP: case IW_ENCODE_ALG_TKIP:
alg = "TKIP"; alg = "TKIP";
module = "hostap_crypt_tkip"; module = "ieee80211_crypt_tkip";
break; break;
case IW_ENCODE_ALG_CCMP: case IW_ENCODE_ALG_CCMP:
alg = "CCMP"; alg = "CCMP";
module = "hostap_crypt_ccmp"; module = "ieee80211_crypt_ccmp";
break; break;
default: default:
printk(KERN_DEBUG "%s: unsupported algorithm %d\n", printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
...@@ -3325,10 +3326,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, ...@@ -3325,10 +3326,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
goto done; goto done;
} }
ops = hostap_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) { if (ops == NULL) {
request_module(module); request_module(module);
ops = hostap_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
} }
if (ops == NULL) { if (ops == NULL) {
printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
...@@ -3347,17 +3348,18 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, ...@@ -3347,17 +3348,18 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
} }
if (*crypt == NULL || (*crypt)->ops != ops) { if (*crypt == NULL || (*crypt)->ops != ops) {
struct prism2_crypt_data *new_crypt; struct ieee80211_crypt_data *new_crypt;
prism2_crypt_delayed_deinit(local, crypt); prism2_crypt_delayed_deinit(local, crypt);
new_crypt = (struct prism2_crypt_data *) new_crypt = (struct ieee80211_crypt_data *)
kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); kmalloc(sizeof(struct ieee80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL) { if (new_crypt == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops; new_crypt->ops = ops;
new_crypt->priv = new_crypt->ops->init(i); new_crypt->priv = new_crypt->ops->init(i);
if (new_crypt->priv == NULL) { if (new_crypt->priv == NULL) {
...@@ -3436,7 +3438,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, ...@@ -3436,7 +3438,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
{ {
struct hostap_interface *iface = dev->priv; struct hostap_interface *iface = dev->priv;
local_info_t *local = iface->local; local_info_t *local = iface->local;
struct prism2_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
void *sta_ptr; void *sta_ptr;
int max_key_len, i; int max_key_len, i;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
...@@ -3505,8 +3507,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local, ...@@ -3505,8 +3507,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
int param_len) int param_len)
{ {
int ret = 0; int ret = 0;
struct hostap_crypto_ops *ops; struct ieee80211_crypto_ops *ops;
struct prism2_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
void *sta_ptr; void *sta_ptr;
param->u.crypt.err = 0; param->u.crypt.err = 0;
...@@ -3544,16 +3546,16 @@ static int prism2_ioctl_set_encryption(local_info_t *local, ...@@ -3544,16 +3546,16 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
goto done; goto done;
} }
ops = hostap_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
request_module("hostap_crypt_wep"); request_module("ieee80211_crypt_wep");
ops = hostap_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
request_module("hostap_crypt_tkip"); request_module("ieee80211_crypt_tkip");
ops = hostap_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
request_module("hostap_crypt_ccmp"); request_module("ieee80211_crypt_ccmp");
ops = hostap_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} }
if (ops == NULL) { if (ops == NULL) {
printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
...@@ -3568,17 +3570,18 @@ static int prism2_ioctl_set_encryption(local_info_t *local, ...@@ -3568,17 +3570,18 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
local->host_decrypt = local->host_encrypt = 1; local->host_decrypt = local->host_encrypt = 1;
if (*crypt == NULL || (*crypt)->ops != ops) { if (*crypt == NULL || (*crypt)->ops != ops) {
struct prism2_crypt_data *new_crypt; struct ieee80211_crypt_data *new_crypt;
prism2_crypt_delayed_deinit(local, crypt); prism2_crypt_delayed_deinit(local, crypt);
new_crypt = (struct prism2_crypt_data *) new_crypt = (struct ieee80211_crypt_data *)
kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); kmalloc(sizeof(struct ieee80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL) { if (new_crypt == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops; new_crypt->ops = ops;
new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
if (new_crypt->priv == NULL) { if (new_crypt->priv == NULL) {
...@@ -3642,7 +3645,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local, ...@@ -3642,7 +3645,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local,
struct prism2_hostapd_param *param, struct prism2_hostapd_param *param,
int param_len) int param_len)
{ {
struct prism2_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
void *sta_ptr; void *sta_ptr;
int max_key_len; int max_key_len;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define HOSTAP_WLAN_H #define HOSTAP_WLAN_H
#include "hostap_config.h" #include "hostap_config.h"
#include "hostap_crypt.h"
#include "hostap_common.h" #include "hostap_common.h"
#define MAX_PARM_DEVICES 8 #define MAX_PARM_DEVICES 8
...@@ -534,13 +533,6 @@ struct prism2_frag_entry { ...@@ -534,13 +533,6 @@ struct prism2_frag_entry {
}; };
struct prism2_crypt_data {
struct list_head list; /* delayed deletion list */
struct hostap_crypto_ops *ops;
void *priv;
atomic_t refcnt;
};
struct hostap_cmd_queue { struct hostap_cmd_queue {
struct list_head list; struct list_head list;
wait_queue_head_t compl; wait_queue_head_t compl;
...@@ -765,7 +757,7 @@ struct local_info { ...@@ -765,7 +757,7 @@ struct local_info {
#define WEP_KEYS 4 #define WEP_KEYS 4
#define WEP_KEY_LEN 13 #define WEP_KEY_LEN 13
struct prism2_crypt_data *crypt[WEP_KEYS]; struct ieee80211_crypt_data *crypt[WEP_KEYS];
int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
struct timer_list crypt_deinit_timer; struct timer_list crypt_deinit_timer;
struct list_head crypt_deinit_list; struct list_head crypt_deinit_list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment