diff options
Diffstat (limited to 'drivers')
33 files changed, 21595 insertions, 68 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 0aaa12c0c09..a60866d62ec 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -355,6 +355,8 @@ config PRISM54 | |||
355 | say M here and read <file:Documentation/modules.txt>. The module | 355 | say M here and read <file:Documentation/modules.txt>. The module |
356 | will be called prism54.ko. | 356 | will be called prism54.ko. |
357 | 357 | ||
358 | source "drivers/net/wireless/hostap/Kconfig" | ||
359 | |||
358 | # yes, this works even when no drivers are selected | 360 | # yes, this works even when no drivers are selected |
359 | config NET_WIRELESS | 361 | config NET_WIRELESS |
360 | bool | 362 | bool |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 2b87841322c..6c9cb0eb858 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -28,6 +28,8 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | |||
28 | 28 | ||
29 | obj-$(CONFIG_PRISM54) += prism54/ | 29 | obj-$(CONFIG_PRISM54) += prism54/ |
30 | 30 | ||
31 | obj-$(CONFIG_HOSTAP) += hostap/ | ||
32 | |||
31 | # 16-bit wireless PCMCIA client drivers | 33 | # 16-bit wireless PCMCIA client drivers |
32 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o | 34 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o |
33 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o | 35 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 463c789cdc7..e3168a13b78 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); |
@@ -1223,6 +1223,12 @@ static int setup_proc_entry( struct net_device *dev, | |||
1223 | static int takedown_proc_entry( struct net_device *dev, | 1223 | static int takedown_proc_entry( struct net_device *dev, |
1224 | struct airo_info *apriv ); | 1224 | struct airo_info *apriv ); |
1225 | 1225 | ||
1226 | static int cmdreset(struct airo_info *ai); | ||
1227 | static int setflashmode (struct airo_info *ai); | ||
1228 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); | ||
1229 | static int flashputbuf(struct airo_info *ai); | ||
1230 | static int flashrestart(struct airo_info *ai,struct net_device *dev); | ||
1231 | |||
1226 | #ifdef MICSUPPORT | 1232 | #ifdef MICSUPPORT |
1227 | /*********************************************************************** | 1233 | /*********************************************************************** |
1228 | * MIC ROUTINES * | 1234 | * MIC ROUTINES * |
@@ -1231,10 +1237,11 @@ static int takedown_proc_entry( struct net_device *dev, | |||
1231 | 1237 | ||
1232 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); | 1238 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); |
1233 | static void MoveWindow(miccntx *context, u32 micSeq); | 1239 | static void MoveWindow(miccntx *context, u32 micSeq); |
1234 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); | 1240 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); |
1235 | void emmh32_init(emmh32_context *context); | 1241 | static void emmh32_init(emmh32_context *context); |
1236 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len); | 1242 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); |
1237 | void emmh32_final(emmh32_context *context, u8 digest[4]); | 1243 | static void emmh32_final(emmh32_context *context, u8 digest[4]); |
1244 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime); | ||
1238 | 1245 | ||
1239 | /* micinit - Initialize mic seed */ | 1246 | /* micinit - Initialize mic seed */ |
1240 | 1247 | ||
@@ -1312,7 +1319,7 @@ static int micsetup(struct airo_info *ai) { | |||
1312 | return SUCCESS; | 1319 | return SUCCESS; |
1313 | } | 1320 | } |
1314 | 1321 | ||
1315 | char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; | 1322 | static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; |
1316 | 1323 | ||
1317 | /*=========================================================================== | 1324 | /*=========================================================================== |
1318 | * Description: Mic a packet | 1325 | * Description: Mic a packet |
@@ -1567,7 +1574,7 @@ static void MoveWindow(miccntx *context, u32 micSeq) | |||
1567 | static unsigned char aes_counter[16]; | 1574 | static unsigned char aes_counter[16]; |
1568 | 1575 | ||
1569 | /* expand the key to fill the MMH coefficient array */ | 1576 | /* expand the key to fill the MMH coefficient array */ |
1570 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) | 1577 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) |
1571 | { | 1578 | { |
1572 | /* take the keying material, expand if necessary, truncate at 16-bytes */ | 1579 | /* take the keying material, expand if necessary, truncate at 16-bytes */ |
1573 | /* run through AES counter mode to generate context->coeff[] */ | 1580 | /* run through AES counter mode to generate context->coeff[] */ |
@@ -1599,7 +1606,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto | |||
1599 | } | 1606 | } |
1600 | 1607 | ||
1601 | /* prepare for calculation of a new mic */ | 1608 | /* prepare for calculation of a new mic */ |
1602 | void emmh32_init(emmh32_context *context) | 1609 | static void emmh32_init(emmh32_context *context) |
1603 | { | 1610 | { |
1604 | /* prepare for new mic calculation */ | 1611 | /* prepare for new mic calculation */ |
1605 | context->accum = 0; | 1612 | context->accum = 0; |
@@ -1607,7 +1614,7 @@ void emmh32_init(emmh32_context *context) | |||
1607 | } | 1614 | } |
1608 | 1615 | ||
1609 | /* add some bytes to the mic calculation */ | 1616 | /* add some bytes to the mic calculation */ |
1610 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | 1617 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) |
1611 | { | 1618 | { |
1612 | int coeff_position, byte_position; | 1619 | int coeff_position, byte_position; |
1613 | 1620 | ||
@@ -1649,7 +1656,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | |||
1649 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; | 1656 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; |
1650 | 1657 | ||
1651 | /* calculate the mic */ | 1658 | /* calculate the mic */ |
1652 | void emmh32_final(emmh32_context *context, u8 digest[4]) | 1659 | static void emmh32_final(emmh32_context *context, u8 digest[4]) |
1653 | { | 1660 | { |
1654 | int coeff_position, byte_position; | 1661 | int coeff_position, byte_position; |
1655 | u32 val; | 1662 | u32 val; |
@@ -2251,7 +2258,7 @@ static void airo_read_stats(struct airo_info *ai) { | |||
2251 | ai->stats.rx_fifo_errors = vals[0]; | 2258 | ai->stats.rx_fifo_errors = vals[0]; |
2252 | } | 2259 | } |
2253 | 2260 | ||
2254 | struct net_device_stats *airo_get_stats(struct net_device *dev) | 2261 | static struct net_device_stats *airo_get_stats(struct net_device *dev) |
2255 | { | 2262 | { |
2256 | struct airo_info *local = dev->priv; | 2263 | struct airo_info *local = dev->priv; |
2257 | 2264 | ||
@@ -2410,7 +2417,7 @@ EXPORT_SYMBOL(stop_airo_card); | |||
2410 | 2417 | ||
2411 | static int add_airo_dev( struct net_device *dev ); | 2418 | static int add_airo_dev( struct net_device *dev ); |
2412 | 2419 | ||
2413 | int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) | 2420 | static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) |
2414 | { | 2421 | { |
2415 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); | 2422 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); |
2416 | return ETH_ALEN; | 2423 | return ETH_ALEN; |
@@ -2677,7 +2684,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, | |||
2677 | return dev; | 2684 | return dev; |
2678 | } | 2685 | } |
2679 | 2686 | ||
2680 | int reset_card( struct net_device *dev , int lock) { | 2687 | static int reset_card( struct net_device *dev , int lock) { |
2681 | struct airo_info *ai = dev->priv; | 2688 | struct airo_info *ai = dev->priv; |
2682 | 2689 | ||
2683 | if (lock && down_interruptible(&ai->sem)) | 2690 | if (lock && down_interruptible(&ai->sem)) |
@@ -2692,9 +2699,9 @@ int reset_card( struct net_device *dev , int lock) { | |||
2692 | return 0; | 2699 | return 0; |
2693 | } | 2700 | } |
2694 | 2701 | ||
2695 | struct net_device *_init_airo_card( unsigned short irq, int port, | 2702 | static struct net_device *_init_airo_card( unsigned short irq, int port, |
2696 | int is_pcmcia, struct pci_dev *pci, | 2703 | int is_pcmcia, struct pci_dev *pci, |
2697 | struct device *dmdev ) | 2704 | struct device *dmdev ) |
2698 | { | 2705 | { |
2699 | struct net_device *dev; | 2706 | struct net_device *dev; |
2700 | struct airo_info *ai; | 2707 | struct airo_info *ai; |
@@ -7177,7 +7184,7 @@ static void airo_read_wireless_stats(struct airo_info *local) | |||
7177 | local->wstats.miss.beacon = vals[34]; | 7184 | local->wstats.miss.beacon = vals[34]; |
7178 | } | 7185 | } |
7179 | 7186 | ||
7180 | struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) | 7187 | static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) |
7181 | { | 7188 | { |
7182 | struct airo_info *local = dev->priv; | 7189 | struct airo_info *local = dev->priv; |
7183 | 7190 | ||
@@ -7392,14 +7399,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { | |||
7392 | * Flash command switch table | 7399 | * Flash command switch table |
7393 | */ | 7400 | */ |
7394 | 7401 | ||
7395 | int flashcard(struct net_device *dev, aironet_ioctl *comp) { | 7402 | static int flashcard(struct net_device *dev, aironet_ioctl *comp) { |
7396 | int z; | 7403 | int z; |
7397 | int cmdreset(struct airo_info *); | ||
7398 | int setflashmode(struct airo_info *); | ||
7399 | int flashgchar(struct airo_info *,int,int); | ||
7400 | int flashpchar(struct airo_info *,int,int); | ||
7401 | int flashputbuf(struct airo_info *); | ||
7402 | int flashrestart(struct airo_info *,struct net_device *); | ||
7403 | 7404 | ||
7404 | /* Only super-user can modify flash */ | 7405 | /* Only super-user can modify flash */ |
7405 | if (!capable(CAP_NET_ADMIN)) | 7406 | if (!capable(CAP_NET_ADMIN)) |
@@ -7457,7 +7458,7 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) { | |||
7457 | * card. | 7458 | * card. |
7458 | */ | 7459 | */ |
7459 | 7460 | ||
7460 | int cmdreset(struct airo_info *ai) { | 7461 | static int cmdreset(struct airo_info *ai) { |
7461 | disable_MAC(ai, 1); | 7462 | disable_MAC(ai, 1); |
7462 | 7463 | ||
7463 | if(!waitbusy (ai)){ | 7464 | if(!waitbusy (ai)){ |
@@ -7481,7 +7482,7 @@ int cmdreset(struct airo_info *ai) { | |||
7481 | * mode | 7482 | * mode |
7482 | */ | 7483 | */ |
7483 | 7484 | ||
7484 | int setflashmode (struct airo_info *ai) { | 7485 | static int setflashmode (struct airo_info *ai) { |
7485 | set_bit (FLAG_FLASHING, &ai->flags); | 7486 | set_bit (FLAG_FLASHING, &ai->flags); |
7486 | 7487 | ||
7487 | OUT4500(ai, SWS0, FLASH_COMMAND); | 7488 | OUT4500(ai, SWS0, FLASH_COMMAND); |
@@ -7508,7 +7509,7 @@ int setflashmode (struct airo_info *ai) { | |||
7508 | * x 50us for echo . | 7509 | * x 50us for echo . |
7509 | */ | 7510 | */ |
7510 | 7511 | ||
7511 | int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | 7512 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime) { |
7512 | int echo; | 7513 | int echo; |
7513 | int waittime; | 7514 | int waittime; |
7514 | 7515 | ||
@@ -7548,7 +7549,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | |||
7548 | * Get a character from the card matching matchbyte | 7549 | * Get a character from the card matching matchbyte |
7549 | * Step 3) | 7550 | * Step 3) |
7550 | */ | 7551 | */ |
7551 | int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | 7552 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ |
7552 | int rchar; | 7553 | int rchar; |
7553 | unsigned char rbyte=0; | 7554 | unsigned char rbyte=0; |
7554 | 7555 | ||
@@ -7579,7 +7580,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | |||
7579 | * send to the card | 7580 | * send to the card |
7580 | */ | 7581 | */ |
7581 | 7582 | ||
7582 | int flashputbuf(struct airo_info *ai){ | 7583 | static int flashputbuf(struct airo_info *ai){ |
7583 | int nwords; | 7584 | int nwords; |
7584 | 7585 | ||
7585 | /* Write stuff */ | 7586 | /* Write stuff */ |
@@ -7601,7 +7602,7 @@ int flashputbuf(struct airo_info *ai){ | |||
7601 | /* | 7602 | /* |
7602 | * | 7603 | * |
7603 | */ | 7604 | */ |
7604 | int flashrestart(struct airo_info *ai,struct net_device *dev){ | 7605 | static int flashrestart(struct airo_info *ai,struct net_device *dev){ |
7605 | int i,status; | 7606 | int i,status; |
7606 | 7607 | ||
7607 | ssleep(1); /* Added 12/7/00 */ | 7608 | 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 00000000000..2871e879b51 --- /dev/null +++ b/drivers/net/wireless/hostap/Kconfig | |||
@@ -0,0 +1,104 @@ | |||
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 | In addition, this includes generic IEEE 802.11 code, e.g., for | ||
11 | WEP/TKIP/CCMP encryption that can be shared with other drivers. | ||
12 | |||
13 | See <http://hostap.epitest.fi/> for more information about the | ||
14 | Host AP driver configuration and tools. This site includes | ||
15 | information and tools (hostapd and wpa_supplicant) for WPA/WPA2 | ||
16 | support. | ||
17 | |||
18 | This option includes the base Host AP driver code that is shared by | ||
19 | different hardware models. You will also need to enable support for | ||
20 | PLX/PCI/CS version of the driver to actually use the driver. | ||
21 | |||
22 | The driver can be compiled as a module and it will be called | ||
23 | "hostap.ko". | ||
24 | |||
25 | config HOSTAP_WEP | ||
26 | tristate "IEEE 802.11 WEP encryption" | ||
27 | depends on HOSTAP | ||
28 | select CRYPTO | ||
29 | ---help--- | ||
30 | Software implementation of IEEE 802.11 WEP encryption. | ||
31 | |||
32 | This can be compiled as a modules and it will be called | ||
33 | "hostap_crypt_wep.ko". | ||
34 | |||
35 | config HOSTAP_TKIP | ||
36 | tristate "IEEE 802.11 TKIP encryption" | ||
37 | depends on HOSTAP | ||
38 | select CRYPTO | ||
39 | ---help--- | ||
40 | Software implementation of IEEE 802.11 TKIP encryption. | ||
41 | |||
42 | This can be compiled as a modules and it will be called | ||
43 | "hostap_crypt_tkip.ko". | ||
44 | |||
45 | config HOSTAP_CCMP | ||
46 | tristate "IEEE 802.11 CCMP encryption" | ||
47 | depends on HOSTAP | ||
48 | select CRYPTO | ||
49 | ---help--- | ||
50 | Software implementation of IEEE 802.11 CCMP encryption. | ||
51 | |||
52 | This can be compiled as a modules and it will be called | ||
53 | "hostap_crypt_ccmp.ko". | ||
54 | |||
55 | config HOSTAP_FIRMWARE | ||
56 | bool "Support downloading firmware images with Host AP driver" | ||
57 | depends on HOSTAP | ||
58 | ---help--- | ||
59 | Configure Host AP driver to include support for firmware image | ||
60 | download. Current version supports only downloading to volatile, i.e., | ||
61 | RAM memory. Flash upgrade is not yet supported. | ||
62 | |||
63 | Firmware image downloading needs user space tool, prism2_srec. It is | ||
64 | available from http://hostap.epitest.fi/. | ||
65 | |||
66 | config HOSTAP_PLX | ||
67 | tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" | ||
68 | depends on PCI && HOSTAP | ||
69 | ---help--- | ||
70 | Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based | ||
71 | PCI adaptors. | ||
72 | |||
73 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
74 | driver and its help text includes more information about the Host AP | ||
75 | driver. | ||
76 | |||
77 | The driver can be compiled as a module and will be named | ||
78 | "hostap_plx.ko". | ||
79 | |||
80 | config HOSTAP_PCI | ||
81 | tristate "Host AP driver for Prism2.5 PCI adaptors" | ||
82 | depends on PCI && HOSTAP | ||
83 | ---help--- | ||
84 | Host AP driver's version for Prism2.5 PCI adaptors. | ||
85 | |||
86 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
87 | driver and its help text includes more information about the Host AP | ||
88 | driver. | ||
89 | |||
90 | The driver can be compiled as a module and will be named | ||
91 | "hostap_pci.ko". | ||
92 | |||
93 | config HOSTAP_CS | ||
94 | tristate "Host AP driver for Prism2/2.5/3 PC Cards" | ||
95 | depends on PCMCIA!=n && HOSTAP | ||
96 | ---help--- | ||
97 | Host AP driver's version for Prism2/2.5/3 PC Cards. | ||
98 | |||
99 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
100 | driver and its help text includes more information about the Host AP | ||
101 | driver. | ||
102 | |||
103 | The driver can be compiled as a module and will be named | ||
104 | "hostap_cs.ko". | ||
diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile new file mode 100644 index 00000000000..08755407503 --- /dev/null +++ b/drivers/net/wireless/hostap/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | obj-$(CONFIG_HOSTAP) += hostap.o | ||
2 | obj-$(CONFIG_HOSTAP_WEP) += hostap_crypt_wep.o | ||
3 | obj-$(CONFIG_HOSTAP_TKIP) += hostap_crypt_tkip.o | ||
4 | obj-$(CONFIG_HOSTAP_CCMP) += hostap_crypt_ccmp.o | ||
5 | |||
6 | obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o | ||
7 | obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o | ||
8 | 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 00000000000..4fe8017b877 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap.c | |||
@@ -0,0 +1,1207 @@ | |||
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-2004, 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 | #ifndef EXPORT_SYMTAB | ||
16 | #define EXPORT_SYMTAB | ||
17 | #endif | ||
18 | |||
19 | #include <linux/config.h> | ||
20 | #include <linux/version.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/proc_fs.h> | ||
25 | #include <linux/if_arp.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/random.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/kmod.h> | ||
30 | #include <linux/rtnetlink.h> | ||
31 | #include <linux/wireless.h> | ||
32 | #include <net/iw_handler.h> | ||
33 | #include <asm/uaccess.h> | ||
34 | |||
35 | #include "hostap_wlan.h" | ||
36 | #include "hostap_80211.h" | ||
37 | #include "hostap_ap.h" | ||
38 | #include "hostap.h" | ||
39 | #include "hostap_crypt.h" | ||
40 | |||
41 | MODULE_AUTHOR("Jouni Malinen"); | ||
42 | MODULE_DESCRIPTION("Host AP common routines"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | /* Old hostap_crypt module is now part of hostap module. */ | ||
46 | #include "hostap_crypt.c" | ||
47 | |||
48 | #define TX_TIMEOUT (2 * HZ) | ||
49 | |||
50 | #define PRISM2_MAX_FRAME_SIZE 2304 | ||
51 | #define PRISM2_MIN_MTU 256 | ||
52 | /* FIX: */ | ||
53 | #define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) | ||
54 | |||
55 | |||
56 | /* hostap.c */ | ||
57 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
58 | int rtnl_locked); | ||
59 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
60 | int rtnl_locked, int do_not_remove); | ||
61 | |||
62 | /* hostap_ap.c */ | ||
63 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
64 | struct iw_quality qual[], int buf_size, | ||
65 | int aplist); | ||
66 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); | ||
67 | static int prism2_hostapd(struct ap_data *ap, | ||
68 | struct prism2_hostapd_param *param); | ||
69 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
70 | struct prism2_crypt_data ***crypt); | ||
71 | static void ap_control_kickall(struct ap_data *ap); | ||
72 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
73 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
74 | u8 *mac); | ||
75 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
76 | u8 *mac); | ||
77 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); | ||
78 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
79 | u8 *mac); | ||
80 | #endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
81 | |||
82 | |||
83 | static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
84 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; | ||
85 | #define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) | ||
86 | |||
87 | |||
88 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
89 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
90 | static unsigned char rfc1042_header[] = | ||
91 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
92 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
93 | static unsigned char bridge_tunnel_header[] = | ||
94 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
95 | /* No encapsulation header if EtherType < 0x600 (=length) */ | ||
96 | |||
97 | |||
98 | /* FIX: these could be compiled separately and linked together to hostap.o */ | ||
99 | #include "hostap_ap.c" | ||
100 | #include "hostap_info.c" | ||
101 | #include "hostap_ioctl.c" | ||
102 | #include "hostap_proc.c" | ||
103 | #include "hostap_80211_rx.c" | ||
104 | #include "hostap_80211_tx.c" | ||
105 | |||
106 | |||
107 | struct net_device * hostap_add_interface(struct local_info *local, | ||
108 | int type, int rtnl_locked, | ||
109 | const char *prefix, | ||
110 | const char *name) | ||
111 | { | ||
112 | struct net_device *dev, *mdev; | ||
113 | struct hostap_interface *iface; | ||
114 | int ret; | ||
115 | |||
116 | dev = alloc_etherdev(sizeof(struct hostap_interface)); | ||
117 | if (dev == NULL) | ||
118 | return NULL; | ||
119 | |||
120 | iface = netdev_priv(dev); | ||
121 | iface->dev = dev; | ||
122 | iface->local = local; | ||
123 | iface->type = type; | ||
124 | list_add(&iface->list, &local->hostap_interfaces); | ||
125 | |||
126 | mdev = local->dev; | ||
127 | memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); | ||
128 | dev->base_addr = mdev->base_addr; | ||
129 | dev->irq = mdev->irq; | ||
130 | dev->mem_start = mdev->mem_start; | ||
131 | dev->mem_end = mdev->mem_end; | ||
132 | |||
133 | hostap_setup_dev(dev, local, 0); | ||
134 | dev->destructor = free_netdev; | ||
135 | |||
136 | sprintf(dev->name, "%s%s", prefix, name); | ||
137 | if (!rtnl_locked) | ||
138 | rtnl_lock(); | ||
139 | |||
140 | ret = 0; | ||
141 | if (strchr(dev->name, '%')) | ||
142 | ret = dev_alloc_name(dev, dev->name); | ||
143 | |||
144 | if (ret >= 0) | ||
145 | ret = register_netdevice(dev); | ||
146 | |||
147 | if (!rtnl_locked) | ||
148 | rtnl_unlock(); | ||
149 | |||
150 | if (ret < 0) { | ||
151 | printk(KERN_WARNING "%s: failed to add new netdevice!\n", | ||
152 | dev->name); | ||
153 | free_netdev(dev); | ||
154 | return NULL; | ||
155 | } | ||
156 | |||
157 | printk(KERN_DEBUG "%s: registered netdevice %s\n", | ||
158 | mdev->name, dev->name); | ||
159 | |||
160 | return dev; | ||
161 | } | ||
162 | |||
163 | |||
164 | void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | ||
165 | int remove_from_list) | ||
166 | { | ||
167 | struct hostap_interface *iface; | ||
168 | |||
169 | if (!dev) | ||
170 | return; | ||
171 | |||
172 | iface = netdev_priv(dev); | ||
173 | |||
174 | if (remove_from_list) { | ||
175 | list_del(&iface->list); | ||
176 | } | ||
177 | |||
178 | if (dev == iface->local->ddev) | ||
179 | iface->local->ddev = NULL; | ||
180 | else if (dev == iface->local->apdev) | ||
181 | iface->local->apdev = NULL; | ||
182 | else if (dev == iface->local->stadev) | ||
183 | iface->local->stadev = NULL; | ||
184 | |||
185 | if (rtnl_locked) | ||
186 | unregister_netdevice(dev); | ||
187 | else | ||
188 | unregister_netdev(dev); | ||
189 | |||
190 | /* dev->destructor = free_netdev() will free the device data, including | ||
191 | * private data, when removing the device */ | ||
192 | } | ||
193 | |||
194 | |||
195 | static inline int prism2_wds_special_addr(u8 *addr) | ||
196 | { | ||
197 | if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) | ||
198 | return 0; | ||
199 | |||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | |||
204 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
205 | int rtnl_locked) | ||
206 | { | ||
207 | struct net_device *dev; | ||
208 | struct list_head *ptr; | ||
209 | struct hostap_interface *iface, *empty, *match; | ||
210 | |||
211 | empty = match = NULL; | ||
212 | read_lock_bh(&local->iface_lock); | ||
213 | list_for_each(ptr, &local->hostap_interfaces) { | ||
214 | iface = list_entry(ptr, struct hostap_interface, list); | ||
215 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
216 | continue; | ||
217 | |||
218 | if (prism2_wds_special_addr(iface->u.wds.remote_addr)) | ||
219 | empty = iface; | ||
220 | else if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
221 | ETH_ALEN) == 0) { | ||
222 | match = iface; | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | if (!match && empty && !prism2_wds_special_addr(remote_addr)) { | ||
227 | /* take pre-allocated entry into use */ | ||
228 | memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
229 | read_unlock_bh(&local->iface_lock); | ||
230 | printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", | ||
231 | local->dev->name, empty->dev->name); | ||
232 | return 0; | ||
233 | } | ||
234 | read_unlock_bh(&local->iface_lock); | ||
235 | |||
236 | if (!prism2_wds_special_addr(remote_addr)) { | ||
237 | if (match) | ||
238 | return -EEXIST; | ||
239 | hostap_add_sta(local->ap, remote_addr); | ||
240 | } | ||
241 | |||
242 | if (local->wds_connections >= local->wds_max_connections) | ||
243 | return -ENOBUFS; | ||
244 | |||
245 | /* verify that there is room for wds# postfix in the interface name */ | ||
246 | if (strlen(local->dev->name) > IFNAMSIZ - 5) { | ||
247 | printk(KERN_DEBUG "'%s' too long base device name\n", | ||
248 | local->dev->name); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, | ||
253 | local->ddev->name, "wds%d"); | ||
254 | if (dev == NULL) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | iface = netdev_priv(dev); | ||
258 | memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
259 | |||
260 | local->wds_connections++; | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | |||
266 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
267 | int rtnl_locked, int do_not_remove) | ||
268 | { | ||
269 | unsigned long flags; | ||
270 | struct list_head *ptr; | ||
271 | struct hostap_interface *iface, *selected = NULL; | ||
272 | |||
273 | write_lock_irqsave(&local->iface_lock, flags); | ||
274 | list_for_each(ptr, &local->hostap_interfaces) { | ||
275 | iface = list_entry(ptr, struct hostap_interface, list); | ||
276 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
277 | continue; | ||
278 | |||
279 | if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
280 | ETH_ALEN) == 0) { | ||
281 | selected = iface; | ||
282 | break; | ||
283 | } | ||
284 | } | ||
285 | if (selected && !do_not_remove) | ||
286 | list_del(&selected->list); | ||
287 | write_unlock_irqrestore(&local->iface_lock, flags); | ||
288 | |||
289 | if (selected) { | ||
290 | if (do_not_remove) | ||
291 | memset(selected->u.wds.remote_addr, 0, ETH_ALEN); | ||
292 | else { | ||
293 | hostap_remove_interface(selected->dev, rtnl_locked, 0); | ||
294 | local->wds_connections--; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | return selected ? 0 : -ENODEV; | ||
299 | } | ||
300 | |||
301 | |||
302 | u16 hostap_tx_callback_register(local_info_t *local, | ||
303 | void (*func)(struct sk_buff *, int ok, void *), | ||
304 | void *data) | ||
305 | { | ||
306 | unsigned long flags; | ||
307 | struct hostap_tx_callback_info *entry; | ||
308 | |||
309 | entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry), | ||
310 | GFP_ATOMIC); | ||
311 | if (entry == NULL) | ||
312 | return 0; | ||
313 | |||
314 | entry->func = func; | ||
315 | entry->data = data; | ||
316 | |||
317 | spin_lock_irqsave(&local->lock, flags); | ||
318 | entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; | ||
319 | entry->next = local->tx_callback; | ||
320 | local->tx_callback = entry; | ||
321 | spin_unlock_irqrestore(&local->lock, flags); | ||
322 | |||
323 | return entry->idx; | ||
324 | } | ||
325 | |||
326 | |||
327 | int hostap_tx_callback_unregister(local_info_t *local, u16 idx) | ||
328 | { | ||
329 | unsigned long flags; | ||
330 | struct hostap_tx_callback_info *cb, *prev = NULL; | ||
331 | |||
332 | spin_lock_irqsave(&local->lock, flags); | ||
333 | cb = local->tx_callback; | ||
334 | while (cb != NULL && cb->idx != idx) { | ||
335 | prev = cb; | ||
336 | cb = cb->next; | ||
337 | } | ||
338 | if (cb) { | ||
339 | if (prev == NULL) | ||
340 | local->tx_callback = cb->next; | ||
341 | else | ||
342 | prev->next = cb->next; | ||
343 | kfree(cb); | ||
344 | } | ||
345 | spin_unlock_irqrestore(&local->lock, flags); | ||
346 | |||
347 | return cb ? 0 : -1; | ||
348 | } | ||
349 | |||
350 | |||
351 | /* val is in host byte order */ | ||
352 | int hostap_set_word(struct net_device *dev, int rid, u16 val) | ||
353 | { | ||
354 | struct hostap_interface *iface; | ||
355 | u16 tmp = cpu_to_le16(val); | ||
356 | iface = netdev_priv(dev); | ||
357 | return iface->local->func->set_rid(dev, rid, &tmp, 2); | ||
358 | } | ||
359 | |||
360 | |||
361 | int hostap_set_string(struct net_device *dev, int rid, const char *val) | ||
362 | { | ||
363 | struct hostap_interface *iface; | ||
364 | char buf[MAX_SSID_LEN + 2]; | ||
365 | int len; | ||
366 | |||
367 | iface = netdev_priv(dev); | ||
368 | len = strlen(val); | ||
369 | if (len > MAX_SSID_LEN) | ||
370 | return -1; | ||
371 | memset(buf, 0, sizeof(buf)); | ||
372 | buf[0] = len; /* little endian 16 bit word */ | ||
373 | memcpy(buf + 2, val, len); | ||
374 | |||
375 | return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); | ||
376 | } | ||
377 | |||
378 | |||
379 | u16 hostap_get_porttype(local_info_t *local) | ||
380 | { | ||
381 | if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) | ||
382 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
383 | if (local->iw_mode == IW_MODE_ADHOC) | ||
384 | return HFA384X_PORTTYPE_IBSS; | ||
385 | if (local->iw_mode == IW_MODE_INFRA) | ||
386 | return HFA384X_PORTTYPE_BSS; | ||
387 | if (local->iw_mode == IW_MODE_REPEAT) | ||
388 | return HFA384X_PORTTYPE_WDS; | ||
389 | if (local->iw_mode == IW_MODE_MONITOR) | ||
390 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
391 | return HFA384X_PORTTYPE_HOSTAP; | ||
392 | } | ||
393 | |||
394 | |||
395 | int hostap_set_encryption(local_info_t *local) | ||
396 | { | ||
397 | u16 val, old_val; | ||
398 | int i, keylen, len, idx; | ||
399 | char keybuf[WEP_KEY_LEN + 1]; | ||
400 | enum { NONE, WEP, OTHER } encrypt_type; | ||
401 | |||
402 | idx = local->tx_keyidx; | ||
403 | if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) | ||
404 | encrypt_type = NONE; | ||
405 | else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) | ||
406 | encrypt_type = WEP; | ||
407 | else | ||
408 | encrypt_type = OTHER; | ||
409 | |||
410 | if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, | ||
411 | 1) < 0) { | ||
412 | printk(KERN_DEBUG "Could not read current WEP flags.\n"); | ||
413 | goto fail; | ||
414 | } | ||
415 | le16_to_cpus(&val); | ||
416 | old_val = val; | ||
417 | |||
418 | if (encrypt_type != NONE || local->privacy_invoked) | ||
419 | val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
420 | else | ||
421 | val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
422 | |||
423 | if (local->open_wep || encrypt_type == NONE || | ||
424 | ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) | ||
425 | val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
426 | else | ||
427 | val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
428 | |||
429 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
430 | (encrypt_type == OTHER || local->host_encrypt)) | ||
431 | val |= HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
432 | else | ||
433 | val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
434 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
435 | (encrypt_type == OTHER || local->host_decrypt)) | ||
436 | val |= HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
437 | else | ||
438 | val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
439 | |||
440 | if (val != old_val && | ||
441 | hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { | ||
442 | printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", | ||
443 | val); | ||
444 | goto fail; | ||
445 | } | ||
446 | |||
447 | if (encrypt_type != WEP) | ||
448 | return 0; | ||
449 | |||
450 | /* 104-bit support seems to require that all the keys are set to the | ||
451 | * same keylen */ | ||
452 | keylen = 6; /* first 5 octets */ | ||
453 | len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), | ||
454 | NULL, local->crypt[idx]->priv); | ||
455 | if (idx >= 0 && idx < WEP_KEYS && len > 5) | ||
456 | keylen = WEP_KEY_LEN + 1; /* first 13 octets */ | ||
457 | |||
458 | for (i = 0; i < WEP_KEYS; i++) { | ||
459 | memset(keybuf, 0, sizeof(keybuf)); | ||
460 | if (local->crypt[i]) { | ||
461 | (void) local->crypt[i]->ops->get_key( | ||
462 | keybuf, sizeof(keybuf), | ||
463 | NULL, local->crypt[i]->priv); | ||
464 | } | ||
465 | if (local->func->set_rid(local->dev, | ||
466 | HFA384X_RID_CNFDEFAULTKEY0 + i, | ||
467 | keybuf, keylen)) { | ||
468 | printk(KERN_DEBUG "Could not set key %d (len=%d)\n", | ||
469 | i, keylen); | ||
470 | goto fail; | ||
471 | } | ||
472 | } | ||
473 | if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { | ||
474 | printk(KERN_DEBUG "Could not set default keyid %d\n", idx); | ||
475 | goto fail; | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | |||
480 | fail: | ||
481 | printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); | ||
482 | return -1; | ||
483 | } | ||
484 | |||
485 | |||
486 | int hostap_set_antsel(local_info_t *local) | ||
487 | { | ||
488 | u16 val; | ||
489 | int ret = 0; | ||
490 | |||
491 | if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
492 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
493 | HFA386X_CR_TX_CONFIGURE, | ||
494 | NULL, &val) == 0) { | ||
495 | val &= ~(BIT(2) | BIT(1)); | ||
496 | switch (local->antsel_tx) { | ||
497 | case HOSTAP_ANTSEL_DIVERSITY: | ||
498 | val |= BIT(1); | ||
499 | break; | ||
500 | case HOSTAP_ANTSEL_LOW: | ||
501 | break; | ||
502 | case HOSTAP_ANTSEL_HIGH: | ||
503 | val |= BIT(2); | ||
504 | break; | ||
505 | } | ||
506 | |||
507 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
508 | HFA386X_CR_TX_CONFIGURE, &val, NULL)) { | ||
509 | printk(KERN_INFO "%s: setting TX AntSel failed\n", | ||
510 | local->dev->name); | ||
511 | ret = -1; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
516 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
517 | HFA386X_CR_RX_CONFIGURE, | ||
518 | NULL, &val) == 0) { | ||
519 | val &= ~(BIT(1) | BIT(0)); | ||
520 | switch (local->antsel_rx) { | ||
521 | case HOSTAP_ANTSEL_DIVERSITY: | ||
522 | break; | ||
523 | case HOSTAP_ANTSEL_LOW: | ||
524 | val |= BIT(0); | ||
525 | break; | ||
526 | case HOSTAP_ANTSEL_HIGH: | ||
527 | val |= BIT(0) | BIT(1); | ||
528 | break; | ||
529 | } | ||
530 | |||
531 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
532 | HFA386X_CR_RX_CONFIGURE, &val, NULL)) { | ||
533 | printk(KERN_INFO "%s: setting RX AntSel failed\n", | ||
534 | local->dev->name); | ||
535 | ret = -1; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | |||
543 | int hostap_set_roaming(local_info_t *local) | ||
544 | { | ||
545 | u16 val; | ||
546 | |||
547 | switch (local->host_roaming) { | ||
548 | case 1: | ||
549 | val = HFA384X_ROAMING_HOST; | ||
550 | break; | ||
551 | case 2: | ||
552 | val = HFA384X_ROAMING_DISABLED; | ||
553 | break; | ||
554 | case 0: | ||
555 | default: | ||
556 | val = HFA384X_ROAMING_FIRMWARE; | ||
557 | break; | ||
558 | } | ||
559 | |||
560 | return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); | ||
561 | } | ||
562 | |||
563 | |||
564 | int hostap_set_auth_algs(local_info_t *local) | ||
565 | { | ||
566 | int val = local->auth_algs; | ||
567 | /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication | ||
568 | * set to include both Open and Shared Key flags. It tries to use | ||
569 | * Shared Key authentication in that case even if WEP keys are not | ||
570 | * configured.. STA f/w v0.7.6 is able to handle such configuration, | ||
571 | * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ | ||
572 | if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && | ||
573 | val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) | ||
574 | val = PRISM2_AUTH_OPEN; | ||
575 | |||
576 | if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { | ||
577 | printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " | ||
578 | "failed\n", local->dev->name, local->auth_algs); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | |||
586 | void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) | ||
587 | { | ||
588 | u16 status, fc; | ||
589 | |||
590 | status = __le16_to_cpu(rx->status); | ||
591 | |||
592 | printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " | ||
593 | "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " | ||
594 | "jiffies=%ld\n", | ||
595 | name, status, (status >> 8) & 0x07, status >> 13, status & 1, | ||
596 | rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); | ||
597 | |||
598 | fc = __le16_to_cpu(rx->frame_control); | ||
599 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
600 | "data_len=%d%s%s\n", | ||
601 | fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), | ||
602 | __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), | ||
603 | __le16_to_cpu(rx->data_len), | ||
604 | fc & WLAN_FC_TODS ? " [ToDS]" : "", | ||
605 | fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); | ||
606 | |||
607 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
608 | MACSTR "\n", | ||
609 | MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), | ||
610 | MAC2STR(rx->addr4)); | ||
611 | |||
612 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
613 | MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), | ||
614 | __be16_to_cpu(rx->len)); | ||
615 | } | ||
616 | |||
617 | |||
618 | void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) | ||
619 | { | ||
620 | u16 fc; | ||
621 | |||
622 | printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " | ||
623 | "tx_control=0x%04x; jiffies=%ld\n", | ||
624 | name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, | ||
625 | __le16_to_cpu(tx->tx_control), jiffies); | ||
626 | |||
627 | fc = __le16_to_cpu(tx->frame_control); | ||
628 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
629 | "data_len=%d%s%s\n", | ||
630 | fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), | ||
631 | __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), | ||
632 | __le16_to_cpu(tx->data_len), | ||
633 | fc & WLAN_FC_TODS ? " [ToDS]" : "", | ||
634 | fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); | ||
635 | |||
636 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
637 | MACSTR "\n", | ||
638 | MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), | ||
639 | MAC2STR(tx->addr4)); | ||
640 | |||
641 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
642 | MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), | ||
643 | __be16_to_cpu(tx->len)); | ||
644 | } | ||
645 | |||
646 | |||
647 | int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
648 | { | ||
649 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */ | ||
650 | return ETH_ALEN; | ||
651 | } | ||
652 | |||
653 | |||
654 | int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
655 | { | ||
656 | if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) { | ||
657 | memcpy(haddr, skb->mac.raw + | ||
658 | sizeof(struct linux_wlan_ng_prism_hdr) + 10, | ||
659 | ETH_ALEN); /* addr2 */ | ||
660 | } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */ | ||
661 | memcpy(haddr, skb->mac.raw + | ||
662 | sizeof(struct linux_wlan_ng_cap_hdr) + 10, | ||
663 | ETH_ALEN); /* addr2 */ | ||
664 | } | ||
665 | return ETH_ALEN; | ||
666 | } | ||
667 | |||
668 | |||
669 | int hostap_80211_get_hdrlen(u16 fc) | ||
670 | { | ||
671 | int hdrlen = 24; | ||
672 | |||
673 | switch (WLAN_FC_GET_TYPE(fc)) { | ||
674 | case WLAN_FC_TYPE_DATA: | ||
675 | if ((fc & WLAN_FC_FROMDS) && (fc & WLAN_FC_TODS)) | ||
676 | hdrlen = 30; /* Addr4 */ | ||
677 | break; | ||
678 | case WLAN_FC_TYPE_CTRL: | ||
679 | switch (WLAN_FC_GET_STYPE(fc)) { | ||
680 | case WLAN_FC_STYPE_CTS: | ||
681 | case WLAN_FC_STYPE_ACK: | ||
682 | hdrlen = 10; | ||
683 | break; | ||
684 | default: | ||
685 | hdrlen = 16; | ||
686 | break; | ||
687 | } | ||
688 | break; | ||
689 | } | ||
690 | |||
691 | return hdrlen; | ||
692 | } | ||
693 | |||
694 | |||
695 | struct net_device_stats *hostap_get_stats(struct net_device *dev) | ||
696 | { | ||
697 | struct hostap_interface *iface; | ||
698 | iface = netdev_priv(dev); | ||
699 | return &iface->stats; | ||
700 | } | ||
701 | |||
702 | |||
703 | static int prism2_close(struct net_device *dev) | ||
704 | { | ||
705 | struct hostap_interface *iface; | ||
706 | local_info_t *local; | ||
707 | |||
708 | PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); | ||
709 | |||
710 | iface = netdev_priv(dev); | ||
711 | local = iface->local; | ||
712 | |||
713 | if (dev == local->ddev) { | ||
714 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
715 | } | ||
716 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
717 | if (!local->hostapd && dev == local->dev && | ||
718 | (!local->func->card_present || local->func->card_present(local)) && | ||
719 | local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) | ||
720 | hostap_deauth_all_stas(dev, local->ap, 1); | ||
721 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
722 | |||
723 | if (local->func->dev_close && local->func->dev_close(local)) | ||
724 | return 0; | ||
725 | |||
726 | if (dev == local->dev) { | ||
727 | local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); | ||
728 | } | ||
729 | |||
730 | if (netif_running(dev)) { | ||
731 | netif_stop_queue(dev); | ||
732 | netif_device_detach(dev); | ||
733 | } | ||
734 | |||
735 | flush_scheduled_work(); | ||
736 | |||
737 | module_put(local->hw_module); | ||
738 | |||
739 | local->num_dev_open--; | ||
740 | |||
741 | if (dev != local->dev && local->dev->flags & IFF_UP && | ||
742 | local->master_dev_auto_open && local->num_dev_open == 1) { | ||
743 | /* Close master radio interface automatically if it was also | ||
744 | * opened automatically and we are now closing the last | ||
745 | * remaining non-master device. */ | ||
746 | dev_close(local->dev); | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | |||
753 | static int prism2_open(struct net_device *dev) | ||
754 | { | ||
755 | struct hostap_interface *iface; | ||
756 | local_info_t *local; | ||
757 | |||
758 | PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); | ||
759 | |||
760 | iface = netdev_priv(dev); | ||
761 | local = iface->local; | ||
762 | |||
763 | if (local->no_pri) { | ||
764 | printk(KERN_DEBUG "%s: could not set interface UP - no PRI " | ||
765 | "f/w\n", dev->name); | ||
766 | return 1; | ||
767 | } | ||
768 | |||
769 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
770 | local->hw_downloading) | ||
771 | return -ENODEV; | ||
772 | |||
773 | if (local->func->dev_open && local->func->dev_open(local)) | ||
774 | return 1; | ||
775 | |||
776 | if (!try_module_get(local->hw_module)) | ||
777 | return -ENODEV; | ||
778 | local->num_dev_open++; | ||
779 | |||
780 | if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { | ||
781 | printk(KERN_WARNING "%s: could not enable MAC port\n", | ||
782 | dev->name); | ||
783 | prism2_close(dev); | ||
784 | return 1; | ||
785 | } | ||
786 | if (!local->dev_enabled) | ||
787 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
788 | local->dev_enabled = 1; | ||
789 | |||
790 | if (dev != local->dev && !(local->dev->flags & IFF_UP)) { | ||
791 | /* Master radio interface is needed for all operation, so open | ||
792 | * it automatically when any virtual net_device is opened. */ | ||
793 | local->master_dev_auto_open = 1; | ||
794 | dev_open(local->dev); | ||
795 | } | ||
796 | |||
797 | netif_device_attach(dev); | ||
798 | netif_start_queue(dev); | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | |||
804 | static int prism2_set_mac_address(struct net_device *dev, void *p) | ||
805 | { | ||
806 | struct hostap_interface *iface; | ||
807 | local_info_t *local; | ||
808 | struct list_head *ptr; | ||
809 | struct sockaddr *addr = p; | ||
810 | |||
811 | iface = netdev_priv(dev); | ||
812 | local = iface->local; | ||
813 | |||
814 | if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, | ||
815 | ETH_ALEN) < 0 || local->func->reset_port(dev)) | ||
816 | return -EINVAL; | ||
817 | |||
818 | read_lock_bh(&local->iface_lock); | ||
819 | list_for_each(ptr, &local->hostap_interfaces) { | ||
820 | iface = list_entry(ptr, struct hostap_interface, list); | ||
821 | memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
822 | } | ||
823 | memcpy(local->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
824 | read_unlock_bh(&local->iface_lock); | ||
825 | |||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | |||
830 | /* TODO: to be further implemented as soon as Prism2 fully supports | ||
831 | * GroupAddresses and correct documentation is available */ | ||
832 | void hostap_set_multicast_list_queue(void *data) | ||
833 | { | ||
834 | struct net_device *dev = (struct net_device *) data; | ||
835 | struct hostap_interface *iface; | ||
836 | local_info_t *local; | ||
837 | |||
838 | iface = netdev_priv(dev); | ||
839 | local = iface->local; | ||
840 | if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
841 | local->is_promisc)) { | ||
842 | printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", | ||
843 | dev->name, local->is_promisc ? "en" : "dis"); | ||
844 | } | ||
845 | } | ||
846 | |||
847 | |||
848 | static void hostap_set_multicast_list(struct net_device *dev) | ||
849 | { | ||
850 | #if 0 | ||
851 | /* FIX: promiscuous mode seems to be causing a lot of problems with | ||
852 | * some station firmware versions (FCSErr frames, invalid MACPort, etc. | ||
853 | * corrupted incoming frames). This code is now commented out while the | ||
854 | * problems are investigated. */ | ||
855 | struct hostap_interface *iface; | ||
856 | local_info_t *local; | ||
857 | |||
858 | iface = netdev_priv(dev); | ||
859 | local = iface->local; | ||
860 | if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { | ||
861 | local->is_promisc = 1; | ||
862 | } else { | ||
863 | local->is_promisc = 0; | ||
864 | } | ||
865 | |||
866 | schedule_work(&local->set_multicast_list_queue); | ||
867 | #endif | ||
868 | } | ||
869 | |||
870 | |||
871 | static int prism2_change_mtu(struct net_device *dev, int new_mtu) | ||
872 | { | ||
873 | if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU) | ||
874 | return -EINVAL; | ||
875 | |||
876 | dev->mtu = new_mtu; | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | |||
881 | static void prism2_tx_timeout(struct net_device *dev) | ||
882 | { | ||
883 | struct hostap_interface *iface; | ||
884 | local_info_t *local; | ||
885 | struct hfa384x_regs regs; | ||
886 | |||
887 | iface = netdev_priv(dev); | ||
888 | local = iface->local; | ||
889 | |||
890 | printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); | ||
891 | netif_stop_queue(local->dev); | ||
892 | |||
893 | local->func->read_regs(dev, ®s); | ||
894 | printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " | ||
895 | "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", | ||
896 | dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, | ||
897 | regs.swsupport0); | ||
898 | |||
899 | local->func->schedule_reset(local); | ||
900 | } | ||
901 | |||
902 | |||
903 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | ||
904 | int main_dev) | ||
905 | { | ||
906 | struct hostap_interface *iface; | ||
907 | |||
908 | iface = netdev_priv(dev); | ||
909 | ether_setup(dev); | ||
910 | |||
911 | /* kernel callbacks */ | ||
912 | dev->get_stats = hostap_get_stats; | ||
913 | if (iface) { | ||
914 | /* Currently, we point to the proper spy_data only on | ||
915 | * the main_dev. This could be fixed. Jean II */ | ||
916 | iface->wireless_data.spy_data = &iface->spy_data; | ||
917 | dev->wireless_data = &iface->wireless_data; | ||
918 | } | ||
919 | dev->wireless_handlers = | ||
920 | (struct iw_handler_def *) &hostap_iw_handler_def; | ||
921 | dev->do_ioctl = hostap_ioctl; | ||
922 | dev->open = prism2_open; | ||
923 | dev->stop = prism2_close; | ||
924 | dev->hard_start_xmit = hostap_data_start_xmit; | ||
925 | dev->set_mac_address = prism2_set_mac_address; | ||
926 | dev->set_multicast_list = hostap_set_multicast_list; | ||
927 | dev->change_mtu = prism2_change_mtu; | ||
928 | dev->tx_timeout = prism2_tx_timeout; | ||
929 | dev->watchdog_timeo = TX_TIMEOUT; | ||
930 | |||
931 | dev->mtu = local->mtu; | ||
932 | if (!main_dev) { | ||
933 | /* use main radio device queue */ | ||
934 | dev->tx_queue_len = 0; | ||
935 | } | ||
936 | |||
937 | SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops); | ||
938 | |||
939 | netif_stop_queue(dev); | ||
940 | } | ||
941 | |||
942 | |||
943 | static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) | ||
944 | { | ||
945 | struct net_device *dev = local->dev; | ||
946 | |||
947 | if (local->apdev) | ||
948 | return -EEXIST; | ||
949 | |||
950 | printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); | ||
951 | |||
952 | local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, | ||
953 | rtnl_locked, local->ddev->name, | ||
954 | "ap"); | ||
955 | if (local->apdev == NULL) | ||
956 | return -ENOMEM; | ||
957 | |||
958 | local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; | ||
959 | local->apdev->type = ARPHRD_IEEE80211; | ||
960 | local->apdev->hard_header_parse = hostap_80211_header_parse; | ||
961 | |||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | |||
966 | static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) | ||
967 | { | ||
968 | struct net_device *dev = local->dev; | ||
969 | |||
970 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
971 | |||
972 | hostap_remove_interface(local->apdev, rtnl_locked, 1); | ||
973 | local->apdev = NULL; | ||
974 | |||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | |||
979 | static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
980 | { | ||
981 | struct net_device *dev = local->dev; | ||
982 | |||
983 | if (local->stadev) | ||
984 | return -EEXIST; | ||
985 | |||
986 | printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); | ||
987 | |||
988 | local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, | ||
989 | rtnl_locked, local->ddev->name, | ||
990 | "sta"); | ||
991 | if (local->stadev == NULL) | ||
992 | return -ENOMEM; | ||
993 | |||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | |||
998 | static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
999 | { | ||
1000 | struct net_device *dev = local->dev; | ||
1001 | |||
1002 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
1003 | |||
1004 | hostap_remove_interface(local->stadev, rtnl_locked, 1); | ||
1005 | local->stadev = NULL; | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) | ||
1012 | { | ||
1013 | int ret; | ||
1014 | |||
1015 | if (val < 0 || val > 1) | ||
1016 | return -EINVAL; | ||
1017 | |||
1018 | if (local->hostapd == val) | ||
1019 | return 0; | ||
1020 | |||
1021 | if (val) { | ||
1022 | ret = hostap_enable_hostapd(local, rtnl_locked); | ||
1023 | if (ret == 0) | ||
1024 | local->hostapd = 1; | ||
1025 | } else { | ||
1026 | local->hostapd = 0; | ||
1027 | ret = hostap_disable_hostapd(local, rtnl_locked); | ||
1028 | if (ret != 0) | ||
1029 | local->hostapd = 1; | ||
1030 | } | ||
1031 | |||
1032 | return ret; | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) | ||
1037 | { | ||
1038 | int ret; | ||
1039 | |||
1040 | if (val < 0 || val > 1) | ||
1041 | return -EINVAL; | ||
1042 | |||
1043 | if (local->hostapd_sta == val) | ||
1044 | return 0; | ||
1045 | |||
1046 | if (val) { | ||
1047 | ret = hostap_enable_hostapd_sta(local, rtnl_locked); | ||
1048 | if (ret == 0) | ||
1049 | local->hostapd_sta = 1; | ||
1050 | } else { | ||
1051 | local->hostapd_sta = 0; | ||
1052 | ret = hostap_disable_hostapd_sta(local, rtnl_locked); | ||
1053 | if (ret != 0) | ||
1054 | local->hostapd_sta = 1; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | return ret; | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | int prism2_update_comms_qual(struct net_device *dev) | ||
1063 | { | ||
1064 | struct hostap_interface *iface; | ||
1065 | local_info_t *local; | ||
1066 | int ret = 0; | ||
1067 | struct hfa384x_comms_quality sq; | ||
1068 | |||
1069 | iface = netdev_priv(dev); | ||
1070 | local = iface->local; | ||
1071 | if (!local->sta_fw_ver) | ||
1072 | ret = -1; | ||
1073 | else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1074 | if (local->func->get_rid(local->dev, | ||
1075 | HFA384X_RID_DBMCOMMSQUALITY, | ||
1076 | &sq, sizeof(sq), 1) >= 0) { | ||
1077 | local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); | ||
1078 | local->avg_signal = (s16) le16_to_cpu(sq.signal_level); | ||
1079 | local->avg_noise = (s16) le16_to_cpu(sq.noise_level); | ||
1080 | local->last_comms_qual_update = jiffies; | ||
1081 | } else | ||
1082 | ret = -1; | ||
1083 | } else { | ||
1084 | if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, | ||
1085 | &sq, sizeof(sq), 1) >= 0) { | ||
1086 | local->comms_qual = le16_to_cpu(sq.comm_qual); | ||
1087 | local->avg_signal = HFA384X_LEVEL_TO_dBm( | ||
1088 | le16_to_cpu(sq.signal_level)); | ||
1089 | local->avg_noise = HFA384X_LEVEL_TO_dBm( | ||
1090 | le16_to_cpu(sq.noise_level)); | ||
1091 | local->last_comms_qual_update = jiffies; | ||
1092 | } else | ||
1093 | ret = -1; | ||
1094 | } | ||
1095 | |||
1096 | return ret; | ||
1097 | } | ||
1098 | |||
1099 | |||
1100 | int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u8 stype, | ||
1101 | u8 *body, size_t bodylen) | ||
1102 | { | ||
1103 | struct sk_buff *skb; | ||
1104 | struct hostap_ieee80211_mgmt *mgmt; | ||
1105 | struct hostap_skb_tx_data *meta; | ||
1106 | struct net_device *dev = local->dev; | ||
1107 | |||
1108 | skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); | ||
1109 | if (skb == NULL) | ||
1110 | return -ENOMEM; | ||
1111 | |||
1112 | mgmt = (struct hostap_ieee80211_mgmt *) | ||
1113 | skb_put(skb, IEEE80211_MGMT_HDR_LEN); | ||
1114 | memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN); | ||
1115 | mgmt->frame_control = | ||
1116 | cpu_to_le16((WLAN_FC_TYPE_MGMT << 2) | (stype << 4)); | ||
1117 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
1118 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
1119 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
1120 | if (body) | ||
1121 | memcpy(skb_put(skb, bodylen), body, bodylen); | ||
1122 | |||
1123 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1124 | memset(meta, 0, sizeof(*meta)); | ||
1125 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
1126 | meta->iface = netdev_priv(dev); | ||
1127 | |||
1128 | skb->dev = dev; | ||
1129 | skb->mac.raw = skb->nh.raw = skb->data; | ||
1130 | dev_queue_xmit(skb); | ||
1131 | |||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | int prism2_sta_deauth(local_info_t *local, u16 reason) | ||
1137 | { | ||
1138 | union iwreq_data wrqu; | ||
1139 | int ret; | ||
1140 | |||
1141 | if (local->iw_mode != IW_MODE_INFRA || | ||
1142 | memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 || | ||
1143 | memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0) | ||
1144 | return 0; | ||
1145 | |||
1146 | reason = cpu_to_le16(reason); | ||
1147 | ret = prism2_sta_send_mgmt(local, local->bssid, WLAN_FC_STYPE_DEAUTH, | ||
1148 | (u8 *) &reason, 2); | ||
1149 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
1150 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
1151 | return ret; | ||
1152 | } | ||
1153 | |||
1154 | |||
1155 | struct proc_dir_entry *hostap_proc; | ||
1156 | |||
1157 | static int __init hostap_init(void) | ||
1158 | { | ||
1159 | hostap_crypto_init(); | ||
1160 | |||
1161 | if (proc_net != NULL) { | ||
1162 | hostap_proc = proc_mkdir("hostap", proc_net); | ||
1163 | if (!hostap_proc) | ||
1164 | printk(KERN_WARNING "Failed to mkdir " | ||
1165 | "/proc/net/hostap\n"); | ||
1166 | } else | ||
1167 | hostap_proc = NULL; | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | static void __exit hostap_exit(void) | ||
1174 | { | ||
1175 | if (hostap_proc != NULL) { | ||
1176 | hostap_proc = NULL; | ||
1177 | remove_proc_entry("hostap", proc_net); | ||
1178 | } | ||
1179 | |||
1180 | hostap_crypto_deinit(); | ||
1181 | } | ||
1182 | |||
1183 | |||
1184 | EXPORT_SYMBOL(hostap_set_word); | ||
1185 | EXPORT_SYMBOL(hostap_set_string); | ||
1186 | EXPORT_SYMBOL(hostap_get_porttype); | ||
1187 | EXPORT_SYMBOL(hostap_set_encryption); | ||
1188 | EXPORT_SYMBOL(hostap_set_antsel); | ||
1189 | EXPORT_SYMBOL(hostap_set_roaming); | ||
1190 | EXPORT_SYMBOL(hostap_set_auth_algs); | ||
1191 | EXPORT_SYMBOL(hostap_dump_rx_header); | ||
1192 | EXPORT_SYMBOL(hostap_dump_tx_header); | ||
1193 | EXPORT_SYMBOL(hostap_80211_header_parse); | ||
1194 | EXPORT_SYMBOL(hostap_80211_prism_header_parse); | ||
1195 | EXPORT_SYMBOL(hostap_80211_get_hdrlen); | ||
1196 | EXPORT_SYMBOL(hostap_get_stats); | ||
1197 | EXPORT_SYMBOL(hostap_setup_dev); | ||
1198 | EXPORT_SYMBOL(hostap_proc); | ||
1199 | EXPORT_SYMBOL(hostap_set_multicast_list_queue); | ||
1200 | EXPORT_SYMBOL(hostap_set_hostapd); | ||
1201 | EXPORT_SYMBOL(hostap_set_hostapd_sta); | ||
1202 | EXPORT_SYMBOL(hostap_add_interface); | ||
1203 | EXPORT_SYMBOL(hostap_remove_interface); | ||
1204 | EXPORT_SYMBOL(prism2_update_comms_qual); | ||
1205 | |||
1206 | module_init(hostap_init); | ||
1207 | 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 00000000000..2ddcf5fc59c --- /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, u8 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 00000000000..878151f4065 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211.h | |||
@@ -0,0 +1,107 @@ | |||
1 | #ifndef HOSTAP_80211_H | ||
2 | #define HOSTAP_80211_H | ||
3 | |||
4 | struct hostap_ieee80211_hdr { | ||
5 | u16 frame_control; | ||
6 | u16 duration_id; | ||
7 | u8 addr1[6]; | ||
8 | u8 addr2[6]; | ||
9 | u8 addr3[6]; | ||
10 | u16 seq_ctrl; | ||
11 | u8 addr4[6]; | ||
12 | } __attribute__ ((packed)); | ||
13 | |||
14 | |||
15 | struct hostap_ieee80211_mgmt { | ||
16 | u16 frame_control; | ||
17 | u16 duration; | ||
18 | u8 da[6]; | ||
19 | u8 sa[6]; | ||
20 | u8 bssid[6]; | ||
21 | u16 seq_ctrl; | ||
22 | union { | ||
23 | struct { | ||
24 | u16 auth_alg; | ||
25 | u16 auth_transaction; | ||
26 | u16 status_code; | ||
27 | /* possibly followed by Challenge text */ | ||
28 | u8 variable[0]; | ||
29 | } __attribute__ ((packed)) auth; | ||
30 | struct { | ||
31 | u16 reason_code; | ||
32 | } __attribute__ ((packed)) deauth; | ||
33 | struct { | ||
34 | u16 capab_info; | ||
35 | u16 listen_interval; | ||
36 | /* followed by SSID and Supported rates */ | ||
37 | u8 variable[0]; | ||
38 | } __attribute__ ((packed)) assoc_req; | ||
39 | struct { | ||
40 | u16 capab_info; | ||
41 | u16 status_code; | ||
42 | u16 aid; | ||
43 | /* followed by Supported rates */ | ||
44 | u8 variable[0]; | ||
45 | } __attribute__ ((packed)) assoc_resp, reassoc_resp; | ||
46 | struct { | ||
47 | u16 capab_info; | ||
48 | u16 listen_interval; | ||
49 | u8 current_ap[6]; | ||
50 | /* followed by SSID and Supported rates */ | ||
51 | u8 variable[0]; | ||
52 | } __attribute__ ((packed)) reassoc_req; | ||
53 | struct { | ||
54 | u16 reason_code; | ||
55 | } __attribute__ ((packed)) disassoc; | ||
56 | struct { | ||
57 | } __attribute__ ((packed)) probe_req; | ||
58 | struct { | ||
59 | u8 timestamp[8]; | ||
60 | u16 beacon_int; | ||
61 | u16 capab_info; | ||
62 | /* followed by some of SSID, Supported rates, | ||
63 | * FH Params, DS Params, CF Params, IBSS Params, TIM */ | ||
64 | u8 variable[0]; | ||
65 | } __attribute__ ((packed)) beacon, probe_resp; | ||
66 | } u; | ||
67 | } __attribute__ ((packed)); | ||
68 | |||
69 | |||
70 | #define IEEE80211_MGMT_HDR_LEN 24 | ||
71 | #define IEEE80211_DATA_HDR3_LEN 24 | ||
72 | #define IEEE80211_DATA_HDR4_LEN 30 | ||
73 | |||
74 | |||
75 | struct hostap_80211_rx_status { | ||
76 | u32 mac_time; | ||
77 | u8 signal; | ||
78 | u8 noise; | ||
79 | u16 rate; /* in 100 kbps */ | ||
80 | }; | ||
81 | |||
82 | |||
83 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
84 | struct hostap_80211_rx_status *rx_stats); | ||
85 | |||
86 | |||
87 | /* prism2_rx_80211 'type' argument */ | ||
88 | enum { | ||
89 | PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, | ||
90 | PRISM2_RX_NULLFUNC_ACK | ||
91 | }; | ||
92 | |||
93 | int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | ||
94 | struct hostap_80211_rx_status *rx_stats, int type); | ||
95 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
96 | struct hostap_80211_rx_status *rx_stats); | ||
97 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | ||
98 | struct hostap_80211_rx_status *rx_stats); | ||
99 | |||
100 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); | ||
101 | int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
102 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
103 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
104 | struct prism2_crypt_data *crypt); | ||
105 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
106 | |||
107 | #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 00000000000..917296c4fcb --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c | |||
@@ -0,0 +1,1084 @@ | |||
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 hostap_ieee80211_hdr *hdr; | ||
10 | u16 fc; | ||
11 | |||
12 | hdr = (struct hostap_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_control); | ||
23 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
24 | fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), | ||
25 | fc & WLAN_FC_TODS ? " [ToDS]" : "", | ||
26 | fc & WLAN_FC_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_ctrl)); | ||
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 hostap_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 hostap_ieee80211_hdr *) skb->data; | ||
74 | fc = le16_to_cpu(hdr->frame_control); | ||
75 | |||
76 | if (type == PRISM2_RX_MGMT && (fc & WLAN_FC_PVER)) { | ||
77 | printk(KERN_DEBUG "%s: dropped management frame with header " | ||
78 | "version %d\n", dev->name, fc & WLAN_FC_PVER); | ||
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, 0, 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 hostap_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_ctrl); | ||
226 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
227 | seq = WLAN_GET_SEQ_SEQ(sc); | ||
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 hostap_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 hostap_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_ctrl); | ||
277 | seq = WLAN_GET_SEQ_SEQ(sc); | ||
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 hostap_ieee80211_hdr *) | ||
445 | skb->data); | ||
446 | } | ||
447 | |||
448 | if (local->hostapd && type == WLAN_FC_TYPE_MGMT) { | ||
449 | if (stype == WLAN_FC_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 != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { | ||
471 | printk(KERN_DEBUG "%s: unknown management frame " | ||
472 | "(type=0x%02x, stype=0x%02x) dropped\n", | ||
473 | skb->dev->name, type, stype); | ||
474 | return -1; | ||
475 | } | ||
476 | |||
477 | hostap_rx(skb->dev, skb, rx_stats); | ||
478 | return 0; | ||
479 | } else if (type == WLAN_FC_TYPE_MGMT && | ||
480 | (stype == WLAN_FC_STYPE_BEACON || | ||
481 | stype == WLAN_FC_STYPE_PROBE_RESP)) { | ||
482 | hostap_rx_sta_beacon(local, skb, stype); | ||
483 | return -1; | ||
484 | } else if (type == WLAN_FC_TYPE_MGMT && | ||
485 | (stype == WLAN_FC_STYPE_ASSOC_RESP || | ||
486 | stype == WLAN_FC_STYPE_REASSOC_RESP)) { | ||
487 | /* Ignore (Re)AssocResp silently since these are not currently | ||
488 | * needed but are still received when WPA/RSN mode is enabled. | ||
489 | */ | ||
490 | return -1; | ||
491 | } else { | ||
492 | printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" | ||
493 | " management frame in non-Host AP mode (type=%d:%d)\n", | ||
494 | skb->dev->name, type, stype); | ||
495 | return -1; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | |||
500 | /* Called only as a tasklet (software IRQ) */ | ||
501 | static inline struct net_device *prism2_rx_get_wds(local_info_t *local, | ||
502 | u8 *addr) | ||
503 | { | ||
504 | struct hostap_interface *iface = NULL; | ||
505 | struct list_head *ptr; | ||
506 | |||
507 | read_lock_bh(&local->iface_lock); | ||
508 | list_for_each(ptr, &local->hostap_interfaces) { | ||
509 | iface = list_entry(ptr, struct hostap_interface, list); | ||
510 | if (iface->type == HOSTAP_INTERFACE_WDS && | ||
511 | memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) | ||
512 | break; | ||
513 | iface = NULL; | ||
514 | } | ||
515 | read_unlock_bh(&local->iface_lock); | ||
516 | |||
517 | return iface ? iface->dev : NULL; | ||
518 | } | ||
519 | |||
520 | |||
521 | static inline int | ||
522 | hostap_rx_frame_wds(local_info_t *local, struct hostap_ieee80211_hdr *hdr, | ||
523 | u16 fc, struct net_device **wds) | ||
524 | { | ||
525 | /* FIX: is this really supposed to accept WDS frames only in Master | ||
526 | * mode? What about Repeater or Managed with WDS frames? */ | ||
527 | if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) != | ||
528 | (WLAN_FC_TODS | WLAN_FC_FROMDS) && | ||
529 | (local->iw_mode != IW_MODE_MASTER || !(fc & WLAN_FC_TODS))) | ||
530 | return 0; /* not a WDS frame */ | ||
531 | |||
532 | /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) | ||
533 | * or own non-standard frame with 4th address after payload */ | ||
534 | if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 && | ||
535 | (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || | ||
536 | hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || | ||
537 | hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { | ||
538 | /* RA (or BSSID) is not ours - drop */ | ||
539 | PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " | ||
540 | "not own or broadcast %s=" MACSTR "\n", | ||
541 | local->dev->name, fc & WLAN_FC_FROMDS ? "RA" : "BSSID", | ||
542 | MAC2STR(hdr->addr1)); | ||
543 | return -1; | ||
544 | } | ||
545 | |||
546 | /* check if the frame came from a registered WDS connection */ | ||
547 | *wds = prism2_rx_get_wds(local, hdr->addr2); | ||
548 | if (*wds == NULL && fc & WLAN_FC_FROMDS && | ||
549 | (local->iw_mode != IW_MODE_INFRA || | ||
550 | !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || | ||
551 | memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { | ||
552 | /* require that WDS link has been registered with TA or the | ||
553 | * frame is from current AP when using 'AP client mode' */ | ||
554 | PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " | ||
555 | "from unknown TA=" MACSTR "\n", | ||
556 | local->dev->name, MAC2STR(hdr->addr2)); | ||
557 | if (local->ap && local->ap->autom_ap_wds) | ||
558 | hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); | ||
559 | return -1; | ||
560 | } | ||
561 | |||
562 | if (*wds && !(fc & WLAN_FC_FROMDS) && local->ap && | ||
563 | hostap_is_sta_assoc(local->ap, hdr->addr2)) { | ||
564 | /* STA is actually associated with us even though it has a | ||
565 | * registered WDS link. Assume it is in 'AP client' mode. | ||
566 | * Since this is a 3-addr frame, assume it is not (bogus) WDS | ||
567 | * frame and process it like any normal ToDS frame from | ||
568 | * associated STA. */ | ||
569 | *wds = NULL; | ||
570 | } | ||
571 | |||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | |||
576 | static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) | ||
577 | { | ||
578 | struct net_device *dev = local->dev; | ||
579 | u16 fc, ethertype; | ||
580 | struct hostap_ieee80211_hdr *hdr; | ||
581 | u8 *pos; | ||
582 | |||
583 | if (skb->len < 24) | ||
584 | return 0; | ||
585 | |||
586 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
587 | fc = le16_to_cpu(hdr->frame_control); | ||
588 | |||
589 | /* check that the frame is unicast frame to us */ | ||
590 | if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS && | ||
591 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && | ||
592 | memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
593 | /* ToDS frame with own addr BSSID and DA */ | ||
594 | } else if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && | ||
595 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
596 | /* FromDS frame with own addr as DA */ | ||
597 | } else | ||
598 | return 0; | ||
599 | |||
600 | if (skb->len < 24 + 8) | ||
601 | return 0; | ||
602 | |||
603 | /* check for port access entity Ethernet type */ | ||
604 | pos = skb->data + 24; | ||
605 | ethertype = (pos[6] << 8) | pos[7]; | ||
606 | if (ethertype == ETH_P_PAE) | ||
607 | return 1; | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | |||
613 | /* Called only as a tasklet (software IRQ) */ | ||
614 | static inline int | ||
615 | hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, | ||
616 | struct prism2_crypt_data *crypt) | ||
617 | { | ||
618 | struct hostap_ieee80211_hdr *hdr; | ||
619 | int res, hdrlen; | ||
620 | |||
621 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | ||
622 | return 0; | ||
623 | |||
624 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
625 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); | ||
626 | |||
627 | if (local->tkip_countermeasures && | ||
628 | strcmp(crypt->ops->name, "TKIP") == 0) { | ||
629 | if (net_ratelimit()) { | ||
630 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
631 | "received packet from " MACSTR "\n", | ||
632 | local->dev->name, MAC2STR(hdr->addr2)); | ||
633 | } | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | atomic_inc(&crypt->refcnt); | ||
638 | res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); | ||
639 | atomic_dec(&crypt->refcnt); | ||
640 | if (res < 0) { | ||
641 | printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR | ||
642 | ") res=%d\n", | ||
643 | local->dev->name, MAC2STR(hdr->addr2), res); | ||
644 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | return res; | ||
649 | } | ||
650 | |||
651 | |||
652 | /* Called only as a tasklet (software IRQ) */ | ||
653 | static inline int | ||
654 | hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, | ||
655 | int keyidx, struct prism2_crypt_data *crypt) | ||
656 | { | ||
657 | struct hostap_ieee80211_hdr *hdr; | ||
658 | int res, hdrlen; | ||
659 | |||
660 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | ||
661 | return 0; | ||
662 | |||
663 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
664 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); | ||
665 | |||
666 | atomic_inc(&crypt->refcnt); | ||
667 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | ||
668 | atomic_dec(&crypt->refcnt); | ||
669 | if (res < 0) { | ||
670 | printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" | ||
671 | " (SA=" MACSTR " keyidx=%d)\n", | ||
672 | local->dev->name, MAC2STR(hdr->addr2), keyidx); | ||
673 | return -1; | ||
674 | } | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | |||
680 | /* All received frames are sent to this function. @skb contains the frame in | ||
681 | * IEEE 802.11 format, i.e., in the format it was sent over air. | ||
682 | * This function is called only as a tasklet (software IRQ). */ | ||
683 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
684 | struct hostap_80211_rx_status *rx_stats) | ||
685 | { | ||
686 | struct hostap_interface *iface; | ||
687 | local_info_t *local; | ||
688 | struct hostap_ieee80211_hdr *hdr; | ||
689 | size_t hdrlen; | ||
690 | u16 fc, type, stype, sc; | ||
691 | struct net_device *wds = NULL; | ||
692 | struct net_device_stats *stats; | ||
693 | unsigned int frag; | ||
694 | u8 *payload; | ||
695 | struct sk_buff *skb2 = NULL; | ||
696 | u16 ethertype; | ||
697 | int frame_authorized = 0; | ||
698 | int from_assoc_ap = 0; | ||
699 | u8 dst[ETH_ALEN]; | ||
700 | u8 src[ETH_ALEN]; | ||
701 | struct prism2_crypt_data *crypt = NULL; | ||
702 | void *sta = NULL; | ||
703 | int keyidx = 0; | ||
704 | |||
705 | iface = netdev_priv(dev); | ||
706 | local = iface->local; | ||
707 | iface->stats.rx_packets++; | ||
708 | iface->stats.rx_bytes += skb->len; | ||
709 | |||
710 | /* dev is the master radio device; change this to be the default | ||
711 | * virtual interface (this may be changed to WDS device below) */ | ||
712 | dev = local->ddev; | ||
713 | iface = netdev_priv(dev); | ||
714 | |||
715 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
716 | stats = hostap_get_stats(dev); | ||
717 | |||
718 | if (skb->len < 10) | ||
719 | goto rx_dropped; | ||
720 | |||
721 | fc = le16_to_cpu(hdr->frame_control); | ||
722 | type = WLAN_FC_GET_TYPE(fc); | ||
723 | stype = WLAN_FC_GET_STYPE(fc); | ||
724 | sc = le16_to_cpu(hdr->seq_ctrl); | ||
725 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
726 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
727 | |||
728 | /* Put this code here so that we avoid duplicating it in all | ||
729 | * Rx paths. - Jean II */ | ||
730 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
731 | /* If spy monitoring on */ | ||
732 | if (iface->spy_data.spy_number > 0) { | ||
733 | struct iw_quality wstats; | ||
734 | wstats.level = rx_stats->signal; | ||
735 | wstats.noise = rx_stats->noise; | ||
736 | wstats.updated = 6; /* No qual value */ | ||
737 | /* Update spy records */ | ||
738 | wireless_spy_update(dev, hdr->addr2, &wstats); | ||
739 | } | ||
740 | #endif /* IW_WIRELESS_SPY */ | ||
741 | hostap_update_rx_stats(local->ap, hdr, rx_stats); | ||
742 | |||
743 | if (local->iw_mode == IW_MODE_MONITOR) { | ||
744 | monitor_rx(dev, skb, rx_stats); | ||
745 | return; | ||
746 | } | ||
747 | |||
748 | if (local->host_decrypt) { | ||
749 | int idx = 0; | ||
750 | if (skb->len >= hdrlen + 3) | ||
751 | idx = skb->data[hdrlen + 3] >> 6; | ||
752 | crypt = local->crypt[idx]; | ||
753 | sta = NULL; | ||
754 | |||
755 | /* Use station specific key to override default keys if the | ||
756 | * receiver address is a unicast address ("individual RA"). If | ||
757 | * bcrx_sta_key parameter is set, station specific key is used | ||
758 | * even with broad/multicast targets (this is against IEEE | ||
759 | * 802.11, but makes it easier to use different keys with | ||
760 | * stations that do not support WEP key mapping). */ | ||
761 | |||
762 | if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) | ||
763 | (void) hostap_handle_sta_crypto(local, hdr, &crypt, | ||
764 | &sta); | ||
765 | |||
766 | /* allow NULL decrypt to indicate an station specific override | ||
767 | * for default encryption */ | ||
768 | if (crypt && (crypt->ops == NULL || | ||
769 | crypt->ops->decrypt_mpdu == NULL)) | ||
770 | crypt = NULL; | ||
771 | |||
772 | if (!crypt && (fc & WLAN_FC_ISWEP)) { | ||
773 | #if 0 | ||
774 | /* This seems to be triggered by some (multicast?) | ||
775 | * frames from other than current BSS, so just drop the | ||
776 | * frames silently instead of filling system log with | ||
777 | * these reports. */ | ||
778 | printk(KERN_DEBUG "%s: WEP decryption failed (not set)" | ||
779 | " (SA=" MACSTR ")\n", | ||
780 | local->dev->name, MAC2STR(hdr->addr2)); | ||
781 | #endif | ||
782 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
783 | goto rx_dropped; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (type != WLAN_FC_TYPE_DATA) { | ||
788 | if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && | ||
789 | fc & WLAN_FC_ISWEP && local->host_decrypt && | ||
790 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
791 | { | ||
792 | printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " | ||
793 | "from " MACSTR "\n", dev->name, | ||
794 | MAC2STR(hdr->addr2)); | ||
795 | /* TODO: could inform hostapd about this so that it | ||
796 | * could send auth failure report */ | ||
797 | goto rx_dropped; | ||
798 | } | ||
799 | |||
800 | if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) | ||
801 | goto rx_dropped; | ||
802 | else | ||
803 | goto rx_exit; | ||
804 | } | ||
805 | |||
806 | /* Data frame - extract src/dst addresses */ | ||
807 | if (skb->len < IEEE80211_DATA_HDR3_LEN) | ||
808 | goto rx_dropped; | ||
809 | |||
810 | switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { | ||
811 | case WLAN_FC_FROMDS: | ||
812 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
813 | memcpy(src, hdr->addr3, ETH_ALEN); | ||
814 | break; | ||
815 | case WLAN_FC_TODS: | ||
816 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
817 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
818 | break; | ||
819 | case WLAN_FC_FROMDS | WLAN_FC_TODS: | ||
820 | if (skb->len < IEEE80211_DATA_HDR4_LEN) | ||
821 | goto rx_dropped; | ||
822 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
823 | memcpy(src, hdr->addr4, ETH_ALEN); | ||
824 | break; | ||
825 | case 0: | ||
826 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
827 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | if (hostap_rx_frame_wds(local, hdr, fc, &wds)) | ||
832 | goto rx_dropped; | ||
833 | if (wds) { | ||
834 | skb->dev = dev = wds; | ||
835 | stats = hostap_get_stats(dev); | ||
836 | } | ||
837 | |||
838 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
839 | (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && | ||
840 | local->stadev && | ||
841 | memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { | ||
842 | /* Frame from BSSID of the AP for which we are a client */ | ||
843 | skb->dev = dev = local->stadev; | ||
844 | stats = hostap_get_stats(dev); | ||
845 | from_assoc_ap = 1; | ||
846 | } | ||
847 | |||
848 | dev->last_rx = jiffies; | ||
849 | |||
850 | if ((local->iw_mode == IW_MODE_MASTER || | ||
851 | local->iw_mode == IW_MODE_REPEAT) && | ||
852 | !from_assoc_ap) { | ||
853 | switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, | ||
854 | wds != NULL)) { | ||
855 | case AP_RX_CONTINUE_NOT_AUTHORIZED: | ||
856 | frame_authorized = 0; | ||
857 | break; | ||
858 | case AP_RX_CONTINUE: | ||
859 | frame_authorized = 1; | ||
860 | break; | ||
861 | case AP_RX_DROP: | ||
862 | goto rx_dropped; | ||
863 | case AP_RX_EXIT: | ||
864 | goto rx_exit; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | /* Nullfunc frames may have PS-bit set, so they must be passed to | ||
869 | * hostap_handle_sta_rx() before being dropped here. */ | ||
870 | if (stype != WLAN_FC_STYPE_DATA && | ||
871 | stype != WLAN_FC_STYPE_DATA_CFACK && | ||
872 | stype != WLAN_FC_STYPE_DATA_CFPOLL && | ||
873 | stype != WLAN_FC_STYPE_DATA_CFACKPOLL) { | ||
874 | if (stype != WLAN_FC_STYPE_NULLFUNC) | ||
875 | printk(KERN_DEBUG "%s: RX: dropped data frame " | ||
876 | "with no data (type=0x%02x, subtype=0x%02x)\n", | ||
877 | dev->name, type, stype); | ||
878 | goto rx_dropped; | ||
879 | } | ||
880 | |||
881 | /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ | ||
882 | |||
883 | if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && | ||
884 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
885 | goto rx_dropped; | ||
886 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
887 | |||
888 | /* skb: hdr + (possibly fragmented) plaintext payload */ | ||
889 | |||
890 | if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && | ||
891 | (frag != 0 || (fc & WLAN_FC_MOREFRAG))) { | ||
892 | int flen; | ||
893 | struct sk_buff *frag_skb = | ||
894 | prism2_frag_cache_get(local, hdr); | ||
895 | if (!frag_skb) { | ||
896 | printk(KERN_DEBUG "%s: Rx cannot get skb from " | ||
897 | "fragment cache (morefrag=%d seq=%u frag=%u)\n", | ||
898 | dev->name, (fc & WLAN_FC_MOREFRAG) != 0, | ||
899 | WLAN_GET_SEQ_SEQ(sc), frag); | ||
900 | goto rx_dropped; | ||
901 | } | ||
902 | |||
903 | flen = skb->len; | ||
904 | if (frag != 0) | ||
905 | flen -= hdrlen; | ||
906 | |||
907 | if (frag_skb->tail + flen > frag_skb->end) { | ||
908 | printk(KERN_WARNING "%s: host decrypted and " | ||
909 | "reassembled frame did not fit skb\n", | ||
910 | dev->name); | ||
911 | prism2_frag_cache_invalidate(local, hdr); | ||
912 | goto rx_dropped; | ||
913 | } | ||
914 | |||
915 | if (frag == 0) { | ||
916 | /* copy first fragment (including full headers) into | ||
917 | * beginning of the fragment cache skb */ | ||
918 | memcpy(skb_put(frag_skb, flen), skb->data, flen); | ||
919 | } else { | ||
920 | /* append frame payload to the end of the fragment | ||
921 | * cache skb */ | ||
922 | memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, | ||
923 | flen); | ||
924 | } | ||
925 | dev_kfree_skb(skb); | ||
926 | skb = NULL; | ||
927 | |||
928 | if (fc & WLAN_FC_MOREFRAG) { | ||
929 | /* more fragments expected - leave the skb in fragment | ||
930 | * cache for now; it will be delivered to upper layers | ||
931 | * after all fragments have been received */ | ||
932 | goto rx_exit; | ||
933 | } | ||
934 | |||
935 | /* this was the last fragment and the frame will be | ||
936 | * delivered, so remove skb from fragment cache */ | ||
937 | skb = frag_skb; | ||
938 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
939 | prism2_frag_cache_invalidate(local, hdr); | ||
940 | } | ||
941 | |||
942 | /* skb: hdr + (possible reassembled) full MSDU payload; possibly still | ||
943 | * encrypted/authenticated */ | ||
944 | |||
945 | if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && | ||
946 | hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) | ||
947 | goto rx_dropped; | ||
948 | |||
949 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
950 | if (crypt && !(fc & WLAN_FC_ISWEP) && !local->open_wep) { | ||
951 | if (local->ieee_802_1x && | ||
952 | hostap_is_eapol_frame(local, skb)) { | ||
953 | /* pass unencrypted EAPOL frames even if encryption is | ||
954 | * configured */ | ||
955 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " | ||
956 | "unencrypted EAPOL frame\n", local->dev->name); | ||
957 | } else { | ||
958 | printk(KERN_DEBUG "%s: encryption configured, but RX " | ||
959 | "frame not encrypted (SA=" MACSTR ")\n", | ||
960 | local->dev->name, MAC2STR(hdr->addr2)); | ||
961 | goto rx_dropped; | ||
962 | } | ||
963 | } | ||
964 | |||
965 | if (local->drop_unencrypted && !(fc & WLAN_FC_ISWEP) && | ||
966 | !hostap_is_eapol_frame(local, skb)) { | ||
967 | if (net_ratelimit()) { | ||
968 | printk(KERN_DEBUG "%s: dropped unencrypted RX data " | ||
969 | "frame from " MACSTR " (drop_unencrypted=1)\n", | ||
970 | dev->name, MAC2STR(hdr->addr2)); | ||
971 | } | ||
972 | goto rx_dropped; | ||
973 | } | ||
974 | |||
975 | /* skb: hdr + (possible reassembled) full plaintext payload */ | ||
976 | |||
977 | payload = skb->data + hdrlen; | ||
978 | ethertype = (payload[6] << 8) | payload[7]; | ||
979 | |||
980 | /* If IEEE 802.1X is used, check whether the port is authorized to send | ||
981 | * the received frame. */ | ||
982 | if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { | ||
983 | if (ethertype == ETH_P_PAE) { | ||
984 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", | ||
985 | dev->name); | ||
986 | if (local->hostapd && local->apdev) { | ||
987 | /* Send IEEE 802.1X frames to the user | ||
988 | * space daemon for processing */ | ||
989 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
990 | PRISM2_RX_MGMT); | ||
991 | local->apdevstats.rx_packets++; | ||
992 | local->apdevstats.rx_bytes += skb->len; | ||
993 | goto rx_exit; | ||
994 | } | ||
995 | } else if (!frame_authorized) { | ||
996 | printk(KERN_DEBUG "%s: dropped frame from " | ||
997 | "unauthorized port (IEEE 802.1X): " | ||
998 | "ethertype=0x%04x\n", | ||
999 | dev->name, ethertype); | ||
1000 | goto rx_dropped; | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | /* convert hdr + possible LLC headers into Ethernet header */ | ||
1005 | if (skb->len - hdrlen >= 8 && | ||
1006 | ((memcmp(payload, rfc1042_header, 6) == 0 && | ||
1007 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
1008 | memcmp(payload, bridge_tunnel_header, 6) == 0)) { | ||
1009 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
1010 | * replace EtherType */ | ||
1011 | skb_pull(skb, hdrlen + 6); | ||
1012 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1013 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1014 | } else { | ||
1015 | u16 len; | ||
1016 | /* Leave Ethernet header part of hdr and full payload */ | ||
1017 | skb_pull(skb, hdrlen); | ||
1018 | len = htons(skb->len); | ||
1019 | memcpy(skb_push(skb, 2), &len, 2); | ||
1020 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1021 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1022 | } | ||
1023 | |||
1024 | if (wds && ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS) && | ||
1025 | skb->len >= ETH_HLEN + ETH_ALEN) { | ||
1026 | /* Non-standard frame: get addr4 from its bogus location after | ||
1027 | * the payload */ | ||
1028 | memcpy(skb->data + ETH_ALEN, | ||
1029 | skb->data + skb->len - ETH_ALEN, ETH_ALEN); | ||
1030 | skb_trim(skb, skb->len - ETH_ALEN); | ||
1031 | } | ||
1032 | |||
1033 | stats->rx_packets++; | ||
1034 | stats->rx_bytes += skb->len; | ||
1035 | |||
1036 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
1037 | local->ap->bridge_packets) { | ||
1038 | if (dst[0] & 0x01) { | ||
1039 | /* copy multicast frame both to the higher layers and | ||
1040 | * to the wireless media */ | ||
1041 | local->ap->bridged_multicast++; | ||
1042 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
1043 | if (skb2 == NULL) | ||
1044 | printk(KERN_DEBUG "%s: skb_clone failed for " | ||
1045 | "multicast frame\n", dev->name); | ||
1046 | } else if (hostap_is_sta_authorized(local->ap, dst)) { | ||
1047 | /* send frame directly to the associated STA using | ||
1048 | * wireless media and not passing to higher layers */ | ||
1049 | local->ap->bridged_unicast++; | ||
1050 | skb2 = skb; | ||
1051 | skb = NULL; | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | if (skb2 != NULL) { | ||
1056 | /* send to wireless media */ | ||
1057 | skb2->protocol = __constant_htons(ETH_P_802_3); | ||
1058 | skb2->mac.raw = skb2->nh.raw = skb2->data; | ||
1059 | /* skb2->nh.raw = skb2->data + ETH_HLEN; */ | ||
1060 | skb2->dev = dev; | ||
1061 | dev_queue_xmit(skb2); | ||
1062 | } | ||
1063 | |||
1064 | if (skb) { | ||
1065 | skb->protocol = eth_type_trans(skb, dev); | ||
1066 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1067 | skb->dev = dev; | ||
1068 | netif_rx(skb); | ||
1069 | } | ||
1070 | |||
1071 | rx_exit: | ||
1072 | if (sta) | ||
1073 | hostap_handle_sta_release(sta); | ||
1074 | return; | ||
1075 | |||
1076 | rx_dropped: | ||
1077 | dev_kfree_skb(skb); | ||
1078 | |||
1079 | stats->rx_dropped++; | ||
1080 | goto rx_exit; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | 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 00000000000..8a94a80ec55 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c | |||
@@ -0,0 +1,522 @@ | |||
1 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | ||
2 | { | ||
3 | struct hostap_ieee80211_hdr *hdr; | ||
4 | u16 fc; | ||
5 | |||
6 | hdr = (struct hostap_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_control); | ||
15 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
16 | fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), | ||
17 | fc & WLAN_FC_TODS ? " [ToDS]" : "", | ||
18 | fc & WLAN_FC_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_ctrl)); | ||
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 hostap_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 = (WLAN_FC_TYPE_DATA << 2) | (WLAN_FC_STYPE_DATA << 4); | ||
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 |= WLAN_FC_FROMDS | WLAN_FC_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 |= WLAN_FC_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 |= WLAN_FC_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 |= WLAN_FC_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_control = 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 | meta->wds = use_wds; | ||
230 | meta->ethertype = ethertype; | ||
231 | meta->iface = iface; | ||
232 | |||
233 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
234 | skb->dev = local->dev; | ||
235 | dev_queue_xmit(skb); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | |||
240 | /* hard_start_xmit function for hostapd wlan#ap interfaces */ | ||
241 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
242 | { | ||
243 | struct hostap_interface *iface; | ||
244 | local_info_t *local; | ||
245 | struct hostap_skb_tx_data *meta; | ||
246 | struct hostap_ieee80211_hdr *hdr; | ||
247 | u16 fc; | ||
248 | |||
249 | iface = netdev_priv(dev); | ||
250 | local = iface->local; | ||
251 | |||
252 | if (skb->len < 10) { | ||
253 | printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " | ||
254 | "(len=%d)\n", dev->name, skb->len); | ||
255 | kfree_skb(skb); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | iface->stats.tx_packets++; | ||
260 | iface->stats.tx_bytes += skb->len; | ||
261 | |||
262 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
263 | memset(meta, 0, sizeof(*meta)); | ||
264 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
265 | meta->iface = iface; | ||
266 | |||
267 | if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { | ||
268 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
269 | fc = le16_to_cpu(hdr->frame_control); | ||
270 | if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && | ||
271 | WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DATA) { | ||
272 | u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + | ||
273 | sizeof(rfc1042_header)]; | ||
274 | meta->ethertype = (pos[0] << 8) | pos[1]; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
279 | skb->dev = local->dev; | ||
280 | dev_queue_xmit(skb); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | |||
285 | /* Called only from software IRQ */ | ||
286 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
287 | struct prism2_crypt_data *crypt) | ||
288 | { | ||
289 | struct hostap_interface *iface; | ||
290 | local_info_t *local; | ||
291 | struct hostap_ieee80211_hdr *hdr; | ||
292 | u16 fc; | ||
293 | int hdr_len, res; | ||
294 | |||
295 | iface = netdev_priv(skb->dev); | ||
296 | local = iface->local; | ||
297 | |||
298 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
299 | kfree_skb(skb); | ||
300 | return NULL; | ||
301 | } | ||
302 | |||
303 | if (local->tkip_countermeasures && | ||
304 | crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { | ||
305 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
306 | if (net_ratelimit()) { | ||
307 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
308 | "TX packet to " MACSTR "\n", | ||
309 | local->dev->name, MAC2STR(hdr->addr1)); | ||
310 | } | ||
311 | kfree_skb(skb); | ||
312 | return NULL; | ||
313 | } | ||
314 | |||
315 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
316 | if (skb == NULL) | ||
317 | return NULL; | ||
318 | |||
319 | if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || | ||
320 | skb_tailroom(skb) < crypt->ops->extra_postfix_len) && | ||
321 | pskb_expand_head(skb, crypt->ops->extra_prefix_len, | ||
322 | crypt->ops->extra_postfix_len, GFP_ATOMIC)) { | ||
323 | kfree_skb(skb); | ||
324 | return NULL; | ||
325 | } | ||
326 | |||
327 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
328 | fc = le16_to_cpu(hdr->frame_control); | ||
329 | hdr_len = hostap_80211_get_hdrlen(fc); | ||
330 | |||
331 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | ||
332 | * call both MSDU and MPDU encryption functions from here. */ | ||
333 | atomic_inc(&crypt->refcnt); | ||
334 | res = 0; | ||
335 | if (crypt->ops->encrypt_msdu) | ||
336 | res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); | ||
337 | if (res == 0 && crypt->ops->encrypt_mpdu) | ||
338 | res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); | ||
339 | atomic_dec(&crypt->refcnt); | ||
340 | if (res < 0) { | ||
341 | kfree_skb(skb); | ||
342 | return NULL; | ||
343 | } | ||
344 | |||
345 | return skb; | ||
346 | } | ||
347 | |||
348 | |||
349 | /* hard_start_xmit function for master radio interface wifi#. | ||
350 | * AP processing (TX rate control, power save buffering, etc.). | ||
351 | * Use hardware TX function to send the frame. */ | ||
352 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
353 | { | ||
354 | struct hostap_interface *iface; | ||
355 | local_info_t *local; | ||
356 | int ret = 1; | ||
357 | u16 fc; | ||
358 | struct hostap_tx_data tx; | ||
359 | ap_tx_ret tx_ret; | ||
360 | struct hostap_skb_tx_data *meta; | ||
361 | int no_encrypt = 0; | ||
362 | struct hostap_ieee80211_hdr *hdr; | ||
363 | |||
364 | iface = netdev_priv(dev); | ||
365 | local = iface->local; | ||
366 | |||
367 | tx.skb = skb; | ||
368 | tx.sta_ptr = NULL; | ||
369 | |||
370 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
371 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
372 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
373 | "expected 0x%08x)\n", | ||
374 | dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); | ||
375 | ret = 0; | ||
376 | iface->stats.tx_dropped++; | ||
377 | goto fail; | ||
378 | } | ||
379 | |||
380 | if (local->host_encrypt) { | ||
381 | /* Set crypt to default algorithm and key; will be replaced in | ||
382 | * AP code if STA has own alg/key */ | ||
383 | tx.crypt = local->crypt[local->tx_keyidx]; | ||
384 | tx.host_encrypt = 1; | ||
385 | } else { | ||
386 | tx.crypt = NULL; | ||
387 | tx.host_encrypt = 0; | ||
388 | } | ||
389 | |||
390 | if (skb->len < 24) { | ||
391 | printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " | ||
392 | "(len=%d)\n", dev->name, skb->len); | ||
393 | ret = 0; | ||
394 | iface->stats.tx_dropped++; | ||
395 | goto fail; | ||
396 | } | ||
397 | |||
398 | /* FIX (?): | ||
399 | * Wi-Fi 802.11b test plan suggests that AP should ignore power save | ||
400 | * bit in authentication and (re)association frames and assume tha | ||
401 | * STA remains awake for the response. */ | ||
402 | tx_ret = hostap_handle_sta_tx(local, &tx); | ||
403 | skb = tx.skb; | ||
404 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
405 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
406 | fc = le16_to_cpu(hdr->frame_control); | ||
407 | switch (tx_ret) { | ||
408 | case AP_TX_CONTINUE: | ||
409 | break; | ||
410 | case AP_TX_CONTINUE_NOT_AUTHORIZED: | ||
411 | if (local->ieee_802_1x && | ||
412 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && | ||
413 | meta->ethertype != ETH_P_PAE && !meta->wds) { | ||
414 | printk(KERN_DEBUG "%s: dropped frame to unauthorized " | ||
415 | "port (IEEE 802.1X): ethertype=0x%04x\n", | ||
416 | dev->name, meta->ethertype); | ||
417 | hostap_dump_tx_80211(dev->name, skb); | ||
418 | |||
419 | ret = 0; /* drop packet */ | ||
420 | iface->stats.tx_dropped++; | ||
421 | goto fail; | ||
422 | } | ||
423 | break; | ||
424 | case AP_TX_DROP: | ||
425 | ret = 0; /* drop packet */ | ||
426 | iface->stats.tx_dropped++; | ||
427 | goto fail; | ||
428 | case AP_TX_RETRY: | ||
429 | goto fail; | ||
430 | case AP_TX_BUFFERED: | ||
431 | /* do not free skb here, it will be freed when the | ||
432 | * buffered frame is sent/timed out */ | ||
433 | ret = 0; | ||
434 | goto tx_exit; | ||
435 | } | ||
436 | |||
437 | /* Request TX callback if protocol version is 2 in 802.11 header; | ||
438 | * this version 2 is a special case used between hostapd and kernel | ||
439 | * driver */ | ||
440 | if (((fc & WLAN_FC_PVER) == BIT(1)) && | ||
441 | local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { | ||
442 | meta->tx_cb_idx = local->ap->tx_callback_idx; | ||
443 | |||
444 | /* remove special version from the frame header */ | ||
445 | fc &= ~WLAN_FC_PVER; | ||
446 | hdr->frame_control = cpu_to_le16(fc); | ||
447 | } | ||
448 | |||
449 | if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_DATA) { | ||
450 | no_encrypt = 1; | ||
451 | tx.crypt = NULL; | ||
452 | } | ||
453 | |||
454 | if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && | ||
455 | !(fc & WLAN_FC_ISWEP)) { | ||
456 | no_encrypt = 1; | ||
457 | PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " | ||
458 | "unencrypted EAPOL frame\n", dev->name); | ||
459 | tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ | ||
460 | } | ||
461 | |||
462 | if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) | ||
463 | tx.crypt = NULL; | ||
464 | else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { | ||
465 | /* Add ISWEP flag both for firmware and host based encryption | ||
466 | */ | ||
467 | fc |= WLAN_FC_ISWEP; | ||
468 | hdr->frame_control = cpu_to_le16(fc); | ||
469 | } else if (local->drop_unencrypted && | ||
470 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && | ||
471 | meta->ethertype != ETH_P_PAE) { | ||
472 | if (net_ratelimit()) { | ||
473 | printk(KERN_DEBUG "%s: dropped unencrypted TX data " | ||
474 | "frame (drop_unencrypted=1)\n", dev->name); | ||
475 | } | ||
476 | iface->stats.tx_dropped++; | ||
477 | ret = 0; | ||
478 | goto fail; | ||
479 | } | ||
480 | |||
481 | if (tx.crypt) { | ||
482 | skb = hostap_tx_encrypt(skb, tx.crypt); | ||
483 | if (skb == NULL) { | ||
484 | printk(KERN_DEBUG "%s: TX - encryption failed\n", | ||
485 | dev->name); | ||
486 | ret = 0; | ||
487 | goto fail; | ||
488 | } | ||
489 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
490 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
491 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
492 | "expected 0x%08x) after hostap_tx_encrypt\n", | ||
493 | dev->name, meta->magic, | ||
494 | HOSTAP_SKB_TX_DATA_MAGIC); | ||
495 | ret = 0; | ||
496 | iface->stats.tx_dropped++; | ||
497 | goto fail; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | if (local->func->tx == NULL || local->func->tx(skb, dev)) { | ||
502 | ret = 0; | ||
503 | iface->stats.tx_dropped++; | ||
504 | } else { | ||
505 | ret = 0; | ||
506 | iface->stats.tx_packets++; | ||
507 | iface->stats.tx_bytes += skb->len; | ||
508 | } | ||
509 | |||
510 | fail: | ||
511 | if (!ret && skb) | ||
512 | dev_kfree_skb(skb); | ||
513 | tx_exit: | ||
514 | if (tx.sta_ptr) | ||
515 | hostap_handle_sta_release(tx.sta_ptr); | ||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | |||
520 | EXPORT_SYMBOL(hostap_dump_tx_80211); | ||
521 | EXPORT_SYMBOL(hostap_tx_encrypt); | ||
522 | 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 00000000000..b9684e3a568 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -0,0 +1,3286 @@ | |||
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-2003, 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 | int type, int 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: WLAN_FC_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, WLAN_FC_TYPE_DATA, | ||
245 | WLAN_FC_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, WLAN_FC_TYPE_MGMT, | ||
259 | (deauth ? WLAN_FC_STYPE_DEAUTH : | ||
260 | WLAN_FC_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, WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH, | ||
304 | (char *) &resp, 2, addr, 0); | ||
305 | |||
306 | if (!resend || ap->num_sta <= 0) | ||
307 | return; | ||
308 | |||
309 | mdelay(50); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | |||
314 | static int ap_control_proc_read(char *page, char **start, off_t off, | ||
315 | int count, int *eof, void *data) | ||
316 | { | ||
317 | char *p = page; | ||
318 | struct ap_data *ap = (struct ap_data *) data; | ||
319 | char *policy_txt; | ||
320 | struct list_head *ptr; | ||
321 | struct mac_entry *entry; | ||
322 | |||
323 | if (off != 0) { | ||
324 | *eof = 1; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | switch (ap->mac_restrictions.policy) { | ||
329 | case MAC_POLICY_OPEN: | ||
330 | policy_txt = "open"; | ||
331 | break; | ||
332 | case MAC_POLICY_ALLOW: | ||
333 | policy_txt = "allow"; | ||
334 | break; | ||
335 | case MAC_POLICY_DENY: | ||
336 | policy_txt = "deny"; | ||
337 | break; | ||
338 | default: | ||
339 | policy_txt = "unknown"; | ||
340 | break; | ||
341 | }; | ||
342 | p += sprintf(p, "MAC policy: %s\n", policy_txt); | ||
343 | p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); | ||
344 | p += sprintf(p, "MAC list:\n"); | ||
345 | spin_lock_bh(&ap->mac_restrictions.lock); | ||
346 | for (ptr = ap->mac_restrictions.mac_list.next; | ||
347 | ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) { | ||
348 | if (p - page > PAGE_SIZE - 80) { | ||
349 | p += sprintf(p, "All entries did not fit one page.\n"); | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | entry = list_entry(ptr, struct mac_entry, list); | ||
354 | p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); | ||
355 | } | ||
356 | spin_unlock_bh(&ap->mac_restrictions.lock); | ||
357 | |||
358 | return (p - page); | ||
359 | } | ||
360 | |||
361 | |||
362 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
363 | u8 *mac) | ||
364 | { | ||
365 | struct mac_entry *entry; | ||
366 | |||
367 | entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); | ||
368 | if (entry == NULL) | ||
369 | return -1; | ||
370 | |||
371 | memcpy(entry->addr, mac, ETH_ALEN); | ||
372 | |||
373 | spin_lock_bh(&mac_restrictions->lock); | ||
374 | list_add_tail(&entry->list, &mac_restrictions->mac_list); | ||
375 | mac_restrictions->entries++; | ||
376 | spin_unlock_bh(&mac_restrictions->lock); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | |||
382 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
383 | u8 *mac) | ||
384 | { | ||
385 | struct list_head *ptr; | ||
386 | struct mac_entry *entry; | ||
387 | |||
388 | spin_lock_bh(&mac_restrictions->lock); | ||
389 | for (ptr = mac_restrictions->mac_list.next; | ||
390 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
391 | entry = list_entry(ptr, struct mac_entry, list); | ||
392 | |||
393 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
394 | list_del(ptr); | ||
395 | kfree(entry); | ||
396 | mac_restrictions->entries--; | ||
397 | spin_unlock_bh(&mac_restrictions->lock); | ||
398 | return 0; | ||
399 | } | ||
400 | } | ||
401 | spin_unlock_bh(&mac_restrictions->lock); | ||
402 | return -1; | ||
403 | } | ||
404 | |||
405 | |||
406 | static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, | ||
407 | u8 *mac) | ||
408 | { | ||
409 | struct list_head *ptr; | ||
410 | struct mac_entry *entry; | ||
411 | int found = 0; | ||
412 | |||
413 | if (mac_restrictions->policy == MAC_POLICY_OPEN) | ||
414 | return 0; | ||
415 | |||
416 | spin_lock_bh(&mac_restrictions->lock); | ||
417 | for (ptr = mac_restrictions->mac_list.next; | ||
418 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
419 | entry = list_entry(ptr, struct mac_entry, list); | ||
420 | |||
421 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
422 | found = 1; | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | spin_unlock_bh(&mac_restrictions->lock); | ||
427 | |||
428 | if (mac_restrictions->policy == MAC_POLICY_ALLOW) | ||
429 | return !found; | ||
430 | else | ||
431 | return found; | ||
432 | } | ||
433 | |||
434 | |||
435 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) | ||
436 | { | ||
437 | struct list_head *ptr, *n; | ||
438 | struct mac_entry *entry; | ||
439 | |||
440 | if (mac_restrictions->entries == 0) | ||
441 | return; | ||
442 | |||
443 | spin_lock_bh(&mac_restrictions->lock); | ||
444 | for (ptr = mac_restrictions->mac_list.next, n = ptr->next; | ||
445 | ptr != &mac_restrictions->mac_list; | ||
446 | ptr = n, n = ptr->next) { | ||
447 | entry = list_entry(ptr, struct mac_entry, list); | ||
448 | list_del(ptr); | ||
449 | kfree(entry); | ||
450 | } | ||
451 | mac_restrictions->entries = 0; | ||
452 | spin_unlock_bh(&mac_restrictions->lock); | ||
453 | } | ||
454 | |||
455 | |||
456 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
457 | u8 *mac) | ||
458 | { | ||
459 | struct sta_info *sta; | ||
460 | u16 resp; | ||
461 | |||
462 | spin_lock_bh(&ap->sta_table_lock); | ||
463 | sta = ap_get_sta(ap, mac); | ||
464 | if (sta) { | ||
465 | ap_sta_hash_del(ap, sta); | ||
466 | list_del(&sta->list); | ||
467 | } | ||
468 | spin_unlock_bh(&ap->sta_table_lock); | ||
469 | |||
470 | if (!sta) | ||
471 | return -EINVAL; | ||
472 | |||
473 | resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
474 | prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH, | ||
475 | (char *) &resp, 2, sta->addr, 0); | ||
476 | |||
477 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
478 | hostap_event_expired_sta(dev, sta); | ||
479 | |||
480 | ap_free_sta(ap, sta); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
486 | |||
487 | |||
488 | static void ap_control_kickall(struct ap_data *ap) | ||
489 | { | ||
490 | struct list_head *ptr, *n; | ||
491 | struct sta_info *sta; | ||
492 | |||
493 | spin_lock_bh(&ap->sta_table_lock); | ||
494 | for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; | ||
495 | ptr = n, n = ptr->next) { | ||
496 | sta = list_entry(ptr, struct sta_info, list); | ||
497 | ap_sta_hash_del(ap, sta); | ||
498 | list_del(&sta->list); | ||
499 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
500 | hostap_event_expired_sta(sta->local->dev, sta); | ||
501 | ap_free_sta(ap, sta); | ||
502 | } | ||
503 | spin_unlock_bh(&ap->sta_table_lock); | ||
504 | } | ||
505 | |||
506 | |||
507 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
508 | |||
509 | #define PROC_LIMIT (PAGE_SIZE - 80) | ||
510 | |||
511 | static int prism2_ap_proc_read(char *page, char **start, off_t off, | ||
512 | int count, int *eof, void *data) | ||
513 | { | ||
514 | char *p = page; | ||
515 | struct ap_data *ap = (struct ap_data *) data; | ||
516 | struct list_head *ptr; | ||
517 | int i; | ||
518 | |||
519 | if (off > PROC_LIMIT) { | ||
520 | *eof = 1; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); | ||
525 | spin_lock_bh(&ap->sta_table_lock); | ||
526 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
527 | struct sta_info *sta = (struct sta_info *) ptr; | ||
528 | |||
529 | if (!sta->ap) | ||
530 | continue; | ||
531 | |||
532 | p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), | ||
533 | sta->u.ap.channel, sta->last_rx_signal, | ||
534 | sta->last_rx_silence, sta->last_rx_rate); | ||
535 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
536 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
537 | sta->u.ap.ssid[i] < 127) ? | ||
538 | "%c" : "<%02x>"), | ||
539 | sta->u.ap.ssid[i]); | ||
540 | p += sprintf(p, "'"); | ||
541 | if (sta->capability & WLAN_CAPABILITY_ESS) | ||
542 | p += sprintf(p, " [ESS]"); | ||
543 | if (sta->capability & WLAN_CAPABILITY_IBSS) | ||
544 | p += sprintf(p, " [IBSS]"); | ||
545 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
546 | p += sprintf(p, " [WEP]"); | ||
547 | p += sprintf(p, "\n"); | ||
548 | |||
549 | if ((p - page) > PROC_LIMIT) { | ||
550 | printk(KERN_DEBUG "hostap: ap proc did not fit\n"); | ||
551 | break; | ||
552 | } | ||
553 | } | ||
554 | spin_unlock_bh(&ap->sta_table_lock); | ||
555 | |||
556 | if ((p - page) <= off) { | ||
557 | *eof = 1; | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | *start = page + off; | ||
562 | |||
563 | return (p - page - off); | ||
564 | } | ||
565 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
566 | |||
567 | |||
568 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) | ||
569 | { | ||
570 | if (!ap) | ||
571 | return; | ||
572 | |||
573 | if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { | ||
574 | PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " | ||
575 | "firmware upgrade recommended\n"); | ||
576 | ap->nullfunc_ack = 1; | ||
577 | } else | ||
578 | ap->nullfunc_ack = 0; | ||
579 | |||
580 | if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { | ||
581 | printk(KERN_WARNING "%s: Warning: secondary station firmware " | ||
582 | "version 1.4.2 does not seem to work in Host AP mode\n", | ||
583 | ap->local->dev->name); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | |||
588 | /* Called only as a tasklet (software IRQ) */ | ||
589 | static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) | ||
590 | { | ||
591 | struct ap_data *ap = data; | ||
592 | u16 fc; | ||
593 | struct hostap_ieee80211_hdr *hdr; | ||
594 | |||
595 | if (!ap->local->hostapd || !ap->local->apdev) { | ||
596 | dev_kfree_skb(skb); | ||
597 | return; | ||
598 | } | ||
599 | |||
600 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
601 | fc = le16_to_cpu(hdr->frame_control); | ||
602 | |||
603 | /* Pass the TX callback frame to the hostapd; use 802.11 header version | ||
604 | * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ | ||
605 | |||
606 | fc &= ~WLAN_FC_PVER; | ||
607 | fc |= ok ? BIT(1) : BIT(0); | ||
608 | hdr->frame_control = cpu_to_le16(fc); | ||
609 | |||
610 | skb->dev = ap->local->apdev; | ||
611 | skb_pull(skb, hostap_80211_get_hdrlen(fc)); | ||
612 | skb->pkt_type = PACKET_OTHERHOST; | ||
613 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
614 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
615 | netif_rx(skb); | ||
616 | } | ||
617 | |||
618 | |||
619 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
620 | /* Called only as a tasklet (software IRQ) */ | ||
621 | static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | ||
622 | { | ||
623 | struct ap_data *ap = data; | ||
624 | struct net_device *dev = ap->local->dev; | ||
625 | struct hostap_ieee80211_hdr *hdr; | ||
626 | u16 fc, *pos, auth_alg, auth_transaction, status; | ||
627 | struct sta_info *sta = NULL; | ||
628 | char *txt = NULL; | ||
629 | |||
630 | if (ap->local->hostapd) { | ||
631 | dev_kfree_skb(skb); | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
636 | fc = le16_to_cpu(hdr->frame_control); | ||
637 | if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || | ||
638 | WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_AUTH || | ||
639 | skb->len < IEEE80211_MGMT_HDR_LEN + 6) { | ||
640 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " | ||
641 | "frame\n", dev->name); | ||
642 | dev_kfree_skb(skb); | ||
643 | return; | ||
644 | } | ||
645 | |||
646 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
647 | auth_alg = le16_to_cpu(*pos++); | ||
648 | auth_transaction = le16_to_cpu(*pos++); | ||
649 | status = le16_to_cpu(*pos++); | ||
650 | |||
651 | if (!ok) { | ||
652 | txt = "frame was not ACKed"; | ||
653 | goto done; | ||
654 | } | ||
655 | |||
656 | spin_lock(&ap->sta_table_lock); | ||
657 | sta = ap_get_sta(ap, hdr->addr1); | ||
658 | if (sta) | ||
659 | atomic_inc(&sta->users); | ||
660 | spin_unlock(&ap->sta_table_lock); | ||
661 | |||
662 | if (!sta) { | ||
663 | txt = "STA not found"; | ||
664 | goto done; | ||
665 | } | ||
666 | |||
667 | if (status == WLAN_STATUS_SUCCESS && | ||
668 | ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || | ||
669 | (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { | ||
670 | txt = "STA authenticated"; | ||
671 | sta->flags |= WLAN_STA_AUTH; | ||
672 | sta->last_auth = jiffies; | ||
673 | } else if (status != WLAN_STATUS_SUCCESS) | ||
674 | txt = "authentication failed"; | ||
675 | |||
676 | done: | ||
677 | if (sta) | ||
678 | atomic_dec(&sta->users); | ||
679 | if (txt) { | ||
680 | PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " | ||
681 | "status=%d - %s\n", | ||
682 | dev->name, MAC2STR(hdr->addr1), auth_alg, | ||
683 | auth_transaction, status, txt); | ||
684 | } | ||
685 | dev_kfree_skb(skb); | ||
686 | } | ||
687 | |||
688 | |||
689 | /* Called only as a tasklet (software IRQ) */ | ||
690 | static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | ||
691 | { | ||
692 | struct ap_data *ap = data; | ||
693 | struct net_device *dev = ap->local->dev; | ||
694 | struct hostap_ieee80211_hdr *hdr; | ||
695 | u16 fc, *pos, status; | ||
696 | struct sta_info *sta = NULL; | ||
697 | char *txt = NULL; | ||
698 | |||
699 | if (ap->local->hostapd) { | ||
700 | dev_kfree_skb(skb); | ||
701 | return; | ||
702 | } | ||
703 | |||
704 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
705 | fc = le16_to_cpu(hdr->frame_control); | ||
706 | if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || | ||
707 | (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ASSOC_RESP && | ||
708 | WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_REASSOC_RESP) || | ||
709 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | ||
710 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " | ||
711 | "frame\n", dev->name); | ||
712 | dev_kfree_skb(skb); | ||
713 | return; | ||
714 | } | ||
715 | |||
716 | if (!ok) { | ||
717 | txt = "frame was not ACKed"; | ||
718 | goto done; | ||
719 | } | ||
720 | |||
721 | spin_lock(&ap->sta_table_lock); | ||
722 | sta = ap_get_sta(ap, hdr->addr1); | ||
723 | if (sta) | ||
724 | atomic_inc(&sta->users); | ||
725 | spin_unlock(&ap->sta_table_lock); | ||
726 | |||
727 | if (!sta) { | ||
728 | txt = "STA not found"; | ||
729 | goto done; | ||
730 | } | ||
731 | |||
732 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
733 | pos++; | ||
734 | status = le16_to_cpu(*pos++); | ||
735 | if (status == WLAN_STATUS_SUCCESS) { | ||
736 | if (!(sta->flags & WLAN_STA_ASSOC)) | ||
737 | hostap_event_new_sta(dev, sta); | ||
738 | txt = "STA associated"; | ||
739 | sta->flags |= WLAN_STA_ASSOC; | ||
740 | sta->last_assoc = jiffies; | ||
741 | } else | ||
742 | txt = "association failed"; | ||
743 | |||
744 | done: | ||
745 | if (sta) | ||
746 | atomic_dec(&sta->users); | ||
747 | if (txt) { | ||
748 | PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", | ||
749 | dev->name, MAC2STR(hdr->addr1), txt); | ||
750 | } | ||
751 | dev_kfree_skb(skb); | ||
752 | } | ||
753 | |||
754 | /* Called only as a tasklet (software IRQ); TX callback for poll frames used | ||
755 | * in verifying whether the STA is still present. */ | ||
756 | static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) | ||
757 | { | ||
758 | struct ap_data *ap = data; | ||
759 | struct hostap_ieee80211_hdr *hdr; | ||
760 | struct sta_info *sta; | ||
761 | |||
762 | if (skb->len < 24) | ||
763 | goto fail; | ||
764 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
765 | if (ok) { | ||
766 | spin_lock(&ap->sta_table_lock); | ||
767 | sta = ap_get_sta(ap, hdr->addr1); | ||
768 | if (sta) | ||
769 | sta->flags &= ~WLAN_STA_PENDING_POLL; | ||
770 | spin_unlock(&ap->sta_table_lock); | ||
771 | } else { | ||
772 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " | ||
773 | "poll frame\n", ap->local->dev->name, | ||
774 | MAC2STR(hdr->addr1)); | ||
775 | } | ||
776 | |||
777 | fail: | ||
778 | dev_kfree_skb(skb); | ||
779 | } | ||
780 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
781 | |||
782 | |||
783 | void hostap_init_data(local_info_t *local) | ||
784 | { | ||
785 | struct ap_data *ap = local->ap; | ||
786 | |||
787 | if (ap == NULL) { | ||
788 | printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); | ||
789 | return; | ||
790 | } | ||
791 | memset(ap, 0, sizeof(struct ap_data)); | ||
792 | ap->local = local; | ||
793 | |||
794 | ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); | ||
795 | ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); | ||
796 | ap->max_inactivity = | ||
797 | GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; | ||
798 | ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); | ||
799 | |||
800 | spin_lock_init(&ap->sta_table_lock); | ||
801 | INIT_LIST_HEAD(&ap->sta_list); | ||
802 | |||
803 | /* Initialize task queue structure for AP management */ | ||
804 | INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); | ||
805 | |||
806 | ap->tx_callback_idx = | ||
807 | hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); | ||
808 | if (ap->tx_callback_idx == 0) | ||
809 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
810 | "AP\n", local->dev->name); | ||
811 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
812 | INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); | ||
813 | |||
814 | ap->tx_callback_auth = | ||
815 | hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); | ||
816 | ap->tx_callback_assoc = | ||
817 | hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); | ||
818 | ap->tx_callback_poll = | ||
819 | hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); | ||
820 | if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || | ||
821 | ap->tx_callback_poll == 0) | ||
822 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
823 | "AP\n", local->dev->name); | ||
824 | |||
825 | spin_lock_init(&ap->mac_restrictions.lock); | ||
826 | INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); | ||
827 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
828 | |||
829 | ap->initialized = 1; | ||
830 | } | ||
831 | |||
832 | |||
833 | void hostap_init_ap_proc(local_info_t *local) | ||
834 | { | ||
835 | struct ap_data *ap = local->ap; | ||
836 | |||
837 | ap->proc = local->proc; | ||
838 | if (ap->proc == NULL) | ||
839 | return; | ||
840 | |||
841 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
842 | create_proc_read_entry("ap_debug", 0, ap->proc, | ||
843 | ap_debug_proc_read, ap); | ||
844 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
845 | |||
846 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
847 | create_proc_read_entry("ap_control", 0, ap->proc, | ||
848 | ap_control_proc_read, ap); | ||
849 | create_proc_read_entry("ap", 0, ap->proc, | ||
850 | prism2_ap_proc_read, ap); | ||
851 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
852 | |||
853 | } | ||
854 | |||
855 | |||
856 | void hostap_free_data(struct ap_data *ap) | ||
857 | { | ||
858 | struct list_head *n, *ptr; | ||
859 | |||
860 | if (ap == NULL || !ap->initialized) { | ||
861 | printk(KERN_DEBUG "hostap_free_data: ap has not yet been " | ||
862 | "initialized - skip resource freeing\n"); | ||
863 | return; | ||
864 | } | ||
865 | |||
866 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
867 | if (ap->crypt) | ||
868 | ap->crypt->deinit(ap->crypt_priv); | ||
869 | ap->crypt = ap->crypt_priv = NULL; | ||
870 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
871 | |||
872 | list_for_each_safe(ptr, n, &ap->sta_list) { | ||
873 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
874 | ap_sta_hash_del(ap, sta); | ||
875 | list_del(&sta->list); | ||
876 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
877 | hostap_event_expired_sta(sta->local->dev, sta); | ||
878 | ap_free_sta(ap, sta); | ||
879 | } | ||
880 | |||
881 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
882 | if (ap->proc != NULL) { | ||
883 | remove_proc_entry("ap_debug", ap->proc); | ||
884 | } | ||
885 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
886 | |||
887 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
888 | if (ap->proc != NULL) { | ||
889 | remove_proc_entry("ap", ap->proc); | ||
890 | remove_proc_entry("ap_control", ap->proc); | ||
891 | } | ||
892 | ap_control_flush_macs(&ap->mac_restrictions); | ||
893 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
894 | |||
895 | ap->initialized = 0; | ||
896 | } | ||
897 | |||
898 | |||
899 | /* caller should have mutex for AP STA list handling */ | ||
900 | static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) | ||
901 | { | ||
902 | struct sta_info *s; | ||
903 | |||
904 | s = ap->sta_hash[STA_HASH(sta)]; | ||
905 | while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0) | ||
906 | s = s->hnext; | ||
907 | return s; | ||
908 | } | ||
909 | |||
910 | |||
911 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
912 | |||
913 | /* Called from timer handler and from scheduled AP queue handlers */ | ||
914 | static void prism2_send_mgmt(struct net_device *dev, | ||
915 | int type, int subtype, char *body, | ||
916 | int body_len, u8 *addr, u16 tx_cb_idx) | ||
917 | { | ||
918 | struct hostap_interface *iface; | ||
919 | local_info_t *local; | ||
920 | struct hostap_ieee80211_hdr *hdr; | ||
921 | u16 fc; | ||
922 | struct sk_buff *skb; | ||
923 | struct hostap_skb_tx_data *meta; | ||
924 | int hdrlen; | ||
925 | |||
926 | iface = netdev_priv(dev); | ||
927 | local = iface->local; | ||
928 | dev = local->dev; /* always use master radio device */ | ||
929 | iface = netdev_priv(dev); | ||
930 | |||
931 | if (!(dev->flags & IFF_UP)) { | ||
932 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " | ||
933 | "cannot send frame\n", dev->name); | ||
934 | return; | ||
935 | } | ||
936 | |||
937 | skb = dev_alloc_skb(sizeof(*hdr) + body_len); | ||
938 | if (skb == NULL) { | ||
939 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " | ||
940 | "skb\n", dev->name); | ||
941 | return; | ||
942 | } | ||
943 | |||
944 | fc = (type << 2) | (subtype << 4); | ||
945 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
946 | hdr = (struct hostap_ieee80211_hdr *) skb_put(skb, hdrlen); | ||
947 | if (body) | ||
948 | memcpy(skb_put(skb, body_len), body, body_len); | ||
949 | |||
950 | memset(hdr, 0, hdrlen); | ||
951 | |||
952 | /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 | ||
953 | * tx_control instead of using local->tx_control */ | ||
954 | |||
955 | |||
956 | memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ | ||
957 | if (type == WLAN_FC_TYPE_DATA) { | ||
958 | fc |= WLAN_FC_FROMDS; | ||
959 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
960 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ | ||
961 | } else if (type == WLAN_FC_TYPE_CTRL) { | ||
962 | /* control:ACK does not have addr2 or addr3 */ | ||
963 | memset(hdr->addr2, 0, ETH_ALEN); | ||
964 | memset(hdr->addr3, 0, ETH_ALEN); | ||
965 | } else { | ||
966 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ | ||
967 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
968 | } | ||
969 | |||
970 | hdr->frame_control = cpu_to_le16(fc); | ||
971 | |||
972 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
973 | memset(meta, 0, sizeof(*meta)); | ||
974 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
975 | meta->iface = iface; | ||
976 | meta->tx_cb_idx = tx_cb_idx; | ||
977 | |||
978 | skb->dev = dev; | ||
979 | skb->mac.raw = skb->nh.raw = skb->data; | ||
980 | dev_queue_xmit(skb); | ||
981 | } | ||
982 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
983 | |||
984 | |||
985 | static int prism2_sta_proc_read(char *page, char **start, off_t off, | ||
986 | int count, int *eof, void *data) | ||
987 | { | ||
988 | char *p = page; | ||
989 | struct sta_info *sta = (struct sta_info *) data; | ||
990 | int i; | ||
991 | |||
992 | /* FIX: possible race condition.. the STA data could have just expired, | ||
993 | * but proc entry was still here so that the read could have started; | ||
994 | * some locking should be done here.. */ | ||
995 | |||
996 | if (off != 0) { | ||
997 | *eof = 1; | ||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" | ||
1002 | "flags=0x%04x%s%s%s%s%s%s%s\n" | ||
1003 | "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", | ||
1004 | sta->ap ? "AP" : "STA", | ||
1005 | MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, | ||
1006 | sta->flags, | ||
1007 | sta->flags & WLAN_STA_AUTH ? " AUTH" : "", | ||
1008 | sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", | ||
1009 | sta->flags & WLAN_STA_PS ? " PS" : "", | ||
1010 | sta->flags & WLAN_STA_TIM ? " TIM" : "", | ||
1011 | sta->flags & WLAN_STA_PERM ? " PERM" : "", | ||
1012 | sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", | ||
1013 | sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", | ||
1014 | sta->capability, sta->listen_interval); | ||
1015 | /* supported_rates: 500 kbit/s units with msb ignored */ | ||
1016 | for (i = 0; i < sizeof(sta->supported_rates); i++) | ||
1017 | if (sta->supported_rates[i] != 0) | ||
1018 | p += sprintf(p, "%d%sMbps ", | ||
1019 | (sta->supported_rates[i] & 0x7f) / 2, | ||
1020 | sta->supported_rates[i] & 1 ? ".5" : ""); | ||
1021 | p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" | ||
1022 | "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" | ||
1023 | "tx_packets=%lu\n" | ||
1024 | "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" | ||
1025 | "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" | ||
1026 | "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" | ||
1027 | "tx[11M]=%d\n" | ||
1028 | "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", | ||
1029 | jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, | ||
1030 | sta->last_tx, | ||
1031 | sta->rx_packets, sta->tx_packets, sta->rx_bytes, | ||
1032 | sta->tx_bytes, skb_queue_len(&sta->tx_buf), | ||
1033 | sta->last_rx_silence, | ||
1034 | sta->last_rx_signal, sta->last_rx_rate / 10, | ||
1035 | sta->last_rx_rate % 10 ? ".5" : "", | ||
1036 | sta->tx_rate, sta->tx_count[0], sta->tx_count[1], | ||
1037 | sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], | ||
1038 | sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); | ||
1039 | if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) | ||
1040 | p = sta->crypt->ops->print_stats(p, sta->crypt->priv); | ||
1041 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1042 | if (sta->ap) { | ||
1043 | if (sta->u.ap.channel >= 0) | ||
1044 | p += sprintf(p, "channel=%d\n", sta->u.ap.channel); | ||
1045 | p += sprintf(p, "ssid="); | ||
1046 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
1047 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
1048 | sta->u.ap.ssid[i] < 127) ? | ||
1049 | "%c" : "<%02x>"), | ||
1050 | sta->u.ap.ssid[i]); | ||
1051 | p += sprintf(p, "\n"); | ||
1052 | } | ||
1053 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1054 | |||
1055 | return (p - page); | ||
1056 | } | ||
1057 | |||
1058 | |||
1059 | static void handle_add_proc_queue(void *data) | ||
1060 | { | ||
1061 | struct ap_data *ap = (struct ap_data *) data; | ||
1062 | struct sta_info *sta; | ||
1063 | char name[20]; | ||
1064 | struct add_sta_proc_data *entry, *prev; | ||
1065 | |||
1066 | entry = ap->add_sta_proc_entries; | ||
1067 | ap->add_sta_proc_entries = NULL; | ||
1068 | |||
1069 | while (entry) { | ||
1070 | spin_lock_bh(&ap->sta_table_lock); | ||
1071 | sta = ap_get_sta(ap, entry->addr); | ||
1072 | if (sta) | ||
1073 | atomic_inc(&sta->users); | ||
1074 | spin_unlock_bh(&ap->sta_table_lock); | ||
1075 | |||
1076 | if (sta) { | ||
1077 | sprintf(name, MACSTR, MAC2STR(sta->addr)); | ||
1078 | sta->proc = create_proc_read_entry( | ||
1079 | name, 0, ap->proc, | ||
1080 | prism2_sta_proc_read, sta); | ||
1081 | |||
1082 | atomic_dec(&sta->users); | ||
1083 | } | ||
1084 | |||
1085 | prev = entry; | ||
1086 | entry = entry->next; | ||
1087 | kfree(prev); | ||
1088 | } | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) | ||
1093 | { | ||
1094 | struct sta_info *sta; | ||
1095 | |||
1096 | sta = (struct sta_info *) | ||
1097 | kmalloc(sizeof(struct sta_info), GFP_ATOMIC); | ||
1098 | if (sta == NULL) { | ||
1099 | PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); | ||
1100 | return NULL; | ||
1101 | } | ||
1102 | |||
1103 | /* initialize STA info data */ | ||
1104 | memset(sta, 0, sizeof(struct sta_info)); | ||
1105 | sta->local = ap->local; | ||
1106 | skb_queue_head_init(&sta->tx_buf); | ||
1107 | memcpy(sta->addr, addr, ETH_ALEN); | ||
1108 | |||
1109 | atomic_inc(&sta->users); | ||
1110 | spin_lock_bh(&ap->sta_table_lock); | ||
1111 | list_add(&sta->list, &ap->sta_list); | ||
1112 | ap->num_sta++; | ||
1113 | ap_sta_hash_add(ap, sta); | ||
1114 | spin_unlock_bh(&ap->sta_table_lock); | ||
1115 | |||
1116 | if (ap->proc) { | ||
1117 | struct add_sta_proc_data *entry; | ||
1118 | /* schedule a non-interrupt context process to add a procfs | ||
1119 | * entry for the STA since procfs code use GFP_KERNEL */ | ||
1120 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
1121 | if (entry) { | ||
1122 | memcpy(entry->addr, sta->addr, ETH_ALEN); | ||
1123 | entry->next = ap->add_sta_proc_entries; | ||
1124 | ap->add_sta_proc_entries = entry; | ||
1125 | schedule_work(&ap->add_sta_proc_queue); | ||
1126 | } else | ||
1127 | printk(KERN_DEBUG "Failed to add STA proc data\n"); | ||
1128 | } | ||
1129 | |||
1130 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1131 | init_timer(&sta->timer); | ||
1132 | sta->timer.expires = jiffies + ap->max_inactivity; | ||
1133 | sta->timer.data = (unsigned long) sta; | ||
1134 | sta->timer.function = ap_handle_timer; | ||
1135 | if (!ap->local->hostapd) | ||
1136 | add_timer(&sta->timer); | ||
1137 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1138 | |||
1139 | return sta; | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, | ||
1144 | local_info_t *local) | ||
1145 | { | ||
1146 | if (rateidx > sta->tx_max_rate || | ||
1147 | !(sta->tx_supp_rates & (1 << rateidx))) | ||
1148 | return 0; | ||
1149 | |||
1150 | if (local->tx_rate_control != 0 && | ||
1151 | !(local->tx_rate_control & (1 << rateidx))) | ||
1152 | return 0; | ||
1153 | |||
1154 | return 1; | ||
1155 | } | ||
1156 | |||
1157 | |||
1158 | static void prism2_check_tx_rates(struct sta_info *sta) | ||
1159 | { | ||
1160 | int i; | ||
1161 | |||
1162 | sta->tx_supp_rates = 0; | ||
1163 | for (i = 0; i < sizeof(sta->supported_rates); i++) { | ||
1164 | if ((sta->supported_rates[i] & 0x7f) == 2) | ||
1165 | sta->tx_supp_rates |= WLAN_RATE_1M; | ||
1166 | if ((sta->supported_rates[i] & 0x7f) == 4) | ||
1167 | sta->tx_supp_rates |= WLAN_RATE_2M; | ||
1168 | if ((sta->supported_rates[i] & 0x7f) == 11) | ||
1169 | sta->tx_supp_rates |= WLAN_RATE_5M5; | ||
1170 | if ((sta->supported_rates[i] & 0x7f) == 22) | ||
1171 | sta->tx_supp_rates |= WLAN_RATE_11M; | ||
1172 | } | ||
1173 | sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; | ||
1174 | if (sta->tx_supp_rates & WLAN_RATE_1M) { | ||
1175 | sta->tx_max_rate = 0; | ||
1176 | if (ap_tx_rate_ok(0, sta, sta->local)) { | ||
1177 | sta->tx_rate = 10; | ||
1178 | sta->tx_rate_idx = 0; | ||
1179 | } | ||
1180 | } | ||
1181 | if (sta->tx_supp_rates & WLAN_RATE_2M) { | ||
1182 | sta->tx_max_rate = 1; | ||
1183 | if (ap_tx_rate_ok(1, sta, sta->local)) { | ||
1184 | sta->tx_rate = 20; | ||
1185 | sta->tx_rate_idx = 1; | ||
1186 | } | ||
1187 | } | ||
1188 | if (sta->tx_supp_rates & WLAN_RATE_5M5) { | ||
1189 | sta->tx_max_rate = 2; | ||
1190 | if (ap_tx_rate_ok(2, sta, sta->local)) { | ||
1191 | sta->tx_rate = 55; | ||
1192 | sta->tx_rate_idx = 2; | ||
1193 | } | ||
1194 | } | ||
1195 | if (sta->tx_supp_rates & WLAN_RATE_11M) { | ||
1196 | sta->tx_max_rate = 3; | ||
1197 | if (ap_tx_rate_ok(3, sta, sta->local)) { | ||
1198 | sta->tx_rate = 110; | ||
1199 | sta->tx_rate_idx = 3; | ||
1200 | } | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | |||
1205 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1206 | |||
1207 | static void ap_crypt_init(struct ap_data *ap) | ||
1208 | { | ||
1209 | ap->crypt = hostap_get_crypto_ops("WEP"); | ||
1210 | |||
1211 | if (ap->crypt) { | ||
1212 | if (ap->crypt->init) { | ||
1213 | ap->crypt_priv = ap->crypt->init(0); | ||
1214 | if (ap->crypt_priv == NULL) | ||
1215 | ap->crypt = NULL; | ||
1216 | else { | ||
1217 | u8 key[WEP_KEY_LEN]; | ||
1218 | get_random_bytes(key, WEP_KEY_LEN); | ||
1219 | ap->crypt->set_key(key, WEP_KEY_LEN, NULL, | ||
1220 | ap->crypt_priv); | ||
1221 | } | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | if (ap->crypt == NULL) { | ||
1226 | printk(KERN_WARNING "AP could not initialize WEP: load module " | ||
1227 | "hostap_crypt_wep.o\n"); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | |||
1232 | /* Generate challenge data for shared key authentication. IEEE 802.11 specifies | ||
1233 | * that WEP algorithm is used for generating challange. This should be unique, | ||
1234 | * but otherwise there is not really need for randomness etc. Initialize WEP | ||
1235 | * with pseudo random key and then use increasing IV to get unique challenge | ||
1236 | * streams. | ||
1237 | * | ||
1238 | * Called only as a scheduled task for pending AP frames. | ||
1239 | */ | ||
1240 | static char * ap_auth_make_challenge(struct ap_data *ap) | ||
1241 | { | ||
1242 | char *tmpbuf; | ||
1243 | struct sk_buff *skb; | ||
1244 | |||
1245 | if (ap->crypt == NULL) { | ||
1246 | ap_crypt_init(ap); | ||
1247 | if (ap->crypt == NULL) | ||
1248 | return NULL; | ||
1249 | } | ||
1250 | |||
1251 | tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); | ||
1252 | if (tmpbuf == NULL) { | ||
1253 | PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); | ||
1254 | return NULL; | ||
1255 | } | ||
1256 | |||
1257 | skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + | ||
1258 | ap->crypt->extra_prefix_len + | ||
1259 | ap->crypt->extra_postfix_len); | ||
1260 | if (skb == NULL) { | ||
1261 | kfree(tmpbuf); | ||
1262 | return NULL; | ||
1263 | } | ||
1264 | |||
1265 | skb_reserve(skb, ap->crypt->extra_prefix_len); | ||
1266 | memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, | ||
1267 | WLAN_AUTH_CHALLENGE_LEN); | ||
1268 | if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { | ||
1269 | dev_kfree_skb(skb); | ||
1270 | kfree(tmpbuf); | ||
1271 | return NULL; | ||
1272 | } | ||
1273 | |||
1274 | memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, | ||
1275 | WLAN_AUTH_CHALLENGE_LEN); | ||
1276 | dev_kfree_skb(skb); | ||
1277 | |||
1278 | return tmpbuf; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | /* Called only as a scheduled task for pending AP frames. */ | ||
1283 | static void handle_authen(local_info_t *local, struct sk_buff *skb, | ||
1284 | struct hostap_80211_rx_status *rx_stats) | ||
1285 | { | ||
1286 | struct net_device *dev = local->dev; | ||
1287 | struct hostap_ieee80211_hdr *hdr = | ||
1288 | (struct hostap_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 prism2_crypt_data *crypt; | ||
1297 | char *txt = ""; | ||
1298 | |||
1299 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1300 | |||
1301 | fc = le16_to_cpu(hdr->frame_control); | ||
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 & WLAN_FC_ISWEP)) { | ||
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, WLAN_FC_TYPE_MGMT, WLAN_FC_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 hostap_ieee80211_hdr *hdr = | ||
1502 | (struct hostap_ieee80211_hdr *) skb->data; | ||
1503 | char body[12], *p, *lpos; | ||
1504 | int len, left; | ||
1505 | u16 *pos; | ||
1506 | u16 resp = WLAN_STATUS_SUCCESS; | ||
1507 | struct sta_info *sta = NULL; | ||
1508 | int send_deauth = 0; | ||
1509 | char *txt = ""; | ||
1510 | u8 prev_ap[ETH_ALEN]; | ||
1511 | |||
1512 | left = len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1513 | |||
1514 | if (len < (reassoc ? 10 : 4)) { | ||
1515 | PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " | ||
1516 | "(len=%d, reassoc=%d) from " MACSTR "\n", | ||
1517 | dev->name, len, reassoc, MAC2STR(hdr->addr2)); | ||
1518 | return; | ||
1519 | } | ||
1520 | |||
1521 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1522 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1523 | if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { | ||
1524 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1525 | txt = "trying to associate before authentication"; | ||
1526 | send_deauth = 1; | ||
1527 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1528 | sta = NULL; /* do not decrement sta->users */ | ||
1529 | goto fail; | ||
1530 | } | ||
1531 | atomic_inc(&sta->users); | ||
1532 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1533 | |||
1534 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1535 | sta->capability = __le16_to_cpu(*pos); | ||
1536 | pos++; left -= 2; | ||
1537 | sta->listen_interval = __le16_to_cpu(*pos); | ||
1538 | pos++; left -= 2; | ||
1539 | |||
1540 | if (reassoc) { | ||
1541 | memcpy(prev_ap, pos, ETH_ALEN); | ||
1542 | pos++; pos++; pos++; left -= 6; | ||
1543 | } else | ||
1544 | memset(prev_ap, 0, ETH_ALEN); | ||
1545 | |||
1546 | if (left >= 2) { | ||
1547 | unsigned int ileft; | ||
1548 | unsigned char *u = (unsigned char *) pos; | ||
1549 | |||
1550 | if (*u == WLAN_EID_SSID) { | ||
1551 | u++; left--; | ||
1552 | ileft = *u; | ||
1553 | u++; left--; | ||
1554 | |||
1555 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
1556 | txt = "SSID overflow"; | ||
1557 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1558 | goto fail; | ||
1559 | } | ||
1560 | |||
1561 | if (ileft != strlen(local->essid) || | ||
1562 | memcmp(local->essid, u, ileft) != 0) { | ||
1563 | txt = "not our SSID"; | ||
1564 | resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||
1565 | goto fail; | ||
1566 | } | ||
1567 | |||
1568 | u += ileft; | ||
1569 | left -= ileft; | ||
1570 | } | ||
1571 | |||
1572 | if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { | ||
1573 | u++; left--; | ||
1574 | ileft = *u; | ||
1575 | u++; left--; | ||
1576 | |||
1577 | if (ileft > left || ileft == 0 || | ||
1578 | ileft > WLAN_SUPP_RATES_MAX) { | ||
1579 | txt = "SUPP_RATES len error"; | ||
1580 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1581 | goto fail; | ||
1582 | } | ||
1583 | |||
1584 | memset(sta->supported_rates, 0, | ||
1585 | sizeof(sta->supported_rates)); | ||
1586 | memcpy(sta->supported_rates, u, ileft); | ||
1587 | prism2_check_tx_rates(sta); | ||
1588 | |||
1589 | u += ileft; | ||
1590 | left -= ileft; | ||
1591 | } | ||
1592 | |||
1593 | if (left > 0) { | ||
1594 | PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" | ||
1595 | " data (%d bytes) [", | ||
1596 | dev->name, MAC2STR(hdr->addr2), left); | ||
1597 | while (left > 0) { | ||
1598 | PDEBUG2(DEBUG_AP, "<%02x>", *u); | ||
1599 | u++; left--; | ||
1600 | } | ||
1601 | PDEBUG2(DEBUG_AP, "]\n"); | ||
1602 | } | ||
1603 | } else { | ||
1604 | txt = "frame underflow"; | ||
1605 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1606 | goto fail; | ||
1607 | } | ||
1608 | |||
1609 | /* get a unique AID */ | ||
1610 | if (sta->aid > 0) | ||
1611 | txt = "OK, old AID"; | ||
1612 | else { | ||
1613 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1614 | for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) | ||
1615 | if (local->ap->sta_aid[sta->aid - 1] == NULL) | ||
1616 | break; | ||
1617 | if (sta->aid > MAX_AID_TABLE_SIZE) { | ||
1618 | sta->aid = 0; | ||
1619 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1620 | resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; | ||
1621 | txt = "no room for more AIDs"; | ||
1622 | } else { | ||
1623 | local->ap->sta_aid[sta->aid - 1] = sta; | ||
1624 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1625 | txt = "OK, new AID"; | ||
1626 | } | ||
1627 | } | ||
1628 | |||
1629 | fail: | ||
1630 | pos = (u16 *) body; | ||
1631 | |||
1632 | if (send_deauth) { | ||
1633 | *pos = __constant_cpu_to_le16( | ||
1634 | WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); | ||
1635 | pos++; | ||
1636 | } else { | ||
1637 | /* FIX: CF-Pollable and CF-PollReq should be set to match the | ||
1638 | * values in beacons/probe responses */ | ||
1639 | /* FIX: how about privacy and WEP? */ | ||
1640 | /* capability */ | ||
1641 | *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
1642 | pos++; | ||
1643 | |||
1644 | /* status_code */ | ||
1645 | *pos = __cpu_to_le16(resp); | ||
1646 | pos++; | ||
1647 | |||
1648 | *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | | ||
1649 | BIT(14) | BIT(15)); /* AID */ | ||
1650 | pos++; | ||
1651 | |||
1652 | /* Supported rates (Information element) */ | ||
1653 | p = (char *) pos; | ||
1654 | *p++ = WLAN_EID_SUPP_RATES; | ||
1655 | lpos = p; | ||
1656 | *p++ = 0; /* len */ | ||
1657 | if (local->tx_rate_control & WLAN_RATE_1M) { | ||
1658 | *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; | ||
1659 | (*lpos)++; | ||
1660 | } | ||
1661 | if (local->tx_rate_control & WLAN_RATE_2M) { | ||
1662 | *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; | ||
1663 | (*lpos)++; | ||
1664 | } | ||
1665 | if (local->tx_rate_control & WLAN_RATE_5M5) { | ||
1666 | *p++ = local->basic_rates & WLAN_RATE_5M5 ? | ||
1667 | 0x8b : 0x0b; | ||
1668 | (*lpos)++; | ||
1669 | } | ||
1670 | if (local->tx_rate_control & WLAN_RATE_11M) { | ||
1671 | *p++ = local->basic_rates & WLAN_RATE_11M ? | ||
1672 | 0x96 : 0x16; | ||
1673 | (*lpos)++; | ||
1674 | } | ||
1675 | pos = (u16 *) p; | ||
1676 | } | ||
1677 | |||
1678 | prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, | ||
1679 | (send_deauth ? WLAN_FC_STYPE_DEAUTH : | ||
1680 | (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : | ||
1681 | WLAN_FC_STYPE_ASSOC_RESP)), | ||
1682 | body, (u8 *) pos - (u8 *) body, | ||
1683 | hdr->addr2, | ||
1684 | send_deauth ? 0 : local->ap->tx_callback_assoc); | ||
1685 | |||
1686 | if (sta) { | ||
1687 | if (resp == WLAN_STATUS_SUCCESS) { | ||
1688 | sta->last_rx = jiffies; | ||
1689 | /* STA will be marked associated from TX callback, if | ||
1690 | * AssocResp is ACKed */ | ||
1691 | } | ||
1692 | atomic_dec(&sta->users); | ||
1693 | } | ||
1694 | |||
1695 | #if 0 | ||
1696 | PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR | ||
1697 | ") => %d(%d) (%s)\n", | ||
1698 | dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, | ||
1699 | MAC2STR(prev_ap), resp, send_deauth, txt); | ||
1700 | #endif | ||
1701 | } | ||
1702 | |||
1703 | |||
1704 | /* Called only as a scheduled task for pending AP frames. */ | ||
1705 | static void handle_deauth(local_info_t *local, struct sk_buff *skb, | ||
1706 | struct hostap_80211_rx_status *rx_stats) | ||
1707 | { | ||
1708 | struct net_device *dev = local->dev; | ||
1709 | struct hostap_ieee80211_hdr *hdr = | ||
1710 | (struct hostap_ieee80211_hdr *) skb->data; | ||
1711 | char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1712 | int len; | ||
1713 | u16 reason_code, *pos; | ||
1714 | struct sta_info *sta = NULL; | ||
1715 | |||
1716 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1717 | |||
1718 | if (len < 2) { | ||
1719 | printk("handle_deauth - too short payload (len=%d)\n", len); | ||
1720 | return; | ||
1721 | } | ||
1722 | |||
1723 | pos = (u16 *) body; | ||
1724 | reason_code = __le16_to_cpu(*pos); | ||
1725 | |||
1726 | PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " | ||
1727 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1728 | reason_code); | ||
1729 | |||
1730 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1731 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1732 | if (sta != NULL) { | ||
1733 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1734 | hostap_event_expired_sta(local->dev, sta); | ||
1735 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | ||
1736 | } | ||
1737 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1738 | if (sta == NULL) { | ||
1739 | printk("%s: deauthentication from " MACSTR ", " | ||
1740 | "reason_code=%d, but STA not authenticated\n", dev->name, | ||
1741 | MAC2STR(hdr->addr2), reason_code); | ||
1742 | } | ||
1743 | } | ||
1744 | |||
1745 | |||
1746 | /* Called only as a scheduled task for pending AP frames. */ | ||
1747 | static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | ||
1748 | struct hostap_80211_rx_status *rx_stats) | ||
1749 | { | ||
1750 | struct net_device *dev = local->dev; | ||
1751 | struct hostap_ieee80211_hdr *hdr = | ||
1752 | (struct hostap_ieee80211_hdr *) skb->data; | ||
1753 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1754 | int len; | ||
1755 | u16 reason_code, *pos; | ||
1756 | struct sta_info *sta = NULL; | ||
1757 | |||
1758 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1759 | |||
1760 | if (len < 2) { | ||
1761 | printk("handle_disassoc - too short payload (len=%d)\n", len); | ||
1762 | return; | ||
1763 | } | ||
1764 | |||
1765 | pos = (u16 *) body; | ||
1766 | reason_code = __le16_to_cpu(*pos); | ||
1767 | |||
1768 | PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " | ||
1769 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1770 | reason_code); | ||
1771 | |||
1772 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1773 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1774 | if (sta != NULL) { | ||
1775 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1776 | hostap_event_expired_sta(local->dev, sta); | ||
1777 | sta->flags &= ~WLAN_STA_ASSOC; | ||
1778 | } | ||
1779 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1780 | if (sta == NULL) { | ||
1781 | printk("%s: disassociation from " MACSTR ", " | ||
1782 | "reason_code=%d, but STA not authenticated\n", | ||
1783 | dev->name, MAC2STR(hdr->addr2), reason_code); | ||
1784 | } | ||
1785 | } | ||
1786 | |||
1787 | |||
1788 | /* Called only as a scheduled task for pending AP frames. */ | ||
1789 | static void ap_handle_data_nullfunc(local_info_t *local, | ||
1790 | struct hostap_ieee80211_hdr *hdr) | ||
1791 | { | ||
1792 | struct net_device *dev = local->dev; | ||
1793 | |||
1794 | /* some STA f/w's seem to require control::ACK frame for | ||
1795 | * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does | ||
1796 | * not send this.. | ||
1797 | * send control::ACK for the data::nullfunc */ | ||
1798 | |||
1799 | printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); | ||
1800 | prism2_send_mgmt(dev, WLAN_FC_TYPE_CTRL, WLAN_FC_STYPE_ACK, | ||
1801 | NULL, 0, hdr->addr2, 0); | ||
1802 | } | ||
1803 | |||
1804 | |||
1805 | /* Called only as a scheduled task for pending AP frames. */ | ||
1806 | static void ap_handle_dropped_data(local_info_t *local, | ||
1807 | struct hostap_ieee80211_hdr *hdr) | ||
1808 | { | ||
1809 | struct net_device *dev = local->dev; | ||
1810 | struct sta_info *sta; | ||
1811 | u16 reason; | ||
1812 | |||
1813 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1814 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1815 | if (sta) | ||
1816 | atomic_inc(&sta->users); | ||
1817 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1818 | |||
1819 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { | ||
1820 | PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); | ||
1821 | atomic_dec(&sta->users); | ||
1822 | return; | ||
1823 | } | ||
1824 | |||
1825 | reason = __constant_cpu_to_le16( | ||
1826 | WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | ||
1827 | prism2_send_mgmt(dev, WLAN_FC_TYPE_MGMT, | ||
1828 | ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? | ||
1829 | WLAN_FC_STYPE_DEAUTH : WLAN_FC_STYPE_DISASSOC), | ||
1830 | (char *) &reason, sizeof(reason), hdr->addr2, 0); | ||
1831 | |||
1832 | if (sta) | ||
1833 | atomic_dec(&sta->users); | ||
1834 | } | ||
1835 | |||
1836 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1837 | |||
1838 | |||
1839 | /* Called only as a scheduled task for pending AP frames. */ | ||
1840 | static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, | ||
1841 | struct sk_buff *skb) | ||
1842 | { | ||
1843 | if (!(sta->flags & WLAN_STA_PS)) { | ||
1844 | /* Station has moved to non-PS mode, so send all buffered | ||
1845 | * frames using normal device queue. */ | ||
1846 | dev_queue_xmit(skb); | ||
1847 | return; | ||
1848 | } | ||
1849 | |||
1850 | /* add a flag for hostap_handle_sta_tx() to know that this skb should | ||
1851 | * be passed through even though STA is using PS */ | ||
1852 | memcpy(skb->cb, AP_SKB_CB_MAGIC, AP_SKB_CB_MAGIC_LEN); | ||
1853 | skb->cb[AP_SKB_CB_MAGIC_LEN] = AP_SKB_CB_BUFFERED_FRAME; | ||
1854 | if (!skb_queue_empty(&sta->tx_buf)) { | ||
1855 | /* indicate to STA that more frames follow */ | ||
1856 | skb->cb[AP_SKB_CB_MAGIC_LEN] |= AP_SKB_CB_ADD_MOREDATA; | ||
1857 | } | ||
1858 | dev_queue_xmit(skb); | ||
1859 | } | ||
1860 | |||
1861 | |||
1862 | /* Called only as a scheduled task for pending AP frames. */ | ||
1863 | static void handle_pspoll(local_info_t *local, | ||
1864 | struct hostap_ieee80211_hdr *hdr, | ||
1865 | struct hostap_80211_rx_status *rx_stats) | ||
1866 | { | ||
1867 | struct net_device *dev = local->dev; | ||
1868 | struct sta_info *sta; | ||
1869 | u16 aid; | ||
1870 | struct sk_buff *skb; | ||
1871 | |||
1872 | PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR | ||
1873 | " PWRMGT=%d\n", | ||
1874 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | ||
1875 | !!(le16_to_cpu(hdr->frame_control) & WLAN_FC_PWRMGT)); | ||
1876 | |||
1877 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
1878 | PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR | ||
1879 | " not own MAC\n", MAC2STR(hdr->addr1)); | ||
1880 | return; | ||
1881 | } | ||
1882 | |||
1883 | aid = __le16_to_cpu(hdr->duration_id); | ||
1884 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { | ||
1885 | PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); | ||
1886 | return; | ||
1887 | } | ||
1888 | aid &= ~BIT(15) & ~BIT(14); | ||
1889 | if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { | ||
1890 | PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); | ||
1891 | return; | ||
1892 | } | ||
1893 | PDEBUG(DEBUG_PS2, " aid=%d\n", aid); | ||
1894 | |||
1895 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1896 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1897 | if (sta) | ||
1898 | atomic_inc(&sta->users); | ||
1899 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1900 | |||
1901 | if (sta == NULL) { | ||
1902 | PDEBUG(DEBUG_PS, " STA not found\n"); | ||
1903 | return; | ||
1904 | } | ||
1905 | if (sta->aid != aid) { | ||
1906 | PDEBUG(DEBUG_PS, " received aid=%i does not match with " | ||
1907 | "assoc.aid=%d\n", aid, sta->aid); | ||
1908 | return; | ||
1909 | } | ||
1910 | |||
1911 | /* FIX: todo: | ||
1912 | * - add timeout for buffering (clear aid in TIM vector if buffer timed | ||
1913 | * out (expiry time must be longer than ListenInterval for | ||
1914 | * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" | ||
1915 | * - what to do, if buffered, pspolled, and sent frame is not ACKed by | ||
1916 | * sta; store buffer for later use and leave TIM aid bit set? use | ||
1917 | * TX event to check whether frame was ACKed? | ||
1918 | */ | ||
1919 | |||
1920 | while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { | ||
1921 | /* send buffered frame .. */ | ||
1922 | PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" | ||
1923 | " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); | ||
1924 | |||
1925 | pspoll_send_buffered(local, sta, skb); | ||
1926 | |||
1927 | if (sta->flags & WLAN_STA_PS) { | ||
1928 | /* send only one buffered packet per PS Poll */ | ||
1929 | /* FIX: should ignore further PS Polls until the | ||
1930 | * buffered packet that was just sent is acknowledged | ||
1931 | * (Tx or TxExc event) */ | ||
1932 | break; | ||
1933 | } | ||
1934 | } | ||
1935 | |||
1936 | if (skb_queue_empty(&sta->tx_buf)) { | ||
1937 | /* try to clear aid from TIM */ | ||
1938 | if (!(sta->flags & WLAN_STA_TIM)) | ||
1939 | PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", | ||
1940 | aid); | ||
1941 | hostap_set_tim(local, aid, 0); | ||
1942 | sta->flags &= ~WLAN_STA_TIM; | ||
1943 | } | ||
1944 | |||
1945 | atomic_dec(&sta->users); | ||
1946 | } | ||
1947 | |||
1948 | |||
1949 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1950 | |||
1951 | static void handle_wds_oper_queue(void *data) | ||
1952 | { | ||
1953 | local_info_t *local = data; | ||
1954 | struct wds_oper_data *entry, *prev; | ||
1955 | |||
1956 | spin_lock_bh(&local->lock); | ||
1957 | entry = local->ap->wds_oper_entries; | ||
1958 | local->ap->wds_oper_entries = NULL; | ||
1959 | spin_unlock_bh(&local->lock); | ||
1960 | |||
1961 | while (entry) { | ||
1962 | PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " | ||
1963 | "to AP " MACSTR "\n", | ||
1964 | local->dev->name, | ||
1965 | entry->type == WDS_ADD ? "adding" : "removing", | ||
1966 | MAC2STR(entry->addr)); | ||
1967 | if (entry->type == WDS_ADD) | ||
1968 | prism2_wds_add(local, entry->addr, 0); | ||
1969 | else if (entry->type == WDS_DEL) | ||
1970 | prism2_wds_del(local, entry->addr, 0, 1); | ||
1971 | |||
1972 | prev = entry; | ||
1973 | entry = entry->next; | ||
1974 | kfree(prev); | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1978 | |||
1979 | /* Called only as a scheduled task for pending AP frames. */ | ||
1980 | static void handle_beacon(local_info_t *local, struct sk_buff *skb, | ||
1981 | struct hostap_80211_rx_status *rx_stats) | ||
1982 | { | ||
1983 | struct hostap_ieee80211_hdr *hdr = | ||
1984 | (struct hostap_ieee80211_hdr *) skb->data; | ||
1985 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1986 | int len, left; | ||
1987 | u16 *pos, beacon_int, capability; | ||
1988 | char *ssid = NULL; | ||
1989 | unsigned char *supp_rates = NULL; | ||
1990 | int ssid_len = 0, supp_rates_len = 0; | ||
1991 | struct sta_info *sta = NULL; | ||
1992 | int new_sta = 0, channel = -1; | ||
1993 | |||
1994 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1995 | |||
1996 | if (len < 8 + 2 + 2) { | ||
1997 | printk(KERN_DEBUG "handle_beacon - too short payload " | ||
1998 | "(len=%d)\n", len); | ||
1999 | return; | ||
2000 | } | ||
2001 | |||
2002 | pos = (u16 *) body; | ||
2003 | left = len; | ||
2004 | |||
2005 | /* Timestamp (8 octets) */ | ||
2006 | pos += 4; left -= 8; | ||
2007 | /* Beacon interval (2 octets) */ | ||
2008 | beacon_int = __le16_to_cpu(*pos); | ||
2009 | pos++; left -= 2; | ||
2010 | /* Capability information (2 octets) */ | ||
2011 | capability = __le16_to_cpu(*pos); | ||
2012 | pos++; left -= 2; | ||
2013 | |||
2014 | if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && | ||
2015 | capability & WLAN_CAPABILITY_IBSS) | ||
2016 | return; | ||
2017 | |||
2018 | if (left >= 2) { | ||
2019 | unsigned int ileft; | ||
2020 | unsigned char *u = (unsigned char *) pos; | ||
2021 | |||
2022 | if (*u == WLAN_EID_SSID) { | ||
2023 | u++; left--; | ||
2024 | ileft = *u; | ||
2025 | u++; left--; | ||
2026 | |||
2027 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
2028 | PDEBUG(DEBUG_AP, "SSID: overflow\n"); | ||
2029 | return; | ||
2030 | } | ||
2031 | |||
2032 | if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && | ||
2033 | (ileft != strlen(local->essid) || | ||
2034 | memcmp(local->essid, u, ileft) != 0)) { | ||
2035 | /* not our SSID */ | ||
2036 | return; | ||
2037 | } | ||
2038 | |||
2039 | ssid = u; | ||
2040 | ssid_len = ileft; | ||
2041 | |||
2042 | u += ileft; | ||
2043 | left -= ileft; | ||
2044 | } | ||
2045 | |||
2046 | if (*u == WLAN_EID_SUPP_RATES) { | ||
2047 | u++; left--; | ||
2048 | ileft = *u; | ||
2049 | u++; left--; | ||
2050 | |||
2051 | if (ileft > left || ileft == 0 || ileft > 8) { | ||
2052 | PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); | ||
2053 | return; | ||
2054 | } | ||
2055 | |||
2056 | supp_rates = u; | ||
2057 | supp_rates_len = ileft; | ||
2058 | |||
2059 | u += ileft; | ||
2060 | left -= ileft; | ||
2061 | } | ||
2062 | |||
2063 | if (*u == WLAN_EID_DS_PARAMS) { | ||
2064 | u++; left--; | ||
2065 | ileft = *u; | ||
2066 | u++; left--; | ||
2067 | |||
2068 | if (ileft > left || ileft != 1) { | ||
2069 | PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); | ||
2070 | return; | ||
2071 | } | ||
2072 | |||
2073 | channel = *u; | ||
2074 | |||
2075 | u += ileft; | ||
2076 | left -= ileft; | ||
2077 | } | ||
2078 | } | ||
2079 | |||
2080 | spin_lock_bh(&local->ap->sta_table_lock); | ||
2081 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2082 | if (sta != NULL) | ||
2083 | atomic_inc(&sta->users); | ||
2084 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
2085 | |||
2086 | if (sta == NULL) { | ||
2087 | /* add new AP */ | ||
2088 | new_sta = 1; | ||
2089 | sta = ap_add_sta(local->ap, hdr->addr2); | ||
2090 | if (sta == NULL) { | ||
2091 | printk(KERN_INFO "prism2: kmalloc failed for AP " | ||
2092 | "data structure\n"); | ||
2093 | return; | ||
2094 | } | ||
2095 | hostap_event_new_sta(local->dev, sta); | ||
2096 | |||
2097 | /* mark APs authentication and associated for pseudo ad-hoc | ||
2098 | * style communication */ | ||
2099 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2100 | |||
2101 | if (local->ap->autom_ap_wds) { | ||
2102 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
2103 | } | ||
2104 | } | ||
2105 | |||
2106 | sta->ap = 1; | ||
2107 | if (ssid) { | ||
2108 | sta->u.ap.ssid_len = ssid_len; | ||
2109 | memcpy(sta->u.ap.ssid, ssid, ssid_len); | ||
2110 | sta->u.ap.ssid[ssid_len] = '\0'; | ||
2111 | } else { | ||
2112 | sta->u.ap.ssid_len = 0; | ||
2113 | sta->u.ap.ssid[0] = '\0'; | ||
2114 | } | ||
2115 | sta->u.ap.channel = channel; | ||
2116 | sta->rx_packets++; | ||
2117 | sta->rx_bytes += len; | ||
2118 | sta->u.ap.last_beacon = sta->last_rx = jiffies; | ||
2119 | sta->capability = capability; | ||
2120 | sta->listen_interval = beacon_int; | ||
2121 | |||
2122 | atomic_dec(&sta->users); | ||
2123 | |||
2124 | if (new_sta) { | ||
2125 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
2126 | memcpy(sta->supported_rates, supp_rates, supp_rates_len); | ||
2127 | prism2_check_tx_rates(sta); | ||
2128 | } | ||
2129 | } | ||
2130 | |||
2131 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2132 | |||
2133 | |||
2134 | /* Called only as a tasklet. */ | ||
2135 | static void handle_ap_item(local_info_t *local, struct sk_buff *skb, | ||
2136 | struct hostap_80211_rx_status *rx_stats) | ||
2137 | { | ||
2138 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2139 | struct net_device *dev = local->dev; | ||
2140 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2141 | u16 fc, type, stype; | ||
2142 | struct hostap_ieee80211_hdr *hdr; | ||
2143 | |||
2144 | /* FIX: should give skb->len to handler functions and check that the | ||
2145 | * buffer is long enough */ | ||
2146 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
2147 | fc = le16_to_cpu(hdr->frame_control); | ||
2148 | type = WLAN_FC_GET_TYPE(fc); | ||
2149 | stype = WLAN_FC_GET_STYPE(fc); | ||
2150 | |||
2151 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2152 | if (!local->hostapd && type == WLAN_FC_TYPE_DATA) { | ||
2153 | PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); | ||
2154 | |||
2155 | if (!(fc & WLAN_FC_TODS) || (fc & WLAN_FC_FROMDS)) { | ||
2156 | if (stype == WLAN_FC_STYPE_NULLFUNC) { | ||
2157 | /* no ToDS nullfunc seems to be used to check | ||
2158 | * AP association; so send reject message to | ||
2159 | * speed up re-association */ | ||
2160 | ap_handle_dropped_data(local, hdr); | ||
2161 | goto done; | ||
2162 | } | ||
2163 | PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", | ||
2164 | fc); | ||
2165 | goto done; | ||
2166 | } | ||
2167 | |||
2168 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
2169 | PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" | ||
2170 | MACSTR " not own MAC\n", | ||
2171 | MAC2STR(hdr->addr1)); | ||
2172 | goto done; | ||
2173 | } | ||
2174 | |||
2175 | if (local->ap->nullfunc_ack && stype == WLAN_FC_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 == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_BEACON) { | ||
2183 | handle_beacon(local, skb, rx_stats); | ||
2184 | goto done; | ||
2185 | } | ||
2186 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2187 | |||
2188 | if (type == WLAN_FC_TYPE_CTRL && stype == WLAN_FC_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 != WLAN_FC_TYPE_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 WLAN_FC_STYPE_ASSOC_REQ: | ||
2219 | handle_assoc(local, skb, rx_stats, 0); | ||
2220 | break; | ||
2221 | case WLAN_FC_STYPE_ASSOC_RESP: | ||
2222 | PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); | ||
2223 | break; | ||
2224 | case WLAN_FC_STYPE_REASSOC_REQ: | ||
2225 | handle_assoc(local, skb, rx_stats, 1); | ||
2226 | break; | ||
2227 | case WLAN_FC_STYPE_REASSOC_RESP: | ||
2228 | PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); | ||
2229 | break; | ||
2230 | case WLAN_FC_STYPE_ATIM: | ||
2231 | PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); | ||
2232 | break; | ||
2233 | case WLAN_FC_STYPE_DISASSOC: | ||
2234 | handle_disassoc(local, skb, rx_stats); | ||
2235 | break; | ||
2236 | case WLAN_FC_STYPE_AUTH: | ||
2237 | handle_authen(local, skb, rx_stats); | ||
2238 | break; | ||
2239 | case WLAN_FC_STYPE_DEAUTH: | ||
2240 | handle_deauth(local, skb, rx_stats); | ||
2241 | break; | ||
2242 | default: | ||
2243 | PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", stype); | ||
2244 | break; | ||
2245 | } | ||
2246 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2247 | |||
2248 | done: | ||
2249 | dev_kfree_skb(skb); | ||
2250 | } | ||
2251 | |||
2252 | |||
2253 | /* Called only as a tasklet (software IRQ) */ | ||
2254 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
2255 | struct hostap_80211_rx_status *rx_stats) | ||
2256 | { | ||
2257 | struct hostap_interface *iface; | ||
2258 | local_info_t *local; | ||
2259 | u16 fc; | ||
2260 | struct hostap_ieee80211_hdr *hdr; | ||
2261 | |||
2262 | iface = netdev_priv(dev); | ||
2263 | local = iface->local; | ||
2264 | |||
2265 | if (skb->len < 16) | ||
2266 | goto drop; | ||
2267 | |||
2268 | local->stats.rx_packets++; | ||
2269 | |||
2270 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
2271 | fc = le16_to_cpu(hdr->frame_control); | ||
2272 | |||
2273 | if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && | ||
2274 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && | ||
2275 | WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) | ||
2276 | goto drop; | ||
2277 | |||
2278 | skb->protocol = __constant_htons(ETH_P_HOSTAP); | ||
2279 | handle_ap_item(local, skb, rx_stats); | ||
2280 | return; | ||
2281 | |||
2282 | drop: | ||
2283 | dev_kfree_skb(skb); | ||
2284 | } | ||
2285 | |||
2286 | |||
2287 | /* Called only as a tasklet (software IRQ) */ | ||
2288 | static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | ||
2289 | { | ||
2290 | struct sk_buff *skb; | ||
2291 | struct hostap_ieee80211_hdr *hdr; | ||
2292 | struct hostap_80211_rx_status rx_stats; | ||
2293 | |||
2294 | if (skb_queue_empty(&sta->tx_buf)) | ||
2295 | return; | ||
2296 | |||
2297 | skb = dev_alloc_skb(16); | ||
2298 | if (skb == NULL) { | ||
2299 | printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " | ||
2300 | "failed\n", local->dev->name); | ||
2301 | return; | ||
2302 | } | ||
2303 | |||
2304 | hdr = (struct hostap_ieee80211_hdr *) skb_put(skb, 16); | ||
2305 | |||
2306 | /* Generate a fake pspoll frame to start packet delivery */ | ||
2307 | hdr->frame_control = __constant_cpu_to_le16( | ||
2308 | (WLAN_FC_TYPE_CTRL << 2) | (WLAN_FC_STYPE_PSPOLL << 4)); | ||
2309 | memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); | ||
2310 | memcpy(hdr->addr2, sta->addr, ETH_ALEN); | ||
2311 | hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); | ||
2312 | |||
2313 | PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " | ||
2314 | "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); | ||
2315 | |||
2316 | skb->dev = local->dev; | ||
2317 | |||
2318 | memset(&rx_stats, 0, sizeof(rx_stats)); | ||
2319 | hostap_rx(local->dev, skb, &rx_stats); | ||
2320 | } | ||
2321 | |||
2322 | |||
2323 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
2324 | struct iw_quality qual[], int buf_size, | ||
2325 | int aplist) | ||
2326 | { | ||
2327 | struct ap_data *ap = local->ap; | ||
2328 | struct list_head *ptr; | ||
2329 | int count = 0; | ||
2330 | |||
2331 | spin_lock_bh(&ap->sta_table_lock); | ||
2332 | |||
2333 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2334 | ptr = ptr->next) { | ||
2335 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2336 | |||
2337 | if (aplist && !sta->ap) | ||
2338 | continue; | ||
2339 | addr[count].sa_family = ARPHRD_ETHER; | ||
2340 | memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); | ||
2341 | if (sta->last_rx_silence == 0) | ||
2342 | qual[count].qual = sta->last_rx_signal < 27 ? | ||
2343 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2344 | else | ||
2345 | qual[count].qual = sta->last_rx_signal - | ||
2346 | sta->last_rx_silence - 35; | ||
2347 | qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2348 | qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2349 | qual[count].updated = sta->last_rx_updated; | ||
2350 | |||
2351 | sta->last_rx_updated = 0; | ||
2352 | |||
2353 | count++; | ||
2354 | if (count >= buf_size) | ||
2355 | break; | ||
2356 | } | ||
2357 | spin_unlock_bh(&ap->sta_table_lock); | ||
2358 | |||
2359 | return count; | ||
2360 | } | ||
2361 | |||
2362 | |||
2363 | /* Translate our list of Access Points & Stations to a card independant | ||
2364 | * format that the Wireless Tools will understand - Jean II */ | ||
2365 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) | ||
2366 | { | ||
2367 | struct hostap_interface *iface; | ||
2368 | local_info_t *local; | ||
2369 | struct ap_data *ap; | ||
2370 | struct list_head *ptr; | ||
2371 | struct iw_event iwe; | ||
2372 | char *current_ev = buffer; | ||
2373 | char *end_buf = buffer + IW_SCAN_MAX_DATA; | ||
2374 | #if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) | ||
2375 | char buf[64]; | ||
2376 | #endif | ||
2377 | |||
2378 | iface = netdev_priv(dev); | ||
2379 | local = iface->local; | ||
2380 | ap = local->ap; | ||
2381 | |||
2382 | spin_lock_bh(&ap->sta_table_lock); | ||
2383 | |||
2384 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2385 | ptr = ptr->next) { | ||
2386 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2387 | |||
2388 | /* First entry *MUST* be the AP MAC address */ | ||
2389 | memset(&iwe, 0, sizeof(iwe)); | ||
2390 | iwe.cmd = SIOCGIWAP; | ||
2391 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
2392 | memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); | ||
2393 | iwe.len = IW_EV_ADDR_LEN; | ||
2394 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2395 | IW_EV_ADDR_LEN); | ||
2396 | |||
2397 | /* Use the mode to indicate if it's a station or | ||
2398 | * an Access Point */ | ||
2399 | memset(&iwe, 0, sizeof(iwe)); | ||
2400 | iwe.cmd = SIOCGIWMODE; | ||
2401 | if (sta->ap) | ||
2402 | iwe.u.mode = IW_MODE_MASTER; | ||
2403 | else | ||
2404 | iwe.u.mode = IW_MODE_INFRA; | ||
2405 | iwe.len = IW_EV_UINT_LEN; | ||
2406 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2407 | IW_EV_UINT_LEN); | ||
2408 | |||
2409 | /* Some quality */ | ||
2410 | memset(&iwe, 0, sizeof(iwe)); | ||
2411 | iwe.cmd = IWEVQUAL; | ||
2412 | if (sta->last_rx_silence == 0) | ||
2413 | iwe.u.qual.qual = sta->last_rx_signal < 27 ? | ||
2414 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2415 | else | ||
2416 | iwe.u.qual.qual = sta->last_rx_signal - | ||
2417 | sta->last_rx_silence - 35; | ||
2418 | iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2419 | iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2420 | iwe.u.qual.updated = sta->last_rx_updated; | ||
2421 | iwe.len = IW_EV_QUAL_LEN; | ||
2422 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2423 | IW_EV_QUAL_LEN); | ||
2424 | |||
2425 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2426 | if (sta->ap) { | ||
2427 | memset(&iwe, 0, sizeof(iwe)); | ||
2428 | iwe.cmd = SIOCGIWESSID; | ||
2429 | iwe.u.data.length = sta->u.ap.ssid_len; | ||
2430 | iwe.u.data.flags = 1; | ||
2431 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2432 | &iwe, | ||
2433 | sta->u.ap.ssid); | ||
2434 | |||
2435 | memset(&iwe, 0, sizeof(iwe)); | ||
2436 | iwe.cmd = SIOCGIWENCODE; | ||
2437 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
2438 | iwe.u.data.flags = | ||
2439 | IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
2440 | else | ||
2441 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
2442 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2443 | &iwe, | ||
2444 | sta->u.ap.ssid | ||
2445 | /* 0 byte memcpy */); | ||
2446 | |||
2447 | if (sta->u.ap.channel > 0 && | ||
2448 | sta->u.ap.channel <= FREQ_COUNT) { | ||
2449 | memset(&iwe, 0, sizeof(iwe)); | ||
2450 | iwe.cmd = SIOCGIWFREQ; | ||
2451 | iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] | ||
2452 | * 100000; | ||
2453 | iwe.u.freq.e = 1; | ||
2454 | current_ev = iwe_stream_add_event( | ||
2455 | current_ev, end_buf, &iwe, | ||
2456 | IW_EV_FREQ_LEN); | ||
2457 | } | ||
2458 | |||
2459 | memset(&iwe, 0, sizeof(iwe)); | ||
2460 | iwe.cmd = IWEVCUSTOM; | ||
2461 | sprintf(buf, "beacon_interval=%d", | ||
2462 | sta->listen_interval); | ||
2463 | iwe.u.data.length = strlen(buf); | ||
2464 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2465 | &iwe, buf); | ||
2466 | } | ||
2467 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2468 | |||
2469 | sta->last_rx_updated = 0; | ||
2470 | |||
2471 | /* To be continued, we should make good use of IWEVCUSTOM */ | ||
2472 | } | ||
2473 | |||
2474 | spin_unlock_bh(&ap->sta_table_lock); | ||
2475 | |||
2476 | return current_ev - buffer; | ||
2477 | } | ||
2478 | |||
2479 | |||
2480 | static int prism2_hostapd_add_sta(struct ap_data *ap, | ||
2481 | struct prism2_hostapd_param *param) | ||
2482 | { | ||
2483 | struct sta_info *sta; | ||
2484 | |||
2485 | spin_lock_bh(&ap->sta_table_lock); | ||
2486 | sta = ap_get_sta(ap, param->sta_addr); | ||
2487 | if (sta) | ||
2488 | atomic_inc(&sta->users); | ||
2489 | spin_unlock_bh(&ap->sta_table_lock); | ||
2490 | |||
2491 | if (sta == NULL) { | ||
2492 | sta = ap_add_sta(ap, param->sta_addr); | ||
2493 | if (sta == NULL) | ||
2494 | return -1; | ||
2495 | } | ||
2496 | |||
2497 | if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2498 | hostap_event_new_sta(sta->local->dev, sta); | ||
2499 | |||
2500 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2501 | sta->last_rx = jiffies; | ||
2502 | sta->aid = param->u.add_sta.aid; | ||
2503 | sta->capability = param->u.add_sta.capability; | ||
2504 | sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; | ||
2505 | if (sta->tx_supp_rates & WLAN_RATE_1M) | ||
2506 | sta->supported_rates[0] = 2; | ||
2507 | if (sta->tx_supp_rates & WLAN_RATE_2M) | ||
2508 | sta->supported_rates[1] = 4; | ||
2509 | if (sta->tx_supp_rates & WLAN_RATE_5M5) | ||
2510 | sta->supported_rates[2] = 11; | ||
2511 | if (sta->tx_supp_rates & WLAN_RATE_11M) | ||
2512 | sta->supported_rates[3] = 22; | ||
2513 | prism2_check_tx_rates(sta); | ||
2514 | atomic_dec(&sta->users); | ||
2515 | return 0; | ||
2516 | } | ||
2517 | |||
2518 | |||
2519 | static int prism2_hostapd_remove_sta(struct ap_data *ap, | ||
2520 | struct prism2_hostapd_param *param) | ||
2521 | { | ||
2522 | struct sta_info *sta; | ||
2523 | |||
2524 | spin_lock_bh(&ap->sta_table_lock); | ||
2525 | sta = ap_get_sta(ap, param->sta_addr); | ||
2526 | if (sta) { | ||
2527 | ap_sta_hash_del(ap, sta); | ||
2528 | list_del(&sta->list); | ||
2529 | } | ||
2530 | spin_unlock_bh(&ap->sta_table_lock); | ||
2531 | |||
2532 | if (!sta) | ||
2533 | return -ENOENT; | ||
2534 | |||
2535 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2536 | hostap_event_expired_sta(sta->local->dev, sta); | ||
2537 | ap_free_sta(ap, sta); | ||
2538 | |||
2539 | return 0; | ||
2540 | } | ||
2541 | |||
2542 | |||
2543 | static int prism2_hostapd_get_info_sta(struct ap_data *ap, | ||
2544 | struct prism2_hostapd_param *param) | ||
2545 | { | ||
2546 | struct sta_info *sta; | ||
2547 | |||
2548 | spin_lock_bh(&ap->sta_table_lock); | ||
2549 | sta = ap_get_sta(ap, param->sta_addr); | ||
2550 | if (sta) | ||
2551 | atomic_inc(&sta->users); | ||
2552 | spin_unlock_bh(&ap->sta_table_lock); | ||
2553 | |||
2554 | if (!sta) | ||
2555 | return -ENOENT; | ||
2556 | |||
2557 | param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; | ||
2558 | |||
2559 | atomic_dec(&sta->users); | ||
2560 | |||
2561 | return 1; | ||
2562 | } | ||
2563 | |||
2564 | |||
2565 | static int prism2_hostapd_set_flags_sta(struct ap_data *ap, | ||
2566 | struct prism2_hostapd_param *param) | ||
2567 | { | ||
2568 | struct sta_info *sta; | ||
2569 | |||
2570 | spin_lock_bh(&ap->sta_table_lock); | ||
2571 | sta = ap_get_sta(ap, param->sta_addr); | ||
2572 | if (sta) { | ||
2573 | sta->flags |= param->u.set_flags_sta.flags_or; | ||
2574 | sta->flags &= param->u.set_flags_sta.flags_and; | ||
2575 | } | ||
2576 | spin_unlock_bh(&ap->sta_table_lock); | ||
2577 | |||
2578 | if (!sta) | ||
2579 | return -ENOENT; | ||
2580 | |||
2581 | return 0; | ||
2582 | } | ||
2583 | |||
2584 | |||
2585 | static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, | ||
2586 | struct prism2_hostapd_param *param) | ||
2587 | { | ||
2588 | struct sta_info *sta; | ||
2589 | int rate; | ||
2590 | |||
2591 | spin_lock_bh(&ap->sta_table_lock); | ||
2592 | sta = ap_get_sta(ap, param->sta_addr); | ||
2593 | if (sta) { | ||
2594 | sta->rx_packets = sta->tx_packets = 0; | ||
2595 | sta->rx_bytes = sta->tx_bytes = 0; | ||
2596 | for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { | ||
2597 | sta->tx_count[rate] = 0; | ||
2598 | sta->rx_count[rate] = 0; | ||
2599 | } | ||
2600 | } | ||
2601 | spin_unlock_bh(&ap->sta_table_lock); | ||
2602 | |||
2603 | if (!sta) | ||
2604 | return -ENOENT; | ||
2605 | |||
2606 | return 0; | ||
2607 | } | ||
2608 | |||
2609 | |||
2610 | static int prism2_hostapd(struct ap_data *ap, | ||
2611 | struct prism2_hostapd_param *param) | ||
2612 | { | ||
2613 | switch (param->cmd) { | ||
2614 | case PRISM2_HOSTAPD_FLUSH: | ||
2615 | ap_control_kickall(ap); | ||
2616 | return 0; | ||
2617 | case PRISM2_HOSTAPD_ADD_STA: | ||
2618 | return prism2_hostapd_add_sta(ap, param); | ||
2619 | case PRISM2_HOSTAPD_REMOVE_STA: | ||
2620 | return prism2_hostapd_remove_sta(ap, param); | ||
2621 | case PRISM2_HOSTAPD_GET_INFO_STA: | ||
2622 | return prism2_hostapd_get_info_sta(ap, param); | ||
2623 | case PRISM2_HOSTAPD_SET_FLAGS_STA: | ||
2624 | return prism2_hostapd_set_flags_sta(ap, param); | ||
2625 | case PRISM2_HOSTAPD_STA_CLEAR_STATS: | ||
2626 | return prism2_hostapd_sta_clear_stats(ap, param); | ||
2627 | default: | ||
2628 | printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", | ||
2629 | param->cmd); | ||
2630 | return -EOPNOTSUPP; | ||
2631 | } | ||
2632 | } | ||
2633 | |||
2634 | |||
2635 | /* Update station info for host-based TX rate control and return current | ||
2636 | * TX rate */ | ||
2637 | static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) | ||
2638 | { | ||
2639 | int ret = sta->tx_rate; | ||
2640 | struct hostap_interface *iface; | ||
2641 | local_info_t *local; | ||
2642 | |||
2643 | iface = netdev_priv(dev); | ||
2644 | local = iface->local; | ||
2645 | |||
2646 | sta->tx_count[sta->tx_rate_idx]++; | ||
2647 | sta->tx_since_last_failure++; | ||
2648 | sta->tx_consecutive_exc = 0; | ||
2649 | if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && | ||
2650 | sta->tx_rate_idx < sta->tx_max_rate) { | ||
2651 | /* use next higher rate */ | ||
2652 | int old_rate, new_rate; | ||
2653 | old_rate = new_rate = sta->tx_rate_idx; | ||
2654 | while (new_rate < sta->tx_max_rate) { | ||
2655 | new_rate++; | ||
2656 | if (ap_tx_rate_ok(new_rate, sta, local)) { | ||
2657 | sta->tx_rate_idx = new_rate; | ||
2658 | break; | ||
2659 | } | ||
2660 | } | ||
2661 | if (old_rate != sta->tx_rate_idx) { | ||
2662 | switch (sta->tx_rate_idx) { | ||
2663 | case 0: sta->tx_rate = 10; break; | ||
2664 | case 1: sta->tx_rate = 20; break; | ||
2665 | case 2: sta->tx_rate = 55; break; | ||
2666 | case 3: sta->tx_rate = 110; break; | ||
2667 | default: sta->tx_rate = 0; break; | ||
2668 | } | ||
2669 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" | ||
2670 | " %d\n", dev->name, MAC2STR(sta->addr), | ||
2671 | sta->tx_rate); | ||
2672 | } | ||
2673 | sta->tx_since_last_failure = 0; | ||
2674 | } | ||
2675 | |||
2676 | return ret; | ||
2677 | } | ||
2678 | |||
2679 | |||
2680 | /* Called only from software IRQ. Called for each TX frame prior possible | ||
2681 | * encryption and transmit. */ | ||
2682 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | ||
2683 | { | ||
2684 | struct sta_info *sta = NULL; | ||
2685 | struct sk_buff *skb = tx->skb; | ||
2686 | int set_tim, ret; | ||
2687 | struct hostap_ieee80211_hdr *hdr; | ||
2688 | struct hostap_skb_tx_data *meta; | ||
2689 | |||
2690 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
2691 | ret = AP_TX_CONTINUE; | ||
2692 | if (local->ap == NULL || skb->len < 10 || | ||
2693 | meta->iface->type == HOSTAP_INTERFACE_STA) | ||
2694 | goto out; | ||
2695 | |||
2696 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
2697 | |||
2698 | if (hdr->addr1[0] & 0x01) { | ||
2699 | /* broadcast/multicast frame - no AP related processing */ | ||
2700 | goto out; | ||
2701 | } | ||
2702 | |||
2703 | /* unicast packet - check whether destination STA is associated */ | ||
2704 | spin_lock(&local->ap->sta_table_lock); | ||
2705 | sta = ap_get_sta(local->ap, hdr->addr1); | ||
2706 | if (sta) | ||
2707 | atomic_inc(&sta->users); | ||
2708 | spin_unlock(&local->ap->sta_table_lock); | ||
2709 | |||
2710 | if (local->iw_mode == IW_MODE_MASTER && sta == NULL && !meta->wds && | ||
2711 | meta->iface->type != HOSTAP_INTERFACE_MASTER && | ||
2712 | meta->iface->type != HOSTAP_INTERFACE_AP) { | ||
2713 | #if 0 | ||
2714 | /* This can happen, e.g., when wlan0 is added to a bridge and | ||
2715 | * bridging code does not know which port is the correct target | ||
2716 | * for a unicast frame. In this case, the packet is send to all | ||
2717 | * ports of the bridge. Since this is a valid scenario, do not | ||
2718 | * print out any errors here. */ | ||
2719 | if (net_ratelimit()) { | ||
2720 | printk(KERN_DEBUG "AP: drop packet to non-associated " | ||
2721 | "STA " MACSTR "\n", MAC2STR(hdr->addr1)); | ||
2722 | } | ||
2723 | #endif | ||
2724 | local->ap->tx_drop_nonassoc++; | ||
2725 | ret = AP_TX_DROP; | ||
2726 | goto out; | ||
2727 | } | ||
2728 | |||
2729 | if (sta == NULL) | ||
2730 | goto out; | ||
2731 | |||
2732 | if (!(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2733 | ret = AP_TX_CONTINUE_NOT_AUTHORIZED; | ||
2734 | |||
2735 | /* Set tx_rate if using host-based TX rate control */ | ||
2736 | if (!local->fw_tx_rate_control) | ||
2737 | local->ap->last_tx_rate = meta->rate = | ||
2738 | ap_update_sta_tx_rate(sta, local->dev); | ||
2739 | |||
2740 | if (local->iw_mode != IW_MODE_MASTER) | ||
2741 | goto out; | ||
2742 | |||
2743 | if (!(sta->flags & WLAN_STA_PS)) | ||
2744 | goto out; | ||
2745 | |||
2746 | if (memcmp(skb->cb, AP_SKB_CB_MAGIC, AP_SKB_CB_MAGIC_LEN) == 0) { | ||
2747 | if (skb->cb[AP_SKB_CB_MAGIC_LEN] & AP_SKB_CB_ADD_MOREDATA) { | ||
2748 | /* indicate to STA that more frames follow */ | ||
2749 | hdr->frame_control |= | ||
2750 | __constant_cpu_to_le16(WLAN_FC_MOREDATA); | ||
2751 | } | ||
2752 | |||
2753 | if (skb->cb[AP_SKB_CB_MAGIC_LEN] & AP_SKB_CB_BUFFERED_FRAME) { | ||
2754 | /* packet was already buffered and now send due to | ||
2755 | * PS poll, so do not rebuffer it */ | ||
2756 | goto out; | ||
2757 | } | ||
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 hostap_ieee80211_hdr *hdr; | ||
2825 | struct hostap_skb_tx_data *meta; | ||
2826 | |||
2827 | hdr = (struct hostap_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, stype); | ||
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, stype); | ||
2886 | if (type != WLAN_FC_TYPE_CTRL || stype != WLAN_FC_STYPE_PSPOLL) | ||
2887 | schedule_packet_send(local, sta); | ||
2888 | } | ||
2889 | } | ||
2890 | |||
2891 | |||
2892 | /* Called only as a tasklet (software IRQ). Called for each RX frame to update | ||
2893 | * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ | ||
2894 | int hostap_update_sta_ps(local_info_t *local, struct hostap_ieee80211_hdr *hdr) | ||
2895 | { | ||
2896 | struct sta_info *sta; | ||
2897 | u16 fc; | ||
2898 | |||
2899 | spin_lock(&local->ap->sta_table_lock); | ||
2900 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2901 | if (sta) | ||
2902 | atomic_inc(&sta->users); | ||
2903 | spin_unlock(&local->ap->sta_table_lock); | ||
2904 | |||
2905 | if (!sta) | ||
2906 | return -1; | ||
2907 | |||
2908 | fc = le16_to_cpu(hdr->frame_control); | ||
2909 | hostap_update_sta_ps2(local, sta, fc & WLAN_FC_PWRMGT, | ||
2910 | WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc)); | ||
2911 | |||
2912 | atomic_dec(&sta->users); | ||
2913 | return 0; | ||
2914 | } | ||
2915 | |||
2916 | |||
2917 | /* Called only as a tasklet (software IRQ). Called for each RX frame after | ||
2918 | * getting RX header and payload from hardware. */ | ||
2919 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
2920 | struct sk_buff *skb, | ||
2921 | struct hostap_80211_rx_status *rx_stats, | ||
2922 | int wds) | ||
2923 | { | ||
2924 | int ret; | ||
2925 | struct sta_info *sta; | ||
2926 | u16 fc, type, stype; | ||
2927 | struct hostap_ieee80211_hdr *hdr; | ||
2928 | |||
2929 | if (local->ap == NULL) | ||
2930 | return AP_RX_CONTINUE; | ||
2931 | |||
2932 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
2933 | |||
2934 | fc = le16_to_cpu(hdr->frame_control); | ||
2935 | type = WLAN_FC_GET_TYPE(fc); | ||
2936 | stype = WLAN_FC_GET_STYPE(fc); | ||
2937 | |||
2938 | spin_lock(&local->ap->sta_table_lock); | ||
2939 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2940 | if (sta) | ||
2941 | atomic_inc(&sta->users); | ||
2942 | spin_unlock(&local->ap->sta_table_lock); | ||
2943 | |||
2944 | if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2945 | ret = AP_RX_CONTINUE_NOT_AUTHORIZED; | ||
2946 | else | ||
2947 | ret = AP_RX_CONTINUE; | ||
2948 | |||
2949 | |||
2950 | if (fc & WLAN_FC_TODS) { | ||
2951 | if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { | ||
2952 | if (local->hostapd) { | ||
2953 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2954 | PRISM2_RX_NON_ASSOC); | ||
2955 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2956 | } else { | ||
2957 | printk(KERN_DEBUG "%s: dropped received packet" | ||
2958 | " from non-associated STA " MACSTR | ||
2959 | " (type=0x%02x, subtype=0x%02x)\n", | ||
2960 | dev->name, MAC2STR(hdr->addr2), type, | ||
2961 | stype); | ||
2962 | hostap_rx(dev, skb, rx_stats); | ||
2963 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2964 | } | ||
2965 | ret = AP_RX_EXIT; | ||
2966 | goto out; | ||
2967 | } | ||
2968 | } else if (fc & WLAN_FC_FROMDS) { | ||
2969 | if (!wds) { | ||
2970 | /* FromDS frame - not for us; probably | ||
2971 | * broadcast/multicast in another BSS - drop */ | ||
2972 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2973 | printk(KERN_DEBUG "Odd.. FromDS packet " | ||
2974 | "received with own BSSID\n"); | ||
2975 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
2976 | } | ||
2977 | ret = AP_RX_DROP; | ||
2978 | goto out; | ||
2979 | } | ||
2980 | } else if (stype == WLAN_FC_STYPE_NULLFUNC && sta == NULL && | ||
2981 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2982 | |||
2983 | if (local->hostapd) { | ||
2984 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2985 | PRISM2_RX_NON_ASSOC); | ||
2986 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2987 | } else { | ||
2988 | /* At least Lucent f/w seems to send data::nullfunc | ||
2989 | * frames with no ToDS flag when the current AP returns | ||
2990 | * after being unavailable for some time. Speed up | ||
2991 | * re-association by informing the station about it not | ||
2992 | * being associated. */ | ||
2993 | printk(KERN_DEBUG "%s: rejected received nullfunc " | ||
2994 | "frame without ToDS from not associated STA " | ||
2995 | MACSTR "\n", | ||
2996 | dev->name, MAC2STR(hdr->addr2)); | ||
2997 | hostap_rx(dev, skb, rx_stats); | ||
2998 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2999 | } | ||
3000 | ret = AP_RX_EXIT; | ||
3001 | goto out; | ||
3002 | } else if (stype == WLAN_FC_STYPE_NULLFUNC) { | ||
3003 | /* At least Lucent cards seem to send periodic nullfunc | ||
3004 | * frames with ToDS. Let these through to update SQ | ||
3005 | * stats and PS state. Nullfunc frames do not contain | ||
3006 | * any data and they will be dropped below. */ | ||
3007 | } else { | ||
3008 | /* If BSSID (Addr3) is foreign, this frame is a normal | ||
3009 | * broadcast frame from an IBSS network. Drop it silently. | ||
3010 | * If BSSID is own, report the dropping of this frame. */ | ||
3011 | if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
3012 | printk(KERN_DEBUG "%s: dropped received packet from " | ||
3013 | MACSTR " with no ToDS flag (type=0x%02x, " | ||
3014 | "subtype=0x%02x)\n", dev->name, | ||
3015 | MAC2STR(hdr->addr2), type, stype); | ||
3016 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
3017 | } | ||
3018 | ret = AP_RX_DROP; | ||
3019 | goto out; | ||
3020 | } | ||
3021 | |||
3022 | if (sta) { | ||
3023 | hostap_update_sta_ps2(local, sta, fc & WLAN_FC_PWRMGT, | ||
3024 | type, stype); | ||
3025 | |||
3026 | sta->rx_packets++; | ||
3027 | sta->rx_bytes += skb->len; | ||
3028 | sta->last_rx = jiffies; | ||
3029 | } | ||
3030 | |||
3031 | if (local->ap->nullfunc_ack && stype == WLAN_FC_STYPE_NULLFUNC && | ||
3032 | fc & WLAN_FC_TODS) { | ||
3033 | if (local->hostapd) { | ||
3034 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
3035 | PRISM2_RX_NULLFUNC_ACK); | ||
3036 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3037 | } else { | ||
3038 | /* some STA f/w's seem to require control::ACK frame | ||
3039 | * for data::nullfunc, but Prism2 f/w 0.8.0 (at least | ||
3040 | * from Compaq) does not send this.. Try to generate | ||
3041 | * ACK for these frames from the host driver to make | ||
3042 | * power saving work with, e.g., Lucent WaveLAN f/w */ | ||
3043 | hostap_rx(dev, skb, rx_stats); | ||
3044 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3045 | } | ||
3046 | ret = AP_RX_EXIT; | ||
3047 | goto out; | ||
3048 | } | ||
3049 | |||
3050 | out: | ||
3051 | if (sta) | ||
3052 | atomic_dec(&sta->users); | ||
3053 | |||
3054 | return ret; | ||
3055 | } | ||
3056 | |||
3057 | |||
3058 | /* Called only as a tasklet (software IRQ) */ | ||
3059 | int hostap_handle_sta_crypto(local_info_t *local, | ||
3060 | struct hostap_ieee80211_hdr *hdr, | ||
3061 | struct prism2_crypt_data **crypt, void **sta_ptr) | ||
3062 | { | ||
3063 | struct sta_info *sta; | ||
3064 | |||
3065 | spin_lock(&local->ap->sta_table_lock); | ||
3066 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
3067 | if (sta) | ||
3068 | atomic_inc(&sta->users); | ||
3069 | spin_unlock(&local->ap->sta_table_lock); | ||
3070 | |||
3071 | if (!sta) | ||
3072 | return -1; | ||
3073 | |||
3074 | if (sta->crypt) { | ||
3075 | *crypt = sta->crypt; | ||
3076 | *sta_ptr = sta; | ||
3077 | /* hostap_handle_sta_release() will be called to release STA | ||
3078 | * info */ | ||
3079 | } else | ||
3080 | atomic_dec(&sta->users); | ||
3081 | |||
3082 | return 0; | ||
3083 | } | ||
3084 | |||
3085 | |||
3086 | /* Called only as a tasklet (software IRQ) */ | ||
3087 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) | ||
3088 | { | ||
3089 | struct sta_info *sta; | ||
3090 | int ret = 0; | ||
3091 | |||
3092 | spin_lock(&ap->sta_table_lock); | ||
3093 | sta = ap_get_sta(ap, sta_addr); | ||
3094 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
3095 | ret = 1; | ||
3096 | spin_unlock(&ap->sta_table_lock); | ||
3097 | |||
3098 | return ret; | ||
3099 | } | ||
3100 | |||
3101 | |||
3102 | /* Called only as a tasklet (software IRQ) */ | ||
3103 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) | ||
3104 | { | ||
3105 | struct sta_info *sta; | ||
3106 | int ret = 0; | ||
3107 | |||
3108 | spin_lock(&ap->sta_table_lock); | ||
3109 | sta = ap_get_sta(ap, sta_addr); | ||
3110 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && | ||
3111 | ((sta->flags & WLAN_STA_AUTHORIZED) || | ||
3112 | ap->local->ieee_802_1x == 0)) | ||
3113 | ret = 1; | ||
3114 | spin_unlock(&ap->sta_table_lock); | ||
3115 | |||
3116 | return ret; | ||
3117 | } | ||
3118 | |||
3119 | |||
3120 | /* Called only as a tasklet (software IRQ) */ | ||
3121 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) | ||
3122 | { | ||
3123 | struct sta_info *sta; | ||
3124 | int ret = 1; | ||
3125 | |||
3126 | if (!ap) | ||
3127 | return -1; | ||
3128 | |||
3129 | spin_lock(&ap->sta_table_lock); | ||
3130 | sta = ap_get_sta(ap, sta_addr); | ||
3131 | if (sta) | ||
3132 | ret = 0; | ||
3133 | spin_unlock(&ap->sta_table_lock); | ||
3134 | |||
3135 | if (ret == 1) { | ||
3136 | sta = ap_add_sta(ap, sta_addr); | ||
3137 | if (!sta) | ||
3138 | ret = -1; | ||
3139 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
3140 | sta->ap = 1; | ||
3141 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
3142 | /* No way of knowing which rates are supported since we did not | ||
3143 | * get supported rates element from beacon/assoc req. Assume | ||
3144 | * that remote end supports all 802.11b rates. */ | ||
3145 | sta->supported_rates[0] = 0x82; | ||
3146 | sta->supported_rates[1] = 0x84; | ||
3147 | sta->supported_rates[2] = 0x0b; | ||
3148 | sta->supported_rates[3] = 0x16; | ||
3149 | sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | | ||
3150 | WLAN_RATE_5M5 | WLAN_RATE_11M; | ||
3151 | sta->tx_rate = 110; | ||
3152 | sta->tx_max_rate = sta->tx_rate_idx = 3; | ||
3153 | } | ||
3154 | |||
3155 | return ret; | ||
3156 | } | ||
3157 | |||
3158 | |||
3159 | /* Called only as a tasklet (software IRQ) */ | ||
3160 | int hostap_update_rx_stats(struct ap_data *ap, | ||
3161 | struct hostap_ieee80211_hdr *hdr, | ||
3162 | struct hostap_80211_rx_status *rx_stats) | ||
3163 | { | ||
3164 | struct sta_info *sta; | ||
3165 | |||
3166 | if (!ap) | ||
3167 | return -1; | ||
3168 | |||
3169 | spin_lock(&ap->sta_table_lock); | ||
3170 | sta = ap_get_sta(ap, hdr->addr2); | ||
3171 | if (sta) { | ||
3172 | sta->last_rx_silence = rx_stats->noise; | ||
3173 | sta->last_rx_signal = rx_stats->signal; | ||
3174 | sta->last_rx_rate = rx_stats->rate; | ||
3175 | sta->last_rx_updated = 7; | ||
3176 | if (rx_stats->rate == 10) | ||
3177 | sta->rx_count[0]++; | ||
3178 | else if (rx_stats->rate == 20) | ||
3179 | sta->rx_count[1]++; | ||
3180 | else if (rx_stats->rate == 55) | ||
3181 | sta->rx_count[2]++; | ||
3182 | else if (rx_stats->rate == 110) | ||
3183 | sta->rx_count[3]++; | ||
3184 | } | ||
3185 | spin_unlock(&ap->sta_table_lock); | ||
3186 | |||
3187 | return sta ? 0 : -1; | ||
3188 | } | ||
3189 | |||
3190 | |||
3191 | void hostap_update_rates(local_info_t *local) | ||
3192 | { | ||
3193 | struct list_head *ptr; | ||
3194 | struct ap_data *ap = local->ap; | ||
3195 | |||
3196 | if (!ap) | ||
3197 | return; | ||
3198 | |||
3199 | spin_lock_bh(&ap->sta_table_lock); | ||
3200 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
3201 | struct sta_info *sta = (struct sta_info *) ptr; | ||
3202 | prism2_check_tx_rates(sta); | ||
3203 | } | ||
3204 | spin_unlock_bh(&ap->sta_table_lock); | ||
3205 | } | ||
3206 | |||
3207 | |||
3208 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
3209 | struct prism2_crypt_data ***crypt) | ||
3210 | { | ||
3211 | struct sta_info *sta; | ||
3212 | |||
3213 | spin_lock_bh(&ap->sta_table_lock); | ||
3214 | sta = ap_get_sta(ap, addr); | ||
3215 | if (sta) | ||
3216 | atomic_inc(&sta->users); | ||
3217 | spin_unlock_bh(&ap->sta_table_lock); | ||
3218 | |||
3219 | if (!sta && permanent) | ||
3220 | sta = ap_add_sta(ap, addr); | ||
3221 | |||
3222 | if (!sta) | ||
3223 | return NULL; | ||
3224 | |||
3225 | if (permanent) | ||
3226 | sta->flags |= WLAN_STA_PERM; | ||
3227 | |||
3228 | *crypt = &sta->crypt; | ||
3229 | |||
3230 | return sta; | ||
3231 | } | ||
3232 | |||
3233 | |||
3234 | void hostap_add_wds_links(local_info_t *local) | ||
3235 | { | ||
3236 | struct ap_data *ap = local->ap; | ||
3237 | struct list_head *ptr; | ||
3238 | |||
3239 | spin_lock_bh(&ap->sta_table_lock); | ||
3240 | list_for_each(ptr, &ap->sta_list) { | ||
3241 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
3242 | if (sta->ap) | ||
3243 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
3244 | } | ||
3245 | spin_unlock_bh(&ap->sta_table_lock); | ||
3246 | |||
3247 | schedule_work(&local->ap->wds_oper_queue); | ||
3248 | } | ||
3249 | |||
3250 | |||
3251 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) | ||
3252 | { | ||
3253 | struct wds_oper_data *entry; | ||
3254 | |||
3255 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
3256 | if (!entry) | ||
3257 | return; | ||
3258 | memcpy(entry->addr, addr, ETH_ALEN); | ||
3259 | entry->type = type; | ||
3260 | spin_lock_bh(&local->lock); | ||
3261 | entry->next = local->ap->wds_oper_entries; | ||
3262 | local->ap->wds_oper_entries = entry; | ||
3263 | spin_unlock_bh(&local->lock); | ||
3264 | |||
3265 | schedule_work(&local->ap->wds_oper_queue); | ||
3266 | } | ||
3267 | |||
3268 | |||
3269 | EXPORT_SYMBOL(hostap_init_data); | ||
3270 | EXPORT_SYMBOL(hostap_init_ap_proc); | ||
3271 | EXPORT_SYMBOL(hostap_free_data); | ||
3272 | EXPORT_SYMBOL(hostap_check_sta_fw_version); | ||
3273 | EXPORT_SYMBOL(hostap_handle_sta_tx); | ||
3274 | EXPORT_SYMBOL(hostap_handle_sta_release); | ||
3275 | EXPORT_SYMBOL(hostap_handle_sta_tx_exc); | ||
3276 | EXPORT_SYMBOL(hostap_update_sta_ps); | ||
3277 | EXPORT_SYMBOL(hostap_handle_sta_rx); | ||
3278 | EXPORT_SYMBOL(hostap_is_sta_assoc); | ||
3279 | EXPORT_SYMBOL(hostap_is_sta_authorized); | ||
3280 | EXPORT_SYMBOL(hostap_add_sta); | ||
3281 | EXPORT_SYMBOL(hostap_update_rates); | ||
3282 | EXPORT_SYMBOL(hostap_add_wds_links); | ||
3283 | EXPORT_SYMBOL(hostap_wds_link_oper); | ||
3284 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3285 | EXPORT_SYMBOL(hostap_deauth_all_stas); | ||
3286 | #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 00000000000..10137f44436 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.h | |||
@@ -0,0 +1,272 @@ | |||
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 | /* Flags used in skb->cb[6] to control how the packet is handled in TX path. | ||
10 | * skb->cb[0..5] must contain magic value 'hostap' to indicate that cb[6] is | ||
11 | * used. */ | ||
12 | #define AP_SKB_CB_MAGIC "hostap" | ||
13 | #define AP_SKB_CB_MAGIC_LEN 6 | ||
14 | #define AP_SKB_CB_BUFFERED_FRAME BIT(0) | ||
15 | #define AP_SKB_CB_ADD_MOREDATA BIT(1) | ||
16 | |||
17 | |||
18 | /* STA flags */ | ||
19 | #define WLAN_STA_AUTH BIT(0) | ||
20 | #define WLAN_STA_ASSOC BIT(1) | ||
21 | #define WLAN_STA_PS BIT(2) | ||
22 | #define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ | ||
23 | #define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ | ||
24 | #define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is | ||
25 | * controlling whether STA is authorized to | ||
26 | * send and receive non-IEEE 802.1X frames | ||
27 | */ | ||
28 | #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ | ||
29 | |||
30 | #define WLAN_RATE_1M BIT(0) | ||
31 | #define WLAN_RATE_2M BIT(1) | ||
32 | #define WLAN_RATE_5M5 BIT(2) | ||
33 | #define WLAN_RATE_11M BIT(3) | ||
34 | #define WLAN_RATE_COUNT 4 | ||
35 | |||
36 | /* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, | ||
37 | * but some pre-standard IEEE 802.11g products use longer elements. */ | ||
38 | #define WLAN_SUPP_RATES_MAX 32 | ||
39 | |||
40 | /* Try to increase TX rate after # successfully sent consecutive packets */ | ||
41 | #define WLAN_RATE_UPDATE_COUNT 50 | ||
42 | |||
43 | /* Decrease TX rate after # consecutive dropped packets */ | ||
44 | #define WLAN_RATE_DECREASE_THRESHOLD 2 | ||
45 | |||
46 | struct sta_info { | ||
47 | struct list_head list; | ||
48 | struct sta_info *hnext; /* next entry in hash table list */ | ||
49 | atomic_t users; /* number of users (do not remove if > 0) */ | ||
50 | struct proc_dir_entry *proc; | ||
51 | |||
52 | u8 addr[6]; | ||
53 | u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ | ||
54 | u32 flags; | ||
55 | u16 capability; | ||
56 | u16 listen_interval; /* or beacon_int for APs */ | ||
57 | u8 supported_rates[WLAN_SUPP_RATES_MAX]; | ||
58 | |||
59 | unsigned long last_auth; | ||
60 | unsigned long last_assoc; | ||
61 | unsigned long last_rx; | ||
62 | unsigned long last_tx; | ||
63 | unsigned long rx_packets, tx_packets; | ||
64 | unsigned long rx_bytes, tx_bytes; | ||
65 | struct sk_buff_head tx_buf; | ||
66 | /* FIX: timeout buffers with an expiry time somehow derived from | ||
67 | * listen_interval */ | ||
68 | |||
69 | s8 last_rx_silence; /* Noise in dBm */ | ||
70 | s8 last_rx_signal; /* Signal strength in dBm */ | ||
71 | u8 last_rx_rate; /* TX rate in 0.1 Mbps */ | ||
72 | u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ | ||
73 | |||
74 | u8 tx_supp_rates; /* bit field of supported TX rates */ | ||
75 | u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ | ||
76 | u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ | ||
77 | u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ | ||
78 | u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ | ||
79 | u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) | ||
80 | */ | ||
81 | u32 tx_since_last_failure; | ||
82 | u32 tx_consecutive_exc; | ||
83 | |||
84 | struct prism2_crypt_data *crypt; | ||
85 | |||
86 | int ap; /* whether this station is an AP */ | ||
87 | |||
88 | local_info_t *local; | ||
89 | |||
90 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
91 | union { | ||
92 | struct { | ||
93 | char *challenge; /* shared key authentication | ||
94 | * challenge */ | ||
95 | } sta; | ||
96 | struct { | ||
97 | int ssid_len; | ||
98 | unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ | ||
99 | int channel; | ||
100 | unsigned long last_beacon; /* last RX beacon time */ | ||
101 | } ap; | ||
102 | } u; | ||
103 | |||
104 | struct timer_list timer; | ||
105 | enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; | ||
106 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
107 | }; | ||
108 | |||
109 | |||
110 | #define MAX_STA_COUNT 1024 | ||
111 | |||
112 | /* Maximum number of AIDs to use for STAs; must be 2007 or lower | ||
113 | * (8802.11 limitation) */ | ||
114 | #define MAX_AID_TABLE_SIZE 128 | ||
115 | |||
116 | #define STA_HASH_SIZE 256 | ||
117 | #define STA_HASH(sta) (sta[5]) | ||
118 | |||
119 | |||
120 | /* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC | ||
121 | * has passed since last received frame from the station, a nullfunc data | ||
122 | * frame is sent to the station. If this frame is not acknowledged and no other | ||
123 | * frames have been received, the station will be disassociated after | ||
124 | * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after | ||
125 | * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with | ||
126 | * max inactivity timer. */ | ||
127 | #define AP_MAX_INACTIVITY_SEC (5 * 60) | ||
128 | #define AP_DISASSOC_DELAY (HZ) | ||
129 | #define AP_DEAUTH_DELAY (HZ) | ||
130 | |||
131 | /* ap_policy: whether to accept frames to/from other APs/IBSS */ | ||
132 | typedef enum { | ||
133 | AP_OTHER_AP_SKIP_ALL = 0, | ||
134 | AP_OTHER_AP_SAME_SSID = 1, | ||
135 | AP_OTHER_AP_ALL = 2, | ||
136 | AP_OTHER_AP_EVEN_IBSS = 3 | ||
137 | } ap_policy_enum; | ||
138 | |||
139 | #define PRISM2_AUTH_OPEN BIT(0) | ||
140 | #define PRISM2_AUTH_SHARED_KEY BIT(1) | ||
141 | |||
142 | |||
143 | /* MAC address-based restrictions */ | ||
144 | struct mac_entry { | ||
145 | struct list_head list; | ||
146 | u8 addr[6]; | ||
147 | }; | ||
148 | |||
149 | struct mac_restrictions { | ||
150 | enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; | ||
151 | unsigned int entries; | ||
152 | struct list_head mac_list; | ||
153 | spinlock_t lock; | ||
154 | }; | ||
155 | |||
156 | |||
157 | struct add_sta_proc_data { | ||
158 | u8 addr[ETH_ALEN]; | ||
159 | struct add_sta_proc_data *next; | ||
160 | }; | ||
161 | |||
162 | |||
163 | typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; | ||
164 | struct wds_oper_data { | ||
165 | wds_oper_type type; | ||
166 | u8 addr[ETH_ALEN]; | ||
167 | struct wds_oper_data *next; | ||
168 | }; | ||
169 | |||
170 | |||
171 | struct ap_data { | ||
172 | int initialized; /* whether ap_data has been initialized */ | ||
173 | local_info_t *local; | ||
174 | int bridge_packets; /* send packet to associated STAs directly to the | ||
175 | * wireless media instead of higher layers in the | ||
176 | * kernel */ | ||
177 | unsigned int bridged_unicast; /* number of unicast frames bridged on | ||
178 | * wireless media */ | ||
179 | unsigned int bridged_multicast; /* number of non-unicast frames | ||
180 | * bridged on wireless media */ | ||
181 | unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped | ||
182 | * because they were to an address that | ||
183 | * was not associated */ | ||
184 | int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ | ||
185 | |||
186 | spinlock_t sta_table_lock; | ||
187 | int num_sta; /* number of entries in sta_list */ | ||
188 | struct list_head sta_list; /* STA info list head */ | ||
189 | struct sta_info *sta_hash[STA_HASH_SIZE]; | ||
190 | |||
191 | struct proc_dir_entry *proc; | ||
192 | |||
193 | ap_policy_enum ap_policy; | ||
194 | unsigned int max_inactivity; | ||
195 | int autom_ap_wds; | ||
196 | |||
197 | struct mac_restrictions mac_restrictions; /* MAC-based auth */ | ||
198 | int last_tx_rate; | ||
199 | |||
200 | struct work_struct add_sta_proc_queue; | ||
201 | struct add_sta_proc_data *add_sta_proc_entries; | ||
202 | |||
203 | struct work_struct wds_oper_queue; | ||
204 | struct wds_oper_data *wds_oper_entries; | ||
205 | |||
206 | u16 tx_callback_idx; | ||
207 | |||
208 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
209 | /* pointers to STA info; based on allocated AID or NULL if AID free | ||
210 | * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 | ||
211 | * and so on | ||
212 | */ | ||
213 | struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; | ||
214 | |||
215 | u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; | ||
216 | |||
217 | /* WEP operations for generating challenges to be used with shared key | ||
218 | * authentication */ | ||
219 | struct hostap_crypto_ops *crypt; | ||
220 | void *crypt_priv; | ||
221 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
222 | }; | ||
223 | |||
224 | |||
225 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
226 | struct hostap_80211_rx_status *rx_stats); | ||
227 | void hostap_init_data(local_info_t *local); | ||
228 | void hostap_init_ap_proc(local_info_t *local); | ||
229 | void hostap_free_data(struct ap_data *ap); | ||
230 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); | ||
231 | |||
232 | typedef enum { | ||
233 | AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, | ||
234 | AP_TX_CONTINUE_NOT_AUTHORIZED | ||
235 | } ap_tx_ret; | ||
236 | struct hostap_tx_data { | ||
237 | struct sk_buff *skb; | ||
238 | int host_encrypt; | ||
239 | struct prism2_crypt_data *crypt; | ||
240 | void *sta_ptr; | ||
241 | }; | ||
242 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); | ||
243 | void hostap_handle_sta_release(void *ptr); | ||
244 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); | ||
245 | int hostap_update_sta_ps(local_info_t *local, | ||
246 | struct hostap_ieee80211_hdr *hdr); | ||
247 | typedef enum { | ||
248 | AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED | ||
249 | } ap_rx_ret; | ||
250 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
251 | struct sk_buff *skb, | ||
252 | struct hostap_80211_rx_status *rx_stats, | ||
253 | int wds); | ||
254 | int hostap_handle_sta_crypto(local_info_t *local, | ||
255 | struct hostap_ieee80211_hdr *hdr, | ||
256 | struct prism2_crypt_data **crypt, void **sta_ptr); | ||
257 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); | ||
258 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); | ||
259 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); | ||
260 | int hostap_update_rx_stats(struct ap_data *ap, | ||
261 | struct hostap_ieee80211_hdr *hdr, | ||
262 | struct hostap_80211_rx_status *rx_stats); | ||
263 | void hostap_update_rates(local_info_t *local); | ||
264 | void hostap_add_wds_links(local_info_t *local); | ||
265 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); | ||
266 | |||
267 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
268 | void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | ||
269 | int resend); | ||
270 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
271 | |||
272 | #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 00000000000..1a9610add69 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_common.h | |||
@@ -0,0 +1,557 @@ | |||
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 | #ifndef ETH_P_PAE | ||
11 | #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ | ||
12 | #endif /* ETH_P_PAE */ | ||
13 | |||
14 | #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ | ||
15 | |||
16 | |||
17 | |||
18 | /* IEEE 802.11 defines */ | ||
19 | |||
20 | #define WLAN_FC_PVER (BIT(1) | BIT(0)) | ||
21 | #define WLAN_FC_TODS BIT(8) | ||
22 | #define WLAN_FC_FROMDS BIT(9) | ||
23 | #define WLAN_FC_MOREFRAG BIT(10) | ||
24 | #define WLAN_FC_RETRY BIT(11) | ||
25 | #define WLAN_FC_PWRMGT BIT(12) | ||
26 | #define WLAN_FC_MOREDATA BIT(13) | ||
27 | #define WLAN_FC_ISWEP BIT(14) | ||
28 | #define WLAN_FC_ORDER BIT(15) | ||
29 | |||
30 | #define WLAN_FC_GET_TYPE(fc) (((fc) & (BIT(3) | BIT(2))) >> 2) | ||
31 | #define WLAN_FC_GET_STYPE(fc) \ | ||
32 | (((fc) & (BIT(7) | BIT(6) | BIT(5) | BIT(4))) >> 4) | ||
33 | |||
34 | #define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) | ||
35 | #define WLAN_GET_SEQ_SEQ(seq) \ | ||
36 | (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) | ||
37 | |||
38 | #define WLAN_FC_TYPE_MGMT 0 | ||
39 | #define WLAN_FC_TYPE_CTRL 1 | ||
40 | #define WLAN_FC_TYPE_DATA 2 | ||
41 | |||
42 | /* management */ | ||
43 | #define WLAN_FC_STYPE_ASSOC_REQ 0 | ||
44 | #define WLAN_FC_STYPE_ASSOC_RESP 1 | ||
45 | #define WLAN_FC_STYPE_REASSOC_REQ 2 | ||
46 | #define WLAN_FC_STYPE_REASSOC_RESP 3 | ||
47 | #define WLAN_FC_STYPE_PROBE_REQ 4 | ||
48 | #define WLAN_FC_STYPE_PROBE_RESP 5 | ||
49 | #define WLAN_FC_STYPE_BEACON 8 | ||
50 | #define WLAN_FC_STYPE_ATIM 9 | ||
51 | #define WLAN_FC_STYPE_DISASSOC 10 | ||
52 | #define WLAN_FC_STYPE_AUTH 11 | ||
53 | #define WLAN_FC_STYPE_DEAUTH 12 | ||
54 | |||
55 | /* control */ | ||
56 | #define WLAN_FC_STYPE_PSPOLL 10 | ||
57 | #define WLAN_FC_STYPE_RTS 11 | ||
58 | #define WLAN_FC_STYPE_CTS 12 | ||
59 | #define WLAN_FC_STYPE_ACK 13 | ||
60 | #define WLAN_FC_STYPE_CFEND 14 | ||
61 | #define WLAN_FC_STYPE_CFENDACK 15 | ||
62 | |||
63 | /* data */ | ||
64 | #define WLAN_FC_STYPE_DATA 0 | ||
65 | #define WLAN_FC_STYPE_DATA_CFACK 1 | ||
66 | #define WLAN_FC_STYPE_DATA_CFPOLL 2 | ||
67 | #define WLAN_FC_STYPE_DATA_CFACKPOLL 3 | ||
68 | #define WLAN_FC_STYPE_NULLFUNC 4 | ||
69 | #define WLAN_FC_STYPE_CFACK 5 | ||
70 | #define WLAN_FC_STYPE_CFPOLL 6 | ||
71 | #define WLAN_FC_STYPE_CFACKPOLL 7 | ||
72 | |||
73 | /* Authentication algorithms */ | ||
74 | #define WLAN_AUTH_OPEN 0 | ||
75 | #define WLAN_AUTH_SHARED_KEY 1 | ||
76 | |||
77 | #define WLAN_AUTH_CHALLENGE_LEN 128 | ||
78 | |||
79 | #define WLAN_CAPABILITY_ESS BIT(0) | ||
80 | #define WLAN_CAPABILITY_IBSS BIT(1) | ||
81 | #define WLAN_CAPABILITY_CF_POLLABLE BIT(2) | ||
82 | #define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) | ||
83 | #define WLAN_CAPABILITY_PRIVACY BIT(4) | ||
84 | |||
85 | /* Status codes */ | ||
86 | #define WLAN_STATUS_SUCCESS 0 | ||
87 | #define WLAN_STATUS_UNSPECIFIED_FAILURE 1 | ||
88 | #define WLAN_STATUS_CAPS_UNSUPPORTED 10 | ||
89 | #define WLAN_STATUS_REASSOC_NO_ASSOC 11 | ||
90 | #define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 | ||
91 | #define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 | ||
92 | #define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 | ||
93 | #define WLAN_STATUS_CHALLENGE_FAIL 15 | ||
94 | #define WLAN_STATUS_AUTH_TIMEOUT 16 | ||
95 | #define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 | ||
96 | #define WLAN_STATUS_ASSOC_DENIED_RATES 18 | ||
97 | /* 802.11b */ | ||
98 | #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 | ||
99 | #define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 | ||
100 | #define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 | ||
101 | /* IEEE 802.11i */ | ||
102 | #define WLAN_STATUS_INVALID_IE 40 | ||
103 | #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 | ||
104 | #define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 | ||
105 | #define WLAN_STATUS_AKMP_NOT_VALID 43 | ||
106 | #define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 | ||
107 | #define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 | ||
108 | #define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 | ||
109 | |||
110 | /* Reason codes */ | ||
111 | #define WLAN_REASON_UNSPECIFIED 1 | ||
112 | #define WLAN_REASON_PREV_AUTH_NOT_VALID 2 | ||
113 | #define WLAN_REASON_DEAUTH_LEAVING 3 | ||
114 | #define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 | ||
115 | #define WLAN_REASON_DISASSOC_AP_BUSY 5 | ||
116 | #define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 | ||
117 | #define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 | ||
118 | #define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 | ||
119 | #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 | ||
120 | /* IEEE 802.11i */ | ||
121 | #define WLAN_REASON_INVALID_IE 13 | ||
122 | #define WLAN_REASON_MICHAEL_MIC_FAILURE 14 | ||
123 | #define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 | ||
124 | #define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 | ||
125 | #define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 | ||
126 | #define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 | ||
127 | #define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 | ||
128 | #define WLAN_REASON_AKMP_NOT_VALID 20 | ||
129 | #define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 | ||
130 | #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 | ||
131 | #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 | ||
132 | #define WLAN_REASON_CIPHER_SUITE_REJECTED 24 | ||
133 | |||
134 | |||
135 | /* Information Element IDs */ | ||
136 | #define WLAN_EID_SSID 0 | ||
137 | #define WLAN_EID_SUPP_RATES 1 | ||
138 | #define WLAN_EID_FH_PARAMS 2 | ||
139 | #define WLAN_EID_DS_PARAMS 3 | ||
140 | #define WLAN_EID_CF_PARAMS 4 | ||
141 | #define WLAN_EID_TIM 5 | ||
142 | #define WLAN_EID_IBSS_PARAMS 6 | ||
143 | #define WLAN_EID_CHALLENGE 16 | ||
144 | #define WLAN_EID_RSN 48 | ||
145 | #define WLAN_EID_GENERIC 221 | ||
146 | |||
147 | |||
148 | /* HFA384X Configuration RIDs */ | ||
149 | #define HFA384X_RID_CNFPORTTYPE 0xFC00 | ||
150 | #define HFA384X_RID_CNFOWNMACADDR 0xFC01 | ||
151 | #define HFA384X_RID_CNFDESIREDSSID 0xFC02 | ||
152 | #define HFA384X_RID_CNFOWNCHANNEL 0xFC03 | ||
153 | #define HFA384X_RID_CNFOWNSSID 0xFC04 | ||
154 | #define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 | ||
155 | #define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 | ||
156 | #define HFA384X_RID_CNFMAXDATALEN 0xFC07 | ||
157 | #define HFA384X_RID_CNFWDSADDRESS 0xFC08 | ||
158 | #define HFA384X_RID_CNFPMENABLED 0xFC09 | ||
159 | #define HFA384X_RID_CNFPMEPS 0xFC0A | ||
160 | #define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B | ||
161 | #define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C | ||
162 | #define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D | ||
163 | #define HFA384X_RID_CNFOWNNAME 0xFC0E | ||
164 | #define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 | ||
165 | #define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ | ||
166 | #define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ | ||
167 | #define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ | ||
168 | #define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ | ||
169 | #define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ | ||
170 | #define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ | ||
171 | #define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ | ||
172 | #define HFA384X_RID_UNKNOWN1 0xFC20 | ||
173 | #define HFA384X_RID_UNKNOWN2 0xFC21 | ||
174 | #define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 | ||
175 | #define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 | ||
176 | #define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 | ||
177 | #define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 | ||
178 | #define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 | ||
179 | #define HFA384X_RID_CNFWEPFLAGS 0xFC28 | ||
180 | #define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 | ||
181 | #define HFA384X_RID_CNFAUTHENTICATION 0xFC2A | ||
182 | #define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ | ||
183 | #define HFA384X_RID_CNFTXCONTROL 0xFC2C | ||
184 | #define HFA384X_RID_CNFROAMINGMODE 0xFC2D | ||
185 | #define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ | ||
186 | #define HFA384X_RID_CNFRCVCRCERROR 0xFC30 | ||
187 | #define HFA384X_RID_CNFMMLIFE 0xFC31 | ||
188 | #define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 | ||
189 | #define HFA384X_RID_CNFBEACONINT 0xFC33 | ||
190 | #define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ | ||
191 | #define HFA384X_RID_CNFSTAPCFINFO 0xFC35 | ||
192 | #define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 | ||
193 | #define HFA384X_RID_CNFTIMCTRL 0xFC40 | ||
194 | #define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ | ||
195 | #define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ | ||
196 | #define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ | ||
197 | #define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ | ||
198 | #define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; | ||
199 | * write only */ | ||
200 | #define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ | ||
201 | #define HFA384X_RID_GROUPADDRESSES 0xFC80 | ||
202 | #define HFA384X_RID_CREATEIBSS 0xFC81 | ||
203 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 | ||
204 | #define HFA384X_RID_RTSTHRESHOLD 0xFC83 | ||
205 | #define HFA384X_RID_TXRATECONTROL 0xFC84 | ||
206 | #define HFA384X_RID_PROMISCUOUSMODE 0xFC85 | ||
207 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ | ||
208 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ | ||
209 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ | ||
210 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ | ||
211 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ | ||
212 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ | ||
213 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ | ||
214 | #define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ | ||
215 | #define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ | ||
216 | #define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ | ||
217 | #define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ | ||
218 | #define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ | ||
219 | #define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ | ||
220 | #define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ | ||
221 | #define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ | ||
222 | #define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ | ||
223 | #define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ | ||
224 | #define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ | ||
225 | #define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ | ||
226 | #define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ | ||
227 | #define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ | ||
228 | #define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 | ||
229 | #define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 | ||
230 | #define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 | ||
231 | #define HFA384X_RID_CNFBASICRATES 0xFCB3 | ||
232 | #define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 | ||
233 | #define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ | ||
234 | #define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ | ||
235 | #define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ | ||
236 | #define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ | ||
237 | #define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ | ||
238 | #define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ | ||
239 | #define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ | ||
240 | #define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ | ||
241 | #define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ | ||
242 | #define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ | ||
243 | #define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ | ||
244 | #define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ | ||
245 | #define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ | ||
246 | #define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ | ||
247 | #define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ | ||
248 | #define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ | ||
249 | #define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ | ||
250 | #define HFA384X_RID_TICKTIME 0xFCE0 | ||
251 | #define HFA384X_RID_SCANREQUEST 0xFCE1 | ||
252 | #define HFA384X_RID_JOINREQUEST 0xFCE2 | ||
253 | #define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ | ||
254 | #define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ | ||
255 | #define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ | ||
256 | |||
257 | /* HFA384X Information RIDs */ | ||
258 | #define HFA384X_RID_MAXLOADTIME 0xFD00 | ||
259 | #define HFA384X_RID_DOWNLOADBUFFER 0xFD01 | ||
260 | #define HFA384X_RID_PRIID 0xFD02 | ||
261 | #define HFA384X_RID_PRISUPRANGE 0xFD03 | ||
262 | #define HFA384X_RID_CFIACTRANGES 0xFD04 | ||
263 | #define HFA384X_RID_NICSERNUM 0xFD0A | ||
264 | #define HFA384X_RID_NICID 0xFD0B | ||
265 | #define HFA384X_RID_MFISUPRANGE 0xFD0C | ||
266 | #define HFA384X_RID_CFISUPRANGE 0xFD0D | ||
267 | #define HFA384X_RID_CHANNELLIST 0xFD10 | ||
268 | #define HFA384X_RID_REGULATORYDOMAINS 0xFD11 | ||
269 | #define HFA384X_RID_TEMPTYPE 0xFD12 | ||
270 | #define HFA384X_RID_CIS 0xFD13 | ||
271 | #define HFA384X_RID_STAID 0xFD20 | ||
272 | #define HFA384X_RID_STASUPRANGE 0xFD21 | ||
273 | #define HFA384X_RID_MFIACTRANGES 0xFD22 | ||
274 | #define HFA384X_RID_CFIACTRANGES2 0xFD23 | ||
275 | #define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; | ||
276 | * only Prism2.5(?) */ | ||
277 | #define HFA384X_RID_PORTSTATUS 0xFD40 | ||
278 | #define HFA384X_RID_CURRENTSSID 0xFD41 | ||
279 | #define HFA384X_RID_CURRENTBSSID 0xFD42 | ||
280 | #define HFA384X_RID_COMMSQUALITY 0xFD43 | ||
281 | #define HFA384X_RID_CURRENTTXRATE 0xFD44 | ||
282 | #define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 | ||
283 | #define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 | ||
284 | #define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 | ||
285 | #define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 | ||
286 | #define HFA384X_RID_LONGRETRYLIMIT 0xFD49 | ||
287 | #define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A | ||
288 | #define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B | ||
289 | #define HFA384X_RID_CFPOLLABLE 0xFD4C | ||
290 | #define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D | ||
291 | #define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F | ||
292 | #define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ | ||
293 | #define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ | ||
294 | #define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ | ||
295 | #define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ | ||
296 | #define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ | ||
297 | #define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ | ||
298 | #define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ | ||
299 | #define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ | ||
300 | #define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ | ||
301 | #define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ | ||
302 | #define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ | ||
303 | #define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ | ||
304 | #define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ | ||
305 | #define HFA384X_RID_PHYTYPE 0xFDC0 | ||
306 | #define HFA384X_RID_CURRENTCHANNEL 0xFDC1 | ||
307 | #define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 | ||
308 | #define HFA384X_RID_CCAMODE 0xFDC3 | ||
309 | #define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 | ||
310 | #define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ | ||
311 | #define HFA384X_RID_BUILDSEQ 0xFFFE | ||
312 | #define HFA384X_RID_FWID 0xFFFF | ||
313 | |||
314 | |||
315 | struct hfa384x_comp_ident | ||
316 | { | ||
317 | u16 id; | ||
318 | u16 variant; | ||
319 | u16 major; | ||
320 | u16 minor; | ||
321 | } __attribute__ ((packed)); | ||
322 | |||
323 | #define HFA384X_COMP_ID_PRI 0x15 | ||
324 | #define HFA384X_COMP_ID_STA 0x1f | ||
325 | #define HFA384X_COMP_ID_FW_AP 0x14b | ||
326 | |||
327 | struct hfa384x_sup_range | ||
328 | { | ||
329 | u16 role; | ||
330 | u16 id; | ||
331 | u16 variant; | ||
332 | u16 bottom; | ||
333 | u16 top; | ||
334 | } __attribute__ ((packed)); | ||
335 | |||
336 | |||
337 | struct hfa384x_build_id | ||
338 | { | ||
339 | u16 pri_seq; | ||
340 | u16 sec_seq; | ||
341 | } __attribute__ ((packed)); | ||
342 | |||
343 | /* FD01 - Download Buffer */ | ||
344 | struct hfa384x_rid_download_buffer | ||
345 | { | ||
346 | u16 page; | ||
347 | u16 offset; | ||
348 | u16 length; | ||
349 | } __attribute__ ((packed)); | ||
350 | |||
351 | /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ | ||
352 | struct hfa384x_comms_quality { | ||
353 | u16 comm_qual; /* 0 .. 92 */ | ||
354 | u16 signal_level; /* 27 .. 154 */ | ||
355 | u16 noise_level; /* 27 .. 154 */ | ||
356 | } __attribute__ ((packed)); | ||
357 | |||
358 | |||
359 | /* netdevice private ioctls (used, e.g., with iwpriv from user space) */ | ||
360 | |||
361 | /* New wireless extensions API - SET/GET convention (even ioctl numbers are | ||
362 | * root only) | ||
363 | */ | ||
364 | #define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) | ||
365 | #define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) | ||
366 | #define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) | ||
367 | #define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) | ||
368 | #define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) | ||
369 | #define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) | ||
370 | #define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) | ||
371 | #define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) | ||
372 | #define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) | ||
373 | #define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) | ||
374 | #define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) | ||
375 | #define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) | ||
376 | #define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) | ||
377 | #define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) | ||
378 | |||
379 | /* following are not in SIOCGIWPRIV list; check permission in the driver code | ||
380 | */ | ||
381 | #define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) | ||
382 | #define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) | ||
383 | |||
384 | |||
385 | /* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ | ||
386 | enum { | ||
387 | /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ | ||
388 | PRISM2_PARAM_TXRATECTRL = 2, | ||
389 | PRISM2_PARAM_BEACON_INT = 3, | ||
390 | PRISM2_PARAM_PSEUDO_IBSS = 4, | ||
391 | PRISM2_PARAM_ALC = 5, | ||
392 | /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ | ||
393 | PRISM2_PARAM_DUMP = 7, | ||
394 | PRISM2_PARAM_OTHER_AP_POLICY = 8, | ||
395 | PRISM2_PARAM_AP_MAX_INACTIVITY = 9, | ||
396 | PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, | ||
397 | PRISM2_PARAM_DTIM_PERIOD = 11, | ||
398 | PRISM2_PARAM_AP_NULLFUNC_ACK = 12, | ||
399 | PRISM2_PARAM_MAX_WDS = 13, | ||
400 | PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, | ||
401 | PRISM2_PARAM_AP_AUTH_ALGS = 15, | ||
402 | PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, | ||
403 | PRISM2_PARAM_HOST_ENCRYPT = 17, | ||
404 | PRISM2_PARAM_HOST_DECRYPT = 18, | ||
405 | PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, | ||
406 | PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, | ||
407 | PRISM2_PARAM_HOST_ROAMING = 21, | ||
408 | PRISM2_PARAM_BCRX_STA_KEY = 22, | ||
409 | PRISM2_PARAM_IEEE_802_1X = 23, | ||
410 | PRISM2_PARAM_ANTSEL_TX = 24, | ||
411 | PRISM2_PARAM_ANTSEL_RX = 25, | ||
412 | PRISM2_PARAM_MONITOR_TYPE = 26, | ||
413 | PRISM2_PARAM_WDS_TYPE = 27, | ||
414 | PRISM2_PARAM_HOSTSCAN = 28, | ||
415 | PRISM2_PARAM_AP_SCAN = 29, | ||
416 | PRISM2_PARAM_ENH_SEC = 30, | ||
417 | PRISM2_PARAM_IO_DEBUG = 31, | ||
418 | PRISM2_PARAM_BASIC_RATES = 32, | ||
419 | PRISM2_PARAM_OPER_RATES = 33, | ||
420 | PRISM2_PARAM_HOSTAPD = 34, | ||
421 | PRISM2_PARAM_HOSTAPD_STA = 35, | ||
422 | PRISM2_PARAM_WPA = 36, | ||
423 | PRISM2_PARAM_PRIVACY_INVOKED = 37, | ||
424 | PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, | ||
425 | PRISM2_PARAM_DROP_UNENCRYPTED = 39, | ||
426 | }; | ||
427 | |||
428 | enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, | ||
429 | HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; | ||
430 | |||
431 | |||
432 | /* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ | ||
433 | enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, | ||
434 | AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, | ||
435 | AP_MAC_CMD_KICKALL = 4 }; | ||
436 | |||
437 | |||
438 | /* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ | ||
439 | enum { | ||
440 | PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, | ||
441 | /* Note! Old versions of prism2_srec have a fatal error in CRC-16 | ||
442 | * calculation, which will corrupt all non-volatile downloads. | ||
443 | * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to | ||
444 | * prevent use of old versions of prism2_srec for non-volatile | ||
445 | * download. */ | ||
446 | PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, | ||
447 | PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, | ||
448 | /* Persistent versions of volatile download commands (keep firmware | ||
449 | * data in memory and automatically re-download after hw_reset */ | ||
450 | PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, | ||
451 | PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, | ||
452 | }; | ||
453 | |||
454 | struct prism2_download_param { | ||
455 | u32 dl_cmd; | ||
456 | u32 start_addr; | ||
457 | u32 num_areas; | ||
458 | struct prism2_download_area { | ||
459 | u32 addr; /* wlan card address */ | ||
460 | u32 len; | ||
461 | void __user *ptr; /* pointer to data in user space */ | ||
462 | } data[0]; | ||
463 | }; | ||
464 | |||
465 | #define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 | ||
466 | #define PRISM2_MAX_DOWNLOAD_LEN 262144 | ||
467 | |||
468 | |||
469 | /* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ | ||
470 | enum { | ||
471 | PRISM2_HOSTAPD_FLUSH = 1, | ||
472 | PRISM2_HOSTAPD_ADD_STA = 2, | ||
473 | PRISM2_HOSTAPD_REMOVE_STA = 3, | ||
474 | PRISM2_HOSTAPD_GET_INFO_STA = 4, | ||
475 | /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ | ||
476 | PRISM2_SET_ENCRYPTION = 6, | ||
477 | PRISM2_GET_ENCRYPTION = 7, | ||
478 | PRISM2_HOSTAPD_SET_FLAGS_STA = 8, | ||
479 | PRISM2_HOSTAPD_GET_RID = 9, | ||
480 | PRISM2_HOSTAPD_SET_RID = 10, | ||
481 | PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, | ||
482 | PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, | ||
483 | PRISM2_HOSTAPD_MLME = 13, | ||
484 | PRISM2_HOSTAPD_SCAN_REQ = 14, | ||
485 | PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, | ||
486 | }; | ||
487 | |||
488 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | ||
489 | #define PRISM2_HOSTAPD_RID_HDR_LEN \ | ||
490 | ((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) | ||
491 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | ||
492 | ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) | ||
493 | |||
494 | /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() | ||
495 | */ | ||
496 | #define HOSTAP_CRYPT_ALG_NAME_LEN 16 | ||
497 | |||
498 | |||
499 | struct prism2_hostapd_param { | ||
500 | u32 cmd; | ||
501 | u8 sta_addr[ETH_ALEN]; | ||
502 | union { | ||
503 | struct { | ||
504 | u16 aid; | ||
505 | u16 capability; | ||
506 | u8 tx_supp_rates; | ||
507 | } add_sta; | ||
508 | struct { | ||
509 | u32 inactive_sec; | ||
510 | } get_info_sta; | ||
511 | struct { | ||
512 | u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; | ||
513 | u32 flags; | ||
514 | u32 err; | ||
515 | u8 idx; | ||
516 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
517 | u16 key_len; | ||
518 | u8 key[0]; | ||
519 | } crypt; | ||
520 | struct { | ||
521 | u32 flags_and; | ||
522 | u32 flags_or; | ||
523 | } set_flags_sta; | ||
524 | struct { | ||
525 | u16 rid; | ||
526 | u16 len; | ||
527 | u8 data[0]; | ||
528 | } rid; | ||
529 | struct { | ||
530 | u8 len; | ||
531 | u8 data[0]; | ||
532 | } generic_elem; | ||
533 | struct { | ||
534 | #define MLME_STA_DEAUTH 0 | ||
535 | #define MLME_STA_DISASSOC 1 | ||
536 | u16 cmd; | ||
537 | u16 reason_code; | ||
538 | } mlme; | ||
539 | struct { | ||
540 | u8 ssid_len; | ||
541 | u8 ssid[32]; | ||
542 | } scan_req; | ||
543 | } u; | ||
544 | }; | ||
545 | |||
546 | #define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) | ||
547 | #define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) | ||
548 | |||
549 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 | ||
550 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 | ||
551 | #define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 | ||
552 | #define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 | ||
553 | #define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 | ||
554 | #define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 | ||
555 | |||
556 | |||
557 | #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 00000000000..fcf45781f4a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_config.h | |||
@@ -0,0 +1,86 @@ | |||
1 | #ifndef HOSTAP_CONFIG_H | ||
2 | #define HOSTAP_CONFIG_H | ||
3 | |||
4 | #define PRISM2_VERSION "CVS" | ||
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 | /* Use PCI bus master to copy data to/from BAP (only available for | ||
17 | * hostap_pci.o). | ||
18 | * | ||
19 | * Note! This is extremely experimental. PCI bus master is not supported by | ||
20 | * Intersil and it seems to have some problems at least on TX path (see below). | ||
21 | * The driver code for implementing bus master support is based on guessing | ||
22 | * and experimenting suitable control bits and these might not be correct. | ||
23 | * This code is included because using bus master makes a huge difference in | ||
24 | * host CPU load (something like 40% host CPU usage to 5-10% when sending or | ||
25 | * receiving at maximum throughput). | ||
26 | * | ||
27 | * Note2! Station firmware version 1.3.5 and primary firmware version 1.0.7 | ||
28 | * have some fixes for PCI corruption and these (or newer) versions are | ||
29 | * recommended especially when using bus mastering. | ||
30 | * | ||
31 | * NOTE: PCI bus mastering code has not been updated for long time and it is | ||
32 | * not likely to compile and it will _not_ work as is. Only enable this if you | ||
33 | * are prepared to first fix the implementation.. | ||
34 | */ | ||
35 | /* #define PRISM2_BUS_MASTER */ | ||
36 | |||
37 | #ifdef PRISM2_BUS_MASTER | ||
38 | |||
39 | /* PCI bus master implementation seems to be broken in current | ||
40 | * hardware/firmware versions. Enable this to use enable command to fix | ||
41 | * something before starting bus master operation on TX path. This will add | ||
42 | * some latency and an extra interrupt to each TX packet. */ | ||
43 | #define PRISM2_ENABLE_BEFORE_TX_BUS_MASTER | ||
44 | |||
45 | #endif /* PRISM2_BUS_MASTER */ | ||
46 | |||
47 | /* Include code for downloading firmware images into volatile RAM. */ | ||
48 | #define PRISM2_DOWNLOAD_SUPPORT | ||
49 | |||
50 | /* Allow kernel configuration to enable download support. */ | ||
51 | #if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) | ||
52 | #define PRISM2_DOWNLOAD_SUPPORT | ||
53 | #endif | ||
54 | |||
55 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
56 | /* Allow writing firmware images into flash, i.e., to non-volatile storage. | ||
57 | * Before you enable this option, you should make absolutely sure that you are | ||
58 | * using prism2_srec utility that comes with THIS version of the driver! | ||
59 | * In addition, please note that it is possible to kill your card with | ||
60 | * non-volatile download if you are using incorrect image. This feature has not | ||
61 | * been fully tested, so please be careful with it. */ | ||
62 | /* #define PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
63 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
64 | |||
65 | /* Save low-level I/O for debugging. This should not be enabled in normal use. | ||
66 | */ | ||
67 | /* #define PRISM2_IO_DEBUG */ | ||
68 | |||
69 | /* Following defines can be used to remove unneeded parts of the driver, e.g., | ||
70 | * to limit the size of the kernel module. Definitions can be added here in | ||
71 | * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, | ||
72 | * e.g., | ||
73 | * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' | ||
74 | */ | ||
75 | |||
76 | /* Do not include debug messages into the driver */ | ||
77 | /* #define PRISM2_NO_DEBUG */ | ||
78 | |||
79 | /* Do not include /proc/net/prism2/wlan#/{registers,debug} */ | ||
80 | /* #define PRISM2_NO_PROCFS_DEBUG */ | ||
81 | |||
82 | /* Do not include station functionality (i.e., allow only Master (Host AP) mode | ||
83 | */ | ||
84 | /* #define PRISM2_NO_STATION_MODES */ | ||
85 | |||
86 | #endif /* HOSTAP_CONFIG_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_crypt.c b/drivers/net/wireless/hostap/hostap_crypt.c new file mode 100644 index 00000000000..de5390d502f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_crypt.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Host AP crypto routines | ||
3 | * | ||
4 | * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | struct hostap_crypto_alg { | ||
13 | struct list_head list; | ||
14 | struct hostap_crypto_ops *ops; | ||
15 | }; | ||
16 | |||
17 | |||
18 | struct hostap_crypto { | ||
19 | struct list_head algs; | ||
20 | spinlock_t lock; | ||
21 | }; | ||
22 | |||
23 | static struct hostap_crypto *hcrypt; | ||
24 | |||
25 | |||
26 | int hostap_register_crypto_ops(struct hostap_crypto_ops *ops) | ||
27 | { | ||
28 | unsigned long flags; | ||
29 | struct hostap_crypto_alg *alg; | ||
30 | |||
31 | if (hcrypt == NULL) | ||
32 | return -1; | ||
33 | |||
34 | alg = (struct hostap_crypto_alg *) kmalloc(sizeof(*alg), GFP_KERNEL); | ||
35 | if (alg == NULL) | ||
36 | return -ENOMEM; | ||
37 | |||
38 | memset(alg, 0, sizeof(*alg)); | ||
39 | alg->ops = ops; | ||
40 | |||
41 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
42 | list_add(&alg->list, &hcrypt->algs); | ||
43 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
44 | |||
45 | printk(KERN_DEBUG "hostap_crypt: registered algorithm '%s'\n", | ||
46 | ops->name); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | |||
52 | int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops) | ||
53 | { | ||
54 | unsigned long flags; | ||
55 | struct list_head *ptr; | ||
56 | struct hostap_crypto_alg *del_alg = NULL; | ||
57 | |||
58 | if (hcrypt == NULL) | ||
59 | return -1; | ||
60 | |||
61 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
62 | for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { | ||
63 | struct hostap_crypto_alg *alg = | ||
64 | (struct hostap_crypto_alg *) ptr; | ||
65 | if (alg->ops == ops) { | ||
66 | list_del(&alg->list); | ||
67 | del_alg = alg; | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
72 | |||
73 | if (del_alg) { | ||
74 | printk(KERN_DEBUG "hostap_crypt: unregistered algorithm " | ||
75 | "'%s'\n", ops->name); | ||
76 | kfree(del_alg); | ||
77 | } | ||
78 | |||
79 | return del_alg ? 0 : -1; | ||
80 | } | ||
81 | |||
82 | |||
83 | struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name) | ||
84 | { | ||
85 | unsigned long flags; | ||
86 | struct list_head *ptr; | ||
87 | struct hostap_crypto_alg *found_alg = NULL; | ||
88 | |||
89 | if (hcrypt == NULL) | ||
90 | return NULL; | ||
91 | |||
92 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
93 | for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { | ||
94 | struct hostap_crypto_alg *alg = | ||
95 | (struct hostap_crypto_alg *) ptr; | ||
96 | if (strcmp(alg->ops->name, name) == 0) { | ||
97 | found_alg = alg; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
102 | |||
103 | if (found_alg) | ||
104 | return found_alg->ops; | ||
105 | else | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | |||
110 | static void * hostap_crypt_null_init(int keyidx) { return (void *) 1; } | ||
111 | static void hostap_crypt_null_deinit(void *priv) {} | ||
112 | |||
113 | static struct hostap_crypto_ops hostap_crypt_null = { | ||
114 | .name = "NULL", | ||
115 | .init = hostap_crypt_null_init, | ||
116 | .deinit = hostap_crypt_null_deinit, | ||
117 | .encrypt_mpdu = NULL, | ||
118 | .decrypt_mpdu = NULL, | ||
119 | .encrypt_msdu = NULL, | ||
120 | .decrypt_msdu = NULL, | ||
121 | .set_key = NULL, | ||
122 | .get_key = NULL, | ||
123 | .extra_prefix_len = 0, | ||
124 | .extra_postfix_len = 0 | ||
125 | }; | ||
126 | |||
127 | |||
128 | static int __init hostap_crypto_init(void) | ||
129 | { | ||
130 | hcrypt = (struct hostap_crypto *) kmalloc(sizeof(*hcrypt), GFP_KERNEL); | ||
131 | if (hcrypt == NULL) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | memset(hcrypt, 0, sizeof(*hcrypt)); | ||
135 | INIT_LIST_HEAD(&hcrypt->algs); | ||
136 | spin_lock_init(&hcrypt->lock); | ||
137 | |||
138 | (void) hostap_register_crypto_ops(&hostap_crypt_null); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | |||
144 | static void __exit hostap_crypto_deinit(void) | ||
145 | { | ||
146 | struct list_head *ptr, *n; | ||
147 | |||
148 | if (hcrypt == NULL) | ||
149 | return; | ||
150 | |||
151 | for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; | ||
152 | ptr = n, n = ptr->next) { | ||
153 | struct hostap_crypto_alg *alg = | ||
154 | (struct hostap_crypto_alg *) ptr; | ||
155 | list_del(ptr); | ||
156 | printk(KERN_DEBUG "hostap_crypt: unregistered algorithm " | ||
157 | "'%s' (deinit)\n", alg->ops->name); | ||
158 | kfree(alg); | ||
159 | } | ||
160 | |||
161 | kfree(hcrypt); | ||
162 | } | ||
163 | |||
164 | |||
165 | EXPORT_SYMBOL(hostap_register_crypto_ops); | ||
166 | EXPORT_SYMBOL(hostap_unregister_crypto_ops); | ||
167 | EXPORT_SYMBOL(hostap_get_crypto_ops); | ||
diff --git a/drivers/net/wireless/hostap/hostap_crypt.h b/drivers/net/wireless/hostap/hostap_crypt.h new file mode 100644 index 00000000000..45d66d0323b --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_crypt.h | |||
@@ -0,0 +1,50 @@ | |||
1 | #ifndef PRISM2_CRYPT_H | ||
2 | #define PRISM2_CRYPT_H | ||
3 | |||
4 | struct hostap_crypto_ops { | ||
5 | char *name; | ||
6 | |||
7 | /* init new crypto context (e.g., allocate private data space, | ||
8 | * select IV, etc.); returns NULL on failure or pointer to allocated | ||
9 | * private data on success */ | ||
10 | void * (*init)(int keyidx); | ||
11 | |||
12 | /* deinitialize crypto context and free allocated private data */ | ||
13 | void (*deinit)(void *priv); | ||
14 | |||
15 | /* encrypt/decrypt return < 0 on error or >= 0 on success. The return | ||
16 | * value from decrypt_mpdu is passed as the keyidx value for | ||
17 | * decrypt_msdu. skb must have enough head and tail room for the | ||
18 | * encryption; if not, error will be returned; these functions are | ||
19 | * called for all MPDUs (i.e., fragments). | ||
20 | */ | ||
21 | int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); | ||
22 | int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); | ||
23 | |||
24 | /* These functions are called for full MSDUs, i.e. full frames. | ||
25 | * These can be NULL if full MSDU operations are not needed. */ | ||
26 | int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); | ||
27 | int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, | ||
28 | void *priv); | ||
29 | |||
30 | int (*set_key)(void *key, int len, u8 *seq, void *priv); | ||
31 | int (*get_key)(void *key, int len, u8 *seq, void *priv); | ||
32 | |||
33 | /* procfs handler for printing out key information and possible | ||
34 | * statistics */ | ||
35 | char * (*print_stats)(char *p, void *priv); | ||
36 | |||
37 | /* maximum number of bytes added by encryption; encrypt buf is | ||
38 | * allocated with extra_prefix_len bytes, copy of in_buf, and | ||
39 | * extra_postfix_len; encrypt need not use all this space, but | ||
40 | * the result must start at the beginning of the buffer and correct | ||
41 | * length must be returned */ | ||
42 | int extra_prefix_len, extra_postfix_len; | ||
43 | }; | ||
44 | |||
45 | |||
46 | int hostap_register_crypto_ops(struct hostap_crypto_ops *ops); | ||
47 | int hostap_unregister_crypto_ops(struct hostap_crypto_ops *ops); | ||
48 | struct hostap_crypto_ops * hostap_get_crypto_ops(const char *name); | ||
49 | |||
50 | #endif /* PRISM2_CRYPT_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_crypt_ccmp.c b/drivers/net/wireless/hostap/hostap_crypt_ccmp.c new file mode 100644 index 00000000000..e95bcc73dbf --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_crypt_ccmp.c | |||
@@ -0,0 +1,486 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based CCMP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <linux/wireless.h> | ||
23 | #include <net/iw_handler.h> | ||
24 | #include <asm/string.h> | ||
25 | |||
26 | #include "hostap_crypt.h" | ||
27 | #include "hostap_wlan.h" | ||
28 | #include "hostap_80211.h" | ||
29 | |||
30 | #ifndef CONFIG_CRYPTO | ||
31 | #error CONFIG_CRYPTO is required to build this module. | ||
32 | #endif | ||
33 | #include <linux/crypto.h> | ||
34 | #include <asm/scatterlist.h> | ||
35 | |||
36 | MODULE_AUTHOR("Jouni Malinen"); | ||
37 | MODULE_DESCRIPTION("Host AP crypt: CCMP"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | |||
40 | |||
41 | #define AES_BLOCK_LEN 16 | ||
42 | #define CCMP_HDR_LEN 8 | ||
43 | #define CCMP_MIC_LEN 8 | ||
44 | #define CCMP_TK_LEN 16 | ||
45 | #define CCMP_PN_LEN 6 | ||
46 | |||
47 | |||
48 | struct hostap_ccmp_data { | ||
49 | u8 key[CCMP_TK_LEN]; | ||
50 | int key_set; | ||
51 | |||
52 | u8 tx_pn[CCMP_PN_LEN]; | ||
53 | u8 rx_pn[CCMP_PN_LEN]; | ||
54 | |||
55 | u32 dot11RSNAStatsCCMPFormatErrors; | ||
56 | u32 dot11RSNAStatsCCMPReplays; | ||
57 | u32 dot11RSNAStatsCCMPDecryptErrors; | ||
58 | |||
59 | int key_idx; | ||
60 | |||
61 | struct crypto_tfm *tfm; | ||
62 | |||
63 | /* scratch buffers for virt_to_page() (crypto API) */ | ||
64 | u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], | ||
65 | tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; | ||
66 | u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; | ||
67 | }; | ||
68 | |||
69 | |||
70 | void hostap_ccmp_aes_encrypt(struct crypto_tfm *tfm, | ||
71 | const u8 pt[16], u8 ct[16]) | ||
72 | { | ||
73 | struct scatterlist src, dst; | ||
74 | |||
75 | src.page = virt_to_page(pt); | ||
76 | src.offset = offset_in_page(pt); | ||
77 | src.length = AES_BLOCK_LEN; | ||
78 | |||
79 | dst.page = virt_to_page(ct); | ||
80 | dst.offset = offset_in_page(ct); | ||
81 | dst.length = AES_BLOCK_LEN; | ||
82 | |||
83 | crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); | ||
84 | } | ||
85 | |||
86 | |||
87 | static void * hostap_ccmp_init(int key_idx) | ||
88 | { | ||
89 | struct hostap_ccmp_data *priv; | ||
90 | |||
91 | if (!try_module_get(THIS_MODULE)) | ||
92 | return NULL; | ||
93 | |||
94 | priv = (struct hostap_ccmp_data *) kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
95 | if (priv == NULL) { | ||
96 | goto fail; | ||
97 | } | ||
98 | memset(priv, 0, sizeof(*priv)); | ||
99 | priv->key_idx = key_idx; | ||
100 | |||
101 | priv->tfm = crypto_alloc_tfm("aes", 0); | ||
102 | if (priv->tfm == NULL) { | ||
103 | printk(KERN_DEBUG "hostap_crypt_ccmp: could not allocate " | ||
104 | "crypto API aes\n"); | ||
105 | goto fail; | ||
106 | } | ||
107 | |||
108 | return priv; | ||
109 | |||
110 | fail: | ||
111 | if (priv) { | ||
112 | if (priv->tfm) | ||
113 | crypto_free_tfm(priv->tfm); | ||
114 | kfree(priv); | ||
115 | } | ||
116 | module_put(THIS_MODULE); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | |||
121 | static void hostap_ccmp_deinit(void *priv) | ||
122 | { | ||
123 | struct hostap_ccmp_data *_priv = priv; | ||
124 | if (_priv && _priv->tfm) | ||
125 | crypto_free_tfm(_priv->tfm); | ||
126 | kfree(priv); | ||
127 | module_put(THIS_MODULE); | ||
128 | } | ||
129 | |||
130 | |||
131 | static inline void xor_block(u8 *b, u8 *a, size_t len) | ||
132 | { | ||
133 | int i; | ||
134 | for (i = 0; i < len; i++) | ||
135 | b[i] ^= a[i]; | ||
136 | } | ||
137 | |||
138 | |||
139 | static void ccmp_init_blocks(struct crypto_tfm *tfm, | ||
140 | struct hostap_ieee80211_hdr *hdr, | ||
141 | u8 *pn, size_t dlen, u8 *b0, u8 *auth, | ||
142 | u8 *s0) | ||
143 | { | ||
144 | u8 *pos, qc = 0; | ||
145 | size_t aad_len; | ||
146 | u16 fc; | ||
147 | int a4_included, qc_included; | ||
148 | u8 aad[2 * AES_BLOCK_LEN]; | ||
149 | |||
150 | fc = le16_to_cpu(hdr->frame_control); | ||
151 | a4_included = ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == | ||
152 | (WLAN_FC_TODS | WLAN_FC_FROMDS)); | ||
153 | qc_included = ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) && | ||
154 | (WLAN_FC_GET_STYPE(fc) & 0x08)); | ||
155 | aad_len = 22; | ||
156 | if (a4_included) | ||
157 | aad_len += 6; | ||
158 | if (qc_included) { | ||
159 | pos = (u8 *) &hdr->addr4; | ||
160 | if (a4_included) | ||
161 | pos += 6; | ||
162 | qc = *pos & 0x0f; | ||
163 | aad_len += 2; | ||
164 | } | ||
165 | |||
166 | /* CCM Initial Block: | ||
167 | * Flag (Include authentication header, M=3 (8-octet MIC), | ||
168 | * L=1 (2-octet Dlen)) | ||
169 | * Nonce: 0x00 | A2 | PN | ||
170 | * Dlen */ | ||
171 | b0[0] = 0x59; | ||
172 | b0[1] = qc; | ||
173 | memcpy(b0 + 2, hdr->addr2, ETH_ALEN); | ||
174 | memcpy(b0 + 8, pn, CCMP_PN_LEN); | ||
175 | b0[14] = (dlen >> 8) & 0xff; | ||
176 | b0[15] = dlen & 0xff; | ||
177 | |||
178 | /* AAD: | ||
179 | * FC with bits 4..6 and 11..13 masked to zero; 14 is always one | ||
180 | * A1 | A2 | A3 | ||
181 | * SC with bits 4..15 (seq#) masked to zero | ||
182 | * A4 (if present) | ||
183 | * QC (if present) | ||
184 | */ | ||
185 | pos = (u8 *) hdr; | ||
186 | aad[0] = 0; /* aad_len >> 8 */ | ||
187 | aad[1] = aad_len & 0xff; | ||
188 | aad[2] = pos[0] & 0x8f; | ||
189 | aad[3] = pos[1] & 0xc7; | ||
190 | memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); | ||
191 | pos = (u8 *) &hdr->seq_ctrl; | ||
192 | aad[22] = pos[0] & 0x0f; | ||
193 | aad[23] = 0; /* all bits masked */ | ||
194 | memset(aad + 24, 0, 8); | ||
195 | if (a4_included) | ||
196 | memcpy(aad + 24, hdr->addr4, ETH_ALEN); | ||
197 | if (qc_included) { | ||
198 | aad[a4_included ? 30 : 24] = qc; | ||
199 | /* rest of QC masked */ | ||
200 | } | ||
201 | |||
202 | /* Start with the first block and AAD */ | ||
203 | hostap_ccmp_aes_encrypt(tfm, b0, auth); | ||
204 | xor_block(auth, aad, AES_BLOCK_LEN); | ||
205 | hostap_ccmp_aes_encrypt(tfm, auth, auth); | ||
206 | xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); | ||
207 | hostap_ccmp_aes_encrypt(tfm, auth, auth); | ||
208 | b0[0] &= 0x07; | ||
209 | b0[14] = b0[15] = 0; | ||
210 | hostap_ccmp_aes_encrypt(tfm, b0, s0); | ||
211 | } | ||
212 | |||
213 | |||
214 | static int hostap_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
215 | { | ||
216 | struct hostap_ccmp_data *key = priv; | ||
217 | int data_len, i, blocks, last, len; | ||
218 | u8 *pos, *mic; | ||
219 | struct hostap_ieee80211_hdr *hdr; | ||
220 | u8 *b0 = key->tx_b0; | ||
221 | u8 *b = key->tx_b; | ||
222 | u8 *e = key->tx_e; | ||
223 | u8 *s0 = key->tx_s0; | ||
224 | |||
225 | if (skb_headroom(skb) < CCMP_HDR_LEN || | ||
226 | skb_tailroom(skb) < CCMP_MIC_LEN || | ||
227 | skb->len < hdr_len) | ||
228 | return -1; | ||
229 | |||
230 | data_len = skb->len - hdr_len; | ||
231 | pos = skb_push(skb, CCMP_HDR_LEN); | ||
232 | memmove(pos, pos + CCMP_HDR_LEN, hdr_len); | ||
233 | pos += hdr_len; | ||
234 | mic = skb_put(skb, CCMP_MIC_LEN); | ||
235 | |||
236 | i = CCMP_PN_LEN - 1; | ||
237 | while (i >= 0) { | ||
238 | key->tx_pn[i]++; | ||
239 | if (key->tx_pn[i] != 0) | ||
240 | break; | ||
241 | i--; | ||
242 | } | ||
243 | |||
244 | *pos++ = key->tx_pn[5]; | ||
245 | *pos++ = key->tx_pn[4]; | ||
246 | *pos++ = 0; | ||
247 | *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; | ||
248 | *pos++ = key->tx_pn[3]; | ||
249 | *pos++ = key->tx_pn[2]; | ||
250 | *pos++ = key->tx_pn[1]; | ||
251 | *pos++ = key->tx_pn[0]; | ||
252 | |||
253 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
254 | ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); | ||
255 | |||
256 | blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; | ||
257 | last = data_len % AES_BLOCK_LEN; | ||
258 | |||
259 | for (i = 1; i <= blocks; i++) { | ||
260 | len = (i == blocks && last) ? last : AES_BLOCK_LEN; | ||
261 | /* Authentication */ | ||
262 | xor_block(b, pos, len); | ||
263 | hostap_ccmp_aes_encrypt(key->tfm, b, b); | ||
264 | /* Encryption, with counter */ | ||
265 | b0[14] = (i >> 8) & 0xff; | ||
266 | b0[15] = i & 0xff; | ||
267 | hostap_ccmp_aes_encrypt(key->tfm, b0, e); | ||
268 | xor_block(pos, e, len); | ||
269 | pos += len; | ||
270 | } | ||
271 | |||
272 | for (i = 0; i < CCMP_MIC_LEN; i++) | ||
273 | mic[i] = b[i] ^ s0[i]; | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | |||
279 | static int hostap_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
280 | { | ||
281 | struct hostap_ccmp_data *key = priv; | ||
282 | u8 keyidx, *pos; | ||
283 | struct hostap_ieee80211_hdr *hdr; | ||
284 | u8 *b0 = key->rx_b0; | ||
285 | u8 *b = key->rx_b; | ||
286 | u8 *a = key->rx_a; | ||
287 | u8 pn[6]; | ||
288 | int i, blocks, last, len; | ||
289 | size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; | ||
290 | u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; | ||
291 | |||
292 | if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { | ||
293 | key->dot11RSNAStatsCCMPFormatErrors++; | ||
294 | return -1; | ||
295 | } | ||
296 | |||
297 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
298 | pos = skb->data + hdr_len; | ||
299 | keyidx = pos[3]; | ||
300 | if (!(keyidx & (1 << 5))) { | ||
301 | if (net_ratelimit()) { | ||
302 | printk(KERN_DEBUG "CCMP: received packet without ExtIV" | ||
303 | " flag from " MACSTR "\n", MAC2STR(hdr->addr2)); | ||
304 | } | ||
305 | key->dot11RSNAStatsCCMPFormatErrors++; | ||
306 | return -2; | ||
307 | } | ||
308 | keyidx >>= 6; | ||
309 | if (key->key_idx != keyidx) { | ||
310 | printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " | ||
311 | "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); | ||
312 | return -6; | ||
313 | } | ||
314 | if (!key->key_set) { | ||
315 | if (net_ratelimit()) { | ||
316 | printk(KERN_DEBUG "CCMP: received packet from " MACSTR | ||
317 | " with keyid=%d that does not have a configured" | ||
318 | " key\n", MAC2STR(hdr->addr2), keyidx); | ||
319 | } | ||
320 | return -3; | ||
321 | } | ||
322 | |||
323 | pn[0] = pos[7]; | ||
324 | pn[1] = pos[6]; | ||
325 | pn[2] = pos[5]; | ||
326 | pn[3] = pos[4]; | ||
327 | pn[4] = pos[1]; | ||
328 | pn[5] = pos[0]; | ||
329 | pos += 8; | ||
330 | |||
331 | if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { | ||
332 | if (net_ratelimit()) { | ||
333 | printk(KERN_DEBUG "CCMP: replay detected: STA=" MACSTR | ||
334 | " previous PN %02x%02x%02x%02x%02x%02x " | ||
335 | "received PN %02x%02x%02x%02x%02x%02x\n", | ||
336 | MAC2STR(hdr->addr2), MAC2STR(key->rx_pn), | ||
337 | MAC2STR(pn)); | ||
338 | } | ||
339 | key->dot11RSNAStatsCCMPReplays++; | ||
340 | return -4; | ||
341 | } | ||
342 | |||
343 | ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); | ||
344 | xor_block(mic, b, CCMP_MIC_LEN); | ||
345 | |||
346 | blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; | ||
347 | last = data_len % AES_BLOCK_LEN; | ||
348 | |||
349 | for (i = 1; i <= blocks; i++) { | ||
350 | len = (i == blocks && last) ? last : AES_BLOCK_LEN; | ||
351 | /* Decrypt, with counter */ | ||
352 | b0[14] = (i >> 8) & 0xff; | ||
353 | b0[15] = i & 0xff; | ||
354 | hostap_ccmp_aes_encrypt(key->tfm, b0, b); | ||
355 | xor_block(pos, b, len); | ||
356 | /* Authentication */ | ||
357 | xor_block(a, pos, len); | ||
358 | hostap_ccmp_aes_encrypt(key->tfm, a, a); | ||
359 | pos += len; | ||
360 | } | ||
361 | |||
362 | if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { | ||
363 | if (net_ratelimit()) { | ||
364 | printk(KERN_DEBUG "CCMP: decrypt failed: STA=" | ||
365 | MACSTR "\n", MAC2STR(hdr->addr2)); | ||
366 | } | ||
367 | key->dot11RSNAStatsCCMPDecryptErrors++; | ||
368 | return -5; | ||
369 | } | ||
370 | |||
371 | memcpy(key->rx_pn, pn, CCMP_PN_LEN); | ||
372 | |||
373 | /* Remove hdr and MIC */ | ||
374 | memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); | ||
375 | skb_pull(skb, CCMP_HDR_LEN); | ||
376 | skb_trim(skb, skb->len - CCMP_MIC_LEN); | ||
377 | |||
378 | return keyidx; | ||
379 | } | ||
380 | |||
381 | |||
382 | static int hostap_ccmp_set_key(void *key, int len, u8 *seq, void *priv) | ||
383 | { | ||
384 | struct hostap_ccmp_data *data = priv; | ||
385 | int keyidx; | ||
386 | struct crypto_tfm *tfm = data->tfm; | ||
387 | |||
388 | keyidx = data->key_idx; | ||
389 | memset(data, 0, sizeof(*data)); | ||
390 | data->key_idx = keyidx; | ||
391 | data->tfm = tfm; | ||
392 | if (len == CCMP_TK_LEN) { | ||
393 | memcpy(data->key, key, CCMP_TK_LEN); | ||
394 | data->key_set = 1; | ||
395 | if (seq) { | ||
396 | data->rx_pn[0] = seq[5]; | ||
397 | data->rx_pn[1] = seq[4]; | ||
398 | data->rx_pn[2] = seq[3]; | ||
399 | data->rx_pn[3] = seq[2]; | ||
400 | data->rx_pn[4] = seq[1]; | ||
401 | data->rx_pn[5] = seq[0]; | ||
402 | } | ||
403 | crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN); | ||
404 | } else if (len == 0) { | ||
405 | data->key_set = 0; | ||
406 | } else | ||
407 | return -1; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | |||
413 | static int hostap_ccmp_get_key(void *key, int len, u8 *seq, void *priv) | ||
414 | { | ||
415 | struct hostap_ccmp_data *data = priv; | ||
416 | |||
417 | if (len < CCMP_TK_LEN) | ||
418 | return -1; | ||
419 | |||
420 | if (!data->key_set) | ||
421 | return 0; | ||
422 | memcpy(key, data->key, CCMP_TK_LEN); | ||
423 | |||
424 | if (seq) { | ||
425 | seq[0] = data->tx_pn[5]; | ||
426 | seq[1] = data->tx_pn[4]; | ||
427 | seq[2] = data->tx_pn[3]; | ||
428 | seq[3] = data->tx_pn[2]; | ||
429 | seq[4] = data->tx_pn[1]; | ||
430 | seq[5] = data->tx_pn[0]; | ||
431 | } | ||
432 | |||
433 | return CCMP_TK_LEN; | ||
434 | } | ||
435 | |||
436 | |||
437 | static char * hostap_ccmp_print_stats(char *p, void *priv) | ||
438 | { | ||
439 | struct hostap_ccmp_data *ccmp = priv; | ||
440 | p += sprintf(p, "key[%d] alg=CCMP key_set=%d " | ||
441 | "tx_pn=%02x%02x%02x%02x%02x%02x " | ||
442 | "rx_pn=%02x%02x%02x%02x%02x%02x " | ||
443 | "format_errors=%d replays=%d decrypt_errors=%d\n", | ||
444 | ccmp->key_idx, ccmp->key_set, | ||
445 | MAC2STR(ccmp->tx_pn), MAC2STR(ccmp->rx_pn), | ||
446 | ccmp->dot11RSNAStatsCCMPFormatErrors, | ||
447 | ccmp->dot11RSNAStatsCCMPReplays, | ||
448 | ccmp->dot11RSNAStatsCCMPDecryptErrors); | ||
449 | |||
450 | return p; | ||
451 | } | ||
452 | |||
453 | |||
454 | static struct hostap_crypto_ops hostap_crypt_ccmp = { | ||
455 | .name = "CCMP", | ||
456 | .init = hostap_ccmp_init, | ||
457 | .deinit = hostap_ccmp_deinit, | ||
458 | .encrypt_mpdu = hostap_ccmp_encrypt, | ||
459 | .decrypt_mpdu = hostap_ccmp_decrypt, | ||
460 | .encrypt_msdu = NULL, | ||
461 | .decrypt_msdu = NULL, | ||
462 | .set_key = hostap_ccmp_set_key, | ||
463 | .get_key = hostap_ccmp_get_key, | ||
464 | .print_stats = hostap_ccmp_print_stats, | ||
465 | .extra_prefix_len = CCMP_HDR_LEN, | ||
466 | .extra_postfix_len = CCMP_MIC_LEN | ||
467 | }; | ||
468 | |||
469 | |||
470 | static int __init hostap_crypto_ccmp_init(void) | ||
471 | { | ||
472 | if (hostap_register_crypto_ops(&hostap_crypt_ccmp) < 0) | ||
473 | return -1; | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | |||
479 | static void __exit hostap_crypto_ccmp_exit(void) | ||
480 | { | ||
481 | hostap_unregister_crypto_ops(&hostap_crypt_ccmp); | ||
482 | } | ||
483 | |||
484 | |||
485 | module_init(hostap_crypto_ccmp_init); | ||
486 | module_exit(hostap_crypto_ccmp_exit); | ||
diff --git a/drivers/net/wireless/hostap/hostap_crypt_tkip.c b/drivers/net/wireless/hostap/hostap_crypt_tkip.c new file mode 100644 index 00000000000..e8d56bc280a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_crypt_tkip.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based TKIP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <linux/wireless.h> | ||
23 | #include <net/iw_handler.h> | ||
24 | #include <asm/string.h> | ||
25 | |||
26 | #include "hostap_crypt.h" | ||
27 | #include "hostap_wlan.h" | ||
28 | #include "hostap_80211.h" | ||
29 | #include "hostap_config.h" | ||
30 | |||
31 | #ifndef CONFIG_CRYPTO | ||
32 | #error CONFIG_CRYPTO is required to build this module. | ||
33 | #endif | ||
34 | #include <linux/crypto.h> | ||
35 | #include <asm/scatterlist.h> | ||
36 | #include <linux/crc32.h> | ||
37 | |||
38 | MODULE_AUTHOR("Jouni Malinen"); | ||
39 | MODULE_DESCRIPTION("Host AP crypt: TKIP"); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | |||
42 | |||
43 | struct hostap_tkip_data { | ||
44 | #define TKIP_KEY_LEN 32 | ||
45 | u8 key[TKIP_KEY_LEN]; | ||
46 | int key_set; | ||
47 | |||
48 | u32 tx_iv32; | ||
49 | u16 tx_iv16; | ||
50 | u16 tx_ttak[5]; | ||
51 | int tx_phase1_done; | ||
52 | |||
53 | u32 rx_iv32; | ||
54 | u16 rx_iv16; | ||
55 | u16 rx_ttak[5]; | ||
56 | int rx_phase1_done; | ||
57 | u32 rx_iv32_new; | ||
58 | u16 rx_iv16_new; | ||
59 | |||
60 | u32 dot11RSNAStatsTKIPReplays; | ||
61 | u32 dot11RSNAStatsTKIPICVErrors; | ||
62 | u32 dot11RSNAStatsTKIPLocalMICFailures; | ||
63 | |||
64 | int key_idx; | ||
65 | |||
66 | struct crypto_tfm *tfm_arc4; | ||
67 | struct crypto_tfm *tfm_michael; | ||
68 | |||
69 | /* scratch buffers for virt_to_page() (crypto API) */ | ||
70 | u8 rx_hdr[16], tx_hdr[16]; | ||
71 | }; | ||
72 | |||
73 | |||
74 | static void * hostap_tkip_init(int key_idx) | ||
75 | { | ||
76 | struct hostap_tkip_data *priv; | ||
77 | |||
78 | if (!try_module_get(THIS_MODULE)) | ||
79 | return NULL; | ||
80 | |||
81 | priv = (struct hostap_tkip_data *) kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
82 | if (priv == NULL) | ||
83 | goto fail; | ||
84 | memset(priv, 0, sizeof(*priv)); | ||
85 | priv->key_idx = key_idx; | ||
86 | |||
87 | priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); | ||
88 | if (priv->tfm_arc4 == NULL) { | ||
89 | printk(KERN_DEBUG "hostap_crypt_tkip: could not allocate " | ||
90 | "crypto API arc4\n"); | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); | ||
95 | if (priv->tfm_michael == NULL) { | ||
96 | printk(KERN_DEBUG "hostap_crypt_tkip: could not allocate " | ||
97 | "crypto API michael_mic\n"); | ||
98 | goto fail; | ||
99 | } | ||
100 | |||
101 | return priv; | ||
102 | |||
103 | fail: | ||
104 | if (priv) { | ||
105 | if (priv->tfm_michael) | ||
106 | crypto_free_tfm(priv->tfm_michael); | ||
107 | if (priv->tfm_arc4) | ||
108 | crypto_free_tfm(priv->tfm_arc4); | ||
109 | kfree(priv); | ||
110 | } | ||
111 | module_put(THIS_MODULE); | ||
112 | return NULL; | ||
113 | } | ||
114 | |||
115 | |||
116 | static void hostap_tkip_deinit(void *priv) | ||
117 | { | ||
118 | struct hostap_tkip_data *_priv = priv; | ||
119 | if (_priv && _priv->tfm_michael) | ||
120 | crypto_free_tfm(_priv->tfm_michael); | ||
121 | if (_priv && _priv->tfm_arc4) | ||
122 | crypto_free_tfm(_priv->tfm_arc4); | ||
123 | kfree(priv); | ||
124 | module_put(THIS_MODULE); | ||
125 | } | ||
126 | |||
127 | |||
128 | static inline u16 RotR1(u16 val) | ||
129 | { | ||
130 | return (val >> 1) | (val << 15); | ||
131 | } | ||
132 | |||
133 | |||
134 | static inline u8 Lo8(u16 val) | ||
135 | { | ||
136 | return val & 0xff; | ||
137 | } | ||
138 | |||
139 | |||
140 | static inline u8 Hi8(u16 val) | ||
141 | { | ||
142 | return val >> 8; | ||
143 | } | ||
144 | |||
145 | |||
146 | static inline u16 Lo16(u32 val) | ||
147 | { | ||
148 | return val & 0xffff; | ||
149 | } | ||
150 | |||
151 | |||
152 | static inline u16 Hi16(u32 val) | ||
153 | { | ||
154 | return val >> 16; | ||
155 | } | ||
156 | |||
157 | |||
158 | static inline u16 Mk16(u8 hi, u8 lo) | ||
159 | { | ||
160 | return lo | (((u16) hi) << 8); | ||
161 | } | ||
162 | |||
163 | |||
164 | static inline u16 Mk16_le(u16 *v) | ||
165 | { | ||
166 | return le16_to_cpu(*v); | ||
167 | } | ||
168 | |||
169 | |||
170 | static const u16 Sbox[256] = | ||
171 | { | ||
172 | 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, | ||
173 | 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, | ||
174 | 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, | ||
175 | 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, | ||
176 | 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, | ||
177 | 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, | ||
178 | 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, | ||
179 | 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, | ||
180 | 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, | ||
181 | 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, | ||
182 | 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, | ||
183 | 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, | ||
184 | 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, | ||
185 | 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, | ||
186 | 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, | ||
187 | 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, | ||
188 | 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, | ||
189 | 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, | ||
190 | 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, | ||
191 | 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, | ||
192 | 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, | ||
193 | 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, | ||
194 | 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, | ||
195 | 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, | ||
196 | 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, | ||
197 | 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, | ||
198 | 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, | ||
199 | 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, | ||
200 | 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, | ||
201 | 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, | ||
202 | 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, | ||
203 | 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, | ||
204 | }; | ||
205 | |||
206 | |||
207 | static inline u16 _S_(u16 v) | ||
208 | { | ||
209 | u16 t = Sbox[Hi8(v)]; | ||
210 | return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); | ||
211 | } | ||
212 | |||
213 | |||
214 | #define PHASE1_LOOP_COUNT 8 | ||
215 | |||
216 | static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) | ||
217 | { | ||
218 | int i, j; | ||
219 | |||
220 | /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ | ||
221 | TTAK[0] = Lo16(IV32); | ||
222 | TTAK[1] = Hi16(IV32); | ||
223 | TTAK[2] = Mk16(TA[1], TA[0]); | ||
224 | TTAK[3] = Mk16(TA[3], TA[2]); | ||
225 | TTAK[4] = Mk16(TA[5], TA[4]); | ||
226 | |||
227 | for (i = 0; i < PHASE1_LOOP_COUNT; i++) { | ||
228 | j = 2 * (i & 1); | ||
229 | TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); | ||
230 | TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); | ||
231 | TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); | ||
232 | TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); | ||
233 | TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | |||
238 | static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, | ||
239 | u16 IV16) | ||
240 | { | ||
241 | /* Make temporary area overlap WEP seed so that the final copy can be | ||
242 | * avoided on little endian hosts. */ | ||
243 | u16 *PPK = (u16 *) &WEPSeed[4]; | ||
244 | |||
245 | /* Step 1 - make copy of TTAK and bring in TSC */ | ||
246 | PPK[0] = TTAK[0]; | ||
247 | PPK[1] = TTAK[1]; | ||
248 | PPK[2] = TTAK[2]; | ||
249 | PPK[3] = TTAK[3]; | ||
250 | PPK[4] = TTAK[4]; | ||
251 | PPK[5] = TTAK[4] + IV16; | ||
252 | |||
253 | /* Step 2 - 96-bit bijective mixing using S-box */ | ||
254 | PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); | ||
255 | PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); | ||
256 | PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); | ||
257 | PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); | ||
258 | PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); | ||
259 | PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); | ||
260 | |||
261 | PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); | ||
262 | PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); | ||
263 | PPK[2] += RotR1(PPK[1]); | ||
264 | PPK[3] += RotR1(PPK[2]); | ||
265 | PPK[4] += RotR1(PPK[3]); | ||
266 | PPK[5] += RotR1(PPK[4]); | ||
267 | |||
268 | /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value | ||
269 | * WEPSeed[0..2] is transmitted as WEP IV */ | ||
270 | WEPSeed[0] = Hi8(IV16); | ||
271 | WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; | ||
272 | WEPSeed[2] = Lo8(IV16); | ||
273 | WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); | ||
274 | |||
275 | #ifdef __BIG_ENDIAN | ||
276 | { | ||
277 | int i; | ||
278 | for (i = 0; i < 6; i++) | ||
279 | PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); | ||
280 | } | ||
281 | #endif | ||
282 | } | ||
283 | |||
284 | |||
285 | static int hostap_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
286 | { | ||
287 | struct hostap_tkip_data *tkey = priv; | ||
288 | int len; | ||
289 | u8 rc4key[16], *pos, *icv; | ||
290 | struct hostap_ieee80211_hdr *hdr; | ||
291 | u32 crc; | ||
292 | struct scatterlist sg; | ||
293 | |||
294 | if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || | ||
295 | skb->len < hdr_len) | ||
296 | return -1; | ||
297 | |||
298 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
299 | if (!tkey->tx_phase1_done) { | ||
300 | tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, | ||
301 | tkey->tx_iv32); | ||
302 | tkey->tx_phase1_done = 1; | ||
303 | } | ||
304 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); | ||
305 | |||
306 | len = skb->len - hdr_len; | ||
307 | pos = skb_push(skb, 8); | ||
308 | memmove(pos, pos + 8, hdr_len); | ||
309 | pos += hdr_len; | ||
310 | icv = skb_put(skb, 4); | ||
311 | |||
312 | *pos++ = rc4key[0]; | ||
313 | *pos++ = rc4key[1]; | ||
314 | *pos++ = rc4key[2]; | ||
315 | *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; | ||
316 | *pos++ = tkey->tx_iv32 & 0xff; | ||
317 | *pos++ = (tkey->tx_iv32 >> 8) & 0xff; | ||
318 | *pos++ = (tkey->tx_iv32 >> 16) & 0xff; | ||
319 | *pos++ = (tkey->tx_iv32 >> 24) & 0xff; | ||
320 | |||
321 | crc = ~crc32_le(~0, pos, len); | ||
322 | icv[0] = crc; | ||
323 | icv[1] = crc >> 8; | ||
324 | icv[2] = crc >> 16; | ||
325 | icv[3] = crc >> 24; | ||
326 | |||
327 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); | ||
328 | sg.page = virt_to_page(pos); | ||
329 | sg.offset = offset_in_page(pos); | ||
330 | sg.length = len + 4; | ||
331 | crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); | ||
332 | |||
333 | tkey->tx_iv16++; | ||
334 | if (tkey->tx_iv16 == 0) { | ||
335 | tkey->tx_phase1_done = 0; | ||
336 | tkey->tx_iv32++; | ||
337 | } | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | |||
343 | static int hostap_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
344 | { | ||
345 | struct hostap_tkip_data *tkey = priv; | ||
346 | u8 rc4key[16]; | ||
347 | u8 keyidx, *pos, icv[4]; | ||
348 | u32 iv32; | ||
349 | u16 iv16; | ||
350 | struct hostap_ieee80211_hdr *hdr; | ||
351 | u32 crc; | ||
352 | struct scatterlist sg; | ||
353 | int plen; | ||
354 | |||
355 | if (skb->len < hdr_len + 8 + 4) | ||
356 | return -1; | ||
357 | |||
358 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
359 | pos = skb->data + hdr_len; | ||
360 | keyidx = pos[3]; | ||
361 | if (!(keyidx & (1 << 5))) { | ||
362 | if (net_ratelimit()) { | ||
363 | printk(KERN_DEBUG "TKIP: received packet without ExtIV" | ||
364 | " flag from " MACSTR "\n", MAC2STR(hdr->addr2)); | ||
365 | } | ||
366 | return -2; | ||
367 | } | ||
368 | keyidx >>= 6; | ||
369 | if (tkey->key_idx != keyidx) { | ||
370 | printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " | ||
371 | "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); | ||
372 | return -6; | ||
373 | } | ||
374 | if (!tkey->key_set) { | ||
375 | if (net_ratelimit()) { | ||
376 | printk(KERN_DEBUG "TKIP: received packet from " MACSTR | ||
377 | " with keyid=%d that does not have a configured" | ||
378 | " key\n", MAC2STR(hdr->addr2), keyidx); | ||
379 | } | ||
380 | return -3; | ||
381 | } | ||
382 | iv16 = (pos[0] << 8) | pos[2]; | ||
383 | iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); | ||
384 | pos += 8; | ||
385 | |||
386 | if (iv32 < tkey->rx_iv32 || | ||
387 | (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { | ||
388 | if (net_ratelimit()) { | ||
389 | printk(KERN_DEBUG "TKIP: replay detected: STA=" MACSTR | ||
390 | " previous TSC %08x%04x received TSC " | ||
391 | "%08x%04x\n", MAC2STR(hdr->addr2), | ||
392 | tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); | ||
393 | } | ||
394 | tkey->dot11RSNAStatsTKIPReplays++; | ||
395 | return -4; | ||
396 | } | ||
397 | |||
398 | if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { | ||
399 | tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); | ||
400 | tkey->rx_phase1_done = 1; | ||
401 | } | ||
402 | tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); | ||
403 | |||
404 | plen = skb->len - hdr_len - 12; | ||
405 | |||
406 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); | ||
407 | sg.page = virt_to_page(pos); | ||
408 | sg.offset = offset_in_page(pos); | ||
409 | sg.length = plen + 4; | ||
410 | crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); | ||
411 | |||
412 | crc = ~crc32_le(~0, pos, plen); | ||
413 | icv[0] = crc; | ||
414 | icv[1] = crc >> 8; | ||
415 | icv[2] = crc >> 16; | ||
416 | icv[3] = crc >> 24; | ||
417 | if (memcmp(icv, pos + plen, 4) != 0) { | ||
418 | if (iv32 != tkey->rx_iv32) { | ||
419 | /* Previously cached Phase1 result was already lost, so | ||
420 | * it needs to be recalculated for the next packet. */ | ||
421 | tkey->rx_phase1_done = 0; | ||
422 | } | ||
423 | if (net_ratelimit()) { | ||
424 | printk(KERN_DEBUG "TKIP: ICV error detected: STA=" | ||
425 | MACSTR "\n", MAC2STR(hdr->addr2)); | ||
426 | } | ||
427 | tkey->dot11RSNAStatsTKIPICVErrors++; | ||
428 | return -5; | ||
429 | } | ||
430 | |||
431 | /* Update real counters only after Michael MIC verification has | ||
432 | * completed */ | ||
433 | tkey->rx_iv32_new = iv32; | ||
434 | tkey->rx_iv16_new = iv16; | ||
435 | |||
436 | /* Remove IV and ICV */ | ||
437 | memmove(skb->data + 8, skb->data, hdr_len); | ||
438 | skb_pull(skb, 8); | ||
439 | skb_trim(skb, skb->len - 4); | ||
440 | |||
441 | return keyidx; | ||
442 | } | ||
443 | |||
444 | |||
445 | static int michael_mic(struct hostap_tkip_data *tkey, u8 *key, u8 *hdr, | ||
446 | u8 *data, size_t data_len, u8 *mic) | ||
447 | { | ||
448 | struct scatterlist sg[2]; | ||
449 | |||
450 | if (tkey->tfm_michael == NULL) { | ||
451 | printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); | ||
452 | return -1; | ||
453 | } | ||
454 | sg[0].page = virt_to_page(hdr); | ||
455 | sg[0].offset = offset_in_page(hdr); | ||
456 | sg[0].length = 16; | ||
457 | |||
458 | sg[1].page = virt_to_page(data); | ||
459 | sg[1].offset = offset_in_page(data); | ||
460 | sg[1].length = data_len; | ||
461 | |||
462 | crypto_digest_init(tkey->tfm_michael); | ||
463 | crypto_digest_setkey(tkey->tfm_michael, key, 8); | ||
464 | crypto_digest_update(tkey->tfm_michael, sg, 2); | ||
465 | crypto_digest_final(tkey->tfm_michael, mic); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | |||
471 | static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) | ||
472 | { | ||
473 | struct hostap_ieee80211_hdr *hdr11; | ||
474 | |||
475 | hdr11 = (struct hostap_ieee80211_hdr *) skb->data; | ||
476 | switch (le16_to_cpu(hdr11->frame_control) & | ||
477 | (WLAN_FC_FROMDS | WLAN_FC_TODS)) { | ||
478 | case WLAN_FC_TODS: | ||
479 | memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ | ||
480 | memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ | ||
481 | break; | ||
482 | case WLAN_FC_FROMDS: | ||
483 | memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ | ||
484 | memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ | ||
485 | break; | ||
486 | case WLAN_FC_FROMDS | WLAN_FC_TODS: | ||
487 | memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ | ||
488 | memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ | ||
489 | break; | ||
490 | case 0: | ||
491 | memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ | ||
492 | memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ | ||
493 | break; | ||
494 | } | ||
495 | |||
496 | hdr[12] = 0; /* priority */ | ||
497 | hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ | ||
498 | } | ||
499 | |||
500 | |||
501 | static int hostap_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) | ||
502 | { | ||
503 | struct hostap_tkip_data *tkey = priv; | ||
504 | u8 *pos; | ||
505 | |||
506 | if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { | ||
507 | printk(KERN_DEBUG "Invalid packet for Michael MIC add " | ||
508 | "(tailroom=%d hdr_len=%d skb->len=%d)\n", | ||
509 | skb_tailroom(skb), hdr_len, skb->len); | ||
510 | return -1; | ||
511 | } | ||
512 | |||
513 | michael_mic_hdr(skb, tkey->tx_hdr); | ||
514 | pos = skb_put(skb, 8); | ||
515 | if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, | ||
516 | skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) | ||
517 | return -1; | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | |||
523 | static void hostap_michael_mic_failure(struct net_device *dev, | ||
524 | struct hostap_ieee80211_hdr *hdr, | ||
525 | int keyidx) | ||
526 | { | ||
527 | union iwreq_data wrqu; | ||
528 | char buf[128]; | ||
529 | |||
530 | /* TODO: needed parameters: count, keyid, key type, src address, TSC */ | ||
531 | sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" | ||
532 | MACSTR ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", | ||
533 | MAC2STR(hdr->addr2)); | ||
534 | memset(&wrqu, 0, sizeof(wrqu)); | ||
535 | wrqu.data.length = strlen(buf); | ||
536 | wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); | ||
537 | } | ||
538 | |||
539 | |||
540 | static int hostap_michael_mic_verify(struct sk_buff *skb, int keyidx, | ||
541 | int hdr_len, void *priv) | ||
542 | { | ||
543 | struct hostap_tkip_data *tkey = priv; | ||
544 | u8 mic[8]; | ||
545 | |||
546 | if (!tkey->key_set) | ||
547 | return -1; | ||
548 | |||
549 | michael_mic_hdr(skb, tkey->rx_hdr); | ||
550 | if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, | ||
551 | skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) | ||
552 | return -1; | ||
553 | if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { | ||
554 | struct hostap_ieee80211_hdr *hdr; | ||
555 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
556 | printk(KERN_DEBUG "%s: Michael MIC verification failed for " | ||
557 | "MSDU from " MACSTR " keyidx=%d\n", | ||
558 | skb->dev ? skb->dev->name : "N/A", MAC2STR(hdr->addr2), | ||
559 | keyidx); | ||
560 | if (skb->dev) | ||
561 | hostap_michael_mic_failure(skb->dev, hdr, keyidx); | ||
562 | tkey->dot11RSNAStatsTKIPLocalMICFailures++; | ||
563 | return -1; | ||
564 | } | ||
565 | |||
566 | /* Update TSC counters for RX now that the packet verification has | ||
567 | * completed. */ | ||
568 | tkey->rx_iv32 = tkey->rx_iv32_new; | ||
569 | tkey->rx_iv16 = tkey->rx_iv16_new; | ||
570 | |||
571 | skb_trim(skb, skb->len - 8); | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | |||
577 | static int hostap_tkip_set_key(void *key, int len, u8 *seq, void *priv) | ||
578 | { | ||
579 | struct hostap_tkip_data *tkey = priv; | ||
580 | int keyidx; | ||
581 | struct crypto_tfm *tfm = tkey->tfm_michael; | ||
582 | struct crypto_tfm *tfm2 = tkey->tfm_arc4; | ||
583 | |||
584 | keyidx = tkey->key_idx; | ||
585 | memset(tkey, 0, sizeof(*tkey)); | ||
586 | tkey->key_idx = keyidx; | ||
587 | tkey->tfm_michael = tfm; | ||
588 | tkey->tfm_arc4 = tfm2; | ||
589 | if (len == TKIP_KEY_LEN) { | ||
590 | memcpy(tkey->key, key, TKIP_KEY_LEN); | ||
591 | tkey->key_set = 1; | ||
592 | tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ | ||
593 | if (seq) { | ||
594 | tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | | ||
595 | (seq[3] << 8) | seq[2]; | ||
596 | tkey->rx_iv16 = (seq[1] << 8) | seq[0]; | ||
597 | } | ||
598 | } else if (len == 0) { | ||
599 | tkey->key_set = 0; | ||
600 | } else | ||
601 | return -1; | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | |||
607 | static int hostap_tkip_get_key(void *key, int len, u8 *seq, void *priv) | ||
608 | { | ||
609 | struct hostap_tkip_data *tkey = priv; | ||
610 | |||
611 | if (len < TKIP_KEY_LEN) | ||
612 | return -1; | ||
613 | |||
614 | if (!tkey->key_set) | ||
615 | return 0; | ||
616 | memcpy(key, tkey->key, TKIP_KEY_LEN); | ||
617 | |||
618 | if (seq) { | ||
619 | /* Return the sequence number of the last transmitted frame. */ | ||
620 | u16 iv16 = tkey->tx_iv16; | ||
621 | u32 iv32 = tkey->tx_iv32; | ||
622 | if (iv16 == 0) | ||
623 | iv32--; | ||
624 | iv16--; | ||
625 | seq[0] = tkey->tx_iv16; | ||
626 | seq[1] = tkey->tx_iv16 >> 8; | ||
627 | seq[2] = tkey->tx_iv32; | ||
628 | seq[3] = tkey->tx_iv32 >> 8; | ||
629 | seq[4] = tkey->tx_iv32 >> 16; | ||
630 | seq[5] = tkey->tx_iv32 >> 24; | ||
631 | } | ||
632 | |||
633 | return TKIP_KEY_LEN; | ||
634 | } | ||
635 | |||
636 | |||
637 | static char * hostap_tkip_print_stats(char *p, void *priv) | ||
638 | { | ||
639 | struct hostap_tkip_data *tkip = priv; | ||
640 | p += sprintf(p, "key[%d] alg=TKIP key_set=%d " | ||
641 | "tx_pn=%02x%02x%02x%02x%02x%02x " | ||
642 | "rx_pn=%02x%02x%02x%02x%02x%02x " | ||
643 | "replays=%d icv_errors=%d local_mic_failures=%d\n", | ||
644 | tkip->key_idx, tkip->key_set, | ||
645 | (tkip->tx_iv32 >> 24) & 0xff, | ||
646 | (tkip->tx_iv32 >> 16) & 0xff, | ||
647 | (tkip->tx_iv32 >> 8) & 0xff, | ||
648 | tkip->tx_iv32 & 0xff, | ||
649 | (tkip->tx_iv16 >> 8) & 0xff, | ||
650 | tkip->tx_iv16 & 0xff, | ||
651 | (tkip->rx_iv32 >> 24) & 0xff, | ||
652 | (tkip->rx_iv32 >> 16) & 0xff, | ||
653 | (tkip->rx_iv32 >> 8) & 0xff, | ||
654 | tkip->rx_iv32 & 0xff, | ||
655 | (tkip->rx_iv16 >> 8) & 0xff, | ||
656 | tkip->rx_iv16 & 0xff, | ||
657 | tkip->dot11RSNAStatsTKIPReplays, | ||
658 | tkip->dot11RSNAStatsTKIPICVErrors, | ||
659 | tkip->dot11RSNAStatsTKIPLocalMICFailures); | ||
660 | return p; | ||
661 | } | ||
662 | |||
663 | |||
664 | static struct hostap_crypto_ops hostap_crypt_tkip = { | ||
665 | .name = "TKIP", | ||
666 | .init = hostap_tkip_init, | ||
667 | .deinit = hostap_tkip_deinit, | ||
668 | .encrypt_mpdu = hostap_tkip_encrypt, | ||
669 | .decrypt_mpdu = hostap_tkip_decrypt, | ||
670 | .encrypt_msdu = hostap_michael_mic_add, | ||
671 | .decrypt_msdu = hostap_michael_mic_verify, | ||
672 | .set_key = hostap_tkip_set_key, | ||
673 | .get_key = hostap_tkip_get_key, | ||
674 | .print_stats = hostap_tkip_print_stats, | ||
675 | .extra_prefix_len = 4 + 4 /* IV + ExtIV */, | ||
676 | .extra_postfix_len = 8 + 4 /* MIC + ICV */ | ||
677 | }; | ||
678 | |||
679 | |||
680 | static int __init hostap_crypto_tkip_init(void) | ||
681 | { | ||
682 | if (hostap_register_crypto_ops(&hostap_crypt_tkip) < 0) | ||
683 | return -1; | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | |||
689 | static void __exit hostap_crypto_tkip_exit(void) | ||
690 | { | ||
691 | hostap_unregister_crypto_ops(&hostap_crypt_tkip); | ||
692 | } | ||
693 | |||
694 | |||
695 | module_init(hostap_crypto_tkip_init); | ||
696 | module_exit(hostap_crypto_tkip_exit); | ||
diff --git a/drivers/net/wireless/hostap/hostap_crypt_wep.c b/drivers/net/wireless/hostap/hostap_crypt_wep.c new file mode 100644 index 00000000000..a6783e067f1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_crypt_wep.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based WEP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <asm/string.h> | ||
20 | |||
21 | #include "hostap_crypt.h" | ||
22 | |||
23 | #ifndef CONFIG_CRYPTO | ||
24 | #error CONFIG_CRYPTO is required to build this module. | ||
25 | #endif | ||
26 | #include <linux/crypto.h> | ||
27 | #include <asm/scatterlist.h> | ||
28 | #include <linux/crc32.h> | ||
29 | |||
30 | MODULE_AUTHOR("Jouni Malinen"); | ||
31 | MODULE_DESCRIPTION("Host AP crypt: WEP"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | |||
35 | struct prism2_wep_data { | ||
36 | u32 iv; | ||
37 | #define WEP_KEY_LEN 13 | ||
38 | u8 key[WEP_KEY_LEN + 1]; | ||
39 | u8 key_len; | ||
40 | u8 key_idx; | ||
41 | struct crypto_tfm *tfm; | ||
42 | }; | ||
43 | |||
44 | |||
45 | static void * prism2_wep_init(int keyidx) | ||
46 | { | ||
47 | struct prism2_wep_data *priv; | ||
48 | |||
49 | if (!try_module_get(THIS_MODULE)) | ||
50 | return NULL; | ||
51 | |||
52 | priv = (struct prism2_wep_data *) kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
53 | if (priv == NULL) | ||
54 | goto fail; | ||
55 | memset(priv, 0, sizeof(*priv)); | ||
56 | priv->key_idx = keyidx; | ||
57 | |||
58 | priv->tfm = crypto_alloc_tfm("arc4", 0); | ||
59 | if (priv->tfm == NULL) { | ||
60 | printk(KERN_DEBUG "hostap_crypt_wep: could not allocate " | ||
61 | "crypto API arc4\n"); | ||
62 | goto fail; | ||
63 | } | ||
64 | |||
65 | /* start WEP IV from a random value */ | ||
66 | get_random_bytes(&priv->iv, 4); | ||
67 | |||
68 | return priv; | ||
69 | |||
70 | fail: | ||
71 | if (priv) { | ||
72 | if (priv->tfm) | ||
73 | crypto_free_tfm(priv->tfm); | ||
74 | kfree(priv); | ||
75 | } | ||
76 | module_put(THIS_MODULE); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | |||
81 | static void prism2_wep_deinit(void *priv) | ||
82 | { | ||
83 | struct prism2_wep_data *_priv = priv; | ||
84 | if (_priv && _priv->tfm) | ||
85 | crypto_free_tfm(_priv->tfm); | ||
86 | kfree(priv); | ||
87 | module_put(THIS_MODULE); | ||
88 | } | ||
89 | |||
90 | |||
91 | /* Perform WEP encryption on given skb that has at least 4 bytes of headroom | ||
92 | * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, | ||
93 | * so the payload length increases with 8 bytes. | ||
94 | * | ||
95 | * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) | ||
96 | */ | ||
97 | static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
98 | { | ||
99 | struct prism2_wep_data *wep = priv; | ||
100 | u32 crc, klen, len; | ||
101 | u8 key[WEP_KEY_LEN + 3]; | ||
102 | u8 *pos, *icv; | ||
103 | struct scatterlist sg; | ||
104 | |||
105 | if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || | ||
106 | skb->len < hdr_len) | ||
107 | return -1; | ||
108 | |||
109 | len = skb->len - hdr_len; | ||
110 | pos = skb_push(skb, 4); | ||
111 | memmove(pos, pos + 4, hdr_len); | ||
112 | pos += hdr_len; | ||
113 | |||
114 | klen = 3 + wep->key_len; | ||
115 | |||
116 | wep->iv++; | ||
117 | |||
118 | /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key | ||
119 | * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) | ||
120 | * can be used to speedup attacks, so avoid using them. */ | ||
121 | if ((wep->iv & 0xff00) == 0xff00) { | ||
122 | u8 B = (wep->iv >> 16) & 0xff; | ||
123 | if (B >= 3 && B < klen) | ||
124 | wep->iv += 0x0100; | ||
125 | } | ||
126 | |||
127 | /* Prepend 24-bit IV to RC4 key and TX frame */ | ||
128 | *pos++ = key[0] = (wep->iv >> 16) & 0xff; | ||
129 | *pos++ = key[1] = (wep->iv >> 8) & 0xff; | ||
130 | *pos++ = key[2] = wep->iv & 0xff; | ||
131 | *pos++ = wep->key_idx << 6; | ||
132 | |||
133 | /* Copy rest of the WEP key (the secret part) */ | ||
134 | memcpy(key + 3, wep->key, wep->key_len); | ||
135 | |||
136 | /* Append little-endian CRC32 and encrypt it to produce ICV */ | ||
137 | crc = ~crc32_le(~0, pos, len); | ||
138 | icv = skb_put(skb, 4); | ||
139 | icv[0] = crc; | ||
140 | icv[1] = crc >> 8; | ||
141 | icv[2] = crc >> 16; | ||
142 | icv[3] = crc >> 24; | ||
143 | |||
144 | crypto_cipher_setkey(wep->tfm, key, klen); | ||
145 | sg.page = virt_to_page(pos); | ||
146 | sg.offset = offset_in_page(pos); | ||
147 | sg.length = len + 4; | ||
148 | crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of | ||
155 | * the frame: IV (4 bytes), encrypted payload (including SNAP header), | ||
156 | * ICV (4 bytes). len includes both IV and ICV. | ||
157 | * | ||
158 | * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on | ||
159 | * failure. If frame is OK, IV and ICV will be removed. | ||
160 | */ | ||
161 | static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
162 | { | ||
163 | struct prism2_wep_data *wep = priv; | ||
164 | u32 crc, klen, plen; | ||
165 | u8 key[WEP_KEY_LEN + 3]; | ||
166 | u8 keyidx, *pos, icv[4]; | ||
167 | struct scatterlist sg; | ||
168 | |||
169 | if (skb->len < hdr_len + 8) | ||
170 | return -1; | ||
171 | |||
172 | pos = skb->data + hdr_len; | ||
173 | key[0] = *pos++; | ||
174 | key[1] = *pos++; | ||
175 | key[2] = *pos++; | ||
176 | keyidx = *pos++ >> 6; | ||
177 | if (keyidx != wep->key_idx) | ||
178 | return -1; | ||
179 | |||
180 | klen = 3 + wep->key_len; | ||
181 | |||
182 | /* Copy rest of the WEP key (the secret part) */ | ||
183 | memcpy(key + 3, wep->key, wep->key_len); | ||
184 | |||
185 | /* Apply RC4 to data and compute CRC32 over decrypted data */ | ||
186 | plen = skb->len - hdr_len - 8; | ||
187 | |||
188 | crypto_cipher_setkey(wep->tfm, key, klen); | ||
189 | sg.page = virt_to_page(pos); | ||
190 | sg.offset = offset_in_page(pos); | ||
191 | sg.length = plen + 4; | ||
192 | crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); | ||
193 | |||
194 | crc = ~crc32_le(~0, pos, plen); | ||
195 | icv[0] = crc; | ||
196 | icv[1] = crc >> 8; | ||
197 | icv[2] = crc >> 16; | ||
198 | icv[3] = crc >> 24; | ||
199 | if (memcmp(icv, pos + plen, 4) != 0) { | ||
200 | /* ICV mismatch - drop frame */ | ||
201 | return -2; | ||
202 | } | ||
203 | |||
204 | /* Remove IV and ICV */ | ||
205 | memmove(skb->data + 4, skb->data, hdr_len); | ||
206 | skb_pull(skb, 4); | ||
207 | skb_trim(skb, skb->len - 4); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | |||
213 | static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) | ||
214 | { | ||
215 | struct prism2_wep_data *wep = priv; | ||
216 | |||
217 | if (len < 0 || len > WEP_KEY_LEN) | ||
218 | return -1; | ||
219 | |||
220 | memcpy(wep->key, key, len); | ||
221 | wep->key_len = len; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | |||
227 | static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) | ||
228 | { | ||
229 | struct prism2_wep_data *wep = priv; | ||
230 | |||
231 | if (len < wep->key_len) | ||
232 | return -1; | ||
233 | |||
234 | memcpy(key, wep->key, wep->key_len); | ||
235 | |||
236 | return wep->key_len; | ||
237 | } | ||
238 | |||
239 | |||
240 | static char * prism2_wep_print_stats(char *p, void *priv) | ||
241 | { | ||
242 | struct prism2_wep_data *wep = priv; | ||
243 | p += sprintf(p, "key[%d] alg=WEP len=%d\n", | ||
244 | wep->key_idx, wep->key_len); | ||
245 | return p; | ||
246 | } | ||
247 | |||
248 | |||
249 | static struct hostap_crypto_ops hostap_crypt_wep = { | ||
250 | .name = "WEP", | ||
251 | .init = prism2_wep_init, | ||
252 | .deinit = prism2_wep_deinit, | ||
253 | .encrypt_mpdu = prism2_wep_encrypt, | ||
254 | .decrypt_mpdu = prism2_wep_decrypt, | ||
255 | .encrypt_msdu = NULL, | ||
256 | .decrypt_msdu = NULL, | ||
257 | .set_key = prism2_wep_set_key, | ||
258 | .get_key = prism2_wep_get_key, | ||
259 | .print_stats = prism2_wep_print_stats, | ||
260 | .extra_prefix_len = 4 /* IV */, | ||
261 | .extra_postfix_len = 4 /* ICV */ | ||
262 | }; | ||
263 | |||
264 | |||
265 | static int __init hostap_crypto_wep_init(void) | ||
266 | { | ||
267 | if (hostap_register_crypto_ops(&hostap_crypt_wep) < 0) | ||
268 | return -1; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | |||
274 | static void __exit hostap_crypto_wep_exit(void) | ||
275 | { | ||
276 | hostap_unregister_crypto_ops(&hostap_crypt_wep); | ||
277 | } | ||
278 | |||
279 | |||
280 | module_init(hostap_crypto_wep_init); | ||
281 | module_exit(hostap_crypto_wep_exit); | ||
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c new file mode 100644 index 00000000000..e66c797bdc8 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -0,0 +1,950 @@ | |||
1 | #define PRISM2_PCCARD | ||
2 | |||
3 | #include <linux/config.h> | ||
4 | #include <linux/version.h> | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/if.h> | ||
8 | #include <linux/wait.h> | ||
9 | #include <linux/timer.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <linux/netdevice.h> | ||
12 | #include <linux/workqueue.h> | ||
13 | #include <linux/wireless.h> | ||
14 | #include <net/iw_handler.h> | ||
15 | |||
16 | #include <pcmcia/version.h> | ||
17 | #include <pcmcia/cs_types.h> | ||
18 | #include <pcmcia/cs.h> | ||
19 | #include <pcmcia/cistpl.h> | ||
20 | #include <pcmcia/cisreg.h> | ||
21 | #include <pcmcia/ds.h> | ||
22 | |||
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 dev_info_t dev_info = "hostap_cs"; | ||
30 | static dev_link_t *dev_list = NULL; | ||
31 | |||
32 | MODULE_AUTHOR("Jouni Malinen"); | ||
33 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | ||
34 | "cards (PC Card)."); | ||
35 | MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | |||
39 | static int irq_mask = 0xdeb8; | ||
40 | module_param(irq_mask, int, 0444); | ||
41 | |||
42 | static int irq_list[4] = { -1 }; | ||
43 | module_param_array(irq_list, int, NULL, 0444); | ||
44 | |||
45 | static int ignore_cis_vcc; | ||
46 | module_param(ignore_cis_vcc, int, 0444); | ||
47 | MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); | ||
48 | |||
49 | |||
50 | #ifdef PRISM2_IO_DEBUG | ||
51 | |||
52 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
53 | { | ||
54 | struct hostap_interface *iface; | ||
55 | local_info_t *local; | ||
56 | unsigned long flags; | ||
57 | |||
58 | iface = netdev_priv(dev); | ||
59 | local = iface->local; | ||
60 | spin_lock_irqsave(&local->lock, flags); | ||
61 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
62 | outb(v, dev->base_addr + a); | ||
63 | spin_unlock_irqrestore(&local->lock, flags); | ||
64 | } | ||
65 | |||
66 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
67 | { | ||
68 | struct hostap_interface *iface; | ||
69 | local_info_t *local; | ||
70 | unsigned long flags; | ||
71 | u8 v; | ||
72 | |||
73 | iface = netdev_priv(dev); | ||
74 | local = iface->local; | ||
75 | spin_lock_irqsave(&local->lock, flags); | ||
76 | v = inb(dev->base_addr + a); | ||
77 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
78 | spin_unlock_irqrestore(&local->lock, flags); | ||
79 | return v; | ||
80 | } | ||
81 | |||
82 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
83 | { | ||
84 | struct hostap_interface *iface; | ||
85 | local_info_t *local; | ||
86 | unsigned long flags; | ||
87 | |||
88 | iface = netdev_priv(dev); | ||
89 | local = iface->local; | ||
90 | spin_lock_irqsave(&local->lock, flags); | ||
91 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
92 | outw(v, dev->base_addr + a); | ||
93 | spin_unlock_irqrestore(&local->lock, flags); | ||
94 | } | ||
95 | |||
96 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
97 | { | ||
98 | struct hostap_interface *iface; | ||
99 | local_info_t *local; | ||
100 | unsigned long flags; | ||
101 | u16 v; | ||
102 | |||
103 | iface = netdev_priv(dev); | ||
104 | local = iface->local; | ||
105 | spin_lock_irqsave(&local->lock, flags); | ||
106 | v = inw(dev->base_addr + a); | ||
107 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
108 | spin_unlock_irqrestore(&local->lock, flags); | ||
109 | return v; | ||
110 | } | ||
111 | |||
112 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
113 | u8 *buf, int wc) | ||
114 | { | ||
115 | struct hostap_interface *iface; | ||
116 | local_info_t *local; | ||
117 | unsigned long flags; | ||
118 | |||
119 | iface = netdev_priv(dev); | ||
120 | local = iface->local; | ||
121 | spin_lock_irqsave(&local->lock, flags); | ||
122 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
123 | outsw(dev->base_addr + a, buf, wc); | ||
124 | spin_unlock_irqrestore(&local->lock, flags); | ||
125 | } | ||
126 | |||
127 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
128 | u8 *buf, int wc) | ||
129 | { | ||
130 | struct hostap_interface *iface; | ||
131 | local_info_t *local; | ||
132 | unsigned long flags; | ||
133 | |||
134 | iface = netdev_priv(dev); | ||
135 | local = iface->local; | ||
136 | spin_lock_irqsave(&local->lock, flags); | ||
137 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
138 | insw(dev->base_addr + a, buf, wc); | ||
139 | spin_unlock_irqrestore(&local->lock, flags); | ||
140 | } | ||
141 | |||
142 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
143 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
144 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
145 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
146 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
147 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
148 | |||
149 | #else /* PRISM2_IO_DEBUG */ | ||
150 | |||
151 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
152 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
153 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
154 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
155 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
156 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
157 | |||
158 | #endif /* PRISM2_IO_DEBUG */ | ||
159 | |||
160 | |||
161 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
162 | int len) | ||
163 | { | ||
164 | u16 d_off; | ||
165 | u16 *pos; | ||
166 | |||
167 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
168 | pos = (u16 *) buf; | ||
169 | |||
170 | if (len / 2) | ||
171 | HFA384X_INSW(d_off, buf, len / 2); | ||
172 | pos += len / 2; | ||
173 | |||
174 | if (len & 1) | ||
175 | *((char *) pos) = HFA384X_INB(d_off); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | |||
181 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
182 | { | ||
183 | u16 d_off; | ||
184 | u16 *pos; | ||
185 | |||
186 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
187 | pos = (u16 *) buf; | ||
188 | |||
189 | if (len / 2) | ||
190 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
191 | pos += len / 2; | ||
192 | |||
193 | if (len & 1) | ||
194 | HFA384X_OUTB(*((char *) pos), d_off); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | |||
200 | /* FIX: This might change at some point.. */ | ||
201 | #include "hostap_hw.c" | ||
202 | |||
203 | |||
204 | |||
205 | static void prism2_detach(dev_link_t *link); | ||
206 | static void prism2_release(u_long arg); | ||
207 | static int prism2_event(event_t event, int priority, | ||
208 | event_callback_args_t *args); | ||
209 | |||
210 | |||
211 | static int prism2_pccard_card_present(local_info_t *local) | ||
212 | { | ||
213 | if (local->link != NULL && | ||
214 | ((local->link->state & (DEV_PRESENT | DEV_CONFIG)) == | ||
215 | (DEV_PRESENT | DEV_CONFIG))) | ||
216 | return 1; | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | |||
221 | /* | ||
222 | * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 | ||
223 | * Document No. 20-10-00058, January 2004 | ||
224 | * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf | ||
225 | */ | ||
226 | #define SANDISK_WLAN_ACTIVATION_OFF 0x40 | ||
227 | #define SANDISK_HCR_OFF 0x42 | ||
228 | |||
229 | |||
230 | static void sandisk_set_iobase(local_info_t *local) | ||
231 | { | ||
232 | int res; | ||
233 | conf_reg_t reg; | ||
234 | |||
235 | reg.Function = 0; | ||
236 | reg.Action = CS_WRITE; | ||
237 | reg.Offset = 0x10; /* 0x3f0 IO base 1 */ | ||
238 | reg.Value = local->link->io.BasePort1 & 0x00ff; | ||
239 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
240 | if (res != CS_SUCCESS) { | ||
241 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" | ||
242 | " res=%d\n", res); | ||
243 | } | ||
244 | udelay(10); | ||
245 | |||
246 | reg.Function = 0; | ||
247 | reg.Action = CS_WRITE; | ||
248 | reg.Offset = 0x12; /* 0x3f2 IO base 2 */ | ||
249 | reg.Value = (local->link->io.BasePort1 & 0xff00) >> 8; | ||
250 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
251 | if (res != CS_SUCCESS) { | ||
252 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" | ||
253 | " res=%d\n", res); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | |||
258 | static void sandisk_write_hcr(local_info_t *local, int hcr) | ||
259 | { | ||
260 | struct net_device *dev = local->dev; | ||
261 | int i; | ||
262 | |||
263 | HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); | ||
264 | udelay(50); | ||
265 | for (i = 0; i < 10; i++) { | ||
266 | HFA384X_OUTB(hcr, SANDISK_HCR_OFF); | ||
267 | } | ||
268 | udelay(55); | ||
269 | HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); | ||
270 | } | ||
271 | |||
272 | |||
273 | static int sandisk_enable_wireless(struct net_device *dev) | ||
274 | { | ||
275 | int res, ret = 0; | ||
276 | conf_reg_t reg; | ||
277 | struct hostap_interface *iface = dev->priv; | ||
278 | local_info_t *local = iface->local; | ||
279 | tuple_t tuple; | ||
280 | cisparse_t *parse = NULL; | ||
281 | u_char buf[64]; | ||
282 | |||
283 | if (local->link->io.NumPorts1 < 0x42) { | ||
284 | /* Not enough ports to be SanDisk multi-function card */ | ||
285 | ret = -ENODEV; | ||
286 | goto done; | ||
287 | } | ||
288 | |||
289 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
290 | if (parse == NULL) { | ||
291 | ret = -ENOMEM; | ||
292 | goto done; | ||
293 | } | ||
294 | |||
295 | tuple.DesiredTuple = CISTPL_MANFID; | ||
296 | tuple.Attributes = TUPLE_RETURN_COMMON; | ||
297 | tuple.TupleData = buf; | ||
298 | tuple.TupleDataMax = sizeof(buf); | ||
299 | tuple.TupleOffset = 0; | ||
300 | if (pcmcia_get_first_tuple(local->link->handle, &tuple) || | ||
301 | pcmcia_get_tuple_data(local->link->handle, &tuple) || | ||
302 | pcmcia_parse_tuple(local->link->handle, &tuple, parse) || | ||
303 | parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) { | ||
304 | /* No SanDisk manfid found */ | ||
305 | ret = -ENODEV; | ||
306 | goto done; | ||
307 | } | ||
308 | |||
309 | tuple.DesiredTuple = CISTPL_LONGLINK_MFC; | ||
310 | if (pcmcia_get_first_tuple(local->link->handle, &tuple) || | ||
311 | pcmcia_get_tuple_data(local->link->handle, &tuple) || | ||
312 | pcmcia_parse_tuple(local->link->handle, &tuple, parse) || | ||
313 | parse->longlink_mfc.nfn < 2) { | ||
314 | /* No multi-function links found */ | ||
315 | ret = -ENODEV; | ||
316 | goto done; | ||
317 | } | ||
318 | |||
319 | printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" | ||
320 | " - using vendor-specific initialization\n", dev->name); | ||
321 | local->sandisk_connectplus = 1; | ||
322 | |||
323 | reg.Function = 0; | ||
324 | reg.Action = CS_WRITE; | ||
325 | reg.Offset = CISREG_COR; | ||
326 | reg.Value = COR_SOFT_RESET; | ||
327 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
328 | if (res != CS_SUCCESS) { | ||
329 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
330 | dev->name, res); | ||
331 | goto done; | ||
332 | } | ||
333 | mdelay(5); | ||
334 | |||
335 | reg.Function = 0; | ||
336 | reg.Action = CS_WRITE; | ||
337 | reg.Offset = CISREG_COR; | ||
338 | /* | ||
339 | * Do not enable interrupts here to avoid some bogus events. Interrupts | ||
340 | * will be enabled during the first cor_sreset call. | ||
341 | */ | ||
342 | reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; | ||
343 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
344 | if (res != CS_SUCCESS) { | ||
345 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
346 | dev->name, res); | ||
347 | goto done; | ||
348 | } | ||
349 | mdelay(5); | ||
350 | |||
351 | sandisk_set_iobase(local); | ||
352 | |||
353 | HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); | ||
354 | udelay(10); | ||
355 | HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); | ||
356 | udelay(10); | ||
357 | |||
358 | done: | ||
359 | kfree(parse); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | |||
364 | static void prism2_pccard_cor_sreset(local_info_t *local) | ||
365 | { | ||
366 | int res; | ||
367 | conf_reg_t reg; | ||
368 | |||
369 | if (!prism2_pccard_card_present(local)) | ||
370 | return; | ||
371 | |||
372 | reg.Function = 0; | ||
373 | reg.Action = CS_READ; | ||
374 | reg.Offset = CISREG_COR; | ||
375 | reg.Value = 0; | ||
376 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
377 | if (res != CS_SUCCESS) { | ||
378 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", | ||
379 | res); | ||
380 | return; | ||
381 | } | ||
382 | printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", | ||
383 | reg.Value); | ||
384 | |||
385 | reg.Action = CS_WRITE; | ||
386 | reg.Value |= COR_SOFT_RESET; | ||
387 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
388 | if (res != CS_SUCCESS) { | ||
389 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", | ||
390 | res); | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | mdelay(local->sandisk_connectplus ? 5 : 2); | ||
395 | |||
396 | reg.Value &= ~COR_SOFT_RESET; | ||
397 | if (local->sandisk_connectplus) | ||
398 | reg.Value |= COR_IREQ_ENA; | ||
399 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
400 | if (res != CS_SUCCESS) { | ||
401 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", | ||
402 | res); | ||
403 | return; | ||
404 | } | ||
405 | |||
406 | mdelay(local->sandisk_connectplus ? 5 : 2); | ||
407 | |||
408 | if (local->sandisk_connectplus) | ||
409 | sandisk_set_iobase(local); | ||
410 | } | ||
411 | |||
412 | |||
413 | static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) | ||
414 | { | ||
415 | int res; | ||
416 | conf_reg_t reg; | ||
417 | int old_cor; | ||
418 | |||
419 | if (!prism2_pccard_card_present(local)) | ||
420 | return; | ||
421 | |||
422 | if (local->sandisk_connectplus) { | ||
423 | sandisk_write_hcr(local, hcr); | ||
424 | return; | ||
425 | } | ||
426 | |||
427 | reg.Function = 0; | ||
428 | reg.Action = CS_READ; | ||
429 | reg.Offset = CISREG_COR; | ||
430 | reg.Value = 0; | ||
431 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
432 | if (res != CS_SUCCESS) { | ||
433 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " | ||
434 | "(%d)\n", res); | ||
435 | return; | ||
436 | } | ||
437 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n", | ||
438 | reg.Value); | ||
439 | old_cor = reg.Value; | ||
440 | |||
441 | reg.Action = CS_WRITE; | ||
442 | reg.Value |= COR_SOFT_RESET; | ||
443 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
444 | if (res != CS_SUCCESS) { | ||
445 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " | ||
446 | "(%d)\n", res); | ||
447 | return; | ||
448 | } | ||
449 | |||
450 | mdelay(10); | ||
451 | |||
452 | /* Setup Genesis mode */ | ||
453 | reg.Action = CS_WRITE; | ||
454 | reg.Value = hcr; | ||
455 | reg.Offset = CISREG_CCSR; | ||
456 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
457 | if (res != CS_SUCCESS) { | ||
458 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " | ||
459 | "(%d)\n", res); | ||
460 | return; | ||
461 | } | ||
462 | mdelay(10); | ||
463 | |||
464 | reg.Action = CS_WRITE; | ||
465 | reg.Offset = CISREG_COR; | ||
466 | reg.Value = old_cor & ~COR_SOFT_RESET; | ||
467 | res = pcmcia_access_configuration_register(local->link->handle, ®); | ||
468 | if (res != CS_SUCCESS) { | ||
469 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " | ||
470 | "(%d)\n", res); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | mdelay(10); | ||
475 | } | ||
476 | |||
477 | |||
478 | static int prism2_pccard_dev_open(local_info_t *local) | ||
479 | { | ||
480 | local->link->open++; | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | |||
485 | static int prism2_pccard_dev_close(local_info_t *local) | ||
486 | { | ||
487 | if (local == NULL || local->link == NULL) | ||
488 | return 1; | ||
489 | |||
490 | if (!local->link->open) { | ||
491 | printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " | ||
492 | "link not open?!\n", local->dev->name); | ||
493 | return 1; | ||
494 | } | ||
495 | |||
496 | local->link->open--; | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | |||
502 | static struct prism2_helper_functions prism2_pccard_funcs = | ||
503 | { | ||
504 | .card_present = prism2_pccard_card_present, | ||
505 | .cor_sreset = prism2_pccard_cor_sreset, | ||
506 | .dev_open = prism2_pccard_dev_open, | ||
507 | .dev_close = prism2_pccard_dev_close, | ||
508 | .genesis_reset = prism2_pccard_genesis_reset, | ||
509 | .hw_type = HOSTAP_HW_PCCARD, | ||
510 | }; | ||
511 | |||
512 | |||
513 | /* allocate local data and register with CardServices | ||
514 | * initialize dev_link structure, but do not configure the card yet */ | ||
515 | static dev_link_t *prism2_attach(void) | ||
516 | { | ||
517 | dev_link_t *link; | ||
518 | client_reg_t client_reg; | ||
519 | int ret; | ||
520 | |||
521 | link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); | ||
522 | if (link == NULL) | ||
523 | return NULL; | ||
524 | |||
525 | memset(link, 0, sizeof(dev_link_t)); | ||
526 | |||
527 | PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); | ||
528 | link->conf.Vcc = 33; | ||
529 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
530 | |||
531 | /* register with CardServices */ | ||
532 | link->next = dev_list; | ||
533 | dev_list = link; | ||
534 | client_reg.dev_info = &dev_info; | ||
535 | client_reg.Attributes = INFO_IO_CLIENT; | ||
536 | client_reg.EventMask = CS_EVENT_CARD_INSERTION | | ||
537 | CS_EVENT_CARD_REMOVAL | | ||
538 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
539 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
540 | client_reg.event_handler = &prism2_event; | ||
541 | client_reg.Version = 0x0210; | ||
542 | client_reg.event_callback_args.client_data = link; | ||
543 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
544 | if (ret != CS_SUCCESS) { | ||
545 | cs_error(link->handle, RegisterClient, ret); | ||
546 | prism2_detach(link); | ||
547 | return NULL; | ||
548 | } | ||
549 | return link; | ||
550 | } | ||
551 | |||
552 | |||
553 | static void prism2_detach(dev_link_t *link) | ||
554 | { | ||
555 | dev_link_t **linkp; | ||
556 | |||
557 | PDEBUG(DEBUG_FLOW, "prism2_detach\n"); | ||
558 | |||
559 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
560 | if (*linkp == link) | ||
561 | break; | ||
562 | if (*linkp == NULL) { | ||
563 | printk(KERN_WARNING "%s: Attempt to detach non-existing " | ||
564 | "PCMCIA client\n", dev_info); | ||
565 | return; | ||
566 | } | ||
567 | |||
568 | if (link->state & DEV_CONFIG) { | ||
569 | prism2_release((u_long)link); | ||
570 | } | ||
571 | |||
572 | if (link->handle) { | ||
573 | int res = pcmcia_deregister_client(link->handle); | ||
574 | if (res) { | ||
575 | printk("CardService(DeregisterClient) => %d\n", res); | ||
576 | cs_error(link->handle, DeregisterClient, res); | ||
577 | } | ||
578 | } | ||
579 | |||
580 | *linkp = link->next; | ||
581 | /* release net devices */ | ||
582 | if (link->priv) { | ||
583 | prism2_free_local_data((struct net_device *) link->priv); | ||
584 | |||
585 | } | ||
586 | kfree(link); | ||
587 | } | ||
588 | |||
589 | |||
590 | #define CS_CHECK(fn, ret) \ | ||
591 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
592 | |||
593 | #define CFG_CHECK2(fn, retf) \ | ||
594 | do { int ret = (retf); \ | ||
595 | if (ret != 0) { \ | ||
596 | PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ | ||
597 | cs_error(link->handle, fn, ret); \ | ||
598 | goto next_entry; \ | ||
599 | } \ | ||
600 | } while (0) | ||
601 | |||
602 | |||
603 | /* run after a CARD_INSERTION event is received to configure the PCMCIA | ||
604 | * socket and make the device available to the system */ | ||
605 | static int prism2_config(dev_link_t *link) | ||
606 | { | ||
607 | struct net_device *dev; | ||
608 | struct hostap_interface *iface; | ||
609 | local_info_t *local; | ||
610 | int ret = 1; | ||
611 | tuple_t tuple; | ||
612 | cisparse_t *parse; | ||
613 | int last_fn, last_ret; | ||
614 | u_char buf[64]; | ||
615 | config_info_t conf; | ||
616 | cistpl_cftable_entry_t dflt = { 0 }; | ||
617 | |||
618 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | ||
619 | |||
620 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
621 | if (parse == NULL) { | ||
622 | ret = -ENOMEM; | ||
623 | goto failed; | ||
624 | } | ||
625 | |||
626 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
627 | tuple.Attributes = 0; | ||
628 | tuple.TupleData = buf; | ||
629 | tuple.TupleDataMax = sizeof(buf); | ||
630 | tuple.TupleOffset = 0; | ||
631 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
632 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple)); | ||
633 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
634 | link->conf.ConfigBase = parse->config.base; | ||
635 | link->conf.Present = parse->config.rmask[0]; | ||
636 | |||
637 | CS_CHECK(GetConfigurationInfo, | ||
638 | pcmcia_get_configuration_info(link->handle, &conf)); | ||
639 | PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info, | ||
640 | ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc); | ||
641 | link->conf.Vcc = conf.Vcc; | ||
642 | |||
643 | /* Look for an appropriate configuration table entry in the CIS */ | ||
644 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
645 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
646 | for (;;) { | ||
647 | cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); | ||
648 | CFG_CHECK2(GetTupleData, | ||
649 | pcmcia_get_tuple_data(link->handle, &tuple)); | ||
650 | CFG_CHECK2(ParseTuple, | ||
651 | pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
652 | |||
653 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
654 | dflt = *cfg; | ||
655 | if (cfg->index == 0) | ||
656 | goto next_entry; | ||
657 | link->conf.ConfigIndex = cfg->index; | ||
658 | PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " | ||
659 | "(default 0x%02X)\n", cfg->index, dflt.index); | ||
660 | |||
661 | /* Does this card need audio output? */ | ||
662 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
663 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
664 | link->conf.Status = CCSR_AUDIO_ENA; | ||
665 | } | ||
666 | |||
667 | /* Use power settings for Vcc and Vpp if present */ | ||
668 | /* Note that the CIS values need to be rescaled */ | ||
669 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
670 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / | ||
671 | 10000 && !ignore_cis_vcc) { | ||
672 | PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" | ||
673 | " this entry\n"); | ||
674 | goto next_entry; | ||
675 | } | ||
676 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
677 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / | ||
678 | 10000 && !ignore_cis_vcc) { | ||
679 | PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " | ||
680 | "- skipping this entry\n"); | ||
681 | goto next_entry; | ||
682 | } | ||
683 | } | ||
684 | |||
685 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
686 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
687 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
688 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
689 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
690 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
691 | |||
692 | /* Do we need to allocate an interrupt? */ | ||
693 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
694 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
695 | else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { | ||
696 | /* At least Compaq WL200 does not have IRQInfo1 set, | ||
697 | * but it does not work without interrupts.. */ | ||
698 | printk("Config has no IRQ info, but trying to enable " | ||
699 | "IRQ anyway..\n"); | ||
700 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
701 | } | ||
702 | |||
703 | /* IO window settings */ | ||
704 | PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " | ||
705 | "dflt.io.nwin=%d\n", | ||
706 | cfg->io.nwin, dflt.io.nwin); | ||
707 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
708 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
709 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
710 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
711 | PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " | ||
712 | "io.base=0x%04x, len=%d\n", io->flags, | ||
713 | io->win[0].base, io->win[0].len); | ||
714 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
715 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
716 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
717 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
718 | link->io.IOAddrLines = io->flags & | ||
719 | CISTPL_IO_LINES_MASK; | ||
720 | link->io.BasePort1 = io->win[0].base; | ||
721 | link->io.NumPorts1 = io->win[0].len; | ||
722 | if (io->nwin > 1) { | ||
723 | link->io.Attributes2 = link->io.Attributes1; | ||
724 | link->io.BasePort2 = io->win[1].base; | ||
725 | link->io.NumPorts2 = io->win[1].len; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | /* This reserves IO space but doesn't actually enable it */ | ||
730 | CFG_CHECK2(RequestIO, | ||
731 | pcmcia_request_io(link->handle, &link->io)); | ||
732 | |||
733 | /* This configuration table entry is OK */ | ||
734 | break; | ||
735 | |||
736 | next_entry: | ||
737 | CS_CHECK(GetNextTuple, | ||
738 | pcmcia_get_next_tuple(link->handle, &tuple)); | ||
739 | } | ||
740 | |||
741 | /* Need to allocate net_device before requesting IRQ handler */ | ||
742 | dev = prism2_init_local_data(&prism2_pccard_funcs, 0); | ||
743 | if (dev == NULL) | ||
744 | goto failed; | ||
745 | link->priv = dev; | ||
746 | |||
747 | /* | ||
748 | * Allocate an interrupt line. Note that this does not assign a | ||
749 | * handler to the interrupt, unless the 'Handler' member of the | ||
750 | * irq structure is initialized. | ||
751 | */ | ||
752 | if (link->conf.Attributes & CONF_ENABLE_IRQ) { | ||
753 | int i; | ||
754 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
755 | link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; | ||
756 | if (irq_list[0] == -1) | ||
757 | link->irq.IRQInfo2 = irq_mask; | ||
758 | else | ||
759 | for (i = 0; i < 4; i++) | ||
760 | link->irq.IRQInfo2 |= 1 << irq_list[i]; | ||
761 | link->irq.Handler = prism2_interrupt; | ||
762 | link->irq.Instance = dev; | ||
763 | CS_CHECK(RequestIRQ, | ||
764 | pcmcia_request_irq(link->handle, &link->irq)); | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * This actually configures the PCMCIA socket -- setting up | ||
769 | * the I/O windows and the interrupt mapping, and putting the | ||
770 | * card and host interface into "Memory and IO" mode. | ||
771 | */ | ||
772 | CS_CHECK(RequestConfiguration, | ||
773 | pcmcia_request_configuration(link->handle, &link->conf)); | ||
774 | |||
775 | dev->irq = link->irq.AssignedIRQ; | ||
776 | dev->base_addr = link->io.BasePort1; | ||
777 | |||
778 | /* Finally, report what we've done */ | ||
779 | printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", | ||
780 | dev_info, link->conf.ConfigIndex, | ||
781 | link->conf.Vcc / 10, link->conf.Vcc % 10); | ||
782 | if (link->conf.Vpp1) | ||
783 | printk(", Vpp %d.%d", link->conf.Vpp1 / 10, | ||
784 | link->conf.Vpp1 % 10); | ||
785 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
786 | printk(", irq %d", link->irq.AssignedIRQ); | ||
787 | if (link->io.NumPorts1) | ||
788 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
789 | link->io.BasePort1+link->io.NumPorts1-1); | ||
790 | if (link->io.NumPorts2) | ||
791 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
792 | link->io.BasePort2+link->io.NumPorts2-1); | ||
793 | printk("\n"); | ||
794 | |||
795 | link->state |= DEV_CONFIG; | ||
796 | link->state &= ~DEV_CONFIG_PENDING; | ||
797 | |||
798 | iface = netdev_priv(dev); | ||
799 | local = iface->local; | ||
800 | local->link = link; | ||
801 | strcpy(local->node.dev_name, dev->name); | ||
802 | link->dev = &local->node; | ||
803 | |||
804 | local->shutdown = 0; | ||
805 | |||
806 | sandisk_enable_wireless(dev); | ||
807 | |||
808 | ret = prism2_hw_config(dev, 1); | ||
809 | if (!ret) { | ||
810 | ret = hostap_hw_ready(dev); | ||
811 | if (ret == 0 && local->ddev) | ||
812 | strcpy(local->node.dev_name, local->ddev->name); | ||
813 | } | ||
814 | kfree(parse); | ||
815 | return ret; | ||
816 | |||
817 | cs_failed: | ||
818 | cs_error(link->handle, last_fn, last_ret); | ||
819 | |||
820 | failed: | ||
821 | kfree(parse); | ||
822 | prism2_release((u_long)link); | ||
823 | return ret; | ||
824 | } | ||
825 | |||
826 | |||
827 | static void prism2_release(u_long arg) | ||
828 | { | ||
829 | dev_link_t *link = (dev_link_t *)arg; | ||
830 | |||
831 | PDEBUG(DEBUG_FLOW, "prism2_release\n"); | ||
832 | |||
833 | if (link->priv) { | ||
834 | struct net_device *dev = link->priv; | ||
835 | struct hostap_interface *iface; | ||
836 | |||
837 | iface = netdev_priv(dev); | ||
838 | if (link->state & DEV_CONFIG) | ||
839 | prism2_hw_shutdown(dev, 0); | ||
840 | iface->local->shutdown = 1; | ||
841 | } | ||
842 | |||
843 | if (link->win) | ||
844 | pcmcia_release_window(link->win); | ||
845 | pcmcia_release_configuration(link->handle); | ||
846 | if (link->io.NumPorts1) | ||
847 | pcmcia_release_io(link->handle, &link->io); | ||
848 | if (link->irq.AssignedIRQ) | ||
849 | pcmcia_release_irq(link->handle, &link->irq); | ||
850 | |||
851 | link->state &= ~DEV_CONFIG; | ||
852 | |||
853 | PDEBUG(DEBUG_FLOW, "release - done\n"); | ||
854 | } | ||
855 | |||
856 | |||
857 | static int prism2_event(event_t event, int priority, | ||
858 | event_callback_args_t *args) | ||
859 | { | ||
860 | dev_link_t *link = args->client_data; | ||
861 | struct net_device *dev = (struct net_device *) link->priv; | ||
862 | |||
863 | switch (event) { | ||
864 | case CS_EVENT_CARD_INSERTION: | ||
865 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info); | ||
866 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
867 | if (prism2_config(link)) { | ||
868 | PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); | ||
869 | } | ||
870 | break; | ||
871 | |||
872 | case CS_EVENT_CARD_REMOVAL: | ||
873 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info); | ||
874 | link->state &= ~DEV_PRESENT; | ||
875 | if (link->state & DEV_CONFIG) { | ||
876 | netif_stop_queue(dev); | ||
877 | netif_device_detach(dev); | ||
878 | prism2_release((u_long) link); | ||
879 | } | ||
880 | break; | ||
881 | |||
882 | case CS_EVENT_PM_SUSPEND: | ||
883 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | ||
884 | link->state |= DEV_SUSPEND; | ||
885 | /* fall through */ | ||
886 | |||
887 | case CS_EVENT_RESET_PHYSICAL: | ||
888 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); | ||
889 | if (link->state & DEV_CONFIG) { | ||
890 | if (link->open) { | ||
891 | netif_stop_queue(dev); | ||
892 | netif_device_detach(dev); | ||
893 | } | ||
894 | prism2_suspend(dev); | ||
895 | pcmcia_release_configuration(link->handle); | ||
896 | } | ||
897 | break; | ||
898 | |||
899 | case CS_EVENT_PM_RESUME: | ||
900 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); | ||
901 | link->state &= ~DEV_SUSPEND; | ||
902 | /* fall through */ | ||
903 | |||
904 | case CS_EVENT_CARD_RESET: | ||
905 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info); | ||
906 | if (link->state & DEV_CONFIG) { | ||
907 | pcmcia_request_configuration(link->handle, | ||
908 | &link->conf); | ||
909 | prism2_hw_shutdown(dev, 1); | ||
910 | prism2_hw_config(dev, link->open ? 0 : 1); | ||
911 | if (link->open) { | ||
912 | netif_device_attach(dev); | ||
913 | netif_start_queue(dev); | ||
914 | } | ||
915 | } | ||
916 | break; | ||
917 | |||
918 | default: | ||
919 | PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n", | ||
920 | dev_info, event); | ||
921 | break; | ||
922 | } | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | |||
927 | static struct pcmcia_driver hostap_driver = { | ||
928 | .drv = { | ||
929 | .name = "hostap_cs", | ||
930 | }, | ||
931 | .attach = prism2_attach, | ||
932 | .detach = prism2_detach, | ||
933 | .owner = THIS_MODULE, | ||
934 | }; | ||
935 | |||
936 | static int __init init_prism2_pccard(void) | ||
937 | { | ||
938 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
939 | return pcmcia_register_driver(&hostap_driver); | ||
940 | } | ||
941 | |||
942 | static void __exit exit_prism2_pccard(void) | ||
943 | { | ||
944 | pcmcia_unregister_driver(&hostap_driver); | ||
945 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
946 | } | ||
947 | |||
948 | |||
949 | module_init(init_prism2_pccard); | ||
950 | 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 00000000000..ab26b52b3e7 --- /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 00000000000..039ef7f61be --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
@@ -0,0 +1,3631 @@ | |||
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-2004, 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 <asm/irq.h> | ||
52 | |||
53 | |||
54 | #include "hostap_80211.h" | ||
55 | #include "hostap.h" | ||
56 | #include "hostap_ap.h" | ||
57 | |||
58 | |||
59 | /* #define final_version */ | ||
60 | |||
61 | static int mtu = 1500; | ||
62 | module_param(mtu, int, 0444); | ||
63 | MODULE_PARM_DESC(mtu, "Maximum transfer unit"); | ||
64 | |||
65 | static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; | ||
66 | module_param_array(channel, int, NULL, 0444); | ||
67 | MODULE_PARM_DESC(channel, "Initial channel"); | ||
68 | |||
69 | static char essid[33] = "test"; | ||
70 | module_param_string(essid, essid, sizeof(essid), 0444); | ||
71 | MODULE_PARM_DESC(essid, "Host AP's ESSID"); | ||
72 | |||
73 | static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; | ||
74 | module_param_array(iw_mode, int, NULL, 0444); | ||
75 | MODULE_PARM_DESC(iw_mode, "Initial operation mode"); | ||
76 | |||
77 | static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | ||
78 | module_param_array(beacon_int, int, NULL, 0444); | ||
79 | MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); | ||
80 | |||
81 | static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | ||
82 | module_param_array(dtim_period, int, NULL, 0444); | ||
83 | MODULE_PARM_DESC(dtim_period, "DTIM period"); | ||
84 | |||
85 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
86 | static int bus_master_threshold_rx[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | ||
87 | module_param_array(bus_master_threshold_rx, int, NULL, 0444); | ||
88 | MODULE_PARM_DESC(bus_master_threshold_rx, "Packet length threshold for using " | ||
89 | "PCI bus master on RX"); | ||
90 | |||
91 | static int bus_master_threshold_tx[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | ||
92 | module_param_array(bus_master_threshold_tx, int, NULL, 0444); | ||
93 | MODULE_PARM_DESC(bus_master_threshold_tx, "Packet length threshold for using " | ||
94 | "PCI bus master on TX"); | ||
95 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
96 | |||
97 | static char dev_template[16] = "wlan%d"; | ||
98 | module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); | ||
99 | MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " | ||
100 | "wlan%d)"); | ||
101 | |||
102 | #ifdef final_version | ||
103 | #define EXTRA_EVENTS_WTERR 0 | ||
104 | #else | ||
105 | /* check WTERR events (Wait Time-out) in development versions */ | ||
106 | #define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR | ||
107 | #endif | ||
108 | |||
109 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
110 | #define EXTRA_EVENTS_BUS_MASTER (HFA384X_EV_PCI_M0 | HFA384X_EV_PCI_M1) | ||
111 | #else | ||
112 | #define EXTRA_EVENTS_BUS_MASTER 0 | ||
113 | #endif | ||
114 | |||
115 | /* Events that will be using BAP0 */ | ||
116 | #define HFA384X_BAP0_EVENTS \ | ||
117 | (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) | ||
118 | |||
119 | /* event mask, i.e., events that will result in an interrupt */ | ||
120 | #define HFA384X_EVENT_MASK \ | ||
121 | (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ | ||
122 | HFA384X_EV_CMD | HFA384X_EV_TICK | \ | ||
123 | EXTRA_EVENTS_WTERR | EXTRA_EVENTS_BUS_MASTER) | ||
124 | |||
125 | /* Default TX control flags: use 802.11 headers and request interrupt for | ||
126 | * failed transmits. Frames that request ACK callback, will add | ||
127 | * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. | ||
128 | */ | ||
129 | #define HFA384X_TX_CTRL_FLAGS \ | ||
130 | (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) | ||
131 | |||
132 | |||
133 | /* ca. 1 usec */ | ||
134 | #define HFA384X_CMD_BUSY_TIMEOUT 5000 | ||
135 | #define HFA384X_BAP_BUSY_TIMEOUT 50000 | ||
136 | |||
137 | /* ca. 10 usec */ | ||
138 | #define HFA384X_CMD_COMPL_TIMEOUT 20000 | ||
139 | #define HFA384X_DL_COMPL_TIMEOUT 1000000 | ||
140 | |||
141 | /* Wait times for initialization; yield to other processes to avoid busy | ||
142 | * waiting for long time. */ | ||
143 | #define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ | ||
144 | #define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ | ||
145 | |||
146 | |||
147 | static void prism2_hw_reset(struct net_device *dev); | ||
148 | static void prism2_check_sta_fw_version(local_info_t *local); | ||
149 | |||
150 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
151 | /* hostap_download.c */ | ||
152 | static int prism2_download_aux_dump(struct net_device *dev, | ||
153 | unsigned int addr, int len, u8 *buf); | ||
154 | static u8 * prism2_read_pda(struct net_device *dev); | ||
155 | static int prism2_download(local_info_t *local, | ||
156 | struct prism2_download_param *param); | ||
157 | static void prism2_download_free_data(struct prism2_download_data *dl); | ||
158 | static int prism2_download_volatile(local_info_t *local, | ||
159 | struct prism2_download_data *param); | ||
160 | static int prism2_download_genesis(local_info_t *local, | ||
161 | struct prism2_download_data *param); | ||
162 | static int prism2_get_ram_size(local_info_t *local); | ||
163 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
164 | |||
165 | |||
166 | |||
167 | |||
168 | #ifndef final_version | ||
169 | /* magic value written to SWSUPPORT0 reg. for detecting whether card is still | ||
170 | * present */ | ||
171 | #define HFA384X_MAGIC 0x8A32 | ||
172 | #endif | ||
173 | |||
174 | |||
175 | static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) | ||
176 | { | ||
177 | return HFA384X_INW(reg); | ||
178 | } | ||
179 | |||
180 | |||
181 | static void hfa384x_read_regs(struct net_device *dev, | ||
182 | struct hfa384x_regs *regs) | ||
183 | { | ||
184 | regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); | ||
185 | regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
186 | regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); | ||
187 | regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); | ||
188 | regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); | ||
189 | } | ||
190 | |||
191 | |||
192 | /** | ||
193 | * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) | ||
194 | * @local: pointer to private Host AP driver data | ||
195 | * @entry: Prism2 command queue entry to be freed | ||
196 | * @del_req: request the entry to be removed | ||
197 | * | ||
198 | * Internal helper function for freeing Prism2 command queue entries. | ||
199 | * Caller must have acquired local->cmdlock before calling this function. | ||
200 | */ | ||
201 | static inline void __hostap_cmd_queue_free(local_info_t *local, | ||
202 | struct hostap_cmd_queue *entry, | ||
203 | int del_req) | ||
204 | { | ||
205 | if (del_req) { | ||
206 | entry->del_req = 1; | ||
207 | if (!list_empty(&entry->list)) { | ||
208 | list_del_init(&entry->list); | ||
209 | local->cmd_queue_len--; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) | ||
214 | kfree(entry); | ||
215 | } | ||
216 | |||
217 | |||
218 | /** | ||
219 | * hostap_cmd_queue_free - Free Prism2 command queue entry | ||
220 | * @local: pointer to private Host AP driver data | ||
221 | * @entry: Prism2 command queue entry to be freed | ||
222 | * @del_req: request the entry to be removed | ||
223 | * | ||
224 | * Free a Prism2 command queue entry. | ||
225 | */ | ||
226 | static inline void hostap_cmd_queue_free(local_info_t *local, | ||
227 | struct hostap_cmd_queue *entry, | ||
228 | int del_req) | ||
229 | { | ||
230 | unsigned long flags; | ||
231 | |||
232 | spin_lock_irqsave(&local->cmdlock, flags); | ||
233 | __hostap_cmd_queue_free(local, entry, del_req); | ||
234 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries | ||
240 | * @local: pointer to private Host AP driver data | ||
241 | */ | ||
242 | static void prism2_clear_cmd_queue(local_info_t *local) | ||
243 | { | ||
244 | struct list_head *ptr, *n; | ||
245 | unsigned long flags; | ||
246 | struct hostap_cmd_queue *entry; | ||
247 | |||
248 | spin_lock_irqsave(&local->cmdlock, flags); | ||
249 | list_for_each_safe(ptr, n, &local->cmd_queue) { | ||
250 | entry = list_entry(ptr, struct hostap_cmd_queue, list); | ||
251 | atomic_inc(&entry->usecnt); | ||
252 | printk(KERN_DEBUG "%s: removed pending cmd_queue entry " | ||
253 | "(type=%d, cmd=0x%04x, param0=0x%04x)\n", | ||
254 | local->dev->name, entry->type, entry->cmd, | ||
255 | entry->param0); | ||
256 | __hostap_cmd_queue_free(local, entry, 1); | ||
257 | } | ||
258 | if (local->cmd_queue_len) { | ||
259 | /* This should not happen; print debug message and clear | ||
260 | * queue length. */ | ||
261 | printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " | ||
262 | "flush\n", local->dev->name, local->cmd_queue_len); | ||
263 | local->cmd_queue_len = 0; | ||
264 | } | ||
265 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
266 | } | ||
267 | |||
268 | |||
269 | /** | ||
270 | * hfa384x_cmd_issue - Issue a Prism2 command to the hardware | ||
271 | * @dev: pointer to net_device | ||
272 | * @entry: Prism2 command queue entry to be issued | ||
273 | */ | ||
274 | static inline int hfa384x_cmd_issue(struct net_device *dev, | ||
275 | struct hostap_cmd_queue *entry) | ||
276 | { | ||
277 | struct hostap_interface *iface; | ||
278 | local_info_t *local; | ||
279 | int tries; | ||
280 | u16 reg; | ||
281 | unsigned long flags; | ||
282 | |||
283 | iface = netdev_priv(dev); | ||
284 | local = iface->local; | ||
285 | |||
286 | if (local->func->card_present && !local->func->card_present(local)) | ||
287 | return -ENODEV; | ||
288 | |||
289 | if (entry->issued) { | ||
290 | printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", | ||
291 | dev->name, entry); | ||
292 | } | ||
293 | |||
294 | /* wait until busy bit is clear; this should always be clear since the | ||
295 | * commands are serialized */ | ||
296 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
297 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
298 | tries--; | ||
299 | udelay(1); | ||
300 | } | ||
301 | #ifndef final_version | ||
302 | if (tries != HFA384X_CMD_BUSY_TIMEOUT) { | ||
303 | prism2_io_debug_error(dev, 1); | ||
304 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " | ||
305 | "for %d usec\n", dev->name, | ||
306 | HFA384X_CMD_BUSY_TIMEOUT - tries); | ||
307 | } | ||
308 | #endif | ||
309 | if (tries == 0) { | ||
310 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
311 | prism2_io_debug_error(dev, 2); | ||
312 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " | ||
313 | "reg=0x%04x\n", dev->name, reg); | ||
314 | return -ETIMEDOUT; | ||
315 | } | ||
316 | |||
317 | /* write command */ | ||
318 | spin_lock_irqsave(&local->cmdlock, flags); | ||
319 | HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); | ||
320 | HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); | ||
321 | HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); | ||
322 | entry->issued = 1; | ||
323 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | |||
329 | /** | ||
330 | * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion | ||
331 | * @dev: pointer to net_device | ||
332 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
333 | * @param0: value for Param0 register | ||
334 | * @param1: value for Param1 register (pointer; %NULL if not used) | ||
335 | * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed | ||
336 | * | ||
337 | * Issue given command (possibly after waiting in command queue) and sleep | ||
338 | * until the command is completed (or timed out or interrupted). This can be | ||
339 | * called only from user process context. | ||
340 | */ | ||
341 | static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, | ||
342 | u16 *param1, u16 *resp0) | ||
343 | { | ||
344 | struct hostap_interface *iface; | ||
345 | local_info_t *local; | ||
346 | int err, res, issue, issued = 0; | ||
347 | unsigned long flags; | ||
348 | struct hostap_cmd_queue *entry; | ||
349 | DECLARE_WAITQUEUE(wait, current); | ||
350 | |||
351 | iface = netdev_priv(dev); | ||
352 | local = iface->local; | ||
353 | |||
354 | if (in_interrupt()) { | ||
355 | printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt " | ||
356 | "context\n", dev->name); | ||
357 | return -1; | ||
358 | } | ||
359 | |||
360 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { | ||
361 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
362 | dev->name); | ||
363 | return -1; | ||
364 | } | ||
365 | |||
366 | if (signal_pending(current)) | ||
367 | return -EINTR; | ||
368 | |||
369 | entry = (struct hostap_cmd_queue *) | ||
370 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
371 | if (entry == NULL) { | ||
372 | printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n", | ||
373 | dev->name); | ||
374 | return -ENOMEM; | ||
375 | } | ||
376 | memset(entry, 0, sizeof(*entry)); | ||
377 | atomic_set(&entry->usecnt, 1); | ||
378 | entry->type = CMD_SLEEP; | ||
379 | entry->cmd = cmd; | ||
380 | entry->param0 = param0; | ||
381 | if (param1) | ||
382 | entry->param1 = *param1; | ||
383 | init_waitqueue_head(&entry->compl); | ||
384 | |||
385 | /* prepare to wait for command completion event, but do not sleep yet | ||
386 | */ | ||
387 | add_wait_queue(&entry->compl, &wait); | ||
388 | set_current_state(TASK_INTERRUPTIBLE); | ||
389 | |||
390 | spin_lock_irqsave(&local->cmdlock, flags); | ||
391 | issue = list_empty(&local->cmd_queue); | ||
392 | if (issue) | ||
393 | entry->issuing = 1; | ||
394 | list_add_tail(&entry->list, &local->cmd_queue); | ||
395 | local->cmd_queue_len++; | ||
396 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
397 | |||
398 | err = 0; | ||
399 | if (!issue) | ||
400 | goto wait_completion; | ||
401 | |||
402 | if (signal_pending(current)) | ||
403 | err = -EINTR; | ||
404 | |||
405 | if (!err) { | ||
406 | if (hfa384x_cmd_issue(dev, entry)) | ||
407 | err = -ETIMEDOUT; | ||
408 | else | ||
409 | issued = 1; | ||
410 | } | ||
411 | |||
412 | wait_completion: | ||
413 | if (!err && entry->type != CMD_COMPLETED) { | ||
414 | /* sleep until command is completed or timed out */ | ||
415 | res = schedule_timeout(2 * HZ); | ||
416 | } else | ||
417 | res = -1; | ||
418 | |||
419 | if (!err && signal_pending(current)) | ||
420 | err = -EINTR; | ||
421 | |||
422 | if (err && issued) { | ||
423 | /* the command was issued, so a CmdCompl event should occur | ||
424 | * soon; however, there's a pending signal and | ||
425 | * schedule_timeout() would be interrupted; wait a short period | ||
426 | * of time to avoid removing entry from the list before | ||
427 | * CmdCompl event */ | ||
428 | udelay(300); | ||
429 | } | ||
430 | |||
431 | set_current_state(TASK_RUNNING); | ||
432 | remove_wait_queue(&entry->compl, &wait); | ||
433 | |||
434 | /* If entry->list is still in the list, it must be removed | ||
435 | * first and in this case prism2_cmd_ev() does not yet have | ||
436 | * local reference to it, and the data can be kfree()'d | ||
437 | * here. If the command completion event is still generated, | ||
438 | * it will be assigned to next (possibly) pending command, but | ||
439 | * the driver will reset the card anyway due to timeout | ||
440 | * | ||
441 | * If the entry is not in the list prism2_cmd_ev() has a local | ||
442 | * reference to it, but keeps cmdlock as long as the data is | ||
443 | * needed, so the data can be kfree()'d here. */ | ||
444 | |||
445 | /* FIX: if the entry->list is in the list, it has not been completed | ||
446 | * yet, so removing it here is somewhat wrong.. this could cause | ||
447 | * references to freed memory and next list_del() causing NULL pointer | ||
448 | * dereference.. it would probably be better to leave the entry in the | ||
449 | * list and the list should be emptied during hw reset */ | ||
450 | |||
451 | spin_lock_irqsave(&local->cmdlock, flags); | ||
452 | if (!list_empty(&entry->list)) { | ||
453 | printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " | ||
454 | "(entry=%p, type=%d, res=%d)\n", dev->name, entry, | ||
455 | entry->type, res); | ||
456 | list_del_init(&entry->list); | ||
457 | local->cmd_queue_len--; | ||
458 | } | ||
459 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
460 | |||
461 | if (err) { | ||
462 | printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", | ||
463 | dev->name, err); | ||
464 | res = err; | ||
465 | goto done; | ||
466 | } | ||
467 | |||
468 | if (entry->type != CMD_COMPLETED) { | ||
469 | u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
470 | printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " | ||
471 | "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " | ||
472 | "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, | ||
473 | res, entry, entry->type, entry->cmd, entry->param0, reg, | ||
474 | HFA384X_INW(HFA384X_INTEN_OFF)); | ||
475 | if (reg & HFA384X_EV_CMD) { | ||
476 | /* Command completion event is pending, but the | ||
477 | * interrupt was not delivered - probably an issue | ||
478 | * with pcmcia-cs configuration. */ | ||
479 | printk(KERN_WARNING "%s: interrupt delivery does not " | ||
480 | "seem to work\n", dev->name); | ||
481 | } | ||
482 | prism2_io_debug_error(dev, 3); | ||
483 | res = -ETIMEDOUT; | ||
484 | goto done; | ||
485 | } | ||
486 | |||
487 | if (resp0 != NULL) | ||
488 | *resp0 = entry->resp0; | ||
489 | #ifndef final_version | ||
490 | if (entry->res) { | ||
491 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " | ||
492 | "resp0=0x%04x\n", | ||
493 | dev->name, cmd, entry->res, entry->resp0); | ||
494 | } | ||
495 | #endif /* final_version */ | ||
496 | |||
497 | res = entry->res; | ||
498 | done: | ||
499 | hostap_cmd_queue_free(local, entry, 1); | ||
500 | return res; | ||
501 | } | ||
502 | |||
503 | |||
504 | /** | ||
505 | * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed | ||
506 | * @dev: pointer to net_device | ||
507 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
508 | * @param0: value for Param0 register | ||
509 | * @callback: command completion callback function (%NULL = no callback) | ||
510 | * @context: data pointer to be given to callback function | ||
511 | * | ||
512 | * Issue given command (possibly after waiting in command queue) and use | ||
513 | * callback function to indicate command completion. This can be called both | ||
514 | * from user and interrupt context. The callback function will be called in | ||
515 | * hardware IRQ context. It can be %NULL, when no function is called when | ||
516 | * command is completed. | ||
517 | */ | ||
518 | static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, | ||
519 | void (*callback)(struct net_device *dev, | ||
520 | void *context, u16 resp0, | ||
521 | u16 status), | ||
522 | void *context) | ||
523 | { | ||
524 | struct hostap_interface *iface; | ||
525 | local_info_t *local; | ||
526 | int issue, ret; | ||
527 | unsigned long flags; | ||
528 | struct hostap_cmd_queue *entry; | ||
529 | |||
530 | iface = netdev_priv(dev); | ||
531 | local = iface->local; | ||
532 | |||
533 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { | ||
534 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
535 | dev->name); | ||
536 | return -1; | ||
537 | } | ||
538 | |||
539 | entry = (struct hostap_cmd_queue *) | ||
540 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
541 | if (entry == NULL) { | ||
542 | printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc " | ||
543 | "failed\n", dev->name); | ||
544 | return -ENOMEM; | ||
545 | } | ||
546 | memset(entry, 0, sizeof(*entry)); | ||
547 | atomic_set(&entry->usecnt, 1); | ||
548 | entry->type = CMD_CALLBACK; | ||
549 | entry->cmd = cmd; | ||
550 | entry->param0 = param0; | ||
551 | entry->callback = callback; | ||
552 | entry->context = context; | ||
553 | |||
554 | spin_lock_irqsave(&local->cmdlock, flags); | ||
555 | issue = list_empty(&local->cmd_queue); | ||
556 | if (issue) | ||
557 | entry->issuing = 1; | ||
558 | list_add_tail(&entry->list, &local->cmd_queue); | ||
559 | local->cmd_queue_len++; | ||
560 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
561 | |||
562 | if (issue && hfa384x_cmd_issue(dev, entry)) | ||
563 | ret = -ETIMEDOUT; | ||
564 | else | ||
565 | ret = 0; | ||
566 | |||
567 | hostap_cmd_queue_free(local, entry, ret); | ||
568 | |||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | |||
573 | /** | ||
574 | * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) | ||
575 | * @dev: pointer to net_device | ||
576 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
577 | * @param0: value for Param0 register | ||
578 | * @io_debug_num: I/O debug error number | ||
579 | * | ||
580 | * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). | ||
581 | */ | ||
582 | static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, | ||
583 | int io_debug_num) | ||
584 | { | ||
585 | int tries; | ||
586 | u16 reg; | ||
587 | |||
588 | /* wait until busy bit is clear; this should always be clear since the | ||
589 | * commands are serialized */ | ||
590 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
591 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
592 | tries--; | ||
593 | udelay(1); | ||
594 | } | ||
595 | if (tries == 0) { | ||
596 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
597 | prism2_io_debug_error(dev, io_debug_num); | ||
598 | printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " | ||
599 | "reg=0x%04x\n", dev->name, io_debug_num, reg); | ||
600 | return -ETIMEDOUT; | ||
601 | } | ||
602 | |||
603 | /* write command */ | ||
604 | HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); | ||
605 | HFA384X_OUTW(cmd, HFA384X_CMD_OFF); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | |||
611 | /** | ||
612 | * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion | ||
613 | * @dev: pointer to net_device | ||
614 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
615 | * @param0: value for Param0 register | ||
616 | */ | ||
617 | static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) | ||
618 | { | ||
619 | int res, tries; | ||
620 | u16 reg; | ||
621 | |||
622 | res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); | ||
623 | if (res) | ||
624 | return res; | ||
625 | |||
626 | /* wait for command completion */ | ||
627 | if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) | ||
628 | tries = HFA384X_DL_COMPL_TIMEOUT; | ||
629 | else | ||
630 | tries = HFA384X_CMD_COMPL_TIMEOUT; | ||
631 | |||
632 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
633 | tries > 0) { | ||
634 | tries--; | ||
635 | udelay(10); | ||
636 | } | ||
637 | if (tries == 0) { | ||
638 | reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
639 | prism2_io_debug_error(dev, 5); | ||
640 | printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " | ||
641 | "reg=0x%04x\n", dev->name, reg); | ||
642 | return -ETIMEDOUT; | ||
643 | } | ||
644 | |||
645 | res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
646 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | | ||
647 | BIT(8))) >> 8; | ||
648 | #ifndef final_version | ||
649 | if (res) { | ||
650 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", | ||
651 | dev->name, cmd, res); | ||
652 | } | ||
653 | #endif | ||
654 | |||
655 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
656 | |||
657 | return res; | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion | ||
663 | * @dev: pointer to net_device | ||
664 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
665 | * @param0: value for Param0 register | ||
666 | */ | ||
667 | static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, | ||
668 | u16 param0) | ||
669 | { | ||
670 | return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); | ||
671 | } | ||
672 | |||
673 | |||
674 | /** | ||
675 | * prism2_cmd_ev - Prism2 command completion event handler | ||
676 | * @dev: pointer to net_device | ||
677 | * | ||
678 | * Interrupt handler for command completion events. Called by the main | ||
679 | * interrupt handler in hardware IRQ context. Read Resp0 and status registers | ||
680 | * from the hardware and ACK the event. Depending on the issued command type | ||
681 | * either wake up the sleeping process that is waiting for command completion | ||
682 | * or call the callback function. Issue the next command, if one is pending. | ||
683 | */ | ||
684 | static void prism2_cmd_ev(struct net_device *dev) | ||
685 | { | ||
686 | struct hostap_interface *iface; | ||
687 | local_info_t *local; | ||
688 | struct hostap_cmd_queue *entry = NULL; | ||
689 | |||
690 | iface = netdev_priv(dev); | ||
691 | local = iface->local; | ||
692 | |||
693 | spin_lock(&local->cmdlock); | ||
694 | if (!list_empty(&local->cmd_queue)) { | ||
695 | entry = list_entry(local->cmd_queue.next, | ||
696 | struct hostap_cmd_queue, list); | ||
697 | atomic_inc(&entry->usecnt); | ||
698 | list_del_init(&entry->list); | ||
699 | local->cmd_queue_len--; | ||
700 | |||
701 | if (!entry->issued) { | ||
702 | printk(KERN_DEBUG "%s: Command completion event, but " | ||
703 | "cmd not issued\n", dev->name); | ||
704 | __hostap_cmd_queue_free(local, entry, 1); | ||
705 | entry = NULL; | ||
706 | } | ||
707 | } | ||
708 | spin_unlock(&local->cmdlock); | ||
709 | |||
710 | if (!entry) { | ||
711 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
712 | printk(KERN_DEBUG "%s: Command completion event, but no " | ||
713 | "pending commands\n", dev->name); | ||
714 | return; | ||
715 | } | ||
716 | |||
717 | entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); | ||
718 | entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
719 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | | ||
720 | BIT(9) | BIT(8))) >> 8; | ||
721 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
722 | |||
723 | /* TODO: rest of the CmdEv handling could be moved to tasklet */ | ||
724 | if (entry->type == CMD_SLEEP) { | ||
725 | entry->type = CMD_COMPLETED; | ||
726 | wake_up_interruptible(&entry->compl); | ||
727 | } else if (entry->type == CMD_CALLBACK) { | ||
728 | if (entry->callback) | ||
729 | entry->callback(dev, entry->context, entry->resp0, | ||
730 | entry->res); | ||
731 | } else { | ||
732 | printk(KERN_DEBUG "%s: Invalid command completion type %d\n", | ||
733 | dev->name, entry->type); | ||
734 | } | ||
735 | hostap_cmd_queue_free(local, entry, 1); | ||
736 | |||
737 | /* issue next command, if pending */ | ||
738 | entry = NULL; | ||
739 | spin_lock(&local->cmdlock); | ||
740 | if (!list_empty(&local->cmd_queue)) { | ||
741 | entry = list_entry(local->cmd_queue.next, | ||
742 | struct hostap_cmd_queue, list); | ||
743 | if (entry->issuing) { | ||
744 | /* hfa384x_cmd() has already started issuing this | ||
745 | * command, so do not start here */ | ||
746 | entry = NULL; | ||
747 | } | ||
748 | if (entry) | ||
749 | atomic_inc(&entry->usecnt); | ||
750 | } | ||
751 | spin_unlock(&local->cmdlock); | ||
752 | |||
753 | if (entry) { | ||
754 | /* issue next command; if command issuing fails, remove the | ||
755 | * entry from cmd_queue */ | ||
756 | int res = hfa384x_cmd_issue(dev, entry); | ||
757 | spin_lock(&local->cmdlock); | ||
758 | __hostap_cmd_queue_free(local, entry, res); | ||
759 | spin_unlock(&local->cmdlock); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | |||
764 | static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off) | ||
765 | { | ||
766 | int tries = HFA384X_BAP_BUSY_TIMEOUT; | ||
767 | int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
768 | |||
769 | while (res && tries > 0) { | ||
770 | tries--; | ||
771 | udelay(1); | ||
772 | res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
773 | } | ||
774 | return res; | ||
775 | } | ||
776 | |||
777 | |||
778 | /* Offset must be even */ | ||
779 | static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, | ||
780 | int offset) | ||
781 | { | ||
782 | u16 o_off, s_off; | ||
783 | int ret = 0; | ||
784 | |||
785 | if (offset % 2 || bap > 1) | ||
786 | return -EINVAL; | ||
787 | |||
788 | if (bap == BAP1) { | ||
789 | o_off = HFA384X_OFFSET1_OFF; | ||
790 | s_off = HFA384X_SELECT1_OFF; | ||
791 | } else { | ||
792 | o_off = HFA384X_OFFSET0_OFF; | ||
793 | s_off = HFA384X_SELECT0_OFF; | ||
794 | } | ||
795 | |||
796 | if (hfa384x_wait_offset(dev, o_off)) { | ||
797 | prism2_io_debug_error(dev, 7); | ||
798 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", | ||
799 | dev->name); | ||
800 | ret = -ETIMEDOUT; | ||
801 | goto out; | ||
802 | } | ||
803 | |||
804 | HFA384X_OUTW(id, s_off); | ||
805 | HFA384X_OUTW(offset, o_off); | ||
806 | |||
807 | if (hfa384x_wait_offset(dev, o_off)) { | ||
808 | prism2_io_debug_error(dev, 8); | ||
809 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", | ||
810 | dev->name); | ||
811 | ret = -ETIMEDOUT; | ||
812 | goto out; | ||
813 | } | ||
814 | #ifndef final_version | ||
815 | if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { | ||
816 | prism2_io_debug_error(dev, 9); | ||
817 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " | ||
818 | "(%d,0x04%x,%d); reg=0x%04x\n", | ||
819 | dev->name, bap, id, offset, HFA384X_INW(o_off)); | ||
820 | ret = -EINVAL; | ||
821 | } | ||
822 | #endif | ||
823 | |||
824 | out: | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | |||
829 | static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, | ||
830 | int exact_len) | ||
831 | { | ||
832 | struct hostap_interface *iface; | ||
833 | local_info_t *local; | ||
834 | int res, rlen = 0; | ||
835 | struct hfa384x_rid_hdr rec; | ||
836 | |||
837 | iface = netdev_priv(dev); | ||
838 | local = iface->local; | ||
839 | |||
840 | if (local->no_pri) { | ||
841 | printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " | ||
842 | "f/w\n", dev->name, rid, len); | ||
843 | return -ENOTTY; /* Well.. not really correct, but return | ||
844 | * something unique enough.. */ | ||
845 | } | ||
846 | |||
847 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
848 | local->hw_downloading) | ||
849 | return -ENODEV; | ||
850 | |||
851 | res = down_interruptible(&local->rid_bap_sem); | ||
852 | if (res) | ||
853 | return res; | ||
854 | |||
855 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); | ||
856 | if (res) { | ||
857 | printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " | ||
858 | "(res=%d, rid=%04x, len=%d)\n", | ||
859 | dev->name, res, rid, len); | ||
860 | up(&local->rid_bap_sem); | ||
861 | return res; | ||
862 | } | ||
863 | |||
864 | spin_lock_bh(&local->baplock); | ||
865 | |||
866 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
867 | if (!res) | ||
868 | res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); | ||
869 | |||
870 | if (le16_to_cpu(rec.len) == 0) { | ||
871 | /* RID not available */ | ||
872 | res = -ENODATA; | ||
873 | } | ||
874 | |||
875 | rlen = (le16_to_cpu(rec.len) - 1) * 2; | ||
876 | if (!res && exact_len && rlen != len) { | ||
877 | printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " | ||
878 | "rid=0x%04x, len=%d (expected %d)\n", | ||
879 | dev->name, rid, rlen, len); | ||
880 | res = -ENODATA; | ||
881 | } | ||
882 | |||
883 | if (!res) | ||
884 | res = hfa384x_from_bap(dev, BAP0, buf, len); | ||
885 | |||
886 | spin_unlock_bh(&local->baplock); | ||
887 | up(&local->rid_bap_sem); | ||
888 | |||
889 | if (res) { | ||
890 | if (res != -ENODATA) | ||
891 | printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " | ||
892 | "len=%d) - failed - res=%d\n", dev->name, rid, | ||
893 | len, res); | ||
894 | if (res == -ETIMEDOUT) | ||
895 | prism2_hw_reset(dev); | ||
896 | return res; | ||
897 | } | ||
898 | |||
899 | return rlen; | ||
900 | } | ||
901 | |||
902 | |||
903 | static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) | ||
904 | { | ||
905 | struct hostap_interface *iface; | ||
906 | local_info_t *local; | ||
907 | struct hfa384x_rid_hdr rec; | ||
908 | int res; | ||
909 | |||
910 | iface = netdev_priv(dev); | ||
911 | local = iface->local; | ||
912 | |||
913 | if (local->no_pri) { | ||
914 | printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " | ||
915 | "f/w\n", dev->name, rid, len); | ||
916 | return -ENOTTY; /* Well.. not really correct, but return | ||
917 | * something unique enough.. */ | ||
918 | } | ||
919 | |||
920 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
921 | local->hw_downloading) | ||
922 | return -ENODEV; | ||
923 | |||
924 | rec.rid = cpu_to_le16(rid); | ||
925 | /* RID len in words and +1 for rec.rid */ | ||
926 | rec.len = cpu_to_le16(len / 2 + len % 2 + 1); | ||
927 | |||
928 | res = down_interruptible(&local->rid_bap_sem); | ||
929 | if (res) | ||
930 | return res; | ||
931 | |||
932 | spin_lock_bh(&local->baplock); | ||
933 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
934 | if (!res) | ||
935 | res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); | ||
936 | if (!res) | ||
937 | res = hfa384x_to_bap(dev, BAP0, buf, len); | ||
938 | spin_unlock_bh(&local->baplock); | ||
939 | |||
940 | if (res) { | ||
941 | printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " | ||
942 | "failed - res=%d\n", dev->name, rid, len, res); | ||
943 | up(&local->rid_bap_sem); | ||
944 | return res; | ||
945 | } | ||
946 | |||
947 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); | ||
948 | up(&local->rid_bap_sem); | ||
949 | if (res) { | ||
950 | printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " | ||
951 | "failed (res=%d, rid=%04x, len=%d)\n", | ||
952 | dev->name, res, rid, len); | ||
953 | return res; | ||
954 | } | ||
955 | |||
956 | if (res == -ETIMEDOUT) | ||
957 | prism2_hw_reset(dev); | ||
958 | |||
959 | return res; | ||
960 | } | ||
961 | |||
962 | |||
963 | static void hfa384x_disable_interrupts(struct net_device *dev) | ||
964 | { | ||
965 | /* disable interrupts and clear event status */ | ||
966 | HFA384X_OUTW(0, HFA384X_INTEN_OFF); | ||
967 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
968 | } | ||
969 | |||
970 | |||
971 | static void hfa384x_enable_interrupts(struct net_device *dev) | ||
972 | { | ||
973 | /* ack pending events and enable interrupts from selected events */ | ||
974 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
975 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
976 | } | ||
977 | |||
978 | |||
979 | static void hfa384x_events_no_bap0(struct net_device *dev) | ||
980 | { | ||
981 | HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, | ||
982 | HFA384X_INTEN_OFF); | ||
983 | } | ||
984 | |||
985 | |||
986 | static void hfa384x_events_all(struct net_device *dev) | ||
987 | { | ||
988 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
989 | } | ||
990 | |||
991 | |||
992 | static void hfa384x_events_only_cmd(struct net_device *dev) | ||
993 | { | ||
994 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); | ||
995 | } | ||
996 | |||
997 | |||
998 | static u16 hfa384x_allocate_fid(struct net_device *dev, int len) | ||
999 | { | ||
1000 | u16 fid; | ||
1001 | unsigned long delay; | ||
1002 | |||
1003 | /* FIX: this could be replace with hfa384x_cmd() if the Alloc event | ||
1004 | * below would be handled like CmdCompl event (sleep here, wake up from | ||
1005 | * interrupt handler */ | ||
1006 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { | ||
1007 | printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", | ||
1008 | dev->name, len); | ||
1009 | return 0xffff; | ||
1010 | } | ||
1011 | |||
1012 | delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; | ||
1013 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && | ||
1014 | time_before(jiffies, delay)) | ||
1015 | yield(); | ||
1016 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { | ||
1017 | printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); | ||
1018 | return 0xffff; | ||
1019 | } | ||
1020 | |||
1021 | fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); | ||
1022 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
1023 | |||
1024 | return fid; | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | static int prism2_reset_port(struct net_device *dev) | ||
1029 | { | ||
1030 | struct hostap_interface *iface; | ||
1031 | local_info_t *local; | ||
1032 | int res; | ||
1033 | |||
1034 | iface = netdev_priv(dev); | ||
1035 | local = iface->local; | ||
1036 | |||
1037 | if (!local->dev_enabled) | ||
1038 | return 0; | ||
1039 | |||
1040 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, | ||
1041 | NULL, NULL); | ||
1042 | if (res) | ||
1043 | printk(KERN_DEBUG "%s: reset port failed to disable port\n", | ||
1044 | dev->name); | ||
1045 | else { | ||
1046 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, | ||
1047 | NULL, NULL); | ||
1048 | if (res) | ||
1049 | printk(KERN_DEBUG "%s: reset port failed to enable " | ||
1050 | "port\n", dev->name); | ||
1051 | } | ||
1052 | |||
1053 | /* It looks like at least some STA firmware versions reset | ||
1054 | * fragmentation threshold back to 2346 after enable command. Restore | ||
1055 | * the configured value, if it differs from this default. */ | ||
1056 | if (local->fragm_threshold != 2346 && | ||
1057 | hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1058 | local->fragm_threshold)) { | ||
1059 | printk(KERN_DEBUG "%s: failed to restore fragmentation " | ||
1060 | "threshold (%d) after Port0 enable\n", | ||
1061 | dev->name, local->fragm_threshold); | ||
1062 | } | ||
1063 | |||
1064 | return res; | ||
1065 | } | ||
1066 | |||
1067 | |||
1068 | static int prism2_get_version_info(struct net_device *dev, u16 rid, | ||
1069 | const char *txt) | ||
1070 | { | ||
1071 | struct hfa384x_comp_ident comp; | ||
1072 | struct hostap_interface *iface; | ||
1073 | local_info_t *local; | ||
1074 | |||
1075 | iface = netdev_priv(dev); | ||
1076 | local = iface->local; | ||
1077 | |||
1078 | if (local->no_pri) { | ||
1079 | /* PRI f/w not yet available - cannot read RIDs */ | ||
1080 | return -1; | ||
1081 | } | ||
1082 | if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { | ||
1083 | printk(KERN_DEBUG "Could not get RID for component %s\n", txt); | ||
1084 | return -1; | ||
1085 | } | ||
1086 | |||
1087 | printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, | ||
1088 | __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), | ||
1089 | __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | |||
1094 | static int prism2_setup_rids(struct net_device *dev) | ||
1095 | { | ||
1096 | struct hostap_interface *iface; | ||
1097 | local_info_t *local; | ||
1098 | u16 tmp; | ||
1099 | int ret = 0; | ||
1100 | |||
1101 | iface = netdev_priv(dev); | ||
1102 | local = iface->local; | ||
1103 | |||
1104 | hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); | ||
1105 | |||
1106 | if (!local->fw_ap) { | ||
1107 | tmp = hostap_get_porttype(local); | ||
1108 | ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); | ||
1109 | if (ret) { | ||
1110 | printk("%s: Port type setting to %d failed\n", | ||
1111 | dev->name, tmp); | ||
1112 | goto fail; | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | /* Setting SSID to empty string seems to kill the card in Host AP mode | ||
1117 | */ | ||
1118 | if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { | ||
1119 | ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, | ||
1120 | local->essid); | ||
1121 | if (ret) { | ||
1122 | printk("%s: AP own SSID setting failed\n", dev->name); | ||
1123 | goto fail; | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, | ||
1128 | PRISM2_DATA_MAXLEN); | ||
1129 | if (ret) { | ||
1130 | printk("%s: MAC data length setting to %d failed\n", | ||
1131 | dev->name, PRISM2_DATA_MAXLEN); | ||
1132 | goto fail; | ||
1133 | } | ||
1134 | |||
1135 | if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { | ||
1136 | printk("%s: Channel list read failed\n", dev->name); | ||
1137 | ret = -EINVAL; | ||
1138 | goto fail; | ||
1139 | } | ||
1140 | local->channel_mask = __le16_to_cpu(tmp); | ||
1141 | |||
1142 | if (local->channel < 1 || local->channel > 14 || | ||
1143 | !(local->channel_mask & (1 << (local->channel - 1)))) { | ||
1144 | printk(KERN_WARNING "%s: Channel setting out of range " | ||
1145 | "(%d)!\n", dev->name, local->channel); | ||
1146 | ret = -EBUSY; | ||
1147 | goto fail; | ||
1148 | } | ||
1149 | |||
1150 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); | ||
1151 | if (ret) { | ||
1152 | printk("%s: Channel setting to %d failed\n", | ||
1153 | dev->name, local->channel); | ||
1154 | goto fail; | ||
1155 | } | ||
1156 | |||
1157 | ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, | ||
1158 | local->beacon_int); | ||
1159 | if (ret) { | ||
1160 | printk("%s: Beacon interval setting to %d failed\n", | ||
1161 | dev->name, local->beacon_int); | ||
1162 | /* this may fail with Symbol/Lucent firmware */ | ||
1163 | if (ret == -ETIMEDOUT) | ||
1164 | goto fail; | ||
1165 | } | ||
1166 | |||
1167 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, | ||
1168 | local->dtim_period); | ||
1169 | if (ret) { | ||
1170 | printk("%s: DTIM period setting to %d failed\n", | ||
1171 | dev->name, local->dtim_period); | ||
1172 | /* this may fail with Symbol/Lucent firmware */ | ||
1173 | if (ret == -ETIMEDOUT) | ||
1174 | goto fail; | ||
1175 | } | ||
1176 | |||
1177 | ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
1178 | local->is_promisc); | ||
1179 | if (ret) | ||
1180 | printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", | ||
1181 | dev->name, local->is_promisc); | ||
1182 | |||
1183 | if (!local->fw_ap) { | ||
1184 | ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, | ||
1185 | local->essid); | ||
1186 | if (ret) { | ||
1187 | printk("%s: Desired SSID setting failed\n", dev->name); | ||
1188 | goto fail; | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and | ||
1193 | * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic | ||
1194 | * rates */ | ||
1195 | if (local->tx_rate_control == 0) { | ||
1196 | local->tx_rate_control = | ||
1197 | HFA384X_RATES_1MBPS | | ||
1198 | HFA384X_RATES_2MBPS | | ||
1199 | HFA384X_RATES_5MBPS | | ||
1200 | HFA384X_RATES_11MBPS; | ||
1201 | } | ||
1202 | if (local->basic_rates == 0) | ||
1203 | local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; | ||
1204 | |||
1205 | if (!local->fw_ap) { | ||
1206 | ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
1207 | local->tx_rate_control); | ||
1208 | if (ret) { | ||
1209 | printk("%s: TXRateControl setting to %d failed\n", | ||
1210 | dev->name, local->tx_rate_control); | ||
1211 | goto fail; | ||
1212 | } | ||
1213 | |||
1214 | ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
1215 | local->tx_rate_control); | ||
1216 | if (ret) { | ||
1217 | printk("%s: cnfSupportedRates setting to %d failed\n", | ||
1218 | dev->name, local->tx_rate_control); | ||
1219 | } | ||
1220 | |||
1221 | ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
1222 | local->basic_rates); | ||
1223 | if (ret) { | ||
1224 | printk("%s: cnfBasicRates setting to %d failed\n", | ||
1225 | dev->name, local->basic_rates); | ||
1226 | } | ||
1227 | |||
1228 | ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); | ||
1229 | if (ret) { | ||
1230 | printk("%s: Create IBSS setting to 1 failed\n", | ||
1231 | dev->name); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | if (local->name_set) | ||
1236 | (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, | ||
1237 | local->name); | ||
1238 | |||
1239 | if (hostap_set_encryption(local)) { | ||
1240 | printk(KERN_INFO "%s: could not configure encryption\n", | ||
1241 | dev->name); | ||
1242 | } | ||
1243 | |||
1244 | (void) hostap_set_antsel(local); | ||
1245 | |||
1246 | if (hostap_set_roaming(local)) { | ||
1247 | printk(KERN_INFO "%s: could not set host roaming\n", | ||
1248 | dev->name); | ||
1249 | } | ||
1250 | |||
1251 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && | ||
1252 | hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) | ||
1253 | printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", | ||
1254 | dev->name, local->enh_sec); | ||
1255 | |||
1256 | /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently | ||
1257 | * not working correctly (last seven counters report bogus values). | ||
1258 | * This has been fixed in 0.8.2, so enable 32-bit tallies only | ||
1259 | * beginning with that firmware version. Another bug fix for 32-bit | ||
1260 | * tallies in 1.4.0; should 16-bit tallies be used for some other | ||
1261 | * versions, too? */ | ||
1262 | if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { | ||
1263 | if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { | ||
1264 | printk(KERN_INFO "%s: cnfThirty2Tally setting " | ||
1265 | "failed\n", dev->name); | ||
1266 | local->tallies32 = 0; | ||
1267 | } else | ||
1268 | local->tallies32 = 1; | ||
1269 | } else | ||
1270 | local->tallies32 = 0; | ||
1271 | |||
1272 | hostap_set_auth_algs(local); | ||
1273 | |||
1274 | if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1275 | local->fragm_threshold)) { | ||
1276 | printk(KERN_INFO "%s: setting FragmentationThreshold to %d " | ||
1277 | "failed\n", dev->name, local->fragm_threshold); | ||
1278 | } | ||
1279 | |||
1280 | if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, | ||
1281 | local->rts_threshold)) { | ||
1282 | printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", | ||
1283 | dev->name, local->rts_threshold); | ||
1284 | } | ||
1285 | |||
1286 | if (local->manual_retry_count >= 0 && | ||
1287 | hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1288 | local->manual_retry_count)) { | ||
1289 | printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", | ||
1290 | dev->name, local->manual_retry_count); | ||
1291 | } | ||
1292 | |||
1293 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && | ||
1294 | hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { | ||
1295 | local->rssi_to_dBm = le16_to_cpu(tmp); | ||
1296 | } | ||
1297 | |||
1298 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && | ||
1299 | hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { | ||
1300 | printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", | ||
1301 | dev->name); | ||
1302 | } | ||
1303 | |||
1304 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && | ||
1305 | hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, | ||
1306 | local->generic_elem, local->generic_elem_len)) { | ||
1307 | printk(KERN_INFO "%s: setting genericElement failed\n", | ||
1308 | dev->name); | ||
1309 | } | ||
1310 | |||
1311 | fail: | ||
1312 | return ret; | ||
1313 | } | ||
1314 | |||
1315 | |||
1316 | static int prism2_hw_init(struct net_device *dev, int initial) | ||
1317 | { | ||
1318 | struct hostap_interface *iface; | ||
1319 | local_info_t *local; | ||
1320 | int ret, first = 1; | ||
1321 | unsigned long start, delay; | ||
1322 | |||
1323 | PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); | ||
1324 | |||
1325 | iface = netdev_priv(dev); | ||
1326 | local = iface->local; | ||
1327 | |||
1328 | clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); | ||
1329 | |||
1330 | init: | ||
1331 | /* initialize HFA 384x */ | ||
1332 | ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); | ||
1333 | if (ret) { | ||
1334 | printk(KERN_INFO "%s: first command failed - assuming card " | ||
1335 | "does not have primary firmware\n", dev_info); | ||
1336 | } | ||
1337 | |||
1338 | if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1339 | /* EvStat has Cmd bit set in some cases, so retry once if no | ||
1340 | * wait was needed */ | ||
1341 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1342 | printk(KERN_DEBUG "%s: init command completed too quickly - " | ||
1343 | "retrying\n", dev->name); | ||
1344 | first = 0; | ||
1345 | goto init; | ||
1346 | } | ||
1347 | |||
1348 | start = jiffies; | ||
1349 | delay = jiffies + HFA384X_INIT_TIMEOUT; | ||
1350 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
1351 | time_before(jiffies, delay)) | ||
1352 | yield(); | ||
1353 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1354 | printk(KERN_DEBUG "%s: assuming no Primary image in " | ||
1355 | "flash - card initialization not completed\n", | ||
1356 | dev_info); | ||
1357 | local->no_pri = 1; | ||
1358 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1359 | if (local->sram_type == -1) | ||
1360 | local->sram_type = prism2_get_ram_size(local); | ||
1361 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1362 | return 1; | ||
1363 | } | ||
1364 | local->no_pri = 0; | ||
1365 | printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", | ||
1366 | (jiffies - start) * 1000 / HZ); | ||
1367 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1368 | return 0; | ||
1369 | } | ||
1370 | |||
1371 | |||
1372 | static int prism2_hw_init2(struct net_device *dev, int initial) | ||
1373 | { | ||
1374 | struct hostap_interface *iface; | ||
1375 | local_info_t *local; | ||
1376 | int i; | ||
1377 | |||
1378 | iface = netdev_priv(dev); | ||
1379 | local = iface->local; | ||
1380 | |||
1381 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1382 | kfree(local->pda); | ||
1383 | if (local->no_pri) | ||
1384 | local->pda = NULL; | ||
1385 | else | ||
1386 | local->pda = prism2_read_pda(dev); | ||
1387 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1388 | |||
1389 | hfa384x_disable_interrupts(dev); | ||
1390 | |||
1391 | #ifndef final_version | ||
1392 | HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); | ||
1393 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
1394 | printk("SWSUPPORT0 write/read failed: %04X != %04X\n", | ||
1395 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); | ||
1396 | goto failed; | ||
1397 | } | ||
1398 | #endif | ||
1399 | |||
1400 | if (initial || local->pri_only) { | ||
1401 | hfa384x_events_only_cmd(dev); | ||
1402 | /* get card version information */ | ||
1403 | if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || | ||
1404 | prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { | ||
1405 | hfa384x_disable_interrupts(dev); | ||
1406 | goto failed; | ||
1407 | } | ||
1408 | |||
1409 | if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { | ||
1410 | printk(KERN_DEBUG "%s: Failed to read STA f/w version " | ||
1411 | "- only Primary f/w present\n", dev->name); | ||
1412 | local->pri_only = 1; | ||
1413 | return 0; | ||
1414 | } | ||
1415 | local->pri_only = 0; | ||
1416 | hfa384x_disable_interrupts(dev); | ||
1417 | } | ||
1418 | |||
1419 | /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and | ||
1420 | * enable interrupts before this. This would also require some sort of | ||
1421 | * sleeping AllocEv waiting */ | ||
1422 | |||
1423 | /* allocate TX FIDs */ | ||
1424 | local->txfid_len = PRISM2_TXFID_LEN; | ||
1425 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) { | ||
1426 | local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); | ||
1427 | if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { | ||
1428 | local->txfid[i] = hfa384x_allocate_fid(dev, 1600); | ||
1429 | if (local->txfid[i] != 0xffff) { | ||
1430 | printk(KERN_DEBUG "%s: Using shorter TX FID " | ||
1431 | "(1600 bytes)\n", dev->name); | ||
1432 | local->txfid_len = 1600; | ||
1433 | } | ||
1434 | } | ||
1435 | if (local->txfid[i] == 0xffff) | ||
1436 | goto failed; | ||
1437 | local->intransmitfid[i] = PRISM2_TXFID_EMPTY; | ||
1438 | } | ||
1439 | |||
1440 | hfa384x_events_only_cmd(dev); | ||
1441 | |||
1442 | if (initial) { | ||
1443 | struct list_head *ptr; | ||
1444 | prism2_check_sta_fw_version(local); | ||
1445 | |||
1446 | if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, | ||
1447 | &dev->dev_addr, 6, 1) < 0) { | ||
1448 | printk("%s: could not get own MAC address\n", | ||
1449 | dev->name); | ||
1450 | } | ||
1451 | list_for_each(ptr, &local->hostap_interfaces) { | ||
1452 | iface = list_entry(ptr, struct hostap_interface, list); | ||
1453 | memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN); | ||
1454 | } | ||
1455 | } else if (local->fw_ap) | ||
1456 | prism2_check_sta_fw_version(local); | ||
1457 | |||
1458 | prism2_setup_rids(dev); | ||
1459 | |||
1460 | /* MAC is now configured, but port 0 is not yet enabled */ | ||
1461 | return 0; | ||
1462 | |||
1463 | failed: | ||
1464 | if (!local->no_pri) | ||
1465 | printk(KERN_WARNING "%s: Initialization failed\n", dev_info); | ||
1466 | return 1; | ||
1467 | } | ||
1468 | |||
1469 | |||
1470 | static int prism2_hw_enable(struct net_device *dev, int initial) | ||
1471 | { | ||
1472 | struct hostap_interface *iface; | ||
1473 | local_info_t *local; | ||
1474 | int was_resetting; | ||
1475 | |||
1476 | iface = netdev_priv(dev); | ||
1477 | local = iface->local; | ||
1478 | was_resetting = local->hw_resetting; | ||
1479 | |||
1480 | if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { | ||
1481 | printk("%s: MAC port 0 enabling failed\n", dev->name); | ||
1482 | return 1; | ||
1483 | } | ||
1484 | |||
1485 | local->hw_ready = 1; | ||
1486 | local->hw_reset_tries = 0; | ||
1487 | local->hw_resetting = 0; | ||
1488 | hfa384x_enable_interrupts(dev); | ||
1489 | |||
1490 | /* at least D-Link DWL-650 seems to require additional port reset | ||
1491 | * before it starts acting as an AP, so reset port automatically | ||
1492 | * here just in case */ | ||
1493 | if (initial && prism2_reset_port(dev)) { | ||
1494 | printk("%s: MAC port 0 reseting failed\n", dev->name); | ||
1495 | return 1; | ||
1496 | } | ||
1497 | |||
1498 | if (was_resetting && netif_queue_stopped(dev)) { | ||
1499 | /* If hw_reset() was called during pending transmit, netif | ||
1500 | * queue was stopped. Wake it up now since the wlan card has | ||
1501 | * been resetted. */ | ||
1502 | netif_wake_queue(dev); | ||
1503 | } | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | |||
1509 | static int prism2_hw_config(struct net_device *dev, int initial) | ||
1510 | { | ||
1511 | struct hostap_interface *iface; | ||
1512 | local_info_t *local; | ||
1513 | |||
1514 | iface = netdev_priv(dev); | ||
1515 | local = iface->local; | ||
1516 | |||
1517 | if (local->hw_downloading) | ||
1518 | return 1; | ||
1519 | |||
1520 | if (prism2_hw_init(dev, initial)) { | ||
1521 | return local->no_pri ? 0 : 1; | ||
1522 | } | ||
1523 | |||
1524 | if (prism2_hw_init2(dev, initial)) | ||
1525 | return 1; | ||
1526 | |||
1527 | /* Enable firmware if secondary image is loaded and at least one of the | ||
1528 | * netdevices is up. */ | ||
1529 | if (!local->pri_only && | ||
1530 | (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { | ||
1531 | if (!local->dev_enabled) | ||
1532 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
1533 | local->dev_enabled = 1; | ||
1534 | return prism2_hw_enable(dev, initial); | ||
1535 | } | ||
1536 | |||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | |||
1541 | static void prism2_hw_shutdown(struct net_device *dev, int no_disable) | ||
1542 | { | ||
1543 | struct hostap_interface *iface; | ||
1544 | local_info_t *local; | ||
1545 | |||
1546 | iface = netdev_priv(dev); | ||
1547 | local = iface->local; | ||
1548 | |||
1549 | /* Allow only command completion events during disable */ | ||
1550 | hfa384x_events_only_cmd(dev); | ||
1551 | |||
1552 | local->hw_ready = 0; | ||
1553 | if (local->dev_enabled) | ||
1554 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
1555 | local->dev_enabled = 0; | ||
1556 | |||
1557 | if (local->func->card_present && !local->func->card_present(local)) { | ||
1558 | printk(KERN_DEBUG "%s: card already removed or not configured " | ||
1559 | "during shutdown\n", dev->name); | ||
1560 | return; | ||
1561 | } | ||
1562 | |||
1563 | if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && | ||
1564 | hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) | ||
1565 | printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); | ||
1566 | |||
1567 | hfa384x_disable_interrupts(dev); | ||
1568 | |||
1569 | if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) | ||
1570 | hfa384x_events_only_cmd(dev); | ||
1571 | else | ||
1572 | prism2_clear_cmd_queue(local); | ||
1573 | } | ||
1574 | |||
1575 | |||
1576 | static void prism2_hw_reset(struct net_device *dev) | ||
1577 | { | ||
1578 | struct hostap_interface *iface; | ||
1579 | local_info_t *local; | ||
1580 | |||
1581 | #if 0 | ||
1582 | static long last_reset = 0; | ||
1583 | |||
1584 | /* do not reset card more than once per second to avoid ending up in a | ||
1585 | * busy loop reseting the card */ | ||
1586 | if (time_before_eq(jiffies, last_reset + HZ)) | ||
1587 | return; | ||
1588 | last_reset = jiffies; | ||
1589 | #endif | ||
1590 | |||
1591 | iface = netdev_priv(dev); | ||
1592 | local = iface->local; | ||
1593 | |||
1594 | if (in_interrupt()) { | ||
1595 | printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called " | ||
1596 | "in interrupt context\n", dev->name); | ||
1597 | return; | ||
1598 | } | ||
1599 | |||
1600 | if (local->hw_downloading) | ||
1601 | return; | ||
1602 | |||
1603 | if (local->hw_resetting) { | ||
1604 | printk(KERN_WARNING "%s: %s: already resetting card - " | ||
1605 | "ignoring reset request\n", dev_info, dev->name); | ||
1606 | return; | ||
1607 | } | ||
1608 | |||
1609 | local->hw_reset_tries++; | ||
1610 | if (local->hw_reset_tries > 10) { | ||
1611 | printk(KERN_WARNING "%s: too many reset tries, skipping\n", | ||
1612 | dev->name); | ||
1613 | return; | ||
1614 | } | ||
1615 | |||
1616 | printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); | ||
1617 | hfa384x_disable_interrupts(dev); | ||
1618 | local->hw_resetting = 1; | ||
1619 | if (local->func->cor_sreset) { | ||
1620 | /* Host system seems to hang in some cases with high traffic | ||
1621 | * load or shared interrupts during COR sreset. Disable shared | ||
1622 | * interrupts during reset to avoid these crashes. COS sreset | ||
1623 | * takes quite a long time, so it is unfortunate that this | ||
1624 | * seems to be needed. Anyway, I do not know of any better way | ||
1625 | * of avoiding the crash. */ | ||
1626 | disable_irq(dev->irq); | ||
1627 | local->func->cor_sreset(local); | ||
1628 | enable_irq(dev->irq); | ||
1629 | } | ||
1630 | prism2_hw_shutdown(dev, 1); | ||
1631 | prism2_hw_config(dev, 0); | ||
1632 | local->hw_resetting = 0; | ||
1633 | |||
1634 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1635 | if (local->dl_pri) { | ||
1636 | printk(KERN_DEBUG "%s: persistent download of primary " | ||
1637 | "firmware\n", dev->name); | ||
1638 | if (prism2_download_genesis(local, local->dl_pri) < 0) | ||
1639 | printk(KERN_WARNING "%s: download (PRI) failed\n", | ||
1640 | dev->name); | ||
1641 | } | ||
1642 | |||
1643 | if (local->dl_sec) { | ||
1644 | printk(KERN_DEBUG "%s: persistent download of secondary " | ||
1645 | "firmware\n", dev->name); | ||
1646 | if (prism2_download_volatile(local, local->dl_sec) < 0) | ||
1647 | printk(KERN_WARNING "%s: download (SEC) failed\n", | ||
1648 | dev->name); | ||
1649 | } | ||
1650 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1651 | |||
1652 | /* TODO: restore beacon TIM bits for STAs that have buffered frames */ | ||
1653 | } | ||
1654 | |||
1655 | |||
1656 | static void prism2_schedule_reset(local_info_t *local) | ||
1657 | { | ||
1658 | schedule_work(&local->reset_queue); | ||
1659 | } | ||
1660 | |||
1661 | |||
1662 | /* Called only as scheduled task after noticing card timeout in interrupt | ||
1663 | * context */ | ||
1664 | static void handle_reset_queue(void *data) | ||
1665 | { | ||
1666 | local_info_t *local = (local_info_t *) data; | ||
1667 | |||
1668 | printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); | ||
1669 | prism2_hw_reset(local->dev); | ||
1670 | |||
1671 | if (netif_queue_stopped(local->dev)) { | ||
1672 | int i; | ||
1673 | |||
1674 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) | ||
1675 | if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { | ||
1676 | PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " | ||
1677 | "wake up queue\n"); | ||
1678 | netif_wake_queue(local->dev); | ||
1679 | break; | ||
1680 | } | ||
1681 | } | ||
1682 | } | ||
1683 | |||
1684 | |||
1685 | static int prism2_get_txfid_idx(local_info_t *local) | ||
1686 | { | ||
1687 | int idx, end; | ||
1688 | unsigned long flags; | ||
1689 | |||
1690 | spin_lock_irqsave(&local->txfidlock, flags); | ||
1691 | end = idx = local->next_txfid; | ||
1692 | do { | ||
1693 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1694 | local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; | ||
1695 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1696 | return idx; | ||
1697 | } | ||
1698 | idx++; | ||
1699 | if (idx >= PRISM2_TXFID_COUNT) | ||
1700 | idx = 0; | ||
1701 | } while (idx != end); | ||
1702 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1703 | |||
1704 | PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " | ||
1705 | "packet dropped\n"); | ||
1706 | local->stats.tx_dropped++; | ||
1707 | |||
1708 | return -1; | ||
1709 | } | ||
1710 | |||
1711 | |||
1712 | /* Called only from hardware IRQ */ | ||
1713 | static void prism2_transmit_cb(struct net_device *dev, void *context, | ||
1714 | u16 resp0, u16 res) | ||
1715 | { | ||
1716 | struct hostap_interface *iface; | ||
1717 | local_info_t *local; | ||
1718 | int idx = (int) context; | ||
1719 | |||
1720 | iface = netdev_priv(dev); | ||
1721 | local = iface->local; | ||
1722 | |||
1723 | if (res) { | ||
1724 | printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", | ||
1725 | dev->name, res); | ||
1726 | return; | ||
1727 | } | ||
1728 | |||
1729 | if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { | ||
1730 | printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " | ||
1731 | "idx=%d\n", dev->name, idx); | ||
1732 | return; | ||
1733 | } | ||
1734 | |||
1735 | if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1736 | printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " | ||
1737 | "with no pending transmit\n", dev->name); | ||
1738 | } | ||
1739 | |||
1740 | if (netif_queue_stopped(dev)) { | ||
1741 | /* ready for next TX, so wake up queue that was stopped in | ||
1742 | * prism2_transmit() */ | ||
1743 | netif_wake_queue(dev); | ||
1744 | } | ||
1745 | |||
1746 | spin_lock(&local->txfidlock); | ||
1747 | |||
1748 | /* With reclaim, Resp0 contains new txfid for transmit; the old txfid | ||
1749 | * will be automatically allocated for the next TX frame */ | ||
1750 | local->intransmitfid[idx] = resp0; | ||
1751 | |||
1752 | PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " | ||
1753 | "resp0=0x%04x, transmit_txfid=0x%04x\n", | ||
1754 | dev->name, idx, local->txfid[idx], | ||
1755 | resp0, local->intransmitfid[local->next_txfid]); | ||
1756 | |||
1757 | idx++; | ||
1758 | if (idx >= PRISM2_TXFID_COUNT) | ||
1759 | idx = 0; | ||
1760 | local->next_txfid = idx; | ||
1761 | |||
1762 | /* check if all TX buffers are occupied */ | ||
1763 | do { | ||
1764 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1765 | spin_unlock(&local->txfidlock); | ||
1766 | return; | ||
1767 | } | ||
1768 | idx++; | ||
1769 | if (idx >= PRISM2_TXFID_COUNT) | ||
1770 | idx = 0; | ||
1771 | } while (idx != local->next_txfid); | ||
1772 | spin_unlock(&local->txfidlock); | ||
1773 | |||
1774 | /* no empty TX buffers, stop queue */ | ||
1775 | netif_stop_queue(dev); | ||
1776 | } | ||
1777 | |||
1778 | |||
1779 | /* Called only from software IRQ if PCI bus master is not used (with bus master | ||
1780 | * this can be called both from software and hardware IRQ) */ | ||
1781 | static int prism2_transmit(struct net_device *dev, int idx) | ||
1782 | { | ||
1783 | struct hostap_interface *iface; | ||
1784 | local_info_t *local; | ||
1785 | int res; | ||
1786 | |||
1787 | iface = netdev_priv(dev); | ||
1788 | local = iface->local; | ||
1789 | |||
1790 | /* The driver tries to stop netif queue so that there would not be | ||
1791 | * more than one attempt to transmit frames going on; check that this | ||
1792 | * is really the case */ | ||
1793 | |||
1794 | if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1795 | printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " | ||
1796 | "when previous TX was pending\n", dev->name); | ||
1797 | return -1; | ||
1798 | } | ||
1799 | |||
1800 | /* stop the queue for the time that transmit is pending */ | ||
1801 | netif_stop_queue(dev); | ||
1802 | |||
1803 | /* transmit packet */ | ||
1804 | res = hfa384x_cmd_callback( | ||
1805 | dev, | ||
1806 | HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, | ||
1807 | local->txfid[idx], | ||
1808 | prism2_transmit_cb, (void *) idx); | ||
1809 | |||
1810 | if (res) { | ||
1811 | struct net_device_stats *stats; | ||
1812 | printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " | ||
1813 | "failed (res=%d)\n", dev->name, res); | ||
1814 | stats = hostap_get_stats(dev); | ||
1815 | stats->tx_dropped++; | ||
1816 | netif_wake_queue(dev); | ||
1817 | return -1; | ||
1818 | } | ||
1819 | dev->trans_start = jiffies; | ||
1820 | |||
1821 | /* Since we did not wait for command completion, the card continues | ||
1822 | * to process on the background and we will finish handling when | ||
1823 | * command completion event is handled (prism2_cmd_ev() function) */ | ||
1824 | |||
1825 | return 0; | ||
1826 | } | ||
1827 | |||
1828 | |||
1829 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
1830 | /* Called only from hardware IRQ */ | ||
1831 | static void prism2_tx_cb(struct net_device *dev, void *context, | ||
1832 | u16 resp0, u16 res) | ||
1833 | { | ||
1834 | struct hostap_interface *iface; | ||
1835 | local_info_t *local; | ||
1836 | unsigned long addr; | ||
1837 | int buf_len = (int) context; | ||
1838 | |||
1839 | iface = netdev_priv(dev); | ||
1840 | local = iface->local; | ||
1841 | |||
1842 | if (res) { | ||
1843 | printk(KERN_DEBUG "%s: prism2_tx_cb - res=0x%02x\n", | ||
1844 | dev->name, res); | ||
1845 | return; | ||
1846 | } | ||
1847 | |||
1848 | addr = virt_to_phys(local->bus_m0_buf); | ||
1849 | HFA384X_OUTW((addr & 0xffff0000) >> 16, HFA384X_PCI_M0_ADDRH_OFF); | ||
1850 | HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF); | ||
1851 | HFA384X_OUTW(buf_len / 2, HFA384X_PCI_M0_LEN_OFF); | ||
1852 | HFA384X_OUTW(HFA384X_PCI_CTL_TO_BAP, HFA384X_PCI_M0_CTL_OFF); | ||
1853 | } | ||
1854 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
1855 | |||
1856 | |||
1857 | /* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and | ||
1858 | * send the payload with this descriptor) */ | ||
1859 | /* Called only from software IRQ */ | ||
1860 | static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) | ||
1861 | { | ||
1862 | struct hostap_interface *iface; | ||
1863 | local_info_t *local; | ||
1864 | struct hfa384x_tx_frame txdesc; | ||
1865 | struct hostap_ieee80211_hdr *hdr; | ||
1866 | struct hostap_skb_tx_data *meta; | ||
1867 | int hdr_len, data_len, idx, res, ret = -1; | ||
1868 | u16 tx_control, fc; | ||
1869 | |||
1870 | iface = netdev_priv(dev); | ||
1871 | local = iface->local; | ||
1872 | |||
1873 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1874 | hdr = (struct hostap_ieee80211_hdr *) skb->data; | ||
1875 | |||
1876 | prism2_callback(local, PRISM2_CALLBACK_TX_START); | ||
1877 | |||
1878 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
1879 | !local->hw_ready || local->hw_downloading || local->pri_only) { | ||
1880 | if (net_ratelimit()) { | ||
1881 | printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" | ||
1882 | " skipping\n", dev->name); | ||
1883 | } | ||
1884 | goto fail; | ||
1885 | } | ||
1886 | |||
1887 | memset(&txdesc, 0, sizeof(txdesc)); | ||
1888 | |||
1889 | /* skb->data starts with txdesc->frame_control */ | ||
1890 | hdr_len = 24; | ||
1891 | memcpy(&txdesc.frame_control, skb->data, hdr_len); | ||
1892 | fc = le16_to_cpu(txdesc.frame_control); | ||
1893 | if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && | ||
1894 | (fc & WLAN_FC_FROMDS) && (fc & WLAN_FC_TODS) && skb->len >= 30) { | ||
1895 | /* Addr4 */ | ||
1896 | memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); | ||
1897 | hdr_len += ETH_ALEN; | ||
1898 | } | ||
1899 | |||
1900 | tx_control = local->tx_control; | ||
1901 | if (meta->tx_cb_idx) { | ||
1902 | tx_control |= HFA384X_TX_CTRL_TX_OK; | ||
1903 | txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx); | ||
1904 | } | ||
1905 | txdesc.tx_control = cpu_to_le16(tx_control); | ||
1906 | txdesc.tx_rate = meta->rate; | ||
1907 | |||
1908 | data_len = skb->len - hdr_len; | ||
1909 | txdesc.data_len = cpu_to_le16(data_len); | ||
1910 | txdesc.len = cpu_to_be16(data_len); | ||
1911 | |||
1912 | idx = prism2_get_txfid_idx(local); | ||
1913 | if (idx < 0) | ||
1914 | goto fail; | ||
1915 | |||
1916 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) | ||
1917 | hostap_dump_tx_header(dev->name, &txdesc); | ||
1918 | |||
1919 | spin_lock(&local->baplock); | ||
1920 | res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); | ||
1921 | |||
1922 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
1923 | if (!res && skb->len >= local->bus_master_threshold_tx) { | ||
1924 | u8 *pos; | ||
1925 | int buf_len; | ||
1926 | |||
1927 | local->bus_m0_tx_idx = idx; | ||
1928 | |||
1929 | /* FIX: BAP0 should be locked during bus master transfer, but | ||
1930 | * baplock with BH's disabled is not OK for this; netif queue | ||
1931 | * stopping is not enough since BAP0 is used also for RID | ||
1932 | * read/write */ | ||
1933 | |||
1934 | /* stop the queue for the time that bus mastering on BAP0 is | ||
1935 | * in use */ | ||
1936 | netif_stop_queue(dev); | ||
1937 | |||
1938 | spin_unlock(&local->baplock); | ||
1939 | |||
1940 | /* Copy frame data to bus_m0_buf */ | ||
1941 | pos = local->bus_m0_buf; | ||
1942 | memcpy(pos, &txdesc, sizeof(txdesc)); | ||
1943 | pos += sizeof(txdesc); | ||
1944 | memcpy(pos, skb->data + hdr_len, skb->len - hdr_len); | ||
1945 | pos += skb->len - hdr_len; | ||
1946 | buf_len = pos - local->bus_m0_buf; | ||
1947 | if (buf_len & 1) | ||
1948 | buf_len++; | ||
1949 | |||
1950 | #ifdef PRISM2_ENABLE_BEFORE_TX_BUS_MASTER | ||
1951 | /* Any RX packet seems to break something with TX bus | ||
1952 | * mastering; enable command is enough to fix this.. */ | ||
1953 | if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_ENABLE, 0, | ||
1954 | prism2_tx_cb, (void *) buf_len)) { | ||
1955 | printk(KERN_DEBUG "%s: TX: enable port0 failed\n", | ||
1956 | dev->name); | ||
1957 | } | ||
1958 | #else /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */ | ||
1959 | prism2_tx_cb(dev, (void *) buf_len, 0, 0); | ||
1960 | #endif /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */ | ||
1961 | |||
1962 | /* Bus master transfer will be started from command completion | ||
1963 | * event handler and TX handling will be finished by calling | ||
1964 | * prism2_transmit() from bus master event handler */ | ||
1965 | goto tx_stats; | ||
1966 | } | ||
1967 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
1968 | |||
1969 | if (!res) | ||
1970 | res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); | ||
1971 | if (!res) | ||
1972 | res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, | ||
1973 | skb->len - hdr_len); | ||
1974 | spin_unlock(&local->baplock); | ||
1975 | |||
1976 | if (!res) | ||
1977 | res = prism2_transmit(dev, idx); | ||
1978 | if (res) { | ||
1979 | printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", | ||
1980 | dev->name); | ||
1981 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
1982 | schedule_work(&local->reset_queue); | ||
1983 | goto fail; | ||
1984 | } | ||
1985 | |||
1986 | ret = 0; | ||
1987 | |||
1988 | fail: | ||
1989 | prism2_callback(local, PRISM2_CALLBACK_TX_END); | ||
1990 | return ret; | ||
1991 | } | ||
1992 | |||
1993 | |||
1994 | /* Some SMP systems have reported number of odd errors with hostap_pci. fid | ||
1995 | * register has changed values between consecutive reads for an unknown reason. | ||
1996 | * This should really not happen, so more debugging is needed. This test | ||
1997 | * version is a big slower, but it will detect most of such register changes | ||
1998 | * and will try to get the correct fid eventually. */ | ||
1999 | #define EXTRA_FID_READ_TESTS | ||
2000 | |||
2001 | static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) | ||
2002 | { | ||
2003 | #ifdef EXTRA_FID_READ_TESTS | ||
2004 | u16 val, val2, val3; | ||
2005 | int i; | ||
2006 | |||
2007 | for (i = 0; i < 10; i++) { | ||
2008 | val = HFA384X_INW(reg); | ||
2009 | val2 = HFA384X_INW(reg); | ||
2010 | val3 = HFA384X_INW(reg); | ||
2011 | |||
2012 | if (val == val2 && val == val3) | ||
2013 | return val; | ||
2014 | |||
2015 | printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" | ||
2016 | " %04x %04x %04x\n", | ||
2017 | dev->name, i, reg, val, val2, val3); | ||
2018 | if ((val == val2 || val == val3) && val != 0) | ||
2019 | return val; | ||
2020 | if (val2 == val3 && val2 != 0) | ||
2021 | return val2; | ||
2022 | } | ||
2023 | printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " | ||
2024 | "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); | ||
2025 | return val; | ||
2026 | #else /* EXTRA_FID_READ_TESTS */ | ||
2027 | return HFA384X_INW(reg); | ||
2028 | #endif /* EXTRA_FID_READ_TESTS */ | ||
2029 | } | ||
2030 | |||
2031 | |||
2032 | /* Called only as a tasklet (software IRQ) */ | ||
2033 | static void prism2_rx(local_info_t *local) | ||
2034 | { | ||
2035 | struct net_device *dev = local->dev; | ||
2036 | int res, rx_pending = 0; | ||
2037 | u16 len, hdr_len, rxfid, status, macport; | ||
2038 | struct net_device_stats *stats; | ||
2039 | struct hfa384x_rx_frame rxdesc; | ||
2040 | struct sk_buff *skb = NULL; | ||
2041 | |||
2042 | prism2_callback(local, PRISM2_CALLBACK_RX_START); | ||
2043 | stats = hostap_get_stats(dev); | ||
2044 | |||
2045 | rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); | ||
2046 | #ifndef final_version | ||
2047 | if (rxfid == 0) { | ||
2048 | rxfid = HFA384X_INW(HFA384X_RXFID_OFF); | ||
2049 | printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", | ||
2050 | rxfid); | ||
2051 | if (rxfid == 0) { | ||
2052 | schedule_work(&local->reset_queue); | ||
2053 | goto rx_dropped; | ||
2054 | } | ||
2055 | /* try to continue with the new rxfid value */ | ||
2056 | } | ||
2057 | #endif | ||
2058 | |||
2059 | spin_lock(&local->baplock); | ||
2060 | res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); | ||
2061 | if (!res) | ||
2062 | res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); | ||
2063 | |||
2064 | if (res) { | ||
2065 | spin_unlock(&local->baplock); | ||
2066 | printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, | ||
2067 | res); | ||
2068 | if (res == -ETIMEDOUT) { | ||
2069 | schedule_work(&local->reset_queue); | ||
2070 | } | ||
2071 | goto rx_dropped; | ||
2072 | } | ||
2073 | |||
2074 | len = le16_to_cpu(rxdesc.data_len); | ||
2075 | hdr_len = sizeof(rxdesc); | ||
2076 | status = le16_to_cpu(rxdesc.status); | ||
2077 | macport = (status >> 8) & 0x07; | ||
2078 | |||
2079 | /* Drop frames with too large reported payload length. Monitor mode | ||
2080 | * seems to sometimes pass frames (e.g., ctrl::ack) with signed and | ||
2081 | * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for | ||
2082 | * macport 7 */ | ||
2083 | if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { | ||
2084 | if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { | ||
2085 | if (len >= (u16) -14) { | ||
2086 | hdr_len -= 65535 - len; | ||
2087 | hdr_len--; | ||
2088 | } | ||
2089 | len = 0; | ||
2090 | } else { | ||
2091 | spin_unlock(&local->baplock); | ||
2092 | printk(KERN_DEBUG "%s: Received frame with invalid " | ||
2093 | "length 0x%04x\n", dev->name, len); | ||
2094 | hostap_dump_rx_header(dev->name, &rxdesc); | ||
2095 | goto rx_dropped; | ||
2096 | } | ||
2097 | } | ||
2098 | |||
2099 | skb = dev_alloc_skb(len + hdr_len); | ||
2100 | if (!skb) { | ||
2101 | spin_unlock(&local->baplock); | ||
2102 | printk(KERN_DEBUG "%s: RX failed to allocate skb\n", | ||
2103 | dev->name); | ||
2104 | goto rx_dropped; | ||
2105 | } | ||
2106 | skb->dev = dev; | ||
2107 | memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); | ||
2108 | |||
2109 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
2110 | if (len >= local->bus_master_threshold_rx) { | ||
2111 | unsigned long addr; | ||
2112 | |||
2113 | hfa384x_events_no_bap1(dev); | ||
2114 | |||
2115 | local->rx_skb = skb; | ||
2116 | /* Internal BAP0 offset points to the byte following rxdesc; | ||
2117 | * copy rest of the data using bus master */ | ||
2118 | addr = virt_to_phys(skb_put(skb, len)); | ||
2119 | HFA384X_OUTW((addr & 0xffff0000) >> 16, | ||
2120 | HFA384X_PCI_M0_ADDRH_OFF); | ||
2121 | HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF); | ||
2122 | if (len & 1) | ||
2123 | len++; | ||
2124 | HFA384X_OUTW(len / 2, HFA384X_PCI_M0_LEN_OFF); | ||
2125 | HFA384X_OUTW(HFA384X_PCI_CTL_FROM_BAP, HFA384X_PCI_M0_CTL_OFF); | ||
2126 | |||
2127 | /* pci_bus_m1 event will be generated when data transfer is | ||
2128 | * complete and the frame will then be added to rx_list and | ||
2129 | * rx_tasklet is scheduled */ | ||
2130 | rx_pending = 1; | ||
2131 | |||
2132 | /* Have to release baplock before returning, although BAP0 | ||
2133 | * should really not be used before DMA transfer has been | ||
2134 | * completed. */ | ||
2135 | spin_unlock(&local->baplock); | ||
2136 | } else | ||
2137 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
2138 | { | ||
2139 | if (len > 0) | ||
2140 | res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), | ||
2141 | len); | ||
2142 | spin_unlock(&local->baplock); | ||
2143 | if (res) { | ||
2144 | printk(KERN_DEBUG "%s: RX failed to read " | ||
2145 | "frame data\n", dev->name); | ||
2146 | goto rx_dropped; | ||
2147 | } | ||
2148 | |||
2149 | skb_queue_tail(&local->rx_list, skb); | ||
2150 | tasklet_schedule(&local->rx_tasklet); | ||
2151 | } | ||
2152 | |||
2153 | rx_exit: | ||
2154 | prism2_callback(local, PRISM2_CALLBACK_RX_END); | ||
2155 | if (!rx_pending) { | ||
2156 | HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); | ||
2157 | } | ||
2158 | |||
2159 | return; | ||
2160 | |||
2161 | rx_dropped: | ||
2162 | stats->rx_dropped++; | ||
2163 | if (skb) | ||
2164 | dev_kfree_skb(skb); | ||
2165 | goto rx_exit; | ||
2166 | } | ||
2167 | |||
2168 | |||
2169 | /* Called only as a tasklet (software IRQ) */ | ||
2170 | static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) | ||
2171 | { | ||
2172 | struct hfa384x_rx_frame *rxdesc; | ||
2173 | struct net_device *dev = skb->dev; | ||
2174 | struct hostap_80211_rx_status stats; | ||
2175 | int hdrlen, rx_hdrlen; | ||
2176 | |||
2177 | rx_hdrlen = sizeof(*rxdesc); | ||
2178 | if (skb->len < sizeof(*rxdesc)) { | ||
2179 | /* Allow monitor mode to receive shorter frames */ | ||
2180 | if (local->iw_mode == IW_MODE_MONITOR && | ||
2181 | skb->len >= sizeof(*rxdesc) - 30) { | ||
2182 | rx_hdrlen = skb->len; | ||
2183 | } else { | ||
2184 | dev_kfree_skb(skb); | ||
2185 | return; | ||
2186 | } | ||
2187 | } | ||
2188 | |||
2189 | rxdesc = (struct hfa384x_rx_frame *) skb->data; | ||
2190 | |||
2191 | if (local->frame_dump & PRISM2_DUMP_RX_HDR && | ||
2192 | skb->len >= sizeof(*rxdesc)) | ||
2193 | hostap_dump_rx_header(dev->name, rxdesc); | ||
2194 | |||
2195 | if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && | ||
2196 | (!local->monitor_allow_fcserr || | ||
2197 | local->iw_mode != IW_MODE_MONITOR)) | ||
2198 | goto drop; | ||
2199 | |||
2200 | if (skb->len > PRISM2_DATA_MAXLEN) { | ||
2201 | printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", | ||
2202 | dev->name, skb->len, PRISM2_DATA_MAXLEN); | ||
2203 | goto drop; | ||
2204 | } | ||
2205 | |||
2206 | stats.mac_time = le32_to_cpu(rxdesc->time); | ||
2207 | stats.signal = rxdesc->signal - local->rssi_to_dBm; | ||
2208 | stats.noise = rxdesc->silence - local->rssi_to_dBm; | ||
2209 | stats.rate = rxdesc->rate; | ||
2210 | |||
2211 | /* Convert Prism2 RX structure into IEEE 802.11 header */ | ||
2212 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control)); | ||
2213 | if (hdrlen > rx_hdrlen) | ||
2214 | hdrlen = rx_hdrlen; | ||
2215 | |||
2216 | memmove(skb_pull(skb, rx_hdrlen - hdrlen), | ||
2217 | &rxdesc->frame_control, hdrlen); | ||
2218 | |||
2219 | hostap_80211_rx(dev, skb, &stats); | ||
2220 | return; | ||
2221 | |||
2222 | drop: | ||
2223 | dev_kfree_skb(skb); | ||
2224 | } | ||
2225 | |||
2226 | |||
2227 | /* Called only as a tasklet (software IRQ) */ | ||
2228 | static void hostap_rx_tasklet(unsigned long data) | ||
2229 | { | ||
2230 | local_info_t *local = (local_info_t *) data; | ||
2231 | struct sk_buff *skb; | ||
2232 | |||
2233 | while ((skb = skb_dequeue(&local->rx_list)) != NULL) | ||
2234 | hostap_rx_skb(local, skb); | ||
2235 | } | ||
2236 | |||
2237 | |||
2238 | /* Called only from hardware IRQ */ | ||
2239 | static void prism2_alloc_ev(struct net_device *dev) | ||
2240 | { | ||
2241 | struct hostap_interface *iface; | ||
2242 | local_info_t *local; | ||
2243 | int idx; | ||
2244 | u16 fid; | ||
2245 | |||
2246 | iface = netdev_priv(dev); | ||
2247 | local = iface->local; | ||
2248 | |||
2249 | fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); | ||
2250 | |||
2251 | PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); | ||
2252 | |||
2253 | spin_lock(&local->txfidlock); | ||
2254 | idx = local->next_alloc; | ||
2255 | |||
2256 | do { | ||
2257 | if (local->txfid[idx] == fid) { | ||
2258 | PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", | ||
2259 | idx); | ||
2260 | |||
2261 | #ifndef final_version | ||
2262 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) | ||
2263 | printk("Already released txfid found at idx " | ||
2264 | "%d\n", idx); | ||
2265 | if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) | ||
2266 | printk("Already reserved txfid found at idx " | ||
2267 | "%d\n", idx); | ||
2268 | #endif | ||
2269 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
2270 | idx++; | ||
2271 | local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : | ||
2272 | idx; | ||
2273 | |||
2274 | if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && | ||
2275 | netif_queue_stopped(dev)) | ||
2276 | netif_wake_queue(dev); | ||
2277 | |||
2278 | spin_unlock(&local->txfidlock); | ||
2279 | return; | ||
2280 | } | ||
2281 | |||
2282 | idx++; | ||
2283 | if (idx >= PRISM2_TXFID_COUNT) | ||
2284 | idx = 0; | ||
2285 | } while (idx != local->next_alloc); | ||
2286 | |||
2287 | printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " | ||
2288 | "read 0x%04x) for alloc event\n", dev->name, fid, | ||
2289 | HFA384X_INW(HFA384X_ALLOCFID_OFF)); | ||
2290 | printk(KERN_DEBUG "TXFIDs:"); | ||
2291 | for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) | ||
2292 | printk(" %04x[%04x]", local->txfid[idx], | ||
2293 | local->intransmitfid[idx]); | ||
2294 | printk("\n"); | ||
2295 | spin_unlock(&local->txfidlock); | ||
2296 | |||
2297 | /* FIX: should probably schedule reset; reference to one txfid was lost | ||
2298 | * completely.. Bad things will happen if we run out of txfids | ||
2299 | * Actually, this will cause netdev watchdog to notice TX timeout and | ||
2300 | * then card reset after all txfids have been leaked. */ | ||
2301 | } | ||
2302 | |||
2303 | |||
2304 | /* Called only as a tasklet (software IRQ) */ | ||
2305 | static void hostap_tx_callback(local_info_t *local, | ||
2306 | struct hfa384x_tx_frame *txdesc, int ok, | ||
2307 | char *payload) | ||
2308 | { | ||
2309 | u16 sw_support, hdrlen, len; | ||
2310 | struct sk_buff *skb; | ||
2311 | struct hostap_tx_callback_info *cb; | ||
2312 | |||
2313 | /* Make sure that frame was from us. */ | ||
2314 | if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) { | ||
2315 | printk(KERN_DEBUG "%s: TX callback - foreign frame\n", | ||
2316 | local->dev->name); | ||
2317 | return; | ||
2318 | } | ||
2319 | |||
2320 | sw_support = le16_to_cpu(txdesc->sw_support); | ||
2321 | |||
2322 | spin_lock(&local->lock); | ||
2323 | cb = local->tx_callback; | ||
2324 | while (cb != NULL && cb->idx != sw_support) | ||
2325 | cb = cb->next; | ||
2326 | spin_unlock(&local->lock); | ||
2327 | |||
2328 | if (cb == NULL) { | ||
2329 | printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", | ||
2330 | local->dev->name, sw_support); | ||
2331 | return; | ||
2332 | } | ||
2333 | |||
2334 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control)); | ||
2335 | len = le16_to_cpu(txdesc->data_len); | ||
2336 | skb = dev_alloc_skb(hdrlen + len); | ||
2337 | if (skb == NULL) { | ||
2338 | printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " | ||
2339 | "skb\n", local->dev->name); | ||
2340 | return; | ||
2341 | } | ||
2342 | |||
2343 | memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); | ||
2344 | if (payload) | ||
2345 | memcpy(skb_put(skb, len), payload, len); | ||
2346 | |||
2347 | skb->dev = local->dev; | ||
2348 | skb->mac.raw = skb->data; | ||
2349 | |||
2350 | cb->func(skb, ok, cb->data); | ||
2351 | } | ||
2352 | |||
2353 | |||
2354 | /* Called only as a tasklet (software IRQ) */ | ||
2355 | static int hostap_tx_compl_read(local_info_t *local, int error, | ||
2356 | struct hfa384x_tx_frame *txdesc, | ||
2357 | char **payload) | ||
2358 | { | ||
2359 | u16 fid, len; | ||
2360 | int res, ret = 0; | ||
2361 | struct net_device *dev = local->dev; | ||
2362 | |||
2363 | fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); | ||
2364 | |||
2365 | PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); | ||
2366 | |||
2367 | spin_lock(&local->baplock); | ||
2368 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2369 | if (!res) | ||
2370 | res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); | ||
2371 | if (res) { | ||
2372 | PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " | ||
2373 | "read txdesc\n", dev->name, error, fid); | ||
2374 | if (res == -ETIMEDOUT) { | ||
2375 | schedule_work(&local->reset_queue); | ||
2376 | } | ||
2377 | ret = -1; | ||
2378 | goto fail; | ||
2379 | } | ||
2380 | if (txdesc->sw_support) { | ||
2381 | len = le16_to_cpu(txdesc->data_len); | ||
2382 | if (len < PRISM2_DATA_MAXLEN) { | ||
2383 | *payload = (char *) kmalloc(len, GFP_ATOMIC); | ||
2384 | if (*payload == NULL || | ||
2385 | hfa384x_from_bap(dev, BAP0, *payload, len)) { | ||
2386 | PDEBUG(DEBUG_EXTRA, "%s: could not read TX " | ||
2387 | "frame payload\n", dev->name); | ||
2388 | kfree(*payload); | ||
2389 | *payload = NULL; | ||
2390 | ret = -1; | ||
2391 | goto fail; | ||
2392 | } | ||
2393 | } | ||
2394 | } | ||
2395 | |||
2396 | fail: | ||
2397 | spin_unlock(&local->baplock); | ||
2398 | |||
2399 | return ret; | ||
2400 | } | ||
2401 | |||
2402 | |||
2403 | /* Called only as a tasklet (software IRQ) */ | ||
2404 | static void prism2_tx_ev(local_info_t *local) | ||
2405 | { | ||
2406 | struct net_device *dev = local->dev; | ||
2407 | char *payload = NULL; | ||
2408 | struct hfa384x_tx_frame txdesc; | ||
2409 | |||
2410 | if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) | ||
2411 | goto fail; | ||
2412 | |||
2413 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) { | ||
2414 | PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " | ||
2415 | "retry_count=%d tx_rate=%d seq_ctrl=%d " | ||
2416 | "duration_id=%d\n", | ||
2417 | dev->name, le16_to_cpu(txdesc.status), | ||
2418 | txdesc.retry_count, txdesc.tx_rate, | ||
2419 | le16_to_cpu(txdesc.seq_ctrl), | ||
2420 | le16_to_cpu(txdesc.duration_id)); | ||
2421 | } | ||
2422 | |||
2423 | if (txdesc.sw_support) | ||
2424 | hostap_tx_callback(local, &txdesc, 1, payload); | ||
2425 | kfree(payload); | ||
2426 | |||
2427 | fail: | ||
2428 | HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); | ||
2429 | } | ||
2430 | |||
2431 | |||
2432 | /* Called only as a tasklet (software IRQ) */ | ||
2433 | static void hostap_sta_tx_exc_tasklet(unsigned long data) | ||
2434 | { | ||
2435 | local_info_t *local = (local_info_t *) data; | ||
2436 | struct sk_buff *skb; | ||
2437 | |||
2438 | while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { | ||
2439 | struct hfa384x_tx_frame *txdesc = | ||
2440 | (struct hfa384x_tx_frame *) skb->data; | ||
2441 | |||
2442 | if (skb->len >= sizeof(*txdesc)) { | ||
2443 | /* Convert Prism2 RX structure into IEEE 802.11 header | ||
2444 | */ | ||
2445 | u16 fc = le16_to_cpu(txdesc->frame_control); | ||
2446 | int hdrlen = hostap_80211_get_hdrlen(fc); | ||
2447 | memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), | ||
2448 | &txdesc->frame_control, hdrlen); | ||
2449 | |||
2450 | hostap_handle_sta_tx_exc(local, skb); | ||
2451 | } | ||
2452 | dev_kfree_skb(skb); | ||
2453 | } | ||
2454 | } | ||
2455 | |||
2456 | |||
2457 | /* Called only as a tasklet (software IRQ) */ | ||
2458 | static void prism2_txexc(local_info_t *local) | ||
2459 | { | ||
2460 | struct net_device *dev = local->dev; | ||
2461 | u16 status, fc; | ||
2462 | int show_dump, res; | ||
2463 | char *payload = NULL; | ||
2464 | struct hfa384x_tx_frame txdesc; | ||
2465 | |||
2466 | show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; | ||
2467 | local->stats.tx_errors++; | ||
2468 | |||
2469 | res = hostap_tx_compl_read(local, 1, &txdesc, &payload); | ||
2470 | HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); | ||
2471 | if (res) | ||
2472 | return; | ||
2473 | |||
2474 | status = le16_to_cpu(txdesc.status); | ||
2475 | |||
2476 | /* We produce a TXDROP event only for retry or lifetime | ||
2477 | * exceeded, because that's the only status that really mean | ||
2478 | * that this particular node went away. | ||
2479 | * Other errors means that *we* screwed up. - Jean II */ | ||
2480 | if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) | ||
2481 | { | ||
2482 | union iwreq_data wrqu; | ||
2483 | |||
2484 | /* Copy 802.11 dest address. */ | ||
2485 | memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); | ||
2486 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
2487 | wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); | ||
2488 | } else | ||
2489 | show_dump = 1; | ||
2490 | |||
2491 | if (local->iw_mode == IW_MODE_MASTER || | ||
2492 | local->iw_mode == IW_MODE_REPEAT || | ||
2493 | local->wds_type & HOSTAP_WDS_AP_CLIENT) { | ||
2494 | struct sk_buff *skb; | ||
2495 | skb = dev_alloc_skb(sizeof(txdesc)); | ||
2496 | if (skb) { | ||
2497 | memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, | ||
2498 | sizeof(txdesc)); | ||
2499 | skb_queue_tail(&local->sta_tx_exc_list, skb); | ||
2500 | tasklet_schedule(&local->sta_tx_exc_tasklet); | ||
2501 | } | ||
2502 | } | ||
2503 | |||
2504 | if (txdesc.sw_support) | ||
2505 | hostap_tx_callback(local, &txdesc, 0, payload); | ||
2506 | kfree(payload); | ||
2507 | |||
2508 | if (!show_dump) | ||
2509 | return; | ||
2510 | |||
2511 | PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" | ||
2512 | " tx_control=%04x\n", | ||
2513 | dev->name, status, | ||
2514 | status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", | ||
2515 | status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", | ||
2516 | status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", | ||
2517 | status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", | ||
2518 | le16_to_cpu(txdesc.tx_control)); | ||
2519 | |||
2520 | fc = le16_to_cpu(txdesc.frame_control); | ||
2521 | PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " | ||
2522 | "(%s%s%s::%d%s%s)\n", | ||
2523 | txdesc.retry_count, txdesc.tx_rate, fc, | ||
2524 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT ? "Mgmt" : "", | ||
2525 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_CTRL ? "Ctrl" : "", | ||
2526 | WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ? "Data" : "", | ||
2527 | WLAN_FC_GET_STYPE(fc), | ||
2528 | fc & WLAN_FC_TODS ? " ToDS" : "", | ||
2529 | fc & WLAN_FC_FROMDS ? " FromDS" : ""); | ||
2530 | PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" | ||
2531 | MACSTR " A4=" MACSTR "\n", | ||
2532 | MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), | ||
2533 | MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); | ||
2534 | } | ||
2535 | |||
2536 | |||
2537 | /* Called only as a tasklet (software IRQ) */ | ||
2538 | static void hostap_info_tasklet(unsigned long data) | ||
2539 | { | ||
2540 | local_info_t *local = (local_info_t *) data; | ||
2541 | struct sk_buff *skb; | ||
2542 | |||
2543 | while ((skb = skb_dequeue(&local->info_list)) != NULL) { | ||
2544 | hostap_info_process(local, skb); | ||
2545 | dev_kfree_skb(skb); | ||
2546 | } | ||
2547 | } | ||
2548 | |||
2549 | |||
2550 | /* Called only as a tasklet (software IRQ) */ | ||
2551 | static void prism2_info(local_info_t *local) | ||
2552 | { | ||
2553 | struct net_device *dev = local->dev; | ||
2554 | u16 fid; | ||
2555 | int res, left; | ||
2556 | struct hfa384x_info_frame info; | ||
2557 | struct sk_buff *skb; | ||
2558 | |||
2559 | fid = HFA384X_INW(HFA384X_INFOFID_OFF); | ||
2560 | |||
2561 | spin_lock(&local->baplock); | ||
2562 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2563 | if (!res) | ||
2564 | res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); | ||
2565 | if (res) { | ||
2566 | spin_unlock(&local->baplock); | ||
2567 | printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", | ||
2568 | fid); | ||
2569 | if (res == -ETIMEDOUT) { | ||
2570 | schedule_work(&local->reset_queue); | ||
2571 | } | ||
2572 | goto out; | ||
2573 | } | ||
2574 | |||
2575 | le16_to_cpus(&info.len); | ||
2576 | le16_to_cpus(&info.type); | ||
2577 | left = (info.len - 1) * 2; | ||
2578 | |||
2579 | if (info.len & 0x8000 || info.len == 0 || left > 2060) { | ||
2580 | /* data register seems to give 0x8000 in some error cases even | ||
2581 | * though busy bit is not set in offset register; | ||
2582 | * in addition, length must be at least 1 due to type field */ | ||
2583 | spin_unlock(&local->baplock); | ||
2584 | printk(KERN_DEBUG "%s: Received info frame with invalid " | ||
2585 | "length 0x%04x (type 0x%04x)\n", dev->name, info.len, | ||
2586 | info.type); | ||
2587 | goto out; | ||
2588 | } | ||
2589 | |||
2590 | skb = dev_alloc_skb(sizeof(info) + left); | ||
2591 | if (skb == NULL) { | ||
2592 | spin_unlock(&local->baplock); | ||
2593 | printk(KERN_DEBUG "%s: Could not allocate skb for info " | ||
2594 | "frame\n", dev->name); | ||
2595 | goto out; | ||
2596 | } | ||
2597 | |||
2598 | memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); | ||
2599 | if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) | ||
2600 | { | ||
2601 | spin_unlock(&local->baplock); | ||
2602 | printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " | ||
2603 | "len=0x%04x, type=0x%04x\n", | ||
2604 | dev->name, fid, info.len, info.type); | ||
2605 | dev_kfree_skb(skb); | ||
2606 | goto out; | ||
2607 | } | ||
2608 | spin_unlock(&local->baplock); | ||
2609 | |||
2610 | skb_queue_tail(&local->info_list, skb); | ||
2611 | tasklet_schedule(&local->info_tasklet); | ||
2612 | |||
2613 | out: | ||
2614 | HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); | ||
2615 | } | ||
2616 | |||
2617 | |||
2618 | /* Called only as a tasklet (software IRQ) */ | ||
2619 | static void hostap_bap_tasklet(unsigned long data) | ||
2620 | { | ||
2621 | local_info_t *local = (local_info_t *) data; | ||
2622 | struct net_device *dev = local->dev; | ||
2623 | u16 ev; | ||
2624 | int frames = 30; | ||
2625 | |||
2626 | if (local->func->card_present && !local->func->card_present(local)) | ||
2627 | return; | ||
2628 | |||
2629 | set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2630 | |||
2631 | /* Process all pending BAP events without generating new interrupts | ||
2632 | * for them */ | ||
2633 | while (frames-- > 0) { | ||
2634 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2635 | if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) | ||
2636 | break; | ||
2637 | if (ev & HFA384X_EV_RX) | ||
2638 | prism2_rx(local); | ||
2639 | if (ev & HFA384X_EV_INFO) | ||
2640 | prism2_info(local); | ||
2641 | if (ev & HFA384X_EV_TX) | ||
2642 | prism2_tx_ev(local); | ||
2643 | if (ev & HFA384X_EV_TXEXC) | ||
2644 | prism2_txexc(local); | ||
2645 | } | ||
2646 | |||
2647 | set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2648 | clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2649 | |||
2650 | /* Enable interrupts for new BAP events */ | ||
2651 | hfa384x_events_all(dev); | ||
2652 | clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2653 | } | ||
2654 | |||
2655 | |||
2656 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
2657 | /* Called only from hardware IRQ */ | ||
2658 | static void prism2_bus_master_ev(struct net_device *dev, int bap) | ||
2659 | { | ||
2660 | struct hostap_interface *iface; | ||
2661 | local_info_t *local; | ||
2662 | |||
2663 | iface = netdev_priv(dev); | ||
2664 | local = iface->local; | ||
2665 | |||
2666 | if (bap == BAP1) { | ||
2667 | /* FIX: frame payload was DMA'd to skb->data; might need to | ||
2668 | * invalidate data cache for that memory area */ | ||
2669 | skb_queue_tail(&local->rx_list, local->rx_skb); | ||
2670 | tasklet_schedule(&local->rx_tasklet); | ||
2671 | HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); | ||
2672 | } else { | ||
2673 | if (prism2_transmit(dev, local->bus_m0_tx_idx)) { | ||
2674 | printk(KERN_DEBUG "%s: prism2_transmit() failed " | ||
2675 | "when called from bus master event\n", | ||
2676 | dev->name); | ||
2677 | local->intransmitfid[local->bus_m0_tx_idx] = | ||
2678 | PRISM2_TXFID_EMPTY; | ||
2679 | schedule_work(&local->reset_queue); | ||
2680 | } | ||
2681 | } | ||
2682 | } | ||
2683 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
2684 | |||
2685 | |||
2686 | /* Called only from hardware IRQ */ | ||
2687 | static void prism2_infdrop(struct net_device *dev) | ||
2688 | { | ||
2689 | static unsigned long last_inquire = 0; | ||
2690 | |||
2691 | PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); | ||
2692 | |||
2693 | /* some firmware versions seem to get stuck with | ||
2694 | * full CommTallies in high traffic load cases; every | ||
2695 | * packet will then cause INFDROP event and CommTallies | ||
2696 | * info frame will not be sent automatically. Try to | ||
2697 | * get out of this state by inquiring CommTallies. */ | ||
2698 | if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { | ||
2699 | hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, | ||
2700 | HFA384X_INFO_COMMTALLIES, NULL, NULL); | ||
2701 | last_inquire = jiffies; | ||
2702 | } | ||
2703 | } | ||
2704 | |||
2705 | |||
2706 | /* Called only from hardware IRQ */ | ||
2707 | static void prism2_ev_tick(struct net_device *dev) | ||
2708 | { | ||
2709 | struct hostap_interface *iface; | ||
2710 | local_info_t *local; | ||
2711 | u16 evstat, inten; | ||
2712 | static int prev_stuck = 0; | ||
2713 | |||
2714 | iface = netdev_priv(dev); | ||
2715 | local = iface->local; | ||
2716 | |||
2717 | if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && | ||
2718 | local->last_tick_timer) { | ||
2719 | evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2720 | inten = HFA384X_INW(HFA384X_INTEN_OFF); | ||
2721 | if (!prev_stuck) { | ||
2722 | printk(KERN_INFO "%s: SW TICK stuck? " | ||
2723 | "bits=0x%lx EvStat=%04x IntEn=%04x\n", | ||
2724 | dev->name, local->bits, evstat, inten); | ||
2725 | } | ||
2726 | local->sw_tick_stuck++; | ||
2727 | if ((evstat & HFA384X_BAP0_EVENTS) && | ||
2728 | (inten & HFA384X_BAP0_EVENTS)) { | ||
2729 | printk(KERN_INFO "%s: trying to recover from IRQ " | ||
2730 | "hang\n", dev->name); | ||
2731 | hfa384x_events_no_bap0(dev); | ||
2732 | } | ||
2733 | prev_stuck = 1; | ||
2734 | } else | ||
2735 | prev_stuck = 0; | ||
2736 | } | ||
2737 | |||
2738 | |||
2739 | /* Called only from hardware IRQ */ | ||
2740 | static inline void prism2_check_magic(local_info_t *local) | ||
2741 | { | ||
2742 | /* at least PCI Prism2.5 with bus mastering seems to sometimes | ||
2743 | * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the | ||
2744 | * register once or twice seems to get the correct value.. PCI cards | ||
2745 | * cannot anyway be removed during normal operation, so there is not | ||
2746 | * really any need for this verification with them. */ | ||
2747 | |||
2748 | #ifndef PRISM2_PCI | ||
2749 | #ifndef final_version | ||
2750 | static unsigned long last_magic_err = 0; | ||
2751 | struct net_device *dev = local->dev; | ||
2752 | |||
2753 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
2754 | if (!local->hw_ready) | ||
2755 | return; | ||
2756 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2757 | if (time_after(jiffies, last_magic_err + 10 * HZ)) { | ||
2758 | printk("%s: Interrupt, but SWSUPPORT0 does not match: " | ||
2759 | "%04X != %04X - card removed?\n", dev->name, | ||
2760 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2761 | HFA384X_MAGIC); | ||
2762 | last_magic_err = jiffies; | ||
2763 | } else if (net_ratelimit()) { | ||
2764 | printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " | ||
2765 | "MAGIC=%04x\n", dev->name, | ||
2766 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2767 | HFA384X_MAGIC); | ||
2768 | } | ||
2769 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) | ||
2770 | schedule_work(&local->reset_queue); | ||
2771 | return; | ||
2772 | } | ||
2773 | #endif /* final_version */ | ||
2774 | #endif /* !PRISM2_PCI */ | ||
2775 | } | ||
2776 | |||
2777 | |||
2778 | /* Called only from hardware IRQ */ | ||
2779 | static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
2780 | { | ||
2781 | struct net_device *dev = (struct net_device *) dev_id; | ||
2782 | struct hostap_interface *iface; | ||
2783 | local_info_t *local; | ||
2784 | int events = 0; | ||
2785 | u16 ev; | ||
2786 | |||
2787 | iface = netdev_priv(dev); | ||
2788 | local = iface->local; | ||
2789 | |||
2790 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); | ||
2791 | |||
2792 | if (local->func->card_present && !local->func->card_present(local)) { | ||
2793 | if (net_ratelimit()) { | ||
2794 | printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", | ||
2795 | dev->name); | ||
2796 | } | ||
2797 | return IRQ_HANDLED; | ||
2798 | } | ||
2799 | |||
2800 | prism2_check_magic(local); | ||
2801 | |||
2802 | for (;;) { | ||
2803 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2804 | if (ev == 0xffff) { | ||
2805 | if (local->shutdown) | ||
2806 | return IRQ_HANDLED; | ||
2807 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2808 | printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", | ||
2809 | dev->name); | ||
2810 | return IRQ_HANDLED; | ||
2811 | } | ||
2812 | |||
2813 | ev &= HFA384X_INW(HFA384X_INTEN_OFF); | ||
2814 | if (ev == 0) | ||
2815 | break; | ||
2816 | |||
2817 | if (ev & HFA384X_EV_CMD) { | ||
2818 | prism2_cmd_ev(dev); | ||
2819 | } | ||
2820 | |||
2821 | /* Above events are needed even before hw is ready, but other | ||
2822 | * events should be skipped during initialization. This may | ||
2823 | * change for AllocEv if allocate_fid is implemented without | ||
2824 | * busy waiting. */ | ||
2825 | if (!local->hw_ready || local->hw_resetting || | ||
2826 | !local->dev_enabled) { | ||
2827 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2828 | if (ev & HFA384X_EV_CMD) | ||
2829 | goto next_event; | ||
2830 | if ((ev & HFA384X_EVENT_MASK) == 0) | ||
2831 | return IRQ_HANDLED; | ||
2832 | if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && | ||
2833 | net_ratelimit()) { | ||
2834 | printk(KERN_DEBUG "%s: prism2_interrupt: hw " | ||
2835 | "not ready; skipping events 0x%04x " | ||
2836 | "(IntEn=0x%04x)%s%s%s\n", | ||
2837 | dev->name, ev, | ||
2838 | HFA384X_INW(HFA384X_INTEN_OFF), | ||
2839 | !local->hw_ready ? " (!hw_ready)" : "", | ||
2840 | local->hw_resetting ? | ||
2841 | " (hw_resetting)" : "", | ||
2842 | !local->dev_enabled ? | ||
2843 | " (!dev_enabled)" : ""); | ||
2844 | } | ||
2845 | HFA384X_OUTW(ev, HFA384X_EVACK_OFF); | ||
2846 | return IRQ_HANDLED; | ||
2847 | } | ||
2848 | |||
2849 | if (ev & HFA384X_EV_TICK) { | ||
2850 | prism2_ev_tick(dev); | ||
2851 | HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); | ||
2852 | } | ||
2853 | |||
2854 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
2855 | if (ev & HFA384X_EV_PCI_M0) { | ||
2856 | prism2_bus_master_ev(dev, BAP0); | ||
2857 | HFA384X_OUTW(HFA384X_EV_PCI_M0, HFA384X_EVACK_OFF); | ||
2858 | } | ||
2859 | |||
2860 | if (ev & HFA384X_EV_PCI_M1) { | ||
2861 | /* previous RX has been copied can be ACKed now */ | ||
2862 | HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); | ||
2863 | |||
2864 | prism2_bus_master_ev(dev, BAP1); | ||
2865 | HFA384X_OUTW(HFA384X_EV_PCI_M1, HFA384X_EVACK_OFF); | ||
2866 | } | ||
2867 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
2868 | |||
2869 | if (ev & HFA384X_EV_ALLOC) { | ||
2870 | prism2_alloc_ev(dev); | ||
2871 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
2872 | } | ||
2873 | |||
2874 | /* Reading data from the card is quite time consuming, so do it | ||
2875 | * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed | ||
2876 | * and unmasked after needed data has been read completely. */ | ||
2877 | if (ev & HFA384X_BAP0_EVENTS) { | ||
2878 | hfa384x_events_no_bap0(dev); | ||
2879 | tasklet_schedule(&local->bap_tasklet); | ||
2880 | } | ||
2881 | |||
2882 | #ifndef final_version | ||
2883 | if (ev & HFA384X_EV_WTERR) { | ||
2884 | PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); | ||
2885 | HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); | ||
2886 | } | ||
2887 | #endif /* final_version */ | ||
2888 | |||
2889 | if (ev & HFA384X_EV_INFDROP) { | ||
2890 | prism2_infdrop(dev); | ||
2891 | HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); | ||
2892 | } | ||
2893 | |||
2894 | next_event: | ||
2895 | events++; | ||
2896 | if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { | ||
2897 | PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " | ||
2898 | "(EvStat=0x%04x)\n", | ||
2899 | PRISM2_MAX_INTERRUPT_EVENTS, | ||
2900 | HFA384X_INW(HFA384X_EVSTAT_OFF)); | ||
2901 | break; | ||
2902 | } | ||
2903 | } | ||
2904 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); | ||
2905 | return IRQ_RETVAL(events); | ||
2906 | } | ||
2907 | |||
2908 | |||
2909 | static void prism2_check_sta_fw_version(local_info_t *local) | ||
2910 | { | ||
2911 | struct hfa384x_comp_ident comp; | ||
2912 | int id, variant, major, minor; | ||
2913 | |||
2914 | if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, | ||
2915 | &comp, sizeof(comp), 1) < 0) | ||
2916 | return; | ||
2917 | |||
2918 | local->fw_ap = 0; | ||
2919 | id = le16_to_cpu(comp.id); | ||
2920 | if (id != HFA384X_COMP_ID_STA) { | ||
2921 | if (id == HFA384X_COMP_ID_FW_AP) | ||
2922 | local->fw_ap = 1; | ||
2923 | return; | ||
2924 | } | ||
2925 | |||
2926 | major = __le16_to_cpu(comp.major); | ||
2927 | minor = __le16_to_cpu(comp.minor); | ||
2928 | variant = __le16_to_cpu(comp.variant); | ||
2929 | local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); | ||
2930 | |||
2931 | /* Station firmware versions before 1.4.x seem to have a bug in | ||
2932 | * firmware-based WEP encryption when using Host AP mode, so use | ||
2933 | * host_encrypt as a default for them. Firmware version 1.4.9 is the | ||
2934 | * first one that has been seen to produce correct encryption, but the | ||
2935 | * bug might be fixed before that (although, at least 1.4.2 is broken). | ||
2936 | */ | ||
2937 | local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); | ||
2938 | |||
2939 | if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
2940 | !local->fw_encrypt_ok) { | ||
2941 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
2942 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
2943 | local->dev->name); | ||
2944 | local->host_encrypt = 1; | ||
2945 | } | ||
2946 | |||
2947 | /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken | ||
2948 | * in station firmware versions before 1.5.x. With these versions, the | ||
2949 | * driver uses a workaround with bogus frame format (4th address after | ||
2950 | * the payload). This is not compatible with other AP devices. Since | ||
2951 | * the firmware bug is fixed in the latest station firmware versions, | ||
2952 | * automatically enable standard compliant mode for cards using station | ||
2953 | * firmware version 1.5.0 or newer. */ | ||
2954 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) | ||
2955 | local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; | ||
2956 | else { | ||
2957 | printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " | ||
2958 | "workaround for firmware bug in Host AP mode WDS\n", | ||
2959 | local->dev->name); | ||
2960 | } | ||
2961 | |||
2962 | hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); | ||
2963 | } | ||
2964 | |||
2965 | |||
2966 | static void prism2_crypt_deinit_entries(local_info_t *local, int force) | ||
2967 | { | ||
2968 | struct list_head *ptr, *n; | ||
2969 | struct prism2_crypt_data *entry; | ||
2970 | |||
2971 | for (ptr = local->crypt_deinit_list.next, n = ptr->next; | ||
2972 | ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { | ||
2973 | entry = list_entry(ptr, struct prism2_crypt_data, list); | ||
2974 | |||
2975 | if (atomic_read(&entry->refcnt) != 0 && !force) | ||
2976 | continue; | ||
2977 | |||
2978 | list_del(ptr); | ||
2979 | |||
2980 | if (entry->ops) | ||
2981 | entry->ops->deinit(entry->priv); | ||
2982 | kfree(entry); | ||
2983 | } | ||
2984 | } | ||
2985 | |||
2986 | |||
2987 | static void prism2_crypt_deinit_handler(unsigned long data) | ||
2988 | { | ||
2989 | local_info_t *local = (local_info_t *) data; | ||
2990 | unsigned long flags; | ||
2991 | |||
2992 | spin_lock_irqsave(&local->lock, flags); | ||
2993 | prism2_crypt_deinit_entries(local, 0); | ||
2994 | if (!list_empty(&local->crypt_deinit_list)) { | ||
2995 | printk(KERN_DEBUG "%s: entries remaining in delayed crypt " | ||
2996 | "deletion list\n", local->dev->name); | ||
2997 | local->crypt_deinit_timer.expires = jiffies + HZ; | ||
2998 | add_timer(&local->crypt_deinit_timer); | ||
2999 | } | ||
3000 | spin_unlock_irqrestore(&local->lock, flags); | ||
3001 | |||
3002 | } | ||
3003 | |||
3004 | |||
3005 | static void hostap_passive_scan(unsigned long data) | ||
3006 | { | ||
3007 | local_info_t *local = (local_info_t *) data; | ||
3008 | struct net_device *dev = local->dev; | ||
3009 | u16 channel; | ||
3010 | |||
3011 | if (local->passive_scan_interval <= 0) | ||
3012 | return; | ||
3013 | |||
3014 | if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { | ||
3015 | int max_tries = 16; | ||
3016 | |||
3017 | /* Even though host system does not really know when the WLAN | ||
3018 | * MAC is sending frames, try to avoid changing channels for | ||
3019 | * passive scanning when a host-generated frame is being | ||
3020 | * transmitted */ | ||
3021 | if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
3022 | printk(KERN_DEBUG "%s: passive scan detected pending " | ||
3023 | "TX - delaying\n", dev->name); | ||
3024 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
3025 | add_timer(&local->passive_scan_timer); | ||
3026 | return; | ||
3027 | } | ||
3028 | |||
3029 | do { | ||
3030 | local->passive_scan_channel++; | ||
3031 | if (local->passive_scan_channel > 14) | ||
3032 | local->passive_scan_channel = 1; | ||
3033 | max_tries--; | ||
3034 | } while (!(local->channel_mask & | ||
3035 | (1 << (local->passive_scan_channel - 1))) && | ||
3036 | max_tries > 0); | ||
3037 | |||
3038 | if (max_tries == 0) { | ||
3039 | printk(KERN_INFO "%s: no allowed passive scan channels" | ||
3040 | " found\n", dev->name); | ||
3041 | return; | ||
3042 | } | ||
3043 | |||
3044 | printk(KERN_DEBUG "%s: passive scan channel %d\n", | ||
3045 | dev->name, local->passive_scan_channel); | ||
3046 | channel = local->passive_scan_channel; | ||
3047 | local->passive_scan_state = PASSIVE_SCAN_WAIT; | ||
3048 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
3049 | } else { | ||
3050 | channel = local->channel; | ||
3051 | local->passive_scan_state = PASSIVE_SCAN_LISTEN; | ||
3052 | local->passive_scan_timer.expires = jiffies + | ||
3053 | local->passive_scan_interval * HZ; | ||
3054 | } | ||
3055 | |||
3056 | if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | | ||
3057 | (HFA384X_TEST_CHANGE_CHANNEL << 8), | ||
3058 | channel, NULL, NULL)) | ||
3059 | printk(KERN_ERR "%s: passive scan channel set %d " | ||
3060 | "failed\n", dev->name, channel); | ||
3061 | |||
3062 | add_timer(&local->passive_scan_timer); | ||
3063 | } | ||
3064 | |||
3065 | |||
3066 | /* Called only as a scheduled task when communications quality values should | ||
3067 | * be updated. */ | ||
3068 | static void handle_comms_qual_update(void *data) | ||
3069 | { | ||
3070 | local_info_t *local = data; | ||
3071 | prism2_update_comms_qual(local->dev); | ||
3072 | } | ||
3073 | |||
3074 | |||
3075 | /* Software watchdog - called as a timer. Hardware interrupt (Tick event) is | ||
3076 | * used to monitor that local->last_tick_timer is being updated. If not, | ||
3077 | * interrupt busy-loop is assumed and driver tries to recover by masking out | ||
3078 | * some events. */ | ||
3079 | static void hostap_tick_timer(unsigned long data) | ||
3080 | { | ||
3081 | static unsigned long last_inquire = 0; | ||
3082 | local_info_t *local = (local_info_t *) data; | ||
3083 | local->last_tick_timer = jiffies; | ||
3084 | |||
3085 | /* Inquire CommTallies every 10 seconds to keep the statistics updated | ||
3086 | * more often during low load and when using 32-bit tallies. */ | ||
3087 | if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && | ||
3088 | !local->hw_downloading && local->hw_ready && | ||
3089 | !local->hw_resetting && local->dev_enabled) { | ||
3090 | hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, | ||
3091 | HFA384X_INFO_COMMTALLIES, NULL, NULL); | ||
3092 | last_inquire = jiffies; | ||
3093 | } | ||
3094 | |||
3095 | if ((local->last_comms_qual_update == 0 || | ||
3096 | time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && | ||
3097 | (local->iw_mode == IW_MODE_INFRA || | ||
3098 | local->iw_mode == IW_MODE_ADHOC)) { | ||
3099 | schedule_work(&local->comms_qual_update); | ||
3100 | } | ||
3101 | |||
3102 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
3103 | add_timer(&local->tick_timer); | ||
3104 | } | ||
3105 | |||
3106 | |||
3107 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3108 | static int prism2_registers_proc_read(char *page, char **start, off_t off, | ||
3109 | int count, int *eof, void *data) | ||
3110 | { | ||
3111 | char *p = page; | ||
3112 | local_info_t *local = (local_info_t *) data; | ||
3113 | |||
3114 | if (off != 0) { | ||
3115 | *eof = 1; | ||
3116 | return 0; | ||
3117 | } | ||
3118 | |||
3119 | #define SHOW_REG(n) \ | ||
3120 | p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) | ||
3121 | |||
3122 | SHOW_REG(CMD); | ||
3123 | SHOW_REG(PARAM0); | ||
3124 | SHOW_REG(PARAM1); | ||
3125 | SHOW_REG(PARAM2); | ||
3126 | SHOW_REG(STATUS); | ||
3127 | SHOW_REG(RESP0); | ||
3128 | SHOW_REG(RESP1); | ||
3129 | SHOW_REG(RESP2); | ||
3130 | SHOW_REG(INFOFID); | ||
3131 | SHOW_REG(CONTROL); | ||
3132 | SHOW_REG(SELECT0); | ||
3133 | SHOW_REG(SELECT1); | ||
3134 | SHOW_REG(OFFSET0); | ||
3135 | SHOW_REG(OFFSET1); | ||
3136 | SHOW_REG(RXFID); | ||
3137 | SHOW_REG(ALLOCFID); | ||
3138 | SHOW_REG(TXCOMPLFID); | ||
3139 | SHOW_REG(SWSUPPORT0); | ||
3140 | SHOW_REG(SWSUPPORT1); | ||
3141 | SHOW_REG(SWSUPPORT2); | ||
3142 | SHOW_REG(EVSTAT); | ||
3143 | SHOW_REG(INTEN); | ||
3144 | SHOW_REG(EVACK); | ||
3145 | /* Do not read data registers, because they change the state of the | ||
3146 | * MAC (offset += 2) */ | ||
3147 | /* SHOW_REG(DATA0); */ | ||
3148 | /* SHOW_REG(DATA1); */ | ||
3149 | SHOW_REG(AUXPAGE); | ||
3150 | SHOW_REG(AUXOFFSET); | ||
3151 | /* SHOW_REG(AUXDATA); */ | ||
3152 | #ifdef PRISM2_PCI | ||
3153 | SHOW_REG(PCICOR); | ||
3154 | SHOW_REG(PCIHCR); | ||
3155 | SHOW_REG(PCI_M0_ADDRH); | ||
3156 | SHOW_REG(PCI_M0_ADDRL); | ||
3157 | SHOW_REG(PCI_M0_LEN); | ||
3158 | SHOW_REG(PCI_M0_CTL); | ||
3159 | SHOW_REG(PCI_STATUS); | ||
3160 | SHOW_REG(PCI_M1_ADDRH); | ||
3161 | SHOW_REG(PCI_M1_ADDRL); | ||
3162 | SHOW_REG(PCI_M1_LEN); | ||
3163 | SHOW_REG(PCI_M1_CTL); | ||
3164 | #endif /* PRISM2_PCI */ | ||
3165 | |||
3166 | return (p - page); | ||
3167 | } | ||
3168 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3169 | |||
3170 | |||
3171 | struct set_tim_data { | ||
3172 | struct list_head list; | ||
3173 | int aid; | ||
3174 | int set; | ||
3175 | }; | ||
3176 | |||
3177 | static int prism2_set_tim(struct net_device *dev, int aid, int set) | ||
3178 | { | ||
3179 | struct list_head *ptr; | ||
3180 | struct set_tim_data *new_entry; | ||
3181 | struct hostap_interface *iface; | ||
3182 | local_info_t *local; | ||
3183 | |||
3184 | iface = netdev_priv(dev); | ||
3185 | local = iface->local; | ||
3186 | |||
3187 | new_entry = (struct set_tim_data *) | ||
3188 | kmalloc(sizeof(*new_entry), GFP_ATOMIC); | ||
3189 | if (new_entry == NULL) { | ||
3190 | printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n", | ||
3191 | local->dev->name); | ||
3192 | return -ENOMEM; | ||
3193 | } | ||
3194 | memset(new_entry, 0, sizeof(*new_entry)); | ||
3195 | new_entry->aid = aid; | ||
3196 | new_entry->set = set; | ||
3197 | |||
3198 | spin_lock_bh(&local->set_tim_lock); | ||
3199 | list_for_each(ptr, &local->set_tim_list) { | ||
3200 | struct set_tim_data *entry = | ||
3201 | list_entry(ptr, struct set_tim_data, list); | ||
3202 | if (entry->aid == aid) { | ||
3203 | PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " | ||
3204 | "set=%d ==> %d\n", | ||
3205 | local->dev->name, aid, entry->set, set); | ||
3206 | entry->set = set; | ||
3207 | kfree(new_entry); | ||
3208 | new_entry = NULL; | ||
3209 | break; | ||
3210 | } | ||
3211 | } | ||
3212 | if (new_entry) | ||
3213 | list_add_tail(&new_entry->list, &local->set_tim_list); | ||
3214 | spin_unlock_bh(&local->set_tim_lock); | ||
3215 | |||
3216 | schedule_work(&local->set_tim_queue); | ||
3217 | |||
3218 | return 0; | ||
3219 | } | ||
3220 | |||
3221 | |||
3222 | static void handle_set_tim_queue(void *data) | ||
3223 | { | ||
3224 | local_info_t *local = (local_info_t *) data; | ||
3225 | struct set_tim_data *entry; | ||
3226 | u16 val; | ||
3227 | |||
3228 | for (;;) { | ||
3229 | entry = NULL; | ||
3230 | spin_lock_bh(&local->set_tim_lock); | ||
3231 | if (!list_empty(&local->set_tim_list)) { | ||
3232 | entry = list_entry(local->set_tim_list.next, | ||
3233 | struct set_tim_data, list); | ||
3234 | list_del(&entry->list); | ||
3235 | } | ||
3236 | spin_unlock_bh(&local->set_tim_lock); | ||
3237 | if (!entry) | ||
3238 | break; | ||
3239 | |||
3240 | PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", | ||
3241 | local->dev->name, entry->aid, entry->set); | ||
3242 | |||
3243 | val = entry->aid; | ||
3244 | if (entry->set) | ||
3245 | val |= 0x8000; | ||
3246 | if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { | ||
3247 | printk(KERN_DEBUG "%s: set_tim failed (aid=%d " | ||
3248 | "set=%d)\n", | ||
3249 | local->dev->name, entry->aid, entry->set); | ||
3250 | } | ||
3251 | |||
3252 | kfree(entry); | ||
3253 | } | ||
3254 | } | ||
3255 | |||
3256 | |||
3257 | static void prism2_clear_set_tim_queue(local_info_t *local) | ||
3258 | { | ||
3259 | struct list_head *ptr, *n; | ||
3260 | |||
3261 | list_for_each_safe(ptr, n, &local->set_tim_list) { | ||
3262 | struct set_tim_data *entry; | ||
3263 | entry = list_entry(ptr, struct set_tim_data, list); | ||
3264 | list_del(&entry->list); | ||
3265 | kfree(entry); | ||
3266 | } | ||
3267 | } | ||
3268 | |||
3269 | |||
3270 | static struct net_device * | ||
3271 | prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx) | ||
3272 | { | ||
3273 | struct net_device *dev; | ||
3274 | struct hostap_interface *iface; | ||
3275 | struct local_info *local; | ||
3276 | int len, i, ret; | ||
3277 | |||
3278 | if (funcs == NULL) | ||
3279 | return NULL; | ||
3280 | |||
3281 | len = strlen(dev_template); | ||
3282 | if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { | ||
3283 | printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", | ||
3284 | dev_template); | ||
3285 | return NULL; | ||
3286 | } | ||
3287 | |||
3288 | len = sizeof(struct hostap_interface) + | ||
3289 | 3 + sizeof(struct local_info) + | ||
3290 | 3 + sizeof(struct ap_data); | ||
3291 | |||
3292 | dev = alloc_etherdev(len); | ||
3293 | if (dev == NULL) | ||
3294 | return NULL; | ||
3295 | |||
3296 | iface = netdev_priv(dev); | ||
3297 | local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); | ||
3298 | local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); | ||
3299 | local->dev = iface->dev = dev; | ||
3300 | iface->local = local; | ||
3301 | iface->type = HOSTAP_INTERFACE_MASTER; | ||
3302 | INIT_LIST_HEAD(&local->hostap_interfaces); | ||
3303 | |||
3304 | local->hw_module = THIS_MODULE; | ||
3305 | |||
3306 | #ifdef PRISM2_IO_DEBUG | ||
3307 | local->io_debug_enabled = 1; | ||
3308 | #endif /* PRISM2_IO_DEBUG */ | ||
3309 | |||
3310 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
3311 | local->bus_m0_buf = (u8 *) kmalloc(sizeof(struct hfa384x_tx_frame) + | ||
3312 | PRISM2_DATA_MAXLEN, GFP_DMA); | ||
3313 | if (local->bus_m0_buf == NULL) | ||
3314 | goto fail; | ||
3315 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
3316 | |||
3317 | local->func = funcs; | ||
3318 | local->func->cmd = hfa384x_cmd; | ||
3319 | local->func->read_regs = hfa384x_read_regs; | ||
3320 | local->func->get_rid = hfa384x_get_rid; | ||
3321 | local->func->set_rid = hfa384x_set_rid; | ||
3322 | local->func->hw_enable = prism2_hw_enable; | ||
3323 | local->func->hw_config = prism2_hw_config; | ||
3324 | local->func->hw_reset = prism2_hw_reset; | ||
3325 | local->func->hw_shutdown = prism2_hw_shutdown; | ||
3326 | local->func->reset_port = prism2_reset_port; | ||
3327 | local->func->schedule_reset = prism2_schedule_reset; | ||
3328 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3329 | local->func->read_aux = prism2_download_aux_dump; | ||
3330 | local->func->download = prism2_download; | ||
3331 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3332 | local->func->tx = prism2_tx_80211; | ||
3333 | local->func->set_tim = prism2_set_tim; | ||
3334 | local->func->need_tx_headroom = 0; /* no need to add txdesc in | ||
3335 | * skb->data (FIX: maybe for DMA bus | ||
3336 | * mastering? */ | ||
3337 | |||
3338 | local->mtu = mtu; | ||
3339 | |||
3340 | rwlock_init(&local->iface_lock); | ||
3341 | spin_lock_init(&local->txfidlock); | ||
3342 | spin_lock_init(&local->cmdlock); | ||
3343 | spin_lock_init(&local->baplock); | ||
3344 | spin_lock_init(&local->lock); | ||
3345 | init_MUTEX(&local->rid_bap_sem); | ||
3346 | |||
3347 | if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) | ||
3348 | card_idx = 0; | ||
3349 | local->card_idx = card_idx; | ||
3350 | |||
3351 | len = strlen(essid); | ||
3352 | memcpy(local->essid, essid, | ||
3353 | len > MAX_SSID_LEN ? MAX_SSID_LEN : len); | ||
3354 | local->essid[MAX_SSID_LEN] = '\0'; | ||
3355 | i = GET_INT_PARM(iw_mode, card_idx); | ||
3356 | if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || | ||
3357 | i == IW_MODE_MONITOR) { | ||
3358 | local->iw_mode = i; | ||
3359 | } else { | ||
3360 | printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " | ||
3361 | "IW_MODE_MASTER\n", i); | ||
3362 | local->iw_mode = IW_MODE_MASTER; | ||
3363 | } | ||
3364 | local->channel = GET_INT_PARM(channel, card_idx); | ||
3365 | local->beacon_int = GET_INT_PARM(beacon_int, card_idx); | ||
3366 | local->dtim_period = GET_INT_PARM(dtim_period, card_idx); | ||
3367 | local->wds_max_connections = 16; | ||
3368 | local->tx_control = HFA384X_TX_CTRL_FLAGS; | ||
3369 | local->manual_retry_count = -1; | ||
3370 | local->rts_threshold = 2347; | ||
3371 | local->fragm_threshold = 2346; | ||
3372 | local->rssi_to_dBm = 100; /* default; to be overriden by | ||
3373 | * cnfDbmAdjust, if available */ | ||
3374 | local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; | ||
3375 | local->sram_type = -1; | ||
3376 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
3377 | local->bus_master_threshold_rx = GET_INT_PARM(bus_master_threshold_rx, | ||
3378 | card_idx); | ||
3379 | local->bus_master_threshold_tx = GET_INT_PARM(bus_master_threshold_tx, | ||
3380 | card_idx); | ||
3381 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
3382 | |||
3383 | /* Initialize task queue structures */ | ||
3384 | INIT_WORK(&local->reset_queue, handle_reset_queue, local); | ||
3385 | INIT_WORK(&local->set_multicast_list_queue, | ||
3386 | hostap_set_multicast_list_queue, local->dev); | ||
3387 | |||
3388 | INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local); | ||
3389 | INIT_LIST_HEAD(&local->set_tim_list); | ||
3390 | spin_lock_init(&local->set_tim_lock); | ||
3391 | |||
3392 | INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local); | ||
3393 | |||
3394 | /* Initialize tasklets for handling hardware IRQ related operations | ||
3395 | * outside hw IRQ handler */ | ||
3396 | #define HOSTAP_TASKLET_INIT(q, f, d) \ | ||
3397 | do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \ | ||
3398 | while (0) | ||
3399 | HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet, | ||
3400 | (unsigned long) local); | ||
3401 | |||
3402 | HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet, | ||
3403 | (unsigned long) local); | ||
3404 | hostap_info_init(local); | ||
3405 | |||
3406 | HOSTAP_TASKLET_INIT(&local->rx_tasklet, | ||
3407 | hostap_rx_tasklet, (unsigned long) local); | ||
3408 | skb_queue_head_init(&local->rx_list); | ||
3409 | |||
3410 | HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet, | ||
3411 | hostap_sta_tx_exc_tasklet, (unsigned long) local); | ||
3412 | skb_queue_head_init(&local->sta_tx_exc_list); | ||
3413 | |||
3414 | INIT_LIST_HEAD(&local->cmd_queue); | ||
3415 | init_waitqueue_head(&local->hostscan_wq); | ||
3416 | INIT_LIST_HEAD(&local->crypt_deinit_list); | ||
3417 | init_timer(&local->crypt_deinit_timer); | ||
3418 | local->crypt_deinit_timer.data = (unsigned long) local; | ||
3419 | local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; | ||
3420 | |||
3421 | init_timer(&local->passive_scan_timer); | ||
3422 | local->passive_scan_timer.data = (unsigned long) local; | ||
3423 | local->passive_scan_timer.function = hostap_passive_scan; | ||
3424 | |||
3425 | init_timer(&local->tick_timer); | ||
3426 | local->tick_timer.data = (unsigned long) local; | ||
3427 | local->tick_timer.function = hostap_tick_timer; | ||
3428 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
3429 | add_timer(&local->tick_timer); | ||
3430 | |||
3431 | INIT_LIST_HEAD(&local->bss_list); | ||
3432 | |||
3433 | hostap_setup_dev(dev, local, 1); | ||
3434 | local->saved_eth_header_parse = dev->hard_header_parse; | ||
3435 | |||
3436 | dev->hard_start_xmit = hostap_master_start_xmit; | ||
3437 | dev->type = ARPHRD_IEEE80211; | ||
3438 | dev->hard_header_parse = hostap_80211_header_parse; | ||
3439 | |||
3440 | rtnl_lock(); | ||
3441 | ret = dev_alloc_name(dev, "wifi%d"); | ||
3442 | if (ret >= 0) | ||
3443 | ret = register_netdevice(dev); | ||
3444 | rtnl_unlock(); | ||
3445 | if (ret < 0) { | ||
3446 | printk(KERN_WARNING "%s: register netdevice failed!\n", | ||
3447 | dev_info); | ||
3448 | goto fail; | ||
3449 | } | ||
3450 | printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); | ||
3451 | |||
3452 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3453 | create_proc_read_entry("registers", 0, local->proc, | ||
3454 | prism2_registers_proc_read, local); | ||
3455 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3456 | |||
3457 | hostap_init_data(local); | ||
3458 | return dev; | ||
3459 | |||
3460 | fail: | ||
3461 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
3462 | kfree(local->bus_m0_buf); | ||
3463 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
3464 | free_netdev(dev); | ||
3465 | return NULL; | ||
3466 | } | ||
3467 | |||
3468 | |||
3469 | static int hostap_hw_ready(struct net_device *dev) | ||
3470 | { | ||
3471 | struct hostap_interface *iface; | ||
3472 | struct local_info *local; | ||
3473 | |||
3474 | iface = netdev_priv(dev); | ||
3475 | local = iface->local; | ||
3476 | local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, | ||
3477 | "", dev_template); | ||
3478 | |||
3479 | if (local->ddev) { | ||
3480 | if (local->iw_mode == IW_MODE_INFRA || | ||
3481 | local->iw_mode == IW_MODE_ADHOC) { | ||
3482 | netif_carrier_off(local->dev); | ||
3483 | netif_carrier_off(local->ddev); | ||
3484 | } | ||
3485 | hostap_init_proc(local); | ||
3486 | hostap_init_ap_proc(local); | ||
3487 | return 0; | ||
3488 | } | ||
3489 | |||
3490 | return -1; | ||
3491 | } | ||
3492 | |||
3493 | |||
3494 | static void prism2_free_local_data(struct net_device *dev) | ||
3495 | { | ||
3496 | struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; | ||
3497 | int i; | ||
3498 | struct hostap_interface *iface; | ||
3499 | struct local_info *local; | ||
3500 | struct list_head *ptr, *n; | ||
3501 | |||
3502 | if (dev == NULL) | ||
3503 | return; | ||
3504 | |||
3505 | iface = netdev_priv(dev); | ||
3506 | local = iface->local; | ||
3507 | |||
3508 | flush_scheduled_work(); | ||
3509 | |||
3510 | if (timer_pending(&local->crypt_deinit_timer)) | ||
3511 | del_timer(&local->crypt_deinit_timer); | ||
3512 | prism2_crypt_deinit_entries(local, 1); | ||
3513 | |||
3514 | if (timer_pending(&local->passive_scan_timer)) | ||
3515 | del_timer(&local->passive_scan_timer); | ||
3516 | |||
3517 | if (timer_pending(&local->tick_timer)) | ||
3518 | del_timer(&local->tick_timer); | ||
3519 | |||
3520 | prism2_clear_cmd_queue(local); | ||
3521 | |||
3522 | skb_queue_purge(&local->info_list); | ||
3523 | skb_queue_purge(&local->rx_list); | ||
3524 | skb_queue_purge(&local->sta_tx_exc_list); | ||
3525 | |||
3526 | if (local->dev_enabled) | ||
3527 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
3528 | |||
3529 | for (i = 0; i < WEP_KEYS; i++) { | ||
3530 | struct prism2_crypt_data *crypt = local->crypt[i]; | ||
3531 | if (crypt) { | ||
3532 | if (crypt->ops) | ||
3533 | crypt->ops->deinit(crypt->priv); | ||
3534 | kfree(crypt); | ||
3535 | local->crypt[i] = NULL; | ||
3536 | } | ||
3537 | } | ||
3538 | |||
3539 | if (local->ap != NULL) | ||
3540 | hostap_free_data(local->ap); | ||
3541 | |||
3542 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3543 | if (local->proc != NULL) | ||
3544 | remove_proc_entry("registers", local->proc); | ||
3545 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3546 | hostap_remove_proc(local); | ||
3547 | |||
3548 | tx_cb = local->tx_callback; | ||
3549 | while (tx_cb != NULL) { | ||
3550 | tx_cb_prev = tx_cb; | ||
3551 | tx_cb = tx_cb->next; | ||
3552 | kfree(tx_cb_prev); | ||
3553 | } | ||
3554 | |||
3555 | hostap_set_hostapd(local, 0, 0); | ||
3556 | hostap_set_hostapd_sta(local, 0, 0); | ||
3557 | |||
3558 | for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | ||
3559 | if (local->frag_cache[i].skb != NULL) | ||
3560 | dev_kfree_skb(local->frag_cache[i].skb); | ||
3561 | } | ||
3562 | |||
3563 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3564 | prism2_download_free_data(local->dl_pri); | ||
3565 | prism2_download_free_data(local->dl_sec); | ||
3566 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3567 | |||
3568 | list_for_each_safe(ptr, n, &local->hostap_interfaces) { | ||
3569 | iface = list_entry(ptr, struct hostap_interface, list); | ||
3570 | if (iface->type == HOSTAP_INTERFACE_MASTER) { | ||
3571 | /* special handling for this interface below */ | ||
3572 | continue; | ||
3573 | } | ||
3574 | hostap_remove_interface(iface->dev, 0, 1); | ||
3575 | } | ||
3576 | |||
3577 | prism2_clear_set_tim_queue(local); | ||
3578 | |||
3579 | list_for_each_safe(ptr, n, &local->bss_list) { | ||
3580 | struct hostap_bss_info *bss = | ||
3581 | list_entry(ptr, struct hostap_bss_info, list); | ||
3582 | kfree(bss); | ||
3583 | } | ||
3584 | |||
3585 | #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) | ||
3586 | kfree(local->bus_m0_buf); | ||
3587 | #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ | ||
3588 | kfree(local->pda); | ||
3589 | kfree(local->last_scan_results); | ||
3590 | kfree(local->generic_elem); | ||
3591 | |||
3592 | unregister_netdev(local->dev); | ||
3593 | free_netdev(local->dev); | ||
3594 | } | ||
3595 | |||
3596 | |||
3597 | #ifndef PRISM2_PLX | ||
3598 | static void prism2_suspend(struct net_device *dev) | ||
3599 | { | ||
3600 | struct hostap_interface *iface; | ||
3601 | struct local_info *local; | ||
3602 | union iwreq_data wrqu; | ||
3603 | |||
3604 | iface = dev->priv; | ||
3605 | local = iface->local; | ||
3606 | |||
3607 | /* Send disconnect event, e.g., to trigger reassociation after resume | ||
3608 | * if wpa_supplicant is used. */ | ||
3609 | memset(&wrqu, 0, sizeof(wrqu)); | ||
3610 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
3611 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
3612 | |||
3613 | /* Disable hardware and firmware */ | ||
3614 | prism2_hw_shutdown(dev, 0); | ||
3615 | } | ||
3616 | #endif /* PRISM2_PLX */ | ||
3617 | |||
3618 | |||
3619 | /* These might at some point be compiled separately and used as separate | ||
3620 | * kernel modules or linked into one */ | ||
3621 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3622 | #include "hostap_download.c" | ||
3623 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3624 | |||
3625 | #ifdef PRISM2_CALLBACK | ||
3626 | /* External hostap_callback.c file can be used to, e.g., blink activity led. | ||
3627 | * This can use platform specific code and must define prism2_callback() | ||
3628 | * function (if PRISM2_CALLBACK is not defined, these function calls are not | ||
3629 | * used. */ | ||
3630 | #include "hostap_callback.c" | ||
3631 | #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 00000000000..cf9e0898b57 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_info.c | |||
@@ -0,0 +1,478 @@ | |||
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_scan_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; | ||
248 | unsigned long flags; | ||
249 | struct hfa384x_scan_result *results, *prev; | ||
250 | |||
251 | if (left < 4) { | ||
252 | printk(KERN_DEBUG "%s: invalid scanresult info frame " | ||
253 | "length %d\n", local->dev->name, left); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | pos = (u16 *) buf; | ||
258 | pos++; | ||
259 | pos++; | ||
260 | left -= 4; | ||
261 | |||
262 | new_count = left / sizeof(struct hfa384x_scan_result); | ||
263 | results = kmalloc(new_count * sizeof(struct hfa384x_scan_result), | ||
264 | GFP_ATOMIC); | ||
265 | if (results == NULL) | ||
266 | return; | ||
267 | memcpy(results, pos, new_count * sizeof(struct hfa384x_scan_result)); | ||
268 | |||
269 | spin_lock_irqsave(&local->lock, flags); | ||
270 | local->last_scan_type = PRISM2_SCAN; | ||
271 | prev = local->last_scan_results; | ||
272 | local->last_scan_results = results; | ||
273 | local->last_scan_results_count = new_count; | ||
274 | spin_unlock_irqrestore(&local->lock, flags); | ||
275 | kfree(prev); | ||
276 | |||
277 | hostap_report_scan_complete(local); | ||
278 | |||
279 | /* Perform rest of ScanResults handling later in scheduled task */ | ||
280 | set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); | ||
281 | schedule_work(&local->info_queue); | ||
282 | } | ||
283 | |||
284 | |||
285 | /* Called only as a tasklet (software IRQ) */ | ||
286 | static void prism2_info_hostscanresults(local_info_t *local, | ||
287 | unsigned char *buf, int left) | ||
288 | { | ||
289 | int i, result_size, copy_len, new_count; | ||
290 | struct hfa384x_hostscan_result *results, *prev; | ||
291 | unsigned long flags; | ||
292 | u16 *pos; | ||
293 | u8 *ptr; | ||
294 | |||
295 | wake_up_interruptible(&local->hostscan_wq); | ||
296 | |||
297 | if (left < 4) { | ||
298 | printk(KERN_DEBUG "%s: invalid hostscanresult info frame " | ||
299 | "length %d\n", local->dev->name, left); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | pos = (u16 *) buf; | ||
304 | copy_len = result_size = le16_to_cpu(*pos); | ||
305 | if (result_size == 0) { | ||
306 | printk(KERN_DEBUG "%s: invalid result_size (0) in " | ||
307 | "hostscanresults\n", local->dev->name); | ||
308 | return; | ||
309 | } | ||
310 | if (copy_len > sizeof(struct hfa384x_hostscan_result)) | ||
311 | copy_len = sizeof(struct hfa384x_hostscan_result); | ||
312 | |||
313 | pos++; | ||
314 | pos++; | ||
315 | left -= 4; | ||
316 | ptr = (u8 *) pos; | ||
317 | |||
318 | new_count = left / result_size; | ||
319 | results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), | ||
320 | GFP_ATOMIC); | ||
321 | if (results == NULL) | ||
322 | return; | ||
323 | memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result)); | ||
324 | |||
325 | for (i = 0; i < new_count; i++) { | ||
326 | memcpy(&results[i], ptr, copy_len); | ||
327 | ptr += result_size; | ||
328 | left -= result_size; | ||
329 | } | ||
330 | |||
331 | if (left) { | ||
332 | printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", | ||
333 | local->dev->name, left, result_size); | ||
334 | } | ||
335 | |||
336 | spin_lock_irqsave(&local->lock, flags); | ||
337 | local->last_scan_type = PRISM2_HOSTSCAN; | ||
338 | prev = local->last_hostscan_results; | ||
339 | local->last_hostscan_results = results; | ||
340 | local->last_hostscan_results_count = new_count; | ||
341 | spin_unlock_irqrestore(&local->lock, flags); | ||
342 | kfree(prev); | ||
343 | |||
344 | hostap_report_scan_complete(local); | ||
345 | } | ||
346 | #endif /* PRISM2_NO_STATION_MODES */ | ||
347 | |||
348 | |||
349 | /* Called only as a tasklet (software IRQ) */ | ||
350 | void hostap_info_process(local_info_t *local, struct sk_buff *skb) | ||
351 | { | ||
352 | struct hfa384x_info_frame *info; | ||
353 | unsigned char *buf; | ||
354 | int left; | ||
355 | #ifndef PRISM2_NO_DEBUG | ||
356 | int i; | ||
357 | #endif /* PRISM2_NO_DEBUG */ | ||
358 | |||
359 | info = (struct hfa384x_info_frame *) skb->data; | ||
360 | buf = skb->data + sizeof(*info); | ||
361 | left = skb->len - sizeof(*info); | ||
362 | |||
363 | switch (info->type) { | ||
364 | case HFA384X_INFO_COMMTALLIES: | ||
365 | prism2_info_commtallies(local, buf, left); | ||
366 | break; | ||
367 | |||
368 | #ifndef PRISM2_NO_STATION_MODES | ||
369 | case HFA384X_INFO_LINKSTATUS: | ||
370 | prism2_info_linkstatus(local, buf, left); | ||
371 | break; | ||
372 | |||
373 | case HFA384X_INFO_SCANRESULTS: | ||
374 | prism2_info_scanresults(local, buf, left); | ||
375 | break; | ||
376 | |||
377 | case HFA384X_INFO_HOSTSCANRESULTS: | ||
378 | prism2_info_hostscanresults(local, buf, left); | ||
379 | break; | ||
380 | #endif /* PRISM2_NO_STATION_MODES */ | ||
381 | |||
382 | #ifndef PRISM2_NO_DEBUG | ||
383 | default: | ||
384 | PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", | ||
385 | local->dev->name, info->len, info->type); | ||
386 | PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); | ||
387 | for (i = 0; i < (left < 100 ? left : 100); i++) | ||
388 | PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); | ||
389 | PDEBUG2(DEBUG_EXTRA, "\n"); | ||
390 | break; | ||
391 | #endif /* PRISM2_NO_DEBUG */ | ||
392 | } | ||
393 | } | ||
394 | |||
395 | |||
396 | #ifndef PRISM2_NO_STATION_MODES | ||
397 | static void handle_info_queue_linkstatus(local_info_t *local) | ||
398 | { | ||
399 | int val = local->prev_link_status; | ||
400 | int connected; | ||
401 | union iwreq_data wrqu; | ||
402 | |||
403 | connected = | ||
404 | val == HFA384X_LINKSTATUS_CONNECTED || | ||
405 | val == HFA384X_LINKSTATUS_AP_CHANGE || | ||
406 | val == HFA384X_LINKSTATUS_AP_IN_RANGE; | ||
407 | |||
408 | if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, | ||
409 | local->bssid, ETH_ALEN, 1) < 0) { | ||
410 | printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " | ||
411 | "LinkStatus event\n", local->dev->name); | ||
412 | } else { | ||
413 | PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", | ||
414 | local->dev->name, | ||
415 | MAC2STR((unsigned char *) local->bssid)); | ||
416 | if (local->wds_type & HOSTAP_WDS_AP_CLIENT) | ||
417 | hostap_add_sta(local->ap, local->bssid); | ||
418 | } | ||
419 | |||
420 | /* Get BSSID if we have a valid AP address */ | ||
421 | if (connected) { | ||
422 | netif_carrier_on(local->dev); | ||
423 | netif_carrier_on(local->ddev); | ||
424 | memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); | ||
425 | } else { | ||
426 | netif_carrier_off(local->dev); | ||
427 | netif_carrier_off(local->ddev); | ||
428 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
429 | } | ||
430 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
431 | |||
432 | /* | ||
433 | * Filter out sequential disconnect events in order not to cause a | ||
434 | * flood of SIOCGIWAP events that have a race condition with EAPOL | ||
435 | * frames and can confuse wpa_supplicant about the current association | ||
436 | * status. | ||
437 | */ | ||
438 | if (connected || local->prev_linkstatus_connected) | ||
439 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
440 | local->prev_linkstatus_connected = connected; | ||
441 | } | ||
442 | |||
443 | |||
444 | static void handle_info_queue_scanresults(local_info_t *local) | ||
445 | { | ||
446 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) | ||
447 | prism2_host_roaming(local); | ||
448 | } | ||
449 | |||
450 | |||
451 | /* Called only as scheduled task after receiving info frames (used to avoid | ||
452 | * pending too much time in HW IRQ handler). */ | ||
453 | static void handle_info_queue(void *data) | ||
454 | { | ||
455 | local_info_t *local = (local_info_t *) data; | ||
456 | |||
457 | if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, | ||
458 | &local->pending_info)) | ||
459 | handle_info_queue_linkstatus(local); | ||
460 | |||
461 | if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, | ||
462 | &local->pending_info)) | ||
463 | handle_info_queue_scanresults(local); | ||
464 | } | ||
465 | #endif /* PRISM2_NO_STATION_MODES */ | ||
466 | |||
467 | |||
468 | void hostap_info_init(local_info_t *local) | ||
469 | { | ||
470 | skb_queue_head_init(&local->info_list); | ||
471 | #ifndef PRISM2_NO_STATION_MODES | ||
472 | INIT_WORK(&local->info_queue, handle_info_queue, local); | ||
473 | #endif /* PRISM2_NO_STATION_MODES */ | ||
474 | } | ||
475 | |||
476 | |||
477 | EXPORT_SYMBOL(hostap_info_init); | ||
478 | 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 00000000000..e545ac9c1b1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ioctl.c | |||
@@ -0,0 +1,4123 @@ | |||
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 prism2_crypt_data **crypt) | ||
119 | { | ||
120 | struct prism2_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 prism2_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 prism2_crypt_data *new_crypt; | ||
179 | |||
180 | /* take WEP into use */ | ||
181 | new_crypt = (struct prism2_crypt_data *) | ||
182 | kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); | ||
183 | if (new_crypt == NULL) | ||
184 | return -ENOMEM; | ||
185 | memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); | ||
186 | new_crypt->ops = hostap_get_crypto_ops("WEP"); | ||
187 | if (!new_crypt->ops) { | ||
188 | request_module("hostap_crypt_wep"); | ||
189 | new_crypt->ops = hostap_get_crypto_ops("WEP"); | ||
190 | } | ||
191 | if (new_crypt->ops) | ||
192 | new_crypt->priv = new_crypt->ops->init(i); | ||
193 | if (!new_crypt->ops || !new_crypt->priv) { | ||
194 | kfree(new_crypt); | ||
195 | new_crypt = NULL; | ||
196 | |||
197 | printk(KERN_WARNING "%s: could not initialize WEP: " | ||
198 | "load module hostap_crypt_wep.o\n", | ||
199 | dev->name); | ||
200 | return -EOPNOTSUPP; | ||
201 | } | ||
202 | *crypt = new_crypt; | ||
203 | } | ||
204 | |||
205 | if (erq->length > 0) { | ||
206 | int len = erq->length <= 5 ? 5 : 13; | ||
207 | int first = 1, j; | ||
208 | if (len > erq->length) | ||
209 | memset(keybuf + erq->length, 0, len - erq->length); | ||
210 | (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); | ||
211 | for (j = 0; j < WEP_KEYS; j++) { | ||
212 | if (j != i && local->crypt[j]) { | ||
213 | first = 0; | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | if (first) | ||
218 | local->tx_keyidx = i; | ||
219 | } else { | ||
220 | /* No key data - just set the default TX key index */ | ||
221 | local->tx_keyidx = i; | ||
222 | } | ||
223 | |||
224 | done: | ||
225 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
226 | |||
227 | if (hostap_set_encryption(local)) { | ||
228 | printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
233 | * generate new IEEE 802.11 authentication which may end up in looping | ||
234 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
235 | * after WEP configuration. However, keys are apparently changed at | ||
236 | * least in Managed mode. */ | ||
237 | if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { | ||
238 | printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | |||
246 | static int prism2_ioctl_giwencode(struct net_device *dev, | ||
247 | struct iw_request_info *info, | ||
248 | struct iw_point *erq, char *key) | ||
249 | { | ||
250 | struct hostap_interface *iface; | ||
251 | local_info_t *local; | ||
252 | int i, len; | ||
253 | u16 val; | ||
254 | struct prism2_crypt_data *crypt; | ||
255 | |||
256 | iface = netdev_priv(dev); | ||
257 | local = iface->local; | ||
258 | |||
259 | i = erq->flags & IW_ENCODE_INDEX; | ||
260 | if (i < 1 || i > 4) | ||
261 | i = local->tx_keyidx; | ||
262 | else | ||
263 | i--; | ||
264 | if (i < 0 || i >= WEP_KEYS) | ||
265 | return -EINVAL; | ||
266 | |||
267 | crypt = local->crypt[i]; | ||
268 | erq->flags = i + 1; | ||
269 | |||
270 | if (crypt == NULL || crypt->ops == NULL) { | ||
271 | erq->length = 0; | ||
272 | erq->flags |= IW_ENCODE_DISABLED; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | if (strcmp(crypt->ops->name, "WEP") != 0) { | ||
277 | /* only WEP is supported with wireless extensions, so just | ||
278 | * report that encryption is used */ | ||
279 | erq->length = 0; | ||
280 | erq->flags |= IW_ENCODE_ENABLED; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show | ||
285 | * the keys from driver buffer */ | ||
286 | len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); | ||
287 | erq->length = (len >= 0 ? len : 0); | ||
288 | |||
289 | if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) | ||
290 | { | ||
291 | printk("CNFWEPFLAGS reading failed\n"); | ||
292 | return -EOPNOTSUPP; | ||
293 | } | ||
294 | le16_to_cpus(&val); | ||
295 | if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) | ||
296 | erq->flags |= IW_ENCODE_ENABLED; | ||
297 | else | ||
298 | erq->flags |= IW_ENCODE_DISABLED; | ||
299 | if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) | ||
300 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
301 | else | ||
302 | erq->flags |= IW_ENCODE_OPEN; | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | |||
308 | static int hostap_set_rate(struct net_device *dev) | ||
309 | { | ||
310 | struct hostap_interface *iface; | ||
311 | local_info_t *local; | ||
312 | int ret, basic_rates; | ||
313 | |||
314 | iface = netdev_priv(dev); | ||
315 | local = iface->local; | ||
316 | |||
317 | basic_rates = local->basic_rates & local->tx_rate_control; | ||
318 | if (!basic_rates || basic_rates != local->basic_rates) { | ||
319 | printk(KERN_INFO "%s: updating basic rate set automatically " | ||
320 | "to match with the new supported rate set\n", | ||
321 | dev->name); | ||
322 | if (!basic_rates) | ||
323 | basic_rates = local->tx_rate_control; | ||
324 | |||
325 | local->basic_rates = basic_rates; | ||
326 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
327 | basic_rates)) | ||
328 | printk(KERN_WARNING "%s: failed to set " | ||
329 | "cnfBasicRates\n", dev->name); | ||
330 | } | ||
331 | |||
332 | ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
333 | local->tx_rate_control) || | ||
334 | hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
335 | local->tx_rate_control) || | ||
336 | local->func->reset_port(dev)); | ||
337 | |||
338 | if (ret) { | ||
339 | printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " | ||
340 | "setting to 0x%x failed\n", | ||
341 | dev->name, local->tx_rate_control); | ||
342 | } | ||
343 | |||
344 | /* Update TX rate configuration for all STAs based on new operational | ||
345 | * rate set. */ | ||
346 | hostap_update_rates(local); | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | |||
352 | static int prism2_ioctl_siwrate(struct net_device *dev, | ||
353 | struct iw_request_info *info, | ||
354 | struct iw_param *rrq, char *extra) | ||
355 | { | ||
356 | struct hostap_interface *iface; | ||
357 | local_info_t *local; | ||
358 | |||
359 | iface = netdev_priv(dev); | ||
360 | local = iface->local; | ||
361 | |||
362 | if (rrq->fixed) { | ||
363 | switch (rrq->value) { | ||
364 | case 11000000: | ||
365 | local->tx_rate_control = HFA384X_RATES_11MBPS; | ||
366 | break; | ||
367 | case 5500000: | ||
368 | local->tx_rate_control = HFA384X_RATES_5MBPS; | ||
369 | break; | ||
370 | case 2000000: | ||
371 | local->tx_rate_control = HFA384X_RATES_2MBPS; | ||
372 | break; | ||
373 | case 1000000: | ||
374 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
375 | break; | ||
376 | default: | ||
377 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
378 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
379 | HFA384X_RATES_11MBPS; | ||
380 | break; | ||
381 | } | ||
382 | } else { | ||
383 | switch (rrq->value) { | ||
384 | case 11000000: | ||
385 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
386 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
387 | HFA384X_RATES_11MBPS; | ||
388 | break; | ||
389 | case 5500000: | ||
390 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
391 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; | ||
392 | break; | ||
393 | case 2000000: | ||
394 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
395 | HFA384X_RATES_2MBPS; | ||
396 | break; | ||
397 | case 1000000: | ||
398 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
399 | break; | ||
400 | default: | ||
401 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
402 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
403 | HFA384X_RATES_11MBPS; | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | return hostap_set_rate(dev); | ||
409 | } | ||
410 | |||
411 | |||
412 | static int prism2_ioctl_giwrate(struct net_device *dev, | ||
413 | struct iw_request_info *info, | ||
414 | struct iw_param *rrq, char *extra) | ||
415 | { | ||
416 | u16 val; | ||
417 | struct hostap_interface *iface; | ||
418 | local_info_t *local; | ||
419 | int ret = 0; | ||
420 | |||
421 | iface = netdev_priv(dev); | ||
422 | local = iface->local; | ||
423 | |||
424 | if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < | ||
425 | 0) | ||
426 | return -EINVAL; | ||
427 | |||
428 | if ((val & 0x1) && (val > 1)) | ||
429 | rrq->fixed = 0; | ||
430 | else | ||
431 | rrq->fixed = 1; | ||
432 | |||
433 | if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && | ||
434 | !local->fw_tx_rate_control) { | ||
435 | /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in | ||
436 | * Host AP mode, so use the recorded TX rate of the last sent | ||
437 | * frame */ | ||
438 | rrq->value = local->ap->last_tx_rate > 0 ? | ||
439 | local->ap->last_tx_rate * 100000 : 11000000; | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < | ||
444 | 0) | ||
445 | return -EINVAL; | ||
446 | |||
447 | switch (val) { | ||
448 | case HFA384X_RATES_1MBPS: | ||
449 | rrq->value = 1000000; | ||
450 | break; | ||
451 | case HFA384X_RATES_2MBPS: | ||
452 | rrq->value = 2000000; | ||
453 | break; | ||
454 | case HFA384X_RATES_5MBPS: | ||
455 | rrq->value = 5500000; | ||
456 | break; | ||
457 | case HFA384X_RATES_11MBPS: | ||
458 | rrq->value = 11000000; | ||
459 | break; | ||
460 | default: | ||
461 | /* should not happen */ | ||
462 | rrq->value = 11000000; | ||
463 | ret = -EINVAL; | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | |||
471 | static int prism2_ioctl_siwsens(struct net_device *dev, | ||
472 | struct iw_request_info *info, | ||
473 | struct iw_param *sens, char *extra) | ||
474 | { | ||
475 | struct hostap_interface *iface; | ||
476 | local_info_t *local; | ||
477 | |||
478 | iface = netdev_priv(dev); | ||
479 | local = iface->local; | ||
480 | |||
481 | /* Set the desired AP density */ | ||
482 | if (sens->value < 1 || sens->value > 3) | ||
483 | return -EINVAL; | ||
484 | |||
485 | if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || | ||
486 | local->func->reset_port(dev)) | ||
487 | return -EINVAL; | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int prism2_ioctl_giwsens(struct net_device *dev, | ||
493 | struct iw_request_info *info, | ||
494 | struct iw_param *sens, char *extra) | ||
495 | { | ||
496 | struct hostap_interface *iface; | ||
497 | local_info_t *local; | ||
498 | u16 val; | ||
499 | |||
500 | iface = netdev_priv(dev); | ||
501 | local = iface->local; | ||
502 | |||
503 | /* Get the current AP density */ | ||
504 | if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < | ||
505 | 0) | ||
506 | return -EINVAL; | ||
507 | |||
508 | sens->value = __le16_to_cpu(val); | ||
509 | sens->fixed = 1; | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | |||
515 | /* Deprecated in new wireless extension API */ | ||
516 | static int prism2_ioctl_giwaplist(struct net_device *dev, | ||
517 | struct iw_request_info *info, | ||
518 | struct iw_point *data, char *extra) | ||
519 | { | ||
520 | struct hostap_interface *iface; | ||
521 | local_info_t *local; | ||
522 | struct sockaddr *addr; | ||
523 | struct iw_quality *qual; | ||
524 | |||
525 | iface = netdev_priv(dev); | ||
526 | local = iface->local; | ||
527 | |||
528 | if (local->iw_mode != IW_MODE_MASTER) { | ||
529 | printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " | ||
530 | "in Host AP mode\n"); | ||
531 | data->length = 0; | ||
532 | return -EOPNOTSUPP; | ||
533 | } | ||
534 | |||
535 | addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL); | ||
536 | qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL); | ||
537 | if (addr == NULL || qual == NULL) { | ||
538 | kfree(addr); | ||
539 | kfree(qual); | ||
540 | data->length = 0; | ||
541 | return -ENOMEM; | ||
542 | } | ||
543 | |||
544 | data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); | ||
545 | |||
546 | memcpy(extra, &addr, sizeof(struct sockaddr) * data->length); | ||
547 | data->flags = 1; /* has quality information */ | ||
548 | memcpy(extra + sizeof(struct sockaddr) * data->length, &qual, | ||
549 | sizeof(struct iw_quality) * data->length); | ||
550 | |||
551 | kfree(addr); | ||
552 | kfree(qual); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | |||
558 | static int prism2_ioctl_siwrts(struct net_device *dev, | ||
559 | struct iw_request_info *info, | ||
560 | struct iw_param *rts, char *extra) | ||
561 | { | ||
562 | struct hostap_interface *iface; | ||
563 | local_info_t *local; | ||
564 | u16 val; | ||
565 | |||
566 | iface = netdev_priv(dev); | ||
567 | local = iface->local; | ||
568 | |||
569 | if (rts->disabled) | ||
570 | val = __constant_cpu_to_le16(2347); | ||
571 | else if (rts->value < 0 || rts->value > 2347) | ||
572 | return -EINVAL; | ||
573 | else | ||
574 | val = __cpu_to_le16(rts->value); | ||
575 | |||
576 | if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || | ||
577 | local->func->reset_port(dev)) | ||
578 | return -EINVAL; | ||
579 | |||
580 | local->rts_threshold = rts->value; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int prism2_ioctl_giwrts(struct net_device *dev, | ||
586 | struct iw_request_info *info, | ||
587 | struct iw_param *rts, char *extra) | ||
588 | { | ||
589 | struct hostap_interface *iface; | ||
590 | local_info_t *local; | ||
591 | u16 val; | ||
592 | |||
593 | iface = netdev_priv(dev); | ||
594 | local = iface->local; | ||
595 | |||
596 | if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < | ||
597 | 0) | ||
598 | return -EINVAL; | ||
599 | |||
600 | rts->value = __le16_to_cpu(val); | ||
601 | rts->disabled = (rts->value == 2347); | ||
602 | rts->fixed = 1; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | |||
608 | static int prism2_ioctl_siwfrag(struct net_device *dev, | ||
609 | struct iw_request_info *info, | ||
610 | struct iw_param *rts, char *extra) | ||
611 | { | ||
612 | struct hostap_interface *iface; | ||
613 | local_info_t *local; | ||
614 | u16 val; | ||
615 | |||
616 | iface = netdev_priv(dev); | ||
617 | local = iface->local; | ||
618 | |||
619 | if (rts->disabled) | ||
620 | val = __constant_cpu_to_le16(2346); | ||
621 | else if (rts->value < 256 || rts->value > 2346) | ||
622 | return -EINVAL; | ||
623 | else | ||
624 | val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ | ||
625 | |||
626 | local->fragm_threshold = rts->value & ~0x1; | ||
627 | if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, | ||
628 | 2) | ||
629 | || local->func->reset_port(dev)) | ||
630 | return -EINVAL; | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static int prism2_ioctl_giwfrag(struct net_device *dev, | ||
636 | struct iw_request_info *info, | ||
637 | struct iw_param *rts, char *extra) | ||
638 | { | ||
639 | struct hostap_interface *iface; | ||
640 | local_info_t *local; | ||
641 | u16 val; | ||
642 | |||
643 | iface = netdev_priv(dev); | ||
644 | local = iface->local; | ||
645 | |||
646 | if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
647 | &val, 2, 1) < 0) | ||
648 | return -EINVAL; | ||
649 | |||
650 | rts->value = __le16_to_cpu(val); | ||
651 | rts->disabled = (rts->value == 2346); | ||
652 | rts->fixed = 1; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | |||
658 | #ifndef PRISM2_NO_STATION_MODES | ||
659 | static int hostap_join_ap(struct net_device *dev) | ||
660 | { | ||
661 | struct hostap_interface *iface; | ||
662 | local_info_t *local; | ||
663 | struct hfa384x_join_request req; | ||
664 | unsigned long flags; | ||
665 | int i; | ||
666 | struct hfa384x_scan_result *entry; | ||
667 | |||
668 | iface = netdev_priv(dev); | ||
669 | local = iface->local; | ||
670 | |||
671 | memcpy(req.bssid, local->preferred_ap, ETH_ALEN); | ||
672 | req.channel = 0; | ||
673 | |||
674 | spin_lock_irqsave(&local->lock, flags); | ||
675 | for (i = 0; i < local->last_scan_results_count; i++) { | ||
676 | if (!local->last_scan_results) | ||
677 | break; | ||
678 | entry = &local->last_scan_results[i]; | ||
679 | if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) { | ||
680 | req.channel = entry->chid; | ||
681 | break; | ||
682 | } | ||
683 | } | ||
684 | spin_unlock_irqrestore(&local->lock, flags); | ||
685 | |||
686 | if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, | ||
687 | sizeof(req))) { | ||
688 | printk(KERN_DEBUG "%s: JoinRequest " MACSTR | ||
689 | " failed\n", | ||
690 | dev->name, MAC2STR(local->preferred_ap)); | ||
691 | return -1; | ||
692 | } | ||
693 | |||
694 | printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", | ||
695 | dev->name, MAC2STR(local->preferred_ap)); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | #endif /* PRISM2_NO_STATION_MODES */ | ||
700 | |||
701 | |||
702 | static int prism2_ioctl_siwap(struct net_device *dev, | ||
703 | struct iw_request_info *info, | ||
704 | struct sockaddr *ap_addr, char *extra) | ||
705 | { | ||
706 | #ifdef PRISM2_NO_STATION_MODES | ||
707 | return -EOPNOTSUPP; | ||
708 | #else /* PRISM2_NO_STATION_MODES */ | ||
709 | struct hostap_interface *iface; | ||
710 | local_info_t *local; | ||
711 | |||
712 | iface = netdev_priv(dev); | ||
713 | local = iface->local; | ||
714 | |||
715 | memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); | ||
716 | |||
717 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { | ||
718 | struct hfa384x_scan_request scan_req; | ||
719 | memset(&scan_req, 0, sizeof(scan_req)); | ||
720 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
721 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
722 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, | ||
723 | &scan_req, sizeof(scan_req))) { | ||
724 | printk(KERN_DEBUG "%s: ScanResults request failed - " | ||
725 | "preferred AP delayed to next unsolicited " | ||
726 | "scan\n", dev->name); | ||
727 | } | ||
728 | } else if (local->host_roaming == 2 && | ||
729 | local->iw_mode == IW_MODE_INFRA) { | ||
730 | if (hostap_join_ap(dev)) | ||
731 | return -EINVAL; | ||
732 | } else { | ||
733 | printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " | ||
734 | "in Managed mode when host_roaming is enabled\n", | ||
735 | dev->name); | ||
736 | } | ||
737 | |||
738 | return 0; | ||
739 | #endif /* PRISM2_NO_STATION_MODES */ | ||
740 | } | ||
741 | |||
742 | static int prism2_ioctl_giwap(struct net_device *dev, | ||
743 | struct iw_request_info *info, | ||
744 | struct sockaddr *ap_addr, char *extra) | ||
745 | { | ||
746 | struct hostap_interface *iface; | ||
747 | local_info_t *local; | ||
748 | |||
749 | iface = netdev_priv(dev); | ||
750 | local = iface->local; | ||
751 | |||
752 | ap_addr->sa_family = ARPHRD_ETHER; | ||
753 | switch (iface->type) { | ||
754 | case HOSTAP_INTERFACE_AP: | ||
755 | memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); | ||
756 | break; | ||
757 | case HOSTAP_INTERFACE_STA: | ||
758 | memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); | ||
759 | break; | ||
760 | case HOSTAP_INTERFACE_WDS: | ||
761 | memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); | ||
762 | break; | ||
763 | default: | ||
764 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, | ||
765 | &ap_addr->sa_data, ETH_ALEN, 1) < 0) | ||
766 | return -EOPNOTSUPP; | ||
767 | |||
768 | /* local->bssid is also updated in LinkStatus handler when in | ||
769 | * station mode */ | ||
770 | memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | |||
778 | static int prism2_ioctl_siwnickn(struct net_device *dev, | ||
779 | struct iw_request_info *info, | ||
780 | struct iw_point *data, char *nickname) | ||
781 | { | ||
782 | struct hostap_interface *iface; | ||
783 | local_info_t *local; | ||
784 | |||
785 | iface = netdev_priv(dev); | ||
786 | local = iface->local; | ||
787 | |||
788 | memset(local->name, 0, sizeof(local->name)); | ||
789 | memcpy(local->name, nickname, data->length); | ||
790 | local->name_set = 1; | ||
791 | |||
792 | if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || | ||
793 | local->func->reset_port(dev)) | ||
794 | return -EINVAL; | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | static int prism2_ioctl_giwnickn(struct net_device *dev, | ||
800 | struct iw_request_info *info, | ||
801 | struct iw_point *data, char *nickname) | ||
802 | { | ||
803 | struct hostap_interface *iface; | ||
804 | local_info_t *local; | ||
805 | int len; | ||
806 | char name[MAX_NAME_LEN + 3]; | ||
807 | u16 val; | ||
808 | |||
809 | iface = netdev_priv(dev); | ||
810 | local = iface->local; | ||
811 | |||
812 | len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, | ||
813 | &name, MAX_NAME_LEN + 2, 0); | ||
814 | val = __le16_to_cpu(*(u16 *) name); | ||
815 | if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) | ||
816 | return -EOPNOTSUPP; | ||
817 | |||
818 | name[val + 2] = '\0'; | ||
819 | data->length = val + 1; | ||
820 | memcpy(nickname, name + 2, val + 1); | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | |||
826 | static int prism2_ioctl_siwfreq(struct net_device *dev, | ||
827 | struct iw_request_info *info, | ||
828 | struct iw_freq *freq, char *extra) | ||
829 | { | ||
830 | struct hostap_interface *iface; | ||
831 | local_info_t *local; | ||
832 | |||
833 | iface = netdev_priv(dev); | ||
834 | local = iface->local; | ||
835 | |||
836 | /* freq => chan. */ | ||
837 | if (freq->e == 1 && | ||
838 | freq->m / 100000 >= freq_list[0] && | ||
839 | freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { | ||
840 | int ch; | ||
841 | int fr = freq->m / 100000; | ||
842 | for (ch = 0; ch < FREQ_COUNT; ch++) { | ||
843 | if (fr == freq_list[ch]) { | ||
844 | freq->e = 0; | ||
845 | freq->m = ch + 1; | ||
846 | break; | ||
847 | } | ||
848 | } | ||
849 | } | ||
850 | |||
851 | if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || | ||
852 | !(local->channel_mask & (1 << (freq->m - 1)))) | ||
853 | return -EINVAL; | ||
854 | |||
855 | local->channel = freq->m; /* channel is used in prism2_setup_rids() */ | ||
856 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || | ||
857 | local->func->reset_port(dev)) | ||
858 | return -EINVAL; | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static int prism2_ioctl_giwfreq(struct net_device *dev, | ||
864 | struct iw_request_info *info, | ||
865 | struct iw_freq *freq, char *extra) | ||
866 | { | ||
867 | struct hostap_interface *iface; | ||
868 | local_info_t *local; | ||
869 | u16 val; | ||
870 | |||
871 | iface = netdev_priv(dev); | ||
872 | local = iface->local; | ||
873 | |||
874 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < | ||
875 | 0) | ||
876 | return -EINVAL; | ||
877 | |||
878 | le16_to_cpus(&val); | ||
879 | if (val < 1 || val > FREQ_COUNT) | ||
880 | return -EINVAL; | ||
881 | |||
882 | freq->m = freq_list[val - 1] * 100000; | ||
883 | freq->e = 1; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | |||
889 | static void hostap_monitor_set_type(local_info_t *local) | ||
890 | { | ||
891 | struct net_device *dev = local->ddev; | ||
892 | |||
893 | if (dev == NULL) | ||
894 | return; | ||
895 | |||
896 | if (local->monitor_type == PRISM2_MONITOR_PRISM || | ||
897 | local->monitor_type == PRISM2_MONITOR_CAPHDR) { | ||
898 | dev->type = ARPHRD_IEEE80211_PRISM; | ||
899 | dev->hard_header_parse = | ||
900 | hostap_80211_prism_header_parse; | ||
901 | } else { | ||
902 | dev->type = ARPHRD_IEEE80211; | ||
903 | dev->hard_header_parse = hostap_80211_header_parse; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | |||
908 | static int prism2_ioctl_siwessid(struct net_device *dev, | ||
909 | struct iw_request_info *info, | ||
910 | struct iw_point *data, char *ssid) | ||
911 | { | ||
912 | struct hostap_interface *iface; | ||
913 | local_info_t *local; | ||
914 | |||
915 | iface = netdev_priv(dev); | ||
916 | local = iface->local; | ||
917 | |||
918 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
919 | return -EOPNOTSUPP; | ||
920 | |||
921 | if (data->flags == 0) | ||
922 | ssid[0] = '\0'; /* ANY */ | ||
923 | |||
924 | if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { | ||
925 | /* Setting SSID to empty string seems to kill the card in | ||
926 | * Host AP mode */ | ||
927 | printk(KERN_DEBUG "%s: Host AP mode does not support " | ||
928 | "'Any' essid\n", dev->name); | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | memcpy(local->essid, ssid, data->length); | ||
933 | local->essid[data->length] = '\0'; | ||
934 | |||
935 | if ((!local->fw_ap && | ||
936 | hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) | ||
937 | || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || | ||
938 | local->func->reset_port(dev)) | ||
939 | return -EINVAL; | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int prism2_ioctl_giwessid(struct net_device *dev, | ||
945 | struct iw_request_info *info, | ||
946 | struct iw_point *data, char *essid) | ||
947 | { | ||
948 | struct hostap_interface *iface; | ||
949 | local_info_t *local; | ||
950 | u16 val; | ||
951 | |||
952 | iface = netdev_priv(dev); | ||
953 | local = iface->local; | ||
954 | |||
955 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
956 | return -EOPNOTSUPP; | ||
957 | |||
958 | data->flags = 1; /* active */ | ||
959 | if (local->iw_mode == IW_MODE_MASTER) { | ||
960 | data->length = strlen(local->essid); | ||
961 | memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); | ||
962 | } else { | ||
963 | int len; | ||
964 | char ssid[MAX_SSID_LEN + 2]; | ||
965 | memset(ssid, 0, sizeof(ssid)); | ||
966 | len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, | ||
967 | &ssid, MAX_SSID_LEN + 2, 0); | ||
968 | val = __le16_to_cpu(*(u16 *) ssid); | ||
969 | if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { | ||
970 | return -EOPNOTSUPP; | ||
971 | } | ||
972 | data->length = val; | ||
973 | memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); | ||
974 | } | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | |||
980 | static int prism2_ioctl_giwrange(struct net_device *dev, | ||
981 | struct iw_request_info *info, | ||
982 | struct iw_point *data, char *extra) | ||
983 | { | ||
984 | struct hostap_interface *iface; | ||
985 | local_info_t *local; | ||
986 | struct iw_range *range = (struct iw_range *) extra; | ||
987 | u8 rates[10]; | ||
988 | u16 val; | ||
989 | int i, len, over2; | ||
990 | |||
991 | iface = netdev_priv(dev); | ||
992 | local = iface->local; | ||
993 | |||
994 | data->length = sizeof(struct iw_range); | ||
995 | memset(range, 0, sizeof(struct iw_range)); | ||
996 | |||
997 | /* TODO: could fill num_txpower and txpower array with | ||
998 | * something; however, there are 128 different values.. */ | ||
999 | |||
1000 | range->txpower_capa = IW_TXPOW_DBM; | ||
1001 | |||
1002 | if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) | ||
1003 | { | ||
1004 | range->min_pmp = 1 * 1024; | ||
1005 | range->max_pmp = 65535 * 1024; | ||
1006 | range->min_pmt = 1 * 1024; | ||
1007 | range->max_pmt = 1000 * 1024; | ||
1008 | range->pmp_flags = IW_POWER_PERIOD; | ||
1009 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
1010 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | | ||
1011 | IW_POWER_UNICAST_R | IW_POWER_ALL_R; | ||
1012 | } | ||
1013 | |||
1014 | range->we_version_compiled = WIRELESS_EXT; | ||
1015 | range->we_version_source = 18; | ||
1016 | |||
1017 | range->retry_capa = IW_RETRY_LIMIT; | ||
1018 | range->retry_flags = IW_RETRY_LIMIT; | ||
1019 | range->min_retry = 0; | ||
1020 | range->max_retry = 255; | ||
1021 | |||
1022 | range->num_channels = FREQ_COUNT; | ||
1023 | |||
1024 | val = 0; | ||
1025 | for (i = 0; i < FREQ_COUNT; i++) { | ||
1026 | if (local->channel_mask & (1 << i)) { | ||
1027 | range->freq[val].i = i + 1; | ||
1028 | range->freq[val].m = freq_list[i] * 100000; | ||
1029 | range->freq[val].e = 1; | ||
1030 | val++; | ||
1031 | } | ||
1032 | if (val == IW_MAX_FREQUENCIES) | ||
1033 | break; | ||
1034 | } | ||
1035 | range->num_frequency = val; | ||
1036 | |||
1037 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1038 | range->max_qual.qual = 70; /* what is correct max? This was not | ||
1039 | * documented exactly. At least | ||
1040 | * 69 has been observed. */ | ||
1041 | range->max_qual.level = 0; /* dB */ | ||
1042 | range->max_qual.noise = 0; /* dB */ | ||
1043 | |||
1044 | /* What would be suitable values for "average/typical" qual? */ | ||
1045 | range->avg_qual.qual = 20; | ||
1046 | range->avg_qual.level = -60; | ||
1047 | range->avg_qual.noise = -95; | ||
1048 | } else { | ||
1049 | range->max_qual.qual = 92; /* 0 .. 92 */ | ||
1050 | range->max_qual.level = 154; /* 27 .. 154 */ | ||
1051 | range->max_qual.noise = 154; /* 27 .. 154 */ | ||
1052 | } | ||
1053 | range->sensitivity = 3; | ||
1054 | |||
1055 | range->max_encoding_tokens = WEP_KEYS; | ||
1056 | range->num_encoding_sizes = 2; | ||
1057 | range->encoding_size[0] = 5; | ||
1058 | range->encoding_size[1] = 13; | ||
1059 | |||
1060 | over2 = 0; | ||
1061 | len = prism2_get_datarates(dev, rates); | ||
1062 | range->num_bitrates = 0; | ||
1063 | for (i = 0; i < len; i++) { | ||
1064 | if (range->num_bitrates < IW_MAX_BITRATES) { | ||
1065 | range->bitrate[range->num_bitrates] = | ||
1066 | rates[i] * 500000; | ||
1067 | range->num_bitrates++; | ||
1068 | } | ||
1069 | if (rates[i] == 0x0b || rates[i] == 0x16) | ||
1070 | over2 = 1; | ||
1071 | } | ||
1072 | /* estimated maximum TCP throughput values (bps) */ | ||
1073 | range->throughput = over2 ? 5500000 : 1500000; | ||
1074 | |||
1075 | range->min_rts = 0; | ||
1076 | range->max_rts = 2347; | ||
1077 | range->min_frag = 256; | ||
1078 | range->max_frag = 2346; | ||
1079 | |||
1080 | /* Event capability (kernel + driver) */ | ||
1081 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
1082 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | ||
1083 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
1084 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
1085 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
1086 | range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | | ||
1087 | IW_EVENT_CAPA_MASK(IWEVCUSTOM) | | ||
1088 | IW_EVENT_CAPA_MASK(IWEVREGISTERED) | | ||
1089 | IW_EVENT_CAPA_MASK(IWEVEXPIRED)); | ||
1090 | |||
1091 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
1092 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
1093 | |||
1094 | return 0; | ||
1095 | } | ||
1096 | |||
1097 | |||
1098 | static int hostap_monitor_mode_enable(local_info_t *local) | ||
1099 | { | ||
1100 | struct net_device *dev = local->dev; | ||
1101 | |||
1102 | printk(KERN_DEBUG "Enabling monitor mode\n"); | ||
1103 | hostap_monitor_set_type(local); | ||
1104 | |||
1105 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1106 | HFA384X_PORTTYPE_PSEUDO_IBSS)) { | ||
1107 | printk(KERN_DEBUG "Port type setting for monitor mode " | ||
1108 | "failed\n"); | ||
1109 | return -EOPNOTSUPP; | ||
1110 | } | ||
1111 | |||
1112 | /* Host decrypt is needed to get the IV and ICV fields; | ||
1113 | * however, monitor mode seems to remove WEP flag from frame | ||
1114 | * control field */ | ||
1115 | if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, | ||
1116 | HFA384X_WEPFLAGS_HOSTENCRYPT | | ||
1117 | HFA384X_WEPFLAGS_HOSTDECRYPT)) { | ||
1118 | printk(KERN_DEBUG "WEP flags setting failed\n"); | ||
1119 | return -EOPNOTSUPP; | ||
1120 | } | ||
1121 | |||
1122 | if (local->func->reset_port(dev) || | ||
1123 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1124 | (HFA384X_TEST_MONITOR << 8), | ||
1125 | 0, NULL, NULL)) { | ||
1126 | printk(KERN_DEBUG "Setting monitor mode failed\n"); | ||
1127 | return -EOPNOTSUPP; | ||
1128 | } | ||
1129 | |||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | static int hostap_monitor_mode_disable(local_info_t *local) | ||
1135 | { | ||
1136 | struct net_device *dev = local->ddev; | ||
1137 | |||
1138 | if (dev == NULL) | ||
1139 | return -1; | ||
1140 | |||
1141 | printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); | ||
1142 | dev->type = ARPHRD_ETHER; | ||
1143 | dev->hard_header_parse = local->saved_eth_header_parse; | ||
1144 | if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1145 | (HFA384X_TEST_STOP << 8), | ||
1146 | 0, NULL, NULL)) | ||
1147 | return -1; | ||
1148 | return hostap_set_encryption(local); | ||
1149 | } | ||
1150 | |||
1151 | |||
1152 | static int prism2_ioctl_siwmode(struct net_device *dev, | ||
1153 | struct iw_request_info *info, | ||
1154 | __u32 *mode, char *extra) | ||
1155 | { | ||
1156 | struct hostap_interface *iface; | ||
1157 | local_info_t *local; | ||
1158 | int double_reset = 0; | ||
1159 | |||
1160 | iface = netdev_priv(dev); | ||
1161 | local = iface->local; | ||
1162 | |||
1163 | if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && | ||
1164 | *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && | ||
1165 | *mode != IW_MODE_MONITOR) | ||
1166 | return -EOPNOTSUPP; | ||
1167 | |||
1168 | #ifdef PRISM2_NO_STATION_MODES | ||
1169 | if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) | ||
1170 | return -EOPNOTSUPP; | ||
1171 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1172 | |||
1173 | if (*mode == local->iw_mode) | ||
1174 | return 0; | ||
1175 | |||
1176 | if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { | ||
1177 | printk(KERN_WARNING "%s: empty SSID not allowed in Master " | ||
1178 | "mode\n", dev->name); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | |||
1182 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1183 | hostap_monitor_mode_disable(local); | ||
1184 | |||
1185 | if (local->iw_mode == IW_MODE_ADHOC && *mode == IW_MODE_MASTER) { | ||
1186 | /* There seems to be a firmware bug in at least STA f/w v1.5.6 | ||
1187 | * that leaves beacon frames to use IBSS type when moving from | ||
1188 | * IBSS to Host AP mode. Doing double Port0 reset seems to be | ||
1189 | * enough to workaround this. */ | ||
1190 | double_reset = 1; | ||
1191 | } | ||
1192 | |||
1193 | printk(KERN_DEBUG "prism2: %s: operating mode changed " | ||
1194 | "%d -> %d\n", dev->name, local->iw_mode, *mode); | ||
1195 | local->iw_mode = *mode; | ||
1196 | |||
1197 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1198 | hostap_monitor_mode_enable(local); | ||
1199 | else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
1200 | !local->fw_encrypt_ok) { | ||
1201 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
1202 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
1203 | dev->name); | ||
1204 | local->host_encrypt = 1; | ||
1205 | } | ||
1206 | |||
1207 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1208 | hostap_get_porttype(local))) | ||
1209 | return -EOPNOTSUPP; | ||
1210 | |||
1211 | if (local->func->reset_port(dev)) | ||
1212 | return -EINVAL; | ||
1213 | if (double_reset && local->func->reset_port(dev)) | ||
1214 | return -EINVAL; | ||
1215 | |||
1216 | if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) | ||
1217 | { | ||
1218 | /* netif_carrier is used only in client modes for now, so make | ||
1219 | * sure carrier is on when moving to non-client modes. */ | ||
1220 | netif_carrier_on(local->dev); | ||
1221 | netif_carrier_on(local->ddev); | ||
1222 | } | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1226 | |||
1227 | static int prism2_ioctl_giwmode(struct net_device *dev, | ||
1228 | struct iw_request_info *info, | ||
1229 | __u32 *mode, char *extra) | ||
1230 | { | ||
1231 | struct hostap_interface *iface; | ||
1232 | local_info_t *local; | ||
1233 | |||
1234 | iface = netdev_priv(dev); | ||
1235 | local = iface->local; | ||
1236 | |||
1237 | switch (iface->type) { | ||
1238 | case HOSTAP_INTERFACE_STA: | ||
1239 | *mode = IW_MODE_INFRA; | ||
1240 | break; | ||
1241 | case HOSTAP_INTERFACE_WDS: | ||
1242 | *mode = IW_MODE_REPEAT; | ||
1243 | break; | ||
1244 | default: | ||
1245 | *mode = local->iw_mode; | ||
1246 | break; | ||
1247 | } | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | static int prism2_ioctl_siwpower(struct net_device *dev, | ||
1253 | struct iw_request_info *info, | ||
1254 | struct iw_param *wrq, char *extra) | ||
1255 | { | ||
1256 | #ifdef PRISM2_NO_STATION_MODES | ||
1257 | return -EOPNOTSUPP; | ||
1258 | #else /* PRISM2_NO_STATION_MODES */ | ||
1259 | int ret = 0; | ||
1260 | |||
1261 | if (wrq->disabled) | ||
1262 | return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); | ||
1263 | |||
1264 | switch (wrq->flags & IW_POWER_MODE) { | ||
1265 | case IW_POWER_UNICAST_R: | ||
1266 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); | ||
1267 | if (ret) | ||
1268 | return ret; | ||
1269 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1270 | if (ret) | ||
1271 | return ret; | ||
1272 | break; | ||
1273 | case IW_POWER_ALL_R: | ||
1274 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); | ||
1275 | if (ret) | ||
1276 | return ret; | ||
1277 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1278 | if (ret) | ||
1279 | return ret; | ||
1280 | break; | ||
1281 | case IW_POWER_ON: | ||
1282 | break; | ||
1283 | default: | ||
1284 | return -EINVAL; | ||
1285 | } | ||
1286 | |||
1287 | if (wrq->flags & IW_POWER_TIMEOUT) { | ||
1288 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1289 | if (ret) | ||
1290 | return ret; | ||
1291 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1292 | wrq->value / 1024); | ||
1293 | if (ret) | ||
1294 | return ret; | ||
1295 | } | ||
1296 | if (wrq->flags & IW_POWER_PERIOD) { | ||
1297 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1298 | if (ret) | ||
1299 | return ret; | ||
1300 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1301 | wrq->value / 1024); | ||
1302 | if (ret) | ||
1303 | return ret; | ||
1304 | } | ||
1305 | |||
1306 | return ret; | ||
1307 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1308 | } | ||
1309 | |||
1310 | |||
1311 | static int prism2_ioctl_giwpower(struct net_device *dev, | ||
1312 | struct iw_request_info *info, | ||
1313 | struct iw_param *rrq, char *extra) | ||
1314 | { | ||
1315 | #ifdef PRISM2_NO_STATION_MODES | ||
1316 | return -EOPNOTSUPP; | ||
1317 | #else /* PRISM2_NO_STATION_MODES */ | ||
1318 | struct hostap_interface *iface; | ||
1319 | local_info_t *local; | ||
1320 | u16 enable, mcast; | ||
1321 | |||
1322 | iface = netdev_priv(dev); | ||
1323 | local = iface->local; | ||
1324 | |||
1325 | if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) | ||
1326 | < 0) | ||
1327 | return -EINVAL; | ||
1328 | |||
1329 | if (!__le16_to_cpu(enable)) { | ||
1330 | rrq->disabled = 1; | ||
1331 | return 0; | ||
1332 | } | ||
1333 | |||
1334 | rrq->disabled = 0; | ||
1335 | |||
1336 | if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
1337 | u16 timeout; | ||
1338 | if (local->func->get_rid(dev, | ||
1339 | HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1340 | &timeout, 2, 1) < 0) | ||
1341 | return -EINVAL; | ||
1342 | |||
1343 | rrq->flags = IW_POWER_TIMEOUT; | ||
1344 | rrq->value = __le16_to_cpu(timeout) * 1024; | ||
1345 | } else { | ||
1346 | u16 period; | ||
1347 | if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1348 | &period, 2, 1) < 0) | ||
1349 | return -EINVAL; | ||
1350 | |||
1351 | rrq->flags = IW_POWER_PERIOD; | ||
1352 | rrq->value = __le16_to_cpu(period) * 1024; | ||
1353 | } | ||
1354 | |||
1355 | if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, | ||
1356 | 2, 1) < 0) | ||
1357 | return -EINVAL; | ||
1358 | |||
1359 | if (__le16_to_cpu(mcast)) | ||
1360 | rrq->flags |= IW_POWER_ALL_R; | ||
1361 | else | ||
1362 | rrq->flags |= IW_POWER_UNICAST_R; | ||
1363 | |||
1364 | return 0; | ||
1365 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1366 | } | ||
1367 | |||
1368 | |||
1369 | static int prism2_ioctl_siwretry(struct net_device *dev, | ||
1370 | struct iw_request_info *info, | ||
1371 | struct iw_param *rrq, char *extra) | ||
1372 | { | ||
1373 | struct hostap_interface *iface; | ||
1374 | local_info_t *local; | ||
1375 | |||
1376 | iface = netdev_priv(dev); | ||
1377 | local = iface->local; | ||
1378 | |||
1379 | if (rrq->disabled) | ||
1380 | return -EINVAL; | ||
1381 | |||
1382 | /* setting retry limits is not supported with the current station | ||
1383 | * firmware code; simulate this with alternative retry count for now */ | ||
1384 | if (rrq->flags == IW_RETRY_LIMIT) { | ||
1385 | if (rrq->value < 0) { | ||
1386 | /* disable manual retry count setting and use firmware | ||
1387 | * defaults */ | ||
1388 | local->manual_retry_count = -1; | ||
1389 | local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; | ||
1390 | } else { | ||
1391 | if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1392 | rrq->value)) { | ||
1393 | printk(KERN_DEBUG "%s: Alternate retry count " | ||
1394 | "setting to %d failed\n", | ||
1395 | dev->name, rrq->value); | ||
1396 | return -EOPNOTSUPP; | ||
1397 | } | ||
1398 | |||
1399 | local->manual_retry_count = rrq->value; | ||
1400 | local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; | ||
1401 | } | ||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | return -EOPNOTSUPP; | ||
1406 | |||
1407 | #if 0 | ||
1408 | /* what could be done, if firmware would support this.. */ | ||
1409 | |||
1410 | if (rrq->flags & IW_RETRY_LIMIT) { | ||
1411 | if (rrq->flags & IW_RETRY_MAX) | ||
1412 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1413 | else if (rrq->flags & IW_RETRY_MIN) | ||
1414 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1415 | else { | ||
1416 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1417 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1418 | } | ||
1419 | |||
1420 | } | ||
1421 | |||
1422 | if (rrq->flags & IW_RETRY_LIFETIME) { | ||
1423 | HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; | ||
1424 | } | ||
1425 | |||
1426 | return 0; | ||
1427 | #endif /* 0 */ | ||
1428 | } | ||
1429 | |||
1430 | static int prism2_ioctl_giwretry(struct net_device *dev, | ||
1431 | struct iw_request_info *info, | ||
1432 | struct iw_param *rrq, char *extra) | ||
1433 | { | ||
1434 | struct hostap_interface *iface; | ||
1435 | local_info_t *local; | ||
1436 | u16 shortretry, longretry, lifetime, altretry; | ||
1437 | |||
1438 | iface = netdev_priv(dev); | ||
1439 | local = iface->local; | ||
1440 | |||
1441 | if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, | ||
1442 | 2, 1) < 0 || | ||
1443 | local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, | ||
1444 | 2, 1) < 0 || | ||
1445 | local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, | ||
1446 | &lifetime, 2, 1) < 0) | ||
1447 | return -EINVAL; | ||
1448 | |||
1449 | le16_to_cpus(&shortretry); | ||
1450 | le16_to_cpus(&longretry); | ||
1451 | le16_to_cpus(&lifetime); | ||
1452 | |||
1453 | rrq->disabled = 0; | ||
1454 | |||
1455 | if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
1456 | rrq->flags = IW_RETRY_LIFETIME; | ||
1457 | rrq->value = lifetime * 1024; | ||
1458 | } else { | ||
1459 | if (local->manual_retry_count >= 0) { | ||
1460 | rrq->flags = IW_RETRY_LIMIT; | ||
1461 | if (local->func->get_rid(dev, | ||
1462 | HFA384X_RID_CNFALTRETRYCOUNT, | ||
1463 | &altretry, 2, 1) >= 0) | ||
1464 | rrq->value = le16_to_cpu(altretry); | ||
1465 | else | ||
1466 | rrq->value = local->manual_retry_count; | ||
1467 | } else if ((rrq->flags & IW_RETRY_MAX)) { | ||
1468 | rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1469 | rrq->value = longretry; | ||
1470 | } else { | ||
1471 | rrq->flags = IW_RETRY_LIMIT; | ||
1472 | rrq->value = shortretry; | ||
1473 | if (shortretry != longretry) | ||
1474 | rrq->flags |= IW_RETRY_MIN; | ||
1475 | } | ||
1476 | } | ||
1477 | return 0; | ||
1478 | } | ||
1479 | |||
1480 | |||
1481 | /* Note! This TX power controlling is experimental and should not be used in | ||
1482 | * production use. It just sets raw power register and does not use any kind of | ||
1483 | * feedback information from the measured TX power (CR58). This is now | ||
1484 | * commented out to make sure that it is not used by accident. TX power | ||
1485 | * configuration will be enabled again after proper algorithm using feedback | ||
1486 | * has been implemented. */ | ||
1487 | |||
1488 | #ifdef RAW_TXPOWER_SETTING | ||
1489 | /* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. | ||
1490 | * This version assumes following mapping: | ||
1491 | * CR31 is 7-bit value with -64 to +63 range. | ||
1492 | * -64 is mapped into +20dBm and +63 into -43dBm. | ||
1493 | * This is certainly not an exact mapping for every card, but at least | ||
1494 | * increasing dBm value should correspond to increasing TX power. | ||
1495 | */ | ||
1496 | |||
1497 | static int prism2_txpower_hfa386x_to_dBm(u16 val) | ||
1498 | { | ||
1499 | signed char tmp; | ||
1500 | |||
1501 | if (val > 255) | ||
1502 | val = 255; | ||
1503 | |||
1504 | tmp = val; | ||
1505 | tmp >>= 2; | ||
1506 | |||
1507 | return -12 - tmp; | ||
1508 | } | ||
1509 | |||
1510 | static u16 prism2_txpower_dBm_to_hfa386x(int val) | ||
1511 | { | ||
1512 | signed char tmp; | ||
1513 | |||
1514 | if (val > 20) | ||
1515 | return 128; | ||
1516 | else if (val < -43) | ||
1517 | return 127; | ||
1518 | |||
1519 | tmp = val; | ||
1520 | tmp = -12 - tmp; | ||
1521 | tmp <<= 2; | ||
1522 | |||
1523 | return (unsigned char) tmp; | ||
1524 | } | ||
1525 | #endif /* RAW_TXPOWER_SETTING */ | ||
1526 | |||
1527 | |||
1528 | static int prism2_ioctl_siwtxpow(struct net_device *dev, | ||
1529 | struct iw_request_info *info, | ||
1530 | struct iw_param *rrq, char *extra) | ||
1531 | { | ||
1532 | struct hostap_interface *iface; | ||
1533 | local_info_t *local; | ||
1534 | #ifdef RAW_TXPOWER_SETTING | ||
1535 | char *tmp; | ||
1536 | #endif | ||
1537 | u16 val; | ||
1538 | int ret = 0; | ||
1539 | |||
1540 | iface = netdev_priv(dev); | ||
1541 | local = iface->local; | ||
1542 | |||
1543 | if (rrq->disabled) { | ||
1544 | if (local->txpower_type != PRISM2_TXPOWER_OFF) { | ||
1545 | val = 0xff; /* use all standby and sleep modes */ | ||
1546 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1547 | HFA386X_CR_A_D_TEST_MODES2, | ||
1548 | &val, NULL); | ||
1549 | printk(KERN_DEBUG "%s: Turning radio off: %s\n", | ||
1550 | dev->name, ret ? "failed" : "OK"); | ||
1551 | local->txpower_type = PRISM2_TXPOWER_OFF; | ||
1552 | } | ||
1553 | return (ret ? -EOPNOTSUPP : 0); | ||
1554 | } | ||
1555 | |||
1556 | if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1557 | val = 0; /* disable all standby and sleep modes */ | ||
1558 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1559 | HFA386X_CR_A_D_TEST_MODES2, &val, NULL); | ||
1560 | printk(KERN_DEBUG "%s: Turning radio on: %s\n", | ||
1561 | dev->name, ret ? "failed" : "OK"); | ||
1562 | local->txpower_type = PRISM2_TXPOWER_UNKNOWN; | ||
1563 | } | ||
1564 | |||
1565 | #ifdef RAW_TXPOWER_SETTING | ||
1566 | if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { | ||
1567 | printk(KERN_DEBUG "Setting ALC on\n"); | ||
1568 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1569 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1570 | (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); | ||
1571 | local->txpower_type = PRISM2_TXPOWER_AUTO; | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | if (local->txpower_type != PRISM2_TXPOWER_FIXED) { | ||
1576 | printk(KERN_DEBUG "Setting ALC off\n"); | ||
1577 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1578 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1579 | (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); | ||
1580 | local->txpower_type = PRISM2_TXPOWER_FIXED; | ||
1581 | } | ||
1582 | |||
1583 | if (rrq->flags == IW_TXPOW_DBM) | ||
1584 | tmp = "dBm"; | ||
1585 | else if (rrq->flags == IW_TXPOW_MWATT) | ||
1586 | tmp = "mW"; | ||
1587 | else | ||
1588 | tmp = "UNKNOWN"; | ||
1589 | printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); | ||
1590 | |||
1591 | if (rrq->flags != IW_TXPOW_DBM) { | ||
1592 | printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); | ||
1593 | return -EOPNOTSUPP; | ||
1594 | } | ||
1595 | |||
1596 | local->txpower = rrq->value; | ||
1597 | val = prism2_txpower_dBm_to_hfa386x(local->txpower); | ||
1598 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1599 | HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) | ||
1600 | ret = -EOPNOTSUPP; | ||
1601 | #else /* RAW_TXPOWER_SETTING */ | ||
1602 | if (rrq->fixed) | ||
1603 | ret = -EOPNOTSUPP; | ||
1604 | #endif /* RAW_TXPOWER_SETTING */ | ||
1605 | |||
1606 | return ret; | ||
1607 | } | ||
1608 | |||
1609 | static int prism2_ioctl_giwtxpow(struct net_device *dev, | ||
1610 | struct iw_request_info *info, | ||
1611 | struct iw_param *rrq, char *extra) | ||
1612 | { | ||
1613 | #ifdef RAW_TXPOWER_SETTING | ||
1614 | struct hostap_interface *iface; | ||
1615 | local_info_t *local; | ||
1616 | u16 resp0; | ||
1617 | |||
1618 | iface = netdev_priv(dev); | ||
1619 | local = iface->local; | ||
1620 | |||
1621 | rrq->flags = IW_TXPOW_DBM; | ||
1622 | rrq->disabled = 0; | ||
1623 | rrq->fixed = 0; | ||
1624 | |||
1625 | if (local->txpower_type == PRISM2_TXPOWER_AUTO) { | ||
1626 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, | ||
1627 | HFA386X_CR_MANUAL_TX_POWER, | ||
1628 | NULL, &resp0) == 0) { | ||
1629 | rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); | ||
1630 | } else { | ||
1631 | /* Could not get real txpower; guess 15 dBm */ | ||
1632 | rrq->value = 15; | ||
1633 | } | ||
1634 | } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1635 | rrq->value = 0; | ||
1636 | rrq->disabled = 1; | ||
1637 | } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { | ||
1638 | rrq->value = local->txpower; | ||
1639 | rrq->fixed = 1; | ||
1640 | } else { | ||
1641 | printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", | ||
1642 | local->txpower_type); | ||
1643 | } | ||
1644 | return 0; | ||
1645 | #else /* RAW_TXPOWER_SETTING */ | ||
1646 | return -EOPNOTSUPP; | ||
1647 | #endif /* RAW_TXPOWER_SETTING */ | ||
1648 | } | ||
1649 | |||
1650 | |||
1651 | #ifndef PRISM2_NO_STATION_MODES | ||
1652 | |||
1653 | /* HostScan request works with and without host_roaming mode. In addition, it | ||
1654 | * does not break current association. However, it requires newer station | ||
1655 | * firmware version (>= 1.3.1) than scan request. */ | ||
1656 | static int prism2_request_hostscan(struct net_device *dev, | ||
1657 | u8 *ssid, u8 ssid_len) | ||
1658 | { | ||
1659 | struct hostap_interface *iface; | ||
1660 | local_info_t *local; | ||
1661 | struct hfa384x_hostscan_request scan_req; | ||
1662 | |||
1663 | iface = netdev_priv(dev); | ||
1664 | local = iface->local; | ||
1665 | |||
1666 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1667 | scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask); | ||
1668 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1669 | if (ssid) { | ||
1670 | if (ssid_len > 32) | ||
1671 | return -EINVAL; | ||
1672 | scan_req.target_ssid_len = cpu_to_le16(ssid_len); | ||
1673 | memcpy(scan_req.target_ssid, ssid, ssid_len); | ||
1674 | } | ||
1675 | |||
1676 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
1677 | sizeof(scan_req))) { | ||
1678 | printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); | ||
1679 | return -EINVAL; | ||
1680 | } | ||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1684 | |||
1685 | static int prism2_request_scan(struct net_device *dev) | ||
1686 | { | ||
1687 | struct hostap_interface *iface; | ||
1688 | local_info_t *local; | ||
1689 | struct hfa384x_scan_request scan_req; | ||
1690 | int ret = 0; | ||
1691 | |||
1692 | iface = netdev_priv(dev); | ||
1693 | local = iface->local; | ||
1694 | |||
1695 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1696 | scan_req.channel_list = __constant_cpu_to_le16(local->channel_mask); | ||
1697 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1698 | |||
1699 | /* FIX: | ||
1700 | * It seems to be enough to set roaming mode for a short moment to | ||
1701 | * host-based and then setup scanrequest data and return the mode to | ||
1702 | * firmware-based. | ||
1703 | * | ||
1704 | * Master mode would need to drop to Managed mode for a short while | ||
1705 | * to make scanning work.. Or sweep through the different channels and | ||
1706 | * use passive scan based on beacons. */ | ||
1707 | |||
1708 | if (!local->host_roaming) | ||
1709 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1710 | HFA384X_ROAMING_HOST); | ||
1711 | |||
1712 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, | ||
1713 | sizeof(scan_req))) { | ||
1714 | printk(KERN_DEBUG "SCANREQUEST failed\n"); | ||
1715 | ret = -EINVAL; | ||
1716 | } | ||
1717 | |||
1718 | if (!local->host_roaming) | ||
1719 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1720 | HFA384X_ROAMING_FIRMWARE); | ||
1721 | |||
1722 | return 0; | ||
1723 | } | ||
1724 | |||
1725 | #else /* !PRISM2_NO_STATION_MODES */ | ||
1726 | |||
1727 | static inline int prism2_request_hostscan(struct net_device *dev, | ||
1728 | u8 *ssid, u8 ssid_len) | ||
1729 | { | ||
1730 | return -EOPNOTSUPP; | ||
1731 | } | ||
1732 | |||
1733 | |||
1734 | static inline int prism2_request_scan(struct net_device *dev) | ||
1735 | { | ||
1736 | return -EOPNOTSUPP; | ||
1737 | } | ||
1738 | |||
1739 | #endif /* !PRISM2_NO_STATION_MODES */ | ||
1740 | |||
1741 | |||
1742 | static int prism2_ioctl_siwscan(struct net_device *dev, | ||
1743 | struct iw_request_info *info, | ||
1744 | struct iw_point *data, char *extra) | ||
1745 | { | ||
1746 | struct hostap_interface *iface; | ||
1747 | local_info_t *local; | ||
1748 | int ret; | ||
1749 | u8 *ssid = NULL, ssid_len = 0; | ||
1750 | struct iw_scan_req *req = (struct iw_scan_req *) extra; | ||
1751 | |||
1752 | iface = netdev_priv(dev); | ||
1753 | local = iface->local; | ||
1754 | |||
1755 | if (data->length < sizeof(struct iw_scan_req)) | ||
1756 | req = NULL; | ||
1757 | |||
1758 | if (local->iw_mode == IW_MODE_MASTER) { | ||
1759 | /* In master mode, we just return the results of our local | ||
1760 | * tables, so we don't need to start anything... | ||
1761 | * Jean II */ | ||
1762 | data->length = 0; | ||
1763 | return 0; | ||
1764 | } | ||
1765 | |||
1766 | if (!local->dev_enabled) | ||
1767 | return -ENETDOWN; | ||
1768 | |||
1769 | if (req && data->flags & IW_SCAN_THIS_ESSID) { | ||
1770 | ssid = req->essid; | ||
1771 | ssid_len = req->essid_len; | ||
1772 | |||
1773 | if (ssid_len && | ||
1774 | ((local->iw_mode != IW_MODE_INFRA && | ||
1775 | local->iw_mode != IW_MODE_ADHOC) || | ||
1776 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) | ||
1777 | return -EOPNOTSUPP; | ||
1778 | } | ||
1779 | |||
1780 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) | ||
1781 | ret = prism2_request_hostscan(dev, ssid, ssid_len); | ||
1782 | else | ||
1783 | ret = prism2_request_scan(dev); | ||
1784 | |||
1785 | if (ret == 0) | ||
1786 | local->scan_timestamp = jiffies; | ||
1787 | |||
1788 | /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ | ||
1789 | |||
1790 | return ret; | ||
1791 | } | ||
1792 | |||
1793 | |||
1794 | #ifndef PRISM2_NO_STATION_MODES | ||
1795 | static char * __prism2_translate_scan(local_info_t *local, | ||
1796 | struct hfa384x_scan_result *scan, | ||
1797 | struct hfa384x_hostscan_result *hscan, | ||
1798 | int hostscan, | ||
1799 | struct hostap_bss_info *bss, u8 *bssid, | ||
1800 | char *current_ev, char *end_buf) | ||
1801 | { | ||
1802 | int i, chan; | ||
1803 | struct iw_event iwe; | ||
1804 | char *current_val; | ||
1805 | u16 capabilities; | ||
1806 | u8 *pos; | ||
1807 | u8 *ssid; | ||
1808 | size_t ssid_len; | ||
1809 | char *buf; | ||
1810 | |||
1811 | if (bss) { | ||
1812 | ssid = bss->ssid; | ||
1813 | ssid_len = bss->ssid_len; | ||
1814 | } else { | ||
1815 | ssid = hostscan ? hscan->ssid : scan->ssid; | ||
1816 | ssid_len = le16_to_cpu(hostscan ? hscan->ssid_len : | ||
1817 | scan->ssid_len); | ||
1818 | } | ||
1819 | if (ssid_len > 32) | ||
1820 | ssid_len = 32; | ||
1821 | |||
1822 | /* First entry *MUST* be the AP MAC address */ | ||
1823 | memset(&iwe, 0, sizeof(iwe)); | ||
1824 | iwe.cmd = SIOCGIWAP; | ||
1825 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1826 | memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); | ||
1827 | /* FIX: | ||
1828 | * I do not know how this is possible, but iwe_stream_add_event | ||
1829 | * seems to re-order memcpy execution so that len is set only | ||
1830 | * after copying.. Pre-setting len here "fixes" this, but real | ||
1831 | * problems should be solved (after which these iwe.len | ||
1832 | * settings could be removed from this function). */ | ||
1833 | iwe.len = IW_EV_ADDR_LEN; | ||
1834 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1835 | IW_EV_ADDR_LEN); | ||
1836 | |||
1837 | /* Other entries will be displayed in the order we give them */ | ||
1838 | |||
1839 | memset(&iwe, 0, sizeof(iwe)); | ||
1840 | iwe.cmd = SIOCGIWESSID; | ||
1841 | iwe.u.data.length = ssid_len; | ||
1842 | iwe.u.data.flags = 1; | ||
1843 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1844 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); | ||
1845 | |||
1846 | memset(&iwe, 0, sizeof(iwe)); | ||
1847 | iwe.cmd = SIOCGIWMODE; | ||
1848 | if (bss) { | ||
1849 | capabilities = bss->capab_info; | ||
1850 | } else { | ||
1851 | capabilities = le16_to_cpu(hostscan ? hscan->capability : | ||
1852 | scan->capability); | ||
1853 | } | ||
1854 | if (capabilities & (WLAN_CAPABILITY_ESS | | ||
1855 | WLAN_CAPABILITY_IBSS)) { | ||
1856 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
1857 | iwe.u.mode = IW_MODE_MASTER; | ||
1858 | else | ||
1859 | iwe.u.mode = IW_MODE_ADHOC; | ||
1860 | iwe.len = IW_EV_UINT_LEN; | ||
1861 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1862 | IW_EV_UINT_LEN); | ||
1863 | } | ||
1864 | |||
1865 | memset(&iwe, 0, sizeof(iwe)); | ||
1866 | iwe.cmd = SIOCGIWFREQ; | ||
1867 | if (hscan || scan) { | ||
1868 | chan = hostscan ? hscan->chid : scan->chid; | ||
1869 | } else if (bss) { | ||
1870 | chan = bss->chan; | ||
1871 | } else { | ||
1872 | chan = 0; | ||
1873 | } | ||
1874 | |||
1875 | if (chan > 0) { | ||
1876 | iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; | ||
1877 | iwe.u.freq.e = 1; | ||
1878 | iwe.len = IW_EV_FREQ_LEN; | ||
1879 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1880 | IW_EV_FREQ_LEN); | ||
1881 | } | ||
1882 | |||
1883 | if (scan || hscan) { | ||
1884 | memset(&iwe, 0, sizeof(iwe)); | ||
1885 | iwe.cmd = IWEVQUAL; | ||
1886 | if (hostscan) { | ||
1887 | iwe.u.qual.level = le16_to_cpu(hscan->sl); | ||
1888 | iwe.u.qual.noise = le16_to_cpu(hscan->anl); | ||
1889 | } else { | ||
1890 | iwe.u.qual.level = | ||
1891 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); | ||
1892 | iwe.u.qual.noise = | ||
1893 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); | ||
1894 | } | ||
1895 | iwe.len = IW_EV_QUAL_LEN; | ||
1896 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1897 | IW_EV_QUAL_LEN); | ||
1898 | } | ||
1899 | |||
1900 | memset(&iwe, 0, sizeof(iwe)); | ||
1901 | iwe.cmd = SIOCGIWENCODE; | ||
1902 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
1903 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1904 | else | ||
1905 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1906 | iwe.u.data.length = 0; | ||
1907 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1908 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); | ||
1909 | |||
1910 | /* TODO: add SuppRates into BSS table */ | ||
1911 | if (scan || hscan) { | ||
1912 | memset(&iwe, 0, sizeof(iwe)); | ||
1913 | iwe.cmd = SIOCGIWRATE; | ||
1914 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1915 | pos = hostscan ? hscan->sup_rates : scan->sup_rates; | ||
1916 | for (i = 0; i < sizeof(scan->sup_rates); i++) { | ||
1917 | if (pos[i] == 0) | ||
1918 | break; | ||
1919 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1920 | iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); | ||
1921 | current_val = iwe_stream_add_value( | ||
1922 | current_ev, current_val, end_buf, &iwe, | ||
1923 | IW_EV_PARAM_LEN); | ||
1924 | } | ||
1925 | /* Check if we added any event */ | ||
1926 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | ||
1927 | current_ev = current_val; | ||
1928 | } | ||
1929 | |||
1930 | /* TODO: add BeaconInt,resp_rate,atim into BSS table */ | ||
1931 | buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); | ||
1932 | if (buf && (scan || hscan)) { | ||
1933 | memset(&iwe, 0, sizeof(iwe)); | ||
1934 | iwe.cmd = IWEVCUSTOM; | ||
1935 | sprintf(buf, "bcn_int=%d", | ||
1936 | le16_to_cpu(hostscan ? hscan->beacon_interval : | ||
1937 | 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(hostscan ? | ||
1945 | hscan->rate : | ||
1946 | scan->rate)); | ||
1947 | iwe.u.data.length = strlen(buf); | ||
1948 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1949 | buf); | ||
1950 | |||
1951 | if (hostscan && (capabilities & WLAN_CAPABILITY_IBSS)) { | ||
1952 | memset(&iwe, 0, sizeof(iwe)); | ||
1953 | iwe.cmd = IWEVCUSTOM; | ||
1954 | sprintf(buf, "atim=%d", le16_to_cpu(hscan->atim)); | ||
1955 | iwe.u.data.length = strlen(buf); | ||
1956 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1957 | &iwe, buf); | ||
1958 | } | ||
1959 | } | ||
1960 | kfree(buf); | ||
1961 | |||
1962 | if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { | ||
1963 | memset(&iwe, 0, sizeof(iwe)); | ||
1964 | iwe.cmd = IWEVGENIE; | ||
1965 | iwe.u.data.length = bss->wpa_ie_len; | ||
1966 | current_ev = iwe_stream_add_point( | ||
1967 | current_ev, end_buf, &iwe, bss->wpa_ie); | ||
1968 | } | ||
1969 | |||
1970 | if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { | ||
1971 | memset(&iwe, 0, sizeof(iwe)); | ||
1972 | iwe.cmd = IWEVGENIE; | ||
1973 | iwe.u.data.length = bss->rsn_ie_len; | ||
1974 | current_ev = iwe_stream_add_point( | ||
1975 | current_ev, end_buf, &iwe, bss->rsn_ie); | ||
1976 | } | ||
1977 | |||
1978 | return current_ev; | ||
1979 | } | ||
1980 | |||
1981 | |||
1982 | /* Translate scan data returned from the card to a card independant | ||
1983 | * format that the Wireless Tools will understand - Jean II */ | ||
1984 | static inline int prism2_translate_scan(local_info_t *local, | ||
1985 | char *buffer, int buflen) | ||
1986 | { | ||
1987 | struct hfa384x_scan_result *scan; | ||
1988 | struct hfa384x_hostscan_result *hscan; | ||
1989 | int entries, entry, hostscan; | ||
1990 | char *current_ev = buffer; | ||
1991 | char *end_buf = buffer + buflen; | ||
1992 | u8 *bssid; | ||
1993 | struct list_head *ptr; | ||
1994 | |||
1995 | spin_lock_bh(&local->lock); | ||
1996 | |||
1997 | list_for_each(ptr, &local->bss_list) { | ||
1998 | struct hostap_bss_info *bss; | ||
1999 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2000 | bss->included = 0; | ||
2001 | } | ||
2002 | |||
2003 | hostscan = local->last_scan_type == PRISM2_HOSTSCAN; | ||
2004 | entries = hostscan ? local->last_hostscan_results_count : | ||
2005 | local->last_scan_results_count; | ||
2006 | for (entry = 0; entry < entries; entry++) { | ||
2007 | int found = 0; | ||
2008 | scan = &local->last_scan_results[entry]; | ||
2009 | hscan = &local->last_hostscan_results[entry]; | ||
2010 | |||
2011 | bssid = hostscan ? hscan->bssid : scan->bssid; | ||
2012 | |||
2013 | /* Report every SSID if the AP is using multiple SSIDs. If no | ||
2014 | * BSS record is found (e.g., when WPA mode is disabled), | ||
2015 | * report the AP once. */ | ||
2016 | list_for_each(ptr, &local->bss_list) { | ||
2017 | struct hostap_bss_info *bss; | ||
2018 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2019 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { | ||
2020 | bss->included = 1; | ||
2021 | current_ev = __prism2_translate_scan( | ||
2022 | local, scan, hscan, hostscan, bss, | ||
2023 | bssid, current_ev, end_buf); | ||
2024 | found++; | ||
2025 | } | ||
2026 | } | ||
2027 | if (!found) { | ||
2028 | current_ev = __prism2_translate_scan( | ||
2029 | local, scan, hscan, hostscan, NULL, bssid, | ||
2030 | current_ev, end_buf); | ||
2031 | } | ||
2032 | /* Check if there is space for one more entry */ | ||
2033 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2034 | /* Ask user space to try again with a bigger buffer */ | ||
2035 | spin_unlock_bh(&local->lock); | ||
2036 | return -E2BIG; | ||
2037 | } | ||
2038 | } | ||
2039 | |||
2040 | /* Prism2 firmware has limits (32 at least in some versions) for number | ||
2041 | * of BSSes in scan results. Extend this limit by using local BSS list. | ||
2042 | */ | ||
2043 | list_for_each(ptr, &local->bss_list) { | ||
2044 | struct hostap_bss_info *bss; | ||
2045 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2046 | if (bss->included) | ||
2047 | continue; | ||
2048 | current_ev = __prism2_translate_scan(local, NULL, NULL, 0, bss, | ||
2049 | bss->bssid, current_ev, | ||
2050 | end_buf); | ||
2051 | /* Check if there is space for one more entry */ | ||
2052 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2053 | /* Ask user space to try again with a bigger buffer */ | ||
2054 | spin_unlock_bh(&local->lock); | ||
2055 | return -E2BIG; | ||
2056 | } | ||
2057 | } | ||
2058 | |||
2059 | spin_unlock_bh(&local->lock); | ||
2060 | |||
2061 | return current_ev - buffer; | ||
2062 | } | ||
2063 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2064 | |||
2065 | |||
2066 | static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, | ||
2067 | struct iw_request_info *info, | ||
2068 | struct iw_point *data, char *extra) | ||
2069 | { | ||
2070 | #ifdef PRISM2_NO_STATION_MODES | ||
2071 | return -EOPNOTSUPP; | ||
2072 | #else /* PRISM2_NO_STATION_MODES */ | ||
2073 | struct hostap_interface *iface; | ||
2074 | local_info_t *local; | ||
2075 | int res; | ||
2076 | |||
2077 | iface = netdev_priv(dev); | ||
2078 | local = iface->local; | ||
2079 | |||
2080 | /* Wait until the scan is finished. We can probably do better | ||
2081 | * than that - Jean II */ | ||
2082 | if (local->scan_timestamp && | ||
2083 | time_before(jiffies, local->scan_timestamp + 3 * HZ)) { | ||
2084 | /* Important note : we don't want to block the caller | ||
2085 | * until results are ready for various reasons. | ||
2086 | * First, managing wait queues is complex and racy | ||
2087 | * (there may be multiple simultaneous callers). | ||
2088 | * Second, we grab some rtnetlink lock before comming | ||
2089 | * here (in dev_ioctl()). | ||
2090 | * Third, the caller can wait on the Wireless Event | ||
2091 | * - Jean II */ | ||
2092 | return -EAGAIN; | ||
2093 | } | ||
2094 | local->scan_timestamp = 0; | ||
2095 | |||
2096 | res = prism2_translate_scan(local, extra, data->length); | ||
2097 | |||
2098 | if (res >= 0) { | ||
2099 | data->length = res; | ||
2100 | return 0; | ||
2101 | } else { | ||
2102 | data->length = 0; | ||
2103 | return res; | ||
2104 | } | ||
2105 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2106 | } | ||
2107 | |||
2108 | |||
2109 | static int prism2_ioctl_giwscan(struct net_device *dev, | ||
2110 | struct iw_request_info *info, | ||
2111 | struct iw_point *data, char *extra) | ||
2112 | { | ||
2113 | struct hostap_interface *iface; | ||
2114 | local_info_t *local; | ||
2115 | int res; | ||
2116 | |||
2117 | iface = netdev_priv(dev); | ||
2118 | local = iface->local; | ||
2119 | |||
2120 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2121 | /* In MASTER mode, it doesn't make sense to go around | ||
2122 | * scanning the frequencies and make the stations we serve | ||
2123 | * wait when what the user is really interested about is the | ||
2124 | * list of stations and access points we are talking to. | ||
2125 | * So, just extract results from our cache... | ||
2126 | * Jean II */ | ||
2127 | |||
2128 | /* Translate to WE format */ | ||
2129 | res = prism2_ap_translate_scan(dev, extra); | ||
2130 | if (res >= 0) { | ||
2131 | printk(KERN_DEBUG "Scan result translation succeeded " | ||
2132 | "(length=%d)\n", res); | ||
2133 | data->length = res; | ||
2134 | return 0; | ||
2135 | } else { | ||
2136 | printk(KERN_DEBUG | ||
2137 | "Scan result translation failed (res=%d)\n", | ||
2138 | res); | ||
2139 | data->length = 0; | ||
2140 | return res; | ||
2141 | } | ||
2142 | } else { | ||
2143 | /* Station mode */ | ||
2144 | return prism2_ioctl_giwscan_sta(dev, info, data, extra); | ||
2145 | } | ||
2146 | } | ||
2147 | |||
2148 | |||
2149 | static const struct iw_priv_args prism2_priv[] = { | ||
2150 | { PRISM2_IOCTL_MONITOR, | ||
2151 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, | ||
2152 | { PRISM2_IOCTL_READMIF, | ||
2153 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | ||
2154 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, | ||
2155 | { PRISM2_IOCTL_WRITEMIF, | ||
2156 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, | ||
2157 | { PRISM2_IOCTL_RESET, | ||
2158 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, | ||
2159 | { PRISM2_IOCTL_INQUIRE, | ||
2160 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, | ||
2161 | { PRISM2_IOCTL_SET_RID_WORD, | ||
2162 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, | ||
2163 | { PRISM2_IOCTL_MACCMD, | ||
2164 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, | ||
2165 | { PRISM2_IOCTL_WDS_ADD, | ||
2166 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, | ||
2167 | { PRISM2_IOCTL_WDS_DEL, | ||
2168 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, | ||
2169 | { PRISM2_IOCTL_ADDMAC, | ||
2170 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, | ||
2171 | { PRISM2_IOCTL_DELMAC, | ||
2172 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, | ||
2173 | { PRISM2_IOCTL_KICKMAC, | ||
2174 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, | ||
2175 | /* --- raw access to sub-ioctls --- */ | ||
2176 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2177 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, | ||
2178 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2179 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2180 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, | ||
2181 | /* --- sub-ioctls handlers --- */ | ||
2182 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2183 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, | ||
2184 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2185 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, | ||
2186 | /* --- sub-ioctls definitions --- */ | ||
2187 | { PRISM2_PARAM_TXRATECTRL, | ||
2188 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, | ||
2189 | { PRISM2_PARAM_TXRATECTRL, | ||
2190 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, | ||
2191 | { PRISM2_PARAM_BEACON_INT, | ||
2192 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, | ||
2193 | { PRISM2_PARAM_BEACON_INT, | ||
2194 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, | ||
2195 | #ifndef PRISM2_NO_STATION_MODES | ||
2196 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2197 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, | ||
2198 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2199 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, | ||
2200 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2201 | { PRISM2_PARAM_ALC, | ||
2202 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, | ||
2203 | { PRISM2_PARAM_ALC, | ||
2204 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, | ||
2205 | { PRISM2_PARAM_DUMP, | ||
2206 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, | ||
2207 | { PRISM2_PARAM_DUMP, | ||
2208 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, | ||
2209 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2210 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, | ||
2211 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2212 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, | ||
2213 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2214 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, | ||
2215 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2216 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, | ||
2217 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2218 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, | ||
2219 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2220 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, | ||
2221 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2222 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, | ||
2223 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2224 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, | ||
2225 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2226 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, | ||
2227 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2228 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, | ||
2229 | { PRISM2_PARAM_MAX_WDS, | ||
2230 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, | ||
2231 | { PRISM2_PARAM_MAX_WDS, | ||
2232 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, | ||
2233 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2234 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, | ||
2235 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2236 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, | ||
2237 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2238 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, | ||
2239 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2240 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, | ||
2241 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2242 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, | ||
2243 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2244 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, | ||
2245 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2246 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, | ||
2247 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2248 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, | ||
2249 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2250 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, | ||
2251 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2252 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, | ||
2253 | { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX, | ||
2254 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_rx" }, | ||
2255 | { PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX, | ||
2256 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_rx" }, | ||
2257 | { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX, | ||
2258 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "busmaster_tx" }, | ||
2259 | { PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX, | ||
2260 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbusmaster_tx" }, | ||
2261 | #ifndef PRISM2_NO_STATION_MODES | ||
2262 | { PRISM2_PARAM_HOST_ROAMING, | ||
2263 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, | ||
2264 | { PRISM2_PARAM_HOST_ROAMING, | ||
2265 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, | ||
2266 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2267 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2268 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, | ||
2269 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2270 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, | ||
2271 | { PRISM2_PARAM_IEEE_802_1X, | ||
2272 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, | ||
2273 | { PRISM2_PARAM_IEEE_802_1X, | ||
2274 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, | ||
2275 | { PRISM2_PARAM_ANTSEL_TX, | ||
2276 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, | ||
2277 | { PRISM2_PARAM_ANTSEL_TX, | ||
2278 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, | ||
2279 | { PRISM2_PARAM_ANTSEL_RX, | ||
2280 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, | ||
2281 | { PRISM2_PARAM_ANTSEL_RX, | ||
2282 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, | ||
2283 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2284 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, | ||
2285 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2286 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, | ||
2287 | { PRISM2_PARAM_WDS_TYPE, | ||
2288 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, | ||
2289 | { PRISM2_PARAM_WDS_TYPE, | ||
2290 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, | ||
2291 | { PRISM2_PARAM_HOSTSCAN, | ||
2292 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, | ||
2293 | { PRISM2_PARAM_HOSTSCAN, | ||
2294 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, | ||
2295 | { PRISM2_PARAM_AP_SCAN, | ||
2296 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, | ||
2297 | { PRISM2_PARAM_AP_SCAN, | ||
2298 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, | ||
2299 | { PRISM2_PARAM_ENH_SEC, | ||
2300 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, | ||
2301 | { PRISM2_PARAM_ENH_SEC, | ||
2302 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, | ||
2303 | #ifdef PRISM2_IO_DEBUG | ||
2304 | { PRISM2_PARAM_IO_DEBUG, | ||
2305 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, | ||
2306 | { PRISM2_PARAM_IO_DEBUG, | ||
2307 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, | ||
2308 | #endif /* PRISM2_IO_DEBUG */ | ||
2309 | { PRISM2_PARAM_BASIC_RATES, | ||
2310 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, | ||
2311 | { PRISM2_PARAM_BASIC_RATES, | ||
2312 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, | ||
2313 | { PRISM2_PARAM_OPER_RATES, | ||
2314 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, | ||
2315 | { PRISM2_PARAM_OPER_RATES, | ||
2316 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, | ||
2317 | { PRISM2_PARAM_HOSTAPD, | ||
2318 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, | ||
2319 | { PRISM2_PARAM_HOSTAPD, | ||
2320 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, | ||
2321 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2322 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, | ||
2323 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2324 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, | ||
2325 | { PRISM2_PARAM_WPA, | ||
2326 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, | ||
2327 | { PRISM2_PARAM_WPA, | ||
2328 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, | ||
2329 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2330 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, | ||
2331 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2332 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, | ||
2333 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2334 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, | ||
2335 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2336 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, | ||
2337 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2338 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, | ||
2339 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2340 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, | ||
2341 | }; | ||
2342 | |||
2343 | |||
2344 | static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i) | ||
2345 | { | ||
2346 | struct hostap_interface *iface; | ||
2347 | local_info_t *local; | ||
2348 | |||
2349 | iface = netdev_priv(dev); | ||
2350 | local = iface->local; | ||
2351 | |||
2352 | if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL)) | ||
2353 | return -EOPNOTSUPP; | ||
2354 | |||
2355 | return 0; | ||
2356 | } | ||
2357 | |||
2358 | |||
2359 | static int prism2_ioctl_priv_prism2_param(struct net_device *dev, | ||
2360 | struct iw_request_info *info, | ||
2361 | void *wrqu, char *extra) | ||
2362 | { | ||
2363 | struct hostap_interface *iface; | ||
2364 | local_info_t *local; | ||
2365 | int *i = (int *) extra; | ||
2366 | int param = *i; | ||
2367 | int value = *(i + 1); | ||
2368 | int ret = 0; | ||
2369 | u16 val; | ||
2370 | |||
2371 | iface = netdev_priv(dev); | ||
2372 | local = iface->local; | ||
2373 | |||
2374 | switch (param) { | ||
2375 | case PRISM2_PARAM_TXRATECTRL: | ||
2376 | local->fw_tx_rate_control = value; | ||
2377 | break; | ||
2378 | |||
2379 | case PRISM2_PARAM_BEACON_INT: | ||
2380 | if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || | ||
2381 | local->func->reset_port(dev)) | ||
2382 | ret = -EINVAL; | ||
2383 | else | ||
2384 | local->beacon_int = value; | ||
2385 | break; | ||
2386 | |||
2387 | #ifndef PRISM2_NO_STATION_MODES | ||
2388 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2389 | if (value == local->pseudo_adhoc) | ||
2390 | break; | ||
2391 | |||
2392 | if (value != 0 && value != 1) { | ||
2393 | ret = -EINVAL; | ||
2394 | break; | ||
2395 | } | ||
2396 | |||
2397 | printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", | ||
2398 | dev->name, local->pseudo_adhoc, value); | ||
2399 | local->pseudo_adhoc = value; | ||
2400 | if (local->iw_mode != IW_MODE_ADHOC) | ||
2401 | break; | ||
2402 | |||
2403 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2404 | hostap_get_porttype(local))) { | ||
2405 | ret = -EOPNOTSUPP; | ||
2406 | break; | ||
2407 | } | ||
2408 | |||
2409 | if (local->func->reset_port(dev)) | ||
2410 | ret = -EINVAL; | ||
2411 | break; | ||
2412 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2413 | |||
2414 | case PRISM2_PARAM_ALC: | ||
2415 | printk(KERN_DEBUG "%s: %s ALC\n", dev->name, | ||
2416 | value == 0 ? "Disabling" : "Enabling"); | ||
2417 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
2418 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
2419 | (HFA384X_TEST_CFG_BITS << 8), | ||
2420 | value == 0 ? 0 : 1, &val, NULL); | ||
2421 | break; | ||
2422 | |||
2423 | case PRISM2_PARAM_DUMP: | ||
2424 | local->frame_dump = value; | ||
2425 | break; | ||
2426 | |||
2427 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2428 | if (value < 0 || value > 3) { | ||
2429 | ret = -EINVAL; | ||
2430 | break; | ||
2431 | } | ||
2432 | if (local->ap != NULL) | ||
2433 | local->ap->ap_policy = value; | ||
2434 | break; | ||
2435 | |||
2436 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2437 | if (value < 0 || value > 7 * 24 * 60 * 60) { | ||
2438 | ret = -EINVAL; | ||
2439 | break; | ||
2440 | } | ||
2441 | if (local->ap != NULL) | ||
2442 | local->ap->max_inactivity = value * HZ; | ||
2443 | break; | ||
2444 | |||
2445 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2446 | if (local->ap != NULL) | ||
2447 | local->ap->bridge_packets = value; | ||
2448 | break; | ||
2449 | |||
2450 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2451 | if (value < 0 || value > 65535) { | ||
2452 | ret = -EINVAL; | ||
2453 | break; | ||
2454 | } | ||
2455 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) | ||
2456 | || local->func->reset_port(dev)) | ||
2457 | ret = -EINVAL; | ||
2458 | else | ||
2459 | local->dtim_period = value; | ||
2460 | break; | ||
2461 | |||
2462 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2463 | if (local->ap != NULL) | ||
2464 | local->ap->nullfunc_ack = value; | ||
2465 | break; | ||
2466 | |||
2467 | case PRISM2_PARAM_MAX_WDS: | ||
2468 | local->wds_max_connections = value; | ||
2469 | break; | ||
2470 | |||
2471 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2472 | if (local->ap != NULL) { | ||
2473 | if (!local->ap->autom_ap_wds && value) { | ||
2474 | /* add WDS link to all APs in STA table */ | ||
2475 | hostap_add_wds_links(local); | ||
2476 | } | ||
2477 | local->ap->autom_ap_wds = value; | ||
2478 | } | ||
2479 | break; | ||
2480 | |||
2481 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2482 | local->auth_algs = value; | ||
2483 | if (hostap_set_auth_algs(local)) | ||
2484 | ret = -EINVAL; | ||
2485 | break; | ||
2486 | |||
2487 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2488 | local->monitor_allow_fcserr = value; | ||
2489 | break; | ||
2490 | |||
2491 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2492 | local->host_encrypt = value; | ||
2493 | if (hostap_set_encryption(local) || | ||
2494 | local->func->reset_port(dev)) | ||
2495 | ret = -EINVAL; | ||
2496 | break; | ||
2497 | |||
2498 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2499 | local->host_decrypt = value; | ||
2500 | if (hostap_set_encryption(local) || | ||
2501 | local->func->reset_port(dev)) | ||
2502 | ret = -EINVAL; | ||
2503 | break; | ||
2504 | |||
2505 | case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX: | ||
2506 | local->bus_master_threshold_rx = value; | ||
2507 | break; | ||
2508 | |||
2509 | case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX: | ||
2510 | local->bus_master_threshold_tx = value; | ||
2511 | break; | ||
2512 | |||
2513 | #ifndef PRISM2_NO_STATION_MODES | ||
2514 | case PRISM2_PARAM_HOST_ROAMING: | ||
2515 | if (value < 0 || value > 2) { | ||
2516 | ret = -EINVAL; | ||
2517 | break; | ||
2518 | } | ||
2519 | local->host_roaming = value; | ||
2520 | if (hostap_set_roaming(local) || local->func->reset_port(dev)) | ||
2521 | ret = -EINVAL; | ||
2522 | break; | ||
2523 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2524 | |||
2525 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2526 | local->bcrx_sta_key = value; | ||
2527 | break; | ||
2528 | |||
2529 | case PRISM2_PARAM_IEEE_802_1X: | ||
2530 | local->ieee_802_1x = value; | ||
2531 | break; | ||
2532 | |||
2533 | case PRISM2_PARAM_ANTSEL_TX: | ||
2534 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2535 | ret = -EINVAL; | ||
2536 | break; | ||
2537 | } | ||
2538 | local->antsel_tx = value; | ||
2539 | hostap_set_antsel(local); | ||
2540 | break; | ||
2541 | |||
2542 | case PRISM2_PARAM_ANTSEL_RX: | ||
2543 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2544 | ret = -EINVAL; | ||
2545 | break; | ||
2546 | } | ||
2547 | local->antsel_rx = value; | ||
2548 | hostap_set_antsel(local); | ||
2549 | break; | ||
2550 | |||
2551 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2552 | if (value != PRISM2_MONITOR_80211 && | ||
2553 | value != PRISM2_MONITOR_CAPHDR && | ||
2554 | value != PRISM2_MONITOR_PRISM) { | ||
2555 | ret = -EINVAL; | ||
2556 | break; | ||
2557 | } | ||
2558 | local->monitor_type = value; | ||
2559 | if (local->iw_mode == IW_MODE_MONITOR) | ||
2560 | hostap_monitor_set_type(local); | ||
2561 | break; | ||
2562 | |||
2563 | case PRISM2_PARAM_WDS_TYPE: | ||
2564 | local->wds_type = value; | ||
2565 | break; | ||
2566 | |||
2567 | case PRISM2_PARAM_HOSTSCAN: | ||
2568 | { | ||
2569 | struct hfa384x_hostscan_request scan_req; | ||
2570 | u16 rate; | ||
2571 | |||
2572 | memset(&scan_req, 0, sizeof(scan_req)); | ||
2573 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
2574 | switch (value) { | ||
2575 | case 1: rate = HFA384X_RATES_1MBPS; break; | ||
2576 | case 2: rate = HFA384X_RATES_2MBPS; break; | ||
2577 | case 3: rate = HFA384X_RATES_5MBPS; break; | ||
2578 | case 4: rate = HFA384X_RATES_11MBPS; break; | ||
2579 | default: rate = HFA384X_RATES_1MBPS; break; | ||
2580 | } | ||
2581 | scan_req.txrate = cpu_to_le16(rate); | ||
2582 | /* leave SSID empty to accept all SSIDs */ | ||
2583 | |||
2584 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2585 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2586 | HFA384X_PORTTYPE_BSS) || | ||
2587 | local->func->reset_port(dev)) | ||
2588 | printk(KERN_DEBUG "Leaving Host AP mode " | ||
2589 | "for HostScan failed\n"); | ||
2590 | } | ||
2591 | |||
2592 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
2593 | sizeof(scan_req))) { | ||
2594 | printk(KERN_DEBUG "HOSTSCAN failed\n"); | ||
2595 | ret = -EINVAL; | ||
2596 | } | ||
2597 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2598 | wait_queue_t __wait; | ||
2599 | init_waitqueue_entry(&__wait, current); | ||
2600 | add_wait_queue(&local->hostscan_wq, &__wait); | ||
2601 | set_current_state(TASK_INTERRUPTIBLE); | ||
2602 | schedule_timeout(HZ); | ||
2603 | if (signal_pending(current)) | ||
2604 | ret = -EINTR; | ||
2605 | set_current_state(TASK_RUNNING); | ||
2606 | remove_wait_queue(&local->hostscan_wq, &__wait); | ||
2607 | |||
2608 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2609 | HFA384X_PORTTYPE_HOSTAP) || | ||
2610 | local->func->reset_port(dev)) | ||
2611 | printk(KERN_DEBUG "Returning to Host AP mode " | ||
2612 | "after HostScan failed\n"); | ||
2613 | } | ||
2614 | break; | ||
2615 | } | ||
2616 | |||
2617 | case PRISM2_PARAM_AP_SCAN: | ||
2618 | local->passive_scan_interval = value; | ||
2619 | if (timer_pending(&local->passive_scan_timer)) | ||
2620 | del_timer(&local->passive_scan_timer); | ||
2621 | if (value > 0) { | ||
2622 | local->passive_scan_timer.expires = jiffies + | ||
2623 | local->passive_scan_interval * HZ; | ||
2624 | add_timer(&local->passive_scan_timer); | ||
2625 | } | ||
2626 | break; | ||
2627 | |||
2628 | case PRISM2_PARAM_ENH_SEC: | ||
2629 | if (value < 0 || value > 3) { | ||
2630 | ret = -EINVAL; | ||
2631 | break; | ||
2632 | } | ||
2633 | local->enh_sec = value; | ||
2634 | if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, | ||
2635 | local->enh_sec) || | ||
2636 | local->func->reset_port(dev)) { | ||
2637 | printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " | ||
2638 | "1.6.3 or newer\n", dev->name); | ||
2639 | ret = -EOPNOTSUPP; | ||
2640 | } | ||
2641 | break; | ||
2642 | |||
2643 | #ifdef PRISM2_IO_DEBUG | ||
2644 | case PRISM2_PARAM_IO_DEBUG: | ||
2645 | local->io_debug_enabled = value; | ||
2646 | break; | ||
2647 | #endif /* PRISM2_IO_DEBUG */ | ||
2648 | |||
2649 | case PRISM2_PARAM_BASIC_RATES: | ||
2650 | if ((value & local->tx_rate_control) != value || value == 0) { | ||
2651 | printk(KERN_INFO "%s: invalid basic rate set - basic " | ||
2652 | "rates must be in supported rate set\n", | ||
2653 | dev->name); | ||
2654 | ret = -EINVAL; | ||
2655 | break; | ||
2656 | } | ||
2657 | local->basic_rates = value; | ||
2658 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
2659 | local->basic_rates) || | ||
2660 | local->func->reset_port(dev)) | ||
2661 | ret = -EINVAL; | ||
2662 | break; | ||
2663 | |||
2664 | case PRISM2_PARAM_OPER_RATES: | ||
2665 | local->tx_rate_control = value; | ||
2666 | if (hostap_set_rate(dev)) | ||
2667 | ret = -EINVAL; | ||
2668 | break; | ||
2669 | |||
2670 | case PRISM2_PARAM_HOSTAPD: | ||
2671 | ret = hostap_set_hostapd(local, value, 1); | ||
2672 | break; | ||
2673 | |||
2674 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2675 | ret = hostap_set_hostapd_sta(local, value, 1); | ||
2676 | break; | ||
2677 | |||
2678 | case PRISM2_PARAM_WPA: | ||
2679 | local->wpa = value; | ||
2680 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2681 | ret = -EOPNOTSUPP; | ||
2682 | else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
2683 | value ? 1 : 0)) | ||
2684 | ret = -EINVAL; | ||
2685 | break; | ||
2686 | |||
2687 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2688 | local->privacy_invoked = value; | ||
2689 | if (hostap_set_encryption(local) || | ||
2690 | local->func->reset_port(dev)) | ||
2691 | ret = -EINVAL; | ||
2692 | break; | ||
2693 | |||
2694 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2695 | local->tkip_countermeasures = value; | ||
2696 | break; | ||
2697 | |||
2698 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2699 | local->drop_unencrypted = value; | ||
2700 | break; | ||
2701 | |||
2702 | default: | ||
2703 | printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", | ||
2704 | dev->name, param); | ||
2705 | ret = -EOPNOTSUPP; | ||
2706 | break; | ||
2707 | } | ||
2708 | |||
2709 | return ret; | ||
2710 | } | ||
2711 | |||
2712 | |||
2713 | static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, | ||
2714 | struct iw_request_info *info, | ||
2715 | void *wrqu, char *extra) | ||
2716 | { | ||
2717 | struct hostap_interface *iface; | ||
2718 | local_info_t *local; | ||
2719 | int *param = (int *) extra; | ||
2720 | int ret = 0; | ||
2721 | |||
2722 | iface = netdev_priv(dev); | ||
2723 | local = iface->local; | ||
2724 | |||
2725 | switch (*param) { | ||
2726 | case PRISM2_PARAM_TXRATECTRL: | ||
2727 | *param = local->fw_tx_rate_control; | ||
2728 | break; | ||
2729 | |||
2730 | case PRISM2_PARAM_BEACON_INT: | ||
2731 | *param = local->beacon_int; | ||
2732 | break; | ||
2733 | |||
2734 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2735 | *param = local->pseudo_adhoc; | ||
2736 | break; | ||
2737 | |||
2738 | case PRISM2_PARAM_ALC: | ||
2739 | ret = -EOPNOTSUPP; /* FIX */ | ||
2740 | break; | ||
2741 | |||
2742 | case PRISM2_PARAM_DUMP: | ||
2743 | *param = local->frame_dump; | ||
2744 | break; | ||
2745 | |||
2746 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2747 | if (local->ap != NULL) | ||
2748 | *param = local->ap->ap_policy; | ||
2749 | else | ||
2750 | ret = -EOPNOTSUPP; | ||
2751 | break; | ||
2752 | |||
2753 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2754 | if (local->ap != NULL) | ||
2755 | *param = local->ap->max_inactivity / HZ; | ||
2756 | else | ||
2757 | ret = -EOPNOTSUPP; | ||
2758 | break; | ||
2759 | |||
2760 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2761 | if (local->ap != NULL) | ||
2762 | *param = local->ap->bridge_packets; | ||
2763 | else | ||
2764 | ret = -EOPNOTSUPP; | ||
2765 | break; | ||
2766 | |||
2767 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2768 | *param = local->dtim_period; | ||
2769 | break; | ||
2770 | |||
2771 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2772 | if (local->ap != NULL) | ||
2773 | *param = local->ap->nullfunc_ack; | ||
2774 | else | ||
2775 | ret = -EOPNOTSUPP; | ||
2776 | break; | ||
2777 | |||
2778 | case PRISM2_PARAM_MAX_WDS: | ||
2779 | *param = local->wds_max_connections; | ||
2780 | break; | ||
2781 | |||
2782 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2783 | if (local->ap != NULL) | ||
2784 | *param = local->ap->autom_ap_wds; | ||
2785 | else | ||
2786 | ret = -EOPNOTSUPP; | ||
2787 | break; | ||
2788 | |||
2789 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2790 | *param = local->auth_algs; | ||
2791 | break; | ||
2792 | |||
2793 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2794 | *param = local->monitor_allow_fcserr; | ||
2795 | break; | ||
2796 | |||
2797 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2798 | *param = local->host_encrypt; | ||
2799 | break; | ||
2800 | |||
2801 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2802 | *param = local->host_decrypt; | ||
2803 | break; | ||
2804 | |||
2805 | case PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX: | ||
2806 | *param = local->bus_master_threshold_rx; | ||
2807 | break; | ||
2808 | |||
2809 | case PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX: | ||
2810 | *param = local->bus_master_threshold_tx; | ||
2811 | break; | ||
2812 | |||
2813 | case PRISM2_PARAM_HOST_ROAMING: | ||
2814 | *param = local->host_roaming; | ||
2815 | break; | ||
2816 | |||
2817 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2818 | *param = local->bcrx_sta_key; | ||
2819 | break; | ||
2820 | |||
2821 | case PRISM2_PARAM_IEEE_802_1X: | ||
2822 | *param = local->ieee_802_1x; | ||
2823 | break; | ||
2824 | |||
2825 | case PRISM2_PARAM_ANTSEL_TX: | ||
2826 | *param = local->antsel_tx; | ||
2827 | break; | ||
2828 | |||
2829 | case PRISM2_PARAM_ANTSEL_RX: | ||
2830 | *param = local->antsel_rx; | ||
2831 | break; | ||
2832 | |||
2833 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2834 | *param = local->monitor_type; | ||
2835 | break; | ||
2836 | |||
2837 | case PRISM2_PARAM_WDS_TYPE: | ||
2838 | *param = local->wds_type; | ||
2839 | break; | ||
2840 | |||
2841 | case PRISM2_PARAM_HOSTSCAN: | ||
2842 | ret = -EOPNOTSUPP; | ||
2843 | break; | ||
2844 | |||
2845 | case PRISM2_PARAM_AP_SCAN: | ||
2846 | *param = local->passive_scan_interval; | ||
2847 | break; | ||
2848 | |||
2849 | case PRISM2_PARAM_ENH_SEC: | ||
2850 | *param = local->enh_sec; | ||
2851 | break; | ||
2852 | |||
2853 | #ifdef PRISM2_IO_DEBUG | ||
2854 | case PRISM2_PARAM_IO_DEBUG: | ||
2855 | *param = local->io_debug_enabled; | ||
2856 | break; | ||
2857 | #endif /* PRISM2_IO_DEBUG */ | ||
2858 | |||
2859 | case PRISM2_PARAM_BASIC_RATES: | ||
2860 | *param = local->basic_rates; | ||
2861 | break; | ||
2862 | |||
2863 | case PRISM2_PARAM_OPER_RATES: | ||
2864 | *param = local->tx_rate_control; | ||
2865 | break; | ||
2866 | |||
2867 | case PRISM2_PARAM_HOSTAPD: | ||
2868 | *param = local->hostapd; | ||
2869 | break; | ||
2870 | |||
2871 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2872 | *param = local->hostapd_sta; | ||
2873 | break; | ||
2874 | |||
2875 | case PRISM2_PARAM_WPA: | ||
2876 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2877 | ret = -EOPNOTSUPP; | ||
2878 | *param = local->wpa; | ||
2879 | break; | ||
2880 | |||
2881 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2882 | *param = local->privacy_invoked; | ||
2883 | break; | ||
2884 | |||
2885 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2886 | *param = local->tkip_countermeasures; | ||
2887 | break; | ||
2888 | |||
2889 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2890 | *param = local->drop_unencrypted; | ||
2891 | break; | ||
2892 | |||
2893 | default: | ||
2894 | printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", | ||
2895 | dev->name, *param); | ||
2896 | ret = -EOPNOTSUPP; | ||
2897 | break; | ||
2898 | } | ||
2899 | |||
2900 | return ret; | ||
2901 | } | ||
2902 | |||
2903 | |||
2904 | static int prism2_ioctl_priv_readmif(struct net_device *dev, | ||
2905 | struct iw_request_info *info, | ||
2906 | void *wrqu, char *extra) | ||
2907 | { | ||
2908 | struct hostap_interface *iface; | ||
2909 | local_info_t *local; | ||
2910 | u16 resp0; | ||
2911 | |||
2912 | iface = netdev_priv(dev); | ||
2913 | local = iface->local; | ||
2914 | |||
2915 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, | ||
2916 | &resp0)) | ||
2917 | return -EOPNOTSUPP; | ||
2918 | else | ||
2919 | *extra = resp0; | ||
2920 | |||
2921 | return 0; | ||
2922 | } | ||
2923 | |||
2924 | |||
2925 | static int prism2_ioctl_priv_writemif(struct net_device *dev, | ||
2926 | struct iw_request_info *info, | ||
2927 | void *wrqu, char *extra) | ||
2928 | { | ||
2929 | struct hostap_interface *iface; | ||
2930 | local_info_t *local; | ||
2931 | u16 cr, val; | ||
2932 | |||
2933 | iface = netdev_priv(dev); | ||
2934 | local = iface->local; | ||
2935 | |||
2936 | cr = *extra; | ||
2937 | val = *(extra + 1); | ||
2938 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) | ||
2939 | return -EOPNOTSUPP; | ||
2940 | |||
2941 | return 0; | ||
2942 | } | ||
2943 | |||
2944 | |||
2945 | static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i) | ||
2946 | { | ||
2947 | struct hostap_interface *iface; | ||
2948 | local_info_t *local; | ||
2949 | int ret = 0; | ||
2950 | u32 mode; | ||
2951 | |||
2952 | iface = netdev_priv(dev); | ||
2953 | local = iface->local; | ||
2954 | |||
2955 | printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor " | ||
2956 | "- update software to use iwconfig mode monitor\n", | ||
2957 | dev->name, current->pid, current->comm); | ||
2958 | |||
2959 | /* Backward compatibility code - this can be removed at some point */ | ||
2960 | |||
2961 | if (*i == 0) { | ||
2962 | /* Disable monitor mode - old mode was not saved, so go to | ||
2963 | * Master mode */ | ||
2964 | mode = IW_MODE_MASTER; | ||
2965 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2966 | } else if (*i == 1) { | ||
2967 | /* netlink socket mode is not supported anymore since it did | ||
2968 | * not separate different devices from each other and was not | ||
2969 | * best method for delivering large amount of packets to | ||
2970 | * user space */ | ||
2971 | ret = -EOPNOTSUPP; | ||
2972 | } else if (*i == 2 || *i == 3) { | ||
2973 | switch (*i) { | ||
2974 | case 2: | ||
2975 | local->monitor_type = PRISM2_MONITOR_80211; | ||
2976 | break; | ||
2977 | case 3: | ||
2978 | local->monitor_type = PRISM2_MONITOR_PRISM; | ||
2979 | break; | ||
2980 | } | ||
2981 | mode = IW_MODE_MONITOR; | ||
2982 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2983 | hostap_monitor_mode_enable(local); | ||
2984 | } else | ||
2985 | ret = -EINVAL; | ||
2986 | |||
2987 | return ret; | ||
2988 | } | ||
2989 | |||
2990 | |||
2991 | static int prism2_ioctl_priv_reset(struct net_device *dev, int *i) | ||
2992 | { | ||
2993 | struct hostap_interface *iface; | ||
2994 | local_info_t *local; | ||
2995 | |||
2996 | iface = netdev_priv(dev); | ||
2997 | local = iface->local; | ||
2998 | |||
2999 | printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i); | ||
3000 | switch (*i) { | ||
3001 | case 0: | ||
3002 | /* Disable and enable card */ | ||
3003 | local->func->hw_shutdown(dev, 1); | ||
3004 | local->func->hw_config(dev, 0); | ||
3005 | break; | ||
3006 | |||
3007 | case 1: | ||
3008 | /* COR sreset */ | ||
3009 | local->func->hw_reset(dev); | ||
3010 | break; | ||
3011 | |||
3012 | case 2: | ||
3013 | /* Disable and enable port 0 */ | ||
3014 | local->func->reset_port(dev); | ||
3015 | break; | ||
3016 | |||
3017 | case 3: | ||
3018 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
3019 | if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, | ||
3020 | NULL)) | ||
3021 | return -EINVAL; | ||
3022 | break; | ||
3023 | |||
3024 | case 4: | ||
3025 | if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, | ||
3026 | NULL)) | ||
3027 | return -EINVAL; | ||
3028 | break; | ||
3029 | |||
3030 | default: | ||
3031 | printk(KERN_DEBUG "Unknown reset request %d\n", *i); | ||
3032 | return -EOPNOTSUPP; | ||
3033 | } | ||
3034 | |||
3035 | return 0; | ||
3036 | } | ||
3037 | |||
3038 | |||
3039 | static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i) | ||
3040 | { | ||
3041 | int rid = *i; | ||
3042 | int value = *(i + 1); | ||
3043 | |||
3044 | printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value); | ||
3045 | |||
3046 | if (hostap_set_word(dev, rid, value)) | ||
3047 | return -EINVAL; | ||
3048 | |||
3049 | return 0; | ||
3050 | } | ||
3051 | |||
3052 | |||
3053 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3054 | static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd) | ||
3055 | { | ||
3056 | int ret = 0; | ||
3057 | |||
3058 | switch (*cmd) { | ||
3059 | case AP_MAC_CMD_POLICY_OPEN: | ||
3060 | local->ap->mac_restrictions.policy = MAC_POLICY_OPEN; | ||
3061 | break; | ||
3062 | case AP_MAC_CMD_POLICY_ALLOW: | ||
3063 | local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW; | ||
3064 | break; | ||
3065 | case AP_MAC_CMD_POLICY_DENY: | ||
3066 | local->ap->mac_restrictions.policy = MAC_POLICY_DENY; | ||
3067 | break; | ||
3068 | case AP_MAC_CMD_FLUSH: | ||
3069 | ap_control_flush_macs(&local->ap->mac_restrictions); | ||
3070 | break; | ||
3071 | case AP_MAC_CMD_KICKALL: | ||
3072 | ap_control_kickall(local->ap); | ||
3073 | hostap_deauth_all_stas(local->dev, local->ap, 0); | ||
3074 | break; | ||
3075 | default: | ||
3076 | ret = -EOPNOTSUPP; | ||
3077 | break; | ||
3078 | } | ||
3079 | |||
3080 | return ret; | ||
3081 | } | ||
3082 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3083 | |||
3084 | |||
3085 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3086 | static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) | ||
3087 | { | ||
3088 | struct prism2_download_param *param; | ||
3089 | int ret = 0; | ||
3090 | |||
3091 | if (p->length < sizeof(struct prism2_download_param) || | ||
3092 | p->length > 1024 || !p->pointer) | ||
3093 | return -EINVAL; | ||
3094 | |||
3095 | param = (struct prism2_download_param *) | ||
3096 | kmalloc(p->length, GFP_KERNEL); | ||
3097 | if (param == NULL) | ||
3098 | return -ENOMEM; | ||
3099 | |||
3100 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3101 | ret = -EFAULT; | ||
3102 | goto out; | ||
3103 | } | ||
3104 | |||
3105 | if (p->length < sizeof(struct prism2_download_param) + | ||
3106 | param->num_areas * sizeof(struct prism2_download_area)) { | ||
3107 | ret = -EINVAL; | ||
3108 | goto out; | ||
3109 | } | ||
3110 | |||
3111 | ret = local->func->download(local, param); | ||
3112 | |||
3113 | out: | ||
3114 | if (param != NULL) | ||
3115 | kfree(param); | ||
3116 | |||
3117 | return ret; | ||
3118 | } | ||
3119 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3120 | |||
3121 | |||
3122 | static int prism2_set_genericelement(struct net_device *dev, u8 *elem, | ||
3123 | size_t len) | ||
3124 | { | ||
3125 | struct hostap_interface *iface = dev->priv; | ||
3126 | local_info_t *local = iface->local; | ||
3127 | u8 *buf; | ||
3128 | |||
3129 | /* | ||
3130 | * Add 16-bit length in the beginning of the buffer because Prism2 RID | ||
3131 | * includes it. | ||
3132 | */ | ||
3133 | buf = kmalloc(len + 2, GFP_KERNEL); | ||
3134 | if (buf == NULL) | ||
3135 | return -ENOMEM; | ||
3136 | |||
3137 | *((u16 *) buf) = cpu_to_le16(len); | ||
3138 | memcpy(buf + 2, elem, len); | ||
3139 | |||
3140 | kfree(local->generic_elem); | ||
3141 | local->generic_elem = buf; | ||
3142 | local->generic_elem_len = len + 2; | ||
3143 | |||
3144 | return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, | ||
3145 | buf, len + 2); | ||
3146 | } | ||
3147 | |||
3148 | |||
3149 | static int prism2_ioctl_siwauth(struct net_device *dev, | ||
3150 | struct iw_request_info *info, | ||
3151 | struct iw_param *data, char *extra) | ||
3152 | { | ||
3153 | struct hostap_interface *iface = dev->priv; | ||
3154 | local_info_t *local = iface->local; | ||
3155 | |||
3156 | switch (data->flags & IW_AUTH_INDEX) { | ||
3157 | case IW_AUTH_WPA_VERSION: | ||
3158 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3159 | case IW_AUTH_CIPHER_GROUP: | ||
3160 | case IW_AUTH_KEY_MGMT: | ||
3161 | /* | ||
3162 | * Host AP driver does not use these parameters and allows | ||
3163 | * wpa_supplicant to control them internally. | ||
3164 | */ | ||
3165 | break; | ||
3166 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3167 | local->tkip_countermeasures = data->value; | ||
3168 | break; | ||
3169 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3170 | local->drop_unencrypted = data->value; | ||
3171 | break; | ||
3172 | case IW_AUTH_80211_AUTH_ALG: | ||
3173 | local->auth_algs = data->value; | ||
3174 | break; | ||
3175 | case IW_AUTH_WPA_ENABLED: | ||
3176 | if (data->value == 0) { | ||
3177 | local->wpa = 0; | ||
3178 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3179 | break; | ||
3180 | prism2_set_genericelement(dev, "", 0); | ||
3181 | local->host_roaming = 0; | ||
3182 | local->privacy_invoked = 0; | ||
3183 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
3184 | 0) || | ||
3185 | hostap_set_roaming(local) || | ||
3186 | hostap_set_encryption(local) || | ||
3187 | local->func->reset_port(dev)) | ||
3188 | return -EINVAL; | ||
3189 | break; | ||
3190 | } | ||
3191 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3192 | return -EOPNOTSUPP; | ||
3193 | local->host_roaming = 2; | ||
3194 | local->privacy_invoked = 1; | ||
3195 | local->wpa = 1; | ||
3196 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || | ||
3197 | hostap_set_roaming(local) || | ||
3198 | hostap_set_encryption(local) || | ||
3199 | local->func->reset_port(dev)) | ||
3200 | return -EINVAL; | ||
3201 | break; | ||
3202 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3203 | local->ieee_802_1x = data->value; | ||
3204 | break; | ||
3205 | case IW_AUTH_PRIVACY_INVOKED: | ||
3206 | local->privacy_invoked = data->value; | ||
3207 | break; | ||
3208 | default: | ||
3209 | return -EOPNOTSUPP; | ||
3210 | } | ||
3211 | return 0; | ||
3212 | } | ||
3213 | |||
3214 | |||
3215 | static int prism2_ioctl_giwauth(struct net_device *dev, | ||
3216 | struct iw_request_info *info, | ||
3217 | struct iw_param *data, char *extra) | ||
3218 | { | ||
3219 | struct hostap_interface *iface = dev->priv; | ||
3220 | local_info_t *local = iface->local; | ||
3221 | |||
3222 | switch (data->flags & IW_AUTH_INDEX) { | ||
3223 | case IW_AUTH_WPA_VERSION: | ||
3224 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3225 | case IW_AUTH_CIPHER_GROUP: | ||
3226 | case IW_AUTH_KEY_MGMT: | ||
3227 | /* | ||
3228 | * Host AP driver does not use these parameters and allows | ||
3229 | * wpa_supplicant to control them internally. | ||
3230 | */ | ||
3231 | return -EOPNOTSUPP; | ||
3232 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3233 | data->value = local->tkip_countermeasures; | ||
3234 | break; | ||
3235 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3236 | data->value = local->drop_unencrypted; | ||
3237 | break; | ||
3238 | case IW_AUTH_80211_AUTH_ALG: | ||
3239 | data->value = local->auth_algs; | ||
3240 | break; | ||
3241 | case IW_AUTH_WPA_ENABLED: | ||
3242 | data->value = local->wpa; | ||
3243 | break; | ||
3244 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3245 | data->value = local->ieee_802_1x; | ||
3246 | break; | ||
3247 | default: | ||
3248 | return -EOPNOTSUPP; | ||
3249 | } | ||
3250 | return 0; | ||
3251 | } | ||
3252 | |||
3253 | |||
3254 | static int prism2_ioctl_siwencodeext(struct net_device *dev, | ||
3255 | struct iw_request_info *info, | ||
3256 | struct iw_point *erq, char *extra) | ||
3257 | { | ||
3258 | struct hostap_interface *iface = dev->priv; | ||
3259 | local_info_t *local = iface->local; | ||
3260 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3261 | int i, ret = 0; | ||
3262 | struct hostap_crypto_ops *ops; | ||
3263 | struct prism2_crypt_data **crypt; | ||
3264 | void *sta_ptr; | ||
3265 | u8 *addr; | ||
3266 | const char *alg, *module; | ||
3267 | |||
3268 | i = erq->flags & IW_ENCODE_INDEX; | ||
3269 | if (i > WEP_KEYS) | ||
3270 | return -EINVAL; | ||
3271 | if (i < 1 || i > WEP_KEYS) | ||
3272 | i = local->tx_keyidx; | ||
3273 | else | ||
3274 | i--; | ||
3275 | if (i < 0 || i >= WEP_KEYS) | ||
3276 | return -EINVAL; | ||
3277 | |||
3278 | addr = ext->addr.sa_data; | ||
3279 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3280 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3281 | sta_ptr = NULL; | ||
3282 | crypt = &local->crypt[i]; | ||
3283 | } else { | ||
3284 | if (i != 0) | ||
3285 | return -EINVAL; | ||
3286 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3287 | if (sta_ptr == NULL) { | ||
3288 | if (local->iw_mode == IW_MODE_INFRA) { | ||
3289 | /* | ||
3290 | * TODO: add STA entry for the current AP so | ||
3291 | * that unicast key can be used. For now, this | ||
3292 | * is emulated by using default key idx 0. | ||
3293 | */ | ||
3294 | i = 0; | ||
3295 | crypt = &local->crypt[i]; | ||
3296 | } else | ||
3297 | return -EINVAL; | ||
3298 | } | ||
3299 | } | ||
3300 | |||
3301 | if ((erq->flags & IW_ENCODE_DISABLED) || | ||
3302 | ext->alg == IW_ENCODE_ALG_NONE) { | ||
3303 | if (*crypt) | ||
3304 | prism2_crypt_delayed_deinit(local, crypt); | ||
3305 | goto done; | ||
3306 | } | ||
3307 | |||
3308 | switch (ext->alg) { | ||
3309 | case IW_ENCODE_ALG_WEP: | ||
3310 | alg = "WEP"; | ||
3311 | module = "hostap_crypt_wep"; | ||
3312 | break; | ||
3313 | case IW_ENCODE_ALG_TKIP: | ||
3314 | alg = "TKIP"; | ||
3315 | module = "hostap_crypt_tkip"; | ||
3316 | break; | ||
3317 | case IW_ENCODE_ALG_CCMP: | ||
3318 | alg = "CCMP"; | ||
3319 | module = "hostap_crypt_ccmp"; | ||
3320 | break; | ||
3321 | default: | ||
3322 | printk(KERN_DEBUG "%s: unsupported algorithm %d\n", | ||
3323 | local->dev->name, ext->alg); | ||
3324 | ret = -EOPNOTSUPP; | ||
3325 | goto done; | ||
3326 | } | ||
3327 | |||
3328 | ops = hostap_get_crypto_ops(alg); | ||
3329 | if (ops == NULL) { | ||
3330 | request_module(module); | ||
3331 | ops = hostap_get_crypto_ops(alg); | ||
3332 | } | ||
3333 | if (ops == NULL) { | ||
3334 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3335 | local->dev->name, alg); | ||
3336 | ret = -EOPNOTSUPP; | ||
3337 | goto done; | ||
3338 | } | ||
3339 | |||
3340 | if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { | ||
3341 | /* | ||
3342 | * Per station encryption and other than WEP algorithms | ||
3343 | * require host-based encryption, so force them on | ||
3344 | * automatically. | ||
3345 | */ | ||
3346 | local->host_decrypt = local->host_encrypt = 1; | ||
3347 | } | ||
3348 | |||
3349 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3350 | struct prism2_crypt_data *new_crypt; | ||
3351 | |||
3352 | prism2_crypt_delayed_deinit(local, crypt); | ||
3353 | |||
3354 | new_crypt = (struct prism2_crypt_data *) | ||
3355 | kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); | ||
3356 | if (new_crypt == NULL) { | ||
3357 | ret = -ENOMEM; | ||
3358 | goto done; | ||
3359 | } | ||
3360 | memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); | ||
3361 | new_crypt->ops = ops; | ||
3362 | new_crypt->priv = new_crypt->ops->init(i); | ||
3363 | if (new_crypt->priv == NULL) { | ||
3364 | kfree(new_crypt); | ||
3365 | ret = -EINVAL; | ||
3366 | goto done; | ||
3367 | } | ||
3368 | |||
3369 | *crypt = new_crypt; | ||
3370 | } | ||
3371 | |||
3372 | /* | ||
3373 | * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the | ||
3374 | * existing seq# should not be changed. | ||
3375 | * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# | ||
3376 | * should be changed to something else than zero. | ||
3377 | */ | ||
3378 | if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) | ||
3379 | && (*crypt)->ops->set_key && | ||
3380 | (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, | ||
3381 | (*crypt)->priv) < 0) { | ||
3382 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3383 | local->dev->name); | ||
3384 | ret = -EINVAL; | ||
3385 | goto done; | ||
3386 | } | ||
3387 | |||
3388 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
3389 | if (!sta_ptr) | ||
3390 | local->tx_keyidx = i; | ||
3391 | else if (i) { | ||
3392 | ret = -EINVAL; | ||
3393 | goto done; | ||
3394 | } | ||
3395 | } | ||
3396 | |||
3397 | |||
3398 | if (sta_ptr == NULL && ext->key_len > 0) { | ||
3399 | int first = 1, j; | ||
3400 | for (j = 0; j < WEP_KEYS; j++) { | ||
3401 | if (j != i && local->crypt[j]) { | ||
3402 | first = 0; | ||
3403 | break; | ||
3404 | } | ||
3405 | } | ||
3406 | if (first) | ||
3407 | local->tx_keyidx = i; | ||
3408 | } | ||
3409 | |||
3410 | done: | ||
3411 | if (sta_ptr) | ||
3412 | hostap_handle_sta_release(sta_ptr); | ||
3413 | |||
3414 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
3415 | |||
3416 | /* | ||
3417 | * Do not reset port0 if card is in Managed mode since resetting will | ||
3418 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3419 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3420 | * after WEP configuration. However, keys are apparently changed at | ||
3421 | * least in Managed mode. | ||
3422 | */ | ||
3423 | if (ret == 0 && | ||
3424 | (hostap_set_encryption(local) || | ||
3425 | (local->iw_mode != IW_MODE_INFRA && | ||
3426 | local->func->reset_port(local->dev)))) | ||
3427 | ret = -EINVAL; | ||
3428 | |||
3429 | return ret; | ||
3430 | } | ||
3431 | |||
3432 | |||
3433 | static int prism2_ioctl_giwencodeext(struct net_device *dev, | ||
3434 | struct iw_request_info *info, | ||
3435 | struct iw_point *erq, char *extra) | ||
3436 | { | ||
3437 | struct hostap_interface *iface = dev->priv; | ||
3438 | local_info_t *local = iface->local; | ||
3439 | struct prism2_crypt_data **crypt; | ||
3440 | void *sta_ptr; | ||
3441 | int max_key_len, i; | ||
3442 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3443 | u8 *addr; | ||
3444 | |||
3445 | max_key_len = erq->length - sizeof(*ext); | ||
3446 | if (max_key_len < 0) | ||
3447 | return -EINVAL; | ||
3448 | |||
3449 | i = erq->flags & IW_ENCODE_INDEX; | ||
3450 | if (i < 1 || i > WEP_KEYS) | ||
3451 | i = local->tx_keyidx; | ||
3452 | else | ||
3453 | i--; | ||
3454 | |||
3455 | addr = ext->addr.sa_data; | ||
3456 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3457 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3458 | sta_ptr = NULL; | ||
3459 | crypt = &local->crypt[i]; | ||
3460 | } else { | ||
3461 | i = 0; | ||
3462 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3463 | if (sta_ptr == NULL) | ||
3464 | return -EINVAL; | ||
3465 | } | ||
3466 | erq->flags = i + 1; | ||
3467 | memset(ext, 0, sizeof(*ext)); | ||
3468 | |||
3469 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3470 | ext->alg = IW_ENCODE_ALG_NONE; | ||
3471 | ext->key_len = 0; | ||
3472 | erq->flags |= IW_ENCODE_DISABLED; | ||
3473 | } else { | ||
3474 | if (strcmp((*crypt)->ops->name, "WEP") == 0) | ||
3475 | ext->alg = IW_ENCODE_ALG_WEP; | ||
3476 | else if (strcmp((*crypt)->ops->name, "TKIP") == 0) | ||
3477 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
3478 | else if (strcmp((*crypt)->ops->name, "CCMP") == 0) | ||
3479 | ext->alg = IW_ENCODE_ALG_CCMP; | ||
3480 | else | ||
3481 | return -EINVAL; | ||
3482 | |||
3483 | if ((*crypt)->ops->get_key) { | ||
3484 | ext->key_len = | ||
3485 | (*crypt)->ops->get_key(ext->key, | ||
3486 | max_key_len, | ||
3487 | ext->tx_seq, | ||
3488 | (*crypt)->priv); | ||
3489 | if (ext->key_len && | ||
3490 | (ext->alg == IW_ENCODE_ALG_TKIP || | ||
3491 | ext->alg == IW_ENCODE_ALG_CCMP)) | ||
3492 | ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; | ||
3493 | } | ||
3494 | } | ||
3495 | |||
3496 | if (sta_ptr) | ||
3497 | hostap_handle_sta_release(sta_ptr); | ||
3498 | |||
3499 | return 0; | ||
3500 | } | ||
3501 | |||
3502 | |||
3503 | static int prism2_ioctl_set_encryption(local_info_t *local, | ||
3504 | struct prism2_hostapd_param *param, | ||
3505 | int param_len) | ||
3506 | { | ||
3507 | int ret = 0; | ||
3508 | struct hostap_crypto_ops *ops; | ||
3509 | struct prism2_crypt_data **crypt; | ||
3510 | void *sta_ptr; | ||
3511 | |||
3512 | param->u.crypt.err = 0; | ||
3513 | param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
3514 | |||
3515 | if (param_len != | ||
3516 | (int) ((char *) param->u.crypt.key - (char *) param) + | ||
3517 | param->u.crypt.key_len) | ||
3518 | return -EINVAL; | ||
3519 | |||
3520 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3521 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3522 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3523 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3524 | return -EINVAL; | ||
3525 | sta_ptr = NULL; | ||
3526 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3527 | } else { | ||
3528 | if (param->u.crypt.idx) | ||
3529 | return -EINVAL; | ||
3530 | sta_ptr = ap_crypt_get_ptrs( | ||
3531 | local->ap, param->sta_addr, | ||
3532 | (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), | ||
3533 | &crypt); | ||
3534 | |||
3535 | if (sta_ptr == NULL) { | ||
3536 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3537 | return -EINVAL; | ||
3538 | } | ||
3539 | } | ||
3540 | |||
3541 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
3542 | if (crypt) | ||
3543 | prism2_crypt_delayed_deinit(local, crypt); | ||
3544 | goto done; | ||
3545 | } | ||
3546 | |||
3547 | ops = hostap_get_crypto_ops(param->u.crypt.alg); | ||
3548 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
3549 | request_module("hostap_crypt_wep"); | ||
3550 | ops = hostap_get_crypto_ops(param->u.crypt.alg); | ||
3551 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
3552 | request_module("hostap_crypt_tkip"); | ||
3553 | ops = hostap_get_crypto_ops(param->u.crypt.alg); | ||
3554 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
3555 | request_module("hostap_crypt_ccmp"); | ||
3556 | ops = hostap_get_crypto_ops(param->u.crypt.alg); | ||
3557 | } | ||
3558 | if (ops == NULL) { | ||
3559 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3560 | local->dev->name, param->u.crypt.alg); | ||
3561 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; | ||
3562 | ret = -EINVAL; | ||
3563 | goto done; | ||
3564 | } | ||
3565 | |||
3566 | /* station based encryption and other than WEP algorithms require | ||
3567 | * host-based encryption, so force them on automatically */ | ||
3568 | local->host_decrypt = local->host_encrypt = 1; | ||
3569 | |||
3570 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3571 | struct prism2_crypt_data *new_crypt; | ||
3572 | |||
3573 | prism2_crypt_delayed_deinit(local, crypt); | ||
3574 | |||
3575 | new_crypt = (struct prism2_crypt_data *) | ||
3576 | kmalloc(sizeof(struct prism2_crypt_data), GFP_KERNEL); | ||
3577 | if (new_crypt == NULL) { | ||
3578 | ret = -ENOMEM; | ||
3579 | goto done; | ||
3580 | } | ||
3581 | memset(new_crypt, 0, sizeof(struct prism2_crypt_data)); | ||
3582 | new_crypt->ops = ops; | ||
3583 | new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); | ||
3584 | if (new_crypt->priv == NULL) { | ||
3585 | kfree(new_crypt); | ||
3586 | param->u.crypt.err = | ||
3587 | HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
3588 | ret = -EINVAL; | ||
3589 | goto done; | ||
3590 | } | ||
3591 | |||
3592 | *crypt = new_crypt; | ||
3593 | } | ||
3594 | |||
3595 | if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || | ||
3596 | param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && | ||
3597 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
3598 | param->u.crypt.key_len, param->u.crypt.seq, | ||
3599 | (*crypt)->priv) < 0) { | ||
3600 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3601 | local->dev->name); | ||
3602 | param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; | ||
3603 | ret = -EINVAL; | ||
3604 | goto done; | ||
3605 | } | ||
3606 | |||
3607 | if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { | ||
3608 | if (!sta_ptr) | ||
3609 | local->tx_keyidx = param->u.crypt.idx; | ||
3610 | else if (param->u.crypt.idx) { | ||
3611 | printk(KERN_DEBUG "%s: TX key idx setting failed\n", | ||
3612 | local->dev->name); | ||
3613 | param->u.crypt.err = | ||
3614 | HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; | ||
3615 | ret = -EINVAL; | ||
3616 | goto done; | ||
3617 | } | ||
3618 | } | ||
3619 | |||
3620 | done: | ||
3621 | if (sta_ptr) | ||
3622 | hostap_handle_sta_release(sta_ptr); | ||
3623 | |||
3624 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
3625 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3626 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3627 | * after WEP configuration. However, keys are apparently changed at | ||
3628 | * least in Managed mode. */ | ||
3629 | if (ret == 0 && | ||
3630 | (hostap_set_encryption(local) || | ||
3631 | (local->iw_mode != IW_MODE_INFRA && | ||
3632 | local->func->reset_port(local->dev)))) { | ||
3633 | param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; | ||
3634 | return -EINVAL; | ||
3635 | } | ||
3636 | |||
3637 | return ret; | ||
3638 | } | ||
3639 | |||
3640 | |||
3641 | static int prism2_ioctl_get_encryption(local_info_t *local, | ||
3642 | struct prism2_hostapd_param *param, | ||
3643 | int param_len) | ||
3644 | { | ||
3645 | struct prism2_crypt_data **crypt; | ||
3646 | void *sta_ptr; | ||
3647 | int max_key_len; | ||
3648 | |||
3649 | param->u.crypt.err = 0; | ||
3650 | |||
3651 | max_key_len = param_len - | ||
3652 | (int) ((char *) param->u.crypt.key - (char *) param); | ||
3653 | if (max_key_len < 0) | ||
3654 | return -EINVAL; | ||
3655 | |||
3656 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3657 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3658 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3659 | sta_ptr = NULL; | ||
3660 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3661 | param->u.crypt.idx = local->tx_keyidx; | ||
3662 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3663 | } else { | ||
3664 | param->u.crypt.idx = 0; | ||
3665 | sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, | ||
3666 | &crypt); | ||
3667 | |||
3668 | if (sta_ptr == NULL) { | ||
3669 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3670 | return -EINVAL; | ||
3671 | } | ||
3672 | } | ||
3673 | |||
3674 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3675 | memcpy(param->u.crypt.alg, "none", 5); | ||
3676 | param->u.crypt.key_len = 0; | ||
3677 | param->u.crypt.idx = 0xff; | ||
3678 | } else { | ||
3679 | strncpy(param->u.crypt.alg, (*crypt)->ops->name, | ||
3680 | HOSTAP_CRYPT_ALG_NAME_LEN); | ||
3681 | param->u.crypt.key_len = 0; | ||
3682 | |||
3683 | memset(param->u.crypt.seq, 0, 8); | ||
3684 | if ((*crypt)->ops->get_key) { | ||
3685 | param->u.crypt.key_len = | ||
3686 | (*crypt)->ops->get_key(param->u.crypt.key, | ||
3687 | max_key_len, | ||
3688 | param->u.crypt.seq, | ||
3689 | (*crypt)->priv); | ||
3690 | } | ||
3691 | } | ||
3692 | |||
3693 | if (sta_ptr) | ||
3694 | hostap_handle_sta_release(sta_ptr); | ||
3695 | |||
3696 | return 0; | ||
3697 | } | ||
3698 | |||
3699 | |||
3700 | static int prism2_ioctl_get_rid(local_info_t *local, | ||
3701 | struct prism2_hostapd_param *param, | ||
3702 | int param_len) | ||
3703 | { | ||
3704 | int max_len, res; | ||
3705 | |||
3706 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3707 | if (max_len < 0) | ||
3708 | return -EINVAL; | ||
3709 | |||
3710 | res = local->func->get_rid(local->dev, param->u.rid.rid, | ||
3711 | param->u.rid.data, param->u.rid.len, 0); | ||
3712 | if (res >= 0) { | ||
3713 | param->u.rid.len = res; | ||
3714 | return 0; | ||
3715 | } | ||
3716 | |||
3717 | return res; | ||
3718 | } | ||
3719 | |||
3720 | |||
3721 | static int prism2_ioctl_set_rid(local_info_t *local, | ||
3722 | struct prism2_hostapd_param *param, | ||
3723 | int param_len) | ||
3724 | { | ||
3725 | int max_len; | ||
3726 | |||
3727 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3728 | if (max_len < 0 || max_len < param->u.rid.len) | ||
3729 | return -EINVAL; | ||
3730 | |||
3731 | return local->func->set_rid(local->dev, param->u.rid.rid, | ||
3732 | param->u.rid.data, param->u.rid.len); | ||
3733 | } | ||
3734 | |||
3735 | |||
3736 | static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, | ||
3737 | struct prism2_hostapd_param *param, | ||
3738 | int param_len) | ||
3739 | { | ||
3740 | printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", | ||
3741 | local->dev->name, MAC2STR(param->sta_addr)); | ||
3742 | memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); | ||
3743 | return 0; | ||
3744 | } | ||
3745 | |||
3746 | |||
3747 | static int prism2_ioctl_siwgenie(struct net_device *dev, | ||
3748 | struct iw_request_info *info, | ||
3749 | struct iw_point *data, char *extra) | ||
3750 | { | ||
3751 | return prism2_set_genericelement(dev, extra, data->length); | ||
3752 | } | ||
3753 | |||
3754 | |||
3755 | static int prism2_ioctl_giwgenie(struct net_device *dev, | ||
3756 | struct iw_request_info *info, | ||
3757 | struct iw_point *data, char *extra) | ||
3758 | { | ||
3759 | struct hostap_interface *iface = dev->priv; | ||
3760 | local_info_t *local = iface->local; | ||
3761 | int len = local->generic_elem_len - 2; | ||
3762 | |||
3763 | if (len <= 0 || local->generic_elem == NULL) { | ||
3764 | data->length = 0; | ||
3765 | return 0; | ||
3766 | } | ||
3767 | |||
3768 | if (data->length < len) | ||
3769 | return -E2BIG; | ||
3770 | |||
3771 | data->length = len; | ||
3772 | memcpy(extra, local->generic_elem + 2, len); | ||
3773 | |||
3774 | return 0; | ||
3775 | } | ||
3776 | |||
3777 | |||
3778 | static int prism2_ioctl_set_generic_element(local_info_t *local, | ||
3779 | struct prism2_hostapd_param *param, | ||
3780 | int param_len) | ||
3781 | { | ||
3782 | int max_len, len; | ||
3783 | |||
3784 | len = param->u.generic_elem.len; | ||
3785 | max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; | ||
3786 | if (max_len < 0 || max_len < len) | ||
3787 | return -EINVAL; | ||
3788 | |||
3789 | return prism2_set_genericelement(local->dev, | ||
3790 | param->u.generic_elem.data, len); | ||
3791 | } | ||
3792 | |||
3793 | |||
3794 | static int prism2_ioctl_siwmlme(struct net_device *dev, | ||
3795 | struct iw_request_info *info, | ||
3796 | struct iw_point *data, char *extra) | ||
3797 | { | ||
3798 | struct hostap_interface *iface = dev->priv; | ||
3799 | local_info_t *local = iface->local; | ||
3800 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | ||
3801 | u16 reason; | ||
3802 | |||
3803 | reason = cpu_to_le16(mlme->reason_code); | ||
3804 | |||
3805 | switch (mlme->cmd) { | ||
3806 | case IW_MLME_DEAUTH: | ||
3807 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3808 | WLAN_FC_STYPE_DEAUTH, | ||
3809 | (u8 *) &reason, 2); | ||
3810 | case IW_MLME_DISASSOC: | ||
3811 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3812 | WLAN_FC_STYPE_DISASSOC, | ||
3813 | (u8 *) &reason, 2); | ||
3814 | default: | ||
3815 | return -EOPNOTSUPP; | ||
3816 | } | ||
3817 | } | ||
3818 | |||
3819 | |||
3820 | static int prism2_ioctl_mlme(local_info_t *local, | ||
3821 | struct prism2_hostapd_param *param) | ||
3822 | { | ||
3823 | u16 reason; | ||
3824 | |||
3825 | reason = cpu_to_le16(param->u.mlme.reason_code); | ||
3826 | switch (param->u.mlme.cmd) { | ||
3827 | case MLME_STA_DEAUTH: | ||
3828 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3829 | WLAN_FC_STYPE_DEAUTH, | ||
3830 | (u8 *) &reason, 2); | ||
3831 | case MLME_STA_DISASSOC: | ||
3832 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3833 | WLAN_FC_STYPE_DISASSOC, | ||
3834 | (u8 *) &reason, 2); | ||
3835 | default: | ||
3836 | return -EOPNOTSUPP; | ||
3837 | } | ||
3838 | } | ||
3839 | |||
3840 | |||
3841 | static int prism2_ioctl_scan_req(local_info_t *local, | ||
3842 | struct prism2_hostapd_param *param) | ||
3843 | { | ||
3844 | #ifndef PRISM2_NO_STATION_MODES | ||
3845 | if ((local->iw_mode != IW_MODE_INFRA && | ||
3846 | local->iw_mode != IW_MODE_ADHOC) || | ||
3847 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) | ||
3848 | return -EOPNOTSUPP; | ||
3849 | |||
3850 | if (!local->dev_enabled) | ||
3851 | return -ENETDOWN; | ||
3852 | |||
3853 | return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, | ||
3854 | param->u.scan_req.ssid_len); | ||
3855 | #else /* PRISM2_NO_STATION_MODES */ | ||
3856 | return -EOPNOTSUPP; | ||
3857 | #endif /* PRISM2_NO_STATION_MODES */ | ||
3858 | } | ||
3859 | |||
3860 | |||
3861 | static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) | ||
3862 | { | ||
3863 | struct prism2_hostapd_param *param; | ||
3864 | int ret = 0; | ||
3865 | int ap_ioctl = 0; | ||
3866 | |||
3867 | if (p->length < sizeof(struct prism2_hostapd_param) || | ||
3868 | p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) | ||
3869 | return -EINVAL; | ||
3870 | |||
3871 | param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); | ||
3872 | if (param == NULL) | ||
3873 | return -ENOMEM; | ||
3874 | |||
3875 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3876 | ret = -EFAULT; | ||
3877 | goto out; | ||
3878 | } | ||
3879 | |||
3880 | switch (param->cmd) { | ||
3881 | case PRISM2_SET_ENCRYPTION: | ||
3882 | ret = prism2_ioctl_set_encryption(local, param, p->length); | ||
3883 | break; | ||
3884 | case PRISM2_GET_ENCRYPTION: | ||
3885 | ret = prism2_ioctl_get_encryption(local, param, p->length); | ||
3886 | break; | ||
3887 | case PRISM2_HOSTAPD_GET_RID: | ||
3888 | ret = prism2_ioctl_get_rid(local, param, p->length); | ||
3889 | break; | ||
3890 | case PRISM2_HOSTAPD_SET_RID: | ||
3891 | ret = prism2_ioctl_set_rid(local, param, p->length); | ||
3892 | break; | ||
3893 | case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: | ||
3894 | ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); | ||
3895 | break; | ||
3896 | case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: | ||
3897 | ret = prism2_ioctl_set_generic_element(local, param, | ||
3898 | p->length); | ||
3899 | break; | ||
3900 | case PRISM2_HOSTAPD_MLME: | ||
3901 | ret = prism2_ioctl_mlme(local, param); | ||
3902 | break; | ||
3903 | case PRISM2_HOSTAPD_SCAN_REQ: | ||
3904 | ret = prism2_ioctl_scan_req(local, param); | ||
3905 | break; | ||
3906 | default: | ||
3907 | ret = prism2_hostapd(local->ap, param); | ||
3908 | ap_ioctl = 1; | ||
3909 | break; | ||
3910 | } | ||
3911 | |||
3912 | if (ret == 1 || !ap_ioctl) { | ||
3913 | if (copy_to_user(p->pointer, param, p->length)) { | ||
3914 | ret = -EFAULT; | ||
3915 | goto out; | ||
3916 | } else if (ap_ioctl) | ||
3917 | ret = 0; | ||
3918 | } | ||
3919 | |||
3920 | out: | ||
3921 | if (param != NULL) | ||
3922 | kfree(param); | ||
3923 | |||
3924 | return ret; | ||
3925 | } | ||
3926 | |||
3927 | |||
3928 | static void prism2_get_drvinfo(struct net_device *dev, | ||
3929 | struct ethtool_drvinfo *info) | ||
3930 | { | ||
3931 | struct hostap_interface *iface; | ||
3932 | local_info_t *local; | ||
3933 | |||
3934 | iface = netdev_priv(dev); | ||
3935 | local = iface->local; | ||
3936 | |||
3937 | strncpy(info->driver, "hostap", sizeof(info->driver) - 1); | ||
3938 | strncpy(info->version, PRISM2_VERSION, | ||
3939 | sizeof(info->version) - 1); | ||
3940 | snprintf(info->fw_version, sizeof(info->fw_version) - 1, | ||
3941 | "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, | ||
3942 | (local->sta_fw_ver >> 8) & 0xff, | ||
3943 | local->sta_fw_ver & 0xff); | ||
3944 | } | ||
3945 | |||
3946 | static struct ethtool_ops prism2_ethtool_ops = { | ||
3947 | .get_drvinfo = prism2_get_drvinfo | ||
3948 | }; | ||
3949 | |||
3950 | |||
3951 | /* Structures to export the Wireless Handlers */ | ||
3952 | |||
3953 | static const iw_handler prism2_handler[] = | ||
3954 | { | ||
3955 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
3956 | (iw_handler) prism2_get_name, /* SIOCGIWNAME */ | ||
3957 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
3958 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
3959 | (iw_handler) prism2_ioctl_siwfreq, /* SIOCSIWFREQ */ | ||
3960 | (iw_handler) prism2_ioctl_giwfreq, /* SIOCGIWFREQ */ | ||
3961 | (iw_handler) prism2_ioctl_siwmode, /* SIOCSIWMODE */ | ||
3962 | (iw_handler) prism2_ioctl_giwmode, /* SIOCGIWMODE */ | ||
3963 | (iw_handler) prism2_ioctl_siwsens, /* SIOCSIWSENS */ | ||
3964 | (iw_handler) prism2_ioctl_giwsens, /* SIOCGIWSENS */ | ||
3965 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | ||
3966 | (iw_handler) prism2_ioctl_giwrange, /* SIOCGIWRANGE */ | ||
3967 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | ||
3968 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | ||
3969 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | ||
3970 | (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ | ||
3971 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
3972 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
3973 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
3974 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
3975 | (iw_handler) prism2_ioctl_siwap, /* SIOCSIWAP */ | ||
3976 | (iw_handler) prism2_ioctl_giwap, /* SIOCGIWAP */ | ||
3977 | (iw_handler) prism2_ioctl_siwmlme, /* SIOCSIWMLME */ | ||
3978 | (iw_handler) prism2_ioctl_giwaplist, /* SIOCGIWAPLIST */ | ||
3979 | (iw_handler) prism2_ioctl_siwscan, /* SIOCSIWSCAN */ | ||
3980 | (iw_handler) prism2_ioctl_giwscan, /* SIOCGIWSCAN */ | ||
3981 | (iw_handler) prism2_ioctl_siwessid, /* SIOCSIWESSID */ | ||
3982 | (iw_handler) prism2_ioctl_giwessid, /* SIOCGIWESSID */ | ||
3983 | (iw_handler) prism2_ioctl_siwnickn, /* SIOCSIWNICKN */ | ||
3984 | (iw_handler) prism2_ioctl_giwnickn, /* SIOCGIWNICKN */ | ||
3985 | (iw_handler) NULL, /* -- hole -- */ | ||
3986 | (iw_handler) NULL, /* -- hole -- */ | ||
3987 | (iw_handler) prism2_ioctl_siwrate, /* SIOCSIWRATE */ | ||
3988 | (iw_handler) prism2_ioctl_giwrate, /* SIOCGIWRATE */ | ||
3989 | (iw_handler) prism2_ioctl_siwrts, /* SIOCSIWRTS */ | ||
3990 | (iw_handler) prism2_ioctl_giwrts, /* SIOCGIWRTS */ | ||
3991 | (iw_handler) prism2_ioctl_siwfrag, /* SIOCSIWFRAG */ | ||
3992 | (iw_handler) prism2_ioctl_giwfrag, /* SIOCGIWFRAG */ | ||
3993 | (iw_handler) prism2_ioctl_siwtxpow, /* SIOCSIWTXPOW */ | ||
3994 | (iw_handler) prism2_ioctl_giwtxpow, /* SIOCGIWTXPOW */ | ||
3995 | (iw_handler) prism2_ioctl_siwretry, /* SIOCSIWRETRY */ | ||
3996 | (iw_handler) prism2_ioctl_giwretry, /* SIOCGIWRETRY */ | ||
3997 | (iw_handler) prism2_ioctl_siwencode, /* SIOCSIWENCODE */ | ||
3998 | (iw_handler) prism2_ioctl_giwencode, /* SIOCGIWENCODE */ | ||
3999 | (iw_handler) prism2_ioctl_siwpower, /* SIOCSIWPOWER */ | ||
4000 | (iw_handler) prism2_ioctl_giwpower, /* SIOCGIWPOWER */ | ||
4001 | (iw_handler) NULL, /* -- hole -- */ | ||
4002 | (iw_handler) NULL, /* -- hole -- */ | ||
4003 | (iw_handler) prism2_ioctl_siwgenie, /* SIOCSIWGENIE */ | ||
4004 | (iw_handler) prism2_ioctl_giwgenie, /* SIOCGIWGENIE */ | ||
4005 | (iw_handler) prism2_ioctl_siwauth, /* SIOCSIWAUTH */ | ||
4006 | (iw_handler) prism2_ioctl_giwauth, /* SIOCGIWAUTH */ | ||
4007 | (iw_handler) prism2_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | ||
4008 | (iw_handler) prism2_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ | ||
4009 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
4010 | (iw_handler) NULL, /* -- hole -- */ | ||
4011 | }; | ||
4012 | |||
4013 | static const iw_handler prism2_private_handler[] = | ||
4014 | { /* SIOCIWFIRSTPRIV + */ | ||
4015 | (iw_handler) prism2_ioctl_priv_prism2_param, /* 0 */ | ||
4016 | (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */ | ||
4017 | (iw_handler) prism2_ioctl_priv_writemif, /* 2 */ | ||
4018 | (iw_handler) prism2_ioctl_priv_readmif, /* 3 */ | ||
4019 | }; | ||
4020 | |||
4021 | static const struct iw_handler_def hostap_iw_handler_def = | ||
4022 | { | ||
4023 | .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), | ||
4024 | .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), | ||
4025 | .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), | ||
4026 | .standard = (iw_handler *) prism2_handler, | ||
4027 | .private = (iw_handler *) prism2_private_handler, | ||
4028 | .private_args = (struct iw_priv_args *) prism2_priv, | ||
4029 | .get_wireless_stats = hostap_get_wireless_stats, | ||
4030 | }; | ||
4031 | |||
4032 | |||
4033 | int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
4034 | { | ||
4035 | struct iwreq *wrq = (struct iwreq *) ifr; | ||
4036 | struct hostap_interface *iface; | ||
4037 | local_info_t *local; | ||
4038 | int ret = 0; | ||
4039 | |||
4040 | iface = netdev_priv(dev); | ||
4041 | local = iface->local; | ||
4042 | |||
4043 | switch (cmd) { | ||
4044 | /* Private ioctls (iwpriv) that have not yet been converted | ||
4045 | * into new wireless extensions API */ | ||
4046 | |||
4047 | case PRISM2_IOCTL_INQUIRE: | ||
4048 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4049 | else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name); | ||
4050 | break; | ||
4051 | |||
4052 | case PRISM2_IOCTL_MONITOR: | ||
4053 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4054 | else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name); | ||
4055 | break; | ||
4056 | |||
4057 | case PRISM2_IOCTL_RESET: | ||
4058 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4059 | else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name); | ||
4060 | break; | ||
4061 | |||
4062 | case PRISM2_IOCTL_WDS_ADD: | ||
4063 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4064 | else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1); | ||
4065 | break; | ||
4066 | |||
4067 | case PRISM2_IOCTL_WDS_DEL: | ||
4068 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4069 | else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0); | ||
4070 | break; | ||
4071 | |||
4072 | case PRISM2_IOCTL_SET_RID_WORD: | ||
4073 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4074 | else ret = prism2_ioctl_priv_set_rid_word(dev, | ||
4075 | (int *) wrq->u.name); | ||
4076 | break; | ||
4077 | |||
4078 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
4079 | case PRISM2_IOCTL_MACCMD: | ||
4080 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4081 | else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name); | ||
4082 | break; | ||
4083 | |||
4084 | case PRISM2_IOCTL_ADDMAC: | ||
4085 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4086 | else ret = ap_control_add_mac(&local->ap->mac_restrictions, | ||
4087 | wrq->u.ap_addr.sa_data); | ||
4088 | break; | ||
4089 | case PRISM2_IOCTL_DELMAC: | ||
4090 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4091 | else ret = ap_control_del_mac(&local->ap->mac_restrictions, | ||
4092 | wrq->u.ap_addr.sa_data); | ||
4093 | break; | ||
4094 | case PRISM2_IOCTL_KICKMAC: | ||
4095 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4096 | else ret = ap_control_kick_mac(local->ap, local->dev, | ||
4097 | wrq->u.ap_addr.sa_data); | ||
4098 | break; | ||
4099 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
4100 | |||
4101 | |||
4102 | /* Private ioctls that are not used with iwpriv; | ||
4103 | * in SIOCDEVPRIVATE range */ | ||
4104 | |||
4105 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
4106 | case PRISM2_IOCTL_DOWNLOAD: | ||
4107 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4108 | else ret = prism2_ioctl_priv_download(local, &wrq->u.data); | ||
4109 | break; | ||
4110 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
4111 | |||
4112 | case PRISM2_IOCTL_HOSTAPD: | ||
4113 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4114 | else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); | ||
4115 | break; | ||
4116 | |||
4117 | default: | ||
4118 | ret = -EOPNOTSUPP; | ||
4119 | break; | ||
4120 | } | ||
4121 | |||
4122 | return ret; | ||
4123 | } | ||
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c new file mode 100644 index 00000000000..3a208989333 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_pci.c | |||
@@ -0,0 +1,453 @@ | |||
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 | |||
35 | |||
36 | /* FIX: do we need mb/wmb/rmb with memory operations? */ | ||
37 | |||
38 | |||
39 | static struct pci_device_id prism2_pci_id_table[] __devinitdata = { | ||
40 | /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ | ||
41 | { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, | ||
42 | /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ | ||
43 | { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, | ||
44 | /* Samsung MagicLAN SWL-2210P */ | ||
45 | { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, | ||
46 | { 0 } | ||
47 | }; | ||
48 | |||
49 | |||
50 | #ifdef PRISM2_IO_DEBUG | ||
51 | |||
52 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
53 | { | ||
54 | struct hostap_interface *iface; | ||
55 | local_info_t *local; | ||
56 | unsigned long flags; | ||
57 | |||
58 | iface = netdev_priv(dev); | ||
59 | local = iface->local; | ||
60 | |||
61 | spin_lock_irqsave(&local->lock, flags); | ||
62 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
63 | writeb(v, local->mem_start + 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 | |||
77 | spin_lock_irqsave(&local->lock, flags); | ||
78 | v = readb(local->mem_start + a); | ||
79 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
80 | spin_unlock_irqrestore(&local->lock, flags); | ||
81 | return v; | ||
82 | } | ||
83 | |||
84 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
85 | { | ||
86 | struct hostap_interface *iface; | ||
87 | local_info_t *local; | ||
88 | unsigned long flags; | ||
89 | |||
90 | iface = netdev_priv(dev); | ||
91 | local = iface->local; | ||
92 | |||
93 | spin_lock_irqsave(&local->lock, flags); | ||
94 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
95 | writew(v, local->mem_start + a); | ||
96 | spin_unlock_irqrestore(&local->lock, flags); | ||
97 | } | ||
98 | |||
99 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
100 | { | ||
101 | struct hostap_interface *iface; | ||
102 | local_info_t *local; | ||
103 | unsigned long flags; | ||
104 | u16 v; | ||
105 | |||
106 | iface = netdev_priv(dev); | ||
107 | local = iface->local; | ||
108 | |||
109 | spin_lock_irqsave(&local->lock, flags); | ||
110 | v = readw(local->mem_start + a); | ||
111 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
112 | spin_unlock_irqrestore(&local->lock, flags); | ||
113 | return v; | ||
114 | } | ||
115 | |||
116 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
117 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
118 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
119 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
120 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v))) | ||
121 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a))) | ||
122 | |||
123 | #else /* PRISM2_IO_DEBUG */ | ||
124 | |||
125 | static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) | ||
126 | { | ||
127 | struct hostap_interface *iface; | ||
128 | local_info_t *local; | ||
129 | iface = netdev_priv(dev); | ||
130 | local = iface->local; | ||
131 | writeb(v, local->mem_start + a); | ||
132 | } | ||
133 | |||
134 | static inline u8 hfa384x_inb(struct net_device *dev, int a) | ||
135 | { | ||
136 | struct hostap_interface *iface; | ||
137 | local_info_t *local; | ||
138 | iface = netdev_priv(dev); | ||
139 | local = iface->local; | ||
140 | return readb(local->mem_start + a); | ||
141 | } | ||
142 | |||
143 | static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) | ||
144 | { | ||
145 | struct hostap_interface *iface; | ||
146 | local_info_t *local; | ||
147 | iface = netdev_priv(dev); | ||
148 | local = iface->local; | ||
149 | writew(v, local->mem_start + a); | ||
150 | } | ||
151 | |||
152 | static inline u16 hfa384x_inw(struct net_device *dev, int a) | ||
153 | { | ||
154 | struct hostap_interface *iface; | ||
155 | local_info_t *local; | ||
156 | iface = netdev_priv(dev); | ||
157 | local = iface->local; | ||
158 | return readw(local->mem_start + a); | ||
159 | } | ||
160 | |||
161 | #define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) | ||
162 | #define HFA384X_INB(a) hfa384x_inb(dev, (a)) | ||
163 | #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) | ||
164 | #define HFA384X_INW(a) hfa384x_inw(dev, (a)) | ||
165 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v))) | ||
166 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a))) | ||
167 | |||
168 | #endif /* PRISM2_IO_DEBUG */ | ||
169 | |||
170 | |||
171 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
172 | int len) | ||
173 | { | ||
174 | u16 d_off; | ||
175 | u16 *pos; | ||
176 | |||
177 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
178 | pos = (u16 *) buf; | ||
179 | |||
180 | for ( ; len > 1; len -= 2) | ||
181 | *pos++ = HFA384X_INW_DATA(d_off); | ||
182 | |||
183 | if (len & 1) | ||
184 | *((char *) pos) = HFA384X_INB(d_off); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | |||
190 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
191 | { | ||
192 | u16 d_off; | ||
193 | u16 *pos; | ||
194 | |||
195 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
196 | pos = (u16 *) buf; | ||
197 | |||
198 | for ( ; len > 1; len -= 2) | ||
199 | HFA384X_OUTW_DATA(*pos++, d_off); | ||
200 | |||
201 | if (len & 1) | ||
202 | HFA384X_OUTB(*((char *) pos), d_off); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | |||
208 | /* FIX: This might change at some point.. */ | ||
209 | #include "hostap_hw.c" | ||
210 | |||
211 | static void prism2_pci_cor_sreset(local_info_t *local) | ||
212 | { | ||
213 | struct net_device *dev = local->dev; | ||
214 | u16 reg; | ||
215 | |||
216 | reg = HFA384X_INB(HFA384X_PCICOR_OFF); | ||
217 | printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); | ||
218 | |||
219 | /* linux-wlan-ng uses extremely long hold and settle times for | ||
220 | * COR sreset. A comment in the driver code mentions that the long | ||
221 | * delays appear to be necessary. However, at least IBM 22P6901 seems | ||
222 | * to work fine with shorter delays. | ||
223 | * | ||
224 | * Longer delays can be configured by uncommenting following line: */ | ||
225 | /* #define PRISM2_PCI_USE_LONG_DELAYS */ | ||
226 | |||
227 | #ifdef PRISM2_PCI_USE_LONG_DELAYS | ||
228 | int i; | ||
229 | |||
230 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
231 | mdelay(250); | ||
232 | |||
233 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
234 | mdelay(500); | ||
235 | |||
236 | /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ | ||
237 | i = 2000000 / 10; | ||
238 | while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) | ||
239 | udelay(10); | ||
240 | |||
241 | #else /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
242 | |||
243 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
244 | mdelay(2); | ||
245 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
246 | mdelay(2); | ||
247 | |||
248 | #endif /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
249 | |||
250 | if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { | ||
251 | printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | |||
256 | static void prism2_pci_genesis_reset(local_info_t *local, int hcr) | ||
257 | { | ||
258 | struct net_device *dev = local->dev; | ||
259 | |||
260 | HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); | ||
261 | mdelay(10); | ||
262 | HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); | ||
263 | mdelay(10); | ||
264 | HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); | ||
265 | mdelay(10); | ||
266 | } | ||
267 | |||
268 | |||
269 | static struct prism2_helper_functions prism2_pci_funcs = | ||
270 | { | ||
271 | .card_present = NULL, | ||
272 | .cor_sreset = prism2_pci_cor_sreset, | ||
273 | .dev_open = NULL, | ||
274 | .dev_close = NULL, | ||
275 | .genesis_reset = prism2_pci_genesis_reset, | ||
276 | .hw_type = HOSTAP_HW_PCI, | ||
277 | }; | ||
278 | |||
279 | |||
280 | static int prism2_pci_probe(struct pci_dev *pdev, | ||
281 | const struct pci_device_id *id) | ||
282 | { | ||
283 | unsigned long phymem; | ||
284 | void __iomem *mem = NULL; | ||
285 | local_info_t *local = NULL; | ||
286 | struct net_device *dev = NULL; | ||
287 | static int cards_found /* = 0 */; | ||
288 | int irq_registered = 0; | ||
289 | struct hostap_interface *iface; | ||
290 | |||
291 | if (pci_enable_device(pdev)) | ||
292 | return -EIO; | ||
293 | |||
294 | phymem = pci_resource_start(pdev, 0); | ||
295 | |||
296 | if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { | ||
297 | printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); | ||
298 | goto err_out_disable; | ||
299 | } | ||
300 | |||
301 | mem = ioremap(phymem, pci_resource_len(pdev, 0)); | ||
302 | if (mem == NULL) { | ||
303 | printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; | ||
304 | goto fail; | ||
305 | } | ||
306 | |||
307 | #ifdef PRISM2_BUS_MASTER | ||
308 | pci_set_master(pdev); | ||
309 | #endif /* PRISM2_BUS_MASTER */ | ||
310 | |||
311 | dev = prism2_init_local_data(&prism2_pci_funcs, cards_found); | ||
312 | if (dev == NULL) | ||
313 | goto fail; | ||
314 | iface = netdev_priv(dev); | ||
315 | local = iface->local; | ||
316 | cards_found++; | ||
317 | |||
318 | dev->irq = pdev->irq; | ||
319 | local->mem_start = mem; | ||
320 | |||
321 | prism2_pci_cor_sreset(local); | ||
322 | |||
323 | pci_set_drvdata(pdev, dev); | ||
324 | |||
325 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
326 | dev)) { | ||
327 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
328 | goto fail; | ||
329 | } else | ||
330 | irq_registered = 1; | ||
331 | |||
332 | if (!local->pri_only && prism2_hw_config(dev, 1)) { | ||
333 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
334 | dev_info); | ||
335 | goto fail; | ||
336 | } | ||
337 | |||
338 | printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " | ||
339 | "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); | ||
340 | |||
341 | return hostap_hw_ready(dev); | ||
342 | |||
343 | fail: | ||
344 | if (irq_registered && dev) | ||
345 | free_irq(dev->irq, dev); | ||
346 | |||
347 | if (mem) | ||
348 | iounmap(mem); | ||
349 | |||
350 | release_mem_region(phymem, pci_resource_len(pdev, 0)); | ||
351 | |||
352 | err_out_disable: | ||
353 | pci_disable_device(pdev); | ||
354 | prism2_free_local_data(dev); | ||
355 | |||
356 | return -ENODEV; | ||
357 | } | ||
358 | |||
359 | |||
360 | static void prism2_pci_remove(struct pci_dev *pdev) | ||
361 | { | ||
362 | struct net_device *dev; | ||
363 | struct hostap_interface *iface; | ||
364 | void __iomem *mem_start; | ||
365 | |||
366 | dev = pci_get_drvdata(pdev); | ||
367 | iface = netdev_priv(dev); | ||
368 | |||
369 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
370 | prism2_pci_cor_sreset(iface->local); | ||
371 | hfa384x_disable_interrupts(dev); | ||
372 | |||
373 | if (dev->irq) | ||
374 | free_irq(dev->irq, dev); | ||
375 | |||
376 | mem_start = iface->local->mem_start; | ||
377 | prism2_free_local_data(dev); | ||
378 | |||
379 | iounmap(mem_start); | ||
380 | |||
381 | release_mem_region(pci_resource_start(pdev, 0), | ||
382 | pci_resource_len(pdev, 0)); | ||
383 | pci_disable_device(pdev); | ||
384 | } | ||
385 | |||
386 | |||
387 | #ifdef CONFIG_PM | ||
388 | static int prism2_pci_suspend(struct pci_dev *pdev, u32 state) | ||
389 | { | ||
390 | struct net_device *dev = pci_get_drvdata(pdev); | ||
391 | |||
392 | if (netif_running(dev)) { | ||
393 | netif_stop_queue(dev); | ||
394 | netif_device_detach(dev); | ||
395 | } | ||
396 | prism2_suspend(dev); | ||
397 | pci_save_state(pdev); | ||
398 | pci_disable_device(pdev); | ||
399 | pci_set_power_state(pdev, 3); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int prism2_pci_resume(struct pci_dev *pdev) | ||
405 | { | ||
406 | struct net_device *dev = pci_get_drvdata(pdev); | ||
407 | |||
408 | pci_enable_device(pdev); | ||
409 | pci_restore_state(pdev); | ||
410 | prism2_hw_config(dev, 0); | ||
411 | if (netif_running(dev)) { | ||
412 | netif_device_attach(dev); | ||
413 | netif_start_queue(dev); | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | #endif /* CONFIG_PM */ | ||
419 | |||
420 | |||
421 | MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); | ||
422 | |||
423 | static struct pci_driver prism2_pci_drv_id = { | ||
424 | .name = "prism2_pci", | ||
425 | .id_table = prism2_pci_id_table, | ||
426 | .probe = prism2_pci_probe, | ||
427 | .remove = prism2_pci_remove, | ||
428 | #ifdef CONFIG_PM | ||
429 | .suspend = prism2_pci_suspend, | ||
430 | .resume = prism2_pci_resume, | ||
431 | #endif /* CONFIG_PM */ | ||
432 | /* Linux 2.4.6 added save_state and enable_wake that are not used here | ||
433 | */ | ||
434 | }; | ||
435 | |||
436 | |||
437 | static int __init init_prism2_pci(void) | ||
438 | { | ||
439 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
440 | |||
441 | return pci_register_driver(&prism2_pci_drv_id); | ||
442 | } | ||
443 | |||
444 | |||
445 | static void __exit exit_prism2_pci(void) | ||
446 | { | ||
447 | pci_unregister_driver(&prism2_pci_drv_id); | ||
448 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
449 | } | ||
450 | |||
451 | |||
452 | module_init(init_prism2_pci); | ||
453 | 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 00000000000..ec33501e094 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_plx.c | |||
@@ -0,0 +1,620 @@ | |||
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 | |||
38 | |||
39 | static int ignore_cis; | ||
40 | module_param(ignore_cis, int, 0444); | ||
41 | MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); | ||
42 | |||
43 | |||
44 | #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ | ||
45 | #define COR_SRESET 0x80 | ||
46 | #define COR_LEVLREQ 0x40 | ||
47 | #define COR_ENABLE_FUNC 0x01 | ||
48 | /* PCI Configuration Registers */ | ||
49 | #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ | ||
50 | /* Local Configuration Registers */ | ||
51 | #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ | ||
52 | #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ | ||
53 | #define PLX_CNTRL 0x50 | ||
54 | #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) | ||
55 | |||
56 | |||
57 | #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } | ||
58 | |||
59 | static struct pci_device_id prism2_plx_id_table[] __devinitdata = { | ||
60 | PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), | ||
61 | PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), | ||
62 | PLXDEV(0x126c, 0x8030, "Nortel emobility"), | ||
63 | PLXDEV(0x1385, 0x4100, "Netgear MA301"), | ||
64 | PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), | ||
65 | PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), | ||
66 | PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), | ||
67 | PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), | ||
68 | PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), | ||
69 | PLXDEV(0x16ab, 0x1103, "Longshine 8031"), | ||
70 | PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), | ||
71 | PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), | ||
72 | { 0 } | ||
73 | }; | ||
74 | |||
75 | |||
76 | /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid | ||
77 | * is not listed here, you will need to add it here to get the driver | ||
78 | * initialized. */ | ||
79 | static struct prism2_plx_manfid { | ||
80 | u16 manfid1, manfid2; | ||
81 | } prism2_plx_known_manfids[] = { | ||
82 | { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, | ||
83 | { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, | ||
84 | { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, | ||
85 | { 0x0126, 0x8000 } /* Proxim RangeLAN */, | ||
86 | { 0x0138, 0x0002 } /* Compaq WL100 */, | ||
87 | { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, | ||
88 | { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, | ||
89 | { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, | ||
90 | { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, | ||
91 | { 0x028a, 0x0002 } /* D-Link DRC-650 */, | ||
92 | { 0x0250, 0x0002 } /* Samsung SWL2000-N */, | ||
93 | { 0xc250, 0x0002 } /* EMTAC A2424i */, | ||
94 | { 0xd601, 0x0002 } /* Z-Com XI300 */, | ||
95 | { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, | ||
96 | { 0, 0} | ||
97 | }; | ||
98 | |||
99 | |||
100 | #ifdef PRISM2_IO_DEBUG | ||
101 | |||
102 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
103 | { | ||
104 | struct hostap_interface *iface; | ||
105 | local_info_t *local; | ||
106 | unsigned long flags; | ||
107 | |||
108 | iface = netdev_priv(dev); | ||
109 | local = iface->local; | ||
110 | |||
111 | spin_lock_irqsave(&local->lock, flags); | ||
112 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
113 | outb(v, dev->base_addr + a); | ||
114 | spin_unlock_irqrestore(&local->lock, flags); | ||
115 | } | ||
116 | |||
117 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
118 | { | ||
119 | struct hostap_interface *iface; | ||
120 | local_info_t *local; | ||
121 | unsigned long flags; | ||
122 | u8 v; | ||
123 | |||
124 | iface = netdev_priv(dev); | ||
125 | local = iface->local; | ||
126 | |||
127 | spin_lock_irqsave(&local->lock, flags); | ||
128 | v = inb(dev->base_addr + a); | ||
129 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
130 | spin_unlock_irqrestore(&local->lock, flags); | ||
131 | return v; | ||
132 | } | ||
133 | |||
134 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
135 | { | ||
136 | struct hostap_interface *iface; | ||
137 | local_info_t *local; | ||
138 | unsigned long flags; | ||
139 | |||
140 | iface = netdev_priv(dev); | ||
141 | local = iface->local; | ||
142 | |||
143 | spin_lock_irqsave(&local->lock, flags); | ||
144 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
145 | outw(v, dev->base_addr + a); | ||
146 | spin_unlock_irqrestore(&local->lock, flags); | ||
147 | } | ||
148 | |||
149 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
150 | { | ||
151 | struct hostap_interface *iface; | ||
152 | local_info_t *local; | ||
153 | unsigned long flags; | ||
154 | u16 v; | ||
155 | |||
156 | iface = netdev_priv(dev); | ||
157 | local = iface->local; | ||
158 | |||
159 | spin_lock_irqsave(&local->lock, flags); | ||
160 | v = inw(dev->base_addr + a); | ||
161 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
162 | spin_unlock_irqrestore(&local->lock, flags); | ||
163 | return v; | ||
164 | } | ||
165 | |||
166 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
167 | u8 *buf, int wc) | ||
168 | { | ||
169 | struct hostap_interface *iface; | ||
170 | local_info_t *local; | ||
171 | unsigned long flags; | ||
172 | |||
173 | iface = netdev_priv(dev); | ||
174 | local = iface->local; | ||
175 | |||
176 | spin_lock_irqsave(&local->lock, flags); | ||
177 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
178 | outsw(dev->base_addr + a, buf, wc); | ||
179 | spin_unlock_irqrestore(&local->lock, flags); | ||
180 | } | ||
181 | |||
182 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
183 | u8 *buf, int wc) | ||
184 | { | ||
185 | struct hostap_interface *iface; | ||
186 | local_info_t *local; | ||
187 | unsigned long flags; | ||
188 | |||
189 | iface = netdev_priv(dev); | ||
190 | local = iface->local; | ||
191 | |||
192 | spin_lock_irqsave(&local->lock, flags); | ||
193 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
194 | insw(dev->base_addr + a, buf, wc); | ||
195 | spin_unlock_irqrestore(&local->lock, flags); | ||
196 | } | ||
197 | |||
198 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
199 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
200 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
201 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
202 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
203 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
204 | |||
205 | #else /* PRISM2_IO_DEBUG */ | ||
206 | |||
207 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
208 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
209 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
210 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
211 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
212 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
213 | |||
214 | #endif /* PRISM2_IO_DEBUG */ | ||
215 | |||
216 | |||
217 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
218 | int len) | ||
219 | { | ||
220 | u16 d_off; | ||
221 | u16 *pos; | ||
222 | |||
223 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
224 | pos = (u16 *) buf; | ||
225 | |||
226 | if (len / 2) | ||
227 | HFA384X_INSW(d_off, buf, len / 2); | ||
228 | pos += len / 2; | ||
229 | |||
230 | if (len & 1) | ||
231 | *((char *) pos) = HFA384X_INB(d_off); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | |||
237 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
238 | { | ||
239 | u16 d_off; | ||
240 | u16 *pos; | ||
241 | |||
242 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
243 | pos = (u16 *) buf; | ||
244 | |||
245 | if (len / 2) | ||
246 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
247 | pos += len / 2; | ||
248 | |||
249 | if (len & 1) | ||
250 | HFA384X_OUTB(*((char *) pos), d_off); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | /* FIX: This might change at some point.. */ | ||
257 | #include "hostap_hw.c" | ||
258 | |||
259 | |||
260 | static void prism2_plx_cor_sreset(local_info_t *local) | ||
261 | { | ||
262 | unsigned char corsave; | ||
263 | |||
264 | printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", | ||
265 | dev_info); | ||
266 | |||
267 | /* Set sreset bit of COR and clear it after hold time */ | ||
268 | |||
269 | if (local->attr_mem == NULL) { | ||
270 | /* TMD7160 - COR at card's first I/O addr */ | ||
271 | corsave = inb(local->cor_offset); | ||
272 | outb(corsave | COR_SRESET, local->cor_offset); | ||
273 | mdelay(2); | ||
274 | outb(corsave & ~COR_SRESET, local->cor_offset); | ||
275 | mdelay(2); | ||
276 | } else { | ||
277 | /* PLX9052 */ | ||
278 | corsave = readb(local->attr_mem + local->cor_offset); | ||
279 | writeb(corsave | COR_SRESET, | ||
280 | local->attr_mem + local->cor_offset); | ||
281 | mdelay(2); | ||
282 | writeb(corsave & ~COR_SRESET, | ||
283 | local->attr_mem + local->cor_offset); | ||
284 | mdelay(2); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | static void prism2_plx_genesis_reset(local_info_t *local, int hcr) | ||
290 | { | ||
291 | unsigned char corsave; | ||
292 | |||
293 | if (local->attr_mem == NULL) { | ||
294 | /* TMD7160 - COR at card's first I/O addr */ | ||
295 | corsave = inb(local->cor_offset); | ||
296 | outb(corsave | COR_SRESET, local->cor_offset); | ||
297 | mdelay(10); | ||
298 | outb(hcr, local->cor_offset + 2); | ||
299 | mdelay(10); | ||
300 | outb(corsave & ~COR_SRESET, local->cor_offset); | ||
301 | mdelay(10); | ||
302 | } else { | ||
303 | /* PLX9052 */ | ||
304 | corsave = readb(local->attr_mem + local->cor_offset); | ||
305 | writeb(corsave | COR_SRESET, | ||
306 | local->attr_mem + local->cor_offset); | ||
307 | mdelay(10); | ||
308 | writeb(hcr, local->attr_mem + local->cor_offset + 2); | ||
309 | mdelay(10); | ||
310 | writeb(corsave & ~COR_SRESET, | ||
311 | local->attr_mem + local->cor_offset); | ||
312 | mdelay(10); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | |||
317 | static struct prism2_helper_functions prism2_plx_funcs = | ||
318 | { | ||
319 | .card_present = NULL, | ||
320 | .cor_sreset = prism2_plx_cor_sreset, | ||
321 | .dev_open = NULL, | ||
322 | .dev_close = NULL, | ||
323 | .genesis_reset = prism2_plx_genesis_reset, | ||
324 | .hw_type = HOSTAP_HW_PLX, | ||
325 | }; | ||
326 | |||
327 | |||
328 | static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, | ||
329 | unsigned int *cor_offset, | ||
330 | unsigned int *cor_index) | ||
331 | { | ||
332 | #define CISTPL_CONFIG 0x1A | ||
333 | #define CISTPL_MANFID 0x20 | ||
334 | #define CISTPL_END 0xFF | ||
335 | #define CIS_MAX_LEN 256 | ||
336 | u8 *cis; | ||
337 | int i, pos; | ||
338 | unsigned int rmsz, rasz, manfid1, manfid2; | ||
339 | struct prism2_plx_manfid *manfid; | ||
340 | |||
341 | cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); | ||
342 | if (cis == NULL) | ||
343 | return -ENOMEM; | ||
344 | |||
345 | /* read CIS; it is in even offsets in the beginning of attr_mem */ | ||
346 | for (i = 0; i < CIS_MAX_LEN; i++) | ||
347 | cis[i] = readb(attr_mem + 2 * i); | ||
348 | printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n", | ||
349 | dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]); | ||
350 | |||
351 | /* set reasonable defaults for Prism2 cards just in case CIS parsing | ||
352 | * fails */ | ||
353 | *cor_offset = 0x3e0; | ||
354 | *cor_index = 0x01; | ||
355 | manfid1 = manfid2 = 0; | ||
356 | |||
357 | pos = 0; | ||
358 | while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { | ||
359 | if (pos + cis[pos + 1] >= CIS_MAX_LEN) | ||
360 | goto cis_error; | ||
361 | |||
362 | switch (cis[pos]) { | ||
363 | case CISTPL_CONFIG: | ||
364 | if (cis[pos + 1] < 1) | ||
365 | goto cis_error; | ||
366 | rmsz = (cis[pos + 2] & 0x3c) >> 2; | ||
367 | rasz = cis[pos + 2] & 0x03; | ||
368 | if (4 + rasz + rmsz > cis[pos + 1]) | ||
369 | goto cis_error; | ||
370 | *cor_index = cis[pos + 3] & 0x3F; | ||
371 | *cor_offset = 0; | ||
372 | for (i = 0; i <= rasz; i++) | ||
373 | *cor_offset += cis[pos + 4 + i] << (8 * i); | ||
374 | printk(KERN_DEBUG "%s: cor_index=0x%x " | ||
375 | "cor_offset=0x%x\n", dev_info, | ||
376 | *cor_index, *cor_offset); | ||
377 | if (*cor_offset > attr_len) { | ||
378 | printk(KERN_ERR "%s: COR offset not within " | ||
379 | "attr_mem\n", dev_info); | ||
380 | kfree(cis); | ||
381 | return -1; | ||
382 | } | ||
383 | break; | ||
384 | |||
385 | case CISTPL_MANFID: | ||
386 | if (cis[pos + 1] < 4) | ||
387 | goto cis_error; | ||
388 | manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); | ||
389 | manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); | ||
390 | printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", | ||
391 | dev_info, manfid1, manfid2); | ||
392 | break; | ||
393 | } | ||
394 | |||
395 | pos += cis[pos + 1] + 2; | ||
396 | } | ||
397 | |||
398 | if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) | ||
399 | goto cis_error; | ||
400 | |||
401 | for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) | ||
402 | if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { | ||
403 | kfree(cis); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" | ||
408 | " not supported card\n", dev_info, manfid1, manfid2); | ||
409 | goto fail; | ||
410 | |||
411 | cis_error: | ||
412 | printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); | ||
413 | |||
414 | fail: | ||
415 | kfree(cis); | ||
416 | if (ignore_cis) { | ||
417 | printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " | ||
418 | "errors during CIS verification\n", dev_info); | ||
419 | return 0; | ||
420 | } | ||
421 | return -1; | ||
422 | } | ||
423 | |||
424 | |||
425 | static int prism2_plx_probe(struct pci_dev *pdev, | ||
426 | const struct pci_device_id *id) | ||
427 | { | ||
428 | unsigned int pccard_ioaddr, plx_ioaddr; | ||
429 | unsigned long pccard_attr_mem; | ||
430 | unsigned int pccard_attr_len; | ||
431 | void __iomem *attr_mem = NULL; | ||
432 | unsigned int cor_offset, cor_index; | ||
433 | u32 reg; | ||
434 | local_info_t *local = NULL; | ||
435 | struct net_device *dev = NULL; | ||
436 | struct hostap_interface *iface; | ||
437 | static int cards_found /* = 0 */; | ||
438 | int irq_registered = 0; | ||
439 | int tmd7160; | ||
440 | |||
441 | if (pci_enable_device(pdev)) | ||
442 | return -EIO; | ||
443 | |||
444 | /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ | ||
445 | tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); | ||
446 | |||
447 | plx_ioaddr = pci_resource_start(pdev, 1); | ||
448 | pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); | ||
449 | |||
450 | if (tmd7160) { | ||
451 | /* TMD7160 */ | ||
452 | attr_mem = NULL; /* no access to PC Card attribute memory */ | ||
453 | |||
454 | printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " | ||
455 | "irq=%d, pccard_io=0x%x\n", | ||
456 | plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
457 | |||
458 | cor_offset = plx_ioaddr; | ||
459 | cor_index = 0x04; | ||
460 | |||
461 | outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); | ||
462 | mdelay(1); | ||
463 | reg = inb(plx_ioaddr); | ||
464 | if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { | ||
465 | printk(KERN_ERR "%s: Error setting COR (expected=" | ||
466 | "0x%02x, was=0x%02x)\n", dev_info, | ||
467 | cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); | ||
468 | goto fail; | ||
469 | } | ||
470 | } else { | ||
471 | /* PLX9052 */ | ||
472 | pccard_attr_mem = pci_resource_start(pdev, 2); | ||
473 | pccard_attr_len = pci_resource_len(pdev, 2); | ||
474 | if (pccard_attr_len < PLX_MIN_ATTR_LEN) | ||
475 | goto fail; | ||
476 | |||
477 | |||
478 | attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); | ||
479 | if (attr_mem == NULL) { | ||
480 | printk(KERN_ERR "%s: cannot remap attr_mem\n", | ||
481 | dev_info); | ||
482 | goto fail; | ||
483 | } | ||
484 | |||
485 | printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " | ||
486 | "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", | ||
487 | pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
488 | |||
489 | if (prism2_plx_check_cis(attr_mem, pccard_attr_len, | ||
490 | &cor_offset, &cor_index)) { | ||
491 | printk(KERN_INFO "Unknown PC Card CIS - not a " | ||
492 | "Prism2/2.5 card?\n"); | ||
493 | goto fail; | ||
494 | } | ||
495 | |||
496 | printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " | ||
497 | "adapter\n"); | ||
498 | |||
499 | /* Write COR to enable PC Card */ | ||
500 | writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, | ||
501 | attr_mem + cor_offset); | ||
502 | |||
503 | /* Enable PCI interrupts if they are not already enabled */ | ||
504 | reg = inl(plx_ioaddr + PLX_INTCSR); | ||
505 | printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); | ||
506 | if (!(reg & PLX_INTCSR_PCI_INTEN)) { | ||
507 | outl(reg | PLX_INTCSR_PCI_INTEN, | ||
508 | plx_ioaddr + PLX_INTCSR); | ||
509 | if (!(inl(plx_ioaddr + PLX_INTCSR) & | ||
510 | PLX_INTCSR_PCI_INTEN)) { | ||
511 | printk(KERN_WARNING "%s: Could not enable " | ||
512 | "Local Interrupts\n", dev_info); | ||
513 | goto fail; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | reg = inl(plx_ioaddr + PLX_CNTRL); | ||
518 | printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " | ||
519 | "present=%d)\n", | ||
520 | reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); | ||
521 | /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is | ||
522 | * not present; but are there really such cards in use(?) */ | ||
523 | } | ||
524 | |||
525 | dev = prism2_init_local_data(&prism2_plx_funcs, cards_found); | ||
526 | if (dev == NULL) | ||
527 | goto fail; | ||
528 | iface = netdev_priv(dev); | ||
529 | local = iface->local; | ||
530 | cards_found++; | ||
531 | |||
532 | dev->irq = pdev->irq; | ||
533 | dev->base_addr = pccard_ioaddr; | ||
534 | local->attr_mem = attr_mem; | ||
535 | local->cor_offset = cor_offset; | ||
536 | |||
537 | pci_set_drvdata(pdev, dev); | ||
538 | |||
539 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
540 | dev)) { | ||
541 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
542 | goto fail; | ||
543 | } else | ||
544 | irq_registered = 1; | ||
545 | |||
546 | if (prism2_hw_config(dev, 1)) { | ||
547 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
548 | dev_info); | ||
549 | goto fail; | ||
550 | } | ||
551 | |||
552 | return hostap_hw_ready(dev); | ||
553 | |||
554 | fail: | ||
555 | prism2_free_local_data(dev); | ||
556 | |||
557 | if (irq_registered && dev) | ||
558 | free_irq(dev->irq, dev); | ||
559 | |||
560 | if (attr_mem) | ||
561 | iounmap(attr_mem); | ||
562 | |||
563 | pci_disable_device(pdev); | ||
564 | |||
565 | return -ENODEV; | ||
566 | } | ||
567 | |||
568 | |||
569 | static void prism2_plx_remove(struct pci_dev *pdev) | ||
570 | { | ||
571 | struct net_device *dev; | ||
572 | struct hostap_interface *iface; | ||
573 | |||
574 | dev = pci_get_drvdata(pdev); | ||
575 | iface = netdev_priv(dev); | ||
576 | |||
577 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
578 | prism2_plx_cor_sreset(iface->local); | ||
579 | hfa384x_disable_interrupts(dev); | ||
580 | |||
581 | if (iface->local->attr_mem) | ||
582 | iounmap(iface->local->attr_mem); | ||
583 | if (dev->irq) | ||
584 | free_irq(dev->irq, dev); | ||
585 | |||
586 | prism2_free_local_data(dev); | ||
587 | pci_disable_device(pdev); | ||
588 | } | ||
589 | |||
590 | |||
591 | MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); | ||
592 | |||
593 | static struct pci_driver prism2_plx_drv_id = { | ||
594 | .name = "prism2_plx", | ||
595 | .id_table = prism2_plx_id_table, | ||
596 | .probe = prism2_plx_probe, | ||
597 | .remove = prism2_plx_remove, | ||
598 | .suspend = NULL, | ||
599 | .resume = NULL, | ||
600 | .enable_wake = NULL | ||
601 | }; | ||
602 | |||
603 | |||
604 | static int __init init_prism2_plx(void) | ||
605 | { | ||
606 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
607 | |||
608 | return pci_register_driver(&prism2_plx_drv_id); | ||
609 | } | ||
610 | |||
611 | |||
612 | static void __exit exit_prism2_plx(void) | ||
613 | { | ||
614 | pci_unregister_driver(&prism2_plx_drv_id); | ||
615 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
616 | } | ||
617 | |||
618 | |||
619 | module_init(init_prism2_plx); | ||
620 | 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 00000000000..81b321ba189 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_proc.c | |||
@@ -0,0 +1,466 @@ | |||
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 entries, entry, i, len, total = 0, hostscan; | ||
306 | struct hfa384x_scan_result *scanres; | ||
307 | struct hfa384x_hostscan_result *hscanres; | ||
308 | u8 *pos; | ||
309 | |||
310 | p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " | ||
311 | "SSID\n"); | ||
312 | |||
313 | spin_lock_bh(&local->lock); | ||
314 | hostscan = local->last_scan_type == PRISM2_HOSTSCAN; | ||
315 | entries = hostscan ? local->last_hostscan_results_count : | ||
316 | local->last_scan_results_count; | ||
317 | for (entry = 0; entry < entries; entry++) { | ||
318 | hscanres = &local->last_hostscan_results[entry]; | ||
319 | scanres = &local->last_scan_results[entry]; | ||
320 | |||
321 | if (total + (p - page) <= off) { | ||
322 | total += p - page; | ||
323 | p = page; | ||
324 | } | ||
325 | if (total + (p - page) > off + count) | ||
326 | break; | ||
327 | if ((p - page) > (PAGE_SIZE - 200)) | ||
328 | break; | ||
329 | |||
330 | if (hostscan) { | ||
331 | p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", | ||
332 | le16_to_cpu(hscanres->chid), | ||
333 | (s16) le16_to_cpu(hscanres->anl), | ||
334 | (s16) le16_to_cpu(hscanres->sl), | ||
335 | le16_to_cpu(hscanres->beacon_interval), | ||
336 | le16_to_cpu(hscanres->capability), | ||
337 | le16_to_cpu(hscanres->rate), | ||
338 | MAC2STR(hscanres->bssid), | ||
339 | le16_to_cpu(hscanres->atim)); | ||
340 | } else { | ||
341 | p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR | ||
342 | " N/A ", | ||
343 | le16_to_cpu(scanres->chid), | ||
344 | (s16) le16_to_cpu(scanres->anl), | ||
345 | (s16) le16_to_cpu(scanres->sl), | ||
346 | le16_to_cpu(scanres->beacon_interval), | ||
347 | le16_to_cpu(scanres->capability), | ||
348 | le16_to_cpu(scanres->rate), | ||
349 | MAC2STR(scanres->bssid)); | ||
350 | } | ||
351 | |||
352 | pos = hostscan ? hscanres->sup_rates : scanres->sup_rates; | ||
353 | for (i = 0; i < sizeof(hscanres->sup_rates); i++) { | ||
354 | if (pos[i] == 0) | ||
355 | break; | ||
356 | p += sprintf(p, "<%02x>", pos[i]); | ||
357 | } | ||
358 | p += sprintf(p, " "); | ||
359 | |||
360 | pos = hostscan ? hscanres->ssid : scanres->ssid; | ||
361 | len = le16_to_cpu(hostscan ? hscanres->ssid_len : | ||
362 | scanres->ssid_len); | ||
363 | if (len > 32) | ||
364 | len = 32; | ||
365 | for (i = 0; i < len; i++) { | ||
366 | unsigned char c = pos[i]; | ||
367 | if (c >= 32 && c < 127) | ||
368 | p += sprintf(p, "%c", c); | ||
369 | else | ||
370 | p += sprintf(p, "<%02x>", c); | ||
371 | } | ||
372 | p += sprintf(p, "\n"); | ||
373 | } | ||
374 | spin_unlock_bh(&local->lock); | ||
375 | |||
376 | total += (p - page); | ||
377 | if (total >= off + count) | ||
378 | *eof = 1; | ||
379 | |||
380 | if (total < off) { | ||
381 | *eof = 1; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | len = total - off; | ||
386 | if (len > (p - page)) | ||
387 | len = p - page; | ||
388 | *start = p - len; | ||
389 | if (len > count) | ||
390 | len = count; | ||
391 | |||
392 | return len; | ||
393 | } | ||
394 | #endif /* PRISM2_NO_STATION_MODES */ | ||
395 | |||
396 | |||
397 | void hostap_init_proc(local_info_t *local) | ||
398 | { | ||
399 | local->proc = NULL; | ||
400 | |||
401 | if (hostap_proc == NULL) { | ||
402 | printk(KERN_WARNING "%s: hostap proc directory not created\n", | ||
403 | local->dev->name); | ||
404 | return; | ||
405 | } | ||
406 | |||
407 | local->proc = proc_mkdir(local->ddev->name, hostap_proc); | ||
408 | if (local->proc == NULL) { | ||
409 | printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", | ||
410 | local->ddev->name); | ||
411 | return; | ||
412 | } | ||
413 | |||
414 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
415 | create_proc_read_entry("debug", 0, local->proc, | ||
416 | prism2_debug_proc_read, local); | ||
417 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
418 | create_proc_read_entry("stats", 0, local->proc, | ||
419 | prism2_stats_proc_read, local); | ||
420 | create_proc_read_entry("wds", 0, local->proc, | ||
421 | prism2_wds_proc_read, local); | ||
422 | create_proc_read_entry("pda", 0, local->proc, | ||
423 | prism2_pda_proc_read, local); | ||
424 | create_proc_read_entry("aux_dump", 0, local->proc, | ||
425 | prism2_aux_dump_proc_read, local); | ||
426 | create_proc_read_entry("bss_list", 0, local->proc, | ||
427 | prism2_bss_list_proc_read, local); | ||
428 | create_proc_read_entry("crypt", 0, local->proc, | ||
429 | prism2_crypt_proc_read, local); | ||
430 | #ifdef PRISM2_IO_DEBUG | ||
431 | create_proc_read_entry("io_debug", 0, local->proc, | ||
432 | prism2_io_debug_proc_read, local); | ||
433 | #endif /* PRISM2_IO_DEBUG */ | ||
434 | #ifndef PRISM2_NO_STATION_MODES | ||
435 | create_proc_read_entry("scan_results", 0, local->proc, | ||
436 | prism2_scan_results_proc_read, local); | ||
437 | #endif /* PRISM2_NO_STATION_MODES */ | ||
438 | } | ||
439 | |||
440 | |||
441 | void hostap_remove_proc(local_info_t *local) | ||
442 | { | ||
443 | if (local->proc != NULL) { | ||
444 | #ifndef PRISM2_NO_STATION_MODES | ||
445 | remove_proc_entry("scan_results", local->proc); | ||
446 | #endif /* PRISM2_NO_STATION_MODES */ | ||
447 | #ifdef PRISM2_IO_DEBUG | ||
448 | remove_proc_entry("io_debug", local->proc); | ||
449 | #endif /* PRISM2_IO_DEBUG */ | ||
450 | remove_proc_entry("pda", local->proc); | ||
451 | remove_proc_entry("aux_dump", local->proc); | ||
452 | remove_proc_entry("wds", local->proc); | ||
453 | remove_proc_entry("stats", local->proc); | ||
454 | remove_proc_entry("bss_list", local->proc); | ||
455 | remove_proc_entry("crypt", local->proc); | ||
456 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
457 | remove_proc_entry("debug", local->proc); | ||
458 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
459 | if (hostap_proc != NULL) | ||
460 | remove_proc_entry(local->proc->name, hostap_proc); | ||
461 | } | ||
462 | } | ||
463 | |||
464 | |||
465 | EXPORT_SYMBOL(hostap_init_proc); | ||
466 | 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 00000000000..4b32e2e887b --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_wlan.h | |||
@@ -0,0 +1,1075 @@ | |||
1 | #ifndef HOSTAP_WLAN_H | ||
2 | #define HOSTAP_WLAN_H | ||
3 | |||
4 | #include "hostap_config.h" | ||
5 | #include "hostap_crypt.h" | ||
6 | #include "hostap_common.h" | ||
7 | |||
8 | #define MAX_PARM_DEVICES 8 | ||
9 | #define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) | ||
10 | #define DEF_INTS -1, -1, -1, -1, -1, -1, -1 | ||
11 | #define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] | ||
12 | |||
13 | |||
14 | /* Specific skb->protocol value that indicates that the packet already contains | ||
15 | * txdesc header. | ||
16 | * FIX: This might need own value that would be allocated especially for Prism2 | ||
17 | * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". | ||
18 | * However, these skb's should have only minimal path in the kernel side since | ||
19 | * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ | ||
20 | #define ETH_P_HOSTAP ETH_P_CONTROL | ||
21 | |||
22 | #ifndef ARPHRD_IEEE80211 | ||
23 | #define ARPHRD_IEEE80211 801 | ||
24 | #endif | ||
25 | #ifndef ARPHRD_IEEE80211_PRISM | ||
26 | #define ARPHRD_IEEE80211_PRISM 802 | ||
27 | #endif | ||
28 | |||
29 | /* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header | ||
30 | * (from linux-wlan-ng) */ | ||
31 | struct linux_wlan_ng_val { | ||
32 | u32 did; | ||
33 | u16 status, len; | ||
34 | u32 data; | ||
35 | } __attribute__ ((packed)); | ||
36 | |||
37 | struct linux_wlan_ng_prism_hdr { | ||
38 | u32 msgcode, msglen; | ||
39 | char devname[16]; | ||
40 | struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, | ||
41 | noise, rate, istx, frmlen; | ||
42 | } __attribute__ ((packed)); | ||
43 | |||
44 | struct linux_wlan_ng_cap_hdr { | ||
45 | u32 version; | ||
46 | u32 length; | ||
47 | u64 mactime; | ||
48 | u64 hosttime; | ||
49 | u32 phytype; | ||
50 | u32 channel; | ||
51 | u32 datarate; | ||
52 | u32 antenna; | ||
53 | u32 priority; | ||
54 | u32 ssi_type; | ||
55 | s32 ssi_signal; | ||
56 | s32 ssi_noise; | ||
57 | u32 preamble; | ||
58 | u32 encoding; | ||
59 | } __attribute__ ((packed)); | ||
60 | |||
61 | #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ | ||
62 | #define LWNG_CAPHDR_VERSION 0x80211001 | ||
63 | |||
64 | struct hfa384x_rx_frame { | ||
65 | /* HFA384X RX frame descriptor */ | ||
66 | u16 status; /* HFA384X_RX_STATUS_ flags */ | ||
67 | u32 time; /* timestamp, 1 microsecond resolution */ | ||
68 | u8 silence; /* 27 .. 154; seems to be 0 */ | ||
69 | u8 signal; /* 27 .. 154 */ | ||
70 | u8 rate; /* 10, 20, 55, or 110 */ | ||
71 | u8 rxflow; | ||
72 | u32 reserved; | ||
73 | |||
74 | /* 802.11 */ | ||
75 | u16 frame_control; | ||
76 | u16 duration_id; | ||
77 | u8 addr1[6]; | ||
78 | u8 addr2[6]; | ||
79 | u8 addr3[6]; | ||
80 | u16 seq_ctrl; | ||
81 | u8 addr4[6]; | ||
82 | u16 data_len; | ||
83 | |||
84 | /* 802.3 */ | ||
85 | u8 dst_addr[6]; | ||
86 | u8 src_addr[6]; | ||
87 | u16 len; | ||
88 | |||
89 | /* followed by frame data; max 2304 bytes */ | ||
90 | } __attribute__ ((packed)); | ||
91 | |||
92 | |||
93 | struct hfa384x_tx_frame { | ||
94 | /* HFA384X TX frame descriptor */ | ||
95 | u16 status; /* HFA384X_TX_STATUS_ flags */ | ||
96 | u16 reserved1; | ||
97 | u16 reserved2; | ||
98 | u32 sw_support; | ||
99 | u8 retry_count; /* not yet implemented */ | ||
100 | u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ | ||
101 | u16 tx_control; /* HFA384X_TX_CTRL_ flags */ | ||
102 | |||
103 | /* 802.11 */ | ||
104 | u16 frame_control; /* parts not used */ | ||
105 | u16 duration_id; | ||
106 | u8 addr1[6]; | ||
107 | u8 addr2[6]; /* filled by firmware */ | ||
108 | u8 addr3[6]; | ||
109 | u16 seq_ctrl; /* filled by firmware */ | ||
110 | u8 addr4[6]; | ||
111 | u16 data_len; | ||
112 | |||
113 | /* 802.3 */ | ||
114 | u8 dst_addr[6]; | ||
115 | u8 src_addr[6]; | ||
116 | u16 len; | ||
117 | |||
118 | /* followed by frame data; max 2304 bytes */ | ||
119 | } __attribute__ ((packed)); | ||
120 | |||
121 | |||
122 | struct hfa384x_rid_hdr | ||
123 | { | ||
124 | u16 len; | ||
125 | u16 rid; | ||
126 | } __attribute__ ((packed)); | ||
127 | |||
128 | |||
129 | /* Macro for converting signal levels (range 27 .. 154) to wireless ext | ||
130 | * dBm value with some accuracy */ | ||
131 | #define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 | ||
132 | |||
133 | #define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 | ||
134 | |||
135 | struct hfa384x_scan_request { | ||
136 | u16 channel_list; | ||
137 | u16 txrate; /* HFA384X_RATES_* */ | ||
138 | } __attribute__ ((packed)); | ||
139 | |||
140 | struct hfa384x_hostscan_request { | ||
141 | u16 channel_list; | ||
142 | u16 txrate; | ||
143 | u16 target_ssid_len; | ||
144 | u8 target_ssid[32]; | ||
145 | } __attribute__ ((packed)); | ||
146 | |||
147 | struct hfa384x_join_request { | ||
148 | u8 bssid[6]; | ||
149 | u16 channel; | ||
150 | } __attribute__ ((packed)); | ||
151 | |||
152 | struct hfa384x_info_frame { | ||
153 | u16 len; | ||
154 | u16 type; | ||
155 | } __attribute__ ((packed)); | ||
156 | |||
157 | struct hfa384x_comm_tallies { | ||
158 | u16 tx_unicast_frames; | ||
159 | u16 tx_multicast_frames; | ||
160 | u16 tx_fragments; | ||
161 | u16 tx_unicast_octets; | ||
162 | u16 tx_multicast_octets; | ||
163 | u16 tx_deferred_transmissions; | ||
164 | u16 tx_single_retry_frames; | ||
165 | u16 tx_multiple_retry_frames; | ||
166 | u16 tx_retry_limit_exceeded; | ||
167 | u16 tx_discards; | ||
168 | u16 rx_unicast_frames; | ||
169 | u16 rx_multicast_frames; | ||
170 | u16 rx_fragments; | ||
171 | u16 rx_unicast_octets; | ||
172 | u16 rx_multicast_octets; | ||
173 | u16 rx_fcs_errors; | ||
174 | u16 rx_discards_no_buffer; | ||
175 | u16 tx_discards_wrong_sa; | ||
176 | u16 rx_discards_wep_undecryptable; | ||
177 | u16 rx_message_in_msg_fragments; | ||
178 | u16 rx_message_in_bad_msg_fragments; | ||
179 | } __attribute__ ((packed)); | ||
180 | |||
181 | struct hfa384x_comm_tallies32 { | ||
182 | u32 tx_unicast_frames; | ||
183 | u32 tx_multicast_frames; | ||
184 | u32 tx_fragments; | ||
185 | u32 tx_unicast_octets; | ||
186 | u32 tx_multicast_octets; | ||
187 | u32 tx_deferred_transmissions; | ||
188 | u32 tx_single_retry_frames; | ||
189 | u32 tx_multiple_retry_frames; | ||
190 | u32 tx_retry_limit_exceeded; | ||
191 | u32 tx_discards; | ||
192 | u32 rx_unicast_frames; | ||
193 | u32 rx_multicast_frames; | ||
194 | u32 rx_fragments; | ||
195 | u32 rx_unicast_octets; | ||
196 | u32 rx_multicast_octets; | ||
197 | u32 rx_fcs_errors; | ||
198 | u32 rx_discards_no_buffer; | ||
199 | u32 tx_discards_wrong_sa; | ||
200 | u32 rx_discards_wep_undecryptable; | ||
201 | u32 rx_message_in_msg_fragments; | ||
202 | u32 rx_message_in_bad_msg_fragments; | ||
203 | } __attribute__ ((packed)); | ||
204 | |||
205 | struct hfa384x_scan_result_hdr { | ||
206 | u16 reserved; | ||
207 | u16 scan_reason; | ||
208 | #define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ | ||
209 | #define HFA384X_SCAN_HOST_INITIATED 1 | ||
210 | #define HFA384X_SCAN_FIRMWARE_INITIATED 2 | ||
211 | #define HFA384X_SCAN_INQUIRY_FROM_HOST 3 | ||
212 | } __attribute__ ((packed)); | ||
213 | |||
214 | #define HFA384X_SCAN_MAX_RESULTS 32 | ||
215 | |||
216 | struct hfa384x_scan_result { | ||
217 | u16 chid; | ||
218 | u16 anl; | ||
219 | u16 sl; | ||
220 | u8 bssid[6]; | ||
221 | u16 beacon_interval; | ||
222 | u16 capability; | ||
223 | u16 ssid_len; | ||
224 | u8 ssid[32]; | ||
225 | u8 sup_rates[10]; | ||
226 | u16 rate; | ||
227 | } __attribute__ ((packed)); | ||
228 | |||
229 | struct hfa384x_hostscan_result { | ||
230 | u16 chid; | ||
231 | u16 anl; | ||
232 | u16 sl; | ||
233 | u8 bssid[6]; | ||
234 | u16 beacon_interval; | ||
235 | u16 capability; | ||
236 | u16 ssid_len; | ||
237 | u8 ssid[32]; | ||
238 | u8 sup_rates[10]; | ||
239 | u16 rate; | ||
240 | u16 atim; | ||
241 | } __attribute__ ((packed)); | ||
242 | |||
243 | struct comm_tallies_sums { | ||
244 | unsigned int tx_unicast_frames; | ||
245 | unsigned int tx_multicast_frames; | ||
246 | unsigned int tx_fragments; | ||
247 | unsigned int tx_unicast_octets; | ||
248 | unsigned int tx_multicast_octets; | ||
249 | unsigned int tx_deferred_transmissions; | ||
250 | unsigned int tx_single_retry_frames; | ||
251 | unsigned int tx_multiple_retry_frames; | ||
252 | unsigned int tx_retry_limit_exceeded; | ||
253 | unsigned int tx_discards; | ||
254 | unsigned int rx_unicast_frames; | ||
255 | unsigned int rx_multicast_frames; | ||
256 | unsigned int rx_fragments; | ||
257 | unsigned int rx_unicast_octets; | ||
258 | unsigned int rx_multicast_octets; | ||
259 | unsigned int rx_fcs_errors; | ||
260 | unsigned int rx_discards_no_buffer; | ||
261 | unsigned int tx_discards_wrong_sa; | ||
262 | unsigned int rx_discards_wep_undecryptable; | ||
263 | unsigned int rx_message_in_msg_fragments; | ||
264 | unsigned int rx_message_in_bad_msg_fragments; | ||
265 | }; | ||
266 | |||
267 | |||
268 | struct hfa384x_regs { | ||
269 | u16 cmd; | ||
270 | u16 evstat; | ||
271 | u16 offset0; | ||
272 | u16 offset1; | ||
273 | u16 swsupport0; | ||
274 | }; | ||
275 | |||
276 | |||
277 | #if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) | ||
278 | /* I/O ports for HFA384X Controller access */ | ||
279 | #define HFA384X_CMD_OFF 0x00 | ||
280 | #define HFA384X_PARAM0_OFF 0x02 | ||
281 | #define HFA384X_PARAM1_OFF 0x04 | ||
282 | #define HFA384X_PARAM2_OFF 0x06 | ||
283 | #define HFA384X_STATUS_OFF 0x08 | ||
284 | #define HFA384X_RESP0_OFF 0x0A | ||
285 | #define HFA384X_RESP1_OFF 0x0C | ||
286 | #define HFA384X_RESP2_OFF 0x0E | ||
287 | #define HFA384X_INFOFID_OFF 0x10 | ||
288 | #define HFA384X_CONTROL_OFF 0x14 | ||
289 | #define HFA384X_SELECT0_OFF 0x18 | ||
290 | #define HFA384X_SELECT1_OFF 0x1A | ||
291 | #define HFA384X_OFFSET0_OFF 0x1C | ||
292 | #define HFA384X_OFFSET1_OFF 0x1E | ||
293 | #define HFA384X_RXFID_OFF 0x20 | ||
294 | #define HFA384X_ALLOCFID_OFF 0x22 | ||
295 | #define HFA384X_TXCOMPLFID_OFF 0x24 | ||
296 | #define HFA384X_SWSUPPORT0_OFF 0x28 | ||
297 | #define HFA384X_SWSUPPORT1_OFF 0x2A | ||
298 | #define HFA384X_SWSUPPORT2_OFF 0x2C | ||
299 | #define HFA384X_EVSTAT_OFF 0x30 | ||
300 | #define HFA384X_INTEN_OFF 0x32 | ||
301 | #define HFA384X_EVACK_OFF 0x34 | ||
302 | #define HFA384X_DATA0_OFF 0x36 | ||
303 | #define HFA384X_DATA1_OFF 0x38 | ||
304 | #define HFA384X_AUXPAGE_OFF 0x3A | ||
305 | #define HFA384X_AUXOFFSET_OFF 0x3C | ||
306 | #define HFA384X_AUXDATA_OFF 0x3E | ||
307 | #endif /* PRISM2_PCCARD || PRISM2_PLX */ | ||
308 | |||
309 | #ifdef PRISM2_PCI | ||
310 | /* Memory addresses for ISL3874 controller access */ | ||
311 | #define HFA384X_CMD_OFF 0x00 | ||
312 | #define HFA384X_PARAM0_OFF 0x04 | ||
313 | #define HFA384X_PARAM1_OFF 0x08 | ||
314 | #define HFA384X_PARAM2_OFF 0x0C | ||
315 | #define HFA384X_STATUS_OFF 0x10 | ||
316 | #define HFA384X_RESP0_OFF 0x14 | ||
317 | #define HFA384X_RESP1_OFF 0x18 | ||
318 | #define HFA384X_RESP2_OFF 0x1C | ||
319 | #define HFA384X_INFOFID_OFF 0x20 | ||
320 | #define HFA384X_CONTROL_OFF 0x28 | ||
321 | #define HFA384X_SELECT0_OFF 0x30 | ||
322 | #define HFA384X_SELECT1_OFF 0x34 | ||
323 | #define HFA384X_OFFSET0_OFF 0x38 | ||
324 | #define HFA384X_OFFSET1_OFF 0x3C | ||
325 | #define HFA384X_RXFID_OFF 0x40 | ||
326 | #define HFA384X_ALLOCFID_OFF 0x44 | ||
327 | #define HFA384X_TXCOMPLFID_OFF 0x48 | ||
328 | #define HFA384X_PCICOR_OFF 0x4C | ||
329 | #define HFA384X_SWSUPPORT0_OFF 0x50 | ||
330 | #define HFA384X_SWSUPPORT1_OFF 0x54 | ||
331 | #define HFA384X_SWSUPPORT2_OFF 0x58 | ||
332 | #define HFA384X_PCIHCR_OFF 0x5C | ||
333 | #define HFA384X_EVSTAT_OFF 0x60 | ||
334 | #define HFA384X_INTEN_OFF 0x64 | ||
335 | #define HFA384X_EVACK_OFF 0x68 | ||
336 | #define HFA384X_DATA0_OFF 0x6C | ||
337 | #define HFA384X_DATA1_OFF 0x70 | ||
338 | #define HFA384X_AUXPAGE_OFF 0x74 | ||
339 | #define HFA384X_AUXOFFSET_OFF 0x78 | ||
340 | #define HFA384X_AUXDATA_OFF 0x7C | ||
341 | #define HFA384X_PCI_M0_ADDRH_OFF 0x80 | ||
342 | #define HFA384X_PCI_M0_ADDRL_OFF 0x84 | ||
343 | #define HFA384X_PCI_M0_LEN_OFF 0x88 | ||
344 | #define HFA384X_PCI_M0_CTL_OFF 0x8C | ||
345 | #define HFA384X_PCI_STATUS_OFF 0x98 | ||
346 | #define HFA384X_PCI_M1_ADDRH_OFF 0xA0 | ||
347 | #define HFA384X_PCI_M1_ADDRL_OFF 0xA4 | ||
348 | #define HFA384X_PCI_M1_LEN_OFF 0xA8 | ||
349 | #define HFA384X_PCI_M1_CTL_OFF 0xAC | ||
350 | |||
351 | /* PCI bus master control bits (these are undocumented; based on guessing and | ||
352 | * experimenting..) */ | ||
353 | #define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) | ||
354 | #define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) | ||
355 | |||
356 | #endif /* PRISM2_PCI */ | ||
357 | |||
358 | |||
359 | /* Command codes for CMD reg. */ | ||
360 | #define HFA384X_CMDCODE_INIT 0x00 | ||
361 | #define HFA384X_CMDCODE_ENABLE 0x01 | ||
362 | #define HFA384X_CMDCODE_DISABLE 0x02 | ||
363 | #define HFA384X_CMDCODE_ALLOC 0x0A | ||
364 | #define HFA384X_CMDCODE_TRANSMIT 0x0B | ||
365 | #define HFA384X_CMDCODE_INQUIRE 0x11 | ||
366 | #define HFA384X_CMDCODE_ACCESS 0x21 | ||
367 | #define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) | ||
368 | #define HFA384X_CMDCODE_DOWNLOAD 0x22 | ||
369 | #define HFA384X_CMDCODE_READMIF 0x30 | ||
370 | #define HFA384X_CMDCODE_WRITEMIF 0x31 | ||
371 | #define HFA384X_CMDCODE_TEST 0x38 | ||
372 | |||
373 | #define HFA384X_CMDCODE_MASK 0x3F | ||
374 | |||
375 | /* Test mode operations */ | ||
376 | #define HFA384X_TEST_CHANGE_CHANNEL 0x08 | ||
377 | #define HFA384X_TEST_MONITOR 0x0B | ||
378 | #define HFA384X_TEST_STOP 0x0F | ||
379 | #define HFA384X_TEST_CFG_BITS 0x15 | ||
380 | #define HFA384X_TEST_CFG_BIT_ALC BIT(3) | ||
381 | |||
382 | #define HFA384X_CMD_BUSY BIT(15) | ||
383 | |||
384 | #define HFA384X_CMD_TX_RECLAIM BIT(8) | ||
385 | |||
386 | #define HFA384X_OFFSET_ERR BIT(14) | ||
387 | #define HFA384X_OFFSET_BUSY BIT(15) | ||
388 | |||
389 | |||
390 | /* ProgMode for download command */ | ||
391 | #define HFA384X_PROGMODE_DISABLE 0 | ||
392 | #define HFA384X_PROGMODE_ENABLE_VOLATILE 1 | ||
393 | #define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 | ||
394 | #define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 | ||
395 | |||
396 | #define HFA384X_AUX_MAGIC0 0xfe01 | ||
397 | #define HFA384X_AUX_MAGIC1 0xdc23 | ||
398 | #define HFA384X_AUX_MAGIC2 0xba45 | ||
399 | |||
400 | #define HFA384X_AUX_PORT_DISABLED 0 | ||
401 | #define HFA384X_AUX_PORT_DISABLE BIT(14) | ||
402 | #define HFA384X_AUX_PORT_ENABLE BIT(15) | ||
403 | #define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) | ||
404 | #define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) | ||
405 | |||
406 | #define PRISM2_PDA_SIZE 1024 | ||
407 | |||
408 | |||
409 | /* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ | ||
410 | #define HFA384X_EV_TICK BIT(15) | ||
411 | #define HFA384X_EV_WTERR BIT(14) | ||
412 | #define HFA384X_EV_INFDROP BIT(13) | ||
413 | #ifdef PRISM2_PCI | ||
414 | #define HFA384X_EV_PCI_M1 BIT(9) | ||
415 | #define HFA384X_EV_PCI_M0 BIT(8) | ||
416 | #endif /* PRISM2_PCI */ | ||
417 | #define HFA384X_EV_INFO BIT(7) | ||
418 | #define HFA384X_EV_DTIM BIT(5) | ||
419 | #define HFA384X_EV_CMD BIT(4) | ||
420 | #define HFA384X_EV_ALLOC BIT(3) | ||
421 | #define HFA384X_EV_TXEXC BIT(2) | ||
422 | #define HFA384X_EV_TX BIT(1) | ||
423 | #define HFA384X_EV_RX BIT(0) | ||
424 | |||
425 | |||
426 | /* HFA384X Information frames */ | ||
427 | #define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ | ||
428 | #define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ | ||
429 | #define HFA384X_INFO_COMMTALLIES 0xF100 | ||
430 | #define HFA384X_INFO_SCANRESULTS 0xF101 | ||
431 | #define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ | ||
432 | #define HFA384X_INFO_HOSTSCANRESULTS 0xF103 | ||
433 | #define HFA384X_INFO_LINKSTATUS 0xF200 | ||
434 | #define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ | ||
435 | #define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ | ||
436 | #define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ | ||
437 | #define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ | ||
438 | |||
439 | enum { HFA384X_LINKSTATUS_CONNECTED = 1, | ||
440 | HFA384X_LINKSTATUS_DISCONNECTED = 2, | ||
441 | HFA384X_LINKSTATUS_AP_CHANGE = 3, | ||
442 | HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, | ||
443 | HFA384X_LINKSTATUS_AP_IN_RANGE = 5, | ||
444 | HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; | ||
445 | |||
446 | enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, | ||
447 | HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, | ||
448 | HFA384X_PORTTYPE_HOSTAP = 6 }; | ||
449 | |||
450 | #define HFA384X_RATES_1MBPS BIT(0) | ||
451 | #define HFA384X_RATES_2MBPS BIT(1) | ||
452 | #define HFA384X_RATES_5MBPS BIT(2) | ||
453 | #define HFA384X_RATES_11MBPS BIT(3) | ||
454 | |||
455 | #define HFA384X_ROAMING_FIRMWARE 1 | ||
456 | #define HFA384X_ROAMING_HOST 2 | ||
457 | #define HFA384X_ROAMING_DISABLED 3 | ||
458 | |||
459 | #define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) | ||
460 | #define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) | ||
461 | #define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) | ||
462 | #define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) | ||
463 | |||
464 | #define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) | ||
465 | #define HFA384X_RX_STATUS_PCF BIT(12) | ||
466 | #define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) | ||
467 | #define HFA384X_RX_STATUS_UNDECR BIT(1) | ||
468 | #define HFA384X_RX_STATUS_FCSERR BIT(0) | ||
469 | |||
470 | #define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ | ||
471 | (((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) | ||
472 | #define HFA384X_RX_STATUS_GET_MACPORT(s) \ | ||
473 | (((s) & HFA384X_RX_STATUS_MACPORT) >> 8) | ||
474 | |||
475 | enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, | ||
476 | HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; | ||
477 | |||
478 | |||
479 | #define HFA384X_TX_CTRL_ALT_RTRY BIT(5) | ||
480 | #define HFA384X_TX_CTRL_802_11 BIT(3) | ||
481 | #define HFA384X_TX_CTRL_802_3 0 | ||
482 | #define HFA384X_TX_CTRL_TX_EX BIT(2) | ||
483 | #define HFA384X_TX_CTRL_TX_OK BIT(1) | ||
484 | |||
485 | #define HFA384X_TX_STATUS_RETRYERR BIT(0) | ||
486 | #define HFA384X_TX_STATUS_AGEDERR BIT(1) | ||
487 | #define HFA384X_TX_STATUS_DISCON BIT(2) | ||
488 | #define HFA384X_TX_STATUS_FORMERR BIT(3) | ||
489 | |||
490 | /* HFA3861/3863 (BBP) Control Registers */ | ||
491 | #define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ | ||
492 | #define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ | ||
493 | #define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ | ||
494 | #define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ | ||
495 | #define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ | ||
496 | |||
497 | |||
498 | #ifdef __KERNEL__ | ||
499 | |||
500 | #define PRISM2_TXFID_COUNT 8 | ||
501 | #define PRISM2_DATA_MAXLEN 2304 | ||
502 | #define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) | ||
503 | #define PRISM2_TXFID_EMPTY 0xffff | ||
504 | #define PRISM2_TXFID_RESERVED 0xfffe | ||
505 | #define PRISM2_DUMMY_FID 0xffff | ||
506 | #define MAX_SSID_LEN 32 | ||
507 | #define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ | ||
508 | |||
509 | #define PRISM2_DUMP_RX_HDR BIT(0) | ||
510 | #define PRISM2_DUMP_TX_HDR BIT(1) | ||
511 | #define PRISM2_DUMP_TXEXC_HDR BIT(2) | ||
512 | |||
513 | struct hostap_tx_callback_info { | ||
514 | u16 idx; | ||
515 | void (*func)(struct sk_buff *, int ok, void *); | ||
516 | void *data; | ||
517 | struct hostap_tx_callback_info *next; | ||
518 | }; | ||
519 | |||
520 | |||
521 | /* IEEE 802.11 requires that STA supports concurrent reception of at least | ||
522 | * three fragmented frames. This define can be increased to support more | ||
523 | * concurrent frames, but it should be noted that each entry can consume about | ||
524 | * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ | ||
525 | #define PRISM2_FRAG_CACHE_LEN 4 | ||
526 | |||
527 | struct prism2_frag_entry { | ||
528 | unsigned long first_frag_time; | ||
529 | unsigned int seq; | ||
530 | unsigned int last_frag; | ||
531 | struct sk_buff *skb; | ||
532 | u8 src_addr[ETH_ALEN]; | ||
533 | u8 dst_addr[ETH_ALEN]; | ||
534 | }; | ||
535 | |||
536 | |||
537 | struct prism2_crypt_data { | ||
538 | struct list_head list; /* delayed deletion list */ | ||
539 | struct hostap_crypto_ops *ops; | ||
540 | void *priv; | ||
541 | atomic_t refcnt; | ||
542 | }; | ||
543 | |||
544 | struct hostap_cmd_queue { | ||
545 | struct list_head list; | ||
546 | wait_queue_head_t compl; | ||
547 | volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; | ||
548 | void (*callback)(struct net_device *dev, void *context, u16 resp0, | ||
549 | u16 res); | ||
550 | void *context; | ||
551 | u16 cmd, param0, param1; | ||
552 | u16 resp0, res; | ||
553 | volatile int issued, issuing; | ||
554 | |||
555 | atomic_t usecnt; | ||
556 | int del_req; | ||
557 | }; | ||
558 | |||
559 | /* options for hw_shutdown */ | ||
560 | #define HOSTAP_HW_NO_DISABLE BIT(0) | ||
561 | #define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) | ||
562 | |||
563 | typedef struct local_info local_info_t; | ||
564 | |||
565 | struct prism2_helper_functions { | ||
566 | /* these functions are defined in hardware model specific files | ||
567 | * (hostap_{cs,plx,pci}.c */ | ||
568 | int (*card_present)(local_info_t *local); | ||
569 | void (*cor_sreset)(local_info_t *local); | ||
570 | int (*dev_open)(local_info_t *local); | ||
571 | int (*dev_close)(local_info_t *local); | ||
572 | void (*genesis_reset)(local_info_t *local, int hcr); | ||
573 | |||
574 | /* the following functions are from hostap_hw.c, but they may have some | ||
575 | * hardware model specific code */ | ||
576 | |||
577 | /* FIX: low-level commands like cmd might disappear at some point to | ||
578 | * make it easier to change them if needed (e.g., cmd would be replaced | ||
579 | * with write_mif/read_mif/testcmd/inquire); at least get_rid and | ||
580 | * set_rid might move to hostap_{cs,plx,pci}.c */ | ||
581 | int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, | ||
582 | u16 *resp0); | ||
583 | void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); | ||
584 | int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, | ||
585 | int exact_len); | ||
586 | int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); | ||
587 | int (*hw_enable)(struct net_device *dev, int initial); | ||
588 | int (*hw_config)(struct net_device *dev, int initial); | ||
589 | void (*hw_reset)(struct net_device *dev); | ||
590 | void (*hw_shutdown)(struct net_device *dev, int no_disable); | ||
591 | int (*reset_port)(struct net_device *dev); | ||
592 | void (*schedule_reset)(local_info_t *local); | ||
593 | int (*download)(local_info_t *local, | ||
594 | struct prism2_download_param *param); | ||
595 | int (*tx)(struct sk_buff *skb, struct net_device *dev); | ||
596 | int (*set_tim)(struct net_device *dev, int aid, int set); | ||
597 | int (*read_aux)(struct net_device *dev, unsigned addr, int len, | ||
598 | u8 *buf); | ||
599 | |||
600 | int need_tx_headroom; /* number of bytes of headroom needed before | ||
601 | * IEEE 802.11 header */ | ||
602 | enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; | ||
603 | }; | ||
604 | |||
605 | |||
606 | struct prism2_download_data { | ||
607 | u32 dl_cmd; | ||
608 | u32 start_addr; | ||
609 | u32 num_areas; | ||
610 | struct prism2_download_data_area { | ||
611 | u32 addr; /* wlan card address */ | ||
612 | u32 len; | ||
613 | u8 *data; /* allocated data */ | ||
614 | } data[0]; | ||
615 | }; | ||
616 | |||
617 | |||
618 | #define HOSTAP_MAX_BSS_COUNT 64 | ||
619 | #define MAX_WPA_IE_LEN 64 | ||
620 | |||
621 | struct hostap_bss_info { | ||
622 | struct list_head list; | ||
623 | unsigned long last_update; | ||
624 | unsigned int count; | ||
625 | u8 bssid[ETH_ALEN]; | ||
626 | u16 capab_info; | ||
627 | u8 ssid[32]; | ||
628 | size_t ssid_len; | ||
629 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
630 | size_t wpa_ie_len; | ||
631 | u8 rsn_ie[MAX_WPA_IE_LEN]; | ||
632 | size_t rsn_ie_len; | ||
633 | int chan; | ||
634 | int included; | ||
635 | }; | ||
636 | |||
637 | |||
638 | /* Per radio private Host AP data - shared by all net devices interfaces used | ||
639 | * by each radio (wlan#, wlan#ap, wlan#sta, WDS). | ||
640 | * ((struct hostap_interface *) netdev_priv(dev))->local points to this | ||
641 | * structure. */ | ||
642 | struct local_info { | ||
643 | struct module *hw_module; | ||
644 | int card_idx; | ||
645 | int dev_enabled; | ||
646 | int master_dev_auto_open; /* was master device opened automatically */ | ||
647 | int num_dev_open; /* number of open devices */ | ||
648 | struct net_device *dev; /* master radio device */ | ||
649 | struct net_device *ddev; /* main data device */ | ||
650 | struct list_head hostap_interfaces; /* Host AP interface list (contains | ||
651 | * struct hostap_interface entries) | ||
652 | */ | ||
653 | rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock | ||
654 | * when removing entries from the list. | ||
655 | * TX and RX paths can use read lock. */ | ||
656 | spinlock_t cmdlock, baplock, lock; | ||
657 | struct semaphore rid_bap_sem; | ||
658 | u16 infofid; /* MAC buffer id for info frame */ | ||
659 | /* txfid, intransmitfid, next_txtid, and next_alloc are protected by | ||
660 | * txfidlock */ | ||
661 | spinlock_t txfidlock; | ||
662 | int txfid_len; /* length of allocated TX buffers */ | ||
663 | u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ | ||
664 | /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if | ||
665 | * corresponding txfid is free for next TX frame */ | ||
666 | u16 intransmitfid[PRISM2_TXFID_COUNT]; | ||
667 | int next_txfid; /* index to the next txfid to be checked for | ||
668 | * availability */ | ||
669 | int next_alloc; /* index to the next intransmitfid to be checked for | ||
670 | * allocation events */ | ||
671 | |||
672 | /* bitfield for atomic bitops */ | ||
673 | #define HOSTAP_BITS_TRANSMIT 0 | ||
674 | #define HOSTAP_BITS_BAP_TASKLET 1 | ||
675 | #define HOSTAP_BITS_BAP_TASKLET2 2 | ||
676 | long bits; | ||
677 | |||
678 | struct ap_data *ap; | ||
679 | |||
680 | char essid[MAX_SSID_LEN + 1]; | ||
681 | char name[MAX_NAME_LEN + 1]; | ||
682 | int name_set; | ||
683 | u16 channel_mask; | ||
684 | struct comm_tallies_sums comm_tallies; | ||
685 | struct net_device_stats stats; | ||
686 | struct proc_dir_entry *proc; | ||
687 | int iw_mode; /* operating mode (IW_MODE_*) */ | ||
688 | int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS | ||
689 | * 1: IW_MODE_ADHOC is "pseudo IBSS" */ | ||
690 | char bssid[ETH_ALEN]; | ||
691 | int channel; | ||
692 | int beacon_int; | ||
693 | int dtim_period; | ||
694 | int mtu; | ||
695 | int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ | ||
696 | int fw_tx_rate_control; | ||
697 | u16 tx_rate_control; | ||
698 | u16 basic_rates; | ||
699 | int hw_resetting; | ||
700 | int hw_ready; | ||
701 | int hw_reset_tries; /* how many times reset has been tried */ | ||
702 | int hw_downloading; | ||
703 | int shutdown; | ||
704 | int pri_only; | ||
705 | int no_pri; /* no PRI f/w present */ | ||
706 | int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ | ||
707 | |||
708 | enum { | ||
709 | PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, | ||
710 | PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN | ||
711 | } txpower_type; | ||
712 | int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ | ||
713 | |||
714 | /* command queue for hfa384x_cmd(); protected with cmdlock */ | ||
715 | struct list_head cmd_queue; | ||
716 | /* max_len for cmd_queue; in addition, cmd_callback can use two | ||
717 | * additional entries to prevent sleeping commands from stopping | ||
718 | * transmits */ | ||
719 | #define HOSTAP_CMD_QUEUE_MAX_LEN 16 | ||
720 | int cmd_queue_len; /* number of entries in cmd_queue */ | ||
721 | |||
722 | /* if card timeout is detected in interrupt context, reset_queue is | ||
723 | * used to schedule card reseting to be done in user context */ | ||
724 | struct work_struct reset_queue; | ||
725 | |||
726 | /* For scheduling a change of the promiscuous mode RID */ | ||
727 | int is_promisc; | ||
728 | struct work_struct set_multicast_list_queue; | ||
729 | |||
730 | struct work_struct set_tim_queue; | ||
731 | struct list_head set_tim_list; | ||
732 | spinlock_t set_tim_lock; | ||
733 | |||
734 | int wds_max_connections; | ||
735 | int wds_connections; | ||
736 | #define HOSTAP_WDS_BROADCAST_RA BIT(0) | ||
737 | #define HOSTAP_WDS_AP_CLIENT BIT(1) | ||
738 | #define HOSTAP_WDS_STANDARD_FRAME BIT(2) | ||
739 | u32 wds_type; | ||
740 | u16 tx_control; /* flags to be used in TX description */ | ||
741 | int manual_retry_count; /* -1 = use f/w default; otherwise retry count | ||
742 | * to be used with all frames */ | ||
743 | |||
744 | struct iw_statistics wstats; | ||
745 | unsigned long scan_timestamp; /* Time started to scan */ | ||
746 | enum { | ||
747 | PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, | ||
748 | PRISM2_MONITOR_CAPHDR = 2 | ||
749 | } monitor_type; | ||
750 | int (*saved_eth_header_parse)(struct sk_buff *skb, | ||
751 | unsigned char *haddr); | ||
752 | int monitor_allow_fcserr; | ||
753 | |||
754 | int hostapd; /* whether user space daemon, hostapd, is used for AP | ||
755 | * management */ | ||
756 | int hostapd_sta; /* whether hostapd is used with an extra STA interface | ||
757 | */ | ||
758 | struct net_device *apdev; | ||
759 | struct net_device_stats apdevstats; | ||
760 | |||
761 | char assoc_ap_addr[ETH_ALEN]; | ||
762 | struct net_device *stadev; | ||
763 | struct net_device_stats stadevstats; | ||
764 | |||
765 | #define WEP_KEYS 4 | ||
766 | #define WEP_KEY_LEN 13 | ||
767 | struct prism2_crypt_data *crypt[WEP_KEYS]; | ||
768 | int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ | ||
769 | struct timer_list crypt_deinit_timer; | ||
770 | struct list_head crypt_deinit_list; | ||
771 | |||
772 | int open_wep; /* allow unencrypted frames */ | ||
773 | int host_encrypt; | ||
774 | int host_decrypt; | ||
775 | int privacy_invoked; /* force privacy invoked flag even if no keys are | ||
776 | * configured */ | ||
777 | int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working | ||
778 | * in Host AP mode (STA f/w 1.4.9 or newer) */ | ||
779 | int bcrx_sta_key; /* use individual keys to override default keys even | ||
780 | * with RX of broad/multicast frames */ | ||
781 | |||
782 | struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; | ||
783 | unsigned int frag_next_idx; | ||
784 | |||
785 | int ieee_802_1x; /* is IEEE 802.1X used */ | ||
786 | |||
787 | int antsel_tx, antsel_rx; | ||
788 | int rts_threshold; /* dot11RTSThreshold */ | ||
789 | int fragm_threshold; /* dot11FragmentationThreshold */ | ||
790 | int auth_algs; /* PRISM2_AUTH_ flags */ | ||
791 | |||
792 | int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ | ||
793 | int tallies32; /* 32-bit tallies in use */ | ||
794 | |||
795 | struct prism2_helper_functions *func; | ||
796 | |||
797 | int bus_master_threshold_tx; | ||
798 | int bus_master_threshold_rx; | ||
799 | u8 *bus_m1_buf; | ||
800 | |||
801 | u8 *pda; | ||
802 | int fw_ap; | ||
803 | #define PRISM2_FW_VER(major, minor, variant) \ | ||
804 | (((major) << 16) | ((minor) << 8) | variant) | ||
805 | u32 sta_fw_ver; | ||
806 | |||
807 | /* Tasklets for handling hardware IRQ related operations outside hw IRQ | ||
808 | * handler */ | ||
809 | struct tasklet_struct bap_tasklet; | ||
810 | |||
811 | struct tasklet_struct info_tasklet; | ||
812 | struct sk_buff_head info_list; /* info frames as skb's for | ||
813 | * info_tasklet */ | ||
814 | |||
815 | struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks | ||
816 | */ | ||
817 | |||
818 | struct tasklet_struct rx_tasklet; | ||
819 | struct sk_buff_head rx_list; | ||
820 | |||
821 | struct tasklet_struct sta_tx_exc_tasklet; | ||
822 | struct sk_buff_head sta_tx_exc_list; | ||
823 | |||
824 | int host_roaming; | ||
825 | unsigned long last_join_time; /* time of last JoinRequest */ | ||
826 | struct hfa384x_scan_result *last_scan_results; | ||
827 | int last_scan_results_count; | ||
828 | struct hfa384x_hostscan_result *last_hostscan_results; | ||
829 | int last_hostscan_results_count; | ||
830 | enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; | ||
831 | struct work_struct info_queue; | ||
832 | long pending_info; /* bit field of pending info_queue items */ | ||
833 | #define PRISM2_INFO_PENDING_LINKSTATUS 0 | ||
834 | #define PRISM2_INFO_PENDING_SCANRESULTS 1 | ||
835 | int prev_link_status; /* previous received LinkStatus info */ | ||
836 | int prev_linkstatus_connected; | ||
837 | u8 preferred_ap[6]; /* use this AP if possible */ | ||
838 | |||
839 | #ifdef PRISM2_CALLBACK | ||
840 | void *callback_data; /* Can be used in callbacks; e.g., allocate | ||
841 | * on enable event and free on disable event. | ||
842 | * Host AP driver code does not touch this. */ | ||
843 | #endif /* PRISM2_CALLBACK */ | ||
844 | |||
845 | wait_queue_head_t hostscan_wq; | ||
846 | |||
847 | /* Passive scan in Host AP mode */ | ||
848 | struct timer_list passive_scan_timer; | ||
849 | int passive_scan_interval; /* in seconds, 0 = disabled */ | ||
850 | int passive_scan_channel; | ||
851 | enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; | ||
852 | |||
853 | struct timer_list tick_timer; | ||
854 | unsigned long last_tick_timer; | ||
855 | unsigned int sw_tick_stuck; | ||
856 | |||
857 | /* commsQuality / dBmCommsQuality data from periodic polling; only | ||
858 | * valid for Managed and Ad-hoc modes */ | ||
859 | unsigned long last_comms_qual_update; | ||
860 | int comms_qual; /* in some odd unit.. */ | ||
861 | int avg_signal; /* in dB (note: negative) */ | ||
862 | int avg_noise; /* in dB (note: negative) */ | ||
863 | struct work_struct comms_qual_update; | ||
864 | |||
865 | /* RSSI to dBm adjustment (for RX descriptor fields) */ | ||
866 | int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */ | ||
867 | |||
868 | /* BSS list / protected by local->lock */ | ||
869 | struct list_head bss_list; | ||
870 | int num_bss_info; | ||
871 | int wpa; /* WPA support enabled */ | ||
872 | int tkip_countermeasures; | ||
873 | int drop_unencrypted; | ||
874 | /* Generic IEEE 802.11 info element to be added to | ||
875 | * ProbeResp/Beacon/(Re)AssocReq */ | ||
876 | u8 *generic_elem; | ||
877 | size_t generic_elem_len; | ||
878 | |||
879 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
880 | /* Persistent volatile download data */ | ||
881 | struct prism2_download_data *dl_pri; | ||
882 | struct prism2_download_data *dl_sec; | ||
883 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
884 | |||
885 | #ifdef PRISM2_IO_DEBUG | ||
886 | #define PRISM2_IO_DEBUG_SIZE 10000 | ||
887 | u32 io_debug[PRISM2_IO_DEBUG_SIZE]; | ||
888 | int io_debug_head; | ||
889 | int io_debug_enabled; | ||
890 | #endif /* PRISM2_IO_DEBUG */ | ||
891 | |||
892 | /* struct local_info is used also in hostap.o that does not define | ||
893 | * any PRISM2_{PCCARD,PLX,PCI}. Make sure that the hardware version | ||
894 | * specific fields are in the end of the struct (these could also be | ||
895 | * moved to void *priv or something like that). */ | ||
896 | #ifdef PRISM2_PCCARD | ||
897 | dev_node_t node; | ||
898 | dev_link_t *link; | ||
899 | int sandisk_connectplus; | ||
900 | #endif /* PRISM2_PCCARD */ | ||
901 | |||
902 | #ifdef PRISM2_PLX | ||
903 | void __iomem *attr_mem; | ||
904 | unsigned int cor_offset; | ||
905 | #endif /* PRISM2_PLX */ | ||
906 | |||
907 | #ifdef PRISM2_PCI | ||
908 | void __iomem *mem_start; | ||
909 | #ifdef PRISM2_BUS_MASTER | ||
910 | /* bus master for BAP0 (TX) */ | ||
911 | int bus_m0_tx_idx; | ||
912 | u8 *bus_m0_buf; | ||
913 | |||
914 | /* bus master for BAP1 (RX) */ | ||
915 | struct sk_buff *rx_skb; | ||
916 | #endif /* PRISM2_BUS_MASTER */ | ||
917 | #endif /* PRISM2_PCI */ | ||
918 | |||
919 | /* NOTE! Do not add common entries here after hardware version | ||
920 | * specific blocks. */ | ||
921 | }; | ||
922 | |||
923 | |||
924 | /* Per interface private Host AP data | ||
925 | * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, | ||
926 | * WDS) and netdev_priv(dev) points to this structure. */ | ||
927 | struct hostap_interface { | ||
928 | struct list_head list; /* list entry in Host AP interface list */ | ||
929 | struct net_device *dev; /* pointer to this device */ | ||
930 | struct local_info *local; /* pointer to shared private data */ | ||
931 | struct net_device_stats stats; | ||
932 | struct iw_spy_data spy_data; /* iwspy support */ | ||
933 | struct iw_public_data wireless_data; | ||
934 | |||
935 | enum { | ||
936 | HOSTAP_INTERFACE_MASTER, | ||
937 | HOSTAP_INTERFACE_MAIN, | ||
938 | HOSTAP_INTERFACE_AP, | ||
939 | HOSTAP_INTERFACE_STA, | ||
940 | HOSTAP_INTERFACE_WDS, | ||
941 | } type; | ||
942 | |||
943 | union { | ||
944 | struct hostap_interface_wds { | ||
945 | u8 remote_addr[ETH_ALEN]; | ||
946 | } wds; | ||
947 | } u; | ||
948 | }; | ||
949 | |||
950 | |||
951 | #define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 | ||
952 | |||
953 | /* TX meta data - stored in skb->cb buffer, so this must be not increase over | ||
954 | * 48-byte limit */ | ||
955 | struct hostap_skb_tx_data { | ||
956 | unsigned int magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ | ||
957 | int rate; /* transmit rate */ | ||
958 | struct hostap_interface *iface; | ||
959 | unsigned long jiffies; /* queueing timestamp */ | ||
960 | int wds; | ||
961 | unsigned short ethertype; | ||
962 | int tx_cb_idx; | ||
963 | }; | ||
964 | |||
965 | |||
966 | #ifndef PRISM2_NO_DEBUG | ||
967 | |||
968 | #define DEBUG_FID BIT(0) | ||
969 | #define DEBUG_PS BIT(1) | ||
970 | #define DEBUG_FLOW BIT(2) | ||
971 | #define DEBUG_AP BIT(3) | ||
972 | #define DEBUG_HW BIT(4) | ||
973 | #define DEBUG_EXTRA BIT(5) | ||
974 | #define DEBUG_EXTRA2 BIT(6) | ||
975 | #define DEBUG_PS2 BIT(7) | ||
976 | #define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) | ||
977 | #define PDEBUG(n, args...) \ | ||
978 | do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) | ||
979 | #define PDEBUG2(n, args...) \ | ||
980 | do { if ((n) & DEBUG_MASK) printk(args); } while (0) | ||
981 | |||
982 | #else /* PRISM2_NO_DEBUG */ | ||
983 | |||
984 | #define PDEBUG(n, args...) | ||
985 | #define PDEBUG2(n, args...) | ||
986 | |||
987 | #endif /* PRISM2_NO_DEBUG */ | ||
988 | |||
989 | enum { BAP0 = 0, BAP1 = 1 }; | ||
990 | |||
991 | #define PRISM2_IO_DEBUG_CMD_INB 0 | ||
992 | #define PRISM2_IO_DEBUG_CMD_INW 1 | ||
993 | #define PRISM2_IO_DEBUG_CMD_INSW 2 | ||
994 | #define PRISM2_IO_DEBUG_CMD_OUTB 3 | ||
995 | #define PRISM2_IO_DEBUG_CMD_OUTW 4 | ||
996 | #define PRISM2_IO_DEBUG_CMD_OUTSW 5 | ||
997 | #define PRISM2_IO_DEBUG_CMD_ERROR 6 | ||
998 | #define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 | ||
999 | |||
1000 | #ifdef PRISM2_IO_DEBUG | ||
1001 | |||
1002 | #define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ | ||
1003 | (((cmd) << 24) | ((reg) << 16) | value) | ||
1004 | |||
1005 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
1006 | int reg, int value) | ||
1007 | { | ||
1008 | struct hostap_interface *iface = netdev_priv(dev); | ||
1009 | local_info_t *local = iface->local; | ||
1010 | |||
1011 | if (!local->io_debug_enabled) | ||
1012 | return; | ||
1013 | |||
1014 | local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; | ||
1015 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
1016 | local->io_debug_head = 0; | ||
1017 | local->io_debug[local->io_debug_head] = | ||
1018 | PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); | ||
1019 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
1020 | local->io_debug_head = 0; | ||
1021 | } | ||
1022 | |||
1023 | |||
1024 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
1025 | { | ||
1026 | struct hostap_interface *iface = netdev_priv(dev); | ||
1027 | local_info_t *local = iface->local; | ||
1028 | unsigned long flags; | ||
1029 | |||
1030 | if (!local->io_debug_enabled) | ||
1031 | return; | ||
1032 | |||
1033 | spin_lock_irqsave(&local->lock, flags); | ||
1034 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); | ||
1035 | if (local->io_debug_enabled == 1) { | ||
1036 | local->io_debug_enabled = 0; | ||
1037 | printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); | ||
1038 | } | ||
1039 | spin_unlock_irqrestore(&local->lock, flags); | ||
1040 | } | ||
1041 | |||
1042 | #else /* PRISM2_IO_DEBUG */ | ||
1043 | |||
1044 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
1045 | int reg, int value) | ||
1046 | { | ||
1047 | } | ||
1048 | |||
1049 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
1050 | { | ||
1051 | } | ||
1052 | |||
1053 | #endif /* PRISM2_IO_DEBUG */ | ||
1054 | |||
1055 | |||
1056 | #ifdef PRISM2_CALLBACK | ||
1057 | enum { | ||
1058 | /* Called when card is enabled */ | ||
1059 | PRISM2_CALLBACK_ENABLE, | ||
1060 | |||
1061 | /* Called when card is disabled */ | ||
1062 | PRISM2_CALLBACK_DISABLE, | ||
1063 | |||
1064 | /* Called when RX/TX starts/ends */ | ||
1065 | PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, | ||
1066 | PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END | ||
1067 | }; | ||
1068 | void prism2_callback(local_info_t *local, int event); | ||
1069 | #else /* PRISM2_CALLBACK */ | ||
1070 | #define prism2_callback(d, e) do { } while (0) | ||
1071 | #endif /* PRISM2_CALLBACK */ | ||
1072 | |||
1073 | #endif /* __KERNEL__ */ | ||
1074 | |||
1075 | #endif /* HOSTAP_WLAN_H */ | ||
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ec8cf29ffce..8f1e730963b 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 ec8329788e4..5914b637c0a 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 29cff6daf86..fabc63ee153 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 ea2ef8dddb9..4ac359ed5b5 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h | |||
@@ -648,23 +648,6 @@ struct net_local | |||
648 | void __iomem *mem; | 648 | void __iomem *mem; |
649 | }; | 649 | }; |
650 | 650 | ||
651 | /**************************** PROTOTYPES ****************************/ | ||
652 | |||
653 | #ifdef WAVELAN_ROAMING | ||
654 | /* ---------------------- ROAMING SUBROUTINES -----------------------*/ | ||
655 | |||
656 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); | ||
657 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); | ||
658 | void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); | ||
659 | void wl_cell_expiry(unsigned long data); | ||
660 | wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); | ||
661 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); | ||
662 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); | ||
663 | void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
664 | void wv_roam_init(struct net_device *dev); | ||
665 | void wv_roam_cleanup(struct net_device *dev); | ||
666 | #endif /* WAVELAN_ROAMING */ | ||
667 | |||
668 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | 651 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ |
669 | static inline u_char /* data */ | 652 | static inline u_char /* data */ |
670 | hasr_read(u_long); /* Read the host interface : base address */ | 653 | 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 1433e5aaf1b..0e3afab6275 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -297,7 +297,8 @@ static int wl3501_get_flash_mac_addr(struct wl3501_card *this) | |||
297 | * | 297 | * |
298 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) | 298 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) |
299 | */ | 299 | */ |
300 | void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | 300 | static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, |
301 | int size) | ||
301 | { | 302 | { |
302 | /* switch to SRAM Page 0 */ | 303 | /* switch to SRAM Page 0 */ |
303 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : | 304 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -318,8 +319,8 @@ void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | |||
318 | * | 319 | * |
319 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) | 320 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) |
320 | */ | 321 | */ |
321 | void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, | 322 | static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, |
322 | int size) | 323 | int size) |
323 | { | 324 | { |
324 | /* switch to SRAM Page 0 */ | 325 | /* switch to SRAM Page 0 */ |
325 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : | 326 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -1439,14 +1440,14 @@ fail: | |||
1439 | goto out; | 1440 | goto out; |
1440 | } | 1441 | } |
1441 | 1442 | ||
1442 | struct net_device_stats *wl3501_get_stats(struct net_device *dev) | 1443 | static struct net_device_stats *wl3501_get_stats(struct net_device *dev) |
1443 | { | 1444 | { |
1444 | struct wl3501_card *this = dev->priv; | 1445 | struct wl3501_card *this = dev->priv; |
1445 | 1446 | ||
1446 | return &this->stats; | 1447 | return &this->stats; |
1447 | } | 1448 | } |
1448 | 1449 | ||
1449 | struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) | 1450 | static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) |
1450 | { | 1451 | { |
1451 | struct wl3501_card *this = dev->priv; | 1452 | struct wl3501_card *this = dev->priv; |
1452 | struct iw_statistics *wstats = &this->wstats; | 1453 | struct iw_statistics *wstats = &this->wstats; |