diff options
Diffstat (limited to 'drivers/net')
28 files changed, 19585 insertions, 68 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9d4c2fb671e2..dd7dbf7b14d4 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -459,6 +459,8 @@ config PRISM54 | |||
459 | say M here and read <file:Documentation/modules.txt>. The module | 459 | say M here and read <file:Documentation/modules.txt>. The module |
460 | will be called prism54.ko. | 460 | will be called prism54.ko. |
461 | 461 | ||
462 | source "drivers/net/wireless/hostap/Kconfig" | ||
463 | |||
462 | # yes, this works even when no drivers are selected | 464 | # yes, this works even when no drivers are selected |
463 | config NET_WIRELESS | 465 | config NET_WIRELESS |
464 | bool | 466 | bool |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0859787581bb..0953cc0cdee6 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -32,6 +32,8 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | |||
32 | 32 | ||
33 | obj-$(CONFIG_PRISM54) += prism54/ | 33 | obj-$(CONFIG_PRISM54) += prism54/ |
34 | 34 | ||
35 | obj-$(CONFIG_HOSTAP) += hostap/ | ||
36 | |||
35 | # 16-bit wireless PCMCIA client drivers | 37 | # 16-bit wireless PCMCIA client drivers |
36 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o | 38 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o |
37 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o | 39 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index df20adcd0730..6db1fb6461de 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -1040,7 +1040,7 @@ typedef struct { | |||
1040 | u16 status; | 1040 | u16 status; |
1041 | } WifiCtlHdr; | 1041 | } WifiCtlHdr; |
1042 | 1042 | ||
1043 | WifiCtlHdr wifictlhdr8023 = { | 1043 | static WifiCtlHdr wifictlhdr8023 = { |
1044 | .ctlhdr = { | 1044 | .ctlhdr = { |
1045 | .ctl = HOST_DONT_RLSE, | 1045 | .ctl = HOST_DONT_RLSE, |
1046 | } | 1046 | } |
@@ -1111,13 +1111,13 @@ static int airo_thread(void *data); | |||
1111 | static void timer_func( struct net_device *dev ); | 1111 | static void timer_func( struct net_device *dev ); |
1112 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 1112 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
1113 | #ifdef WIRELESS_EXT | 1113 | #ifdef WIRELESS_EXT |
1114 | struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); | 1114 | static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); |
1115 | static void airo_read_wireless_stats (struct airo_info *local); | 1115 | static void airo_read_wireless_stats (struct airo_info *local); |
1116 | #endif /* WIRELESS_EXT */ | 1116 | #endif /* WIRELESS_EXT */ |
1117 | #ifdef CISCO_EXT | 1117 | #ifdef CISCO_EXT |
1118 | static int readrids(struct net_device *dev, aironet_ioctl *comp); | 1118 | static int readrids(struct net_device *dev, aironet_ioctl *comp); |
1119 | static int writerids(struct net_device *dev, aironet_ioctl *comp); | 1119 | static int writerids(struct net_device *dev, aironet_ioctl *comp); |
1120 | int flashcard(struct net_device *dev, aironet_ioctl *comp); | 1120 | static int flashcard(struct net_device *dev, aironet_ioctl *comp); |
1121 | #endif /* CISCO_EXT */ | 1121 | #endif /* CISCO_EXT */ |
1122 | #ifdef MICSUPPORT | 1122 | #ifdef MICSUPPORT |
1123 | static void micinit(struct airo_info *ai); | 1123 | static void micinit(struct airo_info *ai); |
@@ -1226,6 +1226,12 @@ static int setup_proc_entry( struct net_device *dev, | |||
1226 | static int takedown_proc_entry( struct net_device *dev, | 1226 | static int takedown_proc_entry( struct net_device *dev, |
1227 | struct airo_info *apriv ); | 1227 | struct airo_info *apriv ); |
1228 | 1228 | ||
1229 | static int cmdreset(struct airo_info *ai); | ||
1230 | static int setflashmode (struct airo_info *ai); | ||
1231 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); | ||
1232 | static int flashputbuf(struct airo_info *ai); | ||
1233 | static int flashrestart(struct airo_info *ai,struct net_device *dev); | ||
1234 | |||
1229 | #ifdef MICSUPPORT | 1235 | #ifdef MICSUPPORT |
1230 | /*********************************************************************** | 1236 | /*********************************************************************** |
1231 | * MIC ROUTINES * | 1237 | * MIC ROUTINES * |
@@ -1234,10 +1240,11 @@ static int takedown_proc_entry( struct net_device *dev, | |||
1234 | 1240 | ||
1235 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); | 1241 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); |
1236 | static void MoveWindow(miccntx *context, u32 micSeq); | 1242 | static void MoveWindow(miccntx *context, u32 micSeq); |
1237 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); | 1243 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); |
1238 | void emmh32_init(emmh32_context *context); | 1244 | static void emmh32_init(emmh32_context *context); |
1239 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len); | 1245 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); |
1240 | void emmh32_final(emmh32_context *context, u8 digest[4]); | 1246 | static void emmh32_final(emmh32_context *context, u8 digest[4]); |
1247 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime); | ||
1241 | 1248 | ||
1242 | /* micinit - Initialize mic seed */ | 1249 | /* micinit - Initialize mic seed */ |
1243 | 1250 | ||
@@ -1315,7 +1322,7 @@ static int micsetup(struct airo_info *ai) { | |||
1315 | return SUCCESS; | 1322 | return SUCCESS; |
1316 | } | 1323 | } |
1317 | 1324 | ||
1318 | char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; | 1325 | static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; |
1319 | 1326 | ||
1320 | /*=========================================================================== | 1327 | /*=========================================================================== |
1321 | * Description: Mic a packet | 1328 | * Description: Mic a packet |
@@ -1570,7 +1577,7 @@ static void MoveWindow(miccntx *context, u32 micSeq) | |||
1570 | static unsigned char aes_counter[16]; | 1577 | static unsigned char aes_counter[16]; |
1571 | 1578 | ||
1572 | /* expand the key to fill the MMH coefficient array */ | 1579 | /* expand the key to fill the MMH coefficient array */ |
1573 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) | 1580 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) |
1574 | { | 1581 | { |
1575 | /* take the keying material, expand if necessary, truncate at 16-bytes */ | 1582 | /* take the keying material, expand if necessary, truncate at 16-bytes */ |
1576 | /* run through AES counter mode to generate context->coeff[] */ | 1583 | /* run through AES counter mode to generate context->coeff[] */ |
@@ -1602,7 +1609,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto | |||
1602 | } | 1609 | } |
1603 | 1610 | ||
1604 | /* prepare for calculation of a new mic */ | 1611 | /* prepare for calculation of a new mic */ |
1605 | void emmh32_init(emmh32_context *context) | 1612 | static void emmh32_init(emmh32_context *context) |
1606 | { | 1613 | { |
1607 | /* prepare for new mic calculation */ | 1614 | /* prepare for new mic calculation */ |
1608 | context->accum = 0; | 1615 | context->accum = 0; |
@@ -1610,7 +1617,7 @@ void emmh32_init(emmh32_context *context) | |||
1610 | } | 1617 | } |
1611 | 1618 | ||
1612 | /* add some bytes to the mic calculation */ | 1619 | /* add some bytes to the mic calculation */ |
1613 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | 1620 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) |
1614 | { | 1621 | { |
1615 | int coeff_position, byte_position; | 1622 | int coeff_position, byte_position; |
1616 | 1623 | ||
@@ -1652,7 +1659,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | |||
1652 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; | 1659 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; |
1653 | 1660 | ||
1654 | /* calculate the mic */ | 1661 | /* calculate the mic */ |
1655 | void emmh32_final(emmh32_context *context, u8 digest[4]) | 1662 | static void emmh32_final(emmh32_context *context, u8 digest[4]) |
1656 | { | 1663 | { |
1657 | int coeff_position, byte_position; | 1664 | int coeff_position, byte_position; |
1658 | u32 val; | 1665 | u32 val; |
@@ -2255,7 +2262,7 @@ static void airo_read_stats(struct airo_info *ai) { | |||
2255 | ai->stats.rx_fifo_errors = vals[0]; | 2262 | ai->stats.rx_fifo_errors = vals[0]; |
2256 | } | 2263 | } |
2257 | 2264 | ||
2258 | struct net_device_stats *airo_get_stats(struct net_device *dev) | 2265 | static struct net_device_stats *airo_get_stats(struct net_device *dev) |
2259 | { | 2266 | { |
2260 | struct airo_info *local = dev->priv; | 2267 | struct airo_info *local = dev->priv; |
2261 | 2268 | ||
@@ -2414,7 +2421,7 @@ EXPORT_SYMBOL(stop_airo_card); | |||
2414 | 2421 | ||
2415 | static int add_airo_dev( struct net_device *dev ); | 2422 | static int add_airo_dev( struct net_device *dev ); |
2416 | 2423 | ||
2417 | int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) | 2424 | static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) |
2418 | { | 2425 | { |
2419 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); | 2426 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); |
2420 | return ETH_ALEN; | 2427 | return ETH_ALEN; |
@@ -2681,7 +2688,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, | |||
2681 | return dev; | 2688 | return dev; |
2682 | } | 2689 | } |
2683 | 2690 | ||
2684 | int reset_card( struct net_device *dev , int lock) { | 2691 | static int reset_card( struct net_device *dev , int lock) { |
2685 | struct airo_info *ai = dev->priv; | 2692 | struct airo_info *ai = dev->priv; |
2686 | 2693 | ||
2687 | if (lock && down_interruptible(&ai->sem)) | 2694 | if (lock && down_interruptible(&ai->sem)) |
@@ -2696,9 +2703,9 @@ int reset_card( struct net_device *dev , int lock) { | |||
2696 | return 0; | 2703 | return 0; |
2697 | } | 2704 | } |
2698 | 2705 | ||
2699 | struct net_device *_init_airo_card( unsigned short irq, int port, | 2706 | static struct net_device *_init_airo_card( unsigned short irq, int port, |
2700 | int is_pcmcia, struct pci_dev *pci, | 2707 | int is_pcmcia, struct pci_dev *pci, |
2701 | struct device *dmdev ) | 2708 | struct device *dmdev ) |
2702 | { | 2709 | { |
2703 | struct net_device *dev; | 2710 | struct net_device *dev; |
2704 | struct airo_info *ai; | 2711 | struct airo_info *ai; |
@@ -7235,7 +7242,7 @@ static void airo_read_wireless_stats(struct airo_info *local) | |||
7235 | local->wstats.miss.beacon = vals[34]; | 7242 | local->wstats.miss.beacon = vals[34]; |
7236 | } | 7243 | } |
7237 | 7244 | ||
7238 | struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) | 7245 | static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) |
7239 | { | 7246 | { |
7240 | struct airo_info *local = dev->priv; | 7247 | struct airo_info *local = dev->priv; |
7241 | 7248 | ||
@@ -7450,14 +7457,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { | |||
7450 | * Flash command switch table | 7457 | * Flash command switch table |
7451 | */ | 7458 | */ |
7452 | 7459 | ||
7453 | int flashcard(struct net_device *dev, aironet_ioctl *comp) { | 7460 | static int flashcard(struct net_device *dev, aironet_ioctl *comp) { |
7454 | int z; | 7461 | int z; |
7455 | int cmdreset(struct airo_info *); | ||
7456 | int setflashmode(struct airo_info *); | ||
7457 | int flashgchar(struct airo_info *,int,int); | ||
7458 | int flashpchar(struct airo_info *,int,int); | ||
7459 | int flashputbuf(struct airo_info *); | ||
7460 | int flashrestart(struct airo_info *,struct net_device *); | ||
7461 | 7462 | ||
7462 | /* Only super-user can modify flash */ | 7463 | /* Only super-user can modify flash */ |
7463 | if (!capable(CAP_NET_ADMIN)) | 7464 | if (!capable(CAP_NET_ADMIN)) |
@@ -7515,7 +7516,7 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) { | |||
7515 | * card. | 7516 | * card. |
7516 | */ | 7517 | */ |
7517 | 7518 | ||
7518 | int cmdreset(struct airo_info *ai) { | 7519 | static int cmdreset(struct airo_info *ai) { |
7519 | disable_MAC(ai, 1); | 7520 | disable_MAC(ai, 1); |
7520 | 7521 | ||
7521 | if(!waitbusy (ai)){ | 7522 | if(!waitbusy (ai)){ |
@@ -7539,7 +7540,7 @@ int cmdreset(struct airo_info *ai) { | |||
7539 | * mode | 7540 | * mode |
7540 | */ | 7541 | */ |
7541 | 7542 | ||
7542 | int setflashmode (struct airo_info *ai) { | 7543 | static int setflashmode (struct airo_info *ai) { |
7543 | set_bit (FLAG_FLASHING, &ai->flags); | 7544 | set_bit (FLAG_FLASHING, &ai->flags); |
7544 | 7545 | ||
7545 | OUT4500(ai, SWS0, FLASH_COMMAND); | 7546 | OUT4500(ai, SWS0, FLASH_COMMAND); |
@@ -7566,7 +7567,7 @@ int setflashmode (struct airo_info *ai) { | |||
7566 | * x 50us for echo . | 7567 | * x 50us for echo . |
7567 | */ | 7568 | */ |
7568 | 7569 | ||
7569 | int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | 7570 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime) { |
7570 | int echo; | 7571 | int echo; |
7571 | int waittime; | 7572 | int waittime; |
7572 | 7573 | ||
@@ -7606,7 +7607,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | |||
7606 | * Get a character from the card matching matchbyte | 7607 | * Get a character from the card matching matchbyte |
7607 | * Step 3) | 7608 | * Step 3) |
7608 | */ | 7609 | */ |
7609 | int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | 7610 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ |
7610 | int rchar; | 7611 | int rchar; |
7611 | unsigned char rbyte=0; | 7612 | unsigned char rbyte=0; |
7612 | 7613 | ||
@@ -7637,7 +7638,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | |||
7637 | * send to the card | 7638 | * send to the card |
7638 | */ | 7639 | */ |
7639 | 7640 | ||
7640 | int flashputbuf(struct airo_info *ai){ | 7641 | static int flashputbuf(struct airo_info *ai){ |
7641 | int nwords; | 7642 | int nwords; |
7642 | 7643 | ||
7643 | /* Write stuff */ | 7644 | /* Write stuff */ |
@@ -7659,7 +7660,7 @@ int flashputbuf(struct airo_info *ai){ | |||
7659 | /* | 7660 | /* |
7660 | * | 7661 | * |
7661 | */ | 7662 | */ |
7662 | int flashrestart(struct airo_info *ai,struct net_device *dev){ | 7663 | static int flashrestart(struct airo_info *ai,struct net_device *dev){ |
7663 | int i,status; | 7664 | int i,status; |
7664 | 7665 | ||
7665 | ssleep(1); /* Added 12/7/00 */ | 7666 | ssleep(1); /* Added 12/7/00 */ |
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig new file mode 100644 index 000000000000..1445f3f2600f --- /dev/null +++ b/drivers/net/wireless/hostap/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | config HOSTAP | ||
2 | tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" | ||
3 | depends on NET_RADIO | ||
4 | ---help--- | ||
5 | Shared driver code for IEEE 802.11b wireless cards based on | ||
6 | Intersil Prism2/2.5/3 chipset. This driver supports so called | ||
7 | Host AP mode that allows the card to act as an IEEE 802.11 | ||
8 | access point. | ||
9 | |||
10 | See <http://hostap.epitest.fi/> for more information about the | ||
11 | Host AP driver configuration and tools. This site includes | ||
12 | information and tools (hostapd and wpa_supplicant) for WPA/WPA2 | ||
13 | support. | ||
14 | |||
15 | This option includes the base Host AP driver code that is shared by | ||
16 | different hardware models. You will also need to enable support for | ||
17 | PLX/PCI/CS version of the driver to actually use the driver. | ||
18 | |||
19 | The driver can be compiled as a module and it will be called | ||
20 | "hostap.ko". | ||
21 | |||
22 | config HOSTAP_FIRMWARE | ||
23 | bool "Support downloading firmware images with Host AP driver" | ||
24 | depends on HOSTAP | ||
25 | ---help--- | ||
26 | Configure Host AP driver to include support for firmware image | ||
27 | download. Current version supports only downloading to volatile, i.e., | ||
28 | RAM memory. Flash upgrade is not yet supported. | ||
29 | |||
30 | Firmware image downloading needs user space tool, prism2_srec. It is | ||
31 | available from http://hostap.epitest.fi/. | ||
32 | |||
33 | config HOSTAP_PLX | ||
34 | tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" | ||
35 | depends on PCI && HOSTAP | ||
36 | ---help--- | ||
37 | Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based | ||
38 | PCI adaptors. | ||
39 | |||
40 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
41 | driver and its help text includes more information about the Host AP | ||
42 | driver. | ||
43 | |||
44 | The driver can be compiled as a module and will be named | ||
45 | "hostap_plx.ko". | ||
46 | |||
47 | config HOSTAP_PCI | ||
48 | tristate "Host AP driver for Prism2.5 PCI adaptors" | ||
49 | depends on PCI && HOSTAP | ||
50 | ---help--- | ||
51 | Host AP driver's version for Prism2.5 PCI adaptors. | ||
52 | |||
53 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
54 | driver and its help text includes more information about the Host AP | ||
55 | driver. | ||
56 | |||
57 | The driver can be compiled as a module and will be named | ||
58 | "hostap_pci.ko". | ||
59 | |||
60 | config HOSTAP_CS | ||
61 | tristate "Host AP driver for Prism2/2.5/3 PC Cards" | ||
62 | depends on PCMCIA!=n && HOSTAP | ||
63 | ---help--- | ||
64 | Host AP driver's version for Prism2/2.5/3 PC Cards. | ||
65 | |||
66 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
67 | driver and its help text includes more information about the Host AP | ||
68 | driver. | ||
69 | |||
70 | The driver can be compiled as a module and will be named | ||
71 | "hostap_cs.ko". | ||
diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile new file mode 100644 index 000000000000..fc62235bfc24 --- /dev/null +++ b/drivers/net/wireless/hostap/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_HOSTAP) += hostap.o | ||
2 | |||
3 | obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o | ||
4 | obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o | ||
5 | obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o | ||
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c new file mode 100644 index 000000000000..e7f5821b4942 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap.c | |||
@@ -0,0 +1,1198 @@ | |||
1 | /* | ||
2 | * Host AP (software wireless LAN access point) driver for | ||
3 | * Intersil Prism2/2.5/3 - hostap.o module, common routines | ||
4 | * | ||
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
6 | * <jkmaline@cc.hut.fi> | ||
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. See README and COPYING for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/random.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/kmod.h> | ||
26 | #include <linux/rtnetlink.h> | ||
27 | #include <linux/wireless.h> | ||
28 | #include <net/iw_handler.h> | ||
29 | #include <net/ieee80211.h> | ||
30 | #include <net/ieee80211_crypt.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | |||
33 | #include "hostap_wlan.h" | ||
34 | #include "hostap_80211.h" | ||
35 | #include "hostap_ap.h" | ||
36 | #include "hostap.h" | ||
37 | |||
38 | MODULE_AUTHOR("Jouni Malinen"); | ||
39 | MODULE_DESCRIPTION("Host AP common routines"); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | MODULE_VERSION(PRISM2_VERSION); | ||
42 | |||
43 | #define TX_TIMEOUT (2 * HZ) | ||
44 | |||
45 | #define PRISM2_MAX_FRAME_SIZE 2304 | ||
46 | #define PRISM2_MIN_MTU 256 | ||
47 | /* FIX: */ | ||
48 | #define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) | ||
49 | |||
50 | |||
51 | /* hostap.c */ | ||
52 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
53 | int rtnl_locked); | ||
54 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
55 | int rtnl_locked, int do_not_remove); | ||
56 | |||
57 | /* hostap_ap.c */ | ||
58 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
59 | struct iw_quality qual[], int buf_size, | ||
60 | int aplist); | ||
61 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); | ||
62 | static int prism2_hostapd(struct ap_data *ap, | ||
63 | struct prism2_hostapd_param *param); | ||
64 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
65 | struct ieee80211_crypt_data ***crypt); | ||
66 | static void ap_control_kickall(struct ap_data *ap); | ||
67 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
68 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
69 | u8 *mac); | ||
70 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
71 | u8 *mac); | ||
72 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); | ||
73 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
74 | u8 *mac); | ||
75 | #endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
76 | |||
77 | |||
78 | static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
79 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; | ||
80 | #define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) | ||
81 | |||
82 | |||
83 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
84 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
85 | static unsigned char rfc1042_header[] = | ||
86 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
87 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
88 | static unsigned char bridge_tunnel_header[] = | ||
89 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
90 | /* No encapsulation header if EtherType < 0x600 (=length) */ | ||
91 | |||
92 | |||
93 | /* FIX: these could be compiled separately and linked together to hostap.o */ | ||
94 | #include "hostap_ap.c" | ||
95 | #include "hostap_info.c" | ||
96 | #include "hostap_ioctl.c" | ||
97 | #include "hostap_proc.c" | ||
98 | #include "hostap_80211_rx.c" | ||
99 | #include "hostap_80211_tx.c" | ||
100 | |||
101 | |||
102 | struct net_device * hostap_add_interface(struct local_info *local, | ||
103 | int type, int rtnl_locked, | ||
104 | const char *prefix, | ||
105 | const char *name) | ||
106 | { | ||
107 | struct net_device *dev, *mdev; | ||
108 | struct hostap_interface *iface; | ||
109 | int ret; | ||
110 | |||
111 | dev = alloc_etherdev(sizeof(struct hostap_interface)); | ||
112 | if (dev == NULL) | ||
113 | return NULL; | ||
114 | |||
115 | iface = netdev_priv(dev); | ||
116 | iface->dev = dev; | ||
117 | iface->local = local; | ||
118 | iface->type = type; | ||
119 | list_add(&iface->list, &local->hostap_interfaces); | ||
120 | |||
121 | mdev = local->dev; | ||
122 | memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); | ||
123 | dev->base_addr = mdev->base_addr; | ||
124 | dev->irq = mdev->irq; | ||
125 | dev->mem_start = mdev->mem_start; | ||
126 | dev->mem_end = mdev->mem_end; | ||
127 | |||
128 | hostap_setup_dev(dev, local, 0); | ||
129 | dev->destructor = free_netdev; | ||
130 | |||
131 | sprintf(dev->name, "%s%s", prefix, name); | ||
132 | if (!rtnl_locked) | ||
133 | rtnl_lock(); | ||
134 | |||
135 | ret = 0; | ||
136 | if (strchr(dev->name, '%')) | ||
137 | ret = dev_alloc_name(dev, dev->name); | ||
138 | |||
139 | SET_NETDEV_DEV(dev, mdev->class_dev.dev); | ||
140 | if (ret >= 0) | ||
141 | ret = register_netdevice(dev); | ||
142 | |||
143 | if (!rtnl_locked) | ||
144 | rtnl_unlock(); | ||
145 | |||
146 | if (ret < 0) { | ||
147 | printk(KERN_WARNING "%s: failed to add new netdevice!\n", | ||
148 | dev->name); | ||
149 | free_netdev(dev); | ||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | printk(KERN_DEBUG "%s: registered netdevice %s\n", | ||
154 | mdev->name, dev->name); | ||
155 | |||
156 | return dev; | ||
157 | } | ||
158 | |||
159 | |||
160 | void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | ||
161 | int remove_from_list) | ||
162 | { | ||
163 | struct hostap_interface *iface; | ||
164 | |||
165 | if (!dev) | ||
166 | return; | ||
167 | |||
168 | iface = netdev_priv(dev); | ||
169 | |||
170 | if (remove_from_list) { | ||
171 | list_del(&iface->list); | ||
172 | } | ||
173 | |||
174 | if (dev == iface->local->ddev) | ||
175 | iface->local->ddev = NULL; | ||
176 | else if (dev == iface->local->apdev) | ||
177 | iface->local->apdev = NULL; | ||
178 | else if (dev == iface->local->stadev) | ||
179 | iface->local->stadev = NULL; | ||
180 | |||
181 | if (rtnl_locked) | ||
182 | unregister_netdevice(dev); | ||
183 | else | ||
184 | unregister_netdev(dev); | ||
185 | |||
186 | /* dev->destructor = free_netdev() will free the device data, including | ||
187 | * private data, when removing the device */ | ||
188 | } | ||
189 | |||
190 | |||
191 | static inline int prism2_wds_special_addr(u8 *addr) | ||
192 | { | ||
193 | if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) | ||
194 | return 0; | ||
195 | |||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | |||
200 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
201 | int rtnl_locked) | ||
202 | { | ||
203 | struct net_device *dev; | ||
204 | struct list_head *ptr; | ||
205 | struct hostap_interface *iface, *empty, *match; | ||
206 | |||
207 | empty = match = NULL; | ||
208 | read_lock_bh(&local->iface_lock); | ||
209 | list_for_each(ptr, &local->hostap_interfaces) { | ||
210 | iface = list_entry(ptr, struct hostap_interface, list); | ||
211 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
212 | continue; | ||
213 | |||
214 | if (prism2_wds_special_addr(iface->u.wds.remote_addr)) | ||
215 | empty = iface; | ||
216 | else if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
217 | ETH_ALEN) == 0) { | ||
218 | match = iface; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | if (!match && empty && !prism2_wds_special_addr(remote_addr)) { | ||
223 | /* take pre-allocated entry into use */ | ||
224 | memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
225 | read_unlock_bh(&local->iface_lock); | ||
226 | printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", | ||
227 | local->dev->name, empty->dev->name); | ||
228 | return 0; | ||
229 | } | ||
230 | read_unlock_bh(&local->iface_lock); | ||
231 | |||
232 | if (!prism2_wds_special_addr(remote_addr)) { | ||
233 | if (match) | ||
234 | return -EEXIST; | ||
235 | hostap_add_sta(local->ap, remote_addr); | ||
236 | } | ||
237 | |||
238 | if (local->wds_connections >= local->wds_max_connections) | ||
239 | return -ENOBUFS; | ||
240 | |||
241 | /* verify that there is room for wds# postfix in the interface name */ | ||
242 | if (strlen(local->dev->name) > IFNAMSIZ - 5) { | ||
243 | printk(KERN_DEBUG "'%s' too long base device name\n", | ||
244 | local->dev->name); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, | ||
249 | local->ddev->name, "wds%d"); | ||
250 | if (dev == NULL) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | iface = netdev_priv(dev); | ||
254 | memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
255 | |||
256 | local->wds_connections++; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | |||
262 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
263 | int rtnl_locked, int do_not_remove) | ||
264 | { | ||
265 | unsigned long flags; | ||
266 | struct list_head *ptr; | ||
267 | struct hostap_interface *iface, *selected = NULL; | ||
268 | |||
269 | write_lock_irqsave(&local->iface_lock, flags); | ||
270 | list_for_each(ptr, &local->hostap_interfaces) { | ||
271 | iface = list_entry(ptr, struct hostap_interface, list); | ||
272 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
273 | continue; | ||
274 | |||
275 | if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
276 | ETH_ALEN) == 0) { | ||
277 | selected = iface; | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | if (selected && !do_not_remove) | ||
282 | list_del(&selected->list); | ||
283 | write_unlock_irqrestore(&local->iface_lock, flags); | ||
284 | |||
285 | if (selected) { | ||
286 | if (do_not_remove) | ||
287 | memset(selected->u.wds.remote_addr, 0, ETH_ALEN); | ||
288 | else { | ||
289 | hostap_remove_interface(selected->dev, rtnl_locked, 0); | ||
290 | local->wds_connections--; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return selected ? 0 : -ENODEV; | ||
295 | } | ||
296 | |||
297 | |||
298 | u16 hostap_tx_callback_register(local_info_t *local, | ||
299 | void (*func)(struct sk_buff *, int ok, void *), | ||
300 | void *data) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | struct hostap_tx_callback_info *entry; | ||
304 | |||
305 | entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry), | ||
306 | GFP_ATOMIC); | ||
307 | if (entry == NULL) | ||
308 | return 0; | ||
309 | |||
310 | entry->func = func; | ||
311 | entry->data = data; | ||
312 | |||
313 | spin_lock_irqsave(&local->lock, flags); | ||
314 | entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; | ||
315 | entry->next = local->tx_callback; | ||
316 | local->tx_callback = entry; | ||
317 | spin_unlock_irqrestore(&local->lock, flags); | ||
318 | |||
319 | return entry->idx; | ||
320 | } | ||
321 | |||
322 | |||
323 | int hostap_tx_callback_unregister(local_info_t *local, u16 idx) | ||
324 | { | ||
325 | unsigned long flags; | ||
326 | struct hostap_tx_callback_info *cb, *prev = NULL; | ||
327 | |||
328 | spin_lock_irqsave(&local->lock, flags); | ||
329 | cb = local->tx_callback; | ||
330 | while (cb != NULL && cb->idx != idx) { | ||
331 | prev = cb; | ||
332 | cb = cb->next; | ||
333 | } | ||
334 | if (cb) { | ||
335 | if (prev == NULL) | ||
336 | local->tx_callback = cb->next; | ||
337 | else | ||
338 | prev->next = cb->next; | ||
339 | kfree(cb); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&local->lock, flags); | ||
342 | |||
343 | return cb ? 0 : -1; | ||
344 | } | ||
345 | |||
346 | |||
347 | /* val is in host byte order */ | ||
348 | int hostap_set_word(struct net_device *dev, int rid, u16 val) | ||
349 | { | ||
350 | struct hostap_interface *iface; | ||
351 | u16 tmp = cpu_to_le16(val); | ||
352 | iface = netdev_priv(dev); | ||
353 | return iface->local->func->set_rid(dev, rid, &tmp, 2); | ||
354 | } | ||
355 | |||
356 | |||
357 | int hostap_set_string(struct net_device *dev, int rid, const char *val) | ||
358 | { | ||
359 | struct hostap_interface *iface; | ||
360 | char buf[MAX_SSID_LEN + 2]; | ||
361 | int len; | ||
362 | |||
363 | iface = netdev_priv(dev); | ||
364 | len = strlen(val); | ||
365 | if (len > MAX_SSID_LEN) | ||
366 | return -1; | ||
367 | memset(buf, 0, sizeof(buf)); | ||
368 | buf[0] = len; /* little endian 16 bit word */ | ||
369 | memcpy(buf + 2, val, len); | ||
370 | |||
371 | return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); | ||
372 | } | ||
373 | |||
374 | |||
375 | u16 hostap_get_porttype(local_info_t *local) | ||
376 | { | ||
377 | if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) | ||
378 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
379 | if (local->iw_mode == IW_MODE_ADHOC) | ||
380 | return HFA384X_PORTTYPE_IBSS; | ||
381 | if (local->iw_mode == IW_MODE_INFRA) | ||
382 | return HFA384X_PORTTYPE_BSS; | ||
383 | if (local->iw_mode == IW_MODE_REPEAT) | ||
384 | return HFA384X_PORTTYPE_WDS; | ||
385 | if (local->iw_mode == IW_MODE_MONITOR) | ||
386 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
387 | return HFA384X_PORTTYPE_HOSTAP; | ||
388 | } | ||
389 | |||
390 | |||
391 | int hostap_set_encryption(local_info_t *local) | ||
392 | { | ||
393 | u16 val, old_val; | ||
394 | int i, keylen, len, idx; | ||
395 | char keybuf[WEP_KEY_LEN + 1]; | ||
396 | enum { NONE, WEP, OTHER } encrypt_type; | ||
397 | |||
398 | idx = local->tx_keyidx; | ||
399 | if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) | ||
400 | encrypt_type = NONE; | ||
401 | else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) | ||
402 | encrypt_type = WEP; | ||
403 | else | ||
404 | encrypt_type = OTHER; | ||
405 | |||
406 | if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, | ||
407 | 1) < 0) { | ||
408 | printk(KERN_DEBUG "Could not read current WEP flags.\n"); | ||
409 | goto fail; | ||
410 | } | ||
411 | le16_to_cpus(&val); | ||
412 | old_val = val; | ||
413 | |||
414 | if (encrypt_type != NONE || local->privacy_invoked) | ||
415 | val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
416 | else | ||
417 | val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
418 | |||
419 | if (local->open_wep || encrypt_type == NONE || | ||
420 | ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) | ||
421 | val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
422 | else | ||
423 | val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
424 | |||
425 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
426 | (encrypt_type == OTHER || local->host_encrypt)) | ||
427 | val |= HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
428 | else | ||
429 | val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
430 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
431 | (encrypt_type == OTHER || local->host_decrypt)) | ||
432 | val |= HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
433 | else | ||
434 | val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
435 | |||
436 | if (val != old_val && | ||
437 | hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { | ||
438 | printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", | ||
439 | val); | ||
440 | goto fail; | ||
441 | } | ||
442 | |||
443 | if (encrypt_type != WEP) | ||
444 | return 0; | ||
445 | |||
446 | /* 104-bit support seems to require that all the keys are set to the | ||
447 | * same keylen */ | ||
448 | keylen = 6; /* first 5 octets */ | ||
449 | len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), | ||
450 | NULL, local->crypt[idx]->priv); | ||
451 | if (idx >= 0 && idx < WEP_KEYS && len > 5) | ||
452 | keylen = WEP_KEY_LEN + 1; /* first 13 octets */ | ||
453 | |||
454 | for (i = 0; i < WEP_KEYS; i++) { | ||
455 | memset(keybuf, 0, sizeof(keybuf)); | ||
456 | if (local->crypt[i]) { | ||
457 | (void) local->crypt[i]->ops->get_key( | ||
458 | keybuf, sizeof(keybuf), | ||
459 | NULL, local->crypt[i]->priv); | ||
460 | } | ||
461 | if (local->func->set_rid(local->dev, | ||
462 | HFA384X_RID_CNFDEFAULTKEY0 + i, | ||
463 | keybuf, keylen)) { | ||
464 | printk(KERN_DEBUG "Could not set key %d (len=%d)\n", | ||
465 | i, keylen); | ||
466 | goto fail; | ||
467 | } | ||
468 | } | ||
469 | if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { | ||
470 | printk(KERN_DEBUG "Could not set default keyid %d\n", idx); | ||
471 | goto fail; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | fail: | ||
477 | printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); | ||
478 | return -1; | ||
479 | } | ||
480 | |||
481 | |||
482 | int hostap_set_antsel(local_info_t *local) | ||
483 | { | ||
484 | u16 val; | ||
485 | int ret = 0; | ||
486 | |||
487 | if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
488 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
489 | HFA386X_CR_TX_CONFIGURE, | ||
490 | NULL, &val) == 0) { | ||
491 | val &= ~(BIT(2) | BIT(1)); | ||
492 | switch (local->antsel_tx) { | ||
493 | case HOSTAP_ANTSEL_DIVERSITY: | ||
494 | val |= BIT(1); | ||
495 | break; | ||
496 | case HOSTAP_ANTSEL_LOW: | ||
497 | break; | ||
498 | case HOSTAP_ANTSEL_HIGH: | ||
499 | val |= BIT(2); | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
504 | HFA386X_CR_TX_CONFIGURE, &val, NULL)) { | ||
505 | printk(KERN_INFO "%s: setting TX AntSel failed\n", | ||
506 | local->dev->name); | ||
507 | ret = -1; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
512 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
513 | HFA386X_CR_RX_CONFIGURE, | ||
514 | NULL, &val) == 0) { | ||
515 | val &= ~(BIT(1) | BIT(0)); | ||
516 | switch (local->antsel_rx) { | ||
517 | case HOSTAP_ANTSEL_DIVERSITY: | ||
518 | break; | ||
519 | case HOSTAP_ANTSEL_LOW: | ||
520 | val |= BIT(0); | ||
521 | break; | ||
522 | case HOSTAP_ANTSEL_HIGH: | ||
523 | val |= BIT(0) | BIT(1); | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
528 | HFA386X_CR_RX_CONFIGURE, &val, NULL)) { | ||
529 | printk(KERN_INFO "%s: setting RX AntSel failed\n", | ||
530 | local->dev->name); | ||
531 | ret = -1; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | |||
539 | int hostap_set_roaming(local_info_t *local) | ||
540 | { | ||
541 | u16 val; | ||
542 | |||
543 | switch (local->host_roaming) { | ||
544 | case 1: | ||
545 | val = HFA384X_ROAMING_HOST; | ||
546 | break; | ||
547 | case 2: | ||
548 | val = HFA384X_ROAMING_DISABLED; | ||
549 | break; | ||
550 | case 0: | ||
551 | default: | ||
552 | val = HFA384X_ROAMING_FIRMWARE; | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); | ||
557 | } | ||
558 | |||
559 | |||
560 | int hostap_set_auth_algs(local_info_t *local) | ||
561 | { | ||
562 | int val = local->auth_algs; | ||
563 | /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication | ||
564 | * set to include both Open and Shared Key flags. It tries to use | ||
565 | * Shared Key authentication in that case even if WEP keys are not | ||
566 | * configured.. STA f/w v0.7.6 is able to handle such configuration, | ||
567 | * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ | ||
568 | if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && | ||
569 | val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) | ||
570 | val = PRISM2_AUTH_OPEN; | ||
571 | |||
572 | if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { | ||
573 | printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " | ||
574 | "failed\n", local->dev->name, local->auth_algs); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | |||
582 | void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) | ||
583 | { | ||
584 | u16 status, fc; | ||
585 | |||
586 | status = __le16_to_cpu(rx->status); | ||
587 | |||
588 | printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " | ||
589 | "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " | ||
590 | "jiffies=%ld\n", | ||
591 | name, status, (status >> 8) & 0x07, status >> 13, status & 1, | ||
592 | rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); | ||
593 | |||
594 | fc = __le16_to_cpu(rx->frame_control); | ||
595 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
596 | "data_len=%d%s%s\n", | ||
597 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
598 | __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), | ||
599 | __le16_to_cpu(rx->data_len), | ||
600 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
601 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
602 | |||
603 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
604 | MACSTR "\n", | ||
605 | MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), | ||
606 | MAC2STR(rx->addr4)); | ||
607 | |||
608 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
609 | MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), | ||
610 | __be16_to_cpu(rx->len)); | ||
611 | } | ||
612 | |||
613 | |||
614 | void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) | ||
615 | { | ||
616 | u16 fc; | ||
617 | |||
618 | printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " | ||
619 | "tx_control=0x%04x; jiffies=%ld\n", | ||
620 | name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, | ||
621 | __le16_to_cpu(tx->tx_control), jiffies); | ||
622 | |||
623 | fc = __le16_to_cpu(tx->frame_control); | ||
624 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
625 | "data_len=%d%s%s\n", | ||
626 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
627 | __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), | ||
628 | __le16_to_cpu(tx->data_len), | ||
629 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
630 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
631 | |||
632 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
633 | MACSTR "\n", | ||
634 | MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), | ||
635 | MAC2STR(tx->addr4)); | ||
636 | |||
637 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
638 | MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), | ||
639 | __be16_to_cpu(tx->len)); | ||
640 | } | ||
641 | |||
642 | |||
643 | int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
644 | { | ||
645 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */ | ||
646 | return ETH_ALEN; | ||
647 | } | ||
648 | |||
649 | |||
650 | int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
651 | { | ||
652 | if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) { | ||
653 | memcpy(haddr, skb->mac.raw + | ||
654 | sizeof(struct linux_wlan_ng_prism_hdr) + 10, | ||
655 | ETH_ALEN); /* addr2 */ | ||
656 | } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */ | ||
657 | memcpy(haddr, skb->mac.raw + | ||
658 | sizeof(struct linux_wlan_ng_cap_hdr) + 10, | ||
659 | ETH_ALEN); /* addr2 */ | ||
660 | } | ||
661 | return ETH_ALEN; | ||
662 | } | ||
663 | |||
664 | |||
665 | int hostap_80211_get_hdrlen(u16 fc) | ||
666 | { | ||
667 | int hdrlen = 24; | ||
668 | |||
669 | switch (WLAN_FC_GET_TYPE(fc)) { | ||
670 | case IEEE80211_FTYPE_DATA: | ||
671 | if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) | ||
672 | hdrlen = 30; /* Addr4 */ | ||
673 | break; | ||
674 | case IEEE80211_FTYPE_CTL: | ||
675 | switch (WLAN_FC_GET_STYPE(fc)) { | ||
676 | case IEEE80211_STYPE_CTS: | ||
677 | case IEEE80211_STYPE_ACK: | ||
678 | hdrlen = 10; | ||
679 | break; | ||
680 | default: | ||
681 | hdrlen = 16; | ||
682 | break; | ||
683 | } | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | return hdrlen; | ||
688 | } | ||
689 | |||
690 | |||
691 | struct net_device_stats *hostap_get_stats(struct net_device *dev) | ||
692 | { | ||
693 | struct hostap_interface *iface; | ||
694 | iface = netdev_priv(dev); | ||
695 | return &iface->stats; | ||
696 | } | ||
697 | |||
698 | |||
699 | static int prism2_close(struct net_device *dev) | ||
700 | { | ||
701 | struct hostap_interface *iface; | ||
702 | local_info_t *local; | ||
703 | |||
704 | PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); | ||
705 | |||
706 | iface = netdev_priv(dev); | ||
707 | local = iface->local; | ||
708 | |||
709 | if (dev == local->ddev) { | ||
710 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
711 | } | ||
712 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
713 | if (!local->hostapd && dev == local->dev && | ||
714 | (!local->func->card_present || local->func->card_present(local)) && | ||
715 | local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) | ||
716 | hostap_deauth_all_stas(dev, local->ap, 1); | ||
717 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
718 | |||
719 | if (local->func->dev_close && local->func->dev_close(local)) | ||
720 | return 0; | ||
721 | |||
722 | if (dev == local->dev) { | ||
723 | local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); | ||
724 | } | ||
725 | |||
726 | if (netif_running(dev)) { | ||
727 | netif_stop_queue(dev); | ||
728 | netif_device_detach(dev); | ||
729 | } | ||
730 | |||
731 | flush_scheduled_work(); | ||
732 | |||
733 | module_put(local->hw_module); | ||
734 | |||
735 | local->num_dev_open--; | ||
736 | |||
737 | if (dev != local->dev && local->dev->flags & IFF_UP && | ||
738 | local->master_dev_auto_open && local->num_dev_open == 1) { | ||
739 | /* Close master radio interface automatically if it was also | ||
740 | * opened automatically and we are now closing the last | ||
741 | * remaining non-master device. */ | ||
742 | dev_close(local->dev); | ||
743 | } | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | |||
749 | static int prism2_open(struct net_device *dev) | ||
750 | { | ||
751 | struct hostap_interface *iface; | ||
752 | local_info_t *local; | ||
753 | |||
754 | PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); | ||
755 | |||
756 | iface = netdev_priv(dev); | ||
757 | local = iface->local; | ||
758 | |||
759 | if (local->no_pri) { | ||
760 | printk(KERN_DEBUG "%s: could not set interface UP - no PRI " | ||
761 | "f/w\n", dev->name); | ||
762 | return 1; | ||
763 | } | ||
764 | |||
765 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
766 | local->hw_downloading) | ||
767 | return -ENODEV; | ||
768 | |||
769 | if (local->func->dev_open && local->func->dev_open(local)) | ||
770 | return 1; | ||
771 | |||
772 | if (!try_module_get(local->hw_module)) | ||
773 | return -ENODEV; | ||
774 | local->num_dev_open++; | ||
775 | |||
776 | if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { | ||
777 | printk(KERN_WARNING "%s: could not enable MAC port\n", | ||
778 | dev->name); | ||
779 | prism2_close(dev); | ||
780 | return 1; | ||
781 | } | ||
782 | if (!local->dev_enabled) | ||
783 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
784 | local->dev_enabled = 1; | ||
785 | |||
786 | if (dev != local->dev && !(local->dev->flags & IFF_UP)) { | ||
787 | /* Master radio interface is needed for all operation, so open | ||
788 | * it automatically when any virtual net_device is opened. */ | ||
789 | local->master_dev_auto_open = 1; | ||
790 | dev_open(local->dev); | ||
791 | } | ||
792 | |||
793 | netif_device_attach(dev); | ||
794 | netif_start_queue(dev); | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | |||
800 | static int prism2_set_mac_address(struct net_device *dev, void *p) | ||
801 | { | ||
802 | struct hostap_interface *iface; | ||
803 | local_info_t *local; | ||
804 | struct list_head *ptr; | ||
805 | struct sockaddr *addr = p; | ||
806 | |||
807 | iface = netdev_priv(dev); | ||
808 | local = iface->local; | ||
809 | |||
810 | if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, | ||
811 | ETH_ALEN) < 0 || local->func->reset_port(dev)) | ||
812 | return -EINVAL; | ||
813 | |||
814 | read_lock_bh(&local->iface_lock); | ||
815 | list_for_each(ptr, &local->hostap_interfaces) { | ||
816 | iface = list_entry(ptr, struct hostap_interface, list); | ||
817 | memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
818 | } | ||
819 | memcpy(local->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
820 | read_unlock_bh(&local->iface_lock); | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | |||
826 | /* TODO: to be further implemented as soon as Prism2 fully supports | ||
827 | * GroupAddresses and correct documentation is available */ | ||
828 | void hostap_set_multicast_list_queue(void *data) | ||
829 | { | ||
830 | struct net_device *dev = (struct net_device *) data; | ||
831 | struct hostap_interface *iface; | ||
832 | local_info_t *local; | ||
833 | |||
834 | iface = netdev_priv(dev); | ||
835 | local = iface->local; | ||
836 | if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
837 | local->is_promisc)) { | ||
838 | printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", | ||
839 | dev->name, local->is_promisc ? "en" : "dis"); | ||
840 | } | ||
841 | } | ||
842 | |||
843 | |||
844 | static void hostap_set_multicast_list(struct net_device *dev) | ||
845 | { | ||
846 | #if 0 | ||
847 | /* FIX: promiscuous mode seems to be causing a lot of problems with | ||
848 | * some station firmware versions (FCSErr frames, invalid MACPort, etc. | ||
849 | * corrupted incoming frames). This code is now commented out while the | ||
850 | * problems are investigated. */ | ||
851 | struct hostap_interface *iface; | ||
852 | local_info_t *local; | ||
853 | |||
854 | iface = netdev_priv(dev); | ||
855 | local = iface->local; | ||
856 | if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { | ||
857 | local->is_promisc = 1; | ||
858 | } else { | ||
859 | local->is_promisc = 0; | ||
860 | } | ||
861 | |||
862 | schedule_work(&local->set_multicast_list_queue); | ||
863 | #endif | ||
864 | } | ||
865 | |||
866 | |||
867 | static int prism2_change_mtu(struct net_device *dev, int new_mtu) | ||
868 | { | ||
869 | if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU) | ||
870 | return -EINVAL; | ||
871 | |||
872 | dev->mtu = new_mtu; | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | |||
877 | static void prism2_tx_timeout(struct net_device *dev) | ||
878 | { | ||
879 | struct hostap_interface *iface; | ||
880 | local_info_t *local; | ||
881 | struct hfa384x_regs regs; | ||
882 | |||
883 | iface = netdev_priv(dev); | ||
884 | local = iface->local; | ||
885 | |||
886 | printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); | ||
887 | netif_stop_queue(local->dev); | ||
888 | |||
889 | local->func->read_regs(dev, ®s); | ||
890 | printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " | ||
891 | "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", | ||
892 | dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, | ||
893 | regs.swsupport0); | ||
894 | |||
895 | local->func->schedule_reset(local); | ||
896 | } | ||
897 | |||
898 | |||
899 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | ||
900 | int main_dev) | ||
901 | { | ||
902 | struct hostap_interface *iface; | ||
903 | |||
904 | iface = netdev_priv(dev); | ||
905 | ether_setup(dev); | ||
906 | |||
907 | /* kernel callbacks */ | ||
908 | dev->get_stats = hostap_get_stats; | ||
909 | if (iface) { | ||
910 | /* Currently, we point to the proper spy_data only on | ||
911 | * the main_dev. This could be fixed. Jean II */ | ||
912 | iface->wireless_data.spy_data = &iface->spy_data; | ||
913 | dev->wireless_data = &iface->wireless_data; | ||
914 | } | ||
915 | dev->wireless_handlers = | ||
916 | (struct iw_handler_def *) &hostap_iw_handler_def; | ||
917 | dev->do_ioctl = hostap_ioctl; | ||
918 | dev->open = prism2_open; | ||
919 | dev->stop = prism2_close; | ||
920 | dev->hard_start_xmit = hostap_data_start_xmit; | ||
921 | dev->set_mac_address = prism2_set_mac_address; | ||
922 | dev->set_multicast_list = hostap_set_multicast_list; | ||
923 | dev->change_mtu = prism2_change_mtu; | ||
924 | dev->tx_timeout = prism2_tx_timeout; | ||
925 | dev->watchdog_timeo = TX_TIMEOUT; | ||
926 | |||
927 | dev->mtu = local->mtu; | ||
928 | if (!main_dev) { | ||
929 | /* use main radio device queue */ | ||
930 | dev->tx_queue_len = 0; | ||
931 | } | ||
932 | |||
933 | SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops); | ||
934 | |||
935 | netif_stop_queue(dev); | ||
936 | } | ||
937 | |||
938 | |||
939 | static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) | ||
940 | { | ||
941 | struct net_device *dev = local->dev; | ||
942 | |||
943 | if (local->apdev) | ||
944 | return -EEXIST; | ||
945 | |||
946 | printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); | ||
947 | |||
948 | local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, | ||
949 | rtnl_locked, local->ddev->name, | ||
950 | "ap"); | ||
951 | if (local->apdev == NULL) | ||
952 | return -ENOMEM; | ||
953 | |||
954 | local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; | ||
955 | local->apdev->type = ARPHRD_IEEE80211; | ||
956 | local->apdev->hard_header_parse = hostap_80211_header_parse; | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | |||
962 | static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) | ||
963 | { | ||
964 | struct net_device *dev = local->dev; | ||
965 | |||
966 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
967 | |||
968 | hostap_remove_interface(local->apdev, rtnl_locked, 1); | ||
969 | local->apdev = NULL; | ||
970 | |||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | |||
975 | static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
976 | { | ||
977 | struct net_device *dev = local->dev; | ||
978 | |||
979 | if (local->stadev) | ||
980 | return -EEXIST; | ||
981 | |||
982 | printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); | ||
983 | |||
984 | local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, | ||
985 | rtnl_locked, local->ddev->name, | ||
986 | "sta"); | ||
987 | if (local->stadev == NULL) | ||
988 | return -ENOMEM; | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | |||
994 | static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
995 | { | ||
996 | struct net_device *dev = local->dev; | ||
997 | |||
998 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
999 | |||
1000 | hostap_remove_interface(local->stadev, rtnl_locked, 1); | ||
1001 | local->stadev = NULL; | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) | ||
1008 | { | ||
1009 | int ret; | ||
1010 | |||
1011 | if (val < 0 || val > 1) | ||
1012 | return -EINVAL; | ||
1013 | |||
1014 | if (local->hostapd == val) | ||
1015 | return 0; | ||
1016 | |||
1017 | if (val) { | ||
1018 | ret = hostap_enable_hostapd(local, rtnl_locked); | ||
1019 | if (ret == 0) | ||
1020 | local->hostapd = 1; | ||
1021 | } else { | ||
1022 | local->hostapd = 0; | ||
1023 | ret = hostap_disable_hostapd(local, rtnl_locked); | ||
1024 | if (ret != 0) | ||
1025 | local->hostapd = 1; | ||
1026 | } | ||
1027 | |||
1028 | return ret; | ||
1029 | } | ||
1030 | |||
1031 | |||
1032 | int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) | ||
1033 | { | ||
1034 | int ret; | ||
1035 | |||
1036 | if (val < 0 || val > 1) | ||
1037 | return -EINVAL; | ||
1038 | |||
1039 | if (local->hostapd_sta == val) | ||
1040 | return 0; | ||
1041 | |||
1042 | if (val) { | ||
1043 | ret = hostap_enable_hostapd_sta(local, rtnl_locked); | ||
1044 | if (ret == 0) | ||
1045 | local->hostapd_sta = 1; | ||
1046 | } else { | ||
1047 | local->hostapd_sta = 0; | ||
1048 | ret = hostap_disable_hostapd_sta(local, rtnl_locked); | ||
1049 | if (ret != 0) | ||
1050 | local->hostapd_sta = 1; | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | return ret; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | int prism2_update_comms_qual(struct net_device *dev) | ||
1059 | { | ||
1060 | struct hostap_interface *iface; | ||
1061 | local_info_t *local; | ||
1062 | int ret = 0; | ||
1063 | struct hfa384x_comms_quality sq; | ||
1064 | |||
1065 | iface = netdev_priv(dev); | ||
1066 | local = iface->local; | ||
1067 | if (!local->sta_fw_ver) | ||
1068 | ret = -1; | ||
1069 | else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1070 | if (local->func->get_rid(local->dev, | ||
1071 | HFA384X_RID_DBMCOMMSQUALITY, | ||
1072 | &sq, sizeof(sq), 1) >= 0) { | ||
1073 | local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); | ||
1074 | local->avg_signal = (s16) le16_to_cpu(sq.signal_level); | ||
1075 | local->avg_noise = (s16) le16_to_cpu(sq.noise_level); | ||
1076 | local->last_comms_qual_update = jiffies; | ||
1077 | } else | ||
1078 | ret = -1; | ||
1079 | } else { | ||
1080 | if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, | ||
1081 | &sq, sizeof(sq), 1) >= 0) { | ||
1082 | local->comms_qual = le16_to_cpu(sq.comm_qual); | ||
1083 | local->avg_signal = HFA384X_LEVEL_TO_dBm( | ||
1084 | le16_to_cpu(sq.signal_level)); | ||
1085 | local->avg_noise = HFA384X_LEVEL_TO_dBm( | ||
1086 | le16_to_cpu(sq.noise_level)); | ||
1087 | local->last_comms_qual_update = jiffies; | ||
1088 | } else | ||
1089 | ret = -1; | ||
1090 | } | ||
1091 | |||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, | ||
1097 | u8 *body, size_t bodylen) | ||
1098 | { | ||
1099 | struct sk_buff *skb; | ||
1100 | struct hostap_ieee80211_mgmt *mgmt; | ||
1101 | struct hostap_skb_tx_data *meta; | ||
1102 | struct net_device *dev = local->dev; | ||
1103 | |||
1104 | skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); | ||
1105 | if (skb == NULL) | ||
1106 | return -ENOMEM; | ||
1107 | |||
1108 | mgmt = (struct hostap_ieee80211_mgmt *) | ||
1109 | skb_put(skb, IEEE80211_MGMT_HDR_LEN); | ||
1110 | memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN); | ||
1111 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
1112 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
1113 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
1114 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
1115 | if (body) | ||
1116 | memcpy(skb_put(skb, bodylen), body, bodylen); | ||
1117 | |||
1118 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1119 | memset(meta, 0, sizeof(*meta)); | ||
1120 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
1121 | meta->iface = netdev_priv(dev); | ||
1122 | |||
1123 | skb->dev = dev; | ||
1124 | skb->mac.raw = skb->nh.raw = skb->data; | ||
1125 | dev_queue_xmit(skb); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | int prism2_sta_deauth(local_info_t *local, u16 reason) | ||
1132 | { | ||
1133 | union iwreq_data wrqu; | ||
1134 | int ret; | ||
1135 | |||
1136 | if (local->iw_mode != IW_MODE_INFRA || | ||
1137 | memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 || | ||
1138 | memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0) | ||
1139 | return 0; | ||
1140 | |||
1141 | reason = cpu_to_le16(reason); | ||
1142 | ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, | ||
1143 | (u8 *) &reason, 2); | ||
1144 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
1145 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | struct proc_dir_entry *hostap_proc; | ||
1151 | |||
1152 | static int __init hostap_init(void) | ||
1153 | { | ||
1154 | if (proc_net != NULL) { | ||
1155 | hostap_proc = proc_mkdir("hostap", proc_net); | ||
1156 | if (!hostap_proc) | ||
1157 | printk(KERN_WARNING "Failed to mkdir " | ||
1158 | "/proc/net/hostap\n"); | ||
1159 | } else | ||
1160 | hostap_proc = NULL; | ||
1161 | |||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | static void __exit hostap_exit(void) | ||
1167 | { | ||
1168 | if (hostap_proc != NULL) { | ||
1169 | hostap_proc = NULL; | ||
1170 | remove_proc_entry("hostap", proc_net); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | EXPORT_SYMBOL(hostap_set_word); | ||
1176 | EXPORT_SYMBOL(hostap_set_string); | ||
1177 | EXPORT_SYMBOL(hostap_get_porttype); | ||
1178 | EXPORT_SYMBOL(hostap_set_encryption); | ||
1179 | EXPORT_SYMBOL(hostap_set_antsel); | ||
1180 | EXPORT_SYMBOL(hostap_set_roaming); | ||
1181 | EXPORT_SYMBOL(hostap_set_auth_algs); | ||
1182 | EXPORT_SYMBOL(hostap_dump_rx_header); | ||
1183 | EXPORT_SYMBOL(hostap_dump_tx_header); | ||
1184 | EXPORT_SYMBOL(hostap_80211_header_parse); | ||
1185 | EXPORT_SYMBOL(hostap_80211_prism_header_parse); | ||
1186 | EXPORT_SYMBOL(hostap_80211_get_hdrlen); | ||
1187 | EXPORT_SYMBOL(hostap_get_stats); | ||
1188 | EXPORT_SYMBOL(hostap_setup_dev); | ||
1189 | EXPORT_SYMBOL(hostap_proc); | ||
1190 | EXPORT_SYMBOL(hostap_set_multicast_list_queue); | ||
1191 | EXPORT_SYMBOL(hostap_set_hostapd); | ||
1192 | EXPORT_SYMBOL(hostap_set_hostapd_sta); | ||
1193 | EXPORT_SYMBOL(hostap_add_interface); | ||
1194 | EXPORT_SYMBOL(hostap_remove_interface); | ||
1195 | EXPORT_SYMBOL(prism2_update_comms_qual); | ||
1196 | |||
1197 | module_init(hostap_init); | ||
1198 | module_exit(hostap_exit); | ||
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h new file mode 100644 index 000000000000..5fac89b8ce3a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #ifndef HOSTAP_H | ||
2 | #define HOSTAP_H | ||
3 | |||
4 | /* hostap.c */ | ||
5 | |||
6 | extern struct proc_dir_entry *hostap_proc; | ||
7 | |||
8 | u16 hostap_tx_callback_register(local_info_t *local, | ||
9 | void (*func)(struct sk_buff *, int ok, void *), | ||
10 | void *data); | ||
11 | int hostap_tx_callback_unregister(local_info_t *local, u16 idx); | ||
12 | int hostap_set_word(struct net_device *dev, int rid, u16 val); | ||
13 | int hostap_set_string(struct net_device *dev, int rid, const char *val); | ||
14 | u16 hostap_get_porttype(local_info_t *local); | ||
15 | int hostap_set_encryption(local_info_t *local); | ||
16 | int hostap_set_antsel(local_info_t *local); | ||
17 | int hostap_set_roaming(local_info_t *local); | ||
18 | int hostap_set_auth_algs(local_info_t *local); | ||
19 | void hostap_dump_rx_header(const char *name, | ||
20 | const struct hfa384x_rx_frame *rx); | ||
21 | void hostap_dump_tx_header(const char *name, | ||
22 | const struct hfa384x_tx_frame *tx); | ||
23 | int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr); | ||
24 | int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr); | ||
25 | int hostap_80211_get_hdrlen(u16 fc); | ||
26 | struct net_device_stats *hostap_get_stats(struct net_device *dev); | ||
27 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | ||
28 | int main_dev); | ||
29 | void hostap_set_multicast_list_queue(void *data); | ||
30 | int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); | ||
31 | int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); | ||
32 | void hostap_cleanup(local_info_t *local); | ||
33 | void hostap_cleanup_handler(void *data); | ||
34 | struct net_device * hostap_add_interface(struct local_info *local, | ||
35 | int type, int rtnl_locked, | ||
36 | const char *prefix, const char *name); | ||
37 | void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | ||
38 | int remove_from_list); | ||
39 | int prism2_update_comms_qual(struct net_device *dev); | ||
40 | int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, | ||
41 | u8 *body, size_t bodylen); | ||
42 | int prism2_sta_deauth(local_info_t *local, u16 reason); | ||
43 | |||
44 | |||
45 | /* hostap_proc.c */ | ||
46 | |||
47 | void hostap_init_proc(local_info_t *local); | ||
48 | void hostap_remove_proc(local_info_t *local); | ||
49 | |||
50 | |||
51 | /* hostap_info.c */ | ||
52 | |||
53 | void hostap_info_init(local_info_t *local); | ||
54 | void hostap_info_process(local_info_t *local, struct sk_buff *skb); | ||
55 | |||
56 | |||
57 | #endif /* HOSTAP_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h new file mode 100644 index 000000000000..bf506f50d722 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211.h | |||
@@ -0,0 +1,96 @@ | |||
1 | #ifndef HOSTAP_80211_H | ||
2 | #define HOSTAP_80211_H | ||
3 | |||
4 | struct hostap_ieee80211_mgmt { | ||
5 | u16 frame_control; | ||
6 | u16 duration; | ||
7 | u8 da[6]; | ||
8 | u8 sa[6]; | ||
9 | u8 bssid[6]; | ||
10 | u16 seq_ctrl; | ||
11 | union { | ||
12 | struct { | ||
13 | u16 auth_alg; | ||
14 | u16 auth_transaction; | ||
15 | u16 status_code; | ||
16 | /* possibly followed by Challenge text */ | ||
17 | u8 variable[0]; | ||
18 | } __attribute__ ((packed)) auth; | ||
19 | struct { | ||
20 | u16 reason_code; | ||
21 | } __attribute__ ((packed)) deauth; | ||
22 | struct { | ||
23 | u16 capab_info; | ||
24 | u16 listen_interval; | ||
25 | /* followed by SSID and Supported rates */ | ||
26 | u8 variable[0]; | ||
27 | } __attribute__ ((packed)) assoc_req; | ||
28 | struct { | ||
29 | u16 capab_info; | ||
30 | u16 status_code; | ||
31 | u16 aid; | ||
32 | /* followed by Supported rates */ | ||
33 | u8 variable[0]; | ||
34 | } __attribute__ ((packed)) assoc_resp, reassoc_resp; | ||
35 | struct { | ||
36 | u16 capab_info; | ||
37 | u16 listen_interval; | ||
38 | u8 current_ap[6]; | ||
39 | /* followed by SSID and Supported rates */ | ||
40 | u8 variable[0]; | ||
41 | } __attribute__ ((packed)) reassoc_req; | ||
42 | struct { | ||
43 | u16 reason_code; | ||
44 | } __attribute__ ((packed)) disassoc; | ||
45 | struct { | ||
46 | } __attribute__ ((packed)) probe_req; | ||
47 | struct { | ||
48 | u8 timestamp[8]; | ||
49 | u16 beacon_int; | ||
50 | u16 capab_info; | ||
51 | /* followed by some of SSID, Supported rates, | ||
52 | * FH Params, DS Params, CF Params, IBSS Params, TIM */ | ||
53 | u8 variable[0]; | ||
54 | } __attribute__ ((packed)) beacon, probe_resp; | ||
55 | } u; | ||
56 | } __attribute__ ((packed)); | ||
57 | |||
58 | |||
59 | #define IEEE80211_MGMT_HDR_LEN 24 | ||
60 | #define IEEE80211_DATA_HDR3_LEN 24 | ||
61 | #define IEEE80211_DATA_HDR4_LEN 30 | ||
62 | |||
63 | |||
64 | struct hostap_80211_rx_status { | ||
65 | u32 mac_time; | ||
66 | u8 signal; | ||
67 | u8 noise; | ||
68 | u16 rate; /* in 100 kbps */ | ||
69 | }; | ||
70 | |||
71 | |||
72 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
73 | struct hostap_80211_rx_status *rx_stats); | ||
74 | |||
75 | |||
76 | /* prism2_rx_80211 'type' argument */ | ||
77 | enum { | ||
78 | PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, | ||
79 | PRISM2_RX_NULLFUNC_ACK | ||
80 | }; | ||
81 | |||
82 | int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | ||
83 | struct hostap_80211_rx_status *rx_stats, int type); | ||
84 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
85 | struct hostap_80211_rx_status *rx_stats); | ||
86 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | ||
87 | struct hostap_80211_rx_status *rx_stats); | ||
88 | |||
89 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); | ||
90 | int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
91 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
92 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
93 | struct ieee80211_crypt_data *crypt); | ||
94 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
95 | |||
96 | #endif /* HOSTAP_80211_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c new file mode 100644 index 000000000000..b0501243b175 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | #include <linux/etherdevice.h> | ||
2 | |||
3 | #include "hostap_80211.h" | ||
4 | #include "hostap.h" | ||
5 | |||
6 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | ||
7 | struct hostap_80211_rx_status *rx_stats) | ||
8 | { | ||
9 | struct ieee80211_hdr *hdr; | ||
10 | u16 fc; | ||
11 | |||
12 | hdr = (struct ieee80211_hdr *) skb->data; | ||
13 | |||
14 | printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " | ||
15 | "jiffies=%ld\n", | ||
16 | name, rx_stats->signal, rx_stats->noise, rx_stats->rate, | ||
17 | skb->len, jiffies); | ||
18 | |||
19 | if (skb->len < 2) | ||
20 | return; | ||
21 | |||
22 | fc = le16_to_cpu(hdr->frame_ctl); | ||
23 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
24 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
25 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
26 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
27 | |||
28 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
29 | printk("\n"); | ||
30 | return; | ||
31 | } | ||
32 | |||
33 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | ||
34 | le16_to_cpu(hdr->seq_ctl)); | ||
35 | |||
36 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, | ||
37 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); | ||
38 | if (skb->len >= 30) | ||
39 | printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); | ||
40 | printk("\n"); | ||
41 | } | ||
42 | |||
43 | |||
44 | /* Send RX frame to netif with 802.11 (and possible prism) header. | ||
45 | * Called from hardware or software IRQ context. */ | ||
46 | int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | ||
47 | struct hostap_80211_rx_status *rx_stats, int type) | ||
48 | { | ||
49 | struct hostap_interface *iface; | ||
50 | local_info_t *local; | ||
51 | int hdrlen, phdrlen, head_need, tail_need; | ||
52 | u16 fc; | ||
53 | int prism_header, ret; | ||
54 | struct ieee80211_hdr *hdr; | ||
55 | |||
56 | iface = netdev_priv(dev); | ||
57 | local = iface->local; | ||
58 | dev->last_rx = jiffies; | ||
59 | |||
60 | if (dev->type == ARPHRD_IEEE80211_PRISM) { | ||
61 | if (local->monitor_type == PRISM2_MONITOR_PRISM) { | ||
62 | prism_header = 1; | ||
63 | phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); | ||
64 | } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ | ||
65 | prism_header = 2; | ||
66 | phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); | ||
67 | } | ||
68 | } else { | ||
69 | prism_header = 0; | ||
70 | phdrlen = 0; | ||
71 | } | ||
72 | |||
73 | hdr = (struct ieee80211_hdr *) skb->data; | ||
74 | fc = le16_to_cpu(hdr->frame_ctl); | ||
75 | |||
76 | if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { | ||
77 | printk(KERN_DEBUG "%s: dropped management frame with header " | ||
78 | "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); | ||
79 | dev_kfree_skb_any(skb); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
84 | |||
85 | /* check if there is enough room for extra data; if not, expand skb | ||
86 | * buffer to be large enough for the changes */ | ||
87 | head_need = phdrlen; | ||
88 | tail_need = 0; | ||
89 | #ifdef PRISM2_ADD_BOGUS_CRC | ||
90 | tail_need += 4; | ||
91 | #endif /* PRISM2_ADD_BOGUS_CRC */ | ||
92 | |||
93 | head_need -= skb_headroom(skb); | ||
94 | tail_need -= skb_tailroom(skb); | ||
95 | |||
96 | if (head_need > 0 || tail_need > 0) { | ||
97 | if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, | ||
98 | tail_need > 0 ? tail_need : 0, | ||
99 | GFP_ATOMIC)) { | ||
100 | printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " | ||
101 | "reallocate skb buffer\n", dev->name); | ||
102 | dev_kfree_skb_any(skb); | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /* We now have an skb with enough head and tail room, so just insert | ||
108 | * the extra data */ | ||
109 | |||
110 | #ifdef PRISM2_ADD_BOGUS_CRC | ||
111 | memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ | ||
112 | #endif /* PRISM2_ADD_BOGUS_CRC */ | ||
113 | |||
114 | if (prism_header == 1) { | ||
115 | struct linux_wlan_ng_prism_hdr *hdr; | ||
116 | hdr = (struct linux_wlan_ng_prism_hdr *) | ||
117 | skb_push(skb, phdrlen); | ||
118 | memset(hdr, 0, phdrlen); | ||
119 | hdr->msgcode = LWNG_CAP_DID_BASE; | ||
120 | hdr->msglen = sizeof(*hdr); | ||
121 | memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); | ||
122 | #define LWNG_SETVAL(f,i,s,l,d) \ | ||
123 | hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ | ||
124 | hdr->f.status = s; hdr->f.len = l; hdr->f.data = d | ||
125 | LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); | ||
126 | LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); | ||
127 | LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); | ||
128 | LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); | ||
129 | LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); | ||
130 | LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); | ||
131 | LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); | ||
132 | LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); | ||
133 | LWNG_SETVAL(istx, 9, 0, 4, 0); | ||
134 | LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); | ||
135 | #undef LWNG_SETVAL | ||
136 | } else if (prism_header == 2) { | ||
137 | struct linux_wlan_ng_cap_hdr *hdr; | ||
138 | hdr = (struct linux_wlan_ng_cap_hdr *) | ||
139 | skb_push(skb, phdrlen); | ||
140 | memset(hdr, 0, phdrlen); | ||
141 | hdr->version = htonl(LWNG_CAPHDR_VERSION); | ||
142 | hdr->length = htonl(phdrlen); | ||
143 | hdr->mactime = __cpu_to_be64(rx_stats->mac_time); | ||
144 | hdr->hosttime = __cpu_to_be64(jiffies); | ||
145 | hdr->phytype = htonl(4); /* dss_dot11_b */ | ||
146 | hdr->channel = htonl(local->channel); | ||
147 | hdr->datarate = htonl(rx_stats->rate); | ||
148 | hdr->antenna = htonl(0); /* unknown */ | ||
149 | hdr->priority = htonl(0); /* unknown */ | ||
150 | hdr->ssi_type = htonl(3); /* raw */ | ||
151 | hdr->ssi_signal = htonl(rx_stats->signal); | ||
152 | hdr->ssi_noise = htonl(rx_stats->noise); | ||
153 | hdr->preamble = htonl(0); /* unknown */ | ||
154 | hdr->encoding = htonl(1); /* cck */ | ||
155 | } | ||
156 | |||
157 | ret = skb->len - phdrlen; | ||
158 | skb->dev = dev; | ||
159 | skb->mac.raw = skb->data; | ||
160 | skb_pull(skb, hdrlen); | ||
161 | if (prism_header) | ||
162 | skb_pull(skb, phdrlen); | ||
163 | skb->pkt_type = PACKET_OTHERHOST; | ||
164 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
165 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
166 | netif_rx(skb); | ||
167 | |||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | |||
172 | /* Called only as a tasklet (software IRQ) */ | ||
173 | static void monitor_rx(struct net_device *dev, struct sk_buff *skb, | ||
174 | struct hostap_80211_rx_status *rx_stats) | ||
175 | { | ||
176 | struct net_device_stats *stats; | ||
177 | int len; | ||
178 | |||
179 | len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); | ||
180 | stats = hostap_get_stats(dev); | ||
181 | stats->rx_packets++; | ||
182 | stats->rx_bytes += len; | ||
183 | } | ||
184 | |||
185 | |||
186 | /* Called only as a tasklet (software IRQ) */ | ||
187 | static struct prism2_frag_entry * | ||
188 | prism2_frag_cache_find(local_info_t *local, unsigned int seq, | ||
189 | unsigned int frag, u8 *src, u8 *dst) | ||
190 | { | ||
191 | struct prism2_frag_entry *entry; | ||
192 | int i; | ||
193 | |||
194 | for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | ||
195 | entry = &local->frag_cache[i]; | ||
196 | if (entry->skb != NULL && | ||
197 | time_after(jiffies, entry->first_frag_time + 2 * HZ)) { | ||
198 | printk(KERN_DEBUG "%s: expiring fragment cache entry " | ||
199 | "seq=%u last_frag=%u\n", | ||
200 | local->dev->name, entry->seq, entry->last_frag); | ||
201 | dev_kfree_skb(entry->skb); | ||
202 | entry->skb = NULL; | ||
203 | } | ||
204 | |||
205 | if (entry->skb != NULL && entry->seq == seq && | ||
206 | (entry->last_frag + 1 == frag || frag == -1) && | ||
207 | memcmp(entry->src_addr, src, ETH_ALEN) == 0 && | ||
208 | memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) | ||
209 | return entry; | ||
210 | } | ||
211 | |||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | |||
216 | /* Called only as a tasklet (software IRQ) */ | ||
217 | static struct sk_buff * | ||
218 | prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) | ||
219 | { | ||
220 | struct sk_buff *skb = NULL; | ||
221 | u16 sc; | ||
222 | unsigned int frag, seq; | ||
223 | struct prism2_frag_entry *entry; | ||
224 | |||
225 | sc = le16_to_cpu(hdr->seq_ctl); | ||
226 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
227 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | ||
228 | |||
229 | if (frag == 0) { | ||
230 | /* Reserve enough space to fit maximum frame length */ | ||
231 | skb = dev_alloc_skb(local->dev->mtu + | ||
232 | sizeof(struct ieee80211_hdr) + | ||
233 | 8 /* LLC */ + | ||
234 | 2 /* alignment */ + | ||
235 | 8 /* WEP */ + ETH_ALEN /* WDS */); | ||
236 | if (skb == NULL) | ||
237 | return NULL; | ||
238 | |||
239 | entry = &local->frag_cache[local->frag_next_idx]; | ||
240 | local->frag_next_idx++; | ||
241 | if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) | ||
242 | local->frag_next_idx = 0; | ||
243 | |||
244 | if (entry->skb != NULL) | ||
245 | dev_kfree_skb(entry->skb); | ||
246 | |||
247 | entry->first_frag_time = jiffies; | ||
248 | entry->seq = seq; | ||
249 | entry->last_frag = frag; | ||
250 | entry->skb = skb; | ||
251 | memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); | ||
252 | memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); | ||
253 | } else { | ||
254 | /* received a fragment of a frame for which the head fragment | ||
255 | * should have already been received */ | ||
256 | entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, | ||
257 | hdr->addr1); | ||
258 | if (entry != NULL) { | ||
259 | entry->last_frag = frag; | ||
260 | skb = entry->skb; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | return skb; | ||
265 | } | ||
266 | |||
267 | |||
268 | /* Called only as a tasklet (software IRQ) */ | ||
269 | static int prism2_frag_cache_invalidate(local_info_t *local, | ||
270 | struct ieee80211_hdr *hdr) | ||
271 | { | ||
272 | u16 sc; | ||
273 | unsigned int seq; | ||
274 | struct prism2_frag_entry *entry; | ||
275 | |||
276 | sc = le16_to_cpu(hdr->seq_ctl); | ||
277 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | ||
278 | |||
279 | entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); | ||
280 | |||
281 | if (entry == NULL) { | ||
282 | printk(KERN_DEBUG "%s: could not invalidate fragment cache " | ||
283 | "entry (seq=%u)\n", | ||
284 | local->dev->name, seq); | ||
285 | return -1; | ||
286 | } | ||
287 | |||
288 | entry->skb = NULL; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, | ||
294 | u8 *ssid, size_t ssid_len) | ||
295 | { | ||
296 | struct list_head *ptr; | ||
297 | struct hostap_bss_info *bss; | ||
298 | |||
299 | list_for_each(ptr, &local->bss_list) { | ||
300 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
301 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && | ||
302 | (ssid == NULL || | ||
303 | (ssid_len == bss->ssid_len && | ||
304 | memcmp(ssid, bss->ssid, ssid_len) == 0))) { | ||
305 | list_move(&bss->list, &local->bss_list); | ||
306 | return bss; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | return NULL; | ||
311 | } | ||
312 | |||
313 | |||
314 | static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, | ||
315 | u8 *ssid, size_t ssid_len) | ||
316 | { | ||
317 | struct hostap_bss_info *bss; | ||
318 | |||
319 | if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { | ||
320 | bss = list_entry(local->bss_list.prev, | ||
321 | struct hostap_bss_info, list); | ||
322 | list_del(&bss->list); | ||
323 | local->num_bss_info--; | ||
324 | } else { | ||
325 | bss = (struct hostap_bss_info *) | ||
326 | kmalloc(sizeof(*bss), GFP_ATOMIC); | ||
327 | if (bss == NULL) | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | memset(bss, 0, sizeof(*bss)); | ||
332 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
333 | memcpy(bss->ssid, ssid, ssid_len); | ||
334 | bss->ssid_len = ssid_len; | ||
335 | local->num_bss_info++; | ||
336 | list_add(&bss->list, &local->bss_list); | ||
337 | return bss; | ||
338 | } | ||
339 | |||
340 | |||
341 | static void __hostap_expire_bss(local_info_t *local) | ||
342 | { | ||
343 | struct hostap_bss_info *bss; | ||
344 | |||
345 | while (local->num_bss_info > 0) { | ||
346 | bss = list_entry(local->bss_list.prev, | ||
347 | struct hostap_bss_info, list); | ||
348 | if (!time_after(jiffies, bss->last_update + 60 * HZ)) | ||
349 | break; | ||
350 | |||
351 | list_del(&bss->list); | ||
352 | local->num_bss_info--; | ||
353 | kfree(bss); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | |||
358 | /* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so | ||
359 | * the same routine can be used to parse both of them. */ | ||
360 | static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, | ||
361 | int stype) | ||
362 | { | ||
363 | struct hostap_ieee80211_mgmt *mgmt; | ||
364 | int left, chan = 0; | ||
365 | u8 *pos; | ||
366 | u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; | ||
367 | size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; | ||
368 | struct hostap_bss_info *bss; | ||
369 | |||
370 | if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) | ||
371 | return; | ||
372 | |||
373 | mgmt = (struct hostap_ieee80211_mgmt *) skb->data; | ||
374 | pos = mgmt->u.beacon.variable; | ||
375 | left = skb->len - (pos - skb->data); | ||
376 | |||
377 | while (left >= 2) { | ||
378 | if (2 + pos[1] > left) | ||
379 | return; /* parse failed */ | ||
380 | switch (*pos) { | ||
381 | case WLAN_EID_SSID: | ||
382 | ssid = pos + 2; | ||
383 | ssid_len = pos[1]; | ||
384 | break; | ||
385 | case WLAN_EID_GENERIC: | ||
386 | if (pos[1] >= 4 && | ||
387 | pos[2] == 0x00 && pos[3] == 0x50 && | ||
388 | pos[4] == 0xf2 && pos[5] == 1) { | ||
389 | wpa = pos; | ||
390 | wpa_len = pos[1] + 2; | ||
391 | } | ||
392 | break; | ||
393 | case WLAN_EID_RSN: | ||
394 | rsn = pos; | ||
395 | rsn_len = pos[1] + 2; | ||
396 | break; | ||
397 | case WLAN_EID_DS_PARAMS: | ||
398 | if (pos[1] >= 1) | ||
399 | chan = pos[2]; | ||
400 | break; | ||
401 | } | ||
402 | left -= 2 + pos[1]; | ||
403 | pos += 2 + pos[1]; | ||
404 | } | ||
405 | |||
406 | if (wpa_len > MAX_WPA_IE_LEN) | ||
407 | wpa_len = MAX_WPA_IE_LEN; | ||
408 | if (rsn_len > MAX_WPA_IE_LEN) | ||
409 | rsn_len = MAX_WPA_IE_LEN; | ||
410 | if (ssid_len > sizeof(bss->ssid)) | ||
411 | ssid_len = sizeof(bss->ssid); | ||
412 | |||
413 | spin_lock(&local->lock); | ||
414 | bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); | ||
415 | if (bss == NULL) | ||
416 | bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); | ||
417 | if (bss) { | ||
418 | bss->last_update = jiffies; | ||
419 | bss->count++; | ||
420 | bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); | ||
421 | if (wpa) { | ||
422 | memcpy(bss->wpa_ie, wpa, wpa_len); | ||
423 | bss->wpa_ie_len = wpa_len; | ||
424 | } else | ||
425 | bss->wpa_ie_len = 0; | ||
426 | if (rsn) { | ||
427 | memcpy(bss->rsn_ie, rsn, rsn_len); | ||
428 | bss->rsn_ie_len = rsn_len; | ||
429 | } else | ||
430 | bss->rsn_ie_len = 0; | ||
431 | bss->chan = chan; | ||
432 | } | ||
433 | __hostap_expire_bss(local); | ||
434 | spin_unlock(&local->lock); | ||
435 | } | ||
436 | |||
437 | |||
438 | static inline int | ||
439 | hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, | ||
440 | struct hostap_80211_rx_status *rx_stats, u16 type, | ||
441 | u16 stype) | ||
442 | { | ||
443 | if (local->iw_mode == IW_MODE_MASTER) { | ||
444 | hostap_update_sta_ps(local, (struct ieee80211_hdr *) | ||
445 | skb->data); | ||
446 | } | ||
447 | |||
448 | if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { | ||
449 | if (stype == IEEE80211_STYPE_BEACON && | ||
450 | local->iw_mode == IW_MODE_MASTER) { | ||
451 | struct sk_buff *skb2; | ||
452 | /* Process beacon frames also in kernel driver to | ||
453 | * update STA(AP) table statistics */ | ||
454 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
455 | if (skb2) | ||
456 | hostap_rx(skb2->dev, skb2, rx_stats); | ||
457 | } | ||
458 | |||
459 | /* send management frames to the user space daemon for | ||
460 | * processing */ | ||
461 | local->apdevstats.rx_packets++; | ||
462 | local->apdevstats.rx_bytes += skb->len; | ||
463 | if (local->apdev == NULL) | ||
464 | return -1; | ||
465 | prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | if (local->iw_mode == IW_MODE_MASTER) { | ||
470 | if (type != IEEE80211_FTYPE_MGMT && | ||
471 | type != IEEE80211_FTYPE_CTL) { | ||
472 | printk(KERN_DEBUG "%s: unknown management frame " | ||
473 | "(type=0x%02x, stype=0x%02x) dropped\n", | ||
474 | skb->dev->name, type >> 2, stype >> 4); | ||
475 | return -1; | ||
476 | } | ||
477 | |||
478 | hostap_rx(skb->dev, skb, rx_stats); | ||
479 | return 0; | ||
480 | } else if (type == IEEE80211_FTYPE_MGMT && | ||
481 | (stype == IEEE80211_STYPE_BEACON || | ||
482 | stype == IEEE80211_STYPE_PROBE_RESP)) { | ||
483 | hostap_rx_sta_beacon(local, skb, stype); | ||
484 | return -1; | ||
485 | } else if (type == IEEE80211_FTYPE_MGMT && | ||
486 | (stype == IEEE80211_STYPE_ASSOC_RESP || | ||
487 | stype == IEEE80211_STYPE_REASSOC_RESP)) { | ||
488 | /* Ignore (Re)AssocResp silently since these are not currently | ||
489 | * needed but are still received when WPA/RSN mode is enabled. | ||
490 | */ | ||
491 | return -1; | ||
492 | } else { | ||
493 | printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" | ||
494 | " management frame in non-Host AP mode (type=%d:%d)\n", | ||
495 | skb->dev->name, type >> 2, stype >> 4); | ||
496 | return -1; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | |||
501 | /* Called only as a tasklet (software IRQ) */ | ||
502 | static inline struct net_device *prism2_rx_get_wds(local_info_t *local, | ||
503 | u8 *addr) | ||
504 | { | ||
505 | struct hostap_interface *iface = NULL; | ||
506 | struct list_head *ptr; | ||
507 | |||
508 | read_lock_bh(&local->iface_lock); | ||
509 | list_for_each(ptr, &local->hostap_interfaces) { | ||
510 | iface = list_entry(ptr, struct hostap_interface, list); | ||
511 | if (iface->type == HOSTAP_INTERFACE_WDS && | ||
512 | memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) | ||
513 | break; | ||
514 | iface = NULL; | ||
515 | } | ||
516 | read_unlock_bh(&local->iface_lock); | ||
517 | |||
518 | return iface ? iface->dev : NULL; | ||
519 | } | ||
520 | |||
521 | |||
522 | static inline int | ||
523 | hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, | ||
524 | u16 fc, struct net_device **wds) | ||
525 | { | ||
526 | /* FIX: is this really supposed to accept WDS frames only in Master | ||
527 | * mode? What about Repeater or Managed with WDS frames? */ | ||
528 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != | ||
529 | (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && | ||
530 | (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) | ||
531 | return 0; /* not a WDS frame */ | ||
532 | |||
533 | /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) | ||
534 | * or own non-standard frame with 4th address after payload */ | ||
535 | if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 && | ||
536 | (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || | ||
537 | hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || | ||
538 | hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { | ||
539 | /* RA (or BSSID) is not ours - drop */ | ||
540 | PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " | ||
541 | "not own or broadcast %s=" MACSTR "\n", | ||
542 | local->dev->name, | ||
543 | fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", | ||
544 | MAC2STR(hdr->addr1)); | ||
545 | return -1; | ||
546 | } | ||
547 | |||
548 | /* check if the frame came from a registered WDS connection */ | ||
549 | *wds = prism2_rx_get_wds(local, hdr->addr2); | ||
550 | if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && | ||
551 | (local->iw_mode != IW_MODE_INFRA || | ||
552 | !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || | ||
553 | memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { | ||
554 | /* require that WDS link has been registered with TA or the | ||
555 | * frame is from current AP when using 'AP client mode' */ | ||
556 | PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " | ||
557 | "from unknown TA=" MACSTR "\n", | ||
558 | local->dev->name, MAC2STR(hdr->addr2)); | ||
559 | if (local->ap && local->ap->autom_ap_wds) | ||
560 | hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); | ||
561 | return -1; | ||
562 | } | ||
563 | |||
564 | if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && | ||
565 | hostap_is_sta_assoc(local->ap, hdr->addr2)) { | ||
566 | /* STA is actually associated with us even though it has a | ||
567 | * registered WDS link. Assume it is in 'AP client' mode. | ||
568 | * Since this is a 3-addr frame, assume it is not (bogus) WDS | ||
569 | * frame and process it like any normal ToDS frame from | ||
570 | * associated STA. */ | ||
571 | *wds = NULL; | ||
572 | } | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | |||
578 | static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) | ||
579 | { | ||
580 | struct net_device *dev = local->dev; | ||
581 | u16 fc, ethertype; | ||
582 | struct ieee80211_hdr *hdr; | ||
583 | u8 *pos; | ||
584 | |||
585 | if (skb->len < 24) | ||
586 | return 0; | ||
587 | |||
588 | hdr = (struct ieee80211_hdr *) skb->data; | ||
589 | fc = le16_to_cpu(hdr->frame_ctl); | ||
590 | |||
591 | /* check that the frame is unicast frame to us */ | ||
592 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
593 | IEEE80211_FCTL_TODS && | ||
594 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && | ||
595 | memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
596 | /* ToDS frame with own addr BSSID and DA */ | ||
597 | } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
598 | IEEE80211_FCTL_FROMDS && | ||
599 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
600 | /* FromDS frame with own addr as DA */ | ||
601 | } else | ||
602 | return 0; | ||
603 | |||
604 | if (skb->len < 24 + 8) | ||
605 | return 0; | ||
606 | |||
607 | /* check for port access entity Ethernet type */ | ||
608 | pos = skb->data + 24; | ||
609 | ethertype = (pos[6] << 8) | pos[7]; | ||
610 | if (ethertype == ETH_P_PAE) | ||
611 | return 1; | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | |||
617 | /* Called only as a tasklet (software IRQ) */ | ||
618 | static inline int | ||
619 | hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, | ||
620 | struct ieee80211_crypt_data *crypt) | ||
621 | { | ||
622 | struct ieee80211_hdr *hdr; | ||
623 | int res, hdrlen; | ||
624 | |||
625 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | ||
626 | return 0; | ||
627 | |||
628 | hdr = (struct ieee80211_hdr *) skb->data; | ||
629 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
630 | |||
631 | if (local->tkip_countermeasures && | ||
632 | strcmp(crypt->ops->name, "TKIP") == 0) { | ||
633 | if (net_ratelimit()) { | ||
634 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
635 | "received packet from " MACSTR "\n", | ||
636 | local->dev->name, MAC2STR(hdr->addr2)); | ||
637 | } | ||
638 | return -1; | ||
639 | } | ||
640 | |||
641 | atomic_inc(&crypt->refcnt); | ||
642 | res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); | ||
643 | atomic_dec(&crypt->refcnt); | ||
644 | if (res < 0) { | ||
645 | printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR | ||
646 | ") res=%d\n", | ||
647 | local->dev->name, MAC2STR(hdr->addr2), res); | ||
648 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
649 | return -1; | ||
650 | } | ||
651 | |||
652 | return res; | ||
653 | } | ||
654 | |||
655 | |||
656 | /* Called only as a tasklet (software IRQ) */ | ||
657 | static inline int | ||
658 | hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, | ||
659 | int keyidx, struct ieee80211_crypt_data *crypt) | ||
660 | { | ||
661 | struct ieee80211_hdr *hdr; | ||
662 | int res, hdrlen; | ||
663 | |||
664 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | ||
665 | return 0; | ||
666 | |||
667 | hdr = (struct ieee80211_hdr *) skb->data; | ||
668 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
669 | |||
670 | atomic_inc(&crypt->refcnt); | ||
671 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | ||
672 | atomic_dec(&crypt->refcnt); | ||
673 | if (res < 0) { | ||
674 | printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" | ||
675 | " (SA=" MACSTR " keyidx=%d)\n", | ||
676 | local->dev->name, MAC2STR(hdr->addr2), keyidx); | ||
677 | return -1; | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | |||
684 | /* All received frames are sent to this function. @skb contains the frame in | ||
685 | * IEEE 802.11 format, i.e., in the format it was sent over air. | ||
686 | * This function is called only as a tasklet (software IRQ). */ | ||
687 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
688 | struct hostap_80211_rx_status *rx_stats) | ||
689 | { | ||
690 | struct hostap_interface *iface; | ||
691 | local_info_t *local; | ||
692 | struct ieee80211_hdr *hdr; | ||
693 | size_t hdrlen; | ||
694 | u16 fc, type, stype, sc; | ||
695 | struct net_device *wds = NULL; | ||
696 | struct net_device_stats *stats; | ||
697 | unsigned int frag; | ||
698 | u8 *payload; | ||
699 | struct sk_buff *skb2 = NULL; | ||
700 | u16 ethertype; | ||
701 | int frame_authorized = 0; | ||
702 | int from_assoc_ap = 0; | ||
703 | u8 dst[ETH_ALEN]; | ||
704 | u8 src[ETH_ALEN]; | ||
705 | struct ieee80211_crypt_data *crypt = NULL; | ||
706 | void *sta = NULL; | ||
707 | int keyidx = 0; | ||
708 | |||
709 | iface = netdev_priv(dev); | ||
710 | local = iface->local; | ||
711 | iface->stats.rx_packets++; | ||
712 | iface->stats.rx_bytes += skb->len; | ||
713 | |||
714 | /* dev is the master radio device; change this to be the default | ||
715 | * virtual interface (this may be changed to WDS device below) */ | ||
716 | dev = local->ddev; | ||
717 | iface = netdev_priv(dev); | ||
718 | |||
719 | hdr = (struct ieee80211_hdr *) skb->data; | ||
720 | stats = hostap_get_stats(dev); | ||
721 | |||
722 | if (skb->len < 10) | ||
723 | goto rx_dropped; | ||
724 | |||
725 | fc = le16_to_cpu(hdr->frame_ctl); | ||
726 | type = WLAN_FC_GET_TYPE(fc); | ||
727 | stype = WLAN_FC_GET_STYPE(fc); | ||
728 | sc = le16_to_cpu(hdr->seq_ctl); | ||
729 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
730 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
731 | |||
732 | /* Put this code here so that we avoid duplicating it in all | ||
733 | * Rx paths. - Jean II */ | ||
734 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
735 | /* If spy monitoring on */ | ||
736 | if (iface->spy_data.spy_number > 0) { | ||
737 | struct iw_quality wstats; | ||
738 | wstats.level = rx_stats->signal; | ||
739 | wstats.noise = rx_stats->noise; | ||
740 | wstats.updated = 6; /* No qual value */ | ||
741 | /* Update spy records */ | ||
742 | wireless_spy_update(dev, hdr->addr2, &wstats); | ||
743 | } | ||
744 | #endif /* IW_WIRELESS_SPY */ | ||
745 | hostap_update_rx_stats(local->ap, hdr, rx_stats); | ||
746 | |||
747 | if (local->iw_mode == IW_MODE_MONITOR) { | ||
748 | monitor_rx(dev, skb, rx_stats); | ||
749 | return; | ||
750 | } | ||
751 | |||
752 | if (local->host_decrypt) { | ||
753 | int idx = 0; | ||
754 | if (skb->len >= hdrlen + 3) | ||
755 | idx = skb->data[hdrlen + 3] >> 6; | ||
756 | crypt = local->crypt[idx]; | ||
757 | sta = NULL; | ||
758 | |||
759 | /* Use station specific key to override default keys if the | ||
760 | * receiver address is a unicast address ("individual RA"). If | ||
761 | * bcrx_sta_key parameter is set, station specific key is used | ||
762 | * even with broad/multicast targets (this is against IEEE | ||
763 | * 802.11, but makes it easier to use different keys with | ||
764 | * stations that do not support WEP key mapping). */ | ||
765 | |||
766 | if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) | ||
767 | (void) hostap_handle_sta_crypto(local, hdr, &crypt, | ||
768 | &sta); | ||
769 | |||
770 | /* allow NULL decrypt to indicate an station specific override | ||
771 | * for default encryption */ | ||
772 | if (crypt && (crypt->ops == NULL || | ||
773 | crypt->ops->decrypt_mpdu == NULL)) | ||
774 | crypt = NULL; | ||
775 | |||
776 | if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { | ||
777 | #if 0 | ||
778 | /* This seems to be triggered by some (multicast?) | ||
779 | * frames from other than current BSS, so just drop the | ||
780 | * frames silently instead of filling system log with | ||
781 | * these reports. */ | ||
782 | printk(KERN_DEBUG "%s: WEP decryption failed (not set)" | ||
783 | " (SA=" MACSTR ")\n", | ||
784 | local->dev->name, MAC2STR(hdr->addr2)); | ||
785 | #endif | ||
786 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
787 | goto rx_dropped; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | if (type != IEEE80211_FTYPE_DATA) { | ||
792 | if (type == IEEE80211_FTYPE_MGMT && | ||
793 | stype == IEEE80211_STYPE_AUTH && | ||
794 | fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && | ||
795 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
796 | { | ||
797 | printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " | ||
798 | "from " MACSTR "\n", dev->name, | ||
799 | MAC2STR(hdr->addr2)); | ||
800 | /* TODO: could inform hostapd about this so that it | ||
801 | * could send auth failure report */ | ||
802 | goto rx_dropped; | ||
803 | } | ||
804 | |||
805 | if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) | ||
806 | goto rx_dropped; | ||
807 | else | ||
808 | goto rx_exit; | ||
809 | } | ||
810 | |||
811 | /* Data frame - extract src/dst addresses */ | ||
812 | if (skb->len < IEEE80211_DATA_HDR3_LEN) | ||
813 | goto rx_dropped; | ||
814 | |||
815 | switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | ||
816 | case IEEE80211_FCTL_FROMDS: | ||
817 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
818 | memcpy(src, hdr->addr3, ETH_ALEN); | ||
819 | break; | ||
820 | case IEEE80211_FCTL_TODS: | ||
821 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
822 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
823 | break; | ||
824 | case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | ||
825 | if (skb->len < IEEE80211_DATA_HDR4_LEN) | ||
826 | goto rx_dropped; | ||
827 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
828 | memcpy(src, hdr->addr4, ETH_ALEN); | ||
829 | break; | ||
830 | case 0: | ||
831 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
832 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
833 | break; | ||
834 | } | ||
835 | |||
836 | if (hostap_rx_frame_wds(local, hdr, fc, &wds)) | ||
837 | goto rx_dropped; | ||
838 | if (wds) { | ||
839 | skb->dev = dev = wds; | ||
840 | stats = hostap_get_stats(dev); | ||
841 | } | ||
842 | |||
843 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
844 | (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
845 | IEEE80211_FCTL_FROMDS && | ||
846 | local->stadev && | ||
847 | memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { | ||
848 | /* Frame from BSSID of the AP for which we are a client */ | ||
849 | skb->dev = dev = local->stadev; | ||
850 | stats = hostap_get_stats(dev); | ||
851 | from_assoc_ap = 1; | ||
852 | } | ||
853 | |||
854 | dev->last_rx = jiffies; | ||
855 | |||
856 | if ((local->iw_mode == IW_MODE_MASTER || | ||
857 | local->iw_mode == IW_MODE_REPEAT) && | ||
858 | !from_assoc_ap) { | ||
859 | switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, | ||
860 | wds != NULL)) { | ||
861 | case AP_RX_CONTINUE_NOT_AUTHORIZED: | ||
862 | frame_authorized = 0; | ||
863 | break; | ||
864 | case AP_RX_CONTINUE: | ||
865 | frame_authorized = 1; | ||
866 | break; | ||
867 | case AP_RX_DROP: | ||
868 | goto rx_dropped; | ||
869 | case AP_RX_EXIT: | ||
870 | goto rx_exit; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | /* Nullfunc frames may have PS-bit set, so they must be passed to | ||
875 | * hostap_handle_sta_rx() before being dropped here. */ | ||
876 | if (stype != IEEE80211_STYPE_DATA && | ||
877 | stype != IEEE80211_STYPE_DATA_CFACK && | ||
878 | stype != IEEE80211_STYPE_DATA_CFPOLL && | ||
879 | stype != IEEE80211_STYPE_DATA_CFACKPOLL) { | ||
880 | if (stype != IEEE80211_STYPE_NULLFUNC) | ||
881 | printk(KERN_DEBUG "%s: RX: dropped data frame " | ||
882 | "with no data (type=0x%02x, subtype=0x%02x)\n", | ||
883 | dev->name, type >> 2, stype >> 4); | ||
884 | goto rx_dropped; | ||
885 | } | ||
886 | |||
887 | /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ | ||
888 | |||
889 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
890 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
891 | goto rx_dropped; | ||
892 | hdr = (struct ieee80211_hdr *) skb->data; | ||
893 | |||
894 | /* skb: hdr + (possibly fragmented) plaintext payload */ | ||
895 | |||
896 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
897 | (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { | ||
898 | int flen; | ||
899 | struct sk_buff *frag_skb = | ||
900 | prism2_frag_cache_get(local, hdr); | ||
901 | if (!frag_skb) { | ||
902 | printk(KERN_DEBUG "%s: Rx cannot get skb from " | ||
903 | "fragment cache (morefrag=%d seq=%u frag=%u)\n", | ||
904 | dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, | ||
905 | WLAN_GET_SEQ_SEQ(sc) >> 4, frag); | ||
906 | goto rx_dropped; | ||
907 | } | ||
908 | |||
909 | flen = skb->len; | ||
910 | if (frag != 0) | ||
911 | flen -= hdrlen; | ||
912 | |||
913 | if (frag_skb->tail + flen > frag_skb->end) { | ||
914 | printk(KERN_WARNING "%s: host decrypted and " | ||
915 | "reassembled frame did not fit skb\n", | ||
916 | dev->name); | ||
917 | prism2_frag_cache_invalidate(local, hdr); | ||
918 | goto rx_dropped; | ||
919 | } | ||
920 | |||
921 | if (frag == 0) { | ||
922 | /* copy first fragment (including full headers) into | ||
923 | * beginning of the fragment cache skb */ | ||
924 | memcpy(skb_put(frag_skb, flen), skb->data, flen); | ||
925 | } else { | ||
926 | /* append frame payload to the end of the fragment | ||
927 | * cache skb */ | ||
928 | memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, | ||
929 | flen); | ||
930 | } | ||
931 | dev_kfree_skb(skb); | ||
932 | skb = NULL; | ||
933 | |||
934 | if (fc & IEEE80211_FCTL_MOREFRAGS) { | ||
935 | /* more fragments expected - leave the skb in fragment | ||
936 | * cache for now; it will be delivered to upper layers | ||
937 | * after all fragments have been received */ | ||
938 | goto rx_exit; | ||
939 | } | ||
940 | |||
941 | /* this was the last fragment and the frame will be | ||
942 | * delivered, so remove skb from fragment cache */ | ||
943 | skb = frag_skb; | ||
944 | hdr = (struct ieee80211_hdr *) skb->data; | ||
945 | prism2_frag_cache_invalidate(local, hdr); | ||
946 | } | ||
947 | |||
948 | /* skb: hdr + (possible reassembled) full MSDU payload; possibly still | ||
949 | * encrypted/authenticated */ | ||
950 | |||
951 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
952 | hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) | ||
953 | goto rx_dropped; | ||
954 | |||
955 | hdr = (struct ieee80211_hdr *) skb->data; | ||
956 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { | ||
957 | if (local->ieee_802_1x && | ||
958 | hostap_is_eapol_frame(local, skb)) { | ||
959 | /* pass unencrypted EAPOL frames even if encryption is | ||
960 | * configured */ | ||
961 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " | ||
962 | "unencrypted EAPOL frame\n", local->dev->name); | ||
963 | } else { | ||
964 | printk(KERN_DEBUG "%s: encryption configured, but RX " | ||
965 | "frame not encrypted (SA=" MACSTR ")\n", | ||
966 | local->dev->name, MAC2STR(hdr->addr2)); | ||
967 | goto rx_dropped; | ||
968 | } | ||
969 | } | ||
970 | |||
971 | if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && | ||
972 | !hostap_is_eapol_frame(local, skb)) { | ||
973 | if (net_ratelimit()) { | ||
974 | printk(KERN_DEBUG "%s: dropped unencrypted RX data " | ||
975 | "frame from " MACSTR " (drop_unencrypted=1)\n", | ||
976 | dev->name, MAC2STR(hdr->addr2)); | ||
977 | } | ||
978 | goto rx_dropped; | ||
979 | } | ||
980 | |||
981 | /* skb: hdr + (possible reassembled) full plaintext payload */ | ||
982 | |||
983 | payload = skb->data + hdrlen; | ||
984 | ethertype = (payload[6] << 8) | payload[7]; | ||
985 | |||
986 | /* If IEEE 802.1X is used, check whether the port is authorized to send | ||
987 | * the received frame. */ | ||
988 | if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { | ||
989 | if (ethertype == ETH_P_PAE) { | ||
990 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", | ||
991 | dev->name); | ||
992 | if (local->hostapd && local->apdev) { | ||
993 | /* Send IEEE 802.1X frames to the user | ||
994 | * space daemon for processing */ | ||
995 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
996 | PRISM2_RX_MGMT); | ||
997 | local->apdevstats.rx_packets++; | ||
998 | local->apdevstats.rx_bytes += skb->len; | ||
999 | goto rx_exit; | ||
1000 | } | ||
1001 | } else if (!frame_authorized) { | ||
1002 | printk(KERN_DEBUG "%s: dropped frame from " | ||
1003 | "unauthorized port (IEEE 802.1X): " | ||
1004 | "ethertype=0x%04x\n", | ||
1005 | dev->name, ethertype); | ||
1006 | goto rx_dropped; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | /* convert hdr + possible LLC headers into Ethernet header */ | ||
1011 | if (skb->len - hdrlen >= 8 && | ||
1012 | ((memcmp(payload, rfc1042_header, 6) == 0 && | ||
1013 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
1014 | memcmp(payload, bridge_tunnel_header, 6) == 0)) { | ||
1015 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
1016 | * replace EtherType */ | ||
1017 | skb_pull(skb, hdrlen + 6); | ||
1018 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1019 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1020 | } else { | ||
1021 | u16 len; | ||
1022 | /* Leave Ethernet header part of hdr and full payload */ | ||
1023 | skb_pull(skb, hdrlen); | ||
1024 | len = htons(skb->len); | ||
1025 | memcpy(skb_push(skb, 2), &len, 2); | ||
1026 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1027 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1028 | } | ||
1029 | |||
1030 | if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
1031 | IEEE80211_FCTL_TODS) && | ||
1032 | skb->len >= ETH_HLEN + ETH_ALEN) { | ||
1033 | /* Non-standard frame: get addr4 from its bogus location after | ||
1034 | * the payload */ | ||
1035 | memcpy(skb->data + ETH_ALEN, | ||
1036 | skb->data + skb->len - ETH_ALEN, ETH_ALEN); | ||
1037 | skb_trim(skb, skb->len - ETH_ALEN); | ||
1038 | } | ||
1039 | |||
1040 | stats->rx_packets++; | ||
1041 | stats->rx_bytes += skb->len; | ||
1042 | |||
1043 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
1044 | local->ap->bridge_packets) { | ||
1045 | if (dst[0] & 0x01) { | ||
1046 | /* copy multicast frame both to the higher layers and | ||
1047 | * to the wireless media */ | ||
1048 | local->ap->bridged_multicast++; | ||
1049 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
1050 | if (skb2 == NULL) | ||
1051 | printk(KERN_DEBUG "%s: skb_clone failed for " | ||
1052 | "multicast frame\n", dev->name); | ||
1053 | } else if (hostap_is_sta_authorized(local->ap, dst)) { | ||
1054 | /* send frame directly to the associated STA using | ||
1055 | * wireless media and not passing to higher layers */ | ||
1056 | local->ap->bridged_unicast++; | ||
1057 | skb2 = skb; | ||
1058 | skb = NULL; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | if (skb2 != NULL) { | ||
1063 | /* send to wireless media */ | ||
1064 | skb2->protocol = __constant_htons(ETH_P_802_3); | ||
1065 | skb2->mac.raw = skb2->nh.raw = skb2->data; | ||
1066 | /* skb2->nh.raw = skb2->data + ETH_HLEN; */ | ||
1067 | skb2->dev = dev; | ||
1068 | dev_queue_xmit(skb2); | ||
1069 | } | ||
1070 | |||
1071 | if (skb) { | ||
1072 | skb->protocol = eth_type_trans(skb, dev); | ||
1073 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1074 | skb->dev = dev; | ||
1075 | netif_rx(skb); | ||
1076 | } | ||
1077 | |||
1078 | rx_exit: | ||
1079 | if (sta) | ||
1080 | hostap_handle_sta_release(sta); | ||
1081 | return; | ||
1082 | |||
1083 | rx_dropped: | ||
1084 | dev_kfree_skb(skb); | ||
1085 | |||
1086 | stats->rx_dropped++; | ||
1087 | goto rx_exit; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | EXPORT_SYMBOL(hostap_80211_rx); | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c new file mode 100644 index 000000000000..6358015f6526 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c | |||
@@ -0,0 +1,524 @@ | |||
1 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | ||
2 | { | ||
3 | struct ieee80211_hdr *hdr; | ||
4 | u16 fc; | ||
5 | |||
6 | hdr = (struct ieee80211_hdr *) skb->data; | ||
7 | |||
8 | printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", | ||
9 | name, skb->len, jiffies); | ||
10 | |||
11 | if (skb->len < 2) | ||
12 | return; | ||
13 | |||
14 | fc = le16_to_cpu(hdr->frame_ctl); | ||
15 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
16 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
17 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
18 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
19 | |||
20 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
21 | printk("\n"); | ||
22 | return; | ||
23 | } | ||
24 | |||
25 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | ||
26 | le16_to_cpu(hdr->seq_ctl)); | ||
27 | |||
28 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, | ||
29 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); | ||
30 | if (skb->len >= 30) | ||
31 | printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); | ||
32 | printk("\n"); | ||
33 | } | ||
34 | |||
35 | |||
36 | /* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) | ||
37 | * Convert Ethernet header into a suitable IEEE 802.11 header depending on | ||
38 | * device configuration. */ | ||
39 | int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
40 | { | ||
41 | struct hostap_interface *iface; | ||
42 | local_info_t *local; | ||
43 | int need_headroom, need_tailroom = 0; | ||
44 | struct ieee80211_hdr hdr; | ||
45 | u16 fc, ethertype = 0; | ||
46 | enum { | ||
47 | WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME | ||
48 | } use_wds = WDS_NO; | ||
49 | u8 *encaps_data; | ||
50 | int hdr_len, encaps_len, skip_header_bytes; | ||
51 | int to_assoc_ap = 0; | ||
52 | struct hostap_skb_tx_data *meta; | ||
53 | |||
54 | iface = netdev_priv(dev); | ||
55 | local = iface->local; | ||
56 | |||
57 | if (skb->len < ETH_HLEN) { | ||
58 | printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " | ||
59 | "(len=%d)\n", dev->name, skb->len); | ||
60 | kfree_skb(skb); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | if (local->ddev != dev) { | ||
65 | use_wds = (local->iw_mode == IW_MODE_MASTER && | ||
66 | !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? | ||
67 | WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; | ||
68 | if (dev == local->stadev) { | ||
69 | to_assoc_ap = 1; | ||
70 | use_wds = WDS_NO; | ||
71 | } else if (dev == local->apdev) { | ||
72 | printk(KERN_DEBUG "%s: prism2_tx: trying to use " | ||
73 | "AP device with Ethernet net dev\n", dev->name); | ||
74 | kfree_skb(skb); | ||
75 | return 0; | ||
76 | } | ||
77 | } else { | ||
78 | if (local->iw_mode == IW_MODE_REPEAT) { | ||
79 | printk(KERN_DEBUG "%s: prism2_tx: trying to use " | ||
80 | "non-WDS link in Repeater mode\n", dev->name); | ||
81 | kfree_skb(skb); | ||
82 | return 0; | ||
83 | } else if (local->iw_mode == IW_MODE_INFRA && | ||
84 | (local->wds_type & HOSTAP_WDS_AP_CLIENT) && | ||
85 | memcmp(skb->data + ETH_ALEN, dev->dev_addr, | ||
86 | ETH_ALEN) != 0) { | ||
87 | /* AP client mode: send frames with foreign src addr | ||
88 | * using 4-addr WDS frames */ | ||
89 | use_wds = WDS_COMPLIANT_FRAME; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload | ||
94 | * ==> | ||
95 | * Prism2 TX frame with 802.11 header: | ||
96 | * txdesc (address order depending on used mode; includes dst_addr and | ||
97 | * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; | ||
98 | * proto[2], payload {, possible addr4[6]} */ | ||
99 | |||
100 | ethertype = (skb->data[12] << 8) | skb->data[13]; | ||
101 | |||
102 | memset(&hdr, 0, sizeof(hdr)); | ||
103 | |||
104 | /* Length of data after IEEE 802.11 header */ | ||
105 | encaps_data = NULL; | ||
106 | encaps_len = 0; | ||
107 | skip_header_bytes = ETH_HLEN; | ||
108 | if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { | ||
109 | encaps_data = bridge_tunnel_header; | ||
110 | encaps_len = sizeof(bridge_tunnel_header); | ||
111 | skip_header_bytes -= 2; | ||
112 | } else if (ethertype >= 0x600) { | ||
113 | encaps_data = rfc1042_header; | ||
114 | encaps_len = sizeof(rfc1042_header); | ||
115 | skip_header_bytes -= 2; | ||
116 | } | ||
117 | |||
118 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; | ||
119 | hdr_len = IEEE80211_DATA_HDR3_LEN; | ||
120 | |||
121 | if (use_wds != WDS_NO) { | ||
122 | /* Note! Prism2 station firmware has problems with sending real | ||
123 | * 802.11 frames with four addresses; until these problems can | ||
124 | * be fixed or worked around, 4-addr frames needed for WDS are | ||
125 | * using incompatible format: FromDS flag is not set and the | ||
126 | * fourth address is added after the frame payload; it is | ||
127 | * assumed, that the receiving station knows how to handle this | ||
128 | * frame format */ | ||
129 | |||
130 | if (use_wds == WDS_COMPLIANT_FRAME) { | ||
131 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | ||
132 | /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, | ||
133 | * Addr4 = SA */ | ||
134 | memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
135 | hdr_len += ETH_ALEN; | ||
136 | } else { | ||
137 | /* bogus 4-addr format to workaround Prism2 station | ||
138 | * f/w bug */ | ||
139 | fc |= IEEE80211_FCTL_TODS; | ||
140 | /* From DS: Addr1 = DA (used as RA), | ||
141 | * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), | ||
142 | */ | ||
143 | |||
144 | /* SA from skb->data + ETH_ALEN will be added after | ||
145 | * frame payload; use hdr.addr4 as a temporary buffer | ||
146 | */ | ||
147 | memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
148 | need_tailroom += ETH_ALEN; | ||
149 | } | ||
150 | |||
151 | /* send broadcast and multicast frames to broadcast RA, if | ||
152 | * configured; otherwise, use unicast RA of the WDS link */ | ||
153 | if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && | ||
154 | skb->data[0] & 0x01) | ||
155 | memset(&hdr.addr1, 0xff, ETH_ALEN); | ||
156 | else if (iface->type == HOSTAP_INTERFACE_WDS) | ||
157 | memcpy(&hdr.addr1, iface->u.wds.remote_addr, | ||
158 | ETH_ALEN); | ||
159 | else | ||
160 | memcpy(&hdr.addr1, local->bssid, ETH_ALEN); | ||
161 | memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
162 | memcpy(&hdr.addr3, skb->data, ETH_ALEN); | ||
163 | } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { | ||
164 | fc |= IEEE80211_FCTL_FROMDS; | ||
165 | /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ | ||
166 | memcpy(&hdr.addr1, skb->data, ETH_ALEN); | ||
167 | memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
168 | memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | ||
169 | } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { | ||
170 | fc |= IEEE80211_FCTL_TODS; | ||
171 | /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ | ||
172 | memcpy(&hdr.addr1, to_assoc_ap ? | ||
173 | local->assoc_ap_addr : local->bssid, ETH_ALEN); | ||
174 | memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
175 | memcpy(&hdr.addr3, skb->data, ETH_ALEN); | ||
176 | } else if (local->iw_mode == IW_MODE_ADHOC) { | ||
177 | /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ | ||
178 | memcpy(&hdr.addr1, skb->data, ETH_ALEN); | ||
179 | memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
180 | memcpy(&hdr.addr3, local->bssid, ETH_ALEN); | ||
181 | } | ||
182 | |||
183 | hdr.frame_ctl = cpu_to_le16(fc); | ||
184 | |||
185 | skb_pull(skb, skip_header_bytes); | ||
186 | need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; | ||
187 | if (skb_tailroom(skb) < need_tailroom) { | ||
188 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
189 | if (skb == NULL) { | ||
190 | iface->stats.tx_dropped++; | ||
191 | return 0; | ||
192 | } | ||
193 | if (pskb_expand_head(skb, need_headroom, need_tailroom, | ||
194 | GFP_ATOMIC)) { | ||
195 | kfree_skb(skb); | ||
196 | iface->stats.tx_dropped++; | ||
197 | return 0; | ||
198 | } | ||
199 | } else if (skb_headroom(skb) < need_headroom) { | ||
200 | struct sk_buff *tmp = skb; | ||
201 | skb = skb_realloc_headroom(skb, need_headroom); | ||
202 | kfree_skb(tmp); | ||
203 | if (skb == NULL) { | ||
204 | iface->stats.tx_dropped++; | ||
205 | return 0; | ||
206 | } | ||
207 | } else { | ||
208 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
209 | if (skb == NULL) { | ||
210 | iface->stats.tx_dropped++; | ||
211 | return 0; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (encaps_data) | ||
216 | memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); | ||
217 | memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); | ||
218 | if (use_wds == WDS_OWN_FRAME) { | ||
219 | memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN); | ||
220 | } | ||
221 | |||
222 | iface->stats.tx_packets++; | ||
223 | iface->stats.tx_bytes += skb->len; | ||
224 | |||
225 | skb->mac.raw = skb->data; | ||
226 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
227 | memset(meta, 0, sizeof(*meta)); | ||
228 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
229 | if (use_wds) | ||
230 | meta->flags |= HOSTAP_TX_FLAGS_WDS; | ||
231 | meta->ethertype = ethertype; | ||
232 | meta->iface = iface; | ||
233 | |||
234 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
235 | skb->dev = local->dev; | ||
236 | dev_queue_xmit(skb); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* hard_start_xmit function for hostapd wlan#ap interfaces */ | ||
242 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
243 | { | ||
244 | struct hostap_interface *iface; | ||
245 | local_info_t *local; | ||
246 | struct hostap_skb_tx_data *meta; | ||
247 | struct ieee80211_hdr *hdr; | ||
248 | u16 fc; | ||
249 | |||
250 | iface = netdev_priv(dev); | ||
251 | local = iface->local; | ||
252 | |||
253 | if (skb->len < 10) { | ||
254 | printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " | ||
255 | "(len=%d)\n", dev->name, skb->len); | ||
256 | kfree_skb(skb); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | iface->stats.tx_packets++; | ||
261 | iface->stats.tx_bytes += skb->len; | ||
262 | |||
263 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
264 | memset(meta, 0, sizeof(*meta)); | ||
265 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
266 | meta->iface = iface; | ||
267 | |||
268 | if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { | ||
269 | hdr = (struct ieee80211_hdr *) skb->data; | ||
270 | fc = le16_to_cpu(hdr->frame_ctl); | ||
271 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
272 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { | ||
273 | u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + | ||
274 | sizeof(rfc1042_header)]; | ||
275 | meta->ethertype = (pos[0] << 8) | pos[1]; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
280 | skb->dev = local->dev; | ||
281 | dev_queue_xmit(skb); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | |||
286 | /* Called only from software IRQ */ | ||
287 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
288 | struct ieee80211_crypt_data *crypt) | ||
289 | { | ||
290 | struct hostap_interface *iface; | ||
291 | local_info_t *local; | ||
292 | struct ieee80211_hdr *hdr; | ||
293 | u16 fc; | ||
294 | int hdr_len, res; | ||
295 | |||
296 | iface = netdev_priv(skb->dev); | ||
297 | local = iface->local; | ||
298 | |||
299 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
300 | kfree_skb(skb); | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | if (local->tkip_countermeasures && | ||
305 | crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { | ||
306 | hdr = (struct ieee80211_hdr *) skb->data; | ||
307 | if (net_ratelimit()) { | ||
308 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
309 | "TX packet to " MACSTR "\n", | ||
310 | local->dev->name, MAC2STR(hdr->addr1)); | ||
311 | } | ||
312 | kfree_skb(skb); | ||
313 | return NULL; | ||
314 | } | ||
315 | |||
316 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
317 | if (skb == NULL) | ||
318 | return NULL; | ||
319 | |||
320 | if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || | ||
321 | skb_tailroom(skb) < crypt->ops->extra_postfix_len) && | ||
322 | pskb_expand_head(skb, crypt->ops->extra_prefix_len, | ||
323 | crypt->ops->extra_postfix_len, GFP_ATOMIC)) { | ||
324 | kfree_skb(skb); | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
328 | hdr = (struct ieee80211_hdr *) skb->data; | ||
329 | fc = le16_to_cpu(hdr->frame_ctl); | ||
330 | hdr_len = hostap_80211_get_hdrlen(fc); | ||
331 | |||
332 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | ||
333 | * call both MSDU and MPDU encryption functions from here. */ | ||
334 | atomic_inc(&crypt->refcnt); | ||
335 | res = 0; | ||
336 | if (crypt->ops->encrypt_msdu) | ||
337 | res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); | ||
338 | if (res == 0 && crypt->ops->encrypt_mpdu) | ||
339 | res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); | ||
340 | atomic_dec(&crypt->refcnt); | ||
341 | if (res < 0) { | ||
342 | kfree_skb(skb); | ||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | return skb; | ||
347 | } | ||
348 | |||
349 | |||
350 | /* hard_start_xmit function for master radio interface wifi#. | ||
351 | * AP processing (TX rate control, power save buffering, etc.). | ||
352 | * Use hardware TX function to send the frame. */ | ||
353 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
354 | { | ||
355 | struct hostap_interface *iface; | ||
356 | local_info_t *local; | ||
357 | int ret = 1; | ||
358 | u16 fc; | ||
359 | struct hostap_tx_data tx; | ||
360 | ap_tx_ret tx_ret; | ||
361 | struct hostap_skb_tx_data *meta; | ||
362 | int no_encrypt = 0; | ||
363 | struct ieee80211_hdr *hdr; | ||
364 | |||
365 | iface = netdev_priv(dev); | ||
366 | local = iface->local; | ||
367 | |||
368 | tx.skb = skb; | ||
369 | tx.sta_ptr = NULL; | ||
370 | |||
371 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
372 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
373 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
374 | "expected 0x%08x)\n", | ||
375 | dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); | ||
376 | ret = 0; | ||
377 | iface->stats.tx_dropped++; | ||
378 | goto fail; | ||
379 | } | ||
380 | |||
381 | if (local->host_encrypt) { | ||
382 | /* Set crypt to default algorithm and key; will be replaced in | ||
383 | * AP code if STA has own alg/key */ | ||
384 | tx.crypt = local->crypt[local->tx_keyidx]; | ||
385 | tx.host_encrypt = 1; | ||
386 | } else { | ||
387 | tx.crypt = NULL; | ||
388 | tx.host_encrypt = 0; | ||
389 | } | ||
390 | |||
391 | if (skb->len < 24) { | ||
392 | printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " | ||
393 | "(len=%d)\n", dev->name, skb->len); | ||
394 | ret = 0; | ||
395 | iface->stats.tx_dropped++; | ||
396 | goto fail; | ||
397 | } | ||
398 | |||
399 | /* FIX (?): | ||
400 | * Wi-Fi 802.11b test plan suggests that AP should ignore power save | ||
401 | * bit in authentication and (re)association frames and assume tha | ||
402 | * STA remains awake for the response. */ | ||
403 | tx_ret = hostap_handle_sta_tx(local, &tx); | ||
404 | skb = tx.skb; | ||
405 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
406 | hdr = (struct ieee80211_hdr *) skb->data; | ||
407 | fc = le16_to_cpu(hdr->frame_ctl); | ||
408 | switch (tx_ret) { | ||
409 | case AP_TX_CONTINUE: | ||
410 | break; | ||
411 | case AP_TX_CONTINUE_NOT_AUTHORIZED: | ||
412 | if (local->ieee_802_1x && | ||
413 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
414 | meta->ethertype != ETH_P_PAE && | ||
415 | !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { | ||
416 | printk(KERN_DEBUG "%s: dropped frame to unauthorized " | ||
417 | "port (IEEE 802.1X): ethertype=0x%04x\n", | ||
418 | dev->name, meta->ethertype); | ||
419 | hostap_dump_tx_80211(dev->name, skb); | ||
420 | |||
421 | ret = 0; /* drop packet */ | ||
422 | iface->stats.tx_dropped++; | ||
423 | goto fail; | ||
424 | } | ||
425 | break; | ||
426 | case AP_TX_DROP: | ||
427 | ret = 0; /* drop packet */ | ||
428 | iface->stats.tx_dropped++; | ||
429 | goto fail; | ||
430 | case AP_TX_RETRY: | ||
431 | goto fail; | ||
432 | case AP_TX_BUFFERED: | ||
433 | /* do not free skb here, it will be freed when the | ||
434 | * buffered frame is sent/timed out */ | ||
435 | ret = 0; | ||
436 | goto tx_exit; | ||
437 | } | ||
438 | |||
439 | /* Request TX callback if protocol version is 2 in 802.11 header; | ||
440 | * this version 2 is a special case used between hostapd and kernel | ||
441 | * driver */ | ||
442 | if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && | ||
443 | local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { | ||
444 | meta->tx_cb_idx = local->ap->tx_callback_idx; | ||
445 | |||
446 | /* remove special version from the frame header */ | ||
447 | fc &= ~IEEE80211_FCTL_VERS; | ||
448 | hdr->frame_ctl = cpu_to_le16(fc); | ||
449 | } | ||
450 | |||
451 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) { | ||
452 | no_encrypt = 1; | ||
453 | tx.crypt = NULL; | ||
454 | } | ||
455 | |||
456 | if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && | ||
457 | !(fc & IEEE80211_FCTL_VERS)) { | ||
458 | no_encrypt = 1; | ||
459 | PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " | ||
460 | "unencrypted EAPOL frame\n", dev->name); | ||
461 | tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ | ||
462 | } | ||
463 | |||
464 | if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) | ||
465 | tx.crypt = NULL; | ||
466 | else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { | ||
467 | /* Add ISWEP flag both for firmware and host based encryption | ||
468 | */ | ||
469 | fc |= IEEE80211_FCTL_PROTECTED; | ||
470 | hdr->frame_ctl = cpu_to_le16(fc); | ||
471 | } else if (local->drop_unencrypted && | ||
472 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
473 | meta->ethertype != ETH_P_PAE) { | ||
474 | if (net_ratelimit()) { | ||
475 | printk(KERN_DEBUG "%s: dropped unencrypted TX data " | ||
476 | "frame (drop_unencrypted=1)\n", dev->name); | ||
477 | } | ||
478 | iface->stats.tx_dropped++; | ||
479 | ret = 0; | ||
480 | goto fail; | ||
481 | } | ||
482 | |||
483 | if (tx.crypt) { | ||
484 | skb = hostap_tx_encrypt(skb, tx.crypt); | ||
485 | if (skb == NULL) { | ||
486 | printk(KERN_DEBUG "%s: TX - encryption failed\n", | ||
487 | dev->name); | ||
488 | ret = 0; | ||
489 | goto fail; | ||
490 | } | ||
491 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
492 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
493 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
494 | "expected 0x%08x) after hostap_tx_encrypt\n", | ||
495 | dev->name, meta->magic, | ||
496 | HOSTAP_SKB_TX_DATA_MAGIC); | ||
497 | ret = 0; | ||
498 | iface->stats.tx_dropped++; | ||
499 | goto fail; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | if (local->func->tx == NULL || local->func->tx(skb, dev)) { | ||
504 | ret = 0; | ||
505 | iface->stats.tx_dropped++; | ||
506 | } else { | ||
507 | ret = 0; | ||
508 | iface->stats.tx_packets++; | ||
509 | iface->stats.tx_bytes += skb->len; | ||
510 | } | ||
511 | |||
512 | fail: | ||
513 | if (!ret && skb) | ||
514 | dev_kfree_skb(skb); | ||
515 | tx_exit: | ||
516 | if (tx.sta_ptr) | ||
517 | hostap_handle_sta_release(tx.sta_ptr); | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | |||
522 | EXPORT_SYMBOL(hostap_dump_tx_80211); | ||
523 | EXPORT_SYMBOL(hostap_tx_encrypt); | ||
524 | EXPORT_SYMBOL(hostap_master_start_xmit); | ||
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c new file mode 100644 index 000000000000..930cef8367f2 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -0,0 +1,3288 @@ | |||
1 | /* | ||
2 | * Intersil Prism2 driver with Host AP (software access point) support | ||
3 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
4 | * <jkmaline@cc.hut.fi> | ||
5 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
6 | * | ||
7 | * This file is to be included into hostap.c when S/W AP functionality is | ||
8 | * compiled. | ||
9 | * | ||
10 | * AP: FIX: | ||
11 | * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from | ||
12 | * unauthenticated STA, send deauth. frame (8802.11: 5.5) | ||
13 | * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received | ||
14 | * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) | ||
15 | * - if unicast Class 3 received from unauthenticated STA, send deauth. frame | ||
16 | * (8802.11: 5.5) | ||
17 | */ | ||
18 | |||
19 | static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, | ||
20 | DEF_INTS }; | ||
21 | module_param_array(other_ap_policy, int, NULL, 0444); | ||
22 | MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); | ||
23 | |||
24 | static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, | ||
25 | DEF_INTS }; | ||
26 | module_param_array(ap_max_inactivity, int, NULL, 0444); | ||
27 | MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " | ||
28 | "inactivity"); | ||
29 | |||
30 | static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | ||
31 | module_param_array(ap_bridge_packets, int, NULL, 0444); | ||
32 | MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " | ||
33 | "stations"); | ||
34 | |||
35 | static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; | ||
36 | module_param_array(autom_ap_wds, int, NULL, 0444); | ||
37 | MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " | ||
38 | "automatically"); | ||
39 | |||
40 | |||
41 | static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); | ||
42 | static void hostap_event_expired_sta(struct net_device *dev, | ||
43 | struct sta_info *sta); | ||
44 | static void handle_add_proc_queue(void *data); | ||
45 | |||
46 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
47 | static void handle_wds_oper_queue(void *data); | ||
48 | static void prism2_send_mgmt(struct net_device *dev, | ||
49 | u16 type_subtype, char *body, | ||
50 | int body_len, u8 *addr, u16 tx_cb_idx); | ||
51 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
52 | |||
53 | |||
54 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
55 | static int ap_debug_proc_read(char *page, char **start, off_t off, | ||
56 | int count, int *eof, void *data) | ||
57 | { | ||
58 | char *p = page; | ||
59 | struct ap_data *ap = (struct ap_data *) data; | ||
60 | |||
61 | if (off != 0) { | ||
62 | *eof = 1; | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); | ||
67 | p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); | ||
68 | p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ); | ||
69 | p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets); | ||
70 | p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack); | ||
71 | p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds); | ||
72 | p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs); | ||
73 | p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); | ||
74 | |||
75 | return (p - page); | ||
76 | } | ||
77 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
78 | |||
79 | |||
80 | static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) | ||
81 | { | ||
82 | sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; | ||
83 | ap->sta_hash[STA_HASH(sta->addr)] = sta; | ||
84 | } | ||
85 | |||
86 | static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) | ||
87 | { | ||
88 | struct sta_info *s; | ||
89 | |||
90 | s = ap->sta_hash[STA_HASH(sta->addr)]; | ||
91 | if (s == NULL) return; | ||
92 | if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { | ||
93 | ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) | ||
98 | != 0) | ||
99 | s = s->hnext; | ||
100 | if (s->hnext != NULL) | ||
101 | s->hnext = s->hnext->hnext; | ||
102 | else | ||
103 | printk("AP: could not remove STA " MACSTR " from hash table\n", | ||
104 | MAC2STR(sta->addr)); | ||
105 | } | ||
106 | |||
107 | static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) | ||
108 | { | ||
109 | if (sta->ap && sta->local) | ||
110 | hostap_event_expired_sta(sta->local->dev, sta); | ||
111 | |||
112 | if (ap->proc != NULL) { | ||
113 | char name[20]; | ||
114 | sprintf(name, MACSTR, MAC2STR(sta->addr)); | ||
115 | remove_proc_entry(name, ap->proc); | ||
116 | } | ||
117 | |||
118 | if (sta->crypt) { | ||
119 | sta->crypt->ops->deinit(sta->crypt->priv); | ||
120 | kfree(sta->crypt); | ||
121 | sta->crypt = NULL; | ||
122 | } | ||
123 | |||
124 | skb_queue_purge(&sta->tx_buf); | ||
125 | |||
126 | ap->num_sta--; | ||
127 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
128 | if (sta->aid > 0) | ||
129 | ap->sta_aid[sta->aid - 1] = NULL; | ||
130 | |||
131 | if (!sta->ap && sta->u.sta.challenge) | ||
132 | kfree(sta->u.sta.challenge); | ||
133 | del_timer(&sta->timer); | ||
134 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
135 | |||
136 | kfree(sta); | ||
137 | } | ||
138 | |||
139 | |||
140 | static void hostap_set_tim(local_info_t *local, int aid, int set) | ||
141 | { | ||
142 | if (local->func->set_tim) | ||
143 | local->func->set_tim(local->dev, aid, set); | ||
144 | } | ||
145 | |||
146 | |||
147 | static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) | ||
148 | { | ||
149 | union iwreq_data wrqu; | ||
150 | memset(&wrqu, 0, sizeof(wrqu)); | ||
151 | memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | ||
152 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
153 | wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void hostap_event_expired_sta(struct net_device *dev, | ||
158 | struct sta_info *sta) | ||
159 | { | ||
160 | union iwreq_data wrqu; | ||
161 | memset(&wrqu, 0, sizeof(wrqu)); | ||
162 | memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | ||
163 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
164 | wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); | ||
165 | } | ||
166 | |||
167 | |||
168 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
169 | |||
170 | static void ap_handle_timer(unsigned long data) | ||
171 | { | ||
172 | struct sta_info *sta = (struct sta_info *) data; | ||
173 | local_info_t *local; | ||
174 | struct ap_data *ap; | ||
175 | unsigned long next_time = 0; | ||
176 | int was_assoc; | ||
177 | |||
178 | if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { | ||
179 | PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | local = sta->local; | ||
184 | ap = local->ap; | ||
185 | was_assoc = sta->flags & WLAN_STA_ASSOC; | ||
186 | |||
187 | if (atomic_read(&sta->users) != 0) | ||
188 | next_time = jiffies + HZ; | ||
189 | else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) | ||
190 | next_time = jiffies + ap->max_inactivity; | ||
191 | |||
192 | if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { | ||
193 | /* station activity detected; reset timeout state */ | ||
194 | sta->timeout_next = STA_NULLFUNC; | ||
195 | next_time = sta->last_rx + ap->max_inactivity; | ||
196 | } else if (sta->timeout_next == STA_DISASSOC && | ||
197 | !(sta->flags & WLAN_STA_PENDING_POLL)) { | ||
198 | /* STA ACKed data nullfunc frame poll */ | ||
199 | sta->timeout_next = STA_NULLFUNC; | ||
200 | next_time = jiffies + ap->max_inactivity; | ||
201 | } | ||
202 | |||
203 | if (next_time) { | ||
204 | sta->timer.expires = next_time; | ||
205 | add_timer(&sta->timer); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | if (sta->ap) | ||
210 | sta->timeout_next = STA_DEAUTH; | ||
211 | |||
212 | if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { | ||
213 | spin_lock(&ap->sta_table_lock); | ||
214 | ap_sta_hash_del(ap, sta); | ||
215 | list_del(&sta->list); | ||
216 | spin_unlock(&ap->sta_table_lock); | ||
217 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | ||
218 | } else if (sta->timeout_next == STA_DISASSOC) | ||
219 | sta->flags &= ~WLAN_STA_ASSOC; | ||
220 | |||
221 | if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
222 | hostap_event_expired_sta(local->dev, sta); | ||
223 | |||
224 | if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && | ||
225 | !skb_queue_empty(&sta->tx_buf)) { | ||
226 | hostap_set_tim(local, sta->aid, 0); | ||
227 | sta->flags &= ~WLAN_STA_TIM; | ||
228 | } | ||
229 | |||
230 | if (sta->ap) { | ||
231 | if (ap->autom_ap_wds) { | ||
232 | PDEBUG(DEBUG_AP, "%s: removing automatic WDS " | ||
233 | "connection to AP " MACSTR "\n", | ||
234 | local->dev->name, MAC2STR(sta->addr)); | ||
235 | hostap_wds_link_oper(local, sta->addr, WDS_DEL); | ||
236 | } | ||
237 | } else if (sta->timeout_next == STA_NULLFUNC) { | ||
238 | /* send data frame to poll STA and check whether this frame | ||
239 | * is ACKed */ | ||
240 | /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but | ||
241 | * it is apparently not retried so TX Exc events are not | ||
242 | * received for it */ | ||
243 | sta->flags |= WLAN_STA_PENDING_POLL; | ||
244 | prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | | ||
245 | IEEE80211_STYPE_DATA, NULL, 0, | ||
246 | sta->addr, ap->tx_callback_poll); | ||
247 | } else { | ||
248 | int deauth = sta->timeout_next == STA_DEAUTH; | ||
249 | u16 resp; | ||
250 | PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR | ||
251 | "(last=%lu, jiffies=%lu)\n", | ||
252 | local->dev->name, | ||
253 | deauth ? "deauthentication" : "disassociation", | ||
254 | MAC2STR(sta->addr), sta->last_rx, jiffies); | ||
255 | |||
256 | resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : | ||
257 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
258 | prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | | ||
259 | (deauth ? IEEE80211_STYPE_DEAUTH : | ||
260 | IEEE80211_STYPE_DISASSOC), | ||
261 | (char *) &resp, 2, sta->addr, 0); | ||
262 | } | ||
263 | |||
264 | if (sta->timeout_next == STA_DEAUTH) { | ||
265 | if (sta->flags & WLAN_STA_PERM) { | ||
266 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been " | ||
267 | "removed, but it has 'perm' flag\n", | ||
268 | local->dev->name, MAC2STR(sta->addr)); | ||
269 | } else | ||
270 | ap_free_sta(ap, sta); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | if (sta->timeout_next == STA_NULLFUNC) { | ||
275 | sta->timeout_next = STA_DISASSOC; | ||
276 | sta->timer.expires = jiffies + AP_DISASSOC_DELAY; | ||
277 | } else { | ||
278 | sta->timeout_next = STA_DEAUTH; | ||
279 | sta->timer.expires = jiffies + AP_DEAUTH_DELAY; | ||
280 | } | ||
281 | |||
282 | add_timer(&sta->timer); | ||
283 | } | ||
284 | |||
285 | |||
286 | void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | ||
287 | int resend) | ||
288 | { | ||
289 | u8 addr[ETH_ALEN]; | ||
290 | u16 resp; | ||
291 | int i; | ||
292 | |||
293 | PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); | ||
294 | memset(addr, 0xff, ETH_ALEN); | ||
295 | |||
296 | resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
297 | |||
298 | /* deauth message sent; try to resend it few times; the message is | ||
299 | * broadcast, so it may be delayed until next DTIM; there is not much | ||
300 | * else we can do at this point since the driver is going to be shut | ||
301 | * down */ | ||
302 | for (i = 0; i < 5; i++) { | ||
303 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
304 | IEEE80211_STYPE_DEAUTH, | ||
305 | (char *) &resp, 2, addr, 0); | ||
306 | |||
307 | if (!resend || ap->num_sta <= 0) | ||
308 | return; | ||
309 | |||
310 | mdelay(50); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | |||
315 | static int ap_control_proc_read(char *page, char **start, off_t off, | ||
316 | int count, int *eof, void *data) | ||
317 | { | ||
318 | char *p = page; | ||
319 | struct ap_data *ap = (struct ap_data *) data; | ||
320 | char *policy_txt; | ||
321 | struct list_head *ptr; | ||
322 | struct mac_entry *entry; | ||
323 | |||
324 | if (off != 0) { | ||
325 | *eof = 1; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | switch (ap->mac_restrictions.policy) { | ||
330 | case MAC_POLICY_OPEN: | ||
331 | policy_txt = "open"; | ||
332 | break; | ||
333 | case MAC_POLICY_ALLOW: | ||
334 | policy_txt = "allow"; | ||
335 | break; | ||
336 | case MAC_POLICY_DENY: | ||
337 | policy_txt = "deny"; | ||
338 | break; | ||
339 | default: | ||
340 | policy_txt = "unknown"; | ||
341 | break; | ||
342 | }; | ||
343 | p += sprintf(p, "MAC policy: %s\n", policy_txt); | ||
344 | p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); | ||
345 | p += sprintf(p, "MAC list:\n"); | ||
346 | spin_lock_bh(&ap->mac_restrictions.lock); | ||
347 | for (ptr = ap->mac_restrictions.mac_list.next; | ||
348 | ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) { | ||
349 | if (p - page > PAGE_SIZE - 80) { | ||
350 | p += sprintf(p, "All entries did not fit one page.\n"); | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | entry = list_entry(ptr, struct mac_entry, list); | ||
355 | p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); | ||
356 | } | ||
357 | spin_unlock_bh(&ap->mac_restrictions.lock); | ||
358 | |||
359 | return (p - page); | ||
360 | } | ||
361 | |||
362 | |||
363 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
364 | u8 *mac) | ||
365 | { | ||
366 | struct mac_entry *entry; | ||
367 | |||
368 | entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); | ||
369 | if (entry == NULL) | ||
370 | return -1; | ||
371 | |||
372 | memcpy(entry->addr, mac, ETH_ALEN); | ||
373 | |||
374 | spin_lock_bh(&mac_restrictions->lock); | ||
375 | list_add_tail(&entry->list, &mac_restrictions->mac_list); | ||
376 | mac_restrictions->entries++; | ||
377 | spin_unlock_bh(&mac_restrictions->lock); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | |||
383 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
384 | u8 *mac) | ||
385 | { | ||
386 | struct list_head *ptr; | ||
387 | struct mac_entry *entry; | ||
388 | |||
389 | spin_lock_bh(&mac_restrictions->lock); | ||
390 | for (ptr = mac_restrictions->mac_list.next; | ||
391 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
392 | entry = list_entry(ptr, struct mac_entry, list); | ||
393 | |||
394 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
395 | list_del(ptr); | ||
396 | kfree(entry); | ||
397 | mac_restrictions->entries--; | ||
398 | spin_unlock_bh(&mac_restrictions->lock); | ||
399 | return 0; | ||
400 | } | ||
401 | } | ||
402 | spin_unlock_bh(&mac_restrictions->lock); | ||
403 | return -1; | ||
404 | } | ||
405 | |||
406 | |||
407 | static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, | ||
408 | u8 *mac) | ||
409 | { | ||
410 | struct list_head *ptr; | ||
411 | struct mac_entry *entry; | ||
412 | int found = 0; | ||
413 | |||
414 | if (mac_restrictions->policy == MAC_POLICY_OPEN) | ||
415 | return 0; | ||
416 | |||
417 | spin_lock_bh(&mac_restrictions->lock); | ||
418 | for (ptr = mac_restrictions->mac_list.next; | ||
419 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
420 | entry = list_entry(ptr, struct mac_entry, list); | ||
421 | |||
422 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
423 | found = 1; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | spin_unlock_bh(&mac_restrictions->lock); | ||
428 | |||
429 | if (mac_restrictions->policy == MAC_POLICY_ALLOW) | ||
430 | return !found; | ||
431 | else | ||
432 | return found; | ||
433 | } | ||
434 | |||
435 | |||
436 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) | ||
437 | { | ||
438 | struct list_head *ptr, *n; | ||
439 | struct mac_entry *entry; | ||
440 | |||
441 | if (mac_restrictions->entries == 0) | ||
442 | return; | ||
443 | |||
444 | spin_lock_bh(&mac_restrictions->lock); | ||
445 | for (ptr = mac_restrictions->mac_list.next, n = ptr->next; | ||
446 | ptr != &mac_restrictions->mac_list; | ||
447 | ptr = n, n = ptr->next) { | ||
448 | entry = list_entry(ptr, struct mac_entry, list); | ||
449 | list_del(ptr); | ||
450 | kfree(entry); | ||
451 | } | ||
452 | mac_restrictions->entries = 0; | ||
453 | spin_unlock_bh(&mac_restrictions->lock); | ||
454 | } | ||
455 | |||
456 | |||
457 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
458 | u8 *mac) | ||
459 | { | ||
460 | struct sta_info *sta; | ||
461 | u16 resp; | ||
462 | |||
463 | spin_lock_bh(&ap->sta_table_lock); | ||
464 | sta = ap_get_sta(ap, mac); | ||
465 | if (sta) { | ||
466 | ap_sta_hash_del(ap, sta); | ||
467 | list_del(&sta->list); | ||
468 | } | ||
469 | spin_unlock_bh(&ap->sta_table_lock); | ||
470 | |||
471 | if (!sta) | ||
472 | return -EINVAL; | ||
473 | |||
474 | resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
475 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, | ||
476 | (char *) &resp, 2, sta->addr, 0); | ||
477 | |||
478 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
479 | hostap_event_expired_sta(dev, sta); | ||
480 | |||
481 | ap_free_sta(ap, sta); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
487 | |||
488 | |||
489 | static void ap_control_kickall(struct ap_data *ap) | ||
490 | { | ||
491 | struct list_head *ptr, *n; | ||
492 | struct sta_info *sta; | ||
493 | |||
494 | spin_lock_bh(&ap->sta_table_lock); | ||
495 | for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; | ||
496 | ptr = n, n = ptr->next) { | ||
497 | sta = list_entry(ptr, struct sta_info, list); | ||
498 | ap_sta_hash_del(ap, sta); | ||
499 | list_del(&sta->list); | ||
500 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
501 | hostap_event_expired_sta(sta->local->dev, sta); | ||
502 | ap_free_sta(ap, sta); | ||
503 | } | ||
504 | spin_unlock_bh(&ap->sta_table_lock); | ||
505 | } | ||
506 | |||
507 | |||
508 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
509 | |||
510 | #define PROC_LIMIT (PAGE_SIZE - 80) | ||
511 | |||
512 | static int prism2_ap_proc_read(char *page, char **start, off_t off, | ||
513 | int count, int *eof, void *data) | ||
514 | { | ||
515 | char *p = page; | ||
516 | struct ap_data *ap = (struct ap_data *) data; | ||
517 | struct list_head *ptr; | ||
518 | int i; | ||
519 | |||
520 | if (off > PROC_LIMIT) { | ||
521 | *eof = 1; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); | ||
526 | spin_lock_bh(&ap->sta_table_lock); | ||
527 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
528 | struct sta_info *sta = (struct sta_info *) ptr; | ||
529 | |||
530 | if (!sta->ap) | ||
531 | continue; | ||
532 | |||
533 | p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), | ||
534 | sta->u.ap.channel, sta->last_rx_signal, | ||
535 | sta->last_rx_silence, sta->last_rx_rate); | ||
536 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
537 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
538 | sta->u.ap.ssid[i] < 127) ? | ||
539 | "%c" : "<%02x>"), | ||
540 | sta->u.ap.ssid[i]); | ||
541 | p += sprintf(p, "'"); | ||
542 | if (sta->capability & WLAN_CAPABILITY_ESS) | ||
543 | p += sprintf(p, " [ESS]"); | ||
544 | if (sta->capability & WLAN_CAPABILITY_IBSS) | ||
545 | p += sprintf(p, " [IBSS]"); | ||
546 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
547 | p += sprintf(p, " [WEP]"); | ||
548 | p += sprintf(p, "\n"); | ||
549 | |||
550 | if ((p - page) > PROC_LIMIT) { | ||
551 | printk(KERN_DEBUG "hostap: ap proc did not fit\n"); | ||
552 | break; | ||
553 | } | ||
554 | } | ||
555 | spin_unlock_bh(&ap->sta_table_lock); | ||
556 | |||
557 | if ((p - page) <= off) { | ||
558 | *eof = 1; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | *start = page + off; | ||
563 | |||
564 | return (p - page - off); | ||
565 | } | ||
566 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
567 | |||
568 | |||
569 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) | ||
570 | { | ||
571 | if (!ap) | ||
572 | return; | ||
573 | |||
574 | if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { | ||
575 | PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " | ||
576 | "firmware upgrade recommended\n"); | ||
577 | ap->nullfunc_ack = 1; | ||
578 | } else | ||
579 | ap->nullfunc_ack = 0; | ||
580 | |||
581 | if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { | ||
582 | printk(KERN_WARNING "%s: Warning: secondary station firmware " | ||
583 | "version 1.4.2 does not seem to work in Host AP mode\n", | ||
584 | ap->local->dev->name); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | |||
589 | /* Called only as a tasklet (software IRQ) */ | ||
590 | static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) | ||
591 | { | ||
592 | struct ap_data *ap = data; | ||
593 | u16 fc; | ||
594 | struct ieee80211_hdr *hdr; | ||
595 | |||
596 | if (!ap->local->hostapd || !ap->local->apdev) { | ||
597 | dev_kfree_skb(skb); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | hdr = (struct ieee80211_hdr *) skb->data; | ||
602 | fc = le16_to_cpu(hdr->frame_ctl); | ||
603 | |||
604 | /* Pass the TX callback frame to the hostapd; use 802.11 header version | ||
605 | * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ | ||
606 | |||
607 | fc &= ~IEEE80211_FCTL_VERS; | ||
608 | fc |= ok ? BIT(1) : BIT(0); | ||
609 | hdr->frame_ctl = cpu_to_le16(fc); | ||
610 | |||
611 | skb->dev = ap->local->apdev; | ||
612 | skb_pull(skb, hostap_80211_get_hdrlen(fc)); | ||
613 | skb->pkt_type = PACKET_OTHERHOST; | ||
614 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
615 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
616 | netif_rx(skb); | ||
617 | } | ||
618 | |||
619 | |||
620 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
621 | /* Called only as a tasklet (software IRQ) */ | ||
622 | static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | ||
623 | { | ||
624 | struct ap_data *ap = data; | ||
625 | struct net_device *dev = ap->local->dev; | ||
626 | struct ieee80211_hdr *hdr; | ||
627 | u16 fc, *pos, auth_alg, auth_transaction, status; | ||
628 | struct sta_info *sta = NULL; | ||
629 | char *txt = NULL; | ||
630 | |||
631 | if (ap->local->hostapd) { | ||
632 | dev_kfree_skb(skb); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | hdr = (struct ieee80211_hdr *) skb->data; | ||
637 | fc = le16_to_cpu(hdr->frame_ctl); | ||
638 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | ||
639 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || | ||
640 | skb->len < IEEE80211_MGMT_HDR_LEN + 6) { | ||
641 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " | ||
642 | "frame\n", dev->name); | ||
643 | dev_kfree_skb(skb); | ||
644 | return; | ||
645 | } | ||
646 | |||
647 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
648 | auth_alg = le16_to_cpu(*pos++); | ||
649 | auth_transaction = le16_to_cpu(*pos++); | ||
650 | status = le16_to_cpu(*pos++); | ||
651 | |||
652 | if (!ok) { | ||
653 | txt = "frame was not ACKed"; | ||
654 | goto done; | ||
655 | } | ||
656 | |||
657 | spin_lock(&ap->sta_table_lock); | ||
658 | sta = ap_get_sta(ap, hdr->addr1); | ||
659 | if (sta) | ||
660 | atomic_inc(&sta->users); | ||
661 | spin_unlock(&ap->sta_table_lock); | ||
662 | |||
663 | if (!sta) { | ||
664 | txt = "STA not found"; | ||
665 | goto done; | ||
666 | } | ||
667 | |||
668 | if (status == WLAN_STATUS_SUCCESS && | ||
669 | ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || | ||
670 | (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { | ||
671 | txt = "STA authenticated"; | ||
672 | sta->flags |= WLAN_STA_AUTH; | ||
673 | sta->last_auth = jiffies; | ||
674 | } else if (status != WLAN_STATUS_SUCCESS) | ||
675 | txt = "authentication failed"; | ||
676 | |||
677 | done: | ||
678 | if (sta) | ||
679 | atomic_dec(&sta->users); | ||
680 | if (txt) { | ||
681 | PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " | ||
682 | "status=%d - %s\n", | ||
683 | dev->name, MAC2STR(hdr->addr1), auth_alg, | ||
684 | auth_transaction, status, txt); | ||
685 | } | ||
686 | dev_kfree_skb(skb); | ||
687 | } | ||
688 | |||
689 | |||
690 | /* Called only as a tasklet (software IRQ) */ | ||
691 | static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | ||
692 | { | ||
693 | struct ap_data *ap = data; | ||
694 | struct net_device *dev = ap->local->dev; | ||
695 | struct ieee80211_hdr *hdr; | ||
696 | u16 fc, *pos, status; | ||
697 | struct sta_info *sta = NULL; | ||
698 | char *txt = NULL; | ||
699 | |||
700 | if (ap->local->hostapd) { | ||
701 | dev_kfree_skb(skb); | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | hdr = (struct ieee80211_hdr *) skb->data; | ||
706 | fc = le16_to_cpu(hdr->frame_ctl); | ||
707 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | ||
708 | (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && | ||
709 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) || | ||
710 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | ||
711 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " | ||
712 | "frame\n", dev->name); | ||
713 | dev_kfree_skb(skb); | ||
714 | return; | ||
715 | } | ||
716 | |||
717 | if (!ok) { | ||
718 | txt = "frame was not ACKed"; | ||
719 | goto done; | ||
720 | } | ||
721 | |||
722 | spin_lock(&ap->sta_table_lock); | ||
723 | sta = ap_get_sta(ap, hdr->addr1); | ||
724 | if (sta) | ||
725 | atomic_inc(&sta->users); | ||
726 | spin_unlock(&ap->sta_table_lock); | ||
727 | |||
728 | if (!sta) { | ||
729 | txt = "STA not found"; | ||
730 | goto done; | ||
731 | } | ||
732 | |||
733 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
734 | pos++; | ||
735 | status = le16_to_cpu(*pos++); | ||
736 | if (status == WLAN_STATUS_SUCCESS) { | ||
737 | if (!(sta->flags & WLAN_STA_ASSOC)) | ||
738 | hostap_event_new_sta(dev, sta); | ||
739 | txt = "STA associated"; | ||
740 | sta->flags |= WLAN_STA_ASSOC; | ||
741 | sta->last_assoc = jiffies; | ||
742 | } else | ||
743 | txt = "association failed"; | ||
744 | |||
745 | done: | ||
746 | if (sta) | ||
747 | atomic_dec(&sta->users); | ||
748 | if (txt) { | ||
749 | PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", | ||
750 | dev->name, MAC2STR(hdr->addr1), txt); | ||
751 | } | ||
752 | dev_kfree_skb(skb); | ||
753 | } | ||
754 | |||
755 | /* Called only as a tasklet (software IRQ); TX callback for poll frames used | ||
756 | * in verifying whether the STA is still present. */ | ||
757 | static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) | ||
758 | { | ||
759 | struct ap_data *ap = data; | ||
760 | struct ieee80211_hdr *hdr; | ||
761 | struct sta_info *sta; | ||
762 | |||
763 | if (skb->len < 24) | ||
764 | goto fail; | ||
765 | hdr = (struct ieee80211_hdr *) skb->data; | ||
766 | if (ok) { | ||
767 | spin_lock(&ap->sta_table_lock); | ||
768 | sta = ap_get_sta(ap, hdr->addr1); | ||
769 | if (sta) | ||
770 | sta->flags &= ~WLAN_STA_PENDING_POLL; | ||
771 | spin_unlock(&ap->sta_table_lock); | ||
772 | } else { | ||
773 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " | ||
774 | "poll frame\n", ap->local->dev->name, | ||
775 | MAC2STR(hdr->addr1)); | ||
776 | } | ||
777 | |||
778 | fail: | ||
779 | dev_kfree_skb(skb); | ||
780 | } | ||
781 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
782 | |||
783 | |||
784 | void hostap_init_data(local_info_t *local) | ||
785 | { | ||
786 | struct ap_data *ap = local->ap; | ||
787 | |||
788 | if (ap == NULL) { | ||
789 | printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); | ||
790 | return; | ||
791 | } | ||
792 | memset(ap, 0, sizeof(struct ap_data)); | ||
793 | ap->local = local; | ||
794 | |||
795 | ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); | ||
796 | ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); | ||
797 | ap->max_inactivity = | ||
798 | GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; | ||
799 | ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); | ||
800 | |||
801 | spin_lock_init(&ap->sta_table_lock); | ||
802 | INIT_LIST_HEAD(&ap->sta_list); | ||
803 | |||
804 | /* Initialize task queue structure for AP management */ | ||
805 | INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); | ||
806 | |||
807 | ap->tx_callback_idx = | ||
808 | hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); | ||
809 | if (ap->tx_callback_idx == 0) | ||
810 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
811 | "AP\n", local->dev->name); | ||
812 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
813 | INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); | ||
814 | |||
815 | ap->tx_callback_auth = | ||
816 | hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); | ||
817 | ap->tx_callback_assoc = | ||
818 | hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); | ||
819 | ap->tx_callback_poll = | ||
820 | hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); | ||
821 | if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || | ||
822 | ap->tx_callback_poll == 0) | ||
823 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
824 | "AP\n", local->dev->name); | ||
825 | |||
826 | spin_lock_init(&ap->mac_restrictions.lock); | ||
827 | INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); | ||
828 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
829 | |||
830 | ap->initialized = 1; | ||
831 | } | ||
832 | |||
833 | |||
834 | void hostap_init_ap_proc(local_info_t *local) | ||
835 | { | ||
836 | struct ap_data *ap = local->ap; | ||
837 | |||
838 | ap->proc = local->proc; | ||
839 | if (ap->proc == NULL) | ||
840 | return; | ||
841 | |||
842 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
843 | create_proc_read_entry("ap_debug", 0, ap->proc, | ||
844 | ap_debug_proc_read, ap); | ||
845 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
846 | |||
847 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
848 | create_proc_read_entry("ap_control", 0, ap->proc, | ||
849 | ap_control_proc_read, ap); | ||
850 | create_proc_read_entry("ap", 0, ap->proc, | ||
851 | prism2_ap_proc_read, ap); | ||
852 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
853 | |||
854 | } | ||
855 | |||
856 | |||
857 | void hostap_free_data(struct ap_data *ap) | ||
858 | { | ||
859 | struct list_head *n, *ptr; | ||
860 | |||
861 | if (ap == NULL || !ap->initialized) { | ||
862 | printk(KERN_DEBUG "hostap_free_data: ap has not yet been " | ||
863 | "initialized - skip resource freeing\n"); | ||
864 | return; | ||
865 | } | ||
866 | |||
867 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
868 | if (ap->crypt) | ||
869 | ap->crypt->deinit(ap->crypt_priv); | ||
870 | ap->crypt = ap->crypt_priv = NULL; | ||
871 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
872 | |||
873 | list_for_each_safe(ptr, n, &ap->sta_list) { | ||
874 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
875 | ap_sta_hash_del(ap, sta); | ||
876 | list_del(&sta->list); | ||
877 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
878 | hostap_event_expired_sta(sta->local->dev, sta); | ||
879 | ap_free_sta(ap, sta); | ||
880 | } | ||
881 | |||
882 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
883 | if (ap->proc != NULL) { | ||
884 | remove_proc_entry("ap_debug", ap->proc); | ||
885 | } | ||
886 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
887 | |||
888 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
889 | if (ap->proc != NULL) { | ||
890 | remove_proc_entry("ap", ap->proc); | ||
891 | remove_proc_entry("ap_control", ap->proc); | ||
892 | } | ||
893 | ap_control_flush_macs(&ap->mac_restrictions); | ||
894 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
895 | |||
896 | ap->initialized = 0; | ||
897 | } | ||
898 | |||
899 | |||
900 | /* caller should have mutex for AP STA list handling */ | ||
901 | static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) | ||
902 | { | ||
903 | struct sta_info *s; | ||
904 | |||
905 | s = ap->sta_hash[STA_HASH(sta)]; | ||
906 | while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0) | ||
907 | s = s->hnext; | ||
908 | return s; | ||
909 | } | ||
910 | |||
911 | |||
912 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
913 | |||
914 | /* Called from timer handler and from scheduled AP queue handlers */ | ||
915 | static void prism2_send_mgmt(struct net_device *dev, | ||
916 | u16 type_subtype, char *body, | ||
917 | int body_len, u8 *addr, u16 tx_cb_idx) | ||
918 | { | ||
919 | struct hostap_interface *iface; | ||
920 | local_info_t *local; | ||
921 | struct ieee80211_hdr *hdr; | ||
922 | u16 fc; | ||
923 | struct sk_buff *skb; | ||
924 | struct hostap_skb_tx_data *meta; | ||
925 | int hdrlen; | ||
926 | |||
927 | iface = netdev_priv(dev); | ||
928 | local = iface->local; | ||
929 | dev = local->dev; /* always use master radio device */ | ||
930 | iface = netdev_priv(dev); | ||
931 | |||
932 | if (!(dev->flags & IFF_UP)) { | ||
933 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " | ||
934 | "cannot send frame\n", dev->name); | ||
935 | return; | ||
936 | } | ||
937 | |||
938 | skb = dev_alloc_skb(sizeof(*hdr) + body_len); | ||
939 | if (skb == NULL) { | ||
940 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " | ||
941 | "skb\n", dev->name); | ||
942 | return; | ||
943 | } | ||
944 | |||
945 | fc = type_subtype; | ||
946 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
947 | hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); | ||
948 | if (body) | ||
949 | memcpy(skb_put(skb, body_len), body, body_len); | ||
950 | |||
951 | memset(hdr, 0, hdrlen); | ||
952 | |||
953 | /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 | ||
954 | * tx_control instead of using local->tx_control */ | ||
955 | |||
956 | |||
957 | memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ | ||
958 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) { | ||
959 | fc |= IEEE80211_FCTL_FROMDS; | ||
960 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
961 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ | ||
962 | } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) { | ||
963 | /* control:ACK does not have addr2 or addr3 */ | ||
964 | memset(hdr->addr2, 0, ETH_ALEN); | ||
965 | memset(hdr->addr3, 0, ETH_ALEN); | ||
966 | } else { | ||
967 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ | ||
968 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
969 | } | ||
970 | |||
971 | hdr->frame_ctl = cpu_to_le16(fc); | ||
972 | |||
973 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
974 | memset(meta, 0, sizeof(*meta)); | ||
975 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
976 | meta->iface = iface; | ||
977 | meta->tx_cb_idx = tx_cb_idx; | ||
978 | |||
979 | skb->dev = dev; | ||
980 | skb->mac.raw = skb->nh.raw = skb->data; | ||
981 | dev_queue_xmit(skb); | ||
982 | } | ||
983 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
984 | |||
985 | |||
986 | static int prism2_sta_proc_read(char *page, char **start, off_t off, | ||
987 | int count, int *eof, void *data) | ||
988 | { | ||
989 | char *p = page; | ||
990 | struct sta_info *sta = (struct sta_info *) data; | ||
991 | int i; | ||
992 | |||
993 | /* FIX: possible race condition.. the STA data could have just expired, | ||
994 | * but proc entry was still here so that the read could have started; | ||
995 | * some locking should be done here.. */ | ||
996 | |||
997 | if (off != 0) { | ||
998 | *eof = 1; | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" | ||
1003 | "flags=0x%04x%s%s%s%s%s%s%s\n" | ||
1004 | "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", | ||
1005 | sta->ap ? "AP" : "STA", | ||
1006 | MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, | ||
1007 | sta->flags, | ||
1008 | sta->flags & WLAN_STA_AUTH ? " AUTH" : "", | ||
1009 | sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", | ||
1010 | sta->flags & WLAN_STA_PS ? " PS" : "", | ||
1011 | sta->flags & WLAN_STA_TIM ? " TIM" : "", | ||
1012 | sta->flags & WLAN_STA_PERM ? " PERM" : "", | ||
1013 | sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", | ||
1014 | sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", | ||
1015 | sta->capability, sta->listen_interval); | ||
1016 | /* supported_rates: 500 kbit/s units with msb ignored */ | ||
1017 | for (i = 0; i < sizeof(sta->supported_rates); i++) | ||
1018 | if (sta->supported_rates[i] != 0) | ||
1019 | p += sprintf(p, "%d%sMbps ", | ||
1020 | (sta->supported_rates[i] & 0x7f) / 2, | ||
1021 | sta->supported_rates[i] & 1 ? ".5" : ""); | ||
1022 | p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" | ||
1023 | "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" | ||
1024 | "tx_packets=%lu\n" | ||
1025 | "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" | ||
1026 | "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" | ||
1027 | "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" | ||
1028 | "tx[11M]=%d\n" | ||
1029 | "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", | ||
1030 | jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, | ||
1031 | sta->last_tx, | ||
1032 | sta->rx_packets, sta->tx_packets, sta->rx_bytes, | ||
1033 | sta->tx_bytes, skb_queue_len(&sta->tx_buf), | ||
1034 | sta->last_rx_silence, | ||
1035 | sta->last_rx_signal, sta->last_rx_rate / 10, | ||
1036 | sta->last_rx_rate % 10 ? ".5" : "", | ||
1037 | sta->tx_rate, sta->tx_count[0], sta->tx_count[1], | ||
1038 | sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], | ||
1039 | sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); | ||
1040 | if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) | ||
1041 | p = sta->crypt->ops->print_stats(p, sta->crypt->priv); | ||
1042 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1043 | if (sta->ap) { | ||
1044 | if (sta->u.ap.channel >= 0) | ||
1045 | p += sprintf(p, "channel=%d\n", sta->u.ap.channel); | ||
1046 | p += sprintf(p, "ssid="); | ||
1047 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
1048 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
1049 | sta->u.ap.ssid[i] < 127) ? | ||
1050 | "%c" : "<%02x>"), | ||
1051 | sta->u.ap.ssid[i]); | ||
1052 | p += sprintf(p, "\n"); | ||
1053 | } | ||
1054 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1055 | |||
1056 | return (p - page); | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | static void handle_add_proc_queue(void *data) | ||
1061 | { | ||
1062 | struct ap_data *ap = (struct ap_data *) data; | ||
1063 | struct sta_info *sta; | ||
1064 | char name[20]; | ||
1065 | struct add_sta_proc_data *entry, *prev; | ||
1066 | |||
1067 | entry = ap->add_sta_proc_entries; | ||
1068 | ap->add_sta_proc_entries = NULL; | ||
1069 | |||
1070 | while (entry) { | ||
1071 | spin_lock_bh(&ap->sta_table_lock); | ||
1072 | sta = ap_get_sta(ap, entry->addr); | ||
1073 | if (sta) | ||
1074 | atomic_inc(&sta->users); | ||
1075 | spin_unlock_bh(&ap->sta_table_lock); | ||
1076 | |||
1077 | if (sta) { | ||
1078 | sprintf(name, MACSTR, MAC2STR(sta->addr)); | ||
1079 | sta->proc = create_proc_read_entry( | ||
1080 | name, 0, ap->proc, | ||
1081 | prism2_sta_proc_read, sta); | ||
1082 | |||
1083 | atomic_dec(&sta->users); | ||
1084 | } | ||
1085 | |||
1086 | prev = entry; | ||
1087 | entry = entry->next; | ||
1088 | kfree(prev); | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) | ||
1094 | { | ||
1095 | struct sta_info *sta; | ||
1096 | |||
1097 | sta = (struct sta_info *) | ||
1098 | kmalloc(sizeof(struct sta_info), GFP_ATOMIC); | ||
1099 | if (sta == NULL) { | ||
1100 | PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); | ||
1101 | return NULL; | ||
1102 | } | ||
1103 | |||
1104 | /* initialize STA info data */ | ||
1105 | memset(sta, 0, sizeof(struct sta_info)); | ||
1106 | sta->local = ap->local; | ||
1107 | skb_queue_head_init(&sta->tx_buf); | ||
1108 | memcpy(sta->addr, addr, ETH_ALEN); | ||
1109 | |||
1110 | atomic_inc(&sta->users); | ||
1111 | spin_lock_bh(&ap->sta_table_lock); | ||
1112 | list_add(&sta->list, &ap->sta_list); | ||
1113 | ap->num_sta++; | ||
1114 | ap_sta_hash_add(ap, sta); | ||
1115 | spin_unlock_bh(&ap->sta_table_lock); | ||
1116 | |||
1117 | if (ap->proc) { | ||
1118 | struct add_sta_proc_data *entry; | ||
1119 | /* schedule a non-interrupt context process to add a procfs | ||
1120 | * entry for the STA since procfs code use GFP_KERNEL */ | ||
1121 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
1122 | if (entry) { | ||
1123 | memcpy(entry->addr, sta->addr, ETH_ALEN); | ||
1124 | entry->next = ap->add_sta_proc_entries; | ||
1125 | ap->add_sta_proc_entries = entry; | ||
1126 | schedule_work(&ap->add_sta_proc_queue); | ||
1127 | } else | ||
1128 | printk(KERN_DEBUG "Failed to add STA proc data\n"); | ||
1129 | } | ||
1130 | |||
1131 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1132 | init_timer(&sta->timer); | ||
1133 | sta->timer.expires = jiffies + ap->max_inactivity; | ||
1134 | sta->timer.data = (unsigned long) sta; | ||
1135 | sta->timer.function = ap_handle_timer; | ||
1136 | if (!ap->local->hostapd) | ||
1137 | add_timer(&sta->timer); | ||
1138 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1139 | |||
1140 | return sta; | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, | ||
1145 | local_info_t *local) | ||
1146 | { | ||
1147 | if (rateidx > sta->tx_max_rate || | ||
1148 | !(sta->tx_supp_rates & (1 << rateidx))) | ||
1149 | return 0; | ||
1150 | |||
1151 | if (local->tx_rate_control != 0 && | ||
1152 | !(local->tx_rate_control & (1 << rateidx))) | ||
1153 | return 0; | ||
1154 | |||
1155 | return 1; | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | static void prism2_check_tx_rates(struct sta_info *sta) | ||
1160 | { | ||
1161 | int i; | ||
1162 | |||
1163 | sta->tx_supp_rates = 0; | ||
1164 | for (i = 0; i < sizeof(sta->supported_rates); i++) { | ||
1165 | if ((sta->supported_rates[i] & 0x7f) == 2) | ||
1166 | sta->tx_supp_rates |= WLAN_RATE_1M; | ||
1167 | if ((sta->supported_rates[i] & 0x7f) == 4) | ||
1168 | sta->tx_supp_rates |= WLAN_RATE_2M; | ||
1169 | if ((sta->supported_rates[i] & 0x7f) == 11) | ||
1170 | sta->tx_supp_rates |= WLAN_RATE_5M5; | ||
1171 | if ((sta->supported_rates[i] & 0x7f) == 22) | ||
1172 | sta->tx_supp_rates |= WLAN_RATE_11M; | ||
1173 | } | ||
1174 | sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; | ||
1175 | if (sta->tx_supp_rates & WLAN_RATE_1M) { | ||
1176 | sta->tx_max_rate = 0; | ||
1177 | if (ap_tx_rate_ok(0, sta, sta->local)) { | ||
1178 | sta->tx_rate = 10; | ||
1179 | sta->tx_rate_idx = 0; | ||
1180 | } | ||
1181 | } | ||
1182 | if (sta->tx_supp_rates & WLAN_RATE_2M) { | ||
1183 | sta->tx_max_rate = 1; | ||
1184 | if (ap_tx_rate_ok(1, sta, sta->local)) { | ||
1185 | sta->tx_rate = 20; | ||
1186 | sta->tx_rate_idx = 1; | ||
1187 | } | ||
1188 | } | ||
1189 | if (sta->tx_supp_rates & WLAN_RATE_5M5) { | ||
1190 | sta->tx_max_rate = 2; | ||
1191 | if (ap_tx_rate_ok(2, sta, sta->local)) { | ||
1192 | sta->tx_rate = 55; | ||
1193 | sta->tx_rate_idx = 2; | ||
1194 | } | ||
1195 | } | ||
1196 | if (sta->tx_supp_rates & WLAN_RATE_11M) { | ||
1197 | sta->tx_max_rate = 3; | ||
1198 | if (ap_tx_rate_ok(3, sta, sta->local)) { | ||
1199 | sta->tx_rate = 110; | ||
1200 | sta->tx_rate_idx = 3; | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1207 | |||
1208 | static void ap_crypt_init(struct ap_data *ap) | ||
1209 | { | ||
1210 | ap->crypt = ieee80211_get_crypto_ops("WEP"); | ||
1211 | |||
1212 | if (ap->crypt) { | ||
1213 | if (ap->crypt->init) { | ||
1214 | ap->crypt_priv = ap->crypt->init(0); | ||
1215 | if (ap->crypt_priv == NULL) | ||
1216 | ap->crypt = NULL; | ||
1217 | else { | ||
1218 | u8 key[WEP_KEY_LEN]; | ||
1219 | get_random_bytes(key, WEP_KEY_LEN); | ||
1220 | ap->crypt->set_key(key, WEP_KEY_LEN, NULL, | ||
1221 | ap->crypt_priv); | ||
1222 | } | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | if (ap->crypt == NULL) { | ||
1227 | printk(KERN_WARNING "AP could not initialize WEP: load module " | ||
1228 | "ieee80211_crypt_wep.ko\n"); | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | /* Generate challenge data for shared key authentication. IEEE 802.11 specifies | ||
1234 | * that WEP algorithm is used for generating challange. This should be unique, | ||
1235 | * but otherwise there is not really need for randomness etc. Initialize WEP | ||
1236 | * with pseudo random key and then use increasing IV to get unique challenge | ||
1237 | * streams. | ||
1238 | * | ||
1239 | * Called only as a scheduled task for pending AP frames. | ||
1240 | */ | ||
1241 | static char * ap_auth_make_challenge(struct ap_data *ap) | ||
1242 | { | ||
1243 | char *tmpbuf; | ||
1244 | struct sk_buff *skb; | ||
1245 | |||
1246 | if (ap->crypt == NULL) { | ||
1247 | ap_crypt_init(ap); | ||
1248 | if (ap->crypt == NULL) | ||
1249 | return NULL; | ||
1250 | } | ||
1251 | |||
1252 | tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); | ||
1253 | if (tmpbuf == NULL) { | ||
1254 | PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); | ||
1255 | return NULL; | ||
1256 | } | ||
1257 | |||
1258 | skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + | ||
1259 | ap->crypt->extra_prefix_len + | ||
1260 | ap->crypt->extra_postfix_len); | ||
1261 | if (skb == NULL) { | ||
1262 | kfree(tmpbuf); | ||
1263 | return NULL; | ||
1264 | } | ||
1265 | |||
1266 | skb_reserve(skb, ap->crypt->extra_prefix_len); | ||
1267 | memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, | ||
1268 | WLAN_AUTH_CHALLENGE_LEN); | ||
1269 | if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { | ||
1270 | dev_kfree_skb(skb); | ||
1271 | kfree(tmpbuf); | ||
1272 | return NULL; | ||
1273 | } | ||
1274 | |||
1275 | memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, | ||
1276 | WLAN_AUTH_CHALLENGE_LEN); | ||
1277 | dev_kfree_skb(skb); | ||
1278 | |||
1279 | return tmpbuf; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | /* Called only as a scheduled task for pending AP frames. */ | ||
1284 | static void handle_authen(local_info_t *local, struct sk_buff *skb, | ||
1285 | struct hostap_80211_rx_status *rx_stats) | ||
1286 | { | ||
1287 | struct net_device *dev = local->dev; | ||
1288 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1289 | size_t hdrlen; | ||
1290 | struct ap_data *ap = local->ap; | ||
1291 | char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; | ||
1292 | int len, olen; | ||
1293 | u16 auth_alg, auth_transaction, status_code, *pos; | ||
1294 | u16 resp = WLAN_STATUS_SUCCESS, fc; | ||
1295 | struct sta_info *sta = NULL; | ||
1296 | struct ieee80211_crypt_data *crypt; | ||
1297 | char *txt = ""; | ||
1298 | |||
1299 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1300 | |||
1301 | fc = le16_to_cpu(hdr->frame_ctl); | ||
1302 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
1303 | |||
1304 | if (len < 6) { | ||
1305 | PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " | ||
1306 | "(len=%d) from " MACSTR "\n", dev->name, len, | ||
1307 | MAC2STR(hdr->addr2)); | ||
1308 | return; | ||
1309 | } | ||
1310 | |||
1311 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1312 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1313 | if (sta) | ||
1314 | atomic_inc(&sta->users); | ||
1315 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1316 | |||
1317 | if (sta && sta->crypt) | ||
1318 | crypt = sta->crypt; | ||
1319 | else { | ||
1320 | int idx = 0; | ||
1321 | if (skb->len >= hdrlen + 3) | ||
1322 | idx = skb->data[hdrlen + 3] >> 6; | ||
1323 | crypt = local->crypt[idx]; | ||
1324 | } | ||
1325 | |||
1326 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1327 | auth_alg = __le16_to_cpu(*pos); | ||
1328 | pos++; | ||
1329 | auth_transaction = __le16_to_cpu(*pos); | ||
1330 | pos++; | ||
1331 | status_code = __le16_to_cpu(*pos); | ||
1332 | pos++; | ||
1333 | |||
1334 | if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 || | ||
1335 | ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { | ||
1336 | txt = "authentication denied"; | ||
1337 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1338 | goto fail; | ||
1339 | } | ||
1340 | |||
1341 | if (((local->auth_algs & PRISM2_AUTH_OPEN) && | ||
1342 | auth_alg == WLAN_AUTH_OPEN) || | ||
1343 | ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && | ||
1344 | crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { | ||
1345 | } else { | ||
1346 | txt = "unsupported algorithm"; | ||
1347 | resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; | ||
1348 | goto fail; | ||
1349 | } | ||
1350 | |||
1351 | if (len >= 8) { | ||
1352 | u8 *u = (u8 *) pos; | ||
1353 | if (*u == WLAN_EID_CHALLENGE) { | ||
1354 | if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { | ||
1355 | txt = "invalid challenge len"; | ||
1356 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1357 | goto fail; | ||
1358 | } | ||
1359 | if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { | ||
1360 | txt = "challenge underflow"; | ||
1361 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1362 | goto fail; | ||
1363 | } | ||
1364 | challenge = (char *) (u + 2); | ||
1365 | } | ||
1366 | } | ||
1367 | |||
1368 | if (sta && sta->ap) { | ||
1369 | if (time_after(jiffies, sta->u.ap.last_beacon + | ||
1370 | (10 * sta->listen_interval * HZ) / 1024)) { | ||
1371 | PDEBUG(DEBUG_AP, "%s: no beacons received for a while," | ||
1372 | " assuming AP " MACSTR " is now STA\n", | ||
1373 | dev->name, MAC2STR(sta->addr)); | ||
1374 | sta->ap = 0; | ||
1375 | sta->flags = 0; | ||
1376 | sta->u.sta.challenge = NULL; | ||
1377 | } else { | ||
1378 | txt = "AP trying to authenticate?"; | ||
1379 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1380 | goto fail; | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || | ||
1385 | (auth_alg == WLAN_AUTH_SHARED_KEY && | ||
1386 | (auth_transaction == 1 || | ||
1387 | (auth_transaction == 3 && sta != NULL && | ||
1388 | sta->u.sta.challenge != NULL)))) { | ||
1389 | } else { | ||
1390 | txt = "unknown authentication transaction number"; | ||
1391 | resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; | ||
1392 | goto fail; | ||
1393 | } | ||
1394 | |||
1395 | if (sta == NULL) { | ||
1396 | txt = "new STA"; | ||
1397 | |||
1398 | if (local->ap->num_sta >= MAX_STA_COUNT) { | ||
1399 | /* FIX: might try to remove some old STAs first? */ | ||
1400 | txt = "no more room for new STAs"; | ||
1401 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1402 | goto fail; | ||
1403 | } | ||
1404 | |||
1405 | sta = ap_add_sta(local->ap, hdr->addr2); | ||
1406 | if (sta == NULL) { | ||
1407 | txt = "ap_add_sta failed"; | ||
1408 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1409 | goto fail; | ||
1410 | } | ||
1411 | } | ||
1412 | |||
1413 | switch (auth_alg) { | ||
1414 | case WLAN_AUTH_OPEN: | ||
1415 | txt = "authOK"; | ||
1416 | /* IEEE 802.11 standard is not completely clear about | ||
1417 | * whether STA is considered authenticated after | ||
1418 | * authentication OK frame has been send or after it | ||
1419 | * has been ACKed. In order to reduce interoperability | ||
1420 | * issues, mark the STA authenticated before ACK. */ | ||
1421 | sta->flags |= WLAN_STA_AUTH; | ||
1422 | break; | ||
1423 | |||
1424 | case WLAN_AUTH_SHARED_KEY: | ||
1425 | if (auth_transaction == 1) { | ||
1426 | if (sta->u.sta.challenge == NULL) { | ||
1427 | sta->u.sta.challenge = | ||
1428 | ap_auth_make_challenge(local->ap); | ||
1429 | if (sta->u.sta.challenge == NULL) { | ||
1430 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1431 | goto fail; | ||
1432 | } | ||
1433 | } | ||
1434 | } else { | ||
1435 | if (sta->u.sta.challenge == NULL || | ||
1436 | challenge == NULL || | ||
1437 | memcmp(sta->u.sta.challenge, challenge, | ||
1438 | WLAN_AUTH_CHALLENGE_LEN) != 0 || | ||
1439 | !(fc & IEEE80211_FCTL_PROTECTED)) { | ||
1440 | txt = "challenge response incorrect"; | ||
1441 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1442 | goto fail; | ||
1443 | } | ||
1444 | |||
1445 | txt = "challenge OK - authOK"; | ||
1446 | /* IEEE 802.11 standard is not completely clear about | ||
1447 | * whether STA is considered authenticated after | ||
1448 | * authentication OK frame has been send or after it | ||
1449 | * has been ACKed. In order to reduce interoperability | ||
1450 | * issues, mark the STA authenticated before ACK. */ | ||
1451 | sta->flags |= WLAN_STA_AUTH; | ||
1452 | kfree(sta->u.sta.challenge); | ||
1453 | sta->u.sta.challenge = NULL; | ||
1454 | } | ||
1455 | break; | ||
1456 | } | ||
1457 | |||
1458 | fail: | ||
1459 | pos = (u16 *) body; | ||
1460 | *pos = cpu_to_le16(auth_alg); | ||
1461 | pos++; | ||
1462 | *pos = cpu_to_le16(auth_transaction + 1); | ||
1463 | pos++; | ||
1464 | *pos = cpu_to_le16(resp); /* status_code */ | ||
1465 | pos++; | ||
1466 | olen = 6; | ||
1467 | |||
1468 | if (resp == WLAN_STATUS_SUCCESS && sta != NULL && | ||
1469 | sta->u.sta.challenge != NULL && | ||
1470 | auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { | ||
1471 | u8 *tmp = (u8 *) pos; | ||
1472 | *tmp++ = WLAN_EID_CHALLENGE; | ||
1473 | *tmp++ = WLAN_AUTH_CHALLENGE_LEN; | ||
1474 | pos++; | ||
1475 | memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); | ||
1476 | olen += 2 + WLAN_AUTH_CHALLENGE_LEN; | ||
1477 | } | ||
1478 | |||
1479 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, | ||
1480 | body, olen, hdr->addr2, ap->tx_callback_auth); | ||
1481 | |||
1482 | if (sta) { | ||
1483 | sta->last_rx = jiffies; | ||
1484 | atomic_dec(&sta->users); | ||
1485 | } | ||
1486 | |||
1487 | if (resp) { | ||
1488 | PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d " | ||
1489 | "stat=%d len=%d fc=%04x) ==> %d (%s)\n", | ||
1490 | dev->name, MAC2STR(hdr->addr2), auth_alg, | ||
1491 | auth_transaction, status_code, len, fc, resp, txt); | ||
1492 | } | ||
1493 | } | ||
1494 | |||
1495 | |||
1496 | /* Called only as a scheduled task for pending AP frames. */ | ||
1497 | static void handle_assoc(local_info_t *local, struct sk_buff *skb, | ||
1498 | struct hostap_80211_rx_status *rx_stats, int reassoc) | ||
1499 | { | ||
1500 | struct net_device *dev = local->dev; | ||
1501 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1502 | char body[12], *p, *lpos; | ||
1503 | int len, left; | ||
1504 | u16 *pos; | ||
1505 | u16 resp = WLAN_STATUS_SUCCESS; | ||
1506 | struct sta_info *sta = NULL; | ||
1507 | int send_deauth = 0; | ||
1508 | char *txt = ""; | ||
1509 | u8 prev_ap[ETH_ALEN]; | ||
1510 | |||
1511 | left = len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1512 | |||
1513 | if (len < (reassoc ? 10 : 4)) { | ||
1514 | PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " | ||
1515 | "(len=%d, reassoc=%d) from " MACSTR "\n", | ||
1516 | dev->name, len, reassoc, MAC2STR(hdr->addr2)); | ||
1517 | return; | ||
1518 | } | ||
1519 | |||
1520 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1521 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1522 | if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { | ||
1523 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1524 | txt = "trying to associate before authentication"; | ||
1525 | send_deauth = 1; | ||
1526 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1527 | sta = NULL; /* do not decrement sta->users */ | ||
1528 | goto fail; | ||
1529 | } | ||
1530 | atomic_inc(&sta->users); | ||
1531 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1532 | |||
1533 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1534 | sta->capability = __le16_to_cpu(*pos); | ||
1535 | pos++; left -= 2; | ||
1536 | sta->listen_interval = __le16_to_cpu(*pos); | ||
1537 | pos++; left -= 2; | ||
1538 | |||
1539 | if (reassoc) { | ||
1540 | memcpy(prev_ap, pos, ETH_ALEN); | ||
1541 | pos++; pos++; pos++; left -= 6; | ||
1542 | } else | ||
1543 | memset(prev_ap, 0, ETH_ALEN); | ||
1544 | |||
1545 | if (left >= 2) { | ||
1546 | unsigned int ileft; | ||
1547 | unsigned char *u = (unsigned char *) pos; | ||
1548 | |||
1549 | if (*u == WLAN_EID_SSID) { | ||
1550 | u++; left--; | ||
1551 | ileft = *u; | ||
1552 | u++; left--; | ||
1553 | |||
1554 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
1555 | txt = "SSID overflow"; | ||
1556 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1557 | goto fail; | ||
1558 | } | ||
1559 | |||
1560 | if (ileft != strlen(local->essid) || | ||
1561 | memcmp(local->essid, u, ileft) != 0) { | ||
1562 | txt = "not our SSID"; | ||
1563 | resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||
1564 | goto fail; | ||
1565 | } | ||
1566 | |||
1567 | u += ileft; | ||
1568 | left -= ileft; | ||
1569 | } | ||
1570 | |||
1571 | if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { | ||
1572 | u++; left--; | ||
1573 | ileft = *u; | ||
1574 | u++; left--; | ||
1575 | |||
1576 | if (ileft > left || ileft == 0 || | ||
1577 | ileft > WLAN_SUPP_RATES_MAX) { | ||
1578 | txt = "SUPP_RATES len error"; | ||
1579 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1580 | goto fail; | ||
1581 | } | ||
1582 | |||
1583 | memset(sta->supported_rates, 0, | ||
1584 | sizeof(sta->supported_rates)); | ||
1585 | memcpy(sta->supported_rates, u, ileft); | ||
1586 | prism2_check_tx_rates(sta); | ||
1587 | |||
1588 | u += ileft; | ||
1589 | left -= ileft; | ||
1590 | } | ||
1591 | |||
1592 | if (left > 0) { | ||
1593 | PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" | ||
1594 | " data (%d bytes) [", | ||
1595 | dev->name, MAC2STR(hdr->addr2), left); | ||
1596 | while (left > 0) { | ||
1597 | PDEBUG2(DEBUG_AP, "<%02x>", *u); | ||
1598 | u++; left--; | ||
1599 | } | ||
1600 | PDEBUG2(DEBUG_AP, "]\n"); | ||
1601 | } | ||
1602 | } else { | ||
1603 | txt = "frame underflow"; | ||
1604 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1605 | goto fail; | ||
1606 | } | ||
1607 | |||
1608 | /* get a unique AID */ | ||
1609 | if (sta->aid > 0) | ||
1610 | txt = "OK, old AID"; | ||
1611 | else { | ||
1612 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1613 | for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) | ||
1614 | if (local->ap->sta_aid[sta->aid - 1] == NULL) | ||
1615 | break; | ||
1616 | if (sta->aid > MAX_AID_TABLE_SIZE) { | ||
1617 | sta->aid = 0; | ||
1618 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1619 | resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; | ||
1620 | txt = "no room for more AIDs"; | ||
1621 | } else { | ||
1622 | local->ap->sta_aid[sta->aid - 1] = sta; | ||
1623 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1624 | txt = "OK, new AID"; | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | fail: | ||
1629 | pos = (u16 *) body; | ||
1630 | |||
1631 | if (send_deauth) { | ||
1632 | *pos = __constant_cpu_to_le16( | ||
1633 | WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); | ||
1634 | pos++; | ||
1635 | } else { | ||
1636 | /* FIX: CF-Pollable and CF-PollReq should be set to match the | ||
1637 | * values in beacons/probe responses */ | ||
1638 | /* FIX: how about privacy and WEP? */ | ||
1639 | /* capability */ | ||
1640 | *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
1641 | pos++; | ||
1642 | |||
1643 | /* status_code */ | ||
1644 | *pos = __cpu_to_le16(resp); | ||
1645 | pos++; | ||
1646 | |||
1647 | *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | | ||
1648 | BIT(14) | BIT(15)); /* AID */ | ||
1649 | pos++; | ||
1650 | |||
1651 | /* Supported rates (Information element) */ | ||
1652 | p = (char *) pos; | ||
1653 | *p++ = WLAN_EID_SUPP_RATES; | ||
1654 | lpos = p; | ||
1655 | *p++ = 0; /* len */ | ||
1656 | if (local->tx_rate_control & WLAN_RATE_1M) { | ||
1657 | *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; | ||
1658 | (*lpos)++; | ||
1659 | } | ||
1660 | if (local->tx_rate_control & WLAN_RATE_2M) { | ||
1661 | *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; | ||
1662 | (*lpos)++; | ||
1663 | } | ||
1664 | if (local->tx_rate_control & WLAN_RATE_5M5) { | ||
1665 | *p++ = local->basic_rates & WLAN_RATE_5M5 ? | ||
1666 | 0x8b : 0x0b; | ||
1667 | (*lpos)++; | ||
1668 | } | ||
1669 | if (local->tx_rate_control & WLAN_RATE_11M) { | ||
1670 | *p++ = local->basic_rates & WLAN_RATE_11M ? | ||
1671 | 0x96 : 0x16; | ||
1672 | (*lpos)++; | ||
1673 | } | ||
1674 | pos = (u16 *) p; | ||
1675 | } | ||
1676 | |||
1677 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
1678 | (send_deauth ? IEEE80211_STYPE_DEAUTH : | ||
1679 | (reassoc ? IEEE80211_STYPE_REASSOC_RESP : | ||
1680 | IEEE80211_STYPE_ASSOC_RESP)), | ||
1681 | body, (u8 *) pos - (u8 *) body, | ||
1682 | hdr->addr2, | ||
1683 | send_deauth ? 0 : local->ap->tx_callback_assoc); | ||
1684 | |||
1685 | if (sta) { | ||
1686 | if (resp == WLAN_STATUS_SUCCESS) { | ||
1687 | sta->last_rx = jiffies; | ||
1688 | /* STA will be marked associated from TX callback, if | ||
1689 | * AssocResp is ACKed */ | ||
1690 | } | ||
1691 | atomic_dec(&sta->users); | ||
1692 | } | ||
1693 | |||
1694 | #if 0 | ||
1695 | PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR | ||
1696 | ") => %d(%d) (%s)\n", | ||
1697 | dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, | ||
1698 | MAC2STR(prev_ap), resp, send_deauth, txt); | ||
1699 | #endif | ||
1700 | } | ||
1701 | |||
1702 | |||
1703 | /* Called only as a scheduled task for pending AP frames. */ | ||
1704 | static void handle_deauth(local_info_t *local, struct sk_buff *skb, | ||
1705 | struct hostap_80211_rx_status *rx_stats) | ||
1706 | { | ||
1707 | struct net_device *dev = local->dev; | ||
1708 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1709 | char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1710 | int len; | ||
1711 | u16 reason_code, *pos; | ||
1712 | struct sta_info *sta = NULL; | ||
1713 | |||
1714 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1715 | |||
1716 | if (len < 2) { | ||
1717 | printk("handle_deauth - too short payload (len=%d)\n", len); | ||
1718 | return; | ||
1719 | } | ||
1720 | |||
1721 | pos = (u16 *) body; | ||
1722 | reason_code = __le16_to_cpu(*pos); | ||
1723 | |||
1724 | PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " | ||
1725 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1726 | reason_code); | ||
1727 | |||
1728 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1729 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1730 | if (sta != NULL) { | ||
1731 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1732 | hostap_event_expired_sta(local->dev, sta); | ||
1733 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | ||
1734 | } | ||
1735 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1736 | if (sta == NULL) { | ||
1737 | printk("%s: deauthentication from " MACSTR ", " | ||
1738 | "reason_code=%d, but STA not authenticated\n", dev->name, | ||
1739 | MAC2STR(hdr->addr2), reason_code); | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | |||
1744 | /* Called only as a scheduled task for pending AP frames. */ | ||
1745 | static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | ||
1746 | struct hostap_80211_rx_status *rx_stats) | ||
1747 | { | ||
1748 | struct net_device *dev = local->dev; | ||
1749 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1750 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1751 | int len; | ||
1752 | u16 reason_code, *pos; | ||
1753 | struct sta_info *sta = NULL; | ||
1754 | |||
1755 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1756 | |||
1757 | if (len < 2) { | ||
1758 | printk("handle_disassoc - too short payload (len=%d)\n", len); | ||
1759 | return; | ||
1760 | } | ||
1761 | |||
1762 | pos = (u16 *) body; | ||
1763 | reason_code = __le16_to_cpu(*pos); | ||
1764 | |||
1765 | PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " | ||
1766 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1767 | reason_code); | ||
1768 | |||
1769 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1770 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1771 | if (sta != NULL) { | ||
1772 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1773 | hostap_event_expired_sta(local->dev, sta); | ||
1774 | sta->flags &= ~WLAN_STA_ASSOC; | ||
1775 | } | ||
1776 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1777 | if (sta == NULL) { | ||
1778 | printk("%s: disassociation from " MACSTR ", " | ||
1779 | "reason_code=%d, but STA not authenticated\n", | ||
1780 | dev->name, MAC2STR(hdr->addr2), reason_code); | ||
1781 | } | ||
1782 | } | ||
1783 | |||
1784 | |||
1785 | /* Called only as a scheduled task for pending AP frames. */ | ||
1786 | static void ap_handle_data_nullfunc(local_info_t *local, | ||
1787 | struct ieee80211_hdr *hdr) | ||
1788 | { | ||
1789 | struct net_device *dev = local->dev; | ||
1790 | |||
1791 | /* some STA f/w's seem to require control::ACK frame for | ||
1792 | * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does | ||
1793 | * not send this.. | ||
1794 | * send control::ACK for the data::nullfunc */ | ||
1795 | |||
1796 | printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); | ||
1797 | prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, | ||
1798 | NULL, 0, hdr->addr2, 0); | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | /* Called only as a scheduled task for pending AP frames. */ | ||
1803 | static void ap_handle_dropped_data(local_info_t *local, | ||
1804 | struct ieee80211_hdr *hdr) | ||
1805 | { | ||
1806 | struct net_device *dev = local->dev; | ||
1807 | struct sta_info *sta; | ||
1808 | u16 reason; | ||
1809 | |||
1810 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1811 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1812 | if (sta) | ||
1813 | atomic_inc(&sta->users); | ||
1814 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1815 | |||
1816 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { | ||
1817 | PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); | ||
1818 | atomic_dec(&sta->users); | ||
1819 | return; | ||
1820 | } | ||
1821 | |||
1822 | reason = __constant_cpu_to_le16( | ||
1823 | WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | ||
1824 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
1825 | ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? | ||
1826 | IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), | ||
1827 | (char *) &reason, sizeof(reason), hdr->addr2, 0); | ||
1828 | |||
1829 | if (sta) | ||
1830 | atomic_dec(&sta->users); | ||
1831 | } | ||
1832 | |||
1833 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1834 | |||
1835 | |||
1836 | /* Called only as a scheduled task for pending AP frames. */ | ||
1837 | static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, | ||
1838 | struct sk_buff *skb) | ||
1839 | { | ||
1840 | struct hostap_skb_tx_data *meta; | ||
1841 | |||
1842 | if (!(sta->flags & WLAN_STA_PS)) { | ||
1843 | /* Station has moved to non-PS mode, so send all buffered | ||
1844 | * frames using normal device queue. */ | ||
1845 | dev_queue_xmit(skb); | ||
1846 | return; | ||
1847 | } | ||
1848 | |||
1849 | /* add a flag for hostap_handle_sta_tx() to know that this skb should | ||
1850 | * be passed through even though STA is using PS */ | ||
1851 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1852 | meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; | ||
1853 | if (!skb_queue_empty(&sta->tx_buf)) { | ||
1854 | /* indicate to STA that more frames follow */ | ||
1855 | meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; | ||
1856 | } | ||
1857 | dev_queue_xmit(skb); | ||
1858 | } | ||
1859 | |||
1860 | |||
1861 | /* Called only as a scheduled task for pending AP frames. */ | ||
1862 | static void handle_pspoll(local_info_t *local, | ||
1863 | struct ieee80211_hdr *hdr, | ||
1864 | struct hostap_80211_rx_status *rx_stats) | ||
1865 | { | ||
1866 | struct net_device *dev = local->dev; | ||
1867 | struct sta_info *sta; | ||
1868 | u16 aid; | ||
1869 | struct sk_buff *skb; | ||
1870 | |||
1871 | PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR | ||
1872 | " PWRMGT=%d\n", | ||
1873 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | ||
1874 | !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); | ||
1875 | |||
1876 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
1877 | PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR | ||
1878 | " not own MAC\n", MAC2STR(hdr->addr1)); | ||
1879 | return; | ||
1880 | } | ||
1881 | |||
1882 | aid = __le16_to_cpu(hdr->duration_id); | ||
1883 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { | ||
1884 | PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); | ||
1885 | return; | ||
1886 | } | ||
1887 | aid &= ~BIT(15) & ~BIT(14); | ||
1888 | if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { | ||
1889 | PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); | ||
1890 | return; | ||
1891 | } | ||
1892 | PDEBUG(DEBUG_PS2, " aid=%d\n", aid); | ||
1893 | |||
1894 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1895 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1896 | if (sta) | ||
1897 | atomic_inc(&sta->users); | ||
1898 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1899 | |||
1900 | if (sta == NULL) { | ||
1901 | PDEBUG(DEBUG_PS, " STA not found\n"); | ||
1902 | return; | ||
1903 | } | ||
1904 | if (sta->aid != aid) { | ||
1905 | PDEBUG(DEBUG_PS, " received aid=%i does not match with " | ||
1906 | "assoc.aid=%d\n", aid, sta->aid); | ||
1907 | return; | ||
1908 | } | ||
1909 | |||
1910 | /* FIX: todo: | ||
1911 | * - add timeout for buffering (clear aid in TIM vector if buffer timed | ||
1912 | * out (expiry time must be longer than ListenInterval for | ||
1913 | * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" | ||
1914 | * - what to do, if buffered, pspolled, and sent frame is not ACKed by | ||
1915 | * sta; store buffer for later use and leave TIM aid bit set? use | ||
1916 | * TX event to check whether frame was ACKed? | ||
1917 | */ | ||
1918 | |||
1919 | while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { | ||
1920 | /* send buffered frame .. */ | ||
1921 | PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" | ||
1922 | " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); | ||
1923 | |||
1924 | pspoll_send_buffered(local, sta, skb); | ||
1925 | |||
1926 | if (sta->flags & WLAN_STA_PS) { | ||
1927 | /* send only one buffered packet per PS Poll */ | ||
1928 | /* FIX: should ignore further PS Polls until the | ||
1929 | * buffered packet that was just sent is acknowledged | ||
1930 | * (Tx or TxExc event) */ | ||
1931 | break; | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | if (skb_queue_empty(&sta->tx_buf)) { | ||
1936 | /* try to clear aid from TIM */ | ||
1937 | if (!(sta->flags & WLAN_STA_TIM)) | ||
1938 | PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", | ||
1939 | aid); | ||
1940 | hostap_set_tim(local, aid, 0); | ||
1941 | sta->flags &= ~WLAN_STA_TIM; | ||
1942 | } | ||
1943 | |||
1944 | atomic_dec(&sta->users); | ||
1945 | } | ||
1946 | |||
1947 | |||
1948 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1949 | |||
1950 | static void handle_wds_oper_queue(void *data) | ||
1951 | { | ||
1952 | local_info_t *local = data; | ||
1953 | struct wds_oper_data *entry, *prev; | ||
1954 | |||
1955 | spin_lock_bh(&local->lock); | ||
1956 | entry = local->ap->wds_oper_entries; | ||
1957 | local->ap->wds_oper_entries = NULL; | ||
1958 | spin_unlock_bh(&local->lock); | ||
1959 | |||
1960 | while (entry) { | ||
1961 | PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " | ||
1962 | "to AP " MACSTR "\n", | ||
1963 | local->dev->name, | ||
1964 | entry->type == WDS_ADD ? "adding" : "removing", | ||
1965 | MAC2STR(entry->addr)); | ||
1966 | if (entry->type == WDS_ADD) | ||
1967 | prism2_wds_add(local, entry->addr, 0); | ||
1968 | else if (entry->type == WDS_DEL) | ||
1969 | prism2_wds_del(local, entry->addr, 0, 1); | ||
1970 | |||
1971 | prev = entry; | ||
1972 | entry = entry->next; | ||
1973 | kfree(prev); | ||
1974 | } | ||
1975 | } | ||
1976 | |||
1977 | |||
1978 | /* Called only as a scheduled task for pending AP frames. */ | ||
1979 | static void handle_beacon(local_info_t *local, struct sk_buff *skb, | ||
1980 | struct hostap_80211_rx_status *rx_stats) | ||
1981 | { | ||
1982 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1983 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1984 | int len, left; | ||
1985 | u16 *pos, beacon_int, capability; | ||
1986 | char *ssid = NULL; | ||
1987 | unsigned char *supp_rates = NULL; | ||
1988 | int ssid_len = 0, supp_rates_len = 0; | ||
1989 | struct sta_info *sta = NULL; | ||
1990 | int new_sta = 0, channel = -1; | ||
1991 | |||
1992 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1993 | |||
1994 | if (len < 8 + 2 + 2) { | ||
1995 | printk(KERN_DEBUG "handle_beacon - too short payload " | ||
1996 | "(len=%d)\n", len); | ||
1997 | return; | ||
1998 | } | ||
1999 | |||
2000 | pos = (u16 *) body; | ||
2001 | left = len; | ||
2002 | |||
2003 | /* Timestamp (8 octets) */ | ||
2004 | pos += 4; left -= 8; | ||
2005 | /* Beacon interval (2 octets) */ | ||
2006 | beacon_int = __le16_to_cpu(*pos); | ||
2007 | pos++; left -= 2; | ||
2008 | /* Capability information (2 octets) */ | ||
2009 | capability = __le16_to_cpu(*pos); | ||
2010 | pos++; left -= 2; | ||
2011 | |||
2012 | if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && | ||
2013 | capability & WLAN_CAPABILITY_IBSS) | ||
2014 | return; | ||
2015 | |||
2016 | if (left >= 2) { | ||
2017 | unsigned int ileft; | ||
2018 | unsigned char *u = (unsigned char *) pos; | ||
2019 | |||
2020 | if (*u == WLAN_EID_SSID) { | ||
2021 | u++; left--; | ||
2022 | ileft = *u; | ||
2023 | u++; left--; | ||
2024 | |||
2025 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
2026 | PDEBUG(DEBUG_AP, "SSID: overflow\n"); | ||
2027 | return; | ||
2028 | } | ||
2029 | |||
2030 | if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && | ||
2031 | (ileft != strlen(local->essid) || | ||
2032 | memcmp(local->essid, u, ileft) != 0)) { | ||
2033 | /* not our SSID */ | ||
2034 | return; | ||
2035 | } | ||
2036 | |||
2037 | ssid = u; | ||
2038 | ssid_len = ileft; | ||
2039 | |||
2040 | u += ileft; | ||
2041 | left -= ileft; | ||
2042 | } | ||
2043 | |||
2044 | if (*u == WLAN_EID_SUPP_RATES) { | ||
2045 | u++; left--; | ||
2046 | ileft = *u; | ||
2047 | u++; left--; | ||
2048 | |||
2049 | if (ileft > left || ileft == 0 || ileft > 8) { | ||
2050 | PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); | ||
2051 | return; | ||
2052 | } | ||
2053 | |||
2054 | supp_rates = u; | ||
2055 | supp_rates_len = ileft; | ||
2056 | |||
2057 | u += ileft; | ||
2058 | left -= ileft; | ||
2059 | } | ||
2060 | |||
2061 | if (*u == WLAN_EID_DS_PARAMS) { | ||
2062 | u++; left--; | ||
2063 | ileft = *u; | ||
2064 | u++; left--; | ||
2065 | |||
2066 | if (ileft > left || ileft != 1) { | ||
2067 | PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); | ||
2068 | return; | ||
2069 | } | ||
2070 | |||
2071 | channel = *u; | ||
2072 | |||
2073 | u += ileft; | ||
2074 | left -= ileft; | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | spin_lock_bh(&local->ap->sta_table_lock); | ||
2079 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2080 | if (sta != NULL) | ||
2081 | atomic_inc(&sta->users); | ||
2082 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
2083 | |||
2084 | if (sta == NULL) { | ||
2085 | /* add new AP */ | ||
2086 | new_sta = 1; | ||
2087 | sta = ap_add_sta(local->ap, hdr->addr2); | ||
2088 | if (sta == NULL) { | ||
2089 | printk(KERN_INFO "prism2: kmalloc failed for AP " | ||
2090 | "data structure\n"); | ||
2091 | return; | ||
2092 | } | ||
2093 | hostap_event_new_sta(local->dev, sta); | ||
2094 | |||
2095 | /* mark APs authentication and associated for pseudo ad-hoc | ||
2096 | * style communication */ | ||
2097 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2098 | |||
2099 | if (local->ap->autom_ap_wds) { | ||
2100 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
2101 | } | ||
2102 | } | ||
2103 | |||
2104 | sta->ap = 1; | ||
2105 | if (ssid) { | ||
2106 | sta->u.ap.ssid_len = ssid_len; | ||
2107 | memcpy(sta->u.ap.ssid, ssid, ssid_len); | ||
2108 | sta->u.ap.ssid[ssid_len] = '\0'; | ||
2109 | } else { | ||
2110 | sta->u.ap.ssid_len = 0; | ||
2111 | sta->u.ap.ssid[0] = '\0'; | ||
2112 | } | ||
2113 | sta->u.ap.channel = channel; | ||
2114 | sta->rx_packets++; | ||
2115 | sta->rx_bytes += len; | ||
2116 | sta->u.ap.last_beacon = sta->last_rx = jiffies; | ||
2117 | sta->capability = capability; | ||
2118 | sta->listen_interval = beacon_int; | ||
2119 | |||
2120 | atomic_dec(&sta->users); | ||
2121 | |||
2122 | if (new_sta) { | ||
2123 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
2124 | memcpy(sta->supported_rates, supp_rates, supp_rates_len); | ||
2125 | prism2_check_tx_rates(sta); | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2130 | |||
2131 | |||
2132 | /* Called only as a tasklet. */ | ||
2133 | static void handle_ap_item(local_info_t *local, struct sk_buff *skb, | ||
2134 | struct hostap_80211_rx_status *rx_stats) | ||
2135 | { | ||
2136 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2137 | struct net_device *dev = local->dev; | ||
2138 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2139 | u16 fc, type, stype; | ||
2140 | struct ieee80211_hdr *hdr; | ||
2141 | |||
2142 | /* FIX: should give skb->len to handler functions and check that the | ||
2143 | * buffer is long enough */ | ||
2144 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2145 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2146 | type = WLAN_FC_GET_TYPE(fc); | ||
2147 | stype = WLAN_FC_GET_STYPE(fc); | ||
2148 | |||
2149 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2150 | if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { | ||
2151 | PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); | ||
2152 | |||
2153 | if (!(fc & IEEE80211_FCTL_TODS) || | ||
2154 | (fc & IEEE80211_FCTL_FROMDS)) { | ||
2155 | if (stype == IEEE80211_STYPE_NULLFUNC) { | ||
2156 | /* no ToDS nullfunc seems to be used to check | ||
2157 | * AP association; so send reject message to | ||
2158 | * speed up re-association */ | ||
2159 | ap_handle_dropped_data(local, hdr); | ||
2160 | goto done; | ||
2161 | } | ||
2162 | PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", | ||
2163 | fc); | ||
2164 | goto done; | ||
2165 | } | ||
2166 | |||
2167 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
2168 | PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" | ||
2169 | MACSTR " not own MAC\n", | ||
2170 | MAC2STR(hdr->addr1)); | ||
2171 | goto done; | ||
2172 | } | ||
2173 | |||
2174 | if (local->ap->nullfunc_ack && | ||
2175 | stype == IEEE80211_STYPE_NULLFUNC) | ||
2176 | ap_handle_data_nullfunc(local, hdr); | ||
2177 | else | ||
2178 | ap_handle_dropped_data(local, hdr); | ||
2179 | goto done; | ||
2180 | } | ||
2181 | |||
2182 | if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { | ||
2183 | handle_beacon(local, skb, rx_stats); | ||
2184 | goto done; | ||
2185 | } | ||
2186 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2187 | |||
2188 | if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { | ||
2189 | handle_pspoll(local, hdr, rx_stats); | ||
2190 | goto done; | ||
2191 | } | ||
2192 | |||
2193 | if (local->hostapd) { | ||
2194 | PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " | ||
2195 | "subtype=0x%02x\n", type, stype); | ||
2196 | goto done; | ||
2197 | } | ||
2198 | |||
2199 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2200 | if (type != IEEE80211_FTYPE_MGMT) { | ||
2201 | PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); | ||
2202 | goto done; | ||
2203 | } | ||
2204 | |||
2205 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
2206 | PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR | ||
2207 | " not own MAC\n", MAC2STR(hdr->addr1)); | ||
2208 | goto done; | ||
2209 | } | ||
2210 | |||
2211 | if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { | ||
2212 | PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR | ||
2213 | " not own MAC\n", MAC2STR(hdr->addr3)); | ||
2214 | goto done; | ||
2215 | } | ||
2216 | |||
2217 | switch (stype) { | ||
2218 | case IEEE80211_STYPE_ASSOC_REQ: | ||
2219 | handle_assoc(local, skb, rx_stats, 0); | ||
2220 | break; | ||
2221 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2222 | PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); | ||
2223 | break; | ||
2224 | case IEEE80211_STYPE_REASSOC_REQ: | ||
2225 | handle_assoc(local, skb, rx_stats, 1); | ||
2226 | break; | ||
2227 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2228 | PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); | ||
2229 | break; | ||
2230 | case IEEE80211_STYPE_ATIM: | ||
2231 | PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); | ||
2232 | break; | ||
2233 | case IEEE80211_STYPE_DISASSOC: | ||
2234 | handle_disassoc(local, skb, rx_stats); | ||
2235 | break; | ||
2236 | case IEEE80211_STYPE_AUTH: | ||
2237 | handle_authen(local, skb, rx_stats); | ||
2238 | break; | ||
2239 | case IEEE80211_STYPE_DEAUTH: | ||
2240 | handle_deauth(local, skb, rx_stats); | ||
2241 | break; | ||
2242 | default: | ||
2243 | PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", | ||
2244 | stype >> 4); | ||
2245 | break; | ||
2246 | } | ||
2247 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2248 | |||
2249 | done: | ||
2250 | dev_kfree_skb(skb); | ||
2251 | } | ||
2252 | |||
2253 | |||
2254 | /* Called only as a tasklet (software IRQ) */ | ||
2255 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
2256 | struct hostap_80211_rx_status *rx_stats) | ||
2257 | { | ||
2258 | struct hostap_interface *iface; | ||
2259 | local_info_t *local; | ||
2260 | u16 fc; | ||
2261 | struct ieee80211_hdr *hdr; | ||
2262 | |||
2263 | iface = netdev_priv(dev); | ||
2264 | local = iface->local; | ||
2265 | |||
2266 | if (skb->len < 16) | ||
2267 | goto drop; | ||
2268 | |||
2269 | local->stats.rx_packets++; | ||
2270 | |||
2271 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2272 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2273 | |||
2274 | if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && | ||
2275 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT && | ||
2276 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON) | ||
2277 | goto drop; | ||
2278 | |||
2279 | skb->protocol = __constant_htons(ETH_P_HOSTAP); | ||
2280 | handle_ap_item(local, skb, rx_stats); | ||
2281 | return; | ||
2282 | |||
2283 | drop: | ||
2284 | dev_kfree_skb(skb); | ||
2285 | } | ||
2286 | |||
2287 | |||
2288 | /* Called only as a tasklet (software IRQ) */ | ||
2289 | static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | ||
2290 | { | ||
2291 | struct sk_buff *skb; | ||
2292 | struct ieee80211_hdr *hdr; | ||
2293 | struct hostap_80211_rx_status rx_stats; | ||
2294 | |||
2295 | if (skb_queue_empty(&sta->tx_buf)) | ||
2296 | return; | ||
2297 | |||
2298 | skb = dev_alloc_skb(16); | ||
2299 | if (skb == NULL) { | ||
2300 | printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " | ||
2301 | "failed\n", local->dev->name); | ||
2302 | return; | ||
2303 | } | ||
2304 | |||
2305 | hdr = (struct ieee80211_hdr *) skb_put(skb, 16); | ||
2306 | |||
2307 | /* Generate a fake pspoll frame to start packet delivery */ | ||
2308 | hdr->frame_ctl = __constant_cpu_to_le16( | ||
2309 | IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
2310 | memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); | ||
2311 | memcpy(hdr->addr2, sta->addr, ETH_ALEN); | ||
2312 | hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); | ||
2313 | |||
2314 | PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " | ||
2315 | "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); | ||
2316 | |||
2317 | skb->dev = local->dev; | ||
2318 | |||
2319 | memset(&rx_stats, 0, sizeof(rx_stats)); | ||
2320 | hostap_rx(local->dev, skb, &rx_stats); | ||
2321 | } | ||
2322 | |||
2323 | |||
2324 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
2325 | struct iw_quality qual[], int buf_size, | ||
2326 | int aplist) | ||
2327 | { | ||
2328 | struct ap_data *ap = local->ap; | ||
2329 | struct list_head *ptr; | ||
2330 | int count = 0; | ||
2331 | |||
2332 | spin_lock_bh(&ap->sta_table_lock); | ||
2333 | |||
2334 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2335 | ptr = ptr->next) { | ||
2336 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2337 | |||
2338 | if (aplist && !sta->ap) | ||
2339 | continue; | ||
2340 | addr[count].sa_family = ARPHRD_ETHER; | ||
2341 | memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); | ||
2342 | if (sta->last_rx_silence == 0) | ||
2343 | qual[count].qual = sta->last_rx_signal < 27 ? | ||
2344 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2345 | else | ||
2346 | qual[count].qual = sta->last_rx_signal - | ||
2347 | sta->last_rx_silence - 35; | ||
2348 | qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2349 | qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2350 | qual[count].updated = sta->last_rx_updated; | ||
2351 | |||
2352 | sta->last_rx_updated = 0; | ||
2353 | |||
2354 | count++; | ||
2355 | if (count >= buf_size) | ||
2356 | break; | ||
2357 | } | ||
2358 | spin_unlock_bh(&ap->sta_table_lock); | ||
2359 | |||
2360 | return count; | ||
2361 | } | ||
2362 | |||
2363 | |||
2364 | /* Translate our list of Access Points & Stations to a card independant | ||
2365 | * format that the Wireless Tools will understand - Jean II */ | ||
2366 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) | ||
2367 | { | ||
2368 | struct hostap_interface *iface; | ||
2369 | local_info_t *local; | ||
2370 | struct ap_data *ap; | ||
2371 | struct list_head *ptr; | ||
2372 | struct iw_event iwe; | ||
2373 | char *current_ev = buffer; | ||
2374 | char *end_buf = buffer + IW_SCAN_MAX_DATA; | ||
2375 | #if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) | ||
2376 | char buf[64]; | ||
2377 | #endif | ||
2378 | |||
2379 | iface = netdev_priv(dev); | ||
2380 | local = iface->local; | ||
2381 | ap = local->ap; | ||
2382 | |||
2383 | spin_lock_bh(&ap->sta_table_lock); | ||
2384 | |||
2385 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2386 | ptr = ptr->next) { | ||
2387 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2388 | |||
2389 | /* First entry *MUST* be the AP MAC address */ | ||
2390 | memset(&iwe, 0, sizeof(iwe)); | ||
2391 | iwe.cmd = SIOCGIWAP; | ||
2392 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
2393 | memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); | ||
2394 | iwe.len = IW_EV_ADDR_LEN; | ||
2395 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2396 | IW_EV_ADDR_LEN); | ||
2397 | |||
2398 | /* Use the mode to indicate if it's a station or | ||
2399 | * an Access Point */ | ||
2400 | memset(&iwe, 0, sizeof(iwe)); | ||
2401 | iwe.cmd = SIOCGIWMODE; | ||
2402 | if (sta->ap) | ||
2403 | iwe.u.mode = IW_MODE_MASTER; | ||
2404 | else | ||
2405 | iwe.u.mode = IW_MODE_INFRA; | ||
2406 | iwe.len = IW_EV_UINT_LEN; | ||
2407 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2408 | IW_EV_UINT_LEN); | ||
2409 | |||
2410 | /* Some quality */ | ||
2411 | memset(&iwe, 0, sizeof(iwe)); | ||
2412 | iwe.cmd = IWEVQUAL; | ||
2413 | if (sta->last_rx_silence == 0) | ||
2414 | iwe.u.qual.qual = sta->last_rx_signal < 27 ? | ||
2415 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2416 | else | ||
2417 | iwe.u.qual.qual = sta->last_rx_signal - | ||
2418 | sta->last_rx_silence - 35; | ||
2419 | iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2420 | iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2421 | iwe.u.qual.updated = sta->last_rx_updated; | ||
2422 | iwe.len = IW_EV_QUAL_LEN; | ||
2423 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2424 | IW_EV_QUAL_LEN); | ||
2425 | |||
2426 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2427 | if (sta->ap) { | ||
2428 | memset(&iwe, 0, sizeof(iwe)); | ||
2429 | iwe.cmd = SIOCGIWESSID; | ||
2430 | iwe.u.data.length = sta->u.ap.ssid_len; | ||
2431 | iwe.u.data.flags = 1; | ||
2432 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2433 | &iwe, | ||
2434 | sta->u.ap.ssid); | ||
2435 | |||
2436 | memset(&iwe, 0, sizeof(iwe)); | ||
2437 | iwe.cmd = SIOCGIWENCODE; | ||
2438 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
2439 | iwe.u.data.flags = | ||
2440 | IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
2441 | else | ||
2442 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
2443 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2444 | &iwe, | ||
2445 | sta->u.ap.ssid | ||
2446 | /* 0 byte memcpy */); | ||
2447 | |||
2448 | if (sta->u.ap.channel > 0 && | ||
2449 | sta->u.ap.channel <= FREQ_COUNT) { | ||
2450 | memset(&iwe, 0, sizeof(iwe)); | ||
2451 | iwe.cmd = SIOCGIWFREQ; | ||
2452 | iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] | ||
2453 | * 100000; | ||
2454 | iwe.u.freq.e = 1; | ||
2455 | current_ev = iwe_stream_add_event( | ||
2456 | current_ev, end_buf, &iwe, | ||
2457 | IW_EV_FREQ_LEN); | ||
2458 | } | ||
2459 | |||
2460 | memset(&iwe, 0, sizeof(iwe)); | ||
2461 | iwe.cmd = IWEVCUSTOM; | ||
2462 | sprintf(buf, "beacon_interval=%d", | ||
2463 | sta->listen_interval); | ||
2464 | iwe.u.data.length = strlen(buf); | ||
2465 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2466 | &iwe, buf); | ||
2467 | } | ||
2468 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2469 | |||
2470 | sta->last_rx_updated = 0; | ||
2471 | |||
2472 | /* To be continued, we should make good use of IWEVCUSTOM */ | ||
2473 | } | ||
2474 | |||
2475 | spin_unlock_bh(&ap->sta_table_lock); | ||
2476 | |||
2477 | return current_ev - buffer; | ||
2478 | } | ||
2479 | |||
2480 | |||
2481 | static int prism2_hostapd_add_sta(struct ap_data *ap, | ||
2482 | struct prism2_hostapd_param *param) | ||
2483 | { | ||
2484 | struct sta_info *sta; | ||
2485 | |||
2486 | spin_lock_bh(&ap->sta_table_lock); | ||
2487 | sta = ap_get_sta(ap, param->sta_addr); | ||
2488 | if (sta) | ||
2489 | atomic_inc(&sta->users); | ||
2490 | spin_unlock_bh(&ap->sta_table_lock); | ||
2491 | |||
2492 | if (sta == NULL) { | ||
2493 | sta = ap_add_sta(ap, param->sta_addr); | ||
2494 | if (sta == NULL) | ||
2495 | return -1; | ||
2496 | } | ||
2497 | |||
2498 | if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2499 | hostap_event_new_sta(sta->local->dev, sta); | ||
2500 | |||
2501 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2502 | sta->last_rx = jiffies; | ||
2503 | sta->aid = param->u.add_sta.aid; | ||
2504 | sta->capability = param->u.add_sta.capability; | ||
2505 | sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; | ||
2506 | if (sta->tx_supp_rates & WLAN_RATE_1M) | ||
2507 | sta->supported_rates[0] = 2; | ||
2508 | if (sta->tx_supp_rates & WLAN_RATE_2M) | ||
2509 | sta->supported_rates[1] = 4; | ||
2510 | if (sta->tx_supp_rates & WLAN_RATE_5M5) | ||
2511 | sta->supported_rates[2] = 11; | ||
2512 | if (sta->tx_supp_rates & WLAN_RATE_11M) | ||
2513 | sta->supported_rates[3] = 22; | ||
2514 | prism2_check_tx_rates(sta); | ||
2515 | atomic_dec(&sta->users); | ||
2516 | return 0; | ||
2517 | } | ||
2518 | |||
2519 | |||
2520 | static int prism2_hostapd_remove_sta(struct ap_data *ap, | ||
2521 | struct prism2_hostapd_param *param) | ||
2522 | { | ||
2523 | struct sta_info *sta; | ||
2524 | |||
2525 | spin_lock_bh(&ap->sta_table_lock); | ||
2526 | sta = ap_get_sta(ap, param->sta_addr); | ||
2527 | if (sta) { | ||
2528 | ap_sta_hash_del(ap, sta); | ||
2529 | list_del(&sta->list); | ||
2530 | } | ||
2531 | spin_unlock_bh(&ap->sta_table_lock); | ||
2532 | |||
2533 | if (!sta) | ||
2534 | return -ENOENT; | ||
2535 | |||
2536 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2537 | hostap_event_expired_sta(sta->local->dev, sta); | ||
2538 | ap_free_sta(ap, sta); | ||
2539 | |||
2540 | return 0; | ||
2541 | } | ||
2542 | |||
2543 | |||
2544 | static int prism2_hostapd_get_info_sta(struct ap_data *ap, | ||
2545 | struct prism2_hostapd_param *param) | ||
2546 | { | ||
2547 | struct sta_info *sta; | ||
2548 | |||
2549 | spin_lock_bh(&ap->sta_table_lock); | ||
2550 | sta = ap_get_sta(ap, param->sta_addr); | ||
2551 | if (sta) | ||
2552 | atomic_inc(&sta->users); | ||
2553 | spin_unlock_bh(&ap->sta_table_lock); | ||
2554 | |||
2555 | if (!sta) | ||
2556 | return -ENOENT; | ||
2557 | |||
2558 | param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; | ||
2559 | |||
2560 | atomic_dec(&sta->users); | ||
2561 | |||
2562 | return 1; | ||
2563 | } | ||
2564 | |||
2565 | |||
2566 | static int prism2_hostapd_set_flags_sta(struct ap_data *ap, | ||
2567 | struct prism2_hostapd_param *param) | ||
2568 | { | ||
2569 | struct sta_info *sta; | ||
2570 | |||
2571 | spin_lock_bh(&ap->sta_table_lock); | ||
2572 | sta = ap_get_sta(ap, param->sta_addr); | ||
2573 | if (sta) { | ||
2574 | sta->flags |= param->u.set_flags_sta.flags_or; | ||
2575 | sta->flags &= param->u.set_flags_sta.flags_and; | ||
2576 | } | ||
2577 | spin_unlock_bh(&ap->sta_table_lock); | ||
2578 | |||
2579 | if (!sta) | ||
2580 | return -ENOENT; | ||
2581 | |||
2582 | return 0; | ||
2583 | } | ||
2584 | |||
2585 | |||
2586 | static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, | ||
2587 | struct prism2_hostapd_param *param) | ||
2588 | { | ||
2589 | struct sta_info *sta; | ||
2590 | int rate; | ||
2591 | |||
2592 | spin_lock_bh(&ap->sta_table_lock); | ||
2593 | sta = ap_get_sta(ap, param->sta_addr); | ||
2594 | if (sta) { | ||
2595 | sta->rx_packets = sta->tx_packets = 0; | ||
2596 | sta->rx_bytes = sta->tx_bytes = 0; | ||
2597 | for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { | ||
2598 | sta->tx_count[rate] = 0; | ||
2599 | sta->rx_count[rate] = 0; | ||
2600 | } | ||
2601 | } | ||
2602 | spin_unlock_bh(&ap->sta_table_lock); | ||
2603 | |||
2604 | if (!sta) | ||
2605 | return -ENOENT; | ||
2606 | |||
2607 | return 0; | ||
2608 | } | ||
2609 | |||
2610 | |||
2611 | static int prism2_hostapd(struct ap_data *ap, | ||
2612 | struct prism2_hostapd_param *param) | ||
2613 | { | ||
2614 | switch (param->cmd) { | ||
2615 | case PRISM2_HOSTAPD_FLUSH: | ||
2616 | ap_control_kickall(ap); | ||
2617 | return 0; | ||
2618 | case PRISM2_HOSTAPD_ADD_STA: | ||
2619 | return prism2_hostapd_add_sta(ap, param); | ||
2620 | case PRISM2_HOSTAPD_REMOVE_STA: | ||
2621 | return prism2_hostapd_remove_sta(ap, param); | ||
2622 | case PRISM2_HOSTAPD_GET_INFO_STA: | ||
2623 | return prism2_hostapd_get_info_sta(ap, param); | ||
2624 | case PRISM2_HOSTAPD_SET_FLAGS_STA: | ||
2625 | return prism2_hostapd_set_flags_sta(ap, param); | ||
2626 | case PRISM2_HOSTAPD_STA_CLEAR_STATS: | ||
2627 | return prism2_hostapd_sta_clear_stats(ap, param); | ||
2628 | default: | ||
2629 | printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", | ||
2630 | param->cmd); | ||
2631 | return -EOPNOTSUPP; | ||
2632 | } | ||
2633 | } | ||
2634 | |||
2635 | |||
2636 | /* Update station info for host-based TX rate control and return current | ||
2637 | * TX rate */ | ||
2638 | static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) | ||
2639 | { | ||
2640 | int ret = sta->tx_rate; | ||
2641 | struct hostap_interface *iface; | ||
2642 | local_info_t *local; | ||
2643 | |||
2644 | iface = netdev_priv(dev); | ||
2645 | local = iface->local; | ||
2646 | |||
2647 | sta->tx_count[sta->tx_rate_idx]++; | ||
2648 | sta->tx_since_last_failure++; | ||
2649 | sta->tx_consecutive_exc = 0; | ||
2650 | if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && | ||
2651 | sta->tx_rate_idx < sta->tx_max_rate) { | ||
2652 | /* use next higher rate */ | ||
2653 | int old_rate, new_rate; | ||
2654 | old_rate = new_rate = sta->tx_rate_idx; | ||
2655 | while (new_rate < sta->tx_max_rate) { | ||
2656 | new_rate++; | ||
2657 | if (ap_tx_rate_ok(new_rate, sta, local)) { | ||
2658 | sta->tx_rate_idx = new_rate; | ||
2659 | break; | ||
2660 | } | ||
2661 | } | ||
2662 | if (old_rate != sta->tx_rate_idx) { | ||
2663 | switch (sta->tx_rate_idx) { | ||
2664 | case 0: sta->tx_rate = 10; break; | ||
2665 | case 1: sta->tx_rate = 20; break; | ||
2666 | case 2: sta->tx_rate = 55; break; | ||
2667 | case 3: sta->tx_rate = 110; break; | ||
2668 | default: sta->tx_rate = 0; break; | ||
2669 | } | ||
2670 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" | ||
2671 | " %d\n", dev->name, MAC2STR(sta->addr), | ||
2672 | sta->tx_rate); | ||
2673 | } | ||
2674 | sta->tx_since_last_failure = 0; | ||
2675 | } | ||
2676 | |||
2677 | return ret; | ||
2678 | } | ||
2679 | |||
2680 | |||
2681 | /* Called only from software IRQ. Called for each TX frame prior possible | ||
2682 | * encryption and transmit. */ | ||
2683 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | ||
2684 | { | ||
2685 | struct sta_info *sta = NULL; | ||
2686 | struct sk_buff *skb = tx->skb; | ||
2687 | int set_tim, ret; | ||
2688 | struct ieee80211_hdr *hdr; | ||
2689 | struct hostap_skb_tx_data *meta; | ||
2690 | |||
2691 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
2692 | ret = AP_TX_CONTINUE; | ||
2693 | if (local->ap == NULL || skb->len < 10 || | ||
2694 | meta->iface->type == HOSTAP_INTERFACE_STA) | ||
2695 | goto out; | ||
2696 | |||
2697 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2698 | |||
2699 | if (hdr->addr1[0] & 0x01) { | ||
2700 | /* broadcast/multicast frame - no AP related processing */ | ||
2701 | goto out; | ||
2702 | } | ||
2703 | |||
2704 | /* unicast packet - check whether destination STA is associated */ | ||
2705 | spin_lock(&local->ap->sta_table_lock); | ||
2706 | sta = ap_get_sta(local->ap, hdr->addr1); | ||
2707 | if (sta) | ||
2708 | atomic_inc(&sta->users); | ||
2709 | spin_unlock(&local->ap->sta_table_lock); | ||
2710 | |||
2711 | if (local->iw_mode == IW_MODE_MASTER && sta == NULL && | ||
2712 | !(meta->flags & HOSTAP_TX_FLAGS_WDS) && | ||
2713 | meta->iface->type != HOSTAP_INTERFACE_MASTER && | ||
2714 | meta->iface->type != HOSTAP_INTERFACE_AP) { | ||
2715 | #if 0 | ||
2716 | /* This can happen, e.g., when wlan0 is added to a bridge and | ||
2717 | * bridging code does not know which port is the correct target | ||
2718 | * for a unicast frame. In this case, the packet is send to all | ||
2719 | * ports of the bridge. Since this is a valid scenario, do not | ||
2720 | * print out any errors here. */ | ||
2721 | if (net_ratelimit()) { | ||
2722 | printk(KERN_DEBUG "AP: drop packet to non-associated " | ||
2723 | "STA " MACSTR "\n", MAC2STR(hdr->addr1)); | ||
2724 | } | ||
2725 | #endif | ||
2726 | local->ap->tx_drop_nonassoc++; | ||
2727 | ret = AP_TX_DROP; | ||
2728 | goto out; | ||
2729 | } | ||
2730 | |||
2731 | if (sta == NULL) | ||
2732 | goto out; | ||
2733 | |||
2734 | if (!(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2735 | ret = AP_TX_CONTINUE_NOT_AUTHORIZED; | ||
2736 | |||
2737 | /* Set tx_rate if using host-based TX rate control */ | ||
2738 | if (!local->fw_tx_rate_control) | ||
2739 | local->ap->last_tx_rate = meta->rate = | ||
2740 | ap_update_sta_tx_rate(sta, local->dev); | ||
2741 | |||
2742 | if (local->iw_mode != IW_MODE_MASTER) | ||
2743 | goto out; | ||
2744 | |||
2745 | if (!(sta->flags & WLAN_STA_PS)) | ||
2746 | goto out; | ||
2747 | |||
2748 | if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { | ||
2749 | /* indicate to STA that more frames follow */ | ||
2750 | hdr->frame_ctl |= | ||
2751 | __constant_cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
2752 | } | ||
2753 | |||
2754 | if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { | ||
2755 | /* packet was already buffered and now send due to | ||
2756 | * PS poll, so do not rebuffer it */ | ||
2757 | goto out; | ||
2758 | } | ||
2759 | |||
2760 | if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { | ||
2761 | PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS " | ||
2762 | "mode buffer\n", local->dev->name, MAC2STR(sta->addr)); | ||
2763 | /* Make sure that TIM is set for the station (it might not be | ||
2764 | * after AP wlan hw reset). */ | ||
2765 | /* FIX: should fix hw reset to restore bits based on STA | ||
2766 | * buffer state.. */ | ||
2767 | hostap_set_tim(local, sta->aid, 1); | ||
2768 | sta->flags |= WLAN_STA_TIM; | ||
2769 | ret = AP_TX_DROP; | ||
2770 | goto out; | ||
2771 | } | ||
2772 | |||
2773 | /* STA in PS mode, buffer frame for later delivery */ | ||
2774 | set_tim = skb_queue_empty(&sta->tx_buf); | ||
2775 | skb_queue_tail(&sta->tx_buf, skb); | ||
2776 | /* FIX: could save RX time to skb and expire buffered frames after | ||
2777 | * some time if STA does not poll for them */ | ||
2778 | |||
2779 | if (set_tim) { | ||
2780 | if (sta->flags & WLAN_STA_TIM) | ||
2781 | PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", | ||
2782 | sta->aid); | ||
2783 | hostap_set_tim(local, sta->aid, 1); | ||
2784 | sta->flags |= WLAN_STA_TIM; | ||
2785 | } | ||
2786 | |||
2787 | ret = AP_TX_BUFFERED; | ||
2788 | |||
2789 | out: | ||
2790 | if (sta != NULL) { | ||
2791 | if (ret == AP_TX_CONTINUE || | ||
2792 | ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { | ||
2793 | sta->tx_packets++; | ||
2794 | sta->tx_bytes += skb->len; | ||
2795 | sta->last_tx = jiffies; | ||
2796 | } | ||
2797 | |||
2798 | if ((ret == AP_TX_CONTINUE || | ||
2799 | ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && | ||
2800 | sta->crypt && tx->host_encrypt) { | ||
2801 | tx->crypt = sta->crypt; | ||
2802 | tx->sta_ptr = sta; /* hostap_handle_sta_release() will | ||
2803 | * be called to release sta info | ||
2804 | * later */ | ||
2805 | } else | ||
2806 | atomic_dec(&sta->users); | ||
2807 | } | ||
2808 | |||
2809 | return ret; | ||
2810 | } | ||
2811 | |||
2812 | |||
2813 | void hostap_handle_sta_release(void *ptr) | ||
2814 | { | ||
2815 | struct sta_info *sta = ptr; | ||
2816 | atomic_dec(&sta->users); | ||
2817 | } | ||
2818 | |||
2819 | |||
2820 | /* Called only as a tasklet (software IRQ) */ | ||
2821 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) | ||
2822 | { | ||
2823 | struct sta_info *sta; | ||
2824 | struct ieee80211_hdr *hdr; | ||
2825 | struct hostap_skb_tx_data *meta; | ||
2826 | |||
2827 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2828 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
2829 | |||
2830 | spin_lock(&local->ap->sta_table_lock); | ||
2831 | sta = ap_get_sta(local->ap, hdr->addr1); | ||
2832 | if (!sta) { | ||
2833 | spin_unlock(&local->ap->sta_table_lock); | ||
2834 | PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this " | ||
2835 | "TX error (@%lu)\n", | ||
2836 | local->dev->name, MAC2STR(hdr->addr1), jiffies); | ||
2837 | return; | ||
2838 | } | ||
2839 | |||
2840 | sta->tx_since_last_failure = 0; | ||
2841 | sta->tx_consecutive_exc++; | ||
2842 | |||
2843 | if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && | ||
2844 | sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { | ||
2845 | /* use next lower rate */ | ||
2846 | int old, rate; | ||
2847 | old = rate = sta->tx_rate_idx; | ||
2848 | while (rate > 0) { | ||
2849 | rate--; | ||
2850 | if (ap_tx_rate_ok(rate, sta, local)) { | ||
2851 | sta->tx_rate_idx = rate; | ||
2852 | break; | ||
2853 | } | ||
2854 | } | ||
2855 | if (old != sta->tx_rate_idx) { | ||
2856 | switch (sta->tx_rate_idx) { | ||
2857 | case 0: sta->tx_rate = 10; break; | ||
2858 | case 1: sta->tx_rate = 20; break; | ||
2859 | case 2: sta->tx_rate = 55; break; | ||
2860 | case 3: sta->tx_rate = 110; break; | ||
2861 | default: sta->tx_rate = 0; break; | ||
2862 | } | ||
2863 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered " | ||
2864 | "to %d\n", local->dev->name, MAC2STR(sta->addr), | ||
2865 | sta->tx_rate); | ||
2866 | } | ||
2867 | sta->tx_consecutive_exc = 0; | ||
2868 | } | ||
2869 | spin_unlock(&local->ap->sta_table_lock); | ||
2870 | } | ||
2871 | |||
2872 | |||
2873 | static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, | ||
2874 | int pwrmgt, int type, int stype) | ||
2875 | { | ||
2876 | if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { | ||
2877 | sta->flags |= WLAN_STA_PS; | ||
2878 | PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS " | ||
2879 | "mode (type=0x%02X, stype=0x%02X)\n", | ||
2880 | MAC2STR(sta->addr), type >> 2, stype >> 4); | ||
2881 | } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { | ||
2882 | sta->flags &= ~WLAN_STA_PS; | ||
2883 | PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use " | ||
2884 | "PS mode (type=0x%02X, stype=0x%02X)\n", | ||
2885 | MAC2STR(sta->addr), type >> 2, stype >> 4); | ||
2886 | if (type != IEEE80211_FTYPE_CTL || | ||
2887 | stype != IEEE80211_STYPE_PSPOLL) | ||
2888 | schedule_packet_send(local, sta); | ||
2889 | } | ||
2890 | } | ||
2891 | |||
2892 | |||
2893 | /* Called only as a tasklet (software IRQ). Called for each RX frame to update | ||
2894 | * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ | ||
2895 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) | ||
2896 | { | ||
2897 | struct sta_info *sta; | ||
2898 | u16 fc; | ||
2899 | |||
2900 | spin_lock(&local->ap->sta_table_lock); | ||
2901 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2902 | if (sta) | ||
2903 | atomic_inc(&sta->users); | ||
2904 | spin_unlock(&local->ap->sta_table_lock); | ||
2905 | |||
2906 | if (!sta) | ||
2907 | return -1; | ||
2908 | |||
2909 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2910 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | ||
2911 | WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc)); | ||
2912 | |||
2913 | atomic_dec(&sta->users); | ||
2914 | return 0; | ||
2915 | } | ||
2916 | |||
2917 | |||
2918 | /* Called only as a tasklet (software IRQ). Called for each RX frame after | ||
2919 | * getting RX header and payload from hardware. */ | ||
2920 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
2921 | struct sk_buff *skb, | ||
2922 | struct hostap_80211_rx_status *rx_stats, | ||
2923 | int wds) | ||
2924 | { | ||
2925 | int ret; | ||
2926 | struct sta_info *sta; | ||
2927 | u16 fc, type, stype; | ||
2928 | struct ieee80211_hdr *hdr; | ||
2929 | |||
2930 | if (local->ap == NULL) | ||
2931 | return AP_RX_CONTINUE; | ||
2932 | |||
2933 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2934 | |||
2935 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2936 | type = WLAN_FC_GET_TYPE(fc); | ||
2937 | stype = WLAN_FC_GET_STYPE(fc); | ||
2938 | |||
2939 | spin_lock(&local->ap->sta_table_lock); | ||
2940 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2941 | if (sta) | ||
2942 | atomic_inc(&sta->users); | ||
2943 | spin_unlock(&local->ap->sta_table_lock); | ||
2944 | |||
2945 | if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2946 | ret = AP_RX_CONTINUE_NOT_AUTHORIZED; | ||
2947 | else | ||
2948 | ret = AP_RX_CONTINUE; | ||
2949 | |||
2950 | |||
2951 | if (fc & IEEE80211_FCTL_TODS) { | ||
2952 | if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { | ||
2953 | if (local->hostapd) { | ||
2954 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2955 | PRISM2_RX_NON_ASSOC); | ||
2956 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2957 | } else { | ||
2958 | printk(KERN_DEBUG "%s: dropped received packet" | ||
2959 | " from non-associated STA " MACSTR | ||
2960 | " (type=0x%02x, subtype=0x%02x)\n", | ||
2961 | dev->name, MAC2STR(hdr->addr2), | ||
2962 | type >> 2, stype >> 4); | ||
2963 | hostap_rx(dev, skb, rx_stats); | ||
2964 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2965 | } | ||
2966 | ret = AP_RX_EXIT; | ||
2967 | goto out; | ||
2968 | } | ||
2969 | } else if (fc & IEEE80211_FCTL_FROMDS) { | ||
2970 | if (!wds) { | ||
2971 | /* FromDS frame - not for us; probably | ||
2972 | * broadcast/multicast in another BSS - drop */ | ||
2973 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2974 | printk(KERN_DEBUG "Odd.. FromDS packet " | ||
2975 | "received with own BSSID\n"); | ||
2976 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
2977 | } | ||
2978 | ret = AP_RX_DROP; | ||
2979 | goto out; | ||
2980 | } | ||
2981 | } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && | ||
2982 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2983 | |||
2984 | if (local->hostapd) { | ||
2985 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2986 | PRISM2_RX_NON_ASSOC); | ||
2987 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2988 | } else { | ||
2989 | /* At least Lucent f/w seems to send data::nullfunc | ||
2990 | * frames with no ToDS flag when the current AP returns | ||
2991 | * after being unavailable for some time. Speed up | ||
2992 | * re-association by informing the station about it not | ||
2993 | * being associated. */ | ||
2994 | printk(KERN_DEBUG "%s: rejected received nullfunc " | ||
2995 | "frame without ToDS from not associated STA " | ||
2996 | MACSTR "\n", | ||
2997 | dev->name, MAC2STR(hdr->addr2)); | ||
2998 | hostap_rx(dev, skb, rx_stats); | ||
2999 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3000 | } | ||
3001 | ret = AP_RX_EXIT; | ||
3002 | goto out; | ||
3003 | } else if (stype == IEEE80211_STYPE_NULLFUNC) { | ||
3004 | /* At least Lucent cards seem to send periodic nullfunc | ||
3005 | * frames with ToDS. Let these through to update SQ | ||
3006 | * stats and PS state. Nullfunc frames do not contain | ||
3007 | * any data and they will be dropped below. */ | ||
3008 | } else { | ||
3009 | /* If BSSID (Addr3) is foreign, this frame is a normal | ||
3010 | * broadcast frame from an IBSS network. Drop it silently. | ||
3011 | * If BSSID is own, report the dropping of this frame. */ | ||
3012 | if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
3013 | printk(KERN_DEBUG "%s: dropped received packet from " | ||
3014 | MACSTR " with no ToDS flag (type=0x%02x, " | ||
3015 | "subtype=0x%02x)\n", dev->name, | ||
3016 | MAC2STR(hdr->addr2), type >> 2, stype >> 4); | ||
3017 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
3018 | } | ||
3019 | ret = AP_RX_DROP; | ||
3020 | goto out; | ||
3021 | } | ||
3022 | |||
3023 | if (sta) { | ||
3024 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | ||
3025 | type, stype); | ||
3026 | |||
3027 | sta->rx_packets++; | ||
3028 | sta->rx_bytes += skb->len; | ||
3029 | sta->last_rx = jiffies; | ||
3030 | } | ||
3031 | |||
3032 | if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && | ||
3033 | fc & IEEE80211_FCTL_TODS) { | ||
3034 | if (local->hostapd) { | ||
3035 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
3036 | PRISM2_RX_NULLFUNC_ACK); | ||
3037 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3038 | } else { | ||
3039 | /* some STA f/w's seem to require control::ACK frame | ||
3040 | * for data::nullfunc, but Prism2 f/w 0.8.0 (at least | ||
3041 | * from Compaq) does not send this.. Try to generate | ||
3042 | * ACK for these frames from the host driver to make | ||
3043 | * power saving work with, e.g., Lucent WaveLAN f/w */ | ||
3044 | hostap_rx(dev, skb, rx_stats); | ||
3045 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3046 | } | ||
3047 | ret = AP_RX_EXIT; | ||
3048 | goto out; | ||
3049 | } | ||
3050 | |||
3051 | out: | ||
3052 | if (sta) | ||
3053 | atomic_dec(&sta->users); | ||
3054 | |||
3055 | return ret; | ||
3056 | } | ||
3057 | |||
3058 | |||
3059 | /* Called only as a tasklet (software IRQ) */ | ||
3060 | int hostap_handle_sta_crypto(local_info_t *local, | ||
3061 | struct ieee80211_hdr *hdr, | ||
3062 | struct ieee80211_crypt_data **crypt, | ||
3063 | void **sta_ptr) | ||
3064 | { | ||
3065 | struct sta_info *sta; | ||
3066 | |||
3067 | spin_lock(&local->ap->sta_table_lock); | ||
3068 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
3069 | if (sta) | ||
3070 | atomic_inc(&sta->users); | ||
3071 | spin_unlock(&local->ap->sta_table_lock); | ||
3072 | |||
3073 | if (!sta) | ||
3074 | return -1; | ||
3075 | |||
3076 | if (sta->crypt) { | ||
3077 | *crypt = sta->crypt; | ||
3078 | *sta_ptr = sta; | ||
3079 | /* hostap_handle_sta_release() will be called to release STA | ||
3080 | * info */ | ||
3081 | } else | ||
3082 | atomic_dec(&sta->users); | ||
3083 | |||
3084 | return 0; | ||
3085 | } | ||
3086 | |||
3087 | |||
3088 | /* Called only as a tasklet (software IRQ) */ | ||
3089 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) | ||
3090 | { | ||
3091 | struct sta_info *sta; | ||
3092 | int ret = 0; | ||
3093 | |||
3094 | spin_lock(&ap->sta_table_lock); | ||
3095 | sta = ap_get_sta(ap, sta_addr); | ||
3096 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
3097 | ret = 1; | ||
3098 | spin_unlock(&ap->sta_table_lock); | ||
3099 | |||
3100 | return ret; | ||
3101 | } | ||
3102 | |||
3103 | |||
3104 | /* Called only as a tasklet (software IRQ) */ | ||
3105 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) | ||
3106 | { | ||
3107 | struct sta_info *sta; | ||
3108 | int ret = 0; | ||
3109 | |||
3110 | spin_lock(&ap->sta_table_lock); | ||
3111 | sta = ap_get_sta(ap, sta_addr); | ||
3112 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && | ||
3113 | ((sta->flags & WLAN_STA_AUTHORIZED) || | ||
3114 | ap->local->ieee_802_1x == 0)) | ||
3115 | ret = 1; | ||
3116 | spin_unlock(&ap->sta_table_lock); | ||
3117 | |||
3118 | return ret; | ||
3119 | } | ||
3120 | |||
3121 | |||
3122 | /* Called only as a tasklet (software IRQ) */ | ||
3123 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) | ||
3124 | { | ||
3125 | struct sta_info *sta; | ||
3126 | int ret = 1; | ||
3127 | |||
3128 | if (!ap) | ||
3129 | return -1; | ||
3130 | |||
3131 | spin_lock(&ap->sta_table_lock); | ||
3132 | sta = ap_get_sta(ap, sta_addr); | ||
3133 | if (sta) | ||
3134 | ret = 0; | ||
3135 | spin_unlock(&ap->sta_table_lock); | ||
3136 | |||
3137 | if (ret == 1) { | ||
3138 | sta = ap_add_sta(ap, sta_addr); | ||
3139 | if (!sta) | ||
3140 | ret = -1; | ||
3141 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
3142 | sta->ap = 1; | ||
3143 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
3144 | /* No way of knowing which rates are supported since we did not | ||
3145 | * get supported rates element from beacon/assoc req. Assume | ||
3146 | * that remote end supports all 802.11b rates. */ | ||
3147 | sta->supported_rates[0] = 0x82; | ||
3148 | sta->supported_rates[1] = 0x84; | ||
3149 | sta->supported_rates[2] = 0x0b; | ||
3150 | sta->supported_rates[3] = 0x16; | ||
3151 | sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | | ||
3152 | WLAN_RATE_5M5 | WLAN_RATE_11M; | ||
3153 | sta->tx_rate = 110; | ||
3154 | sta->tx_max_rate = sta->tx_rate_idx = 3; | ||
3155 | } | ||
3156 | |||
3157 | return ret; | ||
3158 | } | ||
3159 | |||
3160 | |||
3161 | /* Called only as a tasklet (software IRQ) */ | ||
3162 | int hostap_update_rx_stats(struct ap_data *ap, | ||
3163 | struct ieee80211_hdr *hdr, | ||
3164 | struct hostap_80211_rx_status *rx_stats) | ||
3165 | { | ||
3166 | struct sta_info *sta; | ||
3167 | |||
3168 | if (!ap) | ||
3169 | return -1; | ||
3170 | |||
3171 | spin_lock(&ap->sta_table_lock); | ||
3172 | sta = ap_get_sta(ap, hdr->addr2); | ||
3173 | if (sta) { | ||
3174 | sta->last_rx_silence = rx_stats->noise; | ||
3175 | sta->last_rx_signal = rx_stats->signal; | ||
3176 | sta->last_rx_rate = rx_stats->rate; | ||
3177 | sta->last_rx_updated = 7; | ||
3178 | if (rx_stats->rate == 10) | ||
3179 | sta->rx_count[0]++; | ||
3180 | else if (rx_stats->rate == 20) | ||
3181 | sta->rx_count[1]++; | ||
3182 | else if (rx_stats->rate == 55) | ||
3183 | sta->rx_count[2]++; | ||
3184 | else if (rx_stats->rate == 110) | ||
3185 | sta->rx_count[3]++; | ||
3186 | } | ||
3187 | spin_unlock(&ap->sta_table_lock); | ||
3188 | |||
3189 | return sta ? 0 : -1; | ||
3190 | } | ||
3191 | |||
3192 | |||
3193 | void hostap_update_rates(local_info_t *local) | ||
3194 | { | ||
3195 | struct list_head *ptr; | ||
3196 | struct ap_data *ap = local->ap; | ||
3197 | |||
3198 | if (!ap) | ||
3199 | return; | ||
3200 | |||
3201 | spin_lock_bh(&ap->sta_table_lock); | ||
3202 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
3203 | struct sta_info *sta = (struct sta_info *) ptr; | ||
3204 | prism2_check_tx_rates(sta); | ||
3205 | } | ||
3206 | spin_unlock_bh(&ap->sta_table_lock); | ||
3207 | } | ||
3208 | |||
3209 | |||
3210 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
3211 | struct ieee80211_crypt_data ***crypt) | ||
3212 | { | ||
3213 | struct sta_info *sta; | ||
3214 | |||
3215 | spin_lock_bh(&ap->sta_table_lock); | ||
3216 | sta = ap_get_sta(ap, addr); | ||
3217 | if (sta) | ||
3218 | atomic_inc(&sta->users); | ||
3219 | spin_unlock_bh(&ap->sta_table_lock); | ||
3220 | |||
3221 | if (!sta && permanent) | ||
3222 | sta = ap_add_sta(ap, addr); | ||
3223 | |||
3224 | if (!sta) | ||
3225 | return NULL; | ||
3226 | |||
3227 | if (permanent) | ||
3228 | sta->flags |= WLAN_STA_PERM; | ||
3229 | |||
3230 | *crypt = &sta->crypt; | ||
3231 | |||
3232 | return sta; | ||
3233 | } | ||
3234 | |||
3235 | |||
3236 | void hostap_add_wds_links(local_info_t *local) | ||
3237 | { | ||
3238 | struct ap_data *ap = local->ap; | ||
3239 | struct list_head *ptr; | ||
3240 | |||
3241 | spin_lock_bh(&ap->sta_table_lock); | ||
3242 | list_for_each(ptr, &ap->sta_list) { | ||
3243 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
3244 | if (sta->ap) | ||
3245 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
3246 | } | ||
3247 | spin_unlock_bh(&ap->sta_table_lock); | ||
3248 | |||
3249 | schedule_work(&local->ap->wds_oper_queue); | ||
3250 | } | ||
3251 | |||
3252 | |||
3253 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) | ||
3254 | { | ||
3255 | struct wds_oper_data *entry; | ||
3256 | |||
3257 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
3258 | if (!entry) | ||
3259 | return; | ||
3260 | memcpy(entry->addr, addr, ETH_ALEN); | ||
3261 | entry->type = type; | ||
3262 | spin_lock_bh(&local->lock); | ||
3263 | entry->next = local->ap->wds_oper_entries; | ||
3264 | local->ap->wds_oper_entries = entry; | ||
3265 | spin_unlock_bh(&local->lock); | ||
3266 | |||
3267 | schedule_work(&local->ap->wds_oper_queue); | ||
3268 | } | ||
3269 | |||
3270 | |||
3271 | EXPORT_SYMBOL(hostap_init_data); | ||
3272 | EXPORT_SYMBOL(hostap_init_ap_proc); | ||
3273 | EXPORT_SYMBOL(hostap_free_data); | ||
3274 | EXPORT_SYMBOL(hostap_check_sta_fw_version); | ||
3275 | EXPORT_SYMBOL(hostap_handle_sta_tx); | ||
3276 | EXPORT_SYMBOL(hostap_handle_sta_release); | ||
3277 | EXPORT_SYMBOL(hostap_handle_sta_tx_exc); | ||
3278 | EXPORT_SYMBOL(hostap_update_sta_ps); | ||
3279 | EXPORT_SYMBOL(hostap_handle_sta_rx); | ||
3280 | EXPORT_SYMBOL(hostap_is_sta_assoc); | ||
3281 | EXPORT_SYMBOL(hostap_is_sta_authorized); | ||
3282 | EXPORT_SYMBOL(hostap_add_sta); | ||
3283 | EXPORT_SYMBOL(hostap_update_rates); | ||
3284 | EXPORT_SYMBOL(hostap_add_wds_links); | ||
3285 | EXPORT_SYMBOL(hostap_wds_link_oper); | ||
3286 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3287 | EXPORT_SYMBOL(hostap_deauth_all_stas); | ||
3288 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h new file mode 100644 index 000000000000..816a52bcea8f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.h | |||
@@ -0,0 +1,261 @@ | |||
1 | #ifndef HOSTAP_AP_H | ||
2 | #define HOSTAP_AP_H | ||
3 | |||
4 | /* AP data structures for STAs */ | ||
5 | |||
6 | /* maximum number of frames to buffer per STA */ | ||
7 | #define STA_MAX_TX_BUFFER 32 | ||
8 | |||
9 | /* STA flags */ | ||
10 | #define WLAN_STA_AUTH BIT(0) | ||
11 | #define WLAN_STA_ASSOC BIT(1) | ||
12 | #define WLAN_STA_PS BIT(2) | ||
13 | #define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ | ||
14 | #define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ | ||
15 | #define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is | ||
16 | * controlling whether STA is authorized to | ||
17 | * send and receive non-IEEE 802.1X frames | ||
18 | */ | ||
19 | #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ | ||
20 | |||
21 | #define WLAN_RATE_1M BIT(0) | ||
22 | #define WLAN_RATE_2M BIT(1) | ||
23 | #define WLAN_RATE_5M5 BIT(2) | ||
24 | #define WLAN_RATE_11M BIT(3) | ||
25 | #define WLAN_RATE_COUNT 4 | ||
26 | |||
27 | /* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, | ||
28 | * but some pre-standard IEEE 802.11g products use longer elements. */ | ||
29 | #define WLAN_SUPP_RATES_MAX 32 | ||
30 | |||
31 | /* Try to increase TX rate after # successfully sent consecutive packets */ | ||
32 | #define WLAN_RATE_UPDATE_COUNT 50 | ||
33 | |||
34 | /* Decrease TX rate after # consecutive dropped packets */ | ||
35 | #define WLAN_RATE_DECREASE_THRESHOLD 2 | ||
36 | |||
37 | struct sta_info { | ||
38 | struct list_head list; | ||
39 | struct sta_info *hnext; /* next entry in hash table list */ | ||
40 | atomic_t users; /* number of users (do not remove if > 0) */ | ||
41 | struct proc_dir_entry *proc; | ||
42 | |||
43 | u8 addr[6]; | ||
44 | u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ | ||
45 | u32 flags; | ||
46 | u16 capability; | ||
47 | u16 listen_interval; /* or beacon_int for APs */ | ||
48 | u8 supported_rates[WLAN_SUPP_RATES_MAX]; | ||
49 | |||
50 | unsigned long last_auth; | ||
51 | unsigned long last_assoc; | ||
52 | unsigned long last_rx; | ||
53 | unsigned long last_tx; | ||
54 | unsigned long rx_packets, tx_packets; | ||
55 | unsigned long rx_bytes, tx_bytes; | ||
56 | struct sk_buff_head tx_buf; | ||
57 | /* FIX: timeout buffers with an expiry time somehow derived from | ||
58 | * listen_interval */ | ||
59 | |||
60 | s8 last_rx_silence; /* Noise in dBm */ | ||
61 | s8 last_rx_signal; /* Signal strength in dBm */ | ||
62 | u8 last_rx_rate; /* TX rate in 0.1 Mbps */ | ||
63 | u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ | ||
64 | |||
65 | u8 tx_supp_rates; /* bit field of supported TX rates */ | ||
66 | u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ | ||
67 | u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ | ||
68 | u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ | ||
69 | u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ | ||
70 | u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) | ||
71 | */ | ||
72 | u32 tx_since_last_failure; | ||
73 | u32 tx_consecutive_exc; | ||
74 | |||
75 | struct ieee80211_crypt_data *crypt; | ||
76 | |||
77 | int ap; /* whether this station is an AP */ | ||
78 | |||
79 | local_info_t *local; | ||
80 | |||
81 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
82 | union { | ||
83 | struct { | ||
84 | char *challenge; /* shared key authentication | ||
85 | * challenge */ | ||
86 | } sta; | ||
87 | struct { | ||
88 | int ssid_len; | ||
89 | unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ | ||
90 | int channel; | ||
91 | unsigned long last_beacon; /* last RX beacon time */ | ||
92 | } ap; | ||
93 | } u; | ||
94 | |||
95 | struct timer_list timer; | ||
96 | enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; | ||
97 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
98 | }; | ||
99 | |||
100 | |||
101 | #define MAX_STA_COUNT 1024 | ||
102 | |||
103 | /* Maximum number of AIDs to use for STAs; must be 2007 or lower | ||
104 | * (8802.11 limitation) */ | ||
105 | #define MAX_AID_TABLE_SIZE 128 | ||
106 | |||
107 | #define STA_HASH_SIZE 256 | ||
108 | #define STA_HASH(sta) (sta[5]) | ||
109 | |||
110 | |||
111 | /* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC | ||
112 | * has passed since last received frame from the station, a nullfunc data | ||
113 | * frame is sent to the station. If this frame is not acknowledged and no other | ||
114 | * frames have been received, the station will be disassociated after | ||
115 | * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after | ||
116 | * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with | ||
117 | * max inactivity timer. */ | ||
118 | #define AP_MAX_INACTIVITY_SEC (5 * 60) | ||
119 | #define AP_DISASSOC_DELAY (HZ) | ||
120 | #define AP_DEAUTH_DELAY (HZ) | ||
121 | |||
122 | /* ap_policy: whether to accept frames to/from other APs/IBSS */ | ||
123 | typedef enum { | ||
124 | AP_OTHER_AP_SKIP_ALL = 0, | ||
125 | AP_OTHER_AP_SAME_SSID = 1, | ||
126 | AP_OTHER_AP_ALL = 2, | ||
127 | AP_OTHER_AP_EVEN_IBSS = 3 | ||
128 | } ap_policy_enum; | ||
129 | |||
130 | #define PRISM2_AUTH_OPEN BIT(0) | ||
131 | #define PRISM2_AUTH_SHARED_KEY BIT(1) | ||
132 | |||
133 | |||
134 | /* MAC address-based restrictions */ | ||
135 | struct mac_entry { | ||
136 | struct list_head list; | ||
137 | u8 addr[6]; | ||
138 | }; | ||
139 | |||
140 | struct mac_restrictions { | ||
141 | enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; | ||
142 | unsigned int entries; | ||
143 | struct list_head mac_list; | ||
144 | spinlock_t lock; | ||
145 | }; | ||
146 | |||
147 | |||
148 | struct add_sta_proc_data { | ||
149 | u8 addr[ETH_ALEN]; | ||
150 | struct add_sta_proc_data *next; | ||
151 | }; | ||
152 | |||
153 | |||
154 | typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; | ||
155 | struct wds_oper_data { | ||
156 | wds_oper_type type; | ||
157 | u8 addr[ETH_ALEN]; | ||
158 | struct wds_oper_data *next; | ||
159 | }; | ||
160 | |||
161 | |||
162 | struct ap_data { | ||
163 | int initialized; /* whether ap_data has been initialized */ | ||
164 | local_info_t *local; | ||
165 | int bridge_packets; /* send packet to associated STAs directly to the | ||
166 | * wireless media instead of higher layers in the | ||
167 | * kernel */ | ||
168 | unsigned int bridged_unicast; /* number of unicast frames bridged on | ||
169 | * wireless media */ | ||
170 | unsigned int bridged_multicast; /* number of non-unicast frames | ||
171 | * bridged on wireless media */ | ||
172 | unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped | ||
173 | * because they were to an address that | ||
174 | * was not associated */ | ||
175 | int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ | ||
176 | |||
177 | spinlock_t sta_table_lock; | ||
178 | int num_sta; /* number of entries in sta_list */ | ||
179 | struct list_head sta_list; /* STA info list head */ | ||
180 | struct sta_info *sta_hash[STA_HASH_SIZE]; | ||
181 | |||
182 | struct proc_dir_entry *proc; | ||
183 | |||
184 | ap_policy_enum ap_policy; | ||
185 | unsigned int max_inactivity; | ||
186 | int autom_ap_wds; | ||
187 | |||
188 | struct mac_restrictions mac_restrictions; /* MAC-based auth */ | ||
189 | int last_tx_rate; | ||
190 | |||
191 | struct work_struct add_sta_proc_queue; | ||
192 | struct add_sta_proc_data *add_sta_proc_entries; | ||
193 | |||
194 | struct work_struct wds_oper_queue; | ||
195 | struct wds_oper_data *wds_oper_entries; | ||
196 | |||
197 | u16 tx_callback_idx; | ||
198 | |||
199 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
200 | /* pointers to STA info; based on allocated AID or NULL if AID free | ||
201 | * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 | ||
202 | * and so on | ||
203 | */ | ||
204 | struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; | ||
205 | |||
206 | u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; | ||
207 | |||
208 | /* WEP operations for generating challenges to be used with shared key | ||
209 | * authentication */ | ||
210 | struct ieee80211_crypto_ops *crypt; | ||
211 | void *crypt_priv; | ||
212 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
213 | }; | ||
214 | |||
215 | |||
216 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
217 | struct hostap_80211_rx_status *rx_stats); | ||
218 | void hostap_init_data(local_info_t *local); | ||
219 | void hostap_init_ap_proc(local_info_t *local); | ||
220 | void hostap_free_data(struct ap_data *ap); | ||
221 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); | ||
222 | |||
223 | typedef enum { | ||
224 | AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, | ||
225 | AP_TX_CONTINUE_NOT_AUTHORIZED | ||
226 | } ap_tx_ret; | ||
227 | struct hostap_tx_data { | ||
228 | struct sk_buff *skb; | ||
229 | int host_encrypt; | ||
230 | struct ieee80211_crypt_data *crypt; | ||
231 | void *sta_ptr; | ||
232 | }; | ||
233 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); | ||
234 | void hostap_handle_sta_release(void *ptr); | ||
235 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); | ||
236 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); | ||
237 | typedef enum { | ||
238 | AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED | ||
239 | } ap_rx_ret; | ||
240 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
241 | struct sk_buff *skb, | ||
242 | struct hostap_80211_rx_status *rx_stats, | ||
243 | int wds); | ||
244 | int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, | ||
245 | struct ieee80211_crypt_data **crypt, | ||
246 | void **sta_ptr); | ||
247 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); | ||
248 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); | ||
249 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); | ||
250 | int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, | ||
251 | struct hostap_80211_rx_status *rx_stats); | ||
252 | void hostap_update_rates(local_info_t *local); | ||
253 | void hostap_add_wds_links(local_info_t *local); | ||
254 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); | ||
255 | |||
256 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
257 | void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | ||
258 | int resend); | ||
259 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
260 | |||
261 | #endif /* HOSTAP_AP_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h new file mode 100644 index 000000000000..6f4fa9dc308f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_common.h | |||
@@ -0,0 +1,435 @@ | |||
1 | #ifndef HOSTAP_COMMON_H | ||
2 | #define HOSTAP_COMMON_H | ||
3 | |||
4 | #define BIT(x) (1 << (x)) | ||
5 | |||
6 | #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] | ||
7 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" | ||
8 | |||
9 | |||
10 | /* IEEE 802.11 defines */ | ||
11 | |||
12 | /* Information Element IDs */ | ||
13 | #define WLAN_EID_SSID 0 | ||
14 | #define WLAN_EID_SUPP_RATES 1 | ||
15 | #define WLAN_EID_FH_PARAMS 2 | ||
16 | #define WLAN_EID_DS_PARAMS 3 | ||
17 | #define WLAN_EID_CF_PARAMS 4 | ||
18 | #define WLAN_EID_TIM 5 | ||
19 | #define WLAN_EID_IBSS_PARAMS 6 | ||
20 | #define WLAN_EID_CHALLENGE 16 | ||
21 | #define WLAN_EID_RSN 48 | ||
22 | #define WLAN_EID_GENERIC 221 | ||
23 | |||
24 | |||
25 | /* HFA384X Configuration RIDs */ | ||
26 | #define HFA384X_RID_CNFPORTTYPE 0xFC00 | ||
27 | #define HFA384X_RID_CNFOWNMACADDR 0xFC01 | ||
28 | #define HFA384X_RID_CNFDESIREDSSID 0xFC02 | ||
29 | #define HFA384X_RID_CNFOWNCHANNEL 0xFC03 | ||
30 | #define HFA384X_RID_CNFOWNSSID 0xFC04 | ||
31 | #define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 | ||
32 | #define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 | ||
33 | #define HFA384X_RID_CNFMAXDATALEN 0xFC07 | ||
34 | #define HFA384X_RID_CNFWDSADDRESS 0xFC08 | ||
35 | #define HFA384X_RID_CNFPMENABLED 0xFC09 | ||
36 | #define HFA384X_RID_CNFPMEPS 0xFC0A | ||
37 | #define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B | ||
38 | #define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C | ||
39 | #define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D | ||
40 | #define HFA384X_RID_CNFOWNNAME 0xFC0E | ||
41 | #define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 | ||
42 | #define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ | ||
43 | #define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ | ||
44 | #define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ | ||
45 | #define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ | ||
46 | #define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ | ||
47 | #define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ | ||
48 | #define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ | ||
49 | #define HFA384X_RID_UNKNOWN1 0xFC20 | ||
50 | #define HFA384X_RID_UNKNOWN2 0xFC21 | ||
51 | #define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 | ||
52 | #define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 | ||
53 | #define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 | ||
54 | #define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 | ||
55 | #define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 | ||
56 | #define HFA384X_RID_CNFWEPFLAGS 0xFC28 | ||
57 | #define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 | ||
58 | #define HFA384X_RID_CNFAUTHENTICATION 0xFC2A | ||
59 | #define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ | ||
60 | #define HFA384X_RID_CNFTXCONTROL 0xFC2C | ||
61 | #define HFA384X_RID_CNFROAMINGMODE 0xFC2D | ||
62 | #define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ | ||
63 | #define HFA384X_RID_CNFRCVCRCERROR 0xFC30 | ||
64 | #define HFA384X_RID_CNFMMLIFE 0xFC31 | ||
65 | #define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 | ||
66 | #define HFA384X_RID_CNFBEACONINT 0xFC33 | ||
67 | #define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ | ||
68 | #define HFA384X_RID_CNFSTAPCFINFO 0xFC35 | ||
69 | #define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 | ||
70 | #define HFA384X_RID_CNFTIMCTRL 0xFC40 | ||
71 | #define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ | ||
72 | #define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ | ||
73 | #define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ | ||
74 | #define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ | ||
75 | #define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; | ||
76 | * write only */ | ||
77 | #define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ | ||
78 | #define HFA384X_RID_GROUPADDRESSES 0xFC80 | ||
79 | #define HFA384X_RID_CREATEIBSS 0xFC81 | ||
80 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 | ||
81 | #define HFA384X_RID_RTSTHRESHOLD 0xFC83 | ||
82 | #define HFA384X_RID_TXRATECONTROL 0xFC84 | ||
83 | #define HFA384X_RID_PROMISCUOUSMODE 0xFC85 | ||
84 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ | ||
85 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ | ||
86 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ | ||
87 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ | ||
88 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ | ||
89 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ | ||
90 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ | ||
91 | #define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ | ||
92 | #define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ | ||
93 | #define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ | ||
94 | #define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ | ||
95 | #define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ | ||
96 | #define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ | ||
97 | #define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ | ||
98 | #define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ | ||
99 | #define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ | ||
100 | #define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ | ||
101 | #define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ | ||
102 | #define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ | ||
103 | #define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ | ||
104 | #define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ | ||
105 | #define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 | ||
106 | #define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 | ||
107 | #define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 | ||
108 | #define HFA384X_RID_CNFBASICRATES 0xFCB3 | ||
109 | #define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 | ||
110 | #define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ | ||
111 | #define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ | ||
112 | #define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ | ||
113 | #define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ | ||
114 | #define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ | ||
115 | #define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ | ||
116 | #define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ | ||
117 | #define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ | ||
118 | #define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ | ||
119 | #define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ | ||
120 | #define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ | ||
121 | #define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ | ||
122 | #define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ | ||
123 | #define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ | ||
124 | #define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ | ||
125 | #define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ | ||
126 | #define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ | ||
127 | #define HFA384X_RID_TICKTIME 0xFCE0 | ||
128 | #define HFA384X_RID_SCANREQUEST 0xFCE1 | ||
129 | #define HFA384X_RID_JOINREQUEST 0xFCE2 | ||
130 | #define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ | ||
131 | #define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ | ||
132 | #define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ | ||
133 | |||
134 | /* HFA384X Information RIDs */ | ||
135 | #define HFA384X_RID_MAXLOADTIME 0xFD00 | ||
136 | #define HFA384X_RID_DOWNLOADBUFFER 0xFD01 | ||
137 | #define HFA384X_RID_PRIID 0xFD02 | ||
138 | #define HFA384X_RID_PRISUPRANGE 0xFD03 | ||
139 | #define HFA384X_RID_CFIACTRANGES 0xFD04 | ||
140 | #define HFA384X_RID_NICSERNUM 0xFD0A | ||
141 | #define HFA384X_RID_NICID 0xFD0B | ||
142 | #define HFA384X_RID_MFISUPRANGE 0xFD0C | ||
143 | #define HFA384X_RID_CFISUPRANGE 0xFD0D | ||
144 | #define HFA384X_RID_CHANNELLIST 0xFD10 | ||
145 | #define HFA384X_RID_REGULATORYDOMAINS 0xFD11 | ||
146 | #define HFA384X_RID_TEMPTYPE 0xFD12 | ||
147 | #define HFA384X_RID_CIS 0xFD13 | ||
148 | #define HFA384X_RID_STAID 0xFD20 | ||
149 | #define HFA384X_RID_STASUPRANGE 0xFD21 | ||
150 | #define HFA384X_RID_MFIACTRANGES 0xFD22 | ||
151 | #define HFA384X_RID_CFIACTRANGES2 0xFD23 | ||
152 | #define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; | ||
153 | * only Prism2.5(?) */ | ||
154 | #define HFA384X_RID_PORTSTATUS 0xFD40 | ||
155 | #define HFA384X_RID_CURRENTSSID 0xFD41 | ||
156 | #define HFA384X_RID_CURRENTBSSID 0xFD42 | ||
157 | #define HFA384X_RID_COMMSQUALITY 0xFD43 | ||
158 | #define HFA384X_RID_CURRENTTXRATE 0xFD44 | ||
159 | #define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 | ||
160 | #define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 | ||
161 | #define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 | ||
162 | #define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 | ||
163 | #define HFA384X_RID_LONGRETRYLIMIT 0xFD49 | ||
164 | #define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A | ||
165 | #define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B | ||
166 | #define HFA384X_RID_CFPOLLABLE 0xFD4C | ||
167 | #define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D | ||
168 | #define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F | ||
169 | #define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ | ||
170 | #define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ | ||
171 | #define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ | ||
172 | #define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ | ||
173 | #define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ | ||
174 | #define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ | ||
175 | #define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ | ||
176 | #define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ | ||
177 | #define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ | ||
178 | #define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ | ||
179 | #define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ | ||
180 | #define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ | ||
181 | #define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ | ||
182 | #define HFA384X_RID_PHYTYPE 0xFDC0 | ||
183 | #define HFA384X_RID_CURRENTCHANNEL 0xFDC1 | ||
184 | #define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 | ||
185 | #define HFA384X_RID_CCAMODE 0xFDC3 | ||
186 | #define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 | ||
187 | #define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ | ||
188 | #define HFA384X_RID_BUILDSEQ 0xFFFE | ||
189 | #define HFA384X_RID_FWID 0xFFFF | ||
190 | |||
191 | |||
192 | struct hfa384x_comp_ident | ||
193 | { | ||
194 | u16 id; | ||
195 | u16 variant; | ||
196 | u16 major; | ||
197 | u16 minor; | ||
198 | } __attribute__ ((packed)); | ||
199 | |||
200 | #define HFA384X_COMP_ID_PRI 0x15 | ||
201 | #define HFA384X_COMP_ID_STA 0x1f | ||
202 | #define HFA384X_COMP_ID_FW_AP 0x14b | ||
203 | |||
204 | struct hfa384x_sup_range | ||
205 | { | ||
206 | u16 role; | ||
207 | u16 id; | ||
208 | u16 variant; | ||
209 | u16 bottom; | ||
210 | u16 top; | ||
211 | } __attribute__ ((packed)); | ||
212 | |||
213 | |||
214 | struct hfa384x_build_id | ||
215 | { | ||
216 | u16 pri_seq; | ||
217 | u16 sec_seq; | ||
218 | } __attribute__ ((packed)); | ||
219 | |||
220 | /* FD01 - Download Buffer */ | ||
221 | struct hfa384x_rid_download_buffer | ||
222 | { | ||
223 | u16 page; | ||
224 | u16 offset; | ||
225 | u16 length; | ||
226 | } __attribute__ ((packed)); | ||
227 | |||
228 | /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ | ||
229 | struct hfa384x_comms_quality { | ||
230 | u16 comm_qual; /* 0 .. 92 */ | ||
231 | u16 signal_level; /* 27 .. 154 */ | ||
232 | u16 noise_level; /* 27 .. 154 */ | ||
233 | } __attribute__ ((packed)); | ||
234 | |||
235 | |||
236 | /* netdevice private ioctls (used, e.g., with iwpriv from user space) */ | ||
237 | |||
238 | /* New wireless extensions API - SET/GET convention (even ioctl numbers are | ||
239 | * root only) | ||
240 | */ | ||
241 | #define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) | ||
242 | #define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) | ||
243 | #define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) | ||
244 | #define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) | ||
245 | #define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) | ||
246 | #define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) | ||
247 | #define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) | ||
248 | #define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) | ||
249 | #define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) | ||
250 | #define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) | ||
251 | #define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) | ||
252 | #define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) | ||
253 | #define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) | ||
254 | #define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) | ||
255 | |||
256 | /* following are not in SIOCGIWPRIV list; check permission in the driver code | ||
257 | */ | ||
258 | #define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) | ||
259 | #define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) | ||
260 | |||
261 | |||
262 | /* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ | ||
263 | enum { | ||
264 | /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ | ||
265 | PRISM2_PARAM_TXRATECTRL = 2, | ||
266 | PRISM2_PARAM_BEACON_INT = 3, | ||
267 | PRISM2_PARAM_PSEUDO_IBSS = 4, | ||
268 | PRISM2_PARAM_ALC = 5, | ||
269 | /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ | ||
270 | PRISM2_PARAM_DUMP = 7, | ||
271 | PRISM2_PARAM_OTHER_AP_POLICY = 8, | ||
272 | PRISM2_PARAM_AP_MAX_INACTIVITY = 9, | ||
273 | PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, | ||
274 | PRISM2_PARAM_DTIM_PERIOD = 11, | ||
275 | PRISM2_PARAM_AP_NULLFUNC_ACK = 12, | ||
276 | PRISM2_PARAM_MAX_WDS = 13, | ||
277 | PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, | ||
278 | PRISM2_PARAM_AP_AUTH_ALGS = 15, | ||
279 | PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, | ||
280 | PRISM2_PARAM_HOST_ENCRYPT = 17, | ||
281 | PRISM2_PARAM_HOST_DECRYPT = 18, | ||
282 | /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ | ||
283 | /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ | ||
284 | PRISM2_PARAM_HOST_ROAMING = 21, | ||
285 | PRISM2_PARAM_BCRX_STA_KEY = 22, | ||
286 | PRISM2_PARAM_IEEE_802_1X = 23, | ||
287 | PRISM2_PARAM_ANTSEL_TX = 24, | ||
288 | PRISM2_PARAM_ANTSEL_RX = 25, | ||
289 | PRISM2_PARAM_MONITOR_TYPE = 26, | ||
290 | PRISM2_PARAM_WDS_TYPE = 27, | ||
291 | PRISM2_PARAM_HOSTSCAN = 28, | ||
292 | PRISM2_PARAM_AP_SCAN = 29, | ||
293 | PRISM2_PARAM_ENH_SEC = 30, | ||
294 | PRISM2_PARAM_IO_DEBUG = 31, | ||
295 | PRISM2_PARAM_BASIC_RATES = 32, | ||
296 | PRISM2_PARAM_OPER_RATES = 33, | ||
297 | PRISM2_PARAM_HOSTAPD = 34, | ||
298 | PRISM2_PARAM_HOSTAPD_STA = 35, | ||
299 | PRISM2_PARAM_WPA = 36, | ||
300 | PRISM2_PARAM_PRIVACY_INVOKED = 37, | ||
301 | PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, | ||
302 | PRISM2_PARAM_DROP_UNENCRYPTED = 39, | ||
303 | PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, | ||
304 | }; | ||
305 | |||
306 | enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, | ||
307 | HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; | ||
308 | |||
309 | |||
310 | /* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ | ||
311 | enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, | ||
312 | AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, | ||
313 | AP_MAC_CMD_KICKALL = 4 }; | ||
314 | |||
315 | |||
316 | /* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ | ||
317 | enum { | ||
318 | PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, | ||
319 | /* Note! Old versions of prism2_srec have a fatal error in CRC-16 | ||
320 | * calculation, which will corrupt all non-volatile downloads. | ||
321 | * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to | ||
322 | * prevent use of old versions of prism2_srec for non-volatile | ||
323 | * download. */ | ||
324 | PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, | ||
325 | PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, | ||
326 | /* Persistent versions of volatile download commands (keep firmware | ||
327 | * data in memory and automatically re-download after hw_reset */ | ||
328 | PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, | ||
329 | PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, | ||
330 | }; | ||
331 | |||
332 | struct prism2_download_param { | ||
333 | u32 dl_cmd; | ||
334 | u32 start_addr; | ||
335 | u32 num_areas; | ||
336 | struct prism2_download_area { | ||
337 | u32 addr; /* wlan card address */ | ||
338 | u32 len; | ||
339 | void __user *ptr; /* pointer to data in user space */ | ||
340 | } data[0]; | ||
341 | }; | ||
342 | |||
343 | #define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 | ||
344 | #define PRISM2_MAX_DOWNLOAD_LEN 262144 | ||
345 | |||
346 | |||
347 | /* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ | ||
348 | enum { | ||
349 | PRISM2_HOSTAPD_FLUSH = 1, | ||
350 | PRISM2_HOSTAPD_ADD_STA = 2, | ||
351 | PRISM2_HOSTAPD_REMOVE_STA = 3, | ||
352 | PRISM2_HOSTAPD_GET_INFO_STA = 4, | ||
353 | /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ | ||
354 | PRISM2_SET_ENCRYPTION = 6, | ||
355 | PRISM2_GET_ENCRYPTION = 7, | ||
356 | PRISM2_HOSTAPD_SET_FLAGS_STA = 8, | ||
357 | PRISM2_HOSTAPD_GET_RID = 9, | ||
358 | PRISM2_HOSTAPD_SET_RID = 10, | ||
359 | PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, | ||
360 | PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, | ||
361 | PRISM2_HOSTAPD_MLME = 13, | ||
362 | PRISM2_HOSTAPD_SCAN_REQ = 14, | ||
363 | PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, | ||
364 | }; | ||
365 | |||
366 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | ||
367 | #define PRISM2_HOSTAPD_RID_HDR_LEN \ | ||
368 | ((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) | ||
369 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | ||
370 | ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) | ||
371 | |||
372 | /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() | ||
373 | */ | ||
374 | #define HOSTAP_CRYPT_ALG_NAME_LEN 16 | ||
375 | |||
376 | |||
377 | struct prism2_hostapd_param { | ||
378 | u32 cmd; | ||
379 | u8 sta_addr[ETH_ALEN]; | ||
380 | union { | ||
381 | struct { | ||
382 | u16 aid; | ||
383 | u16 capability; | ||
384 | u8 tx_supp_rates; | ||
385 | } add_sta; | ||
386 | struct { | ||
387 | u32 inactive_sec; | ||
388 | } get_info_sta; | ||
389 | struct { | ||
390 | u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; | ||
391 | u32 flags; | ||
392 | u32 err; | ||
393 | u8 idx; | ||
394 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
395 | u16 key_len; | ||
396 | u8 key[0]; | ||
397 | } crypt; | ||
398 | struct { | ||
399 | u32 flags_and; | ||
400 | u32 flags_or; | ||
401 | } set_flags_sta; | ||
402 | struct { | ||
403 | u16 rid; | ||
404 | u16 len; | ||
405 | u8 data[0]; | ||
406 | } rid; | ||
407 | struct { | ||
408 | u8 len; | ||
409 | u8 data[0]; | ||
410 | } generic_elem; | ||
411 | struct { | ||
412 | #define MLME_STA_DEAUTH 0 | ||
413 | #define MLME_STA_DISASSOC 1 | ||
414 | u16 cmd; | ||
415 | u16 reason_code; | ||
416 | } mlme; | ||
417 | struct { | ||
418 | u8 ssid_len; | ||
419 | u8 ssid[32]; | ||
420 | } scan_req; | ||
421 | } u; | ||
422 | }; | ||
423 | |||
424 | #define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) | ||
425 | #define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) | ||
426 | |||
427 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 | ||
428 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 | ||
429 | #define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 | ||
430 | #define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 | ||
431 | #define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 | ||
432 | #define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 | ||
433 | |||
434 | |||
435 | #endif /* HOSTAP_COMMON_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h new file mode 100644 index 000000000000..7ed3425d08c1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_config.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef HOSTAP_CONFIG_H | ||
2 | #define HOSTAP_CONFIG_H | ||
3 | |||
4 | #define PRISM2_VERSION "0.4.4-kernel" | ||
5 | |||
6 | /* In the previous versions of Host AP driver, support for user space version | ||
7 | * of IEEE 802.11 management (hostapd) used to be disabled in the default | ||
8 | * configuration. From now on, support for hostapd is always included and it is | ||
9 | * possible to disable kernel driver version of IEEE 802.11 management with a | ||
10 | * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ | ||
11 | /* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
12 | |||
13 | /* Maximum number of events handler per one interrupt */ | ||
14 | #define PRISM2_MAX_INTERRUPT_EVENTS 20 | ||
15 | |||
16 | /* Include code for downloading firmware images into volatile RAM. */ | ||
17 | #define PRISM2_DOWNLOAD_SUPPORT | ||
18 | |||
19 | /* Allow kernel configuration to enable download support. */ | ||
20 | #if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) | ||
21 | #define PRISM2_DOWNLOAD_SUPPORT | ||
22 | #endif | ||
23 | |||
24 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
25 | /* Allow writing firmware images into flash, i.e., to non-volatile storage. | ||
26 | * Before you enable this option, you should make absolutely sure that you are | ||
27 | * using prism2_srec utility that comes with THIS version of the driver! | ||
28 | * In addition, please note that it is possible to kill your card with | ||
29 | * non-volatile download if you are using incorrect image. This feature has not | ||
30 | * been fully tested, so please be careful with it. */ | ||
31 | /* #define PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
32 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
33 | |||
34 | /* Save low-level I/O for debugging. This should not be enabled in normal use. | ||
35 | */ | ||
36 | /* #define PRISM2_IO_DEBUG */ | ||
37 | |||
38 | /* Following defines can be used to remove unneeded parts of the driver, e.g., | ||
39 | * to limit the size of the kernel module. Definitions can be added here in | ||
40 | * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, | ||
41 | * e.g., | ||
42 | * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' | ||
43 | */ | ||
44 | |||
45 | /* Do not include debug messages into the driver */ | ||
46 | /* #define PRISM2_NO_DEBUG */ | ||
47 | |||
48 | /* Do not include /proc/net/prism2/wlan#/{registers,debug} */ | ||
49 | /* #define PRISM2_NO_PROCFS_DEBUG */ | ||
50 | |||
51 | /* Do not include station functionality (i.e., allow only Master (Host AP) mode | ||
52 | */ | ||
53 | /* #define PRISM2_NO_STATION_MODES */ | ||
54 | |||
55 | #endif /* HOSTAP_CONFIG_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c new file mode 100644 index 000000000000..faa83badf0a1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -0,0 +1,1030 @@ | |||
1 | #define PRISM2_PCCARD | ||
2 | |||
3 | #include <linux/config.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/init.h> | ||
6 | #include <linux/if.h> | ||
7 | #include <linux/wait.h> | ||
8 | #include <linux/timer.h> | ||
9 | #include <linux/skbuff.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/workqueue.h> | ||
12 | #include <linux/wireless.h> | ||
13 | #include <net/iw_handler.h> | ||
14 | |||
15 | #include <pcmcia/cs_types.h> | ||
16 | #include <pcmcia/cs.h> | ||
17 | #include <pcmcia/cistpl.h> | ||
18 | #include <pcmcia/cisreg.h> | ||
19 | #include <pcmcia/ds.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include "hostap_wlan.h" | ||
24 | |||
25 | |||
26 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
27 | static dev_info_t dev_info = "hostap_cs"; | ||
28 | static dev_link_t *dev_list = NULL; | ||
29 | |||
30 | MODULE_AUTHOR("Jouni Malinen"); | ||
31 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | ||
32 | "cards (PC Card)."); | ||
33 | MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | MODULE_VERSION(PRISM2_VERSION); | ||
36 | |||
37 | |||
38 | static int ignore_cis_vcc; | ||
39 | module_param(ignore_cis_vcc, int, 0444); | ||
40 | MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); | ||
41 | |||
42 | |||
43 | /* struct local_info::hw_priv */ | ||
44 | struct hostap_cs_priv { | ||
45 | dev_node_t node; | ||
46 | dev_link_t *link; | ||
47 | int sandisk_connectplus; | ||
48 | }; | ||
49 | |||
50 | |||
51 | #ifdef PRISM2_IO_DEBUG | ||
52 | |||
53 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
54 | { | ||
55 | struct hostap_interface *iface; | ||
56 | local_info_t *local; | ||
57 | unsigned long flags; | ||
58 | |||
59 | iface = netdev_priv(dev); | ||
60 | local = iface->local; | ||
61 | spin_lock_irqsave(&local->lock, flags); | ||
62 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
63 | outb(v, dev->base_addr + a); | ||
64 | spin_unlock_irqrestore(&local->lock, flags); | ||
65 | } | ||
66 | |||
67 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
68 | { | ||
69 | struct hostap_interface *iface; | ||
70 | local_info_t *local; | ||
71 | unsigned long flags; | ||
72 | u8 v; | ||
73 | |||
74 | iface = netdev_priv(dev); | ||
75 | local = iface->local; | ||
76 | spin_lock_irqsave(&local->lock, flags); | ||
77 | v = inb(dev->base_addr + a); | ||
78 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
79 | spin_unlock_irqrestore(&local->lock, flags); | ||
80 | return v; | ||
81 | } | ||
82 | |||
83 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
84 | { | ||
85 | struct hostap_interface *iface; | ||
86 | local_info_t *local; | ||
87 | unsigned long flags; | ||
88 | |||
89 | iface = netdev_priv(dev); | ||
90 | local = iface->local; | ||
91 | spin_lock_irqsave(&local->lock, flags); | ||
92 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
93 | outw(v, dev->base_addr + a); | ||
94 | spin_unlock_irqrestore(&local->lock, flags); | ||
95 | } | ||
96 | |||
97 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
98 | { | ||
99 | struct hostap_interface *iface; | ||
100 | local_info_t *local; | ||
101 | unsigned long flags; | ||
102 | u16 v; | ||
103 | |||
104 | iface = netdev_priv(dev); | ||
105 | local = iface->local; | ||
106 | spin_lock_irqsave(&local->lock, flags); | ||
107 | v = inw(dev->base_addr + a); | ||
108 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
109 | spin_unlock_irqrestore(&local->lock, flags); | ||
110 | return v; | ||
111 | } | ||
112 | |||
113 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
114 | u8 *buf, int wc) | ||
115 | { | ||
116 | struct hostap_interface *iface; | ||
117 | local_info_t *local; | ||
118 | unsigned long flags; | ||
119 | |||
120 | iface = netdev_priv(dev); | ||
121 | local = iface->local; | ||
122 | spin_lock_irqsave(&local->lock, flags); | ||
123 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
124 | outsw(dev->base_addr + a, buf, wc); | ||
125 | spin_unlock_irqrestore(&local->lock, flags); | ||
126 | } | ||
127 | |||
128 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
129 | u8 *buf, int wc) | ||
130 | { | ||
131 | struct hostap_interface *iface; | ||
132 | local_info_t *local; | ||
133 | unsigned long flags; | ||
134 | |||
135 | iface = netdev_priv(dev); | ||
136 | local = iface->local; | ||
137 | spin_lock_irqsave(&local->lock, flags); | ||
138 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
139 | insw(dev->base_addr + a, buf, wc); | ||
140 | spin_unlock_irqrestore(&local->lock, flags); | ||
141 | } | ||
142 | |||
143 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
144 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
145 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
146 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
147 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
148 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
149 | |||
150 | #else /* PRISM2_IO_DEBUG */ | ||
151 | |||
152 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
153 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
154 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
155 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
156 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
157 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
158 | |||
159 | #endif /* PRISM2_IO_DEBUG */ | ||
160 | |||
161 | |||
162 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
163 | int len) | ||
164 | { | ||
165 | u16 d_off; | ||
166 | u16 *pos; | ||
167 | |||
168 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
169 | pos = (u16 *) buf; | ||
170 | |||
171 | if (len / 2) | ||
172 | HFA384X_INSW(d_off, buf, len / 2); | ||
173 | pos += len / 2; | ||
174 | |||
175 | if (len & 1) | ||
176 | *((char *) pos) = HFA384X_INB(d_off); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | |||
182 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
183 | { | ||
184 | u16 d_off; | ||
185 | u16 *pos; | ||
186 | |||
187 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
188 | pos = (u16 *) buf; | ||
189 | |||
190 | if (len / 2) | ||
191 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
192 | pos += len / 2; | ||
193 | |||
194 | if (len & 1) | ||
195 | HFA384X_OUTB(*((char *) pos), d_off); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | |||
201 | /* FIX: This might change at some point.. */ | ||
202 | #include "hostap_hw.c" | ||
203 | |||
204 | |||
205 | |||
206 | static void prism2_detach(dev_link_t *link); | ||
207 | static void prism2_release(u_long arg); | ||
208 | static int prism2_event(event_t event, int priority, | ||
209 | event_callback_args_t *args); | ||
210 | |||
211 | |||
212 | static int prism2_pccard_card_present(local_info_t *local) | ||
213 | { | ||
214 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
215 | if (hw_priv != NULL && hw_priv->link != NULL && | ||
216 | ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) == | ||
217 | (DEV_PRESENT | DEV_CONFIG))) | ||
218 | return 1; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | |||
223 | /* | ||
224 | * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 | ||
225 | * Document No. 20-10-00058, January 2004 | ||
226 | * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf | ||
227 | */ | ||
228 | #define SANDISK_WLAN_ACTIVATION_OFF 0x40 | ||
229 | #define SANDISK_HCR_OFF 0x42 | ||
230 | |||
231 | |||
232 | static void sandisk_set_iobase(local_info_t *local) | ||
233 | { | ||
234 | int res; | ||
235 | conf_reg_t reg; | ||
236 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
237 | |||
238 | reg.Function = 0; | ||
239 | reg.Action = CS_WRITE; | ||
240 | reg.Offset = 0x10; /* 0x3f0 IO base 1 */ | ||
241 | reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; | ||
242 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
243 | ®); | ||
244 | if (res != CS_SUCCESS) { | ||
245 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" | ||
246 | " res=%d\n", res); | ||
247 | } | ||
248 | udelay(10); | ||
249 | |||
250 | reg.Function = 0; | ||
251 | reg.Action = CS_WRITE; | ||
252 | reg.Offset = 0x12; /* 0x3f2 IO base 2 */ | ||
253 | reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; | ||
254 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
255 | ®); | ||
256 | if (res != CS_SUCCESS) { | ||
257 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" | ||
258 | " res=%d\n", res); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void sandisk_write_hcr(local_info_t *local, int hcr) | ||
264 | { | ||
265 | struct net_device *dev = local->dev; | ||
266 | int i; | ||
267 | |||
268 | HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); | ||
269 | udelay(50); | ||
270 | for (i = 0; i < 10; i++) { | ||
271 | HFA384X_OUTB(hcr, SANDISK_HCR_OFF); | ||
272 | } | ||
273 | udelay(55); | ||
274 | HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); | ||
275 | } | ||
276 | |||
277 | |||
278 | static int sandisk_enable_wireless(struct net_device *dev) | ||
279 | { | ||
280 | int res, ret = 0; | ||
281 | conf_reg_t reg; | ||
282 | struct hostap_interface *iface = dev->priv; | ||
283 | local_info_t *local = iface->local; | ||
284 | tuple_t tuple; | ||
285 | cisparse_t *parse = NULL; | ||
286 | u_char buf[64]; | ||
287 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
288 | |||
289 | if (hw_priv->link->io.NumPorts1 < 0x42) { | ||
290 | /* Not enough ports to be SanDisk multi-function card */ | ||
291 | ret = -ENODEV; | ||
292 | goto done; | ||
293 | } | ||
294 | |||
295 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
296 | if (parse == NULL) { | ||
297 | ret = -ENOMEM; | ||
298 | goto done; | ||
299 | } | ||
300 | |||
301 | tuple.DesiredTuple = CISTPL_MANFID; | ||
302 | tuple.Attributes = TUPLE_RETURN_COMMON; | ||
303 | tuple.TupleData = buf; | ||
304 | tuple.TupleDataMax = sizeof(buf); | ||
305 | tuple.TupleOffset = 0; | ||
306 | if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || | ||
307 | pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || | ||
308 | pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || | ||
309 | parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) { | ||
310 | /* No SanDisk manfid found */ | ||
311 | ret = -ENODEV; | ||
312 | goto done; | ||
313 | } | ||
314 | |||
315 | tuple.DesiredTuple = CISTPL_LONGLINK_MFC; | ||
316 | if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || | ||
317 | pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || | ||
318 | pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || | ||
319 | parse->longlink_mfc.nfn < 2) { | ||
320 | /* No multi-function links found */ | ||
321 | ret = -ENODEV; | ||
322 | goto done; | ||
323 | } | ||
324 | |||
325 | printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" | ||
326 | " - using vendor-specific initialization\n", dev->name); | ||
327 | hw_priv->sandisk_connectplus = 1; | ||
328 | |||
329 | reg.Function = 0; | ||
330 | reg.Action = CS_WRITE; | ||
331 | reg.Offset = CISREG_COR; | ||
332 | reg.Value = COR_SOFT_RESET; | ||
333 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
334 | ®); | ||
335 | if (res != CS_SUCCESS) { | ||
336 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
337 | dev->name, res); | ||
338 | goto done; | ||
339 | } | ||
340 | mdelay(5); | ||
341 | |||
342 | reg.Function = 0; | ||
343 | reg.Action = CS_WRITE; | ||
344 | reg.Offset = CISREG_COR; | ||
345 | /* | ||
346 | * Do not enable interrupts here to avoid some bogus events. Interrupts | ||
347 | * will be enabled during the first cor_sreset call. | ||
348 | */ | ||
349 | reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; | ||
350 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
351 | ®); | ||
352 | if (res != CS_SUCCESS) { | ||
353 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
354 | dev->name, res); | ||
355 | goto done; | ||
356 | } | ||
357 | mdelay(5); | ||
358 | |||
359 | sandisk_set_iobase(local); | ||
360 | |||
361 | HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); | ||
362 | udelay(10); | ||
363 | HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); | ||
364 | udelay(10); | ||
365 | |||
366 | done: | ||
367 | kfree(parse); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | |||
372 | static void prism2_pccard_cor_sreset(local_info_t *local) | ||
373 | { | ||
374 | int res; | ||
375 | conf_reg_t reg; | ||
376 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
377 | |||
378 | if (!prism2_pccard_card_present(local)) | ||
379 | return; | ||
380 | |||
381 | reg.Function = 0; | ||
382 | reg.Action = CS_READ; | ||
383 | reg.Offset = CISREG_COR; | ||
384 | reg.Value = 0; | ||
385 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
386 | ®); | ||
387 | if (res != CS_SUCCESS) { | ||
388 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", | ||
389 | res); | ||
390 | return; | ||
391 | } | ||
392 | printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", | ||
393 | reg.Value); | ||
394 | |||
395 | reg.Action = CS_WRITE; | ||
396 | reg.Value |= COR_SOFT_RESET; | ||
397 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
398 | ®); | ||
399 | if (res != CS_SUCCESS) { | ||
400 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", | ||
401 | res); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | ||
406 | |||
407 | reg.Value &= ~COR_SOFT_RESET; | ||
408 | if (hw_priv->sandisk_connectplus) | ||
409 | reg.Value |= COR_IREQ_ENA; | ||
410 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
411 | ®); | ||
412 | if (res != CS_SUCCESS) { | ||
413 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", | ||
414 | res); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | ||
419 | |||
420 | if (hw_priv->sandisk_connectplus) | ||
421 | sandisk_set_iobase(local); | ||
422 | } | ||
423 | |||
424 | |||
425 | static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) | ||
426 | { | ||
427 | int res; | ||
428 | conf_reg_t reg; | ||
429 | int old_cor; | ||
430 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
431 | |||
432 | if (!prism2_pccard_card_present(local)) | ||
433 | return; | ||
434 | |||
435 | if (hw_priv->sandisk_connectplus) { | ||
436 | sandisk_write_hcr(local, hcr); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | reg.Function = 0; | ||
441 | reg.Action = CS_READ; | ||
442 | reg.Offset = CISREG_COR; | ||
443 | reg.Value = 0; | ||
444 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
445 | ®); | ||
446 | if (res != CS_SUCCESS) { | ||
447 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " | ||
448 | "(%d)\n", res); | ||
449 | return; | ||
450 | } | ||
451 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n", | ||
452 | reg.Value); | ||
453 | old_cor = reg.Value; | ||
454 | |||
455 | reg.Action = CS_WRITE; | ||
456 | reg.Value |= COR_SOFT_RESET; | ||
457 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
458 | ®); | ||
459 | if (res != CS_SUCCESS) { | ||
460 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " | ||
461 | "(%d)\n", res); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | mdelay(10); | ||
466 | |||
467 | /* Setup Genesis mode */ | ||
468 | reg.Action = CS_WRITE; | ||
469 | reg.Value = hcr; | ||
470 | reg.Offset = CISREG_CCSR; | ||
471 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
472 | ®); | ||
473 | if (res != CS_SUCCESS) { | ||
474 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " | ||
475 | "(%d)\n", res); | ||
476 | return; | ||
477 | } | ||
478 | mdelay(10); | ||
479 | |||
480 | reg.Action = CS_WRITE; | ||
481 | reg.Offset = CISREG_COR; | ||
482 | reg.Value = old_cor & ~COR_SOFT_RESET; | ||
483 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
484 | ®); | ||
485 | if (res != CS_SUCCESS) { | ||
486 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " | ||
487 | "(%d)\n", res); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | mdelay(10); | ||
492 | } | ||
493 | |||
494 | |||
495 | static int prism2_pccard_dev_open(local_info_t *local) | ||
496 | { | ||
497 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
498 | hw_priv->link->open++; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | |||
503 | static int prism2_pccard_dev_close(local_info_t *local) | ||
504 | { | ||
505 | struct hostap_cs_priv *hw_priv; | ||
506 | |||
507 | if (local == NULL || local->hw_priv == NULL) | ||
508 | return 1; | ||
509 | hw_priv = local->hw_priv; | ||
510 | if (hw_priv->link == NULL) | ||
511 | return 1; | ||
512 | |||
513 | if (!hw_priv->link->open) { | ||
514 | printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " | ||
515 | "link not open?!\n", local->dev->name); | ||
516 | return 1; | ||
517 | } | ||
518 | |||
519 | hw_priv->link->open--; | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | |||
525 | static struct prism2_helper_functions prism2_pccard_funcs = | ||
526 | { | ||
527 | .card_present = prism2_pccard_card_present, | ||
528 | .cor_sreset = prism2_pccard_cor_sreset, | ||
529 | .dev_open = prism2_pccard_dev_open, | ||
530 | .dev_close = prism2_pccard_dev_close, | ||
531 | .genesis_reset = prism2_pccard_genesis_reset, | ||
532 | .hw_type = HOSTAP_HW_PCCARD, | ||
533 | }; | ||
534 | |||
535 | |||
536 | /* allocate local data and register with CardServices | ||
537 | * initialize dev_link structure, but do not configure the card yet */ | ||
538 | static dev_link_t *prism2_attach(void) | ||
539 | { | ||
540 | dev_link_t *link; | ||
541 | client_reg_t client_reg; | ||
542 | int ret; | ||
543 | |||
544 | link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); | ||
545 | if (link == NULL) | ||
546 | return NULL; | ||
547 | |||
548 | memset(link, 0, sizeof(dev_link_t)); | ||
549 | |||
550 | PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); | ||
551 | link->conf.Vcc = 33; | ||
552 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
553 | |||
554 | /* register with CardServices */ | ||
555 | link->next = dev_list; | ||
556 | dev_list = link; | ||
557 | client_reg.dev_info = &dev_info; | ||
558 | client_reg.Version = 0x0210; | ||
559 | client_reg.event_callback_args.client_data = link; | ||
560 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
561 | if (ret != CS_SUCCESS) { | ||
562 | cs_error(link->handle, RegisterClient, ret); | ||
563 | prism2_detach(link); | ||
564 | return NULL; | ||
565 | } | ||
566 | return link; | ||
567 | } | ||
568 | |||
569 | |||
570 | static void prism2_detach(dev_link_t *link) | ||
571 | { | ||
572 | dev_link_t **linkp; | ||
573 | |||
574 | PDEBUG(DEBUG_FLOW, "prism2_detach\n"); | ||
575 | |||
576 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
577 | if (*linkp == link) | ||
578 | break; | ||
579 | if (*linkp == NULL) { | ||
580 | printk(KERN_WARNING "%s: Attempt to detach non-existing " | ||
581 | "PCMCIA client\n", dev_info); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | if (link->state & DEV_CONFIG) { | ||
586 | prism2_release((u_long)link); | ||
587 | } | ||
588 | |||
589 | if (link->handle) { | ||
590 | int res = pcmcia_deregister_client(link->handle); | ||
591 | if (res) { | ||
592 | printk("CardService(DeregisterClient) => %d\n", res); | ||
593 | cs_error(link->handle, DeregisterClient, res); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | *linkp = link->next; | ||
598 | /* release net devices */ | ||
599 | if (link->priv) { | ||
600 | struct net_device *dev; | ||
601 | struct hostap_interface *iface; | ||
602 | dev = link->priv; | ||
603 | iface = netdev_priv(dev); | ||
604 | kfree(iface->local->hw_priv); | ||
605 | iface->local->hw_priv = NULL; | ||
606 | prism2_free_local_data(dev); | ||
607 | } | ||
608 | kfree(link); | ||
609 | } | ||
610 | |||
611 | |||
612 | #define CS_CHECK(fn, ret) \ | ||
613 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
614 | |||
615 | #define CFG_CHECK2(fn, retf) \ | ||
616 | do { int ret = (retf); \ | ||
617 | if (ret != 0) { \ | ||
618 | PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ | ||
619 | cs_error(link->handle, fn, ret); \ | ||
620 | goto next_entry; \ | ||
621 | } \ | ||
622 | } while (0) | ||
623 | |||
624 | |||
625 | /* run after a CARD_INSERTION event is received to configure the PCMCIA | ||
626 | * socket and make the device available to the system */ | ||
627 | static int prism2_config(dev_link_t *link) | ||
628 | { | ||
629 | struct net_device *dev; | ||
630 | struct hostap_interface *iface; | ||
631 | local_info_t *local; | ||
632 | int ret = 1; | ||
633 | tuple_t tuple; | ||
634 | cisparse_t *parse; | ||
635 | int last_fn, last_ret; | ||
636 | u_char buf[64]; | ||
637 | config_info_t conf; | ||
638 | cistpl_cftable_entry_t dflt = { 0 }; | ||
639 | struct hostap_cs_priv *hw_priv; | ||
640 | |||
641 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | ||
642 | |||
643 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
644 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
645 | if (parse == NULL || hw_priv == NULL) { | ||
646 | kfree(parse); | ||
647 | kfree(hw_priv); | ||
648 | ret = -ENOMEM; | ||
649 | goto failed; | ||
650 | } | ||
651 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
652 | |||
653 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
654 | tuple.Attributes = 0; | ||
655 | tuple.TupleData = buf; | ||
656 | tuple.TupleDataMax = sizeof(buf); | ||
657 | tuple.TupleOffset = 0; | ||
658 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
659 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple)); | ||
660 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
661 | link->conf.ConfigBase = parse->config.base; | ||
662 | link->conf.Present = parse->config.rmask[0]; | ||
663 | |||
664 | CS_CHECK(GetConfigurationInfo, | ||
665 | pcmcia_get_configuration_info(link->handle, &conf)); | ||
666 | PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info, | ||
667 | ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc); | ||
668 | link->conf.Vcc = conf.Vcc; | ||
669 | |||
670 | /* Look for an appropriate configuration table entry in the CIS */ | ||
671 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
672 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
673 | for (;;) { | ||
674 | cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); | ||
675 | CFG_CHECK2(GetTupleData, | ||
676 | pcmcia_get_tuple_data(link->handle, &tuple)); | ||
677 | CFG_CHECK2(ParseTuple, | ||
678 | pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
679 | |||
680 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
681 | dflt = *cfg; | ||
682 | if (cfg->index == 0) | ||
683 | goto next_entry; | ||
684 | link->conf.ConfigIndex = cfg->index; | ||
685 | PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " | ||
686 | "(default 0x%02X)\n", cfg->index, dflt.index); | ||
687 | |||
688 | /* Does this card need audio output? */ | ||
689 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
690 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
691 | link->conf.Status = CCSR_AUDIO_ENA; | ||
692 | } | ||
693 | |||
694 | /* Use power settings for Vcc and Vpp if present */ | ||
695 | /* Note that the CIS values need to be rescaled */ | ||
696 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
697 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / | ||
698 | 10000 && !ignore_cis_vcc) { | ||
699 | PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" | ||
700 | " this entry\n"); | ||
701 | goto next_entry; | ||
702 | } | ||
703 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
704 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / | ||
705 | 10000 && !ignore_cis_vcc) { | ||
706 | PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " | ||
707 | "- skipping this entry\n"); | ||
708 | goto next_entry; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
713 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
714 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
715 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
716 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
717 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
718 | |||
719 | /* Do we need to allocate an interrupt? */ | ||
720 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
721 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
722 | else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { | ||
723 | /* At least Compaq WL200 does not have IRQInfo1 set, | ||
724 | * but it does not work without interrupts.. */ | ||
725 | printk("Config has no IRQ info, but trying to enable " | ||
726 | "IRQ anyway..\n"); | ||
727 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
728 | } | ||
729 | |||
730 | /* IO window settings */ | ||
731 | PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " | ||
732 | "dflt.io.nwin=%d\n", | ||
733 | cfg->io.nwin, dflt.io.nwin); | ||
734 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
735 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
736 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
737 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
738 | PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " | ||
739 | "io.base=0x%04x, len=%d\n", io->flags, | ||
740 | io->win[0].base, io->win[0].len); | ||
741 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
742 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
743 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
744 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
745 | link->io.IOAddrLines = io->flags & | ||
746 | CISTPL_IO_LINES_MASK; | ||
747 | link->io.BasePort1 = io->win[0].base; | ||
748 | link->io.NumPorts1 = io->win[0].len; | ||
749 | if (io->nwin > 1) { | ||
750 | link->io.Attributes2 = link->io.Attributes1; | ||
751 | link->io.BasePort2 = io->win[1].base; | ||
752 | link->io.NumPorts2 = io->win[1].len; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | /* This reserves IO space but doesn't actually enable it */ | ||
757 | CFG_CHECK2(RequestIO, | ||
758 | pcmcia_request_io(link->handle, &link->io)); | ||
759 | |||
760 | /* This configuration table entry is OK */ | ||
761 | break; | ||
762 | |||
763 | next_entry: | ||
764 | CS_CHECK(GetNextTuple, | ||
765 | pcmcia_get_next_tuple(link->handle, &tuple)); | ||
766 | } | ||
767 | |||
768 | /* Need to allocate net_device before requesting IRQ handler */ | ||
769 | dev = prism2_init_local_data(&prism2_pccard_funcs, 0, | ||
770 | &handle_to_dev(link->handle)); | ||
771 | if (dev == NULL) | ||
772 | goto failed; | ||
773 | link->priv = dev; | ||
774 | |||
775 | iface = netdev_priv(dev); | ||
776 | local = iface->local; | ||
777 | local->hw_priv = hw_priv; | ||
778 | hw_priv->link = link; | ||
779 | strcpy(hw_priv->node.dev_name, dev->name); | ||
780 | link->dev = &hw_priv->node; | ||
781 | |||
782 | /* | ||
783 | * Allocate an interrupt line. Note that this does not assign a | ||
784 | * handler to the interrupt, unless the 'Handler' member of the | ||
785 | * irq structure is initialized. | ||
786 | */ | ||
787 | if (link->conf.Attributes & CONF_ENABLE_IRQ) { | ||
788 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
789 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
790 | link->irq.Handler = prism2_interrupt; | ||
791 | link->irq.Instance = dev; | ||
792 | CS_CHECK(RequestIRQ, | ||
793 | pcmcia_request_irq(link->handle, &link->irq)); | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * This actually configures the PCMCIA socket -- setting up | ||
798 | * the I/O windows and the interrupt mapping, and putting the | ||
799 | * card and host interface into "Memory and IO" mode. | ||
800 | */ | ||
801 | CS_CHECK(RequestConfiguration, | ||
802 | pcmcia_request_configuration(link->handle, &link->conf)); | ||
803 | |||
804 | dev->irq = link->irq.AssignedIRQ; | ||
805 | dev->base_addr = link->io.BasePort1; | ||
806 | |||
807 | /* Finally, report what we've done */ | ||
808 | printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", | ||
809 | dev_info, link->conf.ConfigIndex, | ||
810 | link->conf.Vcc / 10, link->conf.Vcc % 10); | ||
811 | if (link->conf.Vpp1) | ||
812 | printk(", Vpp %d.%d", link->conf.Vpp1 / 10, | ||
813 | link->conf.Vpp1 % 10); | ||
814 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
815 | printk(", irq %d", link->irq.AssignedIRQ); | ||
816 | if (link->io.NumPorts1) | ||
817 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
818 | link->io.BasePort1+link->io.NumPorts1-1); | ||
819 | if (link->io.NumPorts2) | ||
820 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
821 | link->io.BasePort2+link->io.NumPorts2-1); | ||
822 | printk("\n"); | ||
823 | |||
824 | link->state |= DEV_CONFIG; | ||
825 | link->state &= ~DEV_CONFIG_PENDING; | ||
826 | |||
827 | local->shutdown = 0; | ||
828 | |||
829 | sandisk_enable_wireless(dev); | ||
830 | |||
831 | ret = prism2_hw_config(dev, 1); | ||
832 | if (!ret) { | ||
833 | ret = hostap_hw_ready(dev); | ||
834 | if (ret == 0 && local->ddev) | ||
835 | strcpy(hw_priv->node.dev_name, local->ddev->name); | ||
836 | } | ||
837 | kfree(parse); | ||
838 | return ret; | ||
839 | |||
840 | cs_failed: | ||
841 | cs_error(link->handle, last_fn, last_ret); | ||
842 | |||
843 | failed: | ||
844 | kfree(parse); | ||
845 | kfree(hw_priv); | ||
846 | prism2_release((u_long)link); | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | |||
851 | static void prism2_release(u_long arg) | ||
852 | { | ||
853 | dev_link_t *link = (dev_link_t *)arg; | ||
854 | |||
855 | PDEBUG(DEBUG_FLOW, "prism2_release\n"); | ||
856 | |||
857 | if (link->priv) { | ||
858 | struct net_device *dev = link->priv; | ||
859 | struct hostap_interface *iface; | ||
860 | |||
861 | iface = netdev_priv(dev); | ||
862 | if (link->state & DEV_CONFIG) | ||
863 | prism2_hw_shutdown(dev, 0); | ||
864 | iface->local->shutdown = 1; | ||
865 | } | ||
866 | |||
867 | if (link->win) | ||
868 | pcmcia_release_window(link->win); | ||
869 | pcmcia_release_configuration(link->handle); | ||
870 | if (link->io.NumPorts1) | ||
871 | pcmcia_release_io(link->handle, &link->io); | ||
872 | if (link->irq.AssignedIRQ) | ||
873 | pcmcia_release_irq(link->handle, &link->irq); | ||
874 | |||
875 | link->state &= ~DEV_CONFIG; | ||
876 | |||
877 | PDEBUG(DEBUG_FLOW, "release - done\n"); | ||
878 | } | ||
879 | |||
880 | |||
881 | static int prism2_event(event_t event, int priority, | ||
882 | event_callback_args_t *args) | ||
883 | { | ||
884 | dev_link_t *link = args->client_data; | ||
885 | struct net_device *dev = (struct net_device *) link->priv; | ||
886 | |||
887 | switch (event) { | ||
888 | case CS_EVENT_CARD_INSERTION: | ||
889 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info); | ||
890 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
891 | if (prism2_config(link)) { | ||
892 | PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); | ||
893 | } | ||
894 | break; | ||
895 | |||
896 | case CS_EVENT_CARD_REMOVAL: | ||
897 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info); | ||
898 | link->state &= ~DEV_PRESENT; | ||
899 | if (link->state & DEV_CONFIG) { | ||
900 | netif_stop_queue(dev); | ||
901 | netif_device_detach(dev); | ||
902 | prism2_release((u_long) link); | ||
903 | } | ||
904 | break; | ||
905 | |||
906 | case CS_EVENT_PM_SUSPEND: | ||
907 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | ||
908 | link->state |= DEV_SUSPEND; | ||
909 | /* fall through */ | ||
910 | |||
911 | case CS_EVENT_RESET_PHYSICAL: | ||
912 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); | ||
913 | if (link->state & DEV_CONFIG) { | ||
914 | if (link->open) { | ||
915 | netif_stop_queue(dev); | ||
916 | netif_device_detach(dev); | ||
917 | } | ||
918 | prism2_suspend(dev); | ||
919 | pcmcia_release_configuration(link->handle); | ||
920 | } | ||
921 | break; | ||
922 | |||
923 | case CS_EVENT_PM_RESUME: | ||
924 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); | ||
925 | link->state &= ~DEV_SUSPEND; | ||
926 | /* fall through */ | ||
927 | |||
928 | case CS_EVENT_CARD_RESET: | ||
929 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info); | ||
930 | if (link->state & DEV_CONFIG) { | ||
931 | pcmcia_request_configuration(link->handle, | ||
932 | &link->conf); | ||
933 | prism2_hw_shutdown(dev, 1); | ||
934 | prism2_hw_config(dev, link->open ? 0 : 1); | ||
935 | if (link->open) { | ||
936 | netif_device_attach(dev); | ||
937 | netif_start_queue(dev); | ||
938 | } | ||
939 | } | ||
940 | break; | ||
941 | |||
942 | default: | ||
943 | PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n", | ||
944 | dev_info, event); | ||
945 | break; | ||
946 | } | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | |||
951 | static struct pcmcia_device_id hostap_cs_ids[] = { | ||
952 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), | ||
953 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), | ||
954 | PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), | ||
955 | PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), | ||
956 | PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), | ||
957 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), | ||
958 | PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), | ||
959 | PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), | ||
960 | PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), | ||
961 | PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), | ||
962 | PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), | ||
963 | PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), | ||
964 | PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), | ||
965 | PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), | ||
966 | PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), | ||
967 | PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), | ||
968 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), | ||
969 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), | ||
970 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), | ||
971 | PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", | ||
972 | 0x7a954bd9, 0x74be00c6), | ||
973 | PCMCIA_DEVICE_PROD_ID1234( | ||
974 | "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", | ||
975 | "Eval-RevA", | ||
976 | 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), | ||
977 | PCMCIA_DEVICE_PROD_ID123( | ||
978 | "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", | ||
979 | 0xe6ec52ce, 0x08649af2, 0x4b74baa0), | ||
980 | PCMCIA_DEVICE_PROD_ID123( | ||
981 | "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", | ||
982 | 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), | ||
983 | PCMCIA_DEVICE_PROD_ID123( | ||
984 | "Instant Wireless ", " Network PC CARD", "Version 01.02", | ||
985 | 0x11d901af, 0x6e9bd926, 0x4b74baa0), | ||
986 | PCMCIA_DEVICE_PROD_ID123( | ||
987 | "SMC", "SMC2632W", "Version 01.02", | ||
988 | 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), | ||
989 | PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", | ||
990 | 0x2decece3, 0x82067c18), | ||
991 | PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", | ||
992 | 0x54f7c49c, 0x15a75e5b), | ||
993 | PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", | ||
994 | 0x74c5e40d, 0xdb472a18), | ||
995 | PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", | ||
996 | 0x0733cc81, 0x0c52f395), | ||
997 | PCMCIA_DEVICE_PROD_ID12( | ||
998 | "ZoomAir 11Mbps High", "Rate wireless Networking", | ||
999 | 0x273fe3db, 0x32a1eaee), | ||
1000 | PCMCIA_DEVICE_NULL | ||
1001 | }; | ||
1002 | MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); | ||
1003 | |||
1004 | |||
1005 | static struct pcmcia_driver hostap_driver = { | ||
1006 | .drv = { | ||
1007 | .name = "hostap_cs", | ||
1008 | }, | ||
1009 | .attach = prism2_attach, | ||
1010 | .detach = prism2_detach, | ||
1011 | .owner = THIS_MODULE, | ||
1012 | .event = prism2_event, | ||
1013 | .id_table = hostap_cs_ids, | ||
1014 | }; | ||
1015 | |||
1016 | static int __init init_prism2_pccard(void) | ||
1017 | { | ||
1018 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
1019 | return pcmcia_register_driver(&hostap_driver); | ||
1020 | } | ||
1021 | |||
1022 | static void __exit exit_prism2_pccard(void) | ||
1023 | { | ||
1024 | pcmcia_unregister_driver(&hostap_driver); | ||
1025 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | module_init(init_prism2_pccard); | ||
1030 | module_exit(exit_prism2_pccard); | ||
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c new file mode 100644 index 000000000000..ab26b52b3e76 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_download.c | |||
@@ -0,0 +1,766 @@ | |||
1 | static int prism2_enable_aux_port(struct net_device *dev, int enable) | ||
2 | { | ||
3 | u16 val, reg; | ||
4 | int i, tries; | ||
5 | unsigned long flags; | ||
6 | struct hostap_interface *iface; | ||
7 | local_info_t *local; | ||
8 | |||
9 | iface = netdev_priv(dev); | ||
10 | local = iface->local; | ||
11 | |||
12 | if (local->no_pri) { | ||
13 | if (enable) { | ||
14 | PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " | ||
15 | "port is already enabled\n", dev->name); | ||
16 | } | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | spin_lock_irqsave(&local->cmdlock, flags); | ||
21 | |||
22 | /* wait until busy bit is clear */ | ||
23 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
24 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
25 | tries--; | ||
26 | udelay(1); | ||
27 | } | ||
28 | if (tries == 0) { | ||
29 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
30 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
31 | printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", | ||
32 | dev->name, reg); | ||
33 | return -ETIMEDOUT; | ||
34 | } | ||
35 | |||
36 | val = HFA384X_INW(HFA384X_CONTROL_OFF); | ||
37 | |||
38 | if (enable) { | ||
39 | HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); | ||
40 | HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); | ||
41 | HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); | ||
42 | |||
43 | if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) | ||
44 | printk("prism2_enable_aux_port: was not disabled!?\n"); | ||
45 | val &= ~HFA384X_AUX_PORT_MASK; | ||
46 | val |= HFA384X_AUX_PORT_ENABLE; | ||
47 | } else { | ||
48 | HFA384X_OUTW(0, HFA384X_PARAM0_OFF); | ||
49 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
50 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
51 | |||
52 | if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) | ||
53 | printk("prism2_enable_aux_port: was not enabled!?\n"); | ||
54 | val &= ~HFA384X_AUX_PORT_MASK; | ||
55 | val |= HFA384X_AUX_PORT_DISABLE; | ||
56 | } | ||
57 | HFA384X_OUTW(val, HFA384X_CONTROL_OFF); | ||
58 | |||
59 | udelay(5); | ||
60 | |||
61 | i = 10000; | ||
62 | while (i > 0) { | ||
63 | val = HFA384X_INW(HFA384X_CONTROL_OFF); | ||
64 | val &= HFA384X_AUX_PORT_MASK; | ||
65 | |||
66 | if ((enable && val == HFA384X_AUX_PORT_ENABLED) || | ||
67 | (!enable && val == HFA384X_AUX_PORT_DISABLED)) | ||
68 | break; | ||
69 | |||
70 | udelay(10); | ||
71 | i--; | ||
72 | } | ||
73 | |||
74 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
75 | |||
76 | if (i == 0) { | ||
77 | printk("prism2_enable_aux_port(%d) timed out\n", | ||
78 | enable); | ||
79 | return -ETIMEDOUT; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | |||
86 | static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, | ||
87 | void *buf) | ||
88 | { | ||
89 | u16 page, offset; | ||
90 | if (addr & 1 || len & 1) | ||
91 | return -1; | ||
92 | |||
93 | page = addr >> 7; | ||
94 | offset = addr & 0x7f; | ||
95 | |||
96 | HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | ||
97 | HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | ||
98 | |||
99 | udelay(5); | ||
100 | |||
101 | #ifdef PRISM2_PCI | ||
102 | { | ||
103 | u16 *pos = (u16 *) buf; | ||
104 | while (len > 0) { | ||
105 | *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); | ||
106 | len -= 2; | ||
107 | } | ||
108 | } | ||
109 | #else /* PRISM2_PCI */ | ||
110 | HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); | ||
111 | #endif /* PRISM2_PCI */ | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, | ||
118 | void *buf) | ||
119 | { | ||
120 | u16 page, offset; | ||
121 | if (addr & 1 || len & 1) | ||
122 | return -1; | ||
123 | |||
124 | page = addr >> 7; | ||
125 | offset = addr & 0x7f; | ||
126 | |||
127 | HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | ||
128 | HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | ||
129 | |||
130 | udelay(5); | ||
131 | |||
132 | #ifdef PRISM2_PCI | ||
133 | { | ||
134 | u16 *pos = (u16 *) buf; | ||
135 | while (len > 0) { | ||
136 | HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); | ||
137 | len -= 2; | ||
138 | } | ||
139 | } | ||
140 | #else /* PRISM2_PCI */ | ||
141 | HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); | ||
142 | #endif /* PRISM2_PCI */ | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
148 | static int prism2_pda_ok(u8 *buf) | ||
149 | { | ||
150 | u16 *pda = (u16 *) buf; | ||
151 | int pos; | ||
152 | u16 len, pdr; | ||
153 | |||
154 | if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && | ||
155 | buf[3] == 0x00) | ||
156 | return 0; | ||
157 | |||
158 | pos = 0; | ||
159 | while (pos + 1 < PRISM2_PDA_SIZE / 2) { | ||
160 | len = le16_to_cpu(pda[pos]); | ||
161 | pdr = le16_to_cpu(pda[pos + 1]); | ||
162 | if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) | ||
163 | return 0; | ||
164 | |||
165 | if (pdr == 0x0000 && len == 2) { | ||
166 | /* PDA end found */ | ||
167 | return 1; | ||
168 | } | ||
169 | |||
170 | pos += len + 1; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | static int prism2_download_aux_dump(struct net_device *dev, | ||
178 | unsigned int addr, int len, u8 *buf) | ||
179 | { | ||
180 | int res; | ||
181 | |||
182 | prism2_enable_aux_port(dev, 1); | ||
183 | res = hfa384x_from_aux(dev, addr, len, buf); | ||
184 | prism2_enable_aux_port(dev, 0); | ||
185 | if (res) | ||
186 | return -1; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | static u8 * prism2_read_pda(struct net_device *dev) | ||
193 | { | ||
194 | u8 *buf; | ||
195 | int res, i, found = 0; | ||
196 | #define NUM_PDA_ADDRS 4 | ||
197 | unsigned int pda_addr[NUM_PDA_ADDRS] = { | ||
198 | 0x7f0000 /* others than HFA3841 */, | ||
199 | 0x3f0000 /* HFA3841 */, | ||
200 | 0x390000 /* apparently used in older cards */, | ||
201 | 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, | ||
202 | }; | ||
203 | |||
204 | buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); | ||
205 | if (buf == NULL) | ||
206 | return NULL; | ||
207 | |||
208 | /* Note: wlan card should be in initial state (just after init cmd) | ||
209 | * and no other operations should be performed concurrently. */ | ||
210 | |||
211 | prism2_enable_aux_port(dev, 1); | ||
212 | |||
213 | for (i = 0; i < NUM_PDA_ADDRS; i++) { | ||
214 | PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", | ||
215 | dev->name, pda_addr[i]); | ||
216 | res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); | ||
217 | if (res) | ||
218 | continue; | ||
219 | if (res == 0 && prism2_pda_ok(buf)) { | ||
220 | PDEBUG2(DEBUG_EXTRA2, ": OK\n"); | ||
221 | found = 1; | ||
222 | break; | ||
223 | } else { | ||
224 | PDEBUG2(DEBUG_EXTRA2, ": failed\n"); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | prism2_enable_aux_port(dev, 0); | ||
229 | |||
230 | if (!found) { | ||
231 | printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); | ||
232 | kfree(buf); | ||
233 | buf = NULL; | ||
234 | } | ||
235 | |||
236 | return buf; | ||
237 | } | ||
238 | |||
239 | |||
240 | static int prism2_download_volatile(local_info_t *local, | ||
241 | struct prism2_download_data *param) | ||
242 | { | ||
243 | struct net_device *dev = local->dev; | ||
244 | int ret = 0, i; | ||
245 | u16 param0, param1; | ||
246 | |||
247 | if (local->hw_downloading) { | ||
248 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
249 | "request\n", dev->name); | ||
250 | return -1; | ||
251 | } | ||
252 | |||
253 | local->hw_downloading = 1; | ||
254 | if (local->pri_only) { | ||
255 | hfa384x_disable_interrupts(dev); | ||
256 | } else { | ||
257 | prism2_hw_shutdown(dev, 0); | ||
258 | |||
259 | if (prism2_hw_init(dev, 0)) { | ||
260 | printk(KERN_WARNING "%s: Could not initialize card for" | ||
261 | " download\n", dev->name); | ||
262 | ret = -1; | ||
263 | goto out; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if (prism2_enable_aux_port(dev, 1)) { | ||
268 | printk(KERN_WARNING "%s: Could not enable AUX port\n", | ||
269 | dev->name); | ||
270 | ret = -1; | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | param0 = param->start_addr & 0xffff; | ||
275 | param1 = param->start_addr >> 16; | ||
276 | |||
277 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
278 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
279 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
280 | (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), | ||
281 | param0)) { | ||
282 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
283 | dev->name); | ||
284 | ret = -1; | ||
285 | goto out; | ||
286 | } | ||
287 | |||
288 | for (i = 0; i < param->num_areas; i++) { | ||
289 | PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | ||
290 | dev->name, param->data[i].len, param->data[i].addr); | ||
291 | if (hfa384x_to_aux(dev, param->data[i].addr, | ||
292 | param->data[i].len, param->data[i].data)) { | ||
293 | printk(KERN_WARNING "%s: RAM download at 0x%08x " | ||
294 | "(len=%d) failed\n", dev->name, | ||
295 | param->data[i].addr, param->data[i].len); | ||
296 | ret = -1; | ||
297 | goto out; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
302 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
303 | if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
304 | (HFA384X_PROGMODE_DISABLE << 8), param0)) { | ||
305 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
306 | dev->name); | ||
307 | ret = -1; | ||
308 | goto out; | ||
309 | } | ||
310 | /* ProgMode disable causes the hardware to restart itself from the | ||
311 | * given starting address. Give hw some time and ACK command just in | ||
312 | * case restart did not happen. */ | ||
313 | mdelay(5); | ||
314 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
315 | |||
316 | if (prism2_enable_aux_port(dev, 0)) { | ||
317 | printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | ||
318 | dev->name); | ||
319 | /* continue anyway.. restart should have taken care of this */ | ||
320 | } | ||
321 | |||
322 | mdelay(5); | ||
323 | local->hw_downloading = 0; | ||
324 | if (prism2_hw_config(dev, 2)) { | ||
325 | printk(KERN_WARNING "%s: Card configuration after RAM " | ||
326 | "download failed\n", dev->name); | ||
327 | ret = -1; | ||
328 | goto out; | ||
329 | } | ||
330 | |||
331 | out: | ||
332 | local->hw_downloading = 0; | ||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | |||
337 | static int prism2_enable_genesis(local_info_t *local, int hcr) | ||
338 | { | ||
339 | struct net_device *dev = local->dev; | ||
340 | u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; | ||
341 | u8 readbuf[4]; | ||
342 | |||
343 | printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", | ||
344 | dev->name, hcr); | ||
345 | local->func->cor_sreset(local); | ||
346 | hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | ||
347 | local->func->genesis_reset(local, hcr); | ||
348 | |||
349 | /* Readback test */ | ||
350 | hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | ||
351 | hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | ||
352 | hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | ||
353 | |||
354 | if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { | ||
355 | printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", | ||
356 | hcr); | ||
357 | return 0; | ||
358 | } else { | ||
359 | printk(KERN_DEBUG "Readback test failed, HCR 0x%02x " | ||
360 | "write %02x %02x %02x %02x read %02x %02x %02x %02x\n", | ||
361 | hcr, initseq[0], initseq[1], initseq[2], initseq[3], | ||
362 | readbuf[0], readbuf[1], readbuf[2], readbuf[3]); | ||
363 | return 1; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | |||
368 | static int prism2_get_ram_size(local_info_t *local) | ||
369 | { | ||
370 | int ret; | ||
371 | |||
372 | /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | ||
373 | if (prism2_enable_genesis(local, 0x1f) == 0) | ||
374 | ret = 8; | ||
375 | else if (prism2_enable_genesis(local, 0x0f) == 0) | ||
376 | ret = 16; | ||
377 | else | ||
378 | ret = -1; | ||
379 | |||
380 | /* Disable genesis mode */ | ||
381 | local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | |||
387 | static int prism2_download_genesis(local_info_t *local, | ||
388 | struct prism2_download_data *param) | ||
389 | { | ||
390 | struct net_device *dev = local->dev; | ||
391 | int ram16 = 0, i; | ||
392 | int ret = 0; | ||
393 | |||
394 | if (local->hw_downloading) { | ||
395 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
396 | "request\n", dev->name); | ||
397 | return -EBUSY; | ||
398 | } | ||
399 | |||
400 | if (!local->func->genesis_reset || !local->func->cor_sreset) { | ||
401 | printk(KERN_INFO "%s: Genesis mode downloading not supported " | ||
402 | "with this hwmodel\n", dev->name); | ||
403 | return -EOPNOTSUPP; | ||
404 | } | ||
405 | |||
406 | local->hw_downloading = 1; | ||
407 | |||
408 | if (prism2_enable_aux_port(dev, 1)) { | ||
409 | printk(KERN_DEBUG "%s: failed to enable AUX port\n", | ||
410 | dev->name); | ||
411 | ret = -EIO; | ||
412 | goto out; | ||
413 | } | ||
414 | |||
415 | if (local->sram_type == -1) { | ||
416 | /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | ||
417 | if (prism2_enable_genesis(local, 0x1f) == 0) { | ||
418 | ram16 = 0; | ||
419 | PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " | ||
420 | "SRAM\n", dev->name); | ||
421 | } else if (prism2_enable_genesis(local, 0x0f) == 0) { | ||
422 | ram16 = 1; | ||
423 | PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " | ||
424 | "SRAM\n", dev->name); | ||
425 | } else { | ||
426 | printk(KERN_DEBUG "%s: Could not initiate genesis " | ||
427 | "mode\n", dev->name); | ||
428 | ret = -EIO; | ||
429 | goto out; | ||
430 | } | ||
431 | } else { | ||
432 | if (prism2_enable_genesis(local, local->sram_type == 8 ? | ||
433 | 0x1f : 0x0f)) { | ||
434 | printk(KERN_DEBUG "%s: Failed to set Genesis " | ||
435 | "mode (sram_type=%d)\n", dev->name, | ||
436 | local->sram_type); | ||
437 | ret = -EIO; | ||
438 | goto out; | ||
439 | } | ||
440 | ram16 = local->sram_type != 8; | ||
441 | } | ||
442 | |||
443 | for (i = 0; i < param->num_areas; i++) { | ||
444 | PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | ||
445 | dev->name, param->data[i].len, param->data[i].addr); | ||
446 | if (hfa384x_to_aux(dev, param->data[i].addr, | ||
447 | param->data[i].len, param->data[i].data)) { | ||
448 | printk(KERN_WARNING "%s: RAM download at 0x%08x " | ||
449 | "(len=%d) failed\n", dev->name, | ||
450 | param->data[i].addr, param->data[i].len); | ||
451 | ret = -EIO; | ||
452 | goto out; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); | ||
457 | local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); | ||
458 | if (prism2_enable_aux_port(dev, 0)) { | ||
459 | printk(KERN_DEBUG "%s: Failed to disable AUX port\n", | ||
460 | dev->name); | ||
461 | } | ||
462 | |||
463 | mdelay(5); | ||
464 | local->hw_downloading = 0; | ||
465 | |||
466 | PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); | ||
467 | /* | ||
468 | * Make sure the INIT command does not generate a command completion | ||
469 | * event by disabling interrupts. | ||
470 | */ | ||
471 | hfa384x_disable_interrupts(dev); | ||
472 | if (prism2_hw_init(dev, 1)) { | ||
473 | printk(KERN_DEBUG "%s: Initialization after genesis mode " | ||
474 | "download failed\n", dev->name); | ||
475 | ret = -EIO; | ||
476 | goto out; | ||
477 | } | ||
478 | |||
479 | PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); | ||
480 | if (prism2_hw_init2(dev, 1)) { | ||
481 | printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " | ||
482 | "download failed\n", dev->name); | ||
483 | ret = -EIO; | ||
484 | goto out; | ||
485 | } | ||
486 | |||
487 | out: | ||
488 | local->hw_downloading = 0; | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | |||
493 | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD | ||
494 | /* Note! Non-volatile downloading functionality has not yet been tested | ||
495 | * thoroughly and it may corrupt flash image and effectively kill the card that | ||
496 | * is being updated. You have been warned. */ | ||
497 | |||
498 | static inline int prism2_download_block(struct net_device *dev, | ||
499 | u32 addr, u8 *data, | ||
500 | u32 bufaddr, int rest_len) | ||
501 | { | ||
502 | u16 param0, param1; | ||
503 | int block_len; | ||
504 | |||
505 | block_len = rest_len < 4096 ? rest_len : 4096; | ||
506 | |||
507 | param0 = addr & 0xffff; | ||
508 | param1 = addr >> 16; | ||
509 | |||
510 | HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); | ||
511 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
512 | |||
513 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
514 | (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), | ||
515 | param0)) { | ||
516 | printk(KERN_WARNING "%s: Flash download command execution " | ||
517 | "failed\n", dev->name); | ||
518 | return -1; | ||
519 | } | ||
520 | |||
521 | if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { | ||
522 | printk(KERN_WARNING "%s: flash download at 0x%08x " | ||
523 | "(len=%d) failed\n", dev->name, addr, block_len); | ||
524 | return -1; | ||
525 | } | ||
526 | |||
527 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
528 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
529 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
530 | (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), | ||
531 | 0)) { | ||
532 | printk(KERN_WARNING "%s: Flash write command execution " | ||
533 | "failed\n", dev->name); | ||
534 | return -1; | ||
535 | } | ||
536 | |||
537 | return block_len; | ||
538 | } | ||
539 | |||
540 | |||
541 | static int prism2_download_nonvolatile(local_info_t *local, | ||
542 | struct prism2_download_data *dl) | ||
543 | { | ||
544 | struct net_device *dev = local->dev; | ||
545 | int ret = 0, i; | ||
546 | struct { | ||
547 | u16 page; | ||
548 | u16 offset; | ||
549 | u16 len; | ||
550 | } dlbuffer; | ||
551 | u32 bufaddr; | ||
552 | |||
553 | if (local->hw_downloading) { | ||
554 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
555 | "request\n", dev->name); | ||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, | ||
560 | &dlbuffer, 6, 0); | ||
561 | |||
562 | if (ret < 0) { | ||
563 | printk(KERN_WARNING "%s: Could not read download buffer " | ||
564 | "parameters\n", dev->name); | ||
565 | goto out; | ||
566 | } | ||
567 | |||
568 | dlbuffer.page = le16_to_cpu(dlbuffer.page); | ||
569 | dlbuffer.offset = le16_to_cpu(dlbuffer.offset); | ||
570 | dlbuffer.len = le16_to_cpu(dlbuffer.len); | ||
571 | |||
572 | printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", | ||
573 | dlbuffer.len, dlbuffer.page, dlbuffer.offset); | ||
574 | |||
575 | bufaddr = (dlbuffer.page << 7) + dlbuffer.offset; | ||
576 | |||
577 | local->hw_downloading = 1; | ||
578 | |||
579 | if (!local->pri_only) { | ||
580 | prism2_hw_shutdown(dev, 0); | ||
581 | |||
582 | if (prism2_hw_init(dev, 0)) { | ||
583 | printk(KERN_WARNING "%s: Could not initialize card for" | ||
584 | " download\n", dev->name); | ||
585 | ret = -1; | ||
586 | goto out; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | hfa384x_disable_interrupts(dev); | ||
591 | |||
592 | if (prism2_enable_aux_port(dev, 1)) { | ||
593 | printk(KERN_WARNING "%s: Could not enable AUX port\n", | ||
594 | dev->name); | ||
595 | ret = -1; | ||
596 | goto out; | ||
597 | } | ||
598 | |||
599 | printk(KERN_DEBUG "%s: starting flash download\n", dev->name); | ||
600 | for (i = 0; i < dl->num_areas; i++) { | ||
601 | int rest_len = dl->data[i].len; | ||
602 | int data_off = 0; | ||
603 | |||
604 | while (rest_len > 0) { | ||
605 | int block_len; | ||
606 | |||
607 | block_len = prism2_download_block( | ||
608 | dev, dl->data[i].addr + data_off, | ||
609 | dl->data[i].data + data_off, bufaddr, | ||
610 | rest_len); | ||
611 | |||
612 | if (block_len < 0) { | ||
613 | ret = -1; | ||
614 | goto out; | ||
615 | } | ||
616 | |||
617 | rest_len -= block_len; | ||
618 | data_off += block_len; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
623 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
624 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
625 | (HFA384X_PROGMODE_DISABLE << 8), 0)) { | ||
626 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
627 | dev->name); | ||
628 | ret = -1; | ||
629 | goto out; | ||
630 | } | ||
631 | |||
632 | if (prism2_enable_aux_port(dev, 0)) { | ||
633 | printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | ||
634 | dev->name); | ||
635 | /* continue anyway.. restart should have taken care of this */ | ||
636 | } | ||
637 | |||
638 | mdelay(5); | ||
639 | |||
640 | local->func->hw_reset(dev); | ||
641 | local->hw_downloading = 0; | ||
642 | if (prism2_hw_config(dev, 2)) { | ||
643 | printk(KERN_WARNING "%s: Card configuration after flash " | ||
644 | "download failed\n", dev->name); | ||
645 | ret = -1; | ||
646 | } else { | ||
647 | printk(KERN_INFO "%s: Card initialized successfully after " | ||
648 | "flash download\n", dev->name); | ||
649 | } | ||
650 | |||
651 | out: | ||
652 | local->hw_downloading = 0; | ||
653 | return ret; | ||
654 | } | ||
655 | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
656 | |||
657 | |||
658 | static void prism2_download_free_data(struct prism2_download_data *dl) | ||
659 | { | ||
660 | int i; | ||
661 | |||
662 | if (dl == NULL) | ||
663 | return; | ||
664 | |||
665 | for (i = 0; i < dl->num_areas; i++) | ||
666 | kfree(dl->data[i].data); | ||
667 | kfree(dl); | ||
668 | } | ||
669 | |||
670 | |||
671 | static int prism2_download(local_info_t *local, | ||
672 | struct prism2_download_param *param) | ||
673 | { | ||
674 | int ret = 0; | ||
675 | int i; | ||
676 | u32 total_len = 0; | ||
677 | struct prism2_download_data *dl = NULL; | ||
678 | |||
679 | printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " | ||
680 | "num_areas=%d\n", | ||
681 | param->dl_cmd, param->start_addr, param->num_areas); | ||
682 | |||
683 | if (param->num_areas > 100) { | ||
684 | ret = -EINVAL; | ||
685 | goto out; | ||
686 | } | ||
687 | |||
688 | dl = kmalloc(sizeof(*dl) + param->num_areas * | ||
689 | sizeof(struct prism2_download_data_area), GFP_KERNEL); | ||
690 | if (dl == NULL) { | ||
691 | ret = -ENOMEM; | ||
692 | goto out; | ||
693 | } | ||
694 | memset(dl, 0, sizeof(*dl) + param->num_areas * | ||
695 | sizeof(struct prism2_download_data_area)); | ||
696 | dl->dl_cmd = param->dl_cmd; | ||
697 | dl->start_addr = param->start_addr; | ||
698 | dl->num_areas = param->num_areas; | ||
699 | for (i = 0; i < param->num_areas; i++) { | ||
700 | PDEBUG(DEBUG_EXTRA2, | ||
701 | " area %d: addr=0x%08x len=%d ptr=0x%p\n", | ||
702 | i, param->data[i].addr, param->data[i].len, | ||
703 | param->data[i].ptr); | ||
704 | |||
705 | dl->data[i].addr = param->data[i].addr; | ||
706 | dl->data[i].len = param->data[i].len; | ||
707 | |||
708 | total_len += param->data[i].len; | ||
709 | if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || | ||
710 | total_len > PRISM2_MAX_DOWNLOAD_LEN) { | ||
711 | ret = -E2BIG; | ||
712 | goto out; | ||
713 | } | ||
714 | |||
715 | dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); | ||
716 | if (dl->data[i].data == NULL) { | ||
717 | ret = -ENOMEM; | ||
718 | goto out; | ||
719 | } | ||
720 | |||
721 | if (copy_from_user(dl->data[i].data, param->data[i].ptr, | ||
722 | param->data[i].len)) { | ||
723 | ret = -EFAULT; | ||
724 | goto out; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | switch (param->dl_cmd) { | ||
729 | case PRISM2_DOWNLOAD_VOLATILE: | ||
730 | case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: | ||
731 | ret = prism2_download_volatile(local, dl); | ||
732 | break; | ||
733 | case PRISM2_DOWNLOAD_VOLATILE_GENESIS: | ||
734 | case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: | ||
735 | ret = prism2_download_genesis(local, dl); | ||
736 | break; | ||
737 | case PRISM2_DOWNLOAD_NON_VOLATILE: | ||
738 | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD | ||
739 | ret = prism2_download_nonvolatile(local, dl); | ||
740 | #else /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
741 | printk(KERN_INFO "%s: non-volatile downloading not enabled\n", | ||
742 | local->dev->name); | ||
743 | ret = -EOPNOTSUPP; | ||
744 | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
745 | break; | ||
746 | default: | ||
747 | printk(KERN_DEBUG "%s: unsupported download command %d\n", | ||
748 | local->dev->name, param->dl_cmd); | ||
749 | ret = -EINVAL; | ||
750 | break; | ||
751 | }; | ||
752 | |||
753 | out: | ||
754 | if (ret == 0 && dl && | ||
755 | param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { | ||
756 | prism2_download_free_data(local->dl_pri); | ||
757 | local->dl_pri = dl; | ||
758 | } else if (ret == 0 && dl && | ||
759 | param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { | ||
760 | prism2_download_free_data(local->dl_sec); | ||
761 | local->dl_sec = dl; | ||
762 | } else | ||
763 | prism2_download_free_data(dl); | ||
764 | |||
765 | return ret; | ||
766 | } | ||
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c new file mode 100644 index 000000000000..e533a663deda --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
@@ -0,0 +1,3445 @@ | |||
1 | /* | ||
2 | * Host AP (software wireless LAN access point) driver for | ||
3 | * Intersil Prism2/2.5/3. | ||
4 | * | ||
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
6 | * <jkmaline@cc.hut.fi> | ||
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. See README and COPYING for | ||
12 | * more details. | ||
13 | * | ||
14 | * FIX: | ||
15 | * - there is currently no way of associating TX packets to correct wds device | ||
16 | * when TX Exc/OK event occurs, so all tx_packets and some | ||
17 | * tx_errors/tx_dropped are added to the main netdevice; using sw_support | ||
18 | * field in txdesc might be used to fix this (using Alloc event to increment | ||
19 | * tx_packets would need some further info in txfid table) | ||
20 | * | ||
21 | * Buffer Access Path (BAP) usage: | ||
22 | * Prism2 cards have two separate BAPs for accessing the card memory. These | ||
23 | * should allow concurrent access to two different frames and the driver | ||
24 | * previously used BAP0 for sending data and BAP1 for receiving data. | ||
25 | * However, there seems to be number of issues with concurrent access and at | ||
26 | * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI | ||
27 | * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between | ||
28 | * host and card memories. BAP0 accesses are protected with local->baplock | ||
29 | * (spin_lock_bh) to prevent concurrent use. | ||
30 | */ | ||
31 | |||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/version.h> | ||
35 | |||
36 | #include <asm/delay.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | |||
39 | #include <linux/slab.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/proc_fs.h> | ||
43 | #include <linux/if_arp.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/random.h> | ||
46 | #include <linux/wait.h> | ||
47 | #include <linux/sched.h> | ||
48 | #include <linux/rtnetlink.h> | ||
49 | #include <linux/wireless.h> | ||
50 | #include <net/iw_handler.h> | ||
51 | #include <net/ieee80211.h> | ||
52 | #include <net/ieee80211_crypt.h> | ||
53 | #include <asm/irq.h> | ||
54 | |||
55 | #include "hostap_80211.h" | ||
56 | #include "hostap.h" | ||
57 | #include "hostap_ap.h" | ||
58 | |||
59 | |||
60 | /* #define final_version */ | ||
61 | |||
62 | static int mtu = 1500; | ||
63 | module_param(mtu, int, 0444); | ||
64 | MODULE_PARM_DESC(mtu, "Maximum transfer unit"); | ||
65 | |||
66 | static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; | ||
67 | module_param_array(channel, int, NULL, 0444); | ||
68 | MODULE_PARM_DESC(channel, "Initial channel"); | ||
69 | |||
70 | static char essid[33] = "test"; | ||
71 | module_param_string(essid, essid, sizeof(essid), 0444); | ||
72 | MODULE_PARM_DESC(essid, "Host AP's ESSID"); | ||
73 | |||
74 | static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; | ||
75 | module_param_array(iw_mode, int, NULL, 0444); | ||
76 | MODULE_PARM_DESC(iw_mode, "Initial operation mode"); | ||
77 | |||
78 | static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | ||
79 | module_param_array(beacon_int, int, NULL, 0444); | ||
80 | MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); | ||
81 | |||
82 | static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | ||
83 | module_param_array(dtim_period, int, NULL, 0444); | ||
84 | MODULE_PARM_DESC(dtim_period, "DTIM period"); | ||
85 | |||
86 | static char dev_template[16] = "wlan%d"; | ||
87 | module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); | ||
88 | MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " | ||
89 | "wlan%d)"); | ||
90 | |||
91 | #ifdef final_version | ||
92 | #define EXTRA_EVENTS_WTERR 0 | ||
93 | #else | ||
94 | /* check WTERR events (Wait Time-out) in development versions */ | ||
95 | #define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR | ||
96 | #endif | ||
97 | |||
98 | /* Events that will be using BAP0 */ | ||
99 | #define HFA384X_BAP0_EVENTS \ | ||
100 | (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) | ||
101 | |||
102 | /* event mask, i.e., events that will result in an interrupt */ | ||
103 | #define HFA384X_EVENT_MASK \ | ||
104 | (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ | ||
105 | HFA384X_EV_CMD | HFA384X_EV_TICK | \ | ||
106 | EXTRA_EVENTS_WTERR) | ||
107 | |||
108 | /* Default TX control flags: use 802.11 headers and request interrupt for | ||
109 | * failed transmits. Frames that request ACK callback, will add | ||
110 | * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. | ||
111 | */ | ||
112 | #define HFA384X_TX_CTRL_FLAGS \ | ||
113 | (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) | ||
114 | |||
115 | |||
116 | /* ca. 1 usec */ | ||
117 | #define HFA384X_CMD_BUSY_TIMEOUT 5000 | ||
118 | #define HFA384X_BAP_BUSY_TIMEOUT 50000 | ||
119 | |||
120 | /* ca. 10 usec */ | ||
121 | #define HFA384X_CMD_COMPL_TIMEOUT 20000 | ||
122 | #define HFA384X_DL_COMPL_TIMEOUT 1000000 | ||
123 | |||
124 | /* Wait times for initialization; yield to other processes to avoid busy | ||
125 | * waiting for long time. */ | ||
126 | #define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ | ||
127 | #define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ | ||
128 | |||
129 | |||
130 | static void prism2_hw_reset(struct net_device *dev); | ||
131 | static void prism2_check_sta_fw_version(local_info_t *local); | ||
132 | |||
133 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
134 | /* hostap_download.c */ | ||
135 | static int prism2_download_aux_dump(struct net_device *dev, | ||
136 | unsigned int addr, int len, u8 *buf); | ||
137 | static u8 * prism2_read_pda(struct net_device *dev); | ||
138 | static int prism2_download(local_info_t *local, | ||
139 | struct prism2_download_param *param); | ||
140 | static void prism2_download_free_data(struct prism2_download_data *dl); | ||
141 | static int prism2_download_volatile(local_info_t *local, | ||
142 | struct prism2_download_data *param); | ||
143 | static int prism2_download_genesis(local_info_t *local, | ||
144 | struct prism2_download_data *param); | ||
145 | static int prism2_get_ram_size(local_info_t *local); | ||
146 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
147 | |||
148 | |||
149 | |||
150 | |||
151 | #ifndef final_version | ||
152 | /* magic value written to SWSUPPORT0 reg. for detecting whether card is still | ||
153 | * present */ | ||
154 | #define HFA384X_MAGIC 0x8A32 | ||
155 | #endif | ||
156 | |||
157 | |||
158 | static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) | ||
159 | { | ||
160 | return HFA384X_INW(reg); | ||
161 | } | ||
162 | |||
163 | |||
164 | static void hfa384x_read_regs(struct net_device *dev, | ||
165 | struct hfa384x_regs *regs) | ||
166 | { | ||
167 | regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); | ||
168 | regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
169 | regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); | ||
170 | regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); | ||
171 | regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); | ||
172 | } | ||
173 | |||
174 | |||
175 | /** | ||
176 | * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) | ||
177 | * @local: pointer to private Host AP driver data | ||
178 | * @entry: Prism2 command queue entry to be freed | ||
179 | * @del_req: request the entry to be removed | ||
180 | * | ||
181 | * Internal helper function for freeing Prism2 command queue entries. | ||
182 | * Caller must have acquired local->cmdlock before calling this function. | ||
183 | */ | ||
184 | static inline void __hostap_cmd_queue_free(local_info_t *local, | ||
185 | struct hostap_cmd_queue *entry, | ||
186 | int del_req) | ||
187 | { | ||
188 | if (del_req) { | ||
189 | entry->del_req = 1; | ||
190 | if (!list_empty(&entry->list)) { | ||
191 | list_del_init(&entry->list); | ||
192 | local->cmd_queue_len--; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) | ||
197 | kfree(entry); | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * hostap_cmd_queue_free - Free Prism2 command queue entry | ||
203 | * @local: pointer to private Host AP driver data | ||
204 | * @entry: Prism2 command queue entry to be freed | ||
205 | * @del_req: request the entry to be removed | ||
206 | * | ||
207 | * Free a Prism2 command queue entry. | ||
208 | */ | ||
209 | static inline void hostap_cmd_queue_free(local_info_t *local, | ||
210 | struct hostap_cmd_queue *entry, | ||
211 | int del_req) | ||
212 | { | ||
213 | unsigned long flags; | ||
214 | |||
215 | spin_lock_irqsave(&local->cmdlock, flags); | ||
216 | __hostap_cmd_queue_free(local, entry, del_req); | ||
217 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
218 | } | ||
219 | |||
220 | |||
221 | /** | ||
222 | * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries | ||
223 | * @local: pointer to private Host AP driver data | ||
224 | */ | ||
225 | static void prism2_clear_cmd_queue(local_info_t *local) | ||
226 | { | ||
227 | struct list_head *ptr, *n; | ||
228 | unsigned long flags; | ||
229 | struct hostap_cmd_queue *entry; | ||
230 | |||
231 | spin_lock_irqsave(&local->cmdlock, flags); | ||
232 | list_for_each_safe(ptr, n, &local->cmd_queue) { | ||
233 | entry = list_entry(ptr, struct hostap_cmd_queue, list); | ||
234 | atomic_inc(&entry->usecnt); | ||
235 | printk(KERN_DEBUG "%s: removed pending cmd_queue entry " | ||
236 | "(type=%d, cmd=0x%04x, param0=0x%04x)\n", | ||
237 | local->dev->name, entry->type, entry->cmd, | ||
238 | entry->param0); | ||
239 | __hostap_cmd_queue_free(local, entry, 1); | ||
240 | } | ||
241 | if (local->cmd_queue_len) { | ||
242 | /* This should not happen; print debug message and clear | ||
243 | * queue length. */ | ||
244 | printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " | ||
245 | "flush\n", local->dev->name, local->cmd_queue_len); | ||
246 | local->cmd_queue_len = 0; | ||
247 | } | ||
248 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * hfa384x_cmd_issue - Issue a Prism2 command to the hardware | ||
254 | * @dev: pointer to net_device | ||
255 | * @entry: Prism2 command queue entry to be issued | ||
256 | */ | ||
257 | static inline int hfa384x_cmd_issue(struct net_device *dev, | ||
258 | struct hostap_cmd_queue *entry) | ||
259 | { | ||
260 | struct hostap_interface *iface; | ||
261 | local_info_t *local; | ||
262 | int tries; | ||
263 | u16 reg; | ||
264 | unsigned long flags; | ||
265 | |||
266 | iface = netdev_priv(dev); | ||
267 | local = iface->local; | ||
268 | |||
269 | if (local->func->card_present && !local->func->card_present(local)) | ||
270 | return -ENODEV; | ||
271 | |||
272 | if (entry->issued) { | ||
273 | printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", | ||
274 | dev->name, entry); | ||
275 | } | ||
276 | |||
277 | /* wait until busy bit is clear; this should always be clear since the | ||
278 | * commands are serialized */ | ||
279 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
280 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
281 | tries--; | ||
282 | udelay(1); | ||
283 | } | ||
284 | #ifndef final_version | ||
285 | if (tries != HFA384X_CMD_BUSY_TIMEOUT) { | ||
286 | prism2_io_debug_error(dev, 1); | ||
287 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " | ||
288 | "for %d usec\n", dev->name, | ||
289 | HFA384X_CMD_BUSY_TIMEOUT - tries); | ||
290 | } | ||
291 | #endif | ||
292 | if (tries == 0) { | ||
293 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
294 | prism2_io_debug_error(dev, 2); | ||
295 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " | ||
296 | "reg=0x%04x\n", dev->name, reg); | ||
297 | return -ETIMEDOUT; | ||
298 | } | ||
299 | |||
300 | /* write command */ | ||
301 | spin_lock_irqsave(&local->cmdlock, flags); | ||
302 | HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); | ||
303 | HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); | ||
304 | HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); | ||
305 | entry->issued = 1; | ||
306 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion | ||
314 | * @dev: pointer to net_device | ||
315 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
316 | * @param0: value for Param0 register | ||
317 | * @param1: value for Param1 register (pointer; %NULL if not used) | ||
318 | * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed | ||
319 | * | ||
320 | * Issue given command (possibly after waiting in command queue) and sleep | ||
321 | * until the command is completed (or timed out or interrupted). This can be | ||
322 | * called only from user process context. | ||
323 | */ | ||
324 | static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, | ||
325 | u16 *param1, u16 *resp0) | ||
326 | { | ||
327 | struct hostap_interface *iface; | ||
328 | local_info_t *local; | ||
329 | int err, res, issue, issued = 0; | ||
330 | unsigned long flags; | ||
331 | struct hostap_cmd_queue *entry; | ||
332 | DECLARE_WAITQUEUE(wait, current); | ||
333 | |||
334 | iface = netdev_priv(dev); | ||
335 | local = iface->local; | ||
336 | |||
337 | if (in_interrupt()) { | ||
338 | printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt " | ||
339 | "context\n", dev->name); | ||
340 | return -1; | ||
341 | } | ||
342 | |||
343 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { | ||
344 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
345 | dev->name); | ||
346 | return -1; | ||
347 | } | ||
348 | |||
349 | if (signal_pending(current)) | ||
350 | return -EINTR; | ||
351 | |||
352 | entry = (struct hostap_cmd_queue *) | ||
353 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
354 | if (entry == NULL) { | ||
355 | printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n", | ||
356 | dev->name); | ||
357 | return -ENOMEM; | ||
358 | } | ||
359 | memset(entry, 0, sizeof(*entry)); | ||
360 | atomic_set(&entry->usecnt, 1); | ||
361 | entry->type = CMD_SLEEP; | ||
362 | entry->cmd = cmd; | ||
363 | entry->param0 = param0; | ||
364 | if (param1) | ||
365 | entry->param1 = *param1; | ||
366 | init_waitqueue_head(&entry->compl); | ||
367 | |||
368 | /* prepare to wait for command completion event, but do not sleep yet | ||
369 | */ | ||
370 | add_wait_queue(&entry->compl, &wait); | ||
371 | set_current_state(TASK_INTERRUPTIBLE); | ||
372 | |||
373 | spin_lock_irqsave(&local->cmdlock, flags); | ||
374 | issue = list_empty(&local->cmd_queue); | ||
375 | if (issue) | ||
376 | entry->issuing = 1; | ||
377 | list_add_tail(&entry->list, &local->cmd_queue); | ||
378 | local->cmd_queue_len++; | ||
379 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
380 | |||
381 | err = 0; | ||
382 | if (!issue) | ||
383 | goto wait_completion; | ||
384 | |||
385 | if (signal_pending(current)) | ||
386 | err = -EINTR; | ||
387 | |||
388 | if (!err) { | ||
389 | if (hfa384x_cmd_issue(dev, entry)) | ||
390 | err = -ETIMEDOUT; | ||
391 | else | ||
392 | issued = 1; | ||
393 | } | ||
394 | |||
395 | wait_completion: | ||
396 | if (!err && entry->type != CMD_COMPLETED) { | ||
397 | /* sleep until command is completed or timed out */ | ||
398 | res = schedule_timeout(2 * HZ); | ||
399 | } else | ||
400 | res = -1; | ||
401 | |||
402 | if (!err && signal_pending(current)) | ||
403 | err = -EINTR; | ||
404 | |||
405 | if (err && issued) { | ||
406 | /* the command was issued, so a CmdCompl event should occur | ||
407 | * soon; however, there's a pending signal and | ||
408 | * schedule_timeout() would be interrupted; wait a short period | ||
409 | * of time to avoid removing entry from the list before | ||
410 | * CmdCompl event */ | ||
411 | udelay(300); | ||
412 | } | ||
413 | |||
414 | set_current_state(TASK_RUNNING); | ||
415 | remove_wait_queue(&entry->compl, &wait); | ||
416 | |||
417 | /* If entry->list is still in the list, it must be removed | ||
418 | * first and in this case prism2_cmd_ev() does not yet have | ||
419 | * local reference to it, and the data can be kfree()'d | ||
420 | * here. If the command completion event is still generated, | ||
421 | * it will be assigned to next (possibly) pending command, but | ||
422 | * the driver will reset the card anyway due to timeout | ||
423 | * | ||
424 | * If the entry is not in the list prism2_cmd_ev() has a local | ||
425 | * reference to it, but keeps cmdlock as long as the data is | ||
426 | * needed, so the data can be kfree()'d here. */ | ||
427 | |||
428 | /* FIX: if the entry->list is in the list, it has not been completed | ||
429 | * yet, so removing it here is somewhat wrong.. this could cause | ||
430 | * references to freed memory and next list_del() causing NULL pointer | ||
431 | * dereference.. it would probably be better to leave the entry in the | ||
432 | * list and the list should be emptied during hw reset */ | ||
433 | |||
434 | spin_lock_irqsave(&local->cmdlock, flags); | ||
435 | if (!list_empty(&entry->list)) { | ||
436 | printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " | ||
437 | "(entry=%p, type=%d, res=%d)\n", dev->name, entry, | ||
438 | entry->type, res); | ||
439 | list_del_init(&entry->list); | ||
440 | local->cmd_queue_len--; | ||
441 | } | ||
442 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
443 | |||
444 | if (err) { | ||
445 | printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", | ||
446 | dev->name, err); | ||
447 | res = err; | ||
448 | goto done; | ||
449 | } | ||
450 | |||
451 | if (entry->type != CMD_COMPLETED) { | ||
452 | u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
453 | printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " | ||
454 | "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " | ||
455 | "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, | ||
456 | res, entry, entry->type, entry->cmd, entry->param0, reg, | ||
457 | HFA384X_INW(HFA384X_INTEN_OFF)); | ||
458 | if (reg & HFA384X_EV_CMD) { | ||
459 | /* Command completion event is pending, but the | ||
460 | * interrupt was not delivered - probably an issue | ||
461 | * with pcmcia-cs configuration. */ | ||
462 | printk(KERN_WARNING "%s: interrupt delivery does not " | ||
463 | "seem to work\n", dev->name); | ||
464 | } | ||
465 | prism2_io_debug_error(dev, 3); | ||
466 | res = -ETIMEDOUT; | ||
467 | goto done; | ||
468 | } | ||
469 | |||
470 | if (resp0 != NULL) | ||
471 | *resp0 = entry->resp0; | ||
472 | #ifndef final_version | ||
473 | if (entry->res) { | ||
474 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " | ||
475 | "resp0=0x%04x\n", | ||
476 | dev->name, cmd, entry->res, entry->resp0); | ||
477 | } | ||
478 | #endif /* final_version */ | ||
479 | |||
480 | res = entry->res; | ||
481 | done: | ||
482 | hostap_cmd_queue_free(local, entry, 1); | ||
483 | return res; | ||
484 | } | ||
485 | |||
486 | |||
487 | /** | ||
488 | * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed | ||
489 | * @dev: pointer to net_device | ||
490 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
491 | * @param0: value for Param0 register | ||
492 | * @callback: command completion callback function (%NULL = no callback) | ||
493 | * @context: context data to be given to the callback function | ||
494 | * | ||
495 | * Issue given command (possibly after waiting in command queue) and use | ||
496 | * callback function to indicate command completion. This can be called both | ||
497 | * from user and interrupt context. The callback function will be called in | ||
498 | * hardware IRQ context. It can be %NULL, when no function is called when | ||
499 | * command is completed. | ||
500 | */ | ||
501 | static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, | ||
502 | void (*callback)(struct net_device *dev, | ||
503 | long context, u16 resp0, | ||
504 | u16 status), | ||
505 | long context) | ||
506 | { | ||
507 | struct hostap_interface *iface; | ||
508 | local_info_t *local; | ||
509 | int issue, ret; | ||
510 | unsigned long flags; | ||
511 | struct hostap_cmd_queue *entry; | ||
512 | |||
513 | iface = netdev_priv(dev); | ||
514 | local = iface->local; | ||
515 | |||
516 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { | ||
517 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
518 | dev->name); | ||
519 | return -1; | ||
520 | } | ||
521 | |||
522 | entry = (struct hostap_cmd_queue *) | ||
523 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
524 | if (entry == NULL) { | ||
525 | printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc " | ||
526 | "failed\n", dev->name); | ||
527 | return -ENOMEM; | ||
528 | } | ||
529 | memset(entry, 0, sizeof(*entry)); | ||
530 | atomic_set(&entry->usecnt, 1); | ||
531 | entry->type = CMD_CALLBACK; | ||
532 | entry->cmd = cmd; | ||
533 | entry->param0 = param0; | ||
534 | entry->callback = callback; | ||
535 | entry->context = context; | ||
536 | |||
537 | spin_lock_irqsave(&local->cmdlock, flags); | ||
538 | issue = list_empty(&local->cmd_queue); | ||
539 | if (issue) | ||
540 | entry->issuing = 1; | ||
541 | list_add_tail(&entry->list, &local->cmd_queue); | ||
542 | local->cmd_queue_len++; | ||
543 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
544 | |||
545 | if (issue && hfa384x_cmd_issue(dev, entry)) | ||
546 | ret = -ETIMEDOUT; | ||
547 | else | ||
548 | ret = 0; | ||
549 | |||
550 | hostap_cmd_queue_free(local, entry, ret); | ||
551 | |||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) | ||
558 | * @dev: pointer to net_device | ||
559 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
560 | * @param0: value for Param0 register | ||
561 | * @io_debug_num: I/O debug error number | ||
562 | * | ||
563 | * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). | ||
564 | */ | ||
565 | static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, | ||
566 | int io_debug_num) | ||
567 | { | ||
568 | int tries; | ||
569 | u16 reg; | ||
570 | |||
571 | /* wait until busy bit is clear; this should always be clear since the | ||
572 | * commands are serialized */ | ||
573 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
574 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
575 | tries--; | ||
576 | udelay(1); | ||
577 | } | ||
578 | if (tries == 0) { | ||
579 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
580 | prism2_io_debug_error(dev, io_debug_num); | ||
581 | printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " | ||
582 | "reg=0x%04x\n", dev->name, io_debug_num, reg); | ||
583 | return -ETIMEDOUT; | ||
584 | } | ||
585 | |||
586 | /* write command */ | ||
587 | HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); | ||
588 | HFA384X_OUTW(cmd, HFA384X_CMD_OFF); | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | |||
594 | /** | ||
595 | * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion | ||
596 | * @dev: pointer to net_device | ||
597 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
598 | * @param0: value for Param0 register | ||
599 | */ | ||
600 | static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) | ||
601 | { | ||
602 | int res, tries; | ||
603 | u16 reg; | ||
604 | |||
605 | res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); | ||
606 | if (res) | ||
607 | return res; | ||
608 | |||
609 | /* wait for command completion */ | ||
610 | if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) | ||
611 | tries = HFA384X_DL_COMPL_TIMEOUT; | ||
612 | else | ||
613 | tries = HFA384X_CMD_COMPL_TIMEOUT; | ||
614 | |||
615 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
616 | tries > 0) { | ||
617 | tries--; | ||
618 | udelay(10); | ||
619 | } | ||
620 | if (tries == 0) { | ||
621 | reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
622 | prism2_io_debug_error(dev, 5); | ||
623 | printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " | ||
624 | "reg=0x%04x\n", dev->name, reg); | ||
625 | return -ETIMEDOUT; | ||
626 | } | ||
627 | |||
628 | res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
629 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | | ||
630 | BIT(8))) >> 8; | ||
631 | #ifndef final_version | ||
632 | if (res) { | ||
633 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", | ||
634 | dev->name, cmd, res); | ||
635 | } | ||
636 | #endif | ||
637 | |||
638 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
639 | |||
640 | return res; | ||
641 | } | ||
642 | |||
643 | |||
644 | /** | ||
645 | * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion | ||
646 | * @dev: pointer to net_device | ||
647 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
648 | * @param0: value for Param0 register | ||
649 | */ | ||
650 | static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, | ||
651 | u16 param0) | ||
652 | { | ||
653 | return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * prism2_cmd_ev - Prism2 command completion event handler | ||
659 | * @dev: pointer to net_device | ||
660 | * | ||
661 | * Interrupt handler for command completion events. Called by the main | ||
662 | * interrupt handler in hardware IRQ context. Read Resp0 and status registers | ||
663 | * from the hardware and ACK the event. Depending on the issued command type | ||
664 | * either wake up the sleeping process that is waiting for command completion | ||
665 | * or call the callback function. Issue the next command, if one is pending. | ||
666 | */ | ||
667 | static void prism2_cmd_ev(struct net_device *dev) | ||
668 | { | ||
669 | struct hostap_interface *iface; | ||
670 | local_info_t *local; | ||
671 | struct hostap_cmd_queue *entry = NULL; | ||
672 | |||
673 | iface = netdev_priv(dev); | ||
674 | local = iface->local; | ||
675 | |||
676 | spin_lock(&local->cmdlock); | ||
677 | if (!list_empty(&local->cmd_queue)) { | ||
678 | entry = list_entry(local->cmd_queue.next, | ||
679 | struct hostap_cmd_queue, list); | ||
680 | atomic_inc(&entry->usecnt); | ||
681 | list_del_init(&entry->list); | ||
682 | local->cmd_queue_len--; | ||
683 | |||
684 | if (!entry->issued) { | ||
685 | printk(KERN_DEBUG "%s: Command completion event, but " | ||
686 | "cmd not issued\n", dev->name); | ||
687 | __hostap_cmd_queue_free(local, entry, 1); | ||
688 | entry = NULL; | ||
689 | } | ||
690 | } | ||
691 | spin_unlock(&local->cmdlock); | ||
692 | |||
693 | if (!entry) { | ||
694 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
695 | printk(KERN_DEBUG "%s: Command completion event, but no " | ||
696 | "pending commands\n", dev->name); | ||
697 | return; | ||
698 | } | ||
699 | |||
700 | entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); | ||
701 | entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
702 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | | ||
703 | BIT(9) | BIT(8))) >> 8; | ||
704 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
705 | |||
706 | /* TODO: rest of the CmdEv handling could be moved to tasklet */ | ||
707 | if (entry->type == CMD_SLEEP) { | ||
708 | entry->type = CMD_COMPLETED; | ||
709 | wake_up_interruptible(&entry->compl); | ||
710 | } else if (entry->type == CMD_CALLBACK) { | ||
711 | if (entry->callback) | ||
712 | entry->callback(dev, entry->context, entry->resp0, | ||
713 | entry->res); | ||
714 | } else { | ||
715 | printk(KERN_DEBUG "%s: Invalid command completion type %d\n", | ||
716 | dev->name, entry->type); | ||
717 | } | ||
718 | hostap_cmd_queue_free(local, entry, 1); | ||
719 | |||
720 | /* issue next command, if pending */ | ||
721 | entry = NULL; | ||
722 | spin_lock(&local->cmdlock); | ||
723 | if (!list_empty(&local->cmd_queue)) { | ||
724 | entry = list_entry(local->cmd_queue.next, | ||
725 | struct hostap_cmd_queue, list); | ||
726 | if (entry->issuing) { | ||
727 | /* hfa384x_cmd() has already started issuing this | ||
728 | * command, so do not start here */ | ||
729 | entry = NULL; | ||
730 | } | ||
731 | if (entry) | ||
732 | atomic_inc(&entry->usecnt); | ||
733 | } | ||
734 | spin_unlock(&local->cmdlock); | ||
735 | |||
736 | if (entry) { | ||
737 | /* issue next command; if command issuing fails, remove the | ||
738 | * entry from cmd_queue */ | ||
739 | int res = hfa384x_cmd_issue(dev, entry); | ||
740 | spin_lock(&local->cmdlock); | ||
741 | __hostap_cmd_queue_free(local, entry, res); | ||
742 | spin_unlock(&local->cmdlock); | ||
743 | } | ||
744 | } | ||
745 | |||
746 | |||
747 | static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off) | ||
748 | { | ||
749 | int tries = HFA384X_BAP_BUSY_TIMEOUT; | ||
750 | int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
751 | |||
752 | while (res && tries > 0) { | ||
753 | tries--; | ||
754 | udelay(1); | ||
755 | res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
756 | } | ||
757 | return res; | ||
758 | } | ||
759 | |||
760 | |||
761 | /* Offset must be even */ | ||
762 | static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, | ||
763 | int offset) | ||
764 | { | ||
765 | u16 o_off, s_off; | ||
766 | int ret = 0; | ||
767 | |||
768 | if (offset % 2 || bap > 1) | ||
769 | return -EINVAL; | ||
770 | |||
771 | if (bap == BAP1) { | ||
772 | o_off = HFA384X_OFFSET1_OFF; | ||
773 | s_off = HFA384X_SELECT1_OFF; | ||
774 | } else { | ||
775 | o_off = HFA384X_OFFSET0_OFF; | ||
776 | s_off = HFA384X_SELECT0_OFF; | ||
777 | } | ||
778 | |||
779 | if (hfa384x_wait_offset(dev, o_off)) { | ||
780 | prism2_io_debug_error(dev, 7); | ||
781 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", | ||
782 | dev->name); | ||
783 | ret = -ETIMEDOUT; | ||
784 | goto out; | ||
785 | } | ||
786 | |||
787 | HFA384X_OUTW(id, s_off); | ||
788 | HFA384X_OUTW(offset, o_off); | ||
789 | |||
790 | if (hfa384x_wait_offset(dev, o_off)) { | ||
791 | prism2_io_debug_error(dev, 8); | ||
792 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", | ||
793 | dev->name); | ||
794 | ret = -ETIMEDOUT; | ||
795 | goto out; | ||
796 | } | ||
797 | #ifndef final_version | ||
798 | if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { | ||
799 | prism2_io_debug_error(dev, 9); | ||
800 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " | ||
801 | "(%d,0x04%x,%d); reg=0x%04x\n", | ||
802 | dev->name, bap, id, offset, HFA384X_INW(o_off)); | ||
803 | ret = -EINVAL; | ||
804 | } | ||
805 | #endif | ||
806 | |||
807 | out: | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | |||
812 | static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, | ||
813 | int exact_len) | ||
814 | { | ||
815 | struct hostap_interface *iface; | ||
816 | local_info_t *local; | ||
817 | int res, rlen = 0; | ||
818 | struct hfa384x_rid_hdr rec; | ||
819 | |||
820 | iface = netdev_priv(dev); | ||
821 | local = iface->local; | ||
822 | |||
823 | if (local->no_pri) { | ||
824 | printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " | ||
825 | "f/w\n", dev->name, rid, len); | ||
826 | return -ENOTTY; /* Well.. not really correct, but return | ||
827 | * something unique enough.. */ | ||
828 | } | ||
829 | |||
830 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
831 | local->hw_downloading) | ||
832 | return -ENODEV; | ||
833 | |||
834 | res = down_interruptible(&local->rid_bap_sem); | ||
835 | if (res) | ||
836 | return res; | ||
837 | |||
838 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); | ||
839 | if (res) { | ||
840 | printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " | ||
841 | "(res=%d, rid=%04x, len=%d)\n", | ||
842 | dev->name, res, rid, len); | ||
843 | up(&local->rid_bap_sem); | ||
844 | return res; | ||
845 | } | ||
846 | |||
847 | spin_lock_bh(&local->baplock); | ||
848 | |||
849 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
850 | if (!res) | ||
851 | res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); | ||
852 | |||
853 | if (le16_to_cpu(rec.len) == 0) { | ||
854 | /* RID not available */ | ||
855 | res = -ENODATA; | ||
856 | } | ||
857 | |||
858 | rlen = (le16_to_cpu(rec.len) - 1) * 2; | ||
859 | if (!res && exact_len && rlen != len) { | ||
860 | printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " | ||
861 | "rid=0x%04x, len=%d (expected %d)\n", | ||
862 | dev->name, rid, rlen, len); | ||
863 | res = -ENODATA; | ||
864 | } | ||
865 | |||
866 | if (!res) | ||
867 | res = hfa384x_from_bap(dev, BAP0, buf, len); | ||
868 | |||
869 | spin_unlock_bh(&local->baplock); | ||
870 | up(&local->rid_bap_sem); | ||
871 | |||
872 | if (res) { | ||
873 | if (res != -ENODATA) | ||
874 | printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " | ||
875 | "len=%d) - failed - res=%d\n", dev->name, rid, | ||
876 | len, res); | ||
877 | if (res == -ETIMEDOUT) | ||
878 | prism2_hw_reset(dev); | ||
879 | return res; | ||
880 | } | ||
881 | |||
882 | return rlen; | ||
883 | } | ||
884 | |||
885 | |||
886 | static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) | ||
887 | { | ||
888 | struct hostap_interface *iface; | ||
889 | local_info_t *local; | ||
890 | struct hfa384x_rid_hdr rec; | ||
891 | int res; | ||
892 | |||
893 | iface = netdev_priv(dev); | ||
894 | local = iface->local; | ||
895 | |||
896 | if (local->no_pri) { | ||
897 | printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " | ||
898 | "f/w\n", dev->name, rid, len); | ||
899 | return -ENOTTY; /* Well.. not really correct, but return | ||
900 | * something unique enough.. */ | ||
901 | } | ||
902 | |||
903 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
904 | local->hw_downloading) | ||
905 | return -ENODEV; | ||
906 | |||
907 | rec.rid = cpu_to_le16(rid); | ||
908 | /* RID len in words and +1 for rec.rid */ | ||
909 | rec.len = cpu_to_le16(len / 2 + len % 2 + 1); | ||
910 | |||
911 | res = down_interruptible(&local->rid_bap_sem); | ||
912 | if (res) | ||
913 | return res; | ||
914 | |||
915 | spin_lock_bh(&local->baplock); | ||
916 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
917 | if (!res) | ||
918 | res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); | ||
919 | if (!res) | ||
920 | res = hfa384x_to_bap(dev, BAP0, buf, len); | ||
921 | spin_unlock_bh(&local->baplock); | ||
922 | |||
923 | if (res) { | ||
924 | printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " | ||
925 | "failed - res=%d\n", dev->name, rid, len, res); | ||
926 | up(&local->rid_bap_sem); | ||
927 | return res; | ||
928 | } | ||
929 | |||
930 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); | ||
931 | up(&local->rid_bap_sem); | ||
932 | if (res) { | ||
933 | printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " | ||
934 | "failed (res=%d, rid=%04x, len=%d)\n", | ||
935 | dev->name, res, rid, len); | ||
936 | return res; | ||
937 | } | ||
938 | |||
939 | if (res == -ETIMEDOUT) | ||
940 | prism2_hw_reset(dev); | ||
941 | |||
942 | return res; | ||
943 | } | ||
944 | |||
945 | |||
946 | static void hfa384x_disable_interrupts(struct net_device *dev) | ||
947 | { | ||
948 | /* disable interrupts and clear event status */ | ||
949 | HFA384X_OUTW(0, HFA384X_INTEN_OFF); | ||
950 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
951 | } | ||
952 | |||
953 | |||
954 | static void hfa384x_enable_interrupts(struct net_device *dev) | ||
955 | { | ||
956 | /* ack pending events and enable interrupts from selected events */ | ||
957 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
958 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
959 | } | ||
960 | |||
961 | |||
962 | static void hfa384x_events_no_bap0(struct net_device *dev) | ||
963 | { | ||
964 | HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, | ||
965 | HFA384X_INTEN_OFF); | ||
966 | } | ||
967 | |||
968 | |||
969 | static void hfa384x_events_all(struct net_device *dev) | ||
970 | { | ||
971 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
972 | } | ||
973 | |||
974 | |||
975 | static void hfa384x_events_only_cmd(struct net_device *dev) | ||
976 | { | ||
977 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); | ||
978 | } | ||
979 | |||
980 | |||
981 | static u16 hfa384x_allocate_fid(struct net_device *dev, int len) | ||
982 | { | ||
983 | u16 fid; | ||
984 | unsigned long delay; | ||
985 | |||
986 | /* FIX: this could be replace with hfa384x_cmd() if the Alloc event | ||
987 | * below would be handled like CmdCompl event (sleep here, wake up from | ||
988 | * interrupt handler */ | ||
989 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { | ||
990 | printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", | ||
991 | dev->name, len); | ||
992 | return 0xffff; | ||
993 | } | ||
994 | |||
995 | delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; | ||
996 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && | ||
997 | time_before(jiffies, delay)) | ||
998 | yield(); | ||
999 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { | ||
1000 | printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); | ||
1001 | return 0xffff; | ||
1002 | } | ||
1003 | |||
1004 | fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); | ||
1005 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
1006 | |||
1007 | return fid; | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | static int prism2_reset_port(struct net_device *dev) | ||
1012 | { | ||
1013 | struct hostap_interface *iface; | ||
1014 | local_info_t *local; | ||
1015 | int res; | ||
1016 | |||
1017 | iface = netdev_priv(dev); | ||
1018 | local = iface->local; | ||
1019 | |||
1020 | if (!local->dev_enabled) | ||
1021 | return 0; | ||
1022 | |||
1023 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, | ||
1024 | NULL, NULL); | ||
1025 | if (res) | ||
1026 | printk(KERN_DEBUG "%s: reset port failed to disable port\n", | ||
1027 | dev->name); | ||
1028 | else { | ||
1029 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, | ||
1030 | NULL, NULL); | ||
1031 | if (res) | ||
1032 | printk(KERN_DEBUG "%s: reset port failed to enable " | ||
1033 | "port\n", dev->name); | ||
1034 | } | ||
1035 | |||
1036 | /* It looks like at least some STA firmware versions reset | ||
1037 | * fragmentation threshold back to 2346 after enable command. Restore | ||
1038 | * the configured value, if it differs from this default. */ | ||
1039 | if (local->fragm_threshold != 2346 && | ||
1040 | hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1041 | local->fragm_threshold)) { | ||
1042 | printk(KERN_DEBUG "%s: failed to restore fragmentation " | ||
1043 | "threshold (%d) after Port0 enable\n", | ||
1044 | dev->name, local->fragm_threshold); | ||
1045 | } | ||
1046 | |||
1047 | return res; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | static int prism2_get_version_info(struct net_device *dev, u16 rid, | ||
1052 | const char *txt) | ||
1053 | { | ||
1054 | struct hfa384x_comp_ident comp; | ||
1055 | struct hostap_interface *iface; | ||
1056 | local_info_t *local; | ||
1057 | |||
1058 | iface = netdev_priv(dev); | ||
1059 | local = iface->local; | ||
1060 | |||
1061 | if (local->no_pri) { | ||
1062 | /* PRI f/w not yet available - cannot read RIDs */ | ||
1063 | return -1; | ||
1064 | } | ||
1065 | if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { | ||
1066 | printk(KERN_DEBUG "Could not get RID for component %s\n", txt); | ||
1067 | return -1; | ||
1068 | } | ||
1069 | |||
1070 | printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, | ||
1071 | __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), | ||
1072 | __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); | ||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | static int prism2_setup_rids(struct net_device *dev) | ||
1078 | { | ||
1079 | struct hostap_interface *iface; | ||
1080 | local_info_t *local; | ||
1081 | u16 tmp; | ||
1082 | int ret = 0; | ||
1083 | |||
1084 | iface = netdev_priv(dev); | ||
1085 | local = iface->local; | ||
1086 | |||
1087 | hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); | ||
1088 | |||
1089 | if (!local->fw_ap) { | ||
1090 | tmp = hostap_get_porttype(local); | ||
1091 | ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); | ||
1092 | if (ret) { | ||
1093 | printk("%s: Port type setting to %d failed\n", | ||
1094 | dev->name, tmp); | ||
1095 | goto fail; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | /* Setting SSID to empty string seems to kill the card in Host AP mode | ||
1100 | */ | ||
1101 | if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { | ||
1102 | ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, | ||
1103 | local->essid); | ||
1104 | if (ret) { | ||
1105 | printk("%s: AP own SSID setting failed\n", dev->name); | ||
1106 | goto fail; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, | ||
1111 | PRISM2_DATA_MAXLEN); | ||
1112 | if (ret) { | ||
1113 | printk("%s: MAC data length setting to %d failed\n", | ||
1114 | dev->name, PRISM2_DATA_MAXLEN); | ||
1115 | goto fail; | ||
1116 | } | ||
1117 | |||
1118 | if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { | ||
1119 | printk("%s: Channel list read failed\n", dev->name); | ||
1120 | ret = -EINVAL; | ||
1121 | goto fail; | ||
1122 | } | ||
1123 | local->channel_mask = __le16_to_cpu(tmp); | ||
1124 | |||
1125 | if (local->channel < 1 || local->channel > 14 || | ||
1126 | !(local->channel_mask & (1 << (local->channel - 1)))) { | ||
1127 | printk(KERN_WARNING "%s: Channel setting out of range " | ||
1128 | "(%d)!\n", dev->name, local->channel); | ||
1129 | ret = -EBUSY; | ||
1130 | goto fail; | ||
1131 | } | ||
1132 | |||
1133 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); | ||
1134 | if (ret) { | ||
1135 | printk("%s: Channel setting to %d failed\n", | ||
1136 | dev->name, local->channel); | ||
1137 | goto fail; | ||
1138 | } | ||
1139 | |||
1140 | ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, | ||
1141 | local->beacon_int); | ||
1142 | if (ret) { | ||
1143 | printk("%s: Beacon interval setting to %d failed\n", | ||
1144 | dev->name, local->beacon_int); | ||
1145 | /* this may fail with Symbol/Lucent firmware */ | ||
1146 | if (ret == -ETIMEDOUT) | ||
1147 | goto fail; | ||
1148 | } | ||
1149 | |||
1150 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, | ||
1151 | local->dtim_period); | ||
1152 | if (ret) { | ||
1153 | printk("%s: DTIM period setting to %d failed\n", | ||
1154 | dev->name, local->dtim_period); | ||
1155 | /* this may fail with Symbol/Lucent firmware */ | ||
1156 | if (ret == -ETIMEDOUT) | ||
1157 | goto fail; | ||
1158 | } | ||
1159 | |||
1160 | ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
1161 | local->is_promisc); | ||
1162 | if (ret) | ||
1163 | printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", | ||
1164 | dev->name, local->is_promisc); | ||
1165 | |||
1166 | if (!local->fw_ap) { | ||
1167 | ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, | ||
1168 | local->essid); | ||
1169 | if (ret) { | ||
1170 | printk("%s: Desired SSID setting failed\n", dev->name); | ||
1171 | goto fail; | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and | ||
1176 | * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic | ||
1177 | * rates */ | ||
1178 | if (local->tx_rate_control == 0) { | ||
1179 | local->tx_rate_control = | ||
1180 | HFA384X_RATES_1MBPS | | ||
1181 | HFA384X_RATES_2MBPS | | ||
1182 | HFA384X_RATES_5MBPS | | ||
1183 | HFA384X_RATES_11MBPS; | ||
1184 | } | ||
1185 | if (local->basic_rates == 0) | ||
1186 | local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; | ||
1187 | |||
1188 | if (!local->fw_ap) { | ||
1189 | ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
1190 | local->tx_rate_control); | ||
1191 | if (ret) { | ||
1192 | printk("%s: TXRateControl setting to %d failed\n", | ||
1193 | dev->name, local->tx_rate_control); | ||
1194 | goto fail; | ||
1195 | } | ||
1196 | |||
1197 | ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
1198 | local->tx_rate_control); | ||
1199 | if (ret) { | ||
1200 | printk("%s: cnfSupportedRates setting to %d failed\n", | ||
1201 | dev->name, local->tx_rate_control); | ||
1202 | } | ||
1203 | |||
1204 | ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
1205 | local->basic_rates); | ||
1206 | if (ret) { | ||
1207 | printk("%s: cnfBasicRates setting to %d failed\n", | ||
1208 | dev->name, local->basic_rates); | ||
1209 | } | ||
1210 | |||
1211 | ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); | ||
1212 | if (ret) { | ||
1213 | printk("%s: Create IBSS setting to 1 failed\n", | ||
1214 | dev->name); | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | if (local->name_set) | ||
1219 | (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, | ||
1220 | local->name); | ||
1221 | |||
1222 | if (hostap_set_encryption(local)) { | ||
1223 | printk(KERN_INFO "%s: could not configure encryption\n", | ||
1224 | dev->name); | ||
1225 | } | ||
1226 | |||
1227 | (void) hostap_set_antsel(local); | ||
1228 | |||
1229 | if (hostap_set_roaming(local)) { | ||
1230 | printk(KERN_INFO "%s: could not set host roaming\n", | ||
1231 | dev->name); | ||
1232 | } | ||
1233 | |||
1234 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && | ||
1235 | hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) | ||
1236 | printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", | ||
1237 | dev->name, local->enh_sec); | ||
1238 | |||
1239 | /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently | ||
1240 | * not working correctly (last seven counters report bogus values). | ||
1241 | * This has been fixed in 0.8.2, so enable 32-bit tallies only | ||
1242 | * beginning with that firmware version. Another bug fix for 32-bit | ||
1243 | * tallies in 1.4.0; should 16-bit tallies be used for some other | ||
1244 | * versions, too? */ | ||
1245 | if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { | ||
1246 | if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { | ||
1247 | printk(KERN_INFO "%s: cnfThirty2Tally setting " | ||
1248 | "failed\n", dev->name); | ||
1249 | local->tallies32 = 0; | ||
1250 | } else | ||
1251 | local->tallies32 = 1; | ||
1252 | } else | ||
1253 | local->tallies32 = 0; | ||
1254 | |||
1255 | hostap_set_auth_algs(local); | ||
1256 | |||
1257 | if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1258 | local->fragm_threshold)) { | ||
1259 | printk(KERN_INFO "%s: setting FragmentationThreshold to %d " | ||
1260 | "failed\n", dev->name, local->fragm_threshold); | ||
1261 | } | ||
1262 | |||
1263 | if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, | ||
1264 | local->rts_threshold)) { | ||
1265 | printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", | ||
1266 | dev->name, local->rts_threshold); | ||
1267 | } | ||
1268 | |||
1269 | if (local->manual_retry_count >= 0 && | ||
1270 | hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1271 | local->manual_retry_count)) { | ||
1272 | printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", | ||
1273 | dev->name, local->manual_retry_count); | ||
1274 | } | ||
1275 | |||
1276 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && | ||
1277 | hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { | ||
1278 | local->rssi_to_dBm = le16_to_cpu(tmp); | ||
1279 | } | ||
1280 | |||
1281 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && | ||
1282 | hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { | ||
1283 | printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", | ||
1284 | dev->name); | ||
1285 | } | ||
1286 | |||
1287 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && | ||
1288 | hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, | ||
1289 | local->generic_elem, local->generic_elem_len)) { | ||
1290 | printk(KERN_INFO "%s: setting genericElement failed\n", | ||
1291 | dev->name); | ||
1292 | } | ||
1293 | |||
1294 | fail: | ||
1295 | return ret; | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | static int prism2_hw_init(struct net_device *dev, int initial) | ||
1300 | { | ||
1301 | struct hostap_interface *iface; | ||
1302 | local_info_t *local; | ||
1303 | int ret, first = 1; | ||
1304 | unsigned long start, delay; | ||
1305 | |||
1306 | PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); | ||
1307 | |||
1308 | iface = netdev_priv(dev); | ||
1309 | local = iface->local; | ||
1310 | |||
1311 | clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); | ||
1312 | |||
1313 | init: | ||
1314 | /* initialize HFA 384x */ | ||
1315 | ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); | ||
1316 | if (ret) { | ||
1317 | printk(KERN_INFO "%s: first command failed - assuming card " | ||
1318 | "does not have primary firmware\n", dev_info); | ||
1319 | } | ||
1320 | |||
1321 | if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1322 | /* EvStat has Cmd bit set in some cases, so retry once if no | ||
1323 | * wait was needed */ | ||
1324 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1325 | printk(KERN_DEBUG "%s: init command completed too quickly - " | ||
1326 | "retrying\n", dev->name); | ||
1327 | first = 0; | ||
1328 | goto init; | ||
1329 | } | ||
1330 | |||
1331 | start = jiffies; | ||
1332 | delay = jiffies + HFA384X_INIT_TIMEOUT; | ||
1333 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
1334 | time_before(jiffies, delay)) | ||
1335 | yield(); | ||
1336 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1337 | printk(KERN_DEBUG "%s: assuming no Primary image in " | ||
1338 | "flash - card initialization not completed\n", | ||
1339 | dev_info); | ||
1340 | local->no_pri = 1; | ||
1341 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1342 | if (local->sram_type == -1) | ||
1343 | local->sram_type = prism2_get_ram_size(local); | ||
1344 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1345 | return 1; | ||
1346 | } | ||
1347 | local->no_pri = 0; | ||
1348 | printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", | ||
1349 | (jiffies - start) * 1000 / HZ); | ||
1350 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | |||
1355 | static int prism2_hw_init2(struct net_device *dev, int initial) | ||
1356 | { | ||
1357 | struct hostap_interface *iface; | ||
1358 | local_info_t *local; | ||
1359 | int i; | ||
1360 | |||
1361 | iface = netdev_priv(dev); | ||
1362 | local = iface->local; | ||
1363 | |||
1364 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1365 | kfree(local->pda); | ||
1366 | if (local->no_pri) | ||
1367 | local->pda = NULL; | ||
1368 | else | ||
1369 | local->pda = prism2_read_pda(dev); | ||
1370 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1371 | |||
1372 | hfa384x_disable_interrupts(dev); | ||
1373 | |||
1374 | #ifndef final_version | ||
1375 | HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); | ||
1376 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
1377 | printk("SWSUPPORT0 write/read failed: %04X != %04X\n", | ||
1378 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); | ||
1379 | goto failed; | ||
1380 | } | ||
1381 | #endif | ||
1382 | |||
1383 | if (initial || local->pri_only) { | ||
1384 | hfa384x_events_only_cmd(dev); | ||
1385 | /* get card version information */ | ||
1386 | if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || | ||
1387 | prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { | ||
1388 | hfa384x_disable_interrupts(dev); | ||
1389 | goto failed; | ||
1390 | } | ||
1391 | |||
1392 | if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { | ||
1393 | printk(KERN_DEBUG "%s: Failed to read STA f/w version " | ||
1394 | "- only Primary f/w present\n", dev->name); | ||
1395 | local->pri_only = 1; | ||
1396 | return 0; | ||
1397 | } | ||
1398 | local->pri_only = 0; | ||
1399 | hfa384x_disable_interrupts(dev); | ||
1400 | } | ||
1401 | |||
1402 | /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and | ||
1403 | * enable interrupts before this. This would also require some sort of | ||
1404 | * sleeping AllocEv waiting */ | ||
1405 | |||
1406 | /* allocate TX FIDs */ | ||
1407 | local->txfid_len = PRISM2_TXFID_LEN; | ||
1408 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) { | ||
1409 | local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); | ||
1410 | if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { | ||
1411 | local->txfid[i] = hfa384x_allocate_fid(dev, 1600); | ||
1412 | if (local->txfid[i] != 0xffff) { | ||
1413 | printk(KERN_DEBUG "%s: Using shorter TX FID " | ||
1414 | "(1600 bytes)\n", dev->name); | ||
1415 | local->txfid_len = 1600; | ||
1416 | } | ||
1417 | } | ||
1418 | if (local->txfid[i] == 0xffff) | ||
1419 | goto failed; | ||
1420 | local->intransmitfid[i] = PRISM2_TXFID_EMPTY; | ||
1421 | } | ||
1422 | |||
1423 | hfa384x_events_only_cmd(dev); | ||
1424 | |||
1425 | if (initial) { | ||
1426 | struct list_head *ptr; | ||
1427 | prism2_check_sta_fw_version(local); | ||
1428 | |||
1429 | if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, | ||
1430 | &dev->dev_addr, 6, 1) < 0) { | ||
1431 | printk("%s: could not get own MAC address\n", | ||
1432 | dev->name); | ||
1433 | } | ||
1434 | list_for_each(ptr, &local->hostap_interfaces) { | ||
1435 | iface = list_entry(ptr, struct hostap_interface, list); | ||
1436 | memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN); | ||
1437 | } | ||
1438 | } else if (local->fw_ap) | ||
1439 | prism2_check_sta_fw_version(local); | ||
1440 | |||
1441 | prism2_setup_rids(dev); | ||
1442 | |||
1443 | /* MAC is now configured, but port 0 is not yet enabled */ | ||
1444 | return 0; | ||
1445 | |||
1446 | failed: | ||
1447 | if (!local->no_pri) | ||
1448 | printk(KERN_WARNING "%s: Initialization failed\n", dev_info); | ||
1449 | return 1; | ||
1450 | } | ||
1451 | |||
1452 | |||
1453 | static int prism2_hw_enable(struct net_device *dev, int initial) | ||
1454 | { | ||
1455 | struct hostap_interface *iface; | ||
1456 | local_info_t *local; | ||
1457 | int was_resetting; | ||
1458 | |||
1459 | iface = netdev_priv(dev); | ||
1460 | local = iface->local; | ||
1461 | was_resetting = local->hw_resetting; | ||
1462 | |||
1463 | if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { | ||
1464 | printk("%s: MAC port 0 enabling failed\n", dev->name); | ||
1465 | return 1; | ||
1466 | } | ||
1467 | |||
1468 | local->hw_ready = 1; | ||
1469 | local->hw_reset_tries = 0; | ||
1470 | local->hw_resetting = 0; | ||
1471 | hfa384x_enable_interrupts(dev); | ||
1472 | |||
1473 | /* at least D-Link DWL-650 seems to require additional port reset | ||
1474 | * before it starts acting as an AP, so reset port automatically | ||
1475 | * here just in case */ | ||
1476 | if (initial && prism2_reset_port(dev)) { | ||
1477 | printk("%s: MAC port 0 reseting failed\n", dev->name); | ||
1478 | return 1; | ||
1479 | } | ||
1480 | |||
1481 | if (was_resetting && netif_queue_stopped(dev)) { | ||
1482 | /* If hw_reset() was called during pending transmit, netif | ||
1483 | * queue was stopped. Wake it up now since the wlan card has | ||
1484 | * been resetted. */ | ||
1485 | netif_wake_queue(dev); | ||
1486 | } | ||
1487 | |||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | static int prism2_hw_config(struct net_device *dev, int initial) | ||
1493 | { | ||
1494 | struct hostap_interface *iface; | ||
1495 | local_info_t *local; | ||
1496 | |||
1497 | iface = netdev_priv(dev); | ||
1498 | local = iface->local; | ||
1499 | |||
1500 | if (local->hw_downloading) | ||
1501 | return 1; | ||
1502 | |||
1503 | if (prism2_hw_init(dev, initial)) { | ||
1504 | return local->no_pri ? 0 : 1; | ||
1505 | } | ||
1506 | |||
1507 | if (prism2_hw_init2(dev, initial)) | ||
1508 | return 1; | ||
1509 | |||
1510 | /* Enable firmware if secondary image is loaded and at least one of the | ||
1511 | * netdevices is up. */ | ||
1512 | if (!local->pri_only && | ||
1513 | (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { | ||
1514 | if (!local->dev_enabled) | ||
1515 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
1516 | local->dev_enabled = 1; | ||
1517 | return prism2_hw_enable(dev, initial); | ||
1518 | } | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | |||
1524 | static void prism2_hw_shutdown(struct net_device *dev, int no_disable) | ||
1525 | { | ||
1526 | struct hostap_interface *iface; | ||
1527 | local_info_t *local; | ||
1528 | |||
1529 | iface = netdev_priv(dev); | ||
1530 | local = iface->local; | ||
1531 | |||
1532 | /* Allow only command completion events during disable */ | ||
1533 | hfa384x_events_only_cmd(dev); | ||
1534 | |||
1535 | local->hw_ready = 0; | ||
1536 | if (local->dev_enabled) | ||
1537 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
1538 | local->dev_enabled = 0; | ||
1539 | |||
1540 | if (local->func->card_present && !local->func->card_present(local)) { | ||
1541 | printk(KERN_DEBUG "%s: card already removed or not configured " | ||
1542 | "during shutdown\n", dev->name); | ||
1543 | return; | ||
1544 | } | ||
1545 | |||
1546 | if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && | ||
1547 | hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) | ||
1548 | printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); | ||
1549 | |||
1550 | hfa384x_disable_interrupts(dev); | ||
1551 | |||
1552 | if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) | ||
1553 | hfa384x_events_only_cmd(dev); | ||
1554 | else | ||
1555 | prism2_clear_cmd_queue(local); | ||
1556 | } | ||
1557 | |||
1558 | |||
1559 | static void prism2_hw_reset(struct net_device *dev) | ||
1560 | { | ||
1561 | struct hostap_interface *iface; | ||
1562 | local_info_t *local; | ||
1563 | |||
1564 | #if 0 | ||
1565 | static long last_reset = 0; | ||
1566 | |||
1567 | /* do not reset card more than once per second to avoid ending up in a | ||
1568 | * busy loop reseting the card */ | ||
1569 | if (time_before_eq(jiffies, last_reset + HZ)) | ||
1570 | return; | ||
1571 | last_reset = jiffies; | ||
1572 | #endif | ||
1573 | |||
1574 | iface = netdev_priv(dev); | ||
1575 | local = iface->local; | ||
1576 | |||
1577 | if (in_interrupt()) { | ||
1578 | printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called " | ||
1579 | "in interrupt context\n", dev->name); | ||
1580 | return; | ||
1581 | } | ||
1582 | |||
1583 | if (local->hw_downloading) | ||
1584 | return; | ||
1585 | |||
1586 | if (local->hw_resetting) { | ||
1587 | printk(KERN_WARNING "%s: %s: already resetting card - " | ||
1588 | "ignoring reset request\n", dev_info, dev->name); | ||
1589 | return; | ||
1590 | } | ||
1591 | |||
1592 | local->hw_reset_tries++; | ||
1593 | if (local->hw_reset_tries > 10) { | ||
1594 | printk(KERN_WARNING "%s: too many reset tries, skipping\n", | ||
1595 | dev->name); | ||
1596 | return; | ||
1597 | } | ||
1598 | |||
1599 | printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); | ||
1600 | hfa384x_disable_interrupts(dev); | ||
1601 | local->hw_resetting = 1; | ||
1602 | if (local->func->cor_sreset) { | ||
1603 | /* Host system seems to hang in some cases with high traffic | ||
1604 | * load or shared interrupts during COR sreset. Disable shared | ||
1605 | * interrupts during reset to avoid these crashes. COS sreset | ||
1606 | * takes quite a long time, so it is unfortunate that this | ||
1607 | * seems to be needed. Anyway, I do not know of any better way | ||
1608 | * of avoiding the crash. */ | ||
1609 | disable_irq(dev->irq); | ||
1610 | local->func->cor_sreset(local); | ||
1611 | enable_irq(dev->irq); | ||
1612 | } | ||
1613 | prism2_hw_shutdown(dev, 1); | ||
1614 | prism2_hw_config(dev, 0); | ||
1615 | local->hw_resetting = 0; | ||
1616 | |||
1617 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1618 | if (local->dl_pri) { | ||
1619 | printk(KERN_DEBUG "%s: persistent download of primary " | ||
1620 | "firmware\n", dev->name); | ||
1621 | if (prism2_download_genesis(local, local->dl_pri) < 0) | ||
1622 | printk(KERN_WARNING "%s: download (PRI) failed\n", | ||
1623 | dev->name); | ||
1624 | } | ||
1625 | |||
1626 | if (local->dl_sec) { | ||
1627 | printk(KERN_DEBUG "%s: persistent download of secondary " | ||
1628 | "firmware\n", dev->name); | ||
1629 | if (prism2_download_volatile(local, local->dl_sec) < 0) | ||
1630 | printk(KERN_WARNING "%s: download (SEC) failed\n", | ||
1631 | dev->name); | ||
1632 | } | ||
1633 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1634 | |||
1635 | /* TODO: restore beacon TIM bits for STAs that have buffered frames */ | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | static void prism2_schedule_reset(local_info_t *local) | ||
1640 | { | ||
1641 | schedule_work(&local->reset_queue); | ||
1642 | } | ||
1643 | |||
1644 | |||
1645 | /* Called only as scheduled task after noticing card timeout in interrupt | ||
1646 | * context */ | ||
1647 | static void handle_reset_queue(void *data) | ||
1648 | { | ||
1649 | local_info_t *local = (local_info_t *) data; | ||
1650 | |||
1651 | printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); | ||
1652 | prism2_hw_reset(local->dev); | ||
1653 | |||
1654 | if (netif_queue_stopped(local->dev)) { | ||
1655 | int i; | ||
1656 | |||
1657 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) | ||
1658 | if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { | ||
1659 | PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " | ||
1660 | "wake up queue\n"); | ||
1661 | netif_wake_queue(local->dev); | ||
1662 | break; | ||
1663 | } | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | |||
1668 | static int prism2_get_txfid_idx(local_info_t *local) | ||
1669 | { | ||
1670 | int idx, end; | ||
1671 | unsigned long flags; | ||
1672 | |||
1673 | spin_lock_irqsave(&local->txfidlock, flags); | ||
1674 | end = idx = local->next_txfid; | ||
1675 | do { | ||
1676 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1677 | local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; | ||
1678 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1679 | return idx; | ||
1680 | } | ||
1681 | idx++; | ||
1682 | if (idx >= PRISM2_TXFID_COUNT) | ||
1683 | idx = 0; | ||
1684 | } while (idx != end); | ||
1685 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1686 | |||
1687 | PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " | ||
1688 | "packet dropped\n"); | ||
1689 | local->stats.tx_dropped++; | ||
1690 | |||
1691 | return -1; | ||
1692 | } | ||
1693 | |||
1694 | |||
1695 | /* Called only from hardware IRQ */ | ||
1696 | static void prism2_transmit_cb(struct net_device *dev, long context, | ||
1697 | u16 resp0, u16 res) | ||
1698 | { | ||
1699 | struct hostap_interface *iface; | ||
1700 | local_info_t *local; | ||
1701 | int idx = (int) context; | ||
1702 | |||
1703 | iface = netdev_priv(dev); | ||
1704 | local = iface->local; | ||
1705 | |||
1706 | if (res) { | ||
1707 | printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", | ||
1708 | dev->name, res); | ||
1709 | return; | ||
1710 | } | ||
1711 | |||
1712 | if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { | ||
1713 | printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " | ||
1714 | "idx=%d\n", dev->name, idx); | ||
1715 | return; | ||
1716 | } | ||
1717 | |||
1718 | if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1719 | printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " | ||
1720 | "with no pending transmit\n", dev->name); | ||
1721 | } | ||
1722 | |||
1723 | if (netif_queue_stopped(dev)) { | ||
1724 | /* ready for next TX, so wake up queue that was stopped in | ||
1725 | * prism2_transmit() */ | ||
1726 | netif_wake_queue(dev); | ||
1727 | } | ||
1728 | |||
1729 | spin_lock(&local->txfidlock); | ||
1730 | |||
1731 | /* With reclaim, Resp0 contains new txfid for transmit; the old txfid | ||
1732 | * will be automatically allocated for the next TX frame */ | ||
1733 | local->intransmitfid[idx] = resp0; | ||
1734 | |||
1735 | PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " | ||
1736 | "resp0=0x%04x, transmit_txfid=0x%04x\n", | ||
1737 | dev->name, idx, local->txfid[idx], | ||
1738 | resp0, local->intransmitfid[local->next_txfid]); | ||
1739 | |||
1740 | idx++; | ||
1741 | if (idx >= PRISM2_TXFID_COUNT) | ||
1742 | idx = 0; | ||
1743 | local->next_txfid = idx; | ||
1744 | |||
1745 | /* check if all TX buffers are occupied */ | ||
1746 | do { | ||
1747 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1748 | spin_unlock(&local->txfidlock); | ||
1749 | return; | ||
1750 | } | ||
1751 | idx++; | ||
1752 | if (idx >= PRISM2_TXFID_COUNT) | ||
1753 | idx = 0; | ||
1754 | } while (idx != local->next_txfid); | ||
1755 | spin_unlock(&local->txfidlock); | ||
1756 | |||
1757 | /* no empty TX buffers, stop queue */ | ||
1758 | netif_stop_queue(dev); | ||
1759 | } | ||
1760 | |||
1761 | |||
1762 | /* Called only from software IRQ if PCI bus master is not used (with bus master | ||
1763 | * this can be called both from software and hardware IRQ) */ | ||
1764 | static int prism2_transmit(struct net_device *dev, int idx) | ||
1765 | { | ||
1766 | struct hostap_interface *iface; | ||
1767 | local_info_t *local; | ||
1768 | int res; | ||
1769 | |||
1770 | iface = netdev_priv(dev); | ||
1771 | local = iface->local; | ||
1772 | |||
1773 | /* The driver tries to stop netif queue so that there would not be | ||
1774 | * more than one attempt to transmit frames going on; check that this | ||
1775 | * is really the case */ | ||
1776 | |||
1777 | if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1778 | printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " | ||
1779 | "when previous TX was pending\n", dev->name); | ||
1780 | return -1; | ||
1781 | } | ||
1782 | |||
1783 | /* stop the queue for the time that transmit is pending */ | ||
1784 | netif_stop_queue(dev); | ||
1785 | |||
1786 | /* transmit packet */ | ||
1787 | res = hfa384x_cmd_callback( | ||
1788 | dev, | ||
1789 | HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, | ||
1790 | local->txfid[idx], | ||
1791 | prism2_transmit_cb, (long) idx); | ||
1792 | |||
1793 | if (res) { | ||
1794 | struct net_device_stats *stats; | ||
1795 | printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " | ||
1796 | "failed (res=%d)\n", dev->name, res); | ||
1797 | stats = hostap_get_stats(dev); | ||
1798 | stats->tx_dropped++; | ||
1799 | netif_wake_queue(dev); | ||
1800 | return -1; | ||
1801 | } | ||
1802 | dev->trans_start = jiffies; | ||
1803 | |||
1804 | /* Since we did not wait for command completion, the card continues | ||
1805 | * to process on the background and we will finish handling when | ||
1806 | * command completion event is handled (prism2_cmd_ev() function) */ | ||
1807 | |||
1808 | return 0; | ||
1809 | } | ||
1810 | |||
1811 | |||
1812 | /* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and | ||
1813 | * send the payload with this descriptor) */ | ||
1814 | /* Called only from software IRQ */ | ||
1815 | static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) | ||
1816 | { | ||
1817 | struct hostap_interface *iface; | ||
1818 | local_info_t *local; | ||
1819 | struct hfa384x_tx_frame txdesc; | ||
1820 | struct hostap_skb_tx_data *meta; | ||
1821 | int hdr_len, data_len, idx, res, ret = -1; | ||
1822 | u16 tx_control, fc; | ||
1823 | |||
1824 | iface = netdev_priv(dev); | ||
1825 | local = iface->local; | ||
1826 | |||
1827 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1828 | |||
1829 | prism2_callback(local, PRISM2_CALLBACK_TX_START); | ||
1830 | |||
1831 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
1832 | !local->hw_ready || local->hw_downloading || local->pri_only) { | ||
1833 | if (net_ratelimit()) { | ||
1834 | printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" | ||
1835 | " skipping\n", dev->name); | ||
1836 | } | ||
1837 | goto fail; | ||
1838 | } | ||
1839 | |||
1840 | memset(&txdesc, 0, sizeof(txdesc)); | ||
1841 | |||
1842 | /* skb->data starts with txdesc->frame_control */ | ||
1843 | hdr_len = 24; | ||
1844 | memcpy(&txdesc.frame_control, skb->data, hdr_len); | ||
1845 | fc = le16_to_cpu(txdesc.frame_control); | ||
1846 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
1847 | (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) && | ||
1848 | skb->len >= 30) { | ||
1849 | /* Addr4 */ | ||
1850 | memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); | ||
1851 | hdr_len += ETH_ALEN; | ||
1852 | } | ||
1853 | |||
1854 | tx_control = local->tx_control; | ||
1855 | if (meta->tx_cb_idx) { | ||
1856 | tx_control |= HFA384X_TX_CTRL_TX_OK; | ||
1857 | txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx); | ||
1858 | } | ||
1859 | txdesc.tx_control = cpu_to_le16(tx_control); | ||
1860 | txdesc.tx_rate = meta->rate; | ||
1861 | |||
1862 | data_len = skb->len - hdr_len; | ||
1863 | txdesc.data_len = cpu_to_le16(data_len); | ||
1864 | txdesc.len = cpu_to_be16(data_len); | ||
1865 | |||
1866 | idx = prism2_get_txfid_idx(local); | ||
1867 | if (idx < 0) | ||
1868 | goto fail; | ||
1869 | |||
1870 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) | ||
1871 | hostap_dump_tx_header(dev->name, &txdesc); | ||
1872 | |||
1873 | spin_lock(&local->baplock); | ||
1874 | res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); | ||
1875 | |||
1876 | if (!res) | ||
1877 | res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); | ||
1878 | if (!res) | ||
1879 | res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, | ||
1880 | skb->len - hdr_len); | ||
1881 | spin_unlock(&local->baplock); | ||
1882 | |||
1883 | if (!res) | ||
1884 | res = prism2_transmit(dev, idx); | ||
1885 | if (res) { | ||
1886 | printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", | ||
1887 | dev->name); | ||
1888 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
1889 | schedule_work(&local->reset_queue); | ||
1890 | goto fail; | ||
1891 | } | ||
1892 | |||
1893 | ret = 0; | ||
1894 | |||
1895 | fail: | ||
1896 | prism2_callback(local, PRISM2_CALLBACK_TX_END); | ||
1897 | return ret; | ||
1898 | } | ||
1899 | |||
1900 | |||
1901 | /* Some SMP systems have reported number of odd errors with hostap_pci. fid | ||
1902 | * register has changed values between consecutive reads for an unknown reason. | ||
1903 | * This should really not happen, so more debugging is needed. This test | ||
1904 | * version is a big slower, but it will detect most of such register changes | ||
1905 | * and will try to get the correct fid eventually. */ | ||
1906 | #define EXTRA_FID_READ_TESTS | ||
1907 | |||
1908 | static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) | ||
1909 | { | ||
1910 | #ifdef EXTRA_FID_READ_TESTS | ||
1911 | u16 val, val2, val3; | ||
1912 | int i; | ||
1913 | |||
1914 | for (i = 0; i < 10; i++) { | ||
1915 | val = HFA384X_INW(reg); | ||
1916 | val2 = HFA384X_INW(reg); | ||
1917 | val3 = HFA384X_INW(reg); | ||
1918 | |||
1919 | if (val == val2 && val == val3) | ||
1920 | return val; | ||
1921 | |||
1922 | printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" | ||
1923 | " %04x %04x %04x\n", | ||
1924 | dev->name, i, reg, val, val2, val3); | ||
1925 | if ((val == val2 || val == val3) && val != 0) | ||
1926 | return val; | ||
1927 | if (val2 == val3 && val2 != 0) | ||
1928 | return val2; | ||
1929 | } | ||
1930 | printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " | ||
1931 | "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); | ||
1932 | return val; | ||
1933 | #else /* EXTRA_FID_READ_TESTS */ | ||
1934 | return HFA384X_INW(reg); | ||
1935 | #endif /* EXTRA_FID_READ_TESTS */ | ||
1936 | } | ||
1937 | |||
1938 | |||
1939 | /* Called only as a tasklet (software IRQ) */ | ||
1940 | static void prism2_rx(local_info_t *local) | ||
1941 | { | ||
1942 | struct net_device *dev = local->dev; | ||
1943 | int res, rx_pending = 0; | ||
1944 | u16 len, hdr_len, rxfid, status, macport; | ||
1945 | struct net_device_stats *stats; | ||
1946 | struct hfa384x_rx_frame rxdesc; | ||
1947 | struct sk_buff *skb = NULL; | ||
1948 | |||
1949 | prism2_callback(local, PRISM2_CALLBACK_RX_START); | ||
1950 | stats = hostap_get_stats(dev); | ||
1951 | |||
1952 | rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); | ||
1953 | #ifndef final_version | ||
1954 | if (rxfid == 0) { | ||
1955 | rxfid = HFA384X_INW(HFA384X_RXFID_OFF); | ||
1956 | printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", | ||
1957 | rxfid); | ||
1958 | if (rxfid == 0) { | ||
1959 | schedule_work(&local->reset_queue); | ||
1960 | goto rx_dropped; | ||
1961 | } | ||
1962 | /* try to continue with the new rxfid value */ | ||
1963 | } | ||
1964 | #endif | ||
1965 | |||
1966 | spin_lock(&local->baplock); | ||
1967 | res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); | ||
1968 | if (!res) | ||
1969 | res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); | ||
1970 | |||
1971 | if (res) { | ||
1972 | spin_unlock(&local->baplock); | ||
1973 | printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, | ||
1974 | res); | ||
1975 | if (res == -ETIMEDOUT) { | ||
1976 | schedule_work(&local->reset_queue); | ||
1977 | } | ||
1978 | goto rx_dropped; | ||
1979 | } | ||
1980 | |||
1981 | len = le16_to_cpu(rxdesc.data_len); | ||
1982 | hdr_len = sizeof(rxdesc); | ||
1983 | status = le16_to_cpu(rxdesc.status); | ||
1984 | macport = (status >> 8) & 0x07; | ||
1985 | |||
1986 | /* Drop frames with too large reported payload length. Monitor mode | ||
1987 | * seems to sometimes pass frames (e.g., ctrl::ack) with signed and | ||
1988 | * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for | ||
1989 | * macport 7 */ | ||
1990 | if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { | ||
1991 | if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { | ||
1992 | if (len >= (u16) -14) { | ||
1993 | hdr_len -= 65535 - len; | ||
1994 | hdr_len--; | ||
1995 | } | ||
1996 | len = 0; | ||
1997 | } else { | ||
1998 | spin_unlock(&local->baplock); | ||
1999 | printk(KERN_DEBUG "%s: Received frame with invalid " | ||
2000 | "length 0x%04x\n", dev->name, len); | ||
2001 | hostap_dump_rx_header(dev->name, &rxdesc); | ||
2002 | goto rx_dropped; | ||
2003 | } | ||
2004 | } | ||
2005 | |||
2006 | skb = dev_alloc_skb(len + hdr_len); | ||
2007 | if (!skb) { | ||
2008 | spin_unlock(&local->baplock); | ||
2009 | printk(KERN_DEBUG "%s: RX failed to allocate skb\n", | ||
2010 | dev->name); | ||
2011 | goto rx_dropped; | ||
2012 | } | ||
2013 | skb->dev = dev; | ||
2014 | memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); | ||
2015 | |||
2016 | if (len > 0) | ||
2017 | res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); | ||
2018 | spin_unlock(&local->baplock); | ||
2019 | if (res) { | ||
2020 | printk(KERN_DEBUG "%s: RX failed to read " | ||
2021 | "frame data\n", dev->name); | ||
2022 | goto rx_dropped; | ||
2023 | } | ||
2024 | |||
2025 | skb_queue_tail(&local->rx_list, skb); | ||
2026 | tasklet_schedule(&local->rx_tasklet); | ||
2027 | |||
2028 | rx_exit: | ||
2029 | prism2_callback(local, PRISM2_CALLBACK_RX_END); | ||
2030 | if (!rx_pending) { | ||
2031 | HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); | ||
2032 | } | ||
2033 | |||
2034 | return; | ||
2035 | |||
2036 | rx_dropped: | ||
2037 | stats->rx_dropped++; | ||
2038 | if (skb) | ||
2039 | dev_kfree_skb(skb); | ||
2040 | goto rx_exit; | ||
2041 | } | ||
2042 | |||
2043 | |||
2044 | /* Called only as a tasklet (software IRQ) */ | ||
2045 | static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) | ||
2046 | { | ||
2047 | struct hfa384x_rx_frame *rxdesc; | ||
2048 | struct net_device *dev = skb->dev; | ||
2049 | struct hostap_80211_rx_status stats; | ||
2050 | int hdrlen, rx_hdrlen; | ||
2051 | |||
2052 | rx_hdrlen = sizeof(*rxdesc); | ||
2053 | if (skb->len < sizeof(*rxdesc)) { | ||
2054 | /* Allow monitor mode to receive shorter frames */ | ||
2055 | if (local->iw_mode == IW_MODE_MONITOR && | ||
2056 | skb->len >= sizeof(*rxdesc) - 30) { | ||
2057 | rx_hdrlen = skb->len; | ||
2058 | } else { | ||
2059 | dev_kfree_skb(skb); | ||
2060 | return; | ||
2061 | } | ||
2062 | } | ||
2063 | |||
2064 | rxdesc = (struct hfa384x_rx_frame *) skb->data; | ||
2065 | |||
2066 | if (local->frame_dump & PRISM2_DUMP_RX_HDR && | ||
2067 | skb->len >= sizeof(*rxdesc)) | ||
2068 | hostap_dump_rx_header(dev->name, rxdesc); | ||
2069 | |||
2070 | if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && | ||
2071 | (!local->monitor_allow_fcserr || | ||
2072 | local->iw_mode != IW_MODE_MONITOR)) | ||
2073 | goto drop; | ||
2074 | |||
2075 | if (skb->len > PRISM2_DATA_MAXLEN) { | ||
2076 | printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", | ||
2077 | dev->name, skb->len, PRISM2_DATA_MAXLEN); | ||
2078 | goto drop; | ||
2079 | } | ||
2080 | |||
2081 | stats.mac_time = le32_to_cpu(rxdesc->time); | ||
2082 | stats.signal = rxdesc->signal - local->rssi_to_dBm; | ||
2083 | stats.noise = rxdesc->silence - local->rssi_to_dBm; | ||
2084 | stats.rate = rxdesc->rate; | ||
2085 | |||
2086 | /* Convert Prism2 RX structure into IEEE 802.11 header */ | ||
2087 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control)); | ||
2088 | if (hdrlen > rx_hdrlen) | ||
2089 | hdrlen = rx_hdrlen; | ||
2090 | |||
2091 | memmove(skb_pull(skb, rx_hdrlen - hdrlen), | ||
2092 | &rxdesc->frame_control, hdrlen); | ||
2093 | |||
2094 | hostap_80211_rx(dev, skb, &stats); | ||
2095 | return; | ||
2096 | |||
2097 | drop: | ||
2098 | dev_kfree_skb(skb); | ||
2099 | } | ||
2100 | |||
2101 | |||
2102 | /* Called only as a tasklet (software IRQ) */ | ||
2103 | static void hostap_rx_tasklet(unsigned long data) | ||
2104 | { | ||
2105 | local_info_t *local = (local_info_t *) data; | ||
2106 | struct sk_buff *skb; | ||
2107 | |||
2108 | while ((skb = skb_dequeue(&local->rx_list)) != NULL) | ||
2109 | hostap_rx_skb(local, skb); | ||
2110 | } | ||
2111 | |||
2112 | |||
2113 | /* Called only from hardware IRQ */ | ||
2114 | static void prism2_alloc_ev(struct net_device *dev) | ||
2115 | { | ||
2116 | struct hostap_interface *iface; | ||
2117 | local_info_t *local; | ||
2118 | int idx; | ||
2119 | u16 fid; | ||
2120 | |||
2121 | iface = netdev_priv(dev); | ||
2122 | local = iface->local; | ||
2123 | |||
2124 | fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); | ||
2125 | |||
2126 | PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); | ||
2127 | |||
2128 | spin_lock(&local->txfidlock); | ||
2129 | idx = local->next_alloc; | ||
2130 | |||
2131 | do { | ||
2132 | if (local->txfid[idx] == fid) { | ||
2133 | PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", | ||
2134 | idx); | ||
2135 | |||
2136 | #ifndef final_version | ||
2137 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) | ||
2138 | printk("Already released txfid found at idx " | ||
2139 | "%d\n", idx); | ||
2140 | if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) | ||
2141 | printk("Already reserved txfid found at idx " | ||
2142 | "%d\n", idx); | ||
2143 | #endif | ||
2144 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
2145 | idx++; | ||
2146 | local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : | ||
2147 | idx; | ||
2148 | |||
2149 | if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && | ||
2150 | netif_queue_stopped(dev)) | ||
2151 | netif_wake_queue(dev); | ||
2152 | |||
2153 | spin_unlock(&local->txfidlock); | ||
2154 | return; | ||
2155 | } | ||
2156 | |||
2157 | idx++; | ||
2158 | if (idx >= PRISM2_TXFID_COUNT) | ||
2159 | idx = 0; | ||
2160 | } while (idx != local->next_alloc); | ||
2161 | |||
2162 | printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " | ||
2163 | "read 0x%04x) for alloc event\n", dev->name, fid, | ||
2164 | HFA384X_INW(HFA384X_ALLOCFID_OFF)); | ||
2165 | printk(KERN_DEBUG "TXFIDs:"); | ||
2166 | for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) | ||
2167 | printk(" %04x[%04x]", local->txfid[idx], | ||
2168 | local->intransmitfid[idx]); | ||
2169 | printk("\n"); | ||
2170 | spin_unlock(&local->txfidlock); | ||
2171 | |||
2172 | /* FIX: should probably schedule reset; reference to one txfid was lost | ||
2173 | * completely.. Bad things will happen if we run out of txfids | ||
2174 | * Actually, this will cause netdev watchdog to notice TX timeout and | ||
2175 | * then card reset after all txfids have been leaked. */ | ||
2176 | } | ||
2177 | |||
2178 | |||
2179 | /* Called only as a tasklet (software IRQ) */ | ||
2180 | static void hostap_tx_callback(local_info_t *local, | ||
2181 | struct hfa384x_tx_frame *txdesc, int ok, | ||
2182 | char *payload) | ||
2183 | { | ||
2184 | u16 sw_support, hdrlen, len; | ||
2185 | struct sk_buff *skb; | ||
2186 | struct hostap_tx_callback_info *cb; | ||
2187 | |||
2188 | /* Make sure that frame was from us. */ | ||
2189 | if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) { | ||
2190 | printk(KERN_DEBUG "%s: TX callback - foreign frame\n", | ||
2191 | local->dev->name); | ||
2192 | return; | ||
2193 | } | ||
2194 | |||
2195 | sw_support = le16_to_cpu(txdesc->sw_support); | ||
2196 | |||
2197 | spin_lock(&local->lock); | ||
2198 | cb = local->tx_callback; | ||
2199 | while (cb != NULL && cb->idx != sw_support) | ||
2200 | cb = cb->next; | ||
2201 | spin_unlock(&local->lock); | ||
2202 | |||
2203 | if (cb == NULL) { | ||
2204 | printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", | ||
2205 | local->dev->name, sw_support); | ||
2206 | return; | ||
2207 | } | ||
2208 | |||
2209 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control)); | ||
2210 | len = le16_to_cpu(txdesc->data_len); | ||
2211 | skb = dev_alloc_skb(hdrlen + len); | ||
2212 | if (skb == NULL) { | ||
2213 | printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " | ||
2214 | "skb\n", local->dev->name); | ||
2215 | return; | ||
2216 | } | ||
2217 | |||
2218 | memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); | ||
2219 | if (payload) | ||
2220 | memcpy(skb_put(skb, len), payload, len); | ||
2221 | |||
2222 | skb->dev = local->dev; | ||
2223 | skb->mac.raw = skb->data; | ||
2224 | |||
2225 | cb->func(skb, ok, cb->data); | ||
2226 | } | ||
2227 | |||
2228 | |||
2229 | /* Called only as a tasklet (software IRQ) */ | ||
2230 | static int hostap_tx_compl_read(local_info_t *local, int error, | ||
2231 | struct hfa384x_tx_frame *txdesc, | ||
2232 | char **payload) | ||
2233 | { | ||
2234 | u16 fid, len; | ||
2235 | int res, ret = 0; | ||
2236 | struct net_device *dev = local->dev; | ||
2237 | |||
2238 | fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); | ||
2239 | |||
2240 | PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); | ||
2241 | |||
2242 | spin_lock(&local->baplock); | ||
2243 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2244 | if (!res) | ||
2245 | res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); | ||
2246 | if (res) { | ||
2247 | PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " | ||
2248 | "read txdesc\n", dev->name, error, fid); | ||
2249 | if (res == -ETIMEDOUT) { | ||
2250 | schedule_work(&local->reset_queue); | ||
2251 | } | ||
2252 | ret = -1; | ||
2253 | goto fail; | ||
2254 | } | ||
2255 | if (txdesc->sw_support) { | ||
2256 | len = le16_to_cpu(txdesc->data_len); | ||
2257 | if (len < PRISM2_DATA_MAXLEN) { | ||
2258 | *payload = (char *) kmalloc(len, GFP_ATOMIC); | ||
2259 | if (*payload == NULL || | ||
2260 | hfa384x_from_bap(dev, BAP0, *payload, len)) { | ||
2261 | PDEBUG(DEBUG_EXTRA, "%s: could not read TX " | ||
2262 | "frame payload\n", dev->name); | ||
2263 | kfree(*payload); | ||
2264 | *payload = NULL; | ||
2265 | ret = -1; | ||
2266 | goto fail; | ||
2267 | } | ||
2268 | } | ||
2269 | } | ||
2270 | |||
2271 | fail: | ||
2272 | spin_unlock(&local->baplock); | ||
2273 | |||
2274 | return ret; | ||
2275 | } | ||
2276 | |||
2277 | |||
2278 | /* Called only as a tasklet (software IRQ) */ | ||
2279 | static void prism2_tx_ev(local_info_t *local) | ||
2280 | { | ||
2281 | struct net_device *dev = local->dev; | ||
2282 | char *payload = NULL; | ||
2283 | struct hfa384x_tx_frame txdesc; | ||
2284 | |||
2285 | if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) | ||
2286 | goto fail; | ||
2287 | |||
2288 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) { | ||
2289 | PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " | ||
2290 | "retry_count=%d tx_rate=%d seq_ctrl=%d " | ||
2291 | "duration_id=%d\n", | ||
2292 | dev->name, le16_to_cpu(txdesc.status), | ||
2293 | txdesc.retry_count, txdesc.tx_rate, | ||
2294 | le16_to_cpu(txdesc.seq_ctrl), | ||
2295 | le16_to_cpu(txdesc.duration_id)); | ||
2296 | } | ||
2297 | |||
2298 | if (txdesc.sw_support) | ||
2299 | hostap_tx_callback(local, &txdesc, 1, payload); | ||
2300 | kfree(payload); | ||
2301 | |||
2302 | fail: | ||
2303 | HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); | ||
2304 | } | ||
2305 | |||
2306 | |||
2307 | /* Called only as a tasklet (software IRQ) */ | ||
2308 | static void hostap_sta_tx_exc_tasklet(unsigned long data) | ||
2309 | { | ||
2310 | local_info_t *local = (local_info_t *) data; | ||
2311 | struct sk_buff *skb; | ||
2312 | |||
2313 | while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { | ||
2314 | struct hfa384x_tx_frame *txdesc = | ||
2315 | (struct hfa384x_tx_frame *) skb->data; | ||
2316 | |||
2317 | if (skb->len >= sizeof(*txdesc)) { | ||
2318 | /* Convert Prism2 RX structure into IEEE 802.11 header | ||
2319 | */ | ||
2320 | u16 fc = le16_to_cpu(txdesc->frame_control); | ||
2321 | int hdrlen = hostap_80211_get_hdrlen(fc); | ||
2322 | memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), | ||
2323 | &txdesc->frame_control, hdrlen); | ||
2324 | |||
2325 | hostap_handle_sta_tx_exc(local, skb); | ||
2326 | } | ||
2327 | dev_kfree_skb(skb); | ||
2328 | } | ||
2329 | } | ||
2330 | |||
2331 | |||
2332 | /* Called only as a tasklet (software IRQ) */ | ||
2333 | static void prism2_txexc(local_info_t *local) | ||
2334 | { | ||
2335 | struct net_device *dev = local->dev; | ||
2336 | u16 status, fc; | ||
2337 | int show_dump, res; | ||
2338 | char *payload = NULL; | ||
2339 | struct hfa384x_tx_frame txdesc; | ||
2340 | |||
2341 | show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; | ||
2342 | local->stats.tx_errors++; | ||
2343 | |||
2344 | res = hostap_tx_compl_read(local, 1, &txdesc, &payload); | ||
2345 | HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); | ||
2346 | if (res) | ||
2347 | return; | ||
2348 | |||
2349 | status = le16_to_cpu(txdesc.status); | ||
2350 | |||
2351 | /* We produce a TXDROP event only for retry or lifetime | ||
2352 | * exceeded, because that's the only status that really mean | ||
2353 | * that this particular node went away. | ||
2354 | * Other errors means that *we* screwed up. - Jean II */ | ||
2355 | if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) | ||
2356 | { | ||
2357 | union iwreq_data wrqu; | ||
2358 | |||
2359 | /* Copy 802.11 dest address. */ | ||
2360 | memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); | ||
2361 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
2362 | wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); | ||
2363 | } else | ||
2364 | show_dump = 1; | ||
2365 | |||
2366 | if (local->iw_mode == IW_MODE_MASTER || | ||
2367 | local->iw_mode == IW_MODE_REPEAT || | ||
2368 | local->wds_type & HOSTAP_WDS_AP_CLIENT) { | ||
2369 | struct sk_buff *skb; | ||
2370 | skb = dev_alloc_skb(sizeof(txdesc)); | ||
2371 | if (skb) { | ||
2372 | memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, | ||
2373 | sizeof(txdesc)); | ||
2374 | skb_queue_tail(&local->sta_tx_exc_list, skb); | ||
2375 | tasklet_schedule(&local->sta_tx_exc_tasklet); | ||
2376 | } | ||
2377 | } | ||
2378 | |||
2379 | if (txdesc.sw_support) | ||
2380 | hostap_tx_callback(local, &txdesc, 0, payload); | ||
2381 | kfree(payload); | ||
2382 | |||
2383 | if (!show_dump) | ||
2384 | return; | ||
2385 | |||
2386 | PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" | ||
2387 | " tx_control=%04x\n", | ||
2388 | dev->name, status, | ||
2389 | status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", | ||
2390 | status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", | ||
2391 | status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", | ||
2392 | status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", | ||
2393 | le16_to_cpu(txdesc.tx_control)); | ||
2394 | |||
2395 | fc = le16_to_cpu(txdesc.frame_control); | ||
2396 | PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " | ||
2397 | "(%s%s%s::%d%s%s)\n", | ||
2398 | txdesc.retry_count, txdesc.tx_rate, fc, | ||
2399 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "", | ||
2400 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "", | ||
2401 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "", | ||
2402 | WLAN_FC_GET_STYPE(fc) >> 4, | ||
2403 | fc & IEEE80211_FCTL_TODS ? " ToDS" : "", | ||
2404 | fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); | ||
2405 | PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" | ||
2406 | MACSTR " A4=" MACSTR "\n", | ||
2407 | MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), | ||
2408 | MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); | ||
2409 | } | ||
2410 | |||
2411 | |||
2412 | /* Called only as a tasklet (software IRQ) */ | ||
2413 | static void hostap_info_tasklet(unsigned long data) | ||
2414 | { | ||
2415 | local_info_t *local = (local_info_t *) data; | ||
2416 | struct sk_buff *skb; | ||
2417 | |||
2418 | while ((skb = skb_dequeue(&local->info_list)) != NULL) { | ||
2419 | hostap_info_process(local, skb); | ||
2420 | dev_kfree_skb(skb); | ||
2421 | } | ||
2422 | } | ||
2423 | |||
2424 | |||
2425 | /* Called only as a tasklet (software IRQ) */ | ||
2426 | static void prism2_info(local_info_t *local) | ||
2427 | { | ||
2428 | struct net_device *dev = local->dev; | ||
2429 | u16 fid; | ||
2430 | int res, left; | ||
2431 | struct hfa384x_info_frame info; | ||
2432 | struct sk_buff *skb; | ||
2433 | |||
2434 | fid = HFA384X_INW(HFA384X_INFOFID_OFF); | ||
2435 | |||
2436 | spin_lock(&local->baplock); | ||
2437 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2438 | if (!res) | ||
2439 | res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); | ||
2440 | if (res) { | ||
2441 | spin_unlock(&local->baplock); | ||
2442 | printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", | ||
2443 | fid); | ||
2444 | if (res == -ETIMEDOUT) { | ||
2445 | schedule_work(&local->reset_queue); | ||
2446 | } | ||
2447 | goto out; | ||
2448 | } | ||
2449 | |||
2450 | le16_to_cpus(&info.len); | ||
2451 | le16_to_cpus(&info.type); | ||
2452 | left = (info.len - 1) * 2; | ||
2453 | |||
2454 | if (info.len & 0x8000 || info.len == 0 || left > 2060) { | ||
2455 | /* data register seems to give 0x8000 in some error cases even | ||
2456 | * though busy bit is not set in offset register; | ||
2457 | * in addition, length must be at least 1 due to type field */ | ||
2458 | spin_unlock(&local->baplock); | ||
2459 | printk(KERN_DEBUG "%s: Received info frame with invalid " | ||
2460 | "length 0x%04x (type 0x%04x)\n", dev->name, info.len, | ||
2461 | info.type); | ||
2462 | goto out; | ||
2463 | } | ||
2464 | |||
2465 | skb = dev_alloc_skb(sizeof(info) + left); | ||
2466 | if (skb == NULL) { | ||
2467 | spin_unlock(&local->baplock); | ||
2468 | printk(KERN_DEBUG "%s: Could not allocate skb for info " | ||
2469 | "frame\n", dev->name); | ||
2470 | goto out; | ||
2471 | } | ||
2472 | |||
2473 | memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); | ||
2474 | if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) | ||
2475 | { | ||
2476 | spin_unlock(&local->baplock); | ||
2477 | printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " | ||
2478 | "len=0x%04x, type=0x%04x\n", | ||
2479 | dev->name, fid, info.len, info.type); | ||
2480 | dev_kfree_skb(skb); | ||
2481 | goto out; | ||
2482 | } | ||
2483 | spin_unlock(&local->baplock); | ||
2484 | |||
2485 | skb_queue_tail(&local->info_list, skb); | ||
2486 | tasklet_schedule(&local->info_tasklet); | ||
2487 | |||
2488 | out: | ||
2489 | HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); | ||
2490 | } | ||
2491 | |||
2492 | |||
2493 | /* Called only as a tasklet (software IRQ) */ | ||
2494 | static void hostap_bap_tasklet(unsigned long data) | ||
2495 | { | ||
2496 | local_info_t *local = (local_info_t *) data; | ||
2497 | struct net_device *dev = local->dev; | ||
2498 | u16 ev; | ||
2499 | int frames = 30; | ||
2500 | |||
2501 | if (local->func->card_present && !local->func->card_present(local)) | ||
2502 | return; | ||
2503 | |||
2504 | set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2505 | |||
2506 | /* Process all pending BAP events without generating new interrupts | ||
2507 | * for them */ | ||
2508 | while (frames-- > 0) { | ||
2509 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2510 | if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) | ||
2511 | break; | ||
2512 | if (ev & HFA384X_EV_RX) | ||
2513 | prism2_rx(local); | ||
2514 | if (ev & HFA384X_EV_INFO) | ||
2515 | prism2_info(local); | ||
2516 | if (ev & HFA384X_EV_TX) | ||
2517 | prism2_tx_ev(local); | ||
2518 | if (ev & HFA384X_EV_TXEXC) | ||
2519 | prism2_txexc(local); | ||
2520 | } | ||
2521 | |||
2522 | set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2523 | clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2524 | |||
2525 | /* Enable interrupts for new BAP events */ | ||
2526 | hfa384x_events_all(dev); | ||
2527 | clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2528 | } | ||
2529 | |||
2530 | |||
2531 | /* Called only from hardware IRQ */ | ||
2532 | static void prism2_infdrop(struct net_device *dev) | ||
2533 | { | ||
2534 | static unsigned long last_inquire = 0; | ||
2535 | |||
2536 | PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); | ||
2537 | |||
2538 | /* some firmware versions seem to get stuck with | ||
2539 | * full CommTallies in high traffic load cases; every | ||
2540 | * packet will then cause INFDROP event and CommTallies | ||
2541 | * info frame will not be sent automatically. Try to | ||
2542 | * get out of this state by inquiring CommTallies. */ | ||
2543 | if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { | ||
2544 | hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, | ||
2545 | HFA384X_INFO_COMMTALLIES, NULL, 0); | ||
2546 | last_inquire = jiffies; | ||
2547 | } | ||
2548 | } | ||
2549 | |||
2550 | |||
2551 | /* Called only from hardware IRQ */ | ||
2552 | static void prism2_ev_tick(struct net_device *dev) | ||
2553 | { | ||
2554 | struct hostap_interface *iface; | ||
2555 | local_info_t *local; | ||
2556 | u16 evstat, inten; | ||
2557 | static int prev_stuck = 0; | ||
2558 | |||
2559 | iface = netdev_priv(dev); | ||
2560 | local = iface->local; | ||
2561 | |||
2562 | if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && | ||
2563 | local->last_tick_timer) { | ||
2564 | evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2565 | inten = HFA384X_INW(HFA384X_INTEN_OFF); | ||
2566 | if (!prev_stuck) { | ||
2567 | printk(KERN_INFO "%s: SW TICK stuck? " | ||
2568 | "bits=0x%lx EvStat=%04x IntEn=%04x\n", | ||
2569 | dev->name, local->bits, evstat, inten); | ||
2570 | } | ||
2571 | local->sw_tick_stuck++; | ||
2572 | if ((evstat & HFA384X_BAP0_EVENTS) && | ||
2573 | (inten & HFA384X_BAP0_EVENTS)) { | ||
2574 | printk(KERN_INFO "%s: trying to recover from IRQ " | ||
2575 | "hang\n", dev->name); | ||
2576 | hfa384x_events_no_bap0(dev); | ||
2577 | } | ||
2578 | prev_stuck = 1; | ||
2579 | } else | ||
2580 | prev_stuck = 0; | ||
2581 | } | ||
2582 | |||
2583 | |||
2584 | /* Called only from hardware IRQ */ | ||
2585 | static inline void prism2_check_magic(local_info_t *local) | ||
2586 | { | ||
2587 | /* at least PCI Prism2.5 with bus mastering seems to sometimes | ||
2588 | * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the | ||
2589 | * register once or twice seems to get the correct value.. PCI cards | ||
2590 | * cannot anyway be removed during normal operation, so there is not | ||
2591 | * really any need for this verification with them. */ | ||
2592 | |||
2593 | #ifndef PRISM2_PCI | ||
2594 | #ifndef final_version | ||
2595 | static unsigned long last_magic_err = 0; | ||
2596 | struct net_device *dev = local->dev; | ||
2597 | |||
2598 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
2599 | if (!local->hw_ready) | ||
2600 | return; | ||
2601 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2602 | if (time_after(jiffies, last_magic_err + 10 * HZ)) { | ||
2603 | printk("%s: Interrupt, but SWSUPPORT0 does not match: " | ||
2604 | "%04X != %04X - card removed?\n", dev->name, | ||
2605 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2606 | HFA384X_MAGIC); | ||
2607 | last_magic_err = jiffies; | ||
2608 | } else if (net_ratelimit()) { | ||
2609 | printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " | ||
2610 | "MAGIC=%04x\n", dev->name, | ||
2611 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2612 | HFA384X_MAGIC); | ||
2613 | } | ||
2614 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) | ||
2615 | schedule_work(&local->reset_queue); | ||
2616 | return; | ||
2617 | } | ||
2618 | #endif /* final_version */ | ||
2619 | #endif /* !PRISM2_PCI */ | ||
2620 | } | ||
2621 | |||
2622 | |||
2623 | /* Called only from hardware IRQ */ | ||
2624 | static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
2625 | { | ||
2626 | struct net_device *dev = (struct net_device *) dev_id; | ||
2627 | struct hostap_interface *iface; | ||
2628 | local_info_t *local; | ||
2629 | int events = 0; | ||
2630 | u16 ev; | ||
2631 | |||
2632 | iface = netdev_priv(dev); | ||
2633 | local = iface->local; | ||
2634 | |||
2635 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); | ||
2636 | |||
2637 | if (local->func->card_present && !local->func->card_present(local)) { | ||
2638 | if (net_ratelimit()) { | ||
2639 | printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", | ||
2640 | dev->name); | ||
2641 | } | ||
2642 | return IRQ_HANDLED; | ||
2643 | } | ||
2644 | |||
2645 | prism2_check_magic(local); | ||
2646 | |||
2647 | for (;;) { | ||
2648 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2649 | if (ev == 0xffff) { | ||
2650 | if (local->shutdown) | ||
2651 | return IRQ_HANDLED; | ||
2652 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2653 | printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", | ||
2654 | dev->name); | ||
2655 | return IRQ_HANDLED; | ||
2656 | } | ||
2657 | |||
2658 | ev &= HFA384X_INW(HFA384X_INTEN_OFF); | ||
2659 | if (ev == 0) | ||
2660 | break; | ||
2661 | |||
2662 | if (ev & HFA384X_EV_CMD) { | ||
2663 | prism2_cmd_ev(dev); | ||
2664 | } | ||
2665 | |||
2666 | /* Above events are needed even before hw is ready, but other | ||
2667 | * events should be skipped during initialization. This may | ||
2668 | * change for AllocEv if allocate_fid is implemented without | ||
2669 | * busy waiting. */ | ||
2670 | if (!local->hw_ready || local->hw_resetting || | ||
2671 | !local->dev_enabled) { | ||
2672 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2673 | if (ev & HFA384X_EV_CMD) | ||
2674 | goto next_event; | ||
2675 | if ((ev & HFA384X_EVENT_MASK) == 0) | ||
2676 | return IRQ_HANDLED; | ||
2677 | if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && | ||
2678 | net_ratelimit()) { | ||
2679 | printk(KERN_DEBUG "%s: prism2_interrupt: hw " | ||
2680 | "not ready; skipping events 0x%04x " | ||
2681 | "(IntEn=0x%04x)%s%s%s\n", | ||
2682 | dev->name, ev, | ||
2683 | HFA384X_INW(HFA384X_INTEN_OFF), | ||
2684 | !local->hw_ready ? " (!hw_ready)" : "", | ||
2685 | local->hw_resetting ? | ||
2686 | " (hw_resetting)" : "", | ||
2687 | !local->dev_enabled ? | ||
2688 | " (!dev_enabled)" : ""); | ||
2689 | } | ||
2690 | HFA384X_OUTW(ev, HFA384X_EVACK_OFF); | ||
2691 | return IRQ_HANDLED; | ||
2692 | } | ||
2693 | |||
2694 | if (ev & HFA384X_EV_TICK) { | ||
2695 | prism2_ev_tick(dev); | ||
2696 | HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); | ||
2697 | } | ||
2698 | |||
2699 | if (ev & HFA384X_EV_ALLOC) { | ||
2700 | prism2_alloc_ev(dev); | ||
2701 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
2702 | } | ||
2703 | |||
2704 | /* Reading data from the card is quite time consuming, so do it | ||
2705 | * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed | ||
2706 | * and unmasked after needed data has been read completely. */ | ||
2707 | if (ev & HFA384X_BAP0_EVENTS) { | ||
2708 | hfa384x_events_no_bap0(dev); | ||
2709 | tasklet_schedule(&local->bap_tasklet); | ||
2710 | } | ||
2711 | |||
2712 | #ifndef final_version | ||
2713 | if (ev & HFA384X_EV_WTERR) { | ||
2714 | PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); | ||
2715 | HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); | ||
2716 | } | ||
2717 | #endif /* final_version */ | ||
2718 | |||
2719 | if (ev & HFA384X_EV_INFDROP) { | ||
2720 | prism2_infdrop(dev); | ||
2721 | HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); | ||
2722 | } | ||
2723 | |||
2724 | next_event: | ||
2725 | events++; | ||
2726 | if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { | ||
2727 | PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " | ||
2728 | "(EvStat=0x%04x)\n", | ||
2729 | PRISM2_MAX_INTERRUPT_EVENTS, | ||
2730 | HFA384X_INW(HFA384X_EVSTAT_OFF)); | ||
2731 | break; | ||
2732 | } | ||
2733 | } | ||
2734 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); | ||
2735 | return IRQ_RETVAL(events); | ||
2736 | } | ||
2737 | |||
2738 | |||
2739 | static void prism2_check_sta_fw_version(local_info_t *local) | ||
2740 | { | ||
2741 | struct hfa384x_comp_ident comp; | ||
2742 | int id, variant, major, minor; | ||
2743 | |||
2744 | if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, | ||
2745 | &comp, sizeof(comp), 1) < 0) | ||
2746 | return; | ||
2747 | |||
2748 | local->fw_ap = 0; | ||
2749 | id = le16_to_cpu(comp.id); | ||
2750 | if (id != HFA384X_COMP_ID_STA) { | ||
2751 | if (id == HFA384X_COMP_ID_FW_AP) | ||
2752 | local->fw_ap = 1; | ||
2753 | return; | ||
2754 | } | ||
2755 | |||
2756 | major = __le16_to_cpu(comp.major); | ||
2757 | minor = __le16_to_cpu(comp.minor); | ||
2758 | variant = __le16_to_cpu(comp.variant); | ||
2759 | local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); | ||
2760 | |||
2761 | /* Station firmware versions before 1.4.x seem to have a bug in | ||
2762 | * firmware-based WEP encryption when using Host AP mode, so use | ||
2763 | * host_encrypt as a default for them. Firmware version 1.4.9 is the | ||
2764 | * first one that has been seen to produce correct encryption, but the | ||
2765 | * bug might be fixed before that (although, at least 1.4.2 is broken). | ||
2766 | */ | ||
2767 | local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); | ||
2768 | |||
2769 | if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
2770 | !local->fw_encrypt_ok) { | ||
2771 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
2772 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
2773 | local->dev->name); | ||
2774 | local->host_encrypt = 1; | ||
2775 | } | ||
2776 | |||
2777 | /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken | ||
2778 | * in station firmware versions before 1.5.x. With these versions, the | ||
2779 | * driver uses a workaround with bogus frame format (4th address after | ||
2780 | * the payload). This is not compatible with other AP devices. Since | ||
2781 | * the firmware bug is fixed in the latest station firmware versions, | ||
2782 | * automatically enable standard compliant mode for cards using station | ||
2783 | * firmware version 1.5.0 or newer. */ | ||
2784 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) | ||
2785 | local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; | ||
2786 | else { | ||
2787 | printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " | ||
2788 | "workaround for firmware bug in Host AP mode WDS\n", | ||
2789 | local->dev->name); | ||
2790 | } | ||
2791 | |||
2792 | hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); | ||
2793 | } | ||
2794 | |||
2795 | |||
2796 | static void prism2_crypt_deinit_entries(local_info_t *local, int force) | ||
2797 | { | ||
2798 | struct list_head *ptr, *n; | ||
2799 | struct ieee80211_crypt_data *entry; | ||
2800 | |||
2801 | for (ptr = local->crypt_deinit_list.next, n = ptr->next; | ||
2802 | ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { | ||
2803 | entry = list_entry(ptr, struct ieee80211_crypt_data, list); | ||
2804 | |||
2805 | if (atomic_read(&entry->refcnt) != 0 && !force) | ||
2806 | continue; | ||
2807 | |||
2808 | list_del(ptr); | ||
2809 | |||
2810 | if (entry->ops) | ||
2811 | entry->ops->deinit(entry->priv); | ||
2812 | kfree(entry); | ||
2813 | } | ||
2814 | } | ||
2815 | |||
2816 | |||
2817 | static void prism2_crypt_deinit_handler(unsigned long data) | ||
2818 | { | ||
2819 | local_info_t *local = (local_info_t *) data; | ||
2820 | unsigned long flags; | ||
2821 | |||
2822 | spin_lock_irqsave(&local->lock, flags); | ||
2823 | prism2_crypt_deinit_entries(local, 0); | ||
2824 | if (!list_empty(&local->crypt_deinit_list)) { | ||
2825 | printk(KERN_DEBUG "%s: entries remaining in delayed crypt " | ||
2826 | "deletion list\n", local->dev->name); | ||
2827 | local->crypt_deinit_timer.expires = jiffies + HZ; | ||
2828 | add_timer(&local->crypt_deinit_timer); | ||
2829 | } | ||
2830 | spin_unlock_irqrestore(&local->lock, flags); | ||
2831 | |||
2832 | } | ||
2833 | |||
2834 | |||
2835 | static void hostap_passive_scan(unsigned long data) | ||
2836 | { | ||
2837 | local_info_t *local = (local_info_t *) data; | ||
2838 | struct net_device *dev = local->dev; | ||
2839 | u16 channel; | ||
2840 | |||
2841 | if (local->passive_scan_interval <= 0) | ||
2842 | return; | ||
2843 | |||
2844 | if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { | ||
2845 | int max_tries = 16; | ||
2846 | |||
2847 | /* Even though host system does not really know when the WLAN | ||
2848 | * MAC is sending frames, try to avoid changing channels for | ||
2849 | * passive scanning when a host-generated frame is being | ||
2850 | * transmitted */ | ||
2851 | if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
2852 | printk(KERN_DEBUG "%s: passive scan detected pending " | ||
2853 | "TX - delaying\n", dev->name); | ||
2854 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
2855 | add_timer(&local->passive_scan_timer); | ||
2856 | return; | ||
2857 | } | ||
2858 | |||
2859 | do { | ||
2860 | local->passive_scan_channel++; | ||
2861 | if (local->passive_scan_channel > 14) | ||
2862 | local->passive_scan_channel = 1; | ||
2863 | max_tries--; | ||
2864 | } while (!(local->channel_mask & | ||
2865 | (1 << (local->passive_scan_channel - 1))) && | ||
2866 | max_tries > 0); | ||
2867 | |||
2868 | if (max_tries == 0) { | ||
2869 | printk(KERN_INFO "%s: no allowed passive scan channels" | ||
2870 | " found\n", dev->name); | ||
2871 | return; | ||
2872 | } | ||
2873 | |||
2874 | printk(KERN_DEBUG "%s: passive scan channel %d\n", | ||
2875 | dev->name, local->passive_scan_channel); | ||
2876 | channel = local->passive_scan_channel; | ||
2877 | local->passive_scan_state = PASSIVE_SCAN_WAIT; | ||
2878 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
2879 | } else { | ||
2880 | channel = local->channel; | ||
2881 | local->passive_scan_state = PASSIVE_SCAN_LISTEN; | ||
2882 | local->passive_scan_timer.expires = jiffies + | ||
2883 | local->passive_scan_interval * HZ; | ||
2884 | } | ||
2885 | |||
2886 | if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | | ||
2887 | (HFA384X_TEST_CHANGE_CHANNEL << 8), | ||
2888 | channel, NULL, 0)) | ||
2889 | printk(KERN_ERR "%s: passive scan channel set %d " | ||
2890 | "failed\n", dev->name, channel); | ||
2891 | |||
2892 | add_timer(&local->passive_scan_timer); | ||
2893 | } | ||
2894 | |||
2895 | |||
2896 | /* Called only as a scheduled task when communications quality values should | ||
2897 | * be updated. */ | ||
2898 | static void handle_comms_qual_update(void *data) | ||
2899 | { | ||
2900 | local_info_t *local = data; | ||
2901 | prism2_update_comms_qual(local->dev); | ||
2902 | } | ||
2903 | |||
2904 | |||
2905 | /* Software watchdog - called as a timer. Hardware interrupt (Tick event) is | ||
2906 | * used to monitor that local->last_tick_timer is being updated. If not, | ||
2907 | * interrupt busy-loop is assumed and driver tries to recover by masking out | ||
2908 | * some events. */ | ||
2909 | static void hostap_tick_timer(unsigned long data) | ||
2910 | { | ||
2911 | static unsigned long last_inquire = 0; | ||
2912 | local_info_t *local = (local_info_t *) data; | ||
2913 | local->last_tick_timer = jiffies; | ||
2914 | |||
2915 | /* Inquire CommTallies every 10 seconds to keep the statistics updated | ||
2916 | * more often during low load and when using 32-bit tallies. */ | ||
2917 | if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && | ||
2918 | !local->hw_downloading && local->hw_ready && | ||
2919 | !local->hw_resetting && local->dev_enabled) { | ||
2920 | hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, | ||
2921 | HFA384X_INFO_COMMTALLIES, NULL, 0); | ||
2922 | last_inquire = jiffies; | ||
2923 | } | ||
2924 | |||
2925 | if ((local->last_comms_qual_update == 0 || | ||
2926 | time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && | ||
2927 | (local->iw_mode == IW_MODE_INFRA || | ||
2928 | local->iw_mode == IW_MODE_ADHOC)) { | ||
2929 | schedule_work(&local->comms_qual_update); | ||
2930 | } | ||
2931 | |||
2932 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
2933 | add_timer(&local->tick_timer); | ||
2934 | } | ||
2935 | |||
2936 | |||
2937 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
2938 | static int prism2_registers_proc_read(char *page, char **start, off_t off, | ||
2939 | int count, int *eof, void *data) | ||
2940 | { | ||
2941 | char *p = page; | ||
2942 | local_info_t *local = (local_info_t *) data; | ||
2943 | |||
2944 | if (off != 0) { | ||
2945 | *eof = 1; | ||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2949 | #define SHOW_REG(n) \ | ||
2950 | p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) | ||
2951 | |||
2952 | SHOW_REG(CMD); | ||
2953 | SHOW_REG(PARAM0); | ||
2954 | SHOW_REG(PARAM1); | ||
2955 | SHOW_REG(PARAM2); | ||
2956 | SHOW_REG(STATUS); | ||
2957 | SHOW_REG(RESP0); | ||
2958 | SHOW_REG(RESP1); | ||
2959 | SHOW_REG(RESP2); | ||
2960 | SHOW_REG(INFOFID); | ||
2961 | SHOW_REG(CONTROL); | ||
2962 | SHOW_REG(SELECT0); | ||
2963 | SHOW_REG(SELECT1); | ||
2964 | SHOW_REG(OFFSET0); | ||
2965 | SHOW_REG(OFFSET1); | ||
2966 | SHOW_REG(RXFID); | ||
2967 | SHOW_REG(ALLOCFID); | ||
2968 | SHOW_REG(TXCOMPLFID); | ||
2969 | SHOW_REG(SWSUPPORT0); | ||
2970 | SHOW_REG(SWSUPPORT1); | ||
2971 | SHOW_REG(SWSUPPORT2); | ||
2972 | SHOW_REG(EVSTAT); | ||
2973 | SHOW_REG(INTEN); | ||
2974 | SHOW_REG(EVACK); | ||
2975 | /* Do not read data registers, because they change the state of the | ||
2976 | * MAC (offset += 2) */ | ||
2977 | /* SHOW_REG(DATA0); */ | ||
2978 | /* SHOW_REG(DATA1); */ | ||
2979 | SHOW_REG(AUXPAGE); | ||
2980 | SHOW_REG(AUXOFFSET); | ||
2981 | /* SHOW_REG(AUXDATA); */ | ||
2982 | #ifdef PRISM2_PCI | ||
2983 | SHOW_REG(PCICOR); | ||
2984 | SHOW_REG(PCIHCR); | ||
2985 | SHOW_REG(PCI_M0_ADDRH); | ||
2986 | SHOW_REG(PCI_M0_ADDRL); | ||
2987 | SHOW_REG(PCI_M0_LEN); | ||
2988 | SHOW_REG(PCI_M0_CTL); | ||
2989 | SHOW_REG(PCI_STATUS); | ||
2990 | SHOW_REG(PCI_M1_ADDRH); | ||
2991 | SHOW_REG(PCI_M1_ADDRL); | ||
2992 | SHOW_REG(PCI_M1_LEN); | ||
2993 | SHOW_REG(PCI_M1_CTL); | ||
2994 | #endif /* PRISM2_PCI */ | ||
2995 | |||
2996 | return (p - page); | ||
2997 | } | ||
2998 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
2999 | |||
3000 | |||
3001 | struct set_tim_data { | ||
3002 | struct list_head list; | ||
3003 | int aid; | ||
3004 | int set; | ||
3005 | }; | ||
3006 | |||
3007 | static int prism2_set_tim(struct net_device *dev, int aid, int set) | ||
3008 | { | ||
3009 | struct list_head *ptr; | ||
3010 | struct set_tim_data *new_entry; | ||
3011 | struct hostap_interface *iface; | ||
3012 | local_info_t *local; | ||
3013 | |||
3014 | iface = netdev_priv(dev); | ||
3015 | local = iface->local; | ||
3016 | |||
3017 | new_entry = (struct set_tim_data *) | ||
3018 | kmalloc(sizeof(*new_entry), GFP_ATOMIC); | ||
3019 | if (new_entry == NULL) { | ||
3020 | printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n", | ||
3021 | local->dev->name); | ||
3022 | return -ENOMEM; | ||
3023 | } | ||
3024 | memset(new_entry, 0, sizeof(*new_entry)); | ||
3025 | new_entry->aid = aid; | ||
3026 | new_entry->set = set; | ||
3027 | |||
3028 | spin_lock_bh(&local->set_tim_lock); | ||
3029 | list_for_each(ptr, &local->set_tim_list) { | ||
3030 | struct set_tim_data *entry = | ||
3031 | list_entry(ptr, struct set_tim_data, list); | ||
3032 | if (entry->aid == aid) { | ||
3033 | PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " | ||
3034 | "set=%d ==> %d\n", | ||
3035 | local->dev->name, aid, entry->set, set); | ||
3036 | entry->set = set; | ||
3037 | kfree(new_entry); | ||
3038 | new_entry = NULL; | ||
3039 | break; | ||
3040 | } | ||
3041 | } | ||
3042 | if (new_entry) | ||
3043 | list_add_tail(&new_entry->list, &local->set_tim_list); | ||
3044 | spin_unlock_bh(&local->set_tim_lock); | ||
3045 | |||
3046 | schedule_work(&local->set_tim_queue); | ||
3047 | |||
3048 | return 0; | ||
3049 | } | ||
3050 | |||
3051 | |||
3052 | static void handle_set_tim_queue(void *data) | ||
3053 | { | ||
3054 | local_info_t *local = (local_info_t *) data; | ||
3055 | struct set_tim_data *entry; | ||
3056 | u16 val; | ||
3057 | |||
3058 | for (;;) { | ||
3059 | entry = NULL; | ||
3060 | spin_lock_bh(&local->set_tim_lock); | ||
3061 | if (!list_empty(&local->set_tim_list)) { | ||
3062 | entry = list_entry(local->set_tim_list.next, | ||
3063 | struct set_tim_data, list); | ||
3064 | list_del(&entry->list); | ||
3065 | } | ||
3066 | spin_unlock_bh(&local->set_tim_lock); | ||
3067 | if (!entry) | ||
3068 | break; | ||
3069 | |||
3070 | PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", | ||
3071 | local->dev->name, entry->aid, entry->set); | ||
3072 | |||
3073 | val = entry->aid; | ||
3074 | if (entry->set) | ||
3075 | val |= 0x8000; | ||
3076 | if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { | ||
3077 | printk(KERN_DEBUG "%s: set_tim failed (aid=%d " | ||
3078 | "set=%d)\n", | ||
3079 | local->dev->name, entry->aid, entry->set); | ||
3080 | } | ||
3081 | |||
3082 | kfree(entry); | ||
3083 | } | ||
3084 | } | ||
3085 | |||
3086 | |||
3087 | static void prism2_clear_set_tim_queue(local_info_t *local) | ||
3088 | { | ||
3089 | struct list_head *ptr, *n; | ||
3090 | |||
3091 | list_for_each_safe(ptr, n, &local->set_tim_list) { | ||
3092 | struct set_tim_data *entry; | ||
3093 | entry = list_entry(ptr, struct set_tim_data, list); | ||
3094 | list_del(&entry->list); | ||
3095 | kfree(entry); | ||
3096 | } | ||
3097 | } | ||
3098 | |||
3099 | |||
3100 | static struct net_device * | ||
3101 | prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, | ||
3102 | struct device *sdev) | ||
3103 | { | ||
3104 | struct net_device *dev; | ||
3105 | struct hostap_interface *iface; | ||
3106 | struct local_info *local; | ||
3107 | int len, i, ret; | ||
3108 | |||
3109 | if (funcs == NULL) | ||
3110 | return NULL; | ||
3111 | |||
3112 | len = strlen(dev_template); | ||
3113 | if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { | ||
3114 | printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", | ||
3115 | dev_template); | ||
3116 | return NULL; | ||
3117 | } | ||
3118 | |||
3119 | len = sizeof(struct hostap_interface) + | ||
3120 | 3 + sizeof(struct local_info) + | ||
3121 | 3 + sizeof(struct ap_data); | ||
3122 | |||
3123 | dev = alloc_etherdev(len); | ||
3124 | if (dev == NULL) | ||
3125 | return NULL; | ||
3126 | |||
3127 | iface = netdev_priv(dev); | ||
3128 | local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); | ||
3129 | local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); | ||
3130 | local->dev = iface->dev = dev; | ||
3131 | iface->local = local; | ||
3132 | iface->type = HOSTAP_INTERFACE_MASTER; | ||
3133 | INIT_LIST_HEAD(&local->hostap_interfaces); | ||
3134 | |||
3135 | local->hw_module = THIS_MODULE; | ||
3136 | |||
3137 | #ifdef PRISM2_IO_DEBUG | ||
3138 | local->io_debug_enabled = 1; | ||
3139 | #endif /* PRISM2_IO_DEBUG */ | ||
3140 | |||
3141 | local->func = funcs; | ||
3142 | local->func->cmd = hfa384x_cmd; | ||
3143 | local->func->read_regs = hfa384x_read_regs; | ||
3144 | local->func->get_rid = hfa384x_get_rid; | ||
3145 | local->func->set_rid = hfa384x_set_rid; | ||
3146 | local->func->hw_enable = prism2_hw_enable; | ||
3147 | local->func->hw_config = prism2_hw_config; | ||
3148 | local->func->hw_reset = prism2_hw_reset; | ||
3149 | local->func->hw_shutdown = prism2_hw_shutdown; | ||
3150 | local->func->reset_port = prism2_reset_port; | ||
3151 | local->func->schedule_reset = prism2_schedule_reset; | ||
3152 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3153 | local->func->read_aux = prism2_download_aux_dump; | ||
3154 | local->func->download = prism2_download; | ||
3155 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3156 | local->func->tx = prism2_tx_80211; | ||
3157 | local->func->set_tim = prism2_set_tim; | ||
3158 | local->func->need_tx_headroom = 0; /* no need to add txdesc in | ||
3159 | * skb->data (FIX: maybe for DMA bus | ||
3160 | * mastering? */ | ||
3161 | |||
3162 | local->mtu = mtu; | ||
3163 | |||
3164 | rwlock_init(&local->iface_lock); | ||
3165 | spin_lock_init(&local->txfidlock); | ||
3166 | spin_lock_init(&local->cmdlock); | ||
3167 | spin_lock_init(&local->baplock); | ||
3168 | spin_lock_init(&local->lock); | ||
3169 | init_MUTEX(&local->rid_bap_sem); | ||
3170 | |||
3171 | if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) | ||
3172 | card_idx = 0; | ||
3173 | local->card_idx = card_idx; | ||
3174 | |||
3175 | len = strlen(essid); | ||
3176 | memcpy(local->essid, essid, | ||
3177 | len > MAX_SSID_LEN ? MAX_SSID_LEN : len); | ||
3178 | local->essid[MAX_SSID_LEN] = '\0'; | ||
3179 | i = GET_INT_PARM(iw_mode, card_idx); | ||
3180 | if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || | ||
3181 | i == IW_MODE_MONITOR) { | ||
3182 | local->iw_mode = i; | ||
3183 | } else { | ||
3184 | printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " | ||
3185 | "IW_MODE_MASTER\n", i); | ||
3186 | local->iw_mode = IW_MODE_MASTER; | ||
3187 | } | ||
3188 | local->channel = GET_INT_PARM(channel, card_idx); | ||
3189 | local->beacon_int = GET_INT_PARM(beacon_int, card_idx); | ||
3190 | local->dtim_period = GET_INT_PARM(dtim_period, card_idx); | ||
3191 | local->wds_max_connections = 16; | ||
3192 | local->tx_control = HFA384X_TX_CTRL_FLAGS; | ||
3193 | local->manual_retry_count = -1; | ||
3194 | local->rts_threshold = 2347; | ||
3195 | local->fragm_threshold = 2346; | ||
3196 | local->rssi_to_dBm = 100; /* default; to be overriden by | ||
3197 | * cnfDbmAdjust, if available */ | ||
3198 | local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; | ||
3199 | local->sram_type = -1; | ||
3200 | local->scan_channel_mask = 0xffff; | ||
3201 | |||
3202 | /* Initialize task queue structures */ | ||
3203 | INIT_WORK(&local->reset_queue, handle_reset_queue, local); | ||
3204 | INIT_WORK(&local->set_multicast_list_queue, | ||
3205 | hostap_set_multicast_list_queue, local->dev); | ||
3206 | |||
3207 | INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local); | ||
3208 | INIT_LIST_HEAD(&local->set_tim_list); | ||
3209 | spin_lock_init(&local->set_tim_lock); | ||
3210 | |||
3211 | INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local); | ||
3212 | |||
3213 | /* Initialize tasklets for handling hardware IRQ related operations | ||
3214 | * outside hw IRQ handler */ | ||
3215 | #define HOSTAP_TASKLET_INIT(q, f, d) \ | ||
3216 | do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \ | ||
3217 | while (0) | ||
3218 | HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet, | ||
3219 | (unsigned long) local); | ||
3220 | |||
3221 | HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet, | ||
3222 | (unsigned long) local); | ||
3223 | hostap_info_init(local); | ||
3224 | |||
3225 | HOSTAP_TASKLET_INIT(&local->rx_tasklet, | ||
3226 | hostap_rx_tasklet, (unsigned long) local); | ||
3227 | skb_queue_head_init(&local->rx_list); | ||
3228 | |||
3229 | HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet, | ||
3230 | hostap_sta_tx_exc_tasklet, (unsigned long) local); | ||
3231 | skb_queue_head_init(&local->sta_tx_exc_list); | ||
3232 | |||
3233 | INIT_LIST_HEAD(&local->cmd_queue); | ||
3234 | init_waitqueue_head(&local->hostscan_wq); | ||
3235 | INIT_LIST_HEAD(&local->crypt_deinit_list); | ||
3236 | init_timer(&local->crypt_deinit_timer); | ||
3237 | local->crypt_deinit_timer.data = (unsigned long) local; | ||
3238 | local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; | ||
3239 | |||
3240 | init_timer(&local->passive_scan_timer); | ||
3241 | local->passive_scan_timer.data = (unsigned long) local; | ||
3242 | local->passive_scan_timer.function = hostap_passive_scan; | ||
3243 | |||
3244 | init_timer(&local->tick_timer); | ||
3245 | local->tick_timer.data = (unsigned long) local; | ||
3246 | local->tick_timer.function = hostap_tick_timer; | ||
3247 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
3248 | add_timer(&local->tick_timer); | ||
3249 | |||
3250 | INIT_LIST_HEAD(&local->bss_list); | ||
3251 | |||
3252 | hostap_setup_dev(dev, local, 1); | ||
3253 | local->saved_eth_header_parse = dev->hard_header_parse; | ||
3254 | |||
3255 | dev->hard_start_xmit = hostap_master_start_xmit; | ||
3256 | dev->type = ARPHRD_IEEE80211; | ||
3257 | dev->hard_header_parse = hostap_80211_header_parse; | ||
3258 | |||
3259 | rtnl_lock(); | ||
3260 | ret = dev_alloc_name(dev, "wifi%d"); | ||
3261 | SET_NETDEV_DEV(dev, sdev); | ||
3262 | if (ret >= 0) | ||
3263 | ret = register_netdevice(dev); | ||
3264 | rtnl_unlock(); | ||
3265 | if (ret < 0) { | ||
3266 | printk(KERN_WARNING "%s: register netdevice failed!\n", | ||
3267 | dev_info); | ||
3268 | goto fail; | ||
3269 | } | ||
3270 | printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); | ||
3271 | |||
3272 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3273 | create_proc_read_entry("registers", 0, local->proc, | ||
3274 | prism2_registers_proc_read, local); | ||
3275 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3276 | |||
3277 | hostap_init_data(local); | ||
3278 | return dev; | ||
3279 | |||
3280 | fail: | ||
3281 | free_netdev(dev); | ||
3282 | return NULL; | ||
3283 | } | ||
3284 | |||
3285 | |||
3286 | static int hostap_hw_ready(struct net_device *dev) | ||
3287 | { | ||
3288 | struct hostap_interface *iface; | ||
3289 | struct local_info *local; | ||
3290 | |||
3291 | iface = netdev_priv(dev); | ||
3292 | local = iface->local; | ||
3293 | local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, | ||
3294 | "", dev_template); | ||
3295 | |||
3296 | if (local->ddev) { | ||
3297 | if (local->iw_mode == IW_MODE_INFRA || | ||
3298 | local->iw_mode == IW_MODE_ADHOC) { | ||
3299 | netif_carrier_off(local->dev); | ||
3300 | netif_carrier_off(local->ddev); | ||
3301 | } | ||
3302 | hostap_init_proc(local); | ||
3303 | hostap_init_ap_proc(local); | ||
3304 | return 0; | ||
3305 | } | ||
3306 | |||
3307 | return -1; | ||
3308 | } | ||
3309 | |||
3310 | |||
3311 | static void prism2_free_local_data(struct net_device *dev) | ||
3312 | { | ||
3313 | struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; | ||
3314 | int i; | ||
3315 | struct hostap_interface *iface; | ||
3316 | struct local_info *local; | ||
3317 | struct list_head *ptr, *n; | ||
3318 | |||
3319 | if (dev == NULL) | ||
3320 | return; | ||
3321 | |||
3322 | iface = netdev_priv(dev); | ||
3323 | local = iface->local; | ||
3324 | |||
3325 | flush_scheduled_work(); | ||
3326 | |||
3327 | if (timer_pending(&local->crypt_deinit_timer)) | ||
3328 | del_timer(&local->crypt_deinit_timer); | ||
3329 | prism2_crypt_deinit_entries(local, 1); | ||
3330 | |||
3331 | if (timer_pending(&local->passive_scan_timer)) | ||
3332 | del_timer(&local->passive_scan_timer); | ||
3333 | |||
3334 | if (timer_pending(&local->tick_timer)) | ||
3335 | del_timer(&local->tick_timer); | ||
3336 | |||
3337 | prism2_clear_cmd_queue(local); | ||
3338 | |||
3339 | skb_queue_purge(&local->info_list); | ||
3340 | skb_queue_purge(&local->rx_list); | ||
3341 | skb_queue_purge(&local->sta_tx_exc_list); | ||
3342 | |||
3343 | if (local->dev_enabled) | ||
3344 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
3345 | |||
3346 | for (i = 0; i < WEP_KEYS; i++) { | ||
3347 | struct ieee80211_crypt_data *crypt = local->crypt[i]; | ||
3348 | if (crypt) { | ||
3349 | if (crypt->ops) | ||
3350 | crypt->ops->deinit(crypt->priv); | ||
3351 | kfree(crypt); | ||
3352 | local->crypt[i] = NULL; | ||
3353 | } | ||
3354 | } | ||
3355 | |||
3356 | if (local->ap != NULL) | ||
3357 | hostap_free_data(local->ap); | ||
3358 | |||
3359 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3360 | if (local->proc != NULL) | ||
3361 | remove_proc_entry("registers", local->proc); | ||
3362 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3363 | hostap_remove_proc(local); | ||
3364 | |||
3365 | tx_cb = local->tx_callback; | ||
3366 | while (tx_cb != NULL) { | ||
3367 | tx_cb_prev = tx_cb; | ||
3368 | tx_cb = tx_cb->next; | ||
3369 | kfree(tx_cb_prev); | ||
3370 | } | ||
3371 | |||
3372 | hostap_set_hostapd(local, 0, 0); | ||
3373 | hostap_set_hostapd_sta(local, 0, 0); | ||
3374 | |||
3375 | for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | ||
3376 | if (local->frag_cache[i].skb != NULL) | ||
3377 | dev_kfree_skb(local->frag_cache[i].skb); | ||
3378 | } | ||
3379 | |||
3380 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3381 | prism2_download_free_data(local->dl_pri); | ||
3382 | prism2_download_free_data(local->dl_sec); | ||
3383 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3384 | |||
3385 | list_for_each_safe(ptr, n, &local->hostap_interfaces) { | ||
3386 | iface = list_entry(ptr, struct hostap_interface, list); | ||
3387 | if (iface->type == HOSTAP_INTERFACE_MASTER) { | ||
3388 | /* special handling for this interface below */ | ||
3389 | continue; | ||
3390 | } | ||
3391 | hostap_remove_interface(iface->dev, 0, 1); | ||
3392 | } | ||
3393 | |||
3394 | prism2_clear_set_tim_queue(local); | ||
3395 | |||
3396 | list_for_each_safe(ptr, n, &local->bss_list) { | ||
3397 | struct hostap_bss_info *bss = | ||
3398 | list_entry(ptr, struct hostap_bss_info, list); | ||
3399 | kfree(bss); | ||
3400 | } | ||
3401 | |||
3402 | kfree(local->pda); | ||
3403 | kfree(local->last_scan_results); | ||
3404 | kfree(local->generic_elem); | ||
3405 | |||
3406 | unregister_netdev(local->dev); | ||
3407 | free_netdev(local->dev); | ||
3408 | } | ||
3409 | |||
3410 | |||
3411 | #ifndef PRISM2_PLX | ||
3412 | static void prism2_suspend(struct net_device *dev) | ||
3413 | { | ||
3414 | struct hostap_interface *iface; | ||
3415 | struct local_info *local; | ||
3416 | union iwreq_data wrqu; | ||
3417 | |||
3418 | iface = dev->priv; | ||
3419 | local = iface->local; | ||
3420 | |||
3421 | /* Send disconnect event, e.g., to trigger reassociation after resume | ||
3422 | * if wpa_supplicant is used. */ | ||
3423 | memset(&wrqu, 0, sizeof(wrqu)); | ||
3424 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
3425 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
3426 | |||
3427 | /* Disable hardware and firmware */ | ||
3428 | prism2_hw_shutdown(dev, 0); | ||
3429 | } | ||
3430 | #endif /* PRISM2_PLX */ | ||
3431 | |||
3432 | |||
3433 | /* These might at some point be compiled separately and used as separate | ||
3434 | * kernel modules or linked into one */ | ||
3435 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3436 | #include "hostap_download.c" | ||
3437 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3438 | |||
3439 | #ifdef PRISM2_CALLBACK | ||
3440 | /* External hostap_callback.c file can be used to, e.g., blink activity led. | ||
3441 | * This can use platform specific code and must define prism2_callback() | ||
3442 | * function (if PRISM2_CALLBACK is not defined, these function calls are not | ||
3443 | * used. */ | ||
3444 | #include "hostap_callback.c" | ||
3445 | #endif /* PRISM2_CALLBACK */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c new file mode 100644 index 000000000000..5aa998fdf1c4 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_info.c | |||
@@ -0,0 +1,499 @@ | |||
1 | /* Host AP driver Info Frame processing (part of hostap.o module) */ | ||
2 | |||
3 | |||
4 | /* Called only as a tasklet (software IRQ) */ | ||
5 | static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, | ||
6 | int left) | ||
7 | { | ||
8 | struct hfa384x_comm_tallies *tallies; | ||
9 | |||
10 | if (left < sizeof(struct hfa384x_comm_tallies)) { | ||
11 | printk(KERN_DEBUG "%s: too short (len=%d) commtallies " | ||
12 | "info frame\n", local->dev->name, left); | ||
13 | return; | ||
14 | } | ||
15 | |||
16 | tallies = (struct hfa384x_comm_tallies *) buf; | ||
17 | #define ADD_COMM_TALLIES(name) \ | ||
18 | local->comm_tallies.name += le16_to_cpu(tallies->name) | ||
19 | ADD_COMM_TALLIES(tx_unicast_frames); | ||
20 | ADD_COMM_TALLIES(tx_multicast_frames); | ||
21 | ADD_COMM_TALLIES(tx_fragments); | ||
22 | ADD_COMM_TALLIES(tx_unicast_octets); | ||
23 | ADD_COMM_TALLIES(tx_multicast_octets); | ||
24 | ADD_COMM_TALLIES(tx_deferred_transmissions); | ||
25 | ADD_COMM_TALLIES(tx_single_retry_frames); | ||
26 | ADD_COMM_TALLIES(tx_multiple_retry_frames); | ||
27 | ADD_COMM_TALLIES(tx_retry_limit_exceeded); | ||
28 | ADD_COMM_TALLIES(tx_discards); | ||
29 | ADD_COMM_TALLIES(rx_unicast_frames); | ||
30 | ADD_COMM_TALLIES(rx_multicast_frames); | ||
31 | ADD_COMM_TALLIES(rx_fragments); | ||
32 | ADD_COMM_TALLIES(rx_unicast_octets); | ||
33 | ADD_COMM_TALLIES(rx_multicast_octets); | ||
34 | ADD_COMM_TALLIES(rx_fcs_errors); | ||
35 | ADD_COMM_TALLIES(rx_discards_no_buffer); | ||
36 | ADD_COMM_TALLIES(tx_discards_wrong_sa); | ||
37 | ADD_COMM_TALLIES(rx_discards_wep_undecryptable); | ||
38 | ADD_COMM_TALLIES(rx_message_in_msg_fragments); | ||
39 | ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); | ||
40 | #undef ADD_COMM_TALLIES | ||
41 | } | ||
42 | |||
43 | |||
44 | /* Called only as a tasklet (software IRQ) */ | ||
45 | static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, | ||
46 | int left) | ||
47 | { | ||
48 | struct hfa384x_comm_tallies32 *tallies; | ||
49 | |||
50 | if (left < sizeof(struct hfa384x_comm_tallies32)) { | ||
51 | printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " | ||
52 | "info frame\n", local->dev->name, left); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | tallies = (struct hfa384x_comm_tallies32 *) buf; | ||
57 | #define ADD_COMM_TALLIES(name) \ | ||
58 | local->comm_tallies.name += le32_to_cpu(tallies->name) | ||
59 | ADD_COMM_TALLIES(tx_unicast_frames); | ||
60 | ADD_COMM_TALLIES(tx_multicast_frames); | ||
61 | ADD_COMM_TALLIES(tx_fragments); | ||
62 | ADD_COMM_TALLIES(tx_unicast_octets); | ||
63 | ADD_COMM_TALLIES(tx_multicast_octets); | ||
64 | ADD_COMM_TALLIES(tx_deferred_transmissions); | ||
65 | ADD_COMM_TALLIES(tx_single_retry_frames); | ||
66 | ADD_COMM_TALLIES(tx_multiple_retry_frames); | ||
67 | ADD_COMM_TALLIES(tx_retry_limit_exceeded); | ||
68 | ADD_COMM_TALLIES(tx_discards); | ||
69 | ADD_COMM_TALLIES(rx_unicast_frames); | ||
70 | ADD_COMM_TALLIES(rx_multicast_frames); | ||
71 | ADD_COMM_TALLIES(rx_fragments); | ||
72 | ADD_COMM_TALLIES(rx_unicast_octets); | ||
73 | ADD_COMM_TALLIES(rx_multicast_octets); | ||
74 | ADD_COMM_TALLIES(rx_fcs_errors); | ||
75 | ADD_COMM_TALLIES(rx_discards_no_buffer); | ||
76 | ADD_COMM_TALLIES(tx_discards_wrong_sa); | ||
77 | ADD_COMM_TALLIES(rx_discards_wep_undecryptable); | ||
78 | ADD_COMM_TALLIES(rx_message_in_msg_fragments); | ||
79 | ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); | ||
80 | #undef ADD_COMM_TALLIES | ||
81 | } | ||
82 | |||
83 | |||
84 | /* Called only as a tasklet (software IRQ) */ | ||
85 | static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, | ||
86 | int left) | ||
87 | { | ||
88 | if (local->tallies32) | ||
89 | prism2_info_commtallies32(local, buf, left); | ||
90 | else | ||
91 | prism2_info_commtallies16(local, buf, left); | ||
92 | } | ||
93 | |||
94 | |||
95 | #ifndef PRISM2_NO_STATION_MODES | ||
96 | #ifndef PRISM2_NO_DEBUG | ||
97 | static const char* hfa384x_linkstatus_str(u16 linkstatus) | ||
98 | { | ||
99 | switch (linkstatus) { | ||
100 | case HFA384X_LINKSTATUS_CONNECTED: | ||
101 | return "Connected"; | ||
102 | case HFA384X_LINKSTATUS_DISCONNECTED: | ||
103 | return "Disconnected"; | ||
104 | case HFA384X_LINKSTATUS_AP_CHANGE: | ||
105 | return "Access point change"; | ||
106 | case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: | ||
107 | return "Access point out of range"; | ||
108 | case HFA384X_LINKSTATUS_AP_IN_RANGE: | ||
109 | return "Access point in range"; | ||
110 | case HFA384X_LINKSTATUS_ASSOC_FAILED: | ||
111 | return "Association failed"; | ||
112 | default: | ||
113 | return "Unknown"; | ||
114 | } | ||
115 | } | ||
116 | #endif /* PRISM2_NO_DEBUG */ | ||
117 | |||
118 | |||
119 | /* Called only as a tasklet (software IRQ) */ | ||
120 | static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, | ||
121 | int left) | ||
122 | { | ||
123 | u16 val; | ||
124 | int non_sta_mode; | ||
125 | |||
126 | /* Alloc new JoinRequests to occur since LinkStatus for the previous | ||
127 | * has been received */ | ||
128 | local->last_join_time = 0; | ||
129 | |||
130 | if (left != 2) { | ||
131 | printk(KERN_DEBUG "%s: invalid linkstatus info frame " | ||
132 | "length %d\n", local->dev->name, left); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | non_sta_mode = local->iw_mode == IW_MODE_MASTER || | ||
137 | local->iw_mode == IW_MODE_REPEAT || | ||
138 | local->iw_mode == IW_MODE_MONITOR; | ||
139 | |||
140 | val = buf[0] | (buf[1] << 8); | ||
141 | if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { | ||
142 | PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", | ||
143 | local->dev->name, val, hfa384x_linkstatus_str(val)); | ||
144 | } | ||
145 | |||
146 | if (non_sta_mode) { | ||
147 | netif_carrier_on(local->dev); | ||
148 | netif_carrier_on(local->ddev); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | /* Get current BSSID later in scheduled task */ | ||
153 | set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); | ||
154 | local->prev_link_status = val; | ||
155 | schedule_work(&local->info_queue); | ||
156 | } | ||
157 | |||
158 | |||
159 | static void prism2_host_roaming(local_info_t *local) | ||
160 | { | ||
161 | struct hfa384x_join_request req; | ||
162 | struct net_device *dev = local->dev; | ||
163 | struct hfa384x_hostscan_result *selected, *entry; | ||
164 | int i; | ||
165 | unsigned long flags; | ||
166 | |||
167 | if (local->last_join_time && | ||
168 | time_before(jiffies, local->last_join_time + 10 * HZ)) { | ||
169 | PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " | ||
170 | "completed - waiting for it before issuing new one\n", | ||
171 | dev->name); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | /* ScanResults are sorted: first ESS results in decreasing signal | ||
176 | * quality then IBSS results in similar order. | ||
177 | * Trivial roaming policy: just select the first entry. | ||
178 | * This could probably be improved by adding hysteresis to limit | ||
179 | * number of handoffs, etc. | ||
180 | * | ||
181 | * Could do periodic RID_SCANREQUEST or Inquire F101 to get new | ||
182 | * ScanResults */ | ||
183 | spin_lock_irqsave(&local->lock, flags); | ||
184 | if (local->last_scan_results == NULL || | ||
185 | local->last_scan_results_count == 0) { | ||
186 | spin_unlock_irqrestore(&local->lock, flags); | ||
187 | PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", | ||
188 | dev->name); | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | selected = &local->last_scan_results[0]; | ||
193 | |||
194 | if (local->preferred_ap[0] || local->preferred_ap[1] || | ||
195 | local->preferred_ap[2] || local->preferred_ap[3] || | ||
196 | local->preferred_ap[4] || local->preferred_ap[5]) { | ||
197 | /* Try to find preferred AP */ | ||
198 | PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", | ||
199 | dev->name, MAC2STR(local->preferred_ap)); | ||
200 | for (i = 0; i < local->last_scan_results_count; i++) { | ||
201 | entry = &local->last_scan_results[i]; | ||
202 | if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) | ||
203 | { | ||
204 | PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " | ||
205 | "selection\n", dev->name); | ||
206 | selected = entry; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | memcpy(req.bssid, selected->bssid, 6); | ||
213 | req.channel = selected->chid; | ||
214 | spin_unlock_irqrestore(&local->lock, flags); | ||
215 | |||
216 | PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", | ||
217 | dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); | ||
218 | if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, | ||
219 | sizeof(req))) { | ||
220 | printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); | ||
221 | } | ||
222 | local->last_join_time = jiffies; | ||
223 | } | ||
224 | |||
225 | |||
226 | static void hostap_report_scan_complete(local_info_t *local) | ||
227 | { | ||
228 | union iwreq_data wrqu; | ||
229 | |||
230 | /* Inform user space about new scan results (just empty event, | ||
231 | * SIOCGIWSCAN can be used to fetch data */ | ||
232 | wrqu.data.length = 0; | ||
233 | wrqu.data.flags = 0; | ||
234 | wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
235 | |||
236 | /* Allow SIOCGIWSCAN handling to occur since we have received | ||
237 | * scanning result */ | ||
238 | local->scan_timestamp = 0; | ||
239 | } | ||
240 | |||
241 | |||
242 | /* Called only as a tasklet (software IRQ) */ | ||
243 | static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, | ||
244 | int left) | ||
245 | { | ||
246 | u16 *pos; | ||
247 | int new_count, i; | ||
248 | unsigned long flags; | ||
249 | struct hfa384x_scan_result *res; | ||
250 | struct hfa384x_hostscan_result *results, *prev; | ||
251 | |||
252 | if (left < 4) { | ||
253 | printk(KERN_DEBUG "%s: invalid scanresult info frame " | ||
254 | "length %d\n", local->dev->name, left); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | pos = (u16 *) buf; | ||
259 | pos++; | ||
260 | pos++; | ||
261 | left -= 4; | ||
262 | |||
263 | new_count = left / sizeof(struct hfa384x_scan_result); | ||
264 | results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), | ||
265 | GFP_ATOMIC); | ||
266 | if (results == NULL) | ||
267 | return; | ||
268 | |||
269 | /* Convert to hostscan result format. */ | ||
270 | res = (struct hfa384x_scan_result *) pos; | ||
271 | for (i = 0; i < new_count; i++) { | ||
272 | memcpy(&results[i], &res[i], | ||
273 | sizeof(struct hfa384x_scan_result)); | ||
274 | results[i].atim = 0; | ||
275 | } | ||
276 | |||
277 | spin_lock_irqsave(&local->lock, flags); | ||
278 | local->last_scan_type = PRISM2_SCAN; | ||
279 | prev = local->last_scan_results; | ||
280 | local->last_scan_results = results; | ||
281 | local->last_scan_results_count = new_count; | ||
282 | spin_unlock_irqrestore(&local->lock, flags); | ||
283 | kfree(prev); | ||
284 | |||
285 | hostap_report_scan_complete(local); | ||
286 | |||
287 | /* Perform rest of ScanResults handling later in scheduled task */ | ||
288 | set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); | ||
289 | schedule_work(&local->info_queue); | ||
290 | } | ||
291 | |||
292 | |||
293 | /* Called only as a tasklet (software IRQ) */ | ||
294 | static void prism2_info_hostscanresults(local_info_t *local, | ||
295 | unsigned char *buf, int left) | ||
296 | { | ||
297 | int i, result_size, copy_len, new_count; | ||
298 | struct hfa384x_hostscan_result *results, *prev; | ||
299 | unsigned long flags; | ||
300 | u16 *pos; | ||
301 | u8 *ptr; | ||
302 | |||
303 | wake_up_interruptible(&local->hostscan_wq); | ||
304 | |||
305 | if (left < 4) { | ||
306 | printk(KERN_DEBUG "%s: invalid hostscanresult info frame " | ||
307 | "length %d\n", local->dev->name, left); | ||
308 | return; | ||
309 | } | ||
310 | |||
311 | pos = (u16 *) buf; | ||
312 | copy_len = result_size = le16_to_cpu(*pos); | ||
313 | if (result_size == 0) { | ||
314 | printk(KERN_DEBUG "%s: invalid result_size (0) in " | ||
315 | "hostscanresults\n", local->dev->name); | ||
316 | return; | ||
317 | } | ||
318 | if (copy_len > sizeof(struct hfa384x_hostscan_result)) | ||
319 | copy_len = sizeof(struct hfa384x_hostscan_result); | ||
320 | |||
321 | pos++; | ||
322 | pos++; | ||
323 | left -= 4; | ||
324 | ptr = (u8 *) pos; | ||
325 | |||
326 | new_count = left / result_size; | ||
327 | results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), | ||
328 | GFP_ATOMIC); | ||
329 | if (results == NULL) | ||
330 | return; | ||
331 | memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result)); | ||
332 | |||
333 | for (i = 0; i < new_count; i++) { | ||
334 | memcpy(&results[i], ptr, copy_len); | ||
335 | ptr += result_size; | ||
336 | left -= result_size; | ||
337 | } | ||
338 | |||
339 | if (left) { | ||
340 | printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", | ||
341 | local->dev->name, left, result_size); | ||
342 | } | ||
343 | |||
344 | spin_lock_irqsave(&local->lock, flags); | ||
345 | local->last_scan_type = PRISM2_HOSTSCAN; | ||
346 | prev = local->last_scan_results; | ||
347 | local->last_scan_results = results; | ||
348 | local->last_scan_results_count = new_count; | ||
349 | spin_unlock_irqrestore(&local->lock, flags); | ||
350 | kfree(prev); | ||
351 | |||
352 | hostap_report_scan_complete(local); | ||
353 | } | ||
354 | #endif /* PRISM2_NO_STATION_MODES */ | ||
355 | |||
356 | |||
357 | /* Called only as a tasklet (software IRQ) */ | ||
358 | void hostap_info_process(local_info_t *local, struct sk_buff *skb) | ||
359 | { | ||
360 | struct hfa384x_info_frame *info; | ||
361 | unsigned char *buf; | ||
362 | int left; | ||
363 | #ifndef PRISM2_NO_DEBUG | ||
364 | int i; | ||
365 | #endif /* PRISM2_NO_DEBUG */ | ||
366 | |||
367 | info = (struct hfa384x_info_frame *) skb->data; | ||
368 | buf = skb->data + sizeof(*info); | ||
369 | left = skb->len - sizeof(*info); | ||
370 | |||
371 | switch (info->type) { | ||
372 | case HFA384X_INFO_COMMTALLIES: | ||
373 | prism2_info_commtallies(local, buf, left); | ||
374 | break; | ||
375 | |||
376 | #ifndef PRISM2_NO_STATION_MODES | ||
377 | case HFA384X_INFO_LINKSTATUS: | ||
378 | prism2_info_linkstatus(local, buf, left); | ||
379 | break; | ||
380 | |||
381 | case HFA384X_INFO_SCANRESULTS: | ||
382 | prism2_info_scanresults(local, buf, left); | ||
383 | break; | ||
384 | |||
385 | case HFA384X_INFO_HOSTSCANRESULTS: | ||
386 | prism2_info_hostscanresults(local, buf, left); | ||
387 | break; | ||
388 | #endif /* PRISM2_NO_STATION_MODES */ | ||
389 | |||
390 | #ifndef PRISM2_NO_DEBUG | ||
391 | default: | ||
392 | PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", | ||
393 | local->dev->name, info->len, info->type); | ||
394 | PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); | ||
395 | for (i = 0; i < (left < 100 ? left : 100); i++) | ||
396 | PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); | ||
397 | PDEBUG2(DEBUG_EXTRA, "\n"); | ||
398 | break; | ||
399 | #endif /* PRISM2_NO_DEBUG */ | ||
400 | } | ||
401 | } | ||
402 | |||
403 | |||
404 | #ifndef PRISM2_NO_STATION_MODES | ||
405 | static void handle_info_queue_linkstatus(local_info_t *local) | ||
406 | { | ||
407 | int val = local->prev_link_status; | ||
408 | int connected; | ||
409 | union iwreq_data wrqu; | ||
410 | |||
411 | connected = | ||
412 | val == HFA384X_LINKSTATUS_CONNECTED || | ||
413 | val == HFA384X_LINKSTATUS_AP_CHANGE || | ||
414 | val == HFA384X_LINKSTATUS_AP_IN_RANGE; | ||
415 | |||
416 | if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, | ||
417 | local->bssid, ETH_ALEN, 1) < 0) { | ||
418 | printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " | ||
419 | "LinkStatus event\n", local->dev->name); | ||
420 | } else { | ||
421 | PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", | ||
422 | local->dev->name, | ||
423 | MAC2STR((unsigned char *) local->bssid)); | ||
424 | if (local->wds_type & HOSTAP_WDS_AP_CLIENT) | ||
425 | hostap_add_sta(local->ap, local->bssid); | ||
426 | } | ||
427 | |||
428 | /* Get BSSID if we have a valid AP address */ | ||
429 | if (connected) { | ||
430 | netif_carrier_on(local->dev); | ||
431 | netif_carrier_on(local->ddev); | ||
432 | memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); | ||
433 | } else { | ||
434 | netif_carrier_off(local->dev); | ||
435 | netif_carrier_off(local->ddev); | ||
436 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
437 | } | ||
438 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
439 | |||
440 | /* | ||
441 | * Filter out sequential disconnect events in order not to cause a | ||
442 | * flood of SIOCGIWAP events that have a race condition with EAPOL | ||
443 | * frames and can confuse wpa_supplicant about the current association | ||
444 | * status. | ||
445 | */ | ||
446 | if (connected || local->prev_linkstatus_connected) | ||
447 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
448 | local->prev_linkstatus_connected = connected; | ||
449 | } | ||
450 | |||
451 | |||
452 | static void handle_info_queue_scanresults(local_info_t *local) | ||
453 | { | ||
454 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) | ||
455 | prism2_host_roaming(local); | ||
456 | |||
457 | if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA && | ||
458 | memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00", | ||
459 | ETH_ALEN) != 0) { | ||
460 | /* | ||
461 | * Firmware seems to be getting into odd state in host_roaming | ||
462 | * mode 2 when hostscan is used without join command, so try | ||
463 | * to fix this by re-joining the current AP. This does not | ||
464 | * actually trigger a new association if the current AP is | ||
465 | * still in the scan results. | ||
466 | */ | ||
467 | prism2_host_roaming(local); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | |||
472 | /* Called only as scheduled task after receiving info frames (used to avoid | ||
473 | * pending too much time in HW IRQ handler). */ | ||
474 | static void handle_info_queue(void *data) | ||
475 | { | ||
476 | local_info_t *local = (local_info_t *) data; | ||
477 | |||
478 | if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, | ||
479 | &local->pending_info)) | ||
480 | handle_info_queue_linkstatus(local); | ||
481 | |||
482 | if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, | ||
483 | &local->pending_info)) | ||
484 | handle_info_queue_scanresults(local); | ||
485 | } | ||
486 | #endif /* PRISM2_NO_STATION_MODES */ | ||
487 | |||
488 | |||
489 | void hostap_info_init(local_info_t *local) | ||
490 | { | ||
491 | skb_queue_head_init(&local->info_list); | ||
492 | #ifndef PRISM2_NO_STATION_MODES | ||
493 | INIT_WORK(&local->info_queue, handle_info_queue, local); | ||
494 | #endif /* PRISM2_NO_STATION_MODES */ | ||
495 | } | ||
496 | |||
497 | |||
498 | EXPORT_SYMBOL(hostap_info_init); | ||
499 | EXPORT_SYMBOL(hostap_info_process); | ||
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c new file mode 100644 index 000000000000..e720369a3515 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ioctl.c | |||
@@ -0,0 +1,4102 @@ | |||
1 | /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ | ||
2 | |||
3 | #ifdef in_atomic | ||
4 | /* Get kernel_locked() for in_atomic() */ | ||
5 | #include <linux/smp_lock.h> | ||
6 | #endif | ||
7 | #include <linux/ethtool.h> | ||
8 | |||
9 | |||
10 | static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) | ||
11 | { | ||
12 | struct hostap_interface *iface; | ||
13 | local_info_t *local; | ||
14 | struct iw_statistics *wstats; | ||
15 | |||
16 | iface = netdev_priv(dev); | ||
17 | local = iface->local; | ||
18 | |||
19 | /* Why are we doing that ? Jean II */ | ||
20 | if (iface->type != HOSTAP_INTERFACE_MAIN) | ||
21 | return NULL; | ||
22 | |||
23 | wstats = &local->wstats; | ||
24 | |||
25 | wstats->status = 0; | ||
26 | wstats->discard.code = | ||
27 | local->comm_tallies.rx_discards_wep_undecryptable; | ||
28 | wstats->discard.misc = | ||
29 | local->comm_tallies.rx_fcs_errors + | ||
30 | local->comm_tallies.rx_discards_no_buffer + | ||
31 | local->comm_tallies.tx_discards_wrong_sa; | ||
32 | |||
33 | wstats->discard.retries = | ||
34 | local->comm_tallies.tx_retry_limit_exceeded; | ||
35 | wstats->discard.fragment = | ||
36 | local->comm_tallies.rx_message_in_bad_msg_fragments; | ||
37 | |||
38 | if (local->iw_mode != IW_MODE_MASTER && | ||
39 | local->iw_mode != IW_MODE_REPEAT) { | ||
40 | int update = 1; | ||
41 | #ifdef in_atomic | ||
42 | /* RID reading might sleep and it must not be called in | ||
43 | * interrupt context or while atomic. However, this | ||
44 | * function seems to be called while atomic (at least in Linux | ||
45 | * 2.5.59). Update signal quality values only if in suitable | ||
46 | * context. Otherwise, previous values read from tick timer | ||
47 | * will be used. */ | ||
48 | if (in_atomic()) | ||
49 | update = 0; | ||
50 | #endif /* in_atomic */ | ||
51 | |||
52 | if (update && prism2_update_comms_qual(dev) == 0) | ||
53 | wstats->qual.updated = 7; | ||
54 | |||
55 | wstats->qual.qual = local->comms_qual; | ||
56 | wstats->qual.level = local->avg_signal; | ||
57 | wstats->qual.noise = local->avg_noise; | ||
58 | } else { | ||
59 | wstats->qual.qual = 0; | ||
60 | wstats->qual.level = 0; | ||
61 | wstats->qual.noise = 0; | ||
62 | wstats->qual.updated = 0; | ||
63 | } | ||
64 | |||
65 | return wstats; | ||
66 | } | ||
67 | |||
68 | |||
69 | static int prism2_get_datarates(struct net_device *dev, u8 *rates) | ||
70 | { | ||
71 | struct hostap_interface *iface; | ||
72 | local_info_t *local; | ||
73 | u8 buf[12]; | ||
74 | int len; | ||
75 | u16 val; | ||
76 | |||
77 | iface = netdev_priv(dev); | ||
78 | local = iface->local; | ||
79 | |||
80 | len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, | ||
81 | sizeof(buf), 0); | ||
82 | if (len < 2) | ||
83 | return 0; | ||
84 | |||
85 | val = le16_to_cpu(*(u16 *) buf); /* string length */ | ||
86 | |||
87 | if (len - 2 < val || val > 10) | ||
88 | return 0; | ||
89 | |||
90 | memcpy(rates, buf + 2, val); | ||
91 | return val; | ||
92 | } | ||
93 | |||
94 | |||
95 | static int prism2_get_name(struct net_device *dev, | ||
96 | struct iw_request_info *info, | ||
97 | char *name, char *extra) | ||
98 | { | ||
99 | u8 rates[10]; | ||
100 | int len, i, over2 = 0; | ||
101 | |||
102 | len = prism2_get_datarates(dev, rates); | ||
103 | |||
104 | for (i = 0; i < len; i++) { | ||
105 | if (rates[i] == 0x0b || rates[i] == 0x16) { | ||
106 | over2 = 1; | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static void prism2_crypt_delayed_deinit(local_info_t *local, | ||
118 | struct ieee80211_crypt_data **crypt) | ||
119 | { | ||
120 | struct ieee80211_crypt_data *tmp; | ||
121 | unsigned long flags; | ||
122 | |||
123 | tmp = *crypt; | ||
124 | *crypt = NULL; | ||
125 | |||
126 | if (tmp == NULL) | ||
127 | return; | ||
128 | |||
129 | /* must not run ops->deinit() while there may be pending encrypt or | ||
130 | * decrypt operations. Use a list of delayed deinits to avoid needing | ||
131 | * locking. */ | ||
132 | |||
133 | spin_lock_irqsave(&local->lock, flags); | ||
134 | list_add(&tmp->list, &local->crypt_deinit_list); | ||
135 | if (!timer_pending(&local->crypt_deinit_timer)) { | ||
136 | local->crypt_deinit_timer.expires = jiffies + HZ; | ||
137 | add_timer(&local->crypt_deinit_timer); | ||
138 | } | ||
139 | spin_unlock_irqrestore(&local->lock, flags); | ||
140 | } | ||
141 | |||
142 | |||
143 | static int prism2_ioctl_siwencode(struct net_device *dev, | ||
144 | struct iw_request_info *info, | ||
145 | struct iw_point *erq, char *keybuf) | ||
146 | { | ||
147 | struct hostap_interface *iface; | ||
148 | local_info_t *local; | ||
149 | int i; | ||
150 | struct ieee80211_crypt_data **crypt; | ||
151 | |||
152 | iface = netdev_priv(dev); | ||
153 | local = iface->local; | ||
154 | |||
155 | i = erq->flags & IW_ENCODE_INDEX; | ||
156 | if (i < 1 || i > 4) | ||
157 | i = local->tx_keyidx; | ||
158 | else | ||
159 | i--; | ||
160 | if (i < 0 || i >= WEP_KEYS) | ||
161 | return -EINVAL; | ||
162 | |||
163 | crypt = &local->crypt[i]; | ||
164 | |||
165 | if (erq->flags & IW_ENCODE_DISABLED) { | ||
166 | if (*crypt) | ||
167 | prism2_crypt_delayed_deinit(local, crypt); | ||
168 | goto done; | ||
169 | } | ||
170 | |||
171 | if (*crypt != NULL && (*crypt)->ops != NULL && | ||
172 | strcmp((*crypt)->ops->name, "WEP") != 0) { | ||
173 | /* changing to use WEP; deinit previously used algorithm */ | ||
174 | prism2_crypt_delayed_deinit(local, crypt); | ||
175 | } | ||
176 | |||
177 | if (*crypt == NULL) { | ||
178 | struct ieee80211_crypt_data *new_crypt; | ||
179 | |||
180 | /* take WEP into use */ | ||
181 | new_crypt = (struct ieee80211_crypt_data *) | ||
182 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
183 | GFP_KERNEL); | ||
184 | if (new_crypt == NULL) | ||
185 | return -ENOMEM; | ||
186 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
187 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
188 | if (!new_crypt->ops) { | ||
189 | request_module("ieee80211_crypt_wep"); | ||
190 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
191 | } | ||
192 | if (new_crypt->ops) | ||
193 | new_crypt->priv = new_crypt->ops->init(i); | ||
194 | if (!new_crypt->ops || !new_crypt->priv) { | ||
195 | kfree(new_crypt); | ||
196 | new_crypt = NULL; | ||
197 | |||
198 | printk(KERN_WARNING "%s: could not initialize WEP: " | ||
199 | "load module hostap_crypt_wep.o\n", | ||
200 | dev->name); | ||
201 | return -EOPNOTSUPP; | ||
202 | } | ||
203 | *crypt = new_crypt; | ||
204 | } | ||
205 | |||
206 | if (erq->length > 0) { | ||
207 | int len = erq->length <= 5 ? 5 : 13; | ||
208 | int first = 1, j; | ||
209 | if (len > erq->length) | ||
210 | memset(keybuf + erq->length, 0, len - erq->length); | ||
211 | (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); | ||
212 | for (j = 0; j < WEP_KEYS; j++) { | ||
213 | if (j != i && local->crypt[j]) { | ||
214 | first = 0; | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | if (first) | ||
219 | local->tx_keyidx = i; | ||
220 | } else { | ||
221 | /* No key data - just set the default TX key index */ | ||
222 | local->tx_keyidx = i; | ||
223 | } | ||
224 | |||
225 | done: | ||
226 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
227 | |||
228 | if (hostap_set_encryption(local)) { | ||
229 | printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
234 | * generate new IEEE 802.11 authentication which may end up in looping | ||
235 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
236 | * after WEP configuration. However, keys are apparently changed at | ||
237 | * least in Managed mode. */ | ||
238 | if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { | ||
239 | printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | |||
247 | static int prism2_ioctl_giwencode(struct net_device *dev, | ||
248 | struct iw_request_info *info, | ||
249 | struct iw_point *erq, char *key) | ||
250 | { | ||
251 | struct hostap_interface *iface; | ||
252 | local_info_t *local; | ||
253 | int i, len; | ||
254 | u16 val; | ||
255 | struct ieee80211_crypt_data *crypt; | ||
256 | |||
257 | iface = netdev_priv(dev); | ||
258 | local = iface->local; | ||
259 | |||
260 | i = erq->flags & IW_ENCODE_INDEX; | ||
261 | if (i < 1 || i > 4) | ||
262 | i = local->tx_keyidx; | ||
263 | else | ||
264 | i--; | ||
265 | if (i < 0 || i >= WEP_KEYS) | ||
266 | return -EINVAL; | ||
267 | |||
268 | crypt = local->crypt[i]; | ||
269 | erq->flags = i + 1; | ||
270 | |||
271 | if (crypt == NULL || crypt->ops == NULL) { | ||
272 | erq->length = 0; | ||
273 | erq->flags |= IW_ENCODE_DISABLED; | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | if (strcmp(crypt->ops->name, "WEP") != 0) { | ||
278 | /* only WEP is supported with wireless extensions, so just | ||
279 | * report that encryption is used */ | ||
280 | erq->length = 0; | ||
281 | erq->flags |= IW_ENCODE_ENABLED; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show | ||
286 | * the keys from driver buffer */ | ||
287 | len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); | ||
288 | erq->length = (len >= 0 ? len : 0); | ||
289 | |||
290 | if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) | ||
291 | { | ||
292 | printk("CNFWEPFLAGS reading failed\n"); | ||
293 | return -EOPNOTSUPP; | ||
294 | } | ||
295 | le16_to_cpus(&val); | ||
296 | if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) | ||
297 | erq->flags |= IW_ENCODE_ENABLED; | ||
298 | else | ||
299 | erq->flags |= IW_ENCODE_DISABLED; | ||
300 | if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) | ||
301 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
302 | else | ||
303 | erq->flags |= IW_ENCODE_OPEN; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | |||
309 | static int hostap_set_rate(struct net_device *dev) | ||
310 | { | ||
311 | struct hostap_interface *iface; | ||
312 | local_info_t *local; | ||
313 | int ret, basic_rates; | ||
314 | |||
315 | iface = netdev_priv(dev); | ||
316 | local = iface->local; | ||
317 | |||
318 | basic_rates = local->basic_rates & local->tx_rate_control; | ||
319 | if (!basic_rates || basic_rates != local->basic_rates) { | ||
320 | printk(KERN_INFO "%s: updating basic rate set automatically " | ||
321 | "to match with the new supported rate set\n", | ||
322 | dev->name); | ||
323 | if (!basic_rates) | ||
324 | basic_rates = local->tx_rate_control; | ||
325 | |||
326 | local->basic_rates = basic_rates; | ||
327 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
328 | basic_rates)) | ||
329 | printk(KERN_WARNING "%s: failed to set " | ||
330 | "cnfBasicRates\n", dev->name); | ||
331 | } | ||
332 | |||
333 | ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
334 | local->tx_rate_control) || | ||
335 | hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
336 | local->tx_rate_control) || | ||
337 | local->func->reset_port(dev)); | ||
338 | |||
339 | if (ret) { | ||
340 | printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " | ||
341 | "setting to 0x%x failed\n", | ||
342 | dev->name, local->tx_rate_control); | ||
343 | } | ||
344 | |||
345 | /* Update TX rate configuration for all STAs based on new operational | ||
346 | * rate set. */ | ||
347 | hostap_update_rates(local); | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | |||
353 | static int prism2_ioctl_siwrate(struct net_device *dev, | ||
354 | struct iw_request_info *info, | ||
355 | struct iw_param *rrq, char *extra) | ||
356 | { | ||
357 | struct hostap_interface *iface; | ||
358 | local_info_t *local; | ||
359 | |||
360 | iface = netdev_priv(dev); | ||
361 | local = iface->local; | ||
362 | |||
363 | if (rrq->fixed) { | ||
364 | switch (rrq->value) { | ||
365 | case 11000000: | ||
366 | local->tx_rate_control = HFA384X_RATES_11MBPS; | ||
367 | break; | ||
368 | case 5500000: | ||
369 | local->tx_rate_control = HFA384X_RATES_5MBPS; | ||
370 | break; | ||
371 | case 2000000: | ||
372 | local->tx_rate_control = HFA384X_RATES_2MBPS; | ||
373 | break; | ||
374 | case 1000000: | ||
375 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
376 | break; | ||
377 | default: | ||
378 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
379 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
380 | HFA384X_RATES_11MBPS; | ||
381 | break; | ||
382 | } | ||
383 | } else { | ||
384 | switch (rrq->value) { | ||
385 | case 11000000: | ||
386 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
387 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
388 | HFA384X_RATES_11MBPS; | ||
389 | break; | ||
390 | case 5500000: | ||
391 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
392 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; | ||
393 | break; | ||
394 | case 2000000: | ||
395 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
396 | HFA384X_RATES_2MBPS; | ||
397 | break; | ||
398 | case 1000000: | ||
399 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
400 | break; | ||
401 | default: | ||
402 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
403 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
404 | HFA384X_RATES_11MBPS; | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return hostap_set_rate(dev); | ||
410 | } | ||
411 | |||
412 | |||
413 | static int prism2_ioctl_giwrate(struct net_device *dev, | ||
414 | struct iw_request_info *info, | ||
415 | struct iw_param *rrq, char *extra) | ||
416 | { | ||
417 | u16 val; | ||
418 | struct hostap_interface *iface; | ||
419 | local_info_t *local; | ||
420 | int ret = 0; | ||
421 | |||
422 | iface = netdev_priv(dev); | ||
423 | local = iface->local; | ||
424 | |||
425 | if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < | ||
426 | 0) | ||
427 | return -EINVAL; | ||
428 | |||
429 | if ((val & 0x1) && (val > 1)) | ||
430 | rrq->fixed = 0; | ||
431 | else | ||
432 | rrq->fixed = 1; | ||
433 | |||
434 | if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && | ||
435 | !local->fw_tx_rate_control) { | ||
436 | /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in | ||
437 | * Host AP mode, so use the recorded TX rate of the last sent | ||
438 | * frame */ | ||
439 | rrq->value = local->ap->last_tx_rate > 0 ? | ||
440 | local->ap->last_tx_rate * 100000 : 11000000; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < | ||
445 | 0) | ||
446 | return -EINVAL; | ||
447 | |||
448 | switch (val) { | ||
449 | case HFA384X_RATES_1MBPS: | ||
450 | rrq->value = 1000000; | ||
451 | break; | ||
452 | case HFA384X_RATES_2MBPS: | ||
453 | rrq->value = 2000000; | ||
454 | break; | ||
455 | case HFA384X_RATES_5MBPS: | ||
456 | rrq->value = 5500000; | ||
457 | break; | ||
458 | case HFA384X_RATES_11MBPS: | ||
459 | rrq->value = 11000000; | ||
460 | break; | ||
461 | default: | ||
462 | /* should not happen */ | ||
463 | rrq->value = 11000000; | ||
464 | ret = -EINVAL; | ||
465 | break; | ||
466 | } | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | |||
472 | static int prism2_ioctl_siwsens(struct net_device *dev, | ||
473 | struct iw_request_info *info, | ||
474 | struct iw_param *sens, char *extra) | ||
475 | { | ||
476 | struct hostap_interface *iface; | ||
477 | local_info_t *local; | ||
478 | |||
479 | iface = netdev_priv(dev); | ||
480 | local = iface->local; | ||
481 | |||
482 | /* Set the desired AP density */ | ||
483 | if (sens->value < 1 || sens->value > 3) | ||
484 | return -EINVAL; | ||
485 | |||
486 | if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || | ||
487 | local->func->reset_port(dev)) | ||
488 | return -EINVAL; | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static int prism2_ioctl_giwsens(struct net_device *dev, | ||
494 | struct iw_request_info *info, | ||
495 | struct iw_param *sens, char *extra) | ||
496 | { | ||
497 | struct hostap_interface *iface; | ||
498 | local_info_t *local; | ||
499 | u16 val; | ||
500 | |||
501 | iface = netdev_priv(dev); | ||
502 | local = iface->local; | ||
503 | |||
504 | /* Get the current AP density */ | ||
505 | if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < | ||
506 | 0) | ||
507 | return -EINVAL; | ||
508 | |||
509 | sens->value = __le16_to_cpu(val); | ||
510 | sens->fixed = 1; | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | |||
516 | /* Deprecated in new wireless extension API */ | ||
517 | static int prism2_ioctl_giwaplist(struct net_device *dev, | ||
518 | struct iw_request_info *info, | ||
519 | struct iw_point *data, char *extra) | ||
520 | { | ||
521 | struct hostap_interface *iface; | ||
522 | local_info_t *local; | ||
523 | struct sockaddr *addr; | ||
524 | struct iw_quality *qual; | ||
525 | |||
526 | iface = netdev_priv(dev); | ||
527 | local = iface->local; | ||
528 | |||
529 | if (local->iw_mode != IW_MODE_MASTER) { | ||
530 | printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " | ||
531 | "in Host AP mode\n"); | ||
532 | data->length = 0; | ||
533 | return -EOPNOTSUPP; | ||
534 | } | ||
535 | |||
536 | addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL); | ||
537 | qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL); | ||
538 | if (addr == NULL || qual == NULL) { | ||
539 | kfree(addr); | ||
540 | kfree(qual); | ||
541 | data->length = 0; | ||
542 | return -ENOMEM; | ||
543 | } | ||
544 | |||
545 | data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); | ||
546 | |||
547 | memcpy(extra, &addr, sizeof(struct sockaddr) * data->length); | ||
548 | data->flags = 1; /* has quality information */ | ||
549 | memcpy(extra + sizeof(struct sockaddr) * data->length, &qual, | ||
550 | sizeof(struct iw_quality) * data->length); | ||
551 | |||
552 | kfree(addr); | ||
553 | kfree(qual); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | |||
559 | static int prism2_ioctl_siwrts(struct net_device *dev, | ||
560 | struct iw_request_info *info, | ||
561 | struct iw_param *rts, char *extra) | ||
562 | { | ||
563 | struct hostap_interface *iface; | ||
564 | local_info_t *local; | ||
565 | u16 val; | ||
566 | |||
567 | iface = netdev_priv(dev); | ||
568 | local = iface->local; | ||
569 | |||
570 | if (rts->disabled) | ||
571 | val = __constant_cpu_to_le16(2347); | ||
572 | else if (rts->value < 0 || rts->value > 2347) | ||
573 | return -EINVAL; | ||
574 | else | ||
575 | val = __cpu_to_le16(rts->value); | ||
576 | |||
577 | if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || | ||
578 | local->func->reset_port(dev)) | ||
579 | return -EINVAL; | ||
580 | |||
581 | local->rts_threshold = rts->value; | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int prism2_ioctl_giwrts(struct net_device *dev, | ||
587 | struct iw_request_info *info, | ||
588 | struct iw_param *rts, char *extra) | ||
589 | { | ||
590 | struct hostap_interface *iface; | ||
591 | local_info_t *local; | ||
592 | u16 val; | ||
593 | |||
594 | iface = netdev_priv(dev); | ||
595 | local = iface->local; | ||
596 | |||
597 | if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < | ||
598 | 0) | ||
599 | return -EINVAL; | ||
600 | |||
601 | rts->value = __le16_to_cpu(val); | ||
602 | rts->disabled = (rts->value == 2347); | ||
603 | rts->fixed = 1; | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | |||
609 | static int prism2_ioctl_siwfrag(struct net_device *dev, | ||
610 | struct iw_request_info *info, | ||
611 | struct iw_param *rts, char *extra) | ||
612 | { | ||
613 | struct hostap_interface *iface; | ||
614 | local_info_t *local; | ||
615 | u16 val; | ||
616 | |||
617 | iface = netdev_priv(dev); | ||
618 | local = iface->local; | ||
619 | |||
620 | if (rts->disabled) | ||
621 | val = __constant_cpu_to_le16(2346); | ||
622 | else if (rts->value < 256 || rts->value > 2346) | ||
623 | return -EINVAL; | ||
624 | else | ||
625 | val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ | ||
626 | |||
627 | local->fragm_threshold = rts->value & ~0x1; | ||
628 | if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, | ||
629 | 2) | ||
630 | || local->func->reset_port(dev)) | ||
631 | return -EINVAL; | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static int prism2_ioctl_giwfrag(struct net_device *dev, | ||
637 | struct iw_request_info *info, | ||
638 | struct iw_param *rts, char *extra) | ||
639 | { | ||
640 | struct hostap_interface *iface; | ||
641 | local_info_t *local; | ||
642 | u16 val; | ||
643 | |||
644 | iface = netdev_priv(dev); | ||
645 | local = iface->local; | ||
646 | |||
647 | if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
648 | &val, 2, 1) < 0) | ||
649 | return -EINVAL; | ||
650 | |||
651 | rts->value = __le16_to_cpu(val); | ||
652 | rts->disabled = (rts->value == 2346); | ||
653 | rts->fixed = 1; | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | |||
659 | #ifndef PRISM2_NO_STATION_MODES | ||
660 | static int hostap_join_ap(struct net_device *dev) | ||
661 | { | ||
662 | struct hostap_interface *iface; | ||
663 | local_info_t *local; | ||
664 | struct hfa384x_join_request req; | ||
665 | unsigned long flags; | ||
666 | int i; | ||
667 | struct hfa384x_hostscan_result *entry; | ||
668 | |||
669 | iface = netdev_priv(dev); | ||
670 | local = iface->local; | ||
671 | |||
672 | memcpy(req.bssid, local->preferred_ap, ETH_ALEN); | ||
673 | req.channel = 0; | ||
674 | |||
675 | spin_lock_irqsave(&local->lock, flags); | ||
676 | for (i = 0; i < local->last_scan_results_count; i++) { | ||
677 | if (!local->last_scan_results) | ||
678 | break; | ||
679 | entry = &local->last_scan_results[i]; | ||
680 | if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) { | ||
681 | req.channel = entry->chid; | ||
682 | break; | ||
683 | } | ||
684 | } | ||
685 | spin_unlock_irqrestore(&local->lock, flags); | ||
686 | |||
687 | if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, | ||
688 | sizeof(req))) { | ||
689 | printk(KERN_DEBUG "%s: JoinRequest " MACSTR | ||
690 | " failed\n", | ||
691 | dev->name, MAC2STR(local->preferred_ap)); | ||
692 | return -1; | ||
693 | } | ||
694 | |||
695 | printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", | ||
696 | dev->name, MAC2STR(local->preferred_ap)); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | #endif /* PRISM2_NO_STATION_MODES */ | ||
701 | |||
702 | |||
703 | static int prism2_ioctl_siwap(struct net_device *dev, | ||
704 | struct iw_request_info *info, | ||
705 | struct sockaddr *ap_addr, char *extra) | ||
706 | { | ||
707 | #ifdef PRISM2_NO_STATION_MODES | ||
708 | return -EOPNOTSUPP; | ||
709 | #else /* PRISM2_NO_STATION_MODES */ | ||
710 | struct hostap_interface *iface; | ||
711 | local_info_t *local; | ||
712 | |||
713 | iface = netdev_priv(dev); | ||
714 | local = iface->local; | ||
715 | |||
716 | memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); | ||
717 | |||
718 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { | ||
719 | struct hfa384x_scan_request scan_req; | ||
720 | memset(&scan_req, 0, sizeof(scan_req)); | ||
721 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
722 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
723 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, | ||
724 | &scan_req, sizeof(scan_req))) { | ||
725 | printk(KERN_DEBUG "%s: ScanResults request failed - " | ||
726 | "preferred AP delayed to next unsolicited " | ||
727 | "scan\n", dev->name); | ||
728 | } | ||
729 | } else if (local->host_roaming == 2 && | ||
730 | local->iw_mode == IW_MODE_INFRA) { | ||
731 | if (hostap_join_ap(dev)) | ||
732 | return -EINVAL; | ||
733 | } else { | ||
734 | printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " | ||
735 | "in Managed mode when host_roaming is enabled\n", | ||
736 | dev->name); | ||
737 | } | ||
738 | |||
739 | return 0; | ||
740 | #endif /* PRISM2_NO_STATION_MODES */ | ||
741 | } | ||
742 | |||
743 | static int prism2_ioctl_giwap(struct net_device *dev, | ||
744 | struct iw_request_info *info, | ||
745 | struct sockaddr *ap_addr, char *extra) | ||
746 | { | ||
747 | struct hostap_interface *iface; | ||
748 | local_info_t *local; | ||
749 | |||
750 | iface = netdev_priv(dev); | ||
751 | local = iface->local; | ||
752 | |||
753 | ap_addr->sa_family = ARPHRD_ETHER; | ||
754 | switch (iface->type) { | ||
755 | case HOSTAP_INTERFACE_AP: | ||
756 | memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); | ||
757 | break; | ||
758 | case HOSTAP_INTERFACE_STA: | ||
759 | memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); | ||
760 | break; | ||
761 | case HOSTAP_INTERFACE_WDS: | ||
762 | memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); | ||
763 | break; | ||
764 | default: | ||
765 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, | ||
766 | &ap_addr->sa_data, ETH_ALEN, 1) < 0) | ||
767 | return -EOPNOTSUPP; | ||
768 | |||
769 | /* local->bssid is also updated in LinkStatus handler when in | ||
770 | * station mode */ | ||
771 | memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); | ||
772 | break; | ||
773 | } | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | |||
779 | static int prism2_ioctl_siwnickn(struct net_device *dev, | ||
780 | struct iw_request_info *info, | ||
781 | struct iw_point *data, char *nickname) | ||
782 | { | ||
783 | struct hostap_interface *iface; | ||
784 | local_info_t *local; | ||
785 | |||
786 | iface = netdev_priv(dev); | ||
787 | local = iface->local; | ||
788 | |||
789 | memset(local->name, 0, sizeof(local->name)); | ||
790 | memcpy(local->name, nickname, data->length); | ||
791 | local->name_set = 1; | ||
792 | |||
793 | if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || | ||
794 | local->func->reset_port(dev)) | ||
795 | return -EINVAL; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int prism2_ioctl_giwnickn(struct net_device *dev, | ||
801 | struct iw_request_info *info, | ||
802 | struct iw_point *data, char *nickname) | ||
803 | { | ||
804 | struct hostap_interface *iface; | ||
805 | local_info_t *local; | ||
806 | int len; | ||
807 | char name[MAX_NAME_LEN + 3]; | ||
808 | u16 val; | ||
809 | |||
810 | iface = netdev_priv(dev); | ||
811 | local = iface->local; | ||
812 | |||
813 | len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, | ||
814 | &name, MAX_NAME_LEN + 2, 0); | ||
815 | val = __le16_to_cpu(*(u16 *) name); | ||
816 | if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) | ||
817 | return -EOPNOTSUPP; | ||
818 | |||
819 | name[val + 2] = '\0'; | ||
820 | data->length = val + 1; | ||
821 | memcpy(nickname, name + 2, val + 1); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | |||
827 | static int prism2_ioctl_siwfreq(struct net_device *dev, | ||
828 | struct iw_request_info *info, | ||
829 | struct iw_freq *freq, char *extra) | ||
830 | { | ||
831 | struct hostap_interface *iface; | ||
832 | local_info_t *local; | ||
833 | |||
834 | iface = netdev_priv(dev); | ||
835 | local = iface->local; | ||
836 | |||
837 | /* freq => chan. */ | ||
838 | if (freq->e == 1 && | ||
839 | freq->m / 100000 >= freq_list[0] && | ||
840 | freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { | ||
841 | int ch; | ||
842 | int fr = freq->m / 100000; | ||
843 | for (ch = 0; ch < FREQ_COUNT; ch++) { | ||
844 | if (fr == freq_list[ch]) { | ||
845 | freq->e = 0; | ||
846 | freq->m = ch + 1; | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | |||
852 | if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || | ||
853 | !(local->channel_mask & (1 << (freq->m - 1)))) | ||
854 | return -EINVAL; | ||
855 | |||
856 | local->channel = freq->m; /* channel is used in prism2_setup_rids() */ | ||
857 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || | ||
858 | local->func->reset_port(dev)) | ||
859 | return -EINVAL; | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int prism2_ioctl_giwfreq(struct net_device *dev, | ||
865 | struct iw_request_info *info, | ||
866 | struct iw_freq *freq, char *extra) | ||
867 | { | ||
868 | struct hostap_interface *iface; | ||
869 | local_info_t *local; | ||
870 | u16 val; | ||
871 | |||
872 | iface = netdev_priv(dev); | ||
873 | local = iface->local; | ||
874 | |||
875 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < | ||
876 | 0) | ||
877 | return -EINVAL; | ||
878 | |||
879 | le16_to_cpus(&val); | ||
880 | if (val < 1 || val > FREQ_COUNT) | ||
881 | return -EINVAL; | ||
882 | |||
883 | freq->m = freq_list[val - 1] * 100000; | ||
884 | freq->e = 1; | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | |||
890 | static void hostap_monitor_set_type(local_info_t *local) | ||
891 | { | ||
892 | struct net_device *dev = local->ddev; | ||
893 | |||
894 | if (dev == NULL) | ||
895 | return; | ||
896 | |||
897 | if (local->monitor_type == PRISM2_MONITOR_PRISM || | ||
898 | local->monitor_type == PRISM2_MONITOR_CAPHDR) { | ||
899 | dev->type = ARPHRD_IEEE80211_PRISM; | ||
900 | dev->hard_header_parse = | ||
901 | hostap_80211_prism_header_parse; | ||
902 | } else { | ||
903 | dev->type = ARPHRD_IEEE80211; | ||
904 | dev->hard_header_parse = hostap_80211_header_parse; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | |||
909 | static int prism2_ioctl_siwessid(struct net_device *dev, | ||
910 | struct iw_request_info *info, | ||
911 | struct iw_point *data, char *ssid) | ||
912 | { | ||
913 | struct hostap_interface *iface; | ||
914 | local_info_t *local; | ||
915 | |||
916 | iface = netdev_priv(dev); | ||
917 | local = iface->local; | ||
918 | |||
919 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
920 | return -EOPNOTSUPP; | ||
921 | |||
922 | if (data->flags == 0) | ||
923 | ssid[0] = '\0'; /* ANY */ | ||
924 | |||
925 | if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { | ||
926 | /* Setting SSID to empty string seems to kill the card in | ||
927 | * Host AP mode */ | ||
928 | printk(KERN_DEBUG "%s: Host AP mode does not support " | ||
929 | "'Any' essid\n", dev->name); | ||
930 | return -EINVAL; | ||
931 | } | ||
932 | |||
933 | memcpy(local->essid, ssid, data->length); | ||
934 | local->essid[data->length] = '\0'; | ||
935 | |||
936 | if ((!local->fw_ap && | ||
937 | hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) | ||
938 | || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || | ||
939 | local->func->reset_port(dev)) | ||
940 | return -EINVAL; | ||
941 | |||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int prism2_ioctl_giwessid(struct net_device *dev, | ||
946 | struct iw_request_info *info, | ||
947 | struct iw_point *data, char *essid) | ||
948 | { | ||
949 | struct hostap_interface *iface; | ||
950 | local_info_t *local; | ||
951 | u16 val; | ||
952 | |||
953 | iface = netdev_priv(dev); | ||
954 | local = iface->local; | ||
955 | |||
956 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
957 | return -EOPNOTSUPP; | ||
958 | |||
959 | data->flags = 1; /* active */ | ||
960 | if (local->iw_mode == IW_MODE_MASTER) { | ||
961 | data->length = strlen(local->essid); | ||
962 | memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); | ||
963 | } else { | ||
964 | int len; | ||
965 | char ssid[MAX_SSID_LEN + 2]; | ||
966 | memset(ssid, 0, sizeof(ssid)); | ||
967 | len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, | ||
968 | &ssid, MAX_SSID_LEN + 2, 0); | ||
969 | val = __le16_to_cpu(*(u16 *) ssid); | ||
970 | if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { | ||
971 | return -EOPNOTSUPP; | ||
972 | } | ||
973 | data->length = val; | ||
974 | memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); | ||
975 | } | ||
976 | |||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | |||
981 | static int prism2_ioctl_giwrange(struct net_device *dev, | ||
982 | struct iw_request_info *info, | ||
983 | struct iw_point *data, char *extra) | ||
984 | { | ||
985 | struct hostap_interface *iface; | ||
986 | local_info_t *local; | ||
987 | struct iw_range *range = (struct iw_range *) extra; | ||
988 | u8 rates[10]; | ||
989 | u16 val; | ||
990 | int i, len, over2; | ||
991 | |||
992 | iface = netdev_priv(dev); | ||
993 | local = iface->local; | ||
994 | |||
995 | data->length = sizeof(struct iw_range); | ||
996 | memset(range, 0, sizeof(struct iw_range)); | ||
997 | |||
998 | /* TODO: could fill num_txpower and txpower array with | ||
999 | * something; however, there are 128 different values.. */ | ||
1000 | |||
1001 | range->txpower_capa = IW_TXPOW_DBM; | ||
1002 | |||
1003 | if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) | ||
1004 | { | ||
1005 | range->min_pmp = 1 * 1024; | ||
1006 | range->max_pmp = 65535 * 1024; | ||
1007 | range->min_pmt = 1 * 1024; | ||
1008 | range->max_pmt = 1000 * 1024; | ||
1009 | range->pmp_flags = IW_POWER_PERIOD; | ||
1010 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
1011 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | | ||
1012 | IW_POWER_UNICAST_R | IW_POWER_ALL_R; | ||
1013 | } | ||
1014 | |||
1015 | range->we_version_compiled = WIRELESS_EXT; | ||
1016 | range->we_version_source = 18; | ||
1017 | |||
1018 | range->retry_capa = IW_RETRY_LIMIT; | ||
1019 | range->retry_flags = IW_RETRY_LIMIT; | ||
1020 | range->min_retry = 0; | ||
1021 | range->max_retry = 255; | ||
1022 | |||
1023 | range->num_channels = FREQ_COUNT; | ||
1024 | |||
1025 | val = 0; | ||
1026 | for (i = 0; i < FREQ_COUNT; i++) { | ||
1027 | if (local->channel_mask & (1 << i)) { | ||
1028 | range->freq[val].i = i + 1; | ||
1029 | range->freq[val].m = freq_list[i] * 100000; | ||
1030 | range->freq[val].e = 1; | ||
1031 | val++; | ||
1032 | } | ||
1033 | if (val == IW_MAX_FREQUENCIES) | ||
1034 | break; | ||
1035 | } | ||
1036 | range->num_frequency = val; | ||
1037 | |||
1038 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1039 | range->max_qual.qual = 70; /* what is correct max? This was not | ||
1040 | * documented exactly. At least | ||
1041 | * 69 has been observed. */ | ||
1042 | range->max_qual.level = 0; /* dB */ | ||
1043 | range->max_qual.noise = 0; /* dB */ | ||
1044 | |||
1045 | /* What would be suitable values for "average/typical" qual? */ | ||
1046 | range->avg_qual.qual = 20; | ||
1047 | range->avg_qual.level = -60; | ||
1048 | range->avg_qual.noise = -95; | ||
1049 | } else { | ||
1050 | range->max_qual.qual = 92; /* 0 .. 92 */ | ||
1051 | range->max_qual.level = 154; /* 27 .. 154 */ | ||
1052 | range->max_qual.noise = 154; /* 27 .. 154 */ | ||
1053 | } | ||
1054 | range->sensitivity = 3; | ||
1055 | |||
1056 | range->max_encoding_tokens = WEP_KEYS; | ||
1057 | range->num_encoding_sizes = 2; | ||
1058 | range->encoding_size[0] = 5; | ||
1059 | range->encoding_size[1] = 13; | ||
1060 | |||
1061 | over2 = 0; | ||
1062 | len = prism2_get_datarates(dev, rates); | ||
1063 | range->num_bitrates = 0; | ||
1064 | for (i = 0; i < len; i++) { | ||
1065 | if (range->num_bitrates < IW_MAX_BITRATES) { | ||
1066 | range->bitrate[range->num_bitrates] = | ||
1067 | rates[i] * 500000; | ||
1068 | range->num_bitrates++; | ||
1069 | } | ||
1070 | if (rates[i] == 0x0b || rates[i] == 0x16) | ||
1071 | over2 = 1; | ||
1072 | } | ||
1073 | /* estimated maximum TCP throughput values (bps) */ | ||
1074 | range->throughput = over2 ? 5500000 : 1500000; | ||
1075 | |||
1076 | range->min_rts = 0; | ||
1077 | range->max_rts = 2347; | ||
1078 | range->min_frag = 256; | ||
1079 | range->max_frag = 2346; | ||
1080 | |||
1081 | /* Event capability (kernel + driver) */ | ||
1082 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
1083 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | ||
1084 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
1085 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
1086 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
1087 | range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | | ||
1088 | IW_EVENT_CAPA_MASK(IWEVCUSTOM) | | ||
1089 | IW_EVENT_CAPA_MASK(IWEVREGISTERED) | | ||
1090 | IW_EVENT_CAPA_MASK(IWEVEXPIRED)); | ||
1091 | |||
1092 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
1093 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | static int hostap_monitor_mode_enable(local_info_t *local) | ||
1100 | { | ||
1101 | struct net_device *dev = local->dev; | ||
1102 | |||
1103 | printk(KERN_DEBUG "Enabling monitor mode\n"); | ||
1104 | hostap_monitor_set_type(local); | ||
1105 | |||
1106 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1107 | HFA384X_PORTTYPE_PSEUDO_IBSS)) { | ||
1108 | printk(KERN_DEBUG "Port type setting for monitor mode " | ||
1109 | "failed\n"); | ||
1110 | return -EOPNOTSUPP; | ||
1111 | } | ||
1112 | |||
1113 | /* Host decrypt is needed to get the IV and ICV fields; | ||
1114 | * however, monitor mode seems to remove WEP flag from frame | ||
1115 | * control field */ | ||
1116 | if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, | ||
1117 | HFA384X_WEPFLAGS_HOSTENCRYPT | | ||
1118 | HFA384X_WEPFLAGS_HOSTDECRYPT)) { | ||
1119 | printk(KERN_DEBUG "WEP flags setting failed\n"); | ||
1120 | return -EOPNOTSUPP; | ||
1121 | } | ||
1122 | |||
1123 | if (local->func->reset_port(dev) || | ||
1124 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1125 | (HFA384X_TEST_MONITOR << 8), | ||
1126 | 0, NULL, NULL)) { | ||
1127 | printk(KERN_DEBUG "Setting monitor mode failed\n"); | ||
1128 | return -EOPNOTSUPP; | ||
1129 | } | ||
1130 | |||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | static int hostap_monitor_mode_disable(local_info_t *local) | ||
1136 | { | ||
1137 | struct net_device *dev = local->ddev; | ||
1138 | |||
1139 | if (dev == NULL) | ||
1140 | return -1; | ||
1141 | |||
1142 | printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); | ||
1143 | dev->type = ARPHRD_ETHER; | ||
1144 | dev->hard_header_parse = local->saved_eth_header_parse; | ||
1145 | if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1146 | (HFA384X_TEST_STOP << 8), | ||
1147 | 0, NULL, NULL)) | ||
1148 | return -1; | ||
1149 | return hostap_set_encryption(local); | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static int prism2_ioctl_siwmode(struct net_device *dev, | ||
1154 | struct iw_request_info *info, | ||
1155 | __u32 *mode, char *extra) | ||
1156 | { | ||
1157 | struct hostap_interface *iface; | ||
1158 | local_info_t *local; | ||
1159 | int double_reset = 0; | ||
1160 | |||
1161 | iface = netdev_priv(dev); | ||
1162 | local = iface->local; | ||
1163 | |||
1164 | if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && | ||
1165 | *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && | ||
1166 | *mode != IW_MODE_MONITOR) | ||
1167 | return -EOPNOTSUPP; | ||
1168 | |||
1169 | #ifdef PRISM2_NO_STATION_MODES | ||
1170 | if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) | ||
1171 | return -EOPNOTSUPP; | ||
1172 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1173 | |||
1174 | if (*mode == local->iw_mode) | ||
1175 | return 0; | ||
1176 | |||
1177 | if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { | ||
1178 | printk(KERN_WARNING "%s: empty SSID not allowed in Master " | ||
1179 | "mode\n", dev->name); | ||
1180 | return -EINVAL; | ||
1181 | } | ||
1182 | |||
1183 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1184 | hostap_monitor_mode_disable(local); | ||
1185 | |||
1186 | if ((local->iw_mode == IW_MODE_ADHOC || | ||
1187 | local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) { | ||
1188 | /* There seems to be a firmware bug in at least STA f/w v1.5.6 | ||
1189 | * that leaves beacon frames to use IBSS type when moving from | ||
1190 | * IBSS to Host AP mode. Doing double Port0 reset seems to be | ||
1191 | * enough to workaround this. */ | ||
1192 | double_reset = 1; | ||
1193 | } | ||
1194 | |||
1195 | printk(KERN_DEBUG "prism2: %s: operating mode changed " | ||
1196 | "%d -> %d\n", dev->name, local->iw_mode, *mode); | ||
1197 | local->iw_mode = *mode; | ||
1198 | |||
1199 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1200 | hostap_monitor_mode_enable(local); | ||
1201 | else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
1202 | !local->fw_encrypt_ok) { | ||
1203 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
1204 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
1205 | dev->name); | ||
1206 | local->host_encrypt = 1; | ||
1207 | } | ||
1208 | |||
1209 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1210 | hostap_get_porttype(local))) | ||
1211 | return -EOPNOTSUPP; | ||
1212 | |||
1213 | if (local->func->reset_port(dev)) | ||
1214 | return -EINVAL; | ||
1215 | if (double_reset && local->func->reset_port(dev)) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) | ||
1219 | { | ||
1220 | /* netif_carrier is used only in client modes for now, so make | ||
1221 | * sure carrier is on when moving to non-client modes. */ | ||
1222 | netif_carrier_on(local->dev); | ||
1223 | netif_carrier_on(local->ddev); | ||
1224 | } | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | |||
1229 | static int prism2_ioctl_giwmode(struct net_device *dev, | ||
1230 | struct iw_request_info *info, | ||
1231 | __u32 *mode, char *extra) | ||
1232 | { | ||
1233 | struct hostap_interface *iface; | ||
1234 | local_info_t *local; | ||
1235 | |||
1236 | iface = netdev_priv(dev); | ||
1237 | local = iface->local; | ||
1238 | |||
1239 | switch (iface->type) { | ||
1240 | case HOSTAP_INTERFACE_STA: | ||
1241 | *mode = IW_MODE_INFRA; | ||
1242 | break; | ||
1243 | case HOSTAP_INTERFACE_WDS: | ||
1244 | *mode = IW_MODE_REPEAT; | ||
1245 | break; | ||
1246 | default: | ||
1247 | *mode = local->iw_mode; | ||
1248 | break; | ||
1249 | } | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | static int prism2_ioctl_siwpower(struct net_device *dev, | ||
1255 | struct iw_request_info *info, | ||
1256 | struct iw_param *wrq, char *extra) | ||
1257 | { | ||
1258 | #ifdef PRISM2_NO_STATION_MODES | ||
1259 | return -EOPNOTSUPP; | ||
1260 | #else /* PRISM2_NO_STATION_MODES */ | ||
1261 | int ret = 0; | ||
1262 | |||
1263 | if (wrq->disabled) | ||
1264 | return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); | ||
1265 | |||
1266 | switch (wrq->flags & IW_POWER_MODE) { | ||
1267 | case IW_POWER_UNICAST_R: | ||
1268 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); | ||
1269 | if (ret) | ||
1270 | return ret; | ||
1271 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1272 | if (ret) | ||
1273 | return ret; | ||
1274 | break; | ||
1275 | case IW_POWER_ALL_R: | ||
1276 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); | ||
1277 | if (ret) | ||
1278 | return ret; | ||
1279 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1280 | if (ret) | ||
1281 | return ret; | ||
1282 | break; | ||
1283 | case IW_POWER_ON: | ||
1284 | break; | ||
1285 | default: | ||
1286 | return -EINVAL; | ||
1287 | } | ||
1288 | |||
1289 | if (wrq->flags & IW_POWER_TIMEOUT) { | ||
1290 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1291 | if (ret) | ||
1292 | return ret; | ||
1293 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1294 | wrq->value / 1024); | ||
1295 | if (ret) | ||
1296 | return ret; | ||
1297 | } | ||
1298 | if (wrq->flags & IW_POWER_PERIOD) { | ||
1299 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1300 | if (ret) | ||
1301 | return ret; | ||
1302 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1303 | wrq->value / 1024); | ||
1304 | if (ret) | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | return ret; | ||
1309 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | static int prism2_ioctl_giwpower(struct net_device *dev, | ||
1314 | struct iw_request_info *info, | ||
1315 | struct iw_param *rrq, char *extra) | ||
1316 | { | ||
1317 | #ifdef PRISM2_NO_STATION_MODES | ||
1318 | return -EOPNOTSUPP; | ||
1319 | #else /* PRISM2_NO_STATION_MODES */ | ||
1320 | struct hostap_interface *iface; | ||
1321 | local_info_t *local; | ||
1322 | u16 enable, mcast; | ||
1323 | |||
1324 | iface = netdev_priv(dev); | ||
1325 | local = iface->local; | ||
1326 | |||
1327 | if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) | ||
1328 | < 0) | ||
1329 | return -EINVAL; | ||
1330 | |||
1331 | if (!__le16_to_cpu(enable)) { | ||
1332 | rrq->disabled = 1; | ||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | rrq->disabled = 0; | ||
1337 | |||
1338 | if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
1339 | u16 timeout; | ||
1340 | if (local->func->get_rid(dev, | ||
1341 | HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1342 | &timeout, 2, 1) < 0) | ||
1343 | return -EINVAL; | ||
1344 | |||
1345 | rrq->flags = IW_POWER_TIMEOUT; | ||
1346 | rrq->value = __le16_to_cpu(timeout) * 1024; | ||
1347 | } else { | ||
1348 | u16 period; | ||
1349 | if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1350 | &period, 2, 1) < 0) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | rrq->flags = IW_POWER_PERIOD; | ||
1354 | rrq->value = __le16_to_cpu(period) * 1024; | ||
1355 | } | ||
1356 | |||
1357 | if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, | ||
1358 | 2, 1) < 0) | ||
1359 | return -EINVAL; | ||
1360 | |||
1361 | if (__le16_to_cpu(mcast)) | ||
1362 | rrq->flags |= IW_POWER_ALL_R; | ||
1363 | else | ||
1364 | rrq->flags |= IW_POWER_UNICAST_R; | ||
1365 | |||
1366 | return 0; | ||
1367 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1368 | } | ||
1369 | |||
1370 | |||
1371 | static int prism2_ioctl_siwretry(struct net_device *dev, | ||
1372 | struct iw_request_info *info, | ||
1373 | struct iw_param *rrq, char *extra) | ||
1374 | { | ||
1375 | struct hostap_interface *iface; | ||
1376 | local_info_t *local; | ||
1377 | |||
1378 | iface = netdev_priv(dev); | ||
1379 | local = iface->local; | ||
1380 | |||
1381 | if (rrq->disabled) | ||
1382 | return -EINVAL; | ||
1383 | |||
1384 | /* setting retry limits is not supported with the current station | ||
1385 | * firmware code; simulate this with alternative retry count for now */ | ||
1386 | if (rrq->flags == IW_RETRY_LIMIT) { | ||
1387 | if (rrq->value < 0) { | ||
1388 | /* disable manual retry count setting and use firmware | ||
1389 | * defaults */ | ||
1390 | local->manual_retry_count = -1; | ||
1391 | local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; | ||
1392 | } else { | ||
1393 | if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1394 | rrq->value)) { | ||
1395 | printk(KERN_DEBUG "%s: Alternate retry count " | ||
1396 | "setting to %d failed\n", | ||
1397 | dev->name, rrq->value); | ||
1398 | return -EOPNOTSUPP; | ||
1399 | } | ||
1400 | |||
1401 | local->manual_retry_count = rrq->value; | ||
1402 | local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; | ||
1403 | } | ||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | return -EOPNOTSUPP; | ||
1408 | |||
1409 | #if 0 | ||
1410 | /* what could be done, if firmware would support this.. */ | ||
1411 | |||
1412 | if (rrq->flags & IW_RETRY_LIMIT) { | ||
1413 | if (rrq->flags & IW_RETRY_MAX) | ||
1414 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1415 | else if (rrq->flags & IW_RETRY_MIN) | ||
1416 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1417 | else { | ||
1418 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1419 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1420 | } | ||
1421 | |||
1422 | } | ||
1423 | |||
1424 | if (rrq->flags & IW_RETRY_LIFETIME) { | ||
1425 | HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; | ||
1426 | } | ||
1427 | |||
1428 | return 0; | ||
1429 | #endif /* 0 */ | ||
1430 | } | ||
1431 | |||
1432 | static int prism2_ioctl_giwretry(struct net_device *dev, | ||
1433 | struct iw_request_info *info, | ||
1434 | struct iw_param *rrq, char *extra) | ||
1435 | { | ||
1436 | struct hostap_interface *iface; | ||
1437 | local_info_t *local; | ||
1438 | u16 shortretry, longretry, lifetime, altretry; | ||
1439 | |||
1440 | iface = netdev_priv(dev); | ||
1441 | local = iface->local; | ||
1442 | |||
1443 | if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, | ||
1444 | 2, 1) < 0 || | ||
1445 | local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, | ||
1446 | 2, 1) < 0 || | ||
1447 | local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, | ||
1448 | &lifetime, 2, 1) < 0) | ||
1449 | return -EINVAL; | ||
1450 | |||
1451 | le16_to_cpus(&shortretry); | ||
1452 | le16_to_cpus(&longretry); | ||
1453 | le16_to_cpus(&lifetime); | ||
1454 | |||
1455 | rrq->disabled = 0; | ||
1456 | |||
1457 | if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
1458 | rrq->flags = IW_RETRY_LIFETIME; | ||
1459 | rrq->value = lifetime * 1024; | ||
1460 | } else { | ||
1461 | if (local->manual_retry_count >= 0) { | ||
1462 | rrq->flags = IW_RETRY_LIMIT; | ||
1463 | if (local->func->get_rid(dev, | ||
1464 | HFA384X_RID_CNFALTRETRYCOUNT, | ||
1465 | &altretry, 2, 1) >= 0) | ||
1466 | rrq->value = le16_to_cpu(altretry); | ||
1467 | else | ||
1468 | rrq->value = local->manual_retry_count; | ||
1469 | } else if ((rrq->flags & IW_RETRY_MAX)) { | ||
1470 | rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1471 | rrq->value = longretry; | ||
1472 | } else { | ||
1473 | rrq->flags = IW_RETRY_LIMIT; | ||
1474 | rrq->value = shortretry; | ||
1475 | if (shortretry != longretry) | ||
1476 | rrq->flags |= IW_RETRY_MIN; | ||
1477 | } | ||
1478 | } | ||
1479 | return 0; | ||
1480 | } | ||
1481 | |||
1482 | |||
1483 | /* Note! This TX power controlling is experimental and should not be used in | ||
1484 | * production use. It just sets raw power register and does not use any kind of | ||
1485 | * feedback information from the measured TX power (CR58). This is now | ||
1486 | * commented out to make sure that it is not used by accident. TX power | ||
1487 | * configuration will be enabled again after proper algorithm using feedback | ||
1488 | * has been implemented. */ | ||
1489 | |||
1490 | #ifdef RAW_TXPOWER_SETTING | ||
1491 | /* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. | ||
1492 | * This version assumes following mapping: | ||
1493 | * CR31 is 7-bit value with -64 to +63 range. | ||
1494 | * -64 is mapped into +20dBm and +63 into -43dBm. | ||
1495 | * This is certainly not an exact mapping for every card, but at least | ||
1496 | * increasing dBm value should correspond to increasing TX power. | ||
1497 | */ | ||
1498 | |||
1499 | static int prism2_txpower_hfa386x_to_dBm(u16 val) | ||
1500 | { | ||
1501 | signed char tmp; | ||
1502 | |||
1503 | if (val > 255) | ||
1504 | val = 255; | ||
1505 | |||
1506 | tmp = val; | ||
1507 | tmp >>= 2; | ||
1508 | |||
1509 | return -12 - tmp; | ||
1510 | } | ||
1511 | |||
1512 | static u16 prism2_txpower_dBm_to_hfa386x(int val) | ||
1513 | { | ||
1514 | signed char tmp; | ||
1515 | |||
1516 | if (val > 20) | ||
1517 | return 128; | ||
1518 | else if (val < -43) | ||
1519 | return 127; | ||
1520 | |||
1521 | tmp = val; | ||
1522 | tmp = -12 - tmp; | ||
1523 | tmp <<= 2; | ||
1524 | |||
1525 | return (unsigned char) tmp; | ||
1526 | } | ||
1527 | #endif /* RAW_TXPOWER_SETTING */ | ||
1528 | |||
1529 | |||
1530 | static int prism2_ioctl_siwtxpow(struct net_device *dev, | ||
1531 | struct iw_request_info *info, | ||
1532 | struct iw_param *rrq, char *extra) | ||
1533 | { | ||
1534 | struct hostap_interface *iface; | ||
1535 | local_info_t *local; | ||
1536 | #ifdef RAW_TXPOWER_SETTING | ||
1537 | char *tmp; | ||
1538 | #endif | ||
1539 | u16 val; | ||
1540 | int ret = 0; | ||
1541 | |||
1542 | iface = netdev_priv(dev); | ||
1543 | local = iface->local; | ||
1544 | |||
1545 | if (rrq->disabled) { | ||
1546 | if (local->txpower_type != PRISM2_TXPOWER_OFF) { | ||
1547 | val = 0xff; /* use all standby and sleep modes */ | ||
1548 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1549 | HFA386X_CR_A_D_TEST_MODES2, | ||
1550 | &val, NULL); | ||
1551 | printk(KERN_DEBUG "%s: Turning radio off: %s\n", | ||
1552 | dev->name, ret ? "failed" : "OK"); | ||
1553 | local->txpower_type = PRISM2_TXPOWER_OFF; | ||
1554 | } | ||
1555 | return (ret ? -EOPNOTSUPP : 0); | ||
1556 | } | ||
1557 | |||
1558 | if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1559 | val = 0; /* disable all standby and sleep modes */ | ||
1560 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1561 | HFA386X_CR_A_D_TEST_MODES2, &val, NULL); | ||
1562 | printk(KERN_DEBUG "%s: Turning radio on: %s\n", | ||
1563 | dev->name, ret ? "failed" : "OK"); | ||
1564 | local->txpower_type = PRISM2_TXPOWER_UNKNOWN; | ||
1565 | } | ||
1566 | |||
1567 | #ifdef RAW_TXPOWER_SETTING | ||
1568 | if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { | ||
1569 | printk(KERN_DEBUG "Setting ALC on\n"); | ||
1570 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1571 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1572 | (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); | ||
1573 | local->txpower_type = PRISM2_TXPOWER_AUTO; | ||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | if (local->txpower_type != PRISM2_TXPOWER_FIXED) { | ||
1578 | printk(KERN_DEBUG "Setting ALC off\n"); | ||
1579 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1580 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1581 | (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); | ||
1582 | local->txpower_type = PRISM2_TXPOWER_FIXED; | ||
1583 | } | ||
1584 | |||
1585 | if (rrq->flags == IW_TXPOW_DBM) | ||
1586 | tmp = "dBm"; | ||
1587 | else if (rrq->flags == IW_TXPOW_MWATT) | ||
1588 | tmp = "mW"; | ||
1589 | else | ||
1590 | tmp = "UNKNOWN"; | ||
1591 | printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); | ||
1592 | |||
1593 | if (rrq->flags != IW_TXPOW_DBM) { | ||
1594 | printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); | ||
1595 | return -EOPNOTSUPP; | ||
1596 | } | ||
1597 | |||
1598 | local->txpower = rrq->value; | ||
1599 | val = prism2_txpower_dBm_to_hfa386x(local->txpower); | ||
1600 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1601 | HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) | ||
1602 | ret = -EOPNOTSUPP; | ||
1603 | #else /* RAW_TXPOWER_SETTING */ | ||
1604 | if (rrq->fixed) | ||
1605 | ret = -EOPNOTSUPP; | ||
1606 | #endif /* RAW_TXPOWER_SETTING */ | ||
1607 | |||
1608 | return ret; | ||
1609 | } | ||
1610 | |||
1611 | static int prism2_ioctl_giwtxpow(struct net_device *dev, | ||
1612 | struct iw_request_info *info, | ||
1613 | struct iw_param *rrq, char *extra) | ||
1614 | { | ||
1615 | #ifdef RAW_TXPOWER_SETTING | ||
1616 | struct hostap_interface *iface; | ||
1617 | local_info_t *local; | ||
1618 | u16 resp0; | ||
1619 | |||
1620 | iface = netdev_priv(dev); | ||
1621 | local = iface->local; | ||
1622 | |||
1623 | rrq->flags = IW_TXPOW_DBM; | ||
1624 | rrq->disabled = 0; | ||
1625 | rrq->fixed = 0; | ||
1626 | |||
1627 | if (local->txpower_type == PRISM2_TXPOWER_AUTO) { | ||
1628 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, | ||
1629 | HFA386X_CR_MANUAL_TX_POWER, | ||
1630 | NULL, &resp0) == 0) { | ||
1631 | rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); | ||
1632 | } else { | ||
1633 | /* Could not get real txpower; guess 15 dBm */ | ||
1634 | rrq->value = 15; | ||
1635 | } | ||
1636 | } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1637 | rrq->value = 0; | ||
1638 | rrq->disabled = 1; | ||
1639 | } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { | ||
1640 | rrq->value = local->txpower; | ||
1641 | rrq->fixed = 1; | ||
1642 | } else { | ||
1643 | printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", | ||
1644 | local->txpower_type); | ||
1645 | } | ||
1646 | return 0; | ||
1647 | #else /* RAW_TXPOWER_SETTING */ | ||
1648 | return -EOPNOTSUPP; | ||
1649 | #endif /* RAW_TXPOWER_SETTING */ | ||
1650 | } | ||
1651 | |||
1652 | |||
1653 | #ifndef PRISM2_NO_STATION_MODES | ||
1654 | |||
1655 | /* HostScan request works with and without host_roaming mode. In addition, it | ||
1656 | * does not break current association. However, it requires newer station | ||
1657 | * firmware version (>= 1.3.1) than scan request. */ | ||
1658 | static int prism2_request_hostscan(struct net_device *dev, | ||
1659 | u8 *ssid, u8 ssid_len) | ||
1660 | { | ||
1661 | struct hostap_interface *iface; | ||
1662 | local_info_t *local; | ||
1663 | struct hfa384x_hostscan_request scan_req; | ||
1664 | |||
1665 | iface = netdev_priv(dev); | ||
1666 | local = iface->local; | ||
1667 | |||
1668 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1669 | scan_req.channel_list = cpu_to_le16(local->channel_mask & | ||
1670 | local->scan_channel_mask); | ||
1671 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1672 | if (ssid) { | ||
1673 | if (ssid_len > 32) | ||
1674 | return -EINVAL; | ||
1675 | scan_req.target_ssid_len = cpu_to_le16(ssid_len); | ||
1676 | memcpy(scan_req.target_ssid, ssid, ssid_len); | ||
1677 | } | ||
1678 | |||
1679 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
1680 | sizeof(scan_req))) { | ||
1681 | printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); | ||
1682 | return -EINVAL; | ||
1683 | } | ||
1684 | return 0; | ||
1685 | } | ||
1686 | |||
1687 | |||
1688 | static int prism2_request_scan(struct net_device *dev) | ||
1689 | { | ||
1690 | struct hostap_interface *iface; | ||
1691 | local_info_t *local; | ||
1692 | struct hfa384x_scan_request scan_req; | ||
1693 | int ret = 0; | ||
1694 | |||
1695 | iface = netdev_priv(dev); | ||
1696 | local = iface->local; | ||
1697 | |||
1698 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1699 | scan_req.channel_list = cpu_to_le16(local->channel_mask & | ||
1700 | local->scan_channel_mask); | ||
1701 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1702 | |||
1703 | /* FIX: | ||
1704 | * It seems to be enough to set roaming mode for a short moment to | ||
1705 | * host-based and then setup scanrequest data and return the mode to | ||
1706 | * firmware-based. | ||
1707 | * | ||
1708 | * Master mode would need to drop to Managed mode for a short while | ||
1709 | * to make scanning work.. Or sweep through the different channels and | ||
1710 | * use passive scan based on beacons. */ | ||
1711 | |||
1712 | if (!local->host_roaming) | ||
1713 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1714 | HFA384X_ROAMING_HOST); | ||
1715 | |||
1716 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, | ||
1717 | sizeof(scan_req))) { | ||
1718 | printk(KERN_DEBUG "SCANREQUEST failed\n"); | ||
1719 | ret = -EINVAL; | ||
1720 | } | ||
1721 | |||
1722 | if (!local->host_roaming) | ||
1723 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1724 | HFA384X_ROAMING_FIRMWARE); | ||
1725 | |||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1729 | #else /* !PRISM2_NO_STATION_MODES */ | ||
1730 | |||
1731 | static inline int prism2_request_hostscan(struct net_device *dev, | ||
1732 | u8 *ssid, u8 ssid_len) | ||
1733 | { | ||
1734 | return -EOPNOTSUPP; | ||
1735 | } | ||
1736 | |||
1737 | |||
1738 | static inline int prism2_request_scan(struct net_device *dev) | ||
1739 | { | ||
1740 | return -EOPNOTSUPP; | ||
1741 | } | ||
1742 | |||
1743 | #endif /* !PRISM2_NO_STATION_MODES */ | ||
1744 | |||
1745 | |||
1746 | static int prism2_ioctl_siwscan(struct net_device *dev, | ||
1747 | struct iw_request_info *info, | ||
1748 | struct iw_point *data, char *extra) | ||
1749 | { | ||
1750 | struct hostap_interface *iface; | ||
1751 | local_info_t *local; | ||
1752 | int ret; | ||
1753 | u8 *ssid = NULL, ssid_len = 0; | ||
1754 | struct iw_scan_req *req = (struct iw_scan_req *) extra; | ||
1755 | |||
1756 | iface = netdev_priv(dev); | ||
1757 | local = iface->local; | ||
1758 | |||
1759 | if (data->length < sizeof(struct iw_scan_req)) | ||
1760 | req = NULL; | ||
1761 | |||
1762 | if (local->iw_mode == IW_MODE_MASTER) { | ||
1763 | /* In master mode, we just return the results of our local | ||
1764 | * tables, so we don't need to start anything... | ||
1765 | * Jean II */ | ||
1766 | data->length = 0; | ||
1767 | return 0; | ||
1768 | } | ||
1769 | |||
1770 | if (!local->dev_enabled) | ||
1771 | return -ENETDOWN; | ||
1772 | |||
1773 | if (req && data->flags & IW_SCAN_THIS_ESSID) { | ||
1774 | ssid = req->essid; | ||
1775 | ssid_len = req->essid_len; | ||
1776 | |||
1777 | if (ssid_len && | ||
1778 | ((local->iw_mode != IW_MODE_INFRA && | ||
1779 | local->iw_mode != IW_MODE_ADHOC) || | ||
1780 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) | ||
1781 | return -EOPNOTSUPP; | ||
1782 | } | ||
1783 | |||
1784 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) | ||
1785 | ret = prism2_request_hostscan(dev, ssid, ssid_len); | ||
1786 | else | ||
1787 | ret = prism2_request_scan(dev); | ||
1788 | |||
1789 | if (ret == 0) | ||
1790 | local->scan_timestamp = jiffies; | ||
1791 | |||
1792 | /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ | ||
1793 | |||
1794 | return ret; | ||
1795 | } | ||
1796 | |||
1797 | |||
1798 | #ifndef PRISM2_NO_STATION_MODES | ||
1799 | static char * __prism2_translate_scan(local_info_t *local, | ||
1800 | struct hfa384x_hostscan_result *scan, | ||
1801 | struct hostap_bss_info *bss, | ||
1802 | char *current_ev, char *end_buf) | ||
1803 | { | ||
1804 | int i, chan; | ||
1805 | struct iw_event iwe; | ||
1806 | char *current_val; | ||
1807 | u16 capabilities; | ||
1808 | u8 *pos; | ||
1809 | u8 *ssid, *bssid; | ||
1810 | size_t ssid_len; | ||
1811 | char *buf; | ||
1812 | |||
1813 | if (bss) { | ||
1814 | ssid = bss->ssid; | ||
1815 | ssid_len = bss->ssid_len; | ||
1816 | bssid = bss->bssid; | ||
1817 | } else { | ||
1818 | ssid = scan->ssid; | ||
1819 | ssid_len = le16_to_cpu(scan->ssid_len); | ||
1820 | bssid = scan->bssid; | ||
1821 | } | ||
1822 | if (ssid_len > 32) | ||
1823 | ssid_len = 32; | ||
1824 | |||
1825 | /* First entry *MUST* be the AP MAC address */ | ||
1826 | memset(&iwe, 0, sizeof(iwe)); | ||
1827 | iwe.cmd = SIOCGIWAP; | ||
1828 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1829 | memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); | ||
1830 | /* FIX: | ||
1831 | * I do not know how this is possible, but iwe_stream_add_event | ||
1832 | * seems to re-order memcpy execution so that len is set only | ||
1833 | * after copying.. Pre-setting len here "fixes" this, but real | ||
1834 | * problems should be solved (after which these iwe.len | ||
1835 | * settings could be removed from this function). */ | ||
1836 | iwe.len = IW_EV_ADDR_LEN; | ||
1837 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1838 | IW_EV_ADDR_LEN); | ||
1839 | |||
1840 | /* Other entries will be displayed in the order we give them */ | ||
1841 | |||
1842 | memset(&iwe, 0, sizeof(iwe)); | ||
1843 | iwe.cmd = SIOCGIWESSID; | ||
1844 | iwe.u.data.length = ssid_len; | ||
1845 | iwe.u.data.flags = 1; | ||
1846 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1847 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); | ||
1848 | |||
1849 | memset(&iwe, 0, sizeof(iwe)); | ||
1850 | iwe.cmd = SIOCGIWMODE; | ||
1851 | if (bss) { | ||
1852 | capabilities = bss->capab_info; | ||
1853 | } else { | ||
1854 | capabilities = le16_to_cpu(scan->capability); | ||
1855 | } | ||
1856 | if (capabilities & (WLAN_CAPABILITY_ESS | | ||
1857 | WLAN_CAPABILITY_IBSS)) { | ||
1858 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
1859 | iwe.u.mode = IW_MODE_MASTER; | ||
1860 | else | ||
1861 | iwe.u.mode = IW_MODE_ADHOC; | ||
1862 | iwe.len = IW_EV_UINT_LEN; | ||
1863 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1864 | IW_EV_UINT_LEN); | ||
1865 | } | ||
1866 | |||
1867 | memset(&iwe, 0, sizeof(iwe)); | ||
1868 | iwe.cmd = SIOCGIWFREQ; | ||
1869 | if (scan) { | ||
1870 | chan = scan->chid; | ||
1871 | } else if (bss) { | ||
1872 | chan = bss->chan; | ||
1873 | } else { | ||
1874 | chan = 0; | ||
1875 | } | ||
1876 | |||
1877 | if (chan > 0) { | ||
1878 | iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; | ||
1879 | iwe.u.freq.e = 1; | ||
1880 | iwe.len = IW_EV_FREQ_LEN; | ||
1881 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1882 | IW_EV_FREQ_LEN); | ||
1883 | } | ||
1884 | |||
1885 | if (scan) { | ||
1886 | memset(&iwe, 0, sizeof(iwe)); | ||
1887 | iwe.cmd = IWEVQUAL; | ||
1888 | if (local->last_scan_type == PRISM2_HOSTSCAN) { | ||
1889 | iwe.u.qual.level = le16_to_cpu(scan->sl); | ||
1890 | iwe.u.qual.noise = le16_to_cpu(scan->anl); | ||
1891 | } else { | ||
1892 | iwe.u.qual.level = | ||
1893 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); | ||
1894 | iwe.u.qual.noise = | ||
1895 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); | ||
1896 | } | ||
1897 | iwe.len = IW_EV_QUAL_LEN; | ||
1898 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1899 | IW_EV_QUAL_LEN); | ||
1900 | } | ||
1901 | |||
1902 | memset(&iwe, 0, sizeof(iwe)); | ||
1903 | iwe.cmd = SIOCGIWENCODE; | ||
1904 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
1905 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1906 | else | ||
1907 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1908 | iwe.u.data.length = 0; | ||
1909 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1910 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); | ||
1911 | |||
1912 | /* TODO: add SuppRates into BSS table */ | ||
1913 | if (scan) { | ||
1914 | memset(&iwe, 0, sizeof(iwe)); | ||
1915 | iwe.cmd = SIOCGIWRATE; | ||
1916 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1917 | pos = scan->sup_rates; | ||
1918 | for (i = 0; i < sizeof(scan->sup_rates); i++) { | ||
1919 | if (pos[i] == 0) | ||
1920 | break; | ||
1921 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1922 | iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); | ||
1923 | current_val = iwe_stream_add_value( | ||
1924 | current_ev, current_val, end_buf, &iwe, | ||
1925 | IW_EV_PARAM_LEN); | ||
1926 | } | ||
1927 | /* Check if we added any event */ | ||
1928 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | ||
1929 | current_ev = current_val; | ||
1930 | } | ||
1931 | |||
1932 | /* TODO: add BeaconInt,resp_rate,atim into BSS table */ | ||
1933 | buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); | ||
1934 | if (buf && scan) { | ||
1935 | memset(&iwe, 0, sizeof(iwe)); | ||
1936 | iwe.cmd = IWEVCUSTOM; | ||
1937 | sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); | ||
1938 | iwe.u.data.length = strlen(buf); | ||
1939 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1940 | buf); | ||
1941 | |||
1942 | memset(&iwe, 0, sizeof(iwe)); | ||
1943 | iwe.cmd = IWEVCUSTOM; | ||
1944 | sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); | ||
1945 | iwe.u.data.length = strlen(buf); | ||
1946 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1947 | buf); | ||
1948 | |||
1949 | if (local->last_scan_type == PRISM2_HOSTSCAN && | ||
1950 | (capabilities & WLAN_CAPABILITY_IBSS)) { | ||
1951 | memset(&iwe, 0, sizeof(iwe)); | ||
1952 | iwe.cmd = IWEVCUSTOM; | ||
1953 | sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); | ||
1954 | iwe.u.data.length = strlen(buf); | ||
1955 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1956 | &iwe, buf); | ||
1957 | } | ||
1958 | } | ||
1959 | kfree(buf); | ||
1960 | |||
1961 | if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { | ||
1962 | memset(&iwe, 0, sizeof(iwe)); | ||
1963 | iwe.cmd = IWEVGENIE; | ||
1964 | iwe.u.data.length = bss->wpa_ie_len; | ||
1965 | current_ev = iwe_stream_add_point( | ||
1966 | current_ev, end_buf, &iwe, bss->wpa_ie); | ||
1967 | } | ||
1968 | |||
1969 | if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { | ||
1970 | memset(&iwe, 0, sizeof(iwe)); | ||
1971 | iwe.cmd = IWEVGENIE; | ||
1972 | iwe.u.data.length = bss->rsn_ie_len; | ||
1973 | current_ev = iwe_stream_add_point( | ||
1974 | current_ev, end_buf, &iwe, bss->rsn_ie); | ||
1975 | } | ||
1976 | |||
1977 | return current_ev; | ||
1978 | } | ||
1979 | |||
1980 | |||
1981 | /* Translate scan data returned from the card to a card independant | ||
1982 | * format that the Wireless Tools will understand - Jean II */ | ||
1983 | static inline int prism2_translate_scan(local_info_t *local, | ||
1984 | char *buffer, int buflen) | ||
1985 | { | ||
1986 | struct hfa384x_hostscan_result *scan; | ||
1987 | int entry, hostscan; | ||
1988 | char *current_ev = buffer; | ||
1989 | char *end_buf = buffer + buflen; | ||
1990 | struct list_head *ptr; | ||
1991 | |||
1992 | spin_lock_bh(&local->lock); | ||
1993 | |||
1994 | list_for_each(ptr, &local->bss_list) { | ||
1995 | struct hostap_bss_info *bss; | ||
1996 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
1997 | bss->included = 0; | ||
1998 | } | ||
1999 | |||
2000 | hostscan = local->last_scan_type == PRISM2_HOSTSCAN; | ||
2001 | for (entry = 0; entry < local->last_scan_results_count; entry++) { | ||
2002 | int found = 0; | ||
2003 | scan = &local->last_scan_results[entry]; | ||
2004 | |||
2005 | /* Report every SSID if the AP is using multiple SSIDs. If no | ||
2006 | * BSS record is found (e.g., when WPA mode is disabled), | ||
2007 | * report the AP once. */ | ||
2008 | list_for_each(ptr, &local->bss_list) { | ||
2009 | struct hostap_bss_info *bss; | ||
2010 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2011 | if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) { | ||
2012 | bss->included = 1; | ||
2013 | current_ev = __prism2_translate_scan( | ||
2014 | local, scan, bss, current_ev, end_buf); | ||
2015 | found++; | ||
2016 | } | ||
2017 | } | ||
2018 | if (!found) { | ||
2019 | current_ev = __prism2_translate_scan( | ||
2020 | local, scan, NULL, current_ev, end_buf); | ||
2021 | } | ||
2022 | /* Check if there is space for one more entry */ | ||
2023 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2024 | /* Ask user space to try again with a bigger buffer */ | ||
2025 | spin_unlock_bh(&local->lock); | ||
2026 | return -E2BIG; | ||
2027 | } | ||
2028 | } | ||
2029 | |||
2030 | /* Prism2 firmware has limits (32 at least in some versions) for number | ||
2031 | * of BSSes in scan results. Extend this limit by using local BSS list. | ||
2032 | */ | ||
2033 | list_for_each(ptr, &local->bss_list) { | ||
2034 | struct hostap_bss_info *bss; | ||
2035 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2036 | if (bss->included) | ||
2037 | continue; | ||
2038 | current_ev = __prism2_translate_scan(local, NULL, bss, | ||
2039 | current_ev, end_buf); | ||
2040 | /* Check if there is space for one more entry */ | ||
2041 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2042 | /* Ask user space to try again with a bigger buffer */ | ||
2043 | spin_unlock_bh(&local->lock); | ||
2044 | return -E2BIG; | ||
2045 | } | ||
2046 | } | ||
2047 | |||
2048 | spin_unlock_bh(&local->lock); | ||
2049 | |||
2050 | return current_ev - buffer; | ||
2051 | } | ||
2052 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2053 | |||
2054 | |||
2055 | static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, | ||
2056 | struct iw_request_info *info, | ||
2057 | struct iw_point *data, char *extra) | ||
2058 | { | ||
2059 | #ifdef PRISM2_NO_STATION_MODES | ||
2060 | return -EOPNOTSUPP; | ||
2061 | #else /* PRISM2_NO_STATION_MODES */ | ||
2062 | struct hostap_interface *iface; | ||
2063 | local_info_t *local; | ||
2064 | int res; | ||
2065 | |||
2066 | iface = netdev_priv(dev); | ||
2067 | local = iface->local; | ||
2068 | |||
2069 | /* Wait until the scan is finished. We can probably do better | ||
2070 | * than that - Jean II */ | ||
2071 | if (local->scan_timestamp && | ||
2072 | time_before(jiffies, local->scan_timestamp + 3 * HZ)) { | ||
2073 | /* Important note : we don't want to block the caller | ||
2074 | * until results are ready for various reasons. | ||
2075 | * First, managing wait queues is complex and racy | ||
2076 | * (there may be multiple simultaneous callers). | ||
2077 | * Second, we grab some rtnetlink lock before comming | ||
2078 | * here (in dev_ioctl()). | ||
2079 | * Third, the caller can wait on the Wireless Event | ||
2080 | * - Jean II */ | ||
2081 | return -EAGAIN; | ||
2082 | } | ||
2083 | local->scan_timestamp = 0; | ||
2084 | |||
2085 | res = prism2_translate_scan(local, extra, data->length); | ||
2086 | |||
2087 | if (res >= 0) { | ||
2088 | data->length = res; | ||
2089 | return 0; | ||
2090 | } else { | ||
2091 | data->length = 0; | ||
2092 | return res; | ||
2093 | } | ||
2094 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2095 | } | ||
2096 | |||
2097 | |||
2098 | static int prism2_ioctl_giwscan(struct net_device *dev, | ||
2099 | struct iw_request_info *info, | ||
2100 | struct iw_point *data, char *extra) | ||
2101 | { | ||
2102 | struct hostap_interface *iface; | ||
2103 | local_info_t *local; | ||
2104 | int res; | ||
2105 | |||
2106 | iface = netdev_priv(dev); | ||
2107 | local = iface->local; | ||
2108 | |||
2109 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2110 | /* In MASTER mode, it doesn't make sense to go around | ||
2111 | * scanning the frequencies and make the stations we serve | ||
2112 | * wait when what the user is really interested about is the | ||
2113 | * list of stations and access points we are talking to. | ||
2114 | * So, just extract results from our cache... | ||
2115 | * Jean II */ | ||
2116 | |||
2117 | /* Translate to WE format */ | ||
2118 | res = prism2_ap_translate_scan(dev, extra); | ||
2119 | if (res >= 0) { | ||
2120 | printk(KERN_DEBUG "Scan result translation succeeded " | ||
2121 | "(length=%d)\n", res); | ||
2122 | data->length = res; | ||
2123 | return 0; | ||
2124 | } else { | ||
2125 | printk(KERN_DEBUG | ||
2126 | "Scan result translation failed (res=%d)\n", | ||
2127 | res); | ||
2128 | data->length = 0; | ||
2129 | return res; | ||
2130 | } | ||
2131 | } else { | ||
2132 | /* Station mode */ | ||
2133 | return prism2_ioctl_giwscan_sta(dev, info, data, extra); | ||
2134 | } | ||
2135 | } | ||
2136 | |||
2137 | |||
2138 | static const struct iw_priv_args prism2_priv[] = { | ||
2139 | { PRISM2_IOCTL_MONITOR, | ||
2140 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, | ||
2141 | { PRISM2_IOCTL_READMIF, | ||
2142 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | ||
2143 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, | ||
2144 | { PRISM2_IOCTL_WRITEMIF, | ||
2145 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, | ||
2146 | { PRISM2_IOCTL_RESET, | ||
2147 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, | ||
2148 | { PRISM2_IOCTL_INQUIRE, | ||
2149 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, | ||
2150 | { PRISM2_IOCTL_SET_RID_WORD, | ||
2151 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, | ||
2152 | { PRISM2_IOCTL_MACCMD, | ||
2153 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, | ||
2154 | { PRISM2_IOCTL_WDS_ADD, | ||
2155 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, | ||
2156 | { PRISM2_IOCTL_WDS_DEL, | ||
2157 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, | ||
2158 | { PRISM2_IOCTL_ADDMAC, | ||
2159 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, | ||
2160 | { PRISM2_IOCTL_DELMAC, | ||
2161 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, | ||
2162 | { PRISM2_IOCTL_KICKMAC, | ||
2163 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, | ||
2164 | /* --- raw access to sub-ioctls --- */ | ||
2165 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2166 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, | ||
2167 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2168 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2169 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, | ||
2170 | /* --- sub-ioctls handlers --- */ | ||
2171 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2172 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, | ||
2173 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2174 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, | ||
2175 | /* --- sub-ioctls definitions --- */ | ||
2176 | { PRISM2_PARAM_TXRATECTRL, | ||
2177 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, | ||
2178 | { PRISM2_PARAM_TXRATECTRL, | ||
2179 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, | ||
2180 | { PRISM2_PARAM_BEACON_INT, | ||
2181 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, | ||
2182 | { PRISM2_PARAM_BEACON_INT, | ||
2183 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, | ||
2184 | #ifndef PRISM2_NO_STATION_MODES | ||
2185 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2186 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, | ||
2187 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2188 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, | ||
2189 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2190 | { PRISM2_PARAM_ALC, | ||
2191 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, | ||
2192 | { PRISM2_PARAM_ALC, | ||
2193 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, | ||
2194 | { PRISM2_PARAM_DUMP, | ||
2195 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, | ||
2196 | { PRISM2_PARAM_DUMP, | ||
2197 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, | ||
2198 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2199 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, | ||
2200 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2201 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, | ||
2202 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2203 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, | ||
2204 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2205 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, | ||
2206 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2207 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, | ||
2208 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2209 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, | ||
2210 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2211 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, | ||
2212 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2213 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, | ||
2214 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2215 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, | ||
2216 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2217 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, | ||
2218 | { PRISM2_PARAM_MAX_WDS, | ||
2219 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, | ||
2220 | { PRISM2_PARAM_MAX_WDS, | ||
2221 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, | ||
2222 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2223 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, | ||
2224 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2225 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, | ||
2226 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2227 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, | ||
2228 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2229 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, | ||
2230 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2231 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, | ||
2232 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2233 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, | ||
2234 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2235 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, | ||
2236 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2237 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, | ||
2238 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2239 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, | ||
2240 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2241 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, | ||
2242 | #ifndef PRISM2_NO_STATION_MODES | ||
2243 | { PRISM2_PARAM_HOST_ROAMING, | ||
2244 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, | ||
2245 | { PRISM2_PARAM_HOST_ROAMING, | ||
2246 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, | ||
2247 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2248 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2249 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, | ||
2250 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2251 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, | ||
2252 | { PRISM2_PARAM_IEEE_802_1X, | ||
2253 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, | ||
2254 | { PRISM2_PARAM_IEEE_802_1X, | ||
2255 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, | ||
2256 | { PRISM2_PARAM_ANTSEL_TX, | ||
2257 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, | ||
2258 | { PRISM2_PARAM_ANTSEL_TX, | ||
2259 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, | ||
2260 | { PRISM2_PARAM_ANTSEL_RX, | ||
2261 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, | ||
2262 | { PRISM2_PARAM_ANTSEL_RX, | ||
2263 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, | ||
2264 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2265 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, | ||
2266 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2267 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, | ||
2268 | { PRISM2_PARAM_WDS_TYPE, | ||
2269 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, | ||
2270 | { PRISM2_PARAM_WDS_TYPE, | ||
2271 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, | ||
2272 | { PRISM2_PARAM_HOSTSCAN, | ||
2273 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, | ||
2274 | { PRISM2_PARAM_HOSTSCAN, | ||
2275 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, | ||
2276 | { PRISM2_PARAM_AP_SCAN, | ||
2277 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, | ||
2278 | { PRISM2_PARAM_AP_SCAN, | ||
2279 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, | ||
2280 | { PRISM2_PARAM_ENH_SEC, | ||
2281 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, | ||
2282 | { PRISM2_PARAM_ENH_SEC, | ||
2283 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, | ||
2284 | #ifdef PRISM2_IO_DEBUG | ||
2285 | { PRISM2_PARAM_IO_DEBUG, | ||
2286 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, | ||
2287 | { PRISM2_PARAM_IO_DEBUG, | ||
2288 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, | ||
2289 | #endif /* PRISM2_IO_DEBUG */ | ||
2290 | { PRISM2_PARAM_BASIC_RATES, | ||
2291 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, | ||
2292 | { PRISM2_PARAM_BASIC_RATES, | ||
2293 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, | ||
2294 | { PRISM2_PARAM_OPER_RATES, | ||
2295 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, | ||
2296 | { PRISM2_PARAM_OPER_RATES, | ||
2297 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, | ||
2298 | { PRISM2_PARAM_HOSTAPD, | ||
2299 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, | ||
2300 | { PRISM2_PARAM_HOSTAPD, | ||
2301 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, | ||
2302 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2303 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, | ||
2304 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2305 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, | ||
2306 | { PRISM2_PARAM_WPA, | ||
2307 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, | ||
2308 | { PRISM2_PARAM_WPA, | ||
2309 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, | ||
2310 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2311 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, | ||
2312 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2313 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, | ||
2314 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2315 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, | ||
2316 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2317 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, | ||
2318 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2319 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, | ||
2320 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2321 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, | ||
2322 | { PRISM2_PARAM_SCAN_CHANNEL_MASK, | ||
2323 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" }, | ||
2324 | { PRISM2_PARAM_SCAN_CHANNEL_MASK, | ||
2325 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" }, | ||
2326 | }; | ||
2327 | |||
2328 | |||
2329 | static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i) | ||
2330 | { | ||
2331 | struct hostap_interface *iface; | ||
2332 | local_info_t *local; | ||
2333 | |||
2334 | iface = netdev_priv(dev); | ||
2335 | local = iface->local; | ||
2336 | |||
2337 | if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL)) | ||
2338 | return -EOPNOTSUPP; | ||
2339 | |||
2340 | return 0; | ||
2341 | } | ||
2342 | |||
2343 | |||
2344 | static int prism2_ioctl_priv_prism2_param(struct net_device *dev, | ||
2345 | struct iw_request_info *info, | ||
2346 | void *wrqu, char *extra) | ||
2347 | { | ||
2348 | struct hostap_interface *iface; | ||
2349 | local_info_t *local; | ||
2350 | int *i = (int *) extra; | ||
2351 | int param = *i; | ||
2352 | int value = *(i + 1); | ||
2353 | int ret = 0; | ||
2354 | u16 val; | ||
2355 | |||
2356 | iface = netdev_priv(dev); | ||
2357 | local = iface->local; | ||
2358 | |||
2359 | switch (param) { | ||
2360 | case PRISM2_PARAM_TXRATECTRL: | ||
2361 | local->fw_tx_rate_control = value; | ||
2362 | break; | ||
2363 | |||
2364 | case PRISM2_PARAM_BEACON_INT: | ||
2365 | if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || | ||
2366 | local->func->reset_port(dev)) | ||
2367 | ret = -EINVAL; | ||
2368 | else | ||
2369 | local->beacon_int = value; | ||
2370 | break; | ||
2371 | |||
2372 | #ifndef PRISM2_NO_STATION_MODES | ||
2373 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2374 | if (value == local->pseudo_adhoc) | ||
2375 | break; | ||
2376 | |||
2377 | if (value != 0 && value != 1) { | ||
2378 | ret = -EINVAL; | ||
2379 | break; | ||
2380 | } | ||
2381 | |||
2382 | printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", | ||
2383 | dev->name, local->pseudo_adhoc, value); | ||
2384 | local->pseudo_adhoc = value; | ||
2385 | if (local->iw_mode != IW_MODE_ADHOC) | ||
2386 | break; | ||
2387 | |||
2388 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2389 | hostap_get_porttype(local))) { | ||
2390 | ret = -EOPNOTSUPP; | ||
2391 | break; | ||
2392 | } | ||
2393 | |||
2394 | if (local->func->reset_port(dev)) | ||
2395 | ret = -EINVAL; | ||
2396 | break; | ||
2397 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2398 | |||
2399 | case PRISM2_PARAM_ALC: | ||
2400 | printk(KERN_DEBUG "%s: %s ALC\n", dev->name, | ||
2401 | value == 0 ? "Disabling" : "Enabling"); | ||
2402 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
2403 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
2404 | (HFA384X_TEST_CFG_BITS << 8), | ||
2405 | value == 0 ? 0 : 1, &val, NULL); | ||
2406 | break; | ||
2407 | |||
2408 | case PRISM2_PARAM_DUMP: | ||
2409 | local->frame_dump = value; | ||
2410 | break; | ||
2411 | |||
2412 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2413 | if (value < 0 || value > 3) { | ||
2414 | ret = -EINVAL; | ||
2415 | break; | ||
2416 | } | ||
2417 | if (local->ap != NULL) | ||
2418 | local->ap->ap_policy = value; | ||
2419 | break; | ||
2420 | |||
2421 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2422 | if (value < 0 || value > 7 * 24 * 60 * 60) { | ||
2423 | ret = -EINVAL; | ||
2424 | break; | ||
2425 | } | ||
2426 | if (local->ap != NULL) | ||
2427 | local->ap->max_inactivity = value * HZ; | ||
2428 | break; | ||
2429 | |||
2430 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2431 | if (local->ap != NULL) | ||
2432 | local->ap->bridge_packets = value; | ||
2433 | break; | ||
2434 | |||
2435 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2436 | if (value < 0 || value > 65535) { | ||
2437 | ret = -EINVAL; | ||
2438 | break; | ||
2439 | } | ||
2440 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) | ||
2441 | || local->func->reset_port(dev)) | ||
2442 | ret = -EINVAL; | ||
2443 | else | ||
2444 | local->dtim_period = value; | ||
2445 | break; | ||
2446 | |||
2447 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2448 | if (local->ap != NULL) | ||
2449 | local->ap->nullfunc_ack = value; | ||
2450 | break; | ||
2451 | |||
2452 | case PRISM2_PARAM_MAX_WDS: | ||
2453 | local->wds_max_connections = value; | ||
2454 | break; | ||
2455 | |||
2456 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2457 | if (local->ap != NULL) { | ||
2458 | if (!local->ap->autom_ap_wds && value) { | ||
2459 | /* add WDS link to all APs in STA table */ | ||
2460 | hostap_add_wds_links(local); | ||
2461 | } | ||
2462 | local->ap->autom_ap_wds = value; | ||
2463 | } | ||
2464 | break; | ||
2465 | |||
2466 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2467 | local->auth_algs = value; | ||
2468 | if (hostap_set_auth_algs(local)) | ||
2469 | ret = -EINVAL; | ||
2470 | break; | ||
2471 | |||
2472 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2473 | local->monitor_allow_fcserr = value; | ||
2474 | break; | ||
2475 | |||
2476 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2477 | local->host_encrypt = value; | ||
2478 | if (hostap_set_encryption(local) || | ||
2479 | local->func->reset_port(dev)) | ||
2480 | ret = -EINVAL; | ||
2481 | break; | ||
2482 | |||
2483 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2484 | local->host_decrypt = value; | ||
2485 | if (hostap_set_encryption(local) || | ||
2486 | local->func->reset_port(dev)) | ||
2487 | ret = -EINVAL; | ||
2488 | break; | ||
2489 | |||
2490 | #ifndef PRISM2_NO_STATION_MODES | ||
2491 | case PRISM2_PARAM_HOST_ROAMING: | ||
2492 | if (value < 0 || value > 2) { | ||
2493 | ret = -EINVAL; | ||
2494 | break; | ||
2495 | } | ||
2496 | local->host_roaming = value; | ||
2497 | if (hostap_set_roaming(local) || local->func->reset_port(dev)) | ||
2498 | ret = -EINVAL; | ||
2499 | break; | ||
2500 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2501 | |||
2502 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2503 | local->bcrx_sta_key = value; | ||
2504 | break; | ||
2505 | |||
2506 | case PRISM2_PARAM_IEEE_802_1X: | ||
2507 | local->ieee_802_1x = value; | ||
2508 | break; | ||
2509 | |||
2510 | case PRISM2_PARAM_ANTSEL_TX: | ||
2511 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2512 | ret = -EINVAL; | ||
2513 | break; | ||
2514 | } | ||
2515 | local->antsel_tx = value; | ||
2516 | hostap_set_antsel(local); | ||
2517 | break; | ||
2518 | |||
2519 | case PRISM2_PARAM_ANTSEL_RX: | ||
2520 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2521 | ret = -EINVAL; | ||
2522 | break; | ||
2523 | } | ||
2524 | local->antsel_rx = value; | ||
2525 | hostap_set_antsel(local); | ||
2526 | break; | ||
2527 | |||
2528 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2529 | if (value != PRISM2_MONITOR_80211 && | ||
2530 | value != PRISM2_MONITOR_CAPHDR && | ||
2531 | value != PRISM2_MONITOR_PRISM) { | ||
2532 | ret = -EINVAL; | ||
2533 | break; | ||
2534 | } | ||
2535 | local->monitor_type = value; | ||
2536 | if (local->iw_mode == IW_MODE_MONITOR) | ||
2537 | hostap_monitor_set_type(local); | ||
2538 | break; | ||
2539 | |||
2540 | case PRISM2_PARAM_WDS_TYPE: | ||
2541 | local->wds_type = value; | ||
2542 | break; | ||
2543 | |||
2544 | case PRISM2_PARAM_HOSTSCAN: | ||
2545 | { | ||
2546 | struct hfa384x_hostscan_request scan_req; | ||
2547 | u16 rate; | ||
2548 | |||
2549 | memset(&scan_req, 0, sizeof(scan_req)); | ||
2550 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
2551 | switch (value) { | ||
2552 | case 1: rate = HFA384X_RATES_1MBPS; break; | ||
2553 | case 2: rate = HFA384X_RATES_2MBPS; break; | ||
2554 | case 3: rate = HFA384X_RATES_5MBPS; break; | ||
2555 | case 4: rate = HFA384X_RATES_11MBPS; break; | ||
2556 | default: rate = HFA384X_RATES_1MBPS; break; | ||
2557 | } | ||
2558 | scan_req.txrate = cpu_to_le16(rate); | ||
2559 | /* leave SSID empty to accept all SSIDs */ | ||
2560 | |||
2561 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2562 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2563 | HFA384X_PORTTYPE_BSS) || | ||
2564 | local->func->reset_port(dev)) | ||
2565 | printk(KERN_DEBUG "Leaving Host AP mode " | ||
2566 | "for HostScan failed\n"); | ||
2567 | } | ||
2568 | |||
2569 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
2570 | sizeof(scan_req))) { | ||
2571 | printk(KERN_DEBUG "HOSTSCAN failed\n"); | ||
2572 | ret = -EINVAL; | ||
2573 | } | ||
2574 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2575 | wait_queue_t __wait; | ||
2576 | init_waitqueue_entry(&__wait, current); | ||
2577 | add_wait_queue(&local->hostscan_wq, &__wait); | ||
2578 | set_current_state(TASK_INTERRUPTIBLE); | ||
2579 | schedule_timeout(HZ); | ||
2580 | if (signal_pending(current)) | ||
2581 | ret = -EINTR; | ||
2582 | set_current_state(TASK_RUNNING); | ||
2583 | remove_wait_queue(&local->hostscan_wq, &__wait); | ||
2584 | |||
2585 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2586 | HFA384X_PORTTYPE_HOSTAP) || | ||
2587 | local->func->reset_port(dev)) | ||
2588 | printk(KERN_DEBUG "Returning to Host AP mode " | ||
2589 | "after HostScan failed\n"); | ||
2590 | } | ||
2591 | break; | ||
2592 | } | ||
2593 | |||
2594 | case PRISM2_PARAM_AP_SCAN: | ||
2595 | local->passive_scan_interval = value; | ||
2596 | if (timer_pending(&local->passive_scan_timer)) | ||
2597 | del_timer(&local->passive_scan_timer); | ||
2598 | if (value > 0) { | ||
2599 | local->passive_scan_timer.expires = jiffies + | ||
2600 | local->passive_scan_interval * HZ; | ||
2601 | add_timer(&local->passive_scan_timer); | ||
2602 | } | ||
2603 | break; | ||
2604 | |||
2605 | case PRISM2_PARAM_ENH_SEC: | ||
2606 | if (value < 0 || value > 3) { | ||
2607 | ret = -EINVAL; | ||
2608 | break; | ||
2609 | } | ||
2610 | local->enh_sec = value; | ||
2611 | if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, | ||
2612 | local->enh_sec) || | ||
2613 | local->func->reset_port(dev)) { | ||
2614 | printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " | ||
2615 | "1.6.3 or newer\n", dev->name); | ||
2616 | ret = -EOPNOTSUPP; | ||
2617 | } | ||
2618 | break; | ||
2619 | |||
2620 | #ifdef PRISM2_IO_DEBUG | ||
2621 | case PRISM2_PARAM_IO_DEBUG: | ||
2622 | local->io_debug_enabled = value; | ||
2623 | break; | ||
2624 | #endif /* PRISM2_IO_DEBUG */ | ||
2625 | |||
2626 | case PRISM2_PARAM_BASIC_RATES: | ||
2627 | if ((value & local->tx_rate_control) != value || value == 0) { | ||
2628 | printk(KERN_INFO "%s: invalid basic rate set - basic " | ||
2629 | "rates must be in supported rate set\n", | ||
2630 | dev->name); | ||
2631 | ret = -EINVAL; | ||
2632 | break; | ||
2633 | } | ||
2634 | local->basic_rates = value; | ||
2635 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
2636 | local->basic_rates) || | ||
2637 | local->func->reset_port(dev)) | ||
2638 | ret = -EINVAL; | ||
2639 | break; | ||
2640 | |||
2641 | case PRISM2_PARAM_OPER_RATES: | ||
2642 | local->tx_rate_control = value; | ||
2643 | if (hostap_set_rate(dev)) | ||
2644 | ret = -EINVAL; | ||
2645 | break; | ||
2646 | |||
2647 | case PRISM2_PARAM_HOSTAPD: | ||
2648 | ret = hostap_set_hostapd(local, value, 1); | ||
2649 | break; | ||
2650 | |||
2651 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2652 | ret = hostap_set_hostapd_sta(local, value, 1); | ||
2653 | break; | ||
2654 | |||
2655 | case PRISM2_PARAM_WPA: | ||
2656 | local->wpa = value; | ||
2657 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2658 | ret = -EOPNOTSUPP; | ||
2659 | else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
2660 | value ? 1 : 0)) | ||
2661 | ret = -EINVAL; | ||
2662 | break; | ||
2663 | |||
2664 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2665 | local->privacy_invoked = value; | ||
2666 | if (hostap_set_encryption(local) || | ||
2667 | local->func->reset_port(dev)) | ||
2668 | ret = -EINVAL; | ||
2669 | break; | ||
2670 | |||
2671 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2672 | local->tkip_countermeasures = value; | ||
2673 | break; | ||
2674 | |||
2675 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2676 | local->drop_unencrypted = value; | ||
2677 | break; | ||
2678 | |||
2679 | case PRISM2_PARAM_SCAN_CHANNEL_MASK: | ||
2680 | local->scan_channel_mask = value; | ||
2681 | break; | ||
2682 | |||
2683 | default: | ||
2684 | printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", | ||
2685 | dev->name, param); | ||
2686 | ret = -EOPNOTSUPP; | ||
2687 | break; | ||
2688 | } | ||
2689 | |||
2690 | return ret; | ||
2691 | } | ||
2692 | |||
2693 | |||
2694 | static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, | ||
2695 | struct iw_request_info *info, | ||
2696 | void *wrqu, char *extra) | ||
2697 | { | ||
2698 | struct hostap_interface *iface; | ||
2699 | local_info_t *local; | ||
2700 | int *param = (int *) extra; | ||
2701 | int ret = 0; | ||
2702 | |||
2703 | iface = netdev_priv(dev); | ||
2704 | local = iface->local; | ||
2705 | |||
2706 | switch (*param) { | ||
2707 | case PRISM2_PARAM_TXRATECTRL: | ||
2708 | *param = local->fw_tx_rate_control; | ||
2709 | break; | ||
2710 | |||
2711 | case PRISM2_PARAM_BEACON_INT: | ||
2712 | *param = local->beacon_int; | ||
2713 | break; | ||
2714 | |||
2715 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2716 | *param = local->pseudo_adhoc; | ||
2717 | break; | ||
2718 | |||
2719 | case PRISM2_PARAM_ALC: | ||
2720 | ret = -EOPNOTSUPP; /* FIX */ | ||
2721 | break; | ||
2722 | |||
2723 | case PRISM2_PARAM_DUMP: | ||
2724 | *param = local->frame_dump; | ||
2725 | break; | ||
2726 | |||
2727 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2728 | if (local->ap != NULL) | ||
2729 | *param = local->ap->ap_policy; | ||
2730 | else | ||
2731 | ret = -EOPNOTSUPP; | ||
2732 | break; | ||
2733 | |||
2734 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2735 | if (local->ap != NULL) | ||
2736 | *param = local->ap->max_inactivity / HZ; | ||
2737 | else | ||
2738 | ret = -EOPNOTSUPP; | ||
2739 | break; | ||
2740 | |||
2741 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2742 | if (local->ap != NULL) | ||
2743 | *param = local->ap->bridge_packets; | ||
2744 | else | ||
2745 | ret = -EOPNOTSUPP; | ||
2746 | break; | ||
2747 | |||
2748 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2749 | *param = local->dtim_period; | ||
2750 | break; | ||
2751 | |||
2752 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2753 | if (local->ap != NULL) | ||
2754 | *param = local->ap->nullfunc_ack; | ||
2755 | else | ||
2756 | ret = -EOPNOTSUPP; | ||
2757 | break; | ||
2758 | |||
2759 | case PRISM2_PARAM_MAX_WDS: | ||
2760 | *param = local->wds_max_connections; | ||
2761 | break; | ||
2762 | |||
2763 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2764 | if (local->ap != NULL) | ||
2765 | *param = local->ap->autom_ap_wds; | ||
2766 | else | ||
2767 | ret = -EOPNOTSUPP; | ||
2768 | break; | ||
2769 | |||
2770 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2771 | *param = local->auth_algs; | ||
2772 | break; | ||
2773 | |||
2774 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2775 | *param = local->monitor_allow_fcserr; | ||
2776 | break; | ||
2777 | |||
2778 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2779 | *param = local->host_encrypt; | ||
2780 | break; | ||
2781 | |||
2782 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2783 | *param = local->host_decrypt; | ||
2784 | break; | ||
2785 | |||
2786 | case PRISM2_PARAM_HOST_ROAMING: | ||
2787 | *param = local->host_roaming; | ||
2788 | break; | ||
2789 | |||
2790 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2791 | *param = local->bcrx_sta_key; | ||
2792 | break; | ||
2793 | |||
2794 | case PRISM2_PARAM_IEEE_802_1X: | ||
2795 | *param = local->ieee_802_1x; | ||
2796 | break; | ||
2797 | |||
2798 | case PRISM2_PARAM_ANTSEL_TX: | ||
2799 | *param = local->antsel_tx; | ||
2800 | break; | ||
2801 | |||
2802 | case PRISM2_PARAM_ANTSEL_RX: | ||
2803 | *param = local->antsel_rx; | ||
2804 | break; | ||
2805 | |||
2806 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2807 | *param = local->monitor_type; | ||
2808 | break; | ||
2809 | |||
2810 | case PRISM2_PARAM_WDS_TYPE: | ||
2811 | *param = local->wds_type; | ||
2812 | break; | ||
2813 | |||
2814 | case PRISM2_PARAM_HOSTSCAN: | ||
2815 | ret = -EOPNOTSUPP; | ||
2816 | break; | ||
2817 | |||
2818 | case PRISM2_PARAM_AP_SCAN: | ||
2819 | *param = local->passive_scan_interval; | ||
2820 | break; | ||
2821 | |||
2822 | case PRISM2_PARAM_ENH_SEC: | ||
2823 | *param = local->enh_sec; | ||
2824 | break; | ||
2825 | |||
2826 | #ifdef PRISM2_IO_DEBUG | ||
2827 | case PRISM2_PARAM_IO_DEBUG: | ||
2828 | *param = local->io_debug_enabled; | ||
2829 | break; | ||
2830 | #endif /* PRISM2_IO_DEBUG */ | ||
2831 | |||
2832 | case PRISM2_PARAM_BASIC_RATES: | ||
2833 | *param = local->basic_rates; | ||
2834 | break; | ||
2835 | |||
2836 | case PRISM2_PARAM_OPER_RATES: | ||
2837 | *param = local->tx_rate_control; | ||
2838 | break; | ||
2839 | |||
2840 | case PRISM2_PARAM_HOSTAPD: | ||
2841 | *param = local->hostapd; | ||
2842 | break; | ||
2843 | |||
2844 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2845 | *param = local->hostapd_sta; | ||
2846 | break; | ||
2847 | |||
2848 | case PRISM2_PARAM_WPA: | ||
2849 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2850 | ret = -EOPNOTSUPP; | ||
2851 | *param = local->wpa; | ||
2852 | break; | ||
2853 | |||
2854 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2855 | *param = local->privacy_invoked; | ||
2856 | break; | ||
2857 | |||
2858 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2859 | *param = local->tkip_countermeasures; | ||
2860 | break; | ||
2861 | |||
2862 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2863 | *param = local->drop_unencrypted; | ||
2864 | break; | ||
2865 | |||
2866 | case PRISM2_PARAM_SCAN_CHANNEL_MASK: | ||
2867 | *param = local->scan_channel_mask; | ||
2868 | break; | ||
2869 | |||
2870 | default: | ||
2871 | printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", | ||
2872 | dev->name, *param); | ||
2873 | ret = -EOPNOTSUPP; | ||
2874 | break; | ||
2875 | } | ||
2876 | |||
2877 | return ret; | ||
2878 | } | ||
2879 | |||
2880 | |||
2881 | static int prism2_ioctl_priv_readmif(struct net_device *dev, | ||
2882 | struct iw_request_info *info, | ||
2883 | void *wrqu, char *extra) | ||
2884 | { | ||
2885 | struct hostap_interface *iface; | ||
2886 | local_info_t *local; | ||
2887 | u16 resp0; | ||
2888 | |||
2889 | iface = netdev_priv(dev); | ||
2890 | local = iface->local; | ||
2891 | |||
2892 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, | ||
2893 | &resp0)) | ||
2894 | return -EOPNOTSUPP; | ||
2895 | else | ||
2896 | *extra = resp0; | ||
2897 | |||
2898 | return 0; | ||
2899 | } | ||
2900 | |||
2901 | |||
2902 | static int prism2_ioctl_priv_writemif(struct net_device *dev, | ||
2903 | struct iw_request_info *info, | ||
2904 | void *wrqu, char *extra) | ||
2905 | { | ||
2906 | struct hostap_interface *iface; | ||
2907 | local_info_t *local; | ||
2908 | u16 cr, val; | ||
2909 | |||
2910 | iface = netdev_priv(dev); | ||
2911 | local = iface->local; | ||
2912 | |||
2913 | cr = *extra; | ||
2914 | val = *(extra + 1); | ||
2915 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) | ||
2916 | return -EOPNOTSUPP; | ||
2917 | |||
2918 | return 0; | ||
2919 | } | ||
2920 | |||
2921 | |||
2922 | static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i) | ||
2923 | { | ||
2924 | struct hostap_interface *iface; | ||
2925 | local_info_t *local; | ||
2926 | int ret = 0; | ||
2927 | u32 mode; | ||
2928 | |||
2929 | iface = netdev_priv(dev); | ||
2930 | local = iface->local; | ||
2931 | |||
2932 | printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor " | ||
2933 | "- update software to use iwconfig mode monitor\n", | ||
2934 | dev->name, current->pid, current->comm); | ||
2935 | |||
2936 | /* Backward compatibility code - this can be removed at some point */ | ||
2937 | |||
2938 | if (*i == 0) { | ||
2939 | /* Disable monitor mode - old mode was not saved, so go to | ||
2940 | * Master mode */ | ||
2941 | mode = IW_MODE_MASTER; | ||
2942 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2943 | } else if (*i == 1) { | ||
2944 | /* netlink socket mode is not supported anymore since it did | ||
2945 | * not separate different devices from each other and was not | ||
2946 | * best method for delivering large amount of packets to | ||
2947 | * user space */ | ||
2948 | ret = -EOPNOTSUPP; | ||
2949 | } else if (*i == 2 || *i == 3) { | ||
2950 | switch (*i) { | ||
2951 | case 2: | ||
2952 | local->monitor_type = PRISM2_MONITOR_80211; | ||
2953 | break; | ||
2954 | case 3: | ||
2955 | local->monitor_type = PRISM2_MONITOR_PRISM; | ||
2956 | break; | ||
2957 | } | ||
2958 | mode = IW_MODE_MONITOR; | ||
2959 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2960 | hostap_monitor_mode_enable(local); | ||
2961 | } else | ||
2962 | ret = -EINVAL; | ||
2963 | |||
2964 | return ret; | ||
2965 | } | ||
2966 | |||
2967 | |||
2968 | static int prism2_ioctl_priv_reset(struct net_device *dev, int *i) | ||
2969 | { | ||
2970 | struct hostap_interface *iface; | ||
2971 | local_info_t *local; | ||
2972 | |||
2973 | iface = netdev_priv(dev); | ||
2974 | local = iface->local; | ||
2975 | |||
2976 | printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i); | ||
2977 | switch (*i) { | ||
2978 | case 0: | ||
2979 | /* Disable and enable card */ | ||
2980 | local->func->hw_shutdown(dev, 1); | ||
2981 | local->func->hw_config(dev, 0); | ||
2982 | break; | ||
2983 | |||
2984 | case 1: | ||
2985 | /* COR sreset */ | ||
2986 | local->func->hw_reset(dev); | ||
2987 | break; | ||
2988 | |||
2989 | case 2: | ||
2990 | /* Disable and enable port 0 */ | ||
2991 | local->func->reset_port(dev); | ||
2992 | break; | ||
2993 | |||
2994 | case 3: | ||
2995 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
2996 | if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, | ||
2997 | NULL)) | ||
2998 | return -EINVAL; | ||
2999 | break; | ||
3000 | |||
3001 | case 4: | ||
3002 | if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, | ||
3003 | NULL)) | ||
3004 | return -EINVAL; | ||
3005 | break; | ||
3006 | |||
3007 | default: | ||
3008 | printk(KERN_DEBUG "Unknown reset request %d\n", *i); | ||
3009 | return -EOPNOTSUPP; | ||
3010 | } | ||
3011 | |||
3012 | return 0; | ||
3013 | } | ||
3014 | |||
3015 | |||
3016 | static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i) | ||
3017 | { | ||
3018 | int rid = *i; | ||
3019 | int value = *(i + 1); | ||
3020 | |||
3021 | printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value); | ||
3022 | |||
3023 | if (hostap_set_word(dev, rid, value)) | ||
3024 | return -EINVAL; | ||
3025 | |||
3026 | return 0; | ||
3027 | } | ||
3028 | |||
3029 | |||
3030 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3031 | static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd) | ||
3032 | { | ||
3033 | int ret = 0; | ||
3034 | |||
3035 | switch (*cmd) { | ||
3036 | case AP_MAC_CMD_POLICY_OPEN: | ||
3037 | local->ap->mac_restrictions.policy = MAC_POLICY_OPEN; | ||
3038 | break; | ||
3039 | case AP_MAC_CMD_POLICY_ALLOW: | ||
3040 | local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW; | ||
3041 | break; | ||
3042 | case AP_MAC_CMD_POLICY_DENY: | ||
3043 | local->ap->mac_restrictions.policy = MAC_POLICY_DENY; | ||
3044 | break; | ||
3045 | case AP_MAC_CMD_FLUSH: | ||
3046 | ap_control_flush_macs(&local->ap->mac_restrictions); | ||
3047 | break; | ||
3048 | case AP_MAC_CMD_KICKALL: | ||
3049 | ap_control_kickall(local->ap); | ||
3050 | hostap_deauth_all_stas(local->dev, local->ap, 0); | ||
3051 | break; | ||
3052 | default: | ||
3053 | ret = -EOPNOTSUPP; | ||
3054 | break; | ||
3055 | } | ||
3056 | |||
3057 | return ret; | ||
3058 | } | ||
3059 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3060 | |||
3061 | |||
3062 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3063 | static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) | ||
3064 | { | ||
3065 | struct prism2_download_param *param; | ||
3066 | int ret = 0; | ||
3067 | |||
3068 | if (p->length < sizeof(struct prism2_download_param) || | ||
3069 | p->length > 1024 || !p->pointer) | ||
3070 | return -EINVAL; | ||
3071 | |||
3072 | param = (struct prism2_download_param *) | ||
3073 | kmalloc(p->length, GFP_KERNEL); | ||
3074 | if (param == NULL) | ||
3075 | return -ENOMEM; | ||
3076 | |||
3077 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3078 | ret = -EFAULT; | ||
3079 | goto out; | ||
3080 | } | ||
3081 | |||
3082 | if (p->length < sizeof(struct prism2_download_param) + | ||
3083 | param->num_areas * sizeof(struct prism2_download_area)) { | ||
3084 | ret = -EINVAL; | ||
3085 | goto out; | ||
3086 | } | ||
3087 | |||
3088 | ret = local->func->download(local, param); | ||
3089 | |||
3090 | out: | ||
3091 | if (param != NULL) | ||
3092 | kfree(param); | ||
3093 | |||
3094 | return ret; | ||
3095 | } | ||
3096 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3097 | |||
3098 | |||
3099 | static int prism2_set_genericelement(struct net_device *dev, u8 *elem, | ||
3100 | size_t len) | ||
3101 | { | ||
3102 | struct hostap_interface *iface = dev->priv; | ||
3103 | local_info_t *local = iface->local; | ||
3104 | u8 *buf; | ||
3105 | |||
3106 | /* | ||
3107 | * Add 16-bit length in the beginning of the buffer because Prism2 RID | ||
3108 | * includes it. | ||
3109 | */ | ||
3110 | buf = kmalloc(len + 2, GFP_KERNEL); | ||
3111 | if (buf == NULL) | ||
3112 | return -ENOMEM; | ||
3113 | |||
3114 | *((u16 *) buf) = cpu_to_le16(len); | ||
3115 | memcpy(buf + 2, elem, len); | ||
3116 | |||
3117 | kfree(local->generic_elem); | ||
3118 | local->generic_elem = buf; | ||
3119 | local->generic_elem_len = len + 2; | ||
3120 | |||
3121 | return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, | ||
3122 | buf, len + 2); | ||
3123 | } | ||
3124 | |||
3125 | |||
3126 | static int prism2_ioctl_siwauth(struct net_device *dev, | ||
3127 | struct iw_request_info *info, | ||
3128 | struct iw_param *data, char *extra) | ||
3129 | { | ||
3130 | struct hostap_interface *iface = dev->priv; | ||
3131 | local_info_t *local = iface->local; | ||
3132 | |||
3133 | switch (data->flags & IW_AUTH_INDEX) { | ||
3134 | case IW_AUTH_WPA_VERSION: | ||
3135 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3136 | case IW_AUTH_CIPHER_GROUP: | ||
3137 | case IW_AUTH_KEY_MGMT: | ||
3138 | /* | ||
3139 | * Host AP driver does not use these parameters and allows | ||
3140 | * wpa_supplicant to control them internally. | ||
3141 | */ | ||
3142 | break; | ||
3143 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3144 | local->tkip_countermeasures = data->value; | ||
3145 | break; | ||
3146 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3147 | local->drop_unencrypted = data->value; | ||
3148 | break; | ||
3149 | case IW_AUTH_80211_AUTH_ALG: | ||
3150 | local->auth_algs = data->value; | ||
3151 | break; | ||
3152 | case IW_AUTH_WPA_ENABLED: | ||
3153 | if (data->value == 0) { | ||
3154 | local->wpa = 0; | ||
3155 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3156 | break; | ||
3157 | prism2_set_genericelement(dev, "", 0); | ||
3158 | local->host_roaming = 0; | ||
3159 | local->privacy_invoked = 0; | ||
3160 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
3161 | 0) || | ||
3162 | hostap_set_roaming(local) || | ||
3163 | hostap_set_encryption(local) || | ||
3164 | local->func->reset_port(dev)) | ||
3165 | return -EINVAL; | ||
3166 | break; | ||
3167 | } | ||
3168 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3169 | return -EOPNOTSUPP; | ||
3170 | local->host_roaming = 2; | ||
3171 | local->privacy_invoked = 1; | ||
3172 | local->wpa = 1; | ||
3173 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || | ||
3174 | hostap_set_roaming(local) || | ||
3175 | hostap_set_encryption(local) || | ||
3176 | local->func->reset_port(dev)) | ||
3177 | return -EINVAL; | ||
3178 | break; | ||
3179 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3180 | local->ieee_802_1x = data->value; | ||
3181 | break; | ||
3182 | case IW_AUTH_PRIVACY_INVOKED: | ||
3183 | local->privacy_invoked = data->value; | ||
3184 | break; | ||
3185 | default: | ||
3186 | return -EOPNOTSUPP; | ||
3187 | } | ||
3188 | return 0; | ||
3189 | } | ||
3190 | |||
3191 | |||
3192 | static int prism2_ioctl_giwauth(struct net_device *dev, | ||
3193 | struct iw_request_info *info, | ||
3194 | struct iw_param *data, char *extra) | ||
3195 | { | ||
3196 | struct hostap_interface *iface = dev->priv; | ||
3197 | local_info_t *local = iface->local; | ||
3198 | |||
3199 | switch (data->flags & IW_AUTH_INDEX) { | ||
3200 | case IW_AUTH_WPA_VERSION: | ||
3201 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3202 | case IW_AUTH_CIPHER_GROUP: | ||
3203 | case IW_AUTH_KEY_MGMT: | ||
3204 | /* | ||
3205 | * Host AP driver does not use these parameters and allows | ||
3206 | * wpa_supplicant to control them internally. | ||
3207 | */ | ||
3208 | return -EOPNOTSUPP; | ||
3209 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3210 | data->value = local->tkip_countermeasures; | ||
3211 | break; | ||
3212 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3213 | data->value = local->drop_unencrypted; | ||
3214 | break; | ||
3215 | case IW_AUTH_80211_AUTH_ALG: | ||
3216 | data->value = local->auth_algs; | ||
3217 | break; | ||
3218 | case IW_AUTH_WPA_ENABLED: | ||
3219 | data->value = local->wpa; | ||
3220 | break; | ||
3221 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3222 | data->value = local->ieee_802_1x; | ||
3223 | break; | ||
3224 | default: | ||
3225 | return -EOPNOTSUPP; | ||
3226 | } | ||
3227 | return 0; | ||
3228 | } | ||
3229 | |||
3230 | |||
3231 | static int prism2_ioctl_siwencodeext(struct net_device *dev, | ||
3232 | struct iw_request_info *info, | ||
3233 | struct iw_point *erq, char *extra) | ||
3234 | { | ||
3235 | struct hostap_interface *iface = dev->priv; | ||
3236 | local_info_t *local = iface->local; | ||
3237 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3238 | int i, ret = 0; | ||
3239 | struct ieee80211_crypto_ops *ops; | ||
3240 | struct ieee80211_crypt_data **crypt; | ||
3241 | void *sta_ptr; | ||
3242 | u8 *addr; | ||
3243 | const char *alg, *module; | ||
3244 | |||
3245 | i = erq->flags & IW_ENCODE_INDEX; | ||
3246 | if (i > WEP_KEYS) | ||
3247 | return -EINVAL; | ||
3248 | if (i < 1 || i > WEP_KEYS) | ||
3249 | i = local->tx_keyidx; | ||
3250 | else | ||
3251 | i--; | ||
3252 | if (i < 0 || i >= WEP_KEYS) | ||
3253 | return -EINVAL; | ||
3254 | |||
3255 | addr = ext->addr.sa_data; | ||
3256 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3257 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3258 | sta_ptr = NULL; | ||
3259 | crypt = &local->crypt[i]; | ||
3260 | } else { | ||
3261 | if (i != 0) | ||
3262 | return -EINVAL; | ||
3263 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3264 | if (sta_ptr == NULL) { | ||
3265 | if (local->iw_mode == IW_MODE_INFRA) { | ||
3266 | /* | ||
3267 | * TODO: add STA entry for the current AP so | ||
3268 | * that unicast key can be used. For now, this | ||
3269 | * is emulated by using default key idx 0. | ||
3270 | */ | ||
3271 | i = 0; | ||
3272 | crypt = &local->crypt[i]; | ||
3273 | } else | ||
3274 | return -EINVAL; | ||
3275 | } | ||
3276 | } | ||
3277 | |||
3278 | if ((erq->flags & IW_ENCODE_DISABLED) || | ||
3279 | ext->alg == IW_ENCODE_ALG_NONE) { | ||
3280 | if (*crypt) | ||
3281 | prism2_crypt_delayed_deinit(local, crypt); | ||
3282 | goto done; | ||
3283 | } | ||
3284 | |||
3285 | switch (ext->alg) { | ||
3286 | case IW_ENCODE_ALG_WEP: | ||
3287 | alg = "WEP"; | ||
3288 | module = "ieee80211_crypt_wep"; | ||
3289 | break; | ||
3290 | case IW_ENCODE_ALG_TKIP: | ||
3291 | alg = "TKIP"; | ||
3292 | module = "ieee80211_crypt_tkip"; | ||
3293 | break; | ||
3294 | case IW_ENCODE_ALG_CCMP: | ||
3295 | alg = "CCMP"; | ||
3296 | module = "ieee80211_crypt_ccmp"; | ||
3297 | break; | ||
3298 | default: | ||
3299 | printk(KERN_DEBUG "%s: unsupported algorithm %d\n", | ||
3300 | local->dev->name, ext->alg); | ||
3301 | ret = -EOPNOTSUPP; | ||
3302 | goto done; | ||
3303 | } | ||
3304 | |||
3305 | ops = ieee80211_get_crypto_ops(alg); | ||
3306 | if (ops == NULL) { | ||
3307 | request_module(module); | ||
3308 | ops = ieee80211_get_crypto_ops(alg); | ||
3309 | } | ||
3310 | if (ops == NULL) { | ||
3311 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3312 | local->dev->name, alg); | ||
3313 | ret = -EOPNOTSUPP; | ||
3314 | goto done; | ||
3315 | } | ||
3316 | |||
3317 | if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { | ||
3318 | /* | ||
3319 | * Per station encryption and other than WEP algorithms | ||
3320 | * require host-based encryption, so force them on | ||
3321 | * automatically. | ||
3322 | */ | ||
3323 | local->host_decrypt = local->host_encrypt = 1; | ||
3324 | } | ||
3325 | |||
3326 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3327 | struct ieee80211_crypt_data *new_crypt; | ||
3328 | |||
3329 | prism2_crypt_delayed_deinit(local, crypt); | ||
3330 | |||
3331 | new_crypt = (struct ieee80211_crypt_data *) | ||
3332 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
3333 | GFP_KERNEL); | ||
3334 | if (new_crypt == NULL) { | ||
3335 | ret = -ENOMEM; | ||
3336 | goto done; | ||
3337 | } | ||
3338 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
3339 | new_crypt->ops = ops; | ||
3340 | new_crypt->priv = new_crypt->ops->init(i); | ||
3341 | if (new_crypt->priv == NULL) { | ||
3342 | kfree(new_crypt); | ||
3343 | ret = -EINVAL; | ||
3344 | goto done; | ||
3345 | } | ||
3346 | |||
3347 | *crypt = new_crypt; | ||
3348 | } | ||
3349 | |||
3350 | /* | ||
3351 | * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the | ||
3352 | * existing seq# should not be changed. | ||
3353 | * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# | ||
3354 | * should be changed to something else than zero. | ||
3355 | */ | ||
3356 | if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) | ||
3357 | && (*crypt)->ops->set_key && | ||
3358 | (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, | ||
3359 | (*crypt)->priv) < 0) { | ||
3360 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3361 | local->dev->name); | ||
3362 | ret = -EINVAL; | ||
3363 | goto done; | ||
3364 | } | ||
3365 | |||
3366 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
3367 | if (!sta_ptr) | ||
3368 | local->tx_keyidx = i; | ||
3369 | else if (i) { | ||
3370 | ret = -EINVAL; | ||
3371 | goto done; | ||
3372 | } | ||
3373 | } | ||
3374 | |||
3375 | |||
3376 | if (sta_ptr == NULL && ext->key_len > 0) { | ||
3377 | int first = 1, j; | ||
3378 | for (j = 0; j < WEP_KEYS; j++) { | ||
3379 | if (j != i && local->crypt[j]) { | ||
3380 | first = 0; | ||
3381 | break; | ||
3382 | } | ||
3383 | } | ||
3384 | if (first) | ||
3385 | local->tx_keyidx = i; | ||
3386 | } | ||
3387 | |||
3388 | done: | ||
3389 | if (sta_ptr) | ||
3390 | hostap_handle_sta_release(sta_ptr); | ||
3391 | |||
3392 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
3393 | |||
3394 | /* | ||
3395 | * Do not reset port0 if card is in Managed mode since resetting will | ||
3396 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3397 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3398 | * after WEP configuration. However, keys are apparently changed at | ||
3399 | * least in Managed mode. | ||
3400 | */ | ||
3401 | if (ret == 0 && | ||
3402 | (hostap_set_encryption(local) || | ||
3403 | (local->iw_mode != IW_MODE_INFRA && | ||
3404 | local->func->reset_port(local->dev)))) | ||
3405 | ret = -EINVAL; | ||
3406 | |||
3407 | return ret; | ||
3408 | } | ||
3409 | |||
3410 | |||
3411 | static int prism2_ioctl_giwencodeext(struct net_device *dev, | ||
3412 | struct iw_request_info *info, | ||
3413 | struct iw_point *erq, char *extra) | ||
3414 | { | ||
3415 | struct hostap_interface *iface = dev->priv; | ||
3416 | local_info_t *local = iface->local; | ||
3417 | struct ieee80211_crypt_data **crypt; | ||
3418 | void *sta_ptr; | ||
3419 | int max_key_len, i; | ||
3420 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3421 | u8 *addr; | ||
3422 | |||
3423 | max_key_len = erq->length - sizeof(*ext); | ||
3424 | if (max_key_len < 0) | ||
3425 | return -EINVAL; | ||
3426 | |||
3427 | i = erq->flags & IW_ENCODE_INDEX; | ||
3428 | if (i < 1 || i > WEP_KEYS) | ||
3429 | i = local->tx_keyidx; | ||
3430 | else | ||
3431 | i--; | ||
3432 | |||
3433 | addr = ext->addr.sa_data; | ||
3434 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3435 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3436 | sta_ptr = NULL; | ||
3437 | crypt = &local->crypt[i]; | ||
3438 | } else { | ||
3439 | i = 0; | ||
3440 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3441 | if (sta_ptr == NULL) | ||
3442 | return -EINVAL; | ||
3443 | } | ||
3444 | erq->flags = i + 1; | ||
3445 | memset(ext, 0, sizeof(*ext)); | ||
3446 | |||
3447 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3448 | ext->alg = IW_ENCODE_ALG_NONE; | ||
3449 | ext->key_len = 0; | ||
3450 | erq->flags |= IW_ENCODE_DISABLED; | ||
3451 | } else { | ||
3452 | if (strcmp((*crypt)->ops->name, "WEP") == 0) | ||
3453 | ext->alg = IW_ENCODE_ALG_WEP; | ||
3454 | else if (strcmp((*crypt)->ops->name, "TKIP") == 0) | ||
3455 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
3456 | else if (strcmp((*crypt)->ops->name, "CCMP") == 0) | ||
3457 | ext->alg = IW_ENCODE_ALG_CCMP; | ||
3458 | else | ||
3459 | return -EINVAL; | ||
3460 | |||
3461 | if ((*crypt)->ops->get_key) { | ||
3462 | ext->key_len = | ||
3463 | (*crypt)->ops->get_key(ext->key, | ||
3464 | max_key_len, | ||
3465 | ext->tx_seq, | ||
3466 | (*crypt)->priv); | ||
3467 | if (ext->key_len && | ||
3468 | (ext->alg == IW_ENCODE_ALG_TKIP || | ||
3469 | ext->alg == IW_ENCODE_ALG_CCMP)) | ||
3470 | ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; | ||
3471 | } | ||
3472 | } | ||
3473 | |||
3474 | if (sta_ptr) | ||
3475 | hostap_handle_sta_release(sta_ptr); | ||
3476 | |||
3477 | return 0; | ||
3478 | } | ||
3479 | |||
3480 | |||
3481 | static int prism2_ioctl_set_encryption(local_info_t *local, | ||
3482 | struct prism2_hostapd_param *param, | ||
3483 | int param_len) | ||
3484 | { | ||
3485 | int ret = 0; | ||
3486 | struct ieee80211_crypto_ops *ops; | ||
3487 | struct ieee80211_crypt_data **crypt; | ||
3488 | void *sta_ptr; | ||
3489 | |||
3490 | param->u.crypt.err = 0; | ||
3491 | param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
3492 | |||
3493 | if (param_len != | ||
3494 | (int) ((char *) param->u.crypt.key - (char *) param) + | ||
3495 | param->u.crypt.key_len) | ||
3496 | return -EINVAL; | ||
3497 | |||
3498 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3499 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3500 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3501 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3502 | return -EINVAL; | ||
3503 | sta_ptr = NULL; | ||
3504 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3505 | } else { | ||
3506 | if (param->u.crypt.idx) | ||
3507 | return -EINVAL; | ||
3508 | sta_ptr = ap_crypt_get_ptrs( | ||
3509 | local->ap, param->sta_addr, | ||
3510 | (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), | ||
3511 | &crypt); | ||
3512 | |||
3513 | if (sta_ptr == NULL) { | ||
3514 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3515 | return -EINVAL; | ||
3516 | } | ||
3517 | } | ||
3518 | |||
3519 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
3520 | if (crypt) | ||
3521 | prism2_crypt_delayed_deinit(local, crypt); | ||
3522 | goto done; | ||
3523 | } | ||
3524 | |||
3525 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3526 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
3527 | request_module("ieee80211_crypt_wep"); | ||
3528 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3529 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
3530 | request_module("ieee80211_crypt_tkip"); | ||
3531 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3532 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
3533 | request_module("ieee80211_crypt_ccmp"); | ||
3534 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3535 | } | ||
3536 | if (ops == NULL) { | ||
3537 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3538 | local->dev->name, param->u.crypt.alg); | ||
3539 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; | ||
3540 | ret = -EINVAL; | ||
3541 | goto done; | ||
3542 | } | ||
3543 | |||
3544 | /* station based encryption and other than WEP algorithms require | ||
3545 | * host-based encryption, so force them on automatically */ | ||
3546 | local->host_decrypt = local->host_encrypt = 1; | ||
3547 | |||
3548 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3549 | struct ieee80211_crypt_data *new_crypt; | ||
3550 | |||
3551 | prism2_crypt_delayed_deinit(local, crypt); | ||
3552 | |||
3553 | new_crypt = (struct ieee80211_crypt_data *) | ||
3554 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
3555 | GFP_KERNEL); | ||
3556 | if (new_crypt == NULL) { | ||
3557 | ret = -ENOMEM; | ||
3558 | goto done; | ||
3559 | } | ||
3560 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
3561 | new_crypt->ops = ops; | ||
3562 | new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); | ||
3563 | if (new_crypt->priv == NULL) { | ||
3564 | kfree(new_crypt); | ||
3565 | param->u.crypt.err = | ||
3566 | HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
3567 | ret = -EINVAL; | ||
3568 | goto done; | ||
3569 | } | ||
3570 | |||
3571 | *crypt = new_crypt; | ||
3572 | } | ||
3573 | |||
3574 | if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || | ||
3575 | param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && | ||
3576 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
3577 | param->u.crypt.key_len, param->u.crypt.seq, | ||
3578 | (*crypt)->priv) < 0) { | ||
3579 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3580 | local->dev->name); | ||
3581 | param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; | ||
3582 | ret = -EINVAL; | ||
3583 | goto done; | ||
3584 | } | ||
3585 | |||
3586 | if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { | ||
3587 | if (!sta_ptr) | ||
3588 | local->tx_keyidx = param->u.crypt.idx; | ||
3589 | else if (param->u.crypt.idx) { | ||
3590 | printk(KERN_DEBUG "%s: TX key idx setting failed\n", | ||
3591 | local->dev->name); | ||
3592 | param->u.crypt.err = | ||
3593 | HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; | ||
3594 | ret = -EINVAL; | ||
3595 | goto done; | ||
3596 | } | ||
3597 | } | ||
3598 | |||
3599 | done: | ||
3600 | if (sta_ptr) | ||
3601 | hostap_handle_sta_release(sta_ptr); | ||
3602 | |||
3603 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
3604 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3605 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3606 | * after WEP configuration. However, keys are apparently changed at | ||
3607 | * least in Managed mode. */ | ||
3608 | if (ret == 0 && | ||
3609 | (hostap_set_encryption(local) || | ||
3610 | (local->iw_mode != IW_MODE_INFRA && | ||
3611 | local->func->reset_port(local->dev)))) { | ||
3612 | param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; | ||
3613 | return -EINVAL; | ||
3614 | } | ||
3615 | |||
3616 | return ret; | ||
3617 | } | ||
3618 | |||
3619 | |||
3620 | static int prism2_ioctl_get_encryption(local_info_t *local, | ||
3621 | struct prism2_hostapd_param *param, | ||
3622 | int param_len) | ||
3623 | { | ||
3624 | struct ieee80211_crypt_data **crypt; | ||
3625 | void *sta_ptr; | ||
3626 | int max_key_len; | ||
3627 | |||
3628 | param->u.crypt.err = 0; | ||
3629 | |||
3630 | max_key_len = param_len - | ||
3631 | (int) ((char *) param->u.crypt.key - (char *) param); | ||
3632 | if (max_key_len < 0) | ||
3633 | return -EINVAL; | ||
3634 | |||
3635 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3636 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3637 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3638 | sta_ptr = NULL; | ||
3639 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3640 | param->u.crypt.idx = local->tx_keyidx; | ||
3641 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3642 | } else { | ||
3643 | param->u.crypt.idx = 0; | ||
3644 | sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, | ||
3645 | &crypt); | ||
3646 | |||
3647 | if (sta_ptr == NULL) { | ||
3648 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3649 | return -EINVAL; | ||
3650 | } | ||
3651 | } | ||
3652 | |||
3653 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3654 | memcpy(param->u.crypt.alg, "none", 5); | ||
3655 | param->u.crypt.key_len = 0; | ||
3656 | param->u.crypt.idx = 0xff; | ||
3657 | } else { | ||
3658 | strncpy(param->u.crypt.alg, (*crypt)->ops->name, | ||
3659 | HOSTAP_CRYPT_ALG_NAME_LEN); | ||
3660 | param->u.crypt.key_len = 0; | ||
3661 | |||
3662 | memset(param->u.crypt.seq, 0, 8); | ||
3663 | if ((*crypt)->ops->get_key) { | ||
3664 | param->u.crypt.key_len = | ||
3665 | (*crypt)->ops->get_key(param->u.crypt.key, | ||
3666 | max_key_len, | ||
3667 | param->u.crypt.seq, | ||
3668 | (*crypt)->priv); | ||
3669 | } | ||
3670 | } | ||
3671 | |||
3672 | if (sta_ptr) | ||
3673 | hostap_handle_sta_release(sta_ptr); | ||
3674 | |||
3675 | return 0; | ||
3676 | } | ||
3677 | |||
3678 | |||
3679 | static int prism2_ioctl_get_rid(local_info_t *local, | ||
3680 | struct prism2_hostapd_param *param, | ||
3681 | int param_len) | ||
3682 | { | ||
3683 | int max_len, res; | ||
3684 | |||
3685 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3686 | if (max_len < 0) | ||
3687 | return -EINVAL; | ||
3688 | |||
3689 | res = local->func->get_rid(local->dev, param->u.rid.rid, | ||
3690 | param->u.rid.data, param->u.rid.len, 0); | ||
3691 | if (res >= 0) { | ||
3692 | param->u.rid.len = res; | ||
3693 | return 0; | ||
3694 | } | ||
3695 | |||
3696 | return res; | ||
3697 | } | ||
3698 | |||
3699 | |||
3700 | static int prism2_ioctl_set_rid(local_info_t *local, | ||
3701 | struct prism2_hostapd_param *param, | ||
3702 | int param_len) | ||
3703 | { | ||
3704 | int max_len; | ||
3705 | |||
3706 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3707 | if (max_len < 0 || max_len < param->u.rid.len) | ||
3708 | return -EINVAL; | ||
3709 | |||
3710 | return local->func->set_rid(local->dev, param->u.rid.rid, | ||
3711 | param->u.rid.data, param->u.rid.len); | ||
3712 | } | ||
3713 | |||
3714 | |||
3715 | static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, | ||
3716 | struct prism2_hostapd_param *param, | ||
3717 | int param_len) | ||
3718 | { | ||
3719 | printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", | ||
3720 | local->dev->name, MAC2STR(param->sta_addr)); | ||
3721 | memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); | ||
3722 | return 0; | ||
3723 | } | ||
3724 | |||
3725 | |||
3726 | static int prism2_ioctl_siwgenie(struct net_device *dev, | ||
3727 | struct iw_request_info *info, | ||
3728 | struct iw_point *data, char *extra) | ||
3729 | { | ||
3730 | return prism2_set_genericelement(dev, extra, data->length); | ||
3731 | } | ||
3732 | |||
3733 | |||
3734 | static int prism2_ioctl_giwgenie(struct net_device *dev, | ||
3735 | struct iw_request_info *info, | ||
3736 | struct iw_point *data, char *extra) | ||
3737 | { | ||
3738 | struct hostap_interface *iface = dev->priv; | ||
3739 | local_info_t *local = iface->local; | ||
3740 | int len = local->generic_elem_len - 2; | ||
3741 | |||
3742 | if (len <= 0 || local->generic_elem == NULL) { | ||
3743 | data->length = 0; | ||
3744 | return 0; | ||
3745 | } | ||
3746 | |||
3747 | if (data->length < len) | ||
3748 | return -E2BIG; | ||
3749 | |||
3750 | data->length = len; | ||
3751 | memcpy(extra, local->generic_elem + 2, len); | ||
3752 | |||
3753 | return 0; | ||
3754 | } | ||
3755 | |||
3756 | |||
3757 | static int prism2_ioctl_set_generic_element(local_info_t *local, | ||
3758 | struct prism2_hostapd_param *param, | ||
3759 | int param_len) | ||
3760 | { | ||
3761 | int max_len, len; | ||
3762 | |||
3763 | len = param->u.generic_elem.len; | ||
3764 | max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; | ||
3765 | if (max_len < 0 || max_len < len) | ||
3766 | return -EINVAL; | ||
3767 | |||
3768 | return prism2_set_genericelement(local->dev, | ||
3769 | param->u.generic_elem.data, len); | ||
3770 | } | ||
3771 | |||
3772 | |||
3773 | static int prism2_ioctl_siwmlme(struct net_device *dev, | ||
3774 | struct iw_request_info *info, | ||
3775 | struct iw_point *data, char *extra) | ||
3776 | { | ||
3777 | struct hostap_interface *iface = dev->priv; | ||
3778 | local_info_t *local = iface->local; | ||
3779 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | ||
3780 | u16 reason; | ||
3781 | |||
3782 | reason = cpu_to_le16(mlme->reason_code); | ||
3783 | |||
3784 | switch (mlme->cmd) { | ||
3785 | case IW_MLME_DEAUTH: | ||
3786 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3787 | IEEE80211_STYPE_DEAUTH, | ||
3788 | (u8 *) &reason, 2); | ||
3789 | case IW_MLME_DISASSOC: | ||
3790 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3791 | IEEE80211_STYPE_DISASSOC, | ||
3792 | (u8 *) &reason, 2); | ||
3793 | default: | ||
3794 | return -EOPNOTSUPP; | ||
3795 | } | ||
3796 | } | ||
3797 | |||
3798 | |||
3799 | static int prism2_ioctl_mlme(local_info_t *local, | ||
3800 | struct prism2_hostapd_param *param) | ||
3801 | { | ||
3802 | u16 reason; | ||
3803 | |||
3804 | reason = cpu_to_le16(param->u.mlme.reason_code); | ||
3805 | switch (param->u.mlme.cmd) { | ||
3806 | case MLME_STA_DEAUTH: | ||
3807 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3808 | IEEE80211_STYPE_DEAUTH, | ||
3809 | (u8 *) &reason, 2); | ||
3810 | case MLME_STA_DISASSOC: | ||
3811 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3812 | IEEE80211_STYPE_DISASSOC, | ||
3813 | (u8 *) &reason, 2); | ||
3814 | default: | ||
3815 | return -EOPNOTSUPP; | ||
3816 | } | ||
3817 | } | ||
3818 | |||
3819 | |||
3820 | static int prism2_ioctl_scan_req(local_info_t *local, | ||
3821 | struct prism2_hostapd_param *param) | ||
3822 | { | ||
3823 | #ifndef PRISM2_NO_STATION_MODES | ||
3824 | if ((local->iw_mode != IW_MODE_INFRA && | ||
3825 | local->iw_mode != IW_MODE_ADHOC) || | ||
3826 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) | ||
3827 | return -EOPNOTSUPP; | ||
3828 | |||
3829 | if (!local->dev_enabled) | ||
3830 | return -ENETDOWN; | ||
3831 | |||
3832 | return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, | ||
3833 | param->u.scan_req.ssid_len); | ||
3834 | #else /* PRISM2_NO_STATION_MODES */ | ||
3835 | return -EOPNOTSUPP; | ||
3836 | #endif /* PRISM2_NO_STATION_MODES */ | ||
3837 | } | ||
3838 | |||
3839 | |||
3840 | static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) | ||
3841 | { | ||
3842 | struct prism2_hostapd_param *param; | ||
3843 | int ret = 0; | ||
3844 | int ap_ioctl = 0; | ||
3845 | |||
3846 | if (p->length < sizeof(struct prism2_hostapd_param) || | ||
3847 | p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) | ||
3848 | return -EINVAL; | ||
3849 | |||
3850 | param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); | ||
3851 | if (param == NULL) | ||
3852 | return -ENOMEM; | ||
3853 | |||
3854 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3855 | ret = -EFAULT; | ||
3856 | goto out; | ||
3857 | } | ||
3858 | |||
3859 | switch (param->cmd) { | ||
3860 | case PRISM2_SET_ENCRYPTION: | ||
3861 | ret = prism2_ioctl_set_encryption(local, param, p->length); | ||
3862 | break; | ||
3863 | case PRISM2_GET_ENCRYPTION: | ||
3864 | ret = prism2_ioctl_get_encryption(local, param, p->length); | ||
3865 | break; | ||
3866 | case PRISM2_HOSTAPD_GET_RID: | ||
3867 | ret = prism2_ioctl_get_rid(local, param, p->length); | ||
3868 | break; | ||
3869 | case PRISM2_HOSTAPD_SET_RID: | ||
3870 | ret = prism2_ioctl_set_rid(local, param, p->length); | ||
3871 | break; | ||
3872 | case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: | ||
3873 | ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); | ||
3874 | break; | ||
3875 | case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: | ||
3876 | ret = prism2_ioctl_set_generic_element(local, param, | ||
3877 | p->length); | ||
3878 | break; | ||
3879 | case PRISM2_HOSTAPD_MLME: | ||
3880 | ret = prism2_ioctl_mlme(local, param); | ||
3881 | break; | ||
3882 | case PRISM2_HOSTAPD_SCAN_REQ: | ||
3883 | ret = prism2_ioctl_scan_req(local, param); | ||
3884 | break; | ||
3885 | default: | ||
3886 | ret = prism2_hostapd(local->ap, param); | ||
3887 | ap_ioctl = 1; | ||
3888 | break; | ||
3889 | } | ||
3890 | |||
3891 | if (ret == 1 || !ap_ioctl) { | ||
3892 | if (copy_to_user(p->pointer, param, p->length)) { | ||
3893 | ret = -EFAULT; | ||
3894 | goto out; | ||
3895 | } else if (ap_ioctl) | ||
3896 | ret = 0; | ||
3897 | } | ||
3898 | |||
3899 | out: | ||
3900 | if (param != NULL) | ||
3901 | kfree(param); | ||
3902 | |||
3903 | return ret; | ||
3904 | } | ||
3905 | |||
3906 | |||
3907 | static void prism2_get_drvinfo(struct net_device *dev, | ||
3908 | struct ethtool_drvinfo *info) | ||
3909 | { | ||
3910 | struct hostap_interface *iface; | ||
3911 | local_info_t *local; | ||
3912 | |||
3913 | iface = netdev_priv(dev); | ||
3914 | local = iface->local; | ||
3915 | |||
3916 | strncpy(info->driver, "hostap", sizeof(info->driver) - 1); | ||
3917 | strncpy(info->version, PRISM2_VERSION, | ||
3918 | sizeof(info->version) - 1); | ||
3919 | snprintf(info->fw_version, sizeof(info->fw_version) - 1, | ||
3920 | "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, | ||
3921 | (local->sta_fw_ver >> 8) & 0xff, | ||
3922 | local->sta_fw_ver & 0xff); | ||
3923 | } | ||
3924 | |||
3925 | static struct ethtool_ops prism2_ethtool_ops = { | ||
3926 | .get_drvinfo = prism2_get_drvinfo | ||
3927 | }; | ||
3928 | |||
3929 | |||
3930 | /* Structures to export the Wireless Handlers */ | ||
3931 | |||
3932 | static const iw_handler prism2_handler[] = | ||
3933 | { | ||
3934 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
3935 | (iw_handler) prism2_get_name, /* SIOCGIWNAME */ | ||
3936 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
3937 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
3938 | (iw_handler) prism2_ioctl_siwfreq, /* SIOCSIWFREQ */ | ||
3939 | (iw_handler) prism2_ioctl_giwfreq, /* SIOCGIWFREQ */ | ||
3940 | (iw_handler) prism2_ioctl_siwmode, /* SIOCSIWMODE */ | ||
3941 | (iw_handler) prism2_ioctl_giwmode, /* SIOCGIWMODE */ | ||
3942 | (iw_handler) prism2_ioctl_siwsens, /* SIOCSIWSENS */ | ||
3943 | (iw_handler) prism2_ioctl_giwsens, /* SIOCGIWSENS */ | ||
3944 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | ||
3945 | (iw_handler) prism2_ioctl_giwrange, /* SIOCGIWRANGE */ | ||
3946 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | ||
3947 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | ||
3948 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | ||
3949 | (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ | ||
3950 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
3951 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
3952 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
3953 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
3954 | (iw_handler) prism2_ioctl_siwap, /* SIOCSIWAP */ | ||
3955 | (iw_handler) prism2_ioctl_giwap, /* SIOCGIWAP */ | ||
3956 | (iw_handler) prism2_ioctl_siwmlme, /* SIOCSIWMLME */ | ||
3957 | (iw_handler) prism2_ioctl_giwaplist, /* SIOCGIWAPLIST */ | ||
3958 | (iw_handler) prism2_ioctl_siwscan, /* SIOCSIWSCAN */ | ||
3959 | (iw_handler) prism2_ioctl_giwscan, /* SIOCGIWSCAN */ | ||
3960 | (iw_handler) prism2_ioctl_siwessid, /* SIOCSIWESSID */ | ||
3961 | (iw_handler) prism2_ioctl_giwessid, /* SIOCGIWESSID */ | ||
3962 | (iw_handler) prism2_ioctl_siwnickn, /* SIOCSIWNICKN */ | ||
3963 | (iw_handler) prism2_ioctl_giwnickn, /* SIOCGIWNICKN */ | ||
3964 | (iw_handler) NULL, /* -- hole -- */ | ||
3965 | (iw_handler) NULL, /* -- hole -- */ | ||
3966 | (iw_handler) prism2_ioctl_siwrate, /* SIOCSIWRATE */ | ||
3967 | (iw_handler) prism2_ioctl_giwrate, /* SIOCGIWRATE */ | ||
3968 | (iw_handler) prism2_ioctl_siwrts, /* SIOCSIWRTS */ | ||
3969 | (iw_handler) prism2_ioctl_giwrts, /* SIOCGIWRTS */ | ||
3970 | (iw_handler) prism2_ioctl_siwfrag, /* SIOCSIWFRAG */ | ||
3971 | (iw_handler) prism2_ioctl_giwfrag, /* SIOCGIWFRAG */ | ||
3972 | (iw_handler) prism2_ioctl_siwtxpow, /* SIOCSIWTXPOW */ | ||
3973 | (iw_handler) prism2_ioctl_giwtxpow, /* SIOCGIWTXPOW */ | ||
3974 | (iw_handler) prism2_ioctl_siwretry, /* SIOCSIWRETRY */ | ||
3975 | (iw_handler) prism2_ioctl_giwretry, /* SIOCGIWRETRY */ | ||
3976 | (iw_handler) prism2_ioctl_siwencode, /* SIOCSIWENCODE */ | ||
3977 | (iw_handler) prism2_ioctl_giwencode, /* SIOCGIWENCODE */ | ||
3978 | (iw_handler) prism2_ioctl_siwpower, /* SIOCSIWPOWER */ | ||
3979 | (iw_handler) prism2_ioctl_giwpower, /* SIOCGIWPOWER */ | ||
3980 | (iw_handler) NULL, /* -- hole -- */ | ||
3981 | (iw_handler) NULL, /* -- hole -- */ | ||
3982 | (iw_handler) prism2_ioctl_siwgenie, /* SIOCSIWGENIE */ | ||
3983 | (iw_handler) prism2_ioctl_giwgenie, /* SIOCGIWGENIE */ | ||
3984 | (iw_handler) prism2_ioctl_siwauth, /* SIOCSIWAUTH */ | ||
3985 | (iw_handler) prism2_ioctl_giwauth, /* SIOCGIWAUTH */ | ||
3986 | (iw_handler) prism2_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | ||
3987 | (iw_handler) prism2_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ | ||
3988 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
3989 | (iw_handler) NULL, /* -- hole -- */ | ||
3990 | }; | ||
3991 | |||
3992 | static const iw_handler prism2_private_handler[] = | ||
3993 | { /* SIOCIWFIRSTPRIV + */ | ||
3994 | (iw_handler) prism2_ioctl_priv_prism2_param, /* 0 */ | ||
3995 | (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */ | ||
3996 | (iw_handler) prism2_ioctl_priv_writemif, /* 2 */ | ||
3997 | (iw_handler) prism2_ioctl_priv_readmif, /* 3 */ | ||
3998 | }; | ||
3999 | |||
4000 | static const struct iw_handler_def hostap_iw_handler_def = | ||
4001 | { | ||
4002 | .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), | ||
4003 | .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), | ||
4004 | .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), | ||
4005 | .standard = (iw_handler *) prism2_handler, | ||
4006 | .private = (iw_handler *) prism2_private_handler, | ||
4007 | .private_args = (struct iw_priv_args *) prism2_priv, | ||
4008 | .get_wireless_stats = hostap_get_wireless_stats, | ||
4009 | }; | ||
4010 | |||
4011 | |||
4012 | int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
4013 | { | ||
4014 | struct iwreq *wrq = (struct iwreq *) ifr; | ||
4015 | struct hostap_interface *iface; | ||
4016 | local_info_t *local; | ||
4017 | int ret = 0; | ||
4018 | |||
4019 | iface = netdev_priv(dev); | ||
4020 | local = iface->local; | ||
4021 | |||
4022 | switch (cmd) { | ||
4023 | /* Private ioctls (iwpriv) that have not yet been converted | ||
4024 | * into new wireless extensions API */ | ||
4025 | |||
4026 | case PRISM2_IOCTL_INQUIRE: | ||
4027 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4028 | else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name); | ||
4029 | break; | ||
4030 | |||
4031 | case PRISM2_IOCTL_MONITOR: | ||
4032 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4033 | else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name); | ||
4034 | break; | ||
4035 | |||
4036 | case PRISM2_IOCTL_RESET: | ||
4037 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4038 | else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name); | ||
4039 | break; | ||
4040 | |||
4041 | case PRISM2_IOCTL_WDS_ADD: | ||
4042 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4043 | else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1); | ||
4044 | break; | ||
4045 | |||
4046 | case PRISM2_IOCTL_WDS_DEL: | ||
4047 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4048 | else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0); | ||
4049 | break; | ||
4050 | |||
4051 | case PRISM2_IOCTL_SET_RID_WORD: | ||
4052 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4053 | else ret = prism2_ioctl_priv_set_rid_word(dev, | ||
4054 | (int *) wrq->u.name); | ||
4055 | break; | ||
4056 | |||
4057 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
4058 | case PRISM2_IOCTL_MACCMD: | ||
4059 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4060 | else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name); | ||
4061 | break; | ||
4062 | |||
4063 | case PRISM2_IOCTL_ADDMAC: | ||
4064 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4065 | else ret = ap_control_add_mac(&local->ap->mac_restrictions, | ||
4066 | wrq->u.ap_addr.sa_data); | ||
4067 | break; | ||
4068 | case PRISM2_IOCTL_DELMAC: | ||
4069 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4070 | else ret = ap_control_del_mac(&local->ap->mac_restrictions, | ||
4071 | wrq->u.ap_addr.sa_data); | ||
4072 | break; | ||
4073 | case PRISM2_IOCTL_KICKMAC: | ||
4074 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4075 | else ret = ap_control_kick_mac(local->ap, local->dev, | ||
4076 | wrq->u.ap_addr.sa_data); | ||
4077 | break; | ||
4078 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
4079 | |||
4080 | |||
4081 | /* Private ioctls that are not used with iwpriv; | ||
4082 | * in SIOCDEVPRIVATE range */ | ||
4083 | |||
4084 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
4085 | case PRISM2_IOCTL_DOWNLOAD: | ||
4086 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4087 | else ret = prism2_ioctl_priv_download(local, &wrq->u.data); | ||
4088 | break; | ||
4089 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
4090 | |||
4091 | case PRISM2_IOCTL_HOSTAPD: | ||
4092 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4093 | else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); | ||
4094 | break; | ||
4095 | |||
4096 | default: | ||
4097 | ret = -EOPNOTSUPP; | ||
4098 | break; | ||
4099 | } | ||
4100 | |||
4101 | return ret; | ||
4102 | } | ||
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c new file mode 100644 index 000000000000..4f567ef6178d --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_pci.c | |||
@@ -0,0 +1,473 @@ | |||
1 | #define PRISM2_PCI | ||
2 | |||
3 | /* Host AP driver's support for Intersil Prism2.5 PCI cards is based on | ||
4 | * driver patches from Reyk Floeter <reyk@vantronix.net> and | ||
5 | * Andy Warner <andyw@pobox.com> */ | ||
6 | |||
7 | #include <linux/config.h> | ||
8 | #include <linux/version.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/if.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include <linux/workqueue.h> | ||
15 | #include <linux/wireless.h> | ||
16 | #include <net/iw_handler.h> | ||
17 | |||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | #include "hostap_wlan.h" | ||
23 | |||
24 | |||
25 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
26 | static char *dev_info = "hostap_pci"; | ||
27 | |||
28 | |||
29 | MODULE_AUTHOR("Jouni Malinen"); | ||
30 | MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " | ||
31 | "PCI cards."); | ||
32 | MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_VERSION(PRISM2_VERSION); | ||
35 | |||
36 | |||
37 | /* struct local_info::hw_priv */ | ||
38 | struct hostap_pci_priv { | ||
39 | void __iomem *mem_start; | ||
40 | }; | ||
41 | |||
42 | |||
43 | /* FIX: do we need mb/wmb/rmb with memory operations? */ | ||
44 | |||
45 | |||
46 | static struct pci_device_id prism2_pci_id_table[] __devinitdata = { | ||
47 | /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ | ||
48 | { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, | ||
49 | /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ | ||
50 | { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, | ||
51 | /* Samsung MagicLAN SWL-2210P */ | ||
52 | { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, | ||
53 | { 0 } | ||
54 | }; | ||
55 | |||
56 | |||
57 | #ifdef PRISM2_IO_DEBUG | ||
58 | |||
59 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
60 | { | ||
61 | struct hostap_interface *iface; | ||
62 | local_info_t *local; | ||
63 | unsigned long flags; | ||
64 | |||
65 | iface = netdev_priv(dev); | ||
66 | local = iface->local; | ||
67 | |||
68 | spin_lock_irqsave(&local->lock, flags); | ||
69 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
70 | writeb(v, hw_priv->mem_start + a); | ||
71 | spin_unlock_irqrestore(&local->lock, flags); | ||
72 | } | ||
73 | |||
74 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
75 | { | ||
76 | struct hostap_interface *iface; | ||
77 | local_info_t *local; | ||
78 | unsigned long flags; | ||
79 | u8 v; | ||
80 | |||
81 | iface = netdev_priv(dev); | ||
82 | local = iface->local; | ||
83 | |||
84 | spin_lock_irqsave(&local->lock, flags); | ||
85 | v = readb(hw_priv->mem_start + a); | ||
86 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
87 | spin_unlock_irqrestore(&local->lock, flags); | ||
88 | return v; | ||
89 | } | ||
90 | |||
91 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
92 | { | ||
93 | struct hostap_interface *iface; | ||
94 | local_info_t *local; | ||
95 | unsigned long flags; | ||
96 | |||
97 | iface = netdev_priv(dev); | ||
98 | local = iface->local; | ||
99 | |||
100 | spin_lock_irqsave(&local->lock, flags); | ||
101 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
102 | writew(v, hw_priv->mem_start + a); | ||
103 | spin_unlock_irqrestore(&local->lock, flags); | ||
104 | } | ||
105 | |||
106 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
107 | { | ||
108 | struct hostap_interface *iface; | ||
109 | local_info_t *local; | ||
110 | unsigned long flags; | ||
111 | u16 v; | ||
112 | |||
113 | iface = netdev_priv(dev); | ||
114 | local = iface->local; | ||
115 | |||
116 | spin_lock_irqsave(&local->lock, flags); | ||
117 | v = readw(hw_priv->mem_start + a); | ||
118 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
119 | spin_unlock_irqrestore(&local->lock, flags); | ||
120 | return v; | ||
121 | } | ||
122 | |||
123 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
124 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
125 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
126 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
127 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v))) | ||
128 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a))) | ||
129 | |||
130 | #else /* PRISM2_IO_DEBUG */ | ||
131 | |||
132 | static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) | ||
133 | { | ||
134 | struct hostap_interface *iface; | ||
135 | struct hostap_pci_priv *hw_priv; | ||
136 | iface = netdev_priv(dev); | ||
137 | hw_priv = iface->local->hw_priv; | ||
138 | writeb(v, hw_priv->mem_start + a); | ||
139 | } | ||
140 | |||
141 | static inline u8 hfa384x_inb(struct net_device *dev, int a) | ||
142 | { | ||
143 | struct hostap_interface *iface; | ||
144 | struct hostap_pci_priv *hw_priv; | ||
145 | iface = netdev_priv(dev); | ||
146 | hw_priv = iface->local->hw_priv; | ||
147 | return readb(hw_priv->mem_start + a); | ||
148 | } | ||
149 | |||
150 | static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) | ||
151 | { | ||
152 | struct hostap_interface *iface; | ||
153 | struct hostap_pci_priv *hw_priv; | ||
154 | iface = netdev_priv(dev); | ||
155 | hw_priv = iface->local->hw_priv; | ||
156 | writew(v, hw_priv->mem_start + a); | ||
157 | } | ||
158 | |||
159 | static inline u16 hfa384x_inw(struct net_device *dev, int a) | ||
160 | { | ||
161 | struct hostap_interface *iface; | ||
162 | struct hostap_pci_priv *hw_priv; | ||
163 | iface = netdev_priv(dev); | ||
164 | hw_priv = iface->local->hw_priv; | ||
165 | return readw(hw_priv->mem_start + a); | ||
166 | } | ||
167 | |||
168 | #define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) | ||
169 | #define HFA384X_INB(a) hfa384x_inb(dev, (a)) | ||
170 | #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) | ||
171 | #define HFA384X_INW(a) hfa384x_inw(dev, (a)) | ||
172 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v))) | ||
173 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a))) | ||
174 | |||
175 | #endif /* PRISM2_IO_DEBUG */ | ||
176 | |||
177 | |||
178 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
179 | int len) | ||
180 | { | ||
181 | u16 d_off; | ||
182 | u16 *pos; | ||
183 | |||
184 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
185 | pos = (u16 *) buf; | ||
186 | |||
187 | for ( ; len > 1; len -= 2) | ||
188 | *pos++ = HFA384X_INW_DATA(d_off); | ||
189 | |||
190 | if (len & 1) | ||
191 | *((char *) pos) = HFA384X_INB(d_off); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
198 | { | ||
199 | u16 d_off; | ||
200 | u16 *pos; | ||
201 | |||
202 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
203 | pos = (u16 *) buf; | ||
204 | |||
205 | for ( ; len > 1; len -= 2) | ||
206 | HFA384X_OUTW_DATA(*pos++, d_off); | ||
207 | |||
208 | if (len & 1) | ||
209 | HFA384X_OUTB(*((char *) pos), d_off); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* FIX: This might change at some point.. */ | ||
216 | #include "hostap_hw.c" | ||
217 | |||
218 | static void prism2_pci_cor_sreset(local_info_t *local) | ||
219 | { | ||
220 | struct net_device *dev = local->dev; | ||
221 | u16 reg; | ||
222 | |||
223 | reg = HFA384X_INB(HFA384X_PCICOR_OFF); | ||
224 | printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); | ||
225 | |||
226 | /* linux-wlan-ng uses extremely long hold and settle times for | ||
227 | * COR sreset. A comment in the driver code mentions that the long | ||
228 | * delays appear to be necessary. However, at least IBM 22P6901 seems | ||
229 | * to work fine with shorter delays. | ||
230 | * | ||
231 | * Longer delays can be configured by uncommenting following line: */ | ||
232 | /* #define PRISM2_PCI_USE_LONG_DELAYS */ | ||
233 | |||
234 | #ifdef PRISM2_PCI_USE_LONG_DELAYS | ||
235 | int i; | ||
236 | |||
237 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
238 | mdelay(250); | ||
239 | |||
240 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
241 | mdelay(500); | ||
242 | |||
243 | /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ | ||
244 | i = 2000000 / 10; | ||
245 | while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) | ||
246 | udelay(10); | ||
247 | |||
248 | #else /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
249 | |||
250 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
251 | mdelay(2); | ||
252 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
253 | mdelay(2); | ||
254 | |||
255 | #endif /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
256 | |||
257 | if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { | ||
258 | printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void prism2_pci_genesis_reset(local_info_t *local, int hcr) | ||
264 | { | ||
265 | struct net_device *dev = local->dev; | ||
266 | |||
267 | HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); | ||
268 | mdelay(10); | ||
269 | HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); | ||
270 | mdelay(10); | ||
271 | HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); | ||
272 | mdelay(10); | ||
273 | } | ||
274 | |||
275 | |||
276 | static struct prism2_helper_functions prism2_pci_funcs = | ||
277 | { | ||
278 | .card_present = NULL, | ||
279 | .cor_sreset = prism2_pci_cor_sreset, | ||
280 | .dev_open = NULL, | ||
281 | .dev_close = NULL, | ||
282 | .genesis_reset = prism2_pci_genesis_reset, | ||
283 | .hw_type = HOSTAP_HW_PCI, | ||
284 | }; | ||
285 | |||
286 | |||
287 | static int prism2_pci_probe(struct pci_dev *pdev, | ||
288 | const struct pci_device_id *id) | ||
289 | { | ||
290 | unsigned long phymem; | ||
291 | void __iomem *mem = NULL; | ||
292 | local_info_t *local = NULL; | ||
293 | struct net_device *dev = NULL; | ||
294 | static int cards_found /* = 0 */; | ||
295 | int irq_registered = 0; | ||
296 | struct hostap_interface *iface; | ||
297 | struct hostap_pci_priv *hw_priv; | ||
298 | |||
299 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
300 | if (hw_priv == NULL) | ||
301 | return -ENOMEM; | ||
302 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
303 | |||
304 | if (pci_enable_device(pdev)) | ||
305 | return -EIO; | ||
306 | |||
307 | phymem = pci_resource_start(pdev, 0); | ||
308 | |||
309 | if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { | ||
310 | printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); | ||
311 | goto err_out_disable; | ||
312 | } | ||
313 | |||
314 | mem = ioremap(phymem, pci_resource_len(pdev, 0)); | ||
315 | if (mem == NULL) { | ||
316 | printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; | ||
317 | goto fail; | ||
318 | } | ||
319 | |||
320 | dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, | ||
321 | &pdev->dev); | ||
322 | if (dev == NULL) | ||
323 | goto fail; | ||
324 | iface = netdev_priv(dev); | ||
325 | local = iface->local; | ||
326 | local->hw_priv = hw_priv; | ||
327 | cards_found++; | ||
328 | |||
329 | dev->irq = pdev->irq; | ||
330 | hw_priv->mem_start = mem; | ||
331 | |||
332 | prism2_pci_cor_sreset(local); | ||
333 | |||
334 | pci_set_drvdata(pdev, dev); | ||
335 | |||
336 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
337 | dev)) { | ||
338 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
339 | goto fail; | ||
340 | } else | ||
341 | irq_registered = 1; | ||
342 | |||
343 | if (!local->pri_only && prism2_hw_config(dev, 1)) { | ||
344 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
345 | dev_info); | ||
346 | goto fail; | ||
347 | } | ||
348 | |||
349 | printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " | ||
350 | "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); | ||
351 | |||
352 | return hostap_hw_ready(dev); | ||
353 | |||
354 | fail: | ||
355 | kfree(hw_priv); | ||
356 | |||
357 | if (irq_registered && dev) | ||
358 | free_irq(dev->irq, dev); | ||
359 | |||
360 | if (mem) | ||
361 | iounmap(mem); | ||
362 | |||
363 | release_mem_region(phymem, pci_resource_len(pdev, 0)); | ||
364 | |||
365 | err_out_disable: | ||
366 | pci_disable_device(pdev); | ||
367 | kfree(hw_priv); | ||
368 | if (local) | ||
369 | local->hw_priv = NULL; | ||
370 | prism2_free_local_data(dev); | ||
371 | |||
372 | return -ENODEV; | ||
373 | } | ||
374 | |||
375 | |||
376 | static void prism2_pci_remove(struct pci_dev *pdev) | ||
377 | { | ||
378 | struct net_device *dev; | ||
379 | struct hostap_interface *iface; | ||
380 | void __iomem *mem_start; | ||
381 | struct hostap_pci_priv *hw_priv; | ||
382 | |||
383 | dev = pci_get_drvdata(pdev); | ||
384 | iface = netdev_priv(dev); | ||
385 | hw_priv = iface->local->hw_priv; | ||
386 | |||
387 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
388 | prism2_pci_cor_sreset(iface->local); | ||
389 | hfa384x_disable_interrupts(dev); | ||
390 | |||
391 | if (dev->irq) | ||
392 | free_irq(dev->irq, dev); | ||
393 | |||
394 | mem_start = hw_priv->mem_start; | ||
395 | kfree(hw_priv); | ||
396 | iface->local->hw_priv = NULL; | ||
397 | prism2_free_local_data(dev); | ||
398 | |||
399 | iounmap(mem_start); | ||
400 | |||
401 | release_mem_region(pci_resource_start(pdev, 0), | ||
402 | pci_resource_len(pdev, 0)); | ||
403 | pci_disable_device(pdev); | ||
404 | } | ||
405 | |||
406 | |||
407 | #ifdef CONFIG_PM | ||
408 | static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
409 | { | ||
410 | struct net_device *dev = pci_get_drvdata(pdev); | ||
411 | |||
412 | if (netif_running(dev)) { | ||
413 | netif_stop_queue(dev); | ||
414 | netif_device_detach(dev); | ||
415 | } | ||
416 | prism2_suspend(dev); | ||
417 | pci_save_state(pdev); | ||
418 | pci_disable_device(pdev); | ||
419 | pci_set_power_state(pdev, 3); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int prism2_pci_resume(struct pci_dev *pdev) | ||
425 | { | ||
426 | struct net_device *dev = pci_get_drvdata(pdev); | ||
427 | |||
428 | pci_enable_device(pdev); | ||
429 | pci_restore_state(pdev); | ||
430 | prism2_hw_config(dev, 0); | ||
431 | if (netif_running(dev)) { | ||
432 | netif_device_attach(dev); | ||
433 | netif_start_queue(dev); | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | #endif /* CONFIG_PM */ | ||
439 | |||
440 | |||
441 | MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); | ||
442 | |||
443 | static struct pci_driver prism2_pci_drv_id = { | ||
444 | .name = "prism2_pci", | ||
445 | .id_table = prism2_pci_id_table, | ||
446 | .probe = prism2_pci_probe, | ||
447 | .remove = prism2_pci_remove, | ||
448 | #ifdef CONFIG_PM | ||
449 | .suspend = prism2_pci_suspend, | ||
450 | .resume = prism2_pci_resume, | ||
451 | #endif /* CONFIG_PM */ | ||
452 | /* Linux 2.4.6 added save_state and enable_wake that are not used here | ||
453 | */ | ||
454 | }; | ||
455 | |||
456 | |||
457 | static int __init init_prism2_pci(void) | ||
458 | { | ||
459 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
460 | |||
461 | return pci_register_driver(&prism2_pci_drv_id); | ||
462 | } | ||
463 | |||
464 | |||
465 | static void __exit exit_prism2_pci(void) | ||
466 | { | ||
467 | pci_unregister_driver(&prism2_pci_drv_id); | ||
468 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
469 | } | ||
470 | |||
471 | |||
472 | module_init(init_prism2_pci); | ||
473 | module_exit(exit_prism2_pci); | ||
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c new file mode 100644 index 000000000000..474ef83d813e --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_plx.c | |||
@@ -0,0 +1,645 @@ | |||
1 | #define PRISM2_PLX | ||
2 | |||
3 | /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is | ||
4 | * based on: | ||
5 | * - Host AP driver patch from james@madingley.org | ||
6 | * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/if.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/netdevice.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/wireless.h> | ||
19 | #include <net/iw_handler.h> | ||
20 | |||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | #include "hostap_wlan.h" | ||
26 | |||
27 | |||
28 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
29 | static char *dev_info = "hostap_plx"; | ||
30 | |||
31 | |||
32 | MODULE_AUTHOR("Jouni Malinen"); | ||
33 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | ||
34 | "cards (PLX)."); | ||
35 | MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | MODULE_VERSION(PRISM2_VERSION); | ||
38 | |||
39 | |||
40 | static int ignore_cis; | ||
41 | module_param(ignore_cis, int, 0444); | ||
42 | MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); | ||
43 | |||
44 | |||
45 | /* struct local_info::hw_priv */ | ||
46 | struct hostap_plx_priv { | ||
47 | void __iomem *attr_mem; | ||
48 | unsigned int cor_offset; | ||
49 | }; | ||
50 | |||
51 | |||
52 | #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ | ||
53 | #define COR_SRESET 0x80 | ||
54 | #define COR_LEVLREQ 0x40 | ||
55 | #define COR_ENABLE_FUNC 0x01 | ||
56 | /* PCI Configuration Registers */ | ||
57 | #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ | ||
58 | /* Local Configuration Registers */ | ||
59 | #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ | ||
60 | #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ | ||
61 | #define PLX_CNTRL 0x50 | ||
62 | #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) | ||
63 | |||
64 | |||
65 | #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } | ||
66 | |||
67 | static struct pci_device_id prism2_plx_id_table[] __devinitdata = { | ||
68 | PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), | ||
69 | PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), | ||
70 | PLXDEV(0x126c, 0x8030, "Nortel emobility"), | ||
71 | PLXDEV(0x1385, 0x4100, "Netgear MA301"), | ||
72 | PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), | ||
73 | PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), | ||
74 | PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), | ||
75 | PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), | ||
76 | PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), | ||
77 | PLXDEV(0x16ab, 0x1103, "Longshine 8031"), | ||
78 | PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), | ||
79 | PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), | ||
80 | { 0 } | ||
81 | }; | ||
82 | |||
83 | |||
84 | /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid | ||
85 | * is not listed here, you will need to add it here to get the driver | ||
86 | * initialized. */ | ||
87 | static struct prism2_plx_manfid { | ||
88 | u16 manfid1, manfid2; | ||
89 | } prism2_plx_known_manfids[] = { | ||
90 | { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, | ||
91 | { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, | ||
92 | { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, | ||
93 | { 0x0126, 0x8000 } /* Proxim RangeLAN */, | ||
94 | { 0x0138, 0x0002 } /* Compaq WL100 */, | ||
95 | { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, | ||
96 | { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, | ||
97 | { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, | ||
98 | { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, | ||
99 | { 0x028a, 0x0002 } /* D-Link DRC-650 */, | ||
100 | { 0x0250, 0x0002 } /* Samsung SWL2000-N */, | ||
101 | { 0xc250, 0x0002 } /* EMTAC A2424i */, | ||
102 | { 0xd601, 0x0002 } /* Z-Com XI300 */, | ||
103 | { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, | ||
104 | { 0, 0} | ||
105 | }; | ||
106 | |||
107 | |||
108 | #ifdef PRISM2_IO_DEBUG | ||
109 | |||
110 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
111 | { | ||
112 | struct hostap_interface *iface; | ||
113 | local_info_t *local; | ||
114 | unsigned long flags; | ||
115 | |||
116 | iface = netdev_priv(dev); | ||
117 | local = iface->local; | ||
118 | |||
119 | spin_lock_irqsave(&local->lock, flags); | ||
120 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
121 | outb(v, dev->base_addr + a); | ||
122 | spin_unlock_irqrestore(&local->lock, flags); | ||
123 | } | ||
124 | |||
125 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
126 | { | ||
127 | struct hostap_interface *iface; | ||
128 | local_info_t *local; | ||
129 | unsigned long flags; | ||
130 | u8 v; | ||
131 | |||
132 | iface = netdev_priv(dev); | ||
133 | local = iface->local; | ||
134 | |||
135 | spin_lock_irqsave(&local->lock, flags); | ||
136 | v = inb(dev->base_addr + a); | ||
137 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
138 | spin_unlock_irqrestore(&local->lock, flags); | ||
139 | return v; | ||
140 | } | ||
141 | |||
142 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
143 | { | ||
144 | struct hostap_interface *iface; | ||
145 | local_info_t *local; | ||
146 | unsigned long flags; | ||
147 | |||
148 | iface = netdev_priv(dev); | ||
149 | local = iface->local; | ||
150 | |||
151 | spin_lock_irqsave(&local->lock, flags); | ||
152 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
153 | outw(v, dev->base_addr + a); | ||
154 | spin_unlock_irqrestore(&local->lock, flags); | ||
155 | } | ||
156 | |||
157 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
158 | { | ||
159 | struct hostap_interface *iface; | ||
160 | local_info_t *local; | ||
161 | unsigned long flags; | ||
162 | u16 v; | ||
163 | |||
164 | iface = netdev_priv(dev); | ||
165 | local = iface->local; | ||
166 | |||
167 | spin_lock_irqsave(&local->lock, flags); | ||
168 | v = inw(dev->base_addr + a); | ||
169 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
170 | spin_unlock_irqrestore(&local->lock, flags); | ||
171 | return v; | ||
172 | } | ||
173 | |||
174 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
175 | u8 *buf, int wc) | ||
176 | { | ||
177 | struct hostap_interface *iface; | ||
178 | local_info_t *local; | ||
179 | unsigned long flags; | ||
180 | |||
181 | iface = netdev_priv(dev); | ||
182 | local = iface->local; | ||
183 | |||
184 | spin_lock_irqsave(&local->lock, flags); | ||
185 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
186 | outsw(dev->base_addr + a, buf, wc); | ||
187 | spin_unlock_irqrestore(&local->lock, flags); | ||
188 | } | ||
189 | |||
190 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
191 | u8 *buf, int wc) | ||
192 | { | ||
193 | struct hostap_interface *iface; | ||
194 | local_info_t *local; | ||
195 | unsigned long flags; | ||
196 | |||
197 | iface = netdev_priv(dev); | ||
198 | local = iface->local; | ||
199 | |||
200 | spin_lock_irqsave(&local->lock, flags); | ||
201 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
202 | insw(dev->base_addr + a, buf, wc); | ||
203 | spin_unlock_irqrestore(&local->lock, flags); | ||
204 | } | ||
205 | |||
206 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
207 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
208 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
209 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
210 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
211 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
212 | |||
213 | #else /* PRISM2_IO_DEBUG */ | ||
214 | |||
215 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
216 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
217 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
218 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
219 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
220 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
221 | |||
222 | #endif /* PRISM2_IO_DEBUG */ | ||
223 | |||
224 | |||
225 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
226 | int len) | ||
227 | { | ||
228 | u16 d_off; | ||
229 | u16 *pos; | ||
230 | |||
231 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
232 | pos = (u16 *) buf; | ||
233 | |||
234 | if (len / 2) | ||
235 | HFA384X_INSW(d_off, buf, len / 2); | ||
236 | pos += len / 2; | ||
237 | |||
238 | if (len & 1) | ||
239 | *((char *) pos) = HFA384X_INB(d_off); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | |||
245 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
246 | { | ||
247 | u16 d_off; | ||
248 | u16 *pos; | ||
249 | |||
250 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
251 | pos = (u16 *) buf; | ||
252 | |||
253 | if (len / 2) | ||
254 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
255 | pos += len / 2; | ||
256 | |||
257 | if (len & 1) | ||
258 | HFA384X_OUTB(*((char *) pos), d_off); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | |||
264 | /* FIX: This might change at some point.. */ | ||
265 | #include "hostap_hw.c" | ||
266 | |||
267 | |||
268 | static void prism2_plx_cor_sreset(local_info_t *local) | ||
269 | { | ||
270 | unsigned char corsave; | ||
271 | struct hostap_plx_priv *hw_priv = local->hw_priv; | ||
272 | |||
273 | printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", | ||
274 | dev_info); | ||
275 | |||
276 | /* Set sreset bit of COR and clear it after hold time */ | ||
277 | |||
278 | if (hw_priv->attr_mem == NULL) { | ||
279 | /* TMD7160 - COR at card's first I/O addr */ | ||
280 | corsave = inb(hw_priv->cor_offset); | ||
281 | outb(corsave | COR_SRESET, hw_priv->cor_offset); | ||
282 | mdelay(2); | ||
283 | outb(corsave & ~COR_SRESET, hw_priv->cor_offset); | ||
284 | mdelay(2); | ||
285 | } else { | ||
286 | /* PLX9052 */ | ||
287 | corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); | ||
288 | writeb(corsave | COR_SRESET, | ||
289 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
290 | mdelay(2); | ||
291 | writeb(corsave & ~COR_SRESET, | ||
292 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
293 | mdelay(2); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | |||
298 | static void prism2_plx_genesis_reset(local_info_t *local, int hcr) | ||
299 | { | ||
300 | unsigned char corsave; | ||
301 | struct hostap_plx_priv *hw_priv = local->hw_priv; | ||
302 | |||
303 | if (hw_priv->attr_mem == NULL) { | ||
304 | /* TMD7160 - COR at card's first I/O addr */ | ||
305 | corsave = inb(hw_priv->cor_offset); | ||
306 | outb(corsave | COR_SRESET, hw_priv->cor_offset); | ||
307 | mdelay(10); | ||
308 | outb(hcr, hw_priv->cor_offset + 2); | ||
309 | mdelay(10); | ||
310 | outb(corsave & ~COR_SRESET, hw_priv->cor_offset); | ||
311 | mdelay(10); | ||
312 | } else { | ||
313 | /* PLX9052 */ | ||
314 | corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); | ||
315 | writeb(corsave | COR_SRESET, | ||
316 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
317 | mdelay(10); | ||
318 | writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2); | ||
319 | mdelay(10); | ||
320 | writeb(corsave & ~COR_SRESET, | ||
321 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
322 | mdelay(10); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | |||
327 | static struct prism2_helper_functions prism2_plx_funcs = | ||
328 | { | ||
329 | .card_present = NULL, | ||
330 | .cor_sreset = prism2_plx_cor_sreset, | ||
331 | .dev_open = NULL, | ||
332 | .dev_close = NULL, | ||
333 | .genesis_reset = prism2_plx_genesis_reset, | ||
334 | .hw_type = HOSTAP_HW_PLX, | ||
335 | }; | ||
336 | |||
337 | |||
338 | static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, | ||
339 | unsigned int *cor_offset, | ||
340 | unsigned int *cor_index) | ||
341 | { | ||
342 | #define CISTPL_CONFIG 0x1A | ||
343 | #define CISTPL_MANFID 0x20 | ||
344 | #define CISTPL_END 0xFF | ||
345 | #define CIS_MAX_LEN 256 | ||
346 | u8 *cis; | ||
347 | int i, pos; | ||
348 | unsigned int rmsz, rasz, manfid1, manfid2; | ||
349 | struct prism2_plx_manfid *manfid; | ||
350 | |||
351 | cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); | ||
352 | if (cis == NULL) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | /* read CIS; it is in even offsets in the beginning of attr_mem */ | ||
356 | for (i = 0; i < CIS_MAX_LEN; i++) | ||
357 | cis[i] = readb(attr_mem + 2 * i); | ||
358 | printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n", | ||
359 | dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]); | ||
360 | |||
361 | /* set reasonable defaults for Prism2 cards just in case CIS parsing | ||
362 | * fails */ | ||
363 | *cor_offset = 0x3e0; | ||
364 | *cor_index = 0x01; | ||
365 | manfid1 = manfid2 = 0; | ||
366 | |||
367 | pos = 0; | ||
368 | while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { | ||
369 | if (pos + cis[pos + 1] >= CIS_MAX_LEN) | ||
370 | goto cis_error; | ||
371 | |||
372 | switch (cis[pos]) { | ||
373 | case CISTPL_CONFIG: | ||
374 | if (cis[pos + 1] < 1) | ||
375 | goto cis_error; | ||
376 | rmsz = (cis[pos + 2] & 0x3c) >> 2; | ||
377 | rasz = cis[pos + 2] & 0x03; | ||
378 | if (4 + rasz + rmsz > cis[pos + 1]) | ||
379 | goto cis_error; | ||
380 | *cor_index = cis[pos + 3] & 0x3F; | ||
381 | *cor_offset = 0; | ||
382 | for (i = 0; i <= rasz; i++) | ||
383 | *cor_offset += cis[pos + 4 + i] << (8 * i); | ||
384 | printk(KERN_DEBUG "%s: cor_index=0x%x " | ||
385 | "cor_offset=0x%x\n", dev_info, | ||
386 | *cor_index, *cor_offset); | ||
387 | if (*cor_offset > attr_len) { | ||
388 | printk(KERN_ERR "%s: COR offset not within " | ||
389 | "attr_mem\n", dev_info); | ||
390 | kfree(cis); | ||
391 | return -1; | ||
392 | } | ||
393 | break; | ||
394 | |||
395 | case CISTPL_MANFID: | ||
396 | if (cis[pos + 1] < 4) | ||
397 | goto cis_error; | ||
398 | manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); | ||
399 | manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); | ||
400 | printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", | ||
401 | dev_info, manfid1, manfid2); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | pos += cis[pos + 1] + 2; | ||
406 | } | ||
407 | |||
408 | if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) | ||
409 | goto cis_error; | ||
410 | |||
411 | for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) | ||
412 | if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { | ||
413 | kfree(cis); | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" | ||
418 | " not supported card\n", dev_info, manfid1, manfid2); | ||
419 | goto fail; | ||
420 | |||
421 | cis_error: | ||
422 | printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); | ||
423 | |||
424 | fail: | ||
425 | kfree(cis); | ||
426 | if (ignore_cis) { | ||
427 | printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " | ||
428 | "errors during CIS verification\n", dev_info); | ||
429 | return 0; | ||
430 | } | ||
431 | return -1; | ||
432 | } | ||
433 | |||
434 | |||
435 | static int prism2_plx_probe(struct pci_dev *pdev, | ||
436 | const struct pci_device_id *id) | ||
437 | { | ||
438 | unsigned int pccard_ioaddr, plx_ioaddr; | ||
439 | unsigned long pccard_attr_mem; | ||
440 | unsigned int pccard_attr_len; | ||
441 | void __iomem *attr_mem = NULL; | ||
442 | unsigned int cor_offset, cor_index; | ||
443 | u32 reg; | ||
444 | local_info_t *local = NULL; | ||
445 | struct net_device *dev = NULL; | ||
446 | struct hostap_interface *iface; | ||
447 | static int cards_found /* = 0 */; | ||
448 | int irq_registered = 0; | ||
449 | int tmd7160; | ||
450 | struct hostap_plx_priv *hw_priv; | ||
451 | |||
452 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
453 | if (hw_priv == NULL) | ||
454 | return -ENOMEM; | ||
455 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
456 | |||
457 | if (pci_enable_device(pdev)) | ||
458 | return -EIO; | ||
459 | |||
460 | /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ | ||
461 | tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); | ||
462 | |||
463 | plx_ioaddr = pci_resource_start(pdev, 1); | ||
464 | pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); | ||
465 | |||
466 | if (tmd7160) { | ||
467 | /* TMD7160 */ | ||
468 | attr_mem = NULL; /* no access to PC Card attribute memory */ | ||
469 | |||
470 | printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " | ||
471 | "irq=%d, pccard_io=0x%x\n", | ||
472 | plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
473 | |||
474 | cor_offset = plx_ioaddr; | ||
475 | cor_index = 0x04; | ||
476 | |||
477 | outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); | ||
478 | mdelay(1); | ||
479 | reg = inb(plx_ioaddr); | ||
480 | if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { | ||
481 | printk(KERN_ERR "%s: Error setting COR (expected=" | ||
482 | "0x%02x, was=0x%02x)\n", dev_info, | ||
483 | cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); | ||
484 | goto fail; | ||
485 | } | ||
486 | } else { | ||
487 | /* PLX9052 */ | ||
488 | pccard_attr_mem = pci_resource_start(pdev, 2); | ||
489 | pccard_attr_len = pci_resource_len(pdev, 2); | ||
490 | if (pccard_attr_len < PLX_MIN_ATTR_LEN) | ||
491 | goto fail; | ||
492 | |||
493 | |||
494 | attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); | ||
495 | if (attr_mem == NULL) { | ||
496 | printk(KERN_ERR "%s: cannot remap attr_mem\n", | ||
497 | dev_info); | ||
498 | goto fail; | ||
499 | } | ||
500 | |||
501 | printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " | ||
502 | "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", | ||
503 | pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
504 | |||
505 | if (prism2_plx_check_cis(attr_mem, pccard_attr_len, | ||
506 | &cor_offset, &cor_index)) { | ||
507 | printk(KERN_INFO "Unknown PC Card CIS - not a " | ||
508 | "Prism2/2.5 card?\n"); | ||
509 | goto fail; | ||
510 | } | ||
511 | |||
512 | printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " | ||
513 | "adapter\n"); | ||
514 | |||
515 | /* Write COR to enable PC Card */ | ||
516 | writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, | ||
517 | attr_mem + cor_offset); | ||
518 | |||
519 | /* Enable PCI interrupts if they are not already enabled */ | ||
520 | reg = inl(plx_ioaddr + PLX_INTCSR); | ||
521 | printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); | ||
522 | if (!(reg & PLX_INTCSR_PCI_INTEN)) { | ||
523 | outl(reg | PLX_INTCSR_PCI_INTEN, | ||
524 | plx_ioaddr + PLX_INTCSR); | ||
525 | if (!(inl(plx_ioaddr + PLX_INTCSR) & | ||
526 | PLX_INTCSR_PCI_INTEN)) { | ||
527 | printk(KERN_WARNING "%s: Could not enable " | ||
528 | "Local Interrupts\n", dev_info); | ||
529 | goto fail; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | reg = inl(plx_ioaddr + PLX_CNTRL); | ||
534 | printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " | ||
535 | "present=%d)\n", | ||
536 | reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); | ||
537 | /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is | ||
538 | * not present; but are there really such cards in use(?) */ | ||
539 | } | ||
540 | |||
541 | dev = prism2_init_local_data(&prism2_plx_funcs, cards_found, | ||
542 | &pdev->dev); | ||
543 | if (dev == NULL) | ||
544 | goto fail; | ||
545 | iface = netdev_priv(dev); | ||
546 | local = iface->local; | ||
547 | local->hw_priv = hw_priv; | ||
548 | cards_found++; | ||
549 | |||
550 | dev->irq = pdev->irq; | ||
551 | dev->base_addr = pccard_ioaddr; | ||
552 | hw_priv->attr_mem = attr_mem; | ||
553 | hw_priv->cor_offset = cor_offset; | ||
554 | |||
555 | pci_set_drvdata(pdev, dev); | ||
556 | |||
557 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
558 | dev)) { | ||
559 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
560 | goto fail; | ||
561 | } else | ||
562 | irq_registered = 1; | ||
563 | |||
564 | if (prism2_hw_config(dev, 1)) { | ||
565 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
566 | dev_info); | ||
567 | goto fail; | ||
568 | } | ||
569 | |||
570 | return hostap_hw_ready(dev); | ||
571 | |||
572 | fail: | ||
573 | kfree(hw_priv); | ||
574 | if (local) | ||
575 | local->hw_priv = NULL; | ||
576 | prism2_free_local_data(dev); | ||
577 | |||
578 | if (irq_registered && dev) | ||
579 | free_irq(dev->irq, dev); | ||
580 | |||
581 | if (attr_mem) | ||
582 | iounmap(attr_mem); | ||
583 | |||
584 | pci_disable_device(pdev); | ||
585 | |||
586 | return -ENODEV; | ||
587 | } | ||
588 | |||
589 | |||
590 | static void prism2_plx_remove(struct pci_dev *pdev) | ||
591 | { | ||
592 | struct net_device *dev; | ||
593 | struct hostap_interface *iface; | ||
594 | struct hostap_plx_priv *hw_priv; | ||
595 | |||
596 | dev = pci_get_drvdata(pdev); | ||
597 | iface = netdev_priv(dev); | ||
598 | hw_priv = iface->local->hw_priv; | ||
599 | |||
600 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
601 | prism2_plx_cor_sreset(iface->local); | ||
602 | hfa384x_disable_interrupts(dev); | ||
603 | |||
604 | if (hw_priv->attr_mem) | ||
605 | iounmap(hw_priv->attr_mem); | ||
606 | if (dev->irq) | ||
607 | free_irq(dev->irq, dev); | ||
608 | |||
609 | kfree(iface->local->hw_priv); | ||
610 | iface->local->hw_priv = NULL; | ||
611 | prism2_free_local_data(dev); | ||
612 | pci_disable_device(pdev); | ||
613 | } | ||
614 | |||
615 | |||
616 | MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); | ||
617 | |||
618 | static struct pci_driver prism2_plx_drv_id = { | ||
619 | .name = "prism2_plx", | ||
620 | .id_table = prism2_plx_id_table, | ||
621 | .probe = prism2_plx_probe, | ||
622 | .remove = prism2_plx_remove, | ||
623 | .suspend = NULL, | ||
624 | .resume = NULL, | ||
625 | .enable_wake = NULL | ||
626 | }; | ||
627 | |||
628 | |||
629 | static int __init init_prism2_plx(void) | ||
630 | { | ||
631 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
632 | |||
633 | return pci_register_driver(&prism2_plx_drv_id); | ||
634 | } | ||
635 | |||
636 | |||
637 | static void __exit exit_prism2_plx(void) | ||
638 | { | ||
639 | pci_unregister_driver(&prism2_plx_drv_id); | ||
640 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
641 | } | ||
642 | |||
643 | |||
644 | module_init(init_prism2_plx); | ||
645 | module_exit(exit_prism2_plx); | ||
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c new file mode 100644 index 000000000000..a0a4cbd4937a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_proc.c | |||
@@ -0,0 +1,448 @@ | |||
1 | /* /proc routines for Host AP driver */ | ||
2 | |||
3 | #define PROC_LIMIT (PAGE_SIZE - 80) | ||
4 | |||
5 | |||
6 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
7 | static int prism2_debug_proc_read(char *page, char **start, off_t off, | ||
8 | int count, int *eof, void *data) | ||
9 | { | ||
10 | char *p = page; | ||
11 | local_info_t *local = (local_info_t *) data; | ||
12 | int i; | ||
13 | |||
14 | if (off != 0) { | ||
15 | *eof = 1; | ||
16 | return 0; | ||
17 | } | ||
18 | |||
19 | p += sprintf(p, "next_txfid=%d next_alloc=%d\n", | ||
20 | local->next_txfid, local->next_alloc); | ||
21 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) | ||
22 | p += sprintf(p, "FID: tx=%04X intransmit=%04X\n", | ||
23 | local->txfid[i], local->intransmitfid[i]); | ||
24 | p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control); | ||
25 | p += sprintf(p, "beacon_int=%d\n", local->beacon_int); | ||
26 | p += sprintf(p, "dtim_period=%d\n", local->dtim_period); | ||
27 | p += sprintf(p, "wds_max_connections=%d\n", | ||
28 | local->wds_max_connections); | ||
29 | p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); | ||
30 | p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); | ||
31 | for (i = 0; i < WEP_KEYS; i++) { | ||
32 | if (local->crypt[i] && local->crypt[i]->ops) { | ||
33 | p += sprintf(p, "crypt[%d]=%s\n", | ||
34 | i, local->crypt[i]->ops->name); | ||
35 | } | ||
36 | } | ||
37 | p += sprintf(p, "pri_only=%d\n", local->pri_only); | ||
38 | p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); | ||
39 | p += sprintf(p, "sram_type=%d\n", local->sram_type); | ||
40 | p += sprintf(p, "no_pri=%d\n", local->no_pri); | ||
41 | |||
42 | return (p - page); | ||
43 | } | ||
44 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
45 | |||
46 | |||
47 | static int prism2_stats_proc_read(char *page, char **start, off_t off, | ||
48 | int count, int *eof, void *data) | ||
49 | { | ||
50 | char *p = page; | ||
51 | local_info_t *local = (local_info_t *) data; | ||
52 | struct comm_tallies_sums *sums = (struct comm_tallies_sums *) | ||
53 | &local->comm_tallies; | ||
54 | |||
55 | if (off != 0) { | ||
56 | *eof = 1; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); | ||
61 | p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames); | ||
62 | p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments); | ||
63 | p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); | ||
64 | p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); | ||
65 | p += sprintf(p, "TxDeferredTransmissions=%u\n", | ||
66 | sums->tx_deferred_transmissions); | ||
67 | p += sprintf(p, "TxSingleRetryFrames=%u\n", | ||
68 | sums->tx_single_retry_frames); | ||
69 | p += sprintf(p, "TxMultipleRetryFrames=%u\n", | ||
70 | sums->tx_multiple_retry_frames); | ||
71 | p += sprintf(p, "TxRetryLimitExceeded=%u\n", | ||
72 | sums->tx_retry_limit_exceeded); | ||
73 | p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards); | ||
74 | p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); | ||
75 | p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); | ||
76 | p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments); | ||
77 | p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); | ||
78 | p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); | ||
79 | p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors); | ||
80 | p += sprintf(p, "RxDiscardsNoBuffer=%u\n", | ||
81 | sums->rx_discards_no_buffer); | ||
82 | p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); | ||
83 | p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n", | ||
84 | sums->rx_discards_wep_undecryptable); | ||
85 | p += sprintf(p, "RxMessageInMsgFragments=%u\n", | ||
86 | sums->rx_message_in_msg_fragments); | ||
87 | p += sprintf(p, "RxMessageInBadMsgFragments=%u\n", | ||
88 | sums->rx_message_in_bad_msg_fragments); | ||
89 | /* FIX: this may grow too long for one page(?) */ | ||
90 | |||
91 | return (p - page); | ||
92 | } | ||
93 | |||
94 | |||
95 | static int prism2_wds_proc_read(char *page, char **start, off_t off, | ||
96 | int count, int *eof, void *data) | ||
97 | { | ||
98 | char *p = page; | ||
99 | local_info_t *local = (local_info_t *) data; | ||
100 | struct list_head *ptr; | ||
101 | struct hostap_interface *iface; | ||
102 | |||
103 | if (off > PROC_LIMIT) { | ||
104 | *eof = 1; | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | read_lock_bh(&local->iface_lock); | ||
109 | list_for_each(ptr, &local->hostap_interfaces) { | ||
110 | iface = list_entry(ptr, struct hostap_interface, list); | ||
111 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
112 | continue; | ||
113 | p += sprintf(p, "%s\t" MACSTR "\n", | ||
114 | iface->dev->name, | ||
115 | MAC2STR(iface->u.wds.remote_addr)); | ||
116 | if ((p - page) > PROC_LIMIT) { | ||
117 | printk(KERN_DEBUG "%s: wds proc did not fit\n", | ||
118 | local->dev->name); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | read_unlock_bh(&local->iface_lock); | ||
123 | |||
124 | if ((p - page) <= off) { | ||
125 | *eof = 1; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | *start = page + off; | ||
130 | |||
131 | return (p - page - off); | ||
132 | } | ||
133 | |||
134 | |||
135 | static int prism2_bss_list_proc_read(char *page, char **start, off_t off, | ||
136 | int count, int *eof, void *data) | ||
137 | { | ||
138 | char *p = page; | ||
139 | local_info_t *local = (local_info_t *) data; | ||
140 | struct list_head *ptr; | ||
141 | struct hostap_bss_info *bss; | ||
142 | int i; | ||
143 | |||
144 | if (off > PROC_LIMIT) { | ||
145 | *eof = 1; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" | ||
150 | "SSID(hex)\tWPA IE\n"); | ||
151 | spin_lock_bh(&local->lock); | ||
152 | list_for_each(ptr, &local->bss_list) { | ||
153 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
154 | p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t", | ||
155 | MAC2STR(bss->bssid), bss->last_update, | ||
156 | bss->count, bss->capab_info); | ||
157 | for (i = 0; i < bss->ssid_len; i++) { | ||
158 | p += sprintf(p, "%c", | ||
159 | bss->ssid[i] >= 32 && bss->ssid[i] < 127 ? | ||
160 | bss->ssid[i] : '_'); | ||
161 | } | ||
162 | p += sprintf(p, "\t"); | ||
163 | for (i = 0; i < bss->ssid_len; i++) { | ||
164 | p += sprintf(p, "%02x", bss->ssid[i]); | ||
165 | } | ||
166 | p += sprintf(p, "\t"); | ||
167 | for (i = 0; i < bss->wpa_ie_len; i++) { | ||
168 | p += sprintf(p, "%02x", bss->wpa_ie[i]); | ||
169 | } | ||
170 | p += sprintf(p, "\n"); | ||
171 | if ((p - page) > PROC_LIMIT) { | ||
172 | printk(KERN_DEBUG "%s: BSS proc did not fit\n", | ||
173 | local->dev->name); | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | spin_unlock_bh(&local->lock); | ||
178 | |||
179 | if ((p - page) <= off) { | ||
180 | *eof = 1; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | *start = page + off; | ||
185 | |||
186 | return (p - page - off); | ||
187 | } | ||
188 | |||
189 | |||
190 | static int prism2_crypt_proc_read(char *page, char **start, off_t off, | ||
191 | int count, int *eof, void *data) | ||
192 | { | ||
193 | char *p = page; | ||
194 | local_info_t *local = (local_info_t *) data; | ||
195 | int i; | ||
196 | |||
197 | if (off > PROC_LIMIT) { | ||
198 | *eof = 1; | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx); | ||
203 | for (i = 0; i < WEP_KEYS; i++) { | ||
204 | if (local->crypt[i] && local->crypt[i]->ops && | ||
205 | local->crypt[i]->ops->print_stats) { | ||
206 | p = local->crypt[i]->ops->print_stats( | ||
207 | p, local->crypt[i]->priv); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if ((p - page) <= off) { | ||
212 | *eof = 1; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | *start = page + off; | ||
217 | |||
218 | return (p - page - off); | ||
219 | } | ||
220 | |||
221 | |||
222 | static int prism2_pda_proc_read(char *page, char **start, off_t off, | ||
223 | int count, int *eof, void *data) | ||
224 | { | ||
225 | local_info_t *local = (local_info_t *) data; | ||
226 | |||
227 | if (local->pda == NULL || off >= PRISM2_PDA_SIZE) { | ||
228 | *eof = 1; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | if (off + count > PRISM2_PDA_SIZE) | ||
233 | count = PRISM2_PDA_SIZE - off; | ||
234 | |||
235 | memcpy(page, local->pda + off, count); | ||
236 | return count; | ||
237 | } | ||
238 | |||
239 | |||
240 | static int prism2_aux_dump_proc_read(char *page, char **start, off_t off, | ||
241 | int count, int *eof, void *data) | ||
242 | { | ||
243 | local_info_t *local = (local_info_t *) data; | ||
244 | |||
245 | if (local->func->read_aux == NULL) { | ||
246 | *eof = 1; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | if (local->func->read_aux(local->dev, off, count, page)) { | ||
251 | *eof = 1; | ||
252 | return 0; | ||
253 | } | ||
254 | *start = page; | ||
255 | |||
256 | return count; | ||
257 | } | ||
258 | |||
259 | |||
260 | #ifdef PRISM2_IO_DEBUG | ||
261 | static int prism2_io_debug_proc_read(char *page, char **start, off_t off, | ||
262 | int count, int *eof, void *data) | ||
263 | { | ||
264 | local_info_t *local = (local_info_t *) data; | ||
265 | int head = local->io_debug_head; | ||
266 | int start_bytes, left, copy, copied; | ||
267 | |||
268 | if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { | ||
269 | *eof = 1; | ||
270 | if (off >= PRISM2_IO_DEBUG_SIZE * 4) | ||
271 | return 0; | ||
272 | count = PRISM2_IO_DEBUG_SIZE * 4 - off; | ||
273 | } | ||
274 | |||
275 | copied = 0; | ||
276 | start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; | ||
277 | left = count; | ||
278 | |||
279 | if (off < start_bytes) { | ||
280 | copy = start_bytes - off; | ||
281 | if (copy > count) | ||
282 | copy = count; | ||
283 | memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); | ||
284 | left -= copy; | ||
285 | if (left > 0) | ||
286 | memcpy(&page[copy], local->io_debug, left); | ||
287 | } else { | ||
288 | memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), | ||
289 | left); | ||
290 | } | ||
291 | |||
292 | *start = page; | ||
293 | |||
294 | return count; | ||
295 | } | ||
296 | #endif /* PRISM2_IO_DEBUG */ | ||
297 | |||
298 | |||
299 | #ifndef PRISM2_NO_STATION_MODES | ||
300 | static int prism2_scan_results_proc_read(char *page, char **start, off_t off, | ||
301 | int count, int *eof, void *data) | ||
302 | { | ||
303 | char *p = page; | ||
304 | local_info_t *local = (local_info_t *) data; | ||
305 | int entry, i, len, total = 0; | ||
306 | struct hfa384x_hostscan_result *scanres; | ||
307 | u8 *pos; | ||
308 | |||
309 | p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " | ||
310 | "SSID\n"); | ||
311 | |||
312 | spin_lock_bh(&local->lock); | ||
313 | for (entry = 0; entry < local->last_scan_results_count; entry++) { | ||
314 | scanres = &local->last_scan_results[entry]; | ||
315 | |||
316 | if (total + (p - page) <= off) { | ||
317 | total += p - page; | ||
318 | p = page; | ||
319 | } | ||
320 | if (total + (p - page) > off + count) | ||
321 | break; | ||
322 | if ((p - page) > (PAGE_SIZE - 200)) | ||
323 | break; | ||
324 | |||
325 | p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", | ||
326 | le16_to_cpu(scanres->chid), | ||
327 | (s16) le16_to_cpu(scanres->anl), | ||
328 | (s16) le16_to_cpu(scanres->sl), | ||
329 | le16_to_cpu(scanres->beacon_interval), | ||
330 | le16_to_cpu(scanres->capability), | ||
331 | le16_to_cpu(scanres->rate), | ||
332 | MAC2STR(scanres->bssid), | ||
333 | le16_to_cpu(scanres->atim)); | ||
334 | |||
335 | pos = scanres->sup_rates; | ||
336 | for (i = 0; i < sizeof(scanres->sup_rates); i++) { | ||
337 | if (pos[i] == 0) | ||
338 | break; | ||
339 | p += sprintf(p, "<%02x>", pos[i]); | ||
340 | } | ||
341 | p += sprintf(p, " "); | ||
342 | |||
343 | pos = scanres->ssid; | ||
344 | len = le16_to_cpu(scanres->ssid_len); | ||
345 | if (len > 32) | ||
346 | len = 32; | ||
347 | for (i = 0; i < len; i++) { | ||
348 | unsigned char c = pos[i]; | ||
349 | if (c >= 32 && c < 127) | ||
350 | p += sprintf(p, "%c", c); | ||
351 | else | ||
352 | p += sprintf(p, "<%02x>", c); | ||
353 | } | ||
354 | p += sprintf(p, "\n"); | ||
355 | } | ||
356 | spin_unlock_bh(&local->lock); | ||
357 | |||
358 | total += (p - page); | ||
359 | if (total >= off + count) | ||
360 | *eof = 1; | ||
361 | |||
362 | if (total < off) { | ||
363 | *eof = 1; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | len = total - off; | ||
368 | if (len > (p - page)) | ||
369 | len = p - page; | ||
370 | *start = p - len; | ||
371 | if (len > count) | ||
372 | len = count; | ||
373 | |||
374 | return len; | ||
375 | } | ||
376 | #endif /* PRISM2_NO_STATION_MODES */ | ||
377 | |||
378 | |||
379 | void hostap_init_proc(local_info_t *local) | ||
380 | { | ||
381 | local->proc = NULL; | ||
382 | |||
383 | if (hostap_proc == NULL) { | ||
384 | printk(KERN_WARNING "%s: hostap proc directory not created\n", | ||
385 | local->dev->name); | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | local->proc = proc_mkdir(local->ddev->name, hostap_proc); | ||
390 | if (local->proc == NULL) { | ||
391 | printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", | ||
392 | local->ddev->name); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
397 | create_proc_read_entry("debug", 0, local->proc, | ||
398 | prism2_debug_proc_read, local); | ||
399 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
400 | create_proc_read_entry("stats", 0, local->proc, | ||
401 | prism2_stats_proc_read, local); | ||
402 | create_proc_read_entry("wds", 0, local->proc, | ||
403 | prism2_wds_proc_read, local); | ||
404 | create_proc_read_entry("pda", 0, local->proc, | ||
405 | prism2_pda_proc_read, local); | ||
406 | create_proc_read_entry("aux_dump", 0, local->proc, | ||
407 | prism2_aux_dump_proc_read, local); | ||
408 | create_proc_read_entry("bss_list", 0, local->proc, | ||
409 | prism2_bss_list_proc_read, local); | ||
410 | create_proc_read_entry("crypt", 0, local->proc, | ||
411 | prism2_crypt_proc_read, local); | ||
412 | #ifdef PRISM2_IO_DEBUG | ||
413 | create_proc_read_entry("io_debug", 0, local->proc, | ||
414 | prism2_io_debug_proc_read, local); | ||
415 | #endif /* PRISM2_IO_DEBUG */ | ||
416 | #ifndef PRISM2_NO_STATION_MODES | ||
417 | create_proc_read_entry("scan_results", 0, local->proc, | ||
418 | prism2_scan_results_proc_read, local); | ||
419 | #endif /* PRISM2_NO_STATION_MODES */ | ||
420 | } | ||
421 | |||
422 | |||
423 | void hostap_remove_proc(local_info_t *local) | ||
424 | { | ||
425 | if (local->proc != NULL) { | ||
426 | #ifndef PRISM2_NO_STATION_MODES | ||
427 | remove_proc_entry("scan_results", local->proc); | ||
428 | #endif /* PRISM2_NO_STATION_MODES */ | ||
429 | #ifdef PRISM2_IO_DEBUG | ||
430 | remove_proc_entry("io_debug", local->proc); | ||
431 | #endif /* PRISM2_IO_DEBUG */ | ||
432 | remove_proc_entry("pda", local->proc); | ||
433 | remove_proc_entry("aux_dump", local->proc); | ||
434 | remove_proc_entry("wds", local->proc); | ||
435 | remove_proc_entry("stats", local->proc); | ||
436 | remove_proc_entry("bss_list", local->proc); | ||
437 | remove_proc_entry("crypt", local->proc); | ||
438 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
439 | remove_proc_entry("debug", local->proc); | ||
440 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
441 | if (hostap_proc != NULL) | ||
442 | remove_proc_entry(local->proc->name, hostap_proc); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | EXPORT_SYMBOL(hostap_init_proc); | ||
448 | EXPORT_SYMBOL(hostap_remove_proc); | ||
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h new file mode 100644 index 000000000000..cc061e1560d3 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_wlan.h | |||
@@ -0,0 +1,1033 @@ | |||
1 | #ifndef HOSTAP_WLAN_H | ||
2 | #define HOSTAP_WLAN_H | ||
3 | |||
4 | #include "hostap_config.h" | ||
5 | #include "hostap_common.h" | ||
6 | |||
7 | #define MAX_PARM_DEVICES 8 | ||
8 | #define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) | ||
9 | #define DEF_INTS -1, -1, -1, -1, -1, -1, -1 | ||
10 | #define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] | ||
11 | |||
12 | |||
13 | /* Specific skb->protocol value that indicates that the packet already contains | ||
14 | * txdesc header. | ||
15 | * FIX: This might need own value that would be allocated especially for Prism2 | ||
16 | * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". | ||
17 | * However, these skb's should have only minimal path in the kernel side since | ||
18 | * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ | ||
19 | #define ETH_P_HOSTAP ETH_P_CONTROL | ||
20 | |||
21 | /* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header | ||
22 | * (from linux-wlan-ng) */ | ||
23 | struct linux_wlan_ng_val { | ||
24 | u32 did; | ||
25 | u16 status, len; | ||
26 | u32 data; | ||
27 | } __attribute__ ((packed)); | ||
28 | |||
29 | struct linux_wlan_ng_prism_hdr { | ||
30 | u32 msgcode, msglen; | ||
31 | char devname[16]; | ||
32 | struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, | ||
33 | noise, rate, istx, frmlen; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct linux_wlan_ng_cap_hdr { | ||
37 | u32 version; | ||
38 | u32 length; | ||
39 | u64 mactime; | ||
40 | u64 hosttime; | ||
41 | u32 phytype; | ||
42 | u32 channel; | ||
43 | u32 datarate; | ||
44 | u32 antenna; | ||
45 | u32 priority; | ||
46 | u32 ssi_type; | ||
47 | s32 ssi_signal; | ||
48 | s32 ssi_noise; | ||
49 | u32 preamble; | ||
50 | u32 encoding; | ||
51 | } __attribute__ ((packed)); | ||
52 | |||
53 | #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ | ||
54 | #define LWNG_CAPHDR_VERSION 0x80211001 | ||
55 | |||
56 | struct hfa384x_rx_frame { | ||
57 | /* HFA384X RX frame descriptor */ | ||
58 | u16 status; /* HFA384X_RX_STATUS_ flags */ | ||
59 | u32 time; /* timestamp, 1 microsecond resolution */ | ||
60 | u8 silence; /* 27 .. 154; seems to be 0 */ | ||
61 | u8 signal; /* 27 .. 154 */ | ||
62 | u8 rate; /* 10, 20, 55, or 110 */ | ||
63 | u8 rxflow; | ||
64 | u32 reserved; | ||
65 | |||
66 | /* 802.11 */ | ||
67 | u16 frame_control; | ||
68 | u16 duration_id; | ||
69 | u8 addr1[6]; | ||
70 | u8 addr2[6]; | ||
71 | u8 addr3[6]; | ||
72 | u16 seq_ctrl; | ||
73 | u8 addr4[6]; | ||
74 | u16 data_len; | ||
75 | |||
76 | /* 802.3 */ | ||
77 | u8 dst_addr[6]; | ||
78 | u8 src_addr[6]; | ||
79 | u16 len; | ||
80 | |||
81 | /* followed by frame data; max 2304 bytes */ | ||
82 | } __attribute__ ((packed)); | ||
83 | |||
84 | |||
85 | struct hfa384x_tx_frame { | ||
86 | /* HFA384X TX frame descriptor */ | ||
87 | u16 status; /* HFA384X_TX_STATUS_ flags */ | ||
88 | u16 reserved1; | ||
89 | u16 reserved2; | ||
90 | u32 sw_support; | ||
91 | u8 retry_count; /* not yet implemented */ | ||
92 | u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ | ||
93 | u16 tx_control; /* HFA384X_TX_CTRL_ flags */ | ||
94 | |||
95 | /* 802.11 */ | ||
96 | u16 frame_control; /* parts not used */ | ||
97 | u16 duration_id; | ||
98 | u8 addr1[6]; | ||
99 | u8 addr2[6]; /* filled by firmware */ | ||
100 | u8 addr3[6]; | ||
101 | u16 seq_ctrl; /* filled by firmware */ | ||
102 | u8 addr4[6]; | ||
103 | u16 data_len; | ||
104 | |||
105 | /* 802.3 */ | ||
106 | u8 dst_addr[6]; | ||
107 | u8 src_addr[6]; | ||
108 | u16 len; | ||
109 | |||
110 | /* followed by frame data; max 2304 bytes */ | ||
111 | } __attribute__ ((packed)); | ||
112 | |||
113 | |||
114 | struct hfa384x_rid_hdr | ||
115 | { | ||
116 | u16 len; | ||
117 | u16 rid; | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | |||
121 | /* Macro for converting signal levels (range 27 .. 154) to wireless ext | ||
122 | * dBm value with some accuracy */ | ||
123 | #define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 | ||
124 | |||
125 | #define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 | ||
126 | |||
127 | struct hfa384x_scan_request { | ||
128 | u16 channel_list; | ||
129 | u16 txrate; /* HFA384X_RATES_* */ | ||
130 | } __attribute__ ((packed)); | ||
131 | |||
132 | struct hfa384x_hostscan_request { | ||
133 | u16 channel_list; | ||
134 | u16 txrate; | ||
135 | u16 target_ssid_len; | ||
136 | u8 target_ssid[32]; | ||
137 | } __attribute__ ((packed)); | ||
138 | |||
139 | struct hfa384x_join_request { | ||
140 | u8 bssid[6]; | ||
141 | u16 channel; | ||
142 | } __attribute__ ((packed)); | ||
143 | |||
144 | struct hfa384x_info_frame { | ||
145 | u16 len; | ||
146 | u16 type; | ||
147 | } __attribute__ ((packed)); | ||
148 | |||
149 | struct hfa384x_comm_tallies { | ||
150 | u16 tx_unicast_frames; | ||
151 | u16 tx_multicast_frames; | ||
152 | u16 tx_fragments; | ||
153 | u16 tx_unicast_octets; | ||
154 | u16 tx_multicast_octets; | ||
155 | u16 tx_deferred_transmissions; | ||
156 | u16 tx_single_retry_frames; | ||
157 | u16 tx_multiple_retry_frames; | ||
158 | u16 tx_retry_limit_exceeded; | ||
159 | u16 tx_discards; | ||
160 | u16 rx_unicast_frames; | ||
161 | u16 rx_multicast_frames; | ||
162 | u16 rx_fragments; | ||
163 | u16 rx_unicast_octets; | ||
164 | u16 rx_multicast_octets; | ||
165 | u16 rx_fcs_errors; | ||
166 | u16 rx_discards_no_buffer; | ||
167 | u16 tx_discards_wrong_sa; | ||
168 | u16 rx_discards_wep_undecryptable; | ||
169 | u16 rx_message_in_msg_fragments; | ||
170 | u16 rx_message_in_bad_msg_fragments; | ||
171 | } __attribute__ ((packed)); | ||
172 | |||
173 | struct hfa384x_comm_tallies32 { | ||
174 | u32 tx_unicast_frames; | ||
175 | u32 tx_multicast_frames; | ||
176 | u32 tx_fragments; | ||
177 | u32 tx_unicast_octets; | ||
178 | u32 tx_multicast_octets; | ||
179 | u32 tx_deferred_transmissions; | ||
180 | u32 tx_single_retry_frames; | ||
181 | u32 tx_multiple_retry_frames; | ||
182 | u32 tx_retry_limit_exceeded; | ||
183 | u32 tx_discards; | ||
184 | u32 rx_unicast_frames; | ||
185 | u32 rx_multicast_frames; | ||
186 | u32 rx_fragments; | ||
187 | u32 rx_unicast_octets; | ||
188 | u32 rx_multicast_octets; | ||
189 | u32 rx_fcs_errors; | ||
190 | u32 rx_discards_no_buffer; | ||
191 | u32 tx_discards_wrong_sa; | ||
192 | u32 rx_discards_wep_undecryptable; | ||
193 | u32 rx_message_in_msg_fragments; | ||
194 | u32 rx_message_in_bad_msg_fragments; | ||
195 | } __attribute__ ((packed)); | ||
196 | |||
197 | struct hfa384x_scan_result_hdr { | ||
198 | u16 reserved; | ||
199 | u16 scan_reason; | ||
200 | #define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ | ||
201 | #define HFA384X_SCAN_HOST_INITIATED 1 | ||
202 | #define HFA384X_SCAN_FIRMWARE_INITIATED 2 | ||
203 | #define HFA384X_SCAN_INQUIRY_FROM_HOST 3 | ||
204 | } __attribute__ ((packed)); | ||
205 | |||
206 | #define HFA384X_SCAN_MAX_RESULTS 32 | ||
207 | |||
208 | struct hfa384x_scan_result { | ||
209 | u16 chid; | ||
210 | u16 anl; | ||
211 | u16 sl; | ||
212 | u8 bssid[6]; | ||
213 | u16 beacon_interval; | ||
214 | u16 capability; | ||
215 | u16 ssid_len; | ||
216 | u8 ssid[32]; | ||
217 | u8 sup_rates[10]; | ||
218 | u16 rate; | ||
219 | } __attribute__ ((packed)); | ||
220 | |||
221 | struct hfa384x_hostscan_result { | ||
222 | u16 chid; | ||
223 | u16 anl; | ||
224 | u16 sl; | ||
225 | u8 bssid[6]; | ||
226 | u16 beacon_interval; | ||
227 | u16 capability; | ||
228 | u16 ssid_len; | ||
229 | u8 ssid[32]; | ||
230 | u8 sup_rates[10]; | ||
231 | u16 rate; | ||
232 | u16 atim; | ||
233 | } __attribute__ ((packed)); | ||
234 | |||
235 | struct comm_tallies_sums { | ||
236 | unsigned int tx_unicast_frames; | ||
237 | unsigned int tx_multicast_frames; | ||
238 | unsigned int tx_fragments; | ||
239 | unsigned int tx_unicast_octets; | ||
240 | unsigned int tx_multicast_octets; | ||
241 | unsigned int tx_deferred_transmissions; | ||
242 | unsigned int tx_single_retry_frames; | ||
243 | unsigned int tx_multiple_retry_frames; | ||
244 | unsigned int tx_retry_limit_exceeded; | ||
245 | unsigned int tx_discards; | ||
246 | unsigned int rx_unicast_frames; | ||
247 | unsigned int rx_multicast_frames; | ||
248 | unsigned int rx_fragments; | ||
249 | unsigned int rx_unicast_octets; | ||
250 | unsigned int rx_multicast_octets; | ||
251 | unsigned int rx_fcs_errors; | ||
252 | unsigned int rx_discards_no_buffer; | ||
253 | unsigned int tx_discards_wrong_sa; | ||
254 | unsigned int rx_discards_wep_undecryptable; | ||
255 | unsigned int rx_message_in_msg_fragments; | ||
256 | unsigned int rx_message_in_bad_msg_fragments; | ||
257 | }; | ||
258 | |||
259 | |||
260 | struct hfa384x_regs { | ||
261 | u16 cmd; | ||
262 | u16 evstat; | ||
263 | u16 offset0; | ||
264 | u16 offset1; | ||
265 | u16 swsupport0; | ||
266 | }; | ||
267 | |||
268 | |||
269 | #if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) | ||
270 | /* I/O ports for HFA384X Controller access */ | ||
271 | #define HFA384X_CMD_OFF 0x00 | ||
272 | #define HFA384X_PARAM0_OFF 0x02 | ||
273 | #define HFA384X_PARAM1_OFF 0x04 | ||
274 | #define HFA384X_PARAM2_OFF 0x06 | ||
275 | #define HFA384X_STATUS_OFF 0x08 | ||
276 | #define HFA384X_RESP0_OFF 0x0A | ||
277 | #define HFA384X_RESP1_OFF 0x0C | ||
278 | #define HFA384X_RESP2_OFF 0x0E | ||
279 | #define HFA384X_INFOFID_OFF 0x10 | ||
280 | #define HFA384X_CONTROL_OFF 0x14 | ||
281 | #define HFA384X_SELECT0_OFF 0x18 | ||
282 | #define HFA384X_SELECT1_OFF 0x1A | ||
283 | #define HFA384X_OFFSET0_OFF 0x1C | ||
284 | #define HFA384X_OFFSET1_OFF 0x1E | ||
285 | #define HFA384X_RXFID_OFF 0x20 | ||
286 | #define HFA384X_ALLOCFID_OFF 0x22 | ||
287 | #define HFA384X_TXCOMPLFID_OFF 0x24 | ||
288 | #define HFA384X_SWSUPPORT0_OFF 0x28 | ||
289 | #define HFA384X_SWSUPPORT1_OFF 0x2A | ||
290 | #define HFA384X_SWSUPPORT2_OFF 0x2C | ||
291 | #define HFA384X_EVSTAT_OFF 0x30 | ||
292 | #define HFA384X_INTEN_OFF 0x32 | ||
293 | #define HFA384X_EVACK_OFF 0x34 | ||
294 | #define HFA384X_DATA0_OFF 0x36 | ||
295 | #define HFA384X_DATA1_OFF 0x38 | ||
296 | #define HFA384X_AUXPAGE_OFF 0x3A | ||
297 | #define HFA384X_AUXOFFSET_OFF 0x3C | ||
298 | #define HFA384X_AUXDATA_OFF 0x3E | ||
299 | #endif /* PRISM2_PCCARD || PRISM2_PLX */ | ||
300 | |||
301 | #ifdef PRISM2_PCI | ||
302 | /* Memory addresses for ISL3874 controller access */ | ||
303 | #define HFA384X_CMD_OFF 0x00 | ||
304 | #define HFA384X_PARAM0_OFF 0x04 | ||
305 | #define HFA384X_PARAM1_OFF 0x08 | ||
306 | #define HFA384X_PARAM2_OFF 0x0C | ||
307 | #define HFA384X_STATUS_OFF 0x10 | ||
308 | #define HFA384X_RESP0_OFF 0x14 | ||
309 | #define HFA384X_RESP1_OFF 0x18 | ||
310 | #define HFA384X_RESP2_OFF 0x1C | ||
311 | #define HFA384X_INFOFID_OFF 0x20 | ||
312 | #define HFA384X_CONTROL_OFF 0x28 | ||
313 | #define HFA384X_SELECT0_OFF 0x30 | ||
314 | #define HFA384X_SELECT1_OFF 0x34 | ||
315 | #define HFA384X_OFFSET0_OFF 0x38 | ||
316 | #define HFA384X_OFFSET1_OFF 0x3C | ||
317 | #define HFA384X_RXFID_OFF 0x40 | ||
318 | #define HFA384X_ALLOCFID_OFF 0x44 | ||
319 | #define HFA384X_TXCOMPLFID_OFF 0x48 | ||
320 | #define HFA384X_PCICOR_OFF 0x4C | ||
321 | #define HFA384X_SWSUPPORT0_OFF 0x50 | ||
322 | #define HFA384X_SWSUPPORT1_OFF 0x54 | ||
323 | #define HFA384X_SWSUPPORT2_OFF 0x58 | ||
324 | #define HFA384X_PCIHCR_OFF 0x5C | ||
325 | #define HFA384X_EVSTAT_OFF 0x60 | ||
326 | #define HFA384X_INTEN_OFF 0x64 | ||
327 | #define HFA384X_EVACK_OFF 0x68 | ||
328 | #define HFA384X_DATA0_OFF 0x6C | ||
329 | #define HFA384X_DATA1_OFF 0x70 | ||
330 | #define HFA384X_AUXPAGE_OFF 0x74 | ||
331 | #define HFA384X_AUXOFFSET_OFF 0x78 | ||
332 | #define HFA384X_AUXDATA_OFF 0x7C | ||
333 | #define HFA384X_PCI_M0_ADDRH_OFF 0x80 | ||
334 | #define HFA384X_PCI_M0_ADDRL_OFF 0x84 | ||
335 | #define HFA384X_PCI_M0_LEN_OFF 0x88 | ||
336 | #define HFA384X_PCI_M0_CTL_OFF 0x8C | ||
337 | #define HFA384X_PCI_STATUS_OFF 0x98 | ||
338 | #define HFA384X_PCI_M1_ADDRH_OFF 0xA0 | ||
339 | #define HFA384X_PCI_M1_ADDRL_OFF 0xA4 | ||
340 | #define HFA384X_PCI_M1_LEN_OFF 0xA8 | ||
341 | #define HFA384X_PCI_M1_CTL_OFF 0xAC | ||
342 | |||
343 | /* PCI bus master control bits (these are undocumented; based on guessing and | ||
344 | * experimenting..) */ | ||
345 | #define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) | ||
346 | #define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) | ||
347 | |||
348 | #endif /* PRISM2_PCI */ | ||
349 | |||
350 | |||
351 | /* Command codes for CMD reg. */ | ||
352 | #define HFA384X_CMDCODE_INIT 0x00 | ||
353 | #define HFA384X_CMDCODE_ENABLE 0x01 | ||
354 | #define HFA384X_CMDCODE_DISABLE 0x02 | ||
355 | #define HFA384X_CMDCODE_ALLOC 0x0A | ||
356 | #define HFA384X_CMDCODE_TRANSMIT 0x0B | ||
357 | #define HFA384X_CMDCODE_INQUIRE 0x11 | ||
358 | #define HFA384X_CMDCODE_ACCESS 0x21 | ||
359 | #define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) | ||
360 | #define HFA384X_CMDCODE_DOWNLOAD 0x22 | ||
361 | #define HFA384X_CMDCODE_READMIF 0x30 | ||
362 | #define HFA384X_CMDCODE_WRITEMIF 0x31 | ||
363 | #define HFA384X_CMDCODE_TEST 0x38 | ||
364 | |||
365 | #define HFA384X_CMDCODE_MASK 0x3F | ||
366 | |||
367 | /* Test mode operations */ | ||
368 | #define HFA384X_TEST_CHANGE_CHANNEL 0x08 | ||
369 | #define HFA384X_TEST_MONITOR 0x0B | ||
370 | #define HFA384X_TEST_STOP 0x0F | ||
371 | #define HFA384X_TEST_CFG_BITS 0x15 | ||
372 | #define HFA384X_TEST_CFG_BIT_ALC BIT(3) | ||
373 | |||
374 | #define HFA384X_CMD_BUSY BIT(15) | ||
375 | |||
376 | #define HFA384X_CMD_TX_RECLAIM BIT(8) | ||
377 | |||
378 | #define HFA384X_OFFSET_ERR BIT(14) | ||
379 | #define HFA384X_OFFSET_BUSY BIT(15) | ||
380 | |||
381 | |||
382 | /* ProgMode for download command */ | ||
383 | #define HFA384X_PROGMODE_DISABLE 0 | ||
384 | #define HFA384X_PROGMODE_ENABLE_VOLATILE 1 | ||
385 | #define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 | ||
386 | #define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 | ||
387 | |||
388 | #define HFA384X_AUX_MAGIC0 0xfe01 | ||
389 | #define HFA384X_AUX_MAGIC1 0xdc23 | ||
390 | #define HFA384X_AUX_MAGIC2 0xba45 | ||
391 | |||
392 | #define HFA384X_AUX_PORT_DISABLED 0 | ||
393 | #define HFA384X_AUX_PORT_DISABLE BIT(14) | ||
394 | #define HFA384X_AUX_PORT_ENABLE BIT(15) | ||
395 | #define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) | ||
396 | #define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) | ||
397 | |||
398 | #define PRISM2_PDA_SIZE 1024 | ||
399 | |||
400 | |||
401 | /* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ | ||
402 | #define HFA384X_EV_TICK BIT(15) | ||
403 | #define HFA384X_EV_WTERR BIT(14) | ||
404 | #define HFA384X_EV_INFDROP BIT(13) | ||
405 | #ifdef PRISM2_PCI | ||
406 | #define HFA384X_EV_PCI_M1 BIT(9) | ||
407 | #define HFA384X_EV_PCI_M0 BIT(8) | ||
408 | #endif /* PRISM2_PCI */ | ||
409 | #define HFA384X_EV_INFO BIT(7) | ||
410 | #define HFA384X_EV_DTIM BIT(5) | ||
411 | #define HFA384X_EV_CMD BIT(4) | ||
412 | #define HFA384X_EV_ALLOC BIT(3) | ||
413 | #define HFA384X_EV_TXEXC BIT(2) | ||
414 | #define HFA384X_EV_TX BIT(1) | ||
415 | #define HFA384X_EV_RX BIT(0) | ||
416 | |||
417 | |||
418 | /* HFA384X Information frames */ | ||
419 | #define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ | ||
420 | #define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ | ||
421 | #define HFA384X_INFO_COMMTALLIES 0xF100 | ||
422 | #define HFA384X_INFO_SCANRESULTS 0xF101 | ||
423 | #define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ | ||
424 | #define HFA384X_INFO_HOSTSCANRESULTS 0xF103 | ||
425 | #define HFA384X_INFO_LINKSTATUS 0xF200 | ||
426 | #define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ | ||
427 | #define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ | ||
428 | #define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ | ||
429 | #define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ | ||
430 | |||
431 | enum { HFA384X_LINKSTATUS_CONNECTED = 1, | ||
432 | HFA384X_LINKSTATUS_DISCONNECTED = 2, | ||
433 | HFA384X_LINKSTATUS_AP_CHANGE = 3, | ||
434 | HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, | ||
435 | HFA384X_LINKSTATUS_AP_IN_RANGE = 5, | ||
436 | HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; | ||
437 | |||
438 | enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, | ||
439 | HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, | ||
440 | HFA384X_PORTTYPE_HOSTAP = 6 }; | ||
441 | |||
442 | #define HFA384X_RATES_1MBPS BIT(0) | ||
443 | #define HFA384X_RATES_2MBPS BIT(1) | ||
444 | #define HFA384X_RATES_5MBPS BIT(2) | ||
445 | #define HFA384X_RATES_11MBPS BIT(3) | ||
446 | |||
447 | #define HFA384X_ROAMING_FIRMWARE 1 | ||
448 | #define HFA384X_ROAMING_HOST 2 | ||
449 | #define HFA384X_ROAMING_DISABLED 3 | ||
450 | |||
451 | #define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) | ||
452 | #define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) | ||
453 | #define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) | ||
454 | #define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) | ||
455 | |||
456 | #define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) | ||
457 | #define HFA384X_RX_STATUS_PCF BIT(12) | ||
458 | #define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) | ||
459 | #define HFA384X_RX_STATUS_UNDECR BIT(1) | ||
460 | #define HFA384X_RX_STATUS_FCSERR BIT(0) | ||
461 | |||
462 | #define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ | ||
463 | (((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) | ||
464 | #define HFA384X_RX_STATUS_GET_MACPORT(s) \ | ||
465 | (((s) & HFA384X_RX_STATUS_MACPORT) >> 8) | ||
466 | |||
467 | enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, | ||
468 | HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; | ||
469 | |||
470 | |||
471 | #define HFA384X_TX_CTRL_ALT_RTRY BIT(5) | ||
472 | #define HFA384X_TX_CTRL_802_11 BIT(3) | ||
473 | #define HFA384X_TX_CTRL_802_3 0 | ||
474 | #define HFA384X_TX_CTRL_TX_EX BIT(2) | ||
475 | #define HFA384X_TX_CTRL_TX_OK BIT(1) | ||
476 | |||
477 | #define HFA384X_TX_STATUS_RETRYERR BIT(0) | ||
478 | #define HFA384X_TX_STATUS_AGEDERR BIT(1) | ||
479 | #define HFA384X_TX_STATUS_DISCON BIT(2) | ||
480 | #define HFA384X_TX_STATUS_FORMERR BIT(3) | ||
481 | |||
482 | /* HFA3861/3863 (BBP) Control Registers */ | ||
483 | #define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ | ||
484 | #define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ | ||
485 | #define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ | ||
486 | #define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ | ||
487 | #define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ | ||
488 | |||
489 | |||
490 | #ifdef __KERNEL__ | ||
491 | |||
492 | #define PRISM2_TXFID_COUNT 8 | ||
493 | #define PRISM2_DATA_MAXLEN 2304 | ||
494 | #define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) | ||
495 | #define PRISM2_TXFID_EMPTY 0xffff | ||
496 | #define PRISM2_TXFID_RESERVED 0xfffe | ||
497 | #define PRISM2_DUMMY_FID 0xffff | ||
498 | #define MAX_SSID_LEN 32 | ||
499 | #define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ | ||
500 | |||
501 | #define PRISM2_DUMP_RX_HDR BIT(0) | ||
502 | #define PRISM2_DUMP_TX_HDR BIT(1) | ||
503 | #define PRISM2_DUMP_TXEXC_HDR BIT(2) | ||
504 | |||
505 | struct hostap_tx_callback_info { | ||
506 | u16 idx; | ||
507 | void (*func)(struct sk_buff *, int ok, void *); | ||
508 | void *data; | ||
509 | struct hostap_tx_callback_info *next; | ||
510 | }; | ||
511 | |||
512 | |||
513 | /* IEEE 802.11 requires that STA supports concurrent reception of at least | ||
514 | * three fragmented frames. This define can be increased to support more | ||
515 | * concurrent frames, but it should be noted that each entry can consume about | ||
516 | * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ | ||
517 | #define PRISM2_FRAG_CACHE_LEN 4 | ||
518 | |||
519 | struct prism2_frag_entry { | ||
520 | unsigned long first_frag_time; | ||
521 | unsigned int seq; | ||
522 | unsigned int last_frag; | ||
523 | struct sk_buff *skb; | ||
524 | u8 src_addr[ETH_ALEN]; | ||
525 | u8 dst_addr[ETH_ALEN]; | ||
526 | }; | ||
527 | |||
528 | |||
529 | struct hostap_cmd_queue { | ||
530 | struct list_head list; | ||
531 | wait_queue_head_t compl; | ||
532 | volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; | ||
533 | void (*callback)(struct net_device *dev, long context, u16 resp0, | ||
534 | u16 res); | ||
535 | long context; | ||
536 | u16 cmd, param0, param1; | ||
537 | u16 resp0, res; | ||
538 | volatile int issued, issuing; | ||
539 | |||
540 | atomic_t usecnt; | ||
541 | int del_req; | ||
542 | }; | ||
543 | |||
544 | /* options for hw_shutdown */ | ||
545 | #define HOSTAP_HW_NO_DISABLE BIT(0) | ||
546 | #define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) | ||
547 | |||
548 | typedef struct local_info local_info_t; | ||
549 | |||
550 | struct prism2_helper_functions { | ||
551 | /* these functions are defined in hardware model specific files | ||
552 | * (hostap_{cs,plx,pci}.c */ | ||
553 | int (*card_present)(local_info_t *local); | ||
554 | void (*cor_sreset)(local_info_t *local); | ||
555 | int (*dev_open)(local_info_t *local); | ||
556 | int (*dev_close)(local_info_t *local); | ||
557 | void (*genesis_reset)(local_info_t *local, int hcr); | ||
558 | |||
559 | /* the following functions are from hostap_hw.c, but they may have some | ||
560 | * hardware model specific code */ | ||
561 | |||
562 | /* FIX: low-level commands like cmd might disappear at some point to | ||
563 | * make it easier to change them if needed (e.g., cmd would be replaced | ||
564 | * with write_mif/read_mif/testcmd/inquire); at least get_rid and | ||
565 | * set_rid might move to hostap_{cs,plx,pci}.c */ | ||
566 | int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, | ||
567 | u16 *resp0); | ||
568 | void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); | ||
569 | int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, | ||
570 | int exact_len); | ||
571 | int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); | ||
572 | int (*hw_enable)(struct net_device *dev, int initial); | ||
573 | int (*hw_config)(struct net_device *dev, int initial); | ||
574 | void (*hw_reset)(struct net_device *dev); | ||
575 | void (*hw_shutdown)(struct net_device *dev, int no_disable); | ||
576 | int (*reset_port)(struct net_device *dev); | ||
577 | void (*schedule_reset)(local_info_t *local); | ||
578 | int (*download)(local_info_t *local, | ||
579 | struct prism2_download_param *param); | ||
580 | int (*tx)(struct sk_buff *skb, struct net_device *dev); | ||
581 | int (*set_tim)(struct net_device *dev, int aid, int set); | ||
582 | int (*read_aux)(struct net_device *dev, unsigned addr, int len, | ||
583 | u8 *buf); | ||
584 | |||
585 | int need_tx_headroom; /* number of bytes of headroom needed before | ||
586 | * IEEE 802.11 header */ | ||
587 | enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; | ||
588 | }; | ||
589 | |||
590 | |||
591 | struct prism2_download_data { | ||
592 | u32 dl_cmd; | ||
593 | u32 start_addr; | ||
594 | u32 num_areas; | ||
595 | struct prism2_download_data_area { | ||
596 | u32 addr; /* wlan card address */ | ||
597 | u32 len; | ||
598 | u8 *data; /* allocated data */ | ||
599 | } data[0]; | ||
600 | }; | ||
601 | |||
602 | |||
603 | #define HOSTAP_MAX_BSS_COUNT 64 | ||
604 | #define MAX_WPA_IE_LEN 64 | ||
605 | |||
606 | struct hostap_bss_info { | ||
607 | struct list_head list; | ||
608 | unsigned long last_update; | ||
609 | unsigned int count; | ||
610 | u8 bssid[ETH_ALEN]; | ||
611 | u16 capab_info; | ||
612 | u8 ssid[32]; | ||
613 | size_t ssid_len; | ||
614 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
615 | size_t wpa_ie_len; | ||
616 | u8 rsn_ie[MAX_WPA_IE_LEN]; | ||
617 | size_t rsn_ie_len; | ||
618 | int chan; | ||
619 | int included; | ||
620 | }; | ||
621 | |||
622 | |||
623 | /* Per radio private Host AP data - shared by all net devices interfaces used | ||
624 | * by each radio (wlan#, wlan#ap, wlan#sta, WDS). | ||
625 | * ((struct hostap_interface *) netdev_priv(dev))->local points to this | ||
626 | * structure. */ | ||
627 | struct local_info { | ||
628 | struct module *hw_module; | ||
629 | int card_idx; | ||
630 | int dev_enabled; | ||
631 | int master_dev_auto_open; /* was master device opened automatically */ | ||
632 | int num_dev_open; /* number of open devices */ | ||
633 | struct net_device *dev; /* master radio device */ | ||
634 | struct net_device *ddev; /* main data device */ | ||
635 | struct list_head hostap_interfaces; /* Host AP interface list (contains | ||
636 | * struct hostap_interface entries) | ||
637 | */ | ||
638 | rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock | ||
639 | * when removing entries from the list. | ||
640 | * TX and RX paths can use read lock. */ | ||
641 | spinlock_t cmdlock, baplock, lock; | ||
642 | struct semaphore rid_bap_sem; | ||
643 | u16 infofid; /* MAC buffer id for info frame */ | ||
644 | /* txfid, intransmitfid, next_txtid, and next_alloc are protected by | ||
645 | * txfidlock */ | ||
646 | spinlock_t txfidlock; | ||
647 | int txfid_len; /* length of allocated TX buffers */ | ||
648 | u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ | ||
649 | /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if | ||
650 | * corresponding txfid is free for next TX frame */ | ||
651 | u16 intransmitfid[PRISM2_TXFID_COUNT]; | ||
652 | int next_txfid; /* index to the next txfid to be checked for | ||
653 | * availability */ | ||
654 | int next_alloc; /* index to the next intransmitfid to be checked for | ||
655 | * allocation events */ | ||
656 | |||
657 | /* bitfield for atomic bitops */ | ||
658 | #define HOSTAP_BITS_TRANSMIT 0 | ||
659 | #define HOSTAP_BITS_BAP_TASKLET 1 | ||
660 | #define HOSTAP_BITS_BAP_TASKLET2 2 | ||
661 | long bits; | ||
662 | |||
663 | struct ap_data *ap; | ||
664 | |||
665 | char essid[MAX_SSID_LEN + 1]; | ||
666 | char name[MAX_NAME_LEN + 1]; | ||
667 | int name_set; | ||
668 | u16 channel_mask; /* mask of allowed channels */ | ||
669 | u16 scan_channel_mask; /* mask of channels to be scanned */ | ||
670 | struct comm_tallies_sums comm_tallies; | ||
671 | struct net_device_stats stats; | ||
672 | struct proc_dir_entry *proc; | ||
673 | int iw_mode; /* operating mode (IW_MODE_*) */ | ||
674 | int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS | ||
675 | * 1: IW_MODE_ADHOC is "pseudo IBSS" */ | ||
676 | char bssid[ETH_ALEN]; | ||
677 | int channel; | ||
678 | int beacon_int; | ||
679 | int dtim_period; | ||
680 | int mtu; | ||
681 | int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ | ||
682 | int fw_tx_rate_control; | ||
683 | u16 tx_rate_control; | ||
684 | u16 basic_rates; | ||
685 | int hw_resetting; | ||
686 | int hw_ready; | ||
687 | int hw_reset_tries; /* how many times reset has been tried */ | ||
688 | int hw_downloading; | ||
689 | int shutdown; | ||
690 | int pri_only; | ||
691 | int no_pri; /* no PRI f/w present */ | ||
692 | int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ | ||
693 | |||
694 | enum { | ||
695 | PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, | ||
696 | PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN | ||
697 | } txpower_type; | ||
698 | int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ | ||
699 | |||
700 | /* command queue for hfa384x_cmd(); protected with cmdlock */ | ||
701 | struct list_head cmd_queue; | ||
702 | /* max_len for cmd_queue; in addition, cmd_callback can use two | ||
703 | * additional entries to prevent sleeping commands from stopping | ||
704 | * transmits */ | ||
705 | #define HOSTAP_CMD_QUEUE_MAX_LEN 16 | ||
706 | int cmd_queue_len; /* number of entries in cmd_queue */ | ||
707 | |||
708 | /* if card timeout is detected in interrupt context, reset_queue is | ||
709 | * used to schedule card reseting to be done in user context */ | ||
710 | struct work_struct reset_queue; | ||
711 | |||
712 | /* For scheduling a change of the promiscuous mode RID */ | ||
713 | int is_promisc; | ||
714 | struct work_struct set_multicast_list_queue; | ||
715 | |||
716 | struct work_struct set_tim_queue; | ||
717 | struct list_head set_tim_list; | ||
718 | spinlock_t set_tim_lock; | ||
719 | |||
720 | int wds_max_connections; | ||
721 | int wds_connections; | ||
722 | #define HOSTAP_WDS_BROADCAST_RA BIT(0) | ||
723 | #define HOSTAP_WDS_AP_CLIENT BIT(1) | ||
724 | #define HOSTAP_WDS_STANDARD_FRAME BIT(2) | ||
725 | u32 wds_type; | ||
726 | u16 tx_control; /* flags to be used in TX description */ | ||
727 | int manual_retry_count; /* -1 = use f/w default; otherwise retry count | ||
728 | * to be used with all frames */ | ||
729 | |||
730 | struct iw_statistics wstats; | ||
731 | unsigned long scan_timestamp; /* Time started to scan */ | ||
732 | enum { | ||
733 | PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, | ||
734 | PRISM2_MONITOR_CAPHDR = 2 | ||
735 | } monitor_type; | ||
736 | int (*saved_eth_header_parse)(struct sk_buff *skb, | ||
737 | unsigned char *haddr); | ||
738 | int monitor_allow_fcserr; | ||
739 | |||
740 | int hostapd; /* whether user space daemon, hostapd, is used for AP | ||
741 | * management */ | ||
742 | int hostapd_sta; /* whether hostapd is used with an extra STA interface | ||
743 | */ | ||
744 | struct net_device *apdev; | ||
745 | struct net_device_stats apdevstats; | ||
746 | |||
747 | char assoc_ap_addr[ETH_ALEN]; | ||
748 | struct net_device *stadev; | ||
749 | struct net_device_stats stadevstats; | ||
750 | |||
751 | #define WEP_KEYS 4 | ||
752 | #define WEP_KEY_LEN 13 | ||
753 | struct ieee80211_crypt_data *crypt[WEP_KEYS]; | ||
754 | int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ | ||
755 | struct timer_list crypt_deinit_timer; | ||
756 | struct list_head crypt_deinit_list; | ||
757 | |||
758 | int open_wep; /* allow unencrypted frames */ | ||
759 | int host_encrypt; | ||
760 | int host_decrypt; | ||
761 | int privacy_invoked; /* force privacy invoked flag even if no keys are | ||
762 | * configured */ | ||
763 | int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working | ||
764 | * in Host AP mode (STA f/w 1.4.9 or newer) */ | ||
765 | int bcrx_sta_key; /* use individual keys to override default keys even | ||
766 | * with RX of broad/multicast frames */ | ||
767 | |||
768 | struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; | ||
769 | unsigned int frag_next_idx; | ||
770 | |||
771 | int ieee_802_1x; /* is IEEE 802.1X used */ | ||
772 | |||
773 | int antsel_tx, antsel_rx; | ||
774 | int rts_threshold; /* dot11RTSThreshold */ | ||
775 | int fragm_threshold; /* dot11FragmentationThreshold */ | ||
776 | int auth_algs; /* PRISM2_AUTH_ flags */ | ||
777 | |||
778 | int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ | ||
779 | int tallies32; /* 32-bit tallies in use */ | ||
780 | |||
781 | struct prism2_helper_functions *func; | ||
782 | |||
783 | u8 *pda; | ||
784 | int fw_ap; | ||
785 | #define PRISM2_FW_VER(major, minor, variant) \ | ||
786 | (((major) << 16) | ((minor) << 8) | variant) | ||
787 | u32 sta_fw_ver; | ||
788 | |||
789 | /* Tasklets for handling hardware IRQ related operations outside hw IRQ | ||
790 | * handler */ | ||
791 | struct tasklet_struct bap_tasklet; | ||
792 | |||
793 | struct tasklet_struct info_tasklet; | ||
794 | struct sk_buff_head info_list; /* info frames as skb's for | ||
795 | * info_tasklet */ | ||
796 | |||
797 | struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks | ||
798 | */ | ||
799 | |||
800 | struct tasklet_struct rx_tasklet; | ||
801 | struct sk_buff_head rx_list; | ||
802 | |||
803 | struct tasklet_struct sta_tx_exc_tasklet; | ||
804 | struct sk_buff_head sta_tx_exc_list; | ||
805 | |||
806 | int host_roaming; | ||
807 | unsigned long last_join_time; /* time of last JoinRequest */ | ||
808 | struct hfa384x_hostscan_result *last_scan_results; | ||
809 | int last_scan_results_count; | ||
810 | enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; | ||
811 | struct work_struct info_queue; | ||
812 | long pending_info; /* bit field of pending info_queue items */ | ||
813 | #define PRISM2_INFO_PENDING_LINKSTATUS 0 | ||
814 | #define PRISM2_INFO_PENDING_SCANRESULTS 1 | ||
815 | int prev_link_status; /* previous received LinkStatus info */ | ||
816 | int prev_linkstatus_connected; | ||
817 | u8 preferred_ap[6]; /* use this AP if possible */ | ||
818 | |||
819 | #ifdef PRISM2_CALLBACK | ||
820 | void *callback_data; /* Can be used in callbacks; e.g., allocate | ||
821 | * on enable event and free on disable event. | ||
822 | * Host AP driver code does not touch this. */ | ||
823 | #endif /* PRISM2_CALLBACK */ | ||
824 | |||
825 | wait_queue_head_t hostscan_wq; | ||
826 | |||
827 | /* Passive scan in Host AP mode */ | ||
828 | struct timer_list passive_scan_timer; | ||
829 | int passive_scan_interval; /* in seconds, 0 = disabled */ | ||
830 | int passive_scan_channel; | ||
831 | enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; | ||
832 | |||
833 | struct timer_list tick_timer; | ||
834 | unsigned long last_tick_timer; | ||
835 | unsigned int sw_tick_stuck; | ||
836 | |||
837 | /* commsQuality / dBmCommsQuality data from periodic polling; only | ||
838 | * valid for Managed and Ad-hoc modes */ | ||
839 | unsigned long last_comms_qual_update; | ||
840 | int comms_qual; /* in some odd unit.. */ | ||
841 | int avg_signal; /* in dB (note: negative) */ | ||
842 | int avg_noise; /* in dB (note: negative) */ | ||
843 | struct work_struct comms_qual_update; | ||
844 | |||
845 | /* RSSI to dBm adjustment (for RX descriptor fields) */ | ||
846 | int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */ | ||
847 | |||
848 | /* BSS list / protected by local->lock */ | ||
849 | struct list_head bss_list; | ||
850 | int num_bss_info; | ||
851 | int wpa; /* WPA support enabled */ | ||
852 | int tkip_countermeasures; | ||
853 | int drop_unencrypted; | ||
854 | /* Generic IEEE 802.11 info element to be added to | ||
855 | * ProbeResp/Beacon/(Re)AssocReq */ | ||
856 | u8 *generic_elem; | ||
857 | size_t generic_elem_len; | ||
858 | |||
859 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
860 | /* Persistent volatile download data */ | ||
861 | struct prism2_download_data *dl_pri; | ||
862 | struct prism2_download_data *dl_sec; | ||
863 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
864 | |||
865 | #ifdef PRISM2_IO_DEBUG | ||
866 | #define PRISM2_IO_DEBUG_SIZE 10000 | ||
867 | u32 io_debug[PRISM2_IO_DEBUG_SIZE]; | ||
868 | int io_debug_head; | ||
869 | int io_debug_enabled; | ||
870 | #endif /* PRISM2_IO_DEBUG */ | ||
871 | |||
872 | /* Pointer to hardware model specific (cs,pci,plx) private data. */ | ||
873 | void *hw_priv; | ||
874 | }; | ||
875 | |||
876 | |||
877 | /* Per interface private Host AP data | ||
878 | * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, | ||
879 | * WDS) and netdev_priv(dev) points to this structure. */ | ||
880 | struct hostap_interface { | ||
881 | struct list_head list; /* list entry in Host AP interface list */ | ||
882 | struct net_device *dev; /* pointer to this device */ | ||
883 | struct local_info *local; /* pointer to shared private data */ | ||
884 | struct net_device_stats stats; | ||
885 | struct iw_spy_data spy_data; /* iwspy support */ | ||
886 | struct iw_public_data wireless_data; | ||
887 | |||
888 | enum { | ||
889 | HOSTAP_INTERFACE_MASTER, | ||
890 | HOSTAP_INTERFACE_MAIN, | ||
891 | HOSTAP_INTERFACE_AP, | ||
892 | HOSTAP_INTERFACE_STA, | ||
893 | HOSTAP_INTERFACE_WDS, | ||
894 | } type; | ||
895 | |||
896 | union { | ||
897 | struct hostap_interface_wds { | ||
898 | u8 remote_addr[ETH_ALEN]; | ||
899 | } wds; | ||
900 | } u; | ||
901 | }; | ||
902 | |||
903 | |||
904 | #define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 | ||
905 | |||
906 | /* | ||
907 | * TX meta data - stored in skb->cb buffer, so this must not be increased over | ||
908 | * the 40-byte limit | ||
909 | */ | ||
910 | struct hostap_skb_tx_data { | ||
911 | u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ | ||
912 | u8 rate; /* transmit rate */ | ||
913 | #define HOSTAP_TX_FLAGS_WDS BIT(0) | ||
914 | #define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1) | ||
915 | #define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2) | ||
916 | u8 flags; /* HOSTAP_TX_FLAGS_* */ | ||
917 | u16 tx_cb_idx; | ||
918 | struct hostap_interface *iface; | ||
919 | unsigned long jiffies; /* queueing timestamp */ | ||
920 | unsigned short ethertype; | ||
921 | }; | ||
922 | |||
923 | |||
924 | #ifndef PRISM2_NO_DEBUG | ||
925 | |||
926 | #define DEBUG_FID BIT(0) | ||
927 | #define DEBUG_PS BIT(1) | ||
928 | #define DEBUG_FLOW BIT(2) | ||
929 | #define DEBUG_AP BIT(3) | ||
930 | #define DEBUG_HW BIT(4) | ||
931 | #define DEBUG_EXTRA BIT(5) | ||
932 | #define DEBUG_EXTRA2 BIT(6) | ||
933 | #define DEBUG_PS2 BIT(7) | ||
934 | #define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) | ||
935 | #define PDEBUG(n, args...) \ | ||
936 | do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) | ||
937 | #define PDEBUG2(n, args...) \ | ||
938 | do { if ((n) & DEBUG_MASK) printk(args); } while (0) | ||
939 | |||
940 | #else /* PRISM2_NO_DEBUG */ | ||
941 | |||
942 | #define PDEBUG(n, args...) | ||
943 | #define PDEBUG2(n, args...) | ||
944 | |||
945 | #endif /* PRISM2_NO_DEBUG */ | ||
946 | |||
947 | enum { BAP0 = 0, BAP1 = 1 }; | ||
948 | |||
949 | #define PRISM2_IO_DEBUG_CMD_INB 0 | ||
950 | #define PRISM2_IO_DEBUG_CMD_INW 1 | ||
951 | #define PRISM2_IO_DEBUG_CMD_INSW 2 | ||
952 | #define PRISM2_IO_DEBUG_CMD_OUTB 3 | ||
953 | #define PRISM2_IO_DEBUG_CMD_OUTW 4 | ||
954 | #define PRISM2_IO_DEBUG_CMD_OUTSW 5 | ||
955 | #define PRISM2_IO_DEBUG_CMD_ERROR 6 | ||
956 | #define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 | ||
957 | |||
958 | #ifdef PRISM2_IO_DEBUG | ||
959 | |||
960 | #define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ | ||
961 | (((cmd) << 24) | ((reg) << 16) | value) | ||
962 | |||
963 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
964 | int reg, int value) | ||
965 | { | ||
966 | struct hostap_interface *iface = netdev_priv(dev); | ||
967 | local_info_t *local = iface->local; | ||
968 | |||
969 | if (!local->io_debug_enabled) | ||
970 | return; | ||
971 | |||
972 | local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; | ||
973 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
974 | local->io_debug_head = 0; | ||
975 | local->io_debug[local->io_debug_head] = | ||
976 | PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); | ||
977 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
978 | local->io_debug_head = 0; | ||
979 | } | ||
980 | |||
981 | |||
982 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
983 | { | ||
984 | struct hostap_interface *iface = netdev_priv(dev); | ||
985 | local_info_t *local = iface->local; | ||
986 | unsigned long flags; | ||
987 | |||
988 | if (!local->io_debug_enabled) | ||
989 | return; | ||
990 | |||
991 | spin_lock_irqsave(&local->lock, flags); | ||
992 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); | ||
993 | if (local->io_debug_enabled == 1) { | ||
994 | local->io_debug_enabled = 0; | ||
995 | printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); | ||
996 | } | ||
997 | spin_unlock_irqrestore(&local->lock, flags); | ||
998 | } | ||
999 | |||
1000 | #else /* PRISM2_IO_DEBUG */ | ||
1001 | |||
1002 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
1003 | int reg, int value) | ||
1004 | { | ||
1005 | } | ||
1006 | |||
1007 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
1008 | { | ||
1009 | } | ||
1010 | |||
1011 | #endif /* PRISM2_IO_DEBUG */ | ||
1012 | |||
1013 | |||
1014 | #ifdef PRISM2_CALLBACK | ||
1015 | enum { | ||
1016 | /* Called when card is enabled */ | ||
1017 | PRISM2_CALLBACK_ENABLE, | ||
1018 | |||
1019 | /* Called when card is disabled */ | ||
1020 | PRISM2_CALLBACK_DISABLE, | ||
1021 | |||
1022 | /* Called when RX/TX starts/ends */ | ||
1023 | PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, | ||
1024 | PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END | ||
1025 | }; | ||
1026 | void prism2_callback(local_info_t *local, int event); | ||
1027 | #else /* PRISM2_CALLBACK */ | ||
1028 | #define prism2_callback(d, e) do { } while (0) | ||
1029 | #endif /* PRISM2_CALLBACK */ | ||
1030 | |||
1031 | #endif /* __KERNEL__ */ | ||
1032 | |||
1033 | #endif /* HOSTAP_WLAN_H */ | ||
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 6c42b573a95a..4b0acae22b0d 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c | |||
@@ -209,7 +209,7 @@ enum { | |||
209 | NoStructure = 0, /* Really old firmware */ | 209 | NoStructure = 0, /* Really old firmware */ |
210 | StructuredMessages = 1, /* Parsable AT response msgs */ | 210 | StructuredMessages = 1, /* Parsable AT response msgs */ |
211 | ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ | 211 | ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ |
212 | } FirmwareLevel; | 212 | }; |
213 | 213 | ||
214 | struct strip { | 214 | struct strip { |
215 | int magic; | 215 | int magic; |
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index f6130a53b796..183c4732ef65 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c | |||
@@ -59,6 +59,12 @@ | |||
59 | /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ | 59 | /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ |
60 | #include "wavelan_cs.p.h" /* Private header */ | 60 | #include "wavelan_cs.p.h" /* Private header */ |
61 | 61 | ||
62 | #ifdef WAVELAN_ROAMING | ||
63 | static void wl_cell_expiry(unsigned long data); | ||
64 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp); | ||
65 | static void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
66 | #endif /* WAVELAN_ROAMING */ | ||
67 | |||
62 | /************************* MISC SUBROUTINES **************************/ | 68 | /************************* MISC SUBROUTINES **************************/ |
63 | /* | 69 | /* |
64 | * Subroutines which won't fit in one of the following category | 70 | * Subroutines which won't fit in one of the following category |
@@ -500,9 +506,9 @@ fee_write(u_long base, /* i/o port of the card */ | |||
500 | 506 | ||
501 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ | 507 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ |
502 | 508 | ||
503 | unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; | 509 | static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00}; |
504 | 510 | ||
505 | void wv_roam_init(struct net_device *dev) | 511 | static void wv_roam_init(struct net_device *dev) |
506 | { | 512 | { |
507 | net_local *lp= netdev_priv(dev); | 513 | net_local *lp= netdev_priv(dev); |
508 | 514 | ||
@@ -531,7 +537,7 @@ void wv_roam_init(struct net_device *dev) | |||
531 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); | 537 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); |
532 | } | 538 | } |
533 | 539 | ||
534 | void wv_roam_cleanup(struct net_device *dev) | 540 | static void wv_roam_cleanup(struct net_device *dev) |
535 | { | 541 | { |
536 | wavepoint_history *ptr,*old_ptr; | 542 | wavepoint_history *ptr,*old_ptr; |
537 | net_local *lp= netdev_priv(dev); | 543 | net_local *lp= netdev_priv(dev); |
@@ -550,7 +556,7 @@ void wv_roam_cleanup(struct net_device *dev) | |||
550 | } | 556 | } |
551 | 557 | ||
552 | /* Enable/Disable NWID promiscuous mode on a given device */ | 558 | /* Enable/Disable NWID promiscuous mode on a given device */ |
553 | void wv_nwid_filter(unsigned char mode, net_local *lp) | 559 | static void wv_nwid_filter(unsigned char mode, net_local *lp) |
554 | { | 560 | { |
555 | mm_t m; | 561 | mm_t m; |
556 | unsigned long flags; | 562 | unsigned long flags; |
@@ -575,7 +581,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp) | |||
575 | } | 581 | } |
576 | 582 | ||
577 | /* Find a record in the WavePoint table matching a given NWID */ | 583 | /* Find a record in the WavePoint table matching a given NWID */ |
578 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | 584 | static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) |
579 | { | 585 | { |
580 | wavepoint_history *ptr=lp->wavepoint_table.head; | 586 | wavepoint_history *ptr=lp->wavepoint_table.head; |
581 | 587 | ||
@@ -588,7 +594,7 @@ wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | |||
588 | } | 594 | } |
589 | 595 | ||
590 | /* Create a new wavepoint table entry */ | 596 | /* Create a new wavepoint table entry */ |
591 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) | 597 | static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) |
592 | { | 598 | { |
593 | wavepoint_history *new_wavepoint; | 599 | wavepoint_history *new_wavepoint; |
594 | 600 | ||
@@ -624,7 +630,7 @@ wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_ | |||
624 | } | 630 | } |
625 | 631 | ||
626 | /* Remove a wavepoint entry from WavePoint table */ | 632 | /* Remove a wavepoint entry from WavePoint table */ |
627 | void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | 633 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) |
628 | { | 634 | { |
629 | if(wavepoint==NULL) | 635 | if(wavepoint==NULL) |
630 | return; | 636 | return; |
@@ -646,7 +652,7 @@ void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | |||
646 | } | 652 | } |
647 | 653 | ||
648 | /* Timer callback function - checks WavePoint table for stale entries */ | 654 | /* Timer callback function - checks WavePoint table for stale entries */ |
649 | void wl_cell_expiry(unsigned long data) | 655 | static void wl_cell_expiry(unsigned long data) |
650 | { | 656 | { |
651 | net_local *lp=(net_local *)data; | 657 | net_local *lp=(net_local *)data; |
652 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; | 658 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; |
@@ -686,7 +692,7 @@ void wl_cell_expiry(unsigned long data) | |||
686 | } | 692 | } |
687 | 693 | ||
688 | /* Update SNR history of a wavepoint */ | 694 | /* Update SNR history of a wavepoint */ |
689 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) | 695 | static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) |
690 | { | 696 | { |
691 | int i=0,num_missed=0,ptr=0; | 697 | int i=0,num_missed=0,ptr=0; |
692 | int average_fast=0,average_slow=0; | 698 | int average_fast=0,average_slow=0; |
@@ -723,7 +729,7 @@ void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsi | |||
723 | } | 729 | } |
724 | 730 | ||
725 | /* Perform a handover to a new WavePoint */ | 731 | /* Perform a handover to a new WavePoint */ |
726 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) | 732 | static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) |
727 | { | 733 | { |
728 | kio_addr_t base = lp->dev->base_addr; | 734 | kio_addr_t base = lp->dev->base_addr; |
729 | mm_t m; | 735 | mm_t m; |
diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h index 29cff6daf860..fabc63ee153c 100644 --- a/drivers/net/wireless/wavelan_cs.h +++ b/drivers/net/wireless/wavelan_cs.h | |||
@@ -62,7 +62,7 @@ | |||
62 | * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this | 62 | * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this |
63 | * part to accommodate your hardware... | 63 | * part to accommodate your hardware... |
64 | */ | 64 | */ |
65 | const unsigned char MAC_ADDRESSES[][3] = | 65 | static const unsigned char MAC_ADDRESSES[][3] = |
66 | { | 66 | { |
67 | { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ | 67 | { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ |
68 | { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ | 68 | { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ |
@@ -79,14 +79,14 @@ const unsigned char MAC_ADDRESSES[][3] = | |||
79 | * (as read in the offset register of the dac area). | 79 | * (as read in the offset register of the dac area). |
80 | * Used to map channel numbers used by `wfreqsel' to frequencies | 80 | * Used to map channel numbers used by `wfreqsel' to frequencies |
81 | */ | 81 | */ |
82 | const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, | 82 | static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, |
83 | 0xD0, 0xF0, 0xF8, 0x150 }; | 83 | 0xD0, 0xF0, 0xF8, 0x150 }; |
84 | 84 | ||
85 | /* Frequencies of the 1.0 modem (fixed frequencies). | 85 | /* Frequencies of the 1.0 modem (fixed frequencies). |
86 | * Use to map the PSA `subband' to a frequency | 86 | * Use to map the PSA `subband' to a frequency |
87 | * Note : all frequencies apart from the first one need to be multiplied by 10 | 87 | * Note : all frequencies apart from the first one need to be multiplied by 10 |
88 | */ | 88 | */ |
89 | const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; | 89 | static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; |
90 | 90 | ||
91 | 91 | ||
92 | /*************************** PC INTERFACE ****************************/ | 92 | /*************************** PC INTERFACE ****************************/ |
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 677ff71883cb..01d882be8790 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h | |||
@@ -647,23 +647,6 @@ struct net_local | |||
647 | void __iomem *mem; | 647 | void __iomem *mem; |
648 | }; | 648 | }; |
649 | 649 | ||
650 | /**************************** PROTOTYPES ****************************/ | ||
651 | |||
652 | #ifdef WAVELAN_ROAMING | ||
653 | /* ---------------------- ROAMING SUBROUTINES -----------------------*/ | ||
654 | |||
655 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); | ||
656 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); | ||
657 | void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); | ||
658 | void wl_cell_expiry(unsigned long data); | ||
659 | wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); | ||
660 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); | ||
661 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); | ||
662 | void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
663 | void wv_roam_init(struct net_device *dev); | ||
664 | void wv_roam_cleanup(struct net_device *dev); | ||
665 | #endif /* WAVELAN_ROAMING */ | ||
666 | |||
667 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | 650 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ |
668 | static inline u_char /* data */ | 651 | static inline u_char /* data */ |
669 | hasr_read(u_long); /* Read the host interface : base address */ | 652 | hasr_read(u_long); /* Read the host interface : base address */ |
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index dd902126d018..7cc5edbf6ede 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -296,7 +296,8 @@ static int wl3501_get_flash_mac_addr(struct wl3501_card *this) | |||
296 | * | 296 | * |
297 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) | 297 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) |
298 | */ | 298 | */ |
299 | void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | 299 | static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, |
300 | int size) | ||
300 | { | 301 | { |
301 | /* switch to SRAM Page 0 */ | 302 | /* switch to SRAM Page 0 */ |
302 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : | 303 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -317,8 +318,8 @@ void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | |||
317 | * | 318 | * |
318 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) | 319 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) |
319 | */ | 320 | */ |
320 | void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, | 321 | static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, |
321 | int size) | 322 | int size) |
322 | { | 323 | { |
323 | /* switch to SRAM Page 0 */ | 324 | /* switch to SRAM Page 0 */ |
324 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : | 325 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -1438,14 +1439,14 @@ fail: | |||
1438 | goto out; | 1439 | goto out; |
1439 | } | 1440 | } |
1440 | 1441 | ||
1441 | struct net_device_stats *wl3501_get_stats(struct net_device *dev) | 1442 | static struct net_device_stats *wl3501_get_stats(struct net_device *dev) |
1442 | { | 1443 | { |
1443 | struct wl3501_card *this = dev->priv; | 1444 | struct wl3501_card *this = dev->priv; |
1444 | 1445 | ||
1445 | return &this->stats; | 1446 | return &this->stats; |
1446 | } | 1447 | } |
1447 | 1448 | ||
1448 | struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) | 1449 | static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) |
1449 | { | 1450 | { |
1450 | struct wl3501_card *this = dev->priv; | 1451 | struct wl3501_card *this = dev->priv; |
1451 | struct iw_statistics *wstats = &this->wstats; | 1452 | struct iw_statistics *wstats = &this->wstats; |