You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Add HostAP wireless driver.
Includes minor cleanups from Adrian Bunk <bunk@stusta.de>.
This commit is contained in:
committed by
Jeff Garzik
parent
88d7bd8cb9
commit
ff1d2767d5
@@ -965,6 +965,13 @@ M: mike.miller@hp.com
|
||||
L: iss_storagedev@hp.com
|
||||
S: Supported
|
||||
|
||||
HOST AP DRIVER
|
||||
P: Jouni Malinen
|
||||
M: jkmaline@cc.hut.fi
|
||||
L: hostap@shmoo.com
|
||||
W: http://hostap.epitest.fi/
|
||||
S: Maintained
|
||||
|
||||
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
|
||||
P: Jaroslav Kysela
|
||||
M: perex@suse.cz
|
||||
|
||||
@@ -355,6 +355,8 @@ config PRISM54
|
||||
say M here and read <file:Documentation/modules.txt>. The module
|
||||
will be called prism54.ko.
|
||||
|
||||
source "drivers/net/wireless/hostap/Kconfig"
|
||||
|
||||
# yes, this works even when no drivers are selected
|
||||
config NET_WIRELESS
|
||||
bool
|
||||
|
||||
@@ -28,6 +28,8 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o
|
||||
|
||||
obj-$(CONFIG_PRISM54) += prism54/
|
||||
|
||||
obj-$(CONFIG_HOSTAP) += hostap/
|
||||
|
||||
# 16-bit wireless PCMCIA client drivers
|
||||
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
|
||||
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
|
||||
|
||||
+33
-32
@@ -1040,7 +1040,7 @@ typedef struct {
|
||||
u16 status;
|
||||
} WifiCtlHdr;
|
||||
|
||||
WifiCtlHdr wifictlhdr8023 = {
|
||||
static WifiCtlHdr wifictlhdr8023 = {
|
||||
.ctlhdr = {
|
||||
.ctl = HOST_DONT_RLSE,
|
||||
}
|
||||
@@ -1111,13 +1111,13 @@ static int airo_thread(void *data);
|
||||
static void timer_func( struct net_device *dev );
|
||||
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
#ifdef WIRELESS_EXT
|
||||
struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
|
||||
static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
|
||||
static void airo_read_wireless_stats (struct airo_info *local);
|
||||
#endif /* WIRELESS_EXT */
|
||||
#ifdef CISCO_EXT
|
||||
static int readrids(struct net_device *dev, aironet_ioctl *comp);
|
||||
static int writerids(struct net_device *dev, aironet_ioctl *comp);
|
||||
int flashcard(struct net_device *dev, aironet_ioctl *comp);
|
||||
static int flashcard(struct net_device *dev, aironet_ioctl *comp);
|
||||
#endif /* CISCO_EXT */
|
||||
#ifdef MICSUPPORT
|
||||
static void micinit(struct airo_info *ai);
|
||||
@@ -1223,6 +1223,12 @@ static int setup_proc_entry( struct net_device *dev,
|
||||
static int takedown_proc_entry( struct net_device *dev,
|
||||
struct airo_info *apriv );
|
||||
|
||||
static int cmdreset(struct airo_info *ai);
|
||||
static int setflashmode (struct airo_info *ai);
|
||||
static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
|
||||
static int flashputbuf(struct airo_info *ai);
|
||||
static int flashrestart(struct airo_info *ai,struct net_device *dev);
|
||||
|
||||
#ifdef MICSUPPORT
|
||||
/***********************************************************************
|
||||
* MIC ROUTINES *
|
||||
@@ -1231,10 +1237,11 @@ static int takedown_proc_entry( struct net_device *dev,
|
||||
|
||||
static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
|
||||
static void MoveWindow(miccntx *context, u32 micSeq);
|
||||
void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
|
||||
void emmh32_init(emmh32_context *context);
|
||||
void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
|
||||
void emmh32_final(emmh32_context *context, u8 digest[4]);
|
||||
static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
|
||||
static void emmh32_init(emmh32_context *context);
|
||||
static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
|
||||
static void emmh32_final(emmh32_context *context, u8 digest[4]);
|
||||
static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
|
||||
|
||||
/* micinit - Initialize mic seed */
|
||||
|
||||
@@ -1312,7 +1319,7 @@ static int micsetup(struct airo_info *ai) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
|
||||
static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
|
||||
|
||||
/*===========================================================================
|
||||
* Description: Mic a packet
|
||||
@@ -1567,7 +1574,7 @@ static void MoveWindow(miccntx *context, u32 micSeq)
|
||||
static unsigned char aes_counter[16];
|
||||
|
||||
/* expand the key to fill the MMH coefficient array */
|
||||
void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
|
||||
static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
|
||||
{
|
||||
/* take the keying material, expand if necessary, truncate at 16-bytes */
|
||||
/* run through AES counter mode to generate context->coeff[] */
|
||||
@@ -1599,7 +1606,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto
|
||||
}
|
||||
|
||||
/* prepare for calculation of a new mic */
|
||||
void emmh32_init(emmh32_context *context)
|
||||
static void emmh32_init(emmh32_context *context)
|
||||
{
|
||||
/* prepare for new mic calculation */
|
||||
context->accum = 0;
|
||||
@@ -1607,7 +1614,7 @@ void emmh32_init(emmh32_context *context)
|
||||
}
|
||||
|
||||
/* add some bytes to the mic calculation */
|
||||
void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
|
||||
static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
|
||||
{
|
||||
int coeff_position, byte_position;
|
||||
|
||||
@@ -1649,7 +1656,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
|
||||
static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
|
||||
|
||||
/* calculate the mic */
|
||||
void emmh32_final(emmh32_context *context, u8 digest[4])
|
||||
static void emmh32_final(emmh32_context *context, u8 digest[4])
|
||||
{
|
||||
int coeff_position, byte_position;
|
||||
u32 val;
|
||||
@@ -2251,7 +2258,7 @@ static void airo_read_stats(struct airo_info *ai) {
|
||||
ai->stats.rx_fifo_errors = vals[0];
|
||||
}
|
||||
|
||||
struct net_device_stats *airo_get_stats(struct net_device *dev)
|
||||
static struct net_device_stats *airo_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct airo_info *local = dev->priv;
|
||||
|
||||
@@ -2410,7 +2417,7 @@ EXPORT_SYMBOL(stop_airo_card);
|
||||
|
||||
static int add_airo_dev( struct net_device *dev );
|
||||
|
||||
int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
|
||||
static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
|
||||
{
|
||||
memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
|
||||
return ETH_ALEN;
|
||||
@@ -2677,7 +2684,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
|
||||
return dev;
|
||||
}
|
||||
|
||||
int reset_card( struct net_device *dev , int lock) {
|
||||
static int reset_card( struct net_device *dev , int lock) {
|
||||
struct airo_info *ai = dev->priv;
|
||||
|
||||
if (lock && down_interruptible(&ai->sem))
|
||||
@@ -2692,9 +2699,9 @@ int reset_card( struct net_device *dev , int lock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct net_device *_init_airo_card( unsigned short irq, int port,
|
||||
int is_pcmcia, struct pci_dev *pci,
|
||||
struct device *dmdev )
|
||||
static struct net_device *_init_airo_card( unsigned short irq, int port,
|
||||
int is_pcmcia, struct pci_dev *pci,
|
||||
struct device *dmdev )
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct airo_info *ai;
|
||||
@@ -7177,7 +7184,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
|
||||
local->wstats.miss.beacon = vals[34];
|
||||
}
|
||||
|
||||
struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
|
||||
static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
|
||||
{
|
||||
struct airo_info *local = dev->priv;
|
||||
|
||||
@@ -7392,14 +7399,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
|
||||
* Flash command switch table
|
||||
*/
|
||||
|
||||
int flashcard(struct net_device *dev, aironet_ioctl *comp) {
|
||||
static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
|
||||
int z;
|
||||
int cmdreset(struct airo_info *);
|
||||
int setflashmode(struct airo_info *);
|
||||
int flashgchar(struct airo_info *,int,int);
|
||||
int flashpchar(struct airo_info *,int,int);
|
||||
int flashputbuf(struct airo_info *);
|
||||
int flashrestart(struct airo_info *,struct net_device *);
|
||||
|
||||
/* Only super-user can modify flash */
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
@@ -7457,7 +7458,7 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) {
|
||||
* card.
|
||||
*/
|
||||
|
||||
int cmdreset(struct airo_info *ai) {
|
||||
static int cmdreset(struct airo_info *ai) {
|
||||
disable_MAC(ai, 1);
|
||||
|
||||
if(!waitbusy (ai)){
|
||||
@@ -7481,7 +7482,7 @@ int cmdreset(struct airo_info *ai) {
|
||||
* mode
|
||||
*/
|
||||
|
||||
int setflashmode (struct airo_info *ai) {
|
||||
static int setflashmode (struct airo_info *ai) {
|
||||
set_bit (FLAG_FLASHING, &ai->flags);
|
||||
|
||||
OUT4500(ai, SWS0, FLASH_COMMAND);
|
||||
@@ -7508,7 +7509,7 @@ int setflashmode (struct airo_info *ai) {
|
||||
* x 50us for echo .
|
||||
*/
|
||||
|
||||
int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
|
||||
static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
|
||||
int echo;
|
||||
int waittime;
|
||||
|
||||
@@ -7548,7 +7549,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
|
||||
* Get a character from the card matching matchbyte
|
||||
* Step 3)
|
||||
*/
|
||||
int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
|
||||
static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
|
||||
int rchar;
|
||||
unsigned char rbyte=0;
|
||||
|
||||
@@ -7579,7 +7580,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
|
||||
* send to the card
|
||||
*/
|
||||
|
||||
int flashputbuf(struct airo_info *ai){
|
||||
static int flashputbuf(struct airo_info *ai){
|
||||
int nwords;
|
||||
|
||||
/* Write stuff */
|
||||
@@ -7601,7 +7602,7 @@ int flashputbuf(struct airo_info *ai){
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int flashrestart(struct airo_info *ai,struct net_device *dev){
|
||||
static int flashrestart(struct airo_info *ai,struct net_device *dev){
|
||||
int i,status;
|
||||
|
||||
ssleep(1); /* Added 12/7/00 */
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
config HOSTAP
|
||||
tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
|
||||
depends on NET_RADIO
|
||||
---help---
|
||||
Shared driver code for IEEE 802.11b wireless cards based on
|
||||
Intersil Prism2/2.5/3 chipset. This driver supports so called
|
||||
Host AP mode that allows the card to act as an IEEE 802.11
|
||||
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
|
||||
Host AP driver configuration and tools. This site includes
|
||||
information and tools (hostapd and wpa_supplicant) for WPA/WPA2
|
||||
support.
|
||||
|
||||
This option includes the base Host AP driver code that is shared by
|
||||
different hardware models. You will also need to enable support for
|
||||
PLX/PCI/CS version of the driver to actually use the driver.
|
||||
|
||||
The driver can be compiled as a module and it will be called
|
||||
"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
|
||||
bool "Support downloading firmware images with Host AP driver"
|
||||
depends on HOSTAP
|
||||
---help---
|
||||
Configure Host AP driver to include support for firmware image
|
||||
download. Current version supports only downloading to volatile, i.e.,
|
||||
RAM memory. Flash upgrade is not yet supported.
|
||||
|
||||
Firmware image downloading needs user space tool, prism2_srec. It is
|
||||
available from http://hostap.epitest.fi/.
|
||||
|
||||
config HOSTAP_PLX
|
||||
tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
|
||||
depends on PCI && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
|
||||
PCI adaptors.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
"hostap_plx.ko".
|
||||
|
||||
config HOSTAP_PCI
|
||||
tristate "Host AP driver for Prism2.5 PCI adaptors"
|
||||
depends on PCI && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2.5 PCI adaptors.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
"hostap_pci.ko".
|
||||
|
||||
config HOSTAP_CS
|
||||
tristate "Host AP driver for Prism2/2.5/3 PC Cards"
|
||||
depends on PCMCIA!=n && HOSTAP
|
||||
---help---
|
||||
Host AP driver's version for Prism2/2.5/3 PC Cards.
|
||||
|
||||
"Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
|
||||
driver and its help text includes more information about the Host AP
|
||||
driver.
|
||||
|
||||
The driver can be compiled as a module and will be named
|
||||
"hostap_cs.ko".
|
||||
@@ -0,0 +1,8 @@
|
||||
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_PLX) += hostap_plx.o
|
||||
obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
#ifndef HOSTAP_H
|
||||
#define HOSTAP_H
|
||||
|
||||
/* hostap.c */
|
||||
|
||||
extern struct proc_dir_entry *hostap_proc;
|
||||
|
||||
u16 hostap_tx_callback_register(local_info_t *local,
|
||||
void (*func)(struct sk_buff *, int ok, void *),
|
||||
void *data);
|
||||
int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
|
||||
int hostap_set_word(struct net_device *dev, int rid, u16 val);
|
||||
int hostap_set_string(struct net_device *dev, int rid, const char *val);
|
||||
u16 hostap_get_porttype(local_info_t *local);
|
||||
int hostap_set_encryption(local_info_t *local);
|
||||
int hostap_set_antsel(local_info_t *local);
|
||||
int hostap_set_roaming(local_info_t *local);
|
||||
int hostap_set_auth_algs(local_info_t *local);
|
||||
void hostap_dump_rx_header(const char *name,
|
||||
const struct hfa384x_rx_frame *rx);
|
||||
void hostap_dump_tx_header(const char *name,
|
||||
const struct hfa384x_tx_frame *tx);
|
||||
int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
|
||||
int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
|
||||
int hostap_80211_get_hdrlen(u16 fc);
|
||||
struct net_device_stats *hostap_get_stats(struct net_device *dev);
|
||||
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
|
||||
int main_dev);
|
||||
void hostap_set_multicast_list_queue(void *data);
|
||||
int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
|
||||
int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
|
||||
void hostap_cleanup(local_info_t *local);
|
||||
void hostap_cleanup_handler(void *data);
|
||||
struct net_device * hostap_add_interface(struct local_info *local,
|
||||
int type, int rtnl_locked,
|
||||
const char *prefix, const char *name);
|
||||
void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
|
||||
int remove_from_list);
|
||||
int prism2_update_comms_qual(struct net_device *dev);
|
||||
int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u8 stype,
|
||||
u8 *body, size_t bodylen);
|
||||
int prism2_sta_deauth(local_info_t *local, u16 reason);
|
||||
|
||||
|
||||
/* hostap_proc.c */
|
||||
|
||||
void hostap_init_proc(local_info_t *local);
|
||||
void hostap_remove_proc(local_info_t *local);
|
||||
|
||||
|
||||
/* hostap_info.c */
|
||||
|
||||
void hostap_info_init(local_info_t *local);
|
||||
void hostap_info_process(local_info_t *local, struct sk_buff *skb);
|
||||
|
||||
|
||||
#endif /* HOSTAP_H */
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef HOSTAP_80211_H
|
||||
#define HOSTAP_80211_H
|
||||
|
||||
struct hostap_ieee80211_hdr {
|
||||
u16 frame_control;
|
||||
u16 duration_id;
|
||||
u8 addr1[6];
|
||||
u8 addr2[6];
|
||||
u8 addr3[6];
|
||||
u16 seq_ctrl;
|
||||
u8 addr4[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct hostap_ieee80211_mgmt {
|
||||
u16 frame_control;
|
||||
u16 duration;
|
||||
u8 da[6];
|
||||
u8 sa[6];
|
||||
u8 bssid[6];
|
||||
u16 seq_ctrl;
|
||||
union {
|
||||
struct {
|
||||
u16 auth_alg;
|
||||
u16 auth_transaction;
|
||||
u16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
} __attribute__ ((packed)) auth;
|
||||
struct {
|
||||
u16 reason_code;
|
||||
} __attribute__ ((packed)) deauth;
|
||||
struct {
|
||||
u16 capab_info;
|
||||
u16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} __attribute__ ((packed)) assoc_req;
|
||||
struct {
|
||||
u16 capab_info;
|
||||
u16 status_code;
|
||||
u16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
} __attribute__ ((packed)) assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
u16 capab_info;
|
||||
u16 listen_interval;
|
||||
u8 current_ap[6];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} __attribute__ ((packed)) reassoc_req;
|
||||
struct {
|
||||
u16 reason_code;
|
||||
} __attribute__ ((packed)) disassoc;
|
||||
struct {
|
||||
} __attribute__ ((packed)) probe_req;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
u16 beacon_int;
|
||||
u16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
} __attribute__ ((packed)) beacon, probe_resp;
|
||||
} u;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
#define IEEE80211_MGMT_HDR_LEN 24
|
||||
#define IEEE80211_DATA_HDR3_LEN 24
|
||||
#define IEEE80211_DATA_HDR4_LEN 30
|
||||
|
||||
|
||||
struct hostap_80211_rx_status {
|
||||
u32 mac_time;
|
||||
u8 signal;
|
||||
u8 noise;
|
||||
u16 rate; /* in 100 kbps */
|
||||
};
|
||||
|
||||
|
||||
void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
|
||||
|
||||
/* prism2_rx_80211 'type' argument */
|
||||
enum {
|
||||
PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
|
||||
PRISM2_RX_NULLFUNC_ACK
|
||||
};
|
||||
|
||||
int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats, int type);
|
||||
void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
|
||||
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_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||
struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
|
||||
struct prism2_crypt_data *crypt);
|
||||
int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||
|
||||
#endif /* HOSTAP_80211_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,272 @@
|
||||
#ifndef HOSTAP_AP_H
|
||||
#define HOSTAP_AP_H
|
||||
|
||||
/* AP data structures for STAs */
|
||||
|
||||
/* maximum number of frames to buffer per STA */
|
||||
#define STA_MAX_TX_BUFFER 32
|
||||
|
||||
/* Flags used in skb->cb[6] to control how the packet is handled in TX path.
|
||||
* skb->cb[0..5] must contain magic value 'hostap' to indicate that cb[6] is
|
||||
* used. */
|
||||
#define AP_SKB_CB_MAGIC "hostap"
|
||||
#define AP_SKB_CB_MAGIC_LEN 6
|
||||
#define AP_SKB_CB_BUFFERED_FRAME BIT(0)
|
||||
#define AP_SKB_CB_ADD_MOREDATA BIT(1)
|
||||
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
#define WLAN_STA_PS BIT(2)
|
||||
#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
|
||||
#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
|
||||
#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
|
||||
* controlling whether STA is authorized to
|
||||
* send and receive non-IEEE 802.1X frames
|
||||
*/
|
||||
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
|
||||
|
||||
#define WLAN_RATE_1M BIT(0)
|
||||
#define WLAN_RATE_2M BIT(1)
|
||||
#define WLAN_RATE_5M5 BIT(2)
|
||||
#define WLAN_RATE_11M BIT(3)
|
||||
#define WLAN_RATE_COUNT 4
|
||||
|
||||
/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
|
||||
* but some pre-standard IEEE 802.11g products use longer elements. */
|
||||
#define WLAN_SUPP_RATES_MAX 32
|
||||
|
||||
/* Try to increase TX rate after # successfully sent consecutive packets */
|
||||
#define WLAN_RATE_UPDATE_COUNT 50
|
||||
|
||||
/* Decrease TX rate after # consecutive dropped packets */
|
||||
#define WLAN_RATE_DECREASE_THRESHOLD 2
|
||||
|
||||
struct sta_info {
|
||||
struct list_head list;
|
||||
struct sta_info *hnext; /* next entry in hash table list */
|
||||
atomic_t users; /* number of users (do not remove if > 0) */
|
||||
struct proc_dir_entry *proc;
|
||||
|
||||
u8 addr[6];
|
||||
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
|
||||
u32 flags;
|
||||
u16 capability;
|
||||
u16 listen_interval; /* or beacon_int for APs */
|
||||
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||
|
||||
unsigned long last_auth;
|
||||
unsigned long last_assoc;
|
||||
unsigned long last_rx;
|
||||
unsigned long last_tx;
|
||||
unsigned long rx_packets, tx_packets;
|
||||
unsigned long rx_bytes, tx_bytes;
|
||||
struct sk_buff_head tx_buf;
|
||||
/* FIX: timeout buffers with an expiry time somehow derived from
|
||||
* listen_interval */
|
||||
|
||||
s8 last_rx_silence; /* Noise in dBm */
|
||||
s8 last_rx_signal; /* Signal strength in dBm */
|
||||
u8 last_rx_rate; /* TX rate in 0.1 Mbps */
|
||||
u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
|
||||
|
||||
u8 tx_supp_rates; /* bit field of supported TX rates */
|
||||
u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
|
||||
u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
|
||||
u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
|
||||
u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
|
||||
u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
|
||||
*/
|
||||
u32 tx_since_last_failure;
|
||||
u32 tx_consecutive_exc;
|
||||
|
||||
struct prism2_crypt_data *crypt;
|
||||
|
||||
int ap; /* whether this station is an AP */
|
||||
|
||||
local_info_t *local;
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
union {
|
||||
struct {
|
||||
char *challenge; /* shared key authentication
|
||||
* challenge */
|
||||
} sta;
|
||||
struct {
|
||||
int ssid_len;
|
||||
unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
|
||||
int channel;
|
||||
unsigned long last_beacon; /* last RX beacon time */
|
||||
} ap;
|
||||
} u;
|
||||
|
||||
struct timer_list timer;
|
||||
enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
};
|
||||
|
||||
|
||||
#define MAX_STA_COUNT 1024
|
||||
|
||||
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
|
||||
* (8802.11 limitation) */
|
||||
#define MAX_AID_TABLE_SIZE 128
|
||||
|
||||
#define STA_HASH_SIZE 256
|
||||
#define STA_HASH(sta) (sta[5])
|
||||
|
||||
|
||||
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
|
||||
* has passed since last received frame from the station, a nullfunc data
|
||||
* frame is sent to the station. If this frame is not acknowledged and no other
|
||||
* frames have been received, the station will be disassociated after
|
||||
* AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after
|
||||
* AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
|
||||
* max inactivity timer. */
|
||||
#define AP_MAX_INACTIVITY_SEC (5 * 60)
|
||||
#define AP_DISASSOC_DELAY (HZ)
|
||||
#define AP_DEAUTH_DELAY (HZ)
|
||||
|
||||
/* ap_policy: whether to accept frames to/from other APs/IBSS */
|
||||
typedef enum {
|
||||
AP_OTHER_AP_SKIP_ALL = 0,
|
||||
AP_OTHER_AP_SAME_SSID = 1,
|
||||
AP_OTHER_AP_ALL = 2,
|
||||
AP_OTHER_AP_EVEN_IBSS = 3
|
||||
} ap_policy_enum;
|
||||
|
||||
#define PRISM2_AUTH_OPEN BIT(0)
|
||||
#define PRISM2_AUTH_SHARED_KEY BIT(1)
|
||||
|
||||
|
||||
/* MAC address-based restrictions */
|
||||
struct mac_entry {
|
||||
struct list_head list;
|
||||
u8 addr[6];
|
||||
};
|
||||
|
||||
struct mac_restrictions {
|
||||
enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
|
||||
unsigned int entries;
|
||||
struct list_head mac_list;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
struct add_sta_proc_data {
|
||||
u8 addr[ETH_ALEN];
|
||||
struct add_sta_proc_data *next;
|
||||
};
|
||||
|
||||
|
||||
typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
|
||||
struct wds_oper_data {
|
||||
wds_oper_type type;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct wds_oper_data *next;
|
||||
};
|
||||
|
||||
|
||||
struct ap_data {
|
||||
int initialized; /* whether ap_data has been initialized */
|
||||
local_info_t *local;
|
||||
int bridge_packets; /* send packet to associated STAs directly to the
|
||||
* wireless media instead of higher layers in the
|
||||
* kernel */
|
||||
unsigned int bridged_unicast; /* number of unicast frames bridged on
|
||||
* wireless media */
|
||||
unsigned int bridged_multicast; /* number of non-unicast frames
|
||||
* bridged on wireless media */
|
||||
unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
|
||||
* because they were to an address that
|
||||
* was not associated */
|
||||
int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
|
||||
|
||||
spinlock_t sta_table_lock;
|
||||
int num_sta; /* number of entries in sta_list */
|
||||
struct list_head sta_list; /* STA info list head */
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
|
||||
struct proc_dir_entry *proc;
|
||||
|
||||
ap_policy_enum ap_policy;
|
||||
unsigned int max_inactivity;
|
||||
int autom_ap_wds;
|
||||
|
||||
struct mac_restrictions mac_restrictions; /* MAC-based auth */
|
||||
int last_tx_rate;
|
||||
|
||||
struct work_struct add_sta_proc_queue;
|
||||
struct add_sta_proc_data *add_sta_proc_entries;
|
||||
|
||||
struct work_struct wds_oper_queue;
|
||||
struct wds_oper_data *wds_oper_entries;
|
||||
|
||||
u16 tx_callback_idx;
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
/* pointers to STA info; based on allocated AID or NULL if AID free
|
||||
* AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
|
||||
* and so on
|
||||
*/
|
||||
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
|
||||
|
||||
u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
|
||||
|
||||
/* WEP operations for generating challenges to be used with shared key
|
||||
* authentication */
|
||||
struct hostap_crypto_ops *crypt;
|
||||
void *crypt_priv;
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
};
|
||||
|
||||
|
||||
void hostap_rx(struct net_device *dev, struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_init_data(local_info_t *local);
|
||||
void hostap_init_ap_proc(local_info_t *local);
|
||||
void hostap_free_data(struct ap_data *ap);
|
||||
void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
|
||||
|
||||
typedef enum {
|
||||
AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
|
||||
AP_TX_CONTINUE_NOT_AUTHORIZED
|
||||
} ap_tx_ret;
|
||||
struct hostap_tx_data {
|
||||
struct sk_buff *skb;
|
||||
int host_encrypt;
|
||||
struct prism2_crypt_data *crypt;
|
||||
void *sta_ptr;
|
||||
};
|
||||
ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
|
||||
void hostap_handle_sta_release(void *ptr);
|
||||
void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
|
||||
int hostap_update_sta_ps(local_info_t *local,
|
||||
struct hostap_ieee80211_hdr *hdr);
|
||||
typedef enum {
|
||||
AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
|
||||
} ap_rx_ret;
|
||||
ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct hostap_80211_rx_status *rx_stats,
|
||||
int wds);
|
||||
int hostap_handle_sta_crypto(local_info_t *local,
|
||||
struct hostap_ieee80211_hdr *hdr,
|
||||
struct prism2_crypt_data **crypt, void **sta_ptr);
|
||||
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_add_sta(struct ap_data *ap, u8 *sta_addr);
|
||||
int hostap_update_rx_stats(struct ap_data *ap,
|
||||
struct hostap_ieee80211_hdr *hdr,
|
||||
struct hostap_80211_rx_status *rx_stats);
|
||||
void hostap_update_rates(local_info_t *local);
|
||||
void hostap_add_wds_links(local_info_t *local);
|
||||
void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
|
||||
|
||||
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
|
||||
void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
|
||||
int resend);
|
||||
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
|
||||
#endif /* HOSTAP_AP_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
#ifndef HOSTAP_CONFIG_H
|
||||
#define HOSTAP_CONFIG_H
|
||||
|
||||
#define PRISM2_VERSION "CVS"
|
||||
|
||||
/* In the previous versions of Host AP driver, support for user space version
|
||||
* of IEEE 802.11 management (hostapd) used to be disabled in the default
|
||||
* configuration. From now on, support for hostapd is always included and it is
|
||||
* possible to disable kernel driver version of IEEE 802.11 management with a
|
||||
* separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
|
||||
/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
|
||||
|
||||
/* Maximum number of events handler per one interrupt */
|
||||
#define PRISM2_MAX_INTERRUPT_EVENTS 20
|
||||
|
||||
/* Use PCI bus master to copy data to/from BAP (only available for
|
||||
* hostap_pci.o).
|
||||
*
|
||||
* Note! This is extremely experimental. PCI bus master is not supported by
|
||||
* Intersil and it seems to have some problems at least on TX path (see below).
|
||||
* The driver code for implementing bus master support is based on guessing
|
||||
* and experimenting suitable control bits and these might not be correct.
|
||||
* This code is included because using bus master makes a huge difference in
|
||||
* host CPU load (something like 40% host CPU usage to 5-10% when sending or
|
||||
* receiving at maximum throughput).
|
||||
*
|
||||
* Note2! Station firmware version 1.3.5 and primary firmware version 1.0.7
|
||||
* have some fixes for PCI corruption and these (or newer) versions are
|
||||
* recommended especially when using bus mastering.
|
||||
*
|
||||
* NOTE: PCI bus mastering code has not been updated for long time and it is
|
||||
* not likely to compile and it will _not_ work as is. Only enable this if you
|
||||
* are prepared to first fix the implementation..
|
||||
*/
|
||||
/* #define PRISM2_BUS_MASTER */
|
||||
|
||||
#ifdef PRISM2_BUS_MASTER
|
||||
|
||||
/* PCI bus master implementation seems to be broken in current
|
||||
* hardware/firmware versions. Enable this to use enable command to fix
|
||||
* something before starting bus master operation on TX path. This will add
|
||||
* some latency and an extra interrupt to each TX packet. */
|
||||
#define PRISM2_ENABLE_BEFORE_TX_BUS_MASTER
|
||||
|
||||
#endif /* PRISM2_BUS_MASTER */
|
||||
|
||||
/* Include code for downloading firmware images into volatile RAM. */
|
||||
#define PRISM2_DOWNLOAD_SUPPORT
|
||||
|
||||
/* Allow kernel configuration to enable download support. */
|
||||
#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
|
||||
#define PRISM2_DOWNLOAD_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifdef PRISM2_DOWNLOAD_SUPPORT
|
||||
/* Allow writing firmware images into flash, i.e., to non-volatile storage.
|
||||
* Before you enable this option, you should make absolutely sure that you are
|
||||
* using prism2_srec utility that comes with THIS version of the driver!
|
||||
* In addition, please note that it is possible to kill your card with
|
||||
* non-volatile download if you are using incorrect image. This feature has not
|
||||
* been fully tested, so please be careful with it. */
|
||||
/* #define PRISM2_NON_VOLATILE_DOWNLOAD */
|
||||
#endif /* PRISM2_DOWNLOAD_SUPPORT */
|
||||
|
||||
/* Save low-level I/O for debugging. This should not be enabled in normal use.
|
||||
*/
|
||||
/* #define PRISM2_IO_DEBUG */
|
||||
|
||||
/* Following defines can be used to remove unneeded parts of the driver, e.g.,
|
||||
* to limit the size of the kernel module. Definitions can be added here in
|
||||
* hostap_config.h or they can be added to make command with EXTRA_CFLAGS,
|
||||
* e.g.,
|
||||
* 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
|
||||
*/
|
||||
|
||||
/* Do not include debug messages into the driver */
|
||||
/* #define PRISM2_NO_DEBUG */
|
||||
|
||||
/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
|
||||
/* #define PRISM2_NO_PROCFS_DEBUG */
|
||||
|
||||
/* Do not include station functionality (i.e., allow only Master (Host AP) mode
|
||||
*/
|
||||
/* #define PRISM2_NO_STATION_MODES */
|
||||
|
||||
#endif /* HOSTAP_CONFIG_H */
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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);
|
||||
@@ -0,0 +1,50 @@
|
||||
#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 */
|
||||
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Host AP crypt: host-based CCMP encryption implementation for Host AP driver
|
||||
*
|
||||
* Copyright (c) 2003-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 <linux/netdevice.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <asm/string.h>
|
||||
|
||||
#include "hostap_crypt.h"
|
||||
#include "hostap_wlan.h"
|
||||
#include "hostap_80211.h"
|
||||
|
||||
#ifndef CONFIG_CRYPTO
|
||||
#error CONFIG_CRYPTO is required to build this module.
|
||||
#endif
|
||||
#include <linux/crypto.h>
|
||||
#include <asm/scatterlist.h>
|
||||
|
||||
MODULE_AUTHOR("Jouni Malinen");
|
||||
MODULE_DESCRIPTION("Host AP crypt: CCMP");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define AES_BLOCK_LEN 16
|
||||
#define CCMP_HDR_LEN 8
|
||||
#define CCMP_MIC_LEN 8
|
||||
#define CCMP_TK_LEN 16
|
||||
#define CCMP_PN_LEN 6
|
||||
|
||||
|
||||
struct hostap_ccmp_data {
|
||||
u8 key[CCMP_TK_LEN];
|
||||
int key_set;
|
||||
|
||||
u8 tx_pn[CCMP_PN_LEN];
|
||||
u8 rx_pn[CCMP_PN_LEN];
|
||||
|
||||
u32 dot11RSNAStatsCCMPFormatErrors;
|
||||
u32 dot11RSNAStatsCCMPReplays;
|
||||
u32 dot11RSNAStatsCCMPDecryptErrors;
|
||||
|
||||
int key_idx;
|
||||
|
||||
struct crypto_tfm *tfm;
|
||||
|
||||
/* scratch buffers for virt_to_page() (crypto API) */
|
||||
u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
|
||||
tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
|
||||
u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
|
||||
};
|
||||
|
||||
|
||||
void hostap_ccmp_aes_encrypt(struct crypto_tfm *tfm,
|
||||
const u8 pt[16], u8 ct[16])
|
||||
{
|
||||
struct scatterlist src, dst;
|
||||
|
||||
src.page = virt_to_page(pt);
|
||||
src.offset = offset_in_page(pt);
|
||||
src.length = AES_BLOCK_LEN;
|
||||
|
||||
dst.page = virt_to_page(ct);
|
||||
dst.offset = offset_in_page(ct);
|
||||
dst.length = AES_BLOCK_LEN;
|
||||
|
||||
crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
|
||||
}
|
||||
|
||||
|
||||
static void * hostap_ccmp_init(int key_idx)
|
||||
{
|
||||
struct hostap_ccmp_data *priv;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return NULL;
|
||||
|
||||
priv = (struct hostap_ccmp_data *) kmalloc(sizeof(*priv), GFP_ATOMIC);
|
||||
if (priv == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->key_idx = key_idx;
|
||||
|
||||
priv->tfm = crypto_alloc_tfm("aes", 0);
|
||||
if (priv->tfm == NULL) {
|
||||
printk(KERN_DEBUG "hostap_crypt_ccmp: could not allocate "
|
||||
"crypto API aes\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return priv;
|
||||
|
||||
fail:
|
||||
if (priv) {
|
||||
if (priv->tfm)
|
||||
crypto_free_tfm(priv->tfm);
|
||||
kfree(priv);
|
||||
}
|
||||
module_put(THIS_MODULE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hostap_ccmp_deinit(void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *_priv = priv;
|
||||
if (_priv && _priv->tfm)
|
||||
crypto_free_tfm(_priv->tfm);
|
||||
kfree(priv);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
|
||||
static inline void xor_block(u8 *b, u8 *a, size_t len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
b[i] ^= a[i];
|
||||
}
|
||||
|
||||
|
||||
static void ccmp_init_blocks(struct crypto_tfm *tfm,
|
||||
struct hostap_ieee80211_hdr *hdr,
|
||||
u8 *pn, size_t dlen, u8 *b0, u8 *auth,
|
||||
u8 *s0)
|
||||
{
|
||||
u8 *pos, qc = 0;
|
||||
size_t aad_len;
|
||||
u16 fc;
|
||||
int a4_included, qc_included;
|
||||
u8 aad[2 * AES_BLOCK_LEN];
|
||||
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
a4_included = ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
|
||||
(WLAN_FC_TODS | WLAN_FC_FROMDS));
|
||||
qc_included = ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) &&
|
||||
(WLAN_FC_GET_STYPE(fc) & 0x08));
|
||||
aad_len = 22;
|
||||
if (a4_included)
|
||||
aad_len += 6;
|
||||
if (qc_included) {
|
||||
pos = (u8 *) &hdr->addr4;
|
||||
if (a4_included)
|
||||
pos += 6;
|
||||
qc = *pos & 0x0f;
|
||||
aad_len += 2;
|
||||
}
|
||||
|
||||
/* CCM Initial Block:
|
||||
* Flag (Include authentication header, M=3 (8-octet MIC),
|
||||
* L=1 (2-octet Dlen))
|
||||
* Nonce: 0x00 | A2 | PN
|
||||
* Dlen */
|
||||
b0[0] = 0x59;
|
||||
b0[1] = qc;
|
||||
memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
|
||||
memcpy(b0 + 8, pn, CCMP_PN_LEN);
|
||||
b0[14] = (dlen >> 8) & 0xff;
|
||||
b0[15] = dlen & 0xff;
|
||||
|
||||
/* AAD:
|
||||
* FC with bits 4..6 and 11..13 masked to zero; 14 is always one
|
||||
* A1 | A2 | A3
|
||||
* SC with bits 4..15 (seq#) masked to zero
|
||||
* A4 (if present)
|
||||
* QC (if present)
|
||||
*/
|
||||
pos = (u8 *) hdr;
|
||||
aad[0] = 0; /* aad_len >> 8 */
|
||||
aad[1] = aad_len & 0xff;
|
||||
aad[2] = pos[0] & 0x8f;
|
||||
aad[3] = pos[1] & 0xc7;
|
||||
memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
|
||||
pos = (u8 *) &hdr->seq_ctrl;
|
||||
aad[22] = pos[0] & 0x0f;
|
||||
aad[23] = 0; /* all bits masked */
|
||||
memset(aad + 24, 0, 8);
|
||||
if (a4_included)
|
||||
memcpy(aad + 24, hdr->addr4, ETH_ALEN);
|
||||
if (qc_included) {
|
||||
aad[a4_included ? 30 : 24] = qc;
|
||||
/* rest of QC masked */
|
||||
}
|
||||
|
||||
/* Start with the first block and AAD */
|
||||
hostap_ccmp_aes_encrypt(tfm, b0, auth);
|
||||
xor_block(auth, aad, AES_BLOCK_LEN);
|
||||
hostap_ccmp_aes_encrypt(tfm, auth, auth);
|
||||
xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
|
||||
hostap_ccmp_aes_encrypt(tfm, auth, auth);
|
||||
b0[0] &= 0x07;
|
||||
b0[14] = b0[15] = 0;
|
||||
hostap_ccmp_aes_encrypt(tfm, b0, s0);
|
||||
}
|
||||
|
||||
|
||||
static int hostap_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *key = priv;
|
||||
int data_len, i, blocks, last, len;
|
||||
u8 *pos, *mic;
|
||||
struct hostap_ieee80211_hdr *hdr;
|
||||
u8 *b0 = key->tx_b0;
|
||||
u8 *b = key->tx_b;
|
||||
u8 *e = key->tx_e;
|
||||
u8 *s0 = key->tx_s0;
|
||||
|
||||
if (skb_headroom(skb) < CCMP_HDR_LEN ||
|
||||
skb_tailroom(skb) < CCMP_MIC_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) {
|
||||
key->tx_pn[i]++;
|
||||
if (key->tx_pn[i] != 0)
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
|
||||
*pos++ = key->tx_pn[5];
|
||||
*pos++ = key->tx_pn[4];
|
||||
*pos++ = 0;
|
||||
*pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */;
|
||||
*pos++ = key->tx_pn[3];
|
||||
*pos++ = key->tx_pn[2];
|
||||
*pos++ = key->tx_pn[1];
|
||||
*pos++ = key->tx_pn[0];
|
||||
|
||||
hdr = (struct hostap_ieee80211_hdr *) skb->data;
|
||||
ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
|
||||
|
||||
blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
|
||||
last = data_len % AES_BLOCK_LEN;
|
||||
|
||||
for (i = 1; i <= blocks; i++) {
|
||||
len = (i == blocks && last) ? last : AES_BLOCK_LEN;
|
||||
/* Authentication */
|
||||
xor_block(b, pos, len);
|
||||
hostap_ccmp_aes_encrypt(key->tfm, b, b);
|
||||
/* Encryption, with counter */
|
||||
b0[14] = (i >> 8) & 0xff;
|
||||
b0[15] = i & 0xff;
|
||||
hostap_ccmp_aes_encrypt(key->tfm, b0, e);
|
||||
xor_block(pos, e, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
for (i = 0; i < CCMP_MIC_LEN; i++)
|
||||
mic[i] = b[i] ^ s0[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostap_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *key = priv;
|
||||
u8 keyidx, *pos;
|
||||
struct hostap_ieee80211_hdr *hdr;
|
||||
u8 *b0 = key->rx_b0;
|
||||
u8 *b = key->rx_b;
|
||||
u8 *a = key->rx_a;
|
||||
u8 pn[6];
|
||||
int i, blocks, last, len;
|
||||
size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
|
||||
u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
|
||||
|
||||
if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
|
||||
key->dot11RSNAStatsCCMPFormatErrors++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (struct hostap_ieee80211_hdr *) skb->data;
|
||||
pos = skb->data + hdr_len;
|
||||
keyidx = pos[3];
|
||||
if (!(keyidx & (1 << 5))) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "CCMP: received packet without ExtIV"
|
||||
" flag from " MACSTR "\n", MAC2STR(hdr->addr2));
|
||||
}
|
||||
key->dot11RSNAStatsCCMPFormatErrors++;
|
||||
return -2;
|
||||
}
|
||||
keyidx >>= 6;
|
||||
if (key->key_idx != keyidx) {
|
||||
printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
|
||||
"keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
|
||||
return -6;
|
||||
}
|
||||
if (!key->key_set) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "CCMP: received packet from " MACSTR
|
||||
" with keyid=%d that does not have a configured"
|
||||
" key\n", MAC2STR(hdr->addr2), keyidx);
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
|
||||
pn[0] = pos[7];
|
||||
pn[1] = pos[6];
|
||||
pn[2] = pos[5];
|
||||
pn[3] = pos[4];
|
||||
pn[4] = pos[1];
|
||||
pn[5] = pos[0];
|
||||
pos += 8;
|
||||
|
||||
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "CCMP: replay detected: STA=" MACSTR
|
||||
" previous PN %02x%02x%02x%02x%02x%02x "
|
||||
"received PN %02x%02x%02x%02x%02x%02x\n",
|
||||
MAC2STR(hdr->addr2), MAC2STR(key->rx_pn),
|
||||
MAC2STR(pn));
|
||||
}
|
||||
key->dot11RSNAStatsCCMPReplays++;
|
||||
return -4;
|
||||
}
|
||||
|
||||
ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
|
||||
xor_block(mic, b, CCMP_MIC_LEN);
|
||||
|
||||
blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
|
||||
last = data_len % AES_BLOCK_LEN;
|
||||
|
||||
for (i = 1; i <= blocks; i++) {
|
||||
len = (i == blocks && last) ? last : AES_BLOCK_LEN;
|
||||
/* Decrypt, with counter */
|
||||
b0[14] = (i >> 8) & 0xff;
|
||||
b0[15] = i & 0xff;
|
||||
hostap_ccmp_aes_encrypt(key->tfm, b0, b);
|
||||
xor_block(pos, b, len);
|
||||
/* Authentication */
|
||||
xor_block(a, pos, len);
|
||||
hostap_ccmp_aes_encrypt(key->tfm, a, a);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_DEBUG "CCMP: decrypt failed: STA="
|
||||
MACSTR "\n", MAC2STR(hdr->addr2));
|
||||
}
|
||||
key->dot11RSNAStatsCCMPDecryptErrors++;
|
||||
return -5;
|
||||
}
|
||||
|
||||
memcpy(key->rx_pn, pn, CCMP_PN_LEN);
|
||||
|
||||
/* Remove hdr and MIC */
|
||||
memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
|
||||
skb_pull(skb, CCMP_HDR_LEN);
|
||||
skb_trim(skb, skb->len - CCMP_MIC_LEN);
|
||||
|
||||
return keyidx;
|
||||
}
|
||||
|
||||
|
||||
static int hostap_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *data = priv;
|
||||
int keyidx;
|
||||
struct crypto_tfm *tfm = data->tfm;
|
||||
|
||||
keyidx = data->key_idx;
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->key_idx = keyidx;
|
||||
data->tfm = tfm;
|
||||
if (len == CCMP_TK_LEN) {
|
||||
memcpy(data->key, key, CCMP_TK_LEN);
|
||||
data->key_set = 1;
|
||||
if (seq) {
|
||||
data->rx_pn[0] = seq[5];
|
||||
data->rx_pn[1] = seq[4];
|
||||
data->rx_pn[2] = seq[3];
|
||||
data->rx_pn[3] = seq[2];
|
||||
data->rx_pn[4] = seq[1];
|
||||
data->rx_pn[5] = seq[0];
|
||||
}
|
||||
crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN);
|
||||
} else if (len == 0) {
|
||||
data->key_set = 0;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostap_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *data = priv;
|
||||
|
||||
if (len < CCMP_TK_LEN)
|
||||
return -1;
|
||||
|
||||
if (!data->key_set)
|
||||
return 0;
|
||||
memcpy(key, data->key, CCMP_TK_LEN);
|
||||
|
||||
if (seq) {
|
||||
seq[0] = data->tx_pn[5];
|
||||
seq[1] = data->tx_pn[4];
|
||||
seq[2] = data->tx_pn[3];
|
||||
seq[3] = data->tx_pn[2];
|
||||
seq[4] = data->tx_pn[1];
|
||||
seq[5] = data->tx_pn[0];
|
||||
}
|
||||
|
||||
return CCMP_TK_LEN;
|
||||
}
|
||||
|
||||
|
||||
static char * hostap_ccmp_print_stats(char *p, void *priv)
|
||||
{
|
||||
struct hostap_ccmp_data *ccmp = priv;
|
||||
p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
|
||||
"tx_pn=%02x%02x%02x%02x%02x%02x "
|
||||
"rx_pn=%02x%02x%02x%02x%02x%02x "
|
||||
"format_errors=%d replays=%d decrypt_errors=%d\n",
|
||||
ccmp->key_idx, ccmp->key_set,
|
||||
MAC2STR(ccmp->tx_pn), MAC2STR(ccmp->rx_pn),
|
||||
ccmp->dot11RSNAStatsCCMPFormatErrors,
|
||||
ccmp->dot11RSNAStatsCCMPReplays,
|
||||
ccmp->dot11RSNAStatsCCMPDecryptErrors);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static struct hostap_crypto_ops hostap_crypt_ccmp = {
|
||||
.name = "CCMP",
|
||||
.init = hostap_ccmp_init,
|
||||
.deinit = hostap_ccmp_deinit,
|
||||
.encrypt_mpdu = hostap_ccmp_encrypt,
|
||||
.decrypt_mpdu = hostap_ccmp_decrypt,
|
||||
.encrypt_msdu = NULL,
|
||||
.decrypt_msdu = NULL,
|
||||
.set_key = hostap_ccmp_set_key,
|
||||
.get_key = hostap_ccmp_get_key,
|
||||
.print_stats = hostap_ccmp_print_stats,
|
||||
.extra_prefix_len = CCMP_HDR_LEN,
|
||||
.extra_postfix_len = CCMP_MIC_LEN
|
||||
};
|
||||
|
||||
|
||||
static int __init hostap_crypto_ccmp_init(void)
|
||||
{
|
||||
if (hostap_register_crypto_ops(&hostap_crypt_ccmp) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit hostap_crypto_ccmp_exit(void)
|
||||
{
|
||||
hostap_unregister_crypto_ops(&hostap_crypt_ccmp);
|
||||
}
|
||||
|
||||
|
||||
module_init(hostap_crypto_ccmp_init);
|
||||
module_exit(hostap_crypto_ccmp_exit);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#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");
|
||||
|
||||
|
||||
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);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user