diff options
author | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-02 03:48:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-02 03:48:33 -0400 |
commit | 5d8c397f304e1363f8ff9749b08172eb59e6534a (patch) | |
tree | 57ff502553918aa7309b7375e983f27f719e7b28 /drivers | |
parent | 44757223cd77f6e332dfa0b043c67df7b665bc19 (diff) | |
parent | ceeec3dc375e3b0618f16b34efc56fe093918f8b (diff) |
Merge refs/heads/ieee80211-wifi from master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
Diffstat (limited to 'drivers')
38 files changed, 38681 insertions, 194 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ec3f75a030d2..dd7dbf7b14d4 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -137,6 +137,110 @@ config PCMCIA_RAYCS | |||
137 | comment "Wireless 802.11b ISA/PCI cards support" | 137 | comment "Wireless 802.11b ISA/PCI cards support" |
138 | depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) | 138 | depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) |
139 | 139 | ||
140 | config IPW2100 | ||
141 | tristate "Intel PRO/Wireless 2100 Network Connection" | ||
142 | depends on NET_RADIO && PCI && IEEE80211 | ||
143 | select FW_LOADER | ||
144 | ---help--- | ||
145 | A driver for the Intel PRO/Wireless 2100 Network | ||
146 | Connection 802.11b wireless network adapter. | ||
147 | |||
148 | See <file:Documentation/networking/README.ipw2100> for information on | ||
149 | the capabilities currently enabled in this driver and for tips | ||
150 | for debugging issues and problems. | ||
151 | |||
152 | In order to use this driver, you will need a firmware image for it. | ||
153 | You can obtain the firmware from | ||
154 | <http://ipw2100.sf.net/>. Once you have the firmware image, you | ||
155 | will need to place it in /etc/firmware. | ||
156 | |||
157 | You will also very likely need the Wireless Tools in order to | ||
158 | configure your card: | ||
159 | |||
160 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
161 | |||
162 | If you want to compile the driver as a module ( = code which can be | ||
163 | inserted in and remvoed from the running kernel whenever you want), | ||
164 | say M here and read <file:Documentation/modules.txt>. The module | ||
165 | will be called ipw2100.ko. | ||
166 | |||
167 | config IPW2100_MONITOR | ||
168 | bool "Enable promiscuous mode" | ||
169 | depends on IPW2100 | ||
170 | ---help--- | ||
171 | Enables promiscuous/monitor mode support for the ipw2100 driver. | ||
172 | With this feature compiled into the driver, you can switch to | ||
173 | promiscuous mode via the Wireless Tool's Monitor mode. While in this | ||
174 | mode, no packets can be sent. | ||
175 | |||
176 | config IPW_DEBUG | ||
177 | bool "Enable full debugging output in IPW2100 module." | ||
178 | depends on IPW2100 | ||
179 | ---help--- | ||
180 | This option will enable debug tracing output for the IPW2100. | ||
181 | |||
182 | This will result in the kernel module being ~60k larger. You can | ||
183 | control which debug output is sent to the kernel log by setting the | ||
184 | value in | ||
185 | |||
186 | /sys/bus/pci/drivers/ipw2100/debug_level | ||
187 | |||
188 | This entry will only exist if this option is enabled. | ||
189 | |||
190 | If you are not trying to debug or develop the IPW2100 driver, you | ||
191 | most likely want to say N here. | ||
192 | |||
193 | config IPW2200 | ||
194 | tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" | ||
195 | depends on IEEE80211 && PCI | ||
196 | select FW_LOADER | ||
197 | ---help--- | ||
198 | A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network | ||
199 | Connection adapters. | ||
200 | |||
201 | See <file:Documentation/networking/README.ipw2200> for | ||
202 | information on the capabilities currently enabled in this | ||
203 | driver and for tips for debugging issues and problems. | ||
204 | |||
205 | In order to use this driver, you will need a firmware image for it. | ||
206 | You can obtain the firmware from | ||
207 | <http://ipw2200.sf.net/>. See the above referenced README.ipw2200 | ||
208 | for information on where to install the firmare images. | ||
209 | |||
210 | You will also very likely need the Wireless Tools in order to | ||
211 | configure your card: | ||
212 | |||
213 | <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. | ||
214 | |||
215 | If you want to compile the driver as a module ( = code which can be | ||
216 | inserted in and remvoed from the running kernel whenever you want), | ||
217 | say M here and read <file:Documentation/modules.txt>. The module | ||
218 | will be called ipw2200.ko. | ||
219 | |||
220 | config IPW_DEBUG | ||
221 | bool "Enable full debugging output in IPW2200 module." | ||
222 | depends on IPW2200 | ||
223 | ---help--- | ||
224 | This option will enable debug tracing output for the IPW2200. | ||
225 | |||
226 | This will result in the kernel module being ~100k larger. You can | ||
227 | control which debug output is sent to the kernel log by setting the | ||
228 | value in | ||
229 | |||
230 | /sys/bus/pci/drivers/ipw2200/debug_level | ||
231 | |||
232 | This entry will only exist if this option is enabled. | ||
233 | |||
234 | To set a value, simply echo an 8-byte hex value to the same file: | ||
235 | |||
236 | % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level | ||
237 | |||
238 | You can find the list of debug mask values in | ||
239 | drivers/net/wireless/ipw2200.h | ||
240 | |||
241 | If you are not trying to debug or develop the IPW2200 driver, you | ||
242 | most likely want to say N here. | ||
243 | |||
140 | config AIRO | 244 | config AIRO |
141 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" | 245 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" |
142 | depends on NET_RADIO && ISA && (PCI || BROKEN) | 246 | depends on NET_RADIO && ISA && (PCI || BROKEN) |
@@ -355,6 +459,8 @@ config PRISM54 | |||
355 | say M here and read <file:Documentation/modules.txt>. The module | 459 | say M here and read <file:Documentation/modules.txt>. The module |
356 | will be called prism54.ko. | 460 | will be called prism54.ko. |
357 | 461 | ||
462 | source "drivers/net/wireless/hostap/Kconfig" | ||
463 | |||
358 | # yes, this works even when no drivers are selected | 464 | # yes, this works even when no drivers are selected |
359 | config NET_WIRELESS | 465 | config NET_WIRELESS |
360 | bool | 466 | bool |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 2b87841322cc..0953cc0cdee6 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -2,6 +2,10 @@ | |||
2 | # Makefile for the Linux Wireless network device drivers. | 2 | # Makefile for the Linux Wireless network device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_IPW2100) += ipw2100.o | ||
6 | |||
7 | obj-$(CONFIG_IPW2200) += ipw2200.o | ||
8 | |||
5 | obj-$(CONFIG_STRIP) += strip.o | 9 | obj-$(CONFIG_STRIP) += strip.o |
6 | obj-$(CONFIG_ARLAN) += arlan.o | 10 | obj-$(CONFIG_ARLAN) += arlan.o |
7 | 11 | ||
@@ -28,6 +32,8 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | |||
28 | 32 | ||
29 | obj-$(CONFIG_PRISM54) += prism54/ | 33 | obj-$(CONFIG_PRISM54) += prism54/ |
30 | 34 | ||
35 | obj-$(CONFIG_HOSTAP) += hostap/ | ||
36 | |||
31 | # 16-bit wireless PCMCIA client drivers | 37 | # 16-bit wireless PCMCIA client drivers |
32 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o | 38 | obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o |
33 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o | 39 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index df20adcd0730..6db1fb6461de 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -1040,7 +1040,7 @@ typedef struct { | |||
1040 | u16 status; | 1040 | u16 status; |
1041 | } WifiCtlHdr; | 1041 | } WifiCtlHdr; |
1042 | 1042 | ||
1043 | WifiCtlHdr wifictlhdr8023 = { | 1043 | static WifiCtlHdr wifictlhdr8023 = { |
1044 | .ctlhdr = { | 1044 | .ctlhdr = { |
1045 | .ctl = HOST_DONT_RLSE, | 1045 | .ctl = HOST_DONT_RLSE, |
1046 | } | 1046 | } |
@@ -1111,13 +1111,13 @@ static int airo_thread(void *data); | |||
1111 | static void timer_func( struct net_device *dev ); | 1111 | static void timer_func( struct net_device *dev ); |
1112 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 1112 | static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
1113 | #ifdef WIRELESS_EXT | 1113 | #ifdef WIRELESS_EXT |
1114 | struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); | 1114 | static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); |
1115 | static void airo_read_wireless_stats (struct airo_info *local); | 1115 | static void airo_read_wireless_stats (struct airo_info *local); |
1116 | #endif /* WIRELESS_EXT */ | 1116 | #endif /* WIRELESS_EXT */ |
1117 | #ifdef CISCO_EXT | 1117 | #ifdef CISCO_EXT |
1118 | static int readrids(struct net_device *dev, aironet_ioctl *comp); | 1118 | static int readrids(struct net_device *dev, aironet_ioctl *comp); |
1119 | static int writerids(struct net_device *dev, aironet_ioctl *comp); | 1119 | static int writerids(struct net_device *dev, aironet_ioctl *comp); |
1120 | int flashcard(struct net_device *dev, aironet_ioctl *comp); | 1120 | static int flashcard(struct net_device *dev, aironet_ioctl *comp); |
1121 | #endif /* CISCO_EXT */ | 1121 | #endif /* CISCO_EXT */ |
1122 | #ifdef MICSUPPORT | 1122 | #ifdef MICSUPPORT |
1123 | static void micinit(struct airo_info *ai); | 1123 | static void micinit(struct airo_info *ai); |
@@ -1226,6 +1226,12 @@ static int setup_proc_entry( struct net_device *dev, | |||
1226 | static int takedown_proc_entry( struct net_device *dev, | 1226 | static int takedown_proc_entry( struct net_device *dev, |
1227 | struct airo_info *apriv ); | 1227 | struct airo_info *apriv ); |
1228 | 1228 | ||
1229 | static int cmdreset(struct airo_info *ai); | ||
1230 | static int setflashmode (struct airo_info *ai); | ||
1231 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); | ||
1232 | static int flashputbuf(struct airo_info *ai); | ||
1233 | static int flashrestart(struct airo_info *ai,struct net_device *dev); | ||
1234 | |||
1229 | #ifdef MICSUPPORT | 1235 | #ifdef MICSUPPORT |
1230 | /*********************************************************************** | 1236 | /*********************************************************************** |
1231 | * MIC ROUTINES * | 1237 | * MIC ROUTINES * |
@@ -1234,10 +1240,11 @@ static int takedown_proc_entry( struct net_device *dev, | |||
1234 | 1240 | ||
1235 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); | 1241 | static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); |
1236 | static void MoveWindow(miccntx *context, u32 micSeq); | 1242 | static void MoveWindow(miccntx *context, u32 micSeq); |
1237 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); | 1243 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); |
1238 | void emmh32_init(emmh32_context *context); | 1244 | static void emmh32_init(emmh32_context *context); |
1239 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len); | 1245 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); |
1240 | void emmh32_final(emmh32_context *context, u8 digest[4]); | 1246 | static void emmh32_final(emmh32_context *context, u8 digest[4]); |
1247 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime); | ||
1241 | 1248 | ||
1242 | /* micinit - Initialize mic seed */ | 1249 | /* micinit - Initialize mic seed */ |
1243 | 1250 | ||
@@ -1315,7 +1322,7 @@ static int micsetup(struct airo_info *ai) { | |||
1315 | return SUCCESS; | 1322 | return SUCCESS; |
1316 | } | 1323 | } |
1317 | 1324 | ||
1318 | char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; | 1325 | static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; |
1319 | 1326 | ||
1320 | /*=========================================================================== | 1327 | /*=========================================================================== |
1321 | * Description: Mic a packet | 1328 | * Description: Mic a packet |
@@ -1570,7 +1577,7 @@ static void MoveWindow(miccntx *context, u32 micSeq) | |||
1570 | static unsigned char aes_counter[16]; | 1577 | static unsigned char aes_counter[16]; |
1571 | 1578 | ||
1572 | /* expand the key to fill the MMH coefficient array */ | 1579 | /* expand the key to fill the MMH coefficient array */ |
1573 | void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) | 1580 | static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm) |
1574 | { | 1581 | { |
1575 | /* take the keying material, expand if necessary, truncate at 16-bytes */ | 1582 | /* take the keying material, expand if necessary, truncate at 16-bytes */ |
1576 | /* run through AES counter mode to generate context->coeff[] */ | 1583 | /* run through AES counter mode to generate context->coeff[] */ |
@@ -1602,7 +1609,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto | |||
1602 | } | 1609 | } |
1603 | 1610 | ||
1604 | /* prepare for calculation of a new mic */ | 1611 | /* prepare for calculation of a new mic */ |
1605 | void emmh32_init(emmh32_context *context) | 1612 | static void emmh32_init(emmh32_context *context) |
1606 | { | 1613 | { |
1607 | /* prepare for new mic calculation */ | 1614 | /* prepare for new mic calculation */ |
1608 | context->accum = 0; | 1615 | context->accum = 0; |
@@ -1610,7 +1617,7 @@ void emmh32_init(emmh32_context *context) | |||
1610 | } | 1617 | } |
1611 | 1618 | ||
1612 | /* add some bytes to the mic calculation */ | 1619 | /* add some bytes to the mic calculation */ |
1613 | void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | 1620 | static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) |
1614 | { | 1621 | { |
1615 | int coeff_position, byte_position; | 1622 | int coeff_position, byte_position; |
1616 | 1623 | ||
@@ -1652,7 +1659,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | |||
1652 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; | 1659 | static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; |
1653 | 1660 | ||
1654 | /* calculate the mic */ | 1661 | /* calculate the mic */ |
1655 | void emmh32_final(emmh32_context *context, u8 digest[4]) | 1662 | static void emmh32_final(emmh32_context *context, u8 digest[4]) |
1656 | { | 1663 | { |
1657 | int coeff_position, byte_position; | 1664 | int coeff_position, byte_position; |
1658 | u32 val; | 1665 | u32 val; |
@@ -2255,7 +2262,7 @@ static void airo_read_stats(struct airo_info *ai) { | |||
2255 | ai->stats.rx_fifo_errors = vals[0]; | 2262 | ai->stats.rx_fifo_errors = vals[0]; |
2256 | } | 2263 | } |
2257 | 2264 | ||
2258 | struct net_device_stats *airo_get_stats(struct net_device *dev) | 2265 | static struct net_device_stats *airo_get_stats(struct net_device *dev) |
2259 | { | 2266 | { |
2260 | struct airo_info *local = dev->priv; | 2267 | struct airo_info *local = dev->priv; |
2261 | 2268 | ||
@@ -2414,7 +2421,7 @@ EXPORT_SYMBOL(stop_airo_card); | |||
2414 | 2421 | ||
2415 | static int add_airo_dev( struct net_device *dev ); | 2422 | static int add_airo_dev( struct net_device *dev ); |
2416 | 2423 | ||
2417 | int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) | 2424 | static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) |
2418 | { | 2425 | { |
2419 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); | 2426 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); |
2420 | return ETH_ALEN; | 2427 | return ETH_ALEN; |
@@ -2681,7 +2688,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, | |||
2681 | return dev; | 2688 | return dev; |
2682 | } | 2689 | } |
2683 | 2690 | ||
2684 | int reset_card( struct net_device *dev , int lock) { | 2691 | static int reset_card( struct net_device *dev , int lock) { |
2685 | struct airo_info *ai = dev->priv; | 2692 | struct airo_info *ai = dev->priv; |
2686 | 2693 | ||
2687 | if (lock && down_interruptible(&ai->sem)) | 2694 | if (lock && down_interruptible(&ai->sem)) |
@@ -2696,9 +2703,9 @@ int reset_card( struct net_device *dev , int lock) { | |||
2696 | return 0; | 2703 | return 0; |
2697 | } | 2704 | } |
2698 | 2705 | ||
2699 | struct net_device *_init_airo_card( unsigned short irq, int port, | 2706 | static struct net_device *_init_airo_card( unsigned short irq, int port, |
2700 | int is_pcmcia, struct pci_dev *pci, | 2707 | int is_pcmcia, struct pci_dev *pci, |
2701 | struct device *dmdev ) | 2708 | struct device *dmdev ) |
2702 | { | 2709 | { |
2703 | struct net_device *dev; | 2710 | struct net_device *dev; |
2704 | struct airo_info *ai; | 2711 | struct airo_info *ai; |
@@ -7235,7 +7242,7 @@ static void airo_read_wireless_stats(struct airo_info *local) | |||
7235 | local->wstats.miss.beacon = vals[34]; | 7242 | local->wstats.miss.beacon = vals[34]; |
7236 | } | 7243 | } |
7237 | 7244 | ||
7238 | struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) | 7245 | static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) |
7239 | { | 7246 | { |
7240 | struct airo_info *local = dev->priv; | 7247 | struct airo_info *local = dev->priv; |
7241 | 7248 | ||
@@ -7450,14 +7457,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { | |||
7450 | * Flash command switch table | 7457 | * Flash command switch table |
7451 | */ | 7458 | */ |
7452 | 7459 | ||
7453 | int flashcard(struct net_device *dev, aironet_ioctl *comp) { | 7460 | static int flashcard(struct net_device *dev, aironet_ioctl *comp) { |
7454 | int z; | 7461 | int z; |
7455 | int cmdreset(struct airo_info *); | ||
7456 | int setflashmode(struct airo_info *); | ||
7457 | int flashgchar(struct airo_info *,int,int); | ||
7458 | int flashpchar(struct airo_info *,int,int); | ||
7459 | int flashputbuf(struct airo_info *); | ||
7460 | int flashrestart(struct airo_info *,struct net_device *); | ||
7461 | 7462 | ||
7462 | /* Only super-user can modify flash */ | 7463 | /* Only super-user can modify flash */ |
7463 | if (!capable(CAP_NET_ADMIN)) | 7464 | if (!capable(CAP_NET_ADMIN)) |
@@ -7515,7 +7516,7 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) { | |||
7515 | * card. | 7516 | * card. |
7516 | */ | 7517 | */ |
7517 | 7518 | ||
7518 | int cmdreset(struct airo_info *ai) { | 7519 | static int cmdreset(struct airo_info *ai) { |
7519 | disable_MAC(ai, 1); | 7520 | disable_MAC(ai, 1); |
7520 | 7521 | ||
7521 | if(!waitbusy (ai)){ | 7522 | if(!waitbusy (ai)){ |
@@ -7539,7 +7540,7 @@ int cmdreset(struct airo_info *ai) { | |||
7539 | * mode | 7540 | * mode |
7540 | */ | 7541 | */ |
7541 | 7542 | ||
7542 | int setflashmode (struct airo_info *ai) { | 7543 | static int setflashmode (struct airo_info *ai) { |
7543 | set_bit (FLAG_FLASHING, &ai->flags); | 7544 | set_bit (FLAG_FLASHING, &ai->flags); |
7544 | 7545 | ||
7545 | OUT4500(ai, SWS0, FLASH_COMMAND); | 7546 | OUT4500(ai, SWS0, FLASH_COMMAND); |
@@ -7566,7 +7567,7 @@ int setflashmode (struct airo_info *ai) { | |||
7566 | * x 50us for echo . | 7567 | * x 50us for echo . |
7567 | */ | 7568 | */ |
7568 | 7569 | ||
7569 | int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | 7570 | static int flashpchar(struct airo_info *ai,int byte,int dwelltime) { |
7570 | int echo; | 7571 | int echo; |
7571 | int waittime; | 7572 | int waittime; |
7572 | 7573 | ||
@@ -7606,7 +7607,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) { | |||
7606 | * Get a character from the card matching matchbyte | 7607 | * Get a character from the card matching matchbyte |
7607 | * Step 3) | 7608 | * Step 3) |
7608 | */ | 7609 | */ |
7609 | int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | 7610 | static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ |
7610 | int rchar; | 7611 | int rchar; |
7611 | unsigned char rbyte=0; | 7612 | unsigned char rbyte=0; |
7612 | 7613 | ||
@@ -7637,7 +7638,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ | |||
7637 | * send to the card | 7638 | * send to the card |
7638 | */ | 7639 | */ |
7639 | 7640 | ||
7640 | int flashputbuf(struct airo_info *ai){ | 7641 | static int flashputbuf(struct airo_info *ai){ |
7641 | int nwords; | 7642 | int nwords; |
7642 | 7643 | ||
7643 | /* Write stuff */ | 7644 | /* Write stuff */ |
@@ -7659,7 +7660,7 @@ int flashputbuf(struct airo_info *ai){ | |||
7659 | /* | 7660 | /* |
7660 | * | 7661 | * |
7661 | */ | 7662 | */ |
7662 | int flashrestart(struct airo_info *ai,struct net_device *dev){ | 7663 | static int flashrestart(struct airo_info *ai,struct net_device *dev){ |
7663 | int i,status; | 7664 | int i,status; |
7664 | 7665 | ||
7665 | ssleep(1); /* Added 12/7/00 */ | 7666 | ssleep(1); /* Added 12/7/00 */ |
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 18a7d38d2a13..f48a6e729224 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c | |||
@@ -68,7 +68,7 @@ | |||
68 | #include <linux/device.h> | 68 | #include <linux/device.h> |
69 | #include <linux/moduleparam.h> | 69 | #include <linux/moduleparam.h> |
70 | #include <linux/firmware.h> | 70 | #include <linux/firmware.h> |
71 | #include "ieee802_11.h" | 71 | #include <net/ieee80211.h> |
72 | #include "atmel.h" | 72 | #include "atmel.h" |
73 | 73 | ||
74 | #define DRIVER_MAJOR 0 | 74 | #define DRIVER_MAJOR 0 |
@@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv); | |||
618 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); | 618 | static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); |
619 | static void atmel_command_irq(struct atmel_private *priv); | 619 | static void atmel_command_irq(struct atmel_private *priv); |
620 | static int atmel_validate_channel(struct atmel_private *priv, int channel); | 620 | static int atmel_validate_channel(struct atmel_private *priv, int channel); |
621 | static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | 621 | static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, |
622 | u16 frame_len, u8 rssi); | 622 | u16 frame_len, u8 rssi); |
623 | static void atmel_management_timer(u_long a); | 623 | static void atmel_management_timer(u_long a); |
624 | static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); | 624 | static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); |
625 | static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); | 625 | static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); |
626 | static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | 626 | static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, |
627 | u8 *body, int body_len); | 627 | u8 *body, int body_len); |
628 | 628 | ||
629 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); | 629 | static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); |
@@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l | |||
827 | static int start_tx (struct sk_buff *skb, struct net_device *dev) | 827 | static int start_tx (struct sk_buff *skb, struct net_device *dev) |
828 | { | 828 | { |
829 | struct atmel_private *priv = netdev_priv(dev); | 829 | struct atmel_private *priv = netdev_priv(dev); |
830 | struct ieee802_11_hdr header; | 830 | struct ieee80211_hdr header; |
831 | unsigned long flags; | 831 | unsigned long flags; |
832 | u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; | 832 | u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; |
833 | u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | 833 | u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; |
@@ -863,17 +863,17 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) | |||
863 | return 1; | 863 | return 1; |
864 | } | 864 | } |
865 | 865 | ||
866 | frame_ctl = IEEE802_11_FTYPE_DATA; | 866 | frame_ctl = IEEE80211_FTYPE_DATA; |
867 | header.duration_id = 0; | 867 | header.duration_id = 0; |
868 | header.seq_ctl = 0; | 868 | header.seq_ctl = 0; |
869 | if (priv->wep_is_on) | 869 | if (priv->wep_is_on) |
870 | frame_ctl |= IEEE802_11_FCTL_WEP; | 870 | frame_ctl |= IEEE80211_FCTL_PROTECTED; |
871 | if (priv->operating_mode == IW_MODE_ADHOC) { | 871 | if (priv->operating_mode == IW_MODE_ADHOC) { |
872 | memcpy(&header.addr1, skb->data, 6); | 872 | memcpy(&header.addr1, skb->data, 6); |
873 | memcpy(&header.addr2, dev->dev_addr, 6); | 873 | memcpy(&header.addr2, dev->dev_addr, 6); |
874 | memcpy(&header.addr3, priv->BSSID, 6); | 874 | memcpy(&header.addr3, priv->BSSID, 6); |
875 | } else { | 875 | } else { |
876 | frame_ctl |= IEEE802_11_FCTL_TODS; | 876 | frame_ctl |= IEEE80211_FCTL_TODS; |
877 | memcpy(&header.addr1, priv->CurrentBSSID, 6); | 877 | memcpy(&header.addr1, priv->CurrentBSSID, 6); |
878 | memcpy(&header.addr2, dev->dev_addr, 6); | 878 | memcpy(&header.addr2, dev->dev_addr, 6); |
879 | memcpy(&header.addr3, skb->data, 6); | 879 | memcpy(&header.addr3, skb->data, 6); |
@@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) | |||
902 | } | 902 | } |
903 | 903 | ||
904 | static void atmel_transmit_management_frame(struct atmel_private *priv, | 904 | static void atmel_transmit_management_frame(struct atmel_private *priv, |
905 | struct ieee802_11_hdr *header, | 905 | struct ieee80211_hdr *header, |
906 | u8 *body, int body_len) | 906 | u8 *body, int body_len) |
907 | { | 907 | { |
908 | u16 buff; | 908 | u16 buff; |
@@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, | |||
917 | tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); | 917 | tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); |
918 | } | 918 | } |
919 | 919 | ||
920 | static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, | 920 | static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, |
921 | u16 msdu_size, u16 rx_packet_loc, u32 crc) | 921 | u16 msdu_size, u16 rx_packet_loc, u32 crc) |
922 | { | 922 | { |
923 | /* fast path: unfragmented packet copy directly into skbuf */ | 923 | /* fast path: unfragmented packet copy directly into skbuf */ |
@@ -955,7 +955,7 @@ static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *head | |||
955 | } | 955 | } |
956 | 956 | ||
957 | memcpy(skbp, header->addr1, 6); /* destination address */ | 957 | memcpy(skbp, header->addr1, 6); /* destination address */ |
958 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | 958 | if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) |
959 | memcpy(&skbp[6], header->addr3, 6); | 959 | memcpy(&skbp[6], header->addr3, 6); |
960 | else | 960 | else |
961 | memcpy(&skbp[6], header->addr2, 6); /* source address */ | 961 | memcpy(&skbp[6], header->addr2, 6); /* source address */ |
@@ -990,14 +990,14 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) | |||
990 | return (crc ^ 0xffffffff) == netcrc; | 990 | return (crc ^ 0xffffffff) == netcrc; |
991 | } | 991 | } |
992 | 992 | ||
993 | static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, | 993 | static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header, |
994 | u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) | 994 | u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) |
995 | { | 995 | { |
996 | u8 mac4[6]; | 996 | u8 mac4[6]; |
997 | u8 source[6]; | 997 | u8 source[6]; |
998 | struct sk_buff *skb; | 998 | struct sk_buff *skb; |
999 | 999 | ||
1000 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | 1000 | if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) |
1001 | memcpy(source, header->addr3, 6); | 1001 | memcpy(source, header->addr3, 6); |
1002 | else | 1002 | else |
1003 | memcpy(source, header->addr2, 6); | 1003 | memcpy(source, header->addr2, 6); |
@@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *head | |||
1082 | static void rx_done_irq(struct atmel_private *priv) | 1082 | static void rx_done_irq(struct atmel_private *priv) |
1083 | { | 1083 | { |
1084 | int i; | 1084 | int i; |
1085 | struct ieee802_11_hdr header; | 1085 | struct ieee80211_hdr header; |
1086 | 1086 | ||
1087 | for (i = 0; | 1087 | for (i = 0; |
1088 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && | 1088 | atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && |
@@ -1117,7 +1117,7 @@ static void rx_done_irq(struct atmel_private *priv) | |||
1117 | /* probe for CRC use here if needed once five packets have arrived with | 1117 | /* probe for CRC use here if needed once five packets have arrived with |
1118 | the same crc status, we assume we know what's happening and stop probing */ | 1118 | the same crc status, we assume we know what's happening and stop probing */ |
1119 | if (priv->probe_crc) { | 1119 | if (priv->probe_crc) { |
1120 | if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { | 1120 | if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { |
1121 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); | 1121 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); |
1122 | } else { | 1122 | } else { |
1123 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); | 1123 | priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); |
@@ -1132,16 +1132,16 @@ static void rx_done_irq(struct atmel_private *priv) | |||
1132 | } | 1132 | } |
1133 | 1133 | ||
1134 | /* don't CRC header when WEP in use */ | 1134 | /* don't CRC header when WEP in use */ |
1135 | if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { | 1135 | if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { |
1136 | crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); | 1136 | crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); |
1137 | } | 1137 | } |
1138 | msdu_size -= 24; /* header */ | 1138 | msdu_size -= 24; /* header */ |
1139 | 1139 | ||
1140 | if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { | 1140 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { |
1141 | 1141 | ||
1142 | int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; | 1142 | int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; |
1143 | u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; | 1143 | u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; |
1144 | u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; | 1144 | u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; |
1145 | 1145 | ||
1146 | if (!more_fragments && packet_fragment_no == 0 ) { | 1146 | if (!more_fragments && packet_fragment_no == 0 ) { |
1147 | fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); | 1147 | fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); |
@@ -1151,7 +1151,7 @@ static void rx_done_irq(struct atmel_private *priv) | |||
1151 | } | 1151 | } |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { | 1154 | if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { |
1155 | /* copy rest of packet into buffer */ | 1155 | /* copy rest of packet into buffer */ |
1156 | atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); | 1156 | atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); |
1157 | 1157 | ||
@@ -2663,10 +2663,10 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c | |||
2663 | 2663 | ||
2664 | static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) | 2664 | static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) |
2665 | { | 2665 | { |
2666 | struct ieee802_11_hdr header; | 2666 | struct ieee80211_hdr header; |
2667 | struct auth_body auth; | 2667 | struct auth_body auth; |
2668 | 2668 | ||
2669 | header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); | 2669 | header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); |
2670 | header.duration_id = cpu_to_le16(0x8000); | 2670 | header.duration_id = cpu_to_le16(0x8000); |
2671 | header.seq_ctl = 0; | 2671 | header.seq_ctl = 0; |
2672 | memcpy(header.addr1, priv->CurrentBSSID, 6); | 2672 | memcpy(header.addr1, priv->CurrentBSSID, 6); |
@@ -2677,7 +2677,7 @@ static void send_authentication_request(struct atmel_private *priv, u8 *challeng | |||
2677 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); | 2677 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY); |
2678 | /* no WEP for authentication frames with TrSeqNo 1 */ | 2678 | /* no WEP for authentication frames with TrSeqNo 1 */ |
2679 | if (priv->CurrentAuthentTransactionSeqNum != 1) | 2679 | if (priv->CurrentAuthentTransactionSeqNum != 1) |
2680 | header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP); | 2680 | header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
2681 | } else { | 2681 | } else { |
2682 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM); | 2682 | auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM); |
2683 | } | 2683 | } |
@@ -2701,7 +2701,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) | |||
2701 | { | 2701 | { |
2702 | u8 *ssid_el_p; | 2702 | u8 *ssid_el_p; |
2703 | int bodysize; | 2703 | int bodysize; |
2704 | struct ieee802_11_hdr header; | 2704 | struct ieee80211_hdr header; |
2705 | struct ass_req_format { | 2705 | struct ass_req_format { |
2706 | u16 capability; | 2706 | u16 capability; |
2707 | u16 listen_interval; | 2707 | u16 listen_interval; |
@@ -2714,8 +2714,8 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) | |||
2714 | u8 rates[4]; | 2714 | u8 rates[4]; |
2715 | } body; | 2715 | } body; |
2716 | 2716 | ||
2717 | header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | | 2717 | header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2718 | (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ)); | 2718 | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); |
2719 | header.duration_id = cpu_to_le16(0x8000); | 2719 | header.duration_id = cpu_to_le16(0x8000); |
2720 | header.seq_ctl = 0; | 2720 | header.seq_ctl = 0; |
2721 | 2721 | ||
@@ -2751,9 +2751,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) | |||
2751 | atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); | 2751 | atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); |
2752 | } | 2752 | } |
2753 | 2753 | ||
2754 | static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header) | 2754 | static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header) |
2755 | { | 2755 | { |
2756 | if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) | 2756 | if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) |
2757 | return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; | 2757 | return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; |
2758 | else | 2758 | else |
2759 | return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; | 2759 | return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; |
@@ -2801,7 +2801,7 @@ static int retrieve_bss(struct atmel_private *priv) | |||
2801 | } | 2801 | } |
2802 | 2802 | ||
2803 | 2803 | ||
2804 | static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header, | 2804 | static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header, |
2805 | u16 capability, u16 beacon_period, u8 channel, u8 rssi, | 2805 | u16 capability, u16 beacon_period, u8 channel, u8 rssi, |
2806 | u8 ssid_len, u8 *ssid, int is_beacon) | 2806 | u8 ssid_len, u8 *ssid, int is_beacon) |
2807 | { | 2807 | { |
@@ -3085,12 +3085,12 @@ static void atmel_smooth_qual(struct atmel_private *priv) | |||
3085 | } | 3085 | } |
3086 | 3086 | ||
3087 | /* deals with incoming managment frames. */ | 3087 | /* deals with incoming managment frames. */ |
3088 | static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, | 3088 | static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header, |
3089 | u16 frame_len, u8 rssi) | 3089 | u16 frame_len, u8 rssi) |
3090 | { | 3090 | { |
3091 | u16 subtype; | 3091 | u16 subtype; |
3092 | 3092 | ||
3093 | switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) { | 3093 | switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE) { |
3094 | case C80211_SUBTYPE_MGMT_BEACON : | 3094 | case C80211_SUBTYPE_MGMT_BEACON : |
3095 | case C80211_SUBTYPE_MGMT_ProbeResponse: | 3095 | case C80211_SUBTYPE_MGMT_ProbeResponse: |
3096 | 3096 | ||
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig new file mode 100644 index 000000000000..1445f3f2600f --- /dev/null +++ b/drivers/net/wireless/hostap/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | config HOSTAP | ||
2 | tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" | ||
3 | depends on NET_RADIO | ||
4 | ---help--- | ||
5 | Shared driver code for IEEE 802.11b wireless cards based on | ||
6 | Intersil Prism2/2.5/3 chipset. This driver supports so called | ||
7 | Host AP mode that allows the card to act as an IEEE 802.11 | ||
8 | access point. | ||
9 | |||
10 | See <http://hostap.epitest.fi/> for more information about the | ||
11 | Host AP driver configuration and tools. This site includes | ||
12 | information and tools (hostapd and wpa_supplicant) for WPA/WPA2 | ||
13 | support. | ||
14 | |||
15 | This option includes the base Host AP driver code that is shared by | ||
16 | different hardware models. You will also need to enable support for | ||
17 | PLX/PCI/CS version of the driver to actually use the driver. | ||
18 | |||
19 | The driver can be compiled as a module and it will be called | ||
20 | "hostap.ko". | ||
21 | |||
22 | config HOSTAP_FIRMWARE | ||
23 | bool "Support downloading firmware images with Host AP driver" | ||
24 | depends on HOSTAP | ||
25 | ---help--- | ||
26 | Configure Host AP driver to include support for firmware image | ||
27 | download. Current version supports only downloading to volatile, i.e., | ||
28 | RAM memory. Flash upgrade is not yet supported. | ||
29 | |||
30 | Firmware image downloading needs user space tool, prism2_srec. It is | ||
31 | available from http://hostap.epitest.fi/. | ||
32 | |||
33 | config HOSTAP_PLX | ||
34 | tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" | ||
35 | depends on PCI && HOSTAP | ||
36 | ---help--- | ||
37 | Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based | ||
38 | PCI adaptors. | ||
39 | |||
40 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
41 | driver and its help text includes more information about the Host AP | ||
42 | driver. | ||
43 | |||
44 | The driver can be compiled as a module and will be named | ||
45 | "hostap_plx.ko". | ||
46 | |||
47 | config HOSTAP_PCI | ||
48 | tristate "Host AP driver for Prism2.5 PCI adaptors" | ||
49 | depends on PCI && HOSTAP | ||
50 | ---help--- | ||
51 | Host AP driver's version for Prism2.5 PCI adaptors. | ||
52 | |||
53 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
54 | driver and its help text includes more information about the Host AP | ||
55 | driver. | ||
56 | |||
57 | The driver can be compiled as a module and will be named | ||
58 | "hostap_pci.ko". | ||
59 | |||
60 | config HOSTAP_CS | ||
61 | tristate "Host AP driver for Prism2/2.5/3 PC Cards" | ||
62 | depends on PCMCIA!=n && HOSTAP | ||
63 | ---help--- | ||
64 | Host AP driver's version for Prism2/2.5/3 PC Cards. | ||
65 | |||
66 | "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | ||
67 | driver and its help text includes more information about the Host AP | ||
68 | driver. | ||
69 | |||
70 | The driver can be compiled as a module and will be named | ||
71 | "hostap_cs.ko". | ||
diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile new file mode 100644 index 000000000000..fc62235bfc24 --- /dev/null +++ b/drivers/net/wireless/hostap/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_HOSTAP) += hostap.o | ||
2 | |||
3 | obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o | ||
4 | obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o | ||
5 | obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o | ||
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c new file mode 100644 index 000000000000..e7f5821b4942 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap.c | |||
@@ -0,0 +1,1198 @@ | |||
1 | /* | ||
2 | * Host AP (software wireless LAN access point) driver for | ||
3 | * Intersil Prism2/2.5/3 - hostap.o module, common routines | ||
4 | * | ||
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
6 | * <jkmaline@cc.hut.fi> | ||
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. See README and COPYING for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/random.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/kmod.h> | ||
26 | #include <linux/rtnetlink.h> | ||
27 | #include <linux/wireless.h> | ||
28 | #include <net/iw_handler.h> | ||
29 | #include <net/ieee80211.h> | ||
30 | #include <net/ieee80211_crypt.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | |||
33 | #include "hostap_wlan.h" | ||
34 | #include "hostap_80211.h" | ||
35 | #include "hostap_ap.h" | ||
36 | #include "hostap.h" | ||
37 | |||
38 | MODULE_AUTHOR("Jouni Malinen"); | ||
39 | MODULE_DESCRIPTION("Host AP common routines"); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | MODULE_VERSION(PRISM2_VERSION); | ||
42 | |||
43 | #define TX_TIMEOUT (2 * HZ) | ||
44 | |||
45 | #define PRISM2_MAX_FRAME_SIZE 2304 | ||
46 | #define PRISM2_MIN_MTU 256 | ||
47 | /* FIX: */ | ||
48 | #define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) | ||
49 | |||
50 | |||
51 | /* hostap.c */ | ||
52 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
53 | int rtnl_locked); | ||
54 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
55 | int rtnl_locked, int do_not_remove); | ||
56 | |||
57 | /* hostap_ap.c */ | ||
58 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
59 | struct iw_quality qual[], int buf_size, | ||
60 | int aplist); | ||
61 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); | ||
62 | static int prism2_hostapd(struct ap_data *ap, | ||
63 | struct prism2_hostapd_param *param); | ||
64 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
65 | struct ieee80211_crypt_data ***crypt); | ||
66 | static void ap_control_kickall(struct ap_data *ap); | ||
67 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
68 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
69 | u8 *mac); | ||
70 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
71 | u8 *mac); | ||
72 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); | ||
73 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
74 | u8 *mac); | ||
75 | #endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
76 | |||
77 | |||
78 | static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, | ||
79 | 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; | ||
80 | #define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) | ||
81 | |||
82 | |||
83 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
84 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
85 | static unsigned char rfc1042_header[] = | ||
86 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
87 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
88 | static unsigned char bridge_tunnel_header[] = | ||
89 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
90 | /* No encapsulation header if EtherType < 0x600 (=length) */ | ||
91 | |||
92 | |||
93 | /* FIX: these could be compiled separately and linked together to hostap.o */ | ||
94 | #include "hostap_ap.c" | ||
95 | #include "hostap_info.c" | ||
96 | #include "hostap_ioctl.c" | ||
97 | #include "hostap_proc.c" | ||
98 | #include "hostap_80211_rx.c" | ||
99 | #include "hostap_80211_tx.c" | ||
100 | |||
101 | |||
102 | struct net_device * hostap_add_interface(struct local_info *local, | ||
103 | int type, int rtnl_locked, | ||
104 | const char *prefix, | ||
105 | const char *name) | ||
106 | { | ||
107 | struct net_device *dev, *mdev; | ||
108 | struct hostap_interface *iface; | ||
109 | int ret; | ||
110 | |||
111 | dev = alloc_etherdev(sizeof(struct hostap_interface)); | ||
112 | if (dev == NULL) | ||
113 | return NULL; | ||
114 | |||
115 | iface = netdev_priv(dev); | ||
116 | iface->dev = dev; | ||
117 | iface->local = local; | ||
118 | iface->type = type; | ||
119 | list_add(&iface->list, &local->hostap_interfaces); | ||
120 | |||
121 | mdev = local->dev; | ||
122 | memcpy(dev->dev_addr, mdev->dev_addr, ETH_ALEN); | ||
123 | dev->base_addr = mdev->base_addr; | ||
124 | dev->irq = mdev->irq; | ||
125 | dev->mem_start = mdev->mem_start; | ||
126 | dev->mem_end = mdev->mem_end; | ||
127 | |||
128 | hostap_setup_dev(dev, local, 0); | ||
129 | dev->destructor = free_netdev; | ||
130 | |||
131 | sprintf(dev->name, "%s%s", prefix, name); | ||
132 | if (!rtnl_locked) | ||
133 | rtnl_lock(); | ||
134 | |||
135 | ret = 0; | ||
136 | if (strchr(dev->name, '%')) | ||
137 | ret = dev_alloc_name(dev, dev->name); | ||
138 | |||
139 | SET_NETDEV_DEV(dev, mdev->class_dev.dev); | ||
140 | if (ret >= 0) | ||
141 | ret = register_netdevice(dev); | ||
142 | |||
143 | if (!rtnl_locked) | ||
144 | rtnl_unlock(); | ||
145 | |||
146 | if (ret < 0) { | ||
147 | printk(KERN_WARNING "%s: failed to add new netdevice!\n", | ||
148 | dev->name); | ||
149 | free_netdev(dev); | ||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | printk(KERN_DEBUG "%s: registered netdevice %s\n", | ||
154 | mdev->name, dev->name); | ||
155 | |||
156 | return dev; | ||
157 | } | ||
158 | |||
159 | |||
160 | void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | ||
161 | int remove_from_list) | ||
162 | { | ||
163 | struct hostap_interface *iface; | ||
164 | |||
165 | if (!dev) | ||
166 | return; | ||
167 | |||
168 | iface = netdev_priv(dev); | ||
169 | |||
170 | if (remove_from_list) { | ||
171 | list_del(&iface->list); | ||
172 | } | ||
173 | |||
174 | if (dev == iface->local->ddev) | ||
175 | iface->local->ddev = NULL; | ||
176 | else if (dev == iface->local->apdev) | ||
177 | iface->local->apdev = NULL; | ||
178 | else if (dev == iface->local->stadev) | ||
179 | iface->local->stadev = NULL; | ||
180 | |||
181 | if (rtnl_locked) | ||
182 | unregister_netdevice(dev); | ||
183 | else | ||
184 | unregister_netdev(dev); | ||
185 | |||
186 | /* dev->destructor = free_netdev() will free the device data, including | ||
187 | * private data, when removing the device */ | ||
188 | } | ||
189 | |||
190 | |||
191 | static inline int prism2_wds_special_addr(u8 *addr) | ||
192 | { | ||
193 | if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5]) | ||
194 | return 0; | ||
195 | |||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | |||
200 | static int prism2_wds_add(local_info_t *local, u8 *remote_addr, | ||
201 | int rtnl_locked) | ||
202 | { | ||
203 | struct net_device *dev; | ||
204 | struct list_head *ptr; | ||
205 | struct hostap_interface *iface, *empty, *match; | ||
206 | |||
207 | empty = match = NULL; | ||
208 | read_lock_bh(&local->iface_lock); | ||
209 | list_for_each(ptr, &local->hostap_interfaces) { | ||
210 | iface = list_entry(ptr, struct hostap_interface, list); | ||
211 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
212 | continue; | ||
213 | |||
214 | if (prism2_wds_special_addr(iface->u.wds.remote_addr)) | ||
215 | empty = iface; | ||
216 | else if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
217 | ETH_ALEN) == 0) { | ||
218 | match = iface; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | if (!match && empty && !prism2_wds_special_addr(remote_addr)) { | ||
223 | /* take pre-allocated entry into use */ | ||
224 | memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
225 | read_unlock_bh(&local->iface_lock); | ||
226 | printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n", | ||
227 | local->dev->name, empty->dev->name); | ||
228 | return 0; | ||
229 | } | ||
230 | read_unlock_bh(&local->iface_lock); | ||
231 | |||
232 | if (!prism2_wds_special_addr(remote_addr)) { | ||
233 | if (match) | ||
234 | return -EEXIST; | ||
235 | hostap_add_sta(local->ap, remote_addr); | ||
236 | } | ||
237 | |||
238 | if (local->wds_connections >= local->wds_max_connections) | ||
239 | return -ENOBUFS; | ||
240 | |||
241 | /* verify that there is room for wds# postfix in the interface name */ | ||
242 | if (strlen(local->dev->name) > IFNAMSIZ - 5) { | ||
243 | printk(KERN_DEBUG "'%s' too long base device name\n", | ||
244 | local->dev->name); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked, | ||
249 | local->ddev->name, "wds%d"); | ||
250 | if (dev == NULL) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | iface = netdev_priv(dev); | ||
254 | memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
255 | |||
256 | local->wds_connections++; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | |||
262 | static int prism2_wds_del(local_info_t *local, u8 *remote_addr, | ||
263 | int rtnl_locked, int do_not_remove) | ||
264 | { | ||
265 | unsigned long flags; | ||
266 | struct list_head *ptr; | ||
267 | struct hostap_interface *iface, *selected = NULL; | ||
268 | |||
269 | write_lock_irqsave(&local->iface_lock, flags); | ||
270 | list_for_each(ptr, &local->hostap_interfaces) { | ||
271 | iface = list_entry(ptr, struct hostap_interface, list); | ||
272 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
273 | continue; | ||
274 | |||
275 | if (memcmp(iface->u.wds.remote_addr, remote_addr, | ||
276 | ETH_ALEN) == 0) { | ||
277 | selected = iface; | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | if (selected && !do_not_remove) | ||
282 | list_del(&selected->list); | ||
283 | write_unlock_irqrestore(&local->iface_lock, flags); | ||
284 | |||
285 | if (selected) { | ||
286 | if (do_not_remove) | ||
287 | memset(selected->u.wds.remote_addr, 0, ETH_ALEN); | ||
288 | else { | ||
289 | hostap_remove_interface(selected->dev, rtnl_locked, 0); | ||
290 | local->wds_connections--; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return selected ? 0 : -ENODEV; | ||
295 | } | ||
296 | |||
297 | |||
298 | u16 hostap_tx_callback_register(local_info_t *local, | ||
299 | void (*func)(struct sk_buff *, int ok, void *), | ||
300 | void *data) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | struct hostap_tx_callback_info *entry; | ||
304 | |||
305 | entry = (struct hostap_tx_callback_info *) kmalloc(sizeof(*entry), | ||
306 | GFP_ATOMIC); | ||
307 | if (entry == NULL) | ||
308 | return 0; | ||
309 | |||
310 | entry->func = func; | ||
311 | entry->data = data; | ||
312 | |||
313 | spin_lock_irqsave(&local->lock, flags); | ||
314 | entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1; | ||
315 | entry->next = local->tx_callback; | ||
316 | local->tx_callback = entry; | ||
317 | spin_unlock_irqrestore(&local->lock, flags); | ||
318 | |||
319 | return entry->idx; | ||
320 | } | ||
321 | |||
322 | |||
323 | int hostap_tx_callback_unregister(local_info_t *local, u16 idx) | ||
324 | { | ||
325 | unsigned long flags; | ||
326 | struct hostap_tx_callback_info *cb, *prev = NULL; | ||
327 | |||
328 | spin_lock_irqsave(&local->lock, flags); | ||
329 | cb = local->tx_callback; | ||
330 | while (cb != NULL && cb->idx != idx) { | ||
331 | prev = cb; | ||
332 | cb = cb->next; | ||
333 | } | ||
334 | if (cb) { | ||
335 | if (prev == NULL) | ||
336 | local->tx_callback = cb->next; | ||
337 | else | ||
338 | prev->next = cb->next; | ||
339 | kfree(cb); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&local->lock, flags); | ||
342 | |||
343 | return cb ? 0 : -1; | ||
344 | } | ||
345 | |||
346 | |||
347 | /* val is in host byte order */ | ||
348 | int hostap_set_word(struct net_device *dev, int rid, u16 val) | ||
349 | { | ||
350 | struct hostap_interface *iface; | ||
351 | u16 tmp = cpu_to_le16(val); | ||
352 | iface = netdev_priv(dev); | ||
353 | return iface->local->func->set_rid(dev, rid, &tmp, 2); | ||
354 | } | ||
355 | |||
356 | |||
357 | int hostap_set_string(struct net_device *dev, int rid, const char *val) | ||
358 | { | ||
359 | struct hostap_interface *iface; | ||
360 | char buf[MAX_SSID_LEN + 2]; | ||
361 | int len; | ||
362 | |||
363 | iface = netdev_priv(dev); | ||
364 | len = strlen(val); | ||
365 | if (len > MAX_SSID_LEN) | ||
366 | return -1; | ||
367 | memset(buf, 0, sizeof(buf)); | ||
368 | buf[0] = len; /* little endian 16 bit word */ | ||
369 | memcpy(buf + 2, val, len); | ||
370 | |||
371 | return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2); | ||
372 | } | ||
373 | |||
374 | |||
375 | u16 hostap_get_porttype(local_info_t *local) | ||
376 | { | ||
377 | if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc) | ||
378 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
379 | if (local->iw_mode == IW_MODE_ADHOC) | ||
380 | return HFA384X_PORTTYPE_IBSS; | ||
381 | if (local->iw_mode == IW_MODE_INFRA) | ||
382 | return HFA384X_PORTTYPE_BSS; | ||
383 | if (local->iw_mode == IW_MODE_REPEAT) | ||
384 | return HFA384X_PORTTYPE_WDS; | ||
385 | if (local->iw_mode == IW_MODE_MONITOR) | ||
386 | return HFA384X_PORTTYPE_PSEUDO_IBSS; | ||
387 | return HFA384X_PORTTYPE_HOSTAP; | ||
388 | } | ||
389 | |||
390 | |||
391 | int hostap_set_encryption(local_info_t *local) | ||
392 | { | ||
393 | u16 val, old_val; | ||
394 | int i, keylen, len, idx; | ||
395 | char keybuf[WEP_KEY_LEN + 1]; | ||
396 | enum { NONE, WEP, OTHER } encrypt_type; | ||
397 | |||
398 | idx = local->tx_keyidx; | ||
399 | if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) | ||
400 | encrypt_type = NONE; | ||
401 | else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) | ||
402 | encrypt_type = WEP; | ||
403 | else | ||
404 | encrypt_type = OTHER; | ||
405 | |||
406 | if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, | ||
407 | 1) < 0) { | ||
408 | printk(KERN_DEBUG "Could not read current WEP flags.\n"); | ||
409 | goto fail; | ||
410 | } | ||
411 | le16_to_cpus(&val); | ||
412 | old_val = val; | ||
413 | |||
414 | if (encrypt_type != NONE || local->privacy_invoked) | ||
415 | val |= HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
416 | else | ||
417 | val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED; | ||
418 | |||
419 | if (local->open_wep || encrypt_type == NONE || | ||
420 | ((local->ieee_802_1x || local->wpa) && local->host_decrypt)) | ||
421 | val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
422 | else | ||
423 | val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED; | ||
424 | |||
425 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
426 | (encrypt_type == OTHER || local->host_encrypt)) | ||
427 | val |= HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
428 | else | ||
429 | val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT; | ||
430 | if ((encrypt_type != NONE || local->privacy_invoked) && | ||
431 | (encrypt_type == OTHER || local->host_decrypt)) | ||
432 | val |= HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
433 | else | ||
434 | val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT; | ||
435 | |||
436 | if (val != old_val && | ||
437 | hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) { | ||
438 | printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n", | ||
439 | val); | ||
440 | goto fail; | ||
441 | } | ||
442 | |||
443 | if (encrypt_type != WEP) | ||
444 | return 0; | ||
445 | |||
446 | /* 104-bit support seems to require that all the keys are set to the | ||
447 | * same keylen */ | ||
448 | keylen = 6; /* first 5 octets */ | ||
449 | len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), | ||
450 | NULL, local->crypt[idx]->priv); | ||
451 | if (idx >= 0 && idx < WEP_KEYS && len > 5) | ||
452 | keylen = WEP_KEY_LEN + 1; /* first 13 octets */ | ||
453 | |||
454 | for (i = 0; i < WEP_KEYS; i++) { | ||
455 | memset(keybuf, 0, sizeof(keybuf)); | ||
456 | if (local->crypt[i]) { | ||
457 | (void) local->crypt[i]->ops->get_key( | ||
458 | keybuf, sizeof(keybuf), | ||
459 | NULL, local->crypt[i]->priv); | ||
460 | } | ||
461 | if (local->func->set_rid(local->dev, | ||
462 | HFA384X_RID_CNFDEFAULTKEY0 + i, | ||
463 | keybuf, keylen)) { | ||
464 | printk(KERN_DEBUG "Could not set key %d (len=%d)\n", | ||
465 | i, keylen); | ||
466 | goto fail; | ||
467 | } | ||
468 | } | ||
469 | if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) { | ||
470 | printk(KERN_DEBUG "Could not set default keyid %d\n", idx); | ||
471 | goto fail; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | fail: | ||
477 | printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name); | ||
478 | return -1; | ||
479 | } | ||
480 | |||
481 | |||
482 | int hostap_set_antsel(local_info_t *local) | ||
483 | { | ||
484 | u16 val; | ||
485 | int ret = 0; | ||
486 | |||
487 | if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
488 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
489 | HFA386X_CR_TX_CONFIGURE, | ||
490 | NULL, &val) == 0) { | ||
491 | val &= ~(BIT(2) | BIT(1)); | ||
492 | switch (local->antsel_tx) { | ||
493 | case HOSTAP_ANTSEL_DIVERSITY: | ||
494 | val |= BIT(1); | ||
495 | break; | ||
496 | case HOSTAP_ANTSEL_LOW: | ||
497 | break; | ||
498 | case HOSTAP_ANTSEL_HIGH: | ||
499 | val |= BIT(2); | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
504 | HFA386X_CR_TX_CONFIGURE, &val, NULL)) { | ||
505 | printk(KERN_INFO "%s: setting TX AntSel failed\n", | ||
506 | local->dev->name); | ||
507 | ret = -1; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH && | ||
512 | local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF, | ||
513 | HFA386X_CR_RX_CONFIGURE, | ||
514 | NULL, &val) == 0) { | ||
515 | val &= ~(BIT(1) | BIT(0)); | ||
516 | switch (local->antsel_rx) { | ||
517 | case HOSTAP_ANTSEL_DIVERSITY: | ||
518 | break; | ||
519 | case HOSTAP_ANTSEL_LOW: | ||
520 | val |= BIT(0); | ||
521 | break; | ||
522 | case HOSTAP_ANTSEL_HIGH: | ||
523 | val |= BIT(0) | BIT(1); | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF, | ||
528 | HFA386X_CR_RX_CONFIGURE, &val, NULL)) { | ||
529 | printk(KERN_INFO "%s: setting RX AntSel failed\n", | ||
530 | local->dev->name); | ||
531 | ret = -1; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | |||
539 | int hostap_set_roaming(local_info_t *local) | ||
540 | { | ||
541 | u16 val; | ||
542 | |||
543 | switch (local->host_roaming) { | ||
544 | case 1: | ||
545 | val = HFA384X_ROAMING_HOST; | ||
546 | break; | ||
547 | case 2: | ||
548 | val = HFA384X_ROAMING_DISABLED; | ||
549 | break; | ||
550 | case 0: | ||
551 | default: | ||
552 | val = HFA384X_ROAMING_FIRMWARE; | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val); | ||
557 | } | ||
558 | |||
559 | |||
560 | int hostap_set_auth_algs(local_info_t *local) | ||
561 | { | ||
562 | int val = local->auth_algs; | ||
563 | /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication | ||
564 | * set to include both Open and Shared Key flags. It tries to use | ||
565 | * Shared Key authentication in that case even if WEP keys are not | ||
566 | * configured.. STA f/w v0.7.6 is able to handle such configuration, | ||
567 | * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */ | ||
568 | if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) && | ||
569 | val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY) | ||
570 | val = PRISM2_AUTH_OPEN; | ||
571 | |||
572 | if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) { | ||
573 | printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x " | ||
574 | "failed\n", local->dev->name, local->auth_algs); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | |||
582 | void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) | ||
583 | { | ||
584 | u16 status, fc; | ||
585 | |||
586 | status = __le16_to_cpu(rx->status); | ||
587 | |||
588 | printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, " | ||
589 | "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; " | ||
590 | "jiffies=%ld\n", | ||
591 | name, status, (status >> 8) & 0x07, status >> 13, status & 1, | ||
592 | rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies); | ||
593 | |||
594 | fc = __le16_to_cpu(rx->frame_control); | ||
595 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
596 | "data_len=%d%s%s\n", | ||
597 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
598 | __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), | ||
599 | __le16_to_cpu(rx->data_len), | ||
600 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
601 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
602 | |||
603 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
604 | MACSTR "\n", | ||
605 | MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), | ||
606 | MAC2STR(rx->addr4)); | ||
607 | |||
608 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
609 | MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), | ||
610 | __be16_to_cpu(rx->len)); | ||
611 | } | ||
612 | |||
613 | |||
614 | void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) | ||
615 | { | ||
616 | u16 fc; | ||
617 | |||
618 | printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " | ||
619 | "tx_control=0x%04x; jiffies=%ld\n", | ||
620 | name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate, | ||
621 | __le16_to_cpu(tx->tx_control), jiffies); | ||
622 | |||
623 | fc = __le16_to_cpu(tx->frame_control); | ||
624 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | ||
625 | "data_len=%d%s%s\n", | ||
626 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
627 | __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), | ||
628 | __le16_to_cpu(tx->data_len), | ||
629 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
630 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
631 | |||
632 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" | ||
633 | MACSTR "\n", | ||
634 | MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), | ||
635 | MAC2STR(tx->addr4)); | ||
636 | |||
637 | printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", | ||
638 | MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), | ||
639 | __be16_to_cpu(tx->len)); | ||
640 | } | ||
641 | |||
642 | |||
643 | int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
644 | { | ||
645 | memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */ | ||
646 | return ETH_ALEN; | ||
647 | } | ||
648 | |||
649 | |||
650 | int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) | ||
651 | { | ||
652 | if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) { | ||
653 | memcpy(haddr, skb->mac.raw + | ||
654 | sizeof(struct linux_wlan_ng_prism_hdr) + 10, | ||
655 | ETH_ALEN); /* addr2 */ | ||
656 | } else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */ | ||
657 | memcpy(haddr, skb->mac.raw + | ||
658 | sizeof(struct linux_wlan_ng_cap_hdr) + 10, | ||
659 | ETH_ALEN); /* addr2 */ | ||
660 | } | ||
661 | return ETH_ALEN; | ||
662 | } | ||
663 | |||
664 | |||
665 | int hostap_80211_get_hdrlen(u16 fc) | ||
666 | { | ||
667 | int hdrlen = 24; | ||
668 | |||
669 | switch (WLAN_FC_GET_TYPE(fc)) { | ||
670 | case IEEE80211_FTYPE_DATA: | ||
671 | if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) | ||
672 | hdrlen = 30; /* Addr4 */ | ||
673 | break; | ||
674 | case IEEE80211_FTYPE_CTL: | ||
675 | switch (WLAN_FC_GET_STYPE(fc)) { | ||
676 | case IEEE80211_STYPE_CTS: | ||
677 | case IEEE80211_STYPE_ACK: | ||
678 | hdrlen = 10; | ||
679 | break; | ||
680 | default: | ||
681 | hdrlen = 16; | ||
682 | break; | ||
683 | } | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | return hdrlen; | ||
688 | } | ||
689 | |||
690 | |||
691 | struct net_device_stats *hostap_get_stats(struct net_device *dev) | ||
692 | { | ||
693 | struct hostap_interface *iface; | ||
694 | iface = netdev_priv(dev); | ||
695 | return &iface->stats; | ||
696 | } | ||
697 | |||
698 | |||
699 | static int prism2_close(struct net_device *dev) | ||
700 | { | ||
701 | struct hostap_interface *iface; | ||
702 | local_info_t *local; | ||
703 | |||
704 | PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); | ||
705 | |||
706 | iface = netdev_priv(dev); | ||
707 | local = iface->local; | ||
708 | |||
709 | if (dev == local->ddev) { | ||
710 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
711 | } | ||
712 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
713 | if (!local->hostapd && dev == local->dev && | ||
714 | (!local->func->card_present || local->func->card_present(local)) && | ||
715 | local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) | ||
716 | hostap_deauth_all_stas(dev, local->ap, 1); | ||
717 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
718 | |||
719 | if (local->func->dev_close && local->func->dev_close(local)) | ||
720 | return 0; | ||
721 | |||
722 | if (dev == local->dev) { | ||
723 | local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL); | ||
724 | } | ||
725 | |||
726 | if (netif_running(dev)) { | ||
727 | netif_stop_queue(dev); | ||
728 | netif_device_detach(dev); | ||
729 | } | ||
730 | |||
731 | flush_scheduled_work(); | ||
732 | |||
733 | module_put(local->hw_module); | ||
734 | |||
735 | local->num_dev_open--; | ||
736 | |||
737 | if (dev != local->dev && local->dev->flags & IFF_UP && | ||
738 | local->master_dev_auto_open && local->num_dev_open == 1) { | ||
739 | /* Close master radio interface automatically if it was also | ||
740 | * opened automatically and we are now closing the last | ||
741 | * remaining non-master device. */ | ||
742 | dev_close(local->dev); | ||
743 | } | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | |||
749 | static int prism2_open(struct net_device *dev) | ||
750 | { | ||
751 | struct hostap_interface *iface; | ||
752 | local_info_t *local; | ||
753 | |||
754 | PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name); | ||
755 | |||
756 | iface = netdev_priv(dev); | ||
757 | local = iface->local; | ||
758 | |||
759 | if (local->no_pri) { | ||
760 | printk(KERN_DEBUG "%s: could not set interface UP - no PRI " | ||
761 | "f/w\n", dev->name); | ||
762 | return 1; | ||
763 | } | ||
764 | |||
765 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
766 | local->hw_downloading) | ||
767 | return -ENODEV; | ||
768 | |||
769 | if (local->func->dev_open && local->func->dev_open(local)) | ||
770 | return 1; | ||
771 | |||
772 | if (!try_module_get(local->hw_module)) | ||
773 | return -ENODEV; | ||
774 | local->num_dev_open++; | ||
775 | |||
776 | if (!local->dev_enabled && local->func->hw_enable(dev, 1)) { | ||
777 | printk(KERN_WARNING "%s: could not enable MAC port\n", | ||
778 | dev->name); | ||
779 | prism2_close(dev); | ||
780 | return 1; | ||
781 | } | ||
782 | if (!local->dev_enabled) | ||
783 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
784 | local->dev_enabled = 1; | ||
785 | |||
786 | if (dev != local->dev && !(local->dev->flags & IFF_UP)) { | ||
787 | /* Master radio interface is needed for all operation, so open | ||
788 | * it automatically when any virtual net_device is opened. */ | ||
789 | local->master_dev_auto_open = 1; | ||
790 | dev_open(local->dev); | ||
791 | } | ||
792 | |||
793 | netif_device_attach(dev); | ||
794 | netif_start_queue(dev); | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | |||
800 | static int prism2_set_mac_address(struct net_device *dev, void *p) | ||
801 | { | ||
802 | struct hostap_interface *iface; | ||
803 | local_info_t *local; | ||
804 | struct list_head *ptr; | ||
805 | struct sockaddr *addr = p; | ||
806 | |||
807 | iface = netdev_priv(dev); | ||
808 | local = iface->local; | ||
809 | |||
810 | if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data, | ||
811 | ETH_ALEN) < 0 || local->func->reset_port(dev)) | ||
812 | return -EINVAL; | ||
813 | |||
814 | read_lock_bh(&local->iface_lock); | ||
815 | list_for_each(ptr, &local->hostap_interfaces) { | ||
816 | iface = list_entry(ptr, struct hostap_interface, list); | ||
817 | memcpy(iface->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
818 | } | ||
819 | memcpy(local->dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
820 | read_unlock_bh(&local->iface_lock); | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | |||
826 | /* TODO: to be further implemented as soon as Prism2 fully supports | ||
827 | * GroupAddresses and correct documentation is available */ | ||
828 | void hostap_set_multicast_list_queue(void *data) | ||
829 | { | ||
830 | struct net_device *dev = (struct net_device *) data; | ||
831 | struct hostap_interface *iface; | ||
832 | local_info_t *local; | ||
833 | |||
834 | iface = netdev_priv(dev); | ||
835 | local = iface->local; | ||
836 | if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
837 | local->is_promisc)) { | ||
838 | printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", | ||
839 | dev->name, local->is_promisc ? "en" : "dis"); | ||
840 | } | ||
841 | } | ||
842 | |||
843 | |||
844 | static void hostap_set_multicast_list(struct net_device *dev) | ||
845 | { | ||
846 | #if 0 | ||
847 | /* FIX: promiscuous mode seems to be causing a lot of problems with | ||
848 | * some station firmware versions (FCSErr frames, invalid MACPort, etc. | ||
849 | * corrupted incoming frames). This code is now commented out while the | ||
850 | * problems are investigated. */ | ||
851 | struct hostap_interface *iface; | ||
852 | local_info_t *local; | ||
853 | |||
854 | iface = netdev_priv(dev); | ||
855 | local = iface->local; | ||
856 | if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) { | ||
857 | local->is_promisc = 1; | ||
858 | } else { | ||
859 | local->is_promisc = 0; | ||
860 | } | ||
861 | |||
862 | schedule_work(&local->set_multicast_list_queue); | ||
863 | #endif | ||
864 | } | ||
865 | |||
866 | |||
867 | static int prism2_change_mtu(struct net_device *dev, int new_mtu) | ||
868 | { | ||
869 | if (new_mtu < PRISM2_MIN_MTU || new_mtu > PRISM2_MAX_MTU) | ||
870 | return -EINVAL; | ||
871 | |||
872 | dev->mtu = new_mtu; | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | |||
877 | static void prism2_tx_timeout(struct net_device *dev) | ||
878 | { | ||
879 | struct hostap_interface *iface; | ||
880 | local_info_t *local; | ||
881 | struct hfa384x_regs regs; | ||
882 | |||
883 | iface = netdev_priv(dev); | ||
884 | local = iface->local; | ||
885 | |||
886 | printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name); | ||
887 | netif_stop_queue(local->dev); | ||
888 | |||
889 | local->func->read_regs(dev, ®s); | ||
890 | printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x " | ||
891 | "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n", | ||
892 | dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1, | ||
893 | regs.swsupport0); | ||
894 | |||
895 | local->func->schedule_reset(local); | ||
896 | } | ||
897 | |||
898 | |||
899 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | ||
900 | int main_dev) | ||
901 | { | ||
902 | struct hostap_interface *iface; | ||
903 | |||
904 | iface = netdev_priv(dev); | ||
905 | ether_setup(dev); | ||
906 | |||
907 | /* kernel callbacks */ | ||
908 | dev->get_stats = hostap_get_stats; | ||
909 | if (iface) { | ||
910 | /* Currently, we point to the proper spy_data only on | ||
911 | * the main_dev. This could be fixed. Jean II */ | ||
912 | iface->wireless_data.spy_data = &iface->spy_data; | ||
913 | dev->wireless_data = &iface->wireless_data; | ||
914 | } | ||
915 | dev->wireless_handlers = | ||
916 | (struct iw_handler_def *) &hostap_iw_handler_def; | ||
917 | dev->do_ioctl = hostap_ioctl; | ||
918 | dev->open = prism2_open; | ||
919 | dev->stop = prism2_close; | ||
920 | dev->hard_start_xmit = hostap_data_start_xmit; | ||
921 | dev->set_mac_address = prism2_set_mac_address; | ||
922 | dev->set_multicast_list = hostap_set_multicast_list; | ||
923 | dev->change_mtu = prism2_change_mtu; | ||
924 | dev->tx_timeout = prism2_tx_timeout; | ||
925 | dev->watchdog_timeo = TX_TIMEOUT; | ||
926 | |||
927 | dev->mtu = local->mtu; | ||
928 | if (!main_dev) { | ||
929 | /* use main radio device queue */ | ||
930 | dev->tx_queue_len = 0; | ||
931 | } | ||
932 | |||
933 | SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops); | ||
934 | |||
935 | netif_stop_queue(dev); | ||
936 | } | ||
937 | |||
938 | |||
939 | static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) | ||
940 | { | ||
941 | struct net_device *dev = local->dev; | ||
942 | |||
943 | if (local->apdev) | ||
944 | return -EEXIST; | ||
945 | |||
946 | printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); | ||
947 | |||
948 | local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP, | ||
949 | rtnl_locked, local->ddev->name, | ||
950 | "ap"); | ||
951 | if (local->apdev == NULL) | ||
952 | return -ENOMEM; | ||
953 | |||
954 | local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; | ||
955 | local->apdev->type = ARPHRD_IEEE80211; | ||
956 | local->apdev->hard_header_parse = hostap_80211_header_parse; | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | |||
962 | static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) | ||
963 | { | ||
964 | struct net_device *dev = local->dev; | ||
965 | |||
966 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
967 | |||
968 | hostap_remove_interface(local->apdev, rtnl_locked, 1); | ||
969 | local->apdev = NULL; | ||
970 | |||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | |||
975 | static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
976 | { | ||
977 | struct net_device *dev = local->dev; | ||
978 | |||
979 | if (local->stadev) | ||
980 | return -EEXIST; | ||
981 | |||
982 | printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name); | ||
983 | |||
984 | local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA, | ||
985 | rtnl_locked, local->ddev->name, | ||
986 | "sta"); | ||
987 | if (local->stadev == NULL) | ||
988 | return -ENOMEM; | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | |||
994 | static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked) | ||
995 | { | ||
996 | struct net_device *dev = local->dev; | ||
997 | |||
998 | printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); | ||
999 | |||
1000 | hostap_remove_interface(local->stadev, rtnl_locked, 1); | ||
1001 | local->stadev = NULL; | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) | ||
1008 | { | ||
1009 | int ret; | ||
1010 | |||
1011 | if (val < 0 || val > 1) | ||
1012 | return -EINVAL; | ||
1013 | |||
1014 | if (local->hostapd == val) | ||
1015 | return 0; | ||
1016 | |||
1017 | if (val) { | ||
1018 | ret = hostap_enable_hostapd(local, rtnl_locked); | ||
1019 | if (ret == 0) | ||
1020 | local->hostapd = 1; | ||
1021 | } else { | ||
1022 | local->hostapd = 0; | ||
1023 | ret = hostap_disable_hostapd(local, rtnl_locked); | ||
1024 | if (ret != 0) | ||
1025 | local->hostapd = 1; | ||
1026 | } | ||
1027 | |||
1028 | return ret; | ||
1029 | } | ||
1030 | |||
1031 | |||
1032 | int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked) | ||
1033 | { | ||
1034 | int ret; | ||
1035 | |||
1036 | if (val < 0 || val > 1) | ||
1037 | return -EINVAL; | ||
1038 | |||
1039 | if (local->hostapd_sta == val) | ||
1040 | return 0; | ||
1041 | |||
1042 | if (val) { | ||
1043 | ret = hostap_enable_hostapd_sta(local, rtnl_locked); | ||
1044 | if (ret == 0) | ||
1045 | local->hostapd_sta = 1; | ||
1046 | } else { | ||
1047 | local->hostapd_sta = 0; | ||
1048 | ret = hostap_disable_hostapd_sta(local, rtnl_locked); | ||
1049 | if (ret != 0) | ||
1050 | local->hostapd_sta = 1; | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | return ret; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | int prism2_update_comms_qual(struct net_device *dev) | ||
1059 | { | ||
1060 | struct hostap_interface *iface; | ||
1061 | local_info_t *local; | ||
1062 | int ret = 0; | ||
1063 | struct hfa384x_comms_quality sq; | ||
1064 | |||
1065 | iface = netdev_priv(dev); | ||
1066 | local = iface->local; | ||
1067 | if (!local->sta_fw_ver) | ||
1068 | ret = -1; | ||
1069 | else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1070 | if (local->func->get_rid(local->dev, | ||
1071 | HFA384X_RID_DBMCOMMSQUALITY, | ||
1072 | &sq, sizeof(sq), 1) >= 0) { | ||
1073 | local->comms_qual = (s16) le16_to_cpu(sq.comm_qual); | ||
1074 | local->avg_signal = (s16) le16_to_cpu(sq.signal_level); | ||
1075 | local->avg_noise = (s16) le16_to_cpu(sq.noise_level); | ||
1076 | local->last_comms_qual_update = jiffies; | ||
1077 | } else | ||
1078 | ret = -1; | ||
1079 | } else { | ||
1080 | if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY, | ||
1081 | &sq, sizeof(sq), 1) >= 0) { | ||
1082 | local->comms_qual = le16_to_cpu(sq.comm_qual); | ||
1083 | local->avg_signal = HFA384X_LEVEL_TO_dBm( | ||
1084 | le16_to_cpu(sq.signal_level)); | ||
1085 | local->avg_noise = HFA384X_LEVEL_TO_dBm( | ||
1086 | le16_to_cpu(sq.noise_level)); | ||
1087 | local->last_comms_qual_update = jiffies; | ||
1088 | } else | ||
1089 | ret = -1; | ||
1090 | } | ||
1091 | |||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, | ||
1097 | u8 *body, size_t bodylen) | ||
1098 | { | ||
1099 | struct sk_buff *skb; | ||
1100 | struct hostap_ieee80211_mgmt *mgmt; | ||
1101 | struct hostap_skb_tx_data *meta; | ||
1102 | struct net_device *dev = local->dev; | ||
1103 | |||
1104 | skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen); | ||
1105 | if (skb == NULL) | ||
1106 | return -ENOMEM; | ||
1107 | |||
1108 | mgmt = (struct hostap_ieee80211_mgmt *) | ||
1109 | skb_put(skb, IEEE80211_MGMT_HDR_LEN); | ||
1110 | memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN); | ||
1111 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
1112 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
1113 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
1114 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
1115 | if (body) | ||
1116 | memcpy(skb_put(skb, bodylen), body, bodylen); | ||
1117 | |||
1118 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1119 | memset(meta, 0, sizeof(*meta)); | ||
1120 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
1121 | meta->iface = netdev_priv(dev); | ||
1122 | |||
1123 | skb->dev = dev; | ||
1124 | skb->mac.raw = skb->nh.raw = skb->data; | ||
1125 | dev_queue_xmit(skb); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | int prism2_sta_deauth(local_info_t *local, u16 reason) | ||
1132 | { | ||
1133 | union iwreq_data wrqu; | ||
1134 | int ret; | ||
1135 | |||
1136 | if (local->iw_mode != IW_MODE_INFRA || | ||
1137 | memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 || | ||
1138 | memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0) | ||
1139 | return 0; | ||
1140 | |||
1141 | reason = cpu_to_le16(reason); | ||
1142 | ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, | ||
1143 | (u8 *) &reason, 2); | ||
1144 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
1145 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | struct proc_dir_entry *hostap_proc; | ||
1151 | |||
1152 | static int __init hostap_init(void) | ||
1153 | { | ||
1154 | if (proc_net != NULL) { | ||
1155 | hostap_proc = proc_mkdir("hostap", proc_net); | ||
1156 | if (!hostap_proc) | ||
1157 | printk(KERN_WARNING "Failed to mkdir " | ||
1158 | "/proc/net/hostap\n"); | ||
1159 | } else | ||
1160 | hostap_proc = NULL; | ||
1161 | |||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | static void __exit hostap_exit(void) | ||
1167 | { | ||
1168 | if (hostap_proc != NULL) { | ||
1169 | hostap_proc = NULL; | ||
1170 | remove_proc_entry("hostap", proc_net); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | EXPORT_SYMBOL(hostap_set_word); | ||
1176 | EXPORT_SYMBOL(hostap_set_string); | ||
1177 | EXPORT_SYMBOL(hostap_get_porttype); | ||
1178 | EXPORT_SYMBOL(hostap_set_encryption); | ||
1179 | EXPORT_SYMBOL(hostap_set_antsel); | ||
1180 | EXPORT_SYMBOL(hostap_set_roaming); | ||
1181 | EXPORT_SYMBOL(hostap_set_auth_algs); | ||
1182 | EXPORT_SYMBOL(hostap_dump_rx_header); | ||
1183 | EXPORT_SYMBOL(hostap_dump_tx_header); | ||
1184 | EXPORT_SYMBOL(hostap_80211_header_parse); | ||
1185 | EXPORT_SYMBOL(hostap_80211_prism_header_parse); | ||
1186 | EXPORT_SYMBOL(hostap_80211_get_hdrlen); | ||
1187 | EXPORT_SYMBOL(hostap_get_stats); | ||
1188 | EXPORT_SYMBOL(hostap_setup_dev); | ||
1189 | EXPORT_SYMBOL(hostap_proc); | ||
1190 | EXPORT_SYMBOL(hostap_set_multicast_list_queue); | ||
1191 | EXPORT_SYMBOL(hostap_set_hostapd); | ||
1192 | EXPORT_SYMBOL(hostap_set_hostapd_sta); | ||
1193 | EXPORT_SYMBOL(hostap_add_interface); | ||
1194 | EXPORT_SYMBOL(hostap_remove_interface); | ||
1195 | EXPORT_SYMBOL(prism2_update_comms_qual); | ||
1196 | |||
1197 | module_init(hostap_init); | ||
1198 | module_exit(hostap_exit); | ||
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h new file mode 100644 index 000000000000..5fac89b8ce3a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #ifndef HOSTAP_H | ||
2 | #define HOSTAP_H | ||
3 | |||
4 | /* hostap.c */ | ||
5 | |||
6 | extern struct proc_dir_entry *hostap_proc; | ||
7 | |||
8 | u16 hostap_tx_callback_register(local_info_t *local, | ||
9 | void (*func)(struct sk_buff *, int ok, void *), | ||
10 | void *data); | ||
11 | int hostap_tx_callback_unregister(local_info_t *local, u16 idx); | ||
12 | int hostap_set_word(struct net_device *dev, int rid, u16 val); | ||
13 | int hostap_set_string(struct net_device *dev, int rid, const char *val); | ||
14 | u16 hostap_get_porttype(local_info_t *local); | ||
15 | int hostap_set_encryption(local_info_t *local); | ||
16 | int hostap_set_antsel(local_info_t *local); | ||
17 | int hostap_set_roaming(local_info_t *local); | ||
18 | int hostap_set_auth_algs(local_info_t *local); | ||
19 | void hostap_dump_rx_header(const char *name, | ||
20 | const struct hfa384x_rx_frame *rx); | ||
21 | void hostap_dump_tx_header(const char *name, | ||
22 | const struct hfa384x_tx_frame *tx); | ||
23 | int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr); | ||
24 | int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr); | ||
25 | int hostap_80211_get_hdrlen(u16 fc); | ||
26 | struct net_device_stats *hostap_get_stats(struct net_device *dev); | ||
27 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | ||
28 | int main_dev); | ||
29 | void hostap_set_multicast_list_queue(void *data); | ||
30 | int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); | ||
31 | int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); | ||
32 | void hostap_cleanup(local_info_t *local); | ||
33 | void hostap_cleanup_handler(void *data); | ||
34 | struct net_device * hostap_add_interface(struct local_info *local, | ||
35 | int type, int rtnl_locked, | ||
36 | const char *prefix, const char *name); | ||
37 | void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | ||
38 | int remove_from_list); | ||
39 | int prism2_update_comms_qual(struct net_device *dev); | ||
40 | int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, | ||
41 | u8 *body, size_t bodylen); | ||
42 | int prism2_sta_deauth(local_info_t *local, u16 reason); | ||
43 | |||
44 | |||
45 | /* hostap_proc.c */ | ||
46 | |||
47 | void hostap_init_proc(local_info_t *local); | ||
48 | void hostap_remove_proc(local_info_t *local); | ||
49 | |||
50 | |||
51 | /* hostap_info.c */ | ||
52 | |||
53 | void hostap_info_init(local_info_t *local); | ||
54 | void hostap_info_process(local_info_t *local, struct sk_buff *skb); | ||
55 | |||
56 | |||
57 | #endif /* HOSTAP_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h new file mode 100644 index 000000000000..bf506f50d722 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211.h | |||
@@ -0,0 +1,96 @@ | |||
1 | #ifndef HOSTAP_80211_H | ||
2 | #define HOSTAP_80211_H | ||
3 | |||
4 | struct hostap_ieee80211_mgmt { | ||
5 | u16 frame_control; | ||
6 | u16 duration; | ||
7 | u8 da[6]; | ||
8 | u8 sa[6]; | ||
9 | u8 bssid[6]; | ||
10 | u16 seq_ctrl; | ||
11 | union { | ||
12 | struct { | ||
13 | u16 auth_alg; | ||
14 | u16 auth_transaction; | ||
15 | u16 status_code; | ||
16 | /* possibly followed by Challenge text */ | ||
17 | u8 variable[0]; | ||
18 | } __attribute__ ((packed)) auth; | ||
19 | struct { | ||
20 | u16 reason_code; | ||
21 | } __attribute__ ((packed)) deauth; | ||
22 | struct { | ||
23 | u16 capab_info; | ||
24 | u16 listen_interval; | ||
25 | /* followed by SSID and Supported rates */ | ||
26 | u8 variable[0]; | ||
27 | } __attribute__ ((packed)) assoc_req; | ||
28 | struct { | ||
29 | u16 capab_info; | ||
30 | u16 status_code; | ||
31 | u16 aid; | ||
32 | /* followed by Supported rates */ | ||
33 | u8 variable[0]; | ||
34 | } __attribute__ ((packed)) assoc_resp, reassoc_resp; | ||
35 | struct { | ||
36 | u16 capab_info; | ||
37 | u16 listen_interval; | ||
38 | u8 current_ap[6]; | ||
39 | /* followed by SSID and Supported rates */ | ||
40 | u8 variable[0]; | ||
41 | } __attribute__ ((packed)) reassoc_req; | ||
42 | struct { | ||
43 | u16 reason_code; | ||
44 | } __attribute__ ((packed)) disassoc; | ||
45 | struct { | ||
46 | } __attribute__ ((packed)) probe_req; | ||
47 | struct { | ||
48 | u8 timestamp[8]; | ||
49 | u16 beacon_int; | ||
50 | u16 capab_info; | ||
51 | /* followed by some of SSID, Supported rates, | ||
52 | * FH Params, DS Params, CF Params, IBSS Params, TIM */ | ||
53 | u8 variable[0]; | ||
54 | } __attribute__ ((packed)) beacon, probe_resp; | ||
55 | } u; | ||
56 | } __attribute__ ((packed)); | ||
57 | |||
58 | |||
59 | #define IEEE80211_MGMT_HDR_LEN 24 | ||
60 | #define IEEE80211_DATA_HDR3_LEN 24 | ||
61 | #define IEEE80211_DATA_HDR4_LEN 30 | ||
62 | |||
63 | |||
64 | struct hostap_80211_rx_status { | ||
65 | u32 mac_time; | ||
66 | u8 signal; | ||
67 | u8 noise; | ||
68 | u16 rate; /* in 100 kbps */ | ||
69 | }; | ||
70 | |||
71 | |||
72 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
73 | struct hostap_80211_rx_status *rx_stats); | ||
74 | |||
75 | |||
76 | /* prism2_rx_80211 'type' argument */ | ||
77 | enum { | ||
78 | PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, | ||
79 | PRISM2_RX_NULLFUNC_ACK | ||
80 | }; | ||
81 | |||
82 | int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | ||
83 | struct hostap_80211_rx_status *rx_stats, int type); | ||
84 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
85 | struct hostap_80211_rx_status *rx_stats); | ||
86 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | ||
87 | struct hostap_80211_rx_status *rx_stats); | ||
88 | |||
89 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); | ||
90 | int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
91 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
92 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
93 | struct ieee80211_crypt_data *crypt); | ||
94 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
95 | |||
96 | #endif /* HOSTAP_80211_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c new file mode 100644 index 000000000000..b0501243b175 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | #include <linux/etherdevice.h> | ||
2 | |||
3 | #include "hostap_80211.h" | ||
4 | #include "hostap.h" | ||
5 | |||
6 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | ||
7 | struct hostap_80211_rx_status *rx_stats) | ||
8 | { | ||
9 | struct ieee80211_hdr *hdr; | ||
10 | u16 fc; | ||
11 | |||
12 | hdr = (struct ieee80211_hdr *) skb->data; | ||
13 | |||
14 | printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " | ||
15 | "jiffies=%ld\n", | ||
16 | name, rx_stats->signal, rx_stats->noise, rx_stats->rate, | ||
17 | skb->len, jiffies); | ||
18 | |||
19 | if (skb->len < 2) | ||
20 | return; | ||
21 | |||
22 | fc = le16_to_cpu(hdr->frame_ctl); | ||
23 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
24 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
25 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
26 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
27 | |||
28 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
29 | printk("\n"); | ||
30 | return; | ||
31 | } | ||
32 | |||
33 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | ||
34 | le16_to_cpu(hdr->seq_ctl)); | ||
35 | |||
36 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, | ||
37 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); | ||
38 | if (skb->len >= 30) | ||
39 | printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); | ||
40 | printk("\n"); | ||
41 | } | ||
42 | |||
43 | |||
44 | /* Send RX frame to netif with 802.11 (and possible prism) header. | ||
45 | * Called from hardware or software IRQ context. */ | ||
46 | int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | ||
47 | struct hostap_80211_rx_status *rx_stats, int type) | ||
48 | { | ||
49 | struct hostap_interface *iface; | ||
50 | local_info_t *local; | ||
51 | int hdrlen, phdrlen, head_need, tail_need; | ||
52 | u16 fc; | ||
53 | int prism_header, ret; | ||
54 | struct ieee80211_hdr *hdr; | ||
55 | |||
56 | iface = netdev_priv(dev); | ||
57 | local = iface->local; | ||
58 | dev->last_rx = jiffies; | ||
59 | |||
60 | if (dev->type == ARPHRD_IEEE80211_PRISM) { | ||
61 | if (local->monitor_type == PRISM2_MONITOR_PRISM) { | ||
62 | prism_header = 1; | ||
63 | phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); | ||
64 | } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ | ||
65 | prism_header = 2; | ||
66 | phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); | ||
67 | } | ||
68 | } else { | ||
69 | prism_header = 0; | ||
70 | phdrlen = 0; | ||
71 | } | ||
72 | |||
73 | hdr = (struct ieee80211_hdr *) skb->data; | ||
74 | fc = le16_to_cpu(hdr->frame_ctl); | ||
75 | |||
76 | if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { | ||
77 | printk(KERN_DEBUG "%s: dropped management frame with header " | ||
78 | "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); | ||
79 | dev_kfree_skb_any(skb); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
84 | |||
85 | /* check if there is enough room for extra data; if not, expand skb | ||
86 | * buffer to be large enough for the changes */ | ||
87 | head_need = phdrlen; | ||
88 | tail_need = 0; | ||
89 | #ifdef PRISM2_ADD_BOGUS_CRC | ||
90 | tail_need += 4; | ||
91 | #endif /* PRISM2_ADD_BOGUS_CRC */ | ||
92 | |||
93 | head_need -= skb_headroom(skb); | ||
94 | tail_need -= skb_tailroom(skb); | ||
95 | |||
96 | if (head_need > 0 || tail_need > 0) { | ||
97 | if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, | ||
98 | tail_need > 0 ? tail_need : 0, | ||
99 | GFP_ATOMIC)) { | ||
100 | printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " | ||
101 | "reallocate skb buffer\n", dev->name); | ||
102 | dev_kfree_skb_any(skb); | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /* We now have an skb with enough head and tail room, so just insert | ||
108 | * the extra data */ | ||
109 | |||
110 | #ifdef PRISM2_ADD_BOGUS_CRC | ||
111 | memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ | ||
112 | #endif /* PRISM2_ADD_BOGUS_CRC */ | ||
113 | |||
114 | if (prism_header == 1) { | ||
115 | struct linux_wlan_ng_prism_hdr *hdr; | ||
116 | hdr = (struct linux_wlan_ng_prism_hdr *) | ||
117 | skb_push(skb, phdrlen); | ||
118 | memset(hdr, 0, phdrlen); | ||
119 | hdr->msgcode = LWNG_CAP_DID_BASE; | ||
120 | hdr->msglen = sizeof(*hdr); | ||
121 | memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); | ||
122 | #define LWNG_SETVAL(f,i,s,l,d) \ | ||
123 | hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ | ||
124 | hdr->f.status = s; hdr->f.len = l; hdr->f.data = d | ||
125 | LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); | ||
126 | LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); | ||
127 | LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); | ||
128 | LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); | ||
129 | LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); | ||
130 | LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); | ||
131 | LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); | ||
132 | LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); | ||
133 | LWNG_SETVAL(istx, 9, 0, 4, 0); | ||
134 | LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); | ||
135 | #undef LWNG_SETVAL | ||
136 | } else if (prism_header == 2) { | ||
137 | struct linux_wlan_ng_cap_hdr *hdr; | ||
138 | hdr = (struct linux_wlan_ng_cap_hdr *) | ||
139 | skb_push(skb, phdrlen); | ||
140 | memset(hdr, 0, phdrlen); | ||
141 | hdr->version = htonl(LWNG_CAPHDR_VERSION); | ||
142 | hdr->length = htonl(phdrlen); | ||
143 | hdr->mactime = __cpu_to_be64(rx_stats->mac_time); | ||
144 | hdr->hosttime = __cpu_to_be64(jiffies); | ||
145 | hdr->phytype = htonl(4); /* dss_dot11_b */ | ||
146 | hdr->channel = htonl(local->channel); | ||
147 | hdr->datarate = htonl(rx_stats->rate); | ||
148 | hdr->antenna = htonl(0); /* unknown */ | ||
149 | hdr->priority = htonl(0); /* unknown */ | ||
150 | hdr->ssi_type = htonl(3); /* raw */ | ||
151 | hdr->ssi_signal = htonl(rx_stats->signal); | ||
152 | hdr->ssi_noise = htonl(rx_stats->noise); | ||
153 | hdr->preamble = htonl(0); /* unknown */ | ||
154 | hdr->encoding = htonl(1); /* cck */ | ||
155 | } | ||
156 | |||
157 | ret = skb->len - phdrlen; | ||
158 | skb->dev = dev; | ||
159 | skb->mac.raw = skb->data; | ||
160 | skb_pull(skb, hdrlen); | ||
161 | if (prism_header) | ||
162 | skb_pull(skb, phdrlen); | ||
163 | skb->pkt_type = PACKET_OTHERHOST; | ||
164 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
165 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
166 | netif_rx(skb); | ||
167 | |||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | |||
172 | /* Called only as a tasklet (software IRQ) */ | ||
173 | static void monitor_rx(struct net_device *dev, struct sk_buff *skb, | ||
174 | struct hostap_80211_rx_status *rx_stats) | ||
175 | { | ||
176 | struct net_device_stats *stats; | ||
177 | int len; | ||
178 | |||
179 | len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); | ||
180 | stats = hostap_get_stats(dev); | ||
181 | stats->rx_packets++; | ||
182 | stats->rx_bytes += len; | ||
183 | } | ||
184 | |||
185 | |||
186 | /* Called only as a tasklet (software IRQ) */ | ||
187 | static struct prism2_frag_entry * | ||
188 | prism2_frag_cache_find(local_info_t *local, unsigned int seq, | ||
189 | unsigned int frag, u8 *src, u8 *dst) | ||
190 | { | ||
191 | struct prism2_frag_entry *entry; | ||
192 | int i; | ||
193 | |||
194 | for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | ||
195 | entry = &local->frag_cache[i]; | ||
196 | if (entry->skb != NULL && | ||
197 | time_after(jiffies, entry->first_frag_time + 2 * HZ)) { | ||
198 | printk(KERN_DEBUG "%s: expiring fragment cache entry " | ||
199 | "seq=%u last_frag=%u\n", | ||
200 | local->dev->name, entry->seq, entry->last_frag); | ||
201 | dev_kfree_skb(entry->skb); | ||
202 | entry->skb = NULL; | ||
203 | } | ||
204 | |||
205 | if (entry->skb != NULL && entry->seq == seq && | ||
206 | (entry->last_frag + 1 == frag || frag == -1) && | ||
207 | memcmp(entry->src_addr, src, ETH_ALEN) == 0 && | ||
208 | memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) | ||
209 | return entry; | ||
210 | } | ||
211 | |||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | |||
216 | /* Called only as a tasklet (software IRQ) */ | ||
217 | static struct sk_buff * | ||
218 | prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) | ||
219 | { | ||
220 | struct sk_buff *skb = NULL; | ||
221 | u16 sc; | ||
222 | unsigned int frag, seq; | ||
223 | struct prism2_frag_entry *entry; | ||
224 | |||
225 | sc = le16_to_cpu(hdr->seq_ctl); | ||
226 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
227 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | ||
228 | |||
229 | if (frag == 0) { | ||
230 | /* Reserve enough space to fit maximum frame length */ | ||
231 | skb = dev_alloc_skb(local->dev->mtu + | ||
232 | sizeof(struct ieee80211_hdr) + | ||
233 | 8 /* LLC */ + | ||
234 | 2 /* alignment */ + | ||
235 | 8 /* WEP */ + ETH_ALEN /* WDS */); | ||
236 | if (skb == NULL) | ||
237 | return NULL; | ||
238 | |||
239 | entry = &local->frag_cache[local->frag_next_idx]; | ||
240 | local->frag_next_idx++; | ||
241 | if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) | ||
242 | local->frag_next_idx = 0; | ||
243 | |||
244 | if (entry->skb != NULL) | ||
245 | dev_kfree_skb(entry->skb); | ||
246 | |||
247 | entry->first_frag_time = jiffies; | ||
248 | entry->seq = seq; | ||
249 | entry->last_frag = frag; | ||
250 | entry->skb = skb; | ||
251 | memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); | ||
252 | memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); | ||
253 | } else { | ||
254 | /* received a fragment of a frame for which the head fragment | ||
255 | * should have already been received */ | ||
256 | entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, | ||
257 | hdr->addr1); | ||
258 | if (entry != NULL) { | ||
259 | entry->last_frag = frag; | ||
260 | skb = entry->skb; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | return skb; | ||
265 | } | ||
266 | |||
267 | |||
268 | /* Called only as a tasklet (software IRQ) */ | ||
269 | static int prism2_frag_cache_invalidate(local_info_t *local, | ||
270 | struct ieee80211_hdr *hdr) | ||
271 | { | ||
272 | u16 sc; | ||
273 | unsigned int seq; | ||
274 | struct prism2_frag_entry *entry; | ||
275 | |||
276 | sc = le16_to_cpu(hdr->seq_ctl); | ||
277 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | ||
278 | |||
279 | entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); | ||
280 | |||
281 | if (entry == NULL) { | ||
282 | printk(KERN_DEBUG "%s: could not invalidate fragment cache " | ||
283 | "entry (seq=%u)\n", | ||
284 | local->dev->name, seq); | ||
285 | return -1; | ||
286 | } | ||
287 | |||
288 | entry->skb = NULL; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, | ||
294 | u8 *ssid, size_t ssid_len) | ||
295 | { | ||
296 | struct list_head *ptr; | ||
297 | struct hostap_bss_info *bss; | ||
298 | |||
299 | list_for_each(ptr, &local->bss_list) { | ||
300 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
301 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && | ||
302 | (ssid == NULL || | ||
303 | (ssid_len == bss->ssid_len && | ||
304 | memcmp(ssid, bss->ssid, ssid_len) == 0))) { | ||
305 | list_move(&bss->list, &local->bss_list); | ||
306 | return bss; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | return NULL; | ||
311 | } | ||
312 | |||
313 | |||
314 | static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, | ||
315 | u8 *ssid, size_t ssid_len) | ||
316 | { | ||
317 | struct hostap_bss_info *bss; | ||
318 | |||
319 | if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { | ||
320 | bss = list_entry(local->bss_list.prev, | ||
321 | struct hostap_bss_info, list); | ||
322 | list_del(&bss->list); | ||
323 | local->num_bss_info--; | ||
324 | } else { | ||
325 | bss = (struct hostap_bss_info *) | ||
326 | kmalloc(sizeof(*bss), GFP_ATOMIC); | ||
327 | if (bss == NULL) | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | memset(bss, 0, sizeof(*bss)); | ||
332 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
333 | memcpy(bss->ssid, ssid, ssid_len); | ||
334 | bss->ssid_len = ssid_len; | ||
335 | local->num_bss_info++; | ||
336 | list_add(&bss->list, &local->bss_list); | ||
337 | return bss; | ||
338 | } | ||
339 | |||
340 | |||
341 | static void __hostap_expire_bss(local_info_t *local) | ||
342 | { | ||
343 | struct hostap_bss_info *bss; | ||
344 | |||
345 | while (local->num_bss_info > 0) { | ||
346 | bss = list_entry(local->bss_list.prev, | ||
347 | struct hostap_bss_info, list); | ||
348 | if (!time_after(jiffies, bss->last_update + 60 * HZ)) | ||
349 | break; | ||
350 | |||
351 | list_del(&bss->list); | ||
352 | local->num_bss_info--; | ||
353 | kfree(bss); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | |||
358 | /* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so | ||
359 | * the same routine can be used to parse both of them. */ | ||
360 | static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, | ||
361 | int stype) | ||
362 | { | ||
363 | struct hostap_ieee80211_mgmt *mgmt; | ||
364 | int left, chan = 0; | ||
365 | u8 *pos; | ||
366 | u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; | ||
367 | size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; | ||
368 | struct hostap_bss_info *bss; | ||
369 | |||
370 | if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) | ||
371 | return; | ||
372 | |||
373 | mgmt = (struct hostap_ieee80211_mgmt *) skb->data; | ||
374 | pos = mgmt->u.beacon.variable; | ||
375 | left = skb->len - (pos - skb->data); | ||
376 | |||
377 | while (left >= 2) { | ||
378 | if (2 + pos[1] > left) | ||
379 | return; /* parse failed */ | ||
380 | switch (*pos) { | ||
381 | case WLAN_EID_SSID: | ||
382 | ssid = pos + 2; | ||
383 | ssid_len = pos[1]; | ||
384 | break; | ||
385 | case WLAN_EID_GENERIC: | ||
386 | if (pos[1] >= 4 && | ||
387 | pos[2] == 0x00 && pos[3] == 0x50 && | ||
388 | pos[4] == 0xf2 && pos[5] == 1) { | ||
389 | wpa = pos; | ||
390 | wpa_len = pos[1] + 2; | ||
391 | } | ||
392 | break; | ||
393 | case WLAN_EID_RSN: | ||
394 | rsn = pos; | ||
395 | rsn_len = pos[1] + 2; | ||
396 | break; | ||
397 | case WLAN_EID_DS_PARAMS: | ||
398 | if (pos[1] >= 1) | ||
399 | chan = pos[2]; | ||
400 | break; | ||
401 | } | ||
402 | left -= 2 + pos[1]; | ||
403 | pos += 2 + pos[1]; | ||
404 | } | ||
405 | |||
406 | if (wpa_len > MAX_WPA_IE_LEN) | ||
407 | wpa_len = MAX_WPA_IE_LEN; | ||
408 | if (rsn_len > MAX_WPA_IE_LEN) | ||
409 | rsn_len = MAX_WPA_IE_LEN; | ||
410 | if (ssid_len > sizeof(bss->ssid)) | ||
411 | ssid_len = sizeof(bss->ssid); | ||
412 | |||
413 | spin_lock(&local->lock); | ||
414 | bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); | ||
415 | if (bss == NULL) | ||
416 | bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); | ||
417 | if (bss) { | ||
418 | bss->last_update = jiffies; | ||
419 | bss->count++; | ||
420 | bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); | ||
421 | if (wpa) { | ||
422 | memcpy(bss->wpa_ie, wpa, wpa_len); | ||
423 | bss->wpa_ie_len = wpa_len; | ||
424 | } else | ||
425 | bss->wpa_ie_len = 0; | ||
426 | if (rsn) { | ||
427 | memcpy(bss->rsn_ie, rsn, rsn_len); | ||
428 | bss->rsn_ie_len = rsn_len; | ||
429 | } else | ||
430 | bss->rsn_ie_len = 0; | ||
431 | bss->chan = chan; | ||
432 | } | ||
433 | __hostap_expire_bss(local); | ||
434 | spin_unlock(&local->lock); | ||
435 | } | ||
436 | |||
437 | |||
438 | static inline int | ||
439 | hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, | ||
440 | struct hostap_80211_rx_status *rx_stats, u16 type, | ||
441 | u16 stype) | ||
442 | { | ||
443 | if (local->iw_mode == IW_MODE_MASTER) { | ||
444 | hostap_update_sta_ps(local, (struct ieee80211_hdr *) | ||
445 | skb->data); | ||
446 | } | ||
447 | |||
448 | if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { | ||
449 | if (stype == IEEE80211_STYPE_BEACON && | ||
450 | local->iw_mode == IW_MODE_MASTER) { | ||
451 | struct sk_buff *skb2; | ||
452 | /* Process beacon frames also in kernel driver to | ||
453 | * update STA(AP) table statistics */ | ||
454 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
455 | if (skb2) | ||
456 | hostap_rx(skb2->dev, skb2, rx_stats); | ||
457 | } | ||
458 | |||
459 | /* send management frames to the user space daemon for | ||
460 | * processing */ | ||
461 | local->apdevstats.rx_packets++; | ||
462 | local->apdevstats.rx_bytes += skb->len; | ||
463 | if (local->apdev == NULL) | ||
464 | return -1; | ||
465 | prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | if (local->iw_mode == IW_MODE_MASTER) { | ||
470 | if (type != IEEE80211_FTYPE_MGMT && | ||
471 | type != IEEE80211_FTYPE_CTL) { | ||
472 | printk(KERN_DEBUG "%s: unknown management frame " | ||
473 | "(type=0x%02x, stype=0x%02x) dropped\n", | ||
474 | skb->dev->name, type >> 2, stype >> 4); | ||
475 | return -1; | ||
476 | } | ||
477 | |||
478 | hostap_rx(skb->dev, skb, rx_stats); | ||
479 | return 0; | ||
480 | } else if (type == IEEE80211_FTYPE_MGMT && | ||
481 | (stype == IEEE80211_STYPE_BEACON || | ||
482 | stype == IEEE80211_STYPE_PROBE_RESP)) { | ||
483 | hostap_rx_sta_beacon(local, skb, stype); | ||
484 | return -1; | ||
485 | } else if (type == IEEE80211_FTYPE_MGMT && | ||
486 | (stype == IEEE80211_STYPE_ASSOC_RESP || | ||
487 | stype == IEEE80211_STYPE_REASSOC_RESP)) { | ||
488 | /* Ignore (Re)AssocResp silently since these are not currently | ||
489 | * needed but are still received when WPA/RSN mode is enabled. | ||
490 | */ | ||
491 | return -1; | ||
492 | } else { | ||
493 | printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" | ||
494 | " management frame in non-Host AP mode (type=%d:%d)\n", | ||
495 | skb->dev->name, type >> 2, stype >> 4); | ||
496 | return -1; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | |||
501 | /* Called only as a tasklet (software IRQ) */ | ||
502 | static inline struct net_device *prism2_rx_get_wds(local_info_t *local, | ||
503 | u8 *addr) | ||
504 | { | ||
505 | struct hostap_interface *iface = NULL; | ||
506 | struct list_head *ptr; | ||
507 | |||
508 | read_lock_bh(&local->iface_lock); | ||
509 | list_for_each(ptr, &local->hostap_interfaces) { | ||
510 | iface = list_entry(ptr, struct hostap_interface, list); | ||
511 | if (iface->type == HOSTAP_INTERFACE_WDS && | ||
512 | memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) | ||
513 | break; | ||
514 | iface = NULL; | ||
515 | } | ||
516 | read_unlock_bh(&local->iface_lock); | ||
517 | |||
518 | return iface ? iface->dev : NULL; | ||
519 | } | ||
520 | |||
521 | |||
522 | static inline int | ||
523 | hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, | ||
524 | u16 fc, struct net_device **wds) | ||
525 | { | ||
526 | /* FIX: is this really supposed to accept WDS frames only in Master | ||
527 | * mode? What about Repeater or Managed with WDS frames? */ | ||
528 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != | ||
529 | (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && | ||
530 | (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) | ||
531 | return 0; /* not a WDS frame */ | ||
532 | |||
533 | /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) | ||
534 | * or own non-standard frame with 4th address after payload */ | ||
535 | if (memcmp(hdr->addr1, local->dev->dev_addr, ETH_ALEN) != 0 && | ||
536 | (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || | ||
537 | hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || | ||
538 | hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { | ||
539 | /* RA (or BSSID) is not ours - drop */ | ||
540 | PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " | ||
541 | "not own or broadcast %s=" MACSTR "\n", | ||
542 | local->dev->name, | ||
543 | fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", | ||
544 | MAC2STR(hdr->addr1)); | ||
545 | return -1; | ||
546 | } | ||
547 | |||
548 | /* check if the frame came from a registered WDS connection */ | ||
549 | *wds = prism2_rx_get_wds(local, hdr->addr2); | ||
550 | if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && | ||
551 | (local->iw_mode != IW_MODE_INFRA || | ||
552 | !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || | ||
553 | memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { | ||
554 | /* require that WDS link has been registered with TA or the | ||
555 | * frame is from current AP when using 'AP client mode' */ | ||
556 | PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " | ||
557 | "from unknown TA=" MACSTR "\n", | ||
558 | local->dev->name, MAC2STR(hdr->addr2)); | ||
559 | if (local->ap && local->ap->autom_ap_wds) | ||
560 | hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); | ||
561 | return -1; | ||
562 | } | ||
563 | |||
564 | if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && | ||
565 | hostap_is_sta_assoc(local->ap, hdr->addr2)) { | ||
566 | /* STA is actually associated with us even though it has a | ||
567 | * registered WDS link. Assume it is in 'AP client' mode. | ||
568 | * Since this is a 3-addr frame, assume it is not (bogus) WDS | ||
569 | * frame and process it like any normal ToDS frame from | ||
570 | * associated STA. */ | ||
571 | *wds = NULL; | ||
572 | } | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | |||
578 | static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) | ||
579 | { | ||
580 | struct net_device *dev = local->dev; | ||
581 | u16 fc, ethertype; | ||
582 | struct ieee80211_hdr *hdr; | ||
583 | u8 *pos; | ||
584 | |||
585 | if (skb->len < 24) | ||
586 | return 0; | ||
587 | |||
588 | hdr = (struct ieee80211_hdr *) skb->data; | ||
589 | fc = le16_to_cpu(hdr->frame_ctl); | ||
590 | |||
591 | /* check that the frame is unicast frame to us */ | ||
592 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
593 | IEEE80211_FCTL_TODS && | ||
594 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && | ||
595 | memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
596 | /* ToDS frame with own addr BSSID and DA */ | ||
597 | } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
598 | IEEE80211_FCTL_FROMDS && | ||
599 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
600 | /* FromDS frame with own addr as DA */ | ||
601 | } else | ||
602 | return 0; | ||
603 | |||
604 | if (skb->len < 24 + 8) | ||
605 | return 0; | ||
606 | |||
607 | /* check for port access entity Ethernet type */ | ||
608 | pos = skb->data + 24; | ||
609 | ethertype = (pos[6] << 8) | pos[7]; | ||
610 | if (ethertype == ETH_P_PAE) | ||
611 | return 1; | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | |||
617 | /* Called only as a tasklet (software IRQ) */ | ||
618 | static inline int | ||
619 | hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, | ||
620 | struct ieee80211_crypt_data *crypt) | ||
621 | { | ||
622 | struct ieee80211_hdr *hdr; | ||
623 | int res, hdrlen; | ||
624 | |||
625 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | ||
626 | return 0; | ||
627 | |||
628 | hdr = (struct ieee80211_hdr *) skb->data; | ||
629 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
630 | |||
631 | if (local->tkip_countermeasures && | ||
632 | strcmp(crypt->ops->name, "TKIP") == 0) { | ||
633 | if (net_ratelimit()) { | ||
634 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
635 | "received packet from " MACSTR "\n", | ||
636 | local->dev->name, MAC2STR(hdr->addr2)); | ||
637 | } | ||
638 | return -1; | ||
639 | } | ||
640 | |||
641 | atomic_inc(&crypt->refcnt); | ||
642 | res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); | ||
643 | atomic_dec(&crypt->refcnt); | ||
644 | if (res < 0) { | ||
645 | printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR | ||
646 | ") res=%d\n", | ||
647 | local->dev->name, MAC2STR(hdr->addr2), res); | ||
648 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
649 | return -1; | ||
650 | } | ||
651 | |||
652 | return res; | ||
653 | } | ||
654 | |||
655 | |||
656 | /* Called only as a tasklet (software IRQ) */ | ||
657 | static inline int | ||
658 | hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, | ||
659 | int keyidx, struct ieee80211_crypt_data *crypt) | ||
660 | { | ||
661 | struct ieee80211_hdr *hdr; | ||
662 | int res, hdrlen; | ||
663 | |||
664 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | ||
665 | return 0; | ||
666 | |||
667 | hdr = (struct ieee80211_hdr *) skb->data; | ||
668 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
669 | |||
670 | atomic_inc(&crypt->refcnt); | ||
671 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | ||
672 | atomic_dec(&crypt->refcnt); | ||
673 | if (res < 0) { | ||
674 | printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" | ||
675 | " (SA=" MACSTR " keyidx=%d)\n", | ||
676 | local->dev->name, MAC2STR(hdr->addr2), keyidx); | ||
677 | return -1; | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | |||
684 | /* All received frames are sent to this function. @skb contains the frame in | ||
685 | * IEEE 802.11 format, i.e., in the format it was sent over air. | ||
686 | * This function is called only as a tasklet (software IRQ). */ | ||
687 | void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | ||
688 | struct hostap_80211_rx_status *rx_stats) | ||
689 | { | ||
690 | struct hostap_interface *iface; | ||
691 | local_info_t *local; | ||
692 | struct ieee80211_hdr *hdr; | ||
693 | size_t hdrlen; | ||
694 | u16 fc, type, stype, sc; | ||
695 | struct net_device *wds = NULL; | ||
696 | struct net_device_stats *stats; | ||
697 | unsigned int frag; | ||
698 | u8 *payload; | ||
699 | struct sk_buff *skb2 = NULL; | ||
700 | u16 ethertype; | ||
701 | int frame_authorized = 0; | ||
702 | int from_assoc_ap = 0; | ||
703 | u8 dst[ETH_ALEN]; | ||
704 | u8 src[ETH_ALEN]; | ||
705 | struct ieee80211_crypt_data *crypt = NULL; | ||
706 | void *sta = NULL; | ||
707 | int keyidx = 0; | ||
708 | |||
709 | iface = netdev_priv(dev); | ||
710 | local = iface->local; | ||
711 | iface->stats.rx_packets++; | ||
712 | iface->stats.rx_bytes += skb->len; | ||
713 | |||
714 | /* dev is the master radio device; change this to be the default | ||
715 | * virtual interface (this may be changed to WDS device below) */ | ||
716 | dev = local->ddev; | ||
717 | iface = netdev_priv(dev); | ||
718 | |||
719 | hdr = (struct ieee80211_hdr *) skb->data; | ||
720 | stats = hostap_get_stats(dev); | ||
721 | |||
722 | if (skb->len < 10) | ||
723 | goto rx_dropped; | ||
724 | |||
725 | fc = le16_to_cpu(hdr->frame_ctl); | ||
726 | type = WLAN_FC_GET_TYPE(fc); | ||
727 | stype = WLAN_FC_GET_STYPE(fc); | ||
728 | sc = le16_to_cpu(hdr->seq_ctl); | ||
729 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
730 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
731 | |||
732 | /* Put this code here so that we avoid duplicating it in all | ||
733 | * Rx paths. - Jean II */ | ||
734 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
735 | /* If spy monitoring on */ | ||
736 | if (iface->spy_data.spy_number > 0) { | ||
737 | struct iw_quality wstats; | ||
738 | wstats.level = rx_stats->signal; | ||
739 | wstats.noise = rx_stats->noise; | ||
740 | wstats.updated = 6; /* No qual value */ | ||
741 | /* Update spy records */ | ||
742 | wireless_spy_update(dev, hdr->addr2, &wstats); | ||
743 | } | ||
744 | #endif /* IW_WIRELESS_SPY */ | ||
745 | hostap_update_rx_stats(local->ap, hdr, rx_stats); | ||
746 | |||
747 | if (local->iw_mode == IW_MODE_MONITOR) { | ||
748 | monitor_rx(dev, skb, rx_stats); | ||
749 | return; | ||
750 | } | ||
751 | |||
752 | if (local->host_decrypt) { | ||
753 | int idx = 0; | ||
754 | if (skb->len >= hdrlen + 3) | ||
755 | idx = skb->data[hdrlen + 3] >> 6; | ||
756 | crypt = local->crypt[idx]; | ||
757 | sta = NULL; | ||
758 | |||
759 | /* Use station specific key to override default keys if the | ||
760 | * receiver address is a unicast address ("individual RA"). If | ||
761 | * bcrx_sta_key parameter is set, station specific key is used | ||
762 | * even with broad/multicast targets (this is against IEEE | ||
763 | * 802.11, but makes it easier to use different keys with | ||
764 | * stations that do not support WEP key mapping). */ | ||
765 | |||
766 | if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) | ||
767 | (void) hostap_handle_sta_crypto(local, hdr, &crypt, | ||
768 | &sta); | ||
769 | |||
770 | /* allow NULL decrypt to indicate an station specific override | ||
771 | * for default encryption */ | ||
772 | if (crypt && (crypt->ops == NULL || | ||
773 | crypt->ops->decrypt_mpdu == NULL)) | ||
774 | crypt = NULL; | ||
775 | |||
776 | if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { | ||
777 | #if 0 | ||
778 | /* This seems to be triggered by some (multicast?) | ||
779 | * frames from other than current BSS, so just drop the | ||
780 | * frames silently instead of filling system log with | ||
781 | * these reports. */ | ||
782 | printk(KERN_DEBUG "%s: WEP decryption failed (not set)" | ||
783 | " (SA=" MACSTR ")\n", | ||
784 | local->dev->name, MAC2STR(hdr->addr2)); | ||
785 | #endif | ||
786 | local->comm_tallies.rx_discards_wep_undecryptable++; | ||
787 | goto rx_dropped; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | if (type != IEEE80211_FTYPE_DATA) { | ||
792 | if (type == IEEE80211_FTYPE_MGMT && | ||
793 | stype == IEEE80211_STYPE_AUTH && | ||
794 | fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && | ||
795 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
796 | { | ||
797 | printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " | ||
798 | "from " MACSTR "\n", dev->name, | ||
799 | MAC2STR(hdr->addr2)); | ||
800 | /* TODO: could inform hostapd about this so that it | ||
801 | * could send auth failure report */ | ||
802 | goto rx_dropped; | ||
803 | } | ||
804 | |||
805 | if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) | ||
806 | goto rx_dropped; | ||
807 | else | ||
808 | goto rx_exit; | ||
809 | } | ||
810 | |||
811 | /* Data frame - extract src/dst addresses */ | ||
812 | if (skb->len < IEEE80211_DATA_HDR3_LEN) | ||
813 | goto rx_dropped; | ||
814 | |||
815 | switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | ||
816 | case IEEE80211_FCTL_FROMDS: | ||
817 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
818 | memcpy(src, hdr->addr3, ETH_ALEN); | ||
819 | break; | ||
820 | case IEEE80211_FCTL_TODS: | ||
821 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
822 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
823 | break; | ||
824 | case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | ||
825 | if (skb->len < IEEE80211_DATA_HDR4_LEN) | ||
826 | goto rx_dropped; | ||
827 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
828 | memcpy(src, hdr->addr4, ETH_ALEN); | ||
829 | break; | ||
830 | case 0: | ||
831 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
832 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
833 | break; | ||
834 | } | ||
835 | |||
836 | if (hostap_rx_frame_wds(local, hdr, fc, &wds)) | ||
837 | goto rx_dropped; | ||
838 | if (wds) { | ||
839 | skb->dev = dev = wds; | ||
840 | stats = hostap_get_stats(dev); | ||
841 | } | ||
842 | |||
843 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
844 | (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
845 | IEEE80211_FCTL_FROMDS && | ||
846 | local->stadev && | ||
847 | memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { | ||
848 | /* Frame from BSSID of the AP for which we are a client */ | ||
849 | skb->dev = dev = local->stadev; | ||
850 | stats = hostap_get_stats(dev); | ||
851 | from_assoc_ap = 1; | ||
852 | } | ||
853 | |||
854 | dev->last_rx = jiffies; | ||
855 | |||
856 | if ((local->iw_mode == IW_MODE_MASTER || | ||
857 | local->iw_mode == IW_MODE_REPEAT) && | ||
858 | !from_assoc_ap) { | ||
859 | switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, | ||
860 | wds != NULL)) { | ||
861 | case AP_RX_CONTINUE_NOT_AUTHORIZED: | ||
862 | frame_authorized = 0; | ||
863 | break; | ||
864 | case AP_RX_CONTINUE: | ||
865 | frame_authorized = 1; | ||
866 | break; | ||
867 | case AP_RX_DROP: | ||
868 | goto rx_dropped; | ||
869 | case AP_RX_EXIT: | ||
870 | goto rx_exit; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | /* Nullfunc frames may have PS-bit set, so they must be passed to | ||
875 | * hostap_handle_sta_rx() before being dropped here. */ | ||
876 | if (stype != IEEE80211_STYPE_DATA && | ||
877 | stype != IEEE80211_STYPE_DATA_CFACK && | ||
878 | stype != IEEE80211_STYPE_DATA_CFPOLL && | ||
879 | stype != IEEE80211_STYPE_DATA_CFACKPOLL) { | ||
880 | if (stype != IEEE80211_STYPE_NULLFUNC) | ||
881 | printk(KERN_DEBUG "%s: RX: dropped data frame " | ||
882 | "with no data (type=0x%02x, subtype=0x%02x)\n", | ||
883 | dev->name, type >> 2, stype >> 4); | ||
884 | goto rx_dropped; | ||
885 | } | ||
886 | |||
887 | /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ | ||
888 | |||
889 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
890 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | ||
891 | goto rx_dropped; | ||
892 | hdr = (struct ieee80211_hdr *) skb->data; | ||
893 | |||
894 | /* skb: hdr + (possibly fragmented) plaintext payload */ | ||
895 | |||
896 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
897 | (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { | ||
898 | int flen; | ||
899 | struct sk_buff *frag_skb = | ||
900 | prism2_frag_cache_get(local, hdr); | ||
901 | if (!frag_skb) { | ||
902 | printk(KERN_DEBUG "%s: Rx cannot get skb from " | ||
903 | "fragment cache (morefrag=%d seq=%u frag=%u)\n", | ||
904 | dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, | ||
905 | WLAN_GET_SEQ_SEQ(sc) >> 4, frag); | ||
906 | goto rx_dropped; | ||
907 | } | ||
908 | |||
909 | flen = skb->len; | ||
910 | if (frag != 0) | ||
911 | flen -= hdrlen; | ||
912 | |||
913 | if (frag_skb->tail + flen > frag_skb->end) { | ||
914 | printk(KERN_WARNING "%s: host decrypted and " | ||
915 | "reassembled frame did not fit skb\n", | ||
916 | dev->name); | ||
917 | prism2_frag_cache_invalidate(local, hdr); | ||
918 | goto rx_dropped; | ||
919 | } | ||
920 | |||
921 | if (frag == 0) { | ||
922 | /* copy first fragment (including full headers) into | ||
923 | * beginning of the fragment cache skb */ | ||
924 | memcpy(skb_put(frag_skb, flen), skb->data, flen); | ||
925 | } else { | ||
926 | /* append frame payload to the end of the fragment | ||
927 | * cache skb */ | ||
928 | memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, | ||
929 | flen); | ||
930 | } | ||
931 | dev_kfree_skb(skb); | ||
932 | skb = NULL; | ||
933 | |||
934 | if (fc & IEEE80211_FCTL_MOREFRAGS) { | ||
935 | /* more fragments expected - leave the skb in fragment | ||
936 | * cache for now; it will be delivered to upper layers | ||
937 | * after all fragments have been received */ | ||
938 | goto rx_exit; | ||
939 | } | ||
940 | |||
941 | /* this was the last fragment and the frame will be | ||
942 | * delivered, so remove skb from fragment cache */ | ||
943 | skb = frag_skb; | ||
944 | hdr = (struct ieee80211_hdr *) skb->data; | ||
945 | prism2_frag_cache_invalidate(local, hdr); | ||
946 | } | ||
947 | |||
948 | /* skb: hdr + (possible reassembled) full MSDU payload; possibly still | ||
949 | * encrypted/authenticated */ | ||
950 | |||
951 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
952 | hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) | ||
953 | goto rx_dropped; | ||
954 | |||
955 | hdr = (struct ieee80211_hdr *) skb->data; | ||
956 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { | ||
957 | if (local->ieee_802_1x && | ||
958 | hostap_is_eapol_frame(local, skb)) { | ||
959 | /* pass unencrypted EAPOL frames even if encryption is | ||
960 | * configured */ | ||
961 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " | ||
962 | "unencrypted EAPOL frame\n", local->dev->name); | ||
963 | } else { | ||
964 | printk(KERN_DEBUG "%s: encryption configured, but RX " | ||
965 | "frame not encrypted (SA=" MACSTR ")\n", | ||
966 | local->dev->name, MAC2STR(hdr->addr2)); | ||
967 | goto rx_dropped; | ||
968 | } | ||
969 | } | ||
970 | |||
971 | if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && | ||
972 | !hostap_is_eapol_frame(local, skb)) { | ||
973 | if (net_ratelimit()) { | ||
974 | printk(KERN_DEBUG "%s: dropped unencrypted RX data " | ||
975 | "frame from " MACSTR " (drop_unencrypted=1)\n", | ||
976 | dev->name, MAC2STR(hdr->addr2)); | ||
977 | } | ||
978 | goto rx_dropped; | ||
979 | } | ||
980 | |||
981 | /* skb: hdr + (possible reassembled) full plaintext payload */ | ||
982 | |||
983 | payload = skb->data + hdrlen; | ||
984 | ethertype = (payload[6] << 8) | payload[7]; | ||
985 | |||
986 | /* If IEEE 802.1X is used, check whether the port is authorized to send | ||
987 | * the received frame. */ | ||
988 | if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { | ||
989 | if (ethertype == ETH_P_PAE) { | ||
990 | PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", | ||
991 | dev->name); | ||
992 | if (local->hostapd && local->apdev) { | ||
993 | /* Send IEEE 802.1X frames to the user | ||
994 | * space daemon for processing */ | ||
995 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
996 | PRISM2_RX_MGMT); | ||
997 | local->apdevstats.rx_packets++; | ||
998 | local->apdevstats.rx_bytes += skb->len; | ||
999 | goto rx_exit; | ||
1000 | } | ||
1001 | } else if (!frame_authorized) { | ||
1002 | printk(KERN_DEBUG "%s: dropped frame from " | ||
1003 | "unauthorized port (IEEE 802.1X): " | ||
1004 | "ethertype=0x%04x\n", | ||
1005 | dev->name, ethertype); | ||
1006 | goto rx_dropped; | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | /* convert hdr + possible LLC headers into Ethernet header */ | ||
1011 | if (skb->len - hdrlen >= 8 && | ||
1012 | ((memcmp(payload, rfc1042_header, 6) == 0 && | ||
1013 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
1014 | memcmp(payload, bridge_tunnel_header, 6) == 0)) { | ||
1015 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
1016 | * replace EtherType */ | ||
1017 | skb_pull(skb, hdrlen + 6); | ||
1018 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1019 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1020 | } else { | ||
1021 | u16 len; | ||
1022 | /* Leave Ethernet header part of hdr and full payload */ | ||
1023 | skb_pull(skb, hdrlen); | ||
1024 | len = htons(skb->len); | ||
1025 | memcpy(skb_push(skb, 2), &len, 2); | ||
1026 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1027 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1028 | } | ||
1029 | |||
1030 | if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
1031 | IEEE80211_FCTL_TODS) && | ||
1032 | skb->len >= ETH_HLEN + ETH_ALEN) { | ||
1033 | /* Non-standard frame: get addr4 from its bogus location after | ||
1034 | * the payload */ | ||
1035 | memcpy(skb->data + ETH_ALEN, | ||
1036 | skb->data + skb->len - ETH_ALEN, ETH_ALEN); | ||
1037 | skb_trim(skb, skb->len - ETH_ALEN); | ||
1038 | } | ||
1039 | |||
1040 | stats->rx_packets++; | ||
1041 | stats->rx_bytes += skb->len; | ||
1042 | |||
1043 | if (local->iw_mode == IW_MODE_MASTER && !wds && | ||
1044 | local->ap->bridge_packets) { | ||
1045 | if (dst[0] & 0x01) { | ||
1046 | /* copy multicast frame both to the higher layers and | ||
1047 | * to the wireless media */ | ||
1048 | local->ap->bridged_multicast++; | ||
1049 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
1050 | if (skb2 == NULL) | ||
1051 | printk(KERN_DEBUG "%s: skb_clone failed for " | ||
1052 | "multicast frame\n", dev->name); | ||
1053 | } else if (hostap_is_sta_authorized(local->ap, dst)) { | ||
1054 | /* send frame directly to the associated STA using | ||
1055 | * wireless media and not passing to higher layers */ | ||
1056 | local->ap->bridged_unicast++; | ||
1057 | skb2 = skb; | ||
1058 | skb = NULL; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | if (skb2 != NULL) { | ||
1063 | /* send to wireless media */ | ||
1064 | skb2->protocol = __constant_htons(ETH_P_802_3); | ||
1065 | skb2->mac.raw = skb2->nh.raw = skb2->data; | ||
1066 | /* skb2->nh.raw = skb2->data + ETH_HLEN; */ | ||
1067 | skb2->dev = dev; | ||
1068 | dev_queue_xmit(skb2); | ||
1069 | } | ||
1070 | |||
1071 | if (skb) { | ||
1072 | skb->protocol = eth_type_trans(skb, dev); | ||
1073 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1074 | skb->dev = dev; | ||
1075 | netif_rx(skb); | ||
1076 | } | ||
1077 | |||
1078 | rx_exit: | ||
1079 | if (sta) | ||
1080 | hostap_handle_sta_release(sta); | ||
1081 | return; | ||
1082 | |||
1083 | rx_dropped: | ||
1084 | dev_kfree_skb(skb); | ||
1085 | |||
1086 | stats->rx_dropped++; | ||
1087 | goto rx_exit; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | EXPORT_SYMBOL(hostap_80211_rx); | ||
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c new file mode 100644 index 000000000000..6358015f6526 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c | |||
@@ -0,0 +1,524 @@ | |||
1 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | ||
2 | { | ||
3 | struct ieee80211_hdr *hdr; | ||
4 | u16 fc; | ||
5 | |||
6 | hdr = (struct ieee80211_hdr *) skb->data; | ||
7 | |||
8 | printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", | ||
9 | name, skb->len, jiffies); | ||
10 | |||
11 | if (skb->len < 2) | ||
12 | return; | ||
13 | |||
14 | fc = le16_to_cpu(hdr->frame_ctl); | ||
15 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | ||
16 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | ||
17 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | ||
18 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | ||
19 | |||
20 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
21 | printk("\n"); | ||
22 | return; | ||
23 | } | ||
24 | |||
25 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | ||
26 | le16_to_cpu(hdr->seq_ctl)); | ||
27 | |||
28 | printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, | ||
29 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); | ||
30 | if (skb->len >= 30) | ||
31 | printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); | ||
32 | printk("\n"); | ||
33 | } | ||
34 | |||
35 | |||
36 | /* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) | ||
37 | * Convert Ethernet header into a suitable IEEE 802.11 header depending on | ||
38 | * device configuration. */ | ||
39 | int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
40 | { | ||
41 | struct hostap_interface *iface; | ||
42 | local_info_t *local; | ||
43 | int need_headroom, need_tailroom = 0; | ||
44 | struct ieee80211_hdr hdr; | ||
45 | u16 fc, ethertype = 0; | ||
46 | enum { | ||
47 | WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME | ||
48 | } use_wds = WDS_NO; | ||
49 | u8 *encaps_data; | ||
50 | int hdr_len, encaps_len, skip_header_bytes; | ||
51 | int to_assoc_ap = 0; | ||
52 | struct hostap_skb_tx_data *meta; | ||
53 | |||
54 | iface = netdev_priv(dev); | ||
55 | local = iface->local; | ||
56 | |||
57 | if (skb->len < ETH_HLEN) { | ||
58 | printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " | ||
59 | "(len=%d)\n", dev->name, skb->len); | ||
60 | kfree_skb(skb); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | if (local->ddev != dev) { | ||
65 | use_wds = (local->iw_mode == IW_MODE_MASTER && | ||
66 | !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? | ||
67 | WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; | ||
68 | if (dev == local->stadev) { | ||
69 | to_assoc_ap = 1; | ||
70 | use_wds = WDS_NO; | ||
71 | } else if (dev == local->apdev) { | ||
72 | printk(KERN_DEBUG "%s: prism2_tx: trying to use " | ||
73 | "AP device with Ethernet net dev\n", dev->name); | ||
74 | kfree_skb(skb); | ||
75 | return 0; | ||
76 | } | ||
77 | } else { | ||
78 | if (local->iw_mode == IW_MODE_REPEAT) { | ||
79 | printk(KERN_DEBUG "%s: prism2_tx: trying to use " | ||
80 | "non-WDS link in Repeater mode\n", dev->name); | ||
81 | kfree_skb(skb); | ||
82 | return 0; | ||
83 | } else if (local->iw_mode == IW_MODE_INFRA && | ||
84 | (local->wds_type & HOSTAP_WDS_AP_CLIENT) && | ||
85 | memcmp(skb->data + ETH_ALEN, dev->dev_addr, | ||
86 | ETH_ALEN) != 0) { | ||
87 | /* AP client mode: send frames with foreign src addr | ||
88 | * using 4-addr WDS frames */ | ||
89 | use_wds = WDS_COMPLIANT_FRAME; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload | ||
94 | * ==> | ||
95 | * Prism2 TX frame with 802.11 header: | ||
96 | * txdesc (address order depending on used mode; includes dst_addr and | ||
97 | * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; | ||
98 | * proto[2], payload {, possible addr4[6]} */ | ||
99 | |||
100 | ethertype = (skb->data[12] << 8) | skb->data[13]; | ||
101 | |||
102 | memset(&hdr, 0, sizeof(hdr)); | ||
103 | |||
104 | /* Length of data after IEEE 802.11 header */ | ||
105 | encaps_data = NULL; | ||
106 | encaps_len = 0; | ||
107 | skip_header_bytes = ETH_HLEN; | ||
108 | if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { | ||
109 | encaps_data = bridge_tunnel_header; | ||
110 | encaps_len = sizeof(bridge_tunnel_header); | ||
111 | skip_header_bytes -= 2; | ||
112 | } else if (ethertype >= 0x600) { | ||
113 | encaps_data = rfc1042_header; | ||
114 | encaps_len = sizeof(rfc1042_header); | ||
115 | skip_header_bytes -= 2; | ||
116 | } | ||
117 | |||
118 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; | ||
119 | hdr_len = IEEE80211_DATA_HDR3_LEN; | ||
120 | |||
121 | if (use_wds != WDS_NO) { | ||
122 | /* Note! Prism2 station firmware has problems with sending real | ||
123 | * 802.11 frames with four addresses; until these problems can | ||
124 | * be fixed or worked around, 4-addr frames needed for WDS are | ||
125 | * using incompatible format: FromDS flag is not set and the | ||
126 | * fourth address is added after the frame payload; it is | ||
127 | * assumed, that the receiving station knows how to handle this | ||
128 | * frame format */ | ||
129 | |||
130 | if (use_wds == WDS_COMPLIANT_FRAME) { | ||
131 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | ||
132 | /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, | ||
133 | * Addr4 = SA */ | ||
134 | memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
135 | hdr_len += ETH_ALEN; | ||
136 | } else { | ||
137 | /* bogus 4-addr format to workaround Prism2 station | ||
138 | * f/w bug */ | ||
139 | fc |= IEEE80211_FCTL_TODS; | ||
140 | /* From DS: Addr1 = DA (used as RA), | ||
141 | * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), | ||
142 | */ | ||
143 | |||
144 | /* SA from skb->data + ETH_ALEN will be added after | ||
145 | * frame payload; use hdr.addr4 as a temporary buffer | ||
146 | */ | ||
147 | memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
148 | need_tailroom += ETH_ALEN; | ||
149 | } | ||
150 | |||
151 | /* send broadcast and multicast frames to broadcast RA, if | ||
152 | * configured; otherwise, use unicast RA of the WDS link */ | ||
153 | if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && | ||
154 | skb->data[0] & 0x01) | ||
155 | memset(&hdr.addr1, 0xff, ETH_ALEN); | ||
156 | else if (iface->type == HOSTAP_INTERFACE_WDS) | ||
157 | memcpy(&hdr.addr1, iface->u.wds.remote_addr, | ||
158 | ETH_ALEN); | ||
159 | else | ||
160 | memcpy(&hdr.addr1, local->bssid, ETH_ALEN); | ||
161 | memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
162 | memcpy(&hdr.addr3, skb->data, ETH_ALEN); | ||
163 | } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { | ||
164 | fc |= IEEE80211_FCTL_FROMDS; | ||
165 | /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ | ||
166 | memcpy(&hdr.addr1, skb->data, ETH_ALEN); | ||
167 | memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
168 | memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | ||
169 | } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { | ||
170 | fc |= IEEE80211_FCTL_TODS; | ||
171 | /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ | ||
172 | memcpy(&hdr.addr1, to_assoc_ap ? | ||
173 | local->assoc_ap_addr : local->bssid, ETH_ALEN); | ||
174 | memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
175 | memcpy(&hdr.addr3, skb->data, ETH_ALEN); | ||
176 | } else if (local->iw_mode == IW_MODE_ADHOC) { | ||
177 | /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ | ||
178 | memcpy(&hdr.addr1, skb->data, ETH_ALEN); | ||
179 | memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
180 | memcpy(&hdr.addr3, local->bssid, ETH_ALEN); | ||
181 | } | ||
182 | |||
183 | hdr.frame_ctl = cpu_to_le16(fc); | ||
184 | |||
185 | skb_pull(skb, skip_header_bytes); | ||
186 | need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; | ||
187 | if (skb_tailroom(skb) < need_tailroom) { | ||
188 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
189 | if (skb == NULL) { | ||
190 | iface->stats.tx_dropped++; | ||
191 | return 0; | ||
192 | } | ||
193 | if (pskb_expand_head(skb, need_headroom, need_tailroom, | ||
194 | GFP_ATOMIC)) { | ||
195 | kfree_skb(skb); | ||
196 | iface->stats.tx_dropped++; | ||
197 | return 0; | ||
198 | } | ||
199 | } else if (skb_headroom(skb) < need_headroom) { | ||
200 | struct sk_buff *tmp = skb; | ||
201 | skb = skb_realloc_headroom(skb, need_headroom); | ||
202 | kfree_skb(tmp); | ||
203 | if (skb == NULL) { | ||
204 | iface->stats.tx_dropped++; | ||
205 | return 0; | ||
206 | } | ||
207 | } else { | ||
208 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
209 | if (skb == NULL) { | ||
210 | iface->stats.tx_dropped++; | ||
211 | return 0; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (encaps_data) | ||
216 | memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); | ||
217 | memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); | ||
218 | if (use_wds == WDS_OWN_FRAME) { | ||
219 | memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN); | ||
220 | } | ||
221 | |||
222 | iface->stats.tx_packets++; | ||
223 | iface->stats.tx_bytes += skb->len; | ||
224 | |||
225 | skb->mac.raw = skb->data; | ||
226 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
227 | memset(meta, 0, sizeof(*meta)); | ||
228 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
229 | if (use_wds) | ||
230 | meta->flags |= HOSTAP_TX_FLAGS_WDS; | ||
231 | meta->ethertype = ethertype; | ||
232 | meta->iface = iface; | ||
233 | |||
234 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
235 | skb->dev = local->dev; | ||
236 | dev_queue_xmit(skb); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* hard_start_xmit function for hostapd wlan#ap interfaces */ | ||
242 | int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
243 | { | ||
244 | struct hostap_interface *iface; | ||
245 | local_info_t *local; | ||
246 | struct hostap_skb_tx_data *meta; | ||
247 | struct ieee80211_hdr *hdr; | ||
248 | u16 fc; | ||
249 | |||
250 | iface = netdev_priv(dev); | ||
251 | local = iface->local; | ||
252 | |||
253 | if (skb->len < 10) { | ||
254 | printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " | ||
255 | "(len=%d)\n", dev->name, skb->len); | ||
256 | kfree_skb(skb); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | iface->stats.tx_packets++; | ||
261 | iface->stats.tx_bytes += skb->len; | ||
262 | |||
263 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
264 | memset(meta, 0, sizeof(*meta)); | ||
265 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
266 | meta->iface = iface; | ||
267 | |||
268 | if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { | ||
269 | hdr = (struct ieee80211_hdr *) skb->data; | ||
270 | fc = le16_to_cpu(hdr->frame_ctl); | ||
271 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
272 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { | ||
273 | u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + | ||
274 | sizeof(rfc1042_header)]; | ||
275 | meta->ethertype = (pos[0] << 8) | pos[1]; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /* Send IEEE 802.11 encapsulated frame using the master radio device */ | ||
280 | skb->dev = local->dev; | ||
281 | dev_queue_xmit(skb); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | |||
286 | /* Called only from software IRQ */ | ||
287 | struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | ||
288 | struct ieee80211_crypt_data *crypt) | ||
289 | { | ||
290 | struct hostap_interface *iface; | ||
291 | local_info_t *local; | ||
292 | struct ieee80211_hdr *hdr; | ||
293 | u16 fc; | ||
294 | int hdr_len, res; | ||
295 | |||
296 | iface = netdev_priv(skb->dev); | ||
297 | local = iface->local; | ||
298 | |||
299 | if (skb->len < IEEE80211_DATA_HDR3_LEN) { | ||
300 | kfree_skb(skb); | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | if (local->tkip_countermeasures && | ||
305 | crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { | ||
306 | hdr = (struct ieee80211_hdr *) skb->data; | ||
307 | if (net_ratelimit()) { | ||
308 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
309 | "TX packet to " MACSTR "\n", | ||
310 | local->dev->name, MAC2STR(hdr->addr1)); | ||
311 | } | ||
312 | kfree_skb(skb); | ||
313 | return NULL; | ||
314 | } | ||
315 | |||
316 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
317 | if (skb == NULL) | ||
318 | return NULL; | ||
319 | |||
320 | if ((skb_headroom(skb) < crypt->ops->extra_prefix_len || | ||
321 | skb_tailroom(skb) < crypt->ops->extra_postfix_len) && | ||
322 | pskb_expand_head(skb, crypt->ops->extra_prefix_len, | ||
323 | crypt->ops->extra_postfix_len, GFP_ATOMIC)) { | ||
324 | kfree_skb(skb); | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
328 | hdr = (struct ieee80211_hdr *) skb->data; | ||
329 | fc = le16_to_cpu(hdr->frame_ctl); | ||
330 | hdr_len = hostap_80211_get_hdrlen(fc); | ||
331 | |||
332 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | ||
333 | * call both MSDU and MPDU encryption functions from here. */ | ||
334 | atomic_inc(&crypt->refcnt); | ||
335 | res = 0; | ||
336 | if (crypt->ops->encrypt_msdu) | ||
337 | res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); | ||
338 | if (res == 0 && crypt->ops->encrypt_mpdu) | ||
339 | res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); | ||
340 | atomic_dec(&crypt->refcnt); | ||
341 | if (res < 0) { | ||
342 | kfree_skb(skb); | ||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | return skb; | ||
347 | } | ||
348 | |||
349 | |||
350 | /* hard_start_xmit function for master radio interface wifi#. | ||
351 | * AP processing (TX rate control, power save buffering, etc.). | ||
352 | * Use hardware TX function to send the frame. */ | ||
353 | int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
354 | { | ||
355 | struct hostap_interface *iface; | ||
356 | local_info_t *local; | ||
357 | int ret = 1; | ||
358 | u16 fc; | ||
359 | struct hostap_tx_data tx; | ||
360 | ap_tx_ret tx_ret; | ||
361 | struct hostap_skb_tx_data *meta; | ||
362 | int no_encrypt = 0; | ||
363 | struct ieee80211_hdr *hdr; | ||
364 | |||
365 | iface = netdev_priv(dev); | ||
366 | local = iface->local; | ||
367 | |||
368 | tx.skb = skb; | ||
369 | tx.sta_ptr = NULL; | ||
370 | |||
371 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
372 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
373 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
374 | "expected 0x%08x)\n", | ||
375 | dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); | ||
376 | ret = 0; | ||
377 | iface->stats.tx_dropped++; | ||
378 | goto fail; | ||
379 | } | ||
380 | |||
381 | if (local->host_encrypt) { | ||
382 | /* Set crypt to default algorithm and key; will be replaced in | ||
383 | * AP code if STA has own alg/key */ | ||
384 | tx.crypt = local->crypt[local->tx_keyidx]; | ||
385 | tx.host_encrypt = 1; | ||
386 | } else { | ||
387 | tx.crypt = NULL; | ||
388 | tx.host_encrypt = 0; | ||
389 | } | ||
390 | |||
391 | if (skb->len < 24) { | ||
392 | printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " | ||
393 | "(len=%d)\n", dev->name, skb->len); | ||
394 | ret = 0; | ||
395 | iface->stats.tx_dropped++; | ||
396 | goto fail; | ||
397 | } | ||
398 | |||
399 | /* FIX (?): | ||
400 | * Wi-Fi 802.11b test plan suggests that AP should ignore power save | ||
401 | * bit in authentication and (re)association frames and assume tha | ||
402 | * STA remains awake for the response. */ | ||
403 | tx_ret = hostap_handle_sta_tx(local, &tx); | ||
404 | skb = tx.skb; | ||
405 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
406 | hdr = (struct ieee80211_hdr *) skb->data; | ||
407 | fc = le16_to_cpu(hdr->frame_ctl); | ||
408 | switch (tx_ret) { | ||
409 | case AP_TX_CONTINUE: | ||
410 | break; | ||
411 | case AP_TX_CONTINUE_NOT_AUTHORIZED: | ||
412 | if (local->ieee_802_1x && | ||
413 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
414 | meta->ethertype != ETH_P_PAE && | ||
415 | !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { | ||
416 | printk(KERN_DEBUG "%s: dropped frame to unauthorized " | ||
417 | "port (IEEE 802.1X): ethertype=0x%04x\n", | ||
418 | dev->name, meta->ethertype); | ||
419 | hostap_dump_tx_80211(dev->name, skb); | ||
420 | |||
421 | ret = 0; /* drop packet */ | ||
422 | iface->stats.tx_dropped++; | ||
423 | goto fail; | ||
424 | } | ||
425 | break; | ||
426 | case AP_TX_DROP: | ||
427 | ret = 0; /* drop packet */ | ||
428 | iface->stats.tx_dropped++; | ||
429 | goto fail; | ||
430 | case AP_TX_RETRY: | ||
431 | goto fail; | ||
432 | case AP_TX_BUFFERED: | ||
433 | /* do not free skb here, it will be freed when the | ||
434 | * buffered frame is sent/timed out */ | ||
435 | ret = 0; | ||
436 | goto tx_exit; | ||
437 | } | ||
438 | |||
439 | /* Request TX callback if protocol version is 2 in 802.11 header; | ||
440 | * this version 2 is a special case used between hostapd and kernel | ||
441 | * driver */ | ||
442 | if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && | ||
443 | local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { | ||
444 | meta->tx_cb_idx = local->ap->tx_callback_idx; | ||
445 | |||
446 | /* remove special version from the frame header */ | ||
447 | fc &= ~IEEE80211_FCTL_VERS; | ||
448 | hdr->frame_ctl = cpu_to_le16(fc); | ||
449 | } | ||
450 | |||
451 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) { | ||
452 | no_encrypt = 1; | ||
453 | tx.crypt = NULL; | ||
454 | } | ||
455 | |||
456 | if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && | ||
457 | !(fc & IEEE80211_FCTL_VERS)) { | ||
458 | no_encrypt = 1; | ||
459 | PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " | ||
460 | "unencrypted EAPOL frame\n", dev->name); | ||
461 | tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ | ||
462 | } | ||
463 | |||
464 | if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) | ||
465 | tx.crypt = NULL; | ||
466 | else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { | ||
467 | /* Add ISWEP flag both for firmware and host based encryption | ||
468 | */ | ||
469 | fc |= IEEE80211_FCTL_PROTECTED; | ||
470 | hdr->frame_ctl = cpu_to_le16(fc); | ||
471 | } else if (local->drop_unencrypted && | ||
472 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
473 | meta->ethertype != ETH_P_PAE) { | ||
474 | if (net_ratelimit()) { | ||
475 | printk(KERN_DEBUG "%s: dropped unencrypted TX data " | ||
476 | "frame (drop_unencrypted=1)\n", dev->name); | ||
477 | } | ||
478 | iface->stats.tx_dropped++; | ||
479 | ret = 0; | ||
480 | goto fail; | ||
481 | } | ||
482 | |||
483 | if (tx.crypt) { | ||
484 | skb = hostap_tx_encrypt(skb, tx.crypt); | ||
485 | if (skb == NULL) { | ||
486 | printk(KERN_DEBUG "%s: TX - encryption failed\n", | ||
487 | dev->name); | ||
488 | ret = 0; | ||
489 | goto fail; | ||
490 | } | ||
491 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
492 | if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | ||
493 | printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | ||
494 | "expected 0x%08x) after hostap_tx_encrypt\n", | ||
495 | dev->name, meta->magic, | ||
496 | HOSTAP_SKB_TX_DATA_MAGIC); | ||
497 | ret = 0; | ||
498 | iface->stats.tx_dropped++; | ||
499 | goto fail; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | if (local->func->tx == NULL || local->func->tx(skb, dev)) { | ||
504 | ret = 0; | ||
505 | iface->stats.tx_dropped++; | ||
506 | } else { | ||
507 | ret = 0; | ||
508 | iface->stats.tx_packets++; | ||
509 | iface->stats.tx_bytes += skb->len; | ||
510 | } | ||
511 | |||
512 | fail: | ||
513 | if (!ret && skb) | ||
514 | dev_kfree_skb(skb); | ||
515 | tx_exit: | ||
516 | if (tx.sta_ptr) | ||
517 | hostap_handle_sta_release(tx.sta_ptr); | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | |||
522 | EXPORT_SYMBOL(hostap_dump_tx_80211); | ||
523 | EXPORT_SYMBOL(hostap_tx_encrypt); | ||
524 | EXPORT_SYMBOL(hostap_master_start_xmit); | ||
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c new file mode 100644 index 000000000000..930cef8367f2 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -0,0 +1,3288 @@ | |||
1 | /* | ||
2 | * Intersil Prism2 driver with Host AP (software access point) support | ||
3 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
4 | * <jkmaline@cc.hut.fi> | ||
5 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
6 | * | ||
7 | * This file is to be included into hostap.c when S/W AP functionality is | ||
8 | * compiled. | ||
9 | * | ||
10 | * AP: FIX: | ||
11 | * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from | ||
12 | * unauthenticated STA, send deauth. frame (8802.11: 5.5) | ||
13 | * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received | ||
14 | * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) | ||
15 | * - if unicast Class 3 received from unauthenticated STA, send deauth. frame | ||
16 | * (8802.11: 5.5) | ||
17 | */ | ||
18 | |||
19 | static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, | ||
20 | DEF_INTS }; | ||
21 | module_param_array(other_ap_policy, int, NULL, 0444); | ||
22 | MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); | ||
23 | |||
24 | static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, | ||
25 | DEF_INTS }; | ||
26 | module_param_array(ap_max_inactivity, int, NULL, 0444); | ||
27 | MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " | ||
28 | "inactivity"); | ||
29 | |||
30 | static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | ||
31 | module_param_array(ap_bridge_packets, int, NULL, 0444); | ||
32 | MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " | ||
33 | "stations"); | ||
34 | |||
35 | static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; | ||
36 | module_param_array(autom_ap_wds, int, NULL, 0444); | ||
37 | MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " | ||
38 | "automatically"); | ||
39 | |||
40 | |||
41 | static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); | ||
42 | static void hostap_event_expired_sta(struct net_device *dev, | ||
43 | struct sta_info *sta); | ||
44 | static void handle_add_proc_queue(void *data); | ||
45 | |||
46 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
47 | static void handle_wds_oper_queue(void *data); | ||
48 | static void prism2_send_mgmt(struct net_device *dev, | ||
49 | u16 type_subtype, char *body, | ||
50 | int body_len, u8 *addr, u16 tx_cb_idx); | ||
51 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
52 | |||
53 | |||
54 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
55 | static int ap_debug_proc_read(char *page, char **start, off_t off, | ||
56 | int count, int *eof, void *data) | ||
57 | { | ||
58 | char *p = page; | ||
59 | struct ap_data *ap = (struct ap_data *) data; | ||
60 | |||
61 | if (off != 0) { | ||
62 | *eof = 1; | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); | ||
67 | p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); | ||
68 | p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ); | ||
69 | p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets); | ||
70 | p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack); | ||
71 | p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds); | ||
72 | p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs); | ||
73 | p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); | ||
74 | |||
75 | return (p - page); | ||
76 | } | ||
77 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
78 | |||
79 | |||
80 | static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) | ||
81 | { | ||
82 | sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; | ||
83 | ap->sta_hash[STA_HASH(sta->addr)] = sta; | ||
84 | } | ||
85 | |||
86 | static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) | ||
87 | { | ||
88 | struct sta_info *s; | ||
89 | |||
90 | s = ap->sta_hash[STA_HASH(sta->addr)]; | ||
91 | if (s == NULL) return; | ||
92 | if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { | ||
93 | ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) | ||
98 | != 0) | ||
99 | s = s->hnext; | ||
100 | if (s->hnext != NULL) | ||
101 | s->hnext = s->hnext->hnext; | ||
102 | else | ||
103 | printk("AP: could not remove STA " MACSTR " from hash table\n", | ||
104 | MAC2STR(sta->addr)); | ||
105 | } | ||
106 | |||
107 | static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) | ||
108 | { | ||
109 | if (sta->ap && sta->local) | ||
110 | hostap_event_expired_sta(sta->local->dev, sta); | ||
111 | |||
112 | if (ap->proc != NULL) { | ||
113 | char name[20]; | ||
114 | sprintf(name, MACSTR, MAC2STR(sta->addr)); | ||
115 | remove_proc_entry(name, ap->proc); | ||
116 | } | ||
117 | |||
118 | if (sta->crypt) { | ||
119 | sta->crypt->ops->deinit(sta->crypt->priv); | ||
120 | kfree(sta->crypt); | ||
121 | sta->crypt = NULL; | ||
122 | } | ||
123 | |||
124 | skb_queue_purge(&sta->tx_buf); | ||
125 | |||
126 | ap->num_sta--; | ||
127 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
128 | if (sta->aid > 0) | ||
129 | ap->sta_aid[sta->aid - 1] = NULL; | ||
130 | |||
131 | if (!sta->ap && sta->u.sta.challenge) | ||
132 | kfree(sta->u.sta.challenge); | ||
133 | del_timer(&sta->timer); | ||
134 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
135 | |||
136 | kfree(sta); | ||
137 | } | ||
138 | |||
139 | |||
140 | static void hostap_set_tim(local_info_t *local, int aid, int set) | ||
141 | { | ||
142 | if (local->func->set_tim) | ||
143 | local->func->set_tim(local->dev, aid, set); | ||
144 | } | ||
145 | |||
146 | |||
147 | static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) | ||
148 | { | ||
149 | union iwreq_data wrqu; | ||
150 | memset(&wrqu, 0, sizeof(wrqu)); | ||
151 | memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | ||
152 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
153 | wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void hostap_event_expired_sta(struct net_device *dev, | ||
158 | struct sta_info *sta) | ||
159 | { | ||
160 | union iwreq_data wrqu; | ||
161 | memset(&wrqu, 0, sizeof(wrqu)); | ||
162 | memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | ||
163 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
164 | wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); | ||
165 | } | ||
166 | |||
167 | |||
168 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
169 | |||
170 | static void ap_handle_timer(unsigned long data) | ||
171 | { | ||
172 | struct sta_info *sta = (struct sta_info *) data; | ||
173 | local_info_t *local; | ||
174 | struct ap_data *ap; | ||
175 | unsigned long next_time = 0; | ||
176 | int was_assoc; | ||
177 | |||
178 | if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { | ||
179 | PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | local = sta->local; | ||
184 | ap = local->ap; | ||
185 | was_assoc = sta->flags & WLAN_STA_ASSOC; | ||
186 | |||
187 | if (atomic_read(&sta->users) != 0) | ||
188 | next_time = jiffies + HZ; | ||
189 | else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) | ||
190 | next_time = jiffies + ap->max_inactivity; | ||
191 | |||
192 | if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { | ||
193 | /* station activity detected; reset timeout state */ | ||
194 | sta->timeout_next = STA_NULLFUNC; | ||
195 | next_time = sta->last_rx + ap->max_inactivity; | ||
196 | } else if (sta->timeout_next == STA_DISASSOC && | ||
197 | !(sta->flags & WLAN_STA_PENDING_POLL)) { | ||
198 | /* STA ACKed data nullfunc frame poll */ | ||
199 | sta->timeout_next = STA_NULLFUNC; | ||
200 | next_time = jiffies + ap->max_inactivity; | ||
201 | } | ||
202 | |||
203 | if (next_time) { | ||
204 | sta->timer.expires = next_time; | ||
205 | add_timer(&sta->timer); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | if (sta->ap) | ||
210 | sta->timeout_next = STA_DEAUTH; | ||
211 | |||
212 | if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { | ||
213 | spin_lock(&ap->sta_table_lock); | ||
214 | ap_sta_hash_del(ap, sta); | ||
215 | list_del(&sta->list); | ||
216 | spin_unlock(&ap->sta_table_lock); | ||
217 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | ||
218 | } else if (sta->timeout_next == STA_DISASSOC) | ||
219 | sta->flags &= ~WLAN_STA_ASSOC; | ||
220 | |||
221 | if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
222 | hostap_event_expired_sta(local->dev, sta); | ||
223 | |||
224 | if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && | ||
225 | !skb_queue_empty(&sta->tx_buf)) { | ||
226 | hostap_set_tim(local, sta->aid, 0); | ||
227 | sta->flags &= ~WLAN_STA_TIM; | ||
228 | } | ||
229 | |||
230 | if (sta->ap) { | ||
231 | if (ap->autom_ap_wds) { | ||
232 | PDEBUG(DEBUG_AP, "%s: removing automatic WDS " | ||
233 | "connection to AP " MACSTR "\n", | ||
234 | local->dev->name, MAC2STR(sta->addr)); | ||
235 | hostap_wds_link_oper(local, sta->addr, WDS_DEL); | ||
236 | } | ||
237 | } else if (sta->timeout_next == STA_NULLFUNC) { | ||
238 | /* send data frame to poll STA and check whether this frame | ||
239 | * is ACKed */ | ||
240 | /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but | ||
241 | * it is apparently not retried so TX Exc events are not | ||
242 | * received for it */ | ||
243 | sta->flags |= WLAN_STA_PENDING_POLL; | ||
244 | prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | | ||
245 | IEEE80211_STYPE_DATA, NULL, 0, | ||
246 | sta->addr, ap->tx_callback_poll); | ||
247 | } else { | ||
248 | int deauth = sta->timeout_next == STA_DEAUTH; | ||
249 | u16 resp; | ||
250 | PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR | ||
251 | "(last=%lu, jiffies=%lu)\n", | ||
252 | local->dev->name, | ||
253 | deauth ? "deauthentication" : "disassociation", | ||
254 | MAC2STR(sta->addr), sta->last_rx, jiffies); | ||
255 | |||
256 | resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : | ||
257 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | ||
258 | prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | | ||
259 | (deauth ? IEEE80211_STYPE_DEAUTH : | ||
260 | IEEE80211_STYPE_DISASSOC), | ||
261 | (char *) &resp, 2, sta->addr, 0); | ||
262 | } | ||
263 | |||
264 | if (sta->timeout_next == STA_DEAUTH) { | ||
265 | if (sta->flags & WLAN_STA_PERM) { | ||
266 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been " | ||
267 | "removed, but it has 'perm' flag\n", | ||
268 | local->dev->name, MAC2STR(sta->addr)); | ||
269 | } else | ||
270 | ap_free_sta(ap, sta); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | if (sta->timeout_next == STA_NULLFUNC) { | ||
275 | sta->timeout_next = STA_DISASSOC; | ||
276 | sta->timer.expires = jiffies + AP_DISASSOC_DELAY; | ||
277 | } else { | ||
278 | sta->timeout_next = STA_DEAUTH; | ||
279 | sta->timer.expires = jiffies + AP_DEAUTH_DELAY; | ||
280 | } | ||
281 | |||
282 | add_timer(&sta->timer); | ||
283 | } | ||
284 | |||
285 | |||
286 | void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | ||
287 | int resend) | ||
288 | { | ||
289 | u8 addr[ETH_ALEN]; | ||
290 | u16 resp; | ||
291 | int i; | ||
292 | |||
293 | PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); | ||
294 | memset(addr, 0xff, ETH_ALEN); | ||
295 | |||
296 | resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
297 | |||
298 | /* deauth message sent; try to resend it few times; the message is | ||
299 | * broadcast, so it may be delayed until next DTIM; there is not much | ||
300 | * else we can do at this point since the driver is going to be shut | ||
301 | * down */ | ||
302 | for (i = 0; i < 5; i++) { | ||
303 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
304 | IEEE80211_STYPE_DEAUTH, | ||
305 | (char *) &resp, 2, addr, 0); | ||
306 | |||
307 | if (!resend || ap->num_sta <= 0) | ||
308 | return; | ||
309 | |||
310 | mdelay(50); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | |||
315 | static int ap_control_proc_read(char *page, char **start, off_t off, | ||
316 | int count, int *eof, void *data) | ||
317 | { | ||
318 | char *p = page; | ||
319 | struct ap_data *ap = (struct ap_data *) data; | ||
320 | char *policy_txt; | ||
321 | struct list_head *ptr; | ||
322 | struct mac_entry *entry; | ||
323 | |||
324 | if (off != 0) { | ||
325 | *eof = 1; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | switch (ap->mac_restrictions.policy) { | ||
330 | case MAC_POLICY_OPEN: | ||
331 | policy_txt = "open"; | ||
332 | break; | ||
333 | case MAC_POLICY_ALLOW: | ||
334 | policy_txt = "allow"; | ||
335 | break; | ||
336 | case MAC_POLICY_DENY: | ||
337 | policy_txt = "deny"; | ||
338 | break; | ||
339 | default: | ||
340 | policy_txt = "unknown"; | ||
341 | break; | ||
342 | }; | ||
343 | p += sprintf(p, "MAC policy: %s\n", policy_txt); | ||
344 | p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries); | ||
345 | p += sprintf(p, "MAC list:\n"); | ||
346 | spin_lock_bh(&ap->mac_restrictions.lock); | ||
347 | for (ptr = ap->mac_restrictions.mac_list.next; | ||
348 | ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) { | ||
349 | if (p - page > PAGE_SIZE - 80) { | ||
350 | p += sprintf(p, "All entries did not fit one page.\n"); | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | entry = list_entry(ptr, struct mac_entry, list); | ||
355 | p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); | ||
356 | } | ||
357 | spin_unlock_bh(&ap->mac_restrictions.lock); | ||
358 | |||
359 | return (p - page); | ||
360 | } | ||
361 | |||
362 | |||
363 | static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, | ||
364 | u8 *mac) | ||
365 | { | ||
366 | struct mac_entry *entry; | ||
367 | |||
368 | entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); | ||
369 | if (entry == NULL) | ||
370 | return -1; | ||
371 | |||
372 | memcpy(entry->addr, mac, ETH_ALEN); | ||
373 | |||
374 | spin_lock_bh(&mac_restrictions->lock); | ||
375 | list_add_tail(&entry->list, &mac_restrictions->mac_list); | ||
376 | mac_restrictions->entries++; | ||
377 | spin_unlock_bh(&mac_restrictions->lock); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | |||
383 | static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, | ||
384 | u8 *mac) | ||
385 | { | ||
386 | struct list_head *ptr; | ||
387 | struct mac_entry *entry; | ||
388 | |||
389 | spin_lock_bh(&mac_restrictions->lock); | ||
390 | for (ptr = mac_restrictions->mac_list.next; | ||
391 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
392 | entry = list_entry(ptr, struct mac_entry, list); | ||
393 | |||
394 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
395 | list_del(ptr); | ||
396 | kfree(entry); | ||
397 | mac_restrictions->entries--; | ||
398 | spin_unlock_bh(&mac_restrictions->lock); | ||
399 | return 0; | ||
400 | } | ||
401 | } | ||
402 | spin_unlock_bh(&mac_restrictions->lock); | ||
403 | return -1; | ||
404 | } | ||
405 | |||
406 | |||
407 | static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, | ||
408 | u8 *mac) | ||
409 | { | ||
410 | struct list_head *ptr; | ||
411 | struct mac_entry *entry; | ||
412 | int found = 0; | ||
413 | |||
414 | if (mac_restrictions->policy == MAC_POLICY_OPEN) | ||
415 | return 0; | ||
416 | |||
417 | spin_lock_bh(&mac_restrictions->lock); | ||
418 | for (ptr = mac_restrictions->mac_list.next; | ||
419 | ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | ||
420 | entry = list_entry(ptr, struct mac_entry, list); | ||
421 | |||
422 | if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { | ||
423 | found = 1; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | spin_unlock_bh(&mac_restrictions->lock); | ||
428 | |||
429 | if (mac_restrictions->policy == MAC_POLICY_ALLOW) | ||
430 | return !found; | ||
431 | else | ||
432 | return found; | ||
433 | } | ||
434 | |||
435 | |||
436 | static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) | ||
437 | { | ||
438 | struct list_head *ptr, *n; | ||
439 | struct mac_entry *entry; | ||
440 | |||
441 | if (mac_restrictions->entries == 0) | ||
442 | return; | ||
443 | |||
444 | spin_lock_bh(&mac_restrictions->lock); | ||
445 | for (ptr = mac_restrictions->mac_list.next, n = ptr->next; | ||
446 | ptr != &mac_restrictions->mac_list; | ||
447 | ptr = n, n = ptr->next) { | ||
448 | entry = list_entry(ptr, struct mac_entry, list); | ||
449 | list_del(ptr); | ||
450 | kfree(entry); | ||
451 | } | ||
452 | mac_restrictions->entries = 0; | ||
453 | spin_unlock_bh(&mac_restrictions->lock); | ||
454 | } | ||
455 | |||
456 | |||
457 | static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, | ||
458 | u8 *mac) | ||
459 | { | ||
460 | struct sta_info *sta; | ||
461 | u16 resp; | ||
462 | |||
463 | spin_lock_bh(&ap->sta_table_lock); | ||
464 | sta = ap_get_sta(ap, mac); | ||
465 | if (sta) { | ||
466 | ap_sta_hash_del(ap, sta); | ||
467 | list_del(&sta->list); | ||
468 | } | ||
469 | spin_unlock_bh(&ap->sta_table_lock); | ||
470 | |||
471 | if (!sta) | ||
472 | return -EINVAL; | ||
473 | |||
474 | resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
475 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, | ||
476 | (char *) &resp, 2, sta->addr, 0); | ||
477 | |||
478 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
479 | hostap_event_expired_sta(dev, sta); | ||
480 | |||
481 | ap_free_sta(ap, sta); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
487 | |||
488 | |||
489 | static void ap_control_kickall(struct ap_data *ap) | ||
490 | { | ||
491 | struct list_head *ptr, *n; | ||
492 | struct sta_info *sta; | ||
493 | |||
494 | spin_lock_bh(&ap->sta_table_lock); | ||
495 | for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; | ||
496 | ptr = n, n = ptr->next) { | ||
497 | sta = list_entry(ptr, struct sta_info, list); | ||
498 | ap_sta_hash_del(ap, sta); | ||
499 | list_del(&sta->list); | ||
500 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
501 | hostap_event_expired_sta(sta->local->dev, sta); | ||
502 | ap_free_sta(ap, sta); | ||
503 | } | ||
504 | spin_unlock_bh(&ap->sta_table_lock); | ||
505 | } | ||
506 | |||
507 | |||
508 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
509 | |||
510 | #define PROC_LIMIT (PAGE_SIZE - 80) | ||
511 | |||
512 | static int prism2_ap_proc_read(char *page, char **start, off_t off, | ||
513 | int count, int *eof, void *data) | ||
514 | { | ||
515 | char *p = page; | ||
516 | struct ap_data *ap = (struct ap_data *) data; | ||
517 | struct list_head *ptr; | ||
518 | int i; | ||
519 | |||
520 | if (off > PROC_LIMIT) { | ||
521 | *eof = 1; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); | ||
526 | spin_lock_bh(&ap->sta_table_lock); | ||
527 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
528 | struct sta_info *sta = (struct sta_info *) ptr; | ||
529 | |||
530 | if (!sta->ap) | ||
531 | continue; | ||
532 | |||
533 | p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), | ||
534 | sta->u.ap.channel, sta->last_rx_signal, | ||
535 | sta->last_rx_silence, sta->last_rx_rate); | ||
536 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
537 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
538 | sta->u.ap.ssid[i] < 127) ? | ||
539 | "%c" : "<%02x>"), | ||
540 | sta->u.ap.ssid[i]); | ||
541 | p += sprintf(p, "'"); | ||
542 | if (sta->capability & WLAN_CAPABILITY_ESS) | ||
543 | p += sprintf(p, " [ESS]"); | ||
544 | if (sta->capability & WLAN_CAPABILITY_IBSS) | ||
545 | p += sprintf(p, " [IBSS]"); | ||
546 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
547 | p += sprintf(p, " [WEP]"); | ||
548 | p += sprintf(p, "\n"); | ||
549 | |||
550 | if ((p - page) > PROC_LIMIT) { | ||
551 | printk(KERN_DEBUG "hostap: ap proc did not fit\n"); | ||
552 | break; | ||
553 | } | ||
554 | } | ||
555 | spin_unlock_bh(&ap->sta_table_lock); | ||
556 | |||
557 | if ((p - page) <= off) { | ||
558 | *eof = 1; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | *start = page + off; | ||
563 | |||
564 | return (p - page - off); | ||
565 | } | ||
566 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
567 | |||
568 | |||
569 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) | ||
570 | { | ||
571 | if (!ap) | ||
572 | return; | ||
573 | |||
574 | if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { | ||
575 | PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " | ||
576 | "firmware upgrade recommended\n"); | ||
577 | ap->nullfunc_ack = 1; | ||
578 | } else | ||
579 | ap->nullfunc_ack = 0; | ||
580 | |||
581 | if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { | ||
582 | printk(KERN_WARNING "%s: Warning: secondary station firmware " | ||
583 | "version 1.4.2 does not seem to work in Host AP mode\n", | ||
584 | ap->local->dev->name); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | |||
589 | /* Called only as a tasklet (software IRQ) */ | ||
590 | static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) | ||
591 | { | ||
592 | struct ap_data *ap = data; | ||
593 | u16 fc; | ||
594 | struct ieee80211_hdr *hdr; | ||
595 | |||
596 | if (!ap->local->hostapd || !ap->local->apdev) { | ||
597 | dev_kfree_skb(skb); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | hdr = (struct ieee80211_hdr *) skb->data; | ||
602 | fc = le16_to_cpu(hdr->frame_ctl); | ||
603 | |||
604 | /* Pass the TX callback frame to the hostapd; use 802.11 header version | ||
605 | * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ | ||
606 | |||
607 | fc &= ~IEEE80211_FCTL_VERS; | ||
608 | fc |= ok ? BIT(1) : BIT(0); | ||
609 | hdr->frame_ctl = cpu_to_le16(fc); | ||
610 | |||
611 | skb->dev = ap->local->apdev; | ||
612 | skb_pull(skb, hostap_80211_get_hdrlen(fc)); | ||
613 | skb->pkt_type = PACKET_OTHERHOST; | ||
614 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
615 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
616 | netif_rx(skb); | ||
617 | } | ||
618 | |||
619 | |||
620 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
621 | /* Called only as a tasklet (software IRQ) */ | ||
622 | static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | ||
623 | { | ||
624 | struct ap_data *ap = data; | ||
625 | struct net_device *dev = ap->local->dev; | ||
626 | struct ieee80211_hdr *hdr; | ||
627 | u16 fc, *pos, auth_alg, auth_transaction, status; | ||
628 | struct sta_info *sta = NULL; | ||
629 | char *txt = NULL; | ||
630 | |||
631 | if (ap->local->hostapd) { | ||
632 | dev_kfree_skb(skb); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | hdr = (struct ieee80211_hdr *) skb->data; | ||
637 | fc = le16_to_cpu(hdr->frame_ctl); | ||
638 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | ||
639 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || | ||
640 | skb->len < IEEE80211_MGMT_HDR_LEN + 6) { | ||
641 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " | ||
642 | "frame\n", dev->name); | ||
643 | dev_kfree_skb(skb); | ||
644 | return; | ||
645 | } | ||
646 | |||
647 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
648 | auth_alg = le16_to_cpu(*pos++); | ||
649 | auth_transaction = le16_to_cpu(*pos++); | ||
650 | status = le16_to_cpu(*pos++); | ||
651 | |||
652 | if (!ok) { | ||
653 | txt = "frame was not ACKed"; | ||
654 | goto done; | ||
655 | } | ||
656 | |||
657 | spin_lock(&ap->sta_table_lock); | ||
658 | sta = ap_get_sta(ap, hdr->addr1); | ||
659 | if (sta) | ||
660 | atomic_inc(&sta->users); | ||
661 | spin_unlock(&ap->sta_table_lock); | ||
662 | |||
663 | if (!sta) { | ||
664 | txt = "STA not found"; | ||
665 | goto done; | ||
666 | } | ||
667 | |||
668 | if (status == WLAN_STATUS_SUCCESS && | ||
669 | ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || | ||
670 | (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { | ||
671 | txt = "STA authenticated"; | ||
672 | sta->flags |= WLAN_STA_AUTH; | ||
673 | sta->last_auth = jiffies; | ||
674 | } else if (status != WLAN_STATUS_SUCCESS) | ||
675 | txt = "authentication failed"; | ||
676 | |||
677 | done: | ||
678 | if (sta) | ||
679 | atomic_dec(&sta->users); | ||
680 | if (txt) { | ||
681 | PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " | ||
682 | "status=%d - %s\n", | ||
683 | dev->name, MAC2STR(hdr->addr1), auth_alg, | ||
684 | auth_transaction, status, txt); | ||
685 | } | ||
686 | dev_kfree_skb(skb); | ||
687 | } | ||
688 | |||
689 | |||
690 | /* Called only as a tasklet (software IRQ) */ | ||
691 | static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | ||
692 | { | ||
693 | struct ap_data *ap = data; | ||
694 | struct net_device *dev = ap->local->dev; | ||
695 | struct ieee80211_hdr *hdr; | ||
696 | u16 fc, *pos, status; | ||
697 | struct sta_info *sta = NULL; | ||
698 | char *txt = NULL; | ||
699 | |||
700 | if (ap->local->hostapd) { | ||
701 | dev_kfree_skb(skb); | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | hdr = (struct ieee80211_hdr *) skb->data; | ||
706 | fc = le16_to_cpu(hdr->frame_ctl); | ||
707 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | ||
708 | (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && | ||
709 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) || | ||
710 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | ||
711 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " | ||
712 | "frame\n", dev->name); | ||
713 | dev_kfree_skb(skb); | ||
714 | return; | ||
715 | } | ||
716 | |||
717 | if (!ok) { | ||
718 | txt = "frame was not ACKed"; | ||
719 | goto done; | ||
720 | } | ||
721 | |||
722 | spin_lock(&ap->sta_table_lock); | ||
723 | sta = ap_get_sta(ap, hdr->addr1); | ||
724 | if (sta) | ||
725 | atomic_inc(&sta->users); | ||
726 | spin_unlock(&ap->sta_table_lock); | ||
727 | |||
728 | if (!sta) { | ||
729 | txt = "STA not found"; | ||
730 | goto done; | ||
731 | } | ||
732 | |||
733 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
734 | pos++; | ||
735 | status = le16_to_cpu(*pos++); | ||
736 | if (status == WLAN_STATUS_SUCCESS) { | ||
737 | if (!(sta->flags & WLAN_STA_ASSOC)) | ||
738 | hostap_event_new_sta(dev, sta); | ||
739 | txt = "STA associated"; | ||
740 | sta->flags |= WLAN_STA_ASSOC; | ||
741 | sta->last_assoc = jiffies; | ||
742 | } else | ||
743 | txt = "association failed"; | ||
744 | |||
745 | done: | ||
746 | if (sta) | ||
747 | atomic_dec(&sta->users); | ||
748 | if (txt) { | ||
749 | PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", | ||
750 | dev->name, MAC2STR(hdr->addr1), txt); | ||
751 | } | ||
752 | dev_kfree_skb(skb); | ||
753 | } | ||
754 | |||
755 | /* Called only as a tasklet (software IRQ); TX callback for poll frames used | ||
756 | * in verifying whether the STA is still present. */ | ||
757 | static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) | ||
758 | { | ||
759 | struct ap_data *ap = data; | ||
760 | struct ieee80211_hdr *hdr; | ||
761 | struct sta_info *sta; | ||
762 | |||
763 | if (skb->len < 24) | ||
764 | goto fail; | ||
765 | hdr = (struct ieee80211_hdr *) skb->data; | ||
766 | if (ok) { | ||
767 | spin_lock(&ap->sta_table_lock); | ||
768 | sta = ap_get_sta(ap, hdr->addr1); | ||
769 | if (sta) | ||
770 | sta->flags &= ~WLAN_STA_PENDING_POLL; | ||
771 | spin_unlock(&ap->sta_table_lock); | ||
772 | } else { | ||
773 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " | ||
774 | "poll frame\n", ap->local->dev->name, | ||
775 | MAC2STR(hdr->addr1)); | ||
776 | } | ||
777 | |||
778 | fail: | ||
779 | dev_kfree_skb(skb); | ||
780 | } | ||
781 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
782 | |||
783 | |||
784 | void hostap_init_data(local_info_t *local) | ||
785 | { | ||
786 | struct ap_data *ap = local->ap; | ||
787 | |||
788 | if (ap == NULL) { | ||
789 | printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); | ||
790 | return; | ||
791 | } | ||
792 | memset(ap, 0, sizeof(struct ap_data)); | ||
793 | ap->local = local; | ||
794 | |||
795 | ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); | ||
796 | ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); | ||
797 | ap->max_inactivity = | ||
798 | GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; | ||
799 | ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); | ||
800 | |||
801 | spin_lock_init(&ap->sta_table_lock); | ||
802 | INIT_LIST_HEAD(&ap->sta_list); | ||
803 | |||
804 | /* Initialize task queue structure for AP management */ | ||
805 | INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); | ||
806 | |||
807 | ap->tx_callback_idx = | ||
808 | hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); | ||
809 | if (ap->tx_callback_idx == 0) | ||
810 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
811 | "AP\n", local->dev->name); | ||
812 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
813 | INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); | ||
814 | |||
815 | ap->tx_callback_auth = | ||
816 | hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); | ||
817 | ap->tx_callback_assoc = | ||
818 | hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); | ||
819 | ap->tx_callback_poll = | ||
820 | hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); | ||
821 | if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || | ||
822 | ap->tx_callback_poll == 0) | ||
823 | printk(KERN_WARNING "%s: failed to register TX callback for " | ||
824 | "AP\n", local->dev->name); | ||
825 | |||
826 | spin_lock_init(&ap->mac_restrictions.lock); | ||
827 | INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); | ||
828 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
829 | |||
830 | ap->initialized = 1; | ||
831 | } | ||
832 | |||
833 | |||
834 | void hostap_init_ap_proc(local_info_t *local) | ||
835 | { | ||
836 | struct ap_data *ap = local->ap; | ||
837 | |||
838 | ap->proc = local->proc; | ||
839 | if (ap->proc == NULL) | ||
840 | return; | ||
841 | |||
842 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
843 | create_proc_read_entry("ap_debug", 0, ap->proc, | ||
844 | ap_debug_proc_read, ap); | ||
845 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
846 | |||
847 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
848 | create_proc_read_entry("ap_control", 0, ap->proc, | ||
849 | ap_control_proc_read, ap); | ||
850 | create_proc_read_entry("ap", 0, ap->proc, | ||
851 | prism2_ap_proc_read, ap); | ||
852 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
853 | |||
854 | } | ||
855 | |||
856 | |||
857 | void hostap_free_data(struct ap_data *ap) | ||
858 | { | ||
859 | struct list_head *n, *ptr; | ||
860 | |||
861 | if (ap == NULL || !ap->initialized) { | ||
862 | printk(KERN_DEBUG "hostap_free_data: ap has not yet been " | ||
863 | "initialized - skip resource freeing\n"); | ||
864 | return; | ||
865 | } | ||
866 | |||
867 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
868 | if (ap->crypt) | ||
869 | ap->crypt->deinit(ap->crypt_priv); | ||
870 | ap->crypt = ap->crypt_priv = NULL; | ||
871 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
872 | |||
873 | list_for_each_safe(ptr, n, &ap->sta_list) { | ||
874 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
875 | ap_sta_hash_del(ap, sta); | ||
876 | list_del(&sta->list); | ||
877 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
878 | hostap_event_expired_sta(sta->local->dev, sta); | ||
879 | ap_free_sta(ap, sta); | ||
880 | } | ||
881 | |||
882 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
883 | if (ap->proc != NULL) { | ||
884 | remove_proc_entry("ap_debug", ap->proc); | ||
885 | } | ||
886 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
887 | |||
888 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
889 | if (ap->proc != NULL) { | ||
890 | remove_proc_entry("ap", ap->proc); | ||
891 | remove_proc_entry("ap_control", ap->proc); | ||
892 | } | ||
893 | ap_control_flush_macs(&ap->mac_restrictions); | ||
894 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
895 | |||
896 | ap->initialized = 0; | ||
897 | } | ||
898 | |||
899 | |||
900 | /* caller should have mutex for AP STA list handling */ | ||
901 | static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) | ||
902 | { | ||
903 | struct sta_info *s; | ||
904 | |||
905 | s = ap->sta_hash[STA_HASH(sta)]; | ||
906 | while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0) | ||
907 | s = s->hnext; | ||
908 | return s; | ||
909 | } | ||
910 | |||
911 | |||
912 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
913 | |||
914 | /* Called from timer handler and from scheduled AP queue handlers */ | ||
915 | static void prism2_send_mgmt(struct net_device *dev, | ||
916 | u16 type_subtype, char *body, | ||
917 | int body_len, u8 *addr, u16 tx_cb_idx) | ||
918 | { | ||
919 | struct hostap_interface *iface; | ||
920 | local_info_t *local; | ||
921 | struct ieee80211_hdr *hdr; | ||
922 | u16 fc; | ||
923 | struct sk_buff *skb; | ||
924 | struct hostap_skb_tx_data *meta; | ||
925 | int hdrlen; | ||
926 | |||
927 | iface = netdev_priv(dev); | ||
928 | local = iface->local; | ||
929 | dev = local->dev; /* always use master radio device */ | ||
930 | iface = netdev_priv(dev); | ||
931 | |||
932 | if (!(dev->flags & IFF_UP)) { | ||
933 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " | ||
934 | "cannot send frame\n", dev->name); | ||
935 | return; | ||
936 | } | ||
937 | |||
938 | skb = dev_alloc_skb(sizeof(*hdr) + body_len); | ||
939 | if (skb == NULL) { | ||
940 | PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " | ||
941 | "skb\n", dev->name); | ||
942 | return; | ||
943 | } | ||
944 | |||
945 | fc = type_subtype; | ||
946 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
947 | hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); | ||
948 | if (body) | ||
949 | memcpy(skb_put(skb, body_len), body, body_len); | ||
950 | |||
951 | memset(hdr, 0, hdrlen); | ||
952 | |||
953 | /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 | ||
954 | * tx_control instead of using local->tx_control */ | ||
955 | |||
956 | |||
957 | memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ | ||
958 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) { | ||
959 | fc |= IEEE80211_FCTL_FROMDS; | ||
960 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
961 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ | ||
962 | } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) { | ||
963 | /* control:ACK does not have addr2 or addr3 */ | ||
964 | memset(hdr->addr2, 0, ETH_ALEN); | ||
965 | memset(hdr->addr3, 0, ETH_ALEN); | ||
966 | } else { | ||
967 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ | ||
968 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ | ||
969 | } | ||
970 | |||
971 | hdr->frame_ctl = cpu_to_le16(fc); | ||
972 | |||
973 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
974 | memset(meta, 0, sizeof(*meta)); | ||
975 | meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | ||
976 | meta->iface = iface; | ||
977 | meta->tx_cb_idx = tx_cb_idx; | ||
978 | |||
979 | skb->dev = dev; | ||
980 | skb->mac.raw = skb->nh.raw = skb->data; | ||
981 | dev_queue_xmit(skb); | ||
982 | } | ||
983 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
984 | |||
985 | |||
986 | static int prism2_sta_proc_read(char *page, char **start, off_t off, | ||
987 | int count, int *eof, void *data) | ||
988 | { | ||
989 | char *p = page; | ||
990 | struct sta_info *sta = (struct sta_info *) data; | ||
991 | int i; | ||
992 | |||
993 | /* FIX: possible race condition.. the STA data could have just expired, | ||
994 | * but proc entry was still here so that the read could have started; | ||
995 | * some locking should be done here.. */ | ||
996 | |||
997 | if (off != 0) { | ||
998 | *eof = 1; | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" | ||
1003 | "flags=0x%04x%s%s%s%s%s%s%s\n" | ||
1004 | "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", | ||
1005 | sta->ap ? "AP" : "STA", | ||
1006 | MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, | ||
1007 | sta->flags, | ||
1008 | sta->flags & WLAN_STA_AUTH ? " AUTH" : "", | ||
1009 | sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", | ||
1010 | sta->flags & WLAN_STA_PS ? " PS" : "", | ||
1011 | sta->flags & WLAN_STA_TIM ? " TIM" : "", | ||
1012 | sta->flags & WLAN_STA_PERM ? " PERM" : "", | ||
1013 | sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", | ||
1014 | sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", | ||
1015 | sta->capability, sta->listen_interval); | ||
1016 | /* supported_rates: 500 kbit/s units with msb ignored */ | ||
1017 | for (i = 0; i < sizeof(sta->supported_rates); i++) | ||
1018 | if (sta->supported_rates[i] != 0) | ||
1019 | p += sprintf(p, "%d%sMbps ", | ||
1020 | (sta->supported_rates[i] & 0x7f) / 2, | ||
1021 | sta->supported_rates[i] & 1 ? ".5" : ""); | ||
1022 | p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" | ||
1023 | "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" | ||
1024 | "tx_packets=%lu\n" | ||
1025 | "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" | ||
1026 | "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" | ||
1027 | "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" | ||
1028 | "tx[11M]=%d\n" | ||
1029 | "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", | ||
1030 | jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, | ||
1031 | sta->last_tx, | ||
1032 | sta->rx_packets, sta->tx_packets, sta->rx_bytes, | ||
1033 | sta->tx_bytes, skb_queue_len(&sta->tx_buf), | ||
1034 | sta->last_rx_silence, | ||
1035 | sta->last_rx_signal, sta->last_rx_rate / 10, | ||
1036 | sta->last_rx_rate % 10 ? ".5" : "", | ||
1037 | sta->tx_rate, sta->tx_count[0], sta->tx_count[1], | ||
1038 | sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], | ||
1039 | sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); | ||
1040 | if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) | ||
1041 | p = sta->crypt->ops->print_stats(p, sta->crypt->priv); | ||
1042 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1043 | if (sta->ap) { | ||
1044 | if (sta->u.ap.channel >= 0) | ||
1045 | p += sprintf(p, "channel=%d\n", sta->u.ap.channel); | ||
1046 | p += sprintf(p, "ssid="); | ||
1047 | for (i = 0; i < sta->u.ap.ssid_len; i++) | ||
1048 | p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && | ||
1049 | sta->u.ap.ssid[i] < 127) ? | ||
1050 | "%c" : "<%02x>"), | ||
1051 | sta->u.ap.ssid[i]); | ||
1052 | p += sprintf(p, "\n"); | ||
1053 | } | ||
1054 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1055 | |||
1056 | return (p - page); | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | static void handle_add_proc_queue(void *data) | ||
1061 | { | ||
1062 | struct ap_data *ap = (struct ap_data *) data; | ||
1063 | struct sta_info *sta; | ||
1064 | char name[20]; | ||
1065 | struct add_sta_proc_data *entry, *prev; | ||
1066 | |||
1067 | entry = ap->add_sta_proc_entries; | ||
1068 | ap->add_sta_proc_entries = NULL; | ||
1069 | |||
1070 | while (entry) { | ||
1071 | spin_lock_bh(&ap->sta_table_lock); | ||
1072 | sta = ap_get_sta(ap, entry->addr); | ||
1073 | if (sta) | ||
1074 | atomic_inc(&sta->users); | ||
1075 | spin_unlock_bh(&ap->sta_table_lock); | ||
1076 | |||
1077 | if (sta) { | ||
1078 | sprintf(name, MACSTR, MAC2STR(sta->addr)); | ||
1079 | sta->proc = create_proc_read_entry( | ||
1080 | name, 0, ap->proc, | ||
1081 | prism2_sta_proc_read, sta); | ||
1082 | |||
1083 | atomic_dec(&sta->users); | ||
1084 | } | ||
1085 | |||
1086 | prev = entry; | ||
1087 | entry = entry->next; | ||
1088 | kfree(prev); | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) | ||
1094 | { | ||
1095 | struct sta_info *sta; | ||
1096 | |||
1097 | sta = (struct sta_info *) | ||
1098 | kmalloc(sizeof(struct sta_info), GFP_ATOMIC); | ||
1099 | if (sta == NULL) { | ||
1100 | PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); | ||
1101 | return NULL; | ||
1102 | } | ||
1103 | |||
1104 | /* initialize STA info data */ | ||
1105 | memset(sta, 0, sizeof(struct sta_info)); | ||
1106 | sta->local = ap->local; | ||
1107 | skb_queue_head_init(&sta->tx_buf); | ||
1108 | memcpy(sta->addr, addr, ETH_ALEN); | ||
1109 | |||
1110 | atomic_inc(&sta->users); | ||
1111 | spin_lock_bh(&ap->sta_table_lock); | ||
1112 | list_add(&sta->list, &ap->sta_list); | ||
1113 | ap->num_sta++; | ||
1114 | ap_sta_hash_add(ap, sta); | ||
1115 | spin_unlock_bh(&ap->sta_table_lock); | ||
1116 | |||
1117 | if (ap->proc) { | ||
1118 | struct add_sta_proc_data *entry; | ||
1119 | /* schedule a non-interrupt context process to add a procfs | ||
1120 | * entry for the STA since procfs code use GFP_KERNEL */ | ||
1121 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
1122 | if (entry) { | ||
1123 | memcpy(entry->addr, sta->addr, ETH_ALEN); | ||
1124 | entry->next = ap->add_sta_proc_entries; | ||
1125 | ap->add_sta_proc_entries = entry; | ||
1126 | schedule_work(&ap->add_sta_proc_queue); | ||
1127 | } else | ||
1128 | printk(KERN_DEBUG "Failed to add STA proc data\n"); | ||
1129 | } | ||
1130 | |||
1131 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1132 | init_timer(&sta->timer); | ||
1133 | sta->timer.expires = jiffies + ap->max_inactivity; | ||
1134 | sta->timer.data = (unsigned long) sta; | ||
1135 | sta->timer.function = ap_handle_timer; | ||
1136 | if (!ap->local->hostapd) | ||
1137 | add_timer(&sta->timer); | ||
1138 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1139 | |||
1140 | return sta; | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, | ||
1145 | local_info_t *local) | ||
1146 | { | ||
1147 | if (rateidx > sta->tx_max_rate || | ||
1148 | !(sta->tx_supp_rates & (1 << rateidx))) | ||
1149 | return 0; | ||
1150 | |||
1151 | if (local->tx_rate_control != 0 && | ||
1152 | !(local->tx_rate_control & (1 << rateidx))) | ||
1153 | return 0; | ||
1154 | |||
1155 | return 1; | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | static void prism2_check_tx_rates(struct sta_info *sta) | ||
1160 | { | ||
1161 | int i; | ||
1162 | |||
1163 | sta->tx_supp_rates = 0; | ||
1164 | for (i = 0; i < sizeof(sta->supported_rates); i++) { | ||
1165 | if ((sta->supported_rates[i] & 0x7f) == 2) | ||
1166 | sta->tx_supp_rates |= WLAN_RATE_1M; | ||
1167 | if ((sta->supported_rates[i] & 0x7f) == 4) | ||
1168 | sta->tx_supp_rates |= WLAN_RATE_2M; | ||
1169 | if ((sta->supported_rates[i] & 0x7f) == 11) | ||
1170 | sta->tx_supp_rates |= WLAN_RATE_5M5; | ||
1171 | if ((sta->supported_rates[i] & 0x7f) == 22) | ||
1172 | sta->tx_supp_rates |= WLAN_RATE_11M; | ||
1173 | } | ||
1174 | sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; | ||
1175 | if (sta->tx_supp_rates & WLAN_RATE_1M) { | ||
1176 | sta->tx_max_rate = 0; | ||
1177 | if (ap_tx_rate_ok(0, sta, sta->local)) { | ||
1178 | sta->tx_rate = 10; | ||
1179 | sta->tx_rate_idx = 0; | ||
1180 | } | ||
1181 | } | ||
1182 | if (sta->tx_supp_rates & WLAN_RATE_2M) { | ||
1183 | sta->tx_max_rate = 1; | ||
1184 | if (ap_tx_rate_ok(1, sta, sta->local)) { | ||
1185 | sta->tx_rate = 20; | ||
1186 | sta->tx_rate_idx = 1; | ||
1187 | } | ||
1188 | } | ||
1189 | if (sta->tx_supp_rates & WLAN_RATE_5M5) { | ||
1190 | sta->tx_max_rate = 2; | ||
1191 | if (ap_tx_rate_ok(2, sta, sta->local)) { | ||
1192 | sta->tx_rate = 55; | ||
1193 | sta->tx_rate_idx = 2; | ||
1194 | } | ||
1195 | } | ||
1196 | if (sta->tx_supp_rates & WLAN_RATE_11M) { | ||
1197 | sta->tx_max_rate = 3; | ||
1198 | if (ap_tx_rate_ok(3, sta, sta->local)) { | ||
1199 | sta->tx_rate = 110; | ||
1200 | sta->tx_rate_idx = 3; | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1207 | |||
1208 | static void ap_crypt_init(struct ap_data *ap) | ||
1209 | { | ||
1210 | ap->crypt = ieee80211_get_crypto_ops("WEP"); | ||
1211 | |||
1212 | if (ap->crypt) { | ||
1213 | if (ap->crypt->init) { | ||
1214 | ap->crypt_priv = ap->crypt->init(0); | ||
1215 | if (ap->crypt_priv == NULL) | ||
1216 | ap->crypt = NULL; | ||
1217 | else { | ||
1218 | u8 key[WEP_KEY_LEN]; | ||
1219 | get_random_bytes(key, WEP_KEY_LEN); | ||
1220 | ap->crypt->set_key(key, WEP_KEY_LEN, NULL, | ||
1221 | ap->crypt_priv); | ||
1222 | } | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | if (ap->crypt == NULL) { | ||
1227 | printk(KERN_WARNING "AP could not initialize WEP: load module " | ||
1228 | "ieee80211_crypt_wep.ko\n"); | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | /* Generate challenge data for shared key authentication. IEEE 802.11 specifies | ||
1234 | * that WEP algorithm is used for generating challange. This should be unique, | ||
1235 | * but otherwise there is not really need for randomness etc. Initialize WEP | ||
1236 | * with pseudo random key and then use increasing IV to get unique challenge | ||
1237 | * streams. | ||
1238 | * | ||
1239 | * Called only as a scheduled task for pending AP frames. | ||
1240 | */ | ||
1241 | static char * ap_auth_make_challenge(struct ap_data *ap) | ||
1242 | { | ||
1243 | char *tmpbuf; | ||
1244 | struct sk_buff *skb; | ||
1245 | |||
1246 | if (ap->crypt == NULL) { | ||
1247 | ap_crypt_init(ap); | ||
1248 | if (ap->crypt == NULL) | ||
1249 | return NULL; | ||
1250 | } | ||
1251 | |||
1252 | tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); | ||
1253 | if (tmpbuf == NULL) { | ||
1254 | PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); | ||
1255 | return NULL; | ||
1256 | } | ||
1257 | |||
1258 | skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + | ||
1259 | ap->crypt->extra_prefix_len + | ||
1260 | ap->crypt->extra_postfix_len); | ||
1261 | if (skb == NULL) { | ||
1262 | kfree(tmpbuf); | ||
1263 | return NULL; | ||
1264 | } | ||
1265 | |||
1266 | skb_reserve(skb, ap->crypt->extra_prefix_len); | ||
1267 | memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, | ||
1268 | WLAN_AUTH_CHALLENGE_LEN); | ||
1269 | if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { | ||
1270 | dev_kfree_skb(skb); | ||
1271 | kfree(tmpbuf); | ||
1272 | return NULL; | ||
1273 | } | ||
1274 | |||
1275 | memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len, | ||
1276 | WLAN_AUTH_CHALLENGE_LEN); | ||
1277 | dev_kfree_skb(skb); | ||
1278 | |||
1279 | return tmpbuf; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | /* Called only as a scheduled task for pending AP frames. */ | ||
1284 | static void handle_authen(local_info_t *local, struct sk_buff *skb, | ||
1285 | struct hostap_80211_rx_status *rx_stats) | ||
1286 | { | ||
1287 | struct net_device *dev = local->dev; | ||
1288 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1289 | size_t hdrlen; | ||
1290 | struct ap_data *ap = local->ap; | ||
1291 | char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; | ||
1292 | int len, olen; | ||
1293 | u16 auth_alg, auth_transaction, status_code, *pos; | ||
1294 | u16 resp = WLAN_STATUS_SUCCESS, fc; | ||
1295 | struct sta_info *sta = NULL; | ||
1296 | struct ieee80211_crypt_data *crypt; | ||
1297 | char *txt = ""; | ||
1298 | |||
1299 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1300 | |||
1301 | fc = le16_to_cpu(hdr->frame_ctl); | ||
1302 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
1303 | |||
1304 | if (len < 6) { | ||
1305 | PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " | ||
1306 | "(len=%d) from " MACSTR "\n", dev->name, len, | ||
1307 | MAC2STR(hdr->addr2)); | ||
1308 | return; | ||
1309 | } | ||
1310 | |||
1311 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1312 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1313 | if (sta) | ||
1314 | atomic_inc(&sta->users); | ||
1315 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1316 | |||
1317 | if (sta && sta->crypt) | ||
1318 | crypt = sta->crypt; | ||
1319 | else { | ||
1320 | int idx = 0; | ||
1321 | if (skb->len >= hdrlen + 3) | ||
1322 | idx = skb->data[hdrlen + 3] >> 6; | ||
1323 | crypt = local->crypt[idx]; | ||
1324 | } | ||
1325 | |||
1326 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1327 | auth_alg = __le16_to_cpu(*pos); | ||
1328 | pos++; | ||
1329 | auth_transaction = __le16_to_cpu(*pos); | ||
1330 | pos++; | ||
1331 | status_code = __le16_to_cpu(*pos); | ||
1332 | pos++; | ||
1333 | |||
1334 | if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 || | ||
1335 | ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { | ||
1336 | txt = "authentication denied"; | ||
1337 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1338 | goto fail; | ||
1339 | } | ||
1340 | |||
1341 | if (((local->auth_algs & PRISM2_AUTH_OPEN) && | ||
1342 | auth_alg == WLAN_AUTH_OPEN) || | ||
1343 | ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && | ||
1344 | crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { | ||
1345 | } else { | ||
1346 | txt = "unsupported algorithm"; | ||
1347 | resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; | ||
1348 | goto fail; | ||
1349 | } | ||
1350 | |||
1351 | if (len >= 8) { | ||
1352 | u8 *u = (u8 *) pos; | ||
1353 | if (*u == WLAN_EID_CHALLENGE) { | ||
1354 | if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { | ||
1355 | txt = "invalid challenge len"; | ||
1356 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1357 | goto fail; | ||
1358 | } | ||
1359 | if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { | ||
1360 | txt = "challenge underflow"; | ||
1361 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1362 | goto fail; | ||
1363 | } | ||
1364 | challenge = (char *) (u + 2); | ||
1365 | } | ||
1366 | } | ||
1367 | |||
1368 | if (sta && sta->ap) { | ||
1369 | if (time_after(jiffies, sta->u.ap.last_beacon + | ||
1370 | (10 * sta->listen_interval * HZ) / 1024)) { | ||
1371 | PDEBUG(DEBUG_AP, "%s: no beacons received for a while," | ||
1372 | " assuming AP " MACSTR " is now STA\n", | ||
1373 | dev->name, MAC2STR(sta->addr)); | ||
1374 | sta->ap = 0; | ||
1375 | sta->flags = 0; | ||
1376 | sta->u.sta.challenge = NULL; | ||
1377 | } else { | ||
1378 | txt = "AP trying to authenticate?"; | ||
1379 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1380 | goto fail; | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || | ||
1385 | (auth_alg == WLAN_AUTH_SHARED_KEY && | ||
1386 | (auth_transaction == 1 || | ||
1387 | (auth_transaction == 3 && sta != NULL && | ||
1388 | sta->u.sta.challenge != NULL)))) { | ||
1389 | } else { | ||
1390 | txt = "unknown authentication transaction number"; | ||
1391 | resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; | ||
1392 | goto fail; | ||
1393 | } | ||
1394 | |||
1395 | if (sta == NULL) { | ||
1396 | txt = "new STA"; | ||
1397 | |||
1398 | if (local->ap->num_sta >= MAX_STA_COUNT) { | ||
1399 | /* FIX: might try to remove some old STAs first? */ | ||
1400 | txt = "no more room for new STAs"; | ||
1401 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1402 | goto fail; | ||
1403 | } | ||
1404 | |||
1405 | sta = ap_add_sta(local->ap, hdr->addr2); | ||
1406 | if (sta == NULL) { | ||
1407 | txt = "ap_add_sta failed"; | ||
1408 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1409 | goto fail; | ||
1410 | } | ||
1411 | } | ||
1412 | |||
1413 | switch (auth_alg) { | ||
1414 | case WLAN_AUTH_OPEN: | ||
1415 | txt = "authOK"; | ||
1416 | /* IEEE 802.11 standard is not completely clear about | ||
1417 | * whether STA is considered authenticated after | ||
1418 | * authentication OK frame has been send or after it | ||
1419 | * has been ACKed. In order to reduce interoperability | ||
1420 | * issues, mark the STA authenticated before ACK. */ | ||
1421 | sta->flags |= WLAN_STA_AUTH; | ||
1422 | break; | ||
1423 | |||
1424 | case WLAN_AUTH_SHARED_KEY: | ||
1425 | if (auth_transaction == 1) { | ||
1426 | if (sta->u.sta.challenge == NULL) { | ||
1427 | sta->u.sta.challenge = | ||
1428 | ap_auth_make_challenge(local->ap); | ||
1429 | if (sta->u.sta.challenge == NULL) { | ||
1430 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1431 | goto fail; | ||
1432 | } | ||
1433 | } | ||
1434 | } else { | ||
1435 | if (sta->u.sta.challenge == NULL || | ||
1436 | challenge == NULL || | ||
1437 | memcmp(sta->u.sta.challenge, challenge, | ||
1438 | WLAN_AUTH_CHALLENGE_LEN) != 0 || | ||
1439 | !(fc & IEEE80211_FCTL_PROTECTED)) { | ||
1440 | txt = "challenge response incorrect"; | ||
1441 | resp = WLAN_STATUS_CHALLENGE_FAIL; | ||
1442 | goto fail; | ||
1443 | } | ||
1444 | |||
1445 | txt = "challenge OK - authOK"; | ||
1446 | /* IEEE 802.11 standard is not completely clear about | ||
1447 | * whether STA is considered authenticated after | ||
1448 | * authentication OK frame has been send or after it | ||
1449 | * has been ACKed. In order to reduce interoperability | ||
1450 | * issues, mark the STA authenticated before ACK. */ | ||
1451 | sta->flags |= WLAN_STA_AUTH; | ||
1452 | kfree(sta->u.sta.challenge); | ||
1453 | sta->u.sta.challenge = NULL; | ||
1454 | } | ||
1455 | break; | ||
1456 | } | ||
1457 | |||
1458 | fail: | ||
1459 | pos = (u16 *) body; | ||
1460 | *pos = cpu_to_le16(auth_alg); | ||
1461 | pos++; | ||
1462 | *pos = cpu_to_le16(auth_transaction + 1); | ||
1463 | pos++; | ||
1464 | *pos = cpu_to_le16(resp); /* status_code */ | ||
1465 | pos++; | ||
1466 | olen = 6; | ||
1467 | |||
1468 | if (resp == WLAN_STATUS_SUCCESS && sta != NULL && | ||
1469 | sta->u.sta.challenge != NULL && | ||
1470 | auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { | ||
1471 | u8 *tmp = (u8 *) pos; | ||
1472 | *tmp++ = WLAN_EID_CHALLENGE; | ||
1473 | *tmp++ = WLAN_AUTH_CHALLENGE_LEN; | ||
1474 | pos++; | ||
1475 | memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); | ||
1476 | olen += 2 + WLAN_AUTH_CHALLENGE_LEN; | ||
1477 | } | ||
1478 | |||
1479 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, | ||
1480 | body, olen, hdr->addr2, ap->tx_callback_auth); | ||
1481 | |||
1482 | if (sta) { | ||
1483 | sta->last_rx = jiffies; | ||
1484 | atomic_dec(&sta->users); | ||
1485 | } | ||
1486 | |||
1487 | if (resp) { | ||
1488 | PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d " | ||
1489 | "stat=%d len=%d fc=%04x) ==> %d (%s)\n", | ||
1490 | dev->name, MAC2STR(hdr->addr2), auth_alg, | ||
1491 | auth_transaction, status_code, len, fc, resp, txt); | ||
1492 | } | ||
1493 | } | ||
1494 | |||
1495 | |||
1496 | /* Called only as a scheduled task for pending AP frames. */ | ||
1497 | static void handle_assoc(local_info_t *local, struct sk_buff *skb, | ||
1498 | struct hostap_80211_rx_status *rx_stats, int reassoc) | ||
1499 | { | ||
1500 | struct net_device *dev = local->dev; | ||
1501 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1502 | char body[12], *p, *lpos; | ||
1503 | int len, left; | ||
1504 | u16 *pos; | ||
1505 | u16 resp = WLAN_STATUS_SUCCESS; | ||
1506 | struct sta_info *sta = NULL; | ||
1507 | int send_deauth = 0; | ||
1508 | char *txt = ""; | ||
1509 | u8 prev_ap[ETH_ALEN]; | ||
1510 | |||
1511 | left = len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1512 | |||
1513 | if (len < (reassoc ? 10 : 4)) { | ||
1514 | PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " | ||
1515 | "(len=%d, reassoc=%d) from " MACSTR "\n", | ||
1516 | dev->name, len, reassoc, MAC2STR(hdr->addr2)); | ||
1517 | return; | ||
1518 | } | ||
1519 | |||
1520 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1521 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1522 | if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { | ||
1523 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1524 | txt = "trying to associate before authentication"; | ||
1525 | send_deauth = 1; | ||
1526 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1527 | sta = NULL; /* do not decrement sta->users */ | ||
1528 | goto fail; | ||
1529 | } | ||
1530 | atomic_inc(&sta->users); | ||
1531 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1532 | |||
1533 | pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1534 | sta->capability = __le16_to_cpu(*pos); | ||
1535 | pos++; left -= 2; | ||
1536 | sta->listen_interval = __le16_to_cpu(*pos); | ||
1537 | pos++; left -= 2; | ||
1538 | |||
1539 | if (reassoc) { | ||
1540 | memcpy(prev_ap, pos, ETH_ALEN); | ||
1541 | pos++; pos++; pos++; left -= 6; | ||
1542 | } else | ||
1543 | memset(prev_ap, 0, ETH_ALEN); | ||
1544 | |||
1545 | if (left >= 2) { | ||
1546 | unsigned int ileft; | ||
1547 | unsigned char *u = (unsigned char *) pos; | ||
1548 | |||
1549 | if (*u == WLAN_EID_SSID) { | ||
1550 | u++; left--; | ||
1551 | ileft = *u; | ||
1552 | u++; left--; | ||
1553 | |||
1554 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
1555 | txt = "SSID overflow"; | ||
1556 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1557 | goto fail; | ||
1558 | } | ||
1559 | |||
1560 | if (ileft != strlen(local->essid) || | ||
1561 | memcmp(local->essid, u, ileft) != 0) { | ||
1562 | txt = "not our SSID"; | ||
1563 | resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||
1564 | goto fail; | ||
1565 | } | ||
1566 | |||
1567 | u += ileft; | ||
1568 | left -= ileft; | ||
1569 | } | ||
1570 | |||
1571 | if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { | ||
1572 | u++; left--; | ||
1573 | ileft = *u; | ||
1574 | u++; left--; | ||
1575 | |||
1576 | if (ileft > left || ileft == 0 || | ||
1577 | ileft > WLAN_SUPP_RATES_MAX) { | ||
1578 | txt = "SUPP_RATES len error"; | ||
1579 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1580 | goto fail; | ||
1581 | } | ||
1582 | |||
1583 | memset(sta->supported_rates, 0, | ||
1584 | sizeof(sta->supported_rates)); | ||
1585 | memcpy(sta->supported_rates, u, ileft); | ||
1586 | prism2_check_tx_rates(sta); | ||
1587 | |||
1588 | u += ileft; | ||
1589 | left -= ileft; | ||
1590 | } | ||
1591 | |||
1592 | if (left > 0) { | ||
1593 | PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" | ||
1594 | " data (%d bytes) [", | ||
1595 | dev->name, MAC2STR(hdr->addr2), left); | ||
1596 | while (left > 0) { | ||
1597 | PDEBUG2(DEBUG_AP, "<%02x>", *u); | ||
1598 | u++; left--; | ||
1599 | } | ||
1600 | PDEBUG2(DEBUG_AP, "]\n"); | ||
1601 | } | ||
1602 | } else { | ||
1603 | txt = "frame underflow"; | ||
1604 | resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1605 | goto fail; | ||
1606 | } | ||
1607 | |||
1608 | /* get a unique AID */ | ||
1609 | if (sta->aid > 0) | ||
1610 | txt = "OK, old AID"; | ||
1611 | else { | ||
1612 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1613 | for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) | ||
1614 | if (local->ap->sta_aid[sta->aid - 1] == NULL) | ||
1615 | break; | ||
1616 | if (sta->aid > MAX_AID_TABLE_SIZE) { | ||
1617 | sta->aid = 0; | ||
1618 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1619 | resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; | ||
1620 | txt = "no room for more AIDs"; | ||
1621 | } else { | ||
1622 | local->ap->sta_aid[sta->aid - 1] = sta; | ||
1623 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1624 | txt = "OK, new AID"; | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | fail: | ||
1629 | pos = (u16 *) body; | ||
1630 | |||
1631 | if (send_deauth) { | ||
1632 | *pos = __constant_cpu_to_le16( | ||
1633 | WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); | ||
1634 | pos++; | ||
1635 | } else { | ||
1636 | /* FIX: CF-Pollable and CF-PollReq should be set to match the | ||
1637 | * values in beacons/probe responses */ | ||
1638 | /* FIX: how about privacy and WEP? */ | ||
1639 | /* capability */ | ||
1640 | *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
1641 | pos++; | ||
1642 | |||
1643 | /* status_code */ | ||
1644 | *pos = __cpu_to_le16(resp); | ||
1645 | pos++; | ||
1646 | |||
1647 | *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | | ||
1648 | BIT(14) | BIT(15)); /* AID */ | ||
1649 | pos++; | ||
1650 | |||
1651 | /* Supported rates (Information element) */ | ||
1652 | p = (char *) pos; | ||
1653 | *p++ = WLAN_EID_SUPP_RATES; | ||
1654 | lpos = p; | ||
1655 | *p++ = 0; /* len */ | ||
1656 | if (local->tx_rate_control & WLAN_RATE_1M) { | ||
1657 | *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; | ||
1658 | (*lpos)++; | ||
1659 | } | ||
1660 | if (local->tx_rate_control & WLAN_RATE_2M) { | ||
1661 | *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; | ||
1662 | (*lpos)++; | ||
1663 | } | ||
1664 | if (local->tx_rate_control & WLAN_RATE_5M5) { | ||
1665 | *p++ = local->basic_rates & WLAN_RATE_5M5 ? | ||
1666 | 0x8b : 0x0b; | ||
1667 | (*lpos)++; | ||
1668 | } | ||
1669 | if (local->tx_rate_control & WLAN_RATE_11M) { | ||
1670 | *p++ = local->basic_rates & WLAN_RATE_11M ? | ||
1671 | 0x96 : 0x16; | ||
1672 | (*lpos)++; | ||
1673 | } | ||
1674 | pos = (u16 *) p; | ||
1675 | } | ||
1676 | |||
1677 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
1678 | (send_deauth ? IEEE80211_STYPE_DEAUTH : | ||
1679 | (reassoc ? IEEE80211_STYPE_REASSOC_RESP : | ||
1680 | IEEE80211_STYPE_ASSOC_RESP)), | ||
1681 | body, (u8 *) pos - (u8 *) body, | ||
1682 | hdr->addr2, | ||
1683 | send_deauth ? 0 : local->ap->tx_callback_assoc); | ||
1684 | |||
1685 | if (sta) { | ||
1686 | if (resp == WLAN_STATUS_SUCCESS) { | ||
1687 | sta->last_rx = jiffies; | ||
1688 | /* STA will be marked associated from TX callback, if | ||
1689 | * AssocResp is ACKed */ | ||
1690 | } | ||
1691 | atomic_dec(&sta->users); | ||
1692 | } | ||
1693 | |||
1694 | #if 0 | ||
1695 | PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR | ||
1696 | ") => %d(%d) (%s)\n", | ||
1697 | dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, | ||
1698 | MAC2STR(prev_ap), resp, send_deauth, txt); | ||
1699 | #endif | ||
1700 | } | ||
1701 | |||
1702 | |||
1703 | /* Called only as a scheduled task for pending AP frames. */ | ||
1704 | static void handle_deauth(local_info_t *local, struct sk_buff *skb, | ||
1705 | struct hostap_80211_rx_status *rx_stats) | ||
1706 | { | ||
1707 | struct net_device *dev = local->dev; | ||
1708 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1709 | char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); | ||
1710 | int len; | ||
1711 | u16 reason_code, *pos; | ||
1712 | struct sta_info *sta = NULL; | ||
1713 | |||
1714 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1715 | |||
1716 | if (len < 2) { | ||
1717 | printk("handle_deauth - too short payload (len=%d)\n", len); | ||
1718 | return; | ||
1719 | } | ||
1720 | |||
1721 | pos = (u16 *) body; | ||
1722 | reason_code = __le16_to_cpu(*pos); | ||
1723 | |||
1724 | PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " | ||
1725 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1726 | reason_code); | ||
1727 | |||
1728 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1729 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1730 | if (sta != NULL) { | ||
1731 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1732 | hostap_event_expired_sta(local->dev, sta); | ||
1733 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | ||
1734 | } | ||
1735 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1736 | if (sta == NULL) { | ||
1737 | printk("%s: deauthentication from " MACSTR ", " | ||
1738 | "reason_code=%d, but STA not authenticated\n", dev->name, | ||
1739 | MAC2STR(hdr->addr2), reason_code); | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | |||
1744 | /* Called only as a scheduled task for pending AP frames. */ | ||
1745 | static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | ||
1746 | struct hostap_80211_rx_status *rx_stats) | ||
1747 | { | ||
1748 | struct net_device *dev = local->dev; | ||
1749 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1750 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1751 | int len; | ||
1752 | u16 reason_code, *pos; | ||
1753 | struct sta_info *sta = NULL; | ||
1754 | |||
1755 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1756 | |||
1757 | if (len < 2) { | ||
1758 | printk("handle_disassoc - too short payload (len=%d)\n", len); | ||
1759 | return; | ||
1760 | } | ||
1761 | |||
1762 | pos = (u16 *) body; | ||
1763 | reason_code = __le16_to_cpu(*pos); | ||
1764 | |||
1765 | PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " | ||
1766 | "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, | ||
1767 | reason_code); | ||
1768 | |||
1769 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1770 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1771 | if (sta != NULL) { | ||
1772 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
1773 | hostap_event_expired_sta(local->dev, sta); | ||
1774 | sta->flags &= ~WLAN_STA_ASSOC; | ||
1775 | } | ||
1776 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1777 | if (sta == NULL) { | ||
1778 | printk("%s: disassociation from " MACSTR ", " | ||
1779 | "reason_code=%d, but STA not authenticated\n", | ||
1780 | dev->name, MAC2STR(hdr->addr2), reason_code); | ||
1781 | } | ||
1782 | } | ||
1783 | |||
1784 | |||
1785 | /* Called only as a scheduled task for pending AP frames. */ | ||
1786 | static void ap_handle_data_nullfunc(local_info_t *local, | ||
1787 | struct ieee80211_hdr *hdr) | ||
1788 | { | ||
1789 | struct net_device *dev = local->dev; | ||
1790 | |||
1791 | /* some STA f/w's seem to require control::ACK frame for | ||
1792 | * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does | ||
1793 | * not send this.. | ||
1794 | * send control::ACK for the data::nullfunc */ | ||
1795 | |||
1796 | printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); | ||
1797 | prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, | ||
1798 | NULL, 0, hdr->addr2, 0); | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | /* Called only as a scheduled task for pending AP frames. */ | ||
1803 | static void ap_handle_dropped_data(local_info_t *local, | ||
1804 | struct ieee80211_hdr *hdr) | ||
1805 | { | ||
1806 | struct net_device *dev = local->dev; | ||
1807 | struct sta_info *sta; | ||
1808 | u16 reason; | ||
1809 | |||
1810 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1811 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1812 | if (sta) | ||
1813 | atomic_inc(&sta->users); | ||
1814 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1815 | |||
1816 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { | ||
1817 | PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); | ||
1818 | atomic_dec(&sta->users); | ||
1819 | return; | ||
1820 | } | ||
1821 | |||
1822 | reason = __constant_cpu_to_le16( | ||
1823 | WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | ||
1824 | prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | ||
1825 | ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? | ||
1826 | IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), | ||
1827 | (char *) &reason, sizeof(reason), hdr->addr2, 0); | ||
1828 | |||
1829 | if (sta) | ||
1830 | atomic_dec(&sta->users); | ||
1831 | } | ||
1832 | |||
1833 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
1834 | |||
1835 | |||
1836 | /* Called only as a scheduled task for pending AP frames. */ | ||
1837 | static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, | ||
1838 | struct sk_buff *skb) | ||
1839 | { | ||
1840 | struct hostap_skb_tx_data *meta; | ||
1841 | |||
1842 | if (!(sta->flags & WLAN_STA_PS)) { | ||
1843 | /* Station has moved to non-PS mode, so send all buffered | ||
1844 | * frames using normal device queue. */ | ||
1845 | dev_queue_xmit(skb); | ||
1846 | return; | ||
1847 | } | ||
1848 | |||
1849 | /* add a flag for hostap_handle_sta_tx() to know that this skb should | ||
1850 | * be passed through even though STA is using PS */ | ||
1851 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1852 | meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; | ||
1853 | if (!skb_queue_empty(&sta->tx_buf)) { | ||
1854 | /* indicate to STA that more frames follow */ | ||
1855 | meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; | ||
1856 | } | ||
1857 | dev_queue_xmit(skb); | ||
1858 | } | ||
1859 | |||
1860 | |||
1861 | /* Called only as a scheduled task for pending AP frames. */ | ||
1862 | static void handle_pspoll(local_info_t *local, | ||
1863 | struct ieee80211_hdr *hdr, | ||
1864 | struct hostap_80211_rx_status *rx_stats) | ||
1865 | { | ||
1866 | struct net_device *dev = local->dev; | ||
1867 | struct sta_info *sta; | ||
1868 | u16 aid; | ||
1869 | struct sk_buff *skb; | ||
1870 | |||
1871 | PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR | ||
1872 | " PWRMGT=%d\n", | ||
1873 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | ||
1874 | !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); | ||
1875 | |||
1876 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
1877 | PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR | ||
1878 | " not own MAC\n", MAC2STR(hdr->addr1)); | ||
1879 | return; | ||
1880 | } | ||
1881 | |||
1882 | aid = __le16_to_cpu(hdr->duration_id); | ||
1883 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { | ||
1884 | PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); | ||
1885 | return; | ||
1886 | } | ||
1887 | aid &= ~BIT(15) & ~BIT(14); | ||
1888 | if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { | ||
1889 | PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); | ||
1890 | return; | ||
1891 | } | ||
1892 | PDEBUG(DEBUG_PS2, " aid=%d\n", aid); | ||
1893 | |||
1894 | spin_lock_bh(&local->ap->sta_table_lock); | ||
1895 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
1896 | if (sta) | ||
1897 | atomic_inc(&sta->users); | ||
1898 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
1899 | |||
1900 | if (sta == NULL) { | ||
1901 | PDEBUG(DEBUG_PS, " STA not found\n"); | ||
1902 | return; | ||
1903 | } | ||
1904 | if (sta->aid != aid) { | ||
1905 | PDEBUG(DEBUG_PS, " received aid=%i does not match with " | ||
1906 | "assoc.aid=%d\n", aid, sta->aid); | ||
1907 | return; | ||
1908 | } | ||
1909 | |||
1910 | /* FIX: todo: | ||
1911 | * - add timeout for buffering (clear aid in TIM vector if buffer timed | ||
1912 | * out (expiry time must be longer than ListenInterval for | ||
1913 | * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" | ||
1914 | * - what to do, if buffered, pspolled, and sent frame is not ACKed by | ||
1915 | * sta; store buffer for later use and leave TIM aid bit set? use | ||
1916 | * TX event to check whether frame was ACKed? | ||
1917 | */ | ||
1918 | |||
1919 | while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { | ||
1920 | /* send buffered frame .. */ | ||
1921 | PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" | ||
1922 | " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); | ||
1923 | |||
1924 | pspoll_send_buffered(local, sta, skb); | ||
1925 | |||
1926 | if (sta->flags & WLAN_STA_PS) { | ||
1927 | /* send only one buffered packet per PS Poll */ | ||
1928 | /* FIX: should ignore further PS Polls until the | ||
1929 | * buffered packet that was just sent is acknowledged | ||
1930 | * (Tx or TxExc event) */ | ||
1931 | break; | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | if (skb_queue_empty(&sta->tx_buf)) { | ||
1936 | /* try to clear aid from TIM */ | ||
1937 | if (!(sta->flags & WLAN_STA_TIM)) | ||
1938 | PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", | ||
1939 | aid); | ||
1940 | hostap_set_tim(local, aid, 0); | ||
1941 | sta->flags &= ~WLAN_STA_TIM; | ||
1942 | } | ||
1943 | |||
1944 | atomic_dec(&sta->users); | ||
1945 | } | ||
1946 | |||
1947 | |||
1948 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
1949 | |||
1950 | static void handle_wds_oper_queue(void *data) | ||
1951 | { | ||
1952 | local_info_t *local = data; | ||
1953 | struct wds_oper_data *entry, *prev; | ||
1954 | |||
1955 | spin_lock_bh(&local->lock); | ||
1956 | entry = local->ap->wds_oper_entries; | ||
1957 | local->ap->wds_oper_entries = NULL; | ||
1958 | spin_unlock_bh(&local->lock); | ||
1959 | |||
1960 | while (entry) { | ||
1961 | PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " | ||
1962 | "to AP " MACSTR "\n", | ||
1963 | local->dev->name, | ||
1964 | entry->type == WDS_ADD ? "adding" : "removing", | ||
1965 | MAC2STR(entry->addr)); | ||
1966 | if (entry->type == WDS_ADD) | ||
1967 | prism2_wds_add(local, entry->addr, 0); | ||
1968 | else if (entry->type == WDS_DEL) | ||
1969 | prism2_wds_del(local, entry->addr, 0, 1); | ||
1970 | |||
1971 | prev = entry; | ||
1972 | entry = entry->next; | ||
1973 | kfree(prev); | ||
1974 | } | ||
1975 | } | ||
1976 | |||
1977 | |||
1978 | /* Called only as a scheduled task for pending AP frames. */ | ||
1979 | static void handle_beacon(local_info_t *local, struct sk_buff *skb, | ||
1980 | struct hostap_80211_rx_status *rx_stats) | ||
1981 | { | ||
1982 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1983 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | ||
1984 | int len, left; | ||
1985 | u16 *pos, beacon_int, capability; | ||
1986 | char *ssid = NULL; | ||
1987 | unsigned char *supp_rates = NULL; | ||
1988 | int ssid_len = 0, supp_rates_len = 0; | ||
1989 | struct sta_info *sta = NULL; | ||
1990 | int new_sta = 0, channel = -1; | ||
1991 | |||
1992 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | ||
1993 | |||
1994 | if (len < 8 + 2 + 2) { | ||
1995 | printk(KERN_DEBUG "handle_beacon - too short payload " | ||
1996 | "(len=%d)\n", len); | ||
1997 | return; | ||
1998 | } | ||
1999 | |||
2000 | pos = (u16 *) body; | ||
2001 | left = len; | ||
2002 | |||
2003 | /* Timestamp (8 octets) */ | ||
2004 | pos += 4; left -= 8; | ||
2005 | /* Beacon interval (2 octets) */ | ||
2006 | beacon_int = __le16_to_cpu(*pos); | ||
2007 | pos++; left -= 2; | ||
2008 | /* Capability information (2 octets) */ | ||
2009 | capability = __le16_to_cpu(*pos); | ||
2010 | pos++; left -= 2; | ||
2011 | |||
2012 | if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && | ||
2013 | capability & WLAN_CAPABILITY_IBSS) | ||
2014 | return; | ||
2015 | |||
2016 | if (left >= 2) { | ||
2017 | unsigned int ileft; | ||
2018 | unsigned char *u = (unsigned char *) pos; | ||
2019 | |||
2020 | if (*u == WLAN_EID_SSID) { | ||
2021 | u++; left--; | ||
2022 | ileft = *u; | ||
2023 | u++; left--; | ||
2024 | |||
2025 | if (ileft > left || ileft > MAX_SSID_LEN) { | ||
2026 | PDEBUG(DEBUG_AP, "SSID: overflow\n"); | ||
2027 | return; | ||
2028 | } | ||
2029 | |||
2030 | if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && | ||
2031 | (ileft != strlen(local->essid) || | ||
2032 | memcmp(local->essid, u, ileft) != 0)) { | ||
2033 | /* not our SSID */ | ||
2034 | return; | ||
2035 | } | ||
2036 | |||
2037 | ssid = u; | ||
2038 | ssid_len = ileft; | ||
2039 | |||
2040 | u += ileft; | ||
2041 | left -= ileft; | ||
2042 | } | ||
2043 | |||
2044 | if (*u == WLAN_EID_SUPP_RATES) { | ||
2045 | u++; left--; | ||
2046 | ileft = *u; | ||
2047 | u++; left--; | ||
2048 | |||
2049 | if (ileft > left || ileft == 0 || ileft > 8) { | ||
2050 | PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); | ||
2051 | return; | ||
2052 | } | ||
2053 | |||
2054 | supp_rates = u; | ||
2055 | supp_rates_len = ileft; | ||
2056 | |||
2057 | u += ileft; | ||
2058 | left -= ileft; | ||
2059 | } | ||
2060 | |||
2061 | if (*u == WLAN_EID_DS_PARAMS) { | ||
2062 | u++; left--; | ||
2063 | ileft = *u; | ||
2064 | u++; left--; | ||
2065 | |||
2066 | if (ileft > left || ileft != 1) { | ||
2067 | PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); | ||
2068 | return; | ||
2069 | } | ||
2070 | |||
2071 | channel = *u; | ||
2072 | |||
2073 | u += ileft; | ||
2074 | left -= ileft; | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | spin_lock_bh(&local->ap->sta_table_lock); | ||
2079 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2080 | if (sta != NULL) | ||
2081 | atomic_inc(&sta->users); | ||
2082 | spin_unlock_bh(&local->ap->sta_table_lock); | ||
2083 | |||
2084 | if (sta == NULL) { | ||
2085 | /* add new AP */ | ||
2086 | new_sta = 1; | ||
2087 | sta = ap_add_sta(local->ap, hdr->addr2); | ||
2088 | if (sta == NULL) { | ||
2089 | printk(KERN_INFO "prism2: kmalloc failed for AP " | ||
2090 | "data structure\n"); | ||
2091 | return; | ||
2092 | } | ||
2093 | hostap_event_new_sta(local->dev, sta); | ||
2094 | |||
2095 | /* mark APs authentication and associated for pseudo ad-hoc | ||
2096 | * style communication */ | ||
2097 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2098 | |||
2099 | if (local->ap->autom_ap_wds) { | ||
2100 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
2101 | } | ||
2102 | } | ||
2103 | |||
2104 | sta->ap = 1; | ||
2105 | if (ssid) { | ||
2106 | sta->u.ap.ssid_len = ssid_len; | ||
2107 | memcpy(sta->u.ap.ssid, ssid, ssid_len); | ||
2108 | sta->u.ap.ssid[ssid_len] = '\0'; | ||
2109 | } else { | ||
2110 | sta->u.ap.ssid_len = 0; | ||
2111 | sta->u.ap.ssid[0] = '\0'; | ||
2112 | } | ||
2113 | sta->u.ap.channel = channel; | ||
2114 | sta->rx_packets++; | ||
2115 | sta->rx_bytes += len; | ||
2116 | sta->u.ap.last_beacon = sta->last_rx = jiffies; | ||
2117 | sta->capability = capability; | ||
2118 | sta->listen_interval = beacon_int; | ||
2119 | |||
2120 | atomic_dec(&sta->users); | ||
2121 | |||
2122 | if (new_sta) { | ||
2123 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
2124 | memcpy(sta->supported_rates, supp_rates, supp_rates_len); | ||
2125 | prism2_check_tx_rates(sta); | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2130 | |||
2131 | |||
2132 | /* Called only as a tasklet. */ | ||
2133 | static void handle_ap_item(local_info_t *local, struct sk_buff *skb, | ||
2134 | struct hostap_80211_rx_status *rx_stats) | ||
2135 | { | ||
2136 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2137 | struct net_device *dev = local->dev; | ||
2138 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2139 | u16 fc, type, stype; | ||
2140 | struct ieee80211_hdr *hdr; | ||
2141 | |||
2142 | /* FIX: should give skb->len to handler functions and check that the | ||
2143 | * buffer is long enough */ | ||
2144 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2145 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2146 | type = WLAN_FC_GET_TYPE(fc); | ||
2147 | stype = WLAN_FC_GET_STYPE(fc); | ||
2148 | |||
2149 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2150 | if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { | ||
2151 | PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); | ||
2152 | |||
2153 | if (!(fc & IEEE80211_FCTL_TODS) || | ||
2154 | (fc & IEEE80211_FCTL_FROMDS)) { | ||
2155 | if (stype == IEEE80211_STYPE_NULLFUNC) { | ||
2156 | /* no ToDS nullfunc seems to be used to check | ||
2157 | * AP association; so send reject message to | ||
2158 | * speed up re-association */ | ||
2159 | ap_handle_dropped_data(local, hdr); | ||
2160 | goto done; | ||
2161 | } | ||
2162 | PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", | ||
2163 | fc); | ||
2164 | goto done; | ||
2165 | } | ||
2166 | |||
2167 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
2168 | PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" | ||
2169 | MACSTR " not own MAC\n", | ||
2170 | MAC2STR(hdr->addr1)); | ||
2171 | goto done; | ||
2172 | } | ||
2173 | |||
2174 | if (local->ap->nullfunc_ack && | ||
2175 | stype == IEEE80211_STYPE_NULLFUNC) | ||
2176 | ap_handle_data_nullfunc(local, hdr); | ||
2177 | else | ||
2178 | ap_handle_dropped_data(local, hdr); | ||
2179 | goto done; | ||
2180 | } | ||
2181 | |||
2182 | if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { | ||
2183 | handle_beacon(local, skb, rx_stats); | ||
2184 | goto done; | ||
2185 | } | ||
2186 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2187 | |||
2188 | if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { | ||
2189 | handle_pspoll(local, hdr, rx_stats); | ||
2190 | goto done; | ||
2191 | } | ||
2192 | |||
2193 | if (local->hostapd) { | ||
2194 | PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " | ||
2195 | "subtype=0x%02x\n", type, stype); | ||
2196 | goto done; | ||
2197 | } | ||
2198 | |||
2199 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2200 | if (type != IEEE80211_FTYPE_MGMT) { | ||
2201 | PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); | ||
2202 | goto done; | ||
2203 | } | ||
2204 | |||
2205 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | ||
2206 | PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR | ||
2207 | " not own MAC\n", MAC2STR(hdr->addr1)); | ||
2208 | goto done; | ||
2209 | } | ||
2210 | |||
2211 | if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { | ||
2212 | PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR | ||
2213 | " not own MAC\n", MAC2STR(hdr->addr3)); | ||
2214 | goto done; | ||
2215 | } | ||
2216 | |||
2217 | switch (stype) { | ||
2218 | case IEEE80211_STYPE_ASSOC_REQ: | ||
2219 | handle_assoc(local, skb, rx_stats, 0); | ||
2220 | break; | ||
2221 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2222 | PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); | ||
2223 | break; | ||
2224 | case IEEE80211_STYPE_REASSOC_REQ: | ||
2225 | handle_assoc(local, skb, rx_stats, 1); | ||
2226 | break; | ||
2227 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2228 | PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); | ||
2229 | break; | ||
2230 | case IEEE80211_STYPE_ATIM: | ||
2231 | PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); | ||
2232 | break; | ||
2233 | case IEEE80211_STYPE_DISASSOC: | ||
2234 | handle_disassoc(local, skb, rx_stats); | ||
2235 | break; | ||
2236 | case IEEE80211_STYPE_AUTH: | ||
2237 | handle_authen(local, skb, rx_stats); | ||
2238 | break; | ||
2239 | case IEEE80211_STYPE_DEAUTH: | ||
2240 | handle_deauth(local, skb, rx_stats); | ||
2241 | break; | ||
2242 | default: | ||
2243 | PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", | ||
2244 | stype >> 4); | ||
2245 | break; | ||
2246 | } | ||
2247 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2248 | |||
2249 | done: | ||
2250 | dev_kfree_skb(skb); | ||
2251 | } | ||
2252 | |||
2253 | |||
2254 | /* Called only as a tasklet (software IRQ) */ | ||
2255 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
2256 | struct hostap_80211_rx_status *rx_stats) | ||
2257 | { | ||
2258 | struct hostap_interface *iface; | ||
2259 | local_info_t *local; | ||
2260 | u16 fc; | ||
2261 | struct ieee80211_hdr *hdr; | ||
2262 | |||
2263 | iface = netdev_priv(dev); | ||
2264 | local = iface->local; | ||
2265 | |||
2266 | if (skb->len < 16) | ||
2267 | goto drop; | ||
2268 | |||
2269 | local->stats.rx_packets++; | ||
2270 | |||
2271 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2272 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2273 | |||
2274 | if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && | ||
2275 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT && | ||
2276 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON) | ||
2277 | goto drop; | ||
2278 | |||
2279 | skb->protocol = __constant_htons(ETH_P_HOSTAP); | ||
2280 | handle_ap_item(local, skb, rx_stats); | ||
2281 | return; | ||
2282 | |||
2283 | drop: | ||
2284 | dev_kfree_skb(skb); | ||
2285 | } | ||
2286 | |||
2287 | |||
2288 | /* Called only as a tasklet (software IRQ) */ | ||
2289 | static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | ||
2290 | { | ||
2291 | struct sk_buff *skb; | ||
2292 | struct ieee80211_hdr *hdr; | ||
2293 | struct hostap_80211_rx_status rx_stats; | ||
2294 | |||
2295 | if (skb_queue_empty(&sta->tx_buf)) | ||
2296 | return; | ||
2297 | |||
2298 | skb = dev_alloc_skb(16); | ||
2299 | if (skb == NULL) { | ||
2300 | printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " | ||
2301 | "failed\n", local->dev->name); | ||
2302 | return; | ||
2303 | } | ||
2304 | |||
2305 | hdr = (struct ieee80211_hdr *) skb_put(skb, 16); | ||
2306 | |||
2307 | /* Generate a fake pspoll frame to start packet delivery */ | ||
2308 | hdr->frame_ctl = __constant_cpu_to_le16( | ||
2309 | IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
2310 | memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); | ||
2311 | memcpy(hdr->addr2, sta->addr, ETH_ALEN); | ||
2312 | hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); | ||
2313 | |||
2314 | PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " | ||
2315 | "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); | ||
2316 | |||
2317 | skb->dev = local->dev; | ||
2318 | |||
2319 | memset(&rx_stats, 0, sizeof(rx_stats)); | ||
2320 | hostap_rx(local->dev, skb, &rx_stats); | ||
2321 | } | ||
2322 | |||
2323 | |||
2324 | static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | ||
2325 | struct iw_quality qual[], int buf_size, | ||
2326 | int aplist) | ||
2327 | { | ||
2328 | struct ap_data *ap = local->ap; | ||
2329 | struct list_head *ptr; | ||
2330 | int count = 0; | ||
2331 | |||
2332 | spin_lock_bh(&ap->sta_table_lock); | ||
2333 | |||
2334 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2335 | ptr = ptr->next) { | ||
2336 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2337 | |||
2338 | if (aplist && !sta->ap) | ||
2339 | continue; | ||
2340 | addr[count].sa_family = ARPHRD_ETHER; | ||
2341 | memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); | ||
2342 | if (sta->last_rx_silence == 0) | ||
2343 | qual[count].qual = sta->last_rx_signal < 27 ? | ||
2344 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2345 | else | ||
2346 | qual[count].qual = sta->last_rx_signal - | ||
2347 | sta->last_rx_silence - 35; | ||
2348 | qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2349 | qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2350 | qual[count].updated = sta->last_rx_updated; | ||
2351 | |||
2352 | sta->last_rx_updated = 0; | ||
2353 | |||
2354 | count++; | ||
2355 | if (count >= buf_size) | ||
2356 | break; | ||
2357 | } | ||
2358 | spin_unlock_bh(&ap->sta_table_lock); | ||
2359 | |||
2360 | return count; | ||
2361 | } | ||
2362 | |||
2363 | |||
2364 | /* Translate our list of Access Points & Stations to a card independant | ||
2365 | * format that the Wireless Tools will understand - Jean II */ | ||
2366 | static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) | ||
2367 | { | ||
2368 | struct hostap_interface *iface; | ||
2369 | local_info_t *local; | ||
2370 | struct ap_data *ap; | ||
2371 | struct list_head *ptr; | ||
2372 | struct iw_event iwe; | ||
2373 | char *current_ev = buffer; | ||
2374 | char *end_buf = buffer + IW_SCAN_MAX_DATA; | ||
2375 | #if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) | ||
2376 | char buf[64]; | ||
2377 | #endif | ||
2378 | |||
2379 | iface = netdev_priv(dev); | ||
2380 | local = iface->local; | ||
2381 | ap = local->ap; | ||
2382 | |||
2383 | spin_lock_bh(&ap->sta_table_lock); | ||
2384 | |||
2385 | for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | ||
2386 | ptr = ptr->next) { | ||
2387 | struct sta_info *sta = (struct sta_info *) ptr; | ||
2388 | |||
2389 | /* First entry *MUST* be the AP MAC address */ | ||
2390 | memset(&iwe, 0, sizeof(iwe)); | ||
2391 | iwe.cmd = SIOCGIWAP; | ||
2392 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
2393 | memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); | ||
2394 | iwe.len = IW_EV_ADDR_LEN; | ||
2395 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2396 | IW_EV_ADDR_LEN); | ||
2397 | |||
2398 | /* Use the mode to indicate if it's a station or | ||
2399 | * an Access Point */ | ||
2400 | memset(&iwe, 0, sizeof(iwe)); | ||
2401 | iwe.cmd = SIOCGIWMODE; | ||
2402 | if (sta->ap) | ||
2403 | iwe.u.mode = IW_MODE_MASTER; | ||
2404 | else | ||
2405 | iwe.u.mode = IW_MODE_INFRA; | ||
2406 | iwe.len = IW_EV_UINT_LEN; | ||
2407 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2408 | IW_EV_UINT_LEN); | ||
2409 | |||
2410 | /* Some quality */ | ||
2411 | memset(&iwe, 0, sizeof(iwe)); | ||
2412 | iwe.cmd = IWEVQUAL; | ||
2413 | if (sta->last_rx_silence == 0) | ||
2414 | iwe.u.qual.qual = sta->last_rx_signal < 27 ? | ||
2415 | 0 : (sta->last_rx_signal - 27) * 92 / 127; | ||
2416 | else | ||
2417 | iwe.u.qual.qual = sta->last_rx_signal - | ||
2418 | sta->last_rx_silence - 35; | ||
2419 | iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | ||
2420 | iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | ||
2421 | iwe.u.qual.updated = sta->last_rx_updated; | ||
2422 | iwe.len = IW_EV_QUAL_LEN; | ||
2423 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
2424 | IW_EV_QUAL_LEN); | ||
2425 | |||
2426 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2427 | if (sta->ap) { | ||
2428 | memset(&iwe, 0, sizeof(iwe)); | ||
2429 | iwe.cmd = SIOCGIWESSID; | ||
2430 | iwe.u.data.length = sta->u.ap.ssid_len; | ||
2431 | iwe.u.data.flags = 1; | ||
2432 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2433 | &iwe, | ||
2434 | sta->u.ap.ssid); | ||
2435 | |||
2436 | memset(&iwe, 0, sizeof(iwe)); | ||
2437 | iwe.cmd = SIOCGIWENCODE; | ||
2438 | if (sta->capability & WLAN_CAPABILITY_PRIVACY) | ||
2439 | iwe.u.data.flags = | ||
2440 | IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
2441 | else | ||
2442 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
2443 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2444 | &iwe, | ||
2445 | sta->u.ap.ssid | ||
2446 | /* 0 byte memcpy */); | ||
2447 | |||
2448 | if (sta->u.ap.channel > 0 && | ||
2449 | sta->u.ap.channel <= FREQ_COUNT) { | ||
2450 | memset(&iwe, 0, sizeof(iwe)); | ||
2451 | iwe.cmd = SIOCGIWFREQ; | ||
2452 | iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] | ||
2453 | * 100000; | ||
2454 | iwe.u.freq.e = 1; | ||
2455 | current_ev = iwe_stream_add_event( | ||
2456 | current_ev, end_buf, &iwe, | ||
2457 | IW_EV_FREQ_LEN); | ||
2458 | } | ||
2459 | |||
2460 | memset(&iwe, 0, sizeof(iwe)); | ||
2461 | iwe.cmd = IWEVCUSTOM; | ||
2462 | sprintf(buf, "beacon_interval=%d", | ||
2463 | sta->listen_interval); | ||
2464 | iwe.u.data.length = strlen(buf); | ||
2465 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
2466 | &iwe, buf); | ||
2467 | } | ||
2468 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2469 | |||
2470 | sta->last_rx_updated = 0; | ||
2471 | |||
2472 | /* To be continued, we should make good use of IWEVCUSTOM */ | ||
2473 | } | ||
2474 | |||
2475 | spin_unlock_bh(&ap->sta_table_lock); | ||
2476 | |||
2477 | return current_ev - buffer; | ||
2478 | } | ||
2479 | |||
2480 | |||
2481 | static int prism2_hostapd_add_sta(struct ap_data *ap, | ||
2482 | struct prism2_hostapd_param *param) | ||
2483 | { | ||
2484 | struct sta_info *sta; | ||
2485 | |||
2486 | spin_lock_bh(&ap->sta_table_lock); | ||
2487 | sta = ap_get_sta(ap, param->sta_addr); | ||
2488 | if (sta) | ||
2489 | atomic_inc(&sta->users); | ||
2490 | spin_unlock_bh(&ap->sta_table_lock); | ||
2491 | |||
2492 | if (sta == NULL) { | ||
2493 | sta = ap_add_sta(ap, param->sta_addr); | ||
2494 | if (sta == NULL) | ||
2495 | return -1; | ||
2496 | } | ||
2497 | |||
2498 | if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2499 | hostap_event_new_sta(sta->local->dev, sta); | ||
2500 | |||
2501 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
2502 | sta->last_rx = jiffies; | ||
2503 | sta->aid = param->u.add_sta.aid; | ||
2504 | sta->capability = param->u.add_sta.capability; | ||
2505 | sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; | ||
2506 | if (sta->tx_supp_rates & WLAN_RATE_1M) | ||
2507 | sta->supported_rates[0] = 2; | ||
2508 | if (sta->tx_supp_rates & WLAN_RATE_2M) | ||
2509 | sta->supported_rates[1] = 4; | ||
2510 | if (sta->tx_supp_rates & WLAN_RATE_5M5) | ||
2511 | sta->supported_rates[2] = 11; | ||
2512 | if (sta->tx_supp_rates & WLAN_RATE_11M) | ||
2513 | sta->supported_rates[3] = 22; | ||
2514 | prism2_check_tx_rates(sta); | ||
2515 | atomic_dec(&sta->users); | ||
2516 | return 0; | ||
2517 | } | ||
2518 | |||
2519 | |||
2520 | static int prism2_hostapd_remove_sta(struct ap_data *ap, | ||
2521 | struct prism2_hostapd_param *param) | ||
2522 | { | ||
2523 | struct sta_info *sta; | ||
2524 | |||
2525 | spin_lock_bh(&ap->sta_table_lock); | ||
2526 | sta = ap_get_sta(ap, param->sta_addr); | ||
2527 | if (sta) { | ||
2528 | ap_sta_hash_del(ap, sta); | ||
2529 | list_del(&sta->list); | ||
2530 | } | ||
2531 | spin_unlock_bh(&ap->sta_table_lock); | ||
2532 | |||
2533 | if (!sta) | ||
2534 | return -ENOENT; | ||
2535 | |||
2536 | if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | ||
2537 | hostap_event_expired_sta(sta->local->dev, sta); | ||
2538 | ap_free_sta(ap, sta); | ||
2539 | |||
2540 | return 0; | ||
2541 | } | ||
2542 | |||
2543 | |||
2544 | static int prism2_hostapd_get_info_sta(struct ap_data *ap, | ||
2545 | struct prism2_hostapd_param *param) | ||
2546 | { | ||
2547 | struct sta_info *sta; | ||
2548 | |||
2549 | spin_lock_bh(&ap->sta_table_lock); | ||
2550 | sta = ap_get_sta(ap, param->sta_addr); | ||
2551 | if (sta) | ||
2552 | atomic_inc(&sta->users); | ||
2553 | spin_unlock_bh(&ap->sta_table_lock); | ||
2554 | |||
2555 | if (!sta) | ||
2556 | return -ENOENT; | ||
2557 | |||
2558 | param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; | ||
2559 | |||
2560 | atomic_dec(&sta->users); | ||
2561 | |||
2562 | return 1; | ||
2563 | } | ||
2564 | |||
2565 | |||
2566 | static int prism2_hostapd_set_flags_sta(struct ap_data *ap, | ||
2567 | struct prism2_hostapd_param *param) | ||
2568 | { | ||
2569 | struct sta_info *sta; | ||
2570 | |||
2571 | spin_lock_bh(&ap->sta_table_lock); | ||
2572 | sta = ap_get_sta(ap, param->sta_addr); | ||
2573 | if (sta) { | ||
2574 | sta->flags |= param->u.set_flags_sta.flags_or; | ||
2575 | sta->flags &= param->u.set_flags_sta.flags_and; | ||
2576 | } | ||
2577 | spin_unlock_bh(&ap->sta_table_lock); | ||
2578 | |||
2579 | if (!sta) | ||
2580 | return -ENOENT; | ||
2581 | |||
2582 | return 0; | ||
2583 | } | ||
2584 | |||
2585 | |||
2586 | static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, | ||
2587 | struct prism2_hostapd_param *param) | ||
2588 | { | ||
2589 | struct sta_info *sta; | ||
2590 | int rate; | ||
2591 | |||
2592 | spin_lock_bh(&ap->sta_table_lock); | ||
2593 | sta = ap_get_sta(ap, param->sta_addr); | ||
2594 | if (sta) { | ||
2595 | sta->rx_packets = sta->tx_packets = 0; | ||
2596 | sta->rx_bytes = sta->tx_bytes = 0; | ||
2597 | for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { | ||
2598 | sta->tx_count[rate] = 0; | ||
2599 | sta->rx_count[rate] = 0; | ||
2600 | } | ||
2601 | } | ||
2602 | spin_unlock_bh(&ap->sta_table_lock); | ||
2603 | |||
2604 | if (!sta) | ||
2605 | return -ENOENT; | ||
2606 | |||
2607 | return 0; | ||
2608 | } | ||
2609 | |||
2610 | |||
2611 | static int prism2_hostapd(struct ap_data *ap, | ||
2612 | struct prism2_hostapd_param *param) | ||
2613 | { | ||
2614 | switch (param->cmd) { | ||
2615 | case PRISM2_HOSTAPD_FLUSH: | ||
2616 | ap_control_kickall(ap); | ||
2617 | return 0; | ||
2618 | case PRISM2_HOSTAPD_ADD_STA: | ||
2619 | return prism2_hostapd_add_sta(ap, param); | ||
2620 | case PRISM2_HOSTAPD_REMOVE_STA: | ||
2621 | return prism2_hostapd_remove_sta(ap, param); | ||
2622 | case PRISM2_HOSTAPD_GET_INFO_STA: | ||
2623 | return prism2_hostapd_get_info_sta(ap, param); | ||
2624 | case PRISM2_HOSTAPD_SET_FLAGS_STA: | ||
2625 | return prism2_hostapd_set_flags_sta(ap, param); | ||
2626 | case PRISM2_HOSTAPD_STA_CLEAR_STATS: | ||
2627 | return prism2_hostapd_sta_clear_stats(ap, param); | ||
2628 | default: | ||
2629 | printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", | ||
2630 | param->cmd); | ||
2631 | return -EOPNOTSUPP; | ||
2632 | } | ||
2633 | } | ||
2634 | |||
2635 | |||
2636 | /* Update station info for host-based TX rate control and return current | ||
2637 | * TX rate */ | ||
2638 | static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) | ||
2639 | { | ||
2640 | int ret = sta->tx_rate; | ||
2641 | struct hostap_interface *iface; | ||
2642 | local_info_t *local; | ||
2643 | |||
2644 | iface = netdev_priv(dev); | ||
2645 | local = iface->local; | ||
2646 | |||
2647 | sta->tx_count[sta->tx_rate_idx]++; | ||
2648 | sta->tx_since_last_failure++; | ||
2649 | sta->tx_consecutive_exc = 0; | ||
2650 | if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && | ||
2651 | sta->tx_rate_idx < sta->tx_max_rate) { | ||
2652 | /* use next higher rate */ | ||
2653 | int old_rate, new_rate; | ||
2654 | old_rate = new_rate = sta->tx_rate_idx; | ||
2655 | while (new_rate < sta->tx_max_rate) { | ||
2656 | new_rate++; | ||
2657 | if (ap_tx_rate_ok(new_rate, sta, local)) { | ||
2658 | sta->tx_rate_idx = new_rate; | ||
2659 | break; | ||
2660 | } | ||
2661 | } | ||
2662 | if (old_rate != sta->tx_rate_idx) { | ||
2663 | switch (sta->tx_rate_idx) { | ||
2664 | case 0: sta->tx_rate = 10; break; | ||
2665 | case 1: sta->tx_rate = 20; break; | ||
2666 | case 2: sta->tx_rate = 55; break; | ||
2667 | case 3: sta->tx_rate = 110; break; | ||
2668 | default: sta->tx_rate = 0; break; | ||
2669 | } | ||
2670 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" | ||
2671 | " %d\n", dev->name, MAC2STR(sta->addr), | ||
2672 | sta->tx_rate); | ||
2673 | } | ||
2674 | sta->tx_since_last_failure = 0; | ||
2675 | } | ||
2676 | |||
2677 | return ret; | ||
2678 | } | ||
2679 | |||
2680 | |||
2681 | /* Called only from software IRQ. Called for each TX frame prior possible | ||
2682 | * encryption and transmit. */ | ||
2683 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | ||
2684 | { | ||
2685 | struct sta_info *sta = NULL; | ||
2686 | struct sk_buff *skb = tx->skb; | ||
2687 | int set_tim, ret; | ||
2688 | struct ieee80211_hdr *hdr; | ||
2689 | struct hostap_skb_tx_data *meta; | ||
2690 | |||
2691 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
2692 | ret = AP_TX_CONTINUE; | ||
2693 | if (local->ap == NULL || skb->len < 10 || | ||
2694 | meta->iface->type == HOSTAP_INTERFACE_STA) | ||
2695 | goto out; | ||
2696 | |||
2697 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2698 | |||
2699 | if (hdr->addr1[0] & 0x01) { | ||
2700 | /* broadcast/multicast frame - no AP related processing */ | ||
2701 | goto out; | ||
2702 | } | ||
2703 | |||
2704 | /* unicast packet - check whether destination STA is associated */ | ||
2705 | spin_lock(&local->ap->sta_table_lock); | ||
2706 | sta = ap_get_sta(local->ap, hdr->addr1); | ||
2707 | if (sta) | ||
2708 | atomic_inc(&sta->users); | ||
2709 | spin_unlock(&local->ap->sta_table_lock); | ||
2710 | |||
2711 | if (local->iw_mode == IW_MODE_MASTER && sta == NULL && | ||
2712 | !(meta->flags & HOSTAP_TX_FLAGS_WDS) && | ||
2713 | meta->iface->type != HOSTAP_INTERFACE_MASTER && | ||
2714 | meta->iface->type != HOSTAP_INTERFACE_AP) { | ||
2715 | #if 0 | ||
2716 | /* This can happen, e.g., when wlan0 is added to a bridge and | ||
2717 | * bridging code does not know which port is the correct target | ||
2718 | * for a unicast frame. In this case, the packet is send to all | ||
2719 | * ports of the bridge. Since this is a valid scenario, do not | ||
2720 | * print out any errors here. */ | ||
2721 | if (net_ratelimit()) { | ||
2722 | printk(KERN_DEBUG "AP: drop packet to non-associated " | ||
2723 | "STA " MACSTR "\n", MAC2STR(hdr->addr1)); | ||
2724 | } | ||
2725 | #endif | ||
2726 | local->ap->tx_drop_nonassoc++; | ||
2727 | ret = AP_TX_DROP; | ||
2728 | goto out; | ||
2729 | } | ||
2730 | |||
2731 | if (sta == NULL) | ||
2732 | goto out; | ||
2733 | |||
2734 | if (!(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2735 | ret = AP_TX_CONTINUE_NOT_AUTHORIZED; | ||
2736 | |||
2737 | /* Set tx_rate if using host-based TX rate control */ | ||
2738 | if (!local->fw_tx_rate_control) | ||
2739 | local->ap->last_tx_rate = meta->rate = | ||
2740 | ap_update_sta_tx_rate(sta, local->dev); | ||
2741 | |||
2742 | if (local->iw_mode != IW_MODE_MASTER) | ||
2743 | goto out; | ||
2744 | |||
2745 | if (!(sta->flags & WLAN_STA_PS)) | ||
2746 | goto out; | ||
2747 | |||
2748 | if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { | ||
2749 | /* indicate to STA that more frames follow */ | ||
2750 | hdr->frame_ctl |= | ||
2751 | __constant_cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
2752 | } | ||
2753 | |||
2754 | if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { | ||
2755 | /* packet was already buffered and now send due to | ||
2756 | * PS poll, so do not rebuffer it */ | ||
2757 | goto out; | ||
2758 | } | ||
2759 | |||
2760 | if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { | ||
2761 | PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS " | ||
2762 | "mode buffer\n", local->dev->name, MAC2STR(sta->addr)); | ||
2763 | /* Make sure that TIM is set for the station (it might not be | ||
2764 | * after AP wlan hw reset). */ | ||
2765 | /* FIX: should fix hw reset to restore bits based on STA | ||
2766 | * buffer state.. */ | ||
2767 | hostap_set_tim(local, sta->aid, 1); | ||
2768 | sta->flags |= WLAN_STA_TIM; | ||
2769 | ret = AP_TX_DROP; | ||
2770 | goto out; | ||
2771 | } | ||
2772 | |||
2773 | /* STA in PS mode, buffer frame for later delivery */ | ||
2774 | set_tim = skb_queue_empty(&sta->tx_buf); | ||
2775 | skb_queue_tail(&sta->tx_buf, skb); | ||
2776 | /* FIX: could save RX time to skb and expire buffered frames after | ||
2777 | * some time if STA does not poll for them */ | ||
2778 | |||
2779 | if (set_tim) { | ||
2780 | if (sta->flags & WLAN_STA_TIM) | ||
2781 | PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", | ||
2782 | sta->aid); | ||
2783 | hostap_set_tim(local, sta->aid, 1); | ||
2784 | sta->flags |= WLAN_STA_TIM; | ||
2785 | } | ||
2786 | |||
2787 | ret = AP_TX_BUFFERED; | ||
2788 | |||
2789 | out: | ||
2790 | if (sta != NULL) { | ||
2791 | if (ret == AP_TX_CONTINUE || | ||
2792 | ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { | ||
2793 | sta->tx_packets++; | ||
2794 | sta->tx_bytes += skb->len; | ||
2795 | sta->last_tx = jiffies; | ||
2796 | } | ||
2797 | |||
2798 | if ((ret == AP_TX_CONTINUE || | ||
2799 | ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && | ||
2800 | sta->crypt && tx->host_encrypt) { | ||
2801 | tx->crypt = sta->crypt; | ||
2802 | tx->sta_ptr = sta; /* hostap_handle_sta_release() will | ||
2803 | * be called to release sta info | ||
2804 | * later */ | ||
2805 | } else | ||
2806 | atomic_dec(&sta->users); | ||
2807 | } | ||
2808 | |||
2809 | return ret; | ||
2810 | } | ||
2811 | |||
2812 | |||
2813 | void hostap_handle_sta_release(void *ptr) | ||
2814 | { | ||
2815 | struct sta_info *sta = ptr; | ||
2816 | atomic_dec(&sta->users); | ||
2817 | } | ||
2818 | |||
2819 | |||
2820 | /* Called only as a tasklet (software IRQ) */ | ||
2821 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) | ||
2822 | { | ||
2823 | struct sta_info *sta; | ||
2824 | struct ieee80211_hdr *hdr; | ||
2825 | struct hostap_skb_tx_data *meta; | ||
2826 | |||
2827 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2828 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
2829 | |||
2830 | spin_lock(&local->ap->sta_table_lock); | ||
2831 | sta = ap_get_sta(local->ap, hdr->addr1); | ||
2832 | if (!sta) { | ||
2833 | spin_unlock(&local->ap->sta_table_lock); | ||
2834 | PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this " | ||
2835 | "TX error (@%lu)\n", | ||
2836 | local->dev->name, MAC2STR(hdr->addr1), jiffies); | ||
2837 | return; | ||
2838 | } | ||
2839 | |||
2840 | sta->tx_since_last_failure = 0; | ||
2841 | sta->tx_consecutive_exc++; | ||
2842 | |||
2843 | if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && | ||
2844 | sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { | ||
2845 | /* use next lower rate */ | ||
2846 | int old, rate; | ||
2847 | old = rate = sta->tx_rate_idx; | ||
2848 | while (rate > 0) { | ||
2849 | rate--; | ||
2850 | if (ap_tx_rate_ok(rate, sta, local)) { | ||
2851 | sta->tx_rate_idx = rate; | ||
2852 | break; | ||
2853 | } | ||
2854 | } | ||
2855 | if (old != sta->tx_rate_idx) { | ||
2856 | switch (sta->tx_rate_idx) { | ||
2857 | case 0: sta->tx_rate = 10; break; | ||
2858 | case 1: sta->tx_rate = 20; break; | ||
2859 | case 2: sta->tx_rate = 55; break; | ||
2860 | case 3: sta->tx_rate = 110; break; | ||
2861 | default: sta->tx_rate = 0; break; | ||
2862 | } | ||
2863 | PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered " | ||
2864 | "to %d\n", local->dev->name, MAC2STR(sta->addr), | ||
2865 | sta->tx_rate); | ||
2866 | } | ||
2867 | sta->tx_consecutive_exc = 0; | ||
2868 | } | ||
2869 | spin_unlock(&local->ap->sta_table_lock); | ||
2870 | } | ||
2871 | |||
2872 | |||
2873 | static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, | ||
2874 | int pwrmgt, int type, int stype) | ||
2875 | { | ||
2876 | if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { | ||
2877 | sta->flags |= WLAN_STA_PS; | ||
2878 | PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS " | ||
2879 | "mode (type=0x%02X, stype=0x%02X)\n", | ||
2880 | MAC2STR(sta->addr), type >> 2, stype >> 4); | ||
2881 | } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { | ||
2882 | sta->flags &= ~WLAN_STA_PS; | ||
2883 | PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use " | ||
2884 | "PS mode (type=0x%02X, stype=0x%02X)\n", | ||
2885 | MAC2STR(sta->addr), type >> 2, stype >> 4); | ||
2886 | if (type != IEEE80211_FTYPE_CTL || | ||
2887 | stype != IEEE80211_STYPE_PSPOLL) | ||
2888 | schedule_packet_send(local, sta); | ||
2889 | } | ||
2890 | } | ||
2891 | |||
2892 | |||
2893 | /* Called only as a tasklet (software IRQ). Called for each RX frame to update | ||
2894 | * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ | ||
2895 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) | ||
2896 | { | ||
2897 | struct sta_info *sta; | ||
2898 | u16 fc; | ||
2899 | |||
2900 | spin_lock(&local->ap->sta_table_lock); | ||
2901 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2902 | if (sta) | ||
2903 | atomic_inc(&sta->users); | ||
2904 | spin_unlock(&local->ap->sta_table_lock); | ||
2905 | |||
2906 | if (!sta) | ||
2907 | return -1; | ||
2908 | |||
2909 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2910 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | ||
2911 | WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc)); | ||
2912 | |||
2913 | atomic_dec(&sta->users); | ||
2914 | return 0; | ||
2915 | } | ||
2916 | |||
2917 | |||
2918 | /* Called only as a tasklet (software IRQ). Called for each RX frame after | ||
2919 | * getting RX header and payload from hardware. */ | ||
2920 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
2921 | struct sk_buff *skb, | ||
2922 | struct hostap_80211_rx_status *rx_stats, | ||
2923 | int wds) | ||
2924 | { | ||
2925 | int ret; | ||
2926 | struct sta_info *sta; | ||
2927 | u16 fc, type, stype; | ||
2928 | struct ieee80211_hdr *hdr; | ||
2929 | |||
2930 | if (local->ap == NULL) | ||
2931 | return AP_RX_CONTINUE; | ||
2932 | |||
2933 | hdr = (struct ieee80211_hdr *) skb->data; | ||
2934 | |||
2935 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2936 | type = WLAN_FC_GET_TYPE(fc); | ||
2937 | stype = WLAN_FC_GET_STYPE(fc); | ||
2938 | |||
2939 | spin_lock(&local->ap->sta_table_lock); | ||
2940 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
2941 | if (sta) | ||
2942 | atomic_inc(&sta->users); | ||
2943 | spin_unlock(&local->ap->sta_table_lock); | ||
2944 | |||
2945 | if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) | ||
2946 | ret = AP_RX_CONTINUE_NOT_AUTHORIZED; | ||
2947 | else | ||
2948 | ret = AP_RX_CONTINUE; | ||
2949 | |||
2950 | |||
2951 | if (fc & IEEE80211_FCTL_TODS) { | ||
2952 | if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { | ||
2953 | if (local->hostapd) { | ||
2954 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2955 | PRISM2_RX_NON_ASSOC); | ||
2956 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2957 | } else { | ||
2958 | printk(KERN_DEBUG "%s: dropped received packet" | ||
2959 | " from non-associated STA " MACSTR | ||
2960 | " (type=0x%02x, subtype=0x%02x)\n", | ||
2961 | dev->name, MAC2STR(hdr->addr2), | ||
2962 | type >> 2, stype >> 4); | ||
2963 | hostap_rx(dev, skb, rx_stats); | ||
2964 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
2965 | } | ||
2966 | ret = AP_RX_EXIT; | ||
2967 | goto out; | ||
2968 | } | ||
2969 | } else if (fc & IEEE80211_FCTL_FROMDS) { | ||
2970 | if (!wds) { | ||
2971 | /* FromDS frame - not for us; probably | ||
2972 | * broadcast/multicast in another BSS - drop */ | ||
2973 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2974 | printk(KERN_DEBUG "Odd.. FromDS packet " | ||
2975 | "received with own BSSID\n"); | ||
2976 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
2977 | } | ||
2978 | ret = AP_RX_DROP; | ||
2979 | goto out; | ||
2980 | } | ||
2981 | } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && | ||
2982 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
2983 | |||
2984 | if (local->hostapd) { | ||
2985 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
2986 | PRISM2_RX_NON_ASSOC); | ||
2987 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
2988 | } else { | ||
2989 | /* At least Lucent f/w seems to send data::nullfunc | ||
2990 | * frames with no ToDS flag when the current AP returns | ||
2991 | * after being unavailable for some time. Speed up | ||
2992 | * re-association by informing the station about it not | ||
2993 | * being associated. */ | ||
2994 | printk(KERN_DEBUG "%s: rejected received nullfunc " | ||
2995 | "frame without ToDS from not associated STA " | ||
2996 | MACSTR "\n", | ||
2997 | dev->name, MAC2STR(hdr->addr2)); | ||
2998 | hostap_rx(dev, skb, rx_stats); | ||
2999 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3000 | } | ||
3001 | ret = AP_RX_EXIT; | ||
3002 | goto out; | ||
3003 | } else if (stype == IEEE80211_STYPE_NULLFUNC) { | ||
3004 | /* At least Lucent cards seem to send periodic nullfunc | ||
3005 | * frames with ToDS. Let these through to update SQ | ||
3006 | * stats and PS state. Nullfunc frames do not contain | ||
3007 | * any data and they will be dropped below. */ | ||
3008 | } else { | ||
3009 | /* If BSSID (Addr3) is foreign, this frame is a normal | ||
3010 | * broadcast frame from an IBSS network. Drop it silently. | ||
3011 | * If BSSID is own, report the dropping of this frame. */ | ||
3012 | if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
3013 | printk(KERN_DEBUG "%s: dropped received packet from " | ||
3014 | MACSTR " with no ToDS flag (type=0x%02x, " | ||
3015 | "subtype=0x%02x)\n", dev->name, | ||
3016 | MAC2STR(hdr->addr2), type >> 2, stype >> 4); | ||
3017 | hostap_dump_rx_80211(dev->name, skb, rx_stats); | ||
3018 | } | ||
3019 | ret = AP_RX_DROP; | ||
3020 | goto out; | ||
3021 | } | ||
3022 | |||
3023 | if (sta) { | ||
3024 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | ||
3025 | type, stype); | ||
3026 | |||
3027 | sta->rx_packets++; | ||
3028 | sta->rx_bytes += skb->len; | ||
3029 | sta->last_rx = jiffies; | ||
3030 | } | ||
3031 | |||
3032 | if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && | ||
3033 | fc & IEEE80211_FCTL_TODS) { | ||
3034 | if (local->hostapd) { | ||
3035 | prism2_rx_80211(local->apdev, skb, rx_stats, | ||
3036 | PRISM2_RX_NULLFUNC_ACK); | ||
3037 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3038 | } else { | ||
3039 | /* some STA f/w's seem to require control::ACK frame | ||
3040 | * for data::nullfunc, but Prism2 f/w 0.8.0 (at least | ||
3041 | * from Compaq) does not send this.. Try to generate | ||
3042 | * ACK for these frames from the host driver to make | ||
3043 | * power saving work with, e.g., Lucent WaveLAN f/w */ | ||
3044 | hostap_rx(dev, skb, rx_stats); | ||
3045 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3046 | } | ||
3047 | ret = AP_RX_EXIT; | ||
3048 | goto out; | ||
3049 | } | ||
3050 | |||
3051 | out: | ||
3052 | if (sta) | ||
3053 | atomic_dec(&sta->users); | ||
3054 | |||
3055 | return ret; | ||
3056 | } | ||
3057 | |||
3058 | |||
3059 | /* Called only as a tasklet (software IRQ) */ | ||
3060 | int hostap_handle_sta_crypto(local_info_t *local, | ||
3061 | struct ieee80211_hdr *hdr, | ||
3062 | struct ieee80211_crypt_data **crypt, | ||
3063 | void **sta_ptr) | ||
3064 | { | ||
3065 | struct sta_info *sta; | ||
3066 | |||
3067 | spin_lock(&local->ap->sta_table_lock); | ||
3068 | sta = ap_get_sta(local->ap, hdr->addr2); | ||
3069 | if (sta) | ||
3070 | atomic_inc(&sta->users); | ||
3071 | spin_unlock(&local->ap->sta_table_lock); | ||
3072 | |||
3073 | if (!sta) | ||
3074 | return -1; | ||
3075 | |||
3076 | if (sta->crypt) { | ||
3077 | *crypt = sta->crypt; | ||
3078 | *sta_ptr = sta; | ||
3079 | /* hostap_handle_sta_release() will be called to release STA | ||
3080 | * info */ | ||
3081 | } else | ||
3082 | atomic_dec(&sta->users); | ||
3083 | |||
3084 | return 0; | ||
3085 | } | ||
3086 | |||
3087 | |||
3088 | /* Called only as a tasklet (software IRQ) */ | ||
3089 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) | ||
3090 | { | ||
3091 | struct sta_info *sta; | ||
3092 | int ret = 0; | ||
3093 | |||
3094 | spin_lock(&ap->sta_table_lock); | ||
3095 | sta = ap_get_sta(ap, sta_addr); | ||
3096 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) | ||
3097 | ret = 1; | ||
3098 | spin_unlock(&ap->sta_table_lock); | ||
3099 | |||
3100 | return ret; | ||
3101 | } | ||
3102 | |||
3103 | |||
3104 | /* Called only as a tasklet (software IRQ) */ | ||
3105 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) | ||
3106 | { | ||
3107 | struct sta_info *sta; | ||
3108 | int ret = 0; | ||
3109 | |||
3110 | spin_lock(&ap->sta_table_lock); | ||
3111 | sta = ap_get_sta(ap, sta_addr); | ||
3112 | if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && | ||
3113 | ((sta->flags & WLAN_STA_AUTHORIZED) || | ||
3114 | ap->local->ieee_802_1x == 0)) | ||
3115 | ret = 1; | ||
3116 | spin_unlock(&ap->sta_table_lock); | ||
3117 | |||
3118 | return ret; | ||
3119 | } | ||
3120 | |||
3121 | |||
3122 | /* Called only as a tasklet (software IRQ) */ | ||
3123 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) | ||
3124 | { | ||
3125 | struct sta_info *sta; | ||
3126 | int ret = 1; | ||
3127 | |||
3128 | if (!ap) | ||
3129 | return -1; | ||
3130 | |||
3131 | spin_lock(&ap->sta_table_lock); | ||
3132 | sta = ap_get_sta(ap, sta_addr); | ||
3133 | if (sta) | ||
3134 | ret = 0; | ||
3135 | spin_unlock(&ap->sta_table_lock); | ||
3136 | |||
3137 | if (ret == 1) { | ||
3138 | sta = ap_add_sta(ap, sta_addr); | ||
3139 | if (!sta) | ||
3140 | ret = -1; | ||
3141 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | ||
3142 | sta->ap = 1; | ||
3143 | memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | ||
3144 | /* No way of knowing which rates are supported since we did not | ||
3145 | * get supported rates element from beacon/assoc req. Assume | ||
3146 | * that remote end supports all 802.11b rates. */ | ||
3147 | sta->supported_rates[0] = 0x82; | ||
3148 | sta->supported_rates[1] = 0x84; | ||
3149 | sta->supported_rates[2] = 0x0b; | ||
3150 | sta->supported_rates[3] = 0x16; | ||
3151 | sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | | ||
3152 | WLAN_RATE_5M5 | WLAN_RATE_11M; | ||
3153 | sta->tx_rate = 110; | ||
3154 | sta->tx_max_rate = sta->tx_rate_idx = 3; | ||
3155 | } | ||
3156 | |||
3157 | return ret; | ||
3158 | } | ||
3159 | |||
3160 | |||
3161 | /* Called only as a tasklet (software IRQ) */ | ||
3162 | int hostap_update_rx_stats(struct ap_data *ap, | ||
3163 | struct ieee80211_hdr *hdr, | ||
3164 | struct hostap_80211_rx_status *rx_stats) | ||
3165 | { | ||
3166 | struct sta_info *sta; | ||
3167 | |||
3168 | if (!ap) | ||
3169 | return -1; | ||
3170 | |||
3171 | spin_lock(&ap->sta_table_lock); | ||
3172 | sta = ap_get_sta(ap, hdr->addr2); | ||
3173 | if (sta) { | ||
3174 | sta->last_rx_silence = rx_stats->noise; | ||
3175 | sta->last_rx_signal = rx_stats->signal; | ||
3176 | sta->last_rx_rate = rx_stats->rate; | ||
3177 | sta->last_rx_updated = 7; | ||
3178 | if (rx_stats->rate == 10) | ||
3179 | sta->rx_count[0]++; | ||
3180 | else if (rx_stats->rate == 20) | ||
3181 | sta->rx_count[1]++; | ||
3182 | else if (rx_stats->rate == 55) | ||
3183 | sta->rx_count[2]++; | ||
3184 | else if (rx_stats->rate == 110) | ||
3185 | sta->rx_count[3]++; | ||
3186 | } | ||
3187 | spin_unlock(&ap->sta_table_lock); | ||
3188 | |||
3189 | return sta ? 0 : -1; | ||
3190 | } | ||
3191 | |||
3192 | |||
3193 | void hostap_update_rates(local_info_t *local) | ||
3194 | { | ||
3195 | struct list_head *ptr; | ||
3196 | struct ap_data *ap = local->ap; | ||
3197 | |||
3198 | if (!ap) | ||
3199 | return; | ||
3200 | |||
3201 | spin_lock_bh(&ap->sta_table_lock); | ||
3202 | for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { | ||
3203 | struct sta_info *sta = (struct sta_info *) ptr; | ||
3204 | prism2_check_tx_rates(sta); | ||
3205 | } | ||
3206 | spin_unlock_bh(&ap->sta_table_lock); | ||
3207 | } | ||
3208 | |||
3209 | |||
3210 | static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | ||
3211 | struct ieee80211_crypt_data ***crypt) | ||
3212 | { | ||
3213 | struct sta_info *sta; | ||
3214 | |||
3215 | spin_lock_bh(&ap->sta_table_lock); | ||
3216 | sta = ap_get_sta(ap, addr); | ||
3217 | if (sta) | ||
3218 | atomic_inc(&sta->users); | ||
3219 | spin_unlock_bh(&ap->sta_table_lock); | ||
3220 | |||
3221 | if (!sta && permanent) | ||
3222 | sta = ap_add_sta(ap, addr); | ||
3223 | |||
3224 | if (!sta) | ||
3225 | return NULL; | ||
3226 | |||
3227 | if (permanent) | ||
3228 | sta->flags |= WLAN_STA_PERM; | ||
3229 | |||
3230 | *crypt = &sta->crypt; | ||
3231 | |||
3232 | return sta; | ||
3233 | } | ||
3234 | |||
3235 | |||
3236 | void hostap_add_wds_links(local_info_t *local) | ||
3237 | { | ||
3238 | struct ap_data *ap = local->ap; | ||
3239 | struct list_head *ptr; | ||
3240 | |||
3241 | spin_lock_bh(&ap->sta_table_lock); | ||
3242 | list_for_each(ptr, &ap->sta_list) { | ||
3243 | struct sta_info *sta = list_entry(ptr, struct sta_info, list); | ||
3244 | if (sta->ap) | ||
3245 | hostap_wds_link_oper(local, sta->addr, WDS_ADD); | ||
3246 | } | ||
3247 | spin_unlock_bh(&ap->sta_table_lock); | ||
3248 | |||
3249 | schedule_work(&local->ap->wds_oper_queue); | ||
3250 | } | ||
3251 | |||
3252 | |||
3253 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) | ||
3254 | { | ||
3255 | struct wds_oper_data *entry; | ||
3256 | |||
3257 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
3258 | if (!entry) | ||
3259 | return; | ||
3260 | memcpy(entry->addr, addr, ETH_ALEN); | ||
3261 | entry->type = type; | ||
3262 | spin_lock_bh(&local->lock); | ||
3263 | entry->next = local->ap->wds_oper_entries; | ||
3264 | local->ap->wds_oper_entries = entry; | ||
3265 | spin_unlock_bh(&local->lock); | ||
3266 | |||
3267 | schedule_work(&local->ap->wds_oper_queue); | ||
3268 | } | ||
3269 | |||
3270 | |||
3271 | EXPORT_SYMBOL(hostap_init_data); | ||
3272 | EXPORT_SYMBOL(hostap_init_ap_proc); | ||
3273 | EXPORT_SYMBOL(hostap_free_data); | ||
3274 | EXPORT_SYMBOL(hostap_check_sta_fw_version); | ||
3275 | EXPORT_SYMBOL(hostap_handle_sta_tx); | ||
3276 | EXPORT_SYMBOL(hostap_handle_sta_release); | ||
3277 | EXPORT_SYMBOL(hostap_handle_sta_tx_exc); | ||
3278 | EXPORT_SYMBOL(hostap_update_sta_ps); | ||
3279 | EXPORT_SYMBOL(hostap_handle_sta_rx); | ||
3280 | EXPORT_SYMBOL(hostap_is_sta_assoc); | ||
3281 | EXPORT_SYMBOL(hostap_is_sta_authorized); | ||
3282 | EXPORT_SYMBOL(hostap_add_sta); | ||
3283 | EXPORT_SYMBOL(hostap_update_rates); | ||
3284 | EXPORT_SYMBOL(hostap_add_wds_links); | ||
3285 | EXPORT_SYMBOL(hostap_wds_link_oper); | ||
3286 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3287 | EXPORT_SYMBOL(hostap_deauth_all_stas); | ||
3288 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h new file mode 100644 index 000000000000..816a52bcea8f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ap.h | |||
@@ -0,0 +1,261 @@ | |||
1 | #ifndef HOSTAP_AP_H | ||
2 | #define HOSTAP_AP_H | ||
3 | |||
4 | /* AP data structures for STAs */ | ||
5 | |||
6 | /* maximum number of frames to buffer per STA */ | ||
7 | #define STA_MAX_TX_BUFFER 32 | ||
8 | |||
9 | /* STA flags */ | ||
10 | #define WLAN_STA_AUTH BIT(0) | ||
11 | #define WLAN_STA_ASSOC BIT(1) | ||
12 | #define WLAN_STA_PS BIT(2) | ||
13 | #define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ | ||
14 | #define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ | ||
15 | #define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is | ||
16 | * controlling whether STA is authorized to | ||
17 | * send and receive non-IEEE 802.1X frames | ||
18 | */ | ||
19 | #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ | ||
20 | |||
21 | #define WLAN_RATE_1M BIT(0) | ||
22 | #define WLAN_RATE_2M BIT(1) | ||
23 | #define WLAN_RATE_5M5 BIT(2) | ||
24 | #define WLAN_RATE_11M BIT(3) | ||
25 | #define WLAN_RATE_COUNT 4 | ||
26 | |||
27 | /* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, | ||
28 | * but some pre-standard IEEE 802.11g products use longer elements. */ | ||
29 | #define WLAN_SUPP_RATES_MAX 32 | ||
30 | |||
31 | /* Try to increase TX rate after # successfully sent consecutive packets */ | ||
32 | #define WLAN_RATE_UPDATE_COUNT 50 | ||
33 | |||
34 | /* Decrease TX rate after # consecutive dropped packets */ | ||
35 | #define WLAN_RATE_DECREASE_THRESHOLD 2 | ||
36 | |||
37 | struct sta_info { | ||
38 | struct list_head list; | ||
39 | struct sta_info *hnext; /* next entry in hash table list */ | ||
40 | atomic_t users; /* number of users (do not remove if > 0) */ | ||
41 | struct proc_dir_entry *proc; | ||
42 | |||
43 | u8 addr[6]; | ||
44 | u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ | ||
45 | u32 flags; | ||
46 | u16 capability; | ||
47 | u16 listen_interval; /* or beacon_int for APs */ | ||
48 | u8 supported_rates[WLAN_SUPP_RATES_MAX]; | ||
49 | |||
50 | unsigned long last_auth; | ||
51 | unsigned long last_assoc; | ||
52 | unsigned long last_rx; | ||
53 | unsigned long last_tx; | ||
54 | unsigned long rx_packets, tx_packets; | ||
55 | unsigned long rx_bytes, tx_bytes; | ||
56 | struct sk_buff_head tx_buf; | ||
57 | /* FIX: timeout buffers with an expiry time somehow derived from | ||
58 | * listen_interval */ | ||
59 | |||
60 | s8 last_rx_silence; /* Noise in dBm */ | ||
61 | s8 last_rx_signal; /* Signal strength in dBm */ | ||
62 | u8 last_rx_rate; /* TX rate in 0.1 Mbps */ | ||
63 | u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ | ||
64 | |||
65 | u8 tx_supp_rates; /* bit field of supported TX rates */ | ||
66 | u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ | ||
67 | u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ | ||
68 | u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ | ||
69 | u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ | ||
70 | u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) | ||
71 | */ | ||
72 | u32 tx_since_last_failure; | ||
73 | u32 tx_consecutive_exc; | ||
74 | |||
75 | struct ieee80211_crypt_data *crypt; | ||
76 | |||
77 | int ap; /* whether this station is an AP */ | ||
78 | |||
79 | local_info_t *local; | ||
80 | |||
81 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
82 | union { | ||
83 | struct { | ||
84 | char *challenge; /* shared key authentication | ||
85 | * challenge */ | ||
86 | } sta; | ||
87 | struct { | ||
88 | int ssid_len; | ||
89 | unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ | ||
90 | int channel; | ||
91 | unsigned long last_beacon; /* last RX beacon time */ | ||
92 | } ap; | ||
93 | } u; | ||
94 | |||
95 | struct timer_list timer; | ||
96 | enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; | ||
97 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
98 | }; | ||
99 | |||
100 | |||
101 | #define MAX_STA_COUNT 1024 | ||
102 | |||
103 | /* Maximum number of AIDs to use for STAs; must be 2007 or lower | ||
104 | * (8802.11 limitation) */ | ||
105 | #define MAX_AID_TABLE_SIZE 128 | ||
106 | |||
107 | #define STA_HASH_SIZE 256 | ||
108 | #define STA_HASH(sta) (sta[5]) | ||
109 | |||
110 | |||
111 | /* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC | ||
112 | * has passed since last received frame from the station, a nullfunc data | ||
113 | * frame is sent to the station. If this frame is not acknowledged and no other | ||
114 | * frames have been received, the station will be disassociated after | ||
115 | * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after | ||
116 | * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with | ||
117 | * max inactivity timer. */ | ||
118 | #define AP_MAX_INACTIVITY_SEC (5 * 60) | ||
119 | #define AP_DISASSOC_DELAY (HZ) | ||
120 | #define AP_DEAUTH_DELAY (HZ) | ||
121 | |||
122 | /* ap_policy: whether to accept frames to/from other APs/IBSS */ | ||
123 | typedef enum { | ||
124 | AP_OTHER_AP_SKIP_ALL = 0, | ||
125 | AP_OTHER_AP_SAME_SSID = 1, | ||
126 | AP_OTHER_AP_ALL = 2, | ||
127 | AP_OTHER_AP_EVEN_IBSS = 3 | ||
128 | } ap_policy_enum; | ||
129 | |||
130 | #define PRISM2_AUTH_OPEN BIT(0) | ||
131 | #define PRISM2_AUTH_SHARED_KEY BIT(1) | ||
132 | |||
133 | |||
134 | /* MAC address-based restrictions */ | ||
135 | struct mac_entry { | ||
136 | struct list_head list; | ||
137 | u8 addr[6]; | ||
138 | }; | ||
139 | |||
140 | struct mac_restrictions { | ||
141 | enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; | ||
142 | unsigned int entries; | ||
143 | struct list_head mac_list; | ||
144 | spinlock_t lock; | ||
145 | }; | ||
146 | |||
147 | |||
148 | struct add_sta_proc_data { | ||
149 | u8 addr[ETH_ALEN]; | ||
150 | struct add_sta_proc_data *next; | ||
151 | }; | ||
152 | |||
153 | |||
154 | typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; | ||
155 | struct wds_oper_data { | ||
156 | wds_oper_type type; | ||
157 | u8 addr[ETH_ALEN]; | ||
158 | struct wds_oper_data *next; | ||
159 | }; | ||
160 | |||
161 | |||
162 | struct ap_data { | ||
163 | int initialized; /* whether ap_data has been initialized */ | ||
164 | local_info_t *local; | ||
165 | int bridge_packets; /* send packet to associated STAs directly to the | ||
166 | * wireless media instead of higher layers in the | ||
167 | * kernel */ | ||
168 | unsigned int bridged_unicast; /* number of unicast frames bridged on | ||
169 | * wireless media */ | ||
170 | unsigned int bridged_multicast; /* number of non-unicast frames | ||
171 | * bridged on wireless media */ | ||
172 | unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped | ||
173 | * because they were to an address that | ||
174 | * was not associated */ | ||
175 | int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ | ||
176 | |||
177 | spinlock_t sta_table_lock; | ||
178 | int num_sta; /* number of entries in sta_list */ | ||
179 | struct list_head sta_list; /* STA info list head */ | ||
180 | struct sta_info *sta_hash[STA_HASH_SIZE]; | ||
181 | |||
182 | struct proc_dir_entry *proc; | ||
183 | |||
184 | ap_policy_enum ap_policy; | ||
185 | unsigned int max_inactivity; | ||
186 | int autom_ap_wds; | ||
187 | |||
188 | struct mac_restrictions mac_restrictions; /* MAC-based auth */ | ||
189 | int last_tx_rate; | ||
190 | |||
191 | struct work_struct add_sta_proc_queue; | ||
192 | struct add_sta_proc_data *add_sta_proc_entries; | ||
193 | |||
194 | struct work_struct wds_oper_queue; | ||
195 | struct wds_oper_data *wds_oper_entries; | ||
196 | |||
197 | u16 tx_callback_idx; | ||
198 | |||
199 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
200 | /* pointers to STA info; based on allocated AID or NULL if AID free | ||
201 | * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 | ||
202 | * and so on | ||
203 | */ | ||
204 | struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; | ||
205 | |||
206 | u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; | ||
207 | |||
208 | /* WEP operations for generating challenges to be used with shared key | ||
209 | * authentication */ | ||
210 | struct ieee80211_crypto_ops *crypt; | ||
211 | void *crypt_priv; | ||
212 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
213 | }; | ||
214 | |||
215 | |||
216 | void hostap_rx(struct net_device *dev, struct sk_buff *skb, | ||
217 | struct hostap_80211_rx_status *rx_stats); | ||
218 | void hostap_init_data(local_info_t *local); | ||
219 | void hostap_init_ap_proc(local_info_t *local); | ||
220 | void hostap_free_data(struct ap_data *ap); | ||
221 | void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); | ||
222 | |||
223 | typedef enum { | ||
224 | AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, | ||
225 | AP_TX_CONTINUE_NOT_AUTHORIZED | ||
226 | } ap_tx_ret; | ||
227 | struct hostap_tx_data { | ||
228 | struct sk_buff *skb; | ||
229 | int host_encrypt; | ||
230 | struct ieee80211_crypt_data *crypt; | ||
231 | void *sta_ptr; | ||
232 | }; | ||
233 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); | ||
234 | void hostap_handle_sta_release(void *ptr); | ||
235 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); | ||
236 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); | ||
237 | typedef enum { | ||
238 | AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED | ||
239 | } ap_rx_ret; | ||
240 | ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | ||
241 | struct sk_buff *skb, | ||
242 | struct hostap_80211_rx_status *rx_stats, | ||
243 | int wds); | ||
244 | int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, | ||
245 | struct ieee80211_crypt_data **crypt, | ||
246 | void **sta_ptr); | ||
247 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); | ||
248 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); | ||
249 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); | ||
250 | int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, | ||
251 | struct hostap_80211_rx_status *rx_stats); | ||
252 | void hostap_update_rates(local_info_t *local); | ||
253 | void hostap_add_wds_links(local_info_t *local); | ||
254 | void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); | ||
255 | |||
256 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
257 | void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | ||
258 | int resend); | ||
259 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
260 | |||
261 | #endif /* HOSTAP_AP_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h new file mode 100644 index 000000000000..6f4fa9dc308f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_common.h | |||
@@ -0,0 +1,435 @@ | |||
1 | #ifndef HOSTAP_COMMON_H | ||
2 | #define HOSTAP_COMMON_H | ||
3 | |||
4 | #define BIT(x) (1 << (x)) | ||
5 | |||
6 | #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] | ||
7 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" | ||
8 | |||
9 | |||
10 | /* IEEE 802.11 defines */ | ||
11 | |||
12 | /* Information Element IDs */ | ||
13 | #define WLAN_EID_SSID 0 | ||
14 | #define WLAN_EID_SUPP_RATES 1 | ||
15 | #define WLAN_EID_FH_PARAMS 2 | ||
16 | #define WLAN_EID_DS_PARAMS 3 | ||
17 | #define WLAN_EID_CF_PARAMS 4 | ||
18 | #define WLAN_EID_TIM 5 | ||
19 | #define WLAN_EID_IBSS_PARAMS 6 | ||
20 | #define WLAN_EID_CHALLENGE 16 | ||
21 | #define WLAN_EID_RSN 48 | ||
22 | #define WLAN_EID_GENERIC 221 | ||
23 | |||
24 | |||
25 | /* HFA384X Configuration RIDs */ | ||
26 | #define HFA384X_RID_CNFPORTTYPE 0xFC00 | ||
27 | #define HFA384X_RID_CNFOWNMACADDR 0xFC01 | ||
28 | #define HFA384X_RID_CNFDESIREDSSID 0xFC02 | ||
29 | #define HFA384X_RID_CNFOWNCHANNEL 0xFC03 | ||
30 | #define HFA384X_RID_CNFOWNSSID 0xFC04 | ||
31 | #define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 | ||
32 | #define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 | ||
33 | #define HFA384X_RID_CNFMAXDATALEN 0xFC07 | ||
34 | #define HFA384X_RID_CNFWDSADDRESS 0xFC08 | ||
35 | #define HFA384X_RID_CNFPMENABLED 0xFC09 | ||
36 | #define HFA384X_RID_CNFPMEPS 0xFC0A | ||
37 | #define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B | ||
38 | #define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C | ||
39 | #define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D | ||
40 | #define HFA384X_RID_CNFOWNNAME 0xFC0E | ||
41 | #define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 | ||
42 | #define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ | ||
43 | #define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ | ||
44 | #define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ | ||
45 | #define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ | ||
46 | #define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ | ||
47 | #define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ | ||
48 | #define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ | ||
49 | #define HFA384X_RID_UNKNOWN1 0xFC20 | ||
50 | #define HFA384X_RID_UNKNOWN2 0xFC21 | ||
51 | #define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 | ||
52 | #define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 | ||
53 | #define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 | ||
54 | #define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 | ||
55 | #define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 | ||
56 | #define HFA384X_RID_CNFWEPFLAGS 0xFC28 | ||
57 | #define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 | ||
58 | #define HFA384X_RID_CNFAUTHENTICATION 0xFC2A | ||
59 | #define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ | ||
60 | #define HFA384X_RID_CNFTXCONTROL 0xFC2C | ||
61 | #define HFA384X_RID_CNFROAMINGMODE 0xFC2D | ||
62 | #define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ | ||
63 | #define HFA384X_RID_CNFRCVCRCERROR 0xFC30 | ||
64 | #define HFA384X_RID_CNFMMLIFE 0xFC31 | ||
65 | #define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 | ||
66 | #define HFA384X_RID_CNFBEACONINT 0xFC33 | ||
67 | #define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ | ||
68 | #define HFA384X_RID_CNFSTAPCFINFO 0xFC35 | ||
69 | #define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 | ||
70 | #define HFA384X_RID_CNFTIMCTRL 0xFC40 | ||
71 | #define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ | ||
72 | #define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ | ||
73 | #define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ | ||
74 | #define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ | ||
75 | #define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; | ||
76 | * write only */ | ||
77 | #define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ | ||
78 | #define HFA384X_RID_GROUPADDRESSES 0xFC80 | ||
79 | #define HFA384X_RID_CREATEIBSS 0xFC81 | ||
80 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 | ||
81 | #define HFA384X_RID_RTSTHRESHOLD 0xFC83 | ||
82 | #define HFA384X_RID_TXRATECONTROL 0xFC84 | ||
83 | #define HFA384X_RID_PROMISCUOUSMODE 0xFC85 | ||
84 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ | ||
85 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ | ||
86 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ | ||
87 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ | ||
88 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ | ||
89 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ | ||
90 | #define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ | ||
91 | #define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ | ||
92 | #define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ | ||
93 | #define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ | ||
94 | #define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ | ||
95 | #define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ | ||
96 | #define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ | ||
97 | #define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ | ||
98 | #define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ | ||
99 | #define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ | ||
100 | #define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ | ||
101 | #define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ | ||
102 | #define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ | ||
103 | #define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ | ||
104 | #define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ | ||
105 | #define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 | ||
106 | #define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 | ||
107 | #define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 | ||
108 | #define HFA384X_RID_CNFBASICRATES 0xFCB3 | ||
109 | #define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 | ||
110 | #define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ | ||
111 | #define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ | ||
112 | #define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ | ||
113 | #define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ | ||
114 | #define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ | ||
115 | #define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ | ||
116 | #define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ | ||
117 | #define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ | ||
118 | #define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ | ||
119 | #define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ | ||
120 | #define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ | ||
121 | #define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ | ||
122 | #define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ | ||
123 | #define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ | ||
124 | #define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ | ||
125 | #define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ | ||
126 | #define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ | ||
127 | #define HFA384X_RID_TICKTIME 0xFCE0 | ||
128 | #define HFA384X_RID_SCANREQUEST 0xFCE1 | ||
129 | #define HFA384X_RID_JOINREQUEST 0xFCE2 | ||
130 | #define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ | ||
131 | #define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ | ||
132 | #define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ | ||
133 | |||
134 | /* HFA384X Information RIDs */ | ||
135 | #define HFA384X_RID_MAXLOADTIME 0xFD00 | ||
136 | #define HFA384X_RID_DOWNLOADBUFFER 0xFD01 | ||
137 | #define HFA384X_RID_PRIID 0xFD02 | ||
138 | #define HFA384X_RID_PRISUPRANGE 0xFD03 | ||
139 | #define HFA384X_RID_CFIACTRANGES 0xFD04 | ||
140 | #define HFA384X_RID_NICSERNUM 0xFD0A | ||
141 | #define HFA384X_RID_NICID 0xFD0B | ||
142 | #define HFA384X_RID_MFISUPRANGE 0xFD0C | ||
143 | #define HFA384X_RID_CFISUPRANGE 0xFD0D | ||
144 | #define HFA384X_RID_CHANNELLIST 0xFD10 | ||
145 | #define HFA384X_RID_REGULATORYDOMAINS 0xFD11 | ||
146 | #define HFA384X_RID_TEMPTYPE 0xFD12 | ||
147 | #define HFA384X_RID_CIS 0xFD13 | ||
148 | #define HFA384X_RID_STAID 0xFD20 | ||
149 | #define HFA384X_RID_STASUPRANGE 0xFD21 | ||
150 | #define HFA384X_RID_MFIACTRANGES 0xFD22 | ||
151 | #define HFA384X_RID_CFIACTRANGES2 0xFD23 | ||
152 | #define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; | ||
153 | * only Prism2.5(?) */ | ||
154 | #define HFA384X_RID_PORTSTATUS 0xFD40 | ||
155 | #define HFA384X_RID_CURRENTSSID 0xFD41 | ||
156 | #define HFA384X_RID_CURRENTBSSID 0xFD42 | ||
157 | #define HFA384X_RID_COMMSQUALITY 0xFD43 | ||
158 | #define HFA384X_RID_CURRENTTXRATE 0xFD44 | ||
159 | #define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 | ||
160 | #define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 | ||
161 | #define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 | ||
162 | #define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 | ||
163 | #define HFA384X_RID_LONGRETRYLIMIT 0xFD49 | ||
164 | #define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A | ||
165 | #define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B | ||
166 | #define HFA384X_RID_CFPOLLABLE 0xFD4C | ||
167 | #define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D | ||
168 | #define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F | ||
169 | #define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ | ||
170 | #define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ | ||
171 | #define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ | ||
172 | #define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ | ||
173 | #define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ | ||
174 | #define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ | ||
175 | #define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ | ||
176 | #define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ | ||
177 | #define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ | ||
178 | #define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ | ||
179 | #define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ | ||
180 | #define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ | ||
181 | #define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ | ||
182 | #define HFA384X_RID_PHYTYPE 0xFDC0 | ||
183 | #define HFA384X_RID_CURRENTCHANNEL 0xFDC1 | ||
184 | #define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 | ||
185 | #define HFA384X_RID_CCAMODE 0xFDC3 | ||
186 | #define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 | ||
187 | #define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ | ||
188 | #define HFA384X_RID_BUILDSEQ 0xFFFE | ||
189 | #define HFA384X_RID_FWID 0xFFFF | ||
190 | |||
191 | |||
192 | struct hfa384x_comp_ident | ||
193 | { | ||
194 | u16 id; | ||
195 | u16 variant; | ||
196 | u16 major; | ||
197 | u16 minor; | ||
198 | } __attribute__ ((packed)); | ||
199 | |||
200 | #define HFA384X_COMP_ID_PRI 0x15 | ||
201 | #define HFA384X_COMP_ID_STA 0x1f | ||
202 | #define HFA384X_COMP_ID_FW_AP 0x14b | ||
203 | |||
204 | struct hfa384x_sup_range | ||
205 | { | ||
206 | u16 role; | ||
207 | u16 id; | ||
208 | u16 variant; | ||
209 | u16 bottom; | ||
210 | u16 top; | ||
211 | } __attribute__ ((packed)); | ||
212 | |||
213 | |||
214 | struct hfa384x_build_id | ||
215 | { | ||
216 | u16 pri_seq; | ||
217 | u16 sec_seq; | ||
218 | } __attribute__ ((packed)); | ||
219 | |||
220 | /* FD01 - Download Buffer */ | ||
221 | struct hfa384x_rid_download_buffer | ||
222 | { | ||
223 | u16 page; | ||
224 | u16 offset; | ||
225 | u16 length; | ||
226 | } __attribute__ ((packed)); | ||
227 | |||
228 | /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ | ||
229 | struct hfa384x_comms_quality { | ||
230 | u16 comm_qual; /* 0 .. 92 */ | ||
231 | u16 signal_level; /* 27 .. 154 */ | ||
232 | u16 noise_level; /* 27 .. 154 */ | ||
233 | } __attribute__ ((packed)); | ||
234 | |||
235 | |||
236 | /* netdevice private ioctls (used, e.g., with iwpriv from user space) */ | ||
237 | |||
238 | /* New wireless extensions API - SET/GET convention (even ioctl numbers are | ||
239 | * root only) | ||
240 | */ | ||
241 | #define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) | ||
242 | #define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) | ||
243 | #define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) | ||
244 | #define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) | ||
245 | #define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) | ||
246 | #define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) | ||
247 | #define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) | ||
248 | #define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) | ||
249 | #define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) | ||
250 | #define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) | ||
251 | #define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) | ||
252 | #define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) | ||
253 | #define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) | ||
254 | #define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) | ||
255 | |||
256 | /* following are not in SIOCGIWPRIV list; check permission in the driver code | ||
257 | */ | ||
258 | #define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) | ||
259 | #define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) | ||
260 | |||
261 | |||
262 | /* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ | ||
263 | enum { | ||
264 | /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ | ||
265 | PRISM2_PARAM_TXRATECTRL = 2, | ||
266 | PRISM2_PARAM_BEACON_INT = 3, | ||
267 | PRISM2_PARAM_PSEUDO_IBSS = 4, | ||
268 | PRISM2_PARAM_ALC = 5, | ||
269 | /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ | ||
270 | PRISM2_PARAM_DUMP = 7, | ||
271 | PRISM2_PARAM_OTHER_AP_POLICY = 8, | ||
272 | PRISM2_PARAM_AP_MAX_INACTIVITY = 9, | ||
273 | PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, | ||
274 | PRISM2_PARAM_DTIM_PERIOD = 11, | ||
275 | PRISM2_PARAM_AP_NULLFUNC_ACK = 12, | ||
276 | PRISM2_PARAM_MAX_WDS = 13, | ||
277 | PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, | ||
278 | PRISM2_PARAM_AP_AUTH_ALGS = 15, | ||
279 | PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, | ||
280 | PRISM2_PARAM_HOST_ENCRYPT = 17, | ||
281 | PRISM2_PARAM_HOST_DECRYPT = 18, | ||
282 | /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ | ||
283 | /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ | ||
284 | PRISM2_PARAM_HOST_ROAMING = 21, | ||
285 | PRISM2_PARAM_BCRX_STA_KEY = 22, | ||
286 | PRISM2_PARAM_IEEE_802_1X = 23, | ||
287 | PRISM2_PARAM_ANTSEL_TX = 24, | ||
288 | PRISM2_PARAM_ANTSEL_RX = 25, | ||
289 | PRISM2_PARAM_MONITOR_TYPE = 26, | ||
290 | PRISM2_PARAM_WDS_TYPE = 27, | ||
291 | PRISM2_PARAM_HOSTSCAN = 28, | ||
292 | PRISM2_PARAM_AP_SCAN = 29, | ||
293 | PRISM2_PARAM_ENH_SEC = 30, | ||
294 | PRISM2_PARAM_IO_DEBUG = 31, | ||
295 | PRISM2_PARAM_BASIC_RATES = 32, | ||
296 | PRISM2_PARAM_OPER_RATES = 33, | ||
297 | PRISM2_PARAM_HOSTAPD = 34, | ||
298 | PRISM2_PARAM_HOSTAPD_STA = 35, | ||
299 | PRISM2_PARAM_WPA = 36, | ||
300 | PRISM2_PARAM_PRIVACY_INVOKED = 37, | ||
301 | PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, | ||
302 | PRISM2_PARAM_DROP_UNENCRYPTED = 39, | ||
303 | PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, | ||
304 | }; | ||
305 | |||
306 | enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, | ||
307 | HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; | ||
308 | |||
309 | |||
310 | /* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ | ||
311 | enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, | ||
312 | AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, | ||
313 | AP_MAC_CMD_KICKALL = 4 }; | ||
314 | |||
315 | |||
316 | /* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ | ||
317 | enum { | ||
318 | PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, | ||
319 | /* Note! Old versions of prism2_srec have a fatal error in CRC-16 | ||
320 | * calculation, which will corrupt all non-volatile downloads. | ||
321 | * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to | ||
322 | * prevent use of old versions of prism2_srec for non-volatile | ||
323 | * download. */ | ||
324 | PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, | ||
325 | PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, | ||
326 | /* Persistent versions of volatile download commands (keep firmware | ||
327 | * data in memory and automatically re-download after hw_reset */ | ||
328 | PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, | ||
329 | PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, | ||
330 | }; | ||
331 | |||
332 | struct prism2_download_param { | ||
333 | u32 dl_cmd; | ||
334 | u32 start_addr; | ||
335 | u32 num_areas; | ||
336 | struct prism2_download_area { | ||
337 | u32 addr; /* wlan card address */ | ||
338 | u32 len; | ||
339 | void __user *ptr; /* pointer to data in user space */ | ||
340 | } data[0]; | ||
341 | }; | ||
342 | |||
343 | #define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 | ||
344 | #define PRISM2_MAX_DOWNLOAD_LEN 262144 | ||
345 | |||
346 | |||
347 | /* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ | ||
348 | enum { | ||
349 | PRISM2_HOSTAPD_FLUSH = 1, | ||
350 | PRISM2_HOSTAPD_ADD_STA = 2, | ||
351 | PRISM2_HOSTAPD_REMOVE_STA = 3, | ||
352 | PRISM2_HOSTAPD_GET_INFO_STA = 4, | ||
353 | /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ | ||
354 | PRISM2_SET_ENCRYPTION = 6, | ||
355 | PRISM2_GET_ENCRYPTION = 7, | ||
356 | PRISM2_HOSTAPD_SET_FLAGS_STA = 8, | ||
357 | PRISM2_HOSTAPD_GET_RID = 9, | ||
358 | PRISM2_HOSTAPD_SET_RID = 10, | ||
359 | PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, | ||
360 | PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, | ||
361 | PRISM2_HOSTAPD_MLME = 13, | ||
362 | PRISM2_HOSTAPD_SCAN_REQ = 14, | ||
363 | PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, | ||
364 | }; | ||
365 | |||
366 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | ||
367 | #define PRISM2_HOSTAPD_RID_HDR_LEN \ | ||
368 | ((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) | ||
369 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | ||
370 | ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) | ||
371 | |||
372 | /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() | ||
373 | */ | ||
374 | #define HOSTAP_CRYPT_ALG_NAME_LEN 16 | ||
375 | |||
376 | |||
377 | struct prism2_hostapd_param { | ||
378 | u32 cmd; | ||
379 | u8 sta_addr[ETH_ALEN]; | ||
380 | union { | ||
381 | struct { | ||
382 | u16 aid; | ||
383 | u16 capability; | ||
384 | u8 tx_supp_rates; | ||
385 | } add_sta; | ||
386 | struct { | ||
387 | u32 inactive_sec; | ||
388 | } get_info_sta; | ||
389 | struct { | ||
390 | u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; | ||
391 | u32 flags; | ||
392 | u32 err; | ||
393 | u8 idx; | ||
394 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
395 | u16 key_len; | ||
396 | u8 key[0]; | ||
397 | } crypt; | ||
398 | struct { | ||
399 | u32 flags_and; | ||
400 | u32 flags_or; | ||
401 | } set_flags_sta; | ||
402 | struct { | ||
403 | u16 rid; | ||
404 | u16 len; | ||
405 | u8 data[0]; | ||
406 | } rid; | ||
407 | struct { | ||
408 | u8 len; | ||
409 | u8 data[0]; | ||
410 | } generic_elem; | ||
411 | struct { | ||
412 | #define MLME_STA_DEAUTH 0 | ||
413 | #define MLME_STA_DISASSOC 1 | ||
414 | u16 cmd; | ||
415 | u16 reason_code; | ||
416 | } mlme; | ||
417 | struct { | ||
418 | u8 ssid_len; | ||
419 | u8 ssid[32]; | ||
420 | } scan_req; | ||
421 | } u; | ||
422 | }; | ||
423 | |||
424 | #define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) | ||
425 | #define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) | ||
426 | |||
427 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 | ||
428 | #define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 | ||
429 | #define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 | ||
430 | #define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 | ||
431 | #define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 | ||
432 | #define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 | ||
433 | |||
434 | |||
435 | #endif /* HOSTAP_COMMON_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h new file mode 100644 index 000000000000..7ed3425d08c1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_config.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef HOSTAP_CONFIG_H | ||
2 | #define HOSTAP_CONFIG_H | ||
3 | |||
4 | #define PRISM2_VERSION "0.4.4-kernel" | ||
5 | |||
6 | /* In the previous versions of Host AP driver, support for user space version | ||
7 | * of IEEE 802.11 management (hostapd) used to be disabled in the default | ||
8 | * configuration. From now on, support for hostapd is always included and it is | ||
9 | * possible to disable kernel driver version of IEEE 802.11 management with a | ||
10 | * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ | ||
11 | /* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
12 | |||
13 | /* Maximum number of events handler per one interrupt */ | ||
14 | #define PRISM2_MAX_INTERRUPT_EVENTS 20 | ||
15 | |||
16 | /* Include code for downloading firmware images into volatile RAM. */ | ||
17 | #define PRISM2_DOWNLOAD_SUPPORT | ||
18 | |||
19 | /* Allow kernel configuration to enable download support. */ | ||
20 | #if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) | ||
21 | #define PRISM2_DOWNLOAD_SUPPORT | ||
22 | #endif | ||
23 | |||
24 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
25 | /* Allow writing firmware images into flash, i.e., to non-volatile storage. | ||
26 | * Before you enable this option, you should make absolutely sure that you are | ||
27 | * using prism2_srec utility that comes with THIS version of the driver! | ||
28 | * In addition, please note that it is possible to kill your card with | ||
29 | * non-volatile download if you are using incorrect image. This feature has not | ||
30 | * been fully tested, so please be careful with it. */ | ||
31 | /* #define PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
32 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
33 | |||
34 | /* Save low-level I/O for debugging. This should not be enabled in normal use. | ||
35 | */ | ||
36 | /* #define PRISM2_IO_DEBUG */ | ||
37 | |||
38 | /* Following defines can be used to remove unneeded parts of the driver, e.g., | ||
39 | * to limit the size of the kernel module. Definitions can be added here in | ||
40 | * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, | ||
41 | * e.g., | ||
42 | * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' | ||
43 | */ | ||
44 | |||
45 | /* Do not include debug messages into the driver */ | ||
46 | /* #define PRISM2_NO_DEBUG */ | ||
47 | |||
48 | /* Do not include /proc/net/prism2/wlan#/{registers,debug} */ | ||
49 | /* #define PRISM2_NO_PROCFS_DEBUG */ | ||
50 | |||
51 | /* Do not include station functionality (i.e., allow only Master (Host AP) mode | ||
52 | */ | ||
53 | /* #define PRISM2_NO_STATION_MODES */ | ||
54 | |||
55 | #endif /* HOSTAP_CONFIG_H */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c new file mode 100644 index 000000000000..faa83badf0a1 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -0,0 +1,1030 @@ | |||
1 | #define PRISM2_PCCARD | ||
2 | |||
3 | #include <linux/config.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/init.h> | ||
6 | #include <linux/if.h> | ||
7 | #include <linux/wait.h> | ||
8 | #include <linux/timer.h> | ||
9 | #include <linux/skbuff.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/workqueue.h> | ||
12 | #include <linux/wireless.h> | ||
13 | #include <net/iw_handler.h> | ||
14 | |||
15 | #include <pcmcia/cs_types.h> | ||
16 | #include <pcmcia/cs.h> | ||
17 | #include <pcmcia/cistpl.h> | ||
18 | #include <pcmcia/cisreg.h> | ||
19 | #include <pcmcia/ds.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include "hostap_wlan.h" | ||
24 | |||
25 | |||
26 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
27 | static dev_info_t dev_info = "hostap_cs"; | ||
28 | static dev_link_t *dev_list = NULL; | ||
29 | |||
30 | MODULE_AUTHOR("Jouni Malinen"); | ||
31 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | ||
32 | "cards (PC Card)."); | ||
33 | MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | MODULE_VERSION(PRISM2_VERSION); | ||
36 | |||
37 | |||
38 | static int ignore_cis_vcc; | ||
39 | module_param(ignore_cis_vcc, int, 0444); | ||
40 | MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); | ||
41 | |||
42 | |||
43 | /* struct local_info::hw_priv */ | ||
44 | struct hostap_cs_priv { | ||
45 | dev_node_t node; | ||
46 | dev_link_t *link; | ||
47 | int sandisk_connectplus; | ||
48 | }; | ||
49 | |||
50 | |||
51 | #ifdef PRISM2_IO_DEBUG | ||
52 | |||
53 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
54 | { | ||
55 | struct hostap_interface *iface; | ||
56 | local_info_t *local; | ||
57 | unsigned long flags; | ||
58 | |||
59 | iface = netdev_priv(dev); | ||
60 | local = iface->local; | ||
61 | spin_lock_irqsave(&local->lock, flags); | ||
62 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
63 | outb(v, dev->base_addr + a); | ||
64 | spin_unlock_irqrestore(&local->lock, flags); | ||
65 | } | ||
66 | |||
67 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
68 | { | ||
69 | struct hostap_interface *iface; | ||
70 | local_info_t *local; | ||
71 | unsigned long flags; | ||
72 | u8 v; | ||
73 | |||
74 | iface = netdev_priv(dev); | ||
75 | local = iface->local; | ||
76 | spin_lock_irqsave(&local->lock, flags); | ||
77 | v = inb(dev->base_addr + a); | ||
78 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
79 | spin_unlock_irqrestore(&local->lock, flags); | ||
80 | return v; | ||
81 | } | ||
82 | |||
83 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
84 | { | ||
85 | struct hostap_interface *iface; | ||
86 | local_info_t *local; | ||
87 | unsigned long flags; | ||
88 | |||
89 | iface = netdev_priv(dev); | ||
90 | local = iface->local; | ||
91 | spin_lock_irqsave(&local->lock, flags); | ||
92 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
93 | outw(v, dev->base_addr + a); | ||
94 | spin_unlock_irqrestore(&local->lock, flags); | ||
95 | } | ||
96 | |||
97 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
98 | { | ||
99 | struct hostap_interface *iface; | ||
100 | local_info_t *local; | ||
101 | unsigned long flags; | ||
102 | u16 v; | ||
103 | |||
104 | iface = netdev_priv(dev); | ||
105 | local = iface->local; | ||
106 | spin_lock_irqsave(&local->lock, flags); | ||
107 | v = inw(dev->base_addr + a); | ||
108 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
109 | spin_unlock_irqrestore(&local->lock, flags); | ||
110 | return v; | ||
111 | } | ||
112 | |||
113 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
114 | u8 *buf, int wc) | ||
115 | { | ||
116 | struct hostap_interface *iface; | ||
117 | local_info_t *local; | ||
118 | unsigned long flags; | ||
119 | |||
120 | iface = netdev_priv(dev); | ||
121 | local = iface->local; | ||
122 | spin_lock_irqsave(&local->lock, flags); | ||
123 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
124 | outsw(dev->base_addr + a, buf, wc); | ||
125 | spin_unlock_irqrestore(&local->lock, flags); | ||
126 | } | ||
127 | |||
128 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
129 | u8 *buf, int wc) | ||
130 | { | ||
131 | struct hostap_interface *iface; | ||
132 | local_info_t *local; | ||
133 | unsigned long flags; | ||
134 | |||
135 | iface = netdev_priv(dev); | ||
136 | local = iface->local; | ||
137 | spin_lock_irqsave(&local->lock, flags); | ||
138 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
139 | insw(dev->base_addr + a, buf, wc); | ||
140 | spin_unlock_irqrestore(&local->lock, flags); | ||
141 | } | ||
142 | |||
143 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
144 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
145 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
146 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
147 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
148 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
149 | |||
150 | #else /* PRISM2_IO_DEBUG */ | ||
151 | |||
152 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
153 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
154 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
155 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
156 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
157 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
158 | |||
159 | #endif /* PRISM2_IO_DEBUG */ | ||
160 | |||
161 | |||
162 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
163 | int len) | ||
164 | { | ||
165 | u16 d_off; | ||
166 | u16 *pos; | ||
167 | |||
168 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
169 | pos = (u16 *) buf; | ||
170 | |||
171 | if (len / 2) | ||
172 | HFA384X_INSW(d_off, buf, len / 2); | ||
173 | pos += len / 2; | ||
174 | |||
175 | if (len & 1) | ||
176 | *((char *) pos) = HFA384X_INB(d_off); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | |||
182 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
183 | { | ||
184 | u16 d_off; | ||
185 | u16 *pos; | ||
186 | |||
187 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
188 | pos = (u16 *) buf; | ||
189 | |||
190 | if (len / 2) | ||
191 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
192 | pos += len / 2; | ||
193 | |||
194 | if (len & 1) | ||
195 | HFA384X_OUTB(*((char *) pos), d_off); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | |||
201 | /* FIX: This might change at some point.. */ | ||
202 | #include "hostap_hw.c" | ||
203 | |||
204 | |||
205 | |||
206 | static void prism2_detach(dev_link_t *link); | ||
207 | static void prism2_release(u_long arg); | ||
208 | static int prism2_event(event_t event, int priority, | ||
209 | event_callback_args_t *args); | ||
210 | |||
211 | |||
212 | static int prism2_pccard_card_present(local_info_t *local) | ||
213 | { | ||
214 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
215 | if (hw_priv != NULL && hw_priv->link != NULL && | ||
216 | ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) == | ||
217 | (DEV_PRESENT | DEV_CONFIG))) | ||
218 | return 1; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | |||
223 | /* | ||
224 | * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 | ||
225 | * Document No. 20-10-00058, January 2004 | ||
226 | * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf | ||
227 | */ | ||
228 | #define SANDISK_WLAN_ACTIVATION_OFF 0x40 | ||
229 | #define SANDISK_HCR_OFF 0x42 | ||
230 | |||
231 | |||
232 | static void sandisk_set_iobase(local_info_t *local) | ||
233 | { | ||
234 | int res; | ||
235 | conf_reg_t reg; | ||
236 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
237 | |||
238 | reg.Function = 0; | ||
239 | reg.Action = CS_WRITE; | ||
240 | reg.Offset = 0x10; /* 0x3f0 IO base 1 */ | ||
241 | reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; | ||
242 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
243 | ®); | ||
244 | if (res != CS_SUCCESS) { | ||
245 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" | ||
246 | " res=%d\n", res); | ||
247 | } | ||
248 | udelay(10); | ||
249 | |||
250 | reg.Function = 0; | ||
251 | reg.Action = CS_WRITE; | ||
252 | reg.Offset = 0x12; /* 0x3f2 IO base 2 */ | ||
253 | reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; | ||
254 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
255 | ®); | ||
256 | if (res != CS_SUCCESS) { | ||
257 | printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" | ||
258 | " res=%d\n", res); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void sandisk_write_hcr(local_info_t *local, int hcr) | ||
264 | { | ||
265 | struct net_device *dev = local->dev; | ||
266 | int i; | ||
267 | |||
268 | HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); | ||
269 | udelay(50); | ||
270 | for (i = 0; i < 10; i++) { | ||
271 | HFA384X_OUTB(hcr, SANDISK_HCR_OFF); | ||
272 | } | ||
273 | udelay(55); | ||
274 | HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); | ||
275 | } | ||
276 | |||
277 | |||
278 | static int sandisk_enable_wireless(struct net_device *dev) | ||
279 | { | ||
280 | int res, ret = 0; | ||
281 | conf_reg_t reg; | ||
282 | struct hostap_interface *iface = dev->priv; | ||
283 | local_info_t *local = iface->local; | ||
284 | tuple_t tuple; | ||
285 | cisparse_t *parse = NULL; | ||
286 | u_char buf[64]; | ||
287 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
288 | |||
289 | if (hw_priv->link->io.NumPorts1 < 0x42) { | ||
290 | /* Not enough ports to be SanDisk multi-function card */ | ||
291 | ret = -ENODEV; | ||
292 | goto done; | ||
293 | } | ||
294 | |||
295 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
296 | if (parse == NULL) { | ||
297 | ret = -ENOMEM; | ||
298 | goto done; | ||
299 | } | ||
300 | |||
301 | tuple.DesiredTuple = CISTPL_MANFID; | ||
302 | tuple.Attributes = TUPLE_RETURN_COMMON; | ||
303 | tuple.TupleData = buf; | ||
304 | tuple.TupleDataMax = sizeof(buf); | ||
305 | tuple.TupleOffset = 0; | ||
306 | if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || | ||
307 | pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || | ||
308 | pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || | ||
309 | parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) { | ||
310 | /* No SanDisk manfid found */ | ||
311 | ret = -ENODEV; | ||
312 | goto done; | ||
313 | } | ||
314 | |||
315 | tuple.DesiredTuple = CISTPL_LONGLINK_MFC; | ||
316 | if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || | ||
317 | pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || | ||
318 | pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || | ||
319 | parse->longlink_mfc.nfn < 2) { | ||
320 | /* No multi-function links found */ | ||
321 | ret = -ENODEV; | ||
322 | goto done; | ||
323 | } | ||
324 | |||
325 | printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" | ||
326 | " - using vendor-specific initialization\n", dev->name); | ||
327 | hw_priv->sandisk_connectplus = 1; | ||
328 | |||
329 | reg.Function = 0; | ||
330 | reg.Action = CS_WRITE; | ||
331 | reg.Offset = CISREG_COR; | ||
332 | reg.Value = COR_SOFT_RESET; | ||
333 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
334 | ®); | ||
335 | if (res != CS_SUCCESS) { | ||
336 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
337 | dev->name, res); | ||
338 | goto done; | ||
339 | } | ||
340 | mdelay(5); | ||
341 | |||
342 | reg.Function = 0; | ||
343 | reg.Action = CS_WRITE; | ||
344 | reg.Offset = CISREG_COR; | ||
345 | /* | ||
346 | * Do not enable interrupts here to avoid some bogus events. Interrupts | ||
347 | * will be enabled during the first cor_sreset call. | ||
348 | */ | ||
349 | reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; | ||
350 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
351 | ®); | ||
352 | if (res != CS_SUCCESS) { | ||
353 | printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | ||
354 | dev->name, res); | ||
355 | goto done; | ||
356 | } | ||
357 | mdelay(5); | ||
358 | |||
359 | sandisk_set_iobase(local); | ||
360 | |||
361 | HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); | ||
362 | udelay(10); | ||
363 | HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); | ||
364 | udelay(10); | ||
365 | |||
366 | done: | ||
367 | kfree(parse); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | |||
372 | static void prism2_pccard_cor_sreset(local_info_t *local) | ||
373 | { | ||
374 | int res; | ||
375 | conf_reg_t reg; | ||
376 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
377 | |||
378 | if (!prism2_pccard_card_present(local)) | ||
379 | return; | ||
380 | |||
381 | reg.Function = 0; | ||
382 | reg.Action = CS_READ; | ||
383 | reg.Offset = CISREG_COR; | ||
384 | reg.Value = 0; | ||
385 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
386 | ®); | ||
387 | if (res != CS_SUCCESS) { | ||
388 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", | ||
389 | res); | ||
390 | return; | ||
391 | } | ||
392 | printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", | ||
393 | reg.Value); | ||
394 | |||
395 | reg.Action = CS_WRITE; | ||
396 | reg.Value |= COR_SOFT_RESET; | ||
397 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
398 | ®); | ||
399 | if (res != CS_SUCCESS) { | ||
400 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", | ||
401 | res); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | ||
406 | |||
407 | reg.Value &= ~COR_SOFT_RESET; | ||
408 | if (hw_priv->sandisk_connectplus) | ||
409 | reg.Value |= COR_IREQ_ENA; | ||
410 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
411 | ®); | ||
412 | if (res != CS_SUCCESS) { | ||
413 | printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", | ||
414 | res); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | ||
419 | |||
420 | if (hw_priv->sandisk_connectplus) | ||
421 | sandisk_set_iobase(local); | ||
422 | } | ||
423 | |||
424 | |||
425 | static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) | ||
426 | { | ||
427 | int res; | ||
428 | conf_reg_t reg; | ||
429 | int old_cor; | ||
430 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
431 | |||
432 | if (!prism2_pccard_card_present(local)) | ||
433 | return; | ||
434 | |||
435 | if (hw_priv->sandisk_connectplus) { | ||
436 | sandisk_write_hcr(local, hcr); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | reg.Function = 0; | ||
441 | reg.Action = CS_READ; | ||
442 | reg.Offset = CISREG_COR; | ||
443 | reg.Value = 0; | ||
444 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
445 | ®); | ||
446 | if (res != CS_SUCCESS) { | ||
447 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " | ||
448 | "(%d)\n", res); | ||
449 | return; | ||
450 | } | ||
451 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n", | ||
452 | reg.Value); | ||
453 | old_cor = reg.Value; | ||
454 | |||
455 | reg.Action = CS_WRITE; | ||
456 | reg.Value |= COR_SOFT_RESET; | ||
457 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
458 | ®); | ||
459 | if (res != CS_SUCCESS) { | ||
460 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " | ||
461 | "(%d)\n", res); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | mdelay(10); | ||
466 | |||
467 | /* Setup Genesis mode */ | ||
468 | reg.Action = CS_WRITE; | ||
469 | reg.Value = hcr; | ||
470 | reg.Offset = CISREG_CCSR; | ||
471 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
472 | ®); | ||
473 | if (res != CS_SUCCESS) { | ||
474 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " | ||
475 | "(%d)\n", res); | ||
476 | return; | ||
477 | } | ||
478 | mdelay(10); | ||
479 | |||
480 | reg.Action = CS_WRITE; | ||
481 | reg.Offset = CISREG_COR; | ||
482 | reg.Value = old_cor & ~COR_SOFT_RESET; | ||
483 | res = pcmcia_access_configuration_register(hw_priv->link->handle, | ||
484 | ®); | ||
485 | if (res != CS_SUCCESS) { | ||
486 | printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " | ||
487 | "(%d)\n", res); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | mdelay(10); | ||
492 | } | ||
493 | |||
494 | |||
495 | static int prism2_pccard_dev_open(local_info_t *local) | ||
496 | { | ||
497 | struct hostap_cs_priv *hw_priv = local->hw_priv; | ||
498 | hw_priv->link->open++; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | |||
503 | static int prism2_pccard_dev_close(local_info_t *local) | ||
504 | { | ||
505 | struct hostap_cs_priv *hw_priv; | ||
506 | |||
507 | if (local == NULL || local->hw_priv == NULL) | ||
508 | return 1; | ||
509 | hw_priv = local->hw_priv; | ||
510 | if (hw_priv->link == NULL) | ||
511 | return 1; | ||
512 | |||
513 | if (!hw_priv->link->open) { | ||
514 | printk(KERN_WARNING "%s: prism2_pccard_dev_close(): " | ||
515 | "link not open?!\n", local->dev->name); | ||
516 | return 1; | ||
517 | } | ||
518 | |||
519 | hw_priv->link->open--; | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | |||
525 | static struct prism2_helper_functions prism2_pccard_funcs = | ||
526 | { | ||
527 | .card_present = prism2_pccard_card_present, | ||
528 | .cor_sreset = prism2_pccard_cor_sreset, | ||
529 | .dev_open = prism2_pccard_dev_open, | ||
530 | .dev_close = prism2_pccard_dev_close, | ||
531 | .genesis_reset = prism2_pccard_genesis_reset, | ||
532 | .hw_type = HOSTAP_HW_PCCARD, | ||
533 | }; | ||
534 | |||
535 | |||
536 | /* allocate local data and register with CardServices | ||
537 | * initialize dev_link structure, but do not configure the card yet */ | ||
538 | static dev_link_t *prism2_attach(void) | ||
539 | { | ||
540 | dev_link_t *link; | ||
541 | client_reg_t client_reg; | ||
542 | int ret; | ||
543 | |||
544 | link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); | ||
545 | if (link == NULL) | ||
546 | return NULL; | ||
547 | |||
548 | memset(link, 0, sizeof(dev_link_t)); | ||
549 | |||
550 | PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); | ||
551 | link->conf.Vcc = 33; | ||
552 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
553 | |||
554 | /* register with CardServices */ | ||
555 | link->next = dev_list; | ||
556 | dev_list = link; | ||
557 | client_reg.dev_info = &dev_info; | ||
558 | client_reg.Version = 0x0210; | ||
559 | client_reg.event_callback_args.client_data = link; | ||
560 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
561 | if (ret != CS_SUCCESS) { | ||
562 | cs_error(link->handle, RegisterClient, ret); | ||
563 | prism2_detach(link); | ||
564 | return NULL; | ||
565 | } | ||
566 | return link; | ||
567 | } | ||
568 | |||
569 | |||
570 | static void prism2_detach(dev_link_t *link) | ||
571 | { | ||
572 | dev_link_t **linkp; | ||
573 | |||
574 | PDEBUG(DEBUG_FLOW, "prism2_detach\n"); | ||
575 | |||
576 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
577 | if (*linkp == link) | ||
578 | break; | ||
579 | if (*linkp == NULL) { | ||
580 | printk(KERN_WARNING "%s: Attempt to detach non-existing " | ||
581 | "PCMCIA client\n", dev_info); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | if (link->state & DEV_CONFIG) { | ||
586 | prism2_release((u_long)link); | ||
587 | } | ||
588 | |||
589 | if (link->handle) { | ||
590 | int res = pcmcia_deregister_client(link->handle); | ||
591 | if (res) { | ||
592 | printk("CardService(DeregisterClient) => %d\n", res); | ||
593 | cs_error(link->handle, DeregisterClient, res); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | *linkp = link->next; | ||
598 | /* release net devices */ | ||
599 | if (link->priv) { | ||
600 | struct net_device *dev; | ||
601 | struct hostap_interface *iface; | ||
602 | dev = link->priv; | ||
603 | iface = netdev_priv(dev); | ||
604 | kfree(iface->local->hw_priv); | ||
605 | iface->local->hw_priv = NULL; | ||
606 | prism2_free_local_data(dev); | ||
607 | } | ||
608 | kfree(link); | ||
609 | } | ||
610 | |||
611 | |||
612 | #define CS_CHECK(fn, ret) \ | ||
613 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
614 | |||
615 | #define CFG_CHECK2(fn, retf) \ | ||
616 | do { int ret = (retf); \ | ||
617 | if (ret != 0) { \ | ||
618 | PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ | ||
619 | cs_error(link->handle, fn, ret); \ | ||
620 | goto next_entry; \ | ||
621 | } \ | ||
622 | } while (0) | ||
623 | |||
624 | |||
625 | /* run after a CARD_INSERTION event is received to configure the PCMCIA | ||
626 | * socket and make the device available to the system */ | ||
627 | static int prism2_config(dev_link_t *link) | ||
628 | { | ||
629 | struct net_device *dev; | ||
630 | struct hostap_interface *iface; | ||
631 | local_info_t *local; | ||
632 | int ret = 1; | ||
633 | tuple_t tuple; | ||
634 | cisparse_t *parse; | ||
635 | int last_fn, last_ret; | ||
636 | u_char buf[64]; | ||
637 | config_info_t conf; | ||
638 | cistpl_cftable_entry_t dflt = { 0 }; | ||
639 | struct hostap_cs_priv *hw_priv; | ||
640 | |||
641 | PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | ||
642 | |||
643 | parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); | ||
644 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
645 | if (parse == NULL || hw_priv == NULL) { | ||
646 | kfree(parse); | ||
647 | kfree(hw_priv); | ||
648 | ret = -ENOMEM; | ||
649 | goto failed; | ||
650 | } | ||
651 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
652 | |||
653 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
654 | tuple.Attributes = 0; | ||
655 | tuple.TupleData = buf; | ||
656 | tuple.TupleDataMax = sizeof(buf); | ||
657 | tuple.TupleOffset = 0; | ||
658 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
659 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple)); | ||
660 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
661 | link->conf.ConfigBase = parse->config.base; | ||
662 | link->conf.Present = parse->config.rmask[0]; | ||
663 | |||
664 | CS_CHECK(GetConfigurationInfo, | ||
665 | pcmcia_get_configuration_info(link->handle, &conf)); | ||
666 | PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info, | ||
667 | ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc); | ||
668 | link->conf.Vcc = conf.Vcc; | ||
669 | |||
670 | /* Look for an appropriate configuration table entry in the CIS */ | ||
671 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
672 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); | ||
673 | for (;;) { | ||
674 | cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); | ||
675 | CFG_CHECK2(GetTupleData, | ||
676 | pcmcia_get_tuple_data(link->handle, &tuple)); | ||
677 | CFG_CHECK2(ParseTuple, | ||
678 | pcmcia_parse_tuple(link->handle, &tuple, parse)); | ||
679 | |||
680 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
681 | dflt = *cfg; | ||
682 | if (cfg->index == 0) | ||
683 | goto next_entry; | ||
684 | link->conf.ConfigIndex = cfg->index; | ||
685 | PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " | ||
686 | "(default 0x%02X)\n", cfg->index, dflt.index); | ||
687 | |||
688 | /* Does this card need audio output? */ | ||
689 | if (cfg->flags & CISTPL_CFTABLE_AUDIO) { | ||
690 | link->conf.Attributes |= CONF_ENABLE_SPKR; | ||
691 | link->conf.Status = CCSR_AUDIO_ENA; | ||
692 | } | ||
693 | |||
694 | /* Use power settings for Vcc and Vpp if present */ | ||
695 | /* Note that the CIS values need to be rescaled */ | ||
696 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
697 | if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / | ||
698 | 10000 && !ignore_cis_vcc) { | ||
699 | PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" | ||
700 | " this entry\n"); | ||
701 | goto next_entry; | ||
702 | } | ||
703 | } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
704 | if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / | ||
705 | 10000 && !ignore_cis_vcc) { | ||
706 | PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " | ||
707 | "- skipping this entry\n"); | ||
708 | goto next_entry; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
713 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
714 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
715 | else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
716 | link->conf.Vpp1 = link->conf.Vpp2 = | ||
717 | dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
718 | |||
719 | /* Do we need to allocate an interrupt? */ | ||
720 | if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) | ||
721 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
722 | else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { | ||
723 | /* At least Compaq WL200 does not have IRQInfo1 set, | ||
724 | * but it does not work without interrupts.. */ | ||
725 | printk("Config has no IRQ info, but trying to enable " | ||
726 | "IRQ anyway..\n"); | ||
727 | link->conf.Attributes |= CONF_ENABLE_IRQ; | ||
728 | } | ||
729 | |||
730 | /* IO window settings */ | ||
731 | PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " | ||
732 | "dflt.io.nwin=%d\n", | ||
733 | cfg->io.nwin, dflt.io.nwin); | ||
734 | link->io.NumPorts1 = link->io.NumPorts2 = 0; | ||
735 | if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { | ||
736 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; | ||
737 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
738 | PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " | ||
739 | "io.base=0x%04x, len=%d\n", io->flags, | ||
740 | io->win[0].base, io->win[0].len); | ||
741 | if (!(io->flags & CISTPL_IO_8BIT)) | ||
742 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; | ||
743 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
744 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
745 | link->io.IOAddrLines = io->flags & | ||
746 | CISTPL_IO_LINES_MASK; | ||
747 | link->io.BasePort1 = io->win[0].base; | ||
748 | link->io.NumPorts1 = io->win[0].len; | ||
749 | if (io->nwin > 1) { | ||
750 | link->io.Attributes2 = link->io.Attributes1; | ||
751 | link->io.BasePort2 = io->win[1].base; | ||
752 | link->io.NumPorts2 = io->win[1].len; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | /* This reserves IO space but doesn't actually enable it */ | ||
757 | CFG_CHECK2(RequestIO, | ||
758 | pcmcia_request_io(link->handle, &link->io)); | ||
759 | |||
760 | /* This configuration table entry is OK */ | ||
761 | break; | ||
762 | |||
763 | next_entry: | ||
764 | CS_CHECK(GetNextTuple, | ||
765 | pcmcia_get_next_tuple(link->handle, &tuple)); | ||
766 | } | ||
767 | |||
768 | /* Need to allocate net_device before requesting IRQ handler */ | ||
769 | dev = prism2_init_local_data(&prism2_pccard_funcs, 0, | ||
770 | &handle_to_dev(link->handle)); | ||
771 | if (dev == NULL) | ||
772 | goto failed; | ||
773 | link->priv = dev; | ||
774 | |||
775 | iface = netdev_priv(dev); | ||
776 | local = iface->local; | ||
777 | local->hw_priv = hw_priv; | ||
778 | hw_priv->link = link; | ||
779 | strcpy(hw_priv->node.dev_name, dev->name); | ||
780 | link->dev = &hw_priv->node; | ||
781 | |||
782 | /* | ||
783 | * Allocate an interrupt line. Note that this does not assign a | ||
784 | * handler to the interrupt, unless the 'Handler' member of the | ||
785 | * irq structure is initialized. | ||
786 | */ | ||
787 | if (link->conf.Attributes & CONF_ENABLE_IRQ) { | ||
788 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
789 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
790 | link->irq.Handler = prism2_interrupt; | ||
791 | link->irq.Instance = dev; | ||
792 | CS_CHECK(RequestIRQ, | ||
793 | pcmcia_request_irq(link->handle, &link->irq)); | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * This actually configures the PCMCIA socket -- setting up | ||
798 | * the I/O windows and the interrupt mapping, and putting the | ||
799 | * card and host interface into "Memory and IO" mode. | ||
800 | */ | ||
801 | CS_CHECK(RequestConfiguration, | ||
802 | pcmcia_request_configuration(link->handle, &link->conf)); | ||
803 | |||
804 | dev->irq = link->irq.AssignedIRQ; | ||
805 | dev->base_addr = link->io.BasePort1; | ||
806 | |||
807 | /* Finally, report what we've done */ | ||
808 | printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", | ||
809 | dev_info, link->conf.ConfigIndex, | ||
810 | link->conf.Vcc / 10, link->conf.Vcc % 10); | ||
811 | if (link->conf.Vpp1) | ||
812 | printk(", Vpp %d.%d", link->conf.Vpp1 / 10, | ||
813 | link->conf.Vpp1 % 10); | ||
814 | if (link->conf.Attributes & CONF_ENABLE_IRQ) | ||
815 | printk(", irq %d", link->irq.AssignedIRQ); | ||
816 | if (link->io.NumPorts1) | ||
817 | printk(", io 0x%04x-0x%04x", link->io.BasePort1, | ||
818 | link->io.BasePort1+link->io.NumPorts1-1); | ||
819 | if (link->io.NumPorts2) | ||
820 | printk(" & 0x%04x-0x%04x", link->io.BasePort2, | ||
821 | link->io.BasePort2+link->io.NumPorts2-1); | ||
822 | printk("\n"); | ||
823 | |||
824 | link->state |= DEV_CONFIG; | ||
825 | link->state &= ~DEV_CONFIG_PENDING; | ||
826 | |||
827 | local->shutdown = 0; | ||
828 | |||
829 | sandisk_enable_wireless(dev); | ||
830 | |||
831 | ret = prism2_hw_config(dev, 1); | ||
832 | if (!ret) { | ||
833 | ret = hostap_hw_ready(dev); | ||
834 | if (ret == 0 && local->ddev) | ||
835 | strcpy(hw_priv->node.dev_name, local->ddev->name); | ||
836 | } | ||
837 | kfree(parse); | ||
838 | return ret; | ||
839 | |||
840 | cs_failed: | ||
841 | cs_error(link->handle, last_fn, last_ret); | ||
842 | |||
843 | failed: | ||
844 | kfree(parse); | ||
845 | kfree(hw_priv); | ||
846 | prism2_release((u_long)link); | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | |||
851 | static void prism2_release(u_long arg) | ||
852 | { | ||
853 | dev_link_t *link = (dev_link_t *)arg; | ||
854 | |||
855 | PDEBUG(DEBUG_FLOW, "prism2_release\n"); | ||
856 | |||
857 | if (link->priv) { | ||
858 | struct net_device *dev = link->priv; | ||
859 | struct hostap_interface *iface; | ||
860 | |||
861 | iface = netdev_priv(dev); | ||
862 | if (link->state & DEV_CONFIG) | ||
863 | prism2_hw_shutdown(dev, 0); | ||
864 | iface->local->shutdown = 1; | ||
865 | } | ||
866 | |||
867 | if (link->win) | ||
868 | pcmcia_release_window(link->win); | ||
869 | pcmcia_release_configuration(link->handle); | ||
870 | if (link->io.NumPorts1) | ||
871 | pcmcia_release_io(link->handle, &link->io); | ||
872 | if (link->irq.AssignedIRQ) | ||
873 | pcmcia_release_irq(link->handle, &link->irq); | ||
874 | |||
875 | link->state &= ~DEV_CONFIG; | ||
876 | |||
877 | PDEBUG(DEBUG_FLOW, "release - done\n"); | ||
878 | } | ||
879 | |||
880 | |||
881 | static int prism2_event(event_t event, int priority, | ||
882 | event_callback_args_t *args) | ||
883 | { | ||
884 | dev_link_t *link = args->client_data; | ||
885 | struct net_device *dev = (struct net_device *) link->priv; | ||
886 | |||
887 | switch (event) { | ||
888 | case CS_EVENT_CARD_INSERTION: | ||
889 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info); | ||
890 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
891 | if (prism2_config(link)) { | ||
892 | PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); | ||
893 | } | ||
894 | break; | ||
895 | |||
896 | case CS_EVENT_CARD_REMOVAL: | ||
897 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info); | ||
898 | link->state &= ~DEV_PRESENT; | ||
899 | if (link->state & DEV_CONFIG) { | ||
900 | netif_stop_queue(dev); | ||
901 | netif_device_detach(dev); | ||
902 | prism2_release((u_long) link); | ||
903 | } | ||
904 | break; | ||
905 | |||
906 | case CS_EVENT_PM_SUSPEND: | ||
907 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | ||
908 | link->state |= DEV_SUSPEND; | ||
909 | /* fall through */ | ||
910 | |||
911 | case CS_EVENT_RESET_PHYSICAL: | ||
912 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); | ||
913 | if (link->state & DEV_CONFIG) { | ||
914 | if (link->open) { | ||
915 | netif_stop_queue(dev); | ||
916 | netif_device_detach(dev); | ||
917 | } | ||
918 | prism2_suspend(dev); | ||
919 | pcmcia_release_configuration(link->handle); | ||
920 | } | ||
921 | break; | ||
922 | |||
923 | case CS_EVENT_PM_RESUME: | ||
924 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); | ||
925 | link->state &= ~DEV_SUSPEND; | ||
926 | /* fall through */ | ||
927 | |||
928 | case CS_EVENT_CARD_RESET: | ||
929 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info); | ||
930 | if (link->state & DEV_CONFIG) { | ||
931 | pcmcia_request_configuration(link->handle, | ||
932 | &link->conf); | ||
933 | prism2_hw_shutdown(dev, 1); | ||
934 | prism2_hw_config(dev, link->open ? 0 : 1); | ||
935 | if (link->open) { | ||
936 | netif_device_attach(dev); | ||
937 | netif_start_queue(dev); | ||
938 | } | ||
939 | } | ||
940 | break; | ||
941 | |||
942 | default: | ||
943 | PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n", | ||
944 | dev_info, event); | ||
945 | break; | ||
946 | } | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | |||
951 | static struct pcmcia_device_id hostap_cs_ids[] = { | ||
952 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), | ||
953 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), | ||
954 | PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), | ||
955 | PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), | ||
956 | PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), | ||
957 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), | ||
958 | PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), | ||
959 | PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), | ||
960 | PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), | ||
961 | PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), | ||
962 | PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), | ||
963 | PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), | ||
964 | PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), | ||
965 | PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), | ||
966 | PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), | ||
967 | PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), | ||
968 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), | ||
969 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), | ||
970 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), | ||
971 | PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", | ||
972 | 0x7a954bd9, 0x74be00c6), | ||
973 | PCMCIA_DEVICE_PROD_ID1234( | ||
974 | "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", | ||
975 | "Eval-RevA", | ||
976 | 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), | ||
977 | PCMCIA_DEVICE_PROD_ID123( | ||
978 | "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", | ||
979 | 0xe6ec52ce, 0x08649af2, 0x4b74baa0), | ||
980 | PCMCIA_DEVICE_PROD_ID123( | ||
981 | "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", | ||
982 | 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), | ||
983 | PCMCIA_DEVICE_PROD_ID123( | ||
984 | "Instant Wireless ", " Network PC CARD", "Version 01.02", | ||
985 | 0x11d901af, 0x6e9bd926, 0x4b74baa0), | ||
986 | PCMCIA_DEVICE_PROD_ID123( | ||
987 | "SMC", "SMC2632W", "Version 01.02", | ||
988 | 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), | ||
989 | PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", | ||
990 | 0x2decece3, 0x82067c18), | ||
991 | PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", | ||
992 | 0x54f7c49c, 0x15a75e5b), | ||
993 | PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", | ||
994 | 0x74c5e40d, 0xdb472a18), | ||
995 | PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", | ||
996 | 0x0733cc81, 0x0c52f395), | ||
997 | PCMCIA_DEVICE_PROD_ID12( | ||
998 | "ZoomAir 11Mbps High", "Rate wireless Networking", | ||
999 | 0x273fe3db, 0x32a1eaee), | ||
1000 | PCMCIA_DEVICE_NULL | ||
1001 | }; | ||
1002 | MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); | ||
1003 | |||
1004 | |||
1005 | static struct pcmcia_driver hostap_driver = { | ||
1006 | .drv = { | ||
1007 | .name = "hostap_cs", | ||
1008 | }, | ||
1009 | .attach = prism2_attach, | ||
1010 | .detach = prism2_detach, | ||
1011 | .owner = THIS_MODULE, | ||
1012 | .event = prism2_event, | ||
1013 | .id_table = hostap_cs_ids, | ||
1014 | }; | ||
1015 | |||
1016 | static int __init init_prism2_pccard(void) | ||
1017 | { | ||
1018 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
1019 | return pcmcia_register_driver(&hostap_driver); | ||
1020 | } | ||
1021 | |||
1022 | static void __exit exit_prism2_pccard(void) | ||
1023 | { | ||
1024 | pcmcia_unregister_driver(&hostap_driver); | ||
1025 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | module_init(init_prism2_pccard); | ||
1030 | module_exit(exit_prism2_pccard); | ||
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c new file mode 100644 index 000000000000..ab26b52b3e76 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_download.c | |||
@@ -0,0 +1,766 @@ | |||
1 | static int prism2_enable_aux_port(struct net_device *dev, int enable) | ||
2 | { | ||
3 | u16 val, reg; | ||
4 | int i, tries; | ||
5 | unsigned long flags; | ||
6 | struct hostap_interface *iface; | ||
7 | local_info_t *local; | ||
8 | |||
9 | iface = netdev_priv(dev); | ||
10 | local = iface->local; | ||
11 | |||
12 | if (local->no_pri) { | ||
13 | if (enable) { | ||
14 | PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " | ||
15 | "port is already enabled\n", dev->name); | ||
16 | } | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | spin_lock_irqsave(&local->cmdlock, flags); | ||
21 | |||
22 | /* wait until busy bit is clear */ | ||
23 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
24 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
25 | tries--; | ||
26 | udelay(1); | ||
27 | } | ||
28 | if (tries == 0) { | ||
29 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
30 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
31 | printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", | ||
32 | dev->name, reg); | ||
33 | return -ETIMEDOUT; | ||
34 | } | ||
35 | |||
36 | val = HFA384X_INW(HFA384X_CONTROL_OFF); | ||
37 | |||
38 | if (enable) { | ||
39 | HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); | ||
40 | HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); | ||
41 | HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); | ||
42 | |||
43 | if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) | ||
44 | printk("prism2_enable_aux_port: was not disabled!?\n"); | ||
45 | val &= ~HFA384X_AUX_PORT_MASK; | ||
46 | val |= HFA384X_AUX_PORT_ENABLE; | ||
47 | } else { | ||
48 | HFA384X_OUTW(0, HFA384X_PARAM0_OFF); | ||
49 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
50 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
51 | |||
52 | if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) | ||
53 | printk("prism2_enable_aux_port: was not enabled!?\n"); | ||
54 | val &= ~HFA384X_AUX_PORT_MASK; | ||
55 | val |= HFA384X_AUX_PORT_DISABLE; | ||
56 | } | ||
57 | HFA384X_OUTW(val, HFA384X_CONTROL_OFF); | ||
58 | |||
59 | udelay(5); | ||
60 | |||
61 | i = 10000; | ||
62 | while (i > 0) { | ||
63 | val = HFA384X_INW(HFA384X_CONTROL_OFF); | ||
64 | val &= HFA384X_AUX_PORT_MASK; | ||
65 | |||
66 | if ((enable && val == HFA384X_AUX_PORT_ENABLED) || | ||
67 | (!enable && val == HFA384X_AUX_PORT_DISABLED)) | ||
68 | break; | ||
69 | |||
70 | udelay(10); | ||
71 | i--; | ||
72 | } | ||
73 | |||
74 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
75 | |||
76 | if (i == 0) { | ||
77 | printk("prism2_enable_aux_port(%d) timed out\n", | ||
78 | enable); | ||
79 | return -ETIMEDOUT; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | |||
86 | static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, | ||
87 | void *buf) | ||
88 | { | ||
89 | u16 page, offset; | ||
90 | if (addr & 1 || len & 1) | ||
91 | return -1; | ||
92 | |||
93 | page = addr >> 7; | ||
94 | offset = addr & 0x7f; | ||
95 | |||
96 | HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | ||
97 | HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | ||
98 | |||
99 | udelay(5); | ||
100 | |||
101 | #ifdef PRISM2_PCI | ||
102 | { | ||
103 | u16 *pos = (u16 *) buf; | ||
104 | while (len > 0) { | ||
105 | *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); | ||
106 | len -= 2; | ||
107 | } | ||
108 | } | ||
109 | #else /* PRISM2_PCI */ | ||
110 | HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); | ||
111 | #endif /* PRISM2_PCI */ | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, | ||
118 | void *buf) | ||
119 | { | ||
120 | u16 page, offset; | ||
121 | if (addr & 1 || len & 1) | ||
122 | return -1; | ||
123 | |||
124 | page = addr >> 7; | ||
125 | offset = addr & 0x7f; | ||
126 | |||
127 | HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | ||
128 | HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | ||
129 | |||
130 | udelay(5); | ||
131 | |||
132 | #ifdef PRISM2_PCI | ||
133 | { | ||
134 | u16 *pos = (u16 *) buf; | ||
135 | while (len > 0) { | ||
136 | HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); | ||
137 | len -= 2; | ||
138 | } | ||
139 | } | ||
140 | #else /* PRISM2_PCI */ | ||
141 | HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); | ||
142 | #endif /* PRISM2_PCI */ | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
148 | static int prism2_pda_ok(u8 *buf) | ||
149 | { | ||
150 | u16 *pda = (u16 *) buf; | ||
151 | int pos; | ||
152 | u16 len, pdr; | ||
153 | |||
154 | if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && | ||
155 | buf[3] == 0x00) | ||
156 | return 0; | ||
157 | |||
158 | pos = 0; | ||
159 | while (pos + 1 < PRISM2_PDA_SIZE / 2) { | ||
160 | len = le16_to_cpu(pda[pos]); | ||
161 | pdr = le16_to_cpu(pda[pos + 1]); | ||
162 | if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) | ||
163 | return 0; | ||
164 | |||
165 | if (pdr == 0x0000 && len == 2) { | ||
166 | /* PDA end found */ | ||
167 | return 1; | ||
168 | } | ||
169 | |||
170 | pos += len + 1; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | static int prism2_download_aux_dump(struct net_device *dev, | ||
178 | unsigned int addr, int len, u8 *buf) | ||
179 | { | ||
180 | int res; | ||
181 | |||
182 | prism2_enable_aux_port(dev, 1); | ||
183 | res = hfa384x_from_aux(dev, addr, len, buf); | ||
184 | prism2_enable_aux_port(dev, 0); | ||
185 | if (res) | ||
186 | return -1; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | static u8 * prism2_read_pda(struct net_device *dev) | ||
193 | { | ||
194 | u8 *buf; | ||
195 | int res, i, found = 0; | ||
196 | #define NUM_PDA_ADDRS 4 | ||
197 | unsigned int pda_addr[NUM_PDA_ADDRS] = { | ||
198 | 0x7f0000 /* others than HFA3841 */, | ||
199 | 0x3f0000 /* HFA3841 */, | ||
200 | 0x390000 /* apparently used in older cards */, | ||
201 | 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, | ||
202 | }; | ||
203 | |||
204 | buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); | ||
205 | if (buf == NULL) | ||
206 | return NULL; | ||
207 | |||
208 | /* Note: wlan card should be in initial state (just after init cmd) | ||
209 | * and no other operations should be performed concurrently. */ | ||
210 | |||
211 | prism2_enable_aux_port(dev, 1); | ||
212 | |||
213 | for (i = 0; i < NUM_PDA_ADDRS; i++) { | ||
214 | PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", | ||
215 | dev->name, pda_addr[i]); | ||
216 | res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); | ||
217 | if (res) | ||
218 | continue; | ||
219 | if (res == 0 && prism2_pda_ok(buf)) { | ||
220 | PDEBUG2(DEBUG_EXTRA2, ": OK\n"); | ||
221 | found = 1; | ||
222 | break; | ||
223 | } else { | ||
224 | PDEBUG2(DEBUG_EXTRA2, ": failed\n"); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | prism2_enable_aux_port(dev, 0); | ||
229 | |||
230 | if (!found) { | ||
231 | printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); | ||
232 | kfree(buf); | ||
233 | buf = NULL; | ||
234 | } | ||
235 | |||
236 | return buf; | ||
237 | } | ||
238 | |||
239 | |||
240 | static int prism2_download_volatile(local_info_t *local, | ||
241 | struct prism2_download_data *param) | ||
242 | { | ||
243 | struct net_device *dev = local->dev; | ||
244 | int ret = 0, i; | ||
245 | u16 param0, param1; | ||
246 | |||
247 | if (local->hw_downloading) { | ||
248 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
249 | "request\n", dev->name); | ||
250 | return -1; | ||
251 | } | ||
252 | |||
253 | local->hw_downloading = 1; | ||
254 | if (local->pri_only) { | ||
255 | hfa384x_disable_interrupts(dev); | ||
256 | } else { | ||
257 | prism2_hw_shutdown(dev, 0); | ||
258 | |||
259 | if (prism2_hw_init(dev, 0)) { | ||
260 | printk(KERN_WARNING "%s: Could not initialize card for" | ||
261 | " download\n", dev->name); | ||
262 | ret = -1; | ||
263 | goto out; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if (prism2_enable_aux_port(dev, 1)) { | ||
268 | printk(KERN_WARNING "%s: Could not enable AUX port\n", | ||
269 | dev->name); | ||
270 | ret = -1; | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | param0 = param->start_addr & 0xffff; | ||
275 | param1 = param->start_addr >> 16; | ||
276 | |||
277 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
278 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
279 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
280 | (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), | ||
281 | param0)) { | ||
282 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
283 | dev->name); | ||
284 | ret = -1; | ||
285 | goto out; | ||
286 | } | ||
287 | |||
288 | for (i = 0; i < param->num_areas; i++) { | ||
289 | PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | ||
290 | dev->name, param->data[i].len, param->data[i].addr); | ||
291 | if (hfa384x_to_aux(dev, param->data[i].addr, | ||
292 | param->data[i].len, param->data[i].data)) { | ||
293 | printk(KERN_WARNING "%s: RAM download at 0x%08x " | ||
294 | "(len=%d) failed\n", dev->name, | ||
295 | param->data[i].addr, param->data[i].len); | ||
296 | ret = -1; | ||
297 | goto out; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
302 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
303 | if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
304 | (HFA384X_PROGMODE_DISABLE << 8), param0)) { | ||
305 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
306 | dev->name); | ||
307 | ret = -1; | ||
308 | goto out; | ||
309 | } | ||
310 | /* ProgMode disable causes the hardware to restart itself from the | ||
311 | * given starting address. Give hw some time and ACK command just in | ||
312 | * case restart did not happen. */ | ||
313 | mdelay(5); | ||
314 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
315 | |||
316 | if (prism2_enable_aux_port(dev, 0)) { | ||
317 | printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | ||
318 | dev->name); | ||
319 | /* continue anyway.. restart should have taken care of this */ | ||
320 | } | ||
321 | |||
322 | mdelay(5); | ||
323 | local->hw_downloading = 0; | ||
324 | if (prism2_hw_config(dev, 2)) { | ||
325 | printk(KERN_WARNING "%s: Card configuration after RAM " | ||
326 | "download failed\n", dev->name); | ||
327 | ret = -1; | ||
328 | goto out; | ||
329 | } | ||
330 | |||
331 | out: | ||
332 | local->hw_downloading = 0; | ||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | |||
337 | static int prism2_enable_genesis(local_info_t *local, int hcr) | ||
338 | { | ||
339 | struct net_device *dev = local->dev; | ||
340 | u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; | ||
341 | u8 readbuf[4]; | ||
342 | |||
343 | printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", | ||
344 | dev->name, hcr); | ||
345 | local->func->cor_sreset(local); | ||
346 | hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | ||
347 | local->func->genesis_reset(local, hcr); | ||
348 | |||
349 | /* Readback test */ | ||
350 | hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | ||
351 | hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | ||
352 | hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | ||
353 | |||
354 | if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { | ||
355 | printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", | ||
356 | hcr); | ||
357 | return 0; | ||
358 | } else { | ||
359 | printk(KERN_DEBUG "Readback test failed, HCR 0x%02x " | ||
360 | "write %02x %02x %02x %02x read %02x %02x %02x %02x\n", | ||
361 | hcr, initseq[0], initseq[1], initseq[2], initseq[3], | ||
362 | readbuf[0], readbuf[1], readbuf[2], readbuf[3]); | ||
363 | return 1; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | |||
368 | static int prism2_get_ram_size(local_info_t *local) | ||
369 | { | ||
370 | int ret; | ||
371 | |||
372 | /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | ||
373 | if (prism2_enable_genesis(local, 0x1f) == 0) | ||
374 | ret = 8; | ||
375 | else if (prism2_enable_genesis(local, 0x0f) == 0) | ||
376 | ret = 16; | ||
377 | else | ||
378 | ret = -1; | ||
379 | |||
380 | /* Disable genesis mode */ | ||
381 | local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | |||
387 | static int prism2_download_genesis(local_info_t *local, | ||
388 | struct prism2_download_data *param) | ||
389 | { | ||
390 | struct net_device *dev = local->dev; | ||
391 | int ram16 = 0, i; | ||
392 | int ret = 0; | ||
393 | |||
394 | if (local->hw_downloading) { | ||
395 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
396 | "request\n", dev->name); | ||
397 | return -EBUSY; | ||
398 | } | ||
399 | |||
400 | if (!local->func->genesis_reset || !local->func->cor_sreset) { | ||
401 | printk(KERN_INFO "%s: Genesis mode downloading not supported " | ||
402 | "with this hwmodel\n", dev->name); | ||
403 | return -EOPNOTSUPP; | ||
404 | } | ||
405 | |||
406 | local->hw_downloading = 1; | ||
407 | |||
408 | if (prism2_enable_aux_port(dev, 1)) { | ||
409 | printk(KERN_DEBUG "%s: failed to enable AUX port\n", | ||
410 | dev->name); | ||
411 | ret = -EIO; | ||
412 | goto out; | ||
413 | } | ||
414 | |||
415 | if (local->sram_type == -1) { | ||
416 | /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | ||
417 | if (prism2_enable_genesis(local, 0x1f) == 0) { | ||
418 | ram16 = 0; | ||
419 | PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " | ||
420 | "SRAM\n", dev->name); | ||
421 | } else if (prism2_enable_genesis(local, 0x0f) == 0) { | ||
422 | ram16 = 1; | ||
423 | PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " | ||
424 | "SRAM\n", dev->name); | ||
425 | } else { | ||
426 | printk(KERN_DEBUG "%s: Could not initiate genesis " | ||
427 | "mode\n", dev->name); | ||
428 | ret = -EIO; | ||
429 | goto out; | ||
430 | } | ||
431 | } else { | ||
432 | if (prism2_enable_genesis(local, local->sram_type == 8 ? | ||
433 | 0x1f : 0x0f)) { | ||
434 | printk(KERN_DEBUG "%s: Failed to set Genesis " | ||
435 | "mode (sram_type=%d)\n", dev->name, | ||
436 | local->sram_type); | ||
437 | ret = -EIO; | ||
438 | goto out; | ||
439 | } | ||
440 | ram16 = local->sram_type != 8; | ||
441 | } | ||
442 | |||
443 | for (i = 0; i < param->num_areas; i++) { | ||
444 | PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | ||
445 | dev->name, param->data[i].len, param->data[i].addr); | ||
446 | if (hfa384x_to_aux(dev, param->data[i].addr, | ||
447 | param->data[i].len, param->data[i].data)) { | ||
448 | printk(KERN_WARNING "%s: RAM download at 0x%08x " | ||
449 | "(len=%d) failed\n", dev->name, | ||
450 | param->data[i].addr, param->data[i].len); | ||
451 | ret = -EIO; | ||
452 | goto out; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); | ||
457 | local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); | ||
458 | if (prism2_enable_aux_port(dev, 0)) { | ||
459 | printk(KERN_DEBUG "%s: Failed to disable AUX port\n", | ||
460 | dev->name); | ||
461 | } | ||
462 | |||
463 | mdelay(5); | ||
464 | local->hw_downloading = 0; | ||
465 | |||
466 | PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); | ||
467 | /* | ||
468 | * Make sure the INIT command does not generate a command completion | ||
469 | * event by disabling interrupts. | ||
470 | */ | ||
471 | hfa384x_disable_interrupts(dev); | ||
472 | if (prism2_hw_init(dev, 1)) { | ||
473 | printk(KERN_DEBUG "%s: Initialization after genesis mode " | ||
474 | "download failed\n", dev->name); | ||
475 | ret = -EIO; | ||
476 | goto out; | ||
477 | } | ||
478 | |||
479 | PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); | ||
480 | if (prism2_hw_init2(dev, 1)) { | ||
481 | printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " | ||
482 | "download failed\n", dev->name); | ||
483 | ret = -EIO; | ||
484 | goto out; | ||
485 | } | ||
486 | |||
487 | out: | ||
488 | local->hw_downloading = 0; | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | |||
493 | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD | ||
494 | /* Note! Non-volatile downloading functionality has not yet been tested | ||
495 | * thoroughly and it may corrupt flash image and effectively kill the card that | ||
496 | * is being updated. You have been warned. */ | ||
497 | |||
498 | static inline int prism2_download_block(struct net_device *dev, | ||
499 | u32 addr, u8 *data, | ||
500 | u32 bufaddr, int rest_len) | ||
501 | { | ||
502 | u16 param0, param1; | ||
503 | int block_len; | ||
504 | |||
505 | block_len = rest_len < 4096 ? rest_len : 4096; | ||
506 | |||
507 | param0 = addr & 0xffff; | ||
508 | param1 = addr >> 16; | ||
509 | |||
510 | HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); | ||
511 | HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | ||
512 | |||
513 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
514 | (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), | ||
515 | param0)) { | ||
516 | printk(KERN_WARNING "%s: Flash download command execution " | ||
517 | "failed\n", dev->name); | ||
518 | return -1; | ||
519 | } | ||
520 | |||
521 | if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { | ||
522 | printk(KERN_WARNING "%s: flash download at 0x%08x " | ||
523 | "(len=%d) failed\n", dev->name, addr, block_len); | ||
524 | return -1; | ||
525 | } | ||
526 | |||
527 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
528 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
529 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
530 | (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), | ||
531 | 0)) { | ||
532 | printk(KERN_WARNING "%s: Flash write command execution " | ||
533 | "failed\n", dev->name); | ||
534 | return -1; | ||
535 | } | ||
536 | |||
537 | return block_len; | ||
538 | } | ||
539 | |||
540 | |||
541 | static int prism2_download_nonvolatile(local_info_t *local, | ||
542 | struct prism2_download_data *dl) | ||
543 | { | ||
544 | struct net_device *dev = local->dev; | ||
545 | int ret = 0, i; | ||
546 | struct { | ||
547 | u16 page; | ||
548 | u16 offset; | ||
549 | u16 len; | ||
550 | } dlbuffer; | ||
551 | u32 bufaddr; | ||
552 | |||
553 | if (local->hw_downloading) { | ||
554 | printk(KERN_WARNING "%s: Already downloading - aborting new " | ||
555 | "request\n", dev->name); | ||
556 | return -1; | ||
557 | } | ||
558 | |||
559 | ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, | ||
560 | &dlbuffer, 6, 0); | ||
561 | |||
562 | if (ret < 0) { | ||
563 | printk(KERN_WARNING "%s: Could not read download buffer " | ||
564 | "parameters\n", dev->name); | ||
565 | goto out; | ||
566 | } | ||
567 | |||
568 | dlbuffer.page = le16_to_cpu(dlbuffer.page); | ||
569 | dlbuffer.offset = le16_to_cpu(dlbuffer.offset); | ||
570 | dlbuffer.len = le16_to_cpu(dlbuffer.len); | ||
571 | |||
572 | printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", | ||
573 | dlbuffer.len, dlbuffer.page, dlbuffer.offset); | ||
574 | |||
575 | bufaddr = (dlbuffer.page << 7) + dlbuffer.offset; | ||
576 | |||
577 | local->hw_downloading = 1; | ||
578 | |||
579 | if (!local->pri_only) { | ||
580 | prism2_hw_shutdown(dev, 0); | ||
581 | |||
582 | if (prism2_hw_init(dev, 0)) { | ||
583 | printk(KERN_WARNING "%s: Could not initialize card for" | ||
584 | " download\n", dev->name); | ||
585 | ret = -1; | ||
586 | goto out; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | hfa384x_disable_interrupts(dev); | ||
591 | |||
592 | if (prism2_enable_aux_port(dev, 1)) { | ||
593 | printk(KERN_WARNING "%s: Could not enable AUX port\n", | ||
594 | dev->name); | ||
595 | ret = -1; | ||
596 | goto out; | ||
597 | } | ||
598 | |||
599 | printk(KERN_DEBUG "%s: starting flash download\n", dev->name); | ||
600 | for (i = 0; i < dl->num_areas; i++) { | ||
601 | int rest_len = dl->data[i].len; | ||
602 | int data_off = 0; | ||
603 | |||
604 | while (rest_len > 0) { | ||
605 | int block_len; | ||
606 | |||
607 | block_len = prism2_download_block( | ||
608 | dev, dl->data[i].addr + data_off, | ||
609 | dl->data[i].data + data_off, bufaddr, | ||
610 | rest_len); | ||
611 | |||
612 | if (block_len < 0) { | ||
613 | ret = -1; | ||
614 | goto out; | ||
615 | } | ||
616 | |||
617 | rest_len -= block_len; | ||
618 | data_off += block_len; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | ||
623 | HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | ||
624 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | ||
625 | (HFA384X_PROGMODE_DISABLE << 8), 0)) { | ||
626 | printk(KERN_WARNING "%s: Download command execution failed\n", | ||
627 | dev->name); | ||
628 | ret = -1; | ||
629 | goto out; | ||
630 | } | ||
631 | |||
632 | if (prism2_enable_aux_port(dev, 0)) { | ||
633 | printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | ||
634 | dev->name); | ||
635 | /* continue anyway.. restart should have taken care of this */ | ||
636 | } | ||
637 | |||
638 | mdelay(5); | ||
639 | |||
640 | local->func->hw_reset(dev); | ||
641 | local->hw_downloading = 0; | ||
642 | if (prism2_hw_config(dev, 2)) { | ||
643 | printk(KERN_WARNING "%s: Card configuration after flash " | ||
644 | "download failed\n", dev->name); | ||
645 | ret = -1; | ||
646 | } else { | ||
647 | printk(KERN_INFO "%s: Card initialized successfully after " | ||
648 | "flash download\n", dev->name); | ||
649 | } | ||
650 | |||
651 | out: | ||
652 | local->hw_downloading = 0; | ||
653 | return ret; | ||
654 | } | ||
655 | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
656 | |||
657 | |||
658 | static void prism2_download_free_data(struct prism2_download_data *dl) | ||
659 | { | ||
660 | int i; | ||
661 | |||
662 | if (dl == NULL) | ||
663 | return; | ||
664 | |||
665 | for (i = 0; i < dl->num_areas; i++) | ||
666 | kfree(dl->data[i].data); | ||
667 | kfree(dl); | ||
668 | } | ||
669 | |||
670 | |||
671 | static int prism2_download(local_info_t *local, | ||
672 | struct prism2_download_param *param) | ||
673 | { | ||
674 | int ret = 0; | ||
675 | int i; | ||
676 | u32 total_len = 0; | ||
677 | struct prism2_download_data *dl = NULL; | ||
678 | |||
679 | printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " | ||
680 | "num_areas=%d\n", | ||
681 | param->dl_cmd, param->start_addr, param->num_areas); | ||
682 | |||
683 | if (param->num_areas > 100) { | ||
684 | ret = -EINVAL; | ||
685 | goto out; | ||
686 | } | ||
687 | |||
688 | dl = kmalloc(sizeof(*dl) + param->num_areas * | ||
689 | sizeof(struct prism2_download_data_area), GFP_KERNEL); | ||
690 | if (dl == NULL) { | ||
691 | ret = -ENOMEM; | ||
692 | goto out; | ||
693 | } | ||
694 | memset(dl, 0, sizeof(*dl) + param->num_areas * | ||
695 | sizeof(struct prism2_download_data_area)); | ||
696 | dl->dl_cmd = param->dl_cmd; | ||
697 | dl->start_addr = param->start_addr; | ||
698 | dl->num_areas = param->num_areas; | ||
699 | for (i = 0; i < param->num_areas; i++) { | ||
700 | PDEBUG(DEBUG_EXTRA2, | ||
701 | " area %d: addr=0x%08x len=%d ptr=0x%p\n", | ||
702 | i, param->data[i].addr, param->data[i].len, | ||
703 | param->data[i].ptr); | ||
704 | |||
705 | dl->data[i].addr = param->data[i].addr; | ||
706 | dl->data[i].len = param->data[i].len; | ||
707 | |||
708 | total_len += param->data[i].len; | ||
709 | if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || | ||
710 | total_len > PRISM2_MAX_DOWNLOAD_LEN) { | ||
711 | ret = -E2BIG; | ||
712 | goto out; | ||
713 | } | ||
714 | |||
715 | dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); | ||
716 | if (dl->data[i].data == NULL) { | ||
717 | ret = -ENOMEM; | ||
718 | goto out; | ||
719 | } | ||
720 | |||
721 | if (copy_from_user(dl->data[i].data, param->data[i].ptr, | ||
722 | param->data[i].len)) { | ||
723 | ret = -EFAULT; | ||
724 | goto out; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | switch (param->dl_cmd) { | ||
729 | case PRISM2_DOWNLOAD_VOLATILE: | ||
730 | case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: | ||
731 | ret = prism2_download_volatile(local, dl); | ||
732 | break; | ||
733 | case PRISM2_DOWNLOAD_VOLATILE_GENESIS: | ||
734 | case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: | ||
735 | ret = prism2_download_genesis(local, dl); | ||
736 | break; | ||
737 | case PRISM2_DOWNLOAD_NON_VOLATILE: | ||
738 | #ifdef PRISM2_NON_VOLATILE_DOWNLOAD | ||
739 | ret = prism2_download_nonvolatile(local, dl); | ||
740 | #else /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
741 | printk(KERN_INFO "%s: non-volatile downloading not enabled\n", | ||
742 | local->dev->name); | ||
743 | ret = -EOPNOTSUPP; | ||
744 | #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | ||
745 | break; | ||
746 | default: | ||
747 | printk(KERN_DEBUG "%s: unsupported download command %d\n", | ||
748 | local->dev->name, param->dl_cmd); | ||
749 | ret = -EINVAL; | ||
750 | break; | ||
751 | }; | ||
752 | |||
753 | out: | ||
754 | if (ret == 0 && dl && | ||
755 | param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { | ||
756 | prism2_download_free_data(local->dl_pri); | ||
757 | local->dl_pri = dl; | ||
758 | } else if (ret == 0 && dl && | ||
759 | param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { | ||
760 | prism2_download_free_data(local->dl_sec); | ||
761 | local->dl_sec = dl; | ||
762 | } else | ||
763 | prism2_download_free_data(dl); | ||
764 | |||
765 | return ret; | ||
766 | } | ||
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c new file mode 100644 index 000000000000..e533a663deda --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
@@ -0,0 +1,3445 @@ | |||
1 | /* | ||
2 | * Host AP (software wireless LAN access point) driver for | ||
3 | * Intersil Prism2/2.5/3. | ||
4 | * | ||
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
6 | * <jkmaline@cc.hut.fi> | ||
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. See README and COPYING for | ||
12 | * more details. | ||
13 | * | ||
14 | * FIX: | ||
15 | * - there is currently no way of associating TX packets to correct wds device | ||
16 | * when TX Exc/OK event occurs, so all tx_packets and some | ||
17 | * tx_errors/tx_dropped are added to the main netdevice; using sw_support | ||
18 | * field in txdesc might be used to fix this (using Alloc event to increment | ||
19 | * tx_packets would need some further info in txfid table) | ||
20 | * | ||
21 | * Buffer Access Path (BAP) usage: | ||
22 | * Prism2 cards have two separate BAPs for accessing the card memory. These | ||
23 | * should allow concurrent access to two different frames and the driver | ||
24 | * previously used BAP0 for sending data and BAP1 for receiving data. | ||
25 | * However, there seems to be number of issues with concurrent access and at | ||
26 | * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI | ||
27 | * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between | ||
28 | * host and card memories. BAP0 accesses are protected with local->baplock | ||
29 | * (spin_lock_bh) to prevent concurrent use. | ||
30 | */ | ||
31 | |||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/version.h> | ||
35 | |||
36 | #include <asm/delay.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | |||
39 | #include <linux/slab.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/proc_fs.h> | ||
43 | #include <linux/if_arp.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/random.h> | ||
46 | #include <linux/wait.h> | ||
47 | #include <linux/sched.h> | ||
48 | #include <linux/rtnetlink.h> | ||
49 | #include <linux/wireless.h> | ||
50 | #include <net/iw_handler.h> | ||
51 | #include <net/ieee80211.h> | ||
52 | #include <net/ieee80211_crypt.h> | ||
53 | #include <asm/irq.h> | ||
54 | |||
55 | #include "hostap_80211.h" | ||
56 | #include "hostap.h" | ||
57 | #include "hostap_ap.h" | ||
58 | |||
59 | |||
60 | /* #define final_version */ | ||
61 | |||
62 | static int mtu = 1500; | ||
63 | module_param(mtu, int, 0444); | ||
64 | MODULE_PARM_DESC(mtu, "Maximum transfer unit"); | ||
65 | |||
66 | static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; | ||
67 | module_param_array(channel, int, NULL, 0444); | ||
68 | MODULE_PARM_DESC(channel, "Initial channel"); | ||
69 | |||
70 | static char essid[33] = "test"; | ||
71 | module_param_string(essid, essid, sizeof(essid), 0444); | ||
72 | MODULE_PARM_DESC(essid, "Host AP's ESSID"); | ||
73 | |||
74 | static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; | ||
75 | module_param_array(iw_mode, int, NULL, 0444); | ||
76 | MODULE_PARM_DESC(iw_mode, "Initial operation mode"); | ||
77 | |||
78 | static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | ||
79 | module_param_array(beacon_int, int, NULL, 0444); | ||
80 | MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); | ||
81 | |||
82 | static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | ||
83 | module_param_array(dtim_period, int, NULL, 0444); | ||
84 | MODULE_PARM_DESC(dtim_period, "DTIM period"); | ||
85 | |||
86 | static char dev_template[16] = "wlan%d"; | ||
87 | module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); | ||
88 | MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " | ||
89 | "wlan%d)"); | ||
90 | |||
91 | #ifdef final_version | ||
92 | #define EXTRA_EVENTS_WTERR 0 | ||
93 | #else | ||
94 | /* check WTERR events (Wait Time-out) in development versions */ | ||
95 | #define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR | ||
96 | #endif | ||
97 | |||
98 | /* Events that will be using BAP0 */ | ||
99 | #define HFA384X_BAP0_EVENTS \ | ||
100 | (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) | ||
101 | |||
102 | /* event mask, i.e., events that will result in an interrupt */ | ||
103 | #define HFA384X_EVENT_MASK \ | ||
104 | (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ | ||
105 | HFA384X_EV_CMD | HFA384X_EV_TICK | \ | ||
106 | EXTRA_EVENTS_WTERR) | ||
107 | |||
108 | /* Default TX control flags: use 802.11 headers and request interrupt for | ||
109 | * failed transmits. Frames that request ACK callback, will add | ||
110 | * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. | ||
111 | */ | ||
112 | #define HFA384X_TX_CTRL_FLAGS \ | ||
113 | (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) | ||
114 | |||
115 | |||
116 | /* ca. 1 usec */ | ||
117 | #define HFA384X_CMD_BUSY_TIMEOUT 5000 | ||
118 | #define HFA384X_BAP_BUSY_TIMEOUT 50000 | ||
119 | |||
120 | /* ca. 10 usec */ | ||
121 | #define HFA384X_CMD_COMPL_TIMEOUT 20000 | ||
122 | #define HFA384X_DL_COMPL_TIMEOUT 1000000 | ||
123 | |||
124 | /* Wait times for initialization; yield to other processes to avoid busy | ||
125 | * waiting for long time. */ | ||
126 | #define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ | ||
127 | #define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ | ||
128 | |||
129 | |||
130 | static void prism2_hw_reset(struct net_device *dev); | ||
131 | static void prism2_check_sta_fw_version(local_info_t *local); | ||
132 | |||
133 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
134 | /* hostap_download.c */ | ||
135 | static int prism2_download_aux_dump(struct net_device *dev, | ||
136 | unsigned int addr, int len, u8 *buf); | ||
137 | static u8 * prism2_read_pda(struct net_device *dev); | ||
138 | static int prism2_download(local_info_t *local, | ||
139 | struct prism2_download_param *param); | ||
140 | static void prism2_download_free_data(struct prism2_download_data *dl); | ||
141 | static int prism2_download_volatile(local_info_t *local, | ||
142 | struct prism2_download_data *param); | ||
143 | static int prism2_download_genesis(local_info_t *local, | ||
144 | struct prism2_download_data *param); | ||
145 | static int prism2_get_ram_size(local_info_t *local); | ||
146 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
147 | |||
148 | |||
149 | |||
150 | |||
151 | #ifndef final_version | ||
152 | /* magic value written to SWSUPPORT0 reg. for detecting whether card is still | ||
153 | * present */ | ||
154 | #define HFA384X_MAGIC 0x8A32 | ||
155 | #endif | ||
156 | |||
157 | |||
158 | static u16 hfa384x_read_reg(struct net_device *dev, u16 reg) | ||
159 | { | ||
160 | return HFA384X_INW(reg); | ||
161 | } | ||
162 | |||
163 | |||
164 | static void hfa384x_read_regs(struct net_device *dev, | ||
165 | struct hfa384x_regs *regs) | ||
166 | { | ||
167 | regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); | ||
168 | regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
169 | regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); | ||
170 | regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); | ||
171 | regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); | ||
172 | } | ||
173 | |||
174 | |||
175 | /** | ||
176 | * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) | ||
177 | * @local: pointer to private Host AP driver data | ||
178 | * @entry: Prism2 command queue entry to be freed | ||
179 | * @del_req: request the entry to be removed | ||
180 | * | ||
181 | * Internal helper function for freeing Prism2 command queue entries. | ||
182 | * Caller must have acquired local->cmdlock before calling this function. | ||
183 | */ | ||
184 | static inline void __hostap_cmd_queue_free(local_info_t *local, | ||
185 | struct hostap_cmd_queue *entry, | ||
186 | int del_req) | ||
187 | { | ||
188 | if (del_req) { | ||
189 | entry->del_req = 1; | ||
190 | if (!list_empty(&entry->list)) { | ||
191 | list_del_init(&entry->list); | ||
192 | local->cmd_queue_len--; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) | ||
197 | kfree(entry); | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * hostap_cmd_queue_free - Free Prism2 command queue entry | ||
203 | * @local: pointer to private Host AP driver data | ||
204 | * @entry: Prism2 command queue entry to be freed | ||
205 | * @del_req: request the entry to be removed | ||
206 | * | ||
207 | * Free a Prism2 command queue entry. | ||
208 | */ | ||
209 | static inline void hostap_cmd_queue_free(local_info_t *local, | ||
210 | struct hostap_cmd_queue *entry, | ||
211 | int del_req) | ||
212 | { | ||
213 | unsigned long flags; | ||
214 | |||
215 | spin_lock_irqsave(&local->cmdlock, flags); | ||
216 | __hostap_cmd_queue_free(local, entry, del_req); | ||
217 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
218 | } | ||
219 | |||
220 | |||
221 | /** | ||
222 | * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries | ||
223 | * @local: pointer to private Host AP driver data | ||
224 | */ | ||
225 | static void prism2_clear_cmd_queue(local_info_t *local) | ||
226 | { | ||
227 | struct list_head *ptr, *n; | ||
228 | unsigned long flags; | ||
229 | struct hostap_cmd_queue *entry; | ||
230 | |||
231 | spin_lock_irqsave(&local->cmdlock, flags); | ||
232 | list_for_each_safe(ptr, n, &local->cmd_queue) { | ||
233 | entry = list_entry(ptr, struct hostap_cmd_queue, list); | ||
234 | atomic_inc(&entry->usecnt); | ||
235 | printk(KERN_DEBUG "%s: removed pending cmd_queue entry " | ||
236 | "(type=%d, cmd=0x%04x, param0=0x%04x)\n", | ||
237 | local->dev->name, entry->type, entry->cmd, | ||
238 | entry->param0); | ||
239 | __hostap_cmd_queue_free(local, entry, 1); | ||
240 | } | ||
241 | if (local->cmd_queue_len) { | ||
242 | /* This should not happen; print debug message and clear | ||
243 | * queue length. */ | ||
244 | printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " | ||
245 | "flush\n", local->dev->name, local->cmd_queue_len); | ||
246 | local->cmd_queue_len = 0; | ||
247 | } | ||
248 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * hfa384x_cmd_issue - Issue a Prism2 command to the hardware | ||
254 | * @dev: pointer to net_device | ||
255 | * @entry: Prism2 command queue entry to be issued | ||
256 | */ | ||
257 | static inline int hfa384x_cmd_issue(struct net_device *dev, | ||
258 | struct hostap_cmd_queue *entry) | ||
259 | { | ||
260 | struct hostap_interface *iface; | ||
261 | local_info_t *local; | ||
262 | int tries; | ||
263 | u16 reg; | ||
264 | unsigned long flags; | ||
265 | |||
266 | iface = netdev_priv(dev); | ||
267 | local = iface->local; | ||
268 | |||
269 | if (local->func->card_present && !local->func->card_present(local)) | ||
270 | return -ENODEV; | ||
271 | |||
272 | if (entry->issued) { | ||
273 | printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", | ||
274 | dev->name, entry); | ||
275 | } | ||
276 | |||
277 | /* wait until busy bit is clear; this should always be clear since the | ||
278 | * commands are serialized */ | ||
279 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
280 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
281 | tries--; | ||
282 | udelay(1); | ||
283 | } | ||
284 | #ifndef final_version | ||
285 | if (tries != HFA384X_CMD_BUSY_TIMEOUT) { | ||
286 | prism2_io_debug_error(dev, 1); | ||
287 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " | ||
288 | "for %d usec\n", dev->name, | ||
289 | HFA384X_CMD_BUSY_TIMEOUT - tries); | ||
290 | } | ||
291 | #endif | ||
292 | if (tries == 0) { | ||
293 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
294 | prism2_io_debug_error(dev, 2); | ||
295 | printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " | ||
296 | "reg=0x%04x\n", dev->name, reg); | ||
297 | return -ETIMEDOUT; | ||
298 | } | ||
299 | |||
300 | /* write command */ | ||
301 | spin_lock_irqsave(&local->cmdlock, flags); | ||
302 | HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); | ||
303 | HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); | ||
304 | HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); | ||
305 | entry->issued = 1; | ||
306 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion | ||
314 | * @dev: pointer to net_device | ||
315 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
316 | * @param0: value for Param0 register | ||
317 | * @param1: value for Param1 register (pointer; %NULL if not used) | ||
318 | * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed | ||
319 | * | ||
320 | * Issue given command (possibly after waiting in command queue) and sleep | ||
321 | * until the command is completed (or timed out or interrupted). This can be | ||
322 | * called only from user process context. | ||
323 | */ | ||
324 | static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, | ||
325 | u16 *param1, u16 *resp0) | ||
326 | { | ||
327 | struct hostap_interface *iface; | ||
328 | local_info_t *local; | ||
329 | int err, res, issue, issued = 0; | ||
330 | unsigned long flags; | ||
331 | struct hostap_cmd_queue *entry; | ||
332 | DECLARE_WAITQUEUE(wait, current); | ||
333 | |||
334 | iface = netdev_priv(dev); | ||
335 | local = iface->local; | ||
336 | |||
337 | if (in_interrupt()) { | ||
338 | printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt " | ||
339 | "context\n", dev->name); | ||
340 | return -1; | ||
341 | } | ||
342 | |||
343 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { | ||
344 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
345 | dev->name); | ||
346 | return -1; | ||
347 | } | ||
348 | |||
349 | if (signal_pending(current)) | ||
350 | return -EINTR; | ||
351 | |||
352 | entry = (struct hostap_cmd_queue *) | ||
353 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
354 | if (entry == NULL) { | ||
355 | printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n", | ||
356 | dev->name); | ||
357 | return -ENOMEM; | ||
358 | } | ||
359 | memset(entry, 0, sizeof(*entry)); | ||
360 | atomic_set(&entry->usecnt, 1); | ||
361 | entry->type = CMD_SLEEP; | ||
362 | entry->cmd = cmd; | ||
363 | entry->param0 = param0; | ||
364 | if (param1) | ||
365 | entry->param1 = *param1; | ||
366 | init_waitqueue_head(&entry->compl); | ||
367 | |||
368 | /* prepare to wait for command completion event, but do not sleep yet | ||
369 | */ | ||
370 | add_wait_queue(&entry->compl, &wait); | ||
371 | set_current_state(TASK_INTERRUPTIBLE); | ||
372 | |||
373 | spin_lock_irqsave(&local->cmdlock, flags); | ||
374 | issue = list_empty(&local->cmd_queue); | ||
375 | if (issue) | ||
376 | entry->issuing = 1; | ||
377 | list_add_tail(&entry->list, &local->cmd_queue); | ||
378 | local->cmd_queue_len++; | ||
379 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
380 | |||
381 | err = 0; | ||
382 | if (!issue) | ||
383 | goto wait_completion; | ||
384 | |||
385 | if (signal_pending(current)) | ||
386 | err = -EINTR; | ||
387 | |||
388 | if (!err) { | ||
389 | if (hfa384x_cmd_issue(dev, entry)) | ||
390 | err = -ETIMEDOUT; | ||
391 | else | ||
392 | issued = 1; | ||
393 | } | ||
394 | |||
395 | wait_completion: | ||
396 | if (!err && entry->type != CMD_COMPLETED) { | ||
397 | /* sleep until command is completed or timed out */ | ||
398 | res = schedule_timeout(2 * HZ); | ||
399 | } else | ||
400 | res = -1; | ||
401 | |||
402 | if (!err && signal_pending(current)) | ||
403 | err = -EINTR; | ||
404 | |||
405 | if (err && issued) { | ||
406 | /* the command was issued, so a CmdCompl event should occur | ||
407 | * soon; however, there's a pending signal and | ||
408 | * schedule_timeout() would be interrupted; wait a short period | ||
409 | * of time to avoid removing entry from the list before | ||
410 | * CmdCompl event */ | ||
411 | udelay(300); | ||
412 | } | ||
413 | |||
414 | set_current_state(TASK_RUNNING); | ||
415 | remove_wait_queue(&entry->compl, &wait); | ||
416 | |||
417 | /* If entry->list is still in the list, it must be removed | ||
418 | * first and in this case prism2_cmd_ev() does not yet have | ||
419 | * local reference to it, and the data can be kfree()'d | ||
420 | * here. If the command completion event is still generated, | ||
421 | * it will be assigned to next (possibly) pending command, but | ||
422 | * the driver will reset the card anyway due to timeout | ||
423 | * | ||
424 | * If the entry is not in the list prism2_cmd_ev() has a local | ||
425 | * reference to it, but keeps cmdlock as long as the data is | ||
426 | * needed, so the data can be kfree()'d here. */ | ||
427 | |||
428 | /* FIX: if the entry->list is in the list, it has not been completed | ||
429 | * yet, so removing it here is somewhat wrong.. this could cause | ||
430 | * references to freed memory and next list_del() causing NULL pointer | ||
431 | * dereference.. it would probably be better to leave the entry in the | ||
432 | * list and the list should be emptied during hw reset */ | ||
433 | |||
434 | spin_lock_irqsave(&local->cmdlock, flags); | ||
435 | if (!list_empty(&entry->list)) { | ||
436 | printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " | ||
437 | "(entry=%p, type=%d, res=%d)\n", dev->name, entry, | ||
438 | entry->type, res); | ||
439 | list_del_init(&entry->list); | ||
440 | local->cmd_queue_len--; | ||
441 | } | ||
442 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
443 | |||
444 | if (err) { | ||
445 | printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", | ||
446 | dev->name, err); | ||
447 | res = err; | ||
448 | goto done; | ||
449 | } | ||
450 | |||
451 | if (entry->type != CMD_COMPLETED) { | ||
452 | u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
453 | printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " | ||
454 | "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " | ||
455 | "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, | ||
456 | res, entry, entry->type, entry->cmd, entry->param0, reg, | ||
457 | HFA384X_INW(HFA384X_INTEN_OFF)); | ||
458 | if (reg & HFA384X_EV_CMD) { | ||
459 | /* Command completion event is pending, but the | ||
460 | * interrupt was not delivered - probably an issue | ||
461 | * with pcmcia-cs configuration. */ | ||
462 | printk(KERN_WARNING "%s: interrupt delivery does not " | ||
463 | "seem to work\n", dev->name); | ||
464 | } | ||
465 | prism2_io_debug_error(dev, 3); | ||
466 | res = -ETIMEDOUT; | ||
467 | goto done; | ||
468 | } | ||
469 | |||
470 | if (resp0 != NULL) | ||
471 | *resp0 = entry->resp0; | ||
472 | #ifndef final_version | ||
473 | if (entry->res) { | ||
474 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " | ||
475 | "resp0=0x%04x\n", | ||
476 | dev->name, cmd, entry->res, entry->resp0); | ||
477 | } | ||
478 | #endif /* final_version */ | ||
479 | |||
480 | res = entry->res; | ||
481 | done: | ||
482 | hostap_cmd_queue_free(local, entry, 1); | ||
483 | return res; | ||
484 | } | ||
485 | |||
486 | |||
487 | /** | ||
488 | * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed | ||
489 | * @dev: pointer to net_device | ||
490 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
491 | * @param0: value for Param0 register | ||
492 | * @callback: command completion callback function (%NULL = no callback) | ||
493 | * @context: context data to be given to the callback function | ||
494 | * | ||
495 | * Issue given command (possibly after waiting in command queue) and use | ||
496 | * callback function to indicate command completion. This can be called both | ||
497 | * from user and interrupt context. The callback function will be called in | ||
498 | * hardware IRQ context. It can be %NULL, when no function is called when | ||
499 | * command is completed. | ||
500 | */ | ||
501 | static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, | ||
502 | void (*callback)(struct net_device *dev, | ||
503 | long context, u16 resp0, | ||
504 | u16 status), | ||
505 | long context) | ||
506 | { | ||
507 | struct hostap_interface *iface; | ||
508 | local_info_t *local; | ||
509 | int issue, ret; | ||
510 | unsigned long flags; | ||
511 | struct hostap_cmd_queue *entry; | ||
512 | |||
513 | iface = netdev_priv(dev); | ||
514 | local = iface->local; | ||
515 | |||
516 | if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { | ||
517 | printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | ||
518 | dev->name); | ||
519 | return -1; | ||
520 | } | ||
521 | |||
522 | entry = (struct hostap_cmd_queue *) | ||
523 | kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
524 | if (entry == NULL) { | ||
525 | printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc " | ||
526 | "failed\n", dev->name); | ||
527 | return -ENOMEM; | ||
528 | } | ||
529 | memset(entry, 0, sizeof(*entry)); | ||
530 | atomic_set(&entry->usecnt, 1); | ||
531 | entry->type = CMD_CALLBACK; | ||
532 | entry->cmd = cmd; | ||
533 | entry->param0 = param0; | ||
534 | entry->callback = callback; | ||
535 | entry->context = context; | ||
536 | |||
537 | spin_lock_irqsave(&local->cmdlock, flags); | ||
538 | issue = list_empty(&local->cmd_queue); | ||
539 | if (issue) | ||
540 | entry->issuing = 1; | ||
541 | list_add_tail(&entry->list, &local->cmd_queue); | ||
542 | local->cmd_queue_len++; | ||
543 | spin_unlock_irqrestore(&local->cmdlock, flags); | ||
544 | |||
545 | if (issue && hfa384x_cmd_issue(dev, entry)) | ||
546 | ret = -ETIMEDOUT; | ||
547 | else | ||
548 | ret = 0; | ||
549 | |||
550 | hostap_cmd_queue_free(local, entry, ret); | ||
551 | |||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) | ||
558 | * @dev: pointer to net_device | ||
559 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
560 | * @param0: value for Param0 register | ||
561 | * @io_debug_num: I/O debug error number | ||
562 | * | ||
563 | * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). | ||
564 | */ | ||
565 | static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, | ||
566 | int io_debug_num) | ||
567 | { | ||
568 | int tries; | ||
569 | u16 reg; | ||
570 | |||
571 | /* wait until busy bit is clear; this should always be clear since the | ||
572 | * commands are serialized */ | ||
573 | tries = HFA384X_CMD_BUSY_TIMEOUT; | ||
574 | while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | ||
575 | tries--; | ||
576 | udelay(1); | ||
577 | } | ||
578 | if (tries == 0) { | ||
579 | reg = HFA384X_INW(HFA384X_CMD_OFF); | ||
580 | prism2_io_debug_error(dev, io_debug_num); | ||
581 | printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " | ||
582 | "reg=0x%04x\n", dev->name, io_debug_num, reg); | ||
583 | return -ETIMEDOUT; | ||
584 | } | ||
585 | |||
586 | /* write command */ | ||
587 | HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); | ||
588 | HFA384X_OUTW(cmd, HFA384X_CMD_OFF); | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | |||
594 | /** | ||
595 | * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion | ||
596 | * @dev: pointer to net_device | ||
597 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
598 | * @param0: value for Param0 register | ||
599 | */ | ||
600 | static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) | ||
601 | { | ||
602 | int res, tries; | ||
603 | u16 reg; | ||
604 | |||
605 | res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); | ||
606 | if (res) | ||
607 | return res; | ||
608 | |||
609 | /* wait for command completion */ | ||
610 | if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) | ||
611 | tries = HFA384X_DL_COMPL_TIMEOUT; | ||
612 | else | ||
613 | tries = HFA384X_CMD_COMPL_TIMEOUT; | ||
614 | |||
615 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
616 | tries > 0) { | ||
617 | tries--; | ||
618 | udelay(10); | ||
619 | } | ||
620 | if (tries == 0) { | ||
621 | reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
622 | prism2_io_debug_error(dev, 5); | ||
623 | printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " | ||
624 | "reg=0x%04x\n", dev->name, reg); | ||
625 | return -ETIMEDOUT; | ||
626 | } | ||
627 | |||
628 | res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
629 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | | ||
630 | BIT(8))) >> 8; | ||
631 | #ifndef final_version | ||
632 | if (res) { | ||
633 | printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", | ||
634 | dev->name, cmd, res); | ||
635 | } | ||
636 | #endif | ||
637 | |||
638 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
639 | |||
640 | return res; | ||
641 | } | ||
642 | |||
643 | |||
644 | /** | ||
645 | * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion | ||
646 | * @dev: pointer to net_device | ||
647 | * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | ||
648 | * @param0: value for Param0 register | ||
649 | */ | ||
650 | static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, | ||
651 | u16 param0) | ||
652 | { | ||
653 | return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * prism2_cmd_ev - Prism2 command completion event handler | ||
659 | * @dev: pointer to net_device | ||
660 | * | ||
661 | * Interrupt handler for command completion events. Called by the main | ||
662 | * interrupt handler in hardware IRQ context. Read Resp0 and status registers | ||
663 | * from the hardware and ACK the event. Depending on the issued command type | ||
664 | * either wake up the sleeping process that is waiting for command completion | ||
665 | * or call the callback function. Issue the next command, if one is pending. | ||
666 | */ | ||
667 | static void prism2_cmd_ev(struct net_device *dev) | ||
668 | { | ||
669 | struct hostap_interface *iface; | ||
670 | local_info_t *local; | ||
671 | struct hostap_cmd_queue *entry = NULL; | ||
672 | |||
673 | iface = netdev_priv(dev); | ||
674 | local = iface->local; | ||
675 | |||
676 | spin_lock(&local->cmdlock); | ||
677 | if (!list_empty(&local->cmd_queue)) { | ||
678 | entry = list_entry(local->cmd_queue.next, | ||
679 | struct hostap_cmd_queue, list); | ||
680 | atomic_inc(&entry->usecnt); | ||
681 | list_del_init(&entry->list); | ||
682 | local->cmd_queue_len--; | ||
683 | |||
684 | if (!entry->issued) { | ||
685 | printk(KERN_DEBUG "%s: Command completion event, but " | ||
686 | "cmd not issued\n", dev->name); | ||
687 | __hostap_cmd_queue_free(local, entry, 1); | ||
688 | entry = NULL; | ||
689 | } | ||
690 | } | ||
691 | spin_unlock(&local->cmdlock); | ||
692 | |||
693 | if (!entry) { | ||
694 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
695 | printk(KERN_DEBUG "%s: Command completion event, but no " | ||
696 | "pending commands\n", dev->name); | ||
697 | return; | ||
698 | } | ||
699 | |||
700 | entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); | ||
701 | entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & | ||
702 | (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | | ||
703 | BIT(9) | BIT(8))) >> 8; | ||
704 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
705 | |||
706 | /* TODO: rest of the CmdEv handling could be moved to tasklet */ | ||
707 | if (entry->type == CMD_SLEEP) { | ||
708 | entry->type = CMD_COMPLETED; | ||
709 | wake_up_interruptible(&entry->compl); | ||
710 | } else if (entry->type == CMD_CALLBACK) { | ||
711 | if (entry->callback) | ||
712 | entry->callback(dev, entry->context, entry->resp0, | ||
713 | entry->res); | ||
714 | } else { | ||
715 | printk(KERN_DEBUG "%s: Invalid command completion type %d\n", | ||
716 | dev->name, entry->type); | ||
717 | } | ||
718 | hostap_cmd_queue_free(local, entry, 1); | ||
719 | |||
720 | /* issue next command, if pending */ | ||
721 | entry = NULL; | ||
722 | spin_lock(&local->cmdlock); | ||
723 | if (!list_empty(&local->cmd_queue)) { | ||
724 | entry = list_entry(local->cmd_queue.next, | ||
725 | struct hostap_cmd_queue, list); | ||
726 | if (entry->issuing) { | ||
727 | /* hfa384x_cmd() has already started issuing this | ||
728 | * command, so do not start here */ | ||
729 | entry = NULL; | ||
730 | } | ||
731 | if (entry) | ||
732 | atomic_inc(&entry->usecnt); | ||
733 | } | ||
734 | spin_unlock(&local->cmdlock); | ||
735 | |||
736 | if (entry) { | ||
737 | /* issue next command; if command issuing fails, remove the | ||
738 | * entry from cmd_queue */ | ||
739 | int res = hfa384x_cmd_issue(dev, entry); | ||
740 | spin_lock(&local->cmdlock); | ||
741 | __hostap_cmd_queue_free(local, entry, res); | ||
742 | spin_unlock(&local->cmdlock); | ||
743 | } | ||
744 | } | ||
745 | |||
746 | |||
747 | static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off) | ||
748 | { | ||
749 | int tries = HFA384X_BAP_BUSY_TIMEOUT; | ||
750 | int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
751 | |||
752 | while (res && tries > 0) { | ||
753 | tries--; | ||
754 | udelay(1); | ||
755 | res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | ||
756 | } | ||
757 | return res; | ||
758 | } | ||
759 | |||
760 | |||
761 | /* Offset must be even */ | ||
762 | static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, | ||
763 | int offset) | ||
764 | { | ||
765 | u16 o_off, s_off; | ||
766 | int ret = 0; | ||
767 | |||
768 | if (offset % 2 || bap > 1) | ||
769 | return -EINVAL; | ||
770 | |||
771 | if (bap == BAP1) { | ||
772 | o_off = HFA384X_OFFSET1_OFF; | ||
773 | s_off = HFA384X_SELECT1_OFF; | ||
774 | } else { | ||
775 | o_off = HFA384X_OFFSET0_OFF; | ||
776 | s_off = HFA384X_SELECT0_OFF; | ||
777 | } | ||
778 | |||
779 | if (hfa384x_wait_offset(dev, o_off)) { | ||
780 | prism2_io_debug_error(dev, 7); | ||
781 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", | ||
782 | dev->name); | ||
783 | ret = -ETIMEDOUT; | ||
784 | goto out; | ||
785 | } | ||
786 | |||
787 | HFA384X_OUTW(id, s_off); | ||
788 | HFA384X_OUTW(offset, o_off); | ||
789 | |||
790 | if (hfa384x_wait_offset(dev, o_off)) { | ||
791 | prism2_io_debug_error(dev, 8); | ||
792 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", | ||
793 | dev->name); | ||
794 | ret = -ETIMEDOUT; | ||
795 | goto out; | ||
796 | } | ||
797 | #ifndef final_version | ||
798 | if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { | ||
799 | prism2_io_debug_error(dev, 9); | ||
800 | printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " | ||
801 | "(%d,0x04%x,%d); reg=0x%04x\n", | ||
802 | dev->name, bap, id, offset, HFA384X_INW(o_off)); | ||
803 | ret = -EINVAL; | ||
804 | } | ||
805 | #endif | ||
806 | |||
807 | out: | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | |||
812 | static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, | ||
813 | int exact_len) | ||
814 | { | ||
815 | struct hostap_interface *iface; | ||
816 | local_info_t *local; | ||
817 | int res, rlen = 0; | ||
818 | struct hfa384x_rid_hdr rec; | ||
819 | |||
820 | iface = netdev_priv(dev); | ||
821 | local = iface->local; | ||
822 | |||
823 | if (local->no_pri) { | ||
824 | printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " | ||
825 | "f/w\n", dev->name, rid, len); | ||
826 | return -ENOTTY; /* Well.. not really correct, but return | ||
827 | * something unique enough.. */ | ||
828 | } | ||
829 | |||
830 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
831 | local->hw_downloading) | ||
832 | return -ENODEV; | ||
833 | |||
834 | res = down_interruptible(&local->rid_bap_sem); | ||
835 | if (res) | ||
836 | return res; | ||
837 | |||
838 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); | ||
839 | if (res) { | ||
840 | printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " | ||
841 | "(res=%d, rid=%04x, len=%d)\n", | ||
842 | dev->name, res, rid, len); | ||
843 | up(&local->rid_bap_sem); | ||
844 | return res; | ||
845 | } | ||
846 | |||
847 | spin_lock_bh(&local->baplock); | ||
848 | |||
849 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
850 | if (!res) | ||
851 | res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); | ||
852 | |||
853 | if (le16_to_cpu(rec.len) == 0) { | ||
854 | /* RID not available */ | ||
855 | res = -ENODATA; | ||
856 | } | ||
857 | |||
858 | rlen = (le16_to_cpu(rec.len) - 1) * 2; | ||
859 | if (!res && exact_len && rlen != len) { | ||
860 | printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " | ||
861 | "rid=0x%04x, len=%d (expected %d)\n", | ||
862 | dev->name, rid, rlen, len); | ||
863 | res = -ENODATA; | ||
864 | } | ||
865 | |||
866 | if (!res) | ||
867 | res = hfa384x_from_bap(dev, BAP0, buf, len); | ||
868 | |||
869 | spin_unlock_bh(&local->baplock); | ||
870 | up(&local->rid_bap_sem); | ||
871 | |||
872 | if (res) { | ||
873 | if (res != -ENODATA) | ||
874 | printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " | ||
875 | "len=%d) - failed - res=%d\n", dev->name, rid, | ||
876 | len, res); | ||
877 | if (res == -ETIMEDOUT) | ||
878 | prism2_hw_reset(dev); | ||
879 | return res; | ||
880 | } | ||
881 | |||
882 | return rlen; | ||
883 | } | ||
884 | |||
885 | |||
886 | static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) | ||
887 | { | ||
888 | struct hostap_interface *iface; | ||
889 | local_info_t *local; | ||
890 | struct hfa384x_rid_hdr rec; | ||
891 | int res; | ||
892 | |||
893 | iface = netdev_priv(dev); | ||
894 | local = iface->local; | ||
895 | |||
896 | if (local->no_pri) { | ||
897 | printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " | ||
898 | "f/w\n", dev->name, rid, len); | ||
899 | return -ENOTTY; /* Well.. not really correct, but return | ||
900 | * something unique enough.. */ | ||
901 | } | ||
902 | |||
903 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
904 | local->hw_downloading) | ||
905 | return -ENODEV; | ||
906 | |||
907 | rec.rid = cpu_to_le16(rid); | ||
908 | /* RID len in words and +1 for rec.rid */ | ||
909 | rec.len = cpu_to_le16(len / 2 + len % 2 + 1); | ||
910 | |||
911 | res = down_interruptible(&local->rid_bap_sem); | ||
912 | if (res) | ||
913 | return res; | ||
914 | |||
915 | spin_lock_bh(&local->baplock); | ||
916 | res = hfa384x_setup_bap(dev, BAP0, rid, 0); | ||
917 | if (!res) | ||
918 | res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); | ||
919 | if (!res) | ||
920 | res = hfa384x_to_bap(dev, BAP0, buf, len); | ||
921 | spin_unlock_bh(&local->baplock); | ||
922 | |||
923 | if (res) { | ||
924 | printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " | ||
925 | "failed - res=%d\n", dev->name, rid, len, res); | ||
926 | up(&local->rid_bap_sem); | ||
927 | return res; | ||
928 | } | ||
929 | |||
930 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); | ||
931 | up(&local->rid_bap_sem); | ||
932 | if (res) { | ||
933 | printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " | ||
934 | "failed (res=%d, rid=%04x, len=%d)\n", | ||
935 | dev->name, res, rid, len); | ||
936 | return res; | ||
937 | } | ||
938 | |||
939 | if (res == -ETIMEDOUT) | ||
940 | prism2_hw_reset(dev); | ||
941 | |||
942 | return res; | ||
943 | } | ||
944 | |||
945 | |||
946 | static void hfa384x_disable_interrupts(struct net_device *dev) | ||
947 | { | ||
948 | /* disable interrupts and clear event status */ | ||
949 | HFA384X_OUTW(0, HFA384X_INTEN_OFF); | ||
950 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
951 | } | ||
952 | |||
953 | |||
954 | static void hfa384x_enable_interrupts(struct net_device *dev) | ||
955 | { | ||
956 | /* ack pending events and enable interrupts from selected events */ | ||
957 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
958 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
959 | } | ||
960 | |||
961 | |||
962 | static void hfa384x_events_no_bap0(struct net_device *dev) | ||
963 | { | ||
964 | HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, | ||
965 | HFA384X_INTEN_OFF); | ||
966 | } | ||
967 | |||
968 | |||
969 | static void hfa384x_events_all(struct net_device *dev) | ||
970 | { | ||
971 | HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | ||
972 | } | ||
973 | |||
974 | |||
975 | static void hfa384x_events_only_cmd(struct net_device *dev) | ||
976 | { | ||
977 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); | ||
978 | } | ||
979 | |||
980 | |||
981 | static u16 hfa384x_allocate_fid(struct net_device *dev, int len) | ||
982 | { | ||
983 | u16 fid; | ||
984 | unsigned long delay; | ||
985 | |||
986 | /* FIX: this could be replace with hfa384x_cmd() if the Alloc event | ||
987 | * below would be handled like CmdCompl event (sleep here, wake up from | ||
988 | * interrupt handler */ | ||
989 | if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { | ||
990 | printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", | ||
991 | dev->name, len); | ||
992 | return 0xffff; | ||
993 | } | ||
994 | |||
995 | delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; | ||
996 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && | ||
997 | time_before(jiffies, delay)) | ||
998 | yield(); | ||
999 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { | ||
1000 | printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); | ||
1001 | return 0xffff; | ||
1002 | } | ||
1003 | |||
1004 | fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); | ||
1005 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
1006 | |||
1007 | return fid; | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | static int prism2_reset_port(struct net_device *dev) | ||
1012 | { | ||
1013 | struct hostap_interface *iface; | ||
1014 | local_info_t *local; | ||
1015 | int res; | ||
1016 | |||
1017 | iface = netdev_priv(dev); | ||
1018 | local = iface->local; | ||
1019 | |||
1020 | if (!local->dev_enabled) | ||
1021 | return 0; | ||
1022 | |||
1023 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, | ||
1024 | NULL, NULL); | ||
1025 | if (res) | ||
1026 | printk(KERN_DEBUG "%s: reset port failed to disable port\n", | ||
1027 | dev->name); | ||
1028 | else { | ||
1029 | res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, | ||
1030 | NULL, NULL); | ||
1031 | if (res) | ||
1032 | printk(KERN_DEBUG "%s: reset port failed to enable " | ||
1033 | "port\n", dev->name); | ||
1034 | } | ||
1035 | |||
1036 | /* It looks like at least some STA firmware versions reset | ||
1037 | * fragmentation threshold back to 2346 after enable command. Restore | ||
1038 | * the configured value, if it differs from this default. */ | ||
1039 | if (local->fragm_threshold != 2346 && | ||
1040 | hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1041 | local->fragm_threshold)) { | ||
1042 | printk(KERN_DEBUG "%s: failed to restore fragmentation " | ||
1043 | "threshold (%d) after Port0 enable\n", | ||
1044 | dev->name, local->fragm_threshold); | ||
1045 | } | ||
1046 | |||
1047 | return res; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | static int prism2_get_version_info(struct net_device *dev, u16 rid, | ||
1052 | const char *txt) | ||
1053 | { | ||
1054 | struct hfa384x_comp_ident comp; | ||
1055 | struct hostap_interface *iface; | ||
1056 | local_info_t *local; | ||
1057 | |||
1058 | iface = netdev_priv(dev); | ||
1059 | local = iface->local; | ||
1060 | |||
1061 | if (local->no_pri) { | ||
1062 | /* PRI f/w not yet available - cannot read RIDs */ | ||
1063 | return -1; | ||
1064 | } | ||
1065 | if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { | ||
1066 | printk(KERN_DEBUG "Could not get RID for component %s\n", txt); | ||
1067 | return -1; | ||
1068 | } | ||
1069 | |||
1070 | printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, | ||
1071 | __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), | ||
1072 | __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); | ||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | static int prism2_setup_rids(struct net_device *dev) | ||
1078 | { | ||
1079 | struct hostap_interface *iface; | ||
1080 | local_info_t *local; | ||
1081 | u16 tmp; | ||
1082 | int ret = 0; | ||
1083 | |||
1084 | iface = netdev_priv(dev); | ||
1085 | local = iface->local; | ||
1086 | |||
1087 | hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); | ||
1088 | |||
1089 | if (!local->fw_ap) { | ||
1090 | tmp = hostap_get_porttype(local); | ||
1091 | ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); | ||
1092 | if (ret) { | ||
1093 | printk("%s: Port type setting to %d failed\n", | ||
1094 | dev->name, tmp); | ||
1095 | goto fail; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | /* Setting SSID to empty string seems to kill the card in Host AP mode | ||
1100 | */ | ||
1101 | if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { | ||
1102 | ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, | ||
1103 | local->essid); | ||
1104 | if (ret) { | ||
1105 | printk("%s: AP own SSID setting failed\n", dev->name); | ||
1106 | goto fail; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, | ||
1111 | PRISM2_DATA_MAXLEN); | ||
1112 | if (ret) { | ||
1113 | printk("%s: MAC data length setting to %d failed\n", | ||
1114 | dev->name, PRISM2_DATA_MAXLEN); | ||
1115 | goto fail; | ||
1116 | } | ||
1117 | |||
1118 | if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { | ||
1119 | printk("%s: Channel list read failed\n", dev->name); | ||
1120 | ret = -EINVAL; | ||
1121 | goto fail; | ||
1122 | } | ||
1123 | local->channel_mask = __le16_to_cpu(tmp); | ||
1124 | |||
1125 | if (local->channel < 1 || local->channel > 14 || | ||
1126 | !(local->channel_mask & (1 << (local->channel - 1)))) { | ||
1127 | printk(KERN_WARNING "%s: Channel setting out of range " | ||
1128 | "(%d)!\n", dev->name, local->channel); | ||
1129 | ret = -EBUSY; | ||
1130 | goto fail; | ||
1131 | } | ||
1132 | |||
1133 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); | ||
1134 | if (ret) { | ||
1135 | printk("%s: Channel setting to %d failed\n", | ||
1136 | dev->name, local->channel); | ||
1137 | goto fail; | ||
1138 | } | ||
1139 | |||
1140 | ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, | ||
1141 | local->beacon_int); | ||
1142 | if (ret) { | ||
1143 | printk("%s: Beacon interval setting to %d failed\n", | ||
1144 | dev->name, local->beacon_int); | ||
1145 | /* this may fail with Symbol/Lucent firmware */ | ||
1146 | if (ret == -ETIMEDOUT) | ||
1147 | goto fail; | ||
1148 | } | ||
1149 | |||
1150 | ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, | ||
1151 | local->dtim_period); | ||
1152 | if (ret) { | ||
1153 | printk("%s: DTIM period setting to %d failed\n", | ||
1154 | dev->name, local->dtim_period); | ||
1155 | /* this may fail with Symbol/Lucent firmware */ | ||
1156 | if (ret == -ETIMEDOUT) | ||
1157 | goto fail; | ||
1158 | } | ||
1159 | |||
1160 | ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | ||
1161 | local->is_promisc); | ||
1162 | if (ret) | ||
1163 | printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", | ||
1164 | dev->name, local->is_promisc); | ||
1165 | |||
1166 | if (!local->fw_ap) { | ||
1167 | ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, | ||
1168 | local->essid); | ||
1169 | if (ret) { | ||
1170 | printk("%s: Desired SSID setting failed\n", dev->name); | ||
1171 | goto fail; | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and | ||
1176 | * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic | ||
1177 | * rates */ | ||
1178 | if (local->tx_rate_control == 0) { | ||
1179 | local->tx_rate_control = | ||
1180 | HFA384X_RATES_1MBPS | | ||
1181 | HFA384X_RATES_2MBPS | | ||
1182 | HFA384X_RATES_5MBPS | | ||
1183 | HFA384X_RATES_11MBPS; | ||
1184 | } | ||
1185 | if (local->basic_rates == 0) | ||
1186 | local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; | ||
1187 | |||
1188 | if (!local->fw_ap) { | ||
1189 | ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
1190 | local->tx_rate_control); | ||
1191 | if (ret) { | ||
1192 | printk("%s: TXRateControl setting to %d failed\n", | ||
1193 | dev->name, local->tx_rate_control); | ||
1194 | goto fail; | ||
1195 | } | ||
1196 | |||
1197 | ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
1198 | local->tx_rate_control); | ||
1199 | if (ret) { | ||
1200 | printk("%s: cnfSupportedRates setting to %d failed\n", | ||
1201 | dev->name, local->tx_rate_control); | ||
1202 | } | ||
1203 | |||
1204 | ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
1205 | local->basic_rates); | ||
1206 | if (ret) { | ||
1207 | printk("%s: cnfBasicRates setting to %d failed\n", | ||
1208 | dev->name, local->basic_rates); | ||
1209 | } | ||
1210 | |||
1211 | ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); | ||
1212 | if (ret) { | ||
1213 | printk("%s: Create IBSS setting to 1 failed\n", | ||
1214 | dev->name); | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | if (local->name_set) | ||
1219 | (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, | ||
1220 | local->name); | ||
1221 | |||
1222 | if (hostap_set_encryption(local)) { | ||
1223 | printk(KERN_INFO "%s: could not configure encryption\n", | ||
1224 | dev->name); | ||
1225 | } | ||
1226 | |||
1227 | (void) hostap_set_antsel(local); | ||
1228 | |||
1229 | if (hostap_set_roaming(local)) { | ||
1230 | printk(KERN_INFO "%s: could not set host roaming\n", | ||
1231 | dev->name); | ||
1232 | } | ||
1233 | |||
1234 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && | ||
1235 | hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) | ||
1236 | printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", | ||
1237 | dev->name, local->enh_sec); | ||
1238 | |||
1239 | /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently | ||
1240 | * not working correctly (last seven counters report bogus values). | ||
1241 | * This has been fixed in 0.8.2, so enable 32-bit tallies only | ||
1242 | * beginning with that firmware version. Another bug fix for 32-bit | ||
1243 | * tallies in 1.4.0; should 16-bit tallies be used for some other | ||
1244 | * versions, too? */ | ||
1245 | if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { | ||
1246 | if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { | ||
1247 | printk(KERN_INFO "%s: cnfThirty2Tally setting " | ||
1248 | "failed\n", dev->name); | ||
1249 | local->tallies32 = 0; | ||
1250 | } else | ||
1251 | local->tallies32 = 1; | ||
1252 | } else | ||
1253 | local->tallies32 = 0; | ||
1254 | |||
1255 | hostap_set_auth_algs(local); | ||
1256 | |||
1257 | if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
1258 | local->fragm_threshold)) { | ||
1259 | printk(KERN_INFO "%s: setting FragmentationThreshold to %d " | ||
1260 | "failed\n", dev->name, local->fragm_threshold); | ||
1261 | } | ||
1262 | |||
1263 | if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, | ||
1264 | local->rts_threshold)) { | ||
1265 | printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", | ||
1266 | dev->name, local->rts_threshold); | ||
1267 | } | ||
1268 | |||
1269 | if (local->manual_retry_count >= 0 && | ||
1270 | hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1271 | local->manual_retry_count)) { | ||
1272 | printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", | ||
1273 | dev->name, local->manual_retry_count); | ||
1274 | } | ||
1275 | |||
1276 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && | ||
1277 | hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { | ||
1278 | local->rssi_to_dBm = le16_to_cpu(tmp); | ||
1279 | } | ||
1280 | |||
1281 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && | ||
1282 | hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { | ||
1283 | printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", | ||
1284 | dev->name); | ||
1285 | } | ||
1286 | |||
1287 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && | ||
1288 | hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, | ||
1289 | local->generic_elem, local->generic_elem_len)) { | ||
1290 | printk(KERN_INFO "%s: setting genericElement failed\n", | ||
1291 | dev->name); | ||
1292 | } | ||
1293 | |||
1294 | fail: | ||
1295 | return ret; | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | static int prism2_hw_init(struct net_device *dev, int initial) | ||
1300 | { | ||
1301 | struct hostap_interface *iface; | ||
1302 | local_info_t *local; | ||
1303 | int ret, first = 1; | ||
1304 | unsigned long start, delay; | ||
1305 | |||
1306 | PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); | ||
1307 | |||
1308 | iface = netdev_priv(dev); | ||
1309 | local = iface->local; | ||
1310 | |||
1311 | clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); | ||
1312 | |||
1313 | init: | ||
1314 | /* initialize HFA 384x */ | ||
1315 | ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); | ||
1316 | if (ret) { | ||
1317 | printk(KERN_INFO "%s: first command failed - assuming card " | ||
1318 | "does not have primary firmware\n", dev_info); | ||
1319 | } | ||
1320 | |||
1321 | if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1322 | /* EvStat has Cmd bit set in some cases, so retry once if no | ||
1323 | * wait was needed */ | ||
1324 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1325 | printk(KERN_DEBUG "%s: init command completed too quickly - " | ||
1326 | "retrying\n", dev->name); | ||
1327 | first = 0; | ||
1328 | goto init; | ||
1329 | } | ||
1330 | |||
1331 | start = jiffies; | ||
1332 | delay = jiffies + HFA384X_INIT_TIMEOUT; | ||
1333 | while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | ||
1334 | time_before(jiffies, delay)) | ||
1335 | yield(); | ||
1336 | if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | ||
1337 | printk(KERN_DEBUG "%s: assuming no Primary image in " | ||
1338 | "flash - card initialization not completed\n", | ||
1339 | dev_info); | ||
1340 | local->no_pri = 1; | ||
1341 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1342 | if (local->sram_type == -1) | ||
1343 | local->sram_type = prism2_get_ram_size(local); | ||
1344 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1345 | return 1; | ||
1346 | } | ||
1347 | local->no_pri = 0; | ||
1348 | printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", | ||
1349 | (jiffies - start) * 1000 / HZ); | ||
1350 | HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | ||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | |||
1355 | static int prism2_hw_init2(struct net_device *dev, int initial) | ||
1356 | { | ||
1357 | struct hostap_interface *iface; | ||
1358 | local_info_t *local; | ||
1359 | int i; | ||
1360 | |||
1361 | iface = netdev_priv(dev); | ||
1362 | local = iface->local; | ||
1363 | |||
1364 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1365 | kfree(local->pda); | ||
1366 | if (local->no_pri) | ||
1367 | local->pda = NULL; | ||
1368 | else | ||
1369 | local->pda = prism2_read_pda(dev); | ||
1370 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1371 | |||
1372 | hfa384x_disable_interrupts(dev); | ||
1373 | |||
1374 | #ifndef final_version | ||
1375 | HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); | ||
1376 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
1377 | printk("SWSUPPORT0 write/read failed: %04X != %04X\n", | ||
1378 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); | ||
1379 | goto failed; | ||
1380 | } | ||
1381 | #endif | ||
1382 | |||
1383 | if (initial || local->pri_only) { | ||
1384 | hfa384x_events_only_cmd(dev); | ||
1385 | /* get card version information */ | ||
1386 | if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || | ||
1387 | prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { | ||
1388 | hfa384x_disable_interrupts(dev); | ||
1389 | goto failed; | ||
1390 | } | ||
1391 | |||
1392 | if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { | ||
1393 | printk(KERN_DEBUG "%s: Failed to read STA f/w version " | ||
1394 | "- only Primary f/w present\n", dev->name); | ||
1395 | local->pri_only = 1; | ||
1396 | return 0; | ||
1397 | } | ||
1398 | local->pri_only = 0; | ||
1399 | hfa384x_disable_interrupts(dev); | ||
1400 | } | ||
1401 | |||
1402 | /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and | ||
1403 | * enable interrupts before this. This would also require some sort of | ||
1404 | * sleeping AllocEv waiting */ | ||
1405 | |||
1406 | /* allocate TX FIDs */ | ||
1407 | local->txfid_len = PRISM2_TXFID_LEN; | ||
1408 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) { | ||
1409 | local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); | ||
1410 | if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { | ||
1411 | local->txfid[i] = hfa384x_allocate_fid(dev, 1600); | ||
1412 | if (local->txfid[i] != 0xffff) { | ||
1413 | printk(KERN_DEBUG "%s: Using shorter TX FID " | ||
1414 | "(1600 bytes)\n", dev->name); | ||
1415 | local->txfid_len = 1600; | ||
1416 | } | ||
1417 | } | ||
1418 | if (local->txfid[i] == 0xffff) | ||
1419 | goto failed; | ||
1420 | local->intransmitfid[i] = PRISM2_TXFID_EMPTY; | ||
1421 | } | ||
1422 | |||
1423 | hfa384x_events_only_cmd(dev); | ||
1424 | |||
1425 | if (initial) { | ||
1426 | struct list_head *ptr; | ||
1427 | prism2_check_sta_fw_version(local); | ||
1428 | |||
1429 | if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, | ||
1430 | &dev->dev_addr, 6, 1) < 0) { | ||
1431 | printk("%s: could not get own MAC address\n", | ||
1432 | dev->name); | ||
1433 | } | ||
1434 | list_for_each(ptr, &local->hostap_interfaces) { | ||
1435 | iface = list_entry(ptr, struct hostap_interface, list); | ||
1436 | memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN); | ||
1437 | } | ||
1438 | } else if (local->fw_ap) | ||
1439 | prism2_check_sta_fw_version(local); | ||
1440 | |||
1441 | prism2_setup_rids(dev); | ||
1442 | |||
1443 | /* MAC is now configured, but port 0 is not yet enabled */ | ||
1444 | return 0; | ||
1445 | |||
1446 | failed: | ||
1447 | if (!local->no_pri) | ||
1448 | printk(KERN_WARNING "%s: Initialization failed\n", dev_info); | ||
1449 | return 1; | ||
1450 | } | ||
1451 | |||
1452 | |||
1453 | static int prism2_hw_enable(struct net_device *dev, int initial) | ||
1454 | { | ||
1455 | struct hostap_interface *iface; | ||
1456 | local_info_t *local; | ||
1457 | int was_resetting; | ||
1458 | |||
1459 | iface = netdev_priv(dev); | ||
1460 | local = iface->local; | ||
1461 | was_resetting = local->hw_resetting; | ||
1462 | |||
1463 | if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { | ||
1464 | printk("%s: MAC port 0 enabling failed\n", dev->name); | ||
1465 | return 1; | ||
1466 | } | ||
1467 | |||
1468 | local->hw_ready = 1; | ||
1469 | local->hw_reset_tries = 0; | ||
1470 | local->hw_resetting = 0; | ||
1471 | hfa384x_enable_interrupts(dev); | ||
1472 | |||
1473 | /* at least D-Link DWL-650 seems to require additional port reset | ||
1474 | * before it starts acting as an AP, so reset port automatically | ||
1475 | * here just in case */ | ||
1476 | if (initial && prism2_reset_port(dev)) { | ||
1477 | printk("%s: MAC port 0 reseting failed\n", dev->name); | ||
1478 | return 1; | ||
1479 | } | ||
1480 | |||
1481 | if (was_resetting && netif_queue_stopped(dev)) { | ||
1482 | /* If hw_reset() was called during pending transmit, netif | ||
1483 | * queue was stopped. Wake it up now since the wlan card has | ||
1484 | * been resetted. */ | ||
1485 | netif_wake_queue(dev); | ||
1486 | } | ||
1487 | |||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | static int prism2_hw_config(struct net_device *dev, int initial) | ||
1493 | { | ||
1494 | struct hostap_interface *iface; | ||
1495 | local_info_t *local; | ||
1496 | |||
1497 | iface = netdev_priv(dev); | ||
1498 | local = iface->local; | ||
1499 | |||
1500 | if (local->hw_downloading) | ||
1501 | return 1; | ||
1502 | |||
1503 | if (prism2_hw_init(dev, initial)) { | ||
1504 | return local->no_pri ? 0 : 1; | ||
1505 | } | ||
1506 | |||
1507 | if (prism2_hw_init2(dev, initial)) | ||
1508 | return 1; | ||
1509 | |||
1510 | /* Enable firmware if secondary image is loaded and at least one of the | ||
1511 | * netdevices is up. */ | ||
1512 | if (!local->pri_only && | ||
1513 | (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { | ||
1514 | if (!local->dev_enabled) | ||
1515 | prism2_callback(local, PRISM2_CALLBACK_ENABLE); | ||
1516 | local->dev_enabled = 1; | ||
1517 | return prism2_hw_enable(dev, initial); | ||
1518 | } | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | |||
1524 | static void prism2_hw_shutdown(struct net_device *dev, int no_disable) | ||
1525 | { | ||
1526 | struct hostap_interface *iface; | ||
1527 | local_info_t *local; | ||
1528 | |||
1529 | iface = netdev_priv(dev); | ||
1530 | local = iface->local; | ||
1531 | |||
1532 | /* Allow only command completion events during disable */ | ||
1533 | hfa384x_events_only_cmd(dev); | ||
1534 | |||
1535 | local->hw_ready = 0; | ||
1536 | if (local->dev_enabled) | ||
1537 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
1538 | local->dev_enabled = 0; | ||
1539 | |||
1540 | if (local->func->card_present && !local->func->card_present(local)) { | ||
1541 | printk(KERN_DEBUG "%s: card already removed or not configured " | ||
1542 | "during shutdown\n", dev->name); | ||
1543 | return; | ||
1544 | } | ||
1545 | |||
1546 | if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && | ||
1547 | hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) | ||
1548 | printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); | ||
1549 | |||
1550 | hfa384x_disable_interrupts(dev); | ||
1551 | |||
1552 | if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) | ||
1553 | hfa384x_events_only_cmd(dev); | ||
1554 | else | ||
1555 | prism2_clear_cmd_queue(local); | ||
1556 | } | ||
1557 | |||
1558 | |||
1559 | static void prism2_hw_reset(struct net_device *dev) | ||
1560 | { | ||
1561 | struct hostap_interface *iface; | ||
1562 | local_info_t *local; | ||
1563 | |||
1564 | #if 0 | ||
1565 | static long last_reset = 0; | ||
1566 | |||
1567 | /* do not reset card more than once per second to avoid ending up in a | ||
1568 | * busy loop reseting the card */ | ||
1569 | if (time_before_eq(jiffies, last_reset + HZ)) | ||
1570 | return; | ||
1571 | last_reset = jiffies; | ||
1572 | #endif | ||
1573 | |||
1574 | iface = netdev_priv(dev); | ||
1575 | local = iface->local; | ||
1576 | |||
1577 | if (in_interrupt()) { | ||
1578 | printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called " | ||
1579 | "in interrupt context\n", dev->name); | ||
1580 | return; | ||
1581 | } | ||
1582 | |||
1583 | if (local->hw_downloading) | ||
1584 | return; | ||
1585 | |||
1586 | if (local->hw_resetting) { | ||
1587 | printk(KERN_WARNING "%s: %s: already resetting card - " | ||
1588 | "ignoring reset request\n", dev_info, dev->name); | ||
1589 | return; | ||
1590 | } | ||
1591 | |||
1592 | local->hw_reset_tries++; | ||
1593 | if (local->hw_reset_tries > 10) { | ||
1594 | printk(KERN_WARNING "%s: too many reset tries, skipping\n", | ||
1595 | dev->name); | ||
1596 | return; | ||
1597 | } | ||
1598 | |||
1599 | printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); | ||
1600 | hfa384x_disable_interrupts(dev); | ||
1601 | local->hw_resetting = 1; | ||
1602 | if (local->func->cor_sreset) { | ||
1603 | /* Host system seems to hang in some cases with high traffic | ||
1604 | * load or shared interrupts during COR sreset. Disable shared | ||
1605 | * interrupts during reset to avoid these crashes. COS sreset | ||
1606 | * takes quite a long time, so it is unfortunate that this | ||
1607 | * seems to be needed. Anyway, I do not know of any better way | ||
1608 | * of avoiding the crash. */ | ||
1609 | disable_irq(dev->irq); | ||
1610 | local->func->cor_sreset(local); | ||
1611 | enable_irq(dev->irq); | ||
1612 | } | ||
1613 | prism2_hw_shutdown(dev, 1); | ||
1614 | prism2_hw_config(dev, 0); | ||
1615 | local->hw_resetting = 0; | ||
1616 | |||
1617 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
1618 | if (local->dl_pri) { | ||
1619 | printk(KERN_DEBUG "%s: persistent download of primary " | ||
1620 | "firmware\n", dev->name); | ||
1621 | if (prism2_download_genesis(local, local->dl_pri) < 0) | ||
1622 | printk(KERN_WARNING "%s: download (PRI) failed\n", | ||
1623 | dev->name); | ||
1624 | } | ||
1625 | |||
1626 | if (local->dl_sec) { | ||
1627 | printk(KERN_DEBUG "%s: persistent download of secondary " | ||
1628 | "firmware\n", dev->name); | ||
1629 | if (prism2_download_volatile(local, local->dl_sec) < 0) | ||
1630 | printk(KERN_WARNING "%s: download (SEC) failed\n", | ||
1631 | dev->name); | ||
1632 | } | ||
1633 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
1634 | |||
1635 | /* TODO: restore beacon TIM bits for STAs that have buffered frames */ | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | static void prism2_schedule_reset(local_info_t *local) | ||
1640 | { | ||
1641 | schedule_work(&local->reset_queue); | ||
1642 | } | ||
1643 | |||
1644 | |||
1645 | /* Called only as scheduled task after noticing card timeout in interrupt | ||
1646 | * context */ | ||
1647 | static void handle_reset_queue(void *data) | ||
1648 | { | ||
1649 | local_info_t *local = (local_info_t *) data; | ||
1650 | |||
1651 | printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); | ||
1652 | prism2_hw_reset(local->dev); | ||
1653 | |||
1654 | if (netif_queue_stopped(local->dev)) { | ||
1655 | int i; | ||
1656 | |||
1657 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) | ||
1658 | if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { | ||
1659 | PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " | ||
1660 | "wake up queue\n"); | ||
1661 | netif_wake_queue(local->dev); | ||
1662 | break; | ||
1663 | } | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | |||
1668 | static int prism2_get_txfid_idx(local_info_t *local) | ||
1669 | { | ||
1670 | int idx, end; | ||
1671 | unsigned long flags; | ||
1672 | |||
1673 | spin_lock_irqsave(&local->txfidlock, flags); | ||
1674 | end = idx = local->next_txfid; | ||
1675 | do { | ||
1676 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1677 | local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; | ||
1678 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1679 | return idx; | ||
1680 | } | ||
1681 | idx++; | ||
1682 | if (idx >= PRISM2_TXFID_COUNT) | ||
1683 | idx = 0; | ||
1684 | } while (idx != end); | ||
1685 | spin_unlock_irqrestore(&local->txfidlock, flags); | ||
1686 | |||
1687 | PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " | ||
1688 | "packet dropped\n"); | ||
1689 | local->stats.tx_dropped++; | ||
1690 | |||
1691 | return -1; | ||
1692 | } | ||
1693 | |||
1694 | |||
1695 | /* Called only from hardware IRQ */ | ||
1696 | static void prism2_transmit_cb(struct net_device *dev, long context, | ||
1697 | u16 resp0, u16 res) | ||
1698 | { | ||
1699 | struct hostap_interface *iface; | ||
1700 | local_info_t *local; | ||
1701 | int idx = (int) context; | ||
1702 | |||
1703 | iface = netdev_priv(dev); | ||
1704 | local = iface->local; | ||
1705 | |||
1706 | if (res) { | ||
1707 | printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", | ||
1708 | dev->name, res); | ||
1709 | return; | ||
1710 | } | ||
1711 | |||
1712 | if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { | ||
1713 | printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " | ||
1714 | "idx=%d\n", dev->name, idx); | ||
1715 | return; | ||
1716 | } | ||
1717 | |||
1718 | if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1719 | printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " | ||
1720 | "with no pending transmit\n", dev->name); | ||
1721 | } | ||
1722 | |||
1723 | if (netif_queue_stopped(dev)) { | ||
1724 | /* ready for next TX, so wake up queue that was stopped in | ||
1725 | * prism2_transmit() */ | ||
1726 | netif_wake_queue(dev); | ||
1727 | } | ||
1728 | |||
1729 | spin_lock(&local->txfidlock); | ||
1730 | |||
1731 | /* With reclaim, Resp0 contains new txfid for transmit; the old txfid | ||
1732 | * will be automatically allocated for the next TX frame */ | ||
1733 | local->intransmitfid[idx] = resp0; | ||
1734 | |||
1735 | PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " | ||
1736 | "resp0=0x%04x, transmit_txfid=0x%04x\n", | ||
1737 | dev->name, idx, local->txfid[idx], | ||
1738 | resp0, local->intransmitfid[local->next_txfid]); | ||
1739 | |||
1740 | idx++; | ||
1741 | if (idx >= PRISM2_TXFID_COUNT) | ||
1742 | idx = 0; | ||
1743 | local->next_txfid = idx; | ||
1744 | |||
1745 | /* check if all TX buffers are occupied */ | ||
1746 | do { | ||
1747 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | ||
1748 | spin_unlock(&local->txfidlock); | ||
1749 | return; | ||
1750 | } | ||
1751 | idx++; | ||
1752 | if (idx >= PRISM2_TXFID_COUNT) | ||
1753 | idx = 0; | ||
1754 | } while (idx != local->next_txfid); | ||
1755 | spin_unlock(&local->txfidlock); | ||
1756 | |||
1757 | /* no empty TX buffers, stop queue */ | ||
1758 | netif_stop_queue(dev); | ||
1759 | } | ||
1760 | |||
1761 | |||
1762 | /* Called only from software IRQ if PCI bus master is not used (with bus master | ||
1763 | * this can be called both from software and hardware IRQ) */ | ||
1764 | static int prism2_transmit(struct net_device *dev, int idx) | ||
1765 | { | ||
1766 | struct hostap_interface *iface; | ||
1767 | local_info_t *local; | ||
1768 | int res; | ||
1769 | |||
1770 | iface = netdev_priv(dev); | ||
1771 | local = iface->local; | ||
1772 | |||
1773 | /* The driver tries to stop netif queue so that there would not be | ||
1774 | * more than one attempt to transmit frames going on; check that this | ||
1775 | * is really the case */ | ||
1776 | |||
1777 | if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
1778 | printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " | ||
1779 | "when previous TX was pending\n", dev->name); | ||
1780 | return -1; | ||
1781 | } | ||
1782 | |||
1783 | /* stop the queue for the time that transmit is pending */ | ||
1784 | netif_stop_queue(dev); | ||
1785 | |||
1786 | /* transmit packet */ | ||
1787 | res = hfa384x_cmd_callback( | ||
1788 | dev, | ||
1789 | HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, | ||
1790 | local->txfid[idx], | ||
1791 | prism2_transmit_cb, (long) idx); | ||
1792 | |||
1793 | if (res) { | ||
1794 | struct net_device_stats *stats; | ||
1795 | printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " | ||
1796 | "failed (res=%d)\n", dev->name, res); | ||
1797 | stats = hostap_get_stats(dev); | ||
1798 | stats->tx_dropped++; | ||
1799 | netif_wake_queue(dev); | ||
1800 | return -1; | ||
1801 | } | ||
1802 | dev->trans_start = jiffies; | ||
1803 | |||
1804 | /* Since we did not wait for command completion, the card continues | ||
1805 | * to process on the background and we will finish handling when | ||
1806 | * command completion event is handled (prism2_cmd_ev() function) */ | ||
1807 | |||
1808 | return 0; | ||
1809 | } | ||
1810 | |||
1811 | |||
1812 | /* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and | ||
1813 | * send the payload with this descriptor) */ | ||
1814 | /* Called only from software IRQ */ | ||
1815 | static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) | ||
1816 | { | ||
1817 | struct hostap_interface *iface; | ||
1818 | local_info_t *local; | ||
1819 | struct hfa384x_tx_frame txdesc; | ||
1820 | struct hostap_skb_tx_data *meta; | ||
1821 | int hdr_len, data_len, idx, res, ret = -1; | ||
1822 | u16 tx_control, fc; | ||
1823 | |||
1824 | iface = netdev_priv(dev); | ||
1825 | local = iface->local; | ||
1826 | |||
1827 | meta = (struct hostap_skb_tx_data *) skb->cb; | ||
1828 | |||
1829 | prism2_callback(local, PRISM2_CALLBACK_TX_START); | ||
1830 | |||
1831 | if ((local->func->card_present && !local->func->card_present(local)) || | ||
1832 | !local->hw_ready || local->hw_downloading || local->pri_only) { | ||
1833 | if (net_ratelimit()) { | ||
1834 | printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" | ||
1835 | " skipping\n", dev->name); | ||
1836 | } | ||
1837 | goto fail; | ||
1838 | } | ||
1839 | |||
1840 | memset(&txdesc, 0, sizeof(txdesc)); | ||
1841 | |||
1842 | /* skb->data starts with txdesc->frame_control */ | ||
1843 | hdr_len = 24; | ||
1844 | memcpy(&txdesc.frame_control, skb->data, hdr_len); | ||
1845 | fc = le16_to_cpu(txdesc.frame_control); | ||
1846 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | ||
1847 | (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) && | ||
1848 | skb->len >= 30) { | ||
1849 | /* Addr4 */ | ||
1850 | memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); | ||
1851 | hdr_len += ETH_ALEN; | ||
1852 | } | ||
1853 | |||
1854 | tx_control = local->tx_control; | ||
1855 | if (meta->tx_cb_idx) { | ||
1856 | tx_control |= HFA384X_TX_CTRL_TX_OK; | ||
1857 | txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx); | ||
1858 | } | ||
1859 | txdesc.tx_control = cpu_to_le16(tx_control); | ||
1860 | txdesc.tx_rate = meta->rate; | ||
1861 | |||
1862 | data_len = skb->len - hdr_len; | ||
1863 | txdesc.data_len = cpu_to_le16(data_len); | ||
1864 | txdesc.len = cpu_to_be16(data_len); | ||
1865 | |||
1866 | idx = prism2_get_txfid_idx(local); | ||
1867 | if (idx < 0) | ||
1868 | goto fail; | ||
1869 | |||
1870 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) | ||
1871 | hostap_dump_tx_header(dev->name, &txdesc); | ||
1872 | |||
1873 | spin_lock(&local->baplock); | ||
1874 | res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); | ||
1875 | |||
1876 | if (!res) | ||
1877 | res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); | ||
1878 | if (!res) | ||
1879 | res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, | ||
1880 | skb->len - hdr_len); | ||
1881 | spin_unlock(&local->baplock); | ||
1882 | |||
1883 | if (!res) | ||
1884 | res = prism2_transmit(dev, idx); | ||
1885 | if (res) { | ||
1886 | printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", | ||
1887 | dev->name); | ||
1888 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
1889 | schedule_work(&local->reset_queue); | ||
1890 | goto fail; | ||
1891 | } | ||
1892 | |||
1893 | ret = 0; | ||
1894 | |||
1895 | fail: | ||
1896 | prism2_callback(local, PRISM2_CALLBACK_TX_END); | ||
1897 | return ret; | ||
1898 | } | ||
1899 | |||
1900 | |||
1901 | /* Some SMP systems have reported number of odd errors with hostap_pci. fid | ||
1902 | * register has changed values between consecutive reads for an unknown reason. | ||
1903 | * This should really not happen, so more debugging is needed. This test | ||
1904 | * version is a big slower, but it will detect most of such register changes | ||
1905 | * and will try to get the correct fid eventually. */ | ||
1906 | #define EXTRA_FID_READ_TESTS | ||
1907 | |||
1908 | static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) | ||
1909 | { | ||
1910 | #ifdef EXTRA_FID_READ_TESTS | ||
1911 | u16 val, val2, val3; | ||
1912 | int i; | ||
1913 | |||
1914 | for (i = 0; i < 10; i++) { | ||
1915 | val = HFA384X_INW(reg); | ||
1916 | val2 = HFA384X_INW(reg); | ||
1917 | val3 = HFA384X_INW(reg); | ||
1918 | |||
1919 | if (val == val2 && val == val3) | ||
1920 | return val; | ||
1921 | |||
1922 | printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):" | ||
1923 | " %04x %04x %04x\n", | ||
1924 | dev->name, i, reg, val, val2, val3); | ||
1925 | if ((val == val2 || val == val3) && val != 0) | ||
1926 | return val; | ||
1927 | if (val2 == val3 && val2 != 0) | ||
1928 | return val2; | ||
1929 | } | ||
1930 | printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg " | ||
1931 | "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3); | ||
1932 | return val; | ||
1933 | #else /* EXTRA_FID_READ_TESTS */ | ||
1934 | return HFA384X_INW(reg); | ||
1935 | #endif /* EXTRA_FID_READ_TESTS */ | ||
1936 | } | ||
1937 | |||
1938 | |||
1939 | /* Called only as a tasklet (software IRQ) */ | ||
1940 | static void prism2_rx(local_info_t *local) | ||
1941 | { | ||
1942 | struct net_device *dev = local->dev; | ||
1943 | int res, rx_pending = 0; | ||
1944 | u16 len, hdr_len, rxfid, status, macport; | ||
1945 | struct net_device_stats *stats; | ||
1946 | struct hfa384x_rx_frame rxdesc; | ||
1947 | struct sk_buff *skb = NULL; | ||
1948 | |||
1949 | prism2_callback(local, PRISM2_CALLBACK_RX_START); | ||
1950 | stats = hostap_get_stats(dev); | ||
1951 | |||
1952 | rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF); | ||
1953 | #ifndef final_version | ||
1954 | if (rxfid == 0) { | ||
1955 | rxfid = HFA384X_INW(HFA384X_RXFID_OFF); | ||
1956 | printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n", | ||
1957 | rxfid); | ||
1958 | if (rxfid == 0) { | ||
1959 | schedule_work(&local->reset_queue); | ||
1960 | goto rx_dropped; | ||
1961 | } | ||
1962 | /* try to continue with the new rxfid value */ | ||
1963 | } | ||
1964 | #endif | ||
1965 | |||
1966 | spin_lock(&local->baplock); | ||
1967 | res = hfa384x_setup_bap(dev, BAP0, rxfid, 0); | ||
1968 | if (!res) | ||
1969 | res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc)); | ||
1970 | |||
1971 | if (res) { | ||
1972 | spin_unlock(&local->baplock); | ||
1973 | printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name, | ||
1974 | res); | ||
1975 | if (res == -ETIMEDOUT) { | ||
1976 | schedule_work(&local->reset_queue); | ||
1977 | } | ||
1978 | goto rx_dropped; | ||
1979 | } | ||
1980 | |||
1981 | len = le16_to_cpu(rxdesc.data_len); | ||
1982 | hdr_len = sizeof(rxdesc); | ||
1983 | status = le16_to_cpu(rxdesc.status); | ||
1984 | macport = (status >> 8) & 0x07; | ||
1985 | |||
1986 | /* Drop frames with too large reported payload length. Monitor mode | ||
1987 | * seems to sometimes pass frames (e.g., ctrl::ack) with signed and | ||
1988 | * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for | ||
1989 | * macport 7 */ | ||
1990 | if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) { | ||
1991 | if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) { | ||
1992 | if (len >= (u16) -14) { | ||
1993 | hdr_len -= 65535 - len; | ||
1994 | hdr_len--; | ||
1995 | } | ||
1996 | len = 0; | ||
1997 | } else { | ||
1998 | spin_unlock(&local->baplock); | ||
1999 | printk(KERN_DEBUG "%s: Received frame with invalid " | ||
2000 | "length 0x%04x\n", dev->name, len); | ||
2001 | hostap_dump_rx_header(dev->name, &rxdesc); | ||
2002 | goto rx_dropped; | ||
2003 | } | ||
2004 | } | ||
2005 | |||
2006 | skb = dev_alloc_skb(len + hdr_len); | ||
2007 | if (!skb) { | ||
2008 | spin_unlock(&local->baplock); | ||
2009 | printk(KERN_DEBUG "%s: RX failed to allocate skb\n", | ||
2010 | dev->name); | ||
2011 | goto rx_dropped; | ||
2012 | } | ||
2013 | skb->dev = dev; | ||
2014 | memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); | ||
2015 | |||
2016 | if (len > 0) | ||
2017 | res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); | ||
2018 | spin_unlock(&local->baplock); | ||
2019 | if (res) { | ||
2020 | printk(KERN_DEBUG "%s: RX failed to read " | ||
2021 | "frame data\n", dev->name); | ||
2022 | goto rx_dropped; | ||
2023 | } | ||
2024 | |||
2025 | skb_queue_tail(&local->rx_list, skb); | ||
2026 | tasklet_schedule(&local->rx_tasklet); | ||
2027 | |||
2028 | rx_exit: | ||
2029 | prism2_callback(local, PRISM2_CALLBACK_RX_END); | ||
2030 | if (!rx_pending) { | ||
2031 | HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF); | ||
2032 | } | ||
2033 | |||
2034 | return; | ||
2035 | |||
2036 | rx_dropped: | ||
2037 | stats->rx_dropped++; | ||
2038 | if (skb) | ||
2039 | dev_kfree_skb(skb); | ||
2040 | goto rx_exit; | ||
2041 | } | ||
2042 | |||
2043 | |||
2044 | /* Called only as a tasklet (software IRQ) */ | ||
2045 | static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) | ||
2046 | { | ||
2047 | struct hfa384x_rx_frame *rxdesc; | ||
2048 | struct net_device *dev = skb->dev; | ||
2049 | struct hostap_80211_rx_status stats; | ||
2050 | int hdrlen, rx_hdrlen; | ||
2051 | |||
2052 | rx_hdrlen = sizeof(*rxdesc); | ||
2053 | if (skb->len < sizeof(*rxdesc)) { | ||
2054 | /* Allow monitor mode to receive shorter frames */ | ||
2055 | if (local->iw_mode == IW_MODE_MONITOR && | ||
2056 | skb->len >= sizeof(*rxdesc) - 30) { | ||
2057 | rx_hdrlen = skb->len; | ||
2058 | } else { | ||
2059 | dev_kfree_skb(skb); | ||
2060 | return; | ||
2061 | } | ||
2062 | } | ||
2063 | |||
2064 | rxdesc = (struct hfa384x_rx_frame *) skb->data; | ||
2065 | |||
2066 | if (local->frame_dump & PRISM2_DUMP_RX_HDR && | ||
2067 | skb->len >= sizeof(*rxdesc)) | ||
2068 | hostap_dump_rx_header(dev->name, rxdesc); | ||
2069 | |||
2070 | if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR && | ||
2071 | (!local->monitor_allow_fcserr || | ||
2072 | local->iw_mode != IW_MODE_MONITOR)) | ||
2073 | goto drop; | ||
2074 | |||
2075 | if (skb->len > PRISM2_DATA_MAXLEN) { | ||
2076 | printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n", | ||
2077 | dev->name, skb->len, PRISM2_DATA_MAXLEN); | ||
2078 | goto drop; | ||
2079 | } | ||
2080 | |||
2081 | stats.mac_time = le32_to_cpu(rxdesc->time); | ||
2082 | stats.signal = rxdesc->signal - local->rssi_to_dBm; | ||
2083 | stats.noise = rxdesc->silence - local->rssi_to_dBm; | ||
2084 | stats.rate = rxdesc->rate; | ||
2085 | |||
2086 | /* Convert Prism2 RX structure into IEEE 802.11 header */ | ||
2087 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control)); | ||
2088 | if (hdrlen > rx_hdrlen) | ||
2089 | hdrlen = rx_hdrlen; | ||
2090 | |||
2091 | memmove(skb_pull(skb, rx_hdrlen - hdrlen), | ||
2092 | &rxdesc->frame_control, hdrlen); | ||
2093 | |||
2094 | hostap_80211_rx(dev, skb, &stats); | ||
2095 | return; | ||
2096 | |||
2097 | drop: | ||
2098 | dev_kfree_skb(skb); | ||
2099 | } | ||
2100 | |||
2101 | |||
2102 | /* Called only as a tasklet (software IRQ) */ | ||
2103 | static void hostap_rx_tasklet(unsigned long data) | ||
2104 | { | ||
2105 | local_info_t *local = (local_info_t *) data; | ||
2106 | struct sk_buff *skb; | ||
2107 | |||
2108 | while ((skb = skb_dequeue(&local->rx_list)) != NULL) | ||
2109 | hostap_rx_skb(local, skb); | ||
2110 | } | ||
2111 | |||
2112 | |||
2113 | /* Called only from hardware IRQ */ | ||
2114 | static void prism2_alloc_ev(struct net_device *dev) | ||
2115 | { | ||
2116 | struct hostap_interface *iface; | ||
2117 | local_info_t *local; | ||
2118 | int idx; | ||
2119 | u16 fid; | ||
2120 | |||
2121 | iface = netdev_priv(dev); | ||
2122 | local = iface->local; | ||
2123 | |||
2124 | fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF); | ||
2125 | |||
2126 | PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid); | ||
2127 | |||
2128 | spin_lock(&local->txfidlock); | ||
2129 | idx = local->next_alloc; | ||
2130 | |||
2131 | do { | ||
2132 | if (local->txfid[idx] == fid) { | ||
2133 | PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n", | ||
2134 | idx); | ||
2135 | |||
2136 | #ifndef final_version | ||
2137 | if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) | ||
2138 | printk("Already released txfid found at idx " | ||
2139 | "%d\n", idx); | ||
2140 | if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED) | ||
2141 | printk("Already reserved txfid found at idx " | ||
2142 | "%d\n", idx); | ||
2143 | #endif | ||
2144 | local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | ||
2145 | idx++; | ||
2146 | local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 : | ||
2147 | idx; | ||
2148 | |||
2149 | if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) && | ||
2150 | netif_queue_stopped(dev)) | ||
2151 | netif_wake_queue(dev); | ||
2152 | |||
2153 | spin_unlock(&local->txfidlock); | ||
2154 | return; | ||
2155 | } | ||
2156 | |||
2157 | idx++; | ||
2158 | if (idx >= PRISM2_TXFID_COUNT) | ||
2159 | idx = 0; | ||
2160 | } while (idx != local->next_alloc); | ||
2161 | |||
2162 | printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new " | ||
2163 | "read 0x%04x) for alloc event\n", dev->name, fid, | ||
2164 | HFA384X_INW(HFA384X_ALLOCFID_OFF)); | ||
2165 | printk(KERN_DEBUG "TXFIDs:"); | ||
2166 | for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++) | ||
2167 | printk(" %04x[%04x]", local->txfid[idx], | ||
2168 | local->intransmitfid[idx]); | ||
2169 | printk("\n"); | ||
2170 | spin_unlock(&local->txfidlock); | ||
2171 | |||
2172 | /* FIX: should probably schedule reset; reference to one txfid was lost | ||
2173 | * completely.. Bad things will happen if we run out of txfids | ||
2174 | * Actually, this will cause netdev watchdog to notice TX timeout and | ||
2175 | * then card reset after all txfids have been leaked. */ | ||
2176 | } | ||
2177 | |||
2178 | |||
2179 | /* Called only as a tasklet (software IRQ) */ | ||
2180 | static void hostap_tx_callback(local_info_t *local, | ||
2181 | struct hfa384x_tx_frame *txdesc, int ok, | ||
2182 | char *payload) | ||
2183 | { | ||
2184 | u16 sw_support, hdrlen, len; | ||
2185 | struct sk_buff *skb; | ||
2186 | struct hostap_tx_callback_info *cb; | ||
2187 | |||
2188 | /* Make sure that frame was from us. */ | ||
2189 | if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) { | ||
2190 | printk(KERN_DEBUG "%s: TX callback - foreign frame\n", | ||
2191 | local->dev->name); | ||
2192 | return; | ||
2193 | } | ||
2194 | |||
2195 | sw_support = le16_to_cpu(txdesc->sw_support); | ||
2196 | |||
2197 | spin_lock(&local->lock); | ||
2198 | cb = local->tx_callback; | ||
2199 | while (cb != NULL && cb->idx != sw_support) | ||
2200 | cb = cb->next; | ||
2201 | spin_unlock(&local->lock); | ||
2202 | |||
2203 | if (cb == NULL) { | ||
2204 | printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n", | ||
2205 | local->dev->name, sw_support); | ||
2206 | return; | ||
2207 | } | ||
2208 | |||
2209 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control)); | ||
2210 | len = le16_to_cpu(txdesc->data_len); | ||
2211 | skb = dev_alloc_skb(hdrlen + len); | ||
2212 | if (skb == NULL) { | ||
2213 | printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate " | ||
2214 | "skb\n", local->dev->name); | ||
2215 | return; | ||
2216 | } | ||
2217 | |||
2218 | memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); | ||
2219 | if (payload) | ||
2220 | memcpy(skb_put(skb, len), payload, len); | ||
2221 | |||
2222 | skb->dev = local->dev; | ||
2223 | skb->mac.raw = skb->data; | ||
2224 | |||
2225 | cb->func(skb, ok, cb->data); | ||
2226 | } | ||
2227 | |||
2228 | |||
2229 | /* Called only as a tasklet (software IRQ) */ | ||
2230 | static int hostap_tx_compl_read(local_info_t *local, int error, | ||
2231 | struct hfa384x_tx_frame *txdesc, | ||
2232 | char **payload) | ||
2233 | { | ||
2234 | u16 fid, len; | ||
2235 | int res, ret = 0; | ||
2236 | struct net_device *dev = local->dev; | ||
2237 | |||
2238 | fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF); | ||
2239 | |||
2240 | PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error); | ||
2241 | |||
2242 | spin_lock(&local->baplock); | ||
2243 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2244 | if (!res) | ||
2245 | res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc)); | ||
2246 | if (res) { | ||
2247 | PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not " | ||
2248 | "read txdesc\n", dev->name, error, fid); | ||
2249 | if (res == -ETIMEDOUT) { | ||
2250 | schedule_work(&local->reset_queue); | ||
2251 | } | ||
2252 | ret = -1; | ||
2253 | goto fail; | ||
2254 | } | ||
2255 | if (txdesc->sw_support) { | ||
2256 | len = le16_to_cpu(txdesc->data_len); | ||
2257 | if (len < PRISM2_DATA_MAXLEN) { | ||
2258 | *payload = (char *) kmalloc(len, GFP_ATOMIC); | ||
2259 | if (*payload == NULL || | ||
2260 | hfa384x_from_bap(dev, BAP0, *payload, len)) { | ||
2261 | PDEBUG(DEBUG_EXTRA, "%s: could not read TX " | ||
2262 | "frame payload\n", dev->name); | ||
2263 | kfree(*payload); | ||
2264 | *payload = NULL; | ||
2265 | ret = -1; | ||
2266 | goto fail; | ||
2267 | } | ||
2268 | } | ||
2269 | } | ||
2270 | |||
2271 | fail: | ||
2272 | spin_unlock(&local->baplock); | ||
2273 | |||
2274 | return ret; | ||
2275 | } | ||
2276 | |||
2277 | |||
2278 | /* Called only as a tasklet (software IRQ) */ | ||
2279 | static void prism2_tx_ev(local_info_t *local) | ||
2280 | { | ||
2281 | struct net_device *dev = local->dev; | ||
2282 | char *payload = NULL; | ||
2283 | struct hfa384x_tx_frame txdesc; | ||
2284 | |||
2285 | if (hostap_tx_compl_read(local, 0, &txdesc, &payload)) | ||
2286 | goto fail; | ||
2287 | |||
2288 | if (local->frame_dump & PRISM2_DUMP_TX_HDR) { | ||
2289 | PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x " | ||
2290 | "retry_count=%d tx_rate=%d seq_ctrl=%d " | ||
2291 | "duration_id=%d\n", | ||
2292 | dev->name, le16_to_cpu(txdesc.status), | ||
2293 | txdesc.retry_count, txdesc.tx_rate, | ||
2294 | le16_to_cpu(txdesc.seq_ctrl), | ||
2295 | le16_to_cpu(txdesc.duration_id)); | ||
2296 | } | ||
2297 | |||
2298 | if (txdesc.sw_support) | ||
2299 | hostap_tx_callback(local, &txdesc, 1, payload); | ||
2300 | kfree(payload); | ||
2301 | |||
2302 | fail: | ||
2303 | HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF); | ||
2304 | } | ||
2305 | |||
2306 | |||
2307 | /* Called only as a tasklet (software IRQ) */ | ||
2308 | static void hostap_sta_tx_exc_tasklet(unsigned long data) | ||
2309 | { | ||
2310 | local_info_t *local = (local_info_t *) data; | ||
2311 | struct sk_buff *skb; | ||
2312 | |||
2313 | while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) { | ||
2314 | struct hfa384x_tx_frame *txdesc = | ||
2315 | (struct hfa384x_tx_frame *) skb->data; | ||
2316 | |||
2317 | if (skb->len >= sizeof(*txdesc)) { | ||
2318 | /* Convert Prism2 RX structure into IEEE 802.11 header | ||
2319 | */ | ||
2320 | u16 fc = le16_to_cpu(txdesc->frame_control); | ||
2321 | int hdrlen = hostap_80211_get_hdrlen(fc); | ||
2322 | memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), | ||
2323 | &txdesc->frame_control, hdrlen); | ||
2324 | |||
2325 | hostap_handle_sta_tx_exc(local, skb); | ||
2326 | } | ||
2327 | dev_kfree_skb(skb); | ||
2328 | } | ||
2329 | } | ||
2330 | |||
2331 | |||
2332 | /* Called only as a tasklet (software IRQ) */ | ||
2333 | static void prism2_txexc(local_info_t *local) | ||
2334 | { | ||
2335 | struct net_device *dev = local->dev; | ||
2336 | u16 status, fc; | ||
2337 | int show_dump, res; | ||
2338 | char *payload = NULL; | ||
2339 | struct hfa384x_tx_frame txdesc; | ||
2340 | |||
2341 | show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; | ||
2342 | local->stats.tx_errors++; | ||
2343 | |||
2344 | res = hostap_tx_compl_read(local, 1, &txdesc, &payload); | ||
2345 | HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF); | ||
2346 | if (res) | ||
2347 | return; | ||
2348 | |||
2349 | status = le16_to_cpu(txdesc.status); | ||
2350 | |||
2351 | /* We produce a TXDROP event only for retry or lifetime | ||
2352 | * exceeded, because that's the only status that really mean | ||
2353 | * that this particular node went away. | ||
2354 | * Other errors means that *we* screwed up. - Jean II */ | ||
2355 | if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR)) | ||
2356 | { | ||
2357 | union iwreq_data wrqu; | ||
2358 | |||
2359 | /* Copy 802.11 dest address. */ | ||
2360 | memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN); | ||
2361 | wrqu.addr.sa_family = ARPHRD_ETHER; | ||
2362 | wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); | ||
2363 | } else | ||
2364 | show_dump = 1; | ||
2365 | |||
2366 | if (local->iw_mode == IW_MODE_MASTER || | ||
2367 | local->iw_mode == IW_MODE_REPEAT || | ||
2368 | local->wds_type & HOSTAP_WDS_AP_CLIENT) { | ||
2369 | struct sk_buff *skb; | ||
2370 | skb = dev_alloc_skb(sizeof(txdesc)); | ||
2371 | if (skb) { | ||
2372 | memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, | ||
2373 | sizeof(txdesc)); | ||
2374 | skb_queue_tail(&local->sta_tx_exc_list, skb); | ||
2375 | tasklet_schedule(&local->sta_tx_exc_tasklet); | ||
2376 | } | ||
2377 | } | ||
2378 | |||
2379 | if (txdesc.sw_support) | ||
2380 | hostap_tx_callback(local, &txdesc, 0, payload); | ||
2381 | kfree(payload); | ||
2382 | |||
2383 | if (!show_dump) | ||
2384 | return; | ||
2385 | |||
2386 | PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)" | ||
2387 | " tx_control=%04x\n", | ||
2388 | dev->name, status, | ||
2389 | status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "", | ||
2390 | status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "", | ||
2391 | status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "", | ||
2392 | status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "", | ||
2393 | le16_to_cpu(txdesc.tx_control)); | ||
2394 | |||
2395 | fc = le16_to_cpu(txdesc.frame_control); | ||
2396 | PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " | ||
2397 | "(%s%s%s::%d%s%s)\n", | ||
2398 | txdesc.retry_count, txdesc.tx_rate, fc, | ||
2399 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "", | ||
2400 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "", | ||
2401 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "", | ||
2402 | WLAN_FC_GET_STYPE(fc) >> 4, | ||
2403 | fc & IEEE80211_FCTL_TODS ? " ToDS" : "", | ||
2404 | fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); | ||
2405 | PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" | ||
2406 | MACSTR " A4=" MACSTR "\n", | ||
2407 | MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), | ||
2408 | MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); | ||
2409 | } | ||
2410 | |||
2411 | |||
2412 | /* Called only as a tasklet (software IRQ) */ | ||
2413 | static void hostap_info_tasklet(unsigned long data) | ||
2414 | { | ||
2415 | local_info_t *local = (local_info_t *) data; | ||
2416 | struct sk_buff *skb; | ||
2417 | |||
2418 | while ((skb = skb_dequeue(&local->info_list)) != NULL) { | ||
2419 | hostap_info_process(local, skb); | ||
2420 | dev_kfree_skb(skb); | ||
2421 | } | ||
2422 | } | ||
2423 | |||
2424 | |||
2425 | /* Called only as a tasklet (software IRQ) */ | ||
2426 | static void prism2_info(local_info_t *local) | ||
2427 | { | ||
2428 | struct net_device *dev = local->dev; | ||
2429 | u16 fid; | ||
2430 | int res, left; | ||
2431 | struct hfa384x_info_frame info; | ||
2432 | struct sk_buff *skb; | ||
2433 | |||
2434 | fid = HFA384X_INW(HFA384X_INFOFID_OFF); | ||
2435 | |||
2436 | spin_lock(&local->baplock); | ||
2437 | res = hfa384x_setup_bap(dev, BAP0, fid, 0); | ||
2438 | if (!res) | ||
2439 | res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info)); | ||
2440 | if (res) { | ||
2441 | spin_unlock(&local->baplock); | ||
2442 | printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n", | ||
2443 | fid); | ||
2444 | if (res == -ETIMEDOUT) { | ||
2445 | schedule_work(&local->reset_queue); | ||
2446 | } | ||
2447 | goto out; | ||
2448 | } | ||
2449 | |||
2450 | le16_to_cpus(&info.len); | ||
2451 | le16_to_cpus(&info.type); | ||
2452 | left = (info.len - 1) * 2; | ||
2453 | |||
2454 | if (info.len & 0x8000 || info.len == 0 || left > 2060) { | ||
2455 | /* data register seems to give 0x8000 in some error cases even | ||
2456 | * though busy bit is not set in offset register; | ||
2457 | * in addition, length must be at least 1 due to type field */ | ||
2458 | spin_unlock(&local->baplock); | ||
2459 | printk(KERN_DEBUG "%s: Received info frame with invalid " | ||
2460 | "length 0x%04x (type 0x%04x)\n", dev->name, info.len, | ||
2461 | info.type); | ||
2462 | goto out; | ||
2463 | } | ||
2464 | |||
2465 | skb = dev_alloc_skb(sizeof(info) + left); | ||
2466 | if (skb == NULL) { | ||
2467 | spin_unlock(&local->baplock); | ||
2468 | printk(KERN_DEBUG "%s: Could not allocate skb for info " | ||
2469 | "frame\n", dev->name); | ||
2470 | goto out; | ||
2471 | } | ||
2472 | |||
2473 | memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); | ||
2474 | if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) | ||
2475 | { | ||
2476 | spin_unlock(&local->baplock); | ||
2477 | printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " | ||
2478 | "len=0x%04x, type=0x%04x\n", | ||
2479 | dev->name, fid, info.len, info.type); | ||
2480 | dev_kfree_skb(skb); | ||
2481 | goto out; | ||
2482 | } | ||
2483 | spin_unlock(&local->baplock); | ||
2484 | |||
2485 | skb_queue_tail(&local->info_list, skb); | ||
2486 | tasklet_schedule(&local->info_tasklet); | ||
2487 | |||
2488 | out: | ||
2489 | HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF); | ||
2490 | } | ||
2491 | |||
2492 | |||
2493 | /* Called only as a tasklet (software IRQ) */ | ||
2494 | static void hostap_bap_tasklet(unsigned long data) | ||
2495 | { | ||
2496 | local_info_t *local = (local_info_t *) data; | ||
2497 | struct net_device *dev = local->dev; | ||
2498 | u16 ev; | ||
2499 | int frames = 30; | ||
2500 | |||
2501 | if (local->func->card_present && !local->func->card_present(local)) | ||
2502 | return; | ||
2503 | |||
2504 | set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2505 | |||
2506 | /* Process all pending BAP events without generating new interrupts | ||
2507 | * for them */ | ||
2508 | while (frames-- > 0) { | ||
2509 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2510 | if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS)) | ||
2511 | break; | ||
2512 | if (ev & HFA384X_EV_RX) | ||
2513 | prism2_rx(local); | ||
2514 | if (ev & HFA384X_EV_INFO) | ||
2515 | prism2_info(local); | ||
2516 | if (ev & HFA384X_EV_TX) | ||
2517 | prism2_tx_ev(local); | ||
2518 | if (ev & HFA384X_EV_TXEXC) | ||
2519 | prism2_txexc(local); | ||
2520 | } | ||
2521 | |||
2522 | set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2523 | clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); | ||
2524 | |||
2525 | /* Enable interrupts for new BAP events */ | ||
2526 | hfa384x_events_all(dev); | ||
2527 | clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); | ||
2528 | } | ||
2529 | |||
2530 | |||
2531 | /* Called only from hardware IRQ */ | ||
2532 | static void prism2_infdrop(struct net_device *dev) | ||
2533 | { | ||
2534 | static unsigned long last_inquire = 0; | ||
2535 | |||
2536 | PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name); | ||
2537 | |||
2538 | /* some firmware versions seem to get stuck with | ||
2539 | * full CommTallies in high traffic load cases; every | ||
2540 | * packet will then cause INFDROP event and CommTallies | ||
2541 | * info frame will not be sent automatically. Try to | ||
2542 | * get out of this state by inquiring CommTallies. */ | ||
2543 | if (!last_inquire || time_after(jiffies, last_inquire + HZ)) { | ||
2544 | hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE, | ||
2545 | HFA384X_INFO_COMMTALLIES, NULL, 0); | ||
2546 | last_inquire = jiffies; | ||
2547 | } | ||
2548 | } | ||
2549 | |||
2550 | |||
2551 | /* Called only from hardware IRQ */ | ||
2552 | static void prism2_ev_tick(struct net_device *dev) | ||
2553 | { | ||
2554 | struct hostap_interface *iface; | ||
2555 | local_info_t *local; | ||
2556 | u16 evstat, inten; | ||
2557 | static int prev_stuck = 0; | ||
2558 | |||
2559 | iface = netdev_priv(dev); | ||
2560 | local = iface->local; | ||
2561 | |||
2562 | if (time_after(jiffies, local->last_tick_timer + 5 * HZ) && | ||
2563 | local->last_tick_timer) { | ||
2564 | evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2565 | inten = HFA384X_INW(HFA384X_INTEN_OFF); | ||
2566 | if (!prev_stuck) { | ||
2567 | printk(KERN_INFO "%s: SW TICK stuck? " | ||
2568 | "bits=0x%lx EvStat=%04x IntEn=%04x\n", | ||
2569 | dev->name, local->bits, evstat, inten); | ||
2570 | } | ||
2571 | local->sw_tick_stuck++; | ||
2572 | if ((evstat & HFA384X_BAP0_EVENTS) && | ||
2573 | (inten & HFA384X_BAP0_EVENTS)) { | ||
2574 | printk(KERN_INFO "%s: trying to recover from IRQ " | ||
2575 | "hang\n", dev->name); | ||
2576 | hfa384x_events_no_bap0(dev); | ||
2577 | } | ||
2578 | prev_stuck = 1; | ||
2579 | } else | ||
2580 | prev_stuck = 0; | ||
2581 | } | ||
2582 | |||
2583 | |||
2584 | /* Called only from hardware IRQ */ | ||
2585 | static inline void prism2_check_magic(local_info_t *local) | ||
2586 | { | ||
2587 | /* at least PCI Prism2.5 with bus mastering seems to sometimes | ||
2588 | * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the | ||
2589 | * register once or twice seems to get the correct value.. PCI cards | ||
2590 | * cannot anyway be removed during normal operation, so there is not | ||
2591 | * really any need for this verification with them. */ | ||
2592 | |||
2593 | #ifndef PRISM2_PCI | ||
2594 | #ifndef final_version | ||
2595 | static unsigned long last_magic_err = 0; | ||
2596 | struct net_device *dev = local->dev; | ||
2597 | |||
2598 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | ||
2599 | if (!local->hw_ready) | ||
2600 | return; | ||
2601 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2602 | if (time_after(jiffies, last_magic_err + 10 * HZ)) { | ||
2603 | printk("%s: Interrupt, but SWSUPPORT0 does not match: " | ||
2604 | "%04X != %04X - card removed?\n", dev->name, | ||
2605 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2606 | HFA384X_MAGIC); | ||
2607 | last_magic_err = jiffies; | ||
2608 | } else if (net_ratelimit()) { | ||
2609 | printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " | ||
2610 | "MAGIC=%04x\n", dev->name, | ||
2611 | HFA384X_INW(HFA384X_SWSUPPORT0_OFF), | ||
2612 | HFA384X_MAGIC); | ||
2613 | } | ||
2614 | if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff) | ||
2615 | schedule_work(&local->reset_queue); | ||
2616 | return; | ||
2617 | } | ||
2618 | #endif /* final_version */ | ||
2619 | #endif /* !PRISM2_PCI */ | ||
2620 | } | ||
2621 | |||
2622 | |||
2623 | /* Called only from hardware IRQ */ | ||
2624 | static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
2625 | { | ||
2626 | struct net_device *dev = (struct net_device *) dev_id; | ||
2627 | struct hostap_interface *iface; | ||
2628 | local_info_t *local; | ||
2629 | int events = 0; | ||
2630 | u16 ev; | ||
2631 | |||
2632 | iface = netdev_priv(dev); | ||
2633 | local = iface->local; | ||
2634 | |||
2635 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); | ||
2636 | |||
2637 | if (local->func->card_present && !local->func->card_present(local)) { | ||
2638 | if (net_ratelimit()) { | ||
2639 | printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n", | ||
2640 | dev->name); | ||
2641 | } | ||
2642 | return IRQ_HANDLED; | ||
2643 | } | ||
2644 | |||
2645 | prism2_check_magic(local); | ||
2646 | |||
2647 | for (;;) { | ||
2648 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2649 | if (ev == 0xffff) { | ||
2650 | if (local->shutdown) | ||
2651 | return IRQ_HANDLED; | ||
2652 | HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | ||
2653 | printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n", | ||
2654 | dev->name); | ||
2655 | return IRQ_HANDLED; | ||
2656 | } | ||
2657 | |||
2658 | ev &= HFA384X_INW(HFA384X_INTEN_OFF); | ||
2659 | if (ev == 0) | ||
2660 | break; | ||
2661 | |||
2662 | if (ev & HFA384X_EV_CMD) { | ||
2663 | prism2_cmd_ev(dev); | ||
2664 | } | ||
2665 | |||
2666 | /* Above events are needed even before hw is ready, but other | ||
2667 | * events should be skipped during initialization. This may | ||
2668 | * change for AllocEv if allocate_fid is implemented without | ||
2669 | * busy waiting. */ | ||
2670 | if (!local->hw_ready || local->hw_resetting || | ||
2671 | !local->dev_enabled) { | ||
2672 | ev = HFA384X_INW(HFA384X_EVSTAT_OFF); | ||
2673 | if (ev & HFA384X_EV_CMD) | ||
2674 | goto next_event; | ||
2675 | if ((ev & HFA384X_EVENT_MASK) == 0) | ||
2676 | return IRQ_HANDLED; | ||
2677 | if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && | ||
2678 | net_ratelimit()) { | ||
2679 | printk(KERN_DEBUG "%s: prism2_interrupt: hw " | ||
2680 | "not ready; skipping events 0x%04x " | ||
2681 | "(IntEn=0x%04x)%s%s%s\n", | ||
2682 | dev->name, ev, | ||
2683 | HFA384X_INW(HFA384X_INTEN_OFF), | ||
2684 | !local->hw_ready ? " (!hw_ready)" : "", | ||
2685 | local->hw_resetting ? | ||
2686 | " (hw_resetting)" : "", | ||
2687 | !local->dev_enabled ? | ||
2688 | " (!dev_enabled)" : ""); | ||
2689 | } | ||
2690 | HFA384X_OUTW(ev, HFA384X_EVACK_OFF); | ||
2691 | return IRQ_HANDLED; | ||
2692 | } | ||
2693 | |||
2694 | if (ev & HFA384X_EV_TICK) { | ||
2695 | prism2_ev_tick(dev); | ||
2696 | HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); | ||
2697 | } | ||
2698 | |||
2699 | if (ev & HFA384X_EV_ALLOC) { | ||
2700 | prism2_alloc_ev(dev); | ||
2701 | HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | ||
2702 | } | ||
2703 | |||
2704 | /* Reading data from the card is quite time consuming, so do it | ||
2705 | * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed | ||
2706 | * and unmasked after needed data has been read completely. */ | ||
2707 | if (ev & HFA384X_BAP0_EVENTS) { | ||
2708 | hfa384x_events_no_bap0(dev); | ||
2709 | tasklet_schedule(&local->bap_tasklet); | ||
2710 | } | ||
2711 | |||
2712 | #ifndef final_version | ||
2713 | if (ev & HFA384X_EV_WTERR) { | ||
2714 | PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name); | ||
2715 | HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF); | ||
2716 | } | ||
2717 | #endif /* final_version */ | ||
2718 | |||
2719 | if (ev & HFA384X_EV_INFDROP) { | ||
2720 | prism2_infdrop(dev); | ||
2721 | HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF); | ||
2722 | } | ||
2723 | |||
2724 | next_event: | ||
2725 | events++; | ||
2726 | if (events >= PRISM2_MAX_INTERRUPT_EVENTS) { | ||
2727 | PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events " | ||
2728 | "(EvStat=0x%04x)\n", | ||
2729 | PRISM2_MAX_INTERRUPT_EVENTS, | ||
2730 | HFA384X_INW(HFA384X_EVSTAT_OFF)); | ||
2731 | break; | ||
2732 | } | ||
2733 | } | ||
2734 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1); | ||
2735 | return IRQ_RETVAL(events); | ||
2736 | } | ||
2737 | |||
2738 | |||
2739 | static void prism2_check_sta_fw_version(local_info_t *local) | ||
2740 | { | ||
2741 | struct hfa384x_comp_ident comp; | ||
2742 | int id, variant, major, minor; | ||
2743 | |||
2744 | if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID, | ||
2745 | &comp, sizeof(comp), 1) < 0) | ||
2746 | return; | ||
2747 | |||
2748 | local->fw_ap = 0; | ||
2749 | id = le16_to_cpu(comp.id); | ||
2750 | if (id != HFA384X_COMP_ID_STA) { | ||
2751 | if (id == HFA384X_COMP_ID_FW_AP) | ||
2752 | local->fw_ap = 1; | ||
2753 | return; | ||
2754 | } | ||
2755 | |||
2756 | major = __le16_to_cpu(comp.major); | ||
2757 | minor = __le16_to_cpu(comp.minor); | ||
2758 | variant = __le16_to_cpu(comp.variant); | ||
2759 | local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant); | ||
2760 | |||
2761 | /* Station firmware versions before 1.4.x seem to have a bug in | ||
2762 | * firmware-based WEP encryption when using Host AP mode, so use | ||
2763 | * host_encrypt as a default for them. Firmware version 1.4.9 is the | ||
2764 | * first one that has been seen to produce correct encryption, but the | ||
2765 | * bug might be fixed before that (although, at least 1.4.2 is broken). | ||
2766 | */ | ||
2767 | local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9); | ||
2768 | |||
2769 | if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
2770 | !local->fw_encrypt_ok) { | ||
2771 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
2772 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
2773 | local->dev->name); | ||
2774 | local->host_encrypt = 1; | ||
2775 | } | ||
2776 | |||
2777 | /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken | ||
2778 | * in station firmware versions before 1.5.x. With these versions, the | ||
2779 | * driver uses a workaround with bogus frame format (4th address after | ||
2780 | * the payload). This is not compatible with other AP devices. Since | ||
2781 | * the firmware bug is fixed in the latest station firmware versions, | ||
2782 | * automatically enable standard compliant mode for cards using station | ||
2783 | * firmware version 1.5.0 or newer. */ | ||
2784 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0)) | ||
2785 | local->wds_type |= HOSTAP_WDS_STANDARD_FRAME; | ||
2786 | else { | ||
2787 | printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a " | ||
2788 | "workaround for firmware bug in Host AP mode WDS\n", | ||
2789 | local->dev->name); | ||
2790 | } | ||
2791 | |||
2792 | hostap_check_sta_fw_version(local->ap, local->sta_fw_ver); | ||
2793 | } | ||
2794 | |||
2795 | |||
2796 | static void prism2_crypt_deinit_entries(local_info_t *local, int force) | ||
2797 | { | ||
2798 | struct list_head *ptr, *n; | ||
2799 | struct ieee80211_crypt_data *entry; | ||
2800 | |||
2801 | for (ptr = local->crypt_deinit_list.next, n = ptr->next; | ||
2802 | ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { | ||
2803 | entry = list_entry(ptr, struct ieee80211_crypt_data, list); | ||
2804 | |||
2805 | if (atomic_read(&entry->refcnt) != 0 && !force) | ||
2806 | continue; | ||
2807 | |||
2808 | list_del(ptr); | ||
2809 | |||
2810 | if (entry->ops) | ||
2811 | entry->ops->deinit(entry->priv); | ||
2812 | kfree(entry); | ||
2813 | } | ||
2814 | } | ||
2815 | |||
2816 | |||
2817 | static void prism2_crypt_deinit_handler(unsigned long data) | ||
2818 | { | ||
2819 | local_info_t *local = (local_info_t *) data; | ||
2820 | unsigned long flags; | ||
2821 | |||
2822 | spin_lock_irqsave(&local->lock, flags); | ||
2823 | prism2_crypt_deinit_entries(local, 0); | ||
2824 | if (!list_empty(&local->crypt_deinit_list)) { | ||
2825 | printk(KERN_DEBUG "%s: entries remaining in delayed crypt " | ||
2826 | "deletion list\n", local->dev->name); | ||
2827 | local->crypt_deinit_timer.expires = jiffies + HZ; | ||
2828 | add_timer(&local->crypt_deinit_timer); | ||
2829 | } | ||
2830 | spin_unlock_irqrestore(&local->lock, flags); | ||
2831 | |||
2832 | } | ||
2833 | |||
2834 | |||
2835 | static void hostap_passive_scan(unsigned long data) | ||
2836 | { | ||
2837 | local_info_t *local = (local_info_t *) data; | ||
2838 | struct net_device *dev = local->dev; | ||
2839 | u16 channel; | ||
2840 | |||
2841 | if (local->passive_scan_interval <= 0) | ||
2842 | return; | ||
2843 | |||
2844 | if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) { | ||
2845 | int max_tries = 16; | ||
2846 | |||
2847 | /* Even though host system does not really know when the WLAN | ||
2848 | * MAC is sending frames, try to avoid changing channels for | ||
2849 | * passive scanning when a host-generated frame is being | ||
2850 | * transmitted */ | ||
2851 | if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | ||
2852 | printk(KERN_DEBUG "%s: passive scan detected pending " | ||
2853 | "TX - delaying\n", dev->name); | ||
2854 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
2855 | add_timer(&local->passive_scan_timer); | ||
2856 | return; | ||
2857 | } | ||
2858 | |||
2859 | do { | ||
2860 | local->passive_scan_channel++; | ||
2861 | if (local->passive_scan_channel > 14) | ||
2862 | local->passive_scan_channel = 1; | ||
2863 | max_tries--; | ||
2864 | } while (!(local->channel_mask & | ||
2865 | (1 << (local->passive_scan_channel - 1))) && | ||
2866 | max_tries > 0); | ||
2867 | |||
2868 | if (max_tries == 0) { | ||
2869 | printk(KERN_INFO "%s: no allowed passive scan channels" | ||
2870 | " found\n", dev->name); | ||
2871 | return; | ||
2872 | } | ||
2873 | |||
2874 | printk(KERN_DEBUG "%s: passive scan channel %d\n", | ||
2875 | dev->name, local->passive_scan_channel); | ||
2876 | channel = local->passive_scan_channel; | ||
2877 | local->passive_scan_state = PASSIVE_SCAN_WAIT; | ||
2878 | local->passive_scan_timer.expires = jiffies + HZ / 10; | ||
2879 | } else { | ||
2880 | channel = local->channel; | ||
2881 | local->passive_scan_state = PASSIVE_SCAN_LISTEN; | ||
2882 | local->passive_scan_timer.expires = jiffies + | ||
2883 | local->passive_scan_interval * HZ; | ||
2884 | } | ||
2885 | |||
2886 | if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST | | ||
2887 | (HFA384X_TEST_CHANGE_CHANNEL << 8), | ||
2888 | channel, NULL, 0)) | ||
2889 | printk(KERN_ERR "%s: passive scan channel set %d " | ||
2890 | "failed\n", dev->name, channel); | ||
2891 | |||
2892 | add_timer(&local->passive_scan_timer); | ||
2893 | } | ||
2894 | |||
2895 | |||
2896 | /* Called only as a scheduled task when communications quality values should | ||
2897 | * be updated. */ | ||
2898 | static void handle_comms_qual_update(void *data) | ||
2899 | { | ||
2900 | local_info_t *local = data; | ||
2901 | prism2_update_comms_qual(local->dev); | ||
2902 | } | ||
2903 | |||
2904 | |||
2905 | /* Software watchdog - called as a timer. Hardware interrupt (Tick event) is | ||
2906 | * used to monitor that local->last_tick_timer is being updated. If not, | ||
2907 | * interrupt busy-loop is assumed and driver tries to recover by masking out | ||
2908 | * some events. */ | ||
2909 | static void hostap_tick_timer(unsigned long data) | ||
2910 | { | ||
2911 | static unsigned long last_inquire = 0; | ||
2912 | local_info_t *local = (local_info_t *) data; | ||
2913 | local->last_tick_timer = jiffies; | ||
2914 | |||
2915 | /* Inquire CommTallies every 10 seconds to keep the statistics updated | ||
2916 | * more often during low load and when using 32-bit tallies. */ | ||
2917 | if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) && | ||
2918 | !local->hw_downloading && local->hw_ready && | ||
2919 | !local->hw_resetting && local->dev_enabled) { | ||
2920 | hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE, | ||
2921 | HFA384X_INFO_COMMTALLIES, NULL, 0); | ||
2922 | last_inquire = jiffies; | ||
2923 | } | ||
2924 | |||
2925 | if ((local->last_comms_qual_update == 0 || | ||
2926 | time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) && | ||
2927 | (local->iw_mode == IW_MODE_INFRA || | ||
2928 | local->iw_mode == IW_MODE_ADHOC)) { | ||
2929 | schedule_work(&local->comms_qual_update); | ||
2930 | } | ||
2931 | |||
2932 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
2933 | add_timer(&local->tick_timer); | ||
2934 | } | ||
2935 | |||
2936 | |||
2937 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
2938 | static int prism2_registers_proc_read(char *page, char **start, off_t off, | ||
2939 | int count, int *eof, void *data) | ||
2940 | { | ||
2941 | char *p = page; | ||
2942 | local_info_t *local = (local_info_t *) data; | ||
2943 | |||
2944 | if (off != 0) { | ||
2945 | *eof = 1; | ||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2949 | #define SHOW_REG(n) \ | ||
2950 | p += sprintf(p, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF)) | ||
2951 | |||
2952 | SHOW_REG(CMD); | ||
2953 | SHOW_REG(PARAM0); | ||
2954 | SHOW_REG(PARAM1); | ||
2955 | SHOW_REG(PARAM2); | ||
2956 | SHOW_REG(STATUS); | ||
2957 | SHOW_REG(RESP0); | ||
2958 | SHOW_REG(RESP1); | ||
2959 | SHOW_REG(RESP2); | ||
2960 | SHOW_REG(INFOFID); | ||
2961 | SHOW_REG(CONTROL); | ||
2962 | SHOW_REG(SELECT0); | ||
2963 | SHOW_REG(SELECT1); | ||
2964 | SHOW_REG(OFFSET0); | ||
2965 | SHOW_REG(OFFSET1); | ||
2966 | SHOW_REG(RXFID); | ||
2967 | SHOW_REG(ALLOCFID); | ||
2968 | SHOW_REG(TXCOMPLFID); | ||
2969 | SHOW_REG(SWSUPPORT0); | ||
2970 | SHOW_REG(SWSUPPORT1); | ||
2971 | SHOW_REG(SWSUPPORT2); | ||
2972 | SHOW_REG(EVSTAT); | ||
2973 | SHOW_REG(INTEN); | ||
2974 | SHOW_REG(EVACK); | ||
2975 | /* Do not read data registers, because they change the state of the | ||
2976 | * MAC (offset += 2) */ | ||
2977 | /* SHOW_REG(DATA0); */ | ||
2978 | /* SHOW_REG(DATA1); */ | ||
2979 | SHOW_REG(AUXPAGE); | ||
2980 | SHOW_REG(AUXOFFSET); | ||
2981 | /* SHOW_REG(AUXDATA); */ | ||
2982 | #ifdef PRISM2_PCI | ||
2983 | SHOW_REG(PCICOR); | ||
2984 | SHOW_REG(PCIHCR); | ||
2985 | SHOW_REG(PCI_M0_ADDRH); | ||
2986 | SHOW_REG(PCI_M0_ADDRL); | ||
2987 | SHOW_REG(PCI_M0_LEN); | ||
2988 | SHOW_REG(PCI_M0_CTL); | ||
2989 | SHOW_REG(PCI_STATUS); | ||
2990 | SHOW_REG(PCI_M1_ADDRH); | ||
2991 | SHOW_REG(PCI_M1_ADDRL); | ||
2992 | SHOW_REG(PCI_M1_LEN); | ||
2993 | SHOW_REG(PCI_M1_CTL); | ||
2994 | #endif /* PRISM2_PCI */ | ||
2995 | |||
2996 | return (p - page); | ||
2997 | } | ||
2998 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
2999 | |||
3000 | |||
3001 | struct set_tim_data { | ||
3002 | struct list_head list; | ||
3003 | int aid; | ||
3004 | int set; | ||
3005 | }; | ||
3006 | |||
3007 | static int prism2_set_tim(struct net_device *dev, int aid, int set) | ||
3008 | { | ||
3009 | struct list_head *ptr; | ||
3010 | struct set_tim_data *new_entry; | ||
3011 | struct hostap_interface *iface; | ||
3012 | local_info_t *local; | ||
3013 | |||
3014 | iface = netdev_priv(dev); | ||
3015 | local = iface->local; | ||
3016 | |||
3017 | new_entry = (struct set_tim_data *) | ||
3018 | kmalloc(sizeof(*new_entry), GFP_ATOMIC); | ||
3019 | if (new_entry == NULL) { | ||
3020 | printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n", | ||
3021 | local->dev->name); | ||
3022 | return -ENOMEM; | ||
3023 | } | ||
3024 | memset(new_entry, 0, sizeof(*new_entry)); | ||
3025 | new_entry->aid = aid; | ||
3026 | new_entry->set = set; | ||
3027 | |||
3028 | spin_lock_bh(&local->set_tim_lock); | ||
3029 | list_for_each(ptr, &local->set_tim_list) { | ||
3030 | struct set_tim_data *entry = | ||
3031 | list_entry(ptr, struct set_tim_data, list); | ||
3032 | if (entry->aid == aid) { | ||
3033 | PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d " | ||
3034 | "set=%d ==> %d\n", | ||
3035 | local->dev->name, aid, entry->set, set); | ||
3036 | entry->set = set; | ||
3037 | kfree(new_entry); | ||
3038 | new_entry = NULL; | ||
3039 | break; | ||
3040 | } | ||
3041 | } | ||
3042 | if (new_entry) | ||
3043 | list_add_tail(&new_entry->list, &local->set_tim_list); | ||
3044 | spin_unlock_bh(&local->set_tim_lock); | ||
3045 | |||
3046 | schedule_work(&local->set_tim_queue); | ||
3047 | |||
3048 | return 0; | ||
3049 | } | ||
3050 | |||
3051 | |||
3052 | static void handle_set_tim_queue(void *data) | ||
3053 | { | ||
3054 | local_info_t *local = (local_info_t *) data; | ||
3055 | struct set_tim_data *entry; | ||
3056 | u16 val; | ||
3057 | |||
3058 | for (;;) { | ||
3059 | entry = NULL; | ||
3060 | spin_lock_bh(&local->set_tim_lock); | ||
3061 | if (!list_empty(&local->set_tim_list)) { | ||
3062 | entry = list_entry(local->set_tim_list.next, | ||
3063 | struct set_tim_data, list); | ||
3064 | list_del(&entry->list); | ||
3065 | } | ||
3066 | spin_unlock_bh(&local->set_tim_lock); | ||
3067 | if (!entry) | ||
3068 | break; | ||
3069 | |||
3070 | PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n", | ||
3071 | local->dev->name, entry->aid, entry->set); | ||
3072 | |||
3073 | val = entry->aid; | ||
3074 | if (entry->set) | ||
3075 | val |= 0x8000; | ||
3076 | if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) { | ||
3077 | printk(KERN_DEBUG "%s: set_tim failed (aid=%d " | ||
3078 | "set=%d)\n", | ||
3079 | local->dev->name, entry->aid, entry->set); | ||
3080 | } | ||
3081 | |||
3082 | kfree(entry); | ||
3083 | } | ||
3084 | } | ||
3085 | |||
3086 | |||
3087 | static void prism2_clear_set_tim_queue(local_info_t *local) | ||
3088 | { | ||
3089 | struct list_head *ptr, *n; | ||
3090 | |||
3091 | list_for_each_safe(ptr, n, &local->set_tim_list) { | ||
3092 | struct set_tim_data *entry; | ||
3093 | entry = list_entry(ptr, struct set_tim_data, list); | ||
3094 | list_del(&entry->list); | ||
3095 | kfree(entry); | ||
3096 | } | ||
3097 | } | ||
3098 | |||
3099 | |||
3100 | static struct net_device * | ||
3101 | prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, | ||
3102 | struct device *sdev) | ||
3103 | { | ||
3104 | struct net_device *dev; | ||
3105 | struct hostap_interface *iface; | ||
3106 | struct local_info *local; | ||
3107 | int len, i, ret; | ||
3108 | |||
3109 | if (funcs == NULL) | ||
3110 | return NULL; | ||
3111 | |||
3112 | len = strlen(dev_template); | ||
3113 | if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) { | ||
3114 | printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n", | ||
3115 | dev_template); | ||
3116 | return NULL; | ||
3117 | } | ||
3118 | |||
3119 | len = sizeof(struct hostap_interface) + | ||
3120 | 3 + sizeof(struct local_info) + | ||
3121 | 3 + sizeof(struct ap_data); | ||
3122 | |||
3123 | dev = alloc_etherdev(len); | ||
3124 | if (dev == NULL) | ||
3125 | return NULL; | ||
3126 | |||
3127 | iface = netdev_priv(dev); | ||
3128 | local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3); | ||
3129 | local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3); | ||
3130 | local->dev = iface->dev = dev; | ||
3131 | iface->local = local; | ||
3132 | iface->type = HOSTAP_INTERFACE_MASTER; | ||
3133 | INIT_LIST_HEAD(&local->hostap_interfaces); | ||
3134 | |||
3135 | local->hw_module = THIS_MODULE; | ||
3136 | |||
3137 | #ifdef PRISM2_IO_DEBUG | ||
3138 | local->io_debug_enabled = 1; | ||
3139 | #endif /* PRISM2_IO_DEBUG */ | ||
3140 | |||
3141 | local->func = funcs; | ||
3142 | local->func->cmd = hfa384x_cmd; | ||
3143 | local->func->read_regs = hfa384x_read_regs; | ||
3144 | local->func->get_rid = hfa384x_get_rid; | ||
3145 | local->func->set_rid = hfa384x_set_rid; | ||
3146 | local->func->hw_enable = prism2_hw_enable; | ||
3147 | local->func->hw_config = prism2_hw_config; | ||
3148 | local->func->hw_reset = prism2_hw_reset; | ||
3149 | local->func->hw_shutdown = prism2_hw_shutdown; | ||
3150 | local->func->reset_port = prism2_reset_port; | ||
3151 | local->func->schedule_reset = prism2_schedule_reset; | ||
3152 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3153 | local->func->read_aux = prism2_download_aux_dump; | ||
3154 | local->func->download = prism2_download; | ||
3155 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3156 | local->func->tx = prism2_tx_80211; | ||
3157 | local->func->set_tim = prism2_set_tim; | ||
3158 | local->func->need_tx_headroom = 0; /* no need to add txdesc in | ||
3159 | * skb->data (FIX: maybe for DMA bus | ||
3160 | * mastering? */ | ||
3161 | |||
3162 | local->mtu = mtu; | ||
3163 | |||
3164 | rwlock_init(&local->iface_lock); | ||
3165 | spin_lock_init(&local->txfidlock); | ||
3166 | spin_lock_init(&local->cmdlock); | ||
3167 | spin_lock_init(&local->baplock); | ||
3168 | spin_lock_init(&local->lock); | ||
3169 | init_MUTEX(&local->rid_bap_sem); | ||
3170 | |||
3171 | if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) | ||
3172 | card_idx = 0; | ||
3173 | local->card_idx = card_idx; | ||
3174 | |||
3175 | len = strlen(essid); | ||
3176 | memcpy(local->essid, essid, | ||
3177 | len > MAX_SSID_LEN ? MAX_SSID_LEN : len); | ||
3178 | local->essid[MAX_SSID_LEN] = '\0'; | ||
3179 | i = GET_INT_PARM(iw_mode, card_idx); | ||
3180 | if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) || | ||
3181 | i == IW_MODE_MONITOR) { | ||
3182 | local->iw_mode = i; | ||
3183 | } else { | ||
3184 | printk(KERN_WARNING "prism2: Unknown iw_mode %d; using " | ||
3185 | "IW_MODE_MASTER\n", i); | ||
3186 | local->iw_mode = IW_MODE_MASTER; | ||
3187 | } | ||
3188 | local->channel = GET_INT_PARM(channel, card_idx); | ||
3189 | local->beacon_int = GET_INT_PARM(beacon_int, card_idx); | ||
3190 | local->dtim_period = GET_INT_PARM(dtim_period, card_idx); | ||
3191 | local->wds_max_connections = 16; | ||
3192 | local->tx_control = HFA384X_TX_CTRL_FLAGS; | ||
3193 | local->manual_retry_count = -1; | ||
3194 | local->rts_threshold = 2347; | ||
3195 | local->fragm_threshold = 2346; | ||
3196 | local->rssi_to_dBm = 100; /* default; to be overriden by | ||
3197 | * cnfDbmAdjust, if available */ | ||
3198 | local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; | ||
3199 | local->sram_type = -1; | ||
3200 | local->scan_channel_mask = 0xffff; | ||
3201 | |||
3202 | /* Initialize task queue structures */ | ||
3203 | INIT_WORK(&local->reset_queue, handle_reset_queue, local); | ||
3204 | INIT_WORK(&local->set_multicast_list_queue, | ||
3205 | hostap_set_multicast_list_queue, local->dev); | ||
3206 | |||
3207 | INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local); | ||
3208 | INIT_LIST_HEAD(&local->set_tim_list); | ||
3209 | spin_lock_init(&local->set_tim_lock); | ||
3210 | |||
3211 | INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local); | ||
3212 | |||
3213 | /* Initialize tasklets for handling hardware IRQ related operations | ||
3214 | * outside hw IRQ handler */ | ||
3215 | #define HOSTAP_TASKLET_INIT(q, f, d) \ | ||
3216 | do { memset((q), 0, sizeof(*(q))); (q)->func = (f); (q)->data = (d); } \ | ||
3217 | while (0) | ||
3218 | HOSTAP_TASKLET_INIT(&local->bap_tasklet, hostap_bap_tasklet, | ||
3219 | (unsigned long) local); | ||
3220 | |||
3221 | HOSTAP_TASKLET_INIT(&local->info_tasklet, hostap_info_tasklet, | ||
3222 | (unsigned long) local); | ||
3223 | hostap_info_init(local); | ||
3224 | |||
3225 | HOSTAP_TASKLET_INIT(&local->rx_tasklet, | ||
3226 | hostap_rx_tasklet, (unsigned long) local); | ||
3227 | skb_queue_head_init(&local->rx_list); | ||
3228 | |||
3229 | HOSTAP_TASKLET_INIT(&local->sta_tx_exc_tasklet, | ||
3230 | hostap_sta_tx_exc_tasklet, (unsigned long) local); | ||
3231 | skb_queue_head_init(&local->sta_tx_exc_list); | ||
3232 | |||
3233 | INIT_LIST_HEAD(&local->cmd_queue); | ||
3234 | init_waitqueue_head(&local->hostscan_wq); | ||
3235 | INIT_LIST_HEAD(&local->crypt_deinit_list); | ||
3236 | init_timer(&local->crypt_deinit_timer); | ||
3237 | local->crypt_deinit_timer.data = (unsigned long) local; | ||
3238 | local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; | ||
3239 | |||
3240 | init_timer(&local->passive_scan_timer); | ||
3241 | local->passive_scan_timer.data = (unsigned long) local; | ||
3242 | local->passive_scan_timer.function = hostap_passive_scan; | ||
3243 | |||
3244 | init_timer(&local->tick_timer); | ||
3245 | local->tick_timer.data = (unsigned long) local; | ||
3246 | local->tick_timer.function = hostap_tick_timer; | ||
3247 | local->tick_timer.expires = jiffies + 2 * HZ; | ||
3248 | add_timer(&local->tick_timer); | ||
3249 | |||
3250 | INIT_LIST_HEAD(&local->bss_list); | ||
3251 | |||
3252 | hostap_setup_dev(dev, local, 1); | ||
3253 | local->saved_eth_header_parse = dev->hard_header_parse; | ||
3254 | |||
3255 | dev->hard_start_xmit = hostap_master_start_xmit; | ||
3256 | dev->type = ARPHRD_IEEE80211; | ||
3257 | dev->hard_header_parse = hostap_80211_header_parse; | ||
3258 | |||
3259 | rtnl_lock(); | ||
3260 | ret = dev_alloc_name(dev, "wifi%d"); | ||
3261 | SET_NETDEV_DEV(dev, sdev); | ||
3262 | if (ret >= 0) | ||
3263 | ret = register_netdevice(dev); | ||
3264 | rtnl_unlock(); | ||
3265 | if (ret < 0) { | ||
3266 | printk(KERN_WARNING "%s: register netdevice failed!\n", | ||
3267 | dev_info); | ||
3268 | goto fail; | ||
3269 | } | ||
3270 | printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); | ||
3271 | |||
3272 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3273 | create_proc_read_entry("registers", 0, local->proc, | ||
3274 | prism2_registers_proc_read, local); | ||
3275 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3276 | |||
3277 | hostap_init_data(local); | ||
3278 | return dev; | ||
3279 | |||
3280 | fail: | ||
3281 | free_netdev(dev); | ||
3282 | return NULL; | ||
3283 | } | ||
3284 | |||
3285 | |||
3286 | static int hostap_hw_ready(struct net_device *dev) | ||
3287 | { | ||
3288 | struct hostap_interface *iface; | ||
3289 | struct local_info *local; | ||
3290 | |||
3291 | iface = netdev_priv(dev); | ||
3292 | local = iface->local; | ||
3293 | local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0, | ||
3294 | "", dev_template); | ||
3295 | |||
3296 | if (local->ddev) { | ||
3297 | if (local->iw_mode == IW_MODE_INFRA || | ||
3298 | local->iw_mode == IW_MODE_ADHOC) { | ||
3299 | netif_carrier_off(local->dev); | ||
3300 | netif_carrier_off(local->ddev); | ||
3301 | } | ||
3302 | hostap_init_proc(local); | ||
3303 | hostap_init_ap_proc(local); | ||
3304 | return 0; | ||
3305 | } | ||
3306 | |||
3307 | return -1; | ||
3308 | } | ||
3309 | |||
3310 | |||
3311 | static void prism2_free_local_data(struct net_device *dev) | ||
3312 | { | ||
3313 | struct hostap_tx_callback_info *tx_cb, *tx_cb_prev; | ||
3314 | int i; | ||
3315 | struct hostap_interface *iface; | ||
3316 | struct local_info *local; | ||
3317 | struct list_head *ptr, *n; | ||
3318 | |||
3319 | if (dev == NULL) | ||
3320 | return; | ||
3321 | |||
3322 | iface = netdev_priv(dev); | ||
3323 | local = iface->local; | ||
3324 | |||
3325 | flush_scheduled_work(); | ||
3326 | |||
3327 | if (timer_pending(&local->crypt_deinit_timer)) | ||
3328 | del_timer(&local->crypt_deinit_timer); | ||
3329 | prism2_crypt_deinit_entries(local, 1); | ||
3330 | |||
3331 | if (timer_pending(&local->passive_scan_timer)) | ||
3332 | del_timer(&local->passive_scan_timer); | ||
3333 | |||
3334 | if (timer_pending(&local->tick_timer)) | ||
3335 | del_timer(&local->tick_timer); | ||
3336 | |||
3337 | prism2_clear_cmd_queue(local); | ||
3338 | |||
3339 | skb_queue_purge(&local->info_list); | ||
3340 | skb_queue_purge(&local->rx_list); | ||
3341 | skb_queue_purge(&local->sta_tx_exc_list); | ||
3342 | |||
3343 | if (local->dev_enabled) | ||
3344 | prism2_callback(local, PRISM2_CALLBACK_DISABLE); | ||
3345 | |||
3346 | for (i = 0; i < WEP_KEYS; i++) { | ||
3347 | struct ieee80211_crypt_data *crypt = local->crypt[i]; | ||
3348 | if (crypt) { | ||
3349 | if (crypt->ops) | ||
3350 | crypt->ops->deinit(crypt->priv); | ||
3351 | kfree(crypt); | ||
3352 | local->crypt[i] = NULL; | ||
3353 | } | ||
3354 | } | ||
3355 | |||
3356 | if (local->ap != NULL) | ||
3357 | hostap_free_data(local->ap); | ||
3358 | |||
3359 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
3360 | if (local->proc != NULL) | ||
3361 | remove_proc_entry("registers", local->proc); | ||
3362 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
3363 | hostap_remove_proc(local); | ||
3364 | |||
3365 | tx_cb = local->tx_callback; | ||
3366 | while (tx_cb != NULL) { | ||
3367 | tx_cb_prev = tx_cb; | ||
3368 | tx_cb = tx_cb->next; | ||
3369 | kfree(tx_cb_prev); | ||
3370 | } | ||
3371 | |||
3372 | hostap_set_hostapd(local, 0, 0); | ||
3373 | hostap_set_hostapd_sta(local, 0, 0); | ||
3374 | |||
3375 | for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | ||
3376 | if (local->frag_cache[i].skb != NULL) | ||
3377 | dev_kfree_skb(local->frag_cache[i].skb); | ||
3378 | } | ||
3379 | |||
3380 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3381 | prism2_download_free_data(local->dl_pri); | ||
3382 | prism2_download_free_data(local->dl_sec); | ||
3383 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3384 | |||
3385 | list_for_each_safe(ptr, n, &local->hostap_interfaces) { | ||
3386 | iface = list_entry(ptr, struct hostap_interface, list); | ||
3387 | if (iface->type == HOSTAP_INTERFACE_MASTER) { | ||
3388 | /* special handling for this interface below */ | ||
3389 | continue; | ||
3390 | } | ||
3391 | hostap_remove_interface(iface->dev, 0, 1); | ||
3392 | } | ||
3393 | |||
3394 | prism2_clear_set_tim_queue(local); | ||
3395 | |||
3396 | list_for_each_safe(ptr, n, &local->bss_list) { | ||
3397 | struct hostap_bss_info *bss = | ||
3398 | list_entry(ptr, struct hostap_bss_info, list); | ||
3399 | kfree(bss); | ||
3400 | } | ||
3401 | |||
3402 | kfree(local->pda); | ||
3403 | kfree(local->last_scan_results); | ||
3404 | kfree(local->generic_elem); | ||
3405 | |||
3406 | unregister_netdev(local->dev); | ||
3407 | free_netdev(local->dev); | ||
3408 | } | ||
3409 | |||
3410 | |||
3411 | #ifndef PRISM2_PLX | ||
3412 | static void prism2_suspend(struct net_device *dev) | ||
3413 | { | ||
3414 | struct hostap_interface *iface; | ||
3415 | struct local_info *local; | ||
3416 | union iwreq_data wrqu; | ||
3417 | |||
3418 | iface = dev->priv; | ||
3419 | local = iface->local; | ||
3420 | |||
3421 | /* Send disconnect event, e.g., to trigger reassociation after resume | ||
3422 | * if wpa_supplicant is used. */ | ||
3423 | memset(&wrqu, 0, sizeof(wrqu)); | ||
3424 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
3425 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
3426 | |||
3427 | /* Disable hardware and firmware */ | ||
3428 | prism2_hw_shutdown(dev, 0); | ||
3429 | } | ||
3430 | #endif /* PRISM2_PLX */ | ||
3431 | |||
3432 | |||
3433 | /* These might at some point be compiled separately and used as separate | ||
3434 | * kernel modules or linked into one */ | ||
3435 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3436 | #include "hostap_download.c" | ||
3437 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3438 | |||
3439 | #ifdef PRISM2_CALLBACK | ||
3440 | /* External hostap_callback.c file can be used to, e.g., blink activity led. | ||
3441 | * This can use platform specific code and must define prism2_callback() | ||
3442 | * function (if PRISM2_CALLBACK is not defined, these function calls are not | ||
3443 | * used. */ | ||
3444 | #include "hostap_callback.c" | ||
3445 | #endif /* PRISM2_CALLBACK */ | ||
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c new file mode 100644 index 000000000000..5aa998fdf1c4 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_info.c | |||
@@ -0,0 +1,499 @@ | |||
1 | /* Host AP driver Info Frame processing (part of hostap.o module) */ | ||
2 | |||
3 | |||
4 | /* Called only as a tasklet (software IRQ) */ | ||
5 | static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, | ||
6 | int left) | ||
7 | { | ||
8 | struct hfa384x_comm_tallies *tallies; | ||
9 | |||
10 | if (left < sizeof(struct hfa384x_comm_tallies)) { | ||
11 | printk(KERN_DEBUG "%s: too short (len=%d) commtallies " | ||
12 | "info frame\n", local->dev->name, left); | ||
13 | return; | ||
14 | } | ||
15 | |||
16 | tallies = (struct hfa384x_comm_tallies *) buf; | ||
17 | #define ADD_COMM_TALLIES(name) \ | ||
18 | local->comm_tallies.name += le16_to_cpu(tallies->name) | ||
19 | ADD_COMM_TALLIES(tx_unicast_frames); | ||
20 | ADD_COMM_TALLIES(tx_multicast_frames); | ||
21 | ADD_COMM_TALLIES(tx_fragments); | ||
22 | ADD_COMM_TALLIES(tx_unicast_octets); | ||
23 | ADD_COMM_TALLIES(tx_multicast_octets); | ||
24 | ADD_COMM_TALLIES(tx_deferred_transmissions); | ||
25 | ADD_COMM_TALLIES(tx_single_retry_frames); | ||
26 | ADD_COMM_TALLIES(tx_multiple_retry_frames); | ||
27 | ADD_COMM_TALLIES(tx_retry_limit_exceeded); | ||
28 | ADD_COMM_TALLIES(tx_discards); | ||
29 | ADD_COMM_TALLIES(rx_unicast_frames); | ||
30 | ADD_COMM_TALLIES(rx_multicast_frames); | ||
31 | ADD_COMM_TALLIES(rx_fragments); | ||
32 | ADD_COMM_TALLIES(rx_unicast_octets); | ||
33 | ADD_COMM_TALLIES(rx_multicast_octets); | ||
34 | ADD_COMM_TALLIES(rx_fcs_errors); | ||
35 | ADD_COMM_TALLIES(rx_discards_no_buffer); | ||
36 | ADD_COMM_TALLIES(tx_discards_wrong_sa); | ||
37 | ADD_COMM_TALLIES(rx_discards_wep_undecryptable); | ||
38 | ADD_COMM_TALLIES(rx_message_in_msg_fragments); | ||
39 | ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); | ||
40 | #undef ADD_COMM_TALLIES | ||
41 | } | ||
42 | |||
43 | |||
44 | /* Called only as a tasklet (software IRQ) */ | ||
45 | static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, | ||
46 | int left) | ||
47 | { | ||
48 | struct hfa384x_comm_tallies32 *tallies; | ||
49 | |||
50 | if (left < sizeof(struct hfa384x_comm_tallies32)) { | ||
51 | printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " | ||
52 | "info frame\n", local->dev->name, left); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | tallies = (struct hfa384x_comm_tallies32 *) buf; | ||
57 | #define ADD_COMM_TALLIES(name) \ | ||
58 | local->comm_tallies.name += le32_to_cpu(tallies->name) | ||
59 | ADD_COMM_TALLIES(tx_unicast_frames); | ||
60 | ADD_COMM_TALLIES(tx_multicast_frames); | ||
61 | ADD_COMM_TALLIES(tx_fragments); | ||
62 | ADD_COMM_TALLIES(tx_unicast_octets); | ||
63 | ADD_COMM_TALLIES(tx_multicast_octets); | ||
64 | ADD_COMM_TALLIES(tx_deferred_transmissions); | ||
65 | ADD_COMM_TALLIES(tx_single_retry_frames); | ||
66 | ADD_COMM_TALLIES(tx_multiple_retry_frames); | ||
67 | ADD_COMM_TALLIES(tx_retry_limit_exceeded); | ||
68 | ADD_COMM_TALLIES(tx_discards); | ||
69 | ADD_COMM_TALLIES(rx_unicast_frames); | ||
70 | ADD_COMM_TALLIES(rx_multicast_frames); | ||
71 | ADD_COMM_TALLIES(rx_fragments); | ||
72 | ADD_COMM_TALLIES(rx_unicast_octets); | ||
73 | ADD_COMM_TALLIES(rx_multicast_octets); | ||
74 | ADD_COMM_TALLIES(rx_fcs_errors); | ||
75 | ADD_COMM_TALLIES(rx_discards_no_buffer); | ||
76 | ADD_COMM_TALLIES(tx_discards_wrong_sa); | ||
77 | ADD_COMM_TALLIES(rx_discards_wep_undecryptable); | ||
78 | ADD_COMM_TALLIES(rx_message_in_msg_fragments); | ||
79 | ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); | ||
80 | #undef ADD_COMM_TALLIES | ||
81 | } | ||
82 | |||
83 | |||
84 | /* Called only as a tasklet (software IRQ) */ | ||
85 | static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, | ||
86 | int left) | ||
87 | { | ||
88 | if (local->tallies32) | ||
89 | prism2_info_commtallies32(local, buf, left); | ||
90 | else | ||
91 | prism2_info_commtallies16(local, buf, left); | ||
92 | } | ||
93 | |||
94 | |||
95 | #ifndef PRISM2_NO_STATION_MODES | ||
96 | #ifndef PRISM2_NO_DEBUG | ||
97 | static const char* hfa384x_linkstatus_str(u16 linkstatus) | ||
98 | { | ||
99 | switch (linkstatus) { | ||
100 | case HFA384X_LINKSTATUS_CONNECTED: | ||
101 | return "Connected"; | ||
102 | case HFA384X_LINKSTATUS_DISCONNECTED: | ||
103 | return "Disconnected"; | ||
104 | case HFA384X_LINKSTATUS_AP_CHANGE: | ||
105 | return "Access point change"; | ||
106 | case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: | ||
107 | return "Access point out of range"; | ||
108 | case HFA384X_LINKSTATUS_AP_IN_RANGE: | ||
109 | return "Access point in range"; | ||
110 | case HFA384X_LINKSTATUS_ASSOC_FAILED: | ||
111 | return "Association failed"; | ||
112 | default: | ||
113 | return "Unknown"; | ||
114 | } | ||
115 | } | ||
116 | #endif /* PRISM2_NO_DEBUG */ | ||
117 | |||
118 | |||
119 | /* Called only as a tasklet (software IRQ) */ | ||
120 | static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, | ||
121 | int left) | ||
122 | { | ||
123 | u16 val; | ||
124 | int non_sta_mode; | ||
125 | |||
126 | /* Alloc new JoinRequests to occur since LinkStatus for the previous | ||
127 | * has been received */ | ||
128 | local->last_join_time = 0; | ||
129 | |||
130 | if (left != 2) { | ||
131 | printk(KERN_DEBUG "%s: invalid linkstatus info frame " | ||
132 | "length %d\n", local->dev->name, left); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | non_sta_mode = local->iw_mode == IW_MODE_MASTER || | ||
137 | local->iw_mode == IW_MODE_REPEAT || | ||
138 | local->iw_mode == IW_MODE_MONITOR; | ||
139 | |||
140 | val = buf[0] | (buf[1] << 8); | ||
141 | if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { | ||
142 | PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", | ||
143 | local->dev->name, val, hfa384x_linkstatus_str(val)); | ||
144 | } | ||
145 | |||
146 | if (non_sta_mode) { | ||
147 | netif_carrier_on(local->dev); | ||
148 | netif_carrier_on(local->ddev); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | /* Get current BSSID later in scheduled task */ | ||
153 | set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); | ||
154 | local->prev_link_status = val; | ||
155 | schedule_work(&local->info_queue); | ||
156 | } | ||
157 | |||
158 | |||
159 | static void prism2_host_roaming(local_info_t *local) | ||
160 | { | ||
161 | struct hfa384x_join_request req; | ||
162 | struct net_device *dev = local->dev; | ||
163 | struct hfa384x_hostscan_result *selected, *entry; | ||
164 | int i; | ||
165 | unsigned long flags; | ||
166 | |||
167 | if (local->last_join_time && | ||
168 | time_before(jiffies, local->last_join_time + 10 * HZ)) { | ||
169 | PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " | ||
170 | "completed - waiting for it before issuing new one\n", | ||
171 | dev->name); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | /* ScanResults are sorted: first ESS results in decreasing signal | ||
176 | * quality then IBSS results in similar order. | ||
177 | * Trivial roaming policy: just select the first entry. | ||
178 | * This could probably be improved by adding hysteresis to limit | ||
179 | * number of handoffs, etc. | ||
180 | * | ||
181 | * Could do periodic RID_SCANREQUEST or Inquire F101 to get new | ||
182 | * ScanResults */ | ||
183 | spin_lock_irqsave(&local->lock, flags); | ||
184 | if (local->last_scan_results == NULL || | ||
185 | local->last_scan_results_count == 0) { | ||
186 | spin_unlock_irqrestore(&local->lock, flags); | ||
187 | PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", | ||
188 | dev->name); | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | selected = &local->last_scan_results[0]; | ||
193 | |||
194 | if (local->preferred_ap[0] || local->preferred_ap[1] || | ||
195 | local->preferred_ap[2] || local->preferred_ap[3] || | ||
196 | local->preferred_ap[4] || local->preferred_ap[5]) { | ||
197 | /* Try to find preferred AP */ | ||
198 | PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", | ||
199 | dev->name, MAC2STR(local->preferred_ap)); | ||
200 | for (i = 0; i < local->last_scan_results_count; i++) { | ||
201 | entry = &local->last_scan_results[i]; | ||
202 | if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) | ||
203 | { | ||
204 | PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " | ||
205 | "selection\n", dev->name); | ||
206 | selected = entry; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | memcpy(req.bssid, selected->bssid, 6); | ||
213 | req.channel = selected->chid; | ||
214 | spin_unlock_irqrestore(&local->lock, flags); | ||
215 | |||
216 | PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", | ||
217 | dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); | ||
218 | if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, | ||
219 | sizeof(req))) { | ||
220 | printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); | ||
221 | } | ||
222 | local->last_join_time = jiffies; | ||
223 | } | ||
224 | |||
225 | |||
226 | static void hostap_report_scan_complete(local_info_t *local) | ||
227 | { | ||
228 | union iwreq_data wrqu; | ||
229 | |||
230 | /* Inform user space about new scan results (just empty event, | ||
231 | * SIOCGIWSCAN can be used to fetch data */ | ||
232 | wrqu.data.length = 0; | ||
233 | wrqu.data.flags = 0; | ||
234 | wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
235 | |||
236 | /* Allow SIOCGIWSCAN handling to occur since we have received | ||
237 | * scanning result */ | ||
238 | local->scan_timestamp = 0; | ||
239 | } | ||
240 | |||
241 | |||
242 | /* Called only as a tasklet (software IRQ) */ | ||
243 | static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, | ||
244 | int left) | ||
245 | { | ||
246 | u16 *pos; | ||
247 | int new_count, i; | ||
248 | unsigned long flags; | ||
249 | struct hfa384x_scan_result *res; | ||
250 | struct hfa384x_hostscan_result *results, *prev; | ||
251 | |||
252 | if (left < 4) { | ||
253 | printk(KERN_DEBUG "%s: invalid scanresult info frame " | ||
254 | "length %d\n", local->dev->name, left); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | pos = (u16 *) buf; | ||
259 | pos++; | ||
260 | pos++; | ||
261 | left -= 4; | ||
262 | |||
263 | new_count = left / sizeof(struct hfa384x_scan_result); | ||
264 | results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), | ||
265 | GFP_ATOMIC); | ||
266 | if (results == NULL) | ||
267 | return; | ||
268 | |||
269 | /* Convert to hostscan result format. */ | ||
270 | res = (struct hfa384x_scan_result *) pos; | ||
271 | for (i = 0; i < new_count; i++) { | ||
272 | memcpy(&results[i], &res[i], | ||
273 | sizeof(struct hfa384x_scan_result)); | ||
274 | results[i].atim = 0; | ||
275 | } | ||
276 | |||
277 | spin_lock_irqsave(&local->lock, flags); | ||
278 | local->last_scan_type = PRISM2_SCAN; | ||
279 | prev = local->last_scan_results; | ||
280 | local->last_scan_results = results; | ||
281 | local->last_scan_results_count = new_count; | ||
282 | spin_unlock_irqrestore(&local->lock, flags); | ||
283 | kfree(prev); | ||
284 | |||
285 | hostap_report_scan_complete(local); | ||
286 | |||
287 | /* Perform rest of ScanResults handling later in scheduled task */ | ||
288 | set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); | ||
289 | schedule_work(&local->info_queue); | ||
290 | } | ||
291 | |||
292 | |||
293 | /* Called only as a tasklet (software IRQ) */ | ||
294 | static void prism2_info_hostscanresults(local_info_t *local, | ||
295 | unsigned char *buf, int left) | ||
296 | { | ||
297 | int i, result_size, copy_len, new_count; | ||
298 | struct hfa384x_hostscan_result *results, *prev; | ||
299 | unsigned long flags; | ||
300 | u16 *pos; | ||
301 | u8 *ptr; | ||
302 | |||
303 | wake_up_interruptible(&local->hostscan_wq); | ||
304 | |||
305 | if (left < 4) { | ||
306 | printk(KERN_DEBUG "%s: invalid hostscanresult info frame " | ||
307 | "length %d\n", local->dev->name, left); | ||
308 | return; | ||
309 | } | ||
310 | |||
311 | pos = (u16 *) buf; | ||
312 | copy_len = result_size = le16_to_cpu(*pos); | ||
313 | if (result_size == 0) { | ||
314 | printk(KERN_DEBUG "%s: invalid result_size (0) in " | ||
315 | "hostscanresults\n", local->dev->name); | ||
316 | return; | ||
317 | } | ||
318 | if (copy_len > sizeof(struct hfa384x_hostscan_result)) | ||
319 | copy_len = sizeof(struct hfa384x_hostscan_result); | ||
320 | |||
321 | pos++; | ||
322 | pos++; | ||
323 | left -= 4; | ||
324 | ptr = (u8 *) pos; | ||
325 | |||
326 | new_count = left / result_size; | ||
327 | results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), | ||
328 | GFP_ATOMIC); | ||
329 | if (results == NULL) | ||
330 | return; | ||
331 | memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result)); | ||
332 | |||
333 | for (i = 0; i < new_count; i++) { | ||
334 | memcpy(&results[i], ptr, copy_len); | ||
335 | ptr += result_size; | ||
336 | left -= result_size; | ||
337 | } | ||
338 | |||
339 | if (left) { | ||
340 | printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", | ||
341 | local->dev->name, left, result_size); | ||
342 | } | ||
343 | |||
344 | spin_lock_irqsave(&local->lock, flags); | ||
345 | local->last_scan_type = PRISM2_HOSTSCAN; | ||
346 | prev = local->last_scan_results; | ||
347 | local->last_scan_results = results; | ||
348 | local->last_scan_results_count = new_count; | ||
349 | spin_unlock_irqrestore(&local->lock, flags); | ||
350 | kfree(prev); | ||
351 | |||
352 | hostap_report_scan_complete(local); | ||
353 | } | ||
354 | #endif /* PRISM2_NO_STATION_MODES */ | ||
355 | |||
356 | |||
357 | /* Called only as a tasklet (software IRQ) */ | ||
358 | void hostap_info_process(local_info_t *local, struct sk_buff *skb) | ||
359 | { | ||
360 | struct hfa384x_info_frame *info; | ||
361 | unsigned char *buf; | ||
362 | int left; | ||
363 | #ifndef PRISM2_NO_DEBUG | ||
364 | int i; | ||
365 | #endif /* PRISM2_NO_DEBUG */ | ||
366 | |||
367 | info = (struct hfa384x_info_frame *) skb->data; | ||
368 | buf = skb->data + sizeof(*info); | ||
369 | left = skb->len - sizeof(*info); | ||
370 | |||
371 | switch (info->type) { | ||
372 | case HFA384X_INFO_COMMTALLIES: | ||
373 | prism2_info_commtallies(local, buf, left); | ||
374 | break; | ||
375 | |||
376 | #ifndef PRISM2_NO_STATION_MODES | ||
377 | case HFA384X_INFO_LINKSTATUS: | ||
378 | prism2_info_linkstatus(local, buf, left); | ||
379 | break; | ||
380 | |||
381 | case HFA384X_INFO_SCANRESULTS: | ||
382 | prism2_info_scanresults(local, buf, left); | ||
383 | break; | ||
384 | |||
385 | case HFA384X_INFO_HOSTSCANRESULTS: | ||
386 | prism2_info_hostscanresults(local, buf, left); | ||
387 | break; | ||
388 | #endif /* PRISM2_NO_STATION_MODES */ | ||
389 | |||
390 | #ifndef PRISM2_NO_DEBUG | ||
391 | default: | ||
392 | PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", | ||
393 | local->dev->name, info->len, info->type); | ||
394 | PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); | ||
395 | for (i = 0; i < (left < 100 ? left : 100); i++) | ||
396 | PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); | ||
397 | PDEBUG2(DEBUG_EXTRA, "\n"); | ||
398 | break; | ||
399 | #endif /* PRISM2_NO_DEBUG */ | ||
400 | } | ||
401 | } | ||
402 | |||
403 | |||
404 | #ifndef PRISM2_NO_STATION_MODES | ||
405 | static void handle_info_queue_linkstatus(local_info_t *local) | ||
406 | { | ||
407 | int val = local->prev_link_status; | ||
408 | int connected; | ||
409 | union iwreq_data wrqu; | ||
410 | |||
411 | connected = | ||
412 | val == HFA384X_LINKSTATUS_CONNECTED || | ||
413 | val == HFA384X_LINKSTATUS_AP_CHANGE || | ||
414 | val == HFA384X_LINKSTATUS_AP_IN_RANGE; | ||
415 | |||
416 | if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, | ||
417 | local->bssid, ETH_ALEN, 1) < 0) { | ||
418 | printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " | ||
419 | "LinkStatus event\n", local->dev->name); | ||
420 | } else { | ||
421 | PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", | ||
422 | local->dev->name, | ||
423 | MAC2STR((unsigned char *) local->bssid)); | ||
424 | if (local->wds_type & HOSTAP_WDS_AP_CLIENT) | ||
425 | hostap_add_sta(local->ap, local->bssid); | ||
426 | } | ||
427 | |||
428 | /* Get BSSID if we have a valid AP address */ | ||
429 | if (connected) { | ||
430 | netif_carrier_on(local->dev); | ||
431 | netif_carrier_on(local->ddev); | ||
432 | memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); | ||
433 | } else { | ||
434 | netif_carrier_off(local->dev); | ||
435 | netif_carrier_off(local->ddev); | ||
436 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
437 | } | ||
438 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
439 | |||
440 | /* | ||
441 | * Filter out sequential disconnect events in order not to cause a | ||
442 | * flood of SIOCGIWAP events that have a race condition with EAPOL | ||
443 | * frames and can confuse wpa_supplicant about the current association | ||
444 | * status. | ||
445 | */ | ||
446 | if (connected || local->prev_linkstatus_connected) | ||
447 | wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); | ||
448 | local->prev_linkstatus_connected = connected; | ||
449 | } | ||
450 | |||
451 | |||
452 | static void handle_info_queue_scanresults(local_info_t *local) | ||
453 | { | ||
454 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) | ||
455 | prism2_host_roaming(local); | ||
456 | |||
457 | if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA && | ||
458 | memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00", | ||
459 | ETH_ALEN) != 0) { | ||
460 | /* | ||
461 | * Firmware seems to be getting into odd state in host_roaming | ||
462 | * mode 2 when hostscan is used without join command, so try | ||
463 | * to fix this by re-joining the current AP. This does not | ||
464 | * actually trigger a new association if the current AP is | ||
465 | * still in the scan results. | ||
466 | */ | ||
467 | prism2_host_roaming(local); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | |||
472 | /* Called only as scheduled task after receiving info frames (used to avoid | ||
473 | * pending too much time in HW IRQ handler). */ | ||
474 | static void handle_info_queue(void *data) | ||
475 | { | ||
476 | local_info_t *local = (local_info_t *) data; | ||
477 | |||
478 | if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, | ||
479 | &local->pending_info)) | ||
480 | handle_info_queue_linkstatus(local); | ||
481 | |||
482 | if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, | ||
483 | &local->pending_info)) | ||
484 | handle_info_queue_scanresults(local); | ||
485 | } | ||
486 | #endif /* PRISM2_NO_STATION_MODES */ | ||
487 | |||
488 | |||
489 | void hostap_info_init(local_info_t *local) | ||
490 | { | ||
491 | skb_queue_head_init(&local->info_list); | ||
492 | #ifndef PRISM2_NO_STATION_MODES | ||
493 | INIT_WORK(&local->info_queue, handle_info_queue, local); | ||
494 | #endif /* PRISM2_NO_STATION_MODES */ | ||
495 | } | ||
496 | |||
497 | |||
498 | EXPORT_SYMBOL(hostap_info_init); | ||
499 | EXPORT_SYMBOL(hostap_info_process); | ||
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c new file mode 100644 index 000000000000..e720369a3515 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_ioctl.c | |||
@@ -0,0 +1,4102 @@ | |||
1 | /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ | ||
2 | |||
3 | #ifdef in_atomic | ||
4 | /* Get kernel_locked() for in_atomic() */ | ||
5 | #include <linux/smp_lock.h> | ||
6 | #endif | ||
7 | #include <linux/ethtool.h> | ||
8 | |||
9 | |||
10 | static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) | ||
11 | { | ||
12 | struct hostap_interface *iface; | ||
13 | local_info_t *local; | ||
14 | struct iw_statistics *wstats; | ||
15 | |||
16 | iface = netdev_priv(dev); | ||
17 | local = iface->local; | ||
18 | |||
19 | /* Why are we doing that ? Jean II */ | ||
20 | if (iface->type != HOSTAP_INTERFACE_MAIN) | ||
21 | return NULL; | ||
22 | |||
23 | wstats = &local->wstats; | ||
24 | |||
25 | wstats->status = 0; | ||
26 | wstats->discard.code = | ||
27 | local->comm_tallies.rx_discards_wep_undecryptable; | ||
28 | wstats->discard.misc = | ||
29 | local->comm_tallies.rx_fcs_errors + | ||
30 | local->comm_tallies.rx_discards_no_buffer + | ||
31 | local->comm_tallies.tx_discards_wrong_sa; | ||
32 | |||
33 | wstats->discard.retries = | ||
34 | local->comm_tallies.tx_retry_limit_exceeded; | ||
35 | wstats->discard.fragment = | ||
36 | local->comm_tallies.rx_message_in_bad_msg_fragments; | ||
37 | |||
38 | if (local->iw_mode != IW_MODE_MASTER && | ||
39 | local->iw_mode != IW_MODE_REPEAT) { | ||
40 | int update = 1; | ||
41 | #ifdef in_atomic | ||
42 | /* RID reading might sleep and it must not be called in | ||
43 | * interrupt context or while atomic. However, this | ||
44 | * function seems to be called while atomic (at least in Linux | ||
45 | * 2.5.59). Update signal quality values only if in suitable | ||
46 | * context. Otherwise, previous values read from tick timer | ||
47 | * will be used. */ | ||
48 | if (in_atomic()) | ||
49 | update = 0; | ||
50 | #endif /* in_atomic */ | ||
51 | |||
52 | if (update && prism2_update_comms_qual(dev) == 0) | ||
53 | wstats->qual.updated = 7; | ||
54 | |||
55 | wstats->qual.qual = local->comms_qual; | ||
56 | wstats->qual.level = local->avg_signal; | ||
57 | wstats->qual.noise = local->avg_noise; | ||
58 | } else { | ||
59 | wstats->qual.qual = 0; | ||
60 | wstats->qual.level = 0; | ||
61 | wstats->qual.noise = 0; | ||
62 | wstats->qual.updated = 0; | ||
63 | } | ||
64 | |||
65 | return wstats; | ||
66 | } | ||
67 | |||
68 | |||
69 | static int prism2_get_datarates(struct net_device *dev, u8 *rates) | ||
70 | { | ||
71 | struct hostap_interface *iface; | ||
72 | local_info_t *local; | ||
73 | u8 buf[12]; | ||
74 | int len; | ||
75 | u16 val; | ||
76 | |||
77 | iface = netdev_priv(dev); | ||
78 | local = iface->local; | ||
79 | |||
80 | len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf, | ||
81 | sizeof(buf), 0); | ||
82 | if (len < 2) | ||
83 | return 0; | ||
84 | |||
85 | val = le16_to_cpu(*(u16 *) buf); /* string length */ | ||
86 | |||
87 | if (len - 2 < val || val > 10) | ||
88 | return 0; | ||
89 | |||
90 | memcpy(rates, buf + 2, val); | ||
91 | return val; | ||
92 | } | ||
93 | |||
94 | |||
95 | static int prism2_get_name(struct net_device *dev, | ||
96 | struct iw_request_info *info, | ||
97 | char *name, char *extra) | ||
98 | { | ||
99 | u8 rates[10]; | ||
100 | int len, i, over2 = 0; | ||
101 | |||
102 | len = prism2_get_datarates(dev, rates); | ||
103 | |||
104 | for (i = 0; i < len; i++) { | ||
105 | if (rates[i] == 0x0b || rates[i] == 0x16) { | ||
106 | over2 = 1; | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | strcpy(name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS"); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static void prism2_crypt_delayed_deinit(local_info_t *local, | ||
118 | struct ieee80211_crypt_data **crypt) | ||
119 | { | ||
120 | struct ieee80211_crypt_data *tmp; | ||
121 | unsigned long flags; | ||
122 | |||
123 | tmp = *crypt; | ||
124 | *crypt = NULL; | ||
125 | |||
126 | if (tmp == NULL) | ||
127 | return; | ||
128 | |||
129 | /* must not run ops->deinit() while there may be pending encrypt or | ||
130 | * decrypt operations. Use a list of delayed deinits to avoid needing | ||
131 | * locking. */ | ||
132 | |||
133 | spin_lock_irqsave(&local->lock, flags); | ||
134 | list_add(&tmp->list, &local->crypt_deinit_list); | ||
135 | if (!timer_pending(&local->crypt_deinit_timer)) { | ||
136 | local->crypt_deinit_timer.expires = jiffies + HZ; | ||
137 | add_timer(&local->crypt_deinit_timer); | ||
138 | } | ||
139 | spin_unlock_irqrestore(&local->lock, flags); | ||
140 | } | ||
141 | |||
142 | |||
143 | static int prism2_ioctl_siwencode(struct net_device *dev, | ||
144 | struct iw_request_info *info, | ||
145 | struct iw_point *erq, char *keybuf) | ||
146 | { | ||
147 | struct hostap_interface *iface; | ||
148 | local_info_t *local; | ||
149 | int i; | ||
150 | struct ieee80211_crypt_data **crypt; | ||
151 | |||
152 | iface = netdev_priv(dev); | ||
153 | local = iface->local; | ||
154 | |||
155 | i = erq->flags & IW_ENCODE_INDEX; | ||
156 | if (i < 1 || i > 4) | ||
157 | i = local->tx_keyidx; | ||
158 | else | ||
159 | i--; | ||
160 | if (i < 0 || i >= WEP_KEYS) | ||
161 | return -EINVAL; | ||
162 | |||
163 | crypt = &local->crypt[i]; | ||
164 | |||
165 | if (erq->flags & IW_ENCODE_DISABLED) { | ||
166 | if (*crypt) | ||
167 | prism2_crypt_delayed_deinit(local, crypt); | ||
168 | goto done; | ||
169 | } | ||
170 | |||
171 | if (*crypt != NULL && (*crypt)->ops != NULL && | ||
172 | strcmp((*crypt)->ops->name, "WEP") != 0) { | ||
173 | /* changing to use WEP; deinit previously used algorithm */ | ||
174 | prism2_crypt_delayed_deinit(local, crypt); | ||
175 | } | ||
176 | |||
177 | if (*crypt == NULL) { | ||
178 | struct ieee80211_crypt_data *new_crypt; | ||
179 | |||
180 | /* take WEP into use */ | ||
181 | new_crypt = (struct ieee80211_crypt_data *) | ||
182 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
183 | GFP_KERNEL); | ||
184 | if (new_crypt == NULL) | ||
185 | return -ENOMEM; | ||
186 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
187 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
188 | if (!new_crypt->ops) { | ||
189 | request_module("ieee80211_crypt_wep"); | ||
190 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
191 | } | ||
192 | if (new_crypt->ops) | ||
193 | new_crypt->priv = new_crypt->ops->init(i); | ||
194 | if (!new_crypt->ops || !new_crypt->priv) { | ||
195 | kfree(new_crypt); | ||
196 | new_crypt = NULL; | ||
197 | |||
198 | printk(KERN_WARNING "%s: could not initialize WEP: " | ||
199 | "load module hostap_crypt_wep.o\n", | ||
200 | dev->name); | ||
201 | return -EOPNOTSUPP; | ||
202 | } | ||
203 | *crypt = new_crypt; | ||
204 | } | ||
205 | |||
206 | if (erq->length > 0) { | ||
207 | int len = erq->length <= 5 ? 5 : 13; | ||
208 | int first = 1, j; | ||
209 | if (len > erq->length) | ||
210 | memset(keybuf + erq->length, 0, len - erq->length); | ||
211 | (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); | ||
212 | for (j = 0; j < WEP_KEYS; j++) { | ||
213 | if (j != i && local->crypt[j]) { | ||
214 | first = 0; | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | if (first) | ||
219 | local->tx_keyidx = i; | ||
220 | } else { | ||
221 | /* No key data - just set the default TX key index */ | ||
222 | local->tx_keyidx = i; | ||
223 | } | ||
224 | |||
225 | done: | ||
226 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
227 | |||
228 | if (hostap_set_encryption(local)) { | ||
229 | printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | |||
233 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
234 | * generate new IEEE 802.11 authentication which may end up in looping | ||
235 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
236 | * after WEP configuration. However, keys are apparently changed at | ||
237 | * least in Managed mode. */ | ||
238 | if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { | ||
239 | printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | |||
247 | static int prism2_ioctl_giwencode(struct net_device *dev, | ||
248 | struct iw_request_info *info, | ||
249 | struct iw_point *erq, char *key) | ||
250 | { | ||
251 | struct hostap_interface *iface; | ||
252 | local_info_t *local; | ||
253 | int i, len; | ||
254 | u16 val; | ||
255 | struct ieee80211_crypt_data *crypt; | ||
256 | |||
257 | iface = netdev_priv(dev); | ||
258 | local = iface->local; | ||
259 | |||
260 | i = erq->flags & IW_ENCODE_INDEX; | ||
261 | if (i < 1 || i > 4) | ||
262 | i = local->tx_keyidx; | ||
263 | else | ||
264 | i--; | ||
265 | if (i < 0 || i >= WEP_KEYS) | ||
266 | return -EINVAL; | ||
267 | |||
268 | crypt = local->crypt[i]; | ||
269 | erq->flags = i + 1; | ||
270 | |||
271 | if (crypt == NULL || crypt->ops == NULL) { | ||
272 | erq->length = 0; | ||
273 | erq->flags |= IW_ENCODE_DISABLED; | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | if (strcmp(crypt->ops->name, "WEP") != 0) { | ||
278 | /* only WEP is supported with wireless extensions, so just | ||
279 | * report that encryption is used */ | ||
280 | erq->length = 0; | ||
281 | erq->flags |= IW_ENCODE_ENABLED; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show | ||
286 | * the keys from driver buffer */ | ||
287 | len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv); | ||
288 | erq->length = (len >= 0 ? len : 0); | ||
289 | |||
290 | if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0) | ||
291 | { | ||
292 | printk("CNFWEPFLAGS reading failed\n"); | ||
293 | return -EOPNOTSUPP; | ||
294 | } | ||
295 | le16_to_cpus(&val); | ||
296 | if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED) | ||
297 | erq->flags |= IW_ENCODE_ENABLED; | ||
298 | else | ||
299 | erq->flags |= IW_ENCODE_DISABLED; | ||
300 | if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED) | ||
301 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
302 | else | ||
303 | erq->flags |= IW_ENCODE_OPEN; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | |||
309 | static int hostap_set_rate(struct net_device *dev) | ||
310 | { | ||
311 | struct hostap_interface *iface; | ||
312 | local_info_t *local; | ||
313 | int ret, basic_rates; | ||
314 | |||
315 | iface = netdev_priv(dev); | ||
316 | local = iface->local; | ||
317 | |||
318 | basic_rates = local->basic_rates & local->tx_rate_control; | ||
319 | if (!basic_rates || basic_rates != local->basic_rates) { | ||
320 | printk(KERN_INFO "%s: updating basic rate set automatically " | ||
321 | "to match with the new supported rate set\n", | ||
322 | dev->name); | ||
323 | if (!basic_rates) | ||
324 | basic_rates = local->tx_rate_control; | ||
325 | |||
326 | local->basic_rates = basic_rates; | ||
327 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
328 | basic_rates)) | ||
329 | printk(KERN_WARNING "%s: failed to set " | ||
330 | "cnfBasicRates\n", dev->name); | ||
331 | } | ||
332 | |||
333 | ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | ||
334 | local->tx_rate_control) || | ||
335 | hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | ||
336 | local->tx_rate_control) || | ||
337 | local->func->reset_port(dev)); | ||
338 | |||
339 | if (ret) { | ||
340 | printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates " | ||
341 | "setting to 0x%x failed\n", | ||
342 | dev->name, local->tx_rate_control); | ||
343 | } | ||
344 | |||
345 | /* Update TX rate configuration for all STAs based on new operational | ||
346 | * rate set. */ | ||
347 | hostap_update_rates(local); | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | |||
353 | static int prism2_ioctl_siwrate(struct net_device *dev, | ||
354 | struct iw_request_info *info, | ||
355 | struct iw_param *rrq, char *extra) | ||
356 | { | ||
357 | struct hostap_interface *iface; | ||
358 | local_info_t *local; | ||
359 | |||
360 | iface = netdev_priv(dev); | ||
361 | local = iface->local; | ||
362 | |||
363 | if (rrq->fixed) { | ||
364 | switch (rrq->value) { | ||
365 | case 11000000: | ||
366 | local->tx_rate_control = HFA384X_RATES_11MBPS; | ||
367 | break; | ||
368 | case 5500000: | ||
369 | local->tx_rate_control = HFA384X_RATES_5MBPS; | ||
370 | break; | ||
371 | case 2000000: | ||
372 | local->tx_rate_control = HFA384X_RATES_2MBPS; | ||
373 | break; | ||
374 | case 1000000: | ||
375 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
376 | break; | ||
377 | default: | ||
378 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
379 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
380 | HFA384X_RATES_11MBPS; | ||
381 | break; | ||
382 | } | ||
383 | } else { | ||
384 | switch (rrq->value) { | ||
385 | case 11000000: | ||
386 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
387 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
388 | HFA384X_RATES_11MBPS; | ||
389 | break; | ||
390 | case 5500000: | ||
391 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
392 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS; | ||
393 | break; | ||
394 | case 2000000: | ||
395 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
396 | HFA384X_RATES_2MBPS; | ||
397 | break; | ||
398 | case 1000000: | ||
399 | local->tx_rate_control = HFA384X_RATES_1MBPS; | ||
400 | break; | ||
401 | default: | ||
402 | local->tx_rate_control = HFA384X_RATES_1MBPS | | ||
403 | HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS | | ||
404 | HFA384X_RATES_11MBPS; | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return hostap_set_rate(dev); | ||
410 | } | ||
411 | |||
412 | |||
413 | static int prism2_ioctl_giwrate(struct net_device *dev, | ||
414 | struct iw_request_info *info, | ||
415 | struct iw_param *rrq, char *extra) | ||
416 | { | ||
417 | u16 val; | ||
418 | struct hostap_interface *iface; | ||
419 | local_info_t *local; | ||
420 | int ret = 0; | ||
421 | |||
422 | iface = netdev_priv(dev); | ||
423 | local = iface->local; | ||
424 | |||
425 | if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) < | ||
426 | 0) | ||
427 | return -EINVAL; | ||
428 | |||
429 | if ((val & 0x1) && (val > 1)) | ||
430 | rrq->fixed = 0; | ||
431 | else | ||
432 | rrq->fixed = 1; | ||
433 | |||
434 | if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL && | ||
435 | !local->fw_tx_rate_control) { | ||
436 | /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in | ||
437 | * Host AP mode, so use the recorded TX rate of the last sent | ||
438 | * frame */ | ||
439 | rrq->value = local->ap->last_tx_rate > 0 ? | ||
440 | local->ap->last_tx_rate * 100000 : 11000000; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) < | ||
445 | 0) | ||
446 | return -EINVAL; | ||
447 | |||
448 | switch (val) { | ||
449 | case HFA384X_RATES_1MBPS: | ||
450 | rrq->value = 1000000; | ||
451 | break; | ||
452 | case HFA384X_RATES_2MBPS: | ||
453 | rrq->value = 2000000; | ||
454 | break; | ||
455 | case HFA384X_RATES_5MBPS: | ||
456 | rrq->value = 5500000; | ||
457 | break; | ||
458 | case HFA384X_RATES_11MBPS: | ||
459 | rrq->value = 11000000; | ||
460 | break; | ||
461 | default: | ||
462 | /* should not happen */ | ||
463 | rrq->value = 11000000; | ||
464 | ret = -EINVAL; | ||
465 | break; | ||
466 | } | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | |||
472 | static int prism2_ioctl_siwsens(struct net_device *dev, | ||
473 | struct iw_request_info *info, | ||
474 | struct iw_param *sens, char *extra) | ||
475 | { | ||
476 | struct hostap_interface *iface; | ||
477 | local_info_t *local; | ||
478 | |||
479 | iface = netdev_priv(dev); | ||
480 | local = iface->local; | ||
481 | |||
482 | /* Set the desired AP density */ | ||
483 | if (sens->value < 1 || sens->value > 3) | ||
484 | return -EINVAL; | ||
485 | |||
486 | if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) || | ||
487 | local->func->reset_port(dev)) | ||
488 | return -EINVAL; | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static int prism2_ioctl_giwsens(struct net_device *dev, | ||
494 | struct iw_request_info *info, | ||
495 | struct iw_param *sens, char *extra) | ||
496 | { | ||
497 | struct hostap_interface *iface; | ||
498 | local_info_t *local; | ||
499 | u16 val; | ||
500 | |||
501 | iface = netdev_priv(dev); | ||
502 | local = iface->local; | ||
503 | |||
504 | /* Get the current AP density */ | ||
505 | if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) < | ||
506 | 0) | ||
507 | return -EINVAL; | ||
508 | |||
509 | sens->value = __le16_to_cpu(val); | ||
510 | sens->fixed = 1; | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | |||
516 | /* Deprecated in new wireless extension API */ | ||
517 | static int prism2_ioctl_giwaplist(struct net_device *dev, | ||
518 | struct iw_request_info *info, | ||
519 | struct iw_point *data, char *extra) | ||
520 | { | ||
521 | struct hostap_interface *iface; | ||
522 | local_info_t *local; | ||
523 | struct sockaddr *addr; | ||
524 | struct iw_quality *qual; | ||
525 | |||
526 | iface = netdev_priv(dev); | ||
527 | local = iface->local; | ||
528 | |||
529 | if (local->iw_mode != IW_MODE_MASTER) { | ||
530 | printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported " | ||
531 | "in Host AP mode\n"); | ||
532 | data->length = 0; | ||
533 | return -EOPNOTSUPP; | ||
534 | } | ||
535 | |||
536 | addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL); | ||
537 | qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL); | ||
538 | if (addr == NULL || qual == NULL) { | ||
539 | kfree(addr); | ||
540 | kfree(qual); | ||
541 | data->length = 0; | ||
542 | return -ENOMEM; | ||
543 | } | ||
544 | |||
545 | data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); | ||
546 | |||
547 | memcpy(extra, &addr, sizeof(struct sockaddr) * data->length); | ||
548 | data->flags = 1; /* has quality information */ | ||
549 | memcpy(extra + sizeof(struct sockaddr) * data->length, &qual, | ||
550 | sizeof(struct iw_quality) * data->length); | ||
551 | |||
552 | kfree(addr); | ||
553 | kfree(qual); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | |||
559 | static int prism2_ioctl_siwrts(struct net_device *dev, | ||
560 | struct iw_request_info *info, | ||
561 | struct iw_param *rts, char *extra) | ||
562 | { | ||
563 | struct hostap_interface *iface; | ||
564 | local_info_t *local; | ||
565 | u16 val; | ||
566 | |||
567 | iface = netdev_priv(dev); | ||
568 | local = iface->local; | ||
569 | |||
570 | if (rts->disabled) | ||
571 | val = __constant_cpu_to_le16(2347); | ||
572 | else if (rts->value < 0 || rts->value > 2347) | ||
573 | return -EINVAL; | ||
574 | else | ||
575 | val = __cpu_to_le16(rts->value); | ||
576 | |||
577 | if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || | ||
578 | local->func->reset_port(dev)) | ||
579 | return -EINVAL; | ||
580 | |||
581 | local->rts_threshold = rts->value; | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int prism2_ioctl_giwrts(struct net_device *dev, | ||
587 | struct iw_request_info *info, | ||
588 | struct iw_param *rts, char *extra) | ||
589 | { | ||
590 | struct hostap_interface *iface; | ||
591 | local_info_t *local; | ||
592 | u16 val; | ||
593 | |||
594 | iface = netdev_priv(dev); | ||
595 | local = iface->local; | ||
596 | |||
597 | if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) < | ||
598 | 0) | ||
599 | return -EINVAL; | ||
600 | |||
601 | rts->value = __le16_to_cpu(val); | ||
602 | rts->disabled = (rts->value == 2347); | ||
603 | rts->fixed = 1; | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | |||
609 | static int prism2_ioctl_siwfrag(struct net_device *dev, | ||
610 | struct iw_request_info *info, | ||
611 | struct iw_param *rts, char *extra) | ||
612 | { | ||
613 | struct hostap_interface *iface; | ||
614 | local_info_t *local; | ||
615 | u16 val; | ||
616 | |||
617 | iface = netdev_priv(dev); | ||
618 | local = iface->local; | ||
619 | |||
620 | if (rts->disabled) | ||
621 | val = __constant_cpu_to_le16(2346); | ||
622 | else if (rts->value < 256 || rts->value > 2346) | ||
623 | return -EINVAL; | ||
624 | else | ||
625 | val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ | ||
626 | |||
627 | local->fragm_threshold = rts->value & ~0x1; | ||
628 | if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, | ||
629 | 2) | ||
630 | || local->func->reset_port(dev)) | ||
631 | return -EINVAL; | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static int prism2_ioctl_giwfrag(struct net_device *dev, | ||
637 | struct iw_request_info *info, | ||
638 | struct iw_param *rts, char *extra) | ||
639 | { | ||
640 | struct hostap_interface *iface; | ||
641 | local_info_t *local; | ||
642 | u16 val; | ||
643 | |||
644 | iface = netdev_priv(dev); | ||
645 | local = iface->local; | ||
646 | |||
647 | if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | ||
648 | &val, 2, 1) < 0) | ||
649 | return -EINVAL; | ||
650 | |||
651 | rts->value = __le16_to_cpu(val); | ||
652 | rts->disabled = (rts->value == 2346); | ||
653 | rts->fixed = 1; | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | |||
659 | #ifndef PRISM2_NO_STATION_MODES | ||
660 | static int hostap_join_ap(struct net_device *dev) | ||
661 | { | ||
662 | struct hostap_interface *iface; | ||
663 | local_info_t *local; | ||
664 | struct hfa384x_join_request req; | ||
665 | unsigned long flags; | ||
666 | int i; | ||
667 | struct hfa384x_hostscan_result *entry; | ||
668 | |||
669 | iface = netdev_priv(dev); | ||
670 | local = iface->local; | ||
671 | |||
672 | memcpy(req.bssid, local->preferred_ap, ETH_ALEN); | ||
673 | req.channel = 0; | ||
674 | |||
675 | spin_lock_irqsave(&local->lock, flags); | ||
676 | for (i = 0; i < local->last_scan_results_count; i++) { | ||
677 | if (!local->last_scan_results) | ||
678 | break; | ||
679 | entry = &local->last_scan_results[i]; | ||
680 | if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) { | ||
681 | req.channel = entry->chid; | ||
682 | break; | ||
683 | } | ||
684 | } | ||
685 | spin_unlock_irqrestore(&local->lock, flags); | ||
686 | |||
687 | if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, | ||
688 | sizeof(req))) { | ||
689 | printk(KERN_DEBUG "%s: JoinRequest " MACSTR | ||
690 | " failed\n", | ||
691 | dev->name, MAC2STR(local->preferred_ap)); | ||
692 | return -1; | ||
693 | } | ||
694 | |||
695 | printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", | ||
696 | dev->name, MAC2STR(local->preferred_ap)); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | #endif /* PRISM2_NO_STATION_MODES */ | ||
701 | |||
702 | |||
703 | static int prism2_ioctl_siwap(struct net_device *dev, | ||
704 | struct iw_request_info *info, | ||
705 | struct sockaddr *ap_addr, char *extra) | ||
706 | { | ||
707 | #ifdef PRISM2_NO_STATION_MODES | ||
708 | return -EOPNOTSUPP; | ||
709 | #else /* PRISM2_NO_STATION_MODES */ | ||
710 | struct hostap_interface *iface; | ||
711 | local_info_t *local; | ||
712 | |||
713 | iface = netdev_priv(dev); | ||
714 | local = iface->local; | ||
715 | |||
716 | memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN); | ||
717 | |||
718 | if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { | ||
719 | struct hfa384x_scan_request scan_req; | ||
720 | memset(&scan_req, 0, sizeof(scan_req)); | ||
721 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
722 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
723 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, | ||
724 | &scan_req, sizeof(scan_req))) { | ||
725 | printk(KERN_DEBUG "%s: ScanResults request failed - " | ||
726 | "preferred AP delayed to next unsolicited " | ||
727 | "scan\n", dev->name); | ||
728 | } | ||
729 | } else if (local->host_roaming == 2 && | ||
730 | local->iw_mode == IW_MODE_INFRA) { | ||
731 | if (hostap_join_ap(dev)) | ||
732 | return -EINVAL; | ||
733 | } else { | ||
734 | printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only " | ||
735 | "in Managed mode when host_roaming is enabled\n", | ||
736 | dev->name); | ||
737 | } | ||
738 | |||
739 | return 0; | ||
740 | #endif /* PRISM2_NO_STATION_MODES */ | ||
741 | } | ||
742 | |||
743 | static int prism2_ioctl_giwap(struct net_device *dev, | ||
744 | struct iw_request_info *info, | ||
745 | struct sockaddr *ap_addr, char *extra) | ||
746 | { | ||
747 | struct hostap_interface *iface; | ||
748 | local_info_t *local; | ||
749 | |||
750 | iface = netdev_priv(dev); | ||
751 | local = iface->local; | ||
752 | |||
753 | ap_addr->sa_family = ARPHRD_ETHER; | ||
754 | switch (iface->type) { | ||
755 | case HOSTAP_INTERFACE_AP: | ||
756 | memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN); | ||
757 | break; | ||
758 | case HOSTAP_INTERFACE_STA: | ||
759 | memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); | ||
760 | break; | ||
761 | case HOSTAP_INTERFACE_WDS: | ||
762 | memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN); | ||
763 | break; | ||
764 | default: | ||
765 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, | ||
766 | &ap_addr->sa_data, ETH_ALEN, 1) < 0) | ||
767 | return -EOPNOTSUPP; | ||
768 | |||
769 | /* local->bssid is also updated in LinkStatus handler when in | ||
770 | * station mode */ | ||
771 | memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN); | ||
772 | break; | ||
773 | } | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | |||
779 | static int prism2_ioctl_siwnickn(struct net_device *dev, | ||
780 | struct iw_request_info *info, | ||
781 | struct iw_point *data, char *nickname) | ||
782 | { | ||
783 | struct hostap_interface *iface; | ||
784 | local_info_t *local; | ||
785 | |||
786 | iface = netdev_priv(dev); | ||
787 | local = iface->local; | ||
788 | |||
789 | memset(local->name, 0, sizeof(local->name)); | ||
790 | memcpy(local->name, nickname, data->length); | ||
791 | local->name_set = 1; | ||
792 | |||
793 | if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) || | ||
794 | local->func->reset_port(dev)) | ||
795 | return -EINVAL; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int prism2_ioctl_giwnickn(struct net_device *dev, | ||
801 | struct iw_request_info *info, | ||
802 | struct iw_point *data, char *nickname) | ||
803 | { | ||
804 | struct hostap_interface *iface; | ||
805 | local_info_t *local; | ||
806 | int len; | ||
807 | char name[MAX_NAME_LEN + 3]; | ||
808 | u16 val; | ||
809 | |||
810 | iface = netdev_priv(dev); | ||
811 | local = iface->local; | ||
812 | |||
813 | len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, | ||
814 | &name, MAX_NAME_LEN + 2, 0); | ||
815 | val = __le16_to_cpu(*(u16 *) name); | ||
816 | if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) | ||
817 | return -EOPNOTSUPP; | ||
818 | |||
819 | name[val + 2] = '\0'; | ||
820 | data->length = val + 1; | ||
821 | memcpy(nickname, name + 2, val + 1); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | |||
827 | static int prism2_ioctl_siwfreq(struct net_device *dev, | ||
828 | struct iw_request_info *info, | ||
829 | struct iw_freq *freq, char *extra) | ||
830 | { | ||
831 | struct hostap_interface *iface; | ||
832 | local_info_t *local; | ||
833 | |||
834 | iface = netdev_priv(dev); | ||
835 | local = iface->local; | ||
836 | |||
837 | /* freq => chan. */ | ||
838 | if (freq->e == 1 && | ||
839 | freq->m / 100000 >= freq_list[0] && | ||
840 | freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) { | ||
841 | int ch; | ||
842 | int fr = freq->m / 100000; | ||
843 | for (ch = 0; ch < FREQ_COUNT; ch++) { | ||
844 | if (fr == freq_list[ch]) { | ||
845 | freq->e = 0; | ||
846 | freq->m = ch + 1; | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | |||
852 | if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT || | ||
853 | !(local->channel_mask & (1 << (freq->m - 1)))) | ||
854 | return -EINVAL; | ||
855 | |||
856 | local->channel = freq->m; /* channel is used in prism2_setup_rids() */ | ||
857 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) || | ||
858 | local->func->reset_port(dev)) | ||
859 | return -EINVAL; | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int prism2_ioctl_giwfreq(struct net_device *dev, | ||
865 | struct iw_request_info *info, | ||
866 | struct iw_freq *freq, char *extra) | ||
867 | { | ||
868 | struct hostap_interface *iface; | ||
869 | local_info_t *local; | ||
870 | u16 val; | ||
871 | |||
872 | iface = netdev_priv(dev); | ||
873 | local = iface->local; | ||
874 | |||
875 | if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) < | ||
876 | 0) | ||
877 | return -EINVAL; | ||
878 | |||
879 | le16_to_cpus(&val); | ||
880 | if (val < 1 || val > FREQ_COUNT) | ||
881 | return -EINVAL; | ||
882 | |||
883 | freq->m = freq_list[val - 1] * 100000; | ||
884 | freq->e = 1; | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | |||
890 | static void hostap_monitor_set_type(local_info_t *local) | ||
891 | { | ||
892 | struct net_device *dev = local->ddev; | ||
893 | |||
894 | if (dev == NULL) | ||
895 | return; | ||
896 | |||
897 | if (local->monitor_type == PRISM2_MONITOR_PRISM || | ||
898 | local->monitor_type == PRISM2_MONITOR_CAPHDR) { | ||
899 | dev->type = ARPHRD_IEEE80211_PRISM; | ||
900 | dev->hard_header_parse = | ||
901 | hostap_80211_prism_header_parse; | ||
902 | } else { | ||
903 | dev->type = ARPHRD_IEEE80211; | ||
904 | dev->hard_header_parse = hostap_80211_header_parse; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | |||
909 | static int prism2_ioctl_siwessid(struct net_device *dev, | ||
910 | struct iw_request_info *info, | ||
911 | struct iw_point *data, char *ssid) | ||
912 | { | ||
913 | struct hostap_interface *iface; | ||
914 | local_info_t *local; | ||
915 | |||
916 | iface = netdev_priv(dev); | ||
917 | local = iface->local; | ||
918 | |||
919 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
920 | return -EOPNOTSUPP; | ||
921 | |||
922 | if (data->flags == 0) | ||
923 | ssid[0] = '\0'; /* ANY */ | ||
924 | |||
925 | if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') { | ||
926 | /* Setting SSID to empty string seems to kill the card in | ||
927 | * Host AP mode */ | ||
928 | printk(KERN_DEBUG "%s: Host AP mode does not support " | ||
929 | "'Any' essid\n", dev->name); | ||
930 | return -EINVAL; | ||
931 | } | ||
932 | |||
933 | memcpy(local->essid, ssid, data->length); | ||
934 | local->essid[data->length] = '\0'; | ||
935 | |||
936 | if ((!local->fw_ap && | ||
937 | hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid)) | ||
938 | || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) || | ||
939 | local->func->reset_port(dev)) | ||
940 | return -EINVAL; | ||
941 | |||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int prism2_ioctl_giwessid(struct net_device *dev, | ||
946 | struct iw_request_info *info, | ||
947 | struct iw_point *data, char *essid) | ||
948 | { | ||
949 | struct hostap_interface *iface; | ||
950 | local_info_t *local; | ||
951 | u16 val; | ||
952 | |||
953 | iface = netdev_priv(dev); | ||
954 | local = iface->local; | ||
955 | |||
956 | if (iface->type == HOSTAP_INTERFACE_WDS) | ||
957 | return -EOPNOTSUPP; | ||
958 | |||
959 | data->flags = 1; /* active */ | ||
960 | if (local->iw_mode == IW_MODE_MASTER) { | ||
961 | data->length = strlen(local->essid); | ||
962 | memcpy(essid, local->essid, IW_ESSID_MAX_SIZE); | ||
963 | } else { | ||
964 | int len; | ||
965 | char ssid[MAX_SSID_LEN + 2]; | ||
966 | memset(ssid, 0, sizeof(ssid)); | ||
967 | len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, | ||
968 | &ssid, MAX_SSID_LEN + 2, 0); | ||
969 | val = __le16_to_cpu(*(u16 *) ssid); | ||
970 | if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { | ||
971 | return -EOPNOTSUPP; | ||
972 | } | ||
973 | data->length = val; | ||
974 | memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE); | ||
975 | } | ||
976 | |||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | |||
981 | static int prism2_ioctl_giwrange(struct net_device *dev, | ||
982 | struct iw_request_info *info, | ||
983 | struct iw_point *data, char *extra) | ||
984 | { | ||
985 | struct hostap_interface *iface; | ||
986 | local_info_t *local; | ||
987 | struct iw_range *range = (struct iw_range *) extra; | ||
988 | u8 rates[10]; | ||
989 | u16 val; | ||
990 | int i, len, over2; | ||
991 | |||
992 | iface = netdev_priv(dev); | ||
993 | local = iface->local; | ||
994 | |||
995 | data->length = sizeof(struct iw_range); | ||
996 | memset(range, 0, sizeof(struct iw_range)); | ||
997 | |||
998 | /* TODO: could fill num_txpower and txpower array with | ||
999 | * something; however, there are 128 different values.. */ | ||
1000 | |||
1001 | range->txpower_capa = IW_TXPOW_DBM; | ||
1002 | |||
1003 | if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC) | ||
1004 | { | ||
1005 | range->min_pmp = 1 * 1024; | ||
1006 | range->max_pmp = 65535 * 1024; | ||
1007 | range->min_pmt = 1 * 1024; | ||
1008 | range->max_pmt = 1000 * 1024; | ||
1009 | range->pmp_flags = IW_POWER_PERIOD; | ||
1010 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
1011 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | | ||
1012 | IW_POWER_UNICAST_R | IW_POWER_ALL_R; | ||
1013 | } | ||
1014 | |||
1015 | range->we_version_compiled = WIRELESS_EXT; | ||
1016 | range->we_version_source = 18; | ||
1017 | |||
1018 | range->retry_capa = IW_RETRY_LIMIT; | ||
1019 | range->retry_flags = IW_RETRY_LIMIT; | ||
1020 | range->min_retry = 0; | ||
1021 | range->max_retry = 255; | ||
1022 | |||
1023 | range->num_channels = FREQ_COUNT; | ||
1024 | |||
1025 | val = 0; | ||
1026 | for (i = 0; i < FREQ_COUNT; i++) { | ||
1027 | if (local->channel_mask & (1 << i)) { | ||
1028 | range->freq[val].i = i + 1; | ||
1029 | range->freq[val].m = freq_list[i] * 100000; | ||
1030 | range->freq[val].e = 1; | ||
1031 | val++; | ||
1032 | } | ||
1033 | if (val == IW_MAX_FREQUENCIES) | ||
1034 | break; | ||
1035 | } | ||
1036 | range->num_frequency = val; | ||
1037 | |||
1038 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) { | ||
1039 | range->max_qual.qual = 70; /* what is correct max? This was not | ||
1040 | * documented exactly. At least | ||
1041 | * 69 has been observed. */ | ||
1042 | range->max_qual.level = 0; /* dB */ | ||
1043 | range->max_qual.noise = 0; /* dB */ | ||
1044 | |||
1045 | /* What would be suitable values for "average/typical" qual? */ | ||
1046 | range->avg_qual.qual = 20; | ||
1047 | range->avg_qual.level = -60; | ||
1048 | range->avg_qual.noise = -95; | ||
1049 | } else { | ||
1050 | range->max_qual.qual = 92; /* 0 .. 92 */ | ||
1051 | range->max_qual.level = 154; /* 27 .. 154 */ | ||
1052 | range->max_qual.noise = 154; /* 27 .. 154 */ | ||
1053 | } | ||
1054 | range->sensitivity = 3; | ||
1055 | |||
1056 | range->max_encoding_tokens = WEP_KEYS; | ||
1057 | range->num_encoding_sizes = 2; | ||
1058 | range->encoding_size[0] = 5; | ||
1059 | range->encoding_size[1] = 13; | ||
1060 | |||
1061 | over2 = 0; | ||
1062 | len = prism2_get_datarates(dev, rates); | ||
1063 | range->num_bitrates = 0; | ||
1064 | for (i = 0; i < len; i++) { | ||
1065 | if (range->num_bitrates < IW_MAX_BITRATES) { | ||
1066 | range->bitrate[range->num_bitrates] = | ||
1067 | rates[i] * 500000; | ||
1068 | range->num_bitrates++; | ||
1069 | } | ||
1070 | if (rates[i] == 0x0b || rates[i] == 0x16) | ||
1071 | over2 = 1; | ||
1072 | } | ||
1073 | /* estimated maximum TCP throughput values (bps) */ | ||
1074 | range->throughput = over2 ? 5500000 : 1500000; | ||
1075 | |||
1076 | range->min_rts = 0; | ||
1077 | range->max_rts = 2347; | ||
1078 | range->min_frag = 256; | ||
1079 | range->max_frag = 2346; | ||
1080 | |||
1081 | /* Event capability (kernel + driver) */ | ||
1082 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
1083 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | ||
1084 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
1085 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
1086 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
1087 | range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | | ||
1088 | IW_EVENT_CAPA_MASK(IWEVCUSTOM) | | ||
1089 | IW_EVENT_CAPA_MASK(IWEVREGISTERED) | | ||
1090 | IW_EVENT_CAPA_MASK(IWEVEXPIRED)); | ||
1091 | |||
1092 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
1093 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | static int hostap_monitor_mode_enable(local_info_t *local) | ||
1100 | { | ||
1101 | struct net_device *dev = local->dev; | ||
1102 | |||
1103 | printk(KERN_DEBUG "Enabling monitor mode\n"); | ||
1104 | hostap_monitor_set_type(local); | ||
1105 | |||
1106 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1107 | HFA384X_PORTTYPE_PSEUDO_IBSS)) { | ||
1108 | printk(KERN_DEBUG "Port type setting for monitor mode " | ||
1109 | "failed\n"); | ||
1110 | return -EOPNOTSUPP; | ||
1111 | } | ||
1112 | |||
1113 | /* Host decrypt is needed to get the IV and ICV fields; | ||
1114 | * however, monitor mode seems to remove WEP flag from frame | ||
1115 | * control field */ | ||
1116 | if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS, | ||
1117 | HFA384X_WEPFLAGS_HOSTENCRYPT | | ||
1118 | HFA384X_WEPFLAGS_HOSTDECRYPT)) { | ||
1119 | printk(KERN_DEBUG "WEP flags setting failed\n"); | ||
1120 | return -EOPNOTSUPP; | ||
1121 | } | ||
1122 | |||
1123 | if (local->func->reset_port(dev) || | ||
1124 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1125 | (HFA384X_TEST_MONITOR << 8), | ||
1126 | 0, NULL, NULL)) { | ||
1127 | printk(KERN_DEBUG "Setting monitor mode failed\n"); | ||
1128 | return -EOPNOTSUPP; | ||
1129 | } | ||
1130 | |||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | static int hostap_monitor_mode_disable(local_info_t *local) | ||
1136 | { | ||
1137 | struct net_device *dev = local->ddev; | ||
1138 | |||
1139 | if (dev == NULL) | ||
1140 | return -1; | ||
1141 | |||
1142 | printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); | ||
1143 | dev->type = ARPHRD_ETHER; | ||
1144 | dev->hard_header_parse = local->saved_eth_header_parse; | ||
1145 | if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1146 | (HFA384X_TEST_STOP << 8), | ||
1147 | 0, NULL, NULL)) | ||
1148 | return -1; | ||
1149 | return hostap_set_encryption(local); | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static int prism2_ioctl_siwmode(struct net_device *dev, | ||
1154 | struct iw_request_info *info, | ||
1155 | __u32 *mode, char *extra) | ||
1156 | { | ||
1157 | struct hostap_interface *iface; | ||
1158 | local_info_t *local; | ||
1159 | int double_reset = 0; | ||
1160 | |||
1161 | iface = netdev_priv(dev); | ||
1162 | local = iface->local; | ||
1163 | |||
1164 | if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && | ||
1165 | *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT && | ||
1166 | *mode != IW_MODE_MONITOR) | ||
1167 | return -EOPNOTSUPP; | ||
1168 | |||
1169 | #ifdef PRISM2_NO_STATION_MODES | ||
1170 | if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA) | ||
1171 | return -EOPNOTSUPP; | ||
1172 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1173 | |||
1174 | if (*mode == local->iw_mode) | ||
1175 | return 0; | ||
1176 | |||
1177 | if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') { | ||
1178 | printk(KERN_WARNING "%s: empty SSID not allowed in Master " | ||
1179 | "mode\n", dev->name); | ||
1180 | return -EINVAL; | ||
1181 | } | ||
1182 | |||
1183 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1184 | hostap_monitor_mode_disable(local); | ||
1185 | |||
1186 | if ((local->iw_mode == IW_MODE_ADHOC || | ||
1187 | local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) { | ||
1188 | /* There seems to be a firmware bug in at least STA f/w v1.5.6 | ||
1189 | * that leaves beacon frames to use IBSS type when moving from | ||
1190 | * IBSS to Host AP mode. Doing double Port0 reset seems to be | ||
1191 | * enough to workaround this. */ | ||
1192 | double_reset = 1; | ||
1193 | } | ||
1194 | |||
1195 | printk(KERN_DEBUG "prism2: %s: operating mode changed " | ||
1196 | "%d -> %d\n", dev->name, local->iw_mode, *mode); | ||
1197 | local->iw_mode = *mode; | ||
1198 | |||
1199 | if (local->iw_mode == IW_MODE_MONITOR) | ||
1200 | hostap_monitor_mode_enable(local); | ||
1201 | else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt && | ||
1202 | !local->fw_encrypt_ok) { | ||
1203 | printk(KERN_DEBUG "%s: defaulting to host-based encryption as " | ||
1204 | "a workaround for firmware bug in Host AP mode WEP\n", | ||
1205 | dev->name); | ||
1206 | local->host_encrypt = 1; | ||
1207 | } | ||
1208 | |||
1209 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
1210 | hostap_get_porttype(local))) | ||
1211 | return -EOPNOTSUPP; | ||
1212 | |||
1213 | if (local->func->reset_port(dev)) | ||
1214 | return -EINVAL; | ||
1215 | if (double_reset && local->func->reset_port(dev)) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) | ||
1219 | { | ||
1220 | /* netif_carrier is used only in client modes for now, so make | ||
1221 | * sure carrier is on when moving to non-client modes. */ | ||
1222 | netif_carrier_on(local->dev); | ||
1223 | netif_carrier_on(local->ddev); | ||
1224 | } | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | |||
1229 | static int prism2_ioctl_giwmode(struct net_device *dev, | ||
1230 | struct iw_request_info *info, | ||
1231 | __u32 *mode, char *extra) | ||
1232 | { | ||
1233 | struct hostap_interface *iface; | ||
1234 | local_info_t *local; | ||
1235 | |||
1236 | iface = netdev_priv(dev); | ||
1237 | local = iface->local; | ||
1238 | |||
1239 | switch (iface->type) { | ||
1240 | case HOSTAP_INTERFACE_STA: | ||
1241 | *mode = IW_MODE_INFRA; | ||
1242 | break; | ||
1243 | case HOSTAP_INTERFACE_WDS: | ||
1244 | *mode = IW_MODE_REPEAT; | ||
1245 | break; | ||
1246 | default: | ||
1247 | *mode = local->iw_mode; | ||
1248 | break; | ||
1249 | } | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | static int prism2_ioctl_siwpower(struct net_device *dev, | ||
1255 | struct iw_request_info *info, | ||
1256 | struct iw_param *wrq, char *extra) | ||
1257 | { | ||
1258 | #ifdef PRISM2_NO_STATION_MODES | ||
1259 | return -EOPNOTSUPP; | ||
1260 | #else /* PRISM2_NO_STATION_MODES */ | ||
1261 | int ret = 0; | ||
1262 | |||
1263 | if (wrq->disabled) | ||
1264 | return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0); | ||
1265 | |||
1266 | switch (wrq->flags & IW_POWER_MODE) { | ||
1267 | case IW_POWER_UNICAST_R: | ||
1268 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0); | ||
1269 | if (ret) | ||
1270 | return ret; | ||
1271 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1272 | if (ret) | ||
1273 | return ret; | ||
1274 | break; | ||
1275 | case IW_POWER_ALL_R: | ||
1276 | ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1); | ||
1277 | if (ret) | ||
1278 | return ret; | ||
1279 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1280 | if (ret) | ||
1281 | return ret; | ||
1282 | break; | ||
1283 | case IW_POWER_ON: | ||
1284 | break; | ||
1285 | default: | ||
1286 | return -EINVAL; | ||
1287 | } | ||
1288 | |||
1289 | if (wrq->flags & IW_POWER_TIMEOUT) { | ||
1290 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1291 | if (ret) | ||
1292 | return ret; | ||
1293 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1294 | wrq->value / 1024); | ||
1295 | if (ret) | ||
1296 | return ret; | ||
1297 | } | ||
1298 | if (wrq->flags & IW_POWER_PERIOD) { | ||
1299 | ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1); | ||
1300 | if (ret) | ||
1301 | return ret; | ||
1302 | ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1303 | wrq->value / 1024); | ||
1304 | if (ret) | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | return ret; | ||
1309 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | static int prism2_ioctl_giwpower(struct net_device *dev, | ||
1314 | struct iw_request_info *info, | ||
1315 | struct iw_param *rrq, char *extra) | ||
1316 | { | ||
1317 | #ifdef PRISM2_NO_STATION_MODES | ||
1318 | return -EOPNOTSUPP; | ||
1319 | #else /* PRISM2_NO_STATION_MODES */ | ||
1320 | struct hostap_interface *iface; | ||
1321 | local_info_t *local; | ||
1322 | u16 enable, mcast; | ||
1323 | |||
1324 | iface = netdev_priv(dev); | ||
1325 | local = iface->local; | ||
1326 | |||
1327 | if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1) | ||
1328 | < 0) | ||
1329 | return -EINVAL; | ||
1330 | |||
1331 | if (!__le16_to_cpu(enable)) { | ||
1332 | rrq->disabled = 1; | ||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | rrq->disabled = 0; | ||
1337 | |||
1338 | if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
1339 | u16 timeout; | ||
1340 | if (local->func->get_rid(dev, | ||
1341 | HFA384X_RID_CNFPMHOLDOVERDURATION, | ||
1342 | &timeout, 2, 1) < 0) | ||
1343 | return -EINVAL; | ||
1344 | |||
1345 | rrq->flags = IW_POWER_TIMEOUT; | ||
1346 | rrq->value = __le16_to_cpu(timeout) * 1024; | ||
1347 | } else { | ||
1348 | u16 period; | ||
1349 | if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, | ||
1350 | &period, 2, 1) < 0) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | rrq->flags = IW_POWER_PERIOD; | ||
1354 | rrq->value = __le16_to_cpu(period) * 1024; | ||
1355 | } | ||
1356 | |||
1357 | if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, | ||
1358 | 2, 1) < 0) | ||
1359 | return -EINVAL; | ||
1360 | |||
1361 | if (__le16_to_cpu(mcast)) | ||
1362 | rrq->flags |= IW_POWER_ALL_R; | ||
1363 | else | ||
1364 | rrq->flags |= IW_POWER_UNICAST_R; | ||
1365 | |||
1366 | return 0; | ||
1367 | #endif /* PRISM2_NO_STATION_MODES */ | ||
1368 | } | ||
1369 | |||
1370 | |||
1371 | static int prism2_ioctl_siwretry(struct net_device *dev, | ||
1372 | struct iw_request_info *info, | ||
1373 | struct iw_param *rrq, char *extra) | ||
1374 | { | ||
1375 | struct hostap_interface *iface; | ||
1376 | local_info_t *local; | ||
1377 | |||
1378 | iface = netdev_priv(dev); | ||
1379 | local = iface->local; | ||
1380 | |||
1381 | if (rrq->disabled) | ||
1382 | return -EINVAL; | ||
1383 | |||
1384 | /* setting retry limits is not supported with the current station | ||
1385 | * firmware code; simulate this with alternative retry count for now */ | ||
1386 | if (rrq->flags == IW_RETRY_LIMIT) { | ||
1387 | if (rrq->value < 0) { | ||
1388 | /* disable manual retry count setting and use firmware | ||
1389 | * defaults */ | ||
1390 | local->manual_retry_count = -1; | ||
1391 | local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY; | ||
1392 | } else { | ||
1393 | if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | ||
1394 | rrq->value)) { | ||
1395 | printk(KERN_DEBUG "%s: Alternate retry count " | ||
1396 | "setting to %d failed\n", | ||
1397 | dev->name, rrq->value); | ||
1398 | return -EOPNOTSUPP; | ||
1399 | } | ||
1400 | |||
1401 | local->manual_retry_count = rrq->value; | ||
1402 | local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY; | ||
1403 | } | ||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | return -EOPNOTSUPP; | ||
1408 | |||
1409 | #if 0 | ||
1410 | /* what could be done, if firmware would support this.. */ | ||
1411 | |||
1412 | if (rrq->flags & IW_RETRY_LIMIT) { | ||
1413 | if (rrq->flags & IW_RETRY_MAX) | ||
1414 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1415 | else if (rrq->flags & IW_RETRY_MIN) | ||
1416 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1417 | else { | ||
1418 | HFA384X_RID_LONGRETRYLIMIT = rrq->value; | ||
1419 | HFA384X_RID_SHORTRETRYLIMIT = rrq->value; | ||
1420 | } | ||
1421 | |||
1422 | } | ||
1423 | |||
1424 | if (rrq->flags & IW_RETRY_LIFETIME) { | ||
1425 | HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024; | ||
1426 | } | ||
1427 | |||
1428 | return 0; | ||
1429 | #endif /* 0 */ | ||
1430 | } | ||
1431 | |||
1432 | static int prism2_ioctl_giwretry(struct net_device *dev, | ||
1433 | struct iw_request_info *info, | ||
1434 | struct iw_param *rrq, char *extra) | ||
1435 | { | ||
1436 | struct hostap_interface *iface; | ||
1437 | local_info_t *local; | ||
1438 | u16 shortretry, longretry, lifetime, altretry; | ||
1439 | |||
1440 | iface = netdev_priv(dev); | ||
1441 | local = iface->local; | ||
1442 | |||
1443 | if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry, | ||
1444 | 2, 1) < 0 || | ||
1445 | local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry, | ||
1446 | 2, 1) < 0 || | ||
1447 | local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME, | ||
1448 | &lifetime, 2, 1) < 0) | ||
1449 | return -EINVAL; | ||
1450 | |||
1451 | le16_to_cpus(&shortretry); | ||
1452 | le16_to_cpus(&longretry); | ||
1453 | le16_to_cpus(&lifetime); | ||
1454 | |||
1455 | rrq->disabled = 0; | ||
1456 | |||
1457 | if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
1458 | rrq->flags = IW_RETRY_LIFETIME; | ||
1459 | rrq->value = lifetime * 1024; | ||
1460 | } else { | ||
1461 | if (local->manual_retry_count >= 0) { | ||
1462 | rrq->flags = IW_RETRY_LIMIT; | ||
1463 | if (local->func->get_rid(dev, | ||
1464 | HFA384X_RID_CNFALTRETRYCOUNT, | ||
1465 | &altretry, 2, 1) >= 0) | ||
1466 | rrq->value = le16_to_cpu(altretry); | ||
1467 | else | ||
1468 | rrq->value = local->manual_retry_count; | ||
1469 | } else if ((rrq->flags & IW_RETRY_MAX)) { | ||
1470 | rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
1471 | rrq->value = longretry; | ||
1472 | } else { | ||
1473 | rrq->flags = IW_RETRY_LIMIT; | ||
1474 | rrq->value = shortretry; | ||
1475 | if (shortretry != longretry) | ||
1476 | rrq->flags |= IW_RETRY_MIN; | ||
1477 | } | ||
1478 | } | ||
1479 | return 0; | ||
1480 | } | ||
1481 | |||
1482 | |||
1483 | /* Note! This TX power controlling is experimental and should not be used in | ||
1484 | * production use. It just sets raw power register and does not use any kind of | ||
1485 | * feedback information from the measured TX power (CR58). This is now | ||
1486 | * commented out to make sure that it is not used by accident. TX power | ||
1487 | * configuration will be enabled again after proper algorithm using feedback | ||
1488 | * has been implemented. */ | ||
1489 | |||
1490 | #ifdef RAW_TXPOWER_SETTING | ||
1491 | /* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. | ||
1492 | * This version assumes following mapping: | ||
1493 | * CR31 is 7-bit value with -64 to +63 range. | ||
1494 | * -64 is mapped into +20dBm and +63 into -43dBm. | ||
1495 | * This is certainly not an exact mapping for every card, but at least | ||
1496 | * increasing dBm value should correspond to increasing TX power. | ||
1497 | */ | ||
1498 | |||
1499 | static int prism2_txpower_hfa386x_to_dBm(u16 val) | ||
1500 | { | ||
1501 | signed char tmp; | ||
1502 | |||
1503 | if (val > 255) | ||
1504 | val = 255; | ||
1505 | |||
1506 | tmp = val; | ||
1507 | tmp >>= 2; | ||
1508 | |||
1509 | return -12 - tmp; | ||
1510 | } | ||
1511 | |||
1512 | static u16 prism2_txpower_dBm_to_hfa386x(int val) | ||
1513 | { | ||
1514 | signed char tmp; | ||
1515 | |||
1516 | if (val > 20) | ||
1517 | return 128; | ||
1518 | else if (val < -43) | ||
1519 | return 127; | ||
1520 | |||
1521 | tmp = val; | ||
1522 | tmp = -12 - tmp; | ||
1523 | tmp <<= 2; | ||
1524 | |||
1525 | return (unsigned char) tmp; | ||
1526 | } | ||
1527 | #endif /* RAW_TXPOWER_SETTING */ | ||
1528 | |||
1529 | |||
1530 | static int prism2_ioctl_siwtxpow(struct net_device *dev, | ||
1531 | struct iw_request_info *info, | ||
1532 | struct iw_param *rrq, char *extra) | ||
1533 | { | ||
1534 | struct hostap_interface *iface; | ||
1535 | local_info_t *local; | ||
1536 | #ifdef RAW_TXPOWER_SETTING | ||
1537 | char *tmp; | ||
1538 | #endif | ||
1539 | u16 val; | ||
1540 | int ret = 0; | ||
1541 | |||
1542 | iface = netdev_priv(dev); | ||
1543 | local = iface->local; | ||
1544 | |||
1545 | if (rrq->disabled) { | ||
1546 | if (local->txpower_type != PRISM2_TXPOWER_OFF) { | ||
1547 | val = 0xff; /* use all standby and sleep modes */ | ||
1548 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1549 | HFA386X_CR_A_D_TEST_MODES2, | ||
1550 | &val, NULL); | ||
1551 | printk(KERN_DEBUG "%s: Turning radio off: %s\n", | ||
1552 | dev->name, ret ? "failed" : "OK"); | ||
1553 | local->txpower_type = PRISM2_TXPOWER_OFF; | ||
1554 | } | ||
1555 | return (ret ? -EOPNOTSUPP : 0); | ||
1556 | } | ||
1557 | |||
1558 | if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1559 | val = 0; /* disable all standby and sleep modes */ | ||
1560 | ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1561 | HFA386X_CR_A_D_TEST_MODES2, &val, NULL); | ||
1562 | printk(KERN_DEBUG "%s: Turning radio on: %s\n", | ||
1563 | dev->name, ret ? "failed" : "OK"); | ||
1564 | local->txpower_type = PRISM2_TXPOWER_UNKNOWN; | ||
1565 | } | ||
1566 | |||
1567 | #ifdef RAW_TXPOWER_SETTING | ||
1568 | if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { | ||
1569 | printk(KERN_DEBUG "Setting ALC on\n"); | ||
1570 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1571 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1572 | (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); | ||
1573 | local->txpower_type = PRISM2_TXPOWER_AUTO; | ||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | if (local->txpower_type != PRISM2_TXPOWER_FIXED) { | ||
1578 | printk(KERN_DEBUG "Setting ALC off\n"); | ||
1579 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
1580 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
1581 | (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); | ||
1582 | local->txpower_type = PRISM2_TXPOWER_FIXED; | ||
1583 | } | ||
1584 | |||
1585 | if (rrq->flags == IW_TXPOW_DBM) | ||
1586 | tmp = "dBm"; | ||
1587 | else if (rrq->flags == IW_TXPOW_MWATT) | ||
1588 | tmp = "mW"; | ||
1589 | else | ||
1590 | tmp = "UNKNOWN"; | ||
1591 | printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); | ||
1592 | |||
1593 | if (rrq->flags != IW_TXPOW_DBM) { | ||
1594 | printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); | ||
1595 | return -EOPNOTSUPP; | ||
1596 | } | ||
1597 | |||
1598 | local->txpower = rrq->value; | ||
1599 | val = prism2_txpower_dBm_to_hfa386x(local->txpower); | ||
1600 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, | ||
1601 | HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) | ||
1602 | ret = -EOPNOTSUPP; | ||
1603 | #else /* RAW_TXPOWER_SETTING */ | ||
1604 | if (rrq->fixed) | ||
1605 | ret = -EOPNOTSUPP; | ||
1606 | #endif /* RAW_TXPOWER_SETTING */ | ||
1607 | |||
1608 | return ret; | ||
1609 | } | ||
1610 | |||
1611 | static int prism2_ioctl_giwtxpow(struct net_device *dev, | ||
1612 | struct iw_request_info *info, | ||
1613 | struct iw_param *rrq, char *extra) | ||
1614 | { | ||
1615 | #ifdef RAW_TXPOWER_SETTING | ||
1616 | struct hostap_interface *iface; | ||
1617 | local_info_t *local; | ||
1618 | u16 resp0; | ||
1619 | |||
1620 | iface = netdev_priv(dev); | ||
1621 | local = iface->local; | ||
1622 | |||
1623 | rrq->flags = IW_TXPOW_DBM; | ||
1624 | rrq->disabled = 0; | ||
1625 | rrq->fixed = 0; | ||
1626 | |||
1627 | if (local->txpower_type == PRISM2_TXPOWER_AUTO) { | ||
1628 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, | ||
1629 | HFA386X_CR_MANUAL_TX_POWER, | ||
1630 | NULL, &resp0) == 0) { | ||
1631 | rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); | ||
1632 | } else { | ||
1633 | /* Could not get real txpower; guess 15 dBm */ | ||
1634 | rrq->value = 15; | ||
1635 | } | ||
1636 | } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { | ||
1637 | rrq->value = 0; | ||
1638 | rrq->disabled = 1; | ||
1639 | } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { | ||
1640 | rrq->value = local->txpower; | ||
1641 | rrq->fixed = 1; | ||
1642 | } else { | ||
1643 | printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", | ||
1644 | local->txpower_type); | ||
1645 | } | ||
1646 | return 0; | ||
1647 | #else /* RAW_TXPOWER_SETTING */ | ||
1648 | return -EOPNOTSUPP; | ||
1649 | #endif /* RAW_TXPOWER_SETTING */ | ||
1650 | } | ||
1651 | |||
1652 | |||
1653 | #ifndef PRISM2_NO_STATION_MODES | ||
1654 | |||
1655 | /* HostScan request works with and without host_roaming mode. In addition, it | ||
1656 | * does not break current association. However, it requires newer station | ||
1657 | * firmware version (>= 1.3.1) than scan request. */ | ||
1658 | static int prism2_request_hostscan(struct net_device *dev, | ||
1659 | u8 *ssid, u8 ssid_len) | ||
1660 | { | ||
1661 | struct hostap_interface *iface; | ||
1662 | local_info_t *local; | ||
1663 | struct hfa384x_hostscan_request scan_req; | ||
1664 | |||
1665 | iface = netdev_priv(dev); | ||
1666 | local = iface->local; | ||
1667 | |||
1668 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1669 | scan_req.channel_list = cpu_to_le16(local->channel_mask & | ||
1670 | local->scan_channel_mask); | ||
1671 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1672 | if (ssid) { | ||
1673 | if (ssid_len > 32) | ||
1674 | return -EINVAL; | ||
1675 | scan_req.target_ssid_len = cpu_to_le16(ssid_len); | ||
1676 | memcpy(scan_req.target_ssid, ssid, ssid_len); | ||
1677 | } | ||
1678 | |||
1679 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
1680 | sizeof(scan_req))) { | ||
1681 | printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); | ||
1682 | return -EINVAL; | ||
1683 | } | ||
1684 | return 0; | ||
1685 | } | ||
1686 | |||
1687 | |||
1688 | static int prism2_request_scan(struct net_device *dev) | ||
1689 | { | ||
1690 | struct hostap_interface *iface; | ||
1691 | local_info_t *local; | ||
1692 | struct hfa384x_scan_request scan_req; | ||
1693 | int ret = 0; | ||
1694 | |||
1695 | iface = netdev_priv(dev); | ||
1696 | local = iface->local; | ||
1697 | |||
1698 | memset(&scan_req, 0, sizeof(scan_req)); | ||
1699 | scan_req.channel_list = cpu_to_le16(local->channel_mask & | ||
1700 | local->scan_channel_mask); | ||
1701 | scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); | ||
1702 | |||
1703 | /* FIX: | ||
1704 | * It seems to be enough to set roaming mode for a short moment to | ||
1705 | * host-based and then setup scanrequest data and return the mode to | ||
1706 | * firmware-based. | ||
1707 | * | ||
1708 | * Master mode would need to drop to Managed mode for a short while | ||
1709 | * to make scanning work.. Or sweep through the different channels and | ||
1710 | * use passive scan based on beacons. */ | ||
1711 | |||
1712 | if (!local->host_roaming) | ||
1713 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1714 | HFA384X_ROAMING_HOST); | ||
1715 | |||
1716 | if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, | ||
1717 | sizeof(scan_req))) { | ||
1718 | printk(KERN_DEBUG "SCANREQUEST failed\n"); | ||
1719 | ret = -EINVAL; | ||
1720 | } | ||
1721 | |||
1722 | if (!local->host_roaming) | ||
1723 | hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, | ||
1724 | HFA384X_ROAMING_FIRMWARE); | ||
1725 | |||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1729 | #else /* !PRISM2_NO_STATION_MODES */ | ||
1730 | |||
1731 | static inline int prism2_request_hostscan(struct net_device *dev, | ||
1732 | u8 *ssid, u8 ssid_len) | ||
1733 | { | ||
1734 | return -EOPNOTSUPP; | ||
1735 | } | ||
1736 | |||
1737 | |||
1738 | static inline int prism2_request_scan(struct net_device *dev) | ||
1739 | { | ||
1740 | return -EOPNOTSUPP; | ||
1741 | } | ||
1742 | |||
1743 | #endif /* !PRISM2_NO_STATION_MODES */ | ||
1744 | |||
1745 | |||
1746 | static int prism2_ioctl_siwscan(struct net_device *dev, | ||
1747 | struct iw_request_info *info, | ||
1748 | struct iw_point *data, char *extra) | ||
1749 | { | ||
1750 | struct hostap_interface *iface; | ||
1751 | local_info_t *local; | ||
1752 | int ret; | ||
1753 | u8 *ssid = NULL, ssid_len = 0; | ||
1754 | struct iw_scan_req *req = (struct iw_scan_req *) extra; | ||
1755 | |||
1756 | iface = netdev_priv(dev); | ||
1757 | local = iface->local; | ||
1758 | |||
1759 | if (data->length < sizeof(struct iw_scan_req)) | ||
1760 | req = NULL; | ||
1761 | |||
1762 | if (local->iw_mode == IW_MODE_MASTER) { | ||
1763 | /* In master mode, we just return the results of our local | ||
1764 | * tables, so we don't need to start anything... | ||
1765 | * Jean II */ | ||
1766 | data->length = 0; | ||
1767 | return 0; | ||
1768 | } | ||
1769 | |||
1770 | if (!local->dev_enabled) | ||
1771 | return -ENETDOWN; | ||
1772 | |||
1773 | if (req && data->flags & IW_SCAN_THIS_ESSID) { | ||
1774 | ssid = req->essid; | ||
1775 | ssid_len = req->essid_len; | ||
1776 | |||
1777 | if (ssid_len && | ||
1778 | ((local->iw_mode != IW_MODE_INFRA && | ||
1779 | local->iw_mode != IW_MODE_ADHOC) || | ||
1780 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) | ||
1781 | return -EOPNOTSUPP; | ||
1782 | } | ||
1783 | |||
1784 | if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) | ||
1785 | ret = prism2_request_hostscan(dev, ssid, ssid_len); | ||
1786 | else | ||
1787 | ret = prism2_request_scan(dev); | ||
1788 | |||
1789 | if (ret == 0) | ||
1790 | local->scan_timestamp = jiffies; | ||
1791 | |||
1792 | /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ | ||
1793 | |||
1794 | return ret; | ||
1795 | } | ||
1796 | |||
1797 | |||
1798 | #ifndef PRISM2_NO_STATION_MODES | ||
1799 | static char * __prism2_translate_scan(local_info_t *local, | ||
1800 | struct hfa384x_hostscan_result *scan, | ||
1801 | struct hostap_bss_info *bss, | ||
1802 | char *current_ev, char *end_buf) | ||
1803 | { | ||
1804 | int i, chan; | ||
1805 | struct iw_event iwe; | ||
1806 | char *current_val; | ||
1807 | u16 capabilities; | ||
1808 | u8 *pos; | ||
1809 | u8 *ssid, *bssid; | ||
1810 | size_t ssid_len; | ||
1811 | char *buf; | ||
1812 | |||
1813 | if (bss) { | ||
1814 | ssid = bss->ssid; | ||
1815 | ssid_len = bss->ssid_len; | ||
1816 | bssid = bss->bssid; | ||
1817 | } else { | ||
1818 | ssid = scan->ssid; | ||
1819 | ssid_len = le16_to_cpu(scan->ssid_len); | ||
1820 | bssid = scan->bssid; | ||
1821 | } | ||
1822 | if (ssid_len > 32) | ||
1823 | ssid_len = 32; | ||
1824 | |||
1825 | /* First entry *MUST* be the AP MAC address */ | ||
1826 | memset(&iwe, 0, sizeof(iwe)); | ||
1827 | iwe.cmd = SIOCGIWAP; | ||
1828 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1829 | memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); | ||
1830 | /* FIX: | ||
1831 | * I do not know how this is possible, but iwe_stream_add_event | ||
1832 | * seems to re-order memcpy execution so that len is set only | ||
1833 | * after copying.. Pre-setting len here "fixes" this, but real | ||
1834 | * problems should be solved (after which these iwe.len | ||
1835 | * settings could be removed from this function). */ | ||
1836 | iwe.len = IW_EV_ADDR_LEN; | ||
1837 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1838 | IW_EV_ADDR_LEN); | ||
1839 | |||
1840 | /* Other entries will be displayed in the order we give them */ | ||
1841 | |||
1842 | memset(&iwe, 0, sizeof(iwe)); | ||
1843 | iwe.cmd = SIOCGIWESSID; | ||
1844 | iwe.u.data.length = ssid_len; | ||
1845 | iwe.u.data.flags = 1; | ||
1846 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1847 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); | ||
1848 | |||
1849 | memset(&iwe, 0, sizeof(iwe)); | ||
1850 | iwe.cmd = SIOCGIWMODE; | ||
1851 | if (bss) { | ||
1852 | capabilities = bss->capab_info; | ||
1853 | } else { | ||
1854 | capabilities = le16_to_cpu(scan->capability); | ||
1855 | } | ||
1856 | if (capabilities & (WLAN_CAPABILITY_ESS | | ||
1857 | WLAN_CAPABILITY_IBSS)) { | ||
1858 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
1859 | iwe.u.mode = IW_MODE_MASTER; | ||
1860 | else | ||
1861 | iwe.u.mode = IW_MODE_ADHOC; | ||
1862 | iwe.len = IW_EV_UINT_LEN; | ||
1863 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1864 | IW_EV_UINT_LEN); | ||
1865 | } | ||
1866 | |||
1867 | memset(&iwe, 0, sizeof(iwe)); | ||
1868 | iwe.cmd = SIOCGIWFREQ; | ||
1869 | if (scan) { | ||
1870 | chan = scan->chid; | ||
1871 | } else if (bss) { | ||
1872 | chan = bss->chan; | ||
1873 | } else { | ||
1874 | chan = 0; | ||
1875 | } | ||
1876 | |||
1877 | if (chan > 0) { | ||
1878 | iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; | ||
1879 | iwe.u.freq.e = 1; | ||
1880 | iwe.len = IW_EV_FREQ_LEN; | ||
1881 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1882 | IW_EV_FREQ_LEN); | ||
1883 | } | ||
1884 | |||
1885 | if (scan) { | ||
1886 | memset(&iwe, 0, sizeof(iwe)); | ||
1887 | iwe.cmd = IWEVQUAL; | ||
1888 | if (local->last_scan_type == PRISM2_HOSTSCAN) { | ||
1889 | iwe.u.qual.level = le16_to_cpu(scan->sl); | ||
1890 | iwe.u.qual.noise = le16_to_cpu(scan->anl); | ||
1891 | } else { | ||
1892 | iwe.u.qual.level = | ||
1893 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); | ||
1894 | iwe.u.qual.noise = | ||
1895 | HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); | ||
1896 | } | ||
1897 | iwe.len = IW_EV_QUAL_LEN; | ||
1898 | current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, | ||
1899 | IW_EV_QUAL_LEN); | ||
1900 | } | ||
1901 | |||
1902 | memset(&iwe, 0, sizeof(iwe)); | ||
1903 | iwe.cmd = SIOCGIWENCODE; | ||
1904 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
1905 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1906 | else | ||
1907 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1908 | iwe.u.data.length = 0; | ||
1909 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1910 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); | ||
1911 | |||
1912 | /* TODO: add SuppRates into BSS table */ | ||
1913 | if (scan) { | ||
1914 | memset(&iwe, 0, sizeof(iwe)); | ||
1915 | iwe.cmd = SIOCGIWRATE; | ||
1916 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1917 | pos = scan->sup_rates; | ||
1918 | for (i = 0; i < sizeof(scan->sup_rates); i++) { | ||
1919 | if (pos[i] == 0) | ||
1920 | break; | ||
1921 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1922 | iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); | ||
1923 | current_val = iwe_stream_add_value( | ||
1924 | current_ev, current_val, end_buf, &iwe, | ||
1925 | IW_EV_PARAM_LEN); | ||
1926 | } | ||
1927 | /* Check if we added any event */ | ||
1928 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | ||
1929 | current_ev = current_val; | ||
1930 | } | ||
1931 | |||
1932 | /* TODO: add BeaconInt,resp_rate,atim into BSS table */ | ||
1933 | buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); | ||
1934 | if (buf && scan) { | ||
1935 | memset(&iwe, 0, sizeof(iwe)); | ||
1936 | iwe.cmd = IWEVCUSTOM; | ||
1937 | sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); | ||
1938 | iwe.u.data.length = strlen(buf); | ||
1939 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1940 | buf); | ||
1941 | |||
1942 | memset(&iwe, 0, sizeof(iwe)); | ||
1943 | iwe.cmd = IWEVCUSTOM; | ||
1944 | sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); | ||
1945 | iwe.u.data.length = strlen(buf); | ||
1946 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1947 | buf); | ||
1948 | |||
1949 | if (local->last_scan_type == PRISM2_HOSTSCAN && | ||
1950 | (capabilities & WLAN_CAPABILITY_IBSS)) { | ||
1951 | memset(&iwe, 0, sizeof(iwe)); | ||
1952 | iwe.cmd = IWEVCUSTOM; | ||
1953 | sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); | ||
1954 | iwe.u.data.length = strlen(buf); | ||
1955 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1956 | &iwe, buf); | ||
1957 | } | ||
1958 | } | ||
1959 | kfree(buf); | ||
1960 | |||
1961 | if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { | ||
1962 | memset(&iwe, 0, sizeof(iwe)); | ||
1963 | iwe.cmd = IWEVGENIE; | ||
1964 | iwe.u.data.length = bss->wpa_ie_len; | ||
1965 | current_ev = iwe_stream_add_point( | ||
1966 | current_ev, end_buf, &iwe, bss->wpa_ie); | ||
1967 | } | ||
1968 | |||
1969 | if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) { | ||
1970 | memset(&iwe, 0, sizeof(iwe)); | ||
1971 | iwe.cmd = IWEVGENIE; | ||
1972 | iwe.u.data.length = bss->rsn_ie_len; | ||
1973 | current_ev = iwe_stream_add_point( | ||
1974 | current_ev, end_buf, &iwe, bss->rsn_ie); | ||
1975 | } | ||
1976 | |||
1977 | return current_ev; | ||
1978 | } | ||
1979 | |||
1980 | |||
1981 | /* Translate scan data returned from the card to a card independant | ||
1982 | * format that the Wireless Tools will understand - Jean II */ | ||
1983 | static inline int prism2_translate_scan(local_info_t *local, | ||
1984 | char *buffer, int buflen) | ||
1985 | { | ||
1986 | struct hfa384x_hostscan_result *scan; | ||
1987 | int entry, hostscan; | ||
1988 | char *current_ev = buffer; | ||
1989 | char *end_buf = buffer + buflen; | ||
1990 | struct list_head *ptr; | ||
1991 | |||
1992 | spin_lock_bh(&local->lock); | ||
1993 | |||
1994 | list_for_each(ptr, &local->bss_list) { | ||
1995 | struct hostap_bss_info *bss; | ||
1996 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
1997 | bss->included = 0; | ||
1998 | } | ||
1999 | |||
2000 | hostscan = local->last_scan_type == PRISM2_HOSTSCAN; | ||
2001 | for (entry = 0; entry < local->last_scan_results_count; entry++) { | ||
2002 | int found = 0; | ||
2003 | scan = &local->last_scan_results[entry]; | ||
2004 | |||
2005 | /* Report every SSID if the AP is using multiple SSIDs. If no | ||
2006 | * BSS record is found (e.g., when WPA mode is disabled), | ||
2007 | * report the AP once. */ | ||
2008 | list_for_each(ptr, &local->bss_list) { | ||
2009 | struct hostap_bss_info *bss; | ||
2010 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2011 | if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) { | ||
2012 | bss->included = 1; | ||
2013 | current_ev = __prism2_translate_scan( | ||
2014 | local, scan, bss, current_ev, end_buf); | ||
2015 | found++; | ||
2016 | } | ||
2017 | } | ||
2018 | if (!found) { | ||
2019 | current_ev = __prism2_translate_scan( | ||
2020 | local, scan, NULL, current_ev, end_buf); | ||
2021 | } | ||
2022 | /* Check if there is space for one more entry */ | ||
2023 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2024 | /* Ask user space to try again with a bigger buffer */ | ||
2025 | spin_unlock_bh(&local->lock); | ||
2026 | return -E2BIG; | ||
2027 | } | ||
2028 | } | ||
2029 | |||
2030 | /* Prism2 firmware has limits (32 at least in some versions) for number | ||
2031 | * of BSSes in scan results. Extend this limit by using local BSS list. | ||
2032 | */ | ||
2033 | list_for_each(ptr, &local->bss_list) { | ||
2034 | struct hostap_bss_info *bss; | ||
2035 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
2036 | if (bss->included) | ||
2037 | continue; | ||
2038 | current_ev = __prism2_translate_scan(local, NULL, bss, | ||
2039 | current_ev, end_buf); | ||
2040 | /* Check if there is space for one more entry */ | ||
2041 | if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { | ||
2042 | /* Ask user space to try again with a bigger buffer */ | ||
2043 | spin_unlock_bh(&local->lock); | ||
2044 | return -E2BIG; | ||
2045 | } | ||
2046 | } | ||
2047 | |||
2048 | spin_unlock_bh(&local->lock); | ||
2049 | |||
2050 | return current_ev - buffer; | ||
2051 | } | ||
2052 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2053 | |||
2054 | |||
2055 | static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, | ||
2056 | struct iw_request_info *info, | ||
2057 | struct iw_point *data, char *extra) | ||
2058 | { | ||
2059 | #ifdef PRISM2_NO_STATION_MODES | ||
2060 | return -EOPNOTSUPP; | ||
2061 | #else /* PRISM2_NO_STATION_MODES */ | ||
2062 | struct hostap_interface *iface; | ||
2063 | local_info_t *local; | ||
2064 | int res; | ||
2065 | |||
2066 | iface = netdev_priv(dev); | ||
2067 | local = iface->local; | ||
2068 | |||
2069 | /* Wait until the scan is finished. We can probably do better | ||
2070 | * than that - Jean II */ | ||
2071 | if (local->scan_timestamp && | ||
2072 | time_before(jiffies, local->scan_timestamp + 3 * HZ)) { | ||
2073 | /* Important note : we don't want to block the caller | ||
2074 | * until results are ready for various reasons. | ||
2075 | * First, managing wait queues is complex and racy | ||
2076 | * (there may be multiple simultaneous callers). | ||
2077 | * Second, we grab some rtnetlink lock before comming | ||
2078 | * here (in dev_ioctl()). | ||
2079 | * Third, the caller can wait on the Wireless Event | ||
2080 | * - Jean II */ | ||
2081 | return -EAGAIN; | ||
2082 | } | ||
2083 | local->scan_timestamp = 0; | ||
2084 | |||
2085 | res = prism2_translate_scan(local, extra, data->length); | ||
2086 | |||
2087 | if (res >= 0) { | ||
2088 | data->length = res; | ||
2089 | return 0; | ||
2090 | } else { | ||
2091 | data->length = 0; | ||
2092 | return res; | ||
2093 | } | ||
2094 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2095 | } | ||
2096 | |||
2097 | |||
2098 | static int prism2_ioctl_giwscan(struct net_device *dev, | ||
2099 | struct iw_request_info *info, | ||
2100 | struct iw_point *data, char *extra) | ||
2101 | { | ||
2102 | struct hostap_interface *iface; | ||
2103 | local_info_t *local; | ||
2104 | int res; | ||
2105 | |||
2106 | iface = netdev_priv(dev); | ||
2107 | local = iface->local; | ||
2108 | |||
2109 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2110 | /* In MASTER mode, it doesn't make sense to go around | ||
2111 | * scanning the frequencies and make the stations we serve | ||
2112 | * wait when what the user is really interested about is the | ||
2113 | * list of stations and access points we are talking to. | ||
2114 | * So, just extract results from our cache... | ||
2115 | * Jean II */ | ||
2116 | |||
2117 | /* Translate to WE format */ | ||
2118 | res = prism2_ap_translate_scan(dev, extra); | ||
2119 | if (res >= 0) { | ||
2120 | printk(KERN_DEBUG "Scan result translation succeeded " | ||
2121 | "(length=%d)\n", res); | ||
2122 | data->length = res; | ||
2123 | return 0; | ||
2124 | } else { | ||
2125 | printk(KERN_DEBUG | ||
2126 | "Scan result translation failed (res=%d)\n", | ||
2127 | res); | ||
2128 | data->length = 0; | ||
2129 | return res; | ||
2130 | } | ||
2131 | } else { | ||
2132 | /* Station mode */ | ||
2133 | return prism2_ioctl_giwscan_sta(dev, info, data, extra); | ||
2134 | } | ||
2135 | } | ||
2136 | |||
2137 | |||
2138 | static const struct iw_priv_args prism2_priv[] = { | ||
2139 | { PRISM2_IOCTL_MONITOR, | ||
2140 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" }, | ||
2141 | { PRISM2_IOCTL_READMIF, | ||
2142 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | ||
2143 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" }, | ||
2144 | { PRISM2_IOCTL_WRITEMIF, | ||
2145 | IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" }, | ||
2146 | { PRISM2_IOCTL_RESET, | ||
2147 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" }, | ||
2148 | { PRISM2_IOCTL_INQUIRE, | ||
2149 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" }, | ||
2150 | { PRISM2_IOCTL_SET_RID_WORD, | ||
2151 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" }, | ||
2152 | { PRISM2_IOCTL_MACCMD, | ||
2153 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" }, | ||
2154 | { PRISM2_IOCTL_WDS_ADD, | ||
2155 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" }, | ||
2156 | { PRISM2_IOCTL_WDS_DEL, | ||
2157 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" }, | ||
2158 | { PRISM2_IOCTL_ADDMAC, | ||
2159 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" }, | ||
2160 | { PRISM2_IOCTL_DELMAC, | ||
2161 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" }, | ||
2162 | { PRISM2_IOCTL_KICKMAC, | ||
2163 | IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" }, | ||
2164 | /* --- raw access to sub-ioctls --- */ | ||
2165 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2166 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" }, | ||
2167 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2168 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
2169 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" }, | ||
2170 | /* --- sub-ioctls handlers --- */ | ||
2171 | { PRISM2_IOCTL_PRISM2_PARAM, | ||
2172 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, | ||
2173 | { PRISM2_IOCTL_GET_PRISM2_PARAM, | ||
2174 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, | ||
2175 | /* --- sub-ioctls definitions --- */ | ||
2176 | { PRISM2_PARAM_TXRATECTRL, | ||
2177 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" }, | ||
2178 | { PRISM2_PARAM_TXRATECTRL, | ||
2179 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" }, | ||
2180 | { PRISM2_PARAM_BEACON_INT, | ||
2181 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" }, | ||
2182 | { PRISM2_PARAM_BEACON_INT, | ||
2183 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" }, | ||
2184 | #ifndef PRISM2_NO_STATION_MODES | ||
2185 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2186 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" }, | ||
2187 | { PRISM2_PARAM_PSEUDO_IBSS, | ||
2188 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" }, | ||
2189 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2190 | { PRISM2_PARAM_ALC, | ||
2191 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" }, | ||
2192 | { PRISM2_PARAM_ALC, | ||
2193 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" }, | ||
2194 | { PRISM2_PARAM_DUMP, | ||
2195 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" }, | ||
2196 | { PRISM2_PARAM_DUMP, | ||
2197 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" }, | ||
2198 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2199 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" }, | ||
2200 | { PRISM2_PARAM_OTHER_AP_POLICY, | ||
2201 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" }, | ||
2202 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2203 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" }, | ||
2204 | { PRISM2_PARAM_AP_MAX_INACTIVITY, | ||
2205 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" }, | ||
2206 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2207 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" }, | ||
2208 | { PRISM2_PARAM_AP_BRIDGE_PACKETS, | ||
2209 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" }, | ||
2210 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2211 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" }, | ||
2212 | { PRISM2_PARAM_DTIM_PERIOD, | ||
2213 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" }, | ||
2214 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2215 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" }, | ||
2216 | { PRISM2_PARAM_AP_NULLFUNC_ACK, | ||
2217 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" }, | ||
2218 | { PRISM2_PARAM_MAX_WDS, | ||
2219 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" }, | ||
2220 | { PRISM2_PARAM_MAX_WDS, | ||
2221 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" }, | ||
2222 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2223 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" }, | ||
2224 | { PRISM2_PARAM_AP_AUTOM_AP_WDS, | ||
2225 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" }, | ||
2226 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2227 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" }, | ||
2228 | { PRISM2_PARAM_AP_AUTH_ALGS, | ||
2229 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" }, | ||
2230 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2231 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" }, | ||
2232 | { PRISM2_PARAM_MONITOR_ALLOW_FCSERR, | ||
2233 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" }, | ||
2234 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2235 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" }, | ||
2236 | { PRISM2_PARAM_HOST_ENCRYPT, | ||
2237 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" }, | ||
2238 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2239 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" }, | ||
2240 | { PRISM2_PARAM_HOST_DECRYPT, | ||
2241 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" }, | ||
2242 | #ifndef PRISM2_NO_STATION_MODES | ||
2243 | { PRISM2_PARAM_HOST_ROAMING, | ||
2244 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" }, | ||
2245 | { PRISM2_PARAM_HOST_ROAMING, | ||
2246 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" }, | ||
2247 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2248 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2249 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" }, | ||
2250 | { PRISM2_PARAM_BCRX_STA_KEY, | ||
2251 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" }, | ||
2252 | { PRISM2_PARAM_IEEE_802_1X, | ||
2253 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" }, | ||
2254 | { PRISM2_PARAM_IEEE_802_1X, | ||
2255 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" }, | ||
2256 | { PRISM2_PARAM_ANTSEL_TX, | ||
2257 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" }, | ||
2258 | { PRISM2_PARAM_ANTSEL_TX, | ||
2259 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" }, | ||
2260 | { PRISM2_PARAM_ANTSEL_RX, | ||
2261 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" }, | ||
2262 | { PRISM2_PARAM_ANTSEL_RX, | ||
2263 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" }, | ||
2264 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2265 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" }, | ||
2266 | { PRISM2_PARAM_MONITOR_TYPE, | ||
2267 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" }, | ||
2268 | { PRISM2_PARAM_WDS_TYPE, | ||
2269 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" }, | ||
2270 | { PRISM2_PARAM_WDS_TYPE, | ||
2271 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" }, | ||
2272 | { PRISM2_PARAM_HOSTSCAN, | ||
2273 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" }, | ||
2274 | { PRISM2_PARAM_HOSTSCAN, | ||
2275 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" }, | ||
2276 | { PRISM2_PARAM_AP_SCAN, | ||
2277 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" }, | ||
2278 | { PRISM2_PARAM_AP_SCAN, | ||
2279 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" }, | ||
2280 | { PRISM2_PARAM_ENH_SEC, | ||
2281 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" }, | ||
2282 | { PRISM2_PARAM_ENH_SEC, | ||
2283 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" }, | ||
2284 | #ifdef PRISM2_IO_DEBUG | ||
2285 | { PRISM2_PARAM_IO_DEBUG, | ||
2286 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" }, | ||
2287 | { PRISM2_PARAM_IO_DEBUG, | ||
2288 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" }, | ||
2289 | #endif /* PRISM2_IO_DEBUG */ | ||
2290 | { PRISM2_PARAM_BASIC_RATES, | ||
2291 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" }, | ||
2292 | { PRISM2_PARAM_BASIC_RATES, | ||
2293 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" }, | ||
2294 | { PRISM2_PARAM_OPER_RATES, | ||
2295 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, | ||
2296 | { PRISM2_PARAM_OPER_RATES, | ||
2297 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, | ||
2298 | { PRISM2_PARAM_HOSTAPD, | ||
2299 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, | ||
2300 | { PRISM2_PARAM_HOSTAPD, | ||
2301 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, | ||
2302 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2303 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" }, | ||
2304 | { PRISM2_PARAM_HOSTAPD_STA, | ||
2305 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" }, | ||
2306 | { PRISM2_PARAM_WPA, | ||
2307 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" }, | ||
2308 | { PRISM2_PARAM_WPA, | ||
2309 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" }, | ||
2310 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2311 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" }, | ||
2312 | { PRISM2_PARAM_PRIVACY_INVOKED, | ||
2313 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" }, | ||
2314 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2315 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" }, | ||
2316 | { PRISM2_PARAM_TKIP_COUNTERMEASURES, | ||
2317 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" }, | ||
2318 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2319 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" }, | ||
2320 | { PRISM2_PARAM_DROP_UNENCRYPTED, | ||
2321 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" }, | ||
2322 | { PRISM2_PARAM_SCAN_CHANNEL_MASK, | ||
2323 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" }, | ||
2324 | { PRISM2_PARAM_SCAN_CHANNEL_MASK, | ||
2325 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" }, | ||
2326 | }; | ||
2327 | |||
2328 | |||
2329 | static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i) | ||
2330 | { | ||
2331 | struct hostap_interface *iface; | ||
2332 | local_info_t *local; | ||
2333 | |||
2334 | iface = netdev_priv(dev); | ||
2335 | local = iface->local; | ||
2336 | |||
2337 | if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL)) | ||
2338 | return -EOPNOTSUPP; | ||
2339 | |||
2340 | return 0; | ||
2341 | } | ||
2342 | |||
2343 | |||
2344 | static int prism2_ioctl_priv_prism2_param(struct net_device *dev, | ||
2345 | struct iw_request_info *info, | ||
2346 | void *wrqu, char *extra) | ||
2347 | { | ||
2348 | struct hostap_interface *iface; | ||
2349 | local_info_t *local; | ||
2350 | int *i = (int *) extra; | ||
2351 | int param = *i; | ||
2352 | int value = *(i + 1); | ||
2353 | int ret = 0; | ||
2354 | u16 val; | ||
2355 | |||
2356 | iface = netdev_priv(dev); | ||
2357 | local = iface->local; | ||
2358 | |||
2359 | switch (param) { | ||
2360 | case PRISM2_PARAM_TXRATECTRL: | ||
2361 | local->fw_tx_rate_control = value; | ||
2362 | break; | ||
2363 | |||
2364 | case PRISM2_PARAM_BEACON_INT: | ||
2365 | if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) || | ||
2366 | local->func->reset_port(dev)) | ||
2367 | ret = -EINVAL; | ||
2368 | else | ||
2369 | local->beacon_int = value; | ||
2370 | break; | ||
2371 | |||
2372 | #ifndef PRISM2_NO_STATION_MODES | ||
2373 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2374 | if (value == local->pseudo_adhoc) | ||
2375 | break; | ||
2376 | |||
2377 | if (value != 0 && value != 1) { | ||
2378 | ret = -EINVAL; | ||
2379 | break; | ||
2380 | } | ||
2381 | |||
2382 | printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n", | ||
2383 | dev->name, local->pseudo_adhoc, value); | ||
2384 | local->pseudo_adhoc = value; | ||
2385 | if (local->iw_mode != IW_MODE_ADHOC) | ||
2386 | break; | ||
2387 | |||
2388 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2389 | hostap_get_porttype(local))) { | ||
2390 | ret = -EOPNOTSUPP; | ||
2391 | break; | ||
2392 | } | ||
2393 | |||
2394 | if (local->func->reset_port(dev)) | ||
2395 | ret = -EINVAL; | ||
2396 | break; | ||
2397 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2398 | |||
2399 | case PRISM2_PARAM_ALC: | ||
2400 | printk(KERN_DEBUG "%s: %s ALC\n", dev->name, | ||
2401 | value == 0 ? "Disabling" : "Enabling"); | ||
2402 | val = HFA384X_TEST_CFG_BIT_ALC; | ||
2403 | local->func->cmd(dev, HFA384X_CMDCODE_TEST | | ||
2404 | (HFA384X_TEST_CFG_BITS << 8), | ||
2405 | value == 0 ? 0 : 1, &val, NULL); | ||
2406 | break; | ||
2407 | |||
2408 | case PRISM2_PARAM_DUMP: | ||
2409 | local->frame_dump = value; | ||
2410 | break; | ||
2411 | |||
2412 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2413 | if (value < 0 || value > 3) { | ||
2414 | ret = -EINVAL; | ||
2415 | break; | ||
2416 | } | ||
2417 | if (local->ap != NULL) | ||
2418 | local->ap->ap_policy = value; | ||
2419 | break; | ||
2420 | |||
2421 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2422 | if (value < 0 || value > 7 * 24 * 60 * 60) { | ||
2423 | ret = -EINVAL; | ||
2424 | break; | ||
2425 | } | ||
2426 | if (local->ap != NULL) | ||
2427 | local->ap->max_inactivity = value * HZ; | ||
2428 | break; | ||
2429 | |||
2430 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2431 | if (local->ap != NULL) | ||
2432 | local->ap->bridge_packets = value; | ||
2433 | break; | ||
2434 | |||
2435 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2436 | if (value < 0 || value > 65535) { | ||
2437 | ret = -EINVAL; | ||
2438 | break; | ||
2439 | } | ||
2440 | if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value) | ||
2441 | || local->func->reset_port(dev)) | ||
2442 | ret = -EINVAL; | ||
2443 | else | ||
2444 | local->dtim_period = value; | ||
2445 | break; | ||
2446 | |||
2447 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2448 | if (local->ap != NULL) | ||
2449 | local->ap->nullfunc_ack = value; | ||
2450 | break; | ||
2451 | |||
2452 | case PRISM2_PARAM_MAX_WDS: | ||
2453 | local->wds_max_connections = value; | ||
2454 | break; | ||
2455 | |||
2456 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2457 | if (local->ap != NULL) { | ||
2458 | if (!local->ap->autom_ap_wds && value) { | ||
2459 | /* add WDS link to all APs in STA table */ | ||
2460 | hostap_add_wds_links(local); | ||
2461 | } | ||
2462 | local->ap->autom_ap_wds = value; | ||
2463 | } | ||
2464 | break; | ||
2465 | |||
2466 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2467 | local->auth_algs = value; | ||
2468 | if (hostap_set_auth_algs(local)) | ||
2469 | ret = -EINVAL; | ||
2470 | break; | ||
2471 | |||
2472 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2473 | local->monitor_allow_fcserr = value; | ||
2474 | break; | ||
2475 | |||
2476 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2477 | local->host_encrypt = value; | ||
2478 | if (hostap_set_encryption(local) || | ||
2479 | local->func->reset_port(dev)) | ||
2480 | ret = -EINVAL; | ||
2481 | break; | ||
2482 | |||
2483 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2484 | local->host_decrypt = value; | ||
2485 | if (hostap_set_encryption(local) || | ||
2486 | local->func->reset_port(dev)) | ||
2487 | ret = -EINVAL; | ||
2488 | break; | ||
2489 | |||
2490 | #ifndef PRISM2_NO_STATION_MODES | ||
2491 | case PRISM2_PARAM_HOST_ROAMING: | ||
2492 | if (value < 0 || value > 2) { | ||
2493 | ret = -EINVAL; | ||
2494 | break; | ||
2495 | } | ||
2496 | local->host_roaming = value; | ||
2497 | if (hostap_set_roaming(local) || local->func->reset_port(dev)) | ||
2498 | ret = -EINVAL; | ||
2499 | break; | ||
2500 | #endif /* PRISM2_NO_STATION_MODES */ | ||
2501 | |||
2502 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2503 | local->bcrx_sta_key = value; | ||
2504 | break; | ||
2505 | |||
2506 | case PRISM2_PARAM_IEEE_802_1X: | ||
2507 | local->ieee_802_1x = value; | ||
2508 | break; | ||
2509 | |||
2510 | case PRISM2_PARAM_ANTSEL_TX: | ||
2511 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2512 | ret = -EINVAL; | ||
2513 | break; | ||
2514 | } | ||
2515 | local->antsel_tx = value; | ||
2516 | hostap_set_antsel(local); | ||
2517 | break; | ||
2518 | |||
2519 | case PRISM2_PARAM_ANTSEL_RX: | ||
2520 | if (value < 0 || value > HOSTAP_ANTSEL_HIGH) { | ||
2521 | ret = -EINVAL; | ||
2522 | break; | ||
2523 | } | ||
2524 | local->antsel_rx = value; | ||
2525 | hostap_set_antsel(local); | ||
2526 | break; | ||
2527 | |||
2528 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2529 | if (value != PRISM2_MONITOR_80211 && | ||
2530 | value != PRISM2_MONITOR_CAPHDR && | ||
2531 | value != PRISM2_MONITOR_PRISM) { | ||
2532 | ret = -EINVAL; | ||
2533 | break; | ||
2534 | } | ||
2535 | local->monitor_type = value; | ||
2536 | if (local->iw_mode == IW_MODE_MONITOR) | ||
2537 | hostap_monitor_set_type(local); | ||
2538 | break; | ||
2539 | |||
2540 | case PRISM2_PARAM_WDS_TYPE: | ||
2541 | local->wds_type = value; | ||
2542 | break; | ||
2543 | |||
2544 | case PRISM2_PARAM_HOSTSCAN: | ||
2545 | { | ||
2546 | struct hfa384x_hostscan_request scan_req; | ||
2547 | u16 rate; | ||
2548 | |||
2549 | memset(&scan_req, 0, sizeof(scan_req)); | ||
2550 | scan_req.channel_list = __constant_cpu_to_le16(0x3fff); | ||
2551 | switch (value) { | ||
2552 | case 1: rate = HFA384X_RATES_1MBPS; break; | ||
2553 | case 2: rate = HFA384X_RATES_2MBPS; break; | ||
2554 | case 3: rate = HFA384X_RATES_5MBPS; break; | ||
2555 | case 4: rate = HFA384X_RATES_11MBPS; break; | ||
2556 | default: rate = HFA384X_RATES_1MBPS; break; | ||
2557 | } | ||
2558 | scan_req.txrate = cpu_to_le16(rate); | ||
2559 | /* leave SSID empty to accept all SSIDs */ | ||
2560 | |||
2561 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2562 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2563 | HFA384X_PORTTYPE_BSS) || | ||
2564 | local->func->reset_port(dev)) | ||
2565 | printk(KERN_DEBUG "Leaving Host AP mode " | ||
2566 | "for HostScan failed\n"); | ||
2567 | } | ||
2568 | |||
2569 | if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, | ||
2570 | sizeof(scan_req))) { | ||
2571 | printk(KERN_DEBUG "HOSTSCAN failed\n"); | ||
2572 | ret = -EINVAL; | ||
2573 | } | ||
2574 | if (local->iw_mode == IW_MODE_MASTER) { | ||
2575 | wait_queue_t __wait; | ||
2576 | init_waitqueue_entry(&__wait, current); | ||
2577 | add_wait_queue(&local->hostscan_wq, &__wait); | ||
2578 | set_current_state(TASK_INTERRUPTIBLE); | ||
2579 | schedule_timeout(HZ); | ||
2580 | if (signal_pending(current)) | ||
2581 | ret = -EINTR; | ||
2582 | set_current_state(TASK_RUNNING); | ||
2583 | remove_wait_queue(&local->hostscan_wq, &__wait); | ||
2584 | |||
2585 | if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, | ||
2586 | HFA384X_PORTTYPE_HOSTAP) || | ||
2587 | local->func->reset_port(dev)) | ||
2588 | printk(KERN_DEBUG "Returning to Host AP mode " | ||
2589 | "after HostScan failed\n"); | ||
2590 | } | ||
2591 | break; | ||
2592 | } | ||
2593 | |||
2594 | case PRISM2_PARAM_AP_SCAN: | ||
2595 | local->passive_scan_interval = value; | ||
2596 | if (timer_pending(&local->passive_scan_timer)) | ||
2597 | del_timer(&local->passive_scan_timer); | ||
2598 | if (value > 0) { | ||
2599 | local->passive_scan_timer.expires = jiffies + | ||
2600 | local->passive_scan_interval * HZ; | ||
2601 | add_timer(&local->passive_scan_timer); | ||
2602 | } | ||
2603 | break; | ||
2604 | |||
2605 | case PRISM2_PARAM_ENH_SEC: | ||
2606 | if (value < 0 || value > 3) { | ||
2607 | ret = -EINVAL; | ||
2608 | break; | ||
2609 | } | ||
2610 | local->enh_sec = value; | ||
2611 | if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, | ||
2612 | local->enh_sec) || | ||
2613 | local->func->reset_port(dev)) { | ||
2614 | printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w " | ||
2615 | "1.6.3 or newer\n", dev->name); | ||
2616 | ret = -EOPNOTSUPP; | ||
2617 | } | ||
2618 | break; | ||
2619 | |||
2620 | #ifdef PRISM2_IO_DEBUG | ||
2621 | case PRISM2_PARAM_IO_DEBUG: | ||
2622 | local->io_debug_enabled = value; | ||
2623 | break; | ||
2624 | #endif /* PRISM2_IO_DEBUG */ | ||
2625 | |||
2626 | case PRISM2_PARAM_BASIC_RATES: | ||
2627 | if ((value & local->tx_rate_control) != value || value == 0) { | ||
2628 | printk(KERN_INFO "%s: invalid basic rate set - basic " | ||
2629 | "rates must be in supported rate set\n", | ||
2630 | dev->name); | ||
2631 | ret = -EINVAL; | ||
2632 | break; | ||
2633 | } | ||
2634 | local->basic_rates = value; | ||
2635 | if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | ||
2636 | local->basic_rates) || | ||
2637 | local->func->reset_port(dev)) | ||
2638 | ret = -EINVAL; | ||
2639 | break; | ||
2640 | |||
2641 | case PRISM2_PARAM_OPER_RATES: | ||
2642 | local->tx_rate_control = value; | ||
2643 | if (hostap_set_rate(dev)) | ||
2644 | ret = -EINVAL; | ||
2645 | break; | ||
2646 | |||
2647 | case PRISM2_PARAM_HOSTAPD: | ||
2648 | ret = hostap_set_hostapd(local, value, 1); | ||
2649 | break; | ||
2650 | |||
2651 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2652 | ret = hostap_set_hostapd_sta(local, value, 1); | ||
2653 | break; | ||
2654 | |||
2655 | case PRISM2_PARAM_WPA: | ||
2656 | local->wpa = value; | ||
2657 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2658 | ret = -EOPNOTSUPP; | ||
2659 | else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
2660 | value ? 1 : 0)) | ||
2661 | ret = -EINVAL; | ||
2662 | break; | ||
2663 | |||
2664 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2665 | local->privacy_invoked = value; | ||
2666 | if (hostap_set_encryption(local) || | ||
2667 | local->func->reset_port(dev)) | ||
2668 | ret = -EINVAL; | ||
2669 | break; | ||
2670 | |||
2671 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2672 | local->tkip_countermeasures = value; | ||
2673 | break; | ||
2674 | |||
2675 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2676 | local->drop_unencrypted = value; | ||
2677 | break; | ||
2678 | |||
2679 | case PRISM2_PARAM_SCAN_CHANNEL_MASK: | ||
2680 | local->scan_channel_mask = value; | ||
2681 | break; | ||
2682 | |||
2683 | default: | ||
2684 | printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", | ||
2685 | dev->name, param); | ||
2686 | ret = -EOPNOTSUPP; | ||
2687 | break; | ||
2688 | } | ||
2689 | |||
2690 | return ret; | ||
2691 | } | ||
2692 | |||
2693 | |||
2694 | static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev, | ||
2695 | struct iw_request_info *info, | ||
2696 | void *wrqu, char *extra) | ||
2697 | { | ||
2698 | struct hostap_interface *iface; | ||
2699 | local_info_t *local; | ||
2700 | int *param = (int *) extra; | ||
2701 | int ret = 0; | ||
2702 | |||
2703 | iface = netdev_priv(dev); | ||
2704 | local = iface->local; | ||
2705 | |||
2706 | switch (*param) { | ||
2707 | case PRISM2_PARAM_TXRATECTRL: | ||
2708 | *param = local->fw_tx_rate_control; | ||
2709 | break; | ||
2710 | |||
2711 | case PRISM2_PARAM_BEACON_INT: | ||
2712 | *param = local->beacon_int; | ||
2713 | break; | ||
2714 | |||
2715 | case PRISM2_PARAM_PSEUDO_IBSS: | ||
2716 | *param = local->pseudo_adhoc; | ||
2717 | break; | ||
2718 | |||
2719 | case PRISM2_PARAM_ALC: | ||
2720 | ret = -EOPNOTSUPP; /* FIX */ | ||
2721 | break; | ||
2722 | |||
2723 | case PRISM2_PARAM_DUMP: | ||
2724 | *param = local->frame_dump; | ||
2725 | break; | ||
2726 | |||
2727 | case PRISM2_PARAM_OTHER_AP_POLICY: | ||
2728 | if (local->ap != NULL) | ||
2729 | *param = local->ap->ap_policy; | ||
2730 | else | ||
2731 | ret = -EOPNOTSUPP; | ||
2732 | break; | ||
2733 | |||
2734 | case PRISM2_PARAM_AP_MAX_INACTIVITY: | ||
2735 | if (local->ap != NULL) | ||
2736 | *param = local->ap->max_inactivity / HZ; | ||
2737 | else | ||
2738 | ret = -EOPNOTSUPP; | ||
2739 | break; | ||
2740 | |||
2741 | case PRISM2_PARAM_AP_BRIDGE_PACKETS: | ||
2742 | if (local->ap != NULL) | ||
2743 | *param = local->ap->bridge_packets; | ||
2744 | else | ||
2745 | ret = -EOPNOTSUPP; | ||
2746 | break; | ||
2747 | |||
2748 | case PRISM2_PARAM_DTIM_PERIOD: | ||
2749 | *param = local->dtim_period; | ||
2750 | break; | ||
2751 | |||
2752 | case PRISM2_PARAM_AP_NULLFUNC_ACK: | ||
2753 | if (local->ap != NULL) | ||
2754 | *param = local->ap->nullfunc_ack; | ||
2755 | else | ||
2756 | ret = -EOPNOTSUPP; | ||
2757 | break; | ||
2758 | |||
2759 | case PRISM2_PARAM_MAX_WDS: | ||
2760 | *param = local->wds_max_connections; | ||
2761 | break; | ||
2762 | |||
2763 | case PRISM2_PARAM_AP_AUTOM_AP_WDS: | ||
2764 | if (local->ap != NULL) | ||
2765 | *param = local->ap->autom_ap_wds; | ||
2766 | else | ||
2767 | ret = -EOPNOTSUPP; | ||
2768 | break; | ||
2769 | |||
2770 | case PRISM2_PARAM_AP_AUTH_ALGS: | ||
2771 | *param = local->auth_algs; | ||
2772 | break; | ||
2773 | |||
2774 | case PRISM2_PARAM_MONITOR_ALLOW_FCSERR: | ||
2775 | *param = local->monitor_allow_fcserr; | ||
2776 | break; | ||
2777 | |||
2778 | case PRISM2_PARAM_HOST_ENCRYPT: | ||
2779 | *param = local->host_encrypt; | ||
2780 | break; | ||
2781 | |||
2782 | case PRISM2_PARAM_HOST_DECRYPT: | ||
2783 | *param = local->host_decrypt; | ||
2784 | break; | ||
2785 | |||
2786 | case PRISM2_PARAM_HOST_ROAMING: | ||
2787 | *param = local->host_roaming; | ||
2788 | break; | ||
2789 | |||
2790 | case PRISM2_PARAM_BCRX_STA_KEY: | ||
2791 | *param = local->bcrx_sta_key; | ||
2792 | break; | ||
2793 | |||
2794 | case PRISM2_PARAM_IEEE_802_1X: | ||
2795 | *param = local->ieee_802_1x; | ||
2796 | break; | ||
2797 | |||
2798 | case PRISM2_PARAM_ANTSEL_TX: | ||
2799 | *param = local->antsel_tx; | ||
2800 | break; | ||
2801 | |||
2802 | case PRISM2_PARAM_ANTSEL_RX: | ||
2803 | *param = local->antsel_rx; | ||
2804 | break; | ||
2805 | |||
2806 | case PRISM2_PARAM_MONITOR_TYPE: | ||
2807 | *param = local->monitor_type; | ||
2808 | break; | ||
2809 | |||
2810 | case PRISM2_PARAM_WDS_TYPE: | ||
2811 | *param = local->wds_type; | ||
2812 | break; | ||
2813 | |||
2814 | case PRISM2_PARAM_HOSTSCAN: | ||
2815 | ret = -EOPNOTSUPP; | ||
2816 | break; | ||
2817 | |||
2818 | case PRISM2_PARAM_AP_SCAN: | ||
2819 | *param = local->passive_scan_interval; | ||
2820 | break; | ||
2821 | |||
2822 | case PRISM2_PARAM_ENH_SEC: | ||
2823 | *param = local->enh_sec; | ||
2824 | break; | ||
2825 | |||
2826 | #ifdef PRISM2_IO_DEBUG | ||
2827 | case PRISM2_PARAM_IO_DEBUG: | ||
2828 | *param = local->io_debug_enabled; | ||
2829 | break; | ||
2830 | #endif /* PRISM2_IO_DEBUG */ | ||
2831 | |||
2832 | case PRISM2_PARAM_BASIC_RATES: | ||
2833 | *param = local->basic_rates; | ||
2834 | break; | ||
2835 | |||
2836 | case PRISM2_PARAM_OPER_RATES: | ||
2837 | *param = local->tx_rate_control; | ||
2838 | break; | ||
2839 | |||
2840 | case PRISM2_PARAM_HOSTAPD: | ||
2841 | *param = local->hostapd; | ||
2842 | break; | ||
2843 | |||
2844 | case PRISM2_PARAM_HOSTAPD_STA: | ||
2845 | *param = local->hostapd_sta; | ||
2846 | break; | ||
2847 | |||
2848 | case PRISM2_PARAM_WPA: | ||
2849 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
2850 | ret = -EOPNOTSUPP; | ||
2851 | *param = local->wpa; | ||
2852 | break; | ||
2853 | |||
2854 | case PRISM2_PARAM_PRIVACY_INVOKED: | ||
2855 | *param = local->privacy_invoked; | ||
2856 | break; | ||
2857 | |||
2858 | case PRISM2_PARAM_TKIP_COUNTERMEASURES: | ||
2859 | *param = local->tkip_countermeasures; | ||
2860 | break; | ||
2861 | |||
2862 | case PRISM2_PARAM_DROP_UNENCRYPTED: | ||
2863 | *param = local->drop_unencrypted; | ||
2864 | break; | ||
2865 | |||
2866 | case PRISM2_PARAM_SCAN_CHANNEL_MASK: | ||
2867 | *param = local->scan_channel_mask; | ||
2868 | break; | ||
2869 | |||
2870 | default: | ||
2871 | printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", | ||
2872 | dev->name, *param); | ||
2873 | ret = -EOPNOTSUPP; | ||
2874 | break; | ||
2875 | } | ||
2876 | |||
2877 | return ret; | ||
2878 | } | ||
2879 | |||
2880 | |||
2881 | static int prism2_ioctl_priv_readmif(struct net_device *dev, | ||
2882 | struct iw_request_info *info, | ||
2883 | void *wrqu, char *extra) | ||
2884 | { | ||
2885 | struct hostap_interface *iface; | ||
2886 | local_info_t *local; | ||
2887 | u16 resp0; | ||
2888 | |||
2889 | iface = netdev_priv(dev); | ||
2890 | local = iface->local; | ||
2891 | |||
2892 | if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL, | ||
2893 | &resp0)) | ||
2894 | return -EOPNOTSUPP; | ||
2895 | else | ||
2896 | *extra = resp0; | ||
2897 | |||
2898 | return 0; | ||
2899 | } | ||
2900 | |||
2901 | |||
2902 | static int prism2_ioctl_priv_writemif(struct net_device *dev, | ||
2903 | struct iw_request_info *info, | ||
2904 | void *wrqu, char *extra) | ||
2905 | { | ||
2906 | struct hostap_interface *iface; | ||
2907 | local_info_t *local; | ||
2908 | u16 cr, val; | ||
2909 | |||
2910 | iface = netdev_priv(dev); | ||
2911 | local = iface->local; | ||
2912 | |||
2913 | cr = *extra; | ||
2914 | val = *(extra + 1); | ||
2915 | if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL)) | ||
2916 | return -EOPNOTSUPP; | ||
2917 | |||
2918 | return 0; | ||
2919 | } | ||
2920 | |||
2921 | |||
2922 | static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i) | ||
2923 | { | ||
2924 | struct hostap_interface *iface; | ||
2925 | local_info_t *local; | ||
2926 | int ret = 0; | ||
2927 | u32 mode; | ||
2928 | |||
2929 | iface = netdev_priv(dev); | ||
2930 | local = iface->local; | ||
2931 | |||
2932 | printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor " | ||
2933 | "- update software to use iwconfig mode monitor\n", | ||
2934 | dev->name, current->pid, current->comm); | ||
2935 | |||
2936 | /* Backward compatibility code - this can be removed at some point */ | ||
2937 | |||
2938 | if (*i == 0) { | ||
2939 | /* Disable monitor mode - old mode was not saved, so go to | ||
2940 | * Master mode */ | ||
2941 | mode = IW_MODE_MASTER; | ||
2942 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2943 | } else if (*i == 1) { | ||
2944 | /* netlink socket mode is not supported anymore since it did | ||
2945 | * not separate different devices from each other and was not | ||
2946 | * best method for delivering large amount of packets to | ||
2947 | * user space */ | ||
2948 | ret = -EOPNOTSUPP; | ||
2949 | } else if (*i == 2 || *i == 3) { | ||
2950 | switch (*i) { | ||
2951 | case 2: | ||
2952 | local->monitor_type = PRISM2_MONITOR_80211; | ||
2953 | break; | ||
2954 | case 3: | ||
2955 | local->monitor_type = PRISM2_MONITOR_PRISM; | ||
2956 | break; | ||
2957 | } | ||
2958 | mode = IW_MODE_MONITOR; | ||
2959 | ret = prism2_ioctl_siwmode(dev, NULL, &mode, NULL); | ||
2960 | hostap_monitor_mode_enable(local); | ||
2961 | } else | ||
2962 | ret = -EINVAL; | ||
2963 | |||
2964 | return ret; | ||
2965 | } | ||
2966 | |||
2967 | |||
2968 | static int prism2_ioctl_priv_reset(struct net_device *dev, int *i) | ||
2969 | { | ||
2970 | struct hostap_interface *iface; | ||
2971 | local_info_t *local; | ||
2972 | |||
2973 | iface = netdev_priv(dev); | ||
2974 | local = iface->local; | ||
2975 | |||
2976 | printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i); | ||
2977 | switch (*i) { | ||
2978 | case 0: | ||
2979 | /* Disable and enable card */ | ||
2980 | local->func->hw_shutdown(dev, 1); | ||
2981 | local->func->hw_config(dev, 0); | ||
2982 | break; | ||
2983 | |||
2984 | case 1: | ||
2985 | /* COR sreset */ | ||
2986 | local->func->hw_reset(dev); | ||
2987 | break; | ||
2988 | |||
2989 | case 2: | ||
2990 | /* Disable and enable port 0 */ | ||
2991 | local->func->reset_port(dev); | ||
2992 | break; | ||
2993 | |||
2994 | case 3: | ||
2995 | prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING); | ||
2996 | if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, | ||
2997 | NULL)) | ||
2998 | return -EINVAL; | ||
2999 | break; | ||
3000 | |||
3001 | case 4: | ||
3002 | if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, | ||
3003 | NULL)) | ||
3004 | return -EINVAL; | ||
3005 | break; | ||
3006 | |||
3007 | default: | ||
3008 | printk(KERN_DEBUG "Unknown reset request %d\n", *i); | ||
3009 | return -EOPNOTSUPP; | ||
3010 | } | ||
3011 | |||
3012 | return 0; | ||
3013 | } | ||
3014 | |||
3015 | |||
3016 | static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i) | ||
3017 | { | ||
3018 | int rid = *i; | ||
3019 | int value = *(i + 1); | ||
3020 | |||
3021 | printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value); | ||
3022 | |||
3023 | if (hostap_set_word(dev, rid, value)) | ||
3024 | return -EINVAL; | ||
3025 | |||
3026 | return 0; | ||
3027 | } | ||
3028 | |||
3029 | |||
3030 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
3031 | static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd) | ||
3032 | { | ||
3033 | int ret = 0; | ||
3034 | |||
3035 | switch (*cmd) { | ||
3036 | case AP_MAC_CMD_POLICY_OPEN: | ||
3037 | local->ap->mac_restrictions.policy = MAC_POLICY_OPEN; | ||
3038 | break; | ||
3039 | case AP_MAC_CMD_POLICY_ALLOW: | ||
3040 | local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW; | ||
3041 | break; | ||
3042 | case AP_MAC_CMD_POLICY_DENY: | ||
3043 | local->ap->mac_restrictions.policy = MAC_POLICY_DENY; | ||
3044 | break; | ||
3045 | case AP_MAC_CMD_FLUSH: | ||
3046 | ap_control_flush_macs(&local->ap->mac_restrictions); | ||
3047 | break; | ||
3048 | case AP_MAC_CMD_KICKALL: | ||
3049 | ap_control_kickall(local->ap); | ||
3050 | hostap_deauth_all_stas(local->dev, local->ap, 0); | ||
3051 | break; | ||
3052 | default: | ||
3053 | ret = -EOPNOTSUPP; | ||
3054 | break; | ||
3055 | } | ||
3056 | |||
3057 | return ret; | ||
3058 | } | ||
3059 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
3060 | |||
3061 | |||
3062 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
3063 | static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) | ||
3064 | { | ||
3065 | struct prism2_download_param *param; | ||
3066 | int ret = 0; | ||
3067 | |||
3068 | if (p->length < sizeof(struct prism2_download_param) || | ||
3069 | p->length > 1024 || !p->pointer) | ||
3070 | return -EINVAL; | ||
3071 | |||
3072 | param = (struct prism2_download_param *) | ||
3073 | kmalloc(p->length, GFP_KERNEL); | ||
3074 | if (param == NULL) | ||
3075 | return -ENOMEM; | ||
3076 | |||
3077 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3078 | ret = -EFAULT; | ||
3079 | goto out; | ||
3080 | } | ||
3081 | |||
3082 | if (p->length < sizeof(struct prism2_download_param) + | ||
3083 | param->num_areas * sizeof(struct prism2_download_area)) { | ||
3084 | ret = -EINVAL; | ||
3085 | goto out; | ||
3086 | } | ||
3087 | |||
3088 | ret = local->func->download(local, param); | ||
3089 | |||
3090 | out: | ||
3091 | if (param != NULL) | ||
3092 | kfree(param); | ||
3093 | |||
3094 | return ret; | ||
3095 | } | ||
3096 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
3097 | |||
3098 | |||
3099 | static int prism2_set_genericelement(struct net_device *dev, u8 *elem, | ||
3100 | size_t len) | ||
3101 | { | ||
3102 | struct hostap_interface *iface = dev->priv; | ||
3103 | local_info_t *local = iface->local; | ||
3104 | u8 *buf; | ||
3105 | |||
3106 | /* | ||
3107 | * Add 16-bit length in the beginning of the buffer because Prism2 RID | ||
3108 | * includes it. | ||
3109 | */ | ||
3110 | buf = kmalloc(len + 2, GFP_KERNEL); | ||
3111 | if (buf == NULL) | ||
3112 | return -ENOMEM; | ||
3113 | |||
3114 | *((u16 *) buf) = cpu_to_le16(len); | ||
3115 | memcpy(buf + 2, elem, len); | ||
3116 | |||
3117 | kfree(local->generic_elem); | ||
3118 | local->generic_elem = buf; | ||
3119 | local->generic_elem_len = len + 2; | ||
3120 | |||
3121 | return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT, | ||
3122 | buf, len + 2); | ||
3123 | } | ||
3124 | |||
3125 | |||
3126 | static int prism2_ioctl_siwauth(struct net_device *dev, | ||
3127 | struct iw_request_info *info, | ||
3128 | struct iw_param *data, char *extra) | ||
3129 | { | ||
3130 | struct hostap_interface *iface = dev->priv; | ||
3131 | local_info_t *local = iface->local; | ||
3132 | |||
3133 | switch (data->flags & IW_AUTH_INDEX) { | ||
3134 | case IW_AUTH_WPA_VERSION: | ||
3135 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3136 | case IW_AUTH_CIPHER_GROUP: | ||
3137 | case IW_AUTH_KEY_MGMT: | ||
3138 | /* | ||
3139 | * Host AP driver does not use these parameters and allows | ||
3140 | * wpa_supplicant to control them internally. | ||
3141 | */ | ||
3142 | break; | ||
3143 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3144 | local->tkip_countermeasures = data->value; | ||
3145 | break; | ||
3146 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3147 | local->drop_unencrypted = data->value; | ||
3148 | break; | ||
3149 | case IW_AUTH_80211_AUTH_ALG: | ||
3150 | local->auth_algs = data->value; | ||
3151 | break; | ||
3152 | case IW_AUTH_WPA_ENABLED: | ||
3153 | if (data->value == 0) { | ||
3154 | local->wpa = 0; | ||
3155 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3156 | break; | ||
3157 | prism2_set_genericelement(dev, "", 0); | ||
3158 | local->host_roaming = 0; | ||
3159 | local->privacy_invoked = 0; | ||
3160 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, | ||
3161 | 0) || | ||
3162 | hostap_set_roaming(local) || | ||
3163 | hostap_set_encryption(local) || | ||
3164 | local->func->reset_port(dev)) | ||
3165 | return -EINVAL; | ||
3166 | break; | ||
3167 | } | ||
3168 | if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0)) | ||
3169 | return -EOPNOTSUPP; | ||
3170 | local->host_roaming = 2; | ||
3171 | local->privacy_invoked = 1; | ||
3172 | local->wpa = 1; | ||
3173 | if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) || | ||
3174 | hostap_set_roaming(local) || | ||
3175 | hostap_set_encryption(local) || | ||
3176 | local->func->reset_port(dev)) | ||
3177 | return -EINVAL; | ||
3178 | break; | ||
3179 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3180 | local->ieee_802_1x = data->value; | ||
3181 | break; | ||
3182 | case IW_AUTH_PRIVACY_INVOKED: | ||
3183 | local->privacy_invoked = data->value; | ||
3184 | break; | ||
3185 | default: | ||
3186 | return -EOPNOTSUPP; | ||
3187 | } | ||
3188 | return 0; | ||
3189 | } | ||
3190 | |||
3191 | |||
3192 | static int prism2_ioctl_giwauth(struct net_device *dev, | ||
3193 | struct iw_request_info *info, | ||
3194 | struct iw_param *data, char *extra) | ||
3195 | { | ||
3196 | struct hostap_interface *iface = dev->priv; | ||
3197 | local_info_t *local = iface->local; | ||
3198 | |||
3199 | switch (data->flags & IW_AUTH_INDEX) { | ||
3200 | case IW_AUTH_WPA_VERSION: | ||
3201 | case IW_AUTH_CIPHER_PAIRWISE: | ||
3202 | case IW_AUTH_CIPHER_GROUP: | ||
3203 | case IW_AUTH_KEY_MGMT: | ||
3204 | /* | ||
3205 | * Host AP driver does not use these parameters and allows | ||
3206 | * wpa_supplicant to control them internally. | ||
3207 | */ | ||
3208 | return -EOPNOTSUPP; | ||
3209 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
3210 | data->value = local->tkip_countermeasures; | ||
3211 | break; | ||
3212 | case IW_AUTH_DROP_UNENCRYPTED: | ||
3213 | data->value = local->drop_unencrypted; | ||
3214 | break; | ||
3215 | case IW_AUTH_80211_AUTH_ALG: | ||
3216 | data->value = local->auth_algs; | ||
3217 | break; | ||
3218 | case IW_AUTH_WPA_ENABLED: | ||
3219 | data->value = local->wpa; | ||
3220 | break; | ||
3221 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
3222 | data->value = local->ieee_802_1x; | ||
3223 | break; | ||
3224 | default: | ||
3225 | return -EOPNOTSUPP; | ||
3226 | } | ||
3227 | return 0; | ||
3228 | } | ||
3229 | |||
3230 | |||
3231 | static int prism2_ioctl_siwencodeext(struct net_device *dev, | ||
3232 | struct iw_request_info *info, | ||
3233 | struct iw_point *erq, char *extra) | ||
3234 | { | ||
3235 | struct hostap_interface *iface = dev->priv; | ||
3236 | local_info_t *local = iface->local; | ||
3237 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3238 | int i, ret = 0; | ||
3239 | struct ieee80211_crypto_ops *ops; | ||
3240 | struct ieee80211_crypt_data **crypt; | ||
3241 | void *sta_ptr; | ||
3242 | u8 *addr; | ||
3243 | const char *alg, *module; | ||
3244 | |||
3245 | i = erq->flags & IW_ENCODE_INDEX; | ||
3246 | if (i > WEP_KEYS) | ||
3247 | return -EINVAL; | ||
3248 | if (i < 1 || i > WEP_KEYS) | ||
3249 | i = local->tx_keyidx; | ||
3250 | else | ||
3251 | i--; | ||
3252 | if (i < 0 || i >= WEP_KEYS) | ||
3253 | return -EINVAL; | ||
3254 | |||
3255 | addr = ext->addr.sa_data; | ||
3256 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3257 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3258 | sta_ptr = NULL; | ||
3259 | crypt = &local->crypt[i]; | ||
3260 | } else { | ||
3261 | if (i != 0) | ||
3262 | return -EINVAL; | ||
3263 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3264 | if (sta_ptr == NULL) { | ||
3265 | if (local->iw_mode == IW_MODE_INFRA) { | ||
3266 | /* | ||
3267 | * TODO: add STA entry for the current AP so | ||
3268 | * that unicast key can be used. For now, this | ||
3269 | * is emulated by using default key idx 0. | ||
3270 | */ | ||
3271 | i = 0; | ||
3272 | crypt = &local->crypt[i]; | ||
3273 | } else | ||
3274 | return -EINVAL; | ||
3275 | } | ||
3276 | } | ||
3277 | |||
3278 | if ((erq->flags & IW_ENCODE_DISABLED) || | ||
3279 | ext->alg == IW_ENCODE_ALG_NONE) { | ||
3280 | if (*crypt) | ||
3281 | prism2_crypt_delayed_deinit(local, crypt); | ||
3282 | goto done; | ||
3283 | } | ||
3284 | |||
3285 | switch (ext->alg) { | ||
3286 | case IW_ENCODE_ALG_WEP: | ||
3287 | alg = "WEP"; | ||
3288 | module = "ieee80211_crypt_wep"; | ||
3289 | break; | ||
3290 | case IW_ENCODE_ALG_TKIP: | ||
3291 | alg = "TKIP"; | ||
3292 | module = "ieee80211_crypt_tkip"; | ||
3293 | break; | ||
3294 | case IW_ENCODE_ALG_CCMP: | ||
3295 | alg = "CCMP"; | ||
3296 | module = "ieee80211_crypt_ccmp"; | ||
3297 | break; | ||
3298 | default: | ||
3299 | printk(KERN_DEBUG "%s: unsupported algorithm %d\n", | ||
3300 | local->dev->name, ext->alg); | ||
3301 | ret = -EOPNOTSUPP; | ||
3302 | goto done; | ||
3303 | } | ||
3304 | |||
3305 | ops = ieee80211_get_crypto_ops(alg); | ||
3306 | if (ops == NULL) { | ||
3307 | request_module(module); | ||
3308 | ops = ieee80211_get_crypto_ops(alg); | ||
3309 | } | ||
3310 | if (ops == NULL) { | ||
3311 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3312 | local->dev->name, alg); | ||
3313 | ret = -EOPNOTSUPP; | ||
3314 | goto done; | ||
3315 | } | ||
3316 | |||
3317 | if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) { | ||
3318 | /* | ||
3319 | * Per station encryption and other than WEP algorithms | ||
3320 | * require host-based encryption, so force them on | ||
3321 | * automatically. | ||
3322 | */ | ||
3323 | local->host_decrypt = local->host_encrypt = 1; | ||
3324 | } | ||
3325 | |||
3326 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3327 | struct ieee80211_crypt_data *new_crypt; | ||
3328 | |||
3329 | prism2_crypt_delayed_deinit(local, crypt); | ||
3330 | |||
3331 | new_crypt = (struct ieee80211_crypt_data *) | ||
3332 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
3333 | GFP_KERNEL); | ||
3334 | if (new_crypt == NULL) { | ||
3335 | ret = -ENOMEM; | ||
3336 | goto done; | ||
3337 | } | ||
3338 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
3339 | new_crypt->ops = ops; | ||
3340 | new_crypt->priv = new_crypt->ops->init(i); | ||
3341 | if (new_crypt->priv == NULL) { | ||
3342 | kfree(new_crypt); | ||
3343 | ret = -EINVAL; | ||
3344 | goto done; | ||
3345 | } | ||
3346 | |||
3347 | *crypt = new_crypt; | ||
3348 | } | ||
3349 | |||
3350 | /* | ||
3351 | * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the | ||
3352 | * existing seq# should not be changed. | ||
3353 | * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq# | ||
3354 | * should be changed to something else than zero. | ||
3355 | */ | ||
3356 | if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0) | ||
3357 | && (*crypt)->ops->set_key && | ||
3358 | (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, | ||
3359 | (*crypt)->priv) < 0) { | ||
3360 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3361 | local->dev->name); | ||
3362 | ret = -EINVAL; | ||
3363 | goto done; | ||
3364 | } | ||
3365 | |||
3366 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
3367 | if (!sta_ptr) | ||
3368 | local->tx_keyidx = i; | ||
3369 | else if (i) { | ||
3370 | ret = -EINVAL; | ||
3371 | goto done; | ||
3372 | } | ||
3373 | } | ||
3374 | |||
3375 | |||
3376 | if (sta_ptr == NULL && ext->key_len > 0) { | ||
3377 | int first = 1, j; | ||
3378 | for (j = 0; j < WEP_KEYS; j++) { | ||
3379 | if (j != i && local->crypt[j]) { | ||
3380 | first = 0; | ||
3381 | break; | ||
3382 | } | ||
3383 | } | ||
3384 | if (first) | ||
3385 | local->tx_keyidx = i; | ||
3386 | } | ||
3387 | |||
3388 | done: | ||
3389 | if (sta_ptr) | ||
3390 | hostap_handle_sta_release(sta_ptr); | ||
3391 | |||
3392 | local->open_wep = erq->flags & IW_ENCODE_OPEN; | ||
3393 | |||
3394 | /* | ||
3395 | * Do not reset port0 if card is in Managed mode since resetting will | ||
3396 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3397 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3398 | * after WEP configuration. However, keys are apparently changed at | ||
3399 | * least in Managed mode. | ||
3400 | */ | ||
3401 | if (ret == 0 && | ||
3402 | (hostap_set_encryption(local) || | ||
3403 | (local->iw_mode != IW_MODE_INFRA && | ||
3404 | local->func->reset_port(local->dev)))) | ||
3405 | ret = -EINVAL; | ||
3406 | |||
3407 | return ret; | ||
3408 | } | ||
3409 | |||
3410 | |||
3411 | static int prism2_ioctl_giwencodeext(struct net_device *dev, | ||
3412 | struct iw_request_info *info, | ||
3413 | struct iw_point *erq, char *extra) | ||
3414 | { | ||
3415 | struct hostap_interface *iface = dev->priv; | ||
3416 | local_info_t *local = iface->local; | ||
3417 | struct ieee80211_crypt_data **crypt; | ||
3418 | void *sta_ptr; | ||
3419 | int max_key_len, i; | ||
3420 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
3421 | u8 *addr; | ||
3422 | |||
3423 | max_key_len = erq->length - sizeof(*ext); | ||
3424 | if (max_key_len < 0) | ||
3425 | return -EINVAL; | ||
3426 | |||
3427 | i = erq->flags & IW_ENCODE_INDEX; | ||
3428 | if (i < 1 || i > WEP_KEYS) | ||
3429 | i = local->tx_keyidx; | ||
3430 | else | ||
3431 | i--; | ||
3432 | |||
3433 | addr = ext->addr.sa_data; | ||
3434 | if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && | ||
3435 | addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { | ||
3436 | sta_ptr = NULL; | ||
3437 | crypt = &local->crypt[i]; | ||
3438 | } else { | ||
3439 | i = 0; | ||
3440 | sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); | ||
3441 | if (sta_ptr == NULL) | ||
3442 | return -EINVAL; | ||
3443 | } | ||
3444 | erq->flags = i + 1; | ||
3445 | memset(ext, 0, sizeof(*ext)); | ||
3446 | |||
3447 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3448 | ext->alg = IW_ENCODE_ALG_NONE; | ||
3449 | ext->key_len = 0; | ||
3450 | erq->flags |= IW_ENCODE_DISABLED; | ||
3451 | } else { | ||
3452 | if (strcmp((*crypt)->ops->name, "WEP") == 0) | ||
3453 | ext->alg = IW_ENCODE_ALG_WEP; | ||
3454 | else if (strcmp((*crypt)->ops->name, "TKIP") == 0) | ||
3455 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
3456 | else if (strcmp((*crypt)->ops->name, "CCMP") == 0) | ||
3457 | ext->alg = IW_ENCODE_ALG_CCMP; | ||
3458 | else | ||
3459 | return -EINVAL; | ||
3460 | |||
3461 | if ((*crypt)->ops->get_key) { | ||
3462 | ext->key_len = | ||
3463 | (*crypt)->ops->get_key(ext->key, | ||
3464 | max_key_len, | ||
3465 | ext->tx_seq, | ||
3466 | (*crypt)->priv); | ||
3467 | if (ext->key_len && | ||
3468 | (ext->alg == IW_ENCODE_ALG_TKIP || | ||
3469 | ext->alg == IW_ENCODE_ALG_CCMP)) | ||
3470 | ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; | ||
3471 | } | ||
3472 | } | ||
3473 | |||
3474 | if (sta_ptr) | ||
3475 | hostap_handle_sta_release(sta_ptr); | ||
3476 | |||
3477 | return 0; | ||
3478 | } | ||
3479 | |||
3480 | |||
3481 | static int prism2_ioctl_set_encryption(local_info_t *local, | ||
3482 | struct prism2_hostapd_param *param, | ||
3483 | int param_len) | ||
3484 | { | ||
3485 | int ret = 0; | ||
3486 | struct ieee80211_crypto_ops *ops; | ||
3487 | struct ieee80211_crypt_data **crypt; | ||
3488 | void *sta_ptr; | ||
3489 | |||
3490 | param->u.crypt.err = 0; | ||
3491 | param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
3492 | |||
3493 | if (param_len != | ||
3494 | (int) ((char *) param->u.crypt.key - (char *) param) + | ||
3495 | param->u.crypt.key_len) | ||
3496 | return -EINVAL; | ||
3497 | |||
3498 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3499 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3500 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3501 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3502 | return -EINVAL; | ||
3503 | sta_ptr = NULL; | ||
3504 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3505 | } else { | ||
3506 | if (param->u.crypt.idx) | ||
3507 | return -EINVAL; | ||
3508 | sta_ptr = ap_crypt_get_ptrs( | ||
3509 | local->ap, param->sta_addr, | ||
3510 | (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT), | ||
3511 | &crypt); | ||
3512 | |||
3513 | if (sta_ptr == NULL) { | ||
3514 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3515 | return -EINVAL; | ||
3516 | } | ||
3517 | } | ||
3518 | |||
3519 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
3520 | if (crypt) | ||
3521 | prism2_crypt_delayed_deinit(local, crypt); | ||
3522 | goto done; | ||
3523 | } | ||
3524 | |||
3525 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3526 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
3527 | request_module("ieee80211_crypt_wep"); | ||
3528 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3529 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
3530 | request_module("ieee80211_crypt_tkip"); | ||
3531 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3532 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
3533 | request_module("ieee80211_crypt_ccmp"); | ||
3534 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
3535 | } | ||
3536 | if (ops == NULL) { | ||
3537 | printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", | ||
3538 | local->dev->name, param->u.crypt.alg); | ||
3539 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG; | ||
3540 | ret = -EINVAL; | ||
3541 | goto done; | ||
3542 | } | ||
3543 | |||
3544 | /* station based encryption and other than WEP algorithms require | ||
3545 | * host-based encryption, so force them on automatically */ | ||
3546 | local->host_decrypt = local->host_encrypt = 1; | ||
3547 | |||
3548 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3549 | struct ieee80211_crypt_data *new_crypt; | ||
3550 | |||
3551 | prism2_crypt_delayed_deinit(local, crypt); | ||
3552 | |||
3553 | new_crypt = (struct ieee80211_crypt_data *) | ||
3554 | kmalloc(sizeof(struct ieee80211_crypt_data), | ||
3555 | GFP_KERNEL); | ||
3556 | if (new_crypt == NULL) { | ||
3557 | ret = -ENOMEM; | ||
3558 | goto done; | ||
3559 | } | ||
3560 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
3561 | new_crypt->ops = ops; | ||
3562 | new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); | ||
3563 | if (new_crypt->priv == NULL) { | ||
3564 | kfree(new_crypt); | ||
3565 | param->u.crypt.err = | ||
3566 | HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
3567 | ret = -EINVAL; | ||
3568 | goto done; | ||
3569 | } | ||
3570 | |||
3571 | *crypt = new_crypt; | ||
3572 | } | ||
3573 | |||
3574 | if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) || | ||
3575 | param->u.crypt.key_len > 0) && (*crypt)->ops->set_key && | ||
3576 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
3577 | param->u.crypt.key_len, param->u.crypt.seq, | ||
3578 | (*crypt)->priv) < 0) { | ||
3579 | printk(KERN_DEBUG "%s: key setting failed\n", | ||
3580 | local->dev->name); | ||
3581 | param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; | ||
3582 | ret = -EINVAL; | ||
3583 | goto done; | ||
3584 | } | ||
3585 | |||
3586 | if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { | ||
3587 | if (!sta_ptr) | ||
3588 | local->tx_keyidx = param->u.crypt.idx; | ||
3589 | else if (param->u.crypt.idx) { | ||
3590 | printk(KERN_DEBUG "%s: TX key idx setting failed\n", | ||
3591 | local->dev->name); | ||
3592 | param->u.crypt.err = | ||
3593 | HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED; | ||
3594 | ret = -EINVAL; | ||
3595 | goto done; | ||
3596 | } | ||
3597 | } | ||
3598 | |||
3599 | done: | ||
3600 | if (sta_ptr) | ||
3601 | hostap_handle_sta_release(sta_ptr); | ||
3602 | |||
3603 | /* Do not reset port0 if card is in Managed mode since resetting will | ||
3604 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3605 | * with IEEE 802.1X. Prism2 documentation seem to require port reset | ||
3606 | * after WEP configuration. However, keys are apparently changed at | ||
3607 | * least in Managed mode. */ | ||
3608 | if (ret == 0 && | ||
3609 | (hostap_set_encryption(local) || | ||
3610 | (local->iw_mode != IW_MODE_INFRA && | ||
3611 | local->func->reset_port(local->dev)))) { | ||
3612 | param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED; | ||
3613 | return -EINVAL; | ||
3614 | } | ||
3615 | |||
3616 | return ret; | ||
3617 | } | ||
3618 | |||
3619 | |||
3620 | static int prism2_ioctl_get_encryption(local_info_t *local, | ||
3621 | struct prism2_hostapd_param *param, | ||
3622 | int param_len) | ||
3623 | { | ||
3624 | struct ieee80211_crypt_data **crypt; | ||
3625 | void *sta_ptr; | ||
3626 | int max_key_len; | ||
3627 | |||
3628 | param->u.crypt.err = 0; | ||
3629 | |||
3630 | max_key_len = param_len - | ||
3631 | (int) ((char *) param->u.crypt.key - (char *) param); | ||
3632 | if (max_key_len < 0) | ||
3633 | return -EINVAL; | ||
3634 | |||
3635 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3636 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3637 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3638 | sta_ptr = NULL; | ||
3639 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3640 | param->u.crypt.idx = local->tx_keyidx; | ||
3641 | crypt = &local->crypt[param->u.crypt.idx]; | ||
3642 | } else { | ||
3643 | param->u.crypt.idx = 0; | ||
3644 | sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, | ||
3645 | &crypt); | ||
3646 | |||
3647 | if (sta_ptr == NULL) { | ||
3648 | param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; | ||
3649 | return -EINVAL; | ||
3650 | } | ||
3651 | } | ||
3652 | |||
3653 | if (*crypt == NULL || (*crypt)->ops == NULL) { | ||
3654 | memcpy(param->u.crypt.alg, "none", 5); | ||
3655 | param->u.crypt.key_len = 0; | ||
3656 | param->u.crypt.idx = 0xff; | ||
3657 | } else { | ||
3658 | strncpy(param->u.crypt.alg, (*crypt)->ops->name, | ||
3659 | HOSTAP_CRYPT_ALG_NAME_LEN); | ||
3660 | param->u.crypt.key_len = 0; | ||
3661 | |||
3662 | memset(param->u.crypt.seq, 0, 8); | ||
3663 | if ((*crypt)->ops->get_key) { | ||
3664 | param->u.crypt.key_len = | ||
3665 | (*crypt)->ops->get_key(param->u.crypt.key, | ||
3666 | max_key_len, | ||
3667 | param->u.crypt.seq, | ||
3668 | (*crypt)->priv); | ||
3669 | } | ||
3670 | } | ||
3671 | |||
3672 | if (sta_ptr) | ||
3673 | hostap_handle_sta_release(sta_ptr); | ||
3674 | |||
3675 | return 0; | ||
3676 | } | ||
3677 | |||
3678 | |||
3679 | static int prism2_ioctl_get_rid(local_info_t *local, | ||
3680 | struct prism2_hostapd_param *param, | ||
3681 | int param_len) | ||
3682 | { | ||
3683 | int max_len, res; | ||
3684 | |||
3685 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3686 | if (max_len < 0) | ||
3687 | return -EINVAL; | ||
3688 | |||
3689 | res = local->func->get_rid(local->dev, param->u.rid.rid, | ||
3690 | param->u.rid.data, param->u.rid.len, 0); | ||
3691 | if (res >= 0) { | ||
3692 | param->u.rid.len = res; | ||
3693 | return 0; | ||
3694 | } | ||
3695 | |||
3696 | return res; | ||
3697 | } | ||
3698 | |||
3699 | |||
3700 | static int prism2_ioctl_set_rid(local_info_t *local, | ||
3701 | struct prism2_hostapd_param *param, | ||
3702 | int param_len) | ||
3703 | { | ||
3704 | int max_len; | ||
3705 | |||
3706 | max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN; | ||
3707 | if (max_len < 0 || max_len < param->u.rid.len) | ||
3708 | return -EINVAL; | ||
3709 | |||
3710 | return local->func->set_rid(local->dev, param->u.rid.rid, | ||
3711 | param->u.rid.data, param->u.rid.len); | ||
3712 | } | ||
3713 | |||
3714 | |||
3715 | static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, | ||
3716 | struct prism2_hostapd_param *param, | ||
3717 | int param_len) | ||
3718 | { | ||
3719 | printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", | ||
3720 | local->dev->name, MAC2STR(param->sta_addr)); | ||
3721 | memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); | ||
3722 | return 0; | ||
3723 | } | ||
3724 | |||
3725 | |||
3726 | static int prism2_ioctl_siwgenie(struct net_device *dev, | ||
3727 | struct iw_request_info *info, | ||
3728 | struct iw_point *data, char *extra) | ||
3729 | { | ||
3730 | return prism2_set_genericelement(dev, extra, data->length); | ||
3731 | } | ||
3732 | |||
3733 | |||
3734 | static int prism2_ioctl_giwgenie(struct net_device *dev, | ||
3735 | struct iw_request_info *info, | ||
3736 | struct iw_point *data, char *extra) | ||
3737 | { | ||
3738 | struct hostap_interface *iface = dev->priv; | ||
3739 | local_info_t *local = iface->local; | ||
3740 | int len = local->generic_elem_len - 2; | ||
3741 | |||
3742 | if (len <= 0 || local->generic_elem == NULL) { | ||
3743 | data->length = 0; | ||
3744 | return 0; | ||
3745 | } | ||
3746 | |||
3747 | if (data->length < len) | ||
3748 | return -E2BIG; | ||
3749 | |||
3750 | data->length = len; | ||
3751 | memcpy(extra, local->generic_elem + 2, len); | ||
3752 | |||
3753 | return 0; | ||
3754 | } | ||
3755 | |||
3756 | |||
3757 | static int prism2_ioctl_set_generic_element(local_info_t *local, | ||
3758 | struct prism2_hostapd_param *param, | ||
3759 | int param_len) | ||
3760 | { | ||
3761 | int max_len, len; | ||
3762 | |||
3763 | len = param->u.generic_elem.len; | ||
3764 | max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; | ||
3765 | if (max_len < 0 || max_len < len) | ||
3766 | return -EINVAL; | ||
3767 | |||
3768 | return prism2_set_genericelement(local->dev, | ||
3769 | param->u.generic_elem.data, len); | ||
3770 | } | ||
3771 | |||
3772 | |||
3773 | static int prism2_ioctl_siwmlme(struct net_device *dev, | ||
3774 | struct iw_request_info *info, | ||
3775 | struct iw_point *data, char *extra) | ||
3776 | { | ||
3777 | struct hostap_interface *iface = dev->priv; | ||
3778 | local_info_t *local = iface->local; | ||
3779 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | ||
3780 | u16 reason; | ||
3781 | |||
3782 | reason = cpu_to_le16(mlme->reason_code); | ||
3783 | |||
3784 | switch (mlme->cmd) { | ||
3785 | case IW_MLME_DEAUTH: | ||
3786 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3787 | IEEE80211_STYPE_DEAUTH, | ||
3788 | (u8 *) &reason, 2); | ||
3789 | case IW_MLME_DISASSOC: | ||
3790 | return prism2_sta_send_mgmt(local, mlme->addr.sa_data, | ||
3791 | IEEE80211_STYPE_DISASSOC, | ||
3792 | (u8 *) &reason, 2); | ||
3793 | default: | ||
3794 | return -EOPNOTSUPP; | ||
3795 | } | ||
3796 | } | ||
3797 | |||
3798 | |||
3799 | static int prism2_ioctl_mlme(local_info_t *local, | ||
3800 | struct prism2_hostapd_param *param) | ||
3801 | { | ||
3802 | u16 reason; | ||
3803 | |||
3804 | reason = cpu_to_le16(param->u.mlme.reason_code); | ||
3805 | switch (param->u.mlme.cmd) { | ||
3806 | case MLME_STA_DEAUTH: | ||
3807 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3808 | IEEE80211_STYPE_DEAUTH, | ||
3809 | (u8 *) &reason, 2); | ||
3810 | case MLME_STA_DISASSOC: | ||
3811 | return prism2_sta_send_mgmt(local, param->sta_addr, | ||
3812 | IEEE80211_STYPE_DISASSOC, | ||
3813 | (u8 *) &reason, 2); | ||
3814 | default: | ||
3815 | return -EOPNOTSUPP; | ||
3816 | } | ||
3817 | } | ||
3818 | |||
3819 | |||
3820 | static int prism2_ioctl_scan_req(local_info_t *local, | ||
3821 | struct prism2_hostapd_param *param) | ||
3822 | { | ||
3823 | #ifndef PRISM2_NO_STATION_MODES | ||
3824 | if ((local->iw_mode != IW_MODE_INFRA && | ||
3825 | local->iw_mode != IW_MODE_ADHOC) || | ||
3826 | (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))) | ||
3827 | return -EOPNOTSUPP; | ||
3828 | |||
3829 | if (!local->dev_enabled) | ||
3830 | return -ENETDOWN; | ||
3831 | |||
3832 | return prism2_request_hostscan(local->dev, param->u.scan_req.ssid, | ||
3833 | param->u.scan_req.ssid_len); | ||
3834 | #else /* PRISM2_NO_STATION_MODES */ | ||
3835 | return -EOPNOTSUPP; | ||
3836 | #endif /* PRISM2_NO_STATION_MODES */ | ||
3837 | } | ||
3838 | |||
3839 | |||
3840 | static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) | ||
3841 | { | ||
3842 | struct prism2_hostapd_param *param; | ||
3843 | int ret = 0; | ||
3844 | int ap_ioctl = 0; | ||
3845 | |||
3846 | if (p->length < sizeof(struct prism2_hostapd_param) || | ||
3847 | p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) | ||
3848 | return -EINVAL; | ||
3849 | |||
3850 | param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); | ||
3851 | if (param == NULL) | ||
3852 | return -ENOMEM; | ||
3853 | |||
3854 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3855 | ret = -EFAULT; | ||
3856 | goto out; | ||
3857 | } | ||
3858 | |||
3859 | switch (param->cmd) { | ||
3860 | case PRISM2_SET_ENCRYPTION: | ||
3861 | ret = prism2_ioctl_set_encryption(local, param, p->length); | ||
3862 | break; | ||
3863 | case PRISM2_GET_ENCRYPTION: | ||
3864 | ret = prism2_ioctl_get_encryption(local, param, p->length); | ||
3865 | break; | ||
3866 | case PRISM2_HOSTAPD_GET_RID: | ||
3867 | ret = prism2_ioctl_get_rid(local, param, p->length); | ||
3868 | break; | ||
3869 | case PRISM2_HOSTAPD_SET_RID: | ||
3870 | ret = prism2_ioctl_set_rid(local, param, p->length); | ||
3871 | break; | ||
3872 | case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: | ||
3873 | ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); | ||
3874 | break; | ||
3875 | case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: | ||
3876 | ret = prism2_ioctl_set_generic_element(local, param, | ||
3877 | p->length); | ||
3878 | break; | ||
3879 | case PRISM2_HOSTAPD_MLME: | ||
3880 | ret = prism2_ioctl_mlme(local, param); | ||
3881 | break; | ||
3882 | case PRISM2_HOSTAPD_SCAN_REQ: | ||
3883 | ret = prism2_ioctl_scan_req(local, param); | ||
3884 | break; | ||
3885 | default: | ||
3886 | ret = prism2_hostapd(local->ap, param); | ||
3887 | ap_ioctl = 1; | ||
3888 | break; | ||
3889 | } | ||
3890 | |||
3891 | if (ret == 1 || !ap_ioctl) { | ||
3892 | if (copy_to_user(p->pointer, param, p->length)) { | ||
3893 | ret = -EFAULT; | ||
3894 | goto out; | ||
3895 | } else if (ap_ioctl) | ||
3896 | ret = 0; | ||
3897 | } | ||
3898 | |||
3899 | out: | ||
3900 | if (param != NULL) | ||
3901 | kfree(param); | ||
3902 | |||
3903 | return ret; | ||
3904 | } | ||
3905 | |||
3906 | |||
3907 | static void prism2_get_drvinfo(struct net_device *dev, | ||
3908 | struct ethtool_drvinfo *info) | ||
3909 | { | ||
3910 | struct hostap_interface *iface; | ||
3911 | local_info_t *local; | ||
3912 | |||
3913 | iface = netdev_priv(dev); | ||
3914 | local = iface->local; | ||
3915 | |||
3916 | strncpy(info->driver, "hostap", sizeof(info->driver) - 1); | ||
3917 | strncpy(info->version, PRISM2_VERSION, | ||
3918 | sizeof(info->version) - 1); | ||
3919 | snprintf(info->fw_version, sizeof(info->fw_version) - 1, | ||
3920 | "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff, | ||
3921 | (local->sta_fw_ver >> 8) & 0xff, | ||
3922 | local->sta_fw_ver & 0xff); | ||
3923 | } | ||
3924 | |||
3925 | static struct ethtool_ops prism2_ethtool_ops = { | ||
3926 | .get_drvinfo = prism2_get_drvinfo | ||
3927 | }; | ||
3928 | |||
3929 | |||
3930 | /* Structures to export the Wireless Handlers */ | ||
3931 | |||
3932 | static const iw_handler prism2_handler[] = | ||
3933 | { | ||
3934 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
3935 | (iw_handler) prism2_get_name, /* SIOCGIWNAME */ | ||
3936 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
3937 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
3938 | (iw_handler) prism2_ioctl_siwfreq, /* SIOCSIWFREQ */ | ||
3939 | (iw_handler) prism2_ioctl_giwfreq, /* SIOCGIWFREQ */ | ||
3940 | (iw_handler) prism2_ioctl_siwmode, /* SIOCSIWMODE */ | ||
3941 | (iw_handler) prism2_ioctl_giwmode, /* SIOCGIWMODE */ | ||
3942 | (iw_handler) prism2_ioctl_siwsens, /* SIOCSIWSENS */ | ||
3943 | (iw_handler) prism2_ioctl_giwsens, /* SIOCGIWSENS */ | ||
3944 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | ||
3945 | (iw_handler) prism2_ioctl_giwrange, /* SIOCGIWRANGE */ | ||
3946 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | ||
3947 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | ||
3948 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | ||
3949 | (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ | ||
3950 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
3951 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
3952 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
3953 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
3954 | (iw_handler) prism2_ioctl_siwap, /* SIOCSIWAP */ | ||
3955 | (iw_handler) prism2_ioctl_giwap, /* SIOCGIWAP */ | ||
3956 | (iw_handler) prism2_ioctl_siwmlme, /* SIOCSIWMLME */ | ||
3957 | (iw_handler) prism2_ioctl_giwaplist, /* SIOCGIWAPLIST */ | ||
3958 | (iw_handler) prism2_ioctl_siwscan, /* SIOCSIWSCAN */ | ||
3959 | (iw_handler) prism2_ioctl_giwscan, /* SIOCGIWSCAN */ | ||
3960 | (iw_handler) prism2_ioctl_siwessid, /* SIOCSIWESSID */ | ||
3961 | (iw_handler) prism2_ioctl_giwessid, /* SIOCGIWESSID */ | ||
3962 | (iw_handler) prism2_ioctl_siwnickn, /* SIOCSIWNICKN */ | ||
3963 | (iw_handler) prism2_ioctl_giwnickn, /* SIOCGIWNICKN */ | ||
3964 | (iw_handler) NULL, /* -- hole -- */ | ||
3965 | (iw_handler) NULL, /* -- hole -- */ | ||
3966 | (iw_handler) prism2_ioctl_siwrate, /* SIOCSIWRATE */ | ||
3967 | (iw_handler) prism2_ioctl_giwrate, /* SIOCGIWRATE */ | ||
3968 | (iw_handler) prism2_ioctl_siwrts, /* SIOCSIWRTS */ | ||
3969 | (iw_handler) prism2_ioctl_giwrts, /* SIOCGIWRTS */ | ||
3970 | (iw_handler) prism2_ioctl_siwfrag, /* SIOCSIWFRAG */ | ||
3971 | (iw_handler) prism2_ioctl_giwfrag, /* SIOCGIWFRAG */ | ||
3972 | (iw_handler) prism2_ioctl_siwtxpow, /* SIOCSIWTXPOW */ | ||
3973 | (iw_handler) prism2_ioctl_giwtxpow, /* SIOCGIWTXPOW */ | ||
3974 | (iw_handler) prism2_ioctl_siwretry, /* SIOCSIWRETRY */ | ||
3975 | (iw_handler) prism2_ioctl_giwretry, /* SIOCGIWRETRY */ | ||
3976 | (iw_handler) prism2_ioctl_siwencode, /* SIOCSIWENCODE */ | ||
3977 | (iw_handler) prism2_ioctl_giwencode, /* SIOCGIWENCODE */ | ||
3978 | (iw_handler) prism2_ioctl_siwpower, /* SIOCSIWPOWER */ | ||
3979 | (iw_handler) prism2_ioctl_giwpower, /* SIOCGIWPOWER */ | ||
3980 | (iw_handler) NULL, /* -- hole -- */ | ||
3981 | (iw_handler) NULL, /* -- hole -- */ | ||
3982 | (iw_handler) prism2_ioctl_siwgenie, /* SIOCSIWGENIE */ | ||
3983 | (iw_handler) prism2_ioctl_giwgenie, /* SIOCGIWGENIE */ | ||
3984 | (iw_handler) prism2_ioctl_siwauth, /* SIOCSIWAUTH */ | ||
3985 | (iw_handler) prism2_ioctl_giwauth, /* SIOCGIWAUTH */ | ||
3986 | (iw_handler) prism2_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ | ||
3987 | (iw_handler) prism2_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ | ||
3988 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
3989 | (iw_handler) NULL, /* -- hole -- */ | ||
3990 | }; | ||
3991 | |||
3992 | static const iw_handler prism2_private_handler[] = | ||
3993 | { /* SIOCIWFIRSTPRIV + */ | ||
3994 | (iw_handler) prism2_ioctl_priv_prism2_param, /* 0 */ | ||
3995 | (iw_handler) prism2_ioctl_priv_get_prism2_param, /* 1 */ | ||
3996 | (iw_handler) prism2_ioctl_priv_writemif, /* 2 */ | ||
3997 | (iw_handler) prism2_ioctl_priv_readmif, /* 3 */ | ||
3998 | }; | ||
3999 | |||
4000 | static const struct iw_handler_def hostap_iw_handler_def = | ||
4001 | { | ||
4002 | .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), | ||
4003 | .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), | ||
4004 | .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), | ||
4005 | .standard = (iw_handler *) prism2_handler, | ||
4006 | .private = (iw_handler *) prism2_private_handler, | ||
4007 | .private_args = (struct iw_priv_args *) prism2_priv, | ||
4008 | .get_wireless_stats = hostap_get_wireless_stats, | ||
4009 | }; | ||
4010 | |||
4011 | |||
4012 | int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
4013 | { | ||
4014 | struct iwreq *wrq = (struct iwreq *) ifr; | ||
4015 | struct hostap_interface *iface; | ||
4016 | local_info_t *local; | ||
4017 | int ret = 0; | ||
4018 | |||
4019 | iface = netdev_priv(dev); | ||
4020 | local = iface->local; | ||
4021 | |||
4022 | switch (cmd) { | ||
4023 | /* Private ioctls (iwpriv) that have not yet been converted | ||
4024 | * into new wireless extensions API */ | ||
4025 | |||
4026 | case PRISM2_IOCTL_INQUIRE: | ||
4027 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4028 | else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name); | ||
4029 | break; | ||
4030 | |||
4031 | case PRISM2_IOCTL_MONITOR: | ||
4032 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4033 | else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name); | ||
4034 | break; | ||
4035 | |||
4036 | case PRISM2_IOCTL_RESET: | ||
4037 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4038 | else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name); | ||
4039 | break; | ||
4040 | |||
4041 | case PRISM2_IOCTL_WDS_ADD: | ||
4042 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4043 | else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1); | ||
4044 | break; | ||
4045 | |||
4046 | case PRISM2_IOCTL_WDS_DEL: | ||
4047 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4048 | else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0); | ||
4049 | break; | ||
4050 | |||
4051 | case PRISM2_IOCTL_SET_RID_WORD: | ||
4052 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4053 | else ret = prism2_ioctl_priv_set_rid_word(dev, | ||
4054 | (int *) wrq->u.name); | ||
4055 | break; | ||
4056 | |||
4057 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | ||
4058 | case PRISM2_IOCTL_MACCMD: | ||
4059 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4060 | else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name); | ||
4061 | break; | ||
4062 | |||
4063 | case PRISM2_IOCTL_ADDMAC: | ||
4064 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4065 | else ret = ap_control_add_mac(&local->ap->mac_restrictions, | ||
4066 | wrq->u.ap_addr.sa_data); | ||
4067 | break; | ||
4068 | case PRISM2_IOCTL_DELMAC: | ||
4069 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4070 | else ret = ap_control_del_mac(&local->ap->mac_restrictions, | ||
4071 | wrq->u.ap_addr.sa_data); | ||
4072 | break; | ||
4073 | case PRISM2_IOCTL_KICKMAC: | ||
4074 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4075 | else ret = ap_control_kick_mac(local->ap, local->dev, | ||
4076 | wrq->u.ap_addr.sa_data); | ||
4077 | break; | ||
4078 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | ||
4079 | |||
4080 | |||
4081 | /* Private ioctls that are not used with iwpriv; | ||
4082 | * in SIOCDEVPRIVATE range */ | ||
4083 | |||
4084 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
4085 | case PRISM2_IOCTL_DOWNLOAD: | ||
4086 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4087 | else ret = prism2_ioctl_priv_download(local, &wrq->u.data); | ||
4088 | break; | ||
4089 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
4090 | |||
4091 | case PRISM2_IOCTL_HOSTAPD: | ||
4092 | if (!capable(CAP_NET_ADMIN)) ret = -EPERM; | ||
4093 | else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data); | ||
4094 | break; | ||
4095 | |||
4096 | default: | ||
4097 | ret = -EOPNOTSUPP; | ||
4098 | break; | ||
4099 | } | ||
4100 | |||
4101 | return ret; | ||
4102 | } | ||
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c new file mode 100644 index 000000000000..4f567ef6178d --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_pci.c | |||
@@ -0,0 +1,473 @@ | |||
1 | #define PRISM2_PCI | ||
2 | |||
3 | /* Host AP driver's support for Intersil Prism2.5 PCI cards is based on | ||
4 | * driver patches from Reyk Floeter <reyk@vantronix.net> and | ||
5 | * Andy Warner <andyw@pobox.com> */ | ||
6 | |||
7 | #include <linux/config.h> | ||
8 | #include <linux/version.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/if.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include <linux/workqueue.h> | ||
15 | #include <linux/wireless.h> | ||
16 | #include <net/iw_handler.h> | ||
17 | |||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | #include "hostap_wlan.h" | ||
23 | |||
24 | |||
25 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
26 | static char *dev_info = "hostap_pci"; | ||
27 | |||
28 | |||
29 | MODULE_AUTHOR("Jouni Malinen"); | ||
30 | MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN " | ||
31 | "PCI cards."); | ||
32 | MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_VERSION(PRISM2_VERSION); | ||
35 | |||
36 | |||
37 | /* struct local_info::hw_priv */ | ||
38 | struct hostap_pci_priv { | ||
39 | void __iomem *mem_start; | ||
40 | }; | ||
41 | |||
42 | |||
43 | /* FIX: do we need mb/wmb/rmb with memory operations? */ | ||
44 | |||
45 | |||
46 | static struct pci_device_id prism2_pci_id_table[] __devinitdata = { | ||
47 | /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */ | ||
48 | { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID }, | ||
49 | /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */ | ||
50 | { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID }, | ||
51 | /* Samsung MagicLAN SWL-2210P */ | ||
52 | { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID }, | ||
53 | { 0 } | ||
54 | }; | ||
55 | |||
56 | |||
57 | #ifdef PRISM2_IO_DEBUG | ||
58 | |||
59 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
60 | { | ||
61 | struct hostap_interface *iface; | ||
62 | local_info_t *local; | ||
63 | unsigned long flags; | ||
64 | |||
65 | iface = netdev_priv(dev); | ||
66 | local = iface->local; | ||
67 | |||
68 | spin_lock_irqsave(&local->lock, flags); | ||
69 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
70 | writeb(v, hw_priv->mem_start + a); | ||
71 | spin_unlock_irqrestore(&local->lock, flags); | ||
72 | } | ||
73 | |||
74 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
75 | { | ||
76 | struct hostap_interface *iface; | ||
77 | local_info_t *local; | ||
78 | unsigned long flags; | ||
79 | u8 v; | ||
80 | |||
81 | iface = netdev_priv(dev); | ||
82 | local = iface->local; | ||
83 | |||
84 | spin_lock_irqsave(&local->lock, flags); | ||
85 | v = readb(hw_priv->mem_start + a); | ||
86 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
87 | spin_unlock_irqrestore(&local->lock, flags); | ||
88 | return v; | ||
89 | } | ||
90 | |||
91 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
92 | { | ||
93 | struct hostap_interface *iface; | ||
94 | local_info_t *local; | ||
95 | unsigned long flags; | ||
96 | |||
97 | iface = netdev_priv(dev); | ||
98 | local = iface->local; | ||
99 | |||
100 | spin_lock_irqsave(&local->lock, flags); | ||
101 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
102 | writew(v, hw_priv->mem_start + a); | ||
103 | spin_unlock_irqrestore(&local->lock, flags); | ||
104 | } | ||
105 | |||
106 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
107 | { | ||
108 | struct hostap_interface *iface; | ||
109 | local_info_t *local; | ||
110 | unsigned long flags; | ||
111 | u16 v; | ||
112 | |||
113 | iface = netdev_priv(dev); | ||
114 | local = iface->local; | ||
115 | |||
116 | spin_lock_irqsave(&local->lock, flags); | ||
117 | v = readw(hw_priv->mem_start + a); | ||
118 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
119 | spin_unlock_irqrestore(&local->lock, flags); | ||
120 | return v; | ||
121 | } | ||
122 | |||
123 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
124 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
125 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
126 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
127 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v))) | ||
128 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a))) | ||
129 | |||
130 | #else /* PRISM2_IO_DEBUG */ | ||
131 | |||
132 | static inline void hfa384x_outb(struct net_device *dev, int a, u8 v) | ||
133 | { | ||
134 | struct hostap_interface *iface; | ||
135 | struct hostap_pci_priv *hw_priv; | ||
136 | iface = netdev_priv(dev); | ||
137 | hw_priv = iface->local->hw_priv; | ||
138 | writeb(v, hw_priv->mem_start + a); | ||
139 | } | ||
140 | |||
141 | static inline u8 hfa384x_inb(struct net_device *dev, int a) | ||
142 | { | ||
143 | struct hostap_interface *iface; | ||
144 | struct hostap_pci_priv *hw_priv; | ||
145 | iface = netdev_priv(dev); | ||
146 | hw_priv = iface->local->hw_priv; | ||
147 | return readb(hw_priv->mem_start + a); | ||
148 | } | ||
149 | |||
150 | static inline void hfa384x_outw(struct net_device *dev, int a, u16 v) | ||
151 | { | ||
152 | struct hostap_interface *iface; | ||
153 | struct hostap_pci_priv *hw_priv; | ||
154 | iface = netdev_priv(dev); | ||
155 | hw_priv = iface->local->hw_priv; | ||
156 | writew(v, hw_priv->mem_start + a); | ||
157 | } | ||
158 | |||
159 | static inline u16 hfa384x_inw(struct net_device *dev, int a) | ||
160 | { | ||
161 | struct hostap_interface *iface; | ||
162 | struct hostap_pci_priv *hw_priv; | ||
163 | iface = netdev_priv(dev); | ||
164 | hw_priv = iface->local->hw_priv; | ||
165 | return readw(hw_priv->mem_start + a); | ||
166 | } | ||
167 | |||
168 | #define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v)) | ||
169 | #define HFA384X_INB(a) hfa384x_inb(dev, (a)) | ||
170 | #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) | ||
171 | #define HFA384X_INW(a) hfa384x_inw(dev, (a)) | ||
172 | #define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v))) | ||
173 | #define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a))) | ||
174 | |||
175 | #endif /* PRISM2_IO_DEBUG */ | ||
176 | |||
177 | |||
178 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
179 | int len) | ||
180 | { | ||
181 | u16 d_off; | ||
182 | u16 *pos; | ||
183 | |||
184 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
185 | pos = (u16 *) buf; | ||
186 | |||
187 | for ( ; len > 1; len -= 2) | ||
188 | *pos++ = HFA384X_INW_DATA(d_off); | ||
189 | |||
190 | if (len & 1) | ||
191 | *((char *) pos) = HFA384X_INB(d_off); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
198 | { | ||
199 | u16 d_off; | ||
200 | u16 *pos; | ||
201 | |||
202 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
203 | pos = (u16 *) buf; | ||
204 | |||
205 | for ( ; len > 1; len -= 2) | ||
206 | HFA384X_OUTW_DATA(*pos++, d_off); | ||
207 | |||
208 | if (len & 1) | ||
209 | HFA384X_OUTB(*((char *) pos), d_off); | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* FIX: This might change at some point.. */ | ||
216 | #include "hostap_hw.c" | ||
217 | |||
218 | static void prism2_pci_cor_sreset(local_info_t *local) | ||
219 | { | ||
220 | struct net_device *dev = local->dev; | ||
221 | u16 reg; | ||
222 | |||
223 | reg = HFA384X_INB(HFA384X_PCICOR_OFF); | ||
224 | printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg); | ||
225 | |||
226 | /* linux-wlan-ng uses extremely long hold and settle times for | ||
227 | * COR sreset. A comment in the driver code mentions that the long | ||
228 | * delays appear to be necessary. However, at least IBM 22P6901 seems | ||
229 | * to work fine with shorter delays. | ||
230 | * | ||
231 | * Longer delays can be configured by uncommenting following line: */ | ||
232 | /* #define PRISM2_PCI_USE_LONG_DELAYS */ | ||
233 | |||
234 | #ifdef PRISM2_PCI_USE_LONG_DELAYS | ||
235 | int i; | ||
236 | |||
237 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
238 | mdelay(250); | ||
239 | |||
240 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
241 | mdelay(500); | ||
242 | |||
243 | /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ | ||
244 | i = 2000000 / 10; | ||
245 | while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) | ||
246 | udelay(10); | ||
247 | |||
248 | #else /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
249 | |||
250 | HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF); | ||
251 | mdelay(2); | ||
252 | HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF); | ||
253 | mdelay(2); | ||
254 | |||
255 | #endif /* PRISM2_PCI_USE_LONG_DELAYS */ | ||
256 | |||
257 | if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) { | ||
258 | printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void prism2_pci_genesis_reset(local_info_t *local, int hcr) | ||
264 | { | ||
265 | struct net_device *dev = local->dev; | ||
266 | |||
267 | HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF); | ||
268 | mdelay(10); | ||
269 | HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF); | ||
270 | mdelay(10); | ||
271 | HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF); | ||
272 | mdelay(10); | ||
273 | } | ||
274 | |||
275 | |||
276 | static struct prism2_helper_functions prism2_pci_funcs = | ||
277 | { | ||
278 | .card_present = NULL, | ||
279 | .cor_sreset = prism2_pci_cor_sreset, | ||
280 | .dev_open = NULL, | ||
281 | .dev_close = NULL, | ||
282 | .genesis_reset = prism2_pci_genesis_reset, | ||
283 | .hw_type = HOSTAP_HW_PCI, | ||
284 | }; | ||
285 | |||
286 | |||
287 | static int prism2_pci_probe(struct pci_dev *pdev, | ||
288 | const struct pci_device_id *id) | ||
289 | { | ||
290 | unsigned long phymem; | ||
291 | void __iomem *mem = NULL; | ||
292 | local_info_t *local = NULL; | ||
293 | struct net_device *dev = NULL; | ||
294 | static int cards_found /* = 0 */; | ||
295 | int irq_registered = 0; | ||
296 | struct hostap_interface *iface; | ||
297 | struct hostap_pci_priv *hw_priv; | ||
298 | |||
299 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
300 | if (hw_priv == NULL) | ||
301 | return -ENOMEM; | ||
302 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
303 | |||
304 | if (pci_enable_device(pdev)) | ||
305 | return -EIO; | ||
306 | |||
307 | phymem = pci_resource_start(pdev, 0); | ||
308 | |||
309 | if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) { | ||
310 | printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n"); | ||
311 | goto err_out_disable; | ||
312 | } | ||
313 | |||
314 | mem = ioremap(phymem, pci_resource_len(pdev, 0)); | ||
315 | if (mem == NULL) { | ||
316 | printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; | ||
317 | goto fail; | ||
318 | } | ||
319 | |||
320 | dev = prism2_init_local_data(&prism2_pci_funcs, cards_found, | ||
321 | &pdev->dev); | ||
322 | if (dev == NULL) | ||
323 | goto fail; | ||
324 | iface = netdev_priv(dev); | ||
325 | local = iface->local; | ||
326 | local->hw_priv = hw_priv; | ||
327 | cards_found++; | ||
328 | |||
329 | dev->irq = pdev->irq; | ||
330 | hw_priv->mem_start = mem; | ||
331 | |||
332 | prism2_pci_cor_sreset(local); | ||
333 | |||
334 | pci_set_drvdata(pdev, dev); | ||
335 | |||
336 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
337 | dev)) { | ||
338 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
339 | goto fail; | ||
340 | } else | ||
341 | irq_registered = 1; | ||
342 | |||
343 | if (!local->pri_only && prism2_hw_config(dev, 1)) { | ||
344 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
345 | dev_info); | ||
346 | goto fail; | ||
347 | } | ||
348 | |||
349 | printk(KERN_INFO "%s: Intersil Prism2.5 PCI: " | ||
350 | "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq); | ||
351 | |||
352 | return hostap_hw_ready(dev); | ||
353 | |||
354 | fail: | ||
355 | kfree(hw_priv); | ||
356 | |||
357 | if (irq_registered && dev) | ||
358 | free_irq(dev->irq, dev); | ||
359 | |||
360 | if (mem) | ||
361 | iounmap(mem); | ||
362 | |||
363 | release_mem_region(phymem, pci_resource_len(pdev, 0)); | ||
364 | |||
365 | err_out_disable: | ||
366 | pci_disable_device(pdev); | ||
367 | kfree(hw_priv); | ||
368 | if (local) | ||
369 | local->hw_priv = NULL; | ||
370 | prism2_free_local_data(dev); | ||
371 | |||
372 | return -ENODEV; | ||
373 | } | ||
374 | |||
375 | |||
376 | static void prism2_pci_remove(struct pci_dev *pdev) | ||
377 | { | ||
378 | struct net_device *dev; | ||
379 | struct hostap_interface *iface; | ||
380 | void __iomem *mem_start; | ||
381 | struct hostap_pci_priv *hw_priv; | ||
382 | |||
383 | dev = pci_get_drvdata(pdev); | ||
384 | iface = netdev_priv(dev); | ||
385 | hw_priv = iface->local->hw_priv; | ||
386 | |||
387 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
388 | prism2_pci_cor_sreset(iface->local); | ||
389 | hfa384x_disable_interrupts(dev); | ||
390 | |||
391 | if (dev->irq) | ||
392 | free_irq(dev->irq, dev); | ||
393 | |||
394 | mem_start = hw_priv->mem_start; | ||
395 | kfree(hw_priv); | ||
396 | iface->local->hw_priv = NULL; | ||
397 | prism2_free_local_data(dev); | ||
398 | |||
399 | iounmap(mem_start); | ||
400 | |||
401 | release_mem_region(pci_resource_start(pdev, 0), | ||
402 | pci_resource_len(pdev, 0)); | ||
403 | pci_disable_device(pdev); | ||
404 | } | ||
405 | |||
406 | |||
407 | #ifdef CONFIG_PM | ||
408 | static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
409 | { | ||
410 | struct net_device *dev = pci_get_drvdata(pdev); | ||
411 | |||
412 | if (netif_running(dev)) { | ||
413 | netif_stop_queue(dev); | ||
414 | netif_device_detach(dev); | ||
415 | } | ||
416 | prism2_suspend(dev); | ||
417 | pci_save_state(pdev); | ||
418 | pci_disable_device(pdev); | ||
419 | pci_set_power_state(pdev, 3); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int prism2_pci_resume(struct pci_dev *pdev) | ||
425 | { | ||
426 | struct net_device *dev = pci_get_drvdata(pdev); | ||
427 | |||
428 | pci_enable_device(pdev); | ||
429 | pci_restore_state(pdev); | ||
430 | prism2_hw_config(dev, 0); | ||
431 | if (netif_running(dev)) { | ||
432 | netif_device_attach(dev); | ||
433 | netif_start_queue(dev); | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | #endif /* CONFIG_PM */ | ||
439 | |||
440 | |||
441 | MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); | ||
442 | |||
443 | static struct pci_driver prism2_pci_drv_id = { | ||
444 | .name = "prism2_pci", | ||
445 | .id_table = prism2_pci_id_table, | ||
446 | .probe = prism2_pci_probe, | ||
447 | .remove = prism2_pci_remove, | ||
448 | #ifdef CONFIG_PM | ||
449 | .suspend = prism2_pci_suspend, | ||
450 | .resume = prism2_pci_resume, | ||
451 | #endif /* CONFIG_PM */ | ||
452 | /* Linux 2.4.6 added save_state and enable_wake that are not used here | ||
453 | */ | ||
454 | }; | ||
455 | |||
456 | |||
457 | static int __init init_prism2_pci(void) | ||
458 | { | ||
459 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
460 | |||
461 | return pci_register_driver(&prism2_pci_drv_id); | ||
462 | } | ||
463 | |||
464 | |||
465 | static void __exit exit_prism2_pci(void) | ||
466 | { | ||
467 | pci_unregister_driver(&prism2_pci_drv_id); | ||
468 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
469 | } | ||
470 | |||
471 | |||
472 | module_init(init_prism2_pci); | ||
473 | module_exit(exit_prism2_pci); | ||
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c new file mode 100644 index 000000000000..474ef83d813e --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_plx.c | |||
@@ -0,0 +1,645 @@ | |||
1 | #define PRISM2_PLX | ||
2 | |||
3 | /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is | ||
4 | * based on: | ||
5 | * - Host AP driver patch from james@madingley.org | ||
6 | * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/if.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/netdevice.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/wireless.h> | ||
19 | #include <net/iw_handler.h> | ||
20 | |||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | #include "hostap_wlan.h" | ||
26 | |||
27 | |||
28 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | ||
29 | static char *dev_info = "hostap_plx"; | ||
30 | |||
31 | |||
32 | MODULE_AUTHOR("Jouni Malinen"); | ||
33 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | ||
34 | "cards (PLX)."); | ||
35 | MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | MODULE_VERSION(PRISM2_VERSION); | ||
38 | |||
39 | |||
40 | static int ignore_cis; | ||
41 | module_param(ignore_cis, int, 0444); | ||
42 | MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS"); | ||
43 | |||
44 | |||
45 | /* struct local_info::hw_priv */ | ||
46 | struct hostap_plx_priv { | ||
47 | void __iomem *attr_mem; | ||
48 | unsigned int cor_offset; | ||
49 | }; | ||
50 | |||
51 | |||
52 | #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */ | ||
53 | #define COR_SRESET 0x80 | ||
54 | #define COR_LEVLREQ 0x40 | ||
55 | #define COR_ENABLE_FUNC 0x01 | ||
56 | /* PCI Configuration Registers */ | ||
57 | #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */ | ||
58 | /* Local Configuration Registers */ | ||
59 | #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */ | ||
60 | #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */ | ||
61 | #define PLX_CNTRL 0x50 | ||
62 | #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28) | ||
63 | |||
64 | |||
65 | #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID } | ||
66 | |||
67 | static struct pci_device_id prism2_plx_id_table[] __devinitdata = { | ||
68 | PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"), | ||
69 | PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"), | ||
70 | PLXDEV(0x126c, 0x8030, "Nortel emobility"), | ||
71 | PLXDEV(0x1385, 0x4100, "Netgear MA301"), | ||
72 | PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"), | ||
73 | PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"), | ||
74 | PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"), | ||
75 | PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"), | ||
76 | PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"), | ||
77 | PLXDEV(0x16ab, 0x1103, "Longshine 8031"), | ||
78 | PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"), | ||
79 | PLXDEV(0xec80, 0xec00, "Belkin F5D6000"), | ||
80 | { 0 } | ||
81 | }; | ||
82 | |||
83 | |||
84 | /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid | ||
85 | * is not listed here, you will need to add it here to get the driver | ||
86 | * initialized. */ | ||
87 | static struct prism2_plx_manfid { | ||
88 | u16 manfid1, manfid2; | ||
89 | } prism2_plx_known_manfids[] = { | ||
90 | { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */, | ||
91 | { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */, | ||
92 | { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */, | ||
93 | { 0x0126, 0x8000 } /* Proxim RangeLAN */, | ||
94 | { 0x0138, 0x0002 } /* Compaq WL100 */, | ||
95 | { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */, | ||
96 | { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */, | ||
97 | { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */, | ||
98 | { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */, | ||
99 | { 0x028a, 0x0002 } /* D-Link DRC-650 */, | ||
100 | { 0x0250, 0x0002 } /* Samsung SWL2000-N */, | ||
101 | { 0xc250, 0x0002 } /* EMTAC A2424i */, | ||
102 | { 0xd601, 0x0002 } /* Z-Com XI300 */, | ||
103 | { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */, | ||
104 | { 0, 0} | ||
105 | }; | ||
106 | |||
107 | |||
108 | #ifdef PRISM2_IO_DEBUG | ||
109 | |||
110 | static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | ||
111 | { | ||
112 | struct hostap_interface *iface; | ||
113 | local_info_t *local; | ||
114 | unsigned long flags; | ||
115 | |||
116 | iface = netdev_priv(dev); | ||
117 | local = iface->local; | ||
118 | |||
119 | spin_lock_irqsave(&local->lock, flags); | ||
120 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | ||
121 | outb(v, dev->base_addr + a); | ||
122 | spin_unlock_irqrestore(&local->lock, flags); | ||
123 | } | ||
124 | |||
125 | static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | ||
126 | { | ||
127 | struct hostap_interface *iface; | ||
128 | local_info_t *local; | ||
129 | unsigned long flags; | ||
130 | u8 v; | ||
131 | |||
132 | iface = netdev_priv(dev); | ||
133 | local = iface->local; | ||
134 | |||
135 | spin_lock_irqsave(&local->lock, flags); | ||
136 | v = inb(dev->base_addr + a); | ||
137 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | ||
138 | spin_unlock_irqrestore(&local->lock, flags); | ||
139 | return v; | ||
140 | } | ||
141 | |||
142 | static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | ||
143 | { | ||
144 | struct hostap_interface *iface; | ||
145 | local_info_t *local; | ||
146 | unsigned long flags; | ||
147 | |||
148 | iface = netdev_priv(dev); | ||
149 | local = iface->local; | ||
150 | |||
151 | spin_lock_irqsave(&local->lock, flags); | ||
152 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | ||
153 | outw(v, dev->base_addr + a); | ||
154 | spin_unlock_irqrestore(&local->lock, flags); | ||
155 | } | ||
156 | |||
157 | static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | ||
158 | { | ||
159 | struct hostap_interface *iface; | ||
160 | local_info_t *local; | ||
161 | unsigned long flags; | ||
162 | u16 v; | ||
163 | |||
164 | iface = netdev_priv(dev); | ||
165 | local = iface->local; | ||
166 | |||
167 | spin_lock_irqsave(&local->lock, flags); | ||
168 | v = inw(dev->base_addr + a); | ||
169 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | ||
170 | spin_unlock_irqrestore(&local->lock, flags); | ||
171 | return v; | ||
172 | } | ||
173 | |||
174 | static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | ||
175 | u8 *buf, int wc) | ||
176 | { | ||
177 | struct hostap_interface *iface; | ||
178 | local_info_t *local; | ||
179 | unsigned long flags; | ||
180 | |||
181 | iface = netdev_priv(dev); | ||
182 | local = iface->local; | ||
183 | |||
184 | spin_lock_irqsave(&local->lock, flags); | ||
185 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | ||
186 | outsw(dev->base_addr + a, buf, wc); | ||
187 | spin_unlock_irqrestore(&local->lock, flags); | ||
188 | } | ||
189 | |||
190 | static inline void hfa384x_insw_debug(struct net_device *dev, int a, | ||
191 | u8 *buf, int wc) | ||
192 | { | ||
193 | struct hostap_interface *iface; | ||
194 | local_info_t *local; | ||
195 | unsigned long flags; | ||
196 | |||
197 | iface = netdev_priv(dev); | ||
198 | local = iface->local; | ||
199 | |||
200 | spin_lock_irqsave(&local->lock, flags); | ||
201 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | ||
202 | insw(dev->base_addr + a, buf, wc); | ||
203 | spin_unlock_irqrestore(&local->lock, flags); | ||
204 | } | ||
205 | |||
206 | #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | ||
207 | #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | ||
208 | #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | ||
209 | #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | ||
210 | #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | ||
211 | #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | ||
212 | |||
213 | #else /* PRISM2_IO_DEBUG */ | ||
214 | |||
215 | #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | ||
216 | #define HFA384X_INB(a) inb(dev->base_addr + (a)) | ||
217 | #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | ||
218 | #define HFA384X_INW(a) inw(dev->base_addr + (a)) | ||
219 | #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | ||
220 | #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | ||
221 | |||
222 | #endif /* PRISM2_IO_DEBUG */ | ||
223 | |||
224 | |||
225 | static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | ||
226 | int len) | ||
227 | { | ||
228 | u16 d_off; | ||
229 | u16 *pos; | ||
230 | |||
231 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
232 | pos = (u16 *) buf; | ||
233 | |||
234 | if (len / 2) | ||
235 | HFA384X_INSW(d_off, buf, len / 2); | ||
236 | pos += len / 2; | ||
237 | |||
238 | if (len & 1) | ||
239 | *((char *) pos) = HFA384X_INB(d_off); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | |||
245 | static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | ||
246 | { | ||
247 | u16 d_off; | ||
248 | u16 *pos; | ||
249 | |||
250 | d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | ||
251 | pos = (u16 *) buf; | ||
252 | |||
253 | if (len / 2) | ||
254 | HFA384X_OUTSW(d_off, buf, len / 2); | ||
255 | pos += len / 2; | ||
256 | |||
257 | if (len & 1) | ||
258 | HFA384X_OUTB(*((char *) pos), d_off); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | |||
264 | /* FIX: This might change at some point.. */ | ||
265 | #include "hostap_hw.c" | ||
266 | |||
267 | |||
268 | static void prism2_plx_cor_sreset(local_info_t *local) | ||
269 | { | ||
270 | unsigned char corsave; | ||
271 | struct hostap_plx_priv *hw_priv = local->hw_priv; | ||
272 | |||
273 | printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n", | ||
274 | dev_info); | ||
275 | |||
276 | /* Set sreset bit of COR and clear it after hold time */ | ||
277 | |||
278 | if (hw_priv->attr_mem == NULL) { | ||
279 | /* TMD7160 - COR at card's first I/O addr */ | ||
280 | corsave = inb(hw_priv->cor_offset); | ||
281 | outb(corsave | COR_SRESET, hw_priv->cor_offset); | ||
282 | mdelay(2); | ||
283 | outb(corsave & ~COR_SRESET, hw_priv->cor_offset); | ||
284 | mdelay(2); | ||
285 | } else { | ||
286 | /* PLX9052 */ | ||
287 | corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); | ||
288 | writeb(corsave | COR_SRESET, | ||
289 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
290 | mdelay(2); | ||
291 | writeb(corsave & ~COR_SRESET, | ||
292 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
293 | mdelay(2); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | |||
298 | static void prism2_plx_genesis_reset(local_info_t *local, int hcr) | ||
299 | { | ||
300 | unsigned char corsave; | ||
301 | struct hostap_plx_priv *hw_priv = local->hw_priv; | ||
302 | |||
303 | if (hw_priv->attr_mem == NULL) { | ||
304 | /* TMD7160 - COR at card's first I/O addr */ | ||
305 | corsave = inb(hw_priv->cor_offset); | ||
306 | outb(corsave | COR_SRESET, hw_priv->cor_offset); | ||
307 | mdelay(10); | ||
308 | outb(hcr, hw_priv->cor_offset + 2); | ||
309 | mdelay(10); | ||
310 | outb(corsave & ~COR_SRESET, hw_priv->cor_offset); | ||
311 | mdelay(10); | ||
312 | } else { | ||
313 | /* PLX9052 */ | ||
314 | corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset); | ||
315 | writeb(corsave | COR_SRESET, | ||
316 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
317 | mdelay(10); | ||
318 | writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2); | ||
319 | mdelay(10); | ||
320 | writeb(corsave & ~COR_SRESET, | ||
321 | hw_priv->attr_mem + hw_priv->cor_offset); | ||
322 | mdelay(10); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | |||
327 | static struct prism2_helper_functions prism2_plx_funcs = | ||
328 | { | ||
329 | .card_present = NULL, | ||
330 | .cor_sreset = prism2_plx_cor_sreset, | ||
331 | .dev_open = NULL, | ||
332 | .dev_close = NULL, | ||
333 | .genesis_reset = prism2_plx_genesis_reset, | ||
334 | .hw_type = HOSTAP_HW_PLX, | ||
335 | }; | ||
336 | |||
337 | |||
338 | static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, | ||
339 | unsigned int *cor_offset, | ||
340 | unsigned int *cor_index) | ||
341 | { | ||
342 | #define CISTPL_CONFIG 0x1A | ||
343 | #define CISTPL_MANFID 0x20 | ||
344 | #define CISTPL_END 0xFF | ||
345 | #define CIS_MAX_LEN 256 | ||
346 | u8 *cis; | ||
347 | int i, pos; | ||
348 | unsigned int rmsz, rasz, manfid1, manfid2; | ||
349 | struct prism2_plx_manfid *manfid; | ||
350 | |||
351 | cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL); | ||
352 | if (cis == NULL) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | /* read CIS; it is in even offsets in the beginning of attr_mem */ | ||
356 | for (i = 0; i < CIS_MAX_LEN; i++) | ||
357 | cis[i] = readb(attr_mem + 2 * i); | ||
358 | printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n", | ||
359 | dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]); | ||
360 | |||
361 | /* set reasonable defaults for Prism2 cards just in case CIS parsing | ||
362 | * fails */ | ||
363 | *cor_offset = 0x3e0; | ||
364 | *cor_index = 0x01; | ||
365 | manfid1 = manfid2 = 0; | ||
366 | |||
367 | pos = 0; | ||
368 | while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) { | ||
369 | if (pos + cis[pos + 1] >= CIS_MAX_LEN) | ||
370 | goto cis_error; | ||
371 | |||
372 | switch (cis[pos]) { | ||
373 | case CISTPL_CONFIG: | ||
374 | if (cis[pos + 1] < 1) | ||
375 | goto cis_error; | ||
376 | rmsz = (cis[pos + 2] & 0x3c) >> 2; | ||
377 | rasz = cis[pos + 2] & 0x03; | ||
378 | if (4 + rasz + rmsz > cis[pos + 1]) | ||
379 | goto cis_error; | ||
380 | *cor_index = cis[pos + 3] & 0x3F; | ||
381 | *cor_offset = 0; | ||
382 | for (i = 0; i <= rasz; i++) | ||
383 | *cor_offset += cis[pos + 4 + i] << (8 * i); | ||
384 | printk(KERN_DEBUG "%s: cor_index=0x%x " | ||
385 | "cor_offset=0x%x\n", dev_info, | ||
386 | *cor_index, *cor_offset); | ||
387 | if (*cor_offset > attr_len) { | ||
388 | printk(KERN_ERR "%s: COR offset not within " | ||
389 | "attr_mem\n", dev_info); | ||
390 | kfree(cis); | ||
391 | return -1; | ||
392 | } | ||
393 | break; | ||
394 | |||
395 | case CISTPL_MANFID: | ||
396 | if (cis[pos + 1] < 4) | ||
397 | goto cis_error; | ||
398 | manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); | ||
399 | manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); | ||
400 | printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n", | ||
401 | dev_info, manfid1, manfid2); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | pos += cis[pos + 1] + 2; | ||
406 | } | ||
407 | |||
408 | if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END) | ||
409 | goto cis_error; | ||
410 | |||
411 | for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++) | ||
412 | if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) { | ||
413 | kfree(cis); | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is" | ||
418 | " not supported card\n", dev_info, manfid1, manfid2); | ||
419 | goto fail; | ||
420 | |||
421 | cis_error: | ||
422 | printk(KERN_WARNING "%s: invalid CIS data\n", dev_info); | ||
423 | |||
424 | fail: | ||
425 | kfree(cis); | ||
426 | if (ignore_cis) { | ||
427 | printk(KERN_INFO "%s: ignore_cis parameter set - ignoring " | ||
428 | "errors during CIS verification\n", dev_info); | ||
429 | return 0; | ||
430 | } | ||
431 | return -1; | ||
432 | } | ||
433 | |||
434 | |||
435 | static int prism2_plx_probe(struct pci_dev *pdev, | ||
436 | const struct pci_device_id *id) | ||
437 | { | ||
438 | unsigned int pccard_ioaddr, plx_ioaddr; | ||
439 | unsigned long pccard_attr_mem; | ||
440 | unsigned int pccard_attr_len; | ||
441 | void __iomem *attr_mem = NULL; | ||
442 | unsigned int cor_offset, cor_index; | ||
443 | u32 reg; | ||
444 | local_info_t *local = NULL; | ||
445 | struct net_device *dev = NULL; | ||
446 | struct hostap_interface *iface; | ||
447 | static int cards_found /* = 0 */; | ||
448 | int irq_registered = 0; | ||
449 | int tmd7160; | ||
450 | struct hostap_plx_priv *hw_priv; | ||
451 | |||
452 | hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); | ||
453 | if (hw_priv == NULL) | ||
454 | return -ENOMEM; | ||
455 | memset(hw_priv, 0, sizeof(*hw_priv)); | ||
456 | |||
457 | if (pci_enable_device(pdev)) | ||
458 | return -EIO; | ||
459 | |||
460 | /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ | ||
461 | tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); | ||
462 | |||
463 | plx_ioaddr = pci_resource_start(pdev, 1); | ||
464 | pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3); | ||
465 | |||
466 | if (tmd7160) { | ||
467 | /* TMD7160 */ | ||
468 | attr_mem = NULL; /* no access to PC Card attribute memory */ | ||
469 | |||
470 | printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, " | ||
471 | "irq=%d, pccard_io=0x%x\n", | ||
472 | plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
473 | |||
474 | cor_offset = plx_ioaddr; | ||
475 | cor_index = 0x04; | ||
476 | |||
477 | outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr); | ||
478 | mdelay(1); | ||
479 | reg = inb(plx_ioaddr); | ||
480 | if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) { | ||
481 | printk(KERN_ERR "%s: Error setting COR (expected=" | ||
482 | "0x%02x, was=0x%02x)\n", dev_info, | ||
483 | cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg); | ||
484 | goto fail; | ||
485 | } | ||
486 | } else { | ||
487 | /* PLX9052 */ | ||
488 | pccard_attr_mem = pci_resource_start(pdev, 2); | ||
489 | pccard_attr_len = pci_resource_len(pdev, 2); | ||
490 | if (pccard_attr_len < PLX_MIN_ATTR_LEN) | ||
491 | goto fail; | ||
492 | |||
493 | |||
494 | attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); | ||
495 | if (attr_mem == NULL) { | ||
496 | printk(KERN_ERR "%s: cannot remap attr_mem\n", | ||
497 | dev_info); | ||
498 | goto fail; | ||
499 | } | ||
500 | |||
501 | printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: " | ||
502 | "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n", | ||
503 | pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr); | ||
504 | |||
505 | if (prism2_plx_check_cis(attr_mem, pccard_attr_len, | ||
506 | &cor_offset, &cor_index)) { | ||
507 | printk(KERN_INFO "Unknown PC Card CIS - not a " | ||
508 | "Prism2/2.5 card?\n"); | ||
509 | goto fail; | ||
510 | } | ||
511 | |||
512 | printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 " | ||
513 | "adapter\n"); | ||
514 | |||
515 | /* Write COR to enable PC Card */ | ||
516 | writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, | ||
517 | attr_mem + cor_offset); | ||
518 | |||
519 | /* Enable PCI interrupts if they are not already enabled */ | ||
520 | reg = inl(plx_ioaddr + PLX_INTCSR); | ||
521 | printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg); | ||
522 | if (!(reg & PLX_INTCSR_PCI_INTEN)) { | ||
523 | outl(reg | PLX_INTCSR_PCI_INTEN, | ||
524 | plx_ioaddr + PLX_INTCSR); | ||
525 | if (!(inl(plx_ioaddr + PLX_INTCSR) & | ||
526 | PLX_INTCSR_PCI_INTEN)) { | ||
527 | printk(KERN_WARNING "%s: Could not enable " | ||
528 | "Local Interrupts\n", dev_info); | ||
529 | goto fail; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | reg = inl(plx_ioaddr + PLX_CNTRL); | ||
534 | printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM " | ||
535 | "present=%d)\n", | ||
536 | reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0); | ||
537 | /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is | ||
538 | * not present; but are there really such cards in use(?) */ | ||
539 | } | ||
540 | |||
541 | dev = prism2_init_local_data(&prism2_plx_funcs, cards_found, | ||
542 | &pdev->dev); | ||
543 | if (dev == NULL) | ||
544 | goto fail; | ||
545 | iface = netdev_priv(dev); | ||
546 | local = iface->local; | ||
547 | local->hw_priv = hw_priv; | ||
548 | cards_found++; | ||
549 | |||
550 | dev->irq = pdev->irq; | ||
551 | dev->base_addr = pccard_ioaddr; | ||
552 | hw_priv->attr_mem = attr_mem; | ||
553 | hw_priv->cor_offset = cor_offset; | ||
554 | |||
555 | pci_set_drvdata(pdev, dev); | ||
556 | |||
557 | if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name, | ||
558 | dev)) { | ||
559 | printk(KERN_WARNING "%s: request_irq failed\n", dev->name); | ||
560 | goto fail; | ||
561 | } else | ||
562 | irq_registered = 1; | ||
563 | |||
564 | if (prism2_hw_config(dev, 1)) { | ||
565 | printk(KERN_DEBUG "%s: hardware initialization failed\n", | ||
566 | dev_info); | ||
567 | goto fail; | ||
568 | } | ||
569 | |||
570 | return hostap_hw_ready(dev); | ||
571 | |||
572 | fail: | ||
573 | kfree(hw_priv); | ||
574 | if (local) | ||
575 | local->hw_priv = NULL; | ||
576 | prism2_free_local_data(dev); | ||
577 | |||
578 | if (irq_registered && dev) | ||
579 | free_irq(dev->irq, dev); | ||
580 | |||
581 | if (attr_mem) | ||
582 | iounmap(attr_mem); | ||
583 | |||
584 | pci_disable_device(pdev); | ||
585 | |||
586 | return -ENODEV; | ||
587 | } | ||
588 | |||
589 | |||
590 | static void prism2_plx_remove(struct pci_dev *pdev) | ||
591 | { | ||
592 | struct net_device *dev; | ||
593 | struct hostap_interface *iface; | ||
594 | struct hostap_plx_priv *hw_priv; | ||
595 | |||
596 | dev = pci_get_drvdata(pdev); | ||
597 | iface = netdev_priv(dev); | ||
598 | hw_priv = iface->local->hw_priv; | ||
599 | |||
600 | /* Reset the hardware, and ensure interrupts are disabled. */ | ||
601 | prism2_plx_cor_sreset(iface->local); | ||
602 | hfa384x_disable_interrupts(dev); | ||
603 | |||
604 | if (hw_priv->attr_mem) | ||
605 | iounmap(hw_priv->attr_mem); | ||
606 | if (dev->irq) | ||
607 | free_irq(dev->irq, dev); | ||
608 | |||
609 | kfree(iface->local->hw_priv); | ||
610 | iface->local->hw_priv = NULL; | ||
611 | prism2_free_local_data(dev); | ||
612 | pci_disable_device(pdev); | ||
613 | } | ||
614 | |||
615 | |||
616 | MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); | ||
617 | |||
618 | static struct pci_driver prism2_plx_drv_id = { | ||
619 | .name = "prism2_plx", | ||
620 | .id_table = prism2_plx_id_table, | ||
621 | .probe = prism2_plx_probe, | ||
622 | .remove = prism2_plx_remove, | ||
623 | .suspend = NULL, | ||
624 | .resume = NULL, | ||
625 | .enable_wake = NULL | ||
626 | }; | ||
627 | |||
628 | |||
629 | static int __init init_prism2_plx(void) | ||
630 | { | ||
631 | printk(KERN_INFO "%s: %s\n", dev_info, version); | ||
632 | |||
633 | return pci_register_driver(&prism2_plx_drv_id); | ||
634 | } | ||
635 | |||
636 | |||
637 | static void __exit exit_prism2_plx(void) | ||
638 | { | ||
639 | pci_unregister_driver(&prism2_plx_drv_id); | ||
640 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
641 | } | ||
642 | |||
643 | |||
644 | module_init(init_prism2_plx); | ||
645 | module_exit(exit_prism2_plx); | ||
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c new file mode 100644 index 000000000000..a0a4cbd4937a --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_proc.c | |||
@@ -0,0 +1,448 @@ | |||
1 | /* /proc routines for Host AP driver */ | ||
2 | |||
3 | #define PROC_LIMIT (PAGE_SIZE - 80) | ||
4 | |||
5 | |||
6 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
7 | static int prism2_debug_proc_read(char *page, char **start, off_t off, | ||
8 | int count, int *eof, void *data) | ||
9 | { | ||
10 | char *p = page; | ||
11 | local_info_t *local = (local_info_t *) data; | ||
12 | int i; | ||
13 | |||
14 | if (off != 0) { | ||
15 | *eof = 1; | ||
16 | return 0; | ||
17 | } | ||
18 | |||
19 | p += sprintf(p, "next_txfid=%d next_alloc=%d\n", | ||
20 | local->next_txfid, local->next_alloc); | ||
21 | for (i = 0; i < PRISM2_TXFID_COUNT; i++) | ||
22 | p += sprintf(p, "FID: tx=%04X intransmit=%04X\n", | ||
23 | local->txfid[i], local->intransmitfid[i]); | ||
24 | p += sprintf(p, "FW TX rate control: %d\n", local->fw_tx_rate_control); | ||
25 | p += sprintf(p, "beacon_int=%d\n", local->beacon_int); | ||
26 | p += sprintf(p, "dtim_period=%d\n", local->dtim_period); | ||
27 | p += sprintf(p, "wds_max_connections=%d\n", | ||
28 | local->wds_max_connections); | ||
29 | p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); | ||
30 | p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); | ||
31 | for (i = 0; i < WEP_KEYS; i++) { | ||
32 | if (local->crypt[i] && local->crypt[i]->ops) { | ||
33 | p += sprintf(p, "crypt[%d]=%s\n", | ||
34 | i, local->crypt[i]->ops->name); | ||
35 | } | ||
36 | } | ||
37 | p += sprintf(p, "pri_only=%d\n", local->pri_only); | ||
38 | p += sprintf(p, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI); | ||
39 | p += sprintf(p, "sram_type=%d\n", local->sram_type); | ||
40 | p += sprintf(p, "no_pri=%d\n", local->no_pri); | ||
41 | |||
42 | return (p - page); | ||
43 | } | ||
44 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
45 | |||
46 | |||
47 | static int prism2_stats_proc_read(char *page, char **start, off_t off, | ||
48 | int count, int *eof, void *data) | ||
49 | { | ||
50 | char *p = page; | ||
51 | local_info_t *local = (local_info_t *) data; | ||
52 | struct comm_tallies_sums *sums = (struct comm_tallies_sums *) | ||
53 | &local->comm_tallies; | ||
54 | |||
55 | if (off != 0) { | ||
56 | *eof = 1; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | p += sprintf(p, "TxUnicastFrames=%u\n", sums->tx_unicast_frames); | ||
61 | p += sprintf(p, "TxMulticastframes=%u\n", sums->tx_multicast_frames); | ||
62 | p += sprintf(p, "TxFragments=%u\n", sums->tx_fragments); | ||
63 | p += sprintf(p, "TxUnicastOctets=%u\n", sums->tx_unicast_octets); | ||
64 | p += sprintf(p, "TxMulticastOctets=%u\n", sums->tx_multicast_octets); | ||
65 | p += sprintf(p, "TxDeferredTransmissions=%u\n", | ||
66 | sums->tx_deferred_transmissions); | ||
67 | p += sprintf(p, "TxSingleRetryFrames=%u\n", | ||
68 | sums->tx_single_retry_frames); | ||
69 | p += sprintf(p, "TxMultipleRetryFrames=%u\n", | ||
70 | sums->tx_multiple_retry_frames); | ||
71 | p += sprintf(p, "TxRetryLimitExceeded=%u\n", | ||
72 | sums->tx_retry_limit_exceeded); | ||
73 | p += sprintf(p, "TxDiscards=%u\n", sums->tx_discards); | ||
74 | p += sprintf(p, "RxUnicastFrames=%u\n", sums->rx_unicast_frames); | ||
75 | p += sprintf(p, "RxMulticastFrames=%u\n", sums->rx_multicast_frames); | ||
76 | p += sprintf(p, "RxFragments=%u\n", sums->rx_fragments); | ||
77 | p += sprintf(p, "RxUnicastOctets=%u\n", sums->rx_unicast_octets); | ||
78 | p += sprintf(p, "RxMulticastOctets=%u\n", sums->rx_multicast_octets); | ||
79 | p += sprintf(p, "RxFCSErrors=%u\n", sums->rx_fcs_errors); | ||
80 | p += sprintf(p, "RxDiscardsNoBuffer=%u\n", | ||
81 | sums->rx_discards_no_buffer); | ||
82 | p += sprintf(p, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa); | ||
83 | p += sprintf(p, "RxDiscardsWEPUndecryptable=%u\n", | ||
84 | sums->rx_discards_wep_undecryptable); | ||
85 | p += sprintf(p, "RxMessageInMsgFragments=%u\n", | ||
86 | sums->rx_message_in_msg_fragments); | ||
87 | p += sprintf(p, "RxMessageInBadMsgFragments=%u\n", | ||
88 | sums->rx_message_in_bad_msg_fragments); | ||
89 | /* FIX: this may grow too long for one page(?) */ | ||
90 | |||
91 | return (p - page); | ||
92 | } | ||
93 | |||
94 | |||
95 | static int prism2_wds_proc_read(char *page, char **start, off_t off, | ||
96 | int count, int *eof, void *data) | ||
97 | { | ||
98 | char *p = page; | ||
99 | local_info_t *local = (local_info_t *) data; | ||
100 | struct list_head *ptr; | ||
101 | struct hostap_interface *iface; | ||
102 | |||
103 | if (off > PROC_LIMIT) { | ||
104 | *eof = 1; | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | read_lock_bh(&local->iface_lock); | ||
109 | list_for_each(ptr, &local->hostap_interfaces) { | ||
110 | iface = list_entry(ptr, struct hostap_interface, list); | ||
111 | if (iface->type != HOSTAP_INTERFACE_WDS) | ||
112 | continue; | ||
113 | p += sprintf(p, "%s\t" MACSTR "\n", | ||
114 | iface->dev->name, | ||
115 | MAC2STR(iface->u.wds.remote_addr)); | ||
116 | if ((p - page) > PROC_LIMIT) { | ||
117 | printk(KERN_DEBUG "%s: wds proc did not fit\n", | ||
118 | local->dev->name); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | read_unlock_bh(&local->iface_lock); | ||
123 | |||
124 | if ((p - page) <= off) { | ||
125 | *eof = 1; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | *start = page + off; | ||
130 | |||
131 | return (p - page - off); | ||
132 | } | ||
133 | |||
134 | |||
135 | static int prism2_bss_list_proc_read(char *page, char **start, off_t off, | ||
136 | int count, int *eof, void *data) | ||
137 | { | ||
138 | char *p = page; | ||
139 | local_info_t *local = (local_info_t *) data; | ||
140 | struct list_head *ptr; | ||
141 | struct hostap_bss_info *bss; | ||
142 | int i; | ||
143 | |||
144 | if (off > PROC_LIMIT) { | ||
145 | *eof = 1; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | p += sprintf(p, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t" | ||
150 | "SSID(hex)\tWPA IE\n"); | ||
151 | spin_lock_bh(&local->lock); | ||
152 | list_for_each(ptr, &local->bss_list) { | ||
153 | bss = list_entry(ptr, struct hostap_bss_info, list); | ||
154 | p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t", | ||
155 | MAC2STR(bss->bssid), bss->last_update, | ||
156 | bss->count, bss->capab_info); | ||
157 | for (i = 0; i < bss->ssid_len; i++) { | ||
158 | p += sprintf(p, "%c", | ||
159 | bss->ssid[i] >= 32 && bss->ssid[i] < 127 ? | ||
160 | bss->ssid[i] : '_'); | ||
161 | } | ||
162 | p += sprintf(p, "\t"); | ||
163 | for (i = 0; i < bss->ssid_len; i++) { | ||
164 | p += sprintf(p, "%02x", bss->ssid[i]); | ||
165 | } | ||
166 | p += sprintf(p, "\t"); | ||
167 | for (i = 0; i < bss->wpa_ie_len; i++) { | ||
168 | p += sprintf(p, "%02x", bss->wpa_ie[i]); | ||
169 | } | ||
170 | p += sprintf(p, "\n"); | ||
171 | if ((p - page) > PROC_LIMIT) { | ||
172 | printk(KERN_DEBUG "%s: BSS proc did not fit\n", | ||
173 | local->dev->name); | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | spin_unlock_bh(&local->lock); | ||
178 | |||
179 | if ((p - page) <= off) { | ||
180 | *eof = 1; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | *start = page + off; | ||
185 | |||
186 | return (p - page - off); | ||
187 | } | ||
188 | |||
189 | |||
190 | static int prism2_crypt_proc_read(char *page, char **start, off_t off, | ||
191 | int count, int *eof, void *data) | ||
192 | { | ||
193 | char *p = page; | ||
194 | local_info_t *local = (local_info_t *) data; | ||
195 | int i; | ||
196 | |||
197 | if (off > PROC_LIMIT) { | ||
198 | *eof = 1; | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx); | ||
203 | for (i = 0; i < WEP_KEYS; i++) { | ||
204 | if (local->crypt[i] && local->crypt[i]->ops && | ||
205 | local->crypt[i]->ops->print_stats) { | ||
206 | p = local->crypt[i]->ops->print_stats( | ||
207 | p, local->crypt[i]->priv); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if ((p - page) <= off) { | ||
212 | *eof = 1; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | *start = page + off; | ||
217 | |||
218 | return (p - page - off); | ||
219 | } | ||
220 | |||
221 | |||
222 | static int prism2_pda_proc_read(char *page, char **start, off_t off, | ||
223 | int count, int *eof, void *data) | ||
224 | { | ||
225 | local_info_t *local = (local_info_t *) data; | ||
226 | |||
227 | if (local->pda == NULL || off >= PRISM2_PDA_SIZE) { | ||
228 | *eof = 1; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | if (off + count > PRISM2_PDA_SIZE) | ||
233 | count = PRISM2_PDA_SIZE - off; | ||
234 | |||
235 | memcpy(page, local->pda + off, count); | ||
236 | return count; | ||
237 | } | ||
238 | |||
239 | |||
240 | static int prism2_aux_dump_proc_read(char *page, char **start, off_t off, | ||
241 | int count, int *eof, void *data) | ||
242 | { | ||
243 | local_info_t *local = (local_info_t *) data; | ||
244 | |||
245 | if (local->func->read_aux == NULL) { | ||
246 | *eof = 1; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | if (local->func->read_aux(local->dev, off, count, page)) { | ||
251 | *eof = 1; | ||
252 | return 0; | ||
253 | } | ||
254 | *start = page; | ||
255 | |||
256 | return count; | ||
257 | } | ||
258 | |||
259 | |||
260 | #ifdef PRISM2_IO_DEBUG | ||
261 | static int prism2_io_debug_proc_read(char *page, char **start, off_t off, | ||
262 | int count, int *eof, void *data) | ||
263 | { | ||
264 | local_info_t *local = (local_info_t *) data; | ||
265 | int head = local->io_debug_head; | ||
266 | int start_bytes, left, copy, copied; | ||
267 | |||
268 | if (off + count > PRISM2_IO_DEBUG_SIZE * 4) { | ||
269 | *eof = 1; | ||
270 | if (off >= PRISM2_IO_DEBUG_SIZE * 4) | ||
271 | return 0; | ||
272 | count = PRISM2_IO_DEBUG_SIZE * 4 - off; | ||
273 | } | ||
274 | |||
275 | copied = 0; | ||
276 | start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4; | ||
277 | left = count; | ||
278 | |||
279 | if (off < start_bytes) { | ||
280 | copy = start_bytes - off; | ||
281 | if (copy > count) | ||
282 | copy = count; | ||
283 | memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy); | ||
284 | left -= copy; | ||
285 | if (left > 0) | ||
286 | memcpy(&page[copy], local->io_debug, left); | ||
287 | } else { | ||
288 | memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes), | ||
289 | left); | ||
290 | } | ||
291 | |||
292 | *start = page; | ||
293 | |||
294 | return count; | ||
295 | } | ||
296 | #endif /* PRISM2_IO_DEBUG */ | ||
297 | |||
298 | |||
299 | #ifndef PRISM2_NO_STATION_MODES | ||
300 | static int prism2_scan_results_proc_read(char *page, char **start, off_t off, | ||
301 | int count, int *eof, void *data) | ||
302 | { | ||
303 | char *p = page; | ||
304 | local_info_t *local = (local_info_t *) data; | ||
305 | int entry, i, len, total = 0; | ||
306 | struct hfa384x_hostscan_result *scanres; | ||
307 | u8 *pos; | ||
308 | |||
309 | p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " | ||
310 | "SSID\n"); | ||
311 | |||
312 | spin_lock_bh(&local->lock); | ||
313 | for (entry = 0; entry < local->last_scan_results_count; entry++) { | ||
314 | scanres = &local->last_scan_results[entry]; | ||
315 | |||
316 | if (total + (p - page) <= off) { | ||
317 | total += p - page; | ||
318 | p = page; | ||
319 | } | ||
320 | if (total + (p - page) > off + count) | ||
321 | break; | ||
322 | if ((p - page) > (PAGE_SIZE - 200)) | ||
323 | break; | ||
324 | |||
325 | p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", | ||
326 | le16_to_cpu(scanres->chid), | ||
327 | (s16) le16_to_cpu(scanres->anl), | ||
328 | (s16) le16_to_cpu(scanres->sl), | ||
329 | le16_to_cpu(scanres->beacon_interval), | ||
330 | le16_to_cpu(scanres->capability), | ||
331 | le16_to_cpu(scanres->rate), | ||
332 | MAC2STR(scanres->bssid), | ||
333 | le16_to_cpu(scanres->atim)); | ||
334 | |||
335 | pos = scanres->sup_rates; | ||
336 | for (i = 0; i < sizeof(scanres->sup_rates); i++) { | ||
337 | if (pos[i] == 0) | ||
338 | break; | ||
339 | p += sprintf(p, "<%02x>", pos[i]); | ||
340 | } | ||
341 | p += sprintf(p, " "); | ||
342 | |||
343 | pos = scanres->ssid; | ||
344 | len = le16_to_cpu(scanres->ssid_len); | ||
345 | if (len > 32) | ||
346 | len = 32; | ||
347 | for (i = 0; i < len; i++) { | ||
348 | unsigned char c = pos[i]; | ||
349 | if (c >= 32 && c < 127) | ||
350 | p += sprintf(p, "%c", c); | ||
351 | else | ||
352 | p += sprintf(p, "<%02x>", c); | ||
353 | } | ||
354 | p += sprintf(p, "\n"); | ||
355 | } | ||
356 | spin_unlock_bh(&local->lock); | ||
357 | |||
358 | total += (p - page); | ||
359 | if (total >= off + count) | ||
360 | *eof = 1; | ||
361 | |||
362 | if (total < off) { | ||
363 | *eof = 1; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | len = total - off; | ||
368 | if (len > (p - page)) | ||
369 | len = p - page; | ||
370 | *start = p - len; | ||
371 | if (len > count) | ||
372 | len = count; | ||
373 | |||
374 | return len; | ||
375 | } | ||
376 | #endif /* PRISM2_NO_STATION_MODES */ | ||
377 | |||
378 | |||
379 | void hostap_init_proc(local_info_t *local) | ||
380 | { | ||
381 | local->proc = NULL; | ||
382 | |||
383 | if (hostap_proc == NULL) { | ||
384 | printk(KERN_WARNING "%s: hostap proc directory not created\n", | ||
385 | local->dev->name); | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | local->proc = proc_mkdir(local->ddev->name, hostap_proc); | ||
390 | if (local->proc == NULL) { | ||
391 | printk(KERN_INFO "/proc/net/hostap/%s creation failed\n", | ||
392 | local->ddev->name); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
397 | create_proc_read_entry("debug", 0, local->proc, | ||
398 | prism2_debug_proc_read, local); | ||
399 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
400 | create_proc_read_entry("stats", 0, local->proc, | ||
401 | prism2_stats_proc_read, local); | ||
402 | create_proc_read_entry("wds", 0, local->proc, | ||
403 | prism2_wds_proc_read, local); | ||
404 | create_proc_read_entry("pda", 0, local->proc, | ||
405 | prism2_pda_proc_read, local); | ||
406 | create_proc_read_entry("aux_dump", 0, local->proc, | ||
407 | prism2_aux_dump_proc_read, local); | ||
408 | create_proc_read_entry("bss_list", 0, local->proc, | ||
409 | prism2_bss_list_proc_read, local); | ||
410 | create_proc_read_entry("crypt", 0, local->proc, | ||
411 | prism2_crypt_proc_read, local); | ||
412 | #ifdef PRISM2_IO_DEBUG | ||
413 | create_proc_read_entry("io_debug", 0, local->proc, | ||
414 | prism2_io_debug_proc_read, local); | ||
415 | #endif /* PRISM2_IO_DEBUG */ | ||
416 | #ifndef PRISM2_NO_STATION_MODES | ||
417 | create_proc_read_entry("scan_results", 0, local->proc, | ||
418 | prism2_scan_results_proc_read, local); | ||
419 | #endif /* PRISM2_NO_STATION_MODES */ | ||
420 | } | ||
421 | |||
422 | |||
423 | void hostap_remove_proc(local_info_t *local) | ||
424 | { | ||
425 | if (local->proc != NULL) { | ||
426 | #ifndef PRISM2_NO_STATION_MODES | ||
427 | remove_proc_entry("scan_results", local->proc); | ||
428 | #endif /* PRISM2_NO_STATION_MODES */ | ||
429 | #ifdef PRISM2_IO_DEBUG | ||
430 | remove_proc_entry("io_debug", local->proc); | ||
431 | #endif /* PRISM2_IO_DEBUG */ | ||
432 | remove_proc_entry("pda", local->proc); | ||
433 | remove_proc_entry("aux_dump", local->proc); | ||
434 | remove_proc_entry("wds", local->proc); | ||
435 | remove_proc_entry("stats", local->proc); | ||
436 | remove_proc_entry("bss_list", local->proc); | ||
437 | remove_proc_entry("crypt", local->proc); | ||
438 | #ifndef PRISM2_NO_PROCFS_DEBUG | ||
439 | remove_proc_entry("debug", local->proc); | ||
440 | #endif /* PRISM2_NO_PROCFS_DEBUG */ | ||
441 | if (hostap_proc != NULL) | ||
442 | remove_proc_entry(local->proc->name, hostap_proc); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | EXPORT_SYMBOL(hostap_init_proc); | ||
448 | EXPORT_SYMBOL(hostap_remove_proc); | ||
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h new file mode 100644 index 000000000000..cc061e1560d3 --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_wlan.h | |||
@@ -0,0 +1,1033 @@ | |||
1 | #ifndef HOSTAP_WLAN_H | ||
2 | #define HOSTAP_WLAN_H | ||
3 | |||
4 | #include "hostap_config.h" | ||
5 | #include "hostap_common.h" | ||
6 | |||
7 | #define MAX_PARM_DEVICES 8 | ||
8 | #define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES) | ||
9 | #define DEF_INTS -1, -1, -1, -1, -1, -1, -1 | ||
10 | #define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx] | ||
11 | |||
12 | |||
13 | /* Specific skb->protocol value that indicates that the packet already contains | ||
14 | * txdesc header. | ||
15 | * FIX: This might need own value that would be allocated especially for Prism2 | ||
16 | * txdesc; ETH_P_CONTROL is commented as "Card specific control frames". | ||
17 | * However, these skb's should have only minimal path in the kernel side since | ||
18 | * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */ | ||
19 | #define ETH_P_HOSTAP ETH_P_CONTROL | ||
20 | |||
21 | /* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header | ||
22 | * (from linux-wlan-ng) */ | ||
23 | struct linux_wlan_ng_val { | ||
24 | u32 did; | ||
25 | u16 status, len; | ||
26 | u32 data; | ||
27 | } __attribute__ ((packed)); | ||
28 | |||
29 | struct linux_wlan_ng_prism_hdr { | ||
30 | u32 msgcode, msglen; | ||
31 | char devname[16]; | ||
32 | struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal, | ||
33 | noise, rate, istx, frmlen; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct linux_wlan_ng_cap_hdr { | ||
37 | u32 version; | ||
38 | u32 length; | ||
39 | u64 mactime; | ||
40 | u64 hosttime; | ||
41 | u32 phytype; | ||
42 | u32 channel; | ||
43 | u32 datarate; | ||
44 | u32 antenna; | ||
45 | u32 priority; | ||
46 | u32 ssi_type; | ||
47 | s32 ssi_signal; | ||
48 | s32 ssi_noise; | ||
49 | u32 preamble; | ||
50 | u32 encoding; | ||
51 | } __attribute__ ((packed)); | ||
52 | |||
53 | #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ | ||
54 | #define LWNG_CAPHDR_VERSION 0x80211001 | ||
55 | |||
56 | struct hfa384x_rx_frame { | ||
57 | /* HFA384X RX frame descriptor */ | ||
58 | u16 status; /* HFA384X_RX_STATUS_ flags */ | ||
59 | u32 time; /* timestamp, 1 microsecond resolution */ | ||
60 | u8 silence; /* 27 .. 154; seems to be 0 */ | ||
61 | u8 signal; /* 27 .. 154 */ | ||
62 | u8 rate; /* 10, 20, 55, or 110 */ | ||
63 | u8 rxflow; | ||
64 | u32 reserved; | ||
65 | |||
66 | /* 802.11 */ | ||
67 | u16 frame_control; | ||
68 | u16 duration_id; | ||
69 | u8 addr1[6]; | ||
70 | u8 addr2[6]; | ||
71 | u8 addr3[6]; | ||
72 | u16 seq_ctrl; | ||
73 | u8 addr4[6]; | ||
74 | u16 data_len; | ||
75 | |||
76 | /* 802.3 */ | ||
77 | u8 dst_addr[6]; | ||
78 | u8 src_addr[6]; | ||
79 | u16 len; | ||
80 | |||
81 | /* followed by frame data; max 2304 bytes */ | ||
82 | } __attribute__ ((packed)); | ||
83 | |||
84 | |||
85 | struct hfa384x_tx_frame { | ||
86 | /* HFA384X TX frame descriptor */ | ||
87 | u16 status; /* HFA384X_TX_STATUS_ flags */ | ||
88 | u16 reserved1; | ||
89 | u16 reserved2; | ||
90 | u32 sw_support; | ||
91 | u8 retry_count; /* not yet implemented */ | ||
92 | u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ | ||
93 | u16 tx_control; /* HFA384X_TX_CTRL_ flags */ | ||
94 | |||
95 | /* 802.11 */ | ||
96 | u16 frame_control; /* parts not used */ | ||
97 | u16 duration_id; | ||
98 | u8 addr1[6]; | ||
99 | u8 addr2[6]; /* filled by firmware */ | ||
100 | u8 addr3[6]; | ||
101 | u16 seq_ctrl; /* filled by firmware */ | ||
102 | u8 addr4[6]; | ||
103 | u16 data_len; | ||
104 | |||
105 | /* 802.3 */ | ||
106 | u8 dst_addr[6]; | ||
107 | u8 src_addr[6]; | ||
108 | u16 len; | ||
109 | |||
110 | /* followed by frame data; max 2304 bytes */ | ||
111 | } __attribute__ ((packed)); | ||
112 | |||
113 | |||
114 | struct hfa384x_rid_hdr | ||
115 | { | ||
116 | u16 len; | ||
117 | u16 rid; | ||
118 | } __attribute__ ((packed)); | ||
119 | |||
120 | |||
121 | /* Macro for converting signal levels (range 27 .. 154) to wireless ext | ||
122 | * dBm value with some accuracy */ | ||
123 | #define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100 | ||
124 | |||
125 | #define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 | ||
126 | |||
127 | struct hfa384x_scan_request { | ||
128 | u16 channel_list; | ||
129 | u16 txrate; /* HFA384X_RATES_* */ | ||
130 | } __attribute__ ((packed)); | ||
131 | |||
132 | struct hfa384x_hostscan_request { | ||
133 | u16 channel_list; | ||
134 | u16 txrate; | ||
135 | u16 target_ssid_len; | ||
136 | u8 target_ssid[32]; | ||
137 | } __attribute__ ((packed)); | ||
138 | |||
139 | struct hfa384x_join_request { | ||
140 | u8 bssid[6]; | ||
141 | u16 channel; | ||
142 | } __attribute__ ((packed)); | ||
143 | |||
144 | struct hfa384x_info_frame { | ||
145 | u16 len; | ||
146 | u16 type; | ||
147 | } __attribute__ ((packed)); | ||
148 | |||
149 | struct hfa384x_comm_tallies { | ||
150 | u16 tx_unicast_frames; | ||
151 | u16 tx_multicast_frames; | ||
152 | u16 tx_fragments; | ||
153 | u16 tx_unicast_octets; | ||
154 | u16 tx_multicast_octets; | ||
155 | u16 tx_deferred_transmissions; | ||
156 | u16 tx_single_retry_frames; | ||
157 | u16 tx_multiple_retry_frames; | ||
158 | u16 tx_retry_limit_exceeded; | ||
159 | u16 tx_discards; | ||
160 | u16 rx_unicast_frames; | ||
161 | u16 rx_multicast_frames; | ||
162 | u16 rx_fragments; | ||
163 | u16 rx_unicast_octets; | ||
164 | u16 rx_multicast_octets; | ||
165 | u16 rx_fcs_errors; | ||
166 | u16 rx_discards_no_buffer; | ||
167 | u16 tx_discards_wrong_sa; | ||
168 | u16 rx_discards_wep_undecryptable; | ||
169 | u16 rx_message_in_msg_fragments; | ||
170 | u16 rx_message_in_bad_msg_fragments; | ||
171 | } __attribute__ ((packed)); | ||
172 | |||
173 | struct hfa384x_comm_tallies32 { | ||
174 | u32 tx_unicast_frames; | ||
175 | u32 tx_multicast_frames; | ||
176 | u32 tx_fragments; | ||
177 | u32 tx_unicast_octets; | ||
178 | u32 tx_multicast_octets; | ||
179 | u32 tx_deferred_transmissions; | ||
180 | u32 tx_single_retry_frames; | ||
181 | u32 tx_multiple_retry_frames; | ||
182 | u32 tx_retry_limit_exceeded; | ||
183 | u32 tx_discards; | ||
184 | u32 rx_unicast_frames; | ||
185 | u32 rx_multicast_frames; | ||
186 | u32 rx_fragments; | ||
187 | u32 rx_unicast_octets; | ||
188 | u32 rx_multicast_octets; | ||
189 | u32 rx_fcs_errors; | ||
190 | u32 rx_discards_no_buffer; | ||
191 | u32 tx_discards_wrong_sa; | ||
192 | u32 rx_discards_wep_undecryptable; | ||
193 | u32 rx_message_in_msg_fragments; | ||
194 | u32 rx_message_in_bad_msg_fragments; | ||
195 | } __attribute__ ((packed)); | ||
196 | |||
197 | struct hfa384x_scan_result_hdr { | ||
198 | u16 reserved; | ||
199 | u16 scan_reason; | ||
200 | #define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ | ||
201 | #define HFA384X_SCAN_HOST_INITIATED 1 | ||
202 | #define HFA384X_SCAN_FIRMWARE_INITIATED 2 | ||
203 | #define HFA384X_SCAN_INQUIRY_FROM_HOST 3 | ||
204 | } __attribute__ ((packed)); | ||
205 | |||
206 | #define HFA384X_SCAN_MAX_RESULTS 32 | ||
207 | |||
208 | struct hfa384x_scan_result { | ||
209 | u16 chid; | ||
210 | u16 anl; | ||
211 | u16 sl; | ||
212 | u8 bssid[6]; | ||
213 | u16 beacon_interval; | ||
214 | u16 capability; | ||
215 | u16 ssid_len; | ||
216 | u8 ssid[32]; | ||
217 | u8 sup_rates[10]; | ||
218 | u16 rate; | ||
219 | } __attribute__ ((packed)); | ||
220 | |||
221 | struct hfa384x_hostscan_result { | ||
222 | u16 chid; | ||
223 | u16 anl; | ||
224 | u16 sl; | ||
225 | u8 bssid[6]; | ||
226 | u16 beacon_interval; | ||
227 | u16 capability; | ||
228 | u16 ssid_len; | ||
229 | u8 ssid[32]; | ||
230 | u8 sup_rates[10]; | ||
231 | u16 rate; | ||
232 | u16 atim; | ||
233 | } __attribute__ ((packed)); | ||
234 | |||
235 | struct comm_tallies_sums { | ||
236 | unsigned int tx_unicast_frames; | ||
237 | unsigned int tx_multicast_frames; | ||
238 | unsigned int tx_fragments; | ||
239 | unsigned int tx_unicast_octets; | ||
240 | unsigned int tx_multicast_octets; | ||
241 | unsigned int tx_deferred_transmissions; | ||
242 | unsigned int tx_single_retry_frames; | ||
243 | unsigned int tx_multiple_retry_frames; | ||
244 | unsigned int tx_retry_limit_exceeded; | ||
245 | unsigned int tx_discards; | ||
246 | unsigned int rx_unicast_frames; | ||
247 | unsigned int rx_multicast_frames; | ||
248 | unsigned int rx_fragments; | ||
249 | unsigned int rx_unicast_octets; | ||
250 | unsigned int rx_multicast_octets; | ||
251 | unsigned int rx_fcs_errors; | ||
252 | unsigned int rx_discards_no_buffer; | ||
253 | unsigned int tx_discards_wrong_sa; | ||
254 | unsigned int rx_discards_wep_undecryptable; | ||
255 | unsigned int rx_message_in_msg_fragments; | ||
256 | unsigned int rx_message_in_bad_msg_fragments; | ||
257 | }; | ||
258 | |||
259 | |||
260 | struct hfa384x_regs { | ||
261 | u16 cmd; | ||
262 | u16 evstat; | ||
263 | u16 offset0; | ||
264 | u16 offset1; | ||
265 | u16 swsupport0; | ||
266 | }; | ||
267 | |||
268 | |||
269 | #if defined(PRISM2_PCCARD) || defined(PRISM2_PLX) | ||
270 | /* I/O ports for HFA384X Controller access */ | ||
271 | #define HFA384X_CMD_OFF 0x00 | ||
272 | #define HFA384X_PARAM0_OFF 0x02 | ||
273 | #define HFA384X_PARAM1_OFF 0x04 | ||
274 | #define HFA384X_PARAM2_OFF 0x06 | ||
275 | #define HFA384X_STATUS_OFF 0x08 | ||
276 | #define HFA384X_RESP0_OFF 0x0A | ||
277 | #define HFA384X_RESP1_OFF 0x0C | ||
278 | #define HFA384X_RESP2_OFF 0x0E | ||
279 | #define HFA384X_INFOFID_OFF 0x10 | ||
280 | #define HFA384X_CONTROL_OFF 0x14 | ||
281 | #define HFA384X_SELECT0_OFF 0x18 | ||
282 | #define HFA384X_SELECT1_OFF 0x1A | ||
283 | #define HFA384X_OFFSET0_OFF 0x1C | ||
284 | #define HFA384X_OFFSET1_OFF 0x1E | ||
285 | #define HFA384X_RXFID_OFF 0x20 | ||
286 | #define HFA384X_ALLOCFID_OFF 0x22 | ||
287 | #define HFA384X_TXCOMPLFID_OFF 0x24 | ||
288 | #define HFA384X_SWSUPPORT0_OFF 0x28 | ||
289 | #define HFA384X_SWSUPPORT1_OFF 0x2A | ||
290 | #define HFA384X_SWSUPPORT2_OFF 0x2C | ||
291 | #define HFA384X_EVSTAT_OFF 0x30 | ||
292 | #define HFA384X_INTEN_OFF 0x32 | ||
293 | #define HFA384X_EVACK_OFF 0x34 | ||
294 | #define HFA384X_DATA0_OFF 0x36 | ||
295 | #define HFA384X_DATA1_OFF 0x38 | ||
296 | #define HFA384X_AUXPAGE_OFF 0x3A | ||
297 | #define HFA384X_AUXOFFSET_OFF 0x3C | ||
298 | #define HFA384X_AUXDATA_OFF 0x3E | ||
299 | #endif /* PRISM2_PCCARD || PRISM2_PLX */ | ||
300 | |||
301 | #ifdef PRISM2_PCI | ||
302 | /* Memory addresses for ISL3874 controller access */ | ||
303 | #define HFA384X_CMD_OFF 0x00 | ||
304 | #define HFA384X_PARAM0_OFF 0x04 | ||
305 | #define HFA384X_PARAM1_OFF 0x08 | ||
306 | #define HFA384X_PARAM2_OFF 0x0C | ||
307 | #define HFA384X_STATUS_OFF 0x10 | ||
308 | #define HFA384X_RESP0_OFF 0x14 | ||
309 | #define HFA384X_RESP1_OFF 0x18 | ||
310 | #define HFA384X_RESP2_OFF 0x1C | ||
311 | #define HFA384X_INFOFID_OFF 0x20 | ||
312 | #define HFA384X_CONTROL_OFF 0x28 | ||
313 | #define HFA384X_SELECT0_OFF 0x30 | ||
314 | #define HFA384X_SELECT1_OFF 0x34 | ||
315 | #define HFA384X_OFFSET0_OFF 0x38 | ||
316 | #define HFA384X_OFFSET1_OFF 0x3C | ||
317 | #define HFA384X_RXFID_OFF 0x40 | ||
318 | #define HFA384X_ALLOCFID_OFF 0x44 | ||
319 | #define HFA384X_TXCOMPLFID_OFF 0x48 | ||
320 | #define HFA384X_PCICOR_OFF 0x4C | ||
321 | #define HFA384X_SWSUPPORT0_OFF 0x50 | ||
322 | #define HFA384X_SWSUPPORT1_OFF 0x54 | ||
323 | #define HFA384X_SWSUPPORT2_OFF 0x58 | ||
324 | #define HFA384X_PCIHCR_OFF 0x5C | ||
325 | #define HFA384X_EVSTAT_OFF 0x60 | ||
326 | #define HFA384X_INTEN_OFF 0x64 | ||
327 | #define HFA384X_EVACK_OFF 0x68 | ||
328 | #define HFA384X_DATA0_OFF 0x6C | ||
329 | #define HFA384X_DATA1_OFF 0x70 | ||
330 | #define HFA384X_AUXPAGE_OFF 0x74 | ||
331 | #define HFA384X_AUXOFFSET_OFF 0x78 | ||
332 | #define HFA384X_AUXDATA_OFF 0x7C | ||
333 | #define HFA384X_PCI_M0_ADDRH_OFF 0x80 | ||
334 | #define HFA384X_PCI_M0_ADDRL_OFF 0x84 | ||
335 | #define HFA384X_PCI_M0_LEN_OFF 0x88 | ||
336 | #define HFA384X_PCI_M0_CTL_OFF 0x8C | ||
337 | #define HFA384X_PCI_STATUS_OFF 0x98 | ||
338 | #define HFA384X_PCI_M1_ADDRH_OFF 0xA0 | ||
339 | #define HFA384X_PCI_M1_ADDRL_OFF 0xA4 | ||
340 | #define HFA384X_PCI_M1_LEN_OFF 0xA8 | ||
341 | #define HFA384X_PCI_M1_CTL_OFF 0xAC | ||
342 | |||
343 | /* PCI bus master control bits (these are undocumented; based on guessing and | ||
344 | * experimenting..) */ | ||
345 | #define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0)) | ||
346 | #define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0)) | ||
347 | |||
348 | #endif /* PRISM2_PCI */ | ||
349 | |||
350 | |||
351 | /* Command codes for CMD reg. */ | ||
352 | #define HFA384X_CMDCODE_INIT 0x00 | ||
353 | #define HFA384X_CMDCODE_ENABLE 0x01 | ||
354 | #define HFA384X_CMDCODE_DISABLE 0x02 | ||
355 | #define HFA384X_CMDCODE_ALLOC 0x0A | ||
356 | #define HFA384X_CMDCODE_TRANSMIT 0x0B | ||
357 | #define HFA384X_CMDCODE_INQUIRE 0x11 | ||
358 | #define HFA384X_CMDCODE_ACCESS 0x21 | ||
359 | #define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8)) | ||
360 | #define HFA384X_CMDCODE_DOWNLOAD 0x22 | ||
361 | #define HFA384X_CMDCODE_READMIF 0x30 | ||
362 | #define HFA384X_CMDCODE_WRITEMIF 0x31 | ||
363 | #define HFA384X_CMDCODE_TEST 0x38 | ||
364 | |||
365 | #define HFA384X_CMDCODE_MASK 0x3F | ||
366 | |||
367 | /* Test mode operations */ | ||
368 | #define HFA384X_TEST_CHANGE_CHANNEL 0x08 | ||
369 | #define HFA384X_TEST_MONITOR 0x0B | ||
370 | #define HFA384X_TEST_STOP 0x0F | ||
371 | #define HFA384X_TEST_CFG_BITS 0x15 | ||
372 | #define HFA384X_TEST_CFG_BIT_ALC BIT(3) | ||
373 | |||
374 | #define HFA384X_CMD_BUSY BIT(15) | ||
375 | |||
376 | #define HFA384X_CMD_TX_RECLAIM BIT(8) | ||
377 | |||
378 | #define HFA384X_OFFSET_ERR BIT(14) | ||
379 | #define HFA384X_OFFSET_BUSY BIT(15) | ||
380 | |||
381 | |||
382 | /* ProgMode for download command */ | ||
383 | #define HFA384X_PROGMODE_DISABLE 0 | ||
384 | #define HFA384X_PROGMODE_ENABLE_VOLATILE 1 | ||
385 | #define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2 | ||
386 | #define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3 | ||
387 | |||
388 | #define HFA384X_AUX_MAGIC0 0xfe01 | ||
389 | #define HFA384X_AUX_MAGIC1 0xdc23 | ||
390 | #define HFA384X_AUX_MAGIC2 0xba45 | ||
391 | |||
392 | #define HFA384X_AUX_PORT_DISABLED 0 | ||
393 | #define HFA384X_AUX_PORT_DISABLE BIT(14) | ||
394 | #define HFA384X_AUX_PORT_ENABLE BIT(15) | ||
395 | #define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15)) | ||
396 | #define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15)) | ||
397 | |||
398 | #define PRISM2_PDA_SIZE 1024 | ||
399 | |||
400 | |||
401 | /* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */ | ||
402 | #define HFA384X_EV_TICK BIT(15) | ||
403 | #define HFA384X_EV_WTERR BIT(14) | ||
404 | #define HFA384X_EV_INFDROP BIT(13) | ||
405 | #ifdef PRISM2_PCI | ||
406 | #define HFA384X_EV_PCI_M1 BIT(9) | ||
407 | #define HFA384X_EV_PCI_M0 BIT(8) | ||
408 | #endif /* PRISM2_PCI */ | ||
409 | #define HFA384X_EV_INFO BIT(7) | ||
410 | #define HFA384X_EV_DTIM BIT(5) | ||
411 | #define HFA384X_EV_CMD BIT(4) | ||
412 | #define HFA384X_EV_ALLOC BIT(3) | ||
413 | #define HFA384X_EV_TXEXC BIT(2) | ||
414 | #define HFA384X_EV_TX BIT(1) | ||
415 | #define HFA384X_EV_RX BIT(0) | ||
416 | |||
417 | |||
418 | /* HFA384X Information frames */ | ||
419 | #define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */ | ||
420 | #define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */ | ||
421 | #define HFA384X_INFO_COMMTALLIES 0xF100 | ||
422 | #define HFA384X_INFO_SCANRESULTS 0xF101 | ||
423 | #define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */ | ||
424 | #define HFA384X_INFO_HOSTSCANRESULTS 0xF103 | ||
425 | #define HFA384X_INFO_LINKSTATUS 0xF200 | ||
426 | #define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */ | ||
427 | #define HFA384X_INFO_AUTHREQ 0xF202 /* ? */ | ||
428 | #define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */ | ||
429 | #define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */ | ||
430 | |||
431 | enum { HFA384X_LINKSTATUS_CONNECTED = 1, | ||
432 | HFA384X_LINKSTATUS_DISCONNECTED = 2, | ||
433 | HFA384X_LINKSTATUS_AP_CHANGE = 3, | ||
434 | HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4, | ||
435 | HFA384X_LINKSTATUS_AP_IN_RANGE = 5, | ||
436 | HFA384X_LINKSTATUS_ASSOC_FAILED = 6 }; | ||
437 | |||
438 | enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2, | ||
439 | HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0, | ||
440 | HFA384X_PORTTYPE_HOSTAP = 6 }; | ||
441 | |||
442 | #define HFA384X_RATES_1MBPS BIT(0) | ||
443 | #define HFA384X_RATES_2MBPS BIT(1) | ||
444 | #define HFA384X_RATES_5MBPS BIT(2) | ||
445 | #define HFA384X_RATES_11MBPS BIT(3) | ||
446 | |||
447 | #define HFA384X_ROAMING_FIRMWARE 1 | ||
448 | #define HFA384X_ROAMING_HOST 2 | ||
449 | #define HFA384X_ROAMING_DISABLED 3 | ||
450 | |||
451 | #define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0) | ||
452 | #define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1) | ||
453 | #define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4) | ||
454 | #define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7) | ||
455 | |||
456 | #define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13)) | ||
457 | #define HFA384X_RX_STATUS_PCF BIT(12) | ||
458 | #define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8)) | ||
459 | #define HFA384X_RX_STATUS_UNDECR BIT(1) | ||
460 | #define HFA384X_RX_STATUS_FCSERR BIT(0) | ||
461 | |||
462 | #define HFA384X_RX_STATUS_GET_MSGTYPE(s) \ | ||
463 | (((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13) | ||
464 | #define HFA384X_RX_STATUS_GET_MACPORT(s) \ | ||
465 | (((s) & HFA384X_RX_STATUS_MACPORT) >> 8) | ||
466 | |||
467 | enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1, | ||
468 | HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 }; | ||
469 | |||
470 | |||
471 | #define HFA384X_TX_CTRL_ALT_RTRY BIT(5) | ||
472 | #define HFA384X_TX_CTRL_802_11 BIT(3) | ||
473 | #define HFA384X_TX_CTRL_802_3 0 | ||
474 | #define HFA384X_TX_CTRL_TX_EX BIT(2) | ||
475 | #define HFA384X_TX_CTRL_TX_OK BIT(1) | ||
476 | |||
477 | #define HFA384X_TX_STATUS_RETRYERR BIT(0) | ||
478 | #define HFA384X_TX_STATUS_AGEDERR BIT(1) | ||
479 | #define HFA384X_TX_STATUS_DISCON BIT(2) | ||
480 | #define HFA384X_TX_STATUS_FORMERR BIT(3) | ||
481 | |||
482 | /* HFA3861/3863 (BBP) Control Registers */ | ||
483 | #define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */ | ||
484 | #define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */ | ||
485 | #define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */ | ||
486 | #define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */ | ||
487 | #define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */ | ||
488 | |||
489 | |||
490 | #ifdef __KERNEL__ | ||
491 | |||
492 | #define PRISM2_TXFID_COUNT 8 | ||
493 | #define PRISM2_DATA_MAXLEN 2304 | ||
494 | #define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame)) | ||
495 | #define PRISM2_TXFID_EMPTY 0xffff | ||
496 | #define PRISM2_TXFID_RESERVED 0xfffe | ||
497 | #define PRISM2_DUMMY_FID 0xffff | ||
498 | #define MAX_SSID_LEN 32 | ||
499 | #define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */ | ||
500 | |||
501 | #define PRISM2_DUMP_RX_HDR BIT(0) | ||
502 | #define PRISM2_DUMP_TX_HDR BIT(1) | ||
503 | #define PRISM2_DUMP_TXEXC_HDR BIT(2) | ||
504 | |||
505 | struct hostap_tx_callback_info { | ||
506 | u16 idx; | ||
507 | void (*func)(struct sk_buff *, int ok, void *); | ||
508 | void *data; | ||
509 | struct hostap_tx_callback_info *next; | ||
510 | }; | ||
511 | |||
512 | |||
513 | /* IEEE 802.11 requires that STA supports concurrent reception of at least | ||
514 | * three fragmented frames. This define can be increased to support more | ||
515 | * concurrent frames, but it should be noted that each entry can consume about | ||
516 | * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ | ||
517 | #define PRISM2_FRAG_CACHE_LEN 4 | ||
518 | |||
519 | struct prism2_frag_entry { | ||
520 | unsigned long first_frag_time; | ||
521 | unsigned int seq; | ||
522 | unsigned int last_frag; | ||
523 | struct sk_buff *skb; | ||
524 | u8 src_addr[ETH_ALEN]; | ||
525 | u8 dst_addr[ETH_ALEN]; | ||
526 | }; | ||
527 | |||
528 | |||
529 | struct hostap_cmd_queue { | ||
530 | struct list_head list; | ||
531 | wait_queue_head_t compl; | ||
532 | volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type; | ||
533 | void (*callback)(struct net_device *dev, long context, u16 resp0, | ||
534 | u16 res); | ||
535 | long context; | ||
536 | u16 cmd, param0, param1; | ||
537 | u16 resp0, res; | ||
538 | volatile int issued, issuing; | ||
539 | |||
540 | atomic_t usecnt; | ||
541 | int del_req; | ||
542 | }; | ||
543 | |||
544 | /* options for hw_shutdown */ | ||
545 | #define HOSTAP_HW_NO_DISABLE BIT(0) | ||
546 | #define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1) | ||
547 | |||
548 | typedef struct local_info local_info_t; | ||
549 | |||
550 | struct prism2_helper_functions { | ||
551 | /* these functions are defined in hardware model specific files | ||
552 | * (hostap_{cs,plx,pci}.c */ | ||
553 | int (*card_present)(local_info_t *local); | ||
554 | void (*cor_sreset)(local_info_t *local); | ||
555 | int (*dev_open)(local_info_t *local); | ||
556 | int (*dev_close)(local_info_t *local); | ||
557 | void (*genesis_reset)(local_info_t *local, int hcr); | ||
558 | |||
559 | /* the following functions are from hostap_hw.c, but they may have some | ||
560 | * hardware model specific code */ | ||
561 | |||
562 | /* FIX: low-level commands like cmd might disappear at some point to | ||
563 | * make it easier to change them if needed (e.g., cmd would be replaced | ||
564 | * with write_mif/read_mif/testcmd/inquire); at least get_rid and | ||
565 | * set_rid might move to hostap_{cs,plx,pci}.c */ | ||
566 | int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1, | ||
567 | u16 *resp0); | ||
568 | void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs); | ||
569 | int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len, | ||
570 | int exact_len); | ||
571 | int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len); | ||
572 | int (*hw_enable)(struct net_device *dev, int initial); | ||
573 | int (*hw_config)(struct net_device *dev, int initial); | ||
574 | void (*hw_reset)(struct net_device *dev); | ||
575 | void (*hw_shutdown)(struct net_device *dev, int no_disable); | ||
576 | int (*reset_port)(struct net_device *dev); | ||
577 | void (*schedule_reset)(local_info_t *local); | ||
578 | int (*download)(local_info_t *local, | ||
579 | struct prism2_download_param *param); | ||
580 | int (*tx)(struct sk_buff *skb, struct net_device *dev); | ||
581 | int (*set_tim)(struct net_device *dev, int aid, int set); | ||
582 | int (*read_aux)(struct net_device *dev, unsigned addr, int len, | ||
583 | u8 *buf); | ||
584 | |||
585 | int need_tx_headroom; /* number of bytes of headroom needed before | ||
586 | * IEEE 802.11 header */ | ||
587 | enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type; | ||
588 | }; | ||
589 | |||
590 | |||
591 | struct prism2_download_data { | ||
592 | u32 dl_cmd; | ||
593 | u32 start_addr; | ||
594 | u32 num_areas; | ||
595 | struct prism2_download_data_area { | ||
596 | u32 addr; /* wlan card address */ | ||
597 | u32 len; | ||
598 | u8 *data; /* allocated data */ | ||
599 | } data[0]; | ||
600 | }; | ||
601 | |||
602 | |||
603 | #define HOSTAP_MAX_BSS_COUNT 64 | ||
604 | #define MAX_WPA_IE_LEN 64 | ||
605 | |||
606 | struct hostap_bss_info { | ||
607 | struct list_head list; | ||
608 | unsigned long last_update; | ||
609 | unsigned int count; | ||
610 | u8 bssid[ETH_ALEN]; | ||
611 | u16 capab_info; | ||
612 | u8 ssid[32]; | ||
613 | size_t ssid_len; | ||
614 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
615 | size_t wpa_ie_len; | ||
616 | u8 rsn_ie[MAX_WPA_IE_LEN]; | ||
617 | size_t rsn_ie_len; | ||
618 | int chan; | ||
619 | int included; | ||
620 | }; | ||
621 | |||
622 | |||
623 | /* Per radio private Host AP data - shared by all net devices interfaces used | ||
624 | * by each radio (wlan#, wlan#ap, wlan#sta, WDS). | ||
625 | * ((struct hostap_interface *) netdev_priv(dev))->local points to this | ||
626 | * structure. */ | ||
627 | struct local_info { | ||
628 | struct module *hw_module; | ||
629 | int card_idx; | ||
630 | int dev_enabled; | ||
631 | int master_dev_auto_open; /* was master device opened automatically */ | ||
632 | int num_dev_open; /* number of open devices */ | ||
633 | struct net_device *dev; /* master radio device */ | ||
634 | struct net_device *ddev; /* main data device */ | ||
635 | struct list_head hostap_interfaces; /* Host AP interface list (contains | ||
636 | * struct hostap_interface entries) | ||
637 | */ | ||
638 | rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock | ||
639 | * when removing entries from the list. | ||
640 | * TX and RX paths can use read lock. */ | ||
641 | spinlock_t cmdlock, baplock, lock; | ||
642 | struct semaphore rid_bap_sem; | ||
643 | u16 infofid; /* MAC buffer id for info frame */ | ||
644 | /* txfid, intransmitfid, next_txtid, and next_alloc are protected by | ||
645 | * txfidlock */ | ||
646 | spinlock_t txfidlock; | ||
647 | int txfid_len; /* length of allocated TX buffers */ | ||
648 | u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */ | ||
649 | /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if | ||
650 | * corresponding txfid is free for next TX frame */ | ||
651 | u16 intransmitfid[PRISM2_TXFID_COUNT]; | ||
652 | int next_txfid; /* index to the next txfid to be checked for | ||
653 | * availability */ | ||
654 | int next_alloc; /* index to the next intransmitfid to be checked for | ||
655 | * allocation events */ | ||
656 | |||
657 | /* bitfield for atomic bitops */ | ||
658 | #define HOSTAP_BITS_TRANSMIT 0 | ||
659 | #define HOSTAP_BITS_BAP_TASKLET 1 | ||
660 | #define HOSTAP_BITS_BAP_TASKLET2 2 | ||
661 | long bits; | ||
662 | |||
663 | struct ap_data *ap; | ||
664 | |||
665 | char essid[MAX_SSID_LEN + 1]; | ||
666 | char name[MAX_NAME_LEN + 1]; | ||
667 | int name_set; | ||
668 | u16 channel_mask; /* mask of allowed channels */ | ||
669 | u16 scan_channel_mask; /* mask of channels to be scanned */ | ||
670 | struct comm_tallies_sums comm_tallies; | ||
671 | struct net_device_stats stats; | ||
672 | struct proc_dir_entry *proc; | ||
673 | int iw_mode; /* operating mode (IW_MODE_*) */ | ||
674 | int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS | ||
675 | * 1: IW_MODE_ADHOC is "pseudo IBSS" */ | ||
676 | char bssid[ETH_ALEN]; | ||
677 | int channel; | ||
678 | int beacon_int; | ||
679 | int dtim_period; | ||
680 | int mtu; | ||
681 | int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */ | ||
682 | int fw_tx_rate_control; | ||
683 | u16 tx_rate_control; | ||
684 | u16 basic_rates; | ||
685 | int hw_resetting; | ||
686 | int hw_ready; | ||
687 | int hw_reset_tries; /* how many times reset has been tried */ | ||
688 | int hw_downloading; | ||
689 | int shutdown; | ||
690 | int pri_only; | ||
691 | int no_pri; /* no PRI f/w present */ | ||
692 | int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */ | ||
693 | |||
694 | enum { | ||
695 | PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF, | ||
696 | PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN | ||
697 | } txpower_type; | ||
698 | int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */ | ||
699 | |||
700 | /* command queue for hfa384x_cmd(); protected with cmdlock */ | ||
701 | struct list_head cmd_queue; | ||
702 | /* max_len for cmd_queue; in addition, cmd_callback can use two | ||
703 | * additional entries to prevent sleeping commands from stopping | ||
704 | * transmits */ | ||
705 | #define HOSTAP_CMD_QUEUE_MAX_LEN 16 | ||
706 | int cmd_queue_len; /* number of entries in cmd_queue */ | ||
707 | |||
708 | /* if card timeout is detected in interrupt context, reset_queue is | ||
709 | * used to schedule card reseting to be done in user context */ | ||
710 | struct work_struct reset_queue; | ||
711 | |||
712 | /* For scheduling a change of the promiscuous mode RID */ | ||
713 | int is_promisc; | ||
714 | struct work_struct set_multicast_list_queue; | ||
715 | |||
716 | struct work_struct set_tim_queue; | ||
717 | struct list_head set_tim_list; | ||
718 | spinlock_t set_tim_lock; | ||
719 | |||
720 | int wds_max_connections; | ||
721 | int wds_connections; | ||
722 | #define HOSTAP_WDS_BROADCAST_RA BIT(0) | ||
723 | #define HOSTAP_WDS_AP_CLIENT BIT(1) | ||
724 | #define HOSTAP_WDS_STANDARD_FRAME BIT(2) | ||
725 | u32 wds_type; | ||
726 | u16 tx_control; /* flags to be used in TX description */ | ||
727 | int manual_retry_count; /* -1 = use f/w default; otherwise retry count | ||
728 | * to be used with all frames */ | ||
729 | |||
730 | struct iw_statistics wstats; | ||
731 | unsigned long scan_timestamp; /* Time started to scan */ | ||
732 | enum { | ||
733 | PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, | ||
734 | PRISM2_MONITOR_CAPHDR = 2 | ||
735 | } monitor_type; | ||
736 | int (*saved_eth_header_parse)(struct sk_buff *skb, | ||
737 | unsigned char *haddr); | ||
738 | int monitor_allow_fcserr; | ||
739 | |||
740 | int hostapd; /* whether user space daemon, hostapd, is used for AP | ||
741 | * management */ | ||
742 | int hostapd_sta; /* whether hostapd is used with an extra STA interface | ||
743 | */ | ||
744 | struct net_device *apdev; | ||
745 | struct net_device_stats apdevstats; | ||
746 | |||
747 | char assoc_ap_addr[ETH_ALEN]; | ||
748 | struct net_device *stadev; | ||
749 | struct net_device_stats stadevstats; | ||
750 | |||
751 | #define WEP_KEYS 4 | ||
752 | #define WEP_KEY_LEN 13 | ||
753 | struct ieee80211_crypt_data *crypt[WEP_KEYS]; | ||
754 | int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ | ||
755 | struct timer_list crypt_deinit_timer; | ||
756 | struct list_head crypt_deinit_list; | ||
757 | |||
758 | int open_wep; /* allow unencrypted frames */ | ||
759 | int host_encrypt; | ||
760 | int host_decrypt; | ||
761 | int privacy_invoked; /* force privacy invoked flag even if no keys are | ||
762 | * configured */ | ||
763 | int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working | ||
764 | * in Host AP mode (STA f/w 1.4.9 or newer) */ | ||
765 | int bcrx_sta_key; /* use individual keys to override default keys even | ||
766 | * with RX of broad/multicast frames */ | ||
767 | |||
768 | struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN]; | ||
769 | unsigned int frag_next_idx; | ||
770 | |||
771 | int ieee_802_1x; /* is IEEE 802.1X used */ | ||
772 | |||
773 | int antsel_tx, antsel_rx; | ||
774 | int rts_threshold; /* dot11RTSThreshold */ | ||
775 | int fragm_threshold; /* dot11FragmentationThreshold */ | ||
776 | int auth_algs; /* PRISM2_AUTH_ flags */ | ||
777 | |||
778 | int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */ | ||
779 | int tallies32; /* 32-bit tallies in use */ | ||
780 | |||
781 | struct prism2_helper_functions *func; | ||
782 | |||
783 | u8 *pda; | ||
784 | int fw_ap; | ||
785 | #define PRISM2_FW_VER(major, minor, variant) \ | ||
786 | (((major) << 16) | ((minor) << 8) | variant) | ||
787 | u32 sta_fw_ver; | ||
788 | |||
789 | /* Tasklets for handling hardware IRQ related operations outside hw IRQ | ||
790 | * handler */ | ||
791 | struct tasklet_struct bap_tasklet; | ||
792 | |||
793 | struct tasklet_struct info_tasklet; | ||
794 | struct sk_buff_head info_list; /* info frames as skb's for | ||
795 | * info_tasklet */ | ||
796 | |||
797 | struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks | ||
798 | */ | ||
799 | |||
800 | struct tasklet_struct rx_tasklet; | ||
801 | struct sk_buff_head rx_list; | ||
802 | |||
803 | struct tasklet_struct sta_tx_exc_tasklet; | ||
804 | struct sk_buff_head sta_tx_exc_list; | ||
805 | |||
806 | int host_roaming; | ||
807 | unsigned long last_join_time; /* time of last JoinRequest */ | ||
808 | struct hfa384x_hostscan_result *last_scan_results; | ||
809 | int last_scan_results_count; | ||
810 | enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; | ||
811 | struct work_struct info_queue; | ||
812 | long pending_info; /* bit field of pending info_queue items */ | ||
813 | #define PRISM2_INFO_PENDING_LINKSTATUS 0 | ||
814 | #define PRISM2_INFO_PENDING_SCANRESULTS 1 | ||
815 | int prev_link_status; /* previous received LinkStatus info */ | ||
816 | int prev_linkstatus_connected; | ||
817 | u8 preferred_ap[6]; /* use this AP if possible */ | ||
818 | |||
819 | #ifdef PRISM2_CALLBACK | ||
820 | void *callback_data; /* Can be used in callbacks; e.g., allocate | ||
821 | * on enable event and free on disable event. | ||
822 | * Host AP driver code does not touch this. */ | ||
823 | #endif /* PRISM2_CALLBACK */ | ||
824 | |||
825 | wait_queue_head_t hostscan_wq; | ||
826 | |||
827 | /* Passive scan in Host AP mode */ | ||
828 | struct timer_list passive_scan_timer; | ||
829 | int passive_scan_interval; /* in seconds, 0 = disabled */ | ||
830 | int passive_scan_channel; | ||
831 | enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; | ||
832 | |||
833 | struct timer_list tick_timer; | ||
834 | unsigned long last_tick_timer; | ||
835 | unsigned int sw_tick_stuck; | ||
836 | |||
837 | /* commsQuality / dBmCommsQuality data from periodic polling; only | ||
838 | * valid for Managed and Ad-hoc modes */ | ||
839 | unsigned long last_comms_qual_update; | ||
840 | int comms_qual; /* in some odd unit.. */ | ||
841 | int avg_signal; /* in dB (note: negative) */ | ||
842 | int avg_noise; /* in dB (note: negative) */ | ||
843 | struct work_struct comms_qual_update; | ||
844 | |||
845 | /* RSSI to dBm adjustment (for RX descriptor fields) */ | ||
846 | int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */ | ||
847 | |||
848 | /* BSS list / protected by local->lock */ | ||
849 | struct list_head bss_list; | ||
850 | int num_bss_info; | ||
851 | int wpa; /* WPA support enabled */ | ||
852 | int tkip_countermeasures; | ||
853 | int drop_unencrypted; | ||
854 | /* Generic IEEE 802.11 info element to be added to | ||
855 | * ProbeResp/Beacon/(Re)AssocReq */ | ||
856 | u8 *generic_elem; | ||
857 | size_t generic_elem_len; | ||
858 | |||
859 | #ifdef PRISM2_DOWNLOAD_SUPPORT | ||
860 | /* Persistent volatile download data */ | ||
861 | struct prism2_download_data *dl_pri; | ||
862 | struct prism2_download_data *dl_sec; | ||
863 | #endif /* PRISM2_DOWNLOAD_SUPPORT */ | ||
864 | |||
865 | #ifdef PRISM2_IO_DEBUG | ||
866 | #define PRISM2_IO_DEBUG_SIZE 10000 | ||
867 | u32 io_debug[PRISM2_IO_DEBUG_SIZE]; | ||
868 | int io_debug_head; | ||
869 | int io_debug_enabled; | ||
870 | #endif /* PRISM2_IO_DEBUG */ | ||
871 | |||
872 | /* Pointer to hardware model specific (cs,pci,plx) private data. */ | ||
873 | void *hw_priv; | ||
874 | }; | ||
875 | |||
876 | |||
877 | /* Per interface private Host AP data | ||
878 | * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta, | ||
879 | * WDS) and netdev_priv(dev) points to this structure. */ | ||
880 | struct hostap_interface { | ||
881 | struct list_head list; /* list entry in Host AP interface list */ | ||
882 | struct net_device *dev; /* pointer to this device */ | ||
883 | struct local_info *local; /* pointer to shared private data */ | ||
884 | struct net_device_stats stats; | ||
885 | struct iw_spy_data spy_data; /* iwspy support */ | ||
886 | struct iw_public_data wireless_data; | ||
887 | |||
888 | enum { | ||
889 | HOSTAP_INTERFACE_MASTER, | ||
890 | HOSTAP_INTERFACE_MAIN, | ||
891 | HOSTAP_INTERFACE_AP, | ||
892 | HOSTAP_INTERFACE_STA, | ||
893 | HOSTAP_INTERFACE_WDS, | ||
894 | } type; | ||
895 | |||
896 | union { | ||
897 | struct hostap_interface_wds { | ||
898 | u8 remote_addr[ETH_ALEN]; | ||
899 | } wds; | ||
900 | } u; | ||
901 | }; | ||
902 | |||
903 | |||
904 | #define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2 | ||
905 | |||
906 | /* | ||
907 | * TX meta data - stored in skb->cb buffer, so this must not be increased over | ||
908 | * the 40-byte limit | ||
909 | */ | ||
910 | struct hostap_skb_tx_data { | ||
911 | u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */ | ||
912 | u8 rate; /* transmit rate */ | ||
913 | #define HOSTAP_TX_FLAGS_WDS BIT(0) | ||
914 | #define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1) | ||
915 | #define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2) | ||
916 | u8 flags; /* HOSTAP_TX_FLAGS_* */ | ||
917 | u16 tx_cb_idx; | ||
918 | struct hostap_interface *iface; | ||
919 | unsigned long jiffies; /* queueing timestamp */ | ||
920 | unsigned short ethertype; | ||
921 | }; | ||
922 | |||
923 | |||
924 | #ifndef PRISM2_NO_DEBUG | ||
925 | |||
926 | #define DEBUG_FID BIT(0) | ||
927 | #define DEBUG_PS BIT(1) | ||
928 | #define DEBUG_FLOW BIT(2) | ||
929 | #define DEBUG_AP BIT(3) | ||
930 | #define DEBUG_HW BIT(4) | ||
931 | #define DEBUG_EXTRA BIT(5) | ||
932 | #define DEBUG_EXTRA2 BIT(6) | ||
933 | #define DEBUG_PS2 BIT(7) | ||
934 | #define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA) | ||
935 | #define PDEBUG(n, args...) \ | ||
936 | do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0) | ||
937 | #define PDEBUG2(n, args...) \ | ||
938 | do { if ((n) & DEBUG_MASK) printk(args); } while (0) | ||
939 | |||
940 | #else /* PRISM2_NO_DEBUG */ | ||
941 | |||
942 | #define PDEBUG(n, args...) | ||
943 | #define PDEBUG2(n, args...) | ||
944 | |||
945 | #endif /* PRISM2_NO_DEBUG */ | ||
946 | |||
947 | enum { BAP0 = 0, BAP1 = 1 }; | ||
948 | |||
949 | #define PRISM2_IO_DEBUG_CMD_INB 0 | ||
950 | #define PRISM2_IO_DEBUG_CMD_INW 1 | ||
951 | #define PRISM2_IO_DEBUG_CMD_INSW 2 | ||
952 | #define PRISM2_IO_DEBUG_CMD_OUTB 3 | ||
953 | #define PRISM2_IO_DEBUG_CMD_OUTW 4 | ||
954 | #define PRISM2_IO_DEBUG_CMD_OUTSW 5 | ||
955 | #define PRISM2_IO_DEBUG_CMD_ERROR 6 | ||
956 | #define PRISM2_IO_DEBUG_CMD_INTERRUPT 7 | ||
957 | |||
958 | #ifdef PRISM2_IO_DEBUG | ||
959 | |||
960 | #define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \ | ||
961 | (((cmd) << 24) | ((reg) << 16) | value) | ||
962 | |||
963 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
964 | int reg, int value) | ||
965 | { | ||
966 | struct hostap_interface *iface = netdev_priv(dev); | ||
967 | local_info_t *local = iface->local; | ||
968 | |||
969 | if (!local->io_debug_enabled) | ||
970 | return; | ||
971 | |||
972 | local->io_debug[local->io_debug_head] = jiffies & 0xffffffff; | ||
973 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
974 | local->io_debug_head = 0; | ||
975 | local->io_debug[local->io_debug_head] = | ||
976 | PRISM2_IO_DEBUG_ENTRY(cmd, reg, value); | ||
977 | if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE) | ||
978 | local->io_debug_head = 0; | ||
979 | } | ||
980 | |||
981 | |||
982 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
983 | { | ||
984 | struct hostap_interface *iface = netdev_priv(dev); | ||
985 | local_info_t *local = iface->local; | ||
986 | unsigned long flags; | ||
987 | |||
988 | if (!local->io_debug_enabled) | ||
989 | return; | ||
990 | |||
991 | spin_lock_irqsave(&local->lock, flags); | ||
992 | prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err); | ||
993 | if (local->io_debug_enabled == 1) { | ||
994 | local->io_debug_enabled = 0; | ||
995 | printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name); | ||
996 | } | ||
997 | spin_unlock_irqrestore(&local->lock, flags); | ||
998 | } | ||
999 | |||
1000 | #else /* PRISM2_IO_DEBUG */ | ||
1001 | |||
1002 | static inline void prism2_io_debug_add(struct net_device *dev, int cmd, | ||
1003 | int reg, int value) | ||
1004 | { | ||
1005 | } | ||
1006 | |||
1007 | static inline void prism2_io_debug_error(struct net_device *dev, int err) | ||
1008 | { | ||
1009 | } | ||
1010 | |||
1011 | #endif /* PRISM2_IO_DEBUG */ | ||
1012 | |||
1013 | |||
1014 | #ifdef PRISM2_CALLBACK | ||
1015 | enum { | ||
1016 | /* Called when card is enabled */ | ||
1017 | PRISM2_CALLBACK_ENABLE, | ||
1018 | |||
1019 | /* Called when card is disabled */ | ||
1020 | PRISM2_CALLBACK_DISABLE, | ||
1021 | |||
1022 | /* Called when RX/TX starts/ends */ | ||
1023 | PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END, | ||
1024 | PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END | ||
1025 | }; | ||
1026 | void prism2_callback(local_info_t *local, int event); | ||
1027 | #else /* PRISM2_CALLBACK */ | ||
1028 | #define prism2_callback(d, e) do { } while (0) | ||
1029 | #endif /* PRISM2_CALLBACK */ | ||
1030 | |||
1031 | #endif /* __KERNEL__ */ | ||
1032 | |||
1033 | #endif /* HOSTAP_WLAN_H */ | ||
diff --git a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h deleted file mode 100644 index 53dd5248f9f1..000000000000 --- a/drivers/net/wireless/ieee802_11.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | #ifndef _IEEE802_11_H | ||
2 | #define _IEEE802_11_H | ||
3 | |||
4 | #define IEEE802_11_DATA_LEN 2304 | ||
5 | /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section | ||
6 | 6.2.1.1.2. | ||
7 | |||
8 | The figure in section 7.1.2 suggests a body size of up to 2312 | ||
9 | bytes is allowed, which is a bit confusing, I suspect this | ||
10 | represents the 2304 bytes of real data, plus a possible 8 bytes of | ||
11 | WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ | ||
12 | |||
13 | |||
14 | #define IEEE802_11_HLEN 30 | ||
15 | #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN) | ||
16 | |||
17 | struct ieee802_11_hdr { | ||
18 | u16 frame_ctl; | ||
19 | u16 duration_id; | ||
20 | u8 addr1[ETH_ALEN]; | ||
21 | u8 addr2[ETH_ALEN]; | ||
22 | u8 addr3[ETH_ALEN]; | ||
23 | u16 seq_ctl; | ||
24 | u8 addr4[ETH_ALEN]; | ||
25 | } __attribute__ ((packed)); | ||
26 | |||
27 | /* Frame control field constants */ | ||
28 | #define IEEE802_11_FCTL_VERS 0x0002 | ||
29 | #define IEEE802_11_FCTL_FTYPE 0x000c | ||
30 | #define IEEE802_11_FCTL_STYPE 0x00f0 | ||
31 | #define IEEE802_11_FCTL_TODS 0x0100 | ||
32 | #define IEEE802_11_FCTL_FROMDS 0x0200 | ||
33 | #define IEEE802_11_FCTL_MOREFRAGS 0x0400 | ||
34 | #define IEEE802_11_FCTL_RETRY 0x0800 | ||
35 | #define IEEE802_11_FCTL_PM 0x1000 | ||
36 | #define IEEE802_11_FCTL_MOREDATA 0x2000 | ||
37 | #define IEEE802_11_FCTL_WEP 0x4000 | ||
38 | #define IEEE802_11_FCTL_ORDER 0x8000 | ||
39 | |||
40 | #define IEEE802_11_FTYPE_MGMT 0x0000 | ||
41 | #define IEEE802_11_FTYPE_CTL 0x0004 | ||
42 | #define IEEE802_11_FTYPE_DATA 0x0008 | ||
43 | |||
44 | /* management */ | ||
45 | #define IEEE802_11_STYPE_ASSOC_REQ 0x0000 | ||
46 | #define IEEE802_11_STYPE_ASSOC_RESP 0x0010 | ||
47 | #define IEEE802_11_STYPE_REASSOC_REQ 0x0020 | ||
48 | #define IEEE802_11_STYPE_REASSOC_RESP 0x0030 | ||
49 | #define IEEE802_11_STYPE_PROBE_REQ 0x0040 | ||
50 | #define IEEE802_11_STYPE_PROBE_RESP 0x0050 | ||
51 | #define IEEE802_11_STYPE_BEACON 0x0080 | ||
52 | #define IEEE802_11_STYPE_ATIM 0x0090 | ||
53 | #define IEEE802_11_STYPE_DISASSOC 0x00A0 | ||
54 | #define IEEE802_11_STYPE_AUTH 0x00B0 | ||
55 | #define IEEE802_11_STYPE_DEAUTH 0x00C0 | ||
56 | |||
57 | /* control */ | ||
58 | #define IEEE802_11_STYPE_PSPOLL 0x00A0 | ||
59 | #define IEEE802_11_STYPE_RTS 0x00B0 | ||
60 | #define IEEE802_11_STYPE_CTS 0x00C0 | ||
61 | #define IEEE802_11_STYPE_ACK 0x00D0 | ||
62 | #define IEEE802_11_STYPE_CFEND 0x00E0 | ||
63 | #define IEEE802_11_STYPE_CFENDACK 0x00F0 | ||
64 | |||
65 | /* data */ | ||
66 | #define IEEE802_11_STYPE_DATA 0x0000 | ||
67 | #define IEEE802_11_STYPE_DATA_CFACK 0x0010 | ||
68 | #define IEEE802_11_STYPE_DATA_CFPOLL 0x0020 | ||
69 | #define IEEE802_11_STYPE_DATA_CFACKPOLL 0x0030 | ||
70 | #define IEEE802_11_STYPE_NULLFUNC 0x0040 | ||
71 | #define IEEE802_11_STYPE_CFACK 0x0050 | ||
72 | #define IEEE802_11_STYPE_CFPOLL 0x0060 | ||
73 | #define IEEE802_11_STYPE_CFACKPOLL 0x0070 | ||
74 | |||
75 | #define IEEE802_11_SCTL_FRAG 0x000F | ||
76 | #define IEEE802_11_SCTL_SEQ 0xFFF0 | ||
77 | |||
78 | #endif /* _IEEE802_11_H */ | ||
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c new file mode 100644 index 000000000000..a47fce4beadf --- /dev/null +++ b/drivers/net/wireless/ipw2100.c | |||
@@ -0,0 +1,8679 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify it | ||
6 | under the terms of version 2 of the GNU General Public License as | ||
7 | published by the Free Software Foundation. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along with | ||
15 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
16 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | |||
18 | The full GNU General Public License is included in this distribution in the | ||
19 | file called LICENSE. | ||
20 | |||
21 | Contact Information: | ||
22 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
23 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | |||
25 | Portions of this file are based on the sample_* files provided by Wireless | ||
26 | Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes | ||
27 | <jt@hpl.hp.com> | ||
28 | |||
29 | Portions of this file are based on the Host AP project, | ||
30 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
31 | <jkmaline@cc.hut.fi> | ||
32 | Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
33 | |||
34 | Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and | ||
35 | ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c | ||
36 | available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox | ||
37 | |||
38 | ******************************************************************************/ | ||
39 | /* | ||
40 | |||
41 | Initial driver on which this is based was developed by Janusz Gorycki, | ||
42 | Maciej Urbaniak, and Maciej Sosnowski. | ||
43 | |||
44 | Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak. | ||
45 | |||
46 | Theory of Operation | ||
47 | |||
48 | Tx - Commands and Data | ||
49 | |||
50 | Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs) | ||
51 | Each TBD contains a pointer to the physical (dma_addr_t) address of data being | ||
52 | sent to the firmware as well as the length of the data. | ||
53 | |||
54 | The host writes to the TBD queue at the WRITE index. The WRITE index points | ||
55 | to the _next_ packet to be written and is advanced when after the TBD has been | ||
56 | filled. | ||
57 | |||
58 | The firmware pulls from the TBD queue at the READ index. The READ index points | ||
59 | to the currently being read entry, and is advanced once the firmware is | ||
60 | done with a packet. | ||
61 | |||
62 | When data is sent to the firmware, the first TBD is used to indicate to the | ||
63 | firmware if a Command or Data is being sent. If it is Command, all of the | ||
64 | command information is contained within the physical address referred to by the | ||
65 | TBD. If it is Data, the first TBD indicates the type of data packet, number | ||
66 | of fragments, etc. The next TBD then referrs to the actual packet location. | ||
67 | |||
68 | The Tx flow cycle is as follows: | ||
69 | |||
70 | 1) ipw2100_tx() is called by kernel with SKB to transmit | ||
71 | 2) Packet is move from the tx_free_list and appended to the transmit pending | ||
72 | list (tx_pend_list) | ||
73 | 3) work is scheduled to move pending packets into the shared circular queue. | ||
74 | 4) when placing packet in the circular queue, the incoming SKB is DMA mapped | ||
75 | to a physical address. That address is entered into a TBD. Two TBDs are | ||
76 | filled out. The first indicating a data packet, the second referring to the | ||
77 | actual payload data. | ||
78 | 5) the packet is removed from tx_pend_list and placed on the end of the | ||
79 | firmware pending list (fw_pend_list) | ||
80 | 6) firmware is notified that the WRITE index has | ||
81 | 7) Once the firmware has processed the TBD, INTA is triggered. | ||
82 | 8) For each Tx interrupt received from the firmware, the READ index is checked | ||
83 | to see which TBDs are done being processed. | ||
84 | 9) For each TBD that has been processed, the ISR pulls the oldest packet | ||
85 | from the fw_pend_list. | ||
86 | 10)The packet structure contained in the fw_pend_list is then used | ||
87 | to unmap the DMA address and to free the SKB originally passed to the driver | ||
88 | from the kernel. | ||
89 | 11)The packet structure is placed onto the tx_free_list | ||
90 | |||
91 | The above steps are the same for commands, only the msg_free_list/msg_pend_list | ||
92 | are used instead of tx_free_list/tx_pend_list | ||
93 | |||
94 | ... | ||
95 | |||
96 | Critical Sections / Locking : | ||
97 | |||
98 | There are two locks utilized. The first is the low level lock (priv->low_lock) | ||
99 | that protects the following: | ||
100 | |||
101 | - Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows: | ||
102 | |||
103 | tx_free_list : Holds pre-allocated Tx buffers. | ||
104 | TAIL modified in __ipw2100_tx_process() | ||
105 | HEAD modified in ipw2100_tx() | ||
106 | |||
107 | tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring | ||
108 | TAIL modified ipw2100_tx() | ||
109 | HEAD modified by ipw2100_tx_send_data() | ||
110 | |||
111 | msg_free_list : Holds pre-allocated Msg (Command) buffers | ||
112 | TAIL modified in __ipw2100_tx_process() | ||
113 | HEAD modified in ipw2100_hw_send_command() | ||
114 | |||
115 | msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring | ||
116 | TAIL modified in ipw2100_hw_send_command() | ||
117 | HEAD modified in ipw2100_tx_send_commands() | ||
118 | |||
119 | The flow of data on the TX side is as follows: | ||
120 | |||
121 | MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST | ||
122 | TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST | ||
123 | |||
124 | The methods that work on the TBD ring are protected via priv->low_lock. | ||
125 | |||
126 | - The internal data state of the device itself | ||
127 | - Access to the firmware read/write indexes for the BD queues | ||
128 | and associated logic | ||
129 | |||
130 | All external entry functions are locked with the priv->action_lock to ensure | ||
131 | that only one external action is invoked at a time. | ||
132 | |||
133 | |||
134 | */ | ||
135 | |||
136 | #include <linux/compiler.h> | ||
137 | #include <linux/config.h> | ||
138 | #include <linux/errno.h> | ||
139 | #include <linux/if_arp.h> | ||
140 | #include <linux/in6.h> | ||
141 | #include <linux/in.h> | ||
142 | #include <linux/ip.h> | ||
143 | #include <linux/kernel.h> | ||
144 | #include <linux/kmod.h> | ||
145 | #include <linux/module.h> | ||
146 | #include <linux/netdevice.h> | ||
147 | #include <linux/ethtool.h> | ||
148 | #include <linux/pci.h> | ||
149 | #include <linux/dma-mapping.h> | ||
150 | #include <linux/proc_fs.h> | ||
151 | #include <linux/skbuff.h> | ||
152 | #include <asm/uaccess.h> | ||
153 | #include <asm/io.h> | ||
154 | #define __KERNEL_SYSCALLS__ | ||
155 | #include <linux/fs.h> | ||
156 | #include <linux/mm.h> | ||
157 | #include <linux/slab.h> | ||
158 | #include <linux/unistd.h> | ||
159 | #include <linux/stringify.h> | ||
160 | #include <linux/tcp.h> | ||
161 | #include <linux/types.h> | ||
162 | #include <linux/version.h> | ||
163 | #include <linux/time.h> | ||
164 | #include <linux/firmware.h> | ||
165 | #include <linux/acpi.h> | ||
166 | #include <linux/ctype.h> | ||
167 | |||
168 | #include "ipw2100.h" | ||
169 | |||
170 | #define IPW2100_VERSION "1.1.0" | ||
171 | |||
172 | #define DRV_NAME "ipw2100" | ||
173 | #define DRV_VERSION IPW2100_VERSION | ||
174 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" | ||
175 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" | ||
176 | |||
177 | |||
178 | /* Debugging stuff */ | ||
179 | #ifdef CONFIG_IPW_DEBUG | ||
180 | #define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */ | ||
181 | #endif | ||
182 | |||
183 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | ||
184 | MODULE_VERSION(DRV_VERSION); | ||
185 | MODULE_AUTHOR(DRV_COPYRIGHT); | ||
186 | MODULE_LICENSE("GPL"); | ||
187 | |||
188 | static int debug = 0; | ||
189 | static int mode = 0; | ||
190 | static int channel = 0; | ||
191 | static int associate = 1; | ||
192 | static int disable = 0; | ||
193 | #ifdef CONFIG_PM | ||
194 | static struct ipw2100_fw ipw2100_firmware; | ||
195 | #endif | ||
196 | |||
197 | #include <linux/moduleparam.h> | ||
198 | module_param(debug, int, 0444); | ||
199 | module_param(mode, int, 0444); | ||
200 | module_param(channel, int, 0444); | ||
201 | module_param(associate, int, 0444); | ||
202 | module_param(disable, int, 0444); | ||
203 | |||
204 | MODULE_PARM_DESC(debug, "debug level"); | ||
205 | MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); | ||
206 | MODULE_PARM_DESC(channel, "channel"); | ||
207 | MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); | ||
208 | MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); | ||
209 | |||
210 | static u32 ipw2100_debug_level = IPW_DL_NONE; | ||
211 | |||
212 | #ifdef CONFIG_IPW_DEBUG | ||
213 | #define IPW_DEBUG(level, message...) \ | ||
214 | do { \ | ||
215 | if (ipw2100_debug_level & (level)) { \ | ||
216 | printk(KERN_DEBUG "ipw2100: %c %s ", \ | ||
217 | in_interrupt() ? 'I' : 'U', __FUNCTION__); \ | ||
218 | printk(message); \ | ||
219 | } \ | ||
220 | } while (0) | ||
221 | #else | ||
222 | #define IPW_DEBUG(level, message...) do {} while (0) | ||
223 | #endif /* CONFIG_IPW_DEBUG */ | ||
224 | |||
225 | #ifdef CONFIG_IPW_DEBUG | ||
226 | static const char *command_types[] = { | ||
227 | "undefined", | ||
228 | "unused", /* HOST_ATTENTION */ | ||
229 | "HOST_COMPLETE", | ||
230 | "unused", /* SLEEP */ | ||
231 | "unused", /* HOST_POWER_DOWN */ | ||
232 | "unused", | ||
233 | "SYSTEM_CONFIG", | ||
234 | "unused", /* SET_IMR */ | ||
235 | "SSID", | ||
236 | "MANDATORY_BSSID", | ||
237 | "AUTHENTICATION_TYPE", | ||
238 | "ADAPTER_ADDRESS", | ||
239 | "PORT_TYPE", | ||
240 | "INTERNATIONAL_MODE", | ||
241 | "CHANNEL", | ||
242 | "RTS_THRESHOLD", | ||
243 | "FRAG_THRESHOLD", | ||
244 | "POWER_MODE", | ||
245 | "TX_RATES", | ||
246 | "BASIC_TX_RATES", | ||
247 | "WEP_KEY_INFO", | ||
248 | "unused", | ||
249 | "unused", | ||
250 | "unused", | ||
251 | "unused", | ||
252 | "WEP_KEY_INDEX", | ||
253 | "WEP_FLAGS", | ||
254 | "ADD_MULTICAST", | ||
255 | "CLEAR_ALL_MULTICAST", | ||
256 | "BEACON_INTERVAL", | ||
257 | "ATIM_WINDOW", | ||
258 | "CLEAR_STATISTICS", | ||
259 | "undefined", | ||
260 | "undefined", | ||
261 | "undefined", | ||
262 | "undefined", | ||
263 | "TX_POWER_INDEX", | ||
264 | "undefined", | ||
265 | "undefined", | ||
266 | "undefined", | ||
267 | "undefined", | ||
268 | "undefined", | ||
269 | "undefined", | ||
270 | "BROADCAST_SCAN", | ||
271 | "CARD_DISABLE", | ||
272 | "PREFERRED_BSSID", | ||
273 | "SET_SCAN_OPTIONS", | ||
274 | "SCAN_DWELL_TIME", | ||
275 | "SWEEP_TABLE", | ||
276 | "AP_OR_STATION_TABLE", | ||
277 | "GROUP_ORDINALS", | ||
278 | "SHORT_RETRY_LIMIT", | ||
279 | "LONG_RETRY_LIMIT", | ||
280 | "unused", /* SAVE_CALIBRATION */ | ||
281 | "unused", /* RESTORE_CALIBRATION */ | ||
282 | "undefined", | ||
283 | "undefined", | ||
284 | "undefined", | ||
285 | "HOST_PRE_POWER_DOWN", | ||
286 | "unused", /* HOST_INTERRUPT_COALESCING */ | ||
287 | "undefined", | ||
288 | "CARD_DISABLE_PHY_OFF", | ||
289 | "MSDU_TX_RATES" | ||
290 | "undefined", | ||
291 | "undefined", | ||
292 | "SET_STATION_STAT_BITS", | ||
293 | "CLEAR_STATIONS_STAT_BITS", | ||
294 | "LEAP_ROGUE_MODE", | ||
295 | "SET_SECURITY_INFORMATION", | ||
296 | "DISASSOCIATION_BSSID", | ||
297 | "SET_WPA_ASS_IE" | ||
298 | }; | ||
299 | #endif | ||
300 | |||
301 | |||
302 | /* Pre-decl until we get the code solid and then we can clean it up */ | ||
303 | static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); | ||
304 | static void ipw2100_tx_send_data(struct ipw2100_priv *priv); | ||
305 | static int ipw2100_adapter_setup(struct ipw2100_priv *priv); | ||
306 | |||
307 | static void ipw2100_queues_initialize(struct ipw2100_priv *priv); | ||
308 | static void ipw2100_queues_free(struct ipw2100_priv *priv); | ||
309 | static int ipw2100_queues_allocate(struct ipw2100_priv *priv); | ||
310 | |||
311 | static int ipw2100_fw_download(struct ipw2100_priv *priv, | ||
312 | struct ipw2100_fw *fw); | ||
313 | static int ipw2100_get_firmware(struct ipw2100_priv *priv, | ||
314 | struct ipw2100_fw *fw); | ||
315 | static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, | ||
316 | size_t max); | ||
317 | static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, | ||
318 | size_t max); | ||
319 | static void ipw2100_release_firmware(struct ipw2100_priv *priv, | ||
320 | struct ipw2100_fw *fw); | ||
321 | static int ipw2100_ucode_download(struct ipw2100_priv *priv, | ||
322 | struct ipw2100_fw *fw); | ||
323 | static void ipw2100_wx_event_work(struct ipw2100_priv *priv); | ||
324 | static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev); | ||
325 | static struct iw_handler_def ipw2100_wx_handler_def; | ||
326 | |||
327 | |||
328 | static inline void read_register(struct net_device *dev, u32 reg, u32 *val) | ||
329 | { | ||
330 | *val = readl((void *)(dev->base_addr + reg)); | ||
331 | IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); | ||
332 | } | ||
333 | |||
334 | static inline void write_register(struct net_device *dev, u32 reg, u32 val) | ||
335 | { | ||
336 | writel(val, (void *)(dev->base_addr + reg)); | ||
337 | IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); | ||
338 | } | ||
339 | |||
340 | static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val) | ||
341 | { | ||
342 | *val = readw((void *)(dev->base_addr + reg)); | ||
343 | IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); | ||
344 | } | ||
345 | |||
346 | static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val) | ||
347 | { | ||
348 | *val = readb((void *)(dev->base_addr + reg)); | ||
349 | IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); | ||
350 | } | ||
351 | |||
352 | static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) | ||
353 | { | ||
354 | writew(val, (void *)(dev->base_addr + reg)); | ||
355 | IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); | ||
356 | } | ||
357 | |||
358 | |||
359 | static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) | ||
360 | { | ||
361 | writeb(val, (void *)(dev->base_addr + reg)); | ||
362 | IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); | ||
363 | } | ||
364 | |||
365 | static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val) | ||
366 | { | ||
367 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
368 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
369 | read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
370 | } | ||
371 | |||
372 | static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val) | ||
373 | { | ||
374 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
375 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
376 | write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
377 | } | ||
378 | |||
379 | static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val) | ||
380 | { | ||
381 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
382 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
383 | read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
384 | } | ||
385 | |||
386 | static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val) | ||
387 | { | ||
388 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
389 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
390 | write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
391 | } | ||
392 | |||
393 | static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val) | ||
394 | { | ||
395 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
396 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
397 | read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
398 | } | ||
399 | |||
400 | static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val) | ||
401 | { | ||
402 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
403 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
404 | write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); | ||
405 | } | ||
406 | |||
407 | static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr) | ||
408 | { | ||
409 | write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, | ||
410 | addr & IPW_REG_INDIRECT_ADDR_MASK); | ||
411 | } | ||
412 | |||
413 | static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val) | ||
414 | { | ||
415 | write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val); | ||
416 | } | ||
417 | |||
418 | static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len, | ||
419 | const u8 *buf) | ||
420 | { | ||
421 | u32 aligned_addr; | ||
422 | u32 aligned_len; | ||
423 | u32 dif_len; | ||
424 | u32 i; | ||
425 | |||
426 | /* read first nibble byte by byte */ | ||
427 | aligned_addr = addr & (~0x3); | ||
428 | dif_len = addr - aligned_addr; | ||
429 | if (dif_len) { | ||
430 | /* Start reading at aligned_addr + dif_len */ | ||
431 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
432 | aligned_addr); | ||
433 | for (i = dif_len; i < 4; i++, buf++) | ||
434 | write_register_byte( | ||
435 | dev, IPW_REG_INDIRECT_ACCESS_DATA + i, | ||
436 | *buf); | ||
437 | |||
438 | len -= dif_len; | ||
439 | aligned_addr += 4; | ||
440 | } | ||
441 | |||
442 | /* read DWs through autoincrement registers */ | ||
443 | write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, | ||
444 | aligned_addr); | ||
445 | aligned_len = len & (~0x3); | ||
446 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | ||
447 | write_register( | ||
448 | dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf); | ||
449 | |||
450 | /* copy the last nibble */ | ||
451 | dif_len = len - aligned_len; | ||
452 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); | ||
453 | for (i = 0; i < dif_len; i++, buf++) | ||
454 | write_register_byte( | ||
455 | dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf); | ||
456 | } | ||
457 | |||
458 | static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len, | ||
459 | u8 *buf) | ||
460 | { | ||
461 | u32 aligned_addr; | ||
462 | u32 aligned_len; | ||
463 | u32 dif_len; | ||
464 | u32 i; | ||
465 | |||
466 | /* read first nibble byte by byte */ | ||
467 | aligned_addr = addr & (~0x3); | ||
468 | dif_len = addr - aligned_addr; | ||
469 | if (dif_len) { | ||
470 | /* Start reading at aligned_addr + dif_len */ | ||
471 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
472 | aligned_addr); | ||
473 | for (i = dif_len; i < 4; i++, buf++) | ||
474 | read_register_byte( | ||
475 | dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); | ||
476 | |||
477 | len -= dif_len; | ||
478 | aligned_addr += 4; | ||
479 | } | ||
480 | |||
481 | /* read DWs through autoincrement registers */ | ||
482 | write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, | ||
483 | aligned_addr); | ||
484 | aligned_len = len & (~0x3); | ||
485 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | ||
486 | read_register(dev, IPW_REG_AUTOINCREMENT_DATA, | ||
487 | (u32 *)buf); | ||
488 | |||
489 | /* copy the last nibble */ | ||
490 | dif_len = len - aligned_len; | ||
491 | write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, | ||
492 | aligned_addr); | ||
493 | for (i = 0; i < dif_len; i++, buf++) | ||
494 | read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + | ||
495 | i, buf); | ||
496 | } | ||
497 | |||
498 | static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) | ||
499 | { | ||
500 | return (dev->base_addr && | ||
501 | (readl((void *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START)) | ||
502 | == IPW_DATA_DOA_DEBUG_VALUE)); | ||
503 | } | ||
504 | |||
505 | static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, | ||
506 | void *val, u32 *len) | ||
507 | { | ||
508 | struct ipw2100_ordinals *ordinals = &priv->ordinals; | ||
509 | u32 addr; | ||
510 | u32 field_info; | ||
511 | u16 field_len; | ||
512 | u16 field_count; | ||
513 | u32 total_length; | ||
514 | |||
515 | if (ordinals->table1_addr == 0) { | ||
516 | printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals " | ||
517 | "before they have been loaded.\n"); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { | ||
522 | if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) { | ||
523 | *len = IPW_ORD_TAB_1_ENTRY_SIZE; | ||
524 | |||
525 | printk(KERN_WARNING DRV_NAME | ||
526 | ": ordinal buffer length too small, need %zd\n", | ||
527 | IPW_ORD_TAB_1_ENTRY_SIZE); | ||
528 | |||
529 | return -EINVAL; | ||
530 | } | ||
531 | |||
532 | read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), | ||
533 | &addr); | ||
534 | read_nic_dword(priv->net_dev, addr, val); | ||
535 | |||
536 | *len = IPW_ORD_TAB_1_ENTRY_SIZE; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) { | ||
542 | |||
543 | ord -= IPW_START_ORD_TAB_2; | ||
544 | |||
545 | /* get the address of statistic */ | ||
546 | read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3), | ||
547 | &addr); | ||
548 | |||
549 | /* get the second DW of statistics ; | ||
550 | * two 16-bit words - first is length, second is count */ | ||
551 | read_nic_dword(priv->net_dev, | ||
552 | ordinals->table2_addr + (ord << 3) + sizeof(u32), | ||
553 | &field_info); | ||
554 | |||
555 | /* get each entry length */ | ||
556 | field_len = *((u16 *)&field_info); | ||
557 | |||
558 | /* get number of entries */ | ||
559 | field_count = *(((u16 *)&field_info) + 1); | ||
560 | |||
561 | /* abort if no enought memory */ | ||
562 | total_length = field_len * field_count; | ||
563 | if (total_length > *len) { | ||
564 | *len = total_length; | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | *len = total_length; | ||
569 | if (!total_length) | ||
570 | return 0; | ||
571 | |||
572 | /* read the ordinal data from the SRAM */ | ||
573 | read_nic_memory(priv->net_dev, addr, total_length, val); | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor " | ||
579 | "in table 2\n", ord); | ||
580 | |||
581 | return -EINVAL; | ||
582 | } | ||
583 | |||
584 | static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val, | ||
585 | u32 *len) | ||
586 | { | ||
587 | struct ipw2100_ordinals *ordinals = &priv->ordinals; | ||
588 | u32 addr; | ||
589 | |||
590 | if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { | ||
591 | if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) { | ||
592 | *len = IPW_ORD_TAB_1_ENTRY_SIZE; | ||
593 | IPW_DEBUG_INFO("wrong size\n"); | ||
594 | return -EINVAL; | ||
595 | } | ||
596 | |||
597 | read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), | ||
598 | &addr); | ||
599 | |||
600 | write_nic_dword(priv->net_dev, addr, *val); | ||
601 | |||
602 | *len = IPW_ORD_TAB_1_ENTRY_SIZE; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | IPW_DEBUG_INFO("wrong table\n"); | ||
608 | if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) | ||
609 | return -EINVAL; | ||
610 | |||
611 | return -EINVAL; | ||
612 | } | ||
613 | |||
614 | static char *snprint_line(char *buf, size_t count, | ||
615 | const u8 *data, u32 len, u32 ofs) | ||
616 | { | ||
617 | int out, i, j, l; | ||
618 | char c; | ||
619 | |||
620 | out = snprintf(buf, count, "%08X", ofs); | ||
621 | |||
622 | for (l = 0, i = 0; i < 2; i++) { | ||
623 | out += snprintf(buf + out, count - out, " "); | ||
624 | for (j = 0; j < 8 && l < len; j++, l++) | ||
625 | out += snprintf(buf + out, count - out, "%02X ", | ||
626 | data[(i * 8 + j)]); | ||
627 | for (; j < 8; j++) | ||
628 | out += snprintf(buf + out, count - out, " "); | ||
629 | } | ||
630 | |||
631 | out += snprintf(buf + out, count - out, " "); | ||
632 | for (l = 0, i = 0; i < 2; i++) { | ||
633 | out += snprintf(buf + out, count - out, " "); | ||
634 | for (j = 0; j < 8 && l < len; j++, l++) { | ||
635 | c = data[(i * 8 + j)]; | ||
636 | if (!isascii(c) || !isprint(c)) | ||
637 | c = '.'; | ||
638 | |||
639 | out += snprintf(buf + out, count - out, "%c", c); | ||
640 | } | ||
641 | |||
642 | for (; j < 8; j++) | ||
643 | out += snprintf(buf + out, count - out, " "); | ||
644 | } | ||
645 | |||
646 | return buf; | ||
647 | } | ||
648 | |||
649 | static void printk_buf(int level, const u8 *data, u32 len) | ||
650 | { | ||
651 | char line[81]; | ||
652 | u32 ofs = 0; | ||
653 | if (!(ipw2100_debug_level & level)) | ||
654 | return; | ||
655 | |||
656 | while (len) { | ||
657 | printk(KERN_DEBUG "%s\n", | ||
658 | snprint_line(line, sizeof(line), &data[ofs], | ||
659 | min(len, 16U), ofs)); | ||
660 | ofs += 16; | ||
661 | len -= min(len, 16U); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | |||
666 | |||
667 | #define MAX_RESET_BACKOFF 10 | ||
668 | |||
669 | static inline void schedule_reset(struct ipw2100_priv *priv) | ||
670 | { | ||
671 | unsigned long now = get_seconds(); | ||
672 | |||
673 | /* If we haven't received a reset request within the backoff period, | ||
674 | * then we can reset the backoff interval so this reset occurs | ||
675 | * immediately */ | ||
676 | if (priv->reset_backoff && | ||
677 | (now - priv->last_reset > priv->reset_backoff)) | ||
678 | priv->reset_backoff = 0; | ||
679 | |||
680 | priv->last_reset = get_seconds(); | ||
681 | |||
682 | if (!(priv->status & STATUS_RESET_PENDING)) { | ||
683 | IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", | ||
684 | priv->net_dev->name, priv->reset_backoff); | ||
685 | netif_carrier_off(priv->net_dev); | ||
686 | netif_stop_queue(priv->net_dev); | ||
687 | priv->status |= STATUS_RESET_PENDING; | ||
688 | if (priv->reset_backoff) | ||
689 | queue_delayed_work(priv->workqueue, &priv->reset_work, | ||
690 | priv->reset_backoff * HZ); | ||
691 | else | ||
692 | queue_work(priv->workqueue, &priv->reset_work); | ||
693 | |||
694 | if (priv->reset_backoff < MAX_RESET_BACKOFF) | ||
695 | priv->reset_backoff++; | ||
696 | |||
697 | wake_up_interruptible(&priv->wait_command_queue); | ||
698 | } else | ||
699 | IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n", | ||
700 | priv->net_dev->name); | ||
701 | |||
702 | } | ||
703 | |||
704 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | ||
705 | static int ipw2100_hw_send_command(struct ipw2100_priv *priv, | ||
706 | struct host_command * cmd) | ||
707 | { | ||
708 | struct list_head *element; | ||
709 | struct ipw2100_tx_packet *packet; | ||
710 | unsigned long flags; | ||
711 | int err = 0; | ||
712 | |||
713 | IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", | ||
714 | command_types[cmd->host_command], cmd->host_command, | ||
715 | cmd->host_command_length); | ||
716 | printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters, | ||
717 | cmd->host_command_length); | ||
718 | |||
719 | spin_lock_irqsave(&priv->low_lock, flags); | ||
720 | |||
721 | if (priv->fatal_error) { | ||
722 | IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n"); | ||
723 | err = -EIO; | ||
724 | goto fail_unlock; | ||
725 | } | ||
726 | |||
727 | if (!(priv->status & STATUS_RUNNING)) { | ||
728 | IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n"); | ||
729 | err = -EIO; | ||
730 | goto fail_unlock; | ||
731 | } | ||
732 | |||
733 | if (priv->status & STATUS_CMD_ACTIVE) { | ||
734 | IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n"); | ||
735 | err = -EBUSY; | ||
736 | goto fail_unlock; | ||
737 | } | ||
738 | |||
739 | if (list_empty(&priv->msg_free_list)) { | ||
740 | IPW_DEBUG_INFO("no available msg buffers\n"); | ||
741 | goto fail_unlock; | ||
742 | } | ||
743 | |||
744 | priv->status |= STATUS_CMD_ACTIVE; | ||
745 | priv->messages_sent++; | ||
746 | |||
747 | element = priv->msg_free_list.next; | ||
748 | |||
749 | packet = list_entry(element, struct ipw2100_tx_packet, list); | ||
750 | packet->jiffy_start = jiffies; | ||
751 | |||
752 | /* initialize the firmware command packet */ | ||
753 | packet->info.c_struct.cmd->host_command_reg = cmd->host_command; | ||
754 | packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1; | ||
755 | packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length; | ||
756 | packet->info.c_struct.cmd->sequence = cmd->host_command_sequence; | ||
757 | |||
758 | memcpy(packet->info.c_struct.cmd->host_command_params_reg, | ||
759 | cmd->host_command_parameters, | ||
760 | sizeof(packet->info.c_struct.cmd->host_command_params_reg)); | ||
761 | |||
762 | list_del(element); | ||
763 | DEC_STAT(&priv->msg_free_stat); | ||
764 | |||
765 | list_add_tail(element, &priv->msg_pend_list); | ||
766 | INC_STAT(&priv->msg_pend_stat); | ||
767 | |||
768 | ipw2100_tx_send_commands(priv); | ||
769 | ipw2100_tx_send_data(priv); | ||
770 | |||
771 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
772 | |||
773 | /* | ||
774 | * We must wait for this command to complete before another | ||
775 | * command can be sent... but if we wait more than 3 seconds | ||
776 | * then there is a problem. | ||
777 | */ | ||
778 | |||
779 | err = wait_event_interruptible_timeout( | ||
780 | priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE), | ||
781 | HOST_COMPLETE_TIMEOUT); | ||
782 | |||
783 | if (err == 0) { | ||
784 | IPW_DEBUG_INFO("Command completion failed out after %dms.\n", | ||
785 | HOST_COMPLETE_TIMEOUT / (HZ / 100)); | ||
786 | priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT; | ||
787 | priv->status &= ~STATUS_CMD_ACTIVE; | ||
788 | schedule_reset(priv); | ||
789 | return -EIO; | ||
790 | } | ||
791 | |||
792 | if (priv->fatal_error) { | ||
793 | printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n", | ||
794 | priv->net_dev->name); | ||
795 | return -EIO; | ||
796 | } | ||
797 | |||
798 | /* !!!!! HACK TEST !!!!! | ||
799 | * When lots of debug trace statements are enabled, the driver | ||
800 | * doesn't seem to have as many firmware restart cycles... | ||
801 | * | ||
802 | * As a test, we're sticking in a 1/100s delay here */ | ||
803 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
804 | schedule_timeout(HZ / 100); | ||
805 | |||
806 | return 0; | ||
807 | |||
808 | fail_unlock: | ||
809 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
810 | |||
811 | return err; | ||
812 | } | ||
813 | |||
814 | |||
815 | /* | ||
816 | * Verify the values and data access of the hardware | ||
817 | * No locks needed or used. No functions called. | ||
818 | */ | ||
819 | static int ipw2100_verify(struct ipw2100_priv *priv) | ||
820 | { | ||
821 | u32 data1, data2; | ||
822 | u32 address; | ||
823 | |||
824 | u32 val1 = 0x76543210; | ||
825 | u32 val2 = 0xFEDCBA98; | ||
826 | |||
827 | /* Domain 0 check - all values should be DOA_DEBUG */ | ||
828 | for (address = IPW_REG_DOA_DEBUG_AREA_START; | ||
829 | address < IPW_REG_DOA_DEBUG_AREA_END; | ||
830 | address += sizeof(u32)) { | ||
831 | read_register(priv->net_dev, address, &data1); | ||
832 | if (data1 != IPW_DATA_DOA_DEBUG_VALUE) | ||
833 | return -EIO; | ||
834 | } | ||
835 | |||
836 | /* Domain 1 check - use arbitrary read/write compare */ | ||
837 | for (address = 0; address < 5; address++) { | ||
838 | /* The memory area is not used now */ | ||
839 | write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, | ||
840 | val1); | ||
841 | write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, | ||
842 | val2); | ||
843 | read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, | ||
844 | &data1); | ||
845 | read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, | ||
846 | &data2); | ||
847 | if (val1 == data1 && val2 == data2) | ||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | return -EIO; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * | ||
856 | * Loop until the CARD_DISABLED bit is the same value as the | ||
857 | * supplied parameter | ||
858 | * | ||
859 | * TODO: See if it would be more efficient to do a wait/wake | ||
860 | * cycle and have the completion event trigger the wakeup | ||
861 | * | ||
862 | */ | ||
863 | #define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli | ||
864 | static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state) | ||
865 | { | ||
866 | int i; | ||
867 | u32 card_state; | ||
868 | u32 len = sizeof(card_state); | ||
869 | int err; | ||
870 | |||
871 | for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) { | ||
872 | err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED, | ||
873 | &card_state, &len); | ||
874 | if (err) { | ||
875 | IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal " | ||
876 | "failed.\n"); | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | /* We'll break out if either the HW state says it is | ||
881 | * in the state we want, or if HOST_COMPLETE command | ||
882 | * finishes */ | ||
883 | if ((card_state == state) || | ||
884 | ((priv->status & STATUS_ENABLED) ? | ||
885 | IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) { | ||
886 | if (state == IPW_HW_STATE_ENABLED) | ||
887 | priv->status |= STATUS_ENABLED; | ||
888 | else | ||
889 | priv->status &= ~STATUS_ENABLED; | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | udelay(50); | ||
895 | } | ||
896 | |||
897 | IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n", | ||
898 | state ? "DISABLED" : "ENABLED"); | ||
899 | return -EIO; | ||
900 | } | ||
901 | |||
902 | |||
903 | /********************************************************************* | ||
904 | Procedure : sw_reset_and_clock | ||
905 | Purpose : Asserts s/w reset, asserts clock initialization | ||
906 | and waits for clock stabilization | ||
907 | ********************************************************************/ | ||
908 | static int sw_reset_and_clock(struct ipw2100_priv *priv) | ||
909 | { | ||
910 | int i; | ||
911 | u32 r; | ||
912 | |||
913 | // assert s/w reset | ||
914 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
915 | IPW_AUX_HOST_RESET_REG_SW_RESET); | ||
916 | |||
917 | // wait for clock stabilization | ||
918 | for (i = 0; i < 1000; i++) { | ||
919 | udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY); | ||
920 | |||
921 | // check clock ready bit | ||
922 | read_register(priv->net_dev, IPW_REG_RESET_REG, &r); | ||
923 | if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET) | ||
924 | break; | ||
925 | } | ||
926 | |||
927 | if (i == 1000) | ||
928 | return -EIO; // TODO: better error value | ||
929 | |||
930 | /* set "initialization complete" bit to move adapter to | ||
931 | * D0 state */ | ||
932 | write_register(priv->net_dev, IPW_REG_GP_CNTRL, | ||
933 | IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE); | ||
934 | |||
935 | /* wait for clock stabilization */ | ||
936 | for (i = 0; i < 10000; i++) { | ||
937 | udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4); | ||
938 | |||
939 | /* check clock ready bit */ | ||
940 | read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); | ||
941 | if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY) | ||
942 | break; | ||
943 | } | ||
944 | |||
945 | if (i == 10000) | ||
946 | return -EIO; /* TODO: better error value */ | ||
947 | |||
948 | /* set D0 standby bit */ | ||
949 | read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); | ||
950 | write_register(priv->net_dev, IPW_REG_GP_CNTRL, | ||
951 | r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); | ||
952 | |||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | /********************************************************************* | ||
957 | Procedure : ipw2100_download_firmware | ||
958 | Purpose : Initiaze adapter after power on. | ||
959 | The sequence is: | ||
960 | 1. assert s/w reset first! | ||
961 | 2. awake clocks & wait for clock stabilization | ||
962 | 3. hold ARC (don't ask me why...) | ||
963 | 4. load Dino ucode and reset/clock init again | ||
964 | 5. zero-out shared mem | ||
965 | 6. download f/w | ||
966 | *******************************************************************/ | ||
967 | static int ipw2100_download_firmware(struct ipw2100_priv *priv) | ||
968 | { | ||
969 | u32 address; | ||
970 | int err; | ||
971 | |||
972 | #ifndef CONFIG_PM | ||
973 | /* Fetch the firmware and microcode */ | ||
974 | struct ipw2100_fw ipw2100_firmware; | ||
975 | #endif | ||
976 | |||
977 | if (priv->fatal_error) { | ||
978 | IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after " | ||
979 | "fatal error %d. Interface must be brought down.\n", | ||
980 | priv->net_dev->name, priv->fatal_error); | ||
981 | return -EINVAL; | ||
982 | } | ||
983 | |||
984 | #ifdef CONFIG_PM | ||
985 | if (!ipw2100_firmware.version) { | ||
986 | err = ipw2100_get_firmware(priv, &ipw2100_firmware); | ||
987 | if (err) { | ||
988 | IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", | ||
989 | priv->net_dev->name, err); | ||
990 | priv->fatal_error = IPW2100_ERR_FW_LOAD; | ||
991 | goto fail; | ||
992 | } | ||
993 | } | ||
994 | #else | ||
995 | err = ipw2100_get_firmware(priv, &ipw2100_firmware); | ||
996 | if (err) { | ||
997 | IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", | ||
998 | priv->net_dev->name, err); | ||
999 | priv->fatal_error = IPW2100_ERR_FW_LOAD; | ||
1000 | goto fail; | ||
1001 | } | ||
1002 | #endif | ||
1003 | priv->firmware_version = ipw2100_firmware.version; | ||
1004 | |||
1005 | /* s/w reset and clock stabilization */ | ||
1006 | err = sw_reset_and_clock(priv); | ||
1007 | if (err) { | ||
1008 | IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n", | ||
1009 | priv->net_dev->name, err); | ||
1010 | goto fail; | ||
1011 | } | ||
1012 | |||
1013 | err = ipw2100_verify(priv); | ||
1014 | if (err) { | ||
1015 | IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n", | ||
1016 | priv->net_dev->name, err); | ||
1017 | goto fail; | ||
1018 | } | ||
1019 | |||
1020 | /* Hold ARC */ | ||
1021 | write_nic_dword(priv->net_dev, | ||
1022 | IPW_INTERNAL_REGISTER_HALT_AND_RESET, | ||
1023 | 0x80000000); | ||
1024 | |||
1025 | /* allow ARC to run */ | ||
1026 | write_register(priv->net_dev, IPW_REG_RESET_REG, 0); | ||
1027 | |||
1028 | /* load microcode */ | ||
1029 | err = ipw2100_ucode_download(priv, &ipw2100_firmware); | ||
1030 | if (err) { | ||
1031 | printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n", | ||
1032 | priv->net_dev->name, err); | ||
1033 | goto fail; | ||
1034 | } | ||
1035 | |||
1036 | /* release ARC */ | ||
1037 | write_nic_dword(priv->net_dev, | ||
1038 | IPW_INTERNAL_REGISTER_HALT_AND_RESET, | ||
1039 | 0x00000000); | ||
1040 | |||
1041 | /* s/w reset and clock stabilization (again!!!) */ | ||
1042 | err = sw_reset_and_clock(priv); | ||
1043 | if (err) { | ||
1044 | printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n", | ||
1045 | priv->net_dev->name, err); | ||
1046 | goto fail; | ||
1047 | } | ||
1048 | |||
1049 | /* load f/w */ | ||
1050 | err = ipw2100_fw_download(priv, &ipw2100_firmware); | ||
1051 | if (err) { | ||
1052 | IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n", | ||
1053 | priv->net_dev->name, err); | ||
1054 | goto fail; | ||
1055 | } | ||
1056 | |||
1057 | #ifndef CONFIG_PM | ||
1058 | /* | ||
1059 | * When the .resume method of the driver is called, the other | ||
1060 | * part of the system, i.e. the ide driver could still stay in | ||
1061 | * the suspend stage. This prevents us from loading the firmware | ||
1062 | * from the disk. --YZ | ||
1063 | */ | ||
1064 | |||
1065 | /* free any storage allocated for firmware image */ | ||
1066 | ipw2100_release_firmware(priv, &ipw2100_firmware); | ||
1067 | #endif | ||
1068 | |||
1069 | /* zero out Domain 1 area indirectly (Si requirement) */ | ||
1070 | for (address = IPW_HOST_FW_SHARED_AREA0; | ||
1071 | address < IPW_HOST_FW_SHARED_AREA0_END; address += 4) | ||
1072 | write_nic_dword(priv->net_dev, address, 0); | ||
1073 | for (address = IPW_HOST_FW_SHARED_AREA1; | ||
1074 | address < IPW_HOST_FW_SHARED_AREA1_END; address += 4) | ||
1075 | write_nic_dword(priv->net_dev, address, 0); | ||
1076 | for (address = IPW_HOST_FW_SHARED_AREA2; | ||
1077 | address < IPW_HOST_FW_SHARED_AREA2_END; address += 4) | ||
1078 | write_nic_dword(priv->net_dev, address, 0); | ||
1079 | for (address = IPW_HOST_FW_SHARED_AREA3; | ||
1080 | address < IPW_HOST_FW_SHARED_AREA3_END; address += 4) | ||
1081 | write_nic_dword(priv->net_dev, address, 0); | ||
1082 | for (address = IPW_HOST_FW_INTERRUPT_AREA; | ||
1083 | address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4) | ||
1084 | write_nic_dword(priv->net_dev, address, 0); | ||
1085 | |||
1086 | return 0; | ||
1087 | |||
1088 | fail: | ||
1089 | ipw2100_release_firmware(priv, &ipw2100_firmware); | ||
1090 | return err; | ||
1091 | } | ||
1092 | |||
1093 | static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv) | ||
1094 | { | ||
1095 | if (priv->status & STATUS_INT_ENABLED) | ||
1096 | return; | ||
1097 | priv->status |= STATUS_INT_ENABLED; | ||
1098 | write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK); | ||
1099 | } | ||
1100 | |||
1101 | static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv) | ||
1102 | { | ||
1103 | if (!(priv->status & STATUS_INT_ENABLED)) | ||
1104 | return; | ||
1105 | priv->status &= ~STATUS_INT_ENABLED; | ||
1106 | write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0); | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv) | ||
1111 | { | ||
1112 | struct ipw2100_ordinals *ord = &priv->ordinals; | ||
1113 | |||
1114 | IPW_DEBUG_INFO("enter\n"); | ||
1115 | |||
1116 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1, | ||
1117 | &ord->table1_addr); | ||
1118 | |||
1119 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2, | ||
1120 | &ord->table2_addr); | ||
1121 | |||
1122 | read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size); | ||
1123 | read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size); | ||
1124 | |||
1125 | ord->table2_size &= 0x0000FFFF; | ||
1126 | |||
1127 | IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size); | ||
1128 | IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size); | ||
1129 | IPW_DEBUG_INFO("exit\n"); | ||
1130 | } | ||
1131 | |||
1132 | static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv) | ||
1133 | { | ||
1134 | u32 reg = 0; | ||
1135 | /* | ||
1136 | * Set GPIO 3 writable by FW; GPIO 1 writable | ||
1137 | * by driver and enable clock | ||
1138 | */ | ||
1139 | reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE | | ||
1140 | IPW_BIT_GPIO_LED_OFF); | ||
1141 | write_register(priv->net_dev, IPW_REG_GPIO, reg); | ||
1142 | } | ||
1143 | |||
1144 | static inline int rf_kill_active(struct ipw2100_priv *priv) | ||
1145 | { | ||
1146 | #define MAX_RF_KILL_CHECKS 5 | ||
1147 | #define RF_KILL_CHECK_DELAY 40 | ||
1148 | |||
1149 | unsigned short value = 0; | ||
1150 | u32 reg = 0; | ||
1151 | int i; | ||
1152 | |||
1153 | if (!(priv->hw_features & HW_FEATURE_RFKILL)) { | ||
1154 | priv->status &= ~STATUS_RF_KILL_HW; | ||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | for (i = 0; i < MAX_RF_KILL_CHECKS; i++) { | ||
1159 | udelay(RF_KILL_CHECK_DELAY); | ||
1160 | read_register(priv->net_dev, IPW_REG_GPIO, ®); | ||
1161 | value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1); | ||
1162 | } | ||
1163 | |||
1164 | if (value == 0) | ||
1165 | priv->status |= STATUS_RF_KILL_HW; | ||
1166 | else | ||
1167 | priv->status &= ~STATUS_RF_KILL_HW; | ||
1168 | |||
1169 | return (value == 0); | ||
1170 | } | ||
1171 | |||
1172 | static int ipw2100_get_hw_features(struct ipw2100_priv *priv) | ||
1173 | { | ||
1174 | u32 addr, len; | ||
1175 | u32 val; | ||
1176 | |||
1177 | /* | ||
1178 | * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1 | ||
1179 | */ | ||
1180 | len = sizeof(addr); | ||
1181 | if (ipw2100_get_ordinal( | ||
1182 | priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, | ||
1183 | &addr, &len)) { | ||
1184 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
1185 | __LINE__); | ||
1186 | return -EIO; | ||
1187 | } | ||
1188 | |||
1189 | IPW_DEBUG_INFO("EEPROM address: %08X\n", addr); | ||
1190 | |||
1191 | /* | ||
1192 | * EEPROM version is the byte at offset 0xfd in firmware | ||
1193 | * We read 4 bytes, then shift out the byte we actually want */ | ||
1194 | read_nic_dword(priv->net_dev, addr + 0xFC, &val); | ||
1195 | priv->eeprom_version = (val >> 24) & 0xFF; | ||
1196 | IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version); | ||
1197 | |||
1198 | /* | ||
1199 | * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware | ||
1200 | * | ||
1201 | * notice that the EEPROM bit is reverse polarity, i.e. | ||
1202 | * bit = 0 signifies HW RF kill switch is supported | ||
1203 | * bit = 1 signifies HW RF kill switch is NOT supported | ||
1204 | */ | ||
1205 | read_nic_dword(priv->net_dev, addr + 0x20, &val); | ||
1206 | if (!((val >> 24) & 0x01)) | ||
1207 | priv->hw_features |= HW_FEATURE_RFKILL; | ||
1208 | |||
1209 | IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n", | ||
1210 | (priv->hw_features & HW_FEATURE_RFKILL) ? | ||
1211 | "" : "not "); | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * Start firmware execution after power on and intialization | ||
1218 | * The sequence is: | ||
1219 | * 1. Release ARC | ||
1220 | * 2. Wait for f/w initialization completes; | ||
1221 | */ | ||
1222 | static int ipw2100_start_adapter(struct ipw2100_priv *priv) | ||
1223 | { | ||
1224 | int i; | ||
1225 | u32 inta, inta_mask, gpio; | ||
1226 | |||
1227 | IPW_DEBUG_INFO("enter\n"); | ||
1228 | |||
1229 | if (priv->status & STATUS_RUNNING) | ||
1230 | return 0; | ||
1231 | |||
1232 | /* | ||
1233 | * Initialize the hw - drive adapter to DO state by setting | ||
1234 | * init_done bit. Wait for clk_ready bit and Download | ||
1235 | * fw & dino ucode | ||
1236 | */ | ||
1237 | if (ipw2100_download_firmware(priv)) { | ||
1238 | printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n", | ||
1239 | priv->net_dev->name); | ||
1240 | return -EIO; | ||
1241 | } | ||
1242 | |||
1243 | /* Clear the Tx, Rx and Msg queues and the r/w indexes | ||
1244 | * in the firmware RBD and TBD ring queue */ | ||
1245 | ipw2100_queues_initialize(priv); | ||
1246 | |||
1247 | ipw2100_hw_set_gpio(priv); | ||
1248 | |||
1249 | /* TODO -- Look at disabling interrupts here to make sure none | ||
1250 | * get fired during FW initialization */ | ||
1251 | |||
1252 | /* Release ARC - clear reset bit */ | ||
1253 | write_register(priv->net_dev, IPW_REG_RESET_REG, 0); | ||
1254 | |||
1255 | /* wait for f/w intialization complete */ | ||
1256 | IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); | ||
1257 | i = 5000; | ||
1258 | do { | ||
1259 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1260 | schedule_timeout(40 * HZ / 1000); | ||
1261 | /* Todo... wait for sync command ... */ | ||
1262 | |||
1263 | read_register(priv->net_dev, IPW_REG_INTA, &inta); | ||
1264 | |||
1265 | /* check "init done" bit */ | ||
1266 | if (inta & IPW2100_INTA_FW_INIT_DONE) { | ||
1267 | /* reset "init done" bit */ | ||
1268 | write_register(priv->net_dev, IPW_REG_INTA, | ||
1269 | IPW2100_INTA_FW_INIT_DONE); | ||
1270 | break; | ||
1271 | } | ||
1272 | |||
1273 | /* check error conditions : we check these after the firmware | ||
1274 | * check so that if there is an error, the interrupt handler | ||
1275 | * will see it and the adapter will be reset */ | ||
1276 | if (inta & | ||
1277 | (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) { | ||
1278 | /* clear error conditions */ | ||
1279 | write_register(priv->net_dev, IPW_REG_INTA, | ||
1280 | IPW2100_INTA_FATAL_ERROR | | ||
1281 | IPW2100_INTA_PARITY_ERROR); | ||
1282 | } | ||
1283 | } while (i--); | ||
1284 | |||
1285 | /* Clear out any pending INTAs since we aren't supposed to have | ||
1286 | * interrupts enabled at this point... */ | ||
1287 | read_register(priv->net_dev, IPW_REG_INTA, &inta); | ||
1288 | read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); | ||
1289 | inta &= IPW_INTERRUPT_MASK; | ||
1290 | /* Clear out any pending interrupts */ | ||
1291 | if (inta & inta_mask) | ||
1292 | write_register(priv->net_dev, IPW_REG_INTA, inta); | ||
1293 | |||
1294 | IPW_DEBUG_FW("f/w initialization complete: %s\n", | ||
1295 | i ? "SUCCESS" : "FAILED"); | ||
1296 | |||
1297 | if (!i) { | ||
1298 | printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n", | ||
1299 | priv->net_dev->name); | ||
1300 | return -EIO; | ||
1301 | } | ||
1302 | |||
1303 | /* allow firmware to write to GPIO1 & GPIO3 */ | ||
1304 | read_register(priv->net_dev, IPW_REG_GPIO, &gpio); | ||
1305 | |||
1306 | gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK); | ||
1307 | |||
1308 | write_register(priv->net_dev, IPW_REG_GPIO, gpio); | ||
1309 | |||
1310 | /* Ready to receive commands */ | ||
1311 | priv->status |= STATUS_RUNNING; | ||
1312 | |||
1313 | /* The adapter has been reset; we are not associated */ | ||
1314 | priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); | ||
1315 | |||
1316 | IPW_DEBUG_INFO("exit\n"); | ||
1317 | |||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv) | ||
1322 | { | ||
1323 | if (!priv->fatal_error) | ||
1324 | return; | ||
1325 | |||
1326 | priv->fatal_errors[priv->fatal_index++] = priv->fatal_error; | ||
1327 | priv->fatal_index %= IPW2100_ERROR_QUEUE; | ||
1328 | priv->fatal_error = 0; | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | /* NOTE: Our interrupt is disabled when this method is called */ | ||
1333 | static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) | ||
1334 | { | ||
1335 | u32 reg; | ||
1336 | int i; | ||
1337 | |||
1338 | IPW_DEBUG_INFO("Power cycling the hardware.\n"); | ||
1339 | |||
1340 | ipw2100_hw_set_gpio(priv); | ||
1341 | |||
1342 | /* Step 1. Stop Master Assert */ | ||
1343 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
1344 | IPW_AUX_HOST_RESET_REG_STOP_MASTER); | ||
1345 | |||
1346 | /* Step 2. Wait for stop Master Assert | ||
1347 | * (not more then 50us, otherwise ret error */ | ||
1348 | i = 5; | ||
1349 | do { | ||
1350 | udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); | ||
1351 | read_register(priv->net_dev, IPW_REG_RESET_REG, ®); | ||
1352 | |||
1353 | if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) | ||
1354 | break; | ||
1355 | } while(i--); | ||
1356 | |||
1357 | priv->status &= ~STATUS_RESET_PENDING; | ||
1358 | |||
1359 | if (!i) { | ||
1360 | IPW_DEBUG_INFO("exit - waited too long for master assert stop\n"); | ||
1361 | return -EIO; | ||
1362 | } | ||
1363 | |||
1364 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
1365 | IPW_AUX_HOST_RESET_REG_SW_RESET); | ||
1366 | |||
1367 | |||
1368 | /* Reset any fatal_error conditions */ | ||
1369 | ipw2100_reset_fatalerror(priv); | ||
1370 | |||
1371 | /* At this point, the adapter is now stopped and disabled */ | ||
1372 | priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING | | ||
1373 | STATUS_ASSOCIATED | STATUS_ENABLED); | ||
1374 | |||
1375 | return 0; | ||
1376 | } | ||
1377 | |||
1378 | /* | ||
1379 | * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it | ||
1380 | * | ||
1381 | * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent. | ||
1382 | * | ||
1383 | * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of | ||
1384 | * if STATUS_ASSN_LOST is sent. | ||
1385 | */ | ||
1386 | static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) | ||
1387 | { | ||
1388 | |||
1389 | #define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) | ||
1390 | |||
1391 | struct host_command cmd = { | ||
1392 | .host_command = CARD_DISABLE_PHY_OFF, | ||
1393 | .host_command_sequence = 0, | ||
1394 | .host_command_length = 0, | ||
1395 | }; | ||
1396 | int err, i; | ||
1397 | u32 val1, val2; | ||
1398 | |||
1399 | IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n"); | ||
1400 | |||
1401 | /* Turn off the radio */ | ||
1402 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1403 | if (err) | ||
1404 | return err; | ||
1405 | |||
1406 | for (i = 0; i < 2500; i++) { | ||
1407 | read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1); | ||
1408 | read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2); | ||
1409 | |||
1410 | if ((val1 & IPW2100_CONTROL_PHY_OFF) && | ||
1411 | (val2 & IPW2100_COMMAND_PHY_OFF)) | ||
1412 | return 0; | ||
1413 | |||
1414 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1415 | schedule_timeout(HW_PHY_OFF_LOOP_DELAY); | ||
1416 | } | ||
1417 | |||
1418 | return -EIO; | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | static int ipw2100_enable_adapter(struct ipw2100_priv *priv) | ||
1423 | { | ||
1424 | struct host_command cmd = { | ||
1425 | .host_command = HOST_COMPLETE, | ||
1426 | .host_command_sequence = 0, | ||
1427 | .host_command_length = 0 | ||
1428 | }; | ||
1429 | int err = 0; | ||
1430 | |||
1431 | IPW_DEBUG_HC("HOST_COMPLETE\n"); | ||
1432 | |||
1433 | if (priv->status & STATUS_ENABLED) | ||
1434 | return 0; | ||
1435 | |||
1436 | down(&priv->adapter_sem); | ||
1437 | |||
1438 | if (rf_kill_active(priv)) { | ||
1439 | IPW_DEBUG_HC("Command aborted due to RF kill active.\n"); | ||
1440 | goto fail_up; | ||
1441 | } | ||
1442 | |||
1443 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1444 | if (err) { | ||
1445 | IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n"); | ||
1446 | goto fail_up; | ||
1447 | } | ||
1448 | |||
1449 | err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED); | ||
1450 | if (err) { | ||
1451 | IPW_DEBUG_INFO( | ||
1452 | "%s: card not responding to init command.\n", | ||
1453 | priv->net_dev->name); | ||
1454 | goto fail_up; | ||
1455 | } | ||
1456 | |||
1457 | if (priv->stop_hang_check) { | ||
1458 | priv->stop_hang_check = 0; | ||
1459 | queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); | ||
1460 | } | ||
1461 | |||
1462 | fail_up: | ||
1463 | up(&priv->adapter_sem); | ||
1464 | return err; | ||
1465 | } | ||
1466 | |||
1467 | static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) | ||
1468 | { | ||
1469 | #define HW_POWER_DOWN_DELAY (HZ / 10) | ||
1470 | |||
1471 | struct host_command cmd = { | ||
1472 | .host_command = HOST_PRE_POWER_DOWN, | ||
1473 | .host_command_sequence = 0, | ||
1474 | .host_command_length = 0, | ||
1475 | }; | ||
1476 | int err, i; | ||
1477 | u32 reg; | ||
1478 | |||
1479 | if (!(priv->status & STATUS_RUNNING)) | ||
1480 | return 0; | ||
1481 | |||
1482 | priv->status |= STATUS_STOPPING; | ||
1483 | |||
1484 | /* We can only shut down the card if the firmware is operational. So, | ||
1485 | * if we haven't reset since a fatal_error, then we can not send the | ||
1486 | * shutdown commands. */ | ||
1487 | if (!priv->fatal_error) { | ||
1488 | /* First, make sure the adapter is enabled so that the PHY_OFF | ||
1489 | * command can shut it down */ | ||
1490 | ipw2100_enable_adapter(priv); | ||
1491 | |||
1492 | err = ipw2100_hw_phy_off(priv); | ||
1493 | if (err) | ||
1494 | printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err); | ||
1495 | |||
1496 | /* | ||
1497 | * If in D0-standby mode going directly to D3 may cause a | ||
1498 | * PCI bus violation. Therefore we must change out of the D0 | ||
1499 | * state. | ||
1500 | * | ||
1501 | * Sending the PREPARE_FOR_POWER_DOWN will restrict the | ||
1502 | * hardware from going into standby mode and will transition | ||
1503 | * out of D0-standy if it is already in that state. | ||
1504 | * | ||
1505 | * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the | ||
1506 | * driver upon completion. Once received, the driver can | ||
1507 | * proceed to the D3 state. | ||
1508 | * | ||
1509 | * Prepare for power down command to fw. This command would | ||
1510 | * take HW out of D0-standby and prepare it for D3 state. | ||
1511 | * | ||
1512 | * Currently FW does not support event notification for this | ||
1513 | * event. Therefore, skip waiting for it. Just wait a fixed | ||
1514 | * 100ms | ||
1515 | */ | ||
1516 | IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n"); | ||
1517 | |||
1518 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1519 | if (err) | ||
1520 | printk(KERN_WARNING DRV_NAME ": " | ||
1521 | "%s: Power down command failed: Error %d\n", | ||
1522 | priv->net_dev->name, err); | ||
1523 | else { | ||
1524 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
1525 | schedule_timeout(HW_POWER_DOWN_DELAY); | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | priv->status &= ~STATUS_ENABLED; | ||
1530 | |||
1531 | /* | ||
1532 | * Set GPIO 3 writable by FW; GPIO 1 writable | ||
1533 | * by driver and enable clock | ||
1534 | */ | ||
1535 | ipw2100_hw_set_gpio(priv); | ||
1536 | |||
1537 | /* | ||
1538 | * Power down adapter. Sequence: | ||
1539 | * 1. Stop master assert (RESET_REG[9]=1) | ||
1540 | * 2. Wait for stop master (RESET_REG[8]==1) | ||
1541 | * 3. S/w reset assert (RESET_REG[7] = 1) | ||
1542 | */ | ||
1543 | |||
1544 | /* Stop master assert */ | ||
1545 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
1546 | IPW_AUX_HOST_RESET_REG_STOP_MASTER); | ||
1547 | |||
1548 | /* wait stop master not more than 50 usec. | ||
1549 | * Otherwise return error. */ | ||
1550 | for (i = 5; i > 0; i--) { | ||
1551 | udelay(10); | ||
1552 | |||
1553 | /* Check master stop bit */ | ||
1554 | read_register(priv->net_dev, IPW_REG_RESET_REG, ®); | ||
1555 | |||
1556 | if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) | ||
1557 | break; | ||
1558 | } | ||
1559 | |||
1560 | if (i == 0) | ||
1561 | printk(KERN_WARNING DRV_NAME | ||
1562 | ": %s: Could now power down adapter.\n", | ||
1563 | priv->net_dev->name); | ||
1564 | |||
1565 | /* assert s/w reset */ | ||
1566 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
1567 | IPW_AUX_HOST_RESET_REG_SW_RESET); | ||
1568 | |||
1569 | priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING); | ||
1570 | |||
1571 | return 0; | ||
1572 | } | ||
1573 | |||
1574 | |||
1575 | static int ipw2100_disable_adapter(struct ipw2100_priv *priv) | ||
1576 | { | ||
1577 | struct host_command cmd = { | ||
1578 | .host_command = CARD_DISABLE, | ||
1579 | .host_command_sequence = 0, | ||
1580 | .host_command_length = 0 | ||
1581 | }; | ||
1582 | int err = 0; | ||
1583 | |||
1584 | IPW_DEBUG_HC("CARD_DISABLE\n"); | ||
1585 | |||
1586 | if (!(priv->status & STATUS_ENABLED)) | ||
1587 | return 0; | ||
1588 | |||
1589 | /* Make sure we clear the associated state */ | ||
1590 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | ||
1591 | |||
1592 | if (!priv->stop_hang_check) { | ||
1593 | priv->stop_hang_check = 1; | ||
1594 | cancel_delayed_work(&priv->hang_check); | ||
1595 | } | ||
1596 | |||
1597 | down(&priv->adapter_sem); | ||
1598 | |||
1599 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1600 | if (err) { | ||
1601 | printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n"); | ||
1602 | goto fail_up; | ||
1603 | } | ||
1604 | |||
1605 | err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED); | ||
1606 | if (err) { | ||
1607 | printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n"); | ||
1608 | goto fail_up; | ||
1609 | } | ||
1610 | |||
1611 | IPW_DEBUG_INFO("TODO: implement scan state machine\n"); | ||
1612 | |||
1613 | fail_up: | ||
1614 | up(&priv->adapter_sem); | ||
1615 | return err; | ||
1616 | } | ||
1617 | |||
1618 | static int ipw2100_set_scan_options(struct ipw2100_priv *priv) | ||
1619 | { | ||
1620 | struct host_command cmd = { | ||
1621 | .host_command = SET_SCAN_OPTIONS, | ||
1622 | .host_command_sequence = 0, | ||
1623 | .host_command_length = 8 | ||
1624 | }; | ||
1625 | int err; | ||
1626 | |||
1627 | IPW_DEBUG_INFO("enter\n"); | ||
1628 | |||
1629 | IPW_DEBUG_SCAN("setting scan options\n"); | ||
1630 | |||
1631 | cmd.host_command_parameters[0] = 0; | ||
1632 | |||
1633 | if (!(priv->config & CFG_ASSOCIATE)) | ||
1634 | cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE; | ||
1635 | if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled) | ||
1636 | cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL; | ||
1637 | if (priv->config & CFG_PASSIVE_SCAN) | ||
1638 | cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE; | ||
1639 | |||
1640 | cmd.host_command_parameters[1] = priv->channel_mask; | ||
1641 | |||
1642 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1643 | |||
1644 | IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n", | ||
1645 | cmd.host_command_parameters[0]); | ||
1646 | |||
1647 | return err; | ||
1648 | } | ||
1649 | |||
1650 | static int ipw2100_start_scan(struct ipw2100_priv *priv) | ||
1651 | { | ||
1652 | struct host_command cmd = { | ||
1653 | .host_command = BROADCAST_SCAN, | ||
1654 | .host_command_sequence = 0, | ||
1655 | .host_command_length = 4 | ||
1656 | }; | ||
1657 | int err; | ||
1658 | |||
1659 | IPW_DEBUG_HC("START_SCAN\n"); | ||
1660 | |||
1661 | cmd.host_command_parameters[0] = 0; | ||
1662 | |||
1663 | /* No scanning if in monitor mode */ | ||
1664 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | ||
1665 | return 1; | ||
1666 | |||
1667 | if (priv->status & STATUS_SCANNING) { | ||
1668 | IPW_DEBUG_SCAN("Scan requested while already in scan...\n"); | ||
1669 | return 0; | ||
1670 | } | ||
1671 | |||
1672 | IPW_DEBUG_INFO("enter\n"); | ||
1673 | |||
1674 | /* Not clearing here; doing so makes iwlist always return nothing... | ||
1675 | * | ||
1676 | * We should modify the table logic to use aging tables vs. clearing | ||
1677 | * the table on each scan start. | ||
1678 | */ | ||
1679 | IPW_DEBUG_SCAN("starting scan\n"); | ||
1680 | |||
1681 | priv->status |= STATUS_SCANNING; | ||
1682 | err = ipw2100_hw_send_command(priv, &cmd); | ||
1683 | if (err) | ||
1684 | priv->status &= ~STATUS_SCANNING; | ||
1685 | |||
1686 | IPW_DEBUG_INFO("exit\n"); | ||
1687 | |||
1688 | return err; | ||
1689 | } | ||
1690 | |||
1691 | static int ipw2100_up(struct ipw2100_priv *priv, int deferred) | ||
1692 | { | ||
1693 | unsigned long flags; | ||
1694 | int rc = 0; | ||
1695 | u32 lock; | ||
1696 | u32 ord_len = sizeof(lock); | ||
1697 | |||
1698 | /* Quite if manually disabled. */ | ||
1699 | if (priv->status & STATUS_RF_KILL_SW) { | ||
1700 | IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " | ||
1701 | "switch\n", priv->net_dev->name); | ||
1702 | return 0; | ||
1703 | } | ||
1704 | |||
1705 | /* If the interrupt is enabled, turn it off... */ | ||
1706 | spin_lock_irqsave(&priv->low_lock, flags); | ||
1707 | ipw2100_disable_interrupts(priv); | ||
1708 | |||
1709 | /* Reset any fatal_error conditions */ | ||
1710 | ipw2100_reset_fatalerror(priv); | ||
1711 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
1712 | |||
1713 | if (priv->status & STATUS_POWERED || | ||
1714 | (priv->status & STATUS_RESET_PENDING)) { | ||
1715 | /* Power cycle the card ... */ | ||
1716 | if (ipw2100_power_cycle_adapter(priv)) { | ||
1717 | printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n", | ||
1718 | priv->net_dev->name); | ||
1719 | rc = 1; | ||
1720 | goto exit; | ||
1721 | } | ||
1722 | } else | ||
1723 | priv->status |= STATUS_POWERED; | ||
1724 | |||
1725 | /* Load the firmware, start the clocks, etc. */ | ||
1726 | if (ipw2100_start_adapter(priv)) { | ||
1727 | printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n", | ||
1728 | priv->net_dev->name); | ||
1729 | rc = 1; | ||
1730 | goto exit; | ||
1731 | } | ||
1732 | |||
1733 | ipw2100_initialize_ordinals(priv); | ||
1734 | |||
1735 | /* Determine capabilities of this particular HW configuration */ | ||
1736 | if (ipw2100_get_hw_features(priv)) { | ||
1737 | printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n", | ||
1738 | priv->net_dev->name); | ||
1739 | rc = 1; | ||
1740 | goto exit; | ||
1741 | } | ||
1742 | |||
1743 | lock = LOCK_NONE; | ||
1744 | if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { | ||
1745 | printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n", | ||
1746 | priv->net_dev->name); | ||
1747 | rc = 1; | ||
1748 | goto exit; | ||
1749 | } | ||
1750 | |||
1751 | priv->status &= ~STATUS_SCANNING; | ||
1752 | |||
1753 | if (rf_kill_active(priv)) { | ||
1754 | printk(KERN_INFO "%s: Radio is disabled by RF switch.\n", | ||
1755 | priv->net_dev->name); | ||
1756 | |||
1757 | if (priv->stop_rf_kill) { | ||
1758 | priv->stop_rf_kill = 0; | ||
1759 | queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); | ||
1760 | } | ||
1761 | |||
1762 | deferred = 1; | ||
1763 | } | ||
1764 | |||
1765 | /* Turn on the interrupt so that commands can be processed */ | ||
1766 | ipw2100_enable_interrupts(priv); | ||
1767 | |||
1768 | /* Send all of the commands that must be sent prior to | ||
1769 | * HOST_COMPLETE */ | ||
1770 | if (ipw2100_adapter_setup(priv)) { | ||
1771 | printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", | ||
1772 | priv->net_dev->name); | ||
1773 | rc = 1; | ||
1774 | goto exit; | ||
1775 | } | ||
1776 | |||
1777 | if (!deferred) { | ||
1778 | /* Enable the adapter - sends HOST_COMPLETE */ | ||
1779 | if (ipw2100_enable_adapter(priv)) { | ||
1780 | printk(KERN_ERR DRV_NAME ": " | ||
1781 | "%s: failed in call to enable adapter.\n", | ||
1782 | priv->net_dev->name); | ||
1783 | ipw2100_hw_stop_adapter(priv); | ||
1784 | rc = 1; | ||
1785 | goto exit; | ||
1786 | } | ||
1787 | |||
1788 | |||
1789 | /* Start a scan . . . */ | ||
1790 | ipw2100_set_scan_options(priv); | ||
1791 | ipw2100_start_scan(priv); | ||
1792 | } | ||
1793 | |||
1794 | exit: | ||
1795 | return rc; | ||
1796 | } | ||
1797 | |||
1798 | /* Called by register_netdev() */ | ||
1799 | static int ipw2100_net_init(struct net_device *dev) | ||
1800 | { | ||
1801 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
1802 | return ipw2100_up(priv, 1); | ||
1803 | } | ||
1804 | |||
1805 | static void ipw2100_down(struct ipw2100_priv *priv) | ||
1806 | { | ||
1807 | unsigned long flags; | ||
1808 | union iwreq_data wrqu = { | ||
1809 | .ap_addr = { | ||
1810 | .sa_family = ARPHRD_ETHER | ||
1811 | } | ||
1812 | }; | ||
1813 | int associated = priv->status & STATUS_ASSOCIATED; | ||
1814 | |||
1815 | /* Kill the RF switch timer */ | ||
1816 | if (!priv->stop_rf_kill) { | ||
1817 | priv->stop_rf_kill = 1; | ||
1818 | cancel_delayed_work(&priv->rf_kill); | ||
1819 | } | ||
1820 | |||
1821 | /* Kill the firmare hang check timer */ | ||
1822 | if (!priv->stop_hang_check) { | ||
1823 | priv->stop_hang_check = 1; | ||
1824 | cancel_delayed_work(&priv->hang_check); | ||
1825 | } | ||
1826 | |||
1827 | /* Kill any pending resets */ | ||
1828 | if (priv->status & STATUS_RESET_PENDING) | ||
1829 | cancel_delayed_work(&priv->reset_work); | ||
1830 | |||
1831 | /* Make sure the interrupt is on so that FW commands will be | ||
1832 | * processed correctly */ | ||
1833 | spin_lock_irqsave(&priv->low_lock, flags); | ||
1834 | ipw2100_enable_interrupts(priv); | ||
1835 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
1836 | |||
1837 | if (ipw2100_hw_stop_adapter(priv)) | ||
1838 | printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n", | ||
1839 | priv->net_dev->name); | ||
1840 | |||
1841 | /* Do not disable the interrupt until _after_ we disable | ||
1842 | * the adaptor. Otherwise the CARD_DISABLE command will never | ||
1843 | * be ack'd by the firmware */ | ||
1844 | spin_lock_irqsave(&priv->low_lock, flags); | ||
1845 | ipw2100_disable_interrupts(priv); | ||
1846 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
1847 | |||
1848 | #ifdef ACPI_CSTATE_LIMIT_DEFINED | ||
1849 | if (priv->config & CFG_C3_DISABLED) { | ||
1850 | IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n"); | ||
1851 | acpi_set_cstate_limit(priv->cstate_limit); | ||
1852 | priv->config &= ~CFG_C3_DISABLED; | ||
1853 | } | ||
1854 | #endif | ||
1855 | |||
1856 | /* We have to signal any supplicant if we are disassociating */ | ||
1857 | if (associated) | ||
1858 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
1859 | |||
1860 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | ||
1861 | netif_carrier_off(priv->net_dev); | ||
1862 | netif_stop_queue(priv->net_dev); | ||
1863 | } | ||
1864 | |||
1865 | static void ipw2100_reset_adapter(struct ipw2100_priv *priv) | ||
1866 | { | ||
1867 | unsigned long flags; | ||
1868 | union iwreq_data wrqu = { | ||
1869 | .ap_addr = { | ||
1870 | .sa_family = ARPHRD_ETHER | ||
1871 | } | ||
1872 | }; | ||
1873 | int associated = priv->status & STATUS_ASSOCIATED; | ||
1874 | |||
1875 | spin_lock_irqsave(&priv->low_lock, flags); | ||
1876 | IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n", | ||
1877 | priv->net_dev->name); | ||
1878 | priv->resets++; | ||
1879 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | ||
1880 | priv->status |= STATUS_SECURITY_UPDATED; | ||
1881 | |||
1882 | /* Force a power cycle even if interface hasn't been opened | ||
1883 | * yet */ | ||
1884 | cancel_delayed_work(&priv->reset_work); | ||
1885 | priv->status |= STATUS_RESET_PENDING; | ||
1886 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
1887 | |||
1888 | down(&priv->action_sem); | ||
1889 | /* stop timed checks so that they don't interfere with reset */ | ||
1890 | priv->stop_hang_check = 1; | ||
1891 | cancel_delayed_work(&priv->hang_check); | ||
1892 | |||
1893 | /* We have to signal any supplicant if we are disassociating */ | ||
1894 | if (associated) | ||
1895 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
1896 | |||
1897 | ipw2100_up(priv, 0); | ||
1898 | up(&priv->action_sem); | ||
1899 | |||
1900 | } | ||
1901 | |||
1902 | |||
1903 | static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) | ||
1904 | { | ||
1905 | |||
1906 | #define MAC_ASSOCIATION_READ_DELAY (HZ) | ||
1907 | int ret, len, essid_len; | ||
1908 | char essid[IW_ESSID_MAX_SIZE]; | ||
1909 | u32 txrate; | ||
1910 | u32 chan; | ||
1911 | char *txratename; | ||
1912 | u8 bssid[ETH_ALEN]; | ||
1913 | |||
1914 | /* | ||
1915 | * TBD: BSSID is usually 00:00:00:00:00:00 here and not | ||
1916 | * an actual MAC of the AP. Seems like FW sets this | ||
1917 | * address too late. Read it later and expose through | ||
1918 | * /proc or schedule a later task to query and update | ||
1919 | */ | ||
1920 | |||
1921 | essid_len = IW_ESSID_MAX_SIZE; | ||
1922 | ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, | ||
1923 | essid, &essid_len); | ||
1924 | if (ret) { | ||
1925 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
1926 | __LINE__); | ||
1927 | return; | ||
1928 | } | ||
1929 | |||
1930 | len = sizeof(u32); | ||
1931 | ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, | ||
1932 | &txrate, &len); | ||
1933 | if (ret) { | ||
1934 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
1935 | __LINE__); | ||
1936 | return; | ||
1937 | } | ||
1938 | |||
1939 | len = sizeof(u32); | ||
1940 | ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len); | ||
1941 | if (ret) { | ||
1942 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
1943 | __LINE__); | ||
1944 | return; | ||
1945 | } | ||
1946 | len = ETH_ALEN; | ||
1947 | ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); | ||
1948 | if (ret) { | ||
1949 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
1950 | __LINE__); | ||
1951 | return; | ||
1952 | } | ||
1953 | memcpy(priv->ieee->bssid, bssid, ETH_ALEN); | ||
1954 | |||
1955 | |||
1956 | switch (txrate) { | ||
1957 | case TX_RATE_1_MBIT: | ||
1958 | txratename = "1Mbps"; | ||
1959 | break; | ||
1960 | case TX_RATE_2_MBIT: | ||
1961 | txratename = "2Mbsp"; | ||
1962 | break; | ||
1963 | case TX_RATE_5_5_MBIT: | ||
1964 | txratename = "5.5Mbps"; | ||
1965 | break; | ||
1966 | case TX_RATE_11_MBIT: | ||
1967 | txratename = "11Mbps"; | ||
1968 | break; | ||
1969 | default: | ||
1970 | IPW_DEBUG_INFO("Unknown rate: %d\n", txrate); | ||
1971 | txratename = "unknown rate"; | ||
1972 | break; | ||
1973 | } | ||
1974 | |||
1975 | IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" | ||
1976 | MAC_FMT ")\n", | ||
1977 | priv->net_dev->name, escape_essid(essid, essid_len), | ||
1978 | txratename, chan, MAC_ARG(bssid)); | ||
1979 | |||
1980 | /* now we copy read ssid into dev */ | ||
1981 | if (!(priv->config & CFG_STATIC_ESSID)) { | ||
1982 | priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE); | ||
1983 | memcpy(priv->essid, essid, priv->essid_len); | ||
1984 | } | ||
1985 | priv->channel = chan; | ||
1986 | memcpy(priv->bssid, bssid, ETH_ALEN); | ||
1987 | |||
1988 | priv->status |= STATUS_ASSOCIATING; | ||
1989 | priv->connect_start = get_seconds(); | ||
1990 | |||
1991 | queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10); | ||
1992 | } | ||
1993 | |||
1994 | |||
1995 | static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, | ||
1996 | int length, int batch_mode) | ||
1997 | { | ||
1998 | int ssid_len = min(length, IW_ESSID_MAX_SIZE); | ||
1999 | struct host_command cmd = { | ||
2000 | .host_command = SSID, | ||
2001 | .host_command_sequence = 0, | ||
2002 | .host_command_length = ssid_len | ||
2003 | }; | ||
2004 | int err; | ||
2005 | |||
2006 | IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); | ||
2007 | |||
2008 | if (ssid_len) | ||
2009 | memcpy((char*)cmd.host_command_parameters, | ||
2010 | essid, ssid_len); | ||
2011 | |||
2012 | if (!batch_mode) { | ||
2013 | err = ipw2100_disable_adapter(priv); | ||
2014 | if (err) | ||
2015 | return err; | ||
2016 | } | ||
2017 | |||
2018 | /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to | ||
2019 | * disable auto association -- so we cheat by setting a bogus SSID */ | ||
2020 | if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) { | ||
2021 | int i; | ||
2022 | u8 *bogus = (u8*)cmd.host_command_parameters; | ||
2023 | for (i = 0; i < IW_ESSID_MAX_SIZE; i++) | ||
2024 | bogus[i] = 0x18 + i; | ||
2025 | cmd.host_command_length = IW_ESSID_MAX_SIZE; | ||
2026 | } | ||
2027 | |||
2028 | /* NOTE: We always send the SSID command even if the provided ESSID is | ||
2029 | * the same as what we currently think is set. */ | ||
2030 | |||
2031 | err = ipw2100_hw_send_command(priv, &cmd); | ||
2032 | if (!err) { | ||
2033 | memset(priv->essid + ssid_len, 0, | ||
2034 | IW_ESSID_MAX_SIZE - ssid_len); | ||
2035 | memcpy(priv->essid, essid, ssid_len); | ||
2036 | priv->essid_len = ssid_len; | ||
2037 | } | ||
2038 | |||
2039 | if (!batch_mode) { | ||
2040 | if (ipw2100_enable_adapter(priv)) | ||
2041 | err = -EIO; | ||
2042 | } | ||
2043 | |||
2044 | return err; | ||
2045 | } | ||
2046 | |||
2047 | static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) | ||
2048 | { | ||
2049 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
2050 | "disassociated: '%s' " MAC_FMT " \n", | ||
2051 | escape_essid(priv->essid, priv->essid_len), | ||
2052 | MAC_ARG(priv->bssid)); | ||
2053 | |||
2054 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | ||
2055 | |||
2056 | if (priv->status & STATUS_STOPPING) { | ||
2057 | IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n"); | ||
2058 | return; | ||
2059 | } | ||
2060 | |||
2061 | memset(priv->bssid, 0, ETH_ALEN); | ||
2062 | memset(priv->ieee->bssid, 0, ETH_ALEN); | ||
2063 | |||
2064 | netif_carrier_off(priv->net_dev); | ||
2065 | netif_stop_queue(priv->net_dev); | ||
2066 | |||
2067 | if (!(priv->status & STATUS_RUNNING)) | ||
2068 | return; | ||
2069 | |||
2070 | if (priv->status & STATUS_SECURITY_UPDATED) | ||
2071 | queue_work(priv->workqueue, &priv->security_work); | ||
2072 | |||
2073 | queue_work(priv->workqueue, &priv->wx_event_work); | ||
2074 | } | ||
2075 | |||
2076 | static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) | ||
2077 | { | ||
2078 | IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n", | ||
2079 | priv->net_dev->name); | ||
2080 | |||
2081 | /* RF_KILL is now enabled (else we wouldn't be here) */ | ||
2082 | priv->status |= STATUS_RF_KILL_HW; | ||
2083 | |||
2084 | #ifdef ACPI_CSTATE_LIMIT_DEFINED | ||
2085 | if (priv->config & CFG_C3_DISABLED) { | ||
2086 | IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n"); | ||
2087 | acpi_set_cstate_limit(priv->cstate_limit); | ||
2088 | priv->config &= ~CFG_C3_DISABLED; | ||
2089 | } | ||
2090 | #endif | ||
2091 | |||
2092 | /* Make sure the RF Kill check timer is running */ | ||
2093 | priv->stop_rf_kill = 0; | ||
2094 | cancel_delayed_work(&priv->rf_kill); | ||
2095 | queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); | ||
2096 | } | ||
2097 | |||
2098 | static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) | ||
2099 | { | ||
2100 | IPW_DEBUG_SCAN("scan complete\n"); | ||
2101 | /* Age the scan results... */ | ||
2102 | priv->ieee->scans++; | ||
2103 | priv->status &= ~STATUS_SCANNING; | ||
2104 | } | ||
2105 | |||
2106 | #ifdef CONFIG_IPW_DEBUG | ||
2107 | #define IPW2100_HANDLER(v, f) { v, f, # v } | ||
2108 | struct ipw2100_status_indicator { | ||
2109 | int status; | ||
2110 | void (*cb)(struct ipw2100_priv *priv, u32 status); | ||
2111 | char *name; | ||
2112 | }; | ||
2113 | #else | ||
2114 | #define IPW2100_HANDLER(v, f) { v, f } | ||
2115 | struct ipw2100_status_indicator { | ||
2116 | int status; | ||
2117 | void (*cb)(struct ipw2100_priv *priv, u32 status); | ||
2118 | }; | ||
2119 | #endif /* CONFIG_IPW_DEBUG */ | ||
2120 | |||
2121 | static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status) | ||
2122 | { | ||
2123 | IPW_DEBUG_SCAN("Scanning...\n"); | ||
2124 | priv->status |= STATUS_SCANNING; | ||
2125 | } | ||
2126 | |||
2127 | static const struct ipw2100_status_indicator status_handlers[] = { | ||
2128 | IPW2100_HANDLER(IPW_STATE_INITIALIZED, 0), | ||
2129 | IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, 0), | ||
2130 | IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated), | ||
2131 | IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost), | ||
2132 | IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, 0), | ||
2133 | IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete), | ||
2134 | IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, 0), | ||
2135 | IPW2100_HANDLER(IPW_STATE_LEFT_PSP, 0), | ||
2136 | IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill), | ||
2137 | IPW2100_HANDLER(IPW_STATE_DISABLED, 0), | ||
2138 | IPW2100_HANDLER(IPW_STATE_POWER_DOWN, 0), | ||
2139 | IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning), | ||
2140 | IPW2100_HANDLER(-1, 0) | ||
2141 | }; | ||
2142 | |||
2143 | |||
2144 | static void isr_status_change(struct ipw2100_priv *priv, int status) | ||
2145 | { | ||
2146 | int i; | ||
2147 | |||
2148 | if (status == IPW_STATE_SCANNING && | ||
2149 | priv->status & STATUS_ASSOCIATED && | ||
2150 | !(priv->status & STATUS_SCANNING)) { | ||
2151 | IPW_DEBUG_INFO("Scan detected while associated, with " | ||
2152 | "no scan request. Restarting firmware.\n"); | ||
2153 | |||
2154 | /* Wake up any sleeping jobs */ | ||
2155 | schedule_reset(priv); | ||
2156 | } | ||
2157 | |||
2158 | for (i = 0; status_handlers[i].status != -1; i++) { | ||
2159 | if (status == status_handlers[i].status) { | ||
2160 | IPW_DEBUG_NOTIF("Status change: %s\n", | ||
2161 | status_handlers[i].name); | ||
2162 | if (status_handlers[i].cb) | ||
2163 | status_handlers[i].cb(priv, status); | ||
2164 | priv->wstats.status = status; | ||
2165 | return; | ||
2166 | } | ||
2167 | } | ||
2168 | |||
2169 | IPW_DEBUG_NOTIF("unknown status received: %04x\n", status); | ||
2170 | } | ||
2171 | |||
2172 | static void isr_rx_complete_command( | ||
2173 | struct ipw2100_priv *priv, | ||
2174 | struct ipw2100_cmd_header *cmd) | ||
2175 | { | ||
2176 | #ifdef CONFIG_IPW_DEBUG | ||
2177 | if (cmd->host_command_reg < ARRAY_SIZE(command_types)) { | ||
2178 | IPW_DEBUG_HC("Command completed '%s (%d)'\n", | ||
2179 | command_types[cmd->host_command_reg], | ||
2180 | cmd->host_command_reg); | ||
2181 | } | ||
2182 | #endif | ||
2183 | if (cmd->host_command_reg == HOST_COMPLETE) | ||
2184 | priv->status |= STATUS_ENABLED; | ||
2185 | |||
2186 | if (cmd->host_command_reg == CARD_DISABLE) | ||
2187 | priv->status &= ~STATUS_ENABLED; | ||
2188 | |||
2189 | priv->status &= ~STATUS_CMD_ACTIVE; | ||
2190 | |||
2191 | wake_up_interruptible(&priv->wait_command_queue); | ||
2192 | } | ||
2193 | |||
2194 | #ifdef CONFIG_IPW_DEBUG | ||
2195 | static const char *frame_types[] = { | ||
2196 | "COMMAND_STATUS_VAL", | ||
2197 | "STATUS_CHANGE_VAL", | ||
2198 | "P80211_DATA_VAL", | ||
2199 | "P8023_DATA_VAL", | ||
2200 | "HOST_NOTIFICATION_VAL" | ||
2201 | }; | ||
2202 | #endif | ||
2203 | |||
2204 | |||
2205 | static inline int ipw2100_alloc_skb( | ||
2206 | struct ipw2100_priv *priv, | ||
2207 | struct ipw2100_rx_packet *packet) | ||
2208 | { | ||
2209 | packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx)); | ||
2210 | if (!packet->skb) | ||
2211 | return -ENOMEM; | ||
2212 | |||
2213 | packet->rxp = (struct ipw2100_rx *)packet->skb->data; | ||
2214 | packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, | ||
2215 | sizeof(struct ipw2100_rx), | ||
2216 | PCI_DMA_FROMDEVICE); | ||
2217 | /* NOTE: pci_map_single does not return an error code, and 0 is a valid | ||
2218 | * dma_addr */ | ||
2219 | |||
2220 | return 0; | ||
2221 | } | ||
2222 | |||
2223 | |||
2224 | #define SEARCH_ERROR 0xffffffff | ||
2225 | #define SEARCH_FAIL 0xfffffffe | ||
2226 | #define SEARCH_SUCCESS 0xfffffff0 | ||
2227 | #define SEARCH_DISCARD 0 | ||
2228 | #define SEARCH_SNAPSHOT 1 | ||
2229 | |||
2230 | #define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff)) | ||
2231 | static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) | ||
2232 | { | ||
2233 | int i; | ||
2234 | if (priv->snapshot[0]) | ||
2235 | return 1; | ||
2236 | for (i = 0; i < 0x30; i++) { | ||
2237 | priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC); | ||
2238 | if (!priv->snapshot[i]) { | ||
2239 | IPW_DEBUG_INFO("%s: Error allocating snapshot " | ||
2240 | "buffer %d\n", priv->net_dev->name, i); | ||
2241 | while (i > 0) | ||
2242 | kfree(priv->snapshot[--i]); | ||
2243 | priv->snapshot[0] = NULL; | ||
2244 | return 0; | ||
2245 | } | ||
2246 | } | ||
2247 | |||
2248 | return 1; | ||
2249 | } | ||
2250 | |||
2251 | static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv) | ||
2252 | { | ||
2253 | int i; | ||
2254 | if (!priv->snapshot[0]) | ||
2255 | return; | ||
2256 | for (i = 0; i < 0x30; i++) | ||
2257 | kfree(priv->snapshot[i]); | ||
2258 | priv->snapshot[0] = NULL; | ||
2259 | } | ||
2260 | |||
2261 | static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf, | ||
2262 | size_t len, int mode) | ||
2263 | { | ||
2264 | u32 i, j; | ||
2265 | u32 tmp; | ||
2266 | u8 *s, *d; | ||
2267 | u32 ret; | ||
2268 | |||
2269 | s = in_buf; | ||
2270 | if (mode == SEARCH_SNAPSHOT) { | ||
2271 | if (!ipw2100_snapshot_alloc(priv)) | ||
2272 | mode = SEARCH_DISCARD; | ||
2273 | } | ||
2274 | |||
2275 | for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) { | ||
2276 | read_nic_dword(priv->net_dev, i, &tmp); | ||
2277 | if (mode == SEARCH_SNAPSHOT) | ||
2278 | *(u32 *)SNAPSHOT_ADDR(i) = tmp; | ||
2279 | if (ret == SEARCH_FAIL) { | ||
2280 | d = (u8*)&tmp; | ||
2281 | for (j = 0; j < 4; j++) { | ||
2282 | if (*s != *d) { | ||
2283 | s = in_buf; | ||
2284 | continue; | ||
2285 | } | ||
2286 | |||
2287 | s++; | ||
2288 | d++; | ||
2289 | |||
2290 | if ((s - in_buf) == len) | ||
2291 | ret = (i + j) - len + 1; | ||
2292 | } | ||
2293 | } else if (mode == SEARCH_DISCARD) | ||
2294 | return ret; | ||
2295 | } | ||
2296 | |||
2297 | return ret; | ||
2298 | } | ||
2299 | |||
2300 | /* | ||
2301 | * | ||
2302 | * 0) Disconnect the SKB from the firmware (just unmap) | ||
2303 | * 1) Pack the ETH header into the SKB | ||
2304 | * 2) Pass the SKB to the network stack | ||
2305 | * | ||
2306 | * When packet is provided by the firmware, it contains the following: | ||
2307 | * | ||
2308 | * . ieee80211_hdr | ||
2309 | * . ieee80211_snap_hdr | ||
2310 | * | ||
2311 | * The size of the constructed ethernet | ||
2312 | * | ||
2313 | */ | ||
2314 | #ifdef CONFIG_IPW2100_RX_DEBUG | ||
2315 | static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; | ||
2316 | #endif | ||
2317 | |||
2318 | static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, | ||
2319 | int i) | ||
2320 | { | ||
2321 | #ifdef CONFIG_IPW_DEBUG_C3 | ||
2322 | struct ipw2100_status *status = &priv->status_queue.drv[i]; | ||
2323 | u32 match, reg; | ||
2324 | int j; | ||
2325 | #endif | ||
2326 | #ifdef ACPI_CSTATE_LIMIT_DEFINED | ||
2327 | int limit; | ||
2328 | #endif | ||
2329 | |||
2330 | IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at " | ||
2331 | "0x%04zX.\n", i * sizeof(struct ipw2100_status)); | ||
2332 | |||
2333 | #ifdef ACPI_CSTATE_LIMIT_DEFINED | ||
2334 | IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n"); | ||
2335 | limit = acpi_get_cstate_limit(); | ||
2336 | if (limit > 2) { | ||
2337 | priv->cstate_limit = limit; | ||
2338 | acpi_set_cstate_limit(2); | ||
2339 | priv->config |= CFG_C3_DISABLED; | ||
2340 | } | ||
2341 | #endif | ||
2342 | |||
2343 | #ifdef CONFIG_IPW_DEBUG_C3 | ||
2344 | /* Halt the fimrware so we can get a good image */ | ||
2345 | write_register(priv->net_dev, IPW_REG_RESET_REG, | ||
2346 | IPW_AUX_HOST_RESET_REG_STOP_MASTER); | ||
2347 | j = 5; | ||
2348 | do { | ||
2349 | udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); | ||
2350 | read_register(priv->net_dev, IPW_REG_RESET_REG, ®); | ||
2351 | |||
2352 | if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) | ||
2353 | break; | ||
2354 | } while (j--); | ||
2355 | |||
2356 | match = ipw2100_match_buf(priv, (u8*)status, | ||
2357 | sizeof(struct ipw2100_status), | ||
2358 | SEARCH_SNAPSHOT); | ||
2359 | if (match < SEARCH_SUCCESS) | ||
2360 | IPW_DEBUG_INFO("%s: DMA status match in Firmware at " | ||
2361 | "offset 0x%06X, length %d:\n", | ||
2362 | priv->net_dev->name, match, | ||
2363 | sizeof(struct ipw2100_status)); | ||
2364 | else | ||
2365 | IPW_DEBUG_INFO("%s: No DMA status match in " | ||
2366 | "Firmware.\n", priv->net_dev->name); | ||
2367 | |||
2368 | printk_buf((u8*)priv->status_queue.drv, | ||
2369 | sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH); | ||
2370 | #endif | ||
2371 | |||
2372 | priv->fatal_error = IPW2100_ERR_C3_CORRUPTION; | ||
2373 | priv->ieee->stats.rx_errors++; | ||
2374 | schedule_reset(priv); | ||
2375 | } | ||
2376 | |||
2377 | static inline void isr_rx(struct ipw2100_priv *priv, int i, | ||
2378 | struct ieee80211_rx_stats *stats) | ||
2379 | { | ||
2380 | struct ipw2100_status *status = &priv->status_queue.drv[i]; | ||
2381 | struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; | ||
2382 | |||
2383 | IPW_DEBUG_RX("Handler...\n"); | ||
2384 | |||
2385 | if (unlikely(status->frame_size > skb_tailroom(packet->skb))) { | ||
2386 | IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" | ||
2387 | " Dropping.\n", | ||
2388 | priv->net_dev->name, | ||
2389 | status->frame_size, skb_tailroom(packet->skb)); | ||
2390 | priv->ieee->stats.rx_errors++; | ||
2391 | return; | ||
2392 | } | ||
2393 | |||
2394 | if (unlikely(!netif_running(priv->net_dev))) { | ||
2395 | priv->ieee->stats.rx_errors++; | ||
2396 | priv->wstats.discard.misc++; | ||
2397 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | ||
2398 | return; | ||
2399 | } | ||
2400 | |||
2401 | if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR && | ||
2402 | status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { | ||
2403 | IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); | ||
2404 | priv->ieee->stats.rx_errors++; | ||
2405 | return; | ||
2406 | } | ||
2407 | |||
2408 | if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && | ||
2409 | !(priv->status & STATUS_ASSOCIATED))) { | ||
2410 | IPW_DEBUG_DROP("Dropping packet while not associated.\n"); | ||
2411 | priv->wstats.discard.misc++; | ||
2412 | return; | ||
2413 | } | ||
2414 | |||
2415 | |||
2416 | pci_unmap_single(priv->pci_dev, | ||
2417 | packet->dma_addr, | ||
2418 | sizeof(struct ipw2100_rx), | ||
2419 | PCI_DMA_FROMDEVICE); | ||
2420 | |||
2421 | skb_put(packet->skb, status->frame_size); | ||
2422 | |||
2423 | #ifdef CONFIG_IPW2100_RX_DEBUG | ||
2424 | /* Make a copy of the frame so we can dump it to the logs if | ||
2425 | * ieee80211_rx fails */ | ||
2426 | memcpy(packet_data, packet->skb->data, | ||
2427 | min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH)); | ||
2428 | #endif | ||
2429 | |||
2430 | if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { | ||
2431 | #ifdef CONFIG_IPW2100_RX_DEBUG | ||
2432 | IPW_DEBUG_DROP("%s: Non consumed packet:\n", | ||
2433 | priv->net_dev->name); | ||
2434 | printk_buf(IPW_DL_DROP, packet_data, status->frame_size); | ||
2435 | #endif | ||
2436 | priv->ieee->stats.rx_errors++; | ||
2437 | |||
2438 | /* ieee80211_rx failed, so it didn't free the SKB */ | ||
2439 | dev_kfree_skb_any(packet->skb); | ||
2440 | packet->skb = NULL; | ||
2441 | } | ||
2442 | |||
2443 | /* We need to allocate a new SKB and attach it to the RDB. */ | ||
2444 | if (unlikely(ipw2100_alloc_skb(priv, packet))) { | ||
2445 | printk(KERN_WARNING DRV_NAME ": " | ||
2446 | "%s: Unable to allocate SKB onto RBD ring - disabling " | ||
2447 | "adapter.\n", priv->net_dev->name); | ||
2448 | /* TODO: schedule adapter shutdown */ | ||
2449 | IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); | ||
2450 | } | ||
2451 | |||
2452 | /* Update the RDB entry */ | ||
2453 | priv->rx_queue.drv[i].host_addr = packet->dma_addr; | ||
2454 | } | ||
2455 | |||
2456 | static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) | ||
2457 | { | ||
2458 | struct ipw2100_status *status = &priv->status_queue.drv[i]; | ||
2459 | struct ipw2100_rx *u = priv->rx_buffers[i].rxp; | ||
2460 | u16 frame_type = status->status_fields & STATUS_TYPE_MASK; | ||
2461 | |||
2462 | switch (frame_type) { | ||
2463 | case COMMAND_STATUS_VAL: | ||
2464 | return (status->frame_size != sizeof(u->rx_data.command)); | ||
2465 | case STATUS_CHANGE_VAL: | ||
2466 | return (status->frame_size != sizeof(u->rx_data.status)); | ||
2467 | case HOST_NOTIFICATION_VAL: | ||
2468 | return (status->frame_size < sizeof(u->rx_data.notification)); | ||
2469 | case P80211_DATA_VAL: | ||
2470 | case P8023_DATA_VAL: | ||
2471 | #ifdef CONFIG_IPW2100_MONITOR | ||
2472 | return 0; | ||
2473 | #else | ||
2474 | switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) { | ||
2475 | case IEEE80211_FTYPE_MGMT: | ||
2476 | case IEEE80211_FTYPE_CTL: | ||
2477 | return 0; | ||
2478 | case IEEE80211_FTYPE_DATA: | ||
2479 | return (status->frame_size > | ||
2480 | IPW_MAX_802_11_PAYLOAD_LENGTH); | ||
2481 | } | ||
2482 | #endif | ||
2483 | } | ||
2484 | |||
2485 | return 1; | ||
2486 | } | ||
2487 | |||
2488 | /* | ||
2489 | * ipw2100 interrupts are disabled at this point, and the ISR | ||
2490 | * is the only code that calls this method. So, we do not need | ||
2491 | * to play with any locks. | ||
2492 | * | ||
2493 | * RX Queue works as follows: | ||
2494 | * | ||
2495 | * Read index - firmware places packet in entry identified by the | ||
2496 | * Read index and advances Read index. In this manner, | ||
2497 | * Read index will always point to the next packet to | ||
2498 | * be filled--but not yet valid. | ||
2499 | * | ||
2500 | * Write index - driver fills this entry with an unused RBD entry. | ||
2501 | * This entry has not filled by the firmware yet. | ||
2502 | * | ||
2503 | * In between the W and R indexes are the RBDs that have been received | ||
2504 | * but not yet processed. | ||
2505 | * | ||
2506 | * The process of handling packets will start at WRITE + 1 and advance | ||
2507 | * until it reaches the READ index. | ||
2508 | * | ||
2509 | * The WRITE index is cached in the variable 'priv->rx_queue.next'. | ||
2510 | * | ||
2511 | */ | ||
2512 | static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) | ||
2513 | { | ||
2514 | struct ipw2100_bd_queue *rxq = &priv->rx_queue; | ||
2515 | struct ipw2100_status_queue *sq = &priv->status_queue; | ||
2516 | struct ipw2100_rx_packet *packet; | ||
2517 | u16 frame_type; | ||
2518 | u32 r, w, i, s; | ||
2519 | struct ipw2100_rx *u; | ||
2520 | struct ieee80211_rx_stats stats = { | ||
2521 | .mac_time = jiffies, | ||
2522 | }; | ||
2523 | |||
2524 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r); | ||
2525 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w); | ||
2526 | |||
2527 | if (r >= rxq->entries) { | ||
2528 | IPW_DEBUG_RX("exit - bad read index\n"); | ||
2529 | return; | ||
2530 | } | ||
2531 | |||
2532 | i = (rxq->next + 1) % rxq->entries; | ||
2533 | s = i; | ||
2534 | while (i != r) { | ||
2535 | /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n", | ||
2536 | r, rxq->next, i); */ | ||
2537 | |||
2538 | packet = &priv->rx_buffers[i]; | ||
2539 | |||
2540 | /* Sync the DMA for the STATUS buffer so CPU is sure to get | ||
2541 | * the correct values */ | ||
2542 | pci_dma_sync_single_for_cpu( | ||
2543 | priv->pci_dev, | ||
2544 | sq->nic + sizeof(struct ipw2100_status) * i, | ||
2545 | sizeof(struct ipw2100_status), | ||
2546 | PCI_DMA_FROMDEVICE); | ||
2547 | |||
2548 | /* Sync the DMA for the RX buffer so CPU is sure to get | ||
2549 | * the correct values */ | ||
2550 | pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, | ||
2551 | sizeof(struct ipw2100_rx), | ||
2552 | PCI_DMA_FROMDEVICE); | ||
2553 | |||
2554 | if (unlikely(ipw2100_corruption_check(priv, i))) { | ||
2555 | ipw2100_corruption_detected(priv, i); | ||
2556 | goto increment; | ||
2557 | } | ||
2558 | |||
2559 | u = packet->rxp; | ||
2560 | frame_type = sq->drv[i].status_fields & | ||
2561 | STATUS_TYPE_MASK; | ||
2562 | stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM; | ||
2563 | stats.len = sq->drv[i].frame_size; | ||
2564 | |||
2565 | stats.mask = 0; | ||
2566 | if (stats.rssi != 0) | ||
2567 | stats.mask |= IEEE80211_STATMASK_RSSI; | ||
2568 | stats.freq = IEEE80211_24GHZ_BAND; | ||
2569 | |||
2570 | IPW_DEBUG_RX( | ||
2571 | "%s: '%s' frame type received (%d).\n", | ||
2572 | priv->net_dev->name, frame_types[frame_type], | ||
2573 | stats.len); | ||
2574 | |||
2575 | switch (frame_type) { | ||
2576 | case COMMAND_STATUS_VAL: | ||
2577 | /* Reset Rx watchdog */ | ||
2578 | isr_rx_complete_command( | ||
2579 | priv, &u->rx_data.command); | ||
2580 | break; | ||
2581 | |||
2582 | case STATUS_CHANGE_VAL: | ||
2583 | isr_status_change(priv, u->rx_data.status); | ||
2584 | break; | ||
2585 | |||
2586 | case P80211_DATA_VAL: | ||
2587 | case P8023_DATA_VAL: | ||
2588 | #ifdef CONFIG_IPW2100_MONITOR | ||
2589 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | ||
2590 | isr_rx(priv, i, &stats); | ||
2591 | break; | ||
2592 | } | ||
2593 | #endif | ||
2594 | if (stats.len < sizeof(u->rx_data.header)) | ||
2595 | break; | ||
2596 | switch (WLAN_FC_GET_TYPE(u->rx_data.header. | ||
2597 | frame_ctl)) { | ||
2598 | case IEEE80211_FTYPE_MGMT: | ||
2599 | ieee80211_rx_mgt(priv->ieee, | ||
2600 | &u->rx_data.header, | ||
2601 | &stats); | ||
2602 | break; | ||
2603 | |||
2604 | case IEEE80211_FTYPE_CTL: | ||
2605 | break; | ||
2606 | |||
2607 | case IEEE80211_FTYPE_DATA: | ||
2608 | isr_rx(priv, i, &stats); | ||
2609 | break; | ||
2610 | |||
2611 | } | ||
2612 | break; | ||
2613 | } | ||
2614 | |||
2615 | increment: | ||
2616 | /* clear status field associated with this RBD */ | ||
2617 | rxq->drv[i].status.info.field = 0; | ||
2618 | |||
2619 | i = (i + 1) % rxq->entries; | ||
2620 | } | ||
2621 | |||
2622 | if (i != s) { | ||
2623 | /* backtrack one entry, wrapping to end if at 0 */ | ||
2624 | rxq->next = (i ? i : rxq->entries) - 1; | ||
2625 | |||
2626 | write_register(priv->net_dev, | ||
2627 | IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, | ||
2628 | rxq->next); | ||
2629 | } | ||
2630 | } | ||
2631 | |||
2632 | |||
2633 | /* | ||
2634 | * __ipw2100_tx_process | ||
2635 | * | ||
2636 | * This routine will determine whether the next packet on | ||
2637 | * the fw_pend_list has been processed by the firmware yet. | ||
2638 | * | ||
2639 | * If not, then it does nothing and returns. | ||
2640 | * | ||
2641 | * If so, then it removes the item from the fw_pend_list, frees | ||
2642 | * any associated storage, and places the item back on the | ||
2643 | * free list of its source (either msg_free_list or tx_free_list) | ||
2644 | * | ||
2645 | * TX Queue works as follows: | ||
2646 | * | ||
2647 | * Read index - points to the next TBD that the firmware will | ||
2648 | * process. The firmware will read the data, and once | ||
2649 | * done processing, it will advance the Read index. | ||
2650 | * | ||
2651 | * Write index - driver fills this entry with an constructed TBD | ||
2652 | * entry. The Write index is not advanced until the | ||
2653 | * packet has been configured. | ||
2654 | * | ||
2655 | * In between the W and R indexes are the TBDs that have NOT been | ||
2656 | * processed. Lagging behind the R index are packets that have | ||
2657 | * been processed but have not been freed by the driver. | ||
2658 | * | ||
2659 | * In order to free old storage, an internal index will be maintained | ||
2660 | * that points to the next packet to be freed. When all used | ||
2661 | * packets have been freed, the oldest index will be the same as the | ||
2662 | * firmware's read index. | ||
2663 | * | ||
2664 | * The OLDEST index is cached in the variable 'priv->tx_queue.oldest' | ||
2665 | * | ||
2666 | * Because the TBD structure can not contain arbitrary data, the | ||
2667 | * driver must keep an internal queue of cached allocations such that | ||
2668 | * it can put that data back into the tx_free_list and msg_free_list | ||
2669 | * for use by future command and data packets. | ||
2670 | * | ||
2671 | */ | ||
2672 | static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) | ||
2673 | { | ||
2674 | struct ipw2100_bd_queue *txq = &priv->tx_queue; | ||
2675 | struct ipw2100_bd *tbd; | ||
2676 | struct list_head *element; | ||
2677 | struct ipw2100_tx_packet *packet; | ||
2678 | int descriptors_used; | ||
2679 | int e, i; | ||
2680 | u32 r, w, frag_num = 0; | ||
2681 | |||
2682 | if (list_empty(&priv->fw_pend_list)) | ||
2683 | return 0; | ||
2684 | |||
2685 | element = priv->fw_pend_list.next; | ||
2686 | |||
2687 | packet = list_entry(element, struct ipw2100_tx_packet, list); | ||
2688 | tbd = &txq->drv[packet->index]; | ||
2689 | |||
2690 | /* Determine how many TBD entries must be finished... */ | ||
2691 | switch (packet->type) { | ||
2692 | case COMMAND: | ||
2693 | /* COMMAND uses only one slot; don't advance */ | ||
2694 | descriptors_used = 1; | ||
2695 | e = txq->oldest; | ||
2696 | break; | ||
2697 | |||
2698 | case DATA: | ||
2699 | /* DATA uses two slots; advance and loop position. */ | ||
2700 | descriptors_used = tbd->num_fragments; | ||
2701 | frag_num = tbd->num_fragments - 1; | ||
2702 | e = txq->oldest + frag_num; | ||
2703 | e %= txq->entries; | ||
2704 | break; | ||
2705 | |||
2706 | default: | ||
2707 | printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n", | ||
2708 | priv->net_dev->name); | ||
2709 | return 0; | ||
2710 | } | ||
2711 | |||
2712 | /* if the last TBD is not done by NIC yet, then packet is | ||
2713 | * not ready to be released. | ||
2714 | * | ||
2715 | */ | ||
2716 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, | ||
2717 | &r); | ||
2718 | read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, | ||
2719 | &w); | ||
2720 | if (w != txq->next) | ||
2721 | printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n", | ||
2722 | priv->net_dev->name); | ||
2723 | |||
2724 | /* | ||
2725 | * txq->next is the index of the last packet written txq->oldest is | ||
2726 | * the index of the r is the index of the next packet to be read by | ||
2727 | * firmware | ||
2728 | */ | ||
2729 | |||
2730 | |||
2731 | /* | ||
2732 | * Quick graphic to help you visualize the following | ||
2733 | * if / else statement | ||
2734 | * | ||
2735 | * ===>| s---->|=============== | ||
2736 | * e>| | ||
2737 | * | a | b | c | d | e | f | g | h | i | j | k | l | ||
2738 | * r---->| | ||
2739 | * w | ||
2740 | * | ||
2741 | * w - updated by driver | ||
2742 | * r - updated by firmware | ||
2743 | * s - start of oldest BD entry (txq->oldest) | ||
2744 | * e - end of oldest BD entry | ||
2745 | * | ||
2746 | */ | ||
2747 | if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) { | ||
2748 | IPW_DEBUG_TX("exit - no processed packets ready to release.\n"); | ||
2749 | return 0; | ||
2750 | } | ||
2751 | |||
2752 | list_del(element); | ||
2753 | DEC_STAT(&priv->fw_pend_stat); | ||
2754 | |||
2755 | #ifdef CONFIG_IPW_DEBUG | ||
2756 | { | ||
2757 | int i = txq->oldest; | ||
2758 | IPW_DEBUG_TX( | ||
2759 | "TX%d V=%p P=%04X T=%04X L=%d\n", i, | ||
2760 | &txq->drv[i], | ||
2761 | (u32)(txq->nic + i * sizeof(struct ipw2100_bd)), | ||
2762 | txq->drv[i].host_addr, | ||
2763 | txq->drv[i].buf_length); | ||
2764 | |||
2765 | if (packet->type == DATA) { | ||
2766 | i = (i + 1) % txq->entries; | ||
2767 | |||
2768 | IPW_DEBUG_TX( | ||
2769 | "TX%d V=%p P=%04X T=%04X L=%d\n", i, | ||
2770 | &txq->drv[i], | ||
2771 | (u32)(txq->nic + i * | ||
2772 | sizeof(struct ipw2100_bd)), | ||
2773 | (u32)txq->drv[i].host_addr, | ||
2774 | txq->drv[i].buf_length); | ||
2775 | } | ||
2776 | } | ||
2777 | #endif | ||
2778 | |||
2779 | switch (packet->type) { | ||
2780 | case DATA: | ||
2781 | if (txq->drv[txq->oldest].status.info.fields.txType != 0) | ||
2782 | printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " | ||
2783 | "Expecting DATA TBD but pulled " | ||
2784 | "something else: ids %d=%d.\n", | ||
2785 | priv->net_dev->name, txq->oldest, packet->index); | ||
2786 | |||
2787 | /* DATA packet; we have to unmap and free the SKB */ | ||
2788 | priv->ieee->stats.tx_packets++; | ||
2789 | for (i = 0; i < frag_num; i++) { | ||
2790 | tbd = &txq->drv[(packet->index + 1 + i) % | ||
2791 | txq->entries]; | ||
2792 | |||
2793 | IPW_DEBUG_TX( | ||
2794 | "TX%d P=%08x L=%d\n", | ||
2795 | (packet->index + 1 + i) % txq->entries, | ||
2796 | tbd->host_addr, tbd->buf_length); | ||
2797 | |||
2798 | pci_unmap_single(priv->pci_dev, | ||
2799 | tbd->host_addr, | ||
2800 | tbd->buf_length, | ||
2801 | PCI_DMA_TODEVICE); | ||
2802 | } | ||
2803 | |||
2804 | priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size; | ||
2805 | ieee80211_txb_free(packet->info.d_struct.txb); | ||
2806 | packet->info.d_struct.txb = NULL; | ||
2807 | |||
2808 | list_add_tail(element, &priv->tx_free_list); | ||
2809 | INC_STAT(&priv->tx_free_stat); | ||
2810 | |||
2811 | /* We have a free slot in the Tx queue, so wake up the | ||
2812 | * transmit layer if it is stopped. */ | ||
2813 | if (priv->status & STATUS_ASSOCIATED && | ||
2814 | netif_queue_stopped(priv->net_dev)) { | ||
2815 | IPW_DEBUG_INFO(KERN_INFO | ||
2816 | "%s: Waking net queue.\n", | ||
2817 | priv->net_dev->name); | ||
2818 | netif_wake_queue(priv->net_dev); | ||
2819 | } | ||
2820 | |||
2821 | /* A packet was processed by the hardware, so update the | ||
2822 | * watchdog */ | ||
2823 | priv->net_dev->trans_start = jiffies; | ||
2824 | |||
2825 | break; | ||
2826 | |||
2827 | case COMMAND: | ||
2828 | if (txq->drv[txq->oldest].status.info.fields.txType != 1) | ||
2829 | printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " | ||
2830 | "Expecting COMMAND TBD but pulled " | ||
2831 | "something else: ids %d=%d.\n", | ||
2832 | priv->net_dev->name, txq->oldest, packet->index); | ||
2833 | |||
2834 | #ifdef CONFIG_IPW_DEBUG | ||
2835 | if (packet->info.c_struct.cmd->host_command_reg < | ||
2836 | sizeof(command_types) / sizeof(*command_types)) | ||
2837 | IPW_DEBUG_TX( | ||
2838 | "Command '%s (%d)' processed: %d.\n", | ||
2839 | command_types[packet->info.c_struct.cmd->host_command_reg], | ||
2840 | packet->info.c_struct.cmd->host_command_reg, | ||
2841 | packet->info.c_struct.cmd->cmd_status_reg); | ||
2842 | #endif | ||
2843 | |||
2844 | list_add_tail(element, &priv->msg_free_list); | ||
2845 | INC_STAT(&priv->msg_free_stat); | ||
2846 | break; | ||
2847 | } | ||
2848 | |||
2849 | /* advance oldest used TBD pointer to start of next entry */ | ||
2850 | txq->oldest = (e + 1) % txq->entries; | ||
2851 | /* increase available TBDs number */ | ||
2852 | txq->available += descriptors_used; | ||
2853 | SET_STAT(&priv->txq_stat, txq->available); | ||
2854 | |||
2855 | IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n", | ||
2856 | jiffies - packet->jiffy_start); | ||
2857 | |||
2858 | return (!list_empty(&priv->fw_pend_list)); | ||
2859 | } | ||
2860 | |||
2861 | |||
2862 | static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv) | ||
2863 | { | ||
2864 | int i = 0; | ||
2865 | |||
2866 | while (__ipw2100_tx_process(priv) && i < 200) i++; | ||
2867 | |||
2868 | if (i == 200) { | ||
2869 | printk(KERN_WARNING DRV_NAME ": " | ||
2870 | "%s: Driver is running slow (%d iters).\n", | ||
2871 | priv->net_dev->name, i); | ||
2872 | } | ||
2873 | } | ||
2874 | |||
2875 | |||
2876 | static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) | ||
2877 | { | ||
2878 | struct list_head *element; | ||
2879 | struct ipw2100_tx_packet *packet; | ||
2880 | struct ipw2100_bd_queue *txq = &priv->tx_queue; | ||
2881 | struct ipw2100_bd *tbd; | ||
2882 | int next = txq->next; | ||
2883 | |||
2884 | while (!list_empty(&priv->msg_pend_list)) { | ||
2885 | /* if there isn't enough space in TBD queue, then | ||
2886 | * don't stuff a new one in. | ||
2887 | * NOTE: 3 are needed as a command will take one, | ||
2888 | * and there is a minimum of 2 that must be | ||
2889 | * maintained between the r and w indexes | ||
2890 | */ | ||
2891 | if (txq->available <= 3) { | ||
2892 | IPW_DEBUG_TX("no room in tx_queue\n"); | ||
2893 | break; | ||
2894 | } | ||
2895 | |||
2896 | element = priv->msg_pend_list.next; | ||
2897 | list_del(element); | ||
2898 | DEC_STAT(&priv->msg_pend_stat); | ||
2899 | |||
2900 | packet = list_entry(element, | ||
2901 | struct ipw2100_tx_packet, list); | ||
2902 | |||
2903 | IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n", | ||
2904 | &txq->drv[txq->next], | ||
2905 | (void*)(txq->nic + txq->next * | ||
2906 | sizeof(struct ipw2100_bd))); | ||
2907 | |||
2908 | packet->index = txq->next; | ||
2909 | |||
2910 | tbd = &txq->drv[txq->next]; | ||
2911 | |||
2912 | /* initialize TBD */ | ||
2913 | tbd->host_addr = packet->info.c_struct.cmd_phys; | ||
2914 | tbd->buf_length = sizeof(struct ipw2100_cmd_header); | ||
2915 | /* not marking number of fragments causes problems | ||
2916 | * with f/w debug version */ | ||
2917 | tbd->num_fragments = 1; | ||
2918 | tbd->status.info.field = | ||
2919 | IPW_BD_STATUS_TX_FRAME_COMMAND | | ||
2920 | IPW_BD_STATUS_TX_INTERRUPT_ENABLE; | ||
2921 | |||
2922 | /* update TBD queue counters */ | ||
2923 | txq->next++; | ||
2924 | txq->next %= txq->entries; | ||
2925 | txq->available--; | ||
2926 | DEC_STAT(&priv->txq_stat); | ||
2927 | |||
2928 | list_add_tail(element, &priv->fw_pend_list); | ||
2929 | INC_STAT(&priv->fw_pend_stat); | ||
2930 | } | ||
2931 | |||
2932 | if (txq->next != next) { | ||
2933 | /* kick off the DMA by notifying firmware the | ||
2934 | * write index has moved; make sure TBD stores are sync'd */ | ||
2935 | wmb(); | ||
2936 | write_register(priv->net_dev, | ||
2937 | IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, | ||
2938 | txq->next); | ||
2939 | } | ||
2940 | } | ||
2941 | |||
2942 | |||
2943 | /* | ||
2944 | * ipw2100_tx_send_data | ||
2945 | * | ||
2946 | */ | ||
2947 | static void ipw2100_tx_send_data(struct ipw2100_priv *priv) | ||
2948 | { | ||
2949 | struct list_head *element; | ||
2950 | struct ipw2100_tx_packet *packet; | ||
2951 | struct ipw2100_bd_queue *txq = &priv->tx_queue; | ||
2952 | struct ipw2100_bd *tbd; | ||
2953 | int next = txq->next; | ||
2954 | int i = 0; | ||
2955 | struct ipw2100_data_header *ipw_hdr; | ||
2956 | struct ieee80211_hdr *hdr; | ||
2957 | |||
2958 | while (!list_empty(&priv->tx_pend_list)) { | ||
2959 | /* if there isn't enough space in TBD queue, then | ||
2960 | * don't stuff a new one in. | ||
2961 | * NOTE: 4 are needed as a data will take two, | ||
2962 | * and there is a minimum of 2 that must be | ||
2963 | * maintained between the r and w indexes | ||
2964 | */ | ||
2965 | element = priv->tx_pend_list.next; | ||
2966 | packet = list_entry(element, struct ipw2100_tx_packet, list); | ||
2967 | |||
2968 | if (unlikely(1 + packet->info.d_struct.txb->nr_frags > | ||
2969 | IPW_MAX_BDS)) { | ||
2970 | /* TODO: Support merging buffers if more than | ||
2971 | * IPW_MAX_BDS are used */ | ||
2972 | IPW_DEBUG_INFO( | ||
2973 | "%s: Maximum BD theshold exceeded. " | ||
2974 | "Increase fragmentation level.\n", | ||
2975 | priv->net_dev->name); | ||
2976 | } | ||
2977 | |||
2978 | if (txq->available <= 3 + | ||
2979 | packet->info.d_struct.txb->nr_frags) { | ||
2980 | IPW_DEBUG_TX("no room in tx_queue\n"); | ||
2981 | break; | ||
2982 | } | ||
2983 | |||
2984 | list_del(element); | ||
2985 | DEC_STAT(&priv->tx_pend_stat); | ||
2986 | |||
2987 | tbd = &txq->drv[txq->next]; | ||
2988 | |||
2989 | packet->index = txq->next; | ||
2990 | |||
2991 | ipw_hdr = packet->info.d_struct.data; | ||
2992 | hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb-> | ||
2993 | fragments[0]->data; | ||
2994 | |||
2995 | if (priv->ieee->iw_mode == IW_MODE_INFRA) { | ||
2996 | /* To DS: Addr1 = BSSID, Addr2 = SA, | ||
2997 | Addr3 = DA */ | ||
2998 | memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); | ||
2999 | memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN); | ||
3000 | } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
3001 | /* not From/To DS: Addr1 = DA, Addr2 = SA, | ||
3002 | Addr3 = BSSID */ | ||
3003 | memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); | ||
3004 | memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN); | ||
3005 | } | ||
3006 | |||
3007 | ipw_hdr->host_command_reg = SEND; | ||
3008 | ipw_hdr->host_command_reg1 = 0; | ||
3009 | |||
3010 | /* For now we only support host based encryption */ | ||
3011 | ipw_hdr->needs_encryption = 0; | ||
3012 | ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted; | ||
3013 | if (packet->info.d_struct.txb->nr_frags > 1) | ||
3014 | ipw_hdr->fragment_size = | ||
3015 | packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN; | ||
3016 | else | ||
3017 | ipw_hdr->fragment_size = 0; | ||
3018 | |||
3019 | tbd->host_addr = packet->info.d_struct.data_phys; | ||
3020 | tbd->buf_length = sizeof(struct ipw2100_data_header); | ||
3021 | tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags; | ||
3022 | tbd->status.info.field = | ||
3023 | IPW_BD_STATUS_TX_FRAME_802_3 | | ||
3024 | IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; | ||
3025 | txq->next++; | ||
3026 | txq->next %= txq->entries; | ||
3027 | |||
3028 | IPW_DEBUG_TX( | ||
3029 | "data header tbd TX%d P=%08x L=%d\n", | ||
3030 | packet->index, tbd->host_addr, | ||
3031 | tbd->buf_length); | ||
3032 | #ifdef CONFIG_IPW_DEBUG | ||
3033 | if (packet->info.d_struct.txb->nr_frags > 1) | ||
3034 | IPW_DEBUG_FRAG("fragment Tx: %d frames\n", | ||
3035 | packet->info.d_struct.txb->nr_frags); | ||
3036 | #endif | ||
3037 | |||
3038 | for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) { | ||
3039 | tbd = &txq->drv[txq->next]; | ||
3040 | if (i == packet->info.d_struct.txb->nr_frags - 1) | ||
3041 | tbd->status.info.field = | ||
3042 | IPW_BD_STATUS_TX_FRAME_802_3 | | ||
3043 | IPW_BD_STATUS_TX_INTERRUPT_ENABLE; | ||
3044 | else | ||
3045 | tbd->status.info.field = | ||
3046 | IPW_BD_STATUS_TX_FRAME_802_3 | | ||
3047 | IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; | ||
3048 | |||
3049 | tbd->buf_length = packet->info.d_struct.txb-> | ||
3050 | fragments[i]->len - IEEE80211_3ADDR_LEN; | ||
3051 | |||
3052 | tbd->host_addr = pci_map_single( | ||
3053 | priv->pci_dev, | ||
3054 | packet->info.d_struct.txb->fragments[i]->data + | ||
3055 | IEEE80211_3ADDR_LEN, | ||
3056 | tbd->buf_length, | ||
3057 | PCI_DMA_TODEVICE); | ||
3058 | |||
3059 | IPW_DEBUG_TX( | ||
3060 | "data frag tbd TX%d P=%08x L=%d\n", | ||
3061 | txq->next, tbd->host_addr, tbd->buf_length); | ||
3062 | |||
3063 | pci_dma_sync_single_for_device( | ||
3064 | priv->pci_dev, tbd->host_addr, | ||
3065 | tbd->buf_length, | ||
3066 | PCI_DMA_TODEVICE); | ||
3067 | |||
3068 | txq->next++; | ||
3069 | txq->next %= txq->entries; | ||
3070 | } | ||
3071 | |||
3072 | txq->available -= 1 + packet->info.d_struct.txb->nr_frags; | ||
3073 | SET_STAT(&priv->txq_stat, txq->available); | ||
3074 | |||
3075 | list_add_tail(element, &priv->fw_pend_list); | ||
3076 | INC_STAT(&priv->fw_pend_stat); | ||
3077 | } | ||
3078 | |||
3079 | if (txq->next != next) { | ||
3080 | /* kick off the DMA by notifying firmware the | ||
3081 | * write index has moved; make sure TBD stores are sync'd */ | ||
3082 | write_register(priv->net_dev, | ||
3083 | IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, | ||
3084 | txq->next); | ||
3085 | } | ||
3086 | return; | ||
3087 | } | ||
3088 | |||
3089 | static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) | ||
3090 | { | ||
3091 | struct net_device *dev = priv->net_dev; | ||
3092 | unsigned long flags; | ||
3093 | u32 inta, tmp; | ||
3094 | |||
3095 | spin_lock_irqsave(&priv->low_lock, flags); | ||
3096 | ipw2100_disable_interrupts(priv); | ||
3097 | |||
3098 | read_register(dev, IPW_REG_INTA, &inta); | ||
3099 | |||
3100 | IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n", | ||
3101 | (unsigned long)inta & IPW_INTERRUPT_MASK); | ||
3102 | |||
3103 | priv->in_isr++; | ||
3104 | priv->interrupts++; | ||
3105 | |||
3106 | /* We do not loop and keep polling for more interrupts as this | ||
3107 | * is frowned upon and doesn't play nicely with other potentially | ||
3108 | * chained IRQs */ | ||
3109 | IPW_DEBUG_ISR("INTA: 0x%08lX\n", | ||
3110 | (unsigned long)inta & IPW_INTERRUPT_MASK); | ||
3111 | |||
3112 | if (inta & IPW2100_INTA_FATAL_ERROR) { | ||
3113 | printk(KERN_WARNING DRV_NAME | ||
3114 | ": Fatal interrupt. Scheduling firmware restart.\n"); | ||
3115 | priv->inta_other++; | ||
3116 | write_register( | ||
3117 | dev, IPW_REG_INTA, | ||
3118 | IPW2100_INTA_FATAL_ERROR); | ||
3119 | |||
3120 | read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error); | ||
3121 | IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n", | ||
3122 | priv->net_dev->name, priv->fatal_error); | ||
3123 | |||
3124 | read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp); | ||
3125 | IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n", | ||
3126 | priv->net_dev->name, tmp); | ||
3127 | |||
3128 | /* Wake up any sleeping jobs */ | ||
3129 | schedule_reset(priv); | ||
3130 | } | ||
3131 | |||
3132 | if (inta & IPW2100_INTA_PARITY_ERROR) { | ||
3133 | printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n"); | ||
3134 | priv->inta_other++; | ||
3135 | write_register( | ||
3136 | dev, IPW_REG_INTA, | ||
3137 | IPW2100_INTA_PARITY_ERROR); | ||
3138 | } | ||
3139 | |||
3140 | if (inta & IPW2100_INTA_RX_TRANSFER) { | ||
3141 | IPW_DEBUG_ISR("RX interrupt\n"); | ||
3142 | |||
3143 | priv->rx_interrupts++; | ||
3144 | |||
3145 | write_register( | ||
3146 | dev, IPW_REG_INTA, | ||
3147 | IPW2100_INTA_RX_TRANSFER); | ||
3148 | |||
3149 | __ipw2100_rx_process(priv); | ||
3150 | __ipw2100_tx_complete(priv); | ||
3151 | } | ||
3152 | |||
3153 | if (inta & IPW2100_INTA_TX_TRANSFER) { | ||
3154 | IPW_DEBUG_ISR("TX interrupt\n"); | ||
3155 | |||
3156 | priv->tx_interrupts++; | ||
3157 | |||
3158 | write_register(dev, IPW_REG_INTA, | ||
3159 | IPW2100_INTA_TX_TRANSFER); | ||
3160 | |||
3161 | __ipw2100_tx_complete(priv); | ||
3162 | ipw2100_tx_send_commands(priv); | ||
3163 | ipw2100_tx_send_data(priv); | ||
3164 | } | ||
3165 | |||
3166 | if (inta & IPW2100_INTA_TX_COMPLETE) { | ||
3167 | IPW_DEBUG_ISR("TX complete\n"); | ||
3168 | priv->inta_other++; | ||
3169 | write_register( | ||
3170 | dev, IPW_REG_INTA, | ||
3171 | IPW2100_INTA_TX_COMPLETE); | ||
3172 | |||
3173 | __ipw2100_tx_complete(priv); | ||
3174 | } | ||
3175 | |||
3176 | if (inta & IPW2100_INTA_EVENT_INTERRUPT) { | ||
3177 | /* ipw2100_handle_event(dev); */ | ||
3178 | priv->inta_other++; | ||
3179 | write_register( | ||
3180 | dev, IPW_REG_INTA, | ||
3181 | IPW2100_INTA_EVENT_INTERRUPT); | ||
3182 | } | ||
3183 | |||
3184 | if (inta & IPW2100_INTA_FW_INIT_DONE) { | ||
3185 | IPW_DEBUG_ISR("FW init done interrupt\n"); | ||
3186 | priv->inta_other++; | ||
3187 | |||
3188 | read_register(dev, IPW_REG_INTA, &tmp); | ||
3189 | if (tmp & (IPW2100_INTA_FATAL_ERROR | | ||
3190 | IPW2100_INTA_PARITY_ERROR)) { | ||
3191 | write_register( | ||
3192 | dev, IPW_REG_INTA, | ||
3193 | IPW2100_INTA_FATAL_ERROR | | ||
3194 | IPW2100_INTA_PARITY_ERROR); | ||
3195 | } | ||
3196 | |||
3197 | write_register(dev, IPW_REG_INTA, | ||
3198 | IPW2100_INTA_FW_INIT_DONE); | ||
3199 | } | ||
3200 | |||
3201 | if (inta & IPW2100_INTA_STATUS_CHANGE) { | ||
3202 | IPW_DEBUG_ISR("Status change interrupt\n"); | ||
3203 | priv->inta_other++; | ||
3204 | write_register( | ||
3205 | dev, IPW_REG_INTA, | ||
3206 | IPW2100_INTA_STATUS_CHANGE); | ||
3207 | } | ||
3208 | |||
3209 | if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) { | ||
3210 | IPW_DEBUG_ISR("slave host mode interrupt\n"); | ||
3211 | priv->inta_other++; | ||
3212 | write_register( | ||
3213 | dev, IPW_REG_INTA, | ||
3214 | IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE); | ||
3215 | } | ||
3216 | |||
3217 | priv->in_isr--; | ||
3218 | ipw2100_enable_interrupts(priv); | ||
3219 | |||
3220 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
3221 | |||
3222 | IPW_DEBUG_ISR("exit\n"); | ||
3223 | } | ||
3224 | |||
3225 | |||
3226 | static irqreturn_t ipw2100_interrupt(int irq, void *data, | ||
3227 | struct pt_regs *regs) | ||
3228 | { | ||
3229 | struct ipw2100_priv *priv = data; | ||
3230 | u32 inta, inta_mask; | ||
3231 | |||
3232 | if (!data) | ||
3233 | return IRQ_NONE; | ||
3234 | |||
3235 | spin_lock(&priv->low_lock); | ||
3236 | |||
3237 | /* We check to see if we should be ignoring interrupts before | ||
3238 | * we touch the hardware. During ucode load if we try and handle | ||
3239 | * an interrupt we can cause keyboard problems as well as cause | ||
3240 | * the ucode to fail to initialize */ | ||
3241 | if (!(priv->status & STATUS_INT_ENABLED)) { | ||
3242 | /* Shared IRQ */ | ||
3243 | goto none; | ||
3244 | } | ||
3245 | |||
3246 | read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); | ||
3247 | read_register(priv->net_dev, IPW_REG_INTA, &inta); | ||
3248 | |||
3249 | if (inta == 0xFFFFFFFF) { | ||
3250 | /* Hardware disappeared */ | ||
3251 | printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n"); | ||
3252 | goto none; | ||
3253 | } | ||
3254 | |||
3255 | inta &= IPW_INTERRUPT_MASK; | ||
3256 | |||
3257 | if (!(inta & inta_mask)) { | ||
3258 | /* Shared interrupt */ | ||
3259 | goto none; | ||
3260 | } | ||
3261 | |||
3262 | /* We disable the hardware interrupt here just to prevent unneeded | ||
3263 | * calls to be made. We disable this again within the actual | ||
3264 | * work tasklet, so if another part of the code re-enables the | ||
3265 | * interrupt, that is fine */ | ||
3266 | ipw2100_disable_interrupts(priv); | ||
3267 | |||
3268 | tasklet_schedule(&priv->irq_tasklet); | ||
3269 | spin_unlock(&priv->low_lock); | ||
3270 | |||
3271 | return IRQ_HANDLED; | ||
3272 | none: | ||
3273 | spin_unlock(&priv->low_lock); | ||
3274 | return IRQ_NONE; | ||
3275 | } | ||
3276 | |||
3277 | static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev) | ||
3278 | { | ||
3279 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
3280 | struct list_head *element; | ||
3281 | struct ipw2100_tx_packet *packet; | ||
3282 | unsigned long flags; | ||
3283 | |||
3284 | spin_lock_irqsave(&priv->low_lock, flags); | ||
3285 | |||
3286 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
3287 | IPW_DEBUG_INFO("Can not transmit when not connected.\n"); | ||
3288 | priv->ieee->stats.tx_carrier_errors++; | ||
3289 | netif_stop_queue(dev); | ||
3290 | goto fail_unlock; | ||
3291 | } | ||
3292 | |||
3293 | if (list_empty(&priv->tx_free_list)) | ||
3294 | goto fail_unlock; | ||
3295 | |||
3296 | element = priv->tx_free_list.next; | ||
3297 | packet = list_entry(element, struct ipw2100_tx_packet, list); | ||
3298 | |||
3299 | packet->info.d_struct.txb = txb; | ||
3300 | |||
3301 | IPW_DEBUG_TX("Sending fragment (%d bytes):\n", | ||
3302 | txb->fragments[0]->len); | ||
3303 | printk_buf(IPW_DL_TX, txb->fragments[0]->data, | ||
3304 | txb->fragments[0]->len); | ||
3305 | |||
3306 | packet->jiffy_start = jiffies; | ||
3307 | |||
3308 | list_del(element); | ||
3309 | DEC_STAT(&priv->tx_free_stat); | ||
3310 | |||
3311 | list_add_tail(element, &priv->tx_pend_list); | ||
3312 | INC_STAT(&priv->tx_pend_stat); | ||
3313 | |||
3314 | ipw2100_tx_send_data(priv); | ||
3315 | |||
3316 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
3317 | return 0; | ||
3318 | |||
3319 | fail_unlock: | ||
3320 | netif_stop_queue(dev); | ||
3321 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
3322 | return 1; | ||
3323 | } | ||
3324 | |||
3325 | |||
3326 | static int ipw2100_msg_allocate(struct ipw2100_priv *priv) | ||
3327 | { | ||
3328 | int i, j, err = -EINVAL; | ||
3329 | void *v; | ||
3330 | dma_addr_t p; | ||
3331 | |||
3332 | priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc( | ||
3333 | IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet), | ||
3334 | GFP_KERNEL); | ||
3335 | if (!priv->msg_buffers) { | ||
3336 | printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg " | ||
3337 | "buffers.\n", priv->net_dev->name); | ||
3338 | return -ENOMEM; | ||
3339 | } | ||
3340 | |||
3341 | for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { | ||
3342 | v = pci_alloc_consistent( | ||
3343 | priv->pci_dev, | ||
3344 | sizeof(struct ipw2100_cmd_header), | ||
3345 | &p); | ||
3346 | if (!v) { | ||
3347 | printk(KERN_ERR DRV_NAME ": " | ||
3348 | "%s: PCI alloc failed for msg " | ||
3349 | "buffers.\n", | ||
3350 | priv->net_dev->name); | ||
3351 | err = -ENOMEM; | ||
3352 | break; | ||
3353 | } | ||
3354 | |||
3355 | memset(v, 0, sizeof(struct ipw2100_cmd_header)); | ||
3356 | |||
3357 | priv->msg_buffers[i].type = COMMAND; | ||
3358 | priv->msg_buffers[i].info.c_struct.cmd = | ||
3359 | (struct ipw2100_cmd_header*)v; | ||
3360 | priv->msg_buffers[i].info.c_struct.cmd_phys = p; | ||
3361 | } | ||
3362 | |||
3363 | if (i == IPW_COMMAND_POOL_SIZE) | ||
3364 | return 0; | ||
3365 | |||
3366 | for (j = 0; j < i; j++) { | ||
3367 | pci_free_consistent( | ||
3368 | priv->pci_dev, | ||
3369 | sizeof(struct ipw2100_cmd_header), | ||
3370 | priv->msg_buffers[j].info.c_struct.cmd, | ||
3371 | priv->msg_buffers[j].info.c_struct.cmd_phys); | ||
3372 | } | ||
3373 | |||
3374 | kfree(priv->msg_buffers); | ||
3375 | priv->msg_buffers = NULL; | ||
3376 | |||
3377 | return err; | ||
3378 | } | ||
3379 | |||
3380 | static int ipw2100_msg_initialize(struct ipw2100_priv *priv) | ||
3381 | { | ||
3382 | int i; | ||
3383 | |||
3384 | INIT_LIST_HEAD(&priv->msg_free_list); | ||
3385 | INIT_LIST_HEAD(&priv->msg_pend_list); | ||
3386 | |||
3387 | for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) | ||
3388 | list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list); | ||
3389 | SET_STAT(&priv->msg_free_stat, i); | ||
3390 | |||
3391 | return 0; | ||
3392 | } | ||
3393 | |||
3394 | static void ipw2100_msg_free(struct ipw2100_priv *priv) | ||
3395 | { | ||
3396 | int i; | ||
3397 | |||
3398 | if (!priv->msg_buffers) | ||
3399 | return; | ||
3400 | |||
3401 | for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { | ||
3402 | pci_free_consistent(priv->pci_dev, | ||
3403 | sizeof(struct ipw2100_cmd_header), | ||
3404 | priv->msg_buffers[i].info.c_struct.cmd, | ||
3405 | priv->msg_buffers[i].info.c_struct.cmd_phys); | ||
3406 | } | ||
3407 | |||
3408 | kfree(priv->msg_buffers); | ||
3409 | priv->msg_buffers = NULL; | ||
3410 | } | ||
3411 | |||
3412 | static ssize_t show_pci(struct device *d, struct device_attribute *attr, | ||
3413 | char *buf) | ||
3414 | { | ||
3415 | struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev); | ||
3416 | char *out = buf; | ||
3417 | int i, j; | ||
3418 | u32 val; | ||
3419 | |||
3420 | for (i = 0; i < 16; i++) { | ||
3421 | out += sprintf(out, "[%08X] ", i * 16); | ||
3422 | for (j = 0; j < 16; j += 4) { | ||
3423 | pci_read_config_dword(pci_dev, i * 16 + j, &val); | ||
3424 | out += sprintf(out, "%08X ", val); | ||
3425 | } | ||
3426 | out += sprintf(out, "\n"); | ||
3427 | } | ||
3428 | |||
3429 | return out - buf; | ||
3430 | } | ||
3431 | static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); | ||
3432 | |||
3433 | static ssize_t show_cfg(struct device *d, struct device_attribute *attr, | ||
3434 | char *buf) | ||
3435 | { | ||
3436 | struct ipw2100_priv *p = d->driver_data; | ||
3437 | return sprintf(buf, "0x%08x\n", (int)p->config); | ||
3438 | } | ||
3439 | static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); | ||
3440 | |||
3441 | static ssize_t show_status(struct device *d, struct device_attribute *attr, | ||
3442 | char *buf) | ||
3443 | { | ||
3444 | struct ipw2100_priv *p = d->driver_data; | ||
3445 | return sprintf(buf, "0x%08x\n", (int)p->status); | ||
3446 | } | ||
3447 | static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | ||
3448 | |||
3449 | static ssize_t show_capability(struct device *d, struct device_attribute *attr, | ||
3450 | char *buf) | ||
3451 | { | ||
3452 | struct ipw2100_priv *p = d->driver_data; | ||
3453 | return sprintf(buf, "0x%08x\n", (int)p->capability); | ||
3454 | } | ||
3455 | static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); | ||
3456 | |||
3457 | |||
3458 | #define IPW2100_REG(x) { IPW_ ##x, #x } | ||
3459 | static const struct { | ||
3460 | u32 addr; | ||
3461 | const char *name; | ||
3462 | } hw_data[] = { | ||
3463 | IPW2100_REG(REG_GP_CNTRL), | ||
3464 | IPW2100_REG(REG_GPIO), | ||
3465 | IPW2100_REG(REG_INTA), | ||
3466 | IPW2100_REG(REG_INTA_MASK), | ||
3467 | IPW2100_REG(REG_RESET_REG), | ||
3468 | }; | ||
3469 | #define IPW2100_NIC(x, s) { x, #x, s } | ||
3470 | static const struct { | ||
3471 | u32 addr; | ||
3472 | const char *name; | ||
3473 | size_t size; | ||
3474 | } nic_data[] = { | ||
3475 | IPW2100_NIC(IPW2100_CONTROL_REG, 2), | ||
3476 | IPW2100_NIC(0x210014, 1), | ||
3477 | IPW2100_NIC(0x210000, 1), | ||
3478 | }; | ||
3479 | #define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d } | ||
3480 | static const struct { | ||
3481 | u8 index; | ||
3482 | const char *name; | ||
3483 | const char *desc; | ||
3484 | } ord_data[] = { | ||
3485 | IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), | ||
3486 | IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"), | ||
3487 | IPW2100_ORD(STAT_TX_DIR_DATA, "successful Directed Tx's (MSDU)"), | ||
3488 | IPW2100_ORD(STAT_TX_DIR_DATA1, "successful Directed Tx's (MSDU) @ 1MB"), | ||
3489 | IPW2100_ORD(STAT_TX_DIR_DATA2, "successful Directed Tx's (MSDU) @ 2MB"), | ||
3490 | IPW2100_ORD(STAT_TX_DIR_DATA5_5, "successful Directed Tx's (MSDU) @ 5_5MB"), | ||
3491 | IPW2100_ORD(STAT_TX_DIR_DATA11, "successful Directed Tx's (MSDU) @ 11MB"), | ||
3492 | IPW2100_ORD(STAT_TX_NODIR_DATA1, "successful Non_Directed Tx's (MSDU) @ 1MB"), | ||
3493 | IPW2100_ORD(STAT_TX_NODIR_DATA2, "successful Non_Directed Tx's (MSDU) @ 2MB"), | ||
3494 | IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"), | ||
3495 | IPW2100_ORD(STAT_TX_NODIR_DATA11, "successful Non_Directed Tx's (MSDU) @ 11MB"), | ||
3496 | IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"), | ||
3497 | IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"), | ||
3498 | IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"), | ||
3499 | IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"), | ||
3500 | IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"), | ||
3501 | IPW2100_ORD(STAT_TX_ASSN_RESP, "successful Association response Tx's"), | ||
3502 | IPW2100_ORD(STAT_TX_REASSN, "successful Reassociation Tx's"), | ||
3503 | IPW2100_ORD(STAT_TX_REASSN_RESP, "successful Reassociation response Tx's"), | ||
3504 | IPW2100_ORD(STAT_TX_PROBE, "probes successfully transmitted"), | ||
3505 | IPW2100_ORD(STAT_TX_PROBE_RESP, "probe responses successfully transmitted"), | ||
3506 | IPW2100_ORD(STAT_TX_BEACON, "tx beacon"), | ||
3507 | IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"), | ||
3508 | IPW2100_ORD(STAT_TX_DISASSN, "successful Disassociation TX"), | ||
3509 | IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"), | ||
3510 | IPW2100_ORD(STAT_TX_DEAUTH, "successful Deauthentication TX"), | ||
3511 | IPW2100_ORD(STAT_TX_TOTAL_BYTES, "Total successful Tx data bytes"), | ||
3512 | IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"), | ||
3513 | IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"), | ||
3514 | IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"), | ||
3515 | IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"), | ||
3516 | IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"), | ||
3517 | IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"), | ||
3518 | IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"), | ||
3519 | IPW2100_ORD(STAT_TX_DISASSN_FAIL, "times disassociation failed"), | ||
3520 | IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"), | ||
3521 | IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"), | ||
3522 | IPW2100_ORD(STAT_RX_HOST, "packets passed to host"), | ||
3523 | IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"), | ||
3524 | IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"), | ||
3525 | IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"), | ||
3526 | IPW2100_ORD(STAT_RX_DIR_DATA5_5, "directed packets at 5.5MB"), | ||
3527 | IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"), | ||
3528 | IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"), | ||
3529 | IPW2100_ORD(STAT_RX_NODIR_DATA1, "nondirected packets at 1MB"), | ||
3530 | IPW2100_ORD(STAT_RX_NODIR_DATA2, "nondirected packets at 2MB"), | ||
3531 | IPW2100_ORD(STAT_RX_NODIR_DATA5_5, "nondirected packets at 5.5MB"), | ||
3532 | IPW2100_ORD(STAT_RX_NODIR_DATA11, "nondirected packets at 11MB"), | ||
3533 | IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"), | ||
3534 | IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), | ||
3535 | IPW2100_ORD(STAT_RX_CTS, "Rx CTS"), | ||
3536 | IPW2100_ORD(STAT_RX_ACK, "Rx ACK"), | ||
3537 | IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"), | ||
3538 | IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"), | ||
3539 | IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"), | ||
3540 | IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"), | ||
3541 | IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"), | ||
3542 | IPW2100_ORD(STAT_RX_REASSN_RESP, "Reassociation response Rx's"), | ||
3543 | IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"), | ||
3544 | IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"), | ||
3545 | IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"), | ||
3546 | IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"), | ||
3547 | IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"), | ||
3548 | IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"), | ||
3549 | IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"), | ||
3550 | IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"), | ||
3551 | IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"), | ||
3552 | IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"), | ||
3553 | IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"), | ||
3554 | IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"), | ||
3555 | IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"), | ||
3556 | IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"), | ||
3557 | IPW2100_ORD(STAT_RX_DUPLICATE2, "duplicate rx packets at 2MB"), | ||
3558 | IPW2100_ORD(STAT_RX_DUPLICATE5_5, "duplicate rx packets at 5.5MB"), | ||
3559 | IPW2100_ORD(STAT_RX_DUPLICATE11, "duplicate rx packets at 11MB"), | ||
3560 | IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"), | ||
3561 | IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"), | ||
3562 | IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"), | ||
3563 | IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"), | ||
3564 | IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, "rx frames with invalid protocol"), | ||
3565 | IPW2100_ORD(SYS_BOOT_TIME, "Boot time"), | ||
3566 | IPW2100_ORD(STAT_RX_NO_BUFFER, "rx frames rejected due to no buffer"), | ||
3567 | IPW2100_ORD(STAT_RX_MISSING_FRAG, "rx frames dropped due to missing fragment"), | ||
3568 | IPW2100_ORD(STAT_RX_ORPHAN_FRAG, "rx frames dropped due to non-sequential fragment"), | ||
3569 | IPW2100_ORD(STAT_RX_ORPHAN_FRAME, "rx frames dropped due to unmatched 1st frame"), | ||
3570 | IPW2100_ORD(STAT_RX_FRAG_AGEOUT, "rx frames dropped due to uncompleted frame"), | ||
3571 | IPW2100_ORD(STAT_RX_ICV_ERRORS, "ICV errors during decryption"), | ||
3572 | IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"), | ||
3573 | IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"), | ||
3574 | IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, "poll response timeouts"), | ||
3575 | IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"), | ||
3576 | IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"), | ||
3577 | IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"), | ||
3578 | IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"), | ||
3579 | IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"), | ||
3580 | IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"), | ||
3581 | IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"), | ||
3582 | IPW2100_ORD(ASSOCIATED_AP_PTR, "0 if not associated, else pointer to AP table entry"), | ||
3583 | IPW2100_ORD(AVAILABLE_AP_CNT, "AP's decsribed in the AP table"), | ||
3584 | IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), | ||
3585 | IPW2100_ORD(STAT_AP_ASSNS, "associations"), | ||
3586 | IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), | ||
3587 | IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"), | ||
3588 | IPW2100_ORD(STAT_FULL_SCANS, "full scans"), | ||
3589 | IPW2100_ORD(CARD_DISABLED, "Card Disabled"), | ||
3590 | IPW2100_ORD(STAT_ROAM_INHIBIT, "times roaming was inhibited due to activity"), | ||
3591 | IPW2100_ORD(RSSI_AT_ASSN, "RSSI of associated AP at time of association"), | ||
3592 | IPW2100_ORD(STAT_ASSN_CAUSE1, "reassociation: no probe response or TX on hop"), | ||
3593 | IPW2100_ORD(STAT_ASSN_CAUSE2, "reassociation: poor tx/rx quality"), | ||
3594 | IPW2100_ORD(STAT_ASSN_CAUSE3, "reassociation: tx/rx quality (excessive AP load"), | ||
3595 | IPW2100_ORD(STAT_ASSN_CAUSE4, "reassociation: AP RSSI level"), | ||
3596 | IPW2100_ORD(STAT_ASSN_CAUSE5, "reassociations due to load leveling"), | ||
3597 | IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"), | ||
3598 | IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"), | ||
3599 | IPW2100_ORD(STATION_TABLE_CNT, "entries in association table"), | ||
3600 | IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"), | ||
3601 | IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"), | ||
3602 | IPW2100_ORD(COUNTRY_CODE, "IEEE country code as recv'd from beacon"), | ||
3603 | IPW2100_ORD(COUNTRY_CHANNELS, "channels suported by country"), | ||
3604 | IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), | ||
3605 | IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), | ||
3606 | IPW2100_ORD(ANTENNA_DIVERSITY, "TRUE if antenna diversity is disabled"), | ||
3607 | IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"), | ||
3608 | IPW2100_ORD(OUR_FREQ, "current radio freq lower digits - channel ID"), | ||
3609 | IPW2100_ORD(RTC_TIME, "current RTC time"), | ||
3610 | IPW2100_ORD(PORT_TYPE, "operating mode"), | ||
3611 | IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"), | ||
3612 | IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"), | ||
3613 | IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"), | ||
3614 | IPW2100_ORD(BASIC_RATES, "basic tx rates"), | ||
3615 | IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"), | ||
3616 | IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"), | ||
3617 | IPW2100_ORD(CAPABILITIES, "Management frame capability field"), | ||
3618 | IPW2100_ORD(AUTH_TYPE, "Type of authentication"), | ||
3619 | IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"), | ||
3620 | IPW2100_ORD(RTS_THRESHOLD, "Min packet length for RTS handshaking"), | ||
3621 | IPW2100_ORD(INT_MODE, "International mode"), | ||
3622 | IPW2100_ORD(FRAGMENTATION_THRESHOLD, "protocol frag threshold"), | ||
3623 | IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, "EEPROM offset in SRAM"), | ||
3624 | IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, "EEPROM size in SRAM"), | ||
3625 | IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"), | ||
3626 | IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, "EEPROM IBSS 11b channel set"), | ||
3627 | IPW2100_ORD(MAC_VERSION, "MAC Version"), | ||
3628 | IPW2100_ORD(MAC_REVISION, "MAC Revision"), | ||
3629 | IPW2100_ORD(RADIO_VERSION, "Radio Version"), | ||
3630 | IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"), | ||
3631 | IPW2100_ORD(UCODE_VERSION, "Ucode Version"), | ||
3632 | }; | ||
3633 | |||
3634 | |||
3635 | static ssize_t show_registers(struct device *d, struct device_attribute *attr, | ||
3636 | char *buf) | ||
3637 | { | ||
3638 | int i; | ||
3639 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3640 | struct net_device *dev = priv->net_dev; | ||
3641 | char * out = buf; | ||
3642 | u32 val = 0; | ||
3643 | |||
3644 | out += sprintf(out, "%30s [Address ] : Hex\n", "Register"); | ||
3645 | |||
3646 | for (i = 0; i < (sizeof(hw_data) / sizeof(*hw_data)); i++) { | ||
3647 | read_register(dev, hw_data[i].addr, &val); | ||
3648 | out += sprintf(out, "%30s [%08X] : %08X\n", | ||
3649 | hw_data[i].name, hw_data[i].addr, val); | ||
3650 | } | ||
3651 | |||
3652 | return out - buf; | ||
3653 | } | ||
3654 | static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); | ||
3655 | |||
3656 | |||
3657 | static ssize_t show_hardware(struct device *d, struct device_attribute *attr, | ||
3658 | char *buf) | ||
3659 | { | ||
3660 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3661 | struct net_device *dev = priv->net_dev; | ||
3662 | char * out = buf; | ||
3663 | int i; | ||
3664 | |||
3665 | out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry"); | ||
3666 | |||
3667 | for (i = 0; i < (sizeof(nic_data) / sizeof(*nic_data)); i++) { | ||
3668 | u8 tmp8; | ||
3669 | u16 tmp16; | ||
3670 | u32 tmp32; | ||
3671 | |||
3672 | switch (nic_data[i].size) { | ||
3673 | case 1: | ||
3674 | read_nic_byte(dev, nic_data[i].addr, &tmp8); | ||
3675 | out += sprintf(out, "%30s [%08X] : %02X\n", | ||
3676 | nic_data[i].name, nic_data[i].addr, | ||
3677 | tmp8); | ||
3678 | break; | ||
3679 | case 2: | ||
3680 | read_nic_word(dev, nic_data[i].addr, &tmp16); | ||
3681 | out += sprintf(out, "%30s [%08X] : %04X\n", | ||
3682 | nic_data[i].name, nic_data[i].addr, | ||
3683 | tmp16); | ||
3684 | break; | ||
3685 | case 4: | ||
3686 | read_nic_dword(dev, nic_data[i].addr, &tmp32); | ||
3687 | out += sprintf(out, "%30s [%08X] : %08X\n", | ||
3688 | nic_data[i].name, nic_data[i].addr, | ||
3689 | tmp32); | ||
3690 | break; | ||
3691 | } | ||
3692 | } | ||
3693 | return out - buf; | ||
3694 | } | ||
3695 | static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); | ||
3696 | |||
3697 | |||
3698 | static ssize_t show_memory(struct device *d, struct device_attribute *attr, | ||
3699 | char *buf) | ||
3700 | { | ||
3701 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3702 | struct net_device *dev = priv->net_dev; | ||
3703 | static unsigned long loop = 0; | ||
3704 | int len = 0; | ||
3705 | u32 buffer[4]; | ||
3706 | int i; | ||
3707 | char line[81]; | ||
3708 | |||
3709 | if (loop >= 0x30000) | ||
3710 | loop = 0; | ||
3711 | |||
3712 | /* sysfs provides us PAGE_SIZE buffer */ | ||
3713 | while (len < PAGE_SIZE - 128 && loop < 0x30000) { | ||
3714 | |||
3715 | if (priv->snapshot[0]) for (i = 0; i < 4; i++) | ||
3716 | buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4); | ||
3717 | else for (i = 0; i < 4; i++) | ||
3718 | read_nic_dword(dev, loop + i * 4, &buffer[i]); | ||
3719 | |||
3720 | if (priv->dump_raw) | ||
3721 | len += sprintf(buf + len, | ||
3722 | "%c%c%c%c" | ||
3723 | "%c%c%c%c" | ||
3724 | "%c%c%c%c" | ||
3725 | "%c%c%c%c", | ||
3726 | ((u8*)buffer)[0x0], | ||
3727 | ((u8*)buffer)[0x1], | ||
3728 | ((u8*)buffer)[0x2], | ||
3729 | ((u8*)buffer)[0x3], | ||
3730 | ((u8*)buffer)[0x4], | ||
3731 | ((u8*)buffer)[0x5], | ||
3732 | ((u8*)buffer)[0x6], | ||
3733 | ((u8*)buffer)[0x7], | ||
3734 | ((u8*)buffer)[0x8], | ||
3735 | ((u8*)buffer)[0x9], | ||
3736 | ((u8*)buffer)[0xa], | ||
3737 | ((u8*)buffer)[0xb], | ||
3738 | ((u8*)buffer)[0xc], | ||
3739 | ((u8*)buffer)[0xd], | ||
3740 | ((u8*)buffer)[0xe], | ||
3741 | ((u8*)buffer)[0xf]); | ||
3742 | else | ||
3743 | len += sprintf(buf + len, "%s\n", | ||
3744 | snprint_line(line, sizeof(line), | ||
3745 | (u8*)buffer, 16, loop)); | ||
3746 | loop += 16; | ||
3747 | } | ||
3748 | |||
3749 | return len; | ||
3750 | } | ||
3751 | |||
3752 | static ssize_t store_memory(struct device *d, struct device_attribute *attr, | ||
3753 | const char *buf, size_t count) | ||
3754 | { | ||
3755 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3756 | struct net_device *dev = priv->net_dev; | ||
3757 | const char *p = buf; | ||
3758 | |||
3759 | if (count < 1) | ||
3760 | return count; | ||
3761 | |||
3762 | if (p[0] == '1' || | ||
3763 | (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) { | ||
3764 | IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n", | ||
3765 | dev->name); | ||
3766 | priv->dump_raw = 1; | ||
3767 | |||
3768 | } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' && | ||
3769 | tolower(p[1]) == 'f')) { | ||
3770 | IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n", | ||
3771 | dev->name); | ||
3772 | priv->dump_raw = 0; | ||
3773 | |||
3774 | } else if (tolower(p[0]) == 'r') { | ||
3775 | IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", | ||
3776 | dev->name); | ||
3777 | ipw2100_snapshot_free(priv); | ||
3778 | |||
3779 | } else | ||
3780 | IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, " | ||
3781 | "reset = clear memory snapshot\n", | ||
3782 | dev->name); | ||
3783 | |||
3784 | return count; | ||
3785 | } | ||
3786 | static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory); | ||
3787 | |||
3788 | |||
3789 | static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, | ||
3790 | char *buf) | ||
3791 | { | ||
3792 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3793 | u32 val = 0; | ||
3794 | int len = 0; | ||
3795 | u32 val_len; | ||
3796 | static int loop = 0; | ||
3797 | |||
3798 | if (loop >= sizeof(ord_data) / sizeof(*ord_data)) | ||
3799 | loop = 0; | ||
3800 | |||
3801 | /* sysfs provides us PAGE_SIZE buffer */ | ||
3802 | while (len < PAGE_SIZE - 128 && | ||
3803 | loop < (sizeof(ord_data) / sizeof(*ord_data))) { | ||
3804 | |||
3805 | val_len = sizeof(u32); | ||
3806 | |||
3807 | if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val, | ||
3808 | &val_len)) | ||
3809 | len += sprintf(buf + len, "[0x%02X] = ERROR %s\n", | ||
3810 | ord_data[loop].index, | ||
3811 | ord_data[loop].desc); | ||
3812 | else | ||
3813 | len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n", | ||
3814 | ord_data[loop].index, val, | ||
3815 | ord_data[loop].desc); | ||
3816 | loop++; | ||
3817 | } | ||
3818 | |||
3819 | return len; | ||
3820 | } | ||
3821 | static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); | ||
3822 | |||
3823 | |||
3824 | static ssize_t show_stats(struct device *d, struct device_attribute *attr, | ||
3825 | char *buf) | ||
3826 | { | ||
3827 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3828 | char * out = buf; | ||
3829 | |||
3830 | out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n", | ||
3831 | priv->interrupts, priv->tx_interrupts, | ||
3832 | priv->rx_interrupts, priv->inta_other); | ||
3833 | out += sprintf(out, "firmware resets: %d\n", priv->resets); | ||
3834 | out += sprintf(out, "firmware hangs: %d\n", priv->hangs); | ||
3835 | #ifdef CONFIG_IPW_DEBUG | ||
3836 | out += sprintf(out, "packet mismatch image: %s\n", | ||
3837 | priv->snapshot[0] ? "YES" : "NO"); | ||
3838 | #endif | ||
3839 | |||
3840 | return out - buf; | ||
3841 | } | ||
3842 | static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); | ||
3843 | |||
3844 | |||
3845 | static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) | ||
3846 | { | ||
3847 | int err; | ||
3848 | |||
3849 | if (mode == priv->ieee->iw_mode) | ||
3850 | return 0; | ||
3851 | |||
3852 | err = ipw2100_disable_adapter(priv); | ||
3853 | if (err) { | ||
3854 | printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", | ||
3855 | priv->net_dev->name, err); | ||
3856 | return err; | ||
3857 | } | ||
3858 | |||
3859 | switch (mode) { | ||
3860 | case IW_MODE_INFRA: | ||
3861 | priv->net_dev->type = ARPHRD_ETHER; | ||
3862 | break; | ||
3863 | case IW_MODE_ADHOC: | ||
3864 | priv->net_dev->type = ARPHRD_ETHER; | ||
3865 | break; | ||
3866 | #ifdef CONFIG_IPW2100_MONITOR | ||
3867 | case IW_MODE_MONITOR: | ||
3868 | priv->last_mode = priv->ieee->iw_mode; | ||
3869 | priv->net_dev->type = ARPHRD_IEEE80211; | ||
3870 | break; | ||
3871 | #endif /* CONFIG_IPW2100_MONITOR */ | ||
3872 | } | ||
3873 | |||
3874 | priv->ieee->iw_mode = mode; | ||
3875 | |||
3876 | #ifdef CONFIG_PM | ||
3877 | /* Indicate ipw2100_download_firmware download firmware | ||
3878 | * from disk instead of memory. */ | ||
3879 | ipw2100_firmware.version = 0; | ||
3880 | #endif | ||
3881 | |||
3882 | printk(KERN_INFO "%s: Reseting on mode change.\n", | ||
3883 | priv->net_dev->name); | ||
3884 | priv->reset_backoff = 0; | ||
3885 | schedule_reset(priv); | ||
3886 | |||
3887 | return 0; | ||
3888 | } | ||
3889 | |||
3890 | static ssize_t show_internals(struct device *d, struct device_attribute *attr, | ||
3891 | char *buf) | ||
3892 | { | ||
3893 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3894 | int len = 0; | ||
3895 | |||
3896 | #define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x) | ||
3897 | |||
3898 | if (priv->status & STATUS_ASSOCIATED) | ||
3899 | len += sprintf(buf + len, "connected: %lu\n", | ||
3900 | get_seconds() - priv->connect_start); | ||
3901 | else | ||
3902 | len += sprintf(buf + len, "not connected\n"); | ||
3903 | |||
3904 | DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p); | ||
3905 | DUMP_VAR(status, 08lx); | ||
3906 | DUMP_VAR(config, 08lx); | ||
3907 | DUMP_VAR(capability, 08lx); | ||
3908 | |||
3909 | len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc); | ||
3910 | |||
3911 | DUMP_VAR(fatal_error, d); | ||
3912 | DUMP_VAR(stop_hang_check, d); | ||
3913 | DUMP_VAR(stop_rf_kill, d); | ||
3914 | DUMP_VAR(messages_sent, d); | ||
3915 | |||
3916 | DUMP_VAR(tx_pend_stat.value, d); | ||
3917 | DUMP_VAR(tx_pend_stat.hi, d); | ||
3918 | |||
3919 | DUMP_VAR(tx_free_stat.value, d); | ||
3920 | DUMP_VAR(tx_free_stat.lo, d); | ||
3921 | |||
3922 | DUMP_VAR(msg_free_stat.value, d); | ||
3923 | DUMP_VAR(msg_free_stat.lo, d); | ||
3924 | |||
3925 | DUMP_VAR(msg_pend_stat.value, d); | ||
3926 | DUMP_VAR(msg_pend_stat.hi, d); | ||
3927 | |||
3928 | DUMP_VAR(fw_pend_stat.value, d); | ||
3929 | DUMP_VAR(fw_pend_stat.hi, d); | ||
3930 | |||
3931 | DUMP_VAR(txq_stat.value, d); | ||
3932 | DUMP_VAR(txq_stat.lo, d); | ||
3933 | |||
3934 | DUMP_VAR(ieee->scans, d); | ||
3935 | DUMP_VAR(reset_backoff, d); | ||
3936 | |||
3937 | return len; | ||
3938 | } | ||
3939 | static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); | ||
3940 | |||
3941 | |||
3942 | static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, | ||
3943 | char *buf) | ||
3944 | { | ||
3945 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
3946 | char essid[IW_ESSID_MAX_SIZE + 1]; | ||
3947 | u8 bssid[ETH_ALEN]; | ||
3948 | u32 chan = 0; | ||
3949 | char * out = buf; | ||
3950 | int length; | ||
3951 | int ret; | ||
3952 | |||
3953 | memset(essid, 0, sizeof(essid)); | ||
3954 | memset(bssid, 0, sizeof(bssid)); | ||
3955 | |||
3956 | length = IW_ESSID_MAX_SIZE; | ||
3957 | ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length); | ||
3958 | if (ret) | ||
3959 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
3960 | __LINE__); | ||
3961 | |||
3962 | length = sizeof(bssid); | ||
3963 | ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, | ||
3964 | bssid, &length); | ||
3965 | if (ret) | ||
3966 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
3967 | __LINE__); | ||
3968 | |||
3969 | length = sizeof(u32); | ||
3970 | ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length); | ||
3971 | if (ret) | ||
3972 | IPW_DEBUG_INFO("failed querying ordinals at line %d\n", | ||
3973 | __LINE__); | ||
3974 | |||
3975 | out += sprintf(out, "ESSID: %s\n", essid); | ||
3976 | out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
3977 | bssid[0], bssid[1], bssid[2], | ||
3978 | bssid[3], bssid[4], bssid[5]); | ||
3979 | out += sprintf(out, "Channel: %d\n", chan); | ||
3980 | |||
3981 | return out - buf; | ||
3982 | } | ||
3983 | static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); | ||
3984 | |||
3985 | |||
3986 | #ifdef CONFIG_IPW_DEBUG | ||
3987 | static ssize_t show_debug_level(struct device_driver *d, char *buf) | ||
3988 | { | ||
3989 | return sprintf(buf, "0x%08X\n", ipw2100_debug_level); | ||
3990 | } | ||
3991 | |||
3992 | static ssize_t store_debug_level(struct device_driver *d, const char *buf, | ||
3993 | size_t count) | ||
3994 | { | ||
3995 | char *p = (char *)buf; | ||
3996 | u32 val; | ||
3997 | |||
3998 | if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { | ||
3999 | p++; | ||
4000 | if (p[0] == 'x' || p[0] == 'X') | ||
4001 | p++; | ||
4002 | val = simple_strtoul(p, &p, 16); | ||
4003 | } else | ||
4004 | val = simple_strtoul(p, &p, 10); | ||
4005 | if (p == buf) | ||
4006 | IPW_DEBUG_INFO(DRV_NAME | ||
4007 | ": %s is not in hex or decimal form.\n", buf); | ||
4008 | else | ||
4009 | ipw2100_debug_level = val; | ||
4010 | |||
4011 | return strnlen(buf, count); | ||
4012 | } | ||
4013 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, | ||
4014 | store_debug_level); | ||
4015 | #endif /* CONFIG_IPW_DEBUG */ | ||
4016 | |||
4017 | |||
4018 | static ssize_t show_fatal_error(struct device *d, | ||
4019 | struct device_attribute *attr, char *buf) | ||
4020 | { | ||
4021 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
4022 | char *out = buf; | ||
4023 | int i; | ||
4024 | |||
4025 | if (priv->fatal_error) | ||
4026 | out += sprintf(out, "0x%08X\n", | ||
4027 | priv->fatal_error); | ||
4028 | else | ||
4029 | out += sprintf(out, "0\n"); | ||
4030 | |||
4031 | for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) { | ||
4032 | if (!priv->fatal_errors[(priv->fatal_index - i) % | ||
4033 | IPW2100_ERROR_QUEUE]) | ||
4034 | continue; | ||
4035 | |||
4036 | out += sprintf(out, "%d. 0x%08X\n", i, | ||
4037 | priv->fatal_errors[(priv->fatal_index - i) % | ||
4038 | IPW2100_ERROR_QUEUE]); | ||
4039 | } | ||
4040 | |||
4041 | return out - buf; | ||
4042 | } | ||
4043 | |||
4044 | static ssize_t store_fatal_error(struct device *d, | ||
4045 | struct device_attribute *attr, const char *buf, size_t count) | ||
4046 | { | ||
4047 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
4048 | schedule_reset(priv); | ||
4049 | return count; | ||
4050 | } | ||
4051 | static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error); | ||
4052 | |||
4053 | |||
4054 | static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, | ||
4055 | char *buf) | ||
4056 | { | ||
4057 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
4058 | return sprintf(buf, "%d\n", priv->ieee->scan_age); | ||
4059 | } | ||
4060 | |||
4061 | static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, | ||
4062 | const char *buf, size_t count) | ||
4063 | { | ||
4064 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
4065 | struct net_device *dev = priv->net_dev; | ||
4066 | char buffer[] = "00000000"; | ||
4067 | unsigned long len = | ||
4068 | (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; | ||
4069 | unsigned long val; | ||
4070 | char *p = buffer; | ||
4071 | |||
4072 | IPW_DEBUG_INFO("enter\n"); | ||
4073 | |||
4074 | strncpy(buffer, buf, len); | ||
4075 | buffer[len] = 0; | ||
4076 | |||
4077 | if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { | ||
4078 | p++; | ||
4079 | if (p[0] == 'x' || p[0] == 'X') | ||
4080 | p++; | ||
4081 | val = simple_strtoul(p, &p, 16); | ||
4082 | } else | ||
4083 | val = simple_strtoul(p, &p, 10); | ||
4084 | if (p == buffer) { | ||
4085 | IPW_DEBUG_INFO("%s: user supplied invalid value.\n", | ||
4086 | dev->name); | ||
4087 | } else { | ||
4088 | priv->ieee->scan_age = val; | ||
4089 | IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); | ||
4090 | } | ||
4091 | |||
4092 | IPW_DEBUG_INFO("exit\n"); | ||
4093 | return len; | ||
4094 | } | ||
4095 | static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); | ||
4096 | |||
4097 | |||
4098 | static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, | ||
4099 | char *buf) | ||
4100 | { | ||
4101 | /* 0 - RF kill not enabled | ||
4102 | 1 - SW based RF kill active (sysfs) | ||
4103 | 2 - HW based RF kill active | ||
4104 | 3 - Both HW and SW baed RF kill active */ | ||
4105 | struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; | ||
4106 | int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | | ||
4107 | (rf_kill_active(priv) ? 0x2 : 0x0); | ||
4108 | return sprintf(buf, "%i\n", val); | ||
4109 | } | ||
4110 | |||
4111 | static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) | ||
4112 | { | ||
4113 | if ((disable_radio ? 1 : 0) == | ||
4114 | (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) | ||
4115 | return 0 ; | ||
4116 | |||
4117 | IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", | ||
4118 | disable_radio ? "OFF" : "ON"); | ||
4119 | |||
4120 | down(&priv->action_sem); | ||
4121 | |||
4122 | if (disable_radio) { | ||
4123 | priv->status |= STATUS_RF_KILL_SW; | ||
4124 | ipw2100_down(priv); | ||
4125 | } else { | ||
4126 | priv->status &= ~STATUS_RF_KILL_SW; | ||
4127 | if (rf_kill_active(priv)) { | ||
4128 | IPW_DEBUG_RF_KILL("Can not turn radio back on - " | ||
4129 | "disabled by HW switch\n"); | ||
4130 | /* Make sure the RF_KILL check timer is running */ | ||
4131 | priv->stop_rf_kill = 0; | ||
4132 | cancel_delayed_work(&priv->rf_kill); | ||
4133 | queue_delayed_work(priv->workqueue, &priv->rf_kill, | ||
4134 | HZ); | ||
4135 | } else | ||
4136 | schedule_reset(priv); | ||
4137 | } | ||
4138 | |||
4139 | up(&priv->action_sem); | ||
4140 | return 1; | ||
4141 | } | ||
4142 | |||
4143 | static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, | ||
4144 | const char *buf, size_t count) | ||
4145 | { | ||
4146 | struct ipw2100_priv *priv = dev_get_drvdata(d); | ||
4147 | ipw_radio_kill_sw(priv, buf[0] == '1'); | ||
4148 | return count; | ||
4149 | } | ||
4150 | static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill); | ||
4151 | |||
4152 | |||
4153 | static struct attribute *ipw2100_sysfs_entries[] = { | ||
4154 | &dev_attr_hardware.attr, | ||
4155 | &dev_attr_registers.attr, | ||
4156 | &dev_attr_ordinals.attr, | ||
4157 | &dev_attr_pci.attr, | ||
4158 | &dev_attr_stats.attr, | ||
4159 | &dev_attr_internals.attr, | ||
4160 | &dev_attr_bssinfo.attr, | ||
4161 | &dev_attr_memory.attr, | ||
4162 | &dev_attr_scan_age.attr, | ||
4163 | &dev_attr_fatal_error.attr, | ||
4164 | &dev_attr_rf_kill.attr, | ||
4165 | &dev_attr_cfg.attr, | ||
4166 | &dev_attr_status.attr, | ||
4167 | &dev_attr_capability.attr, | ||
4168 | NULL, | ||
4169 | }; | ||
4170 | |||
4171 | static struct attribute_group ipw2100_attribute_group = { | ||
4172 | .attrs = ipw2100_sysfs_entries, | ||
4173 | }; | ||
4174 | |||
4175 | |||
4176 | static int status_queue_allocate(struct ipw2100_priv *priv, int entries) | ||
4177 | { | ||
4178 | struct ipw2100_status_queue *q = &priv->status_queue; | ||
4179 | |||
4180 | IPW_DEBUG_INFO("enter\n"); | ||
4181 | |||
4182 | q->size = entries * sizeof(struct ipw2100_status); | ||
4183 | q->drv = (struct ipw2100_status *)pci_alloc_consistent( | ||
4184 | priv->pci_dev, q->size, &q->nic); | ||
4185 | if (!q->drv) { | ||
4186 | IPW_DEBUG_WARNING( | ||
4187 | "Can not allocate status queue.\n"); | ||
4188 | return -ENOMEM; | ||
4189 | } | ||
4190 | |||
4191 | memset(q->drv, 0, q->size); | ||
4192 | |||
4193 | IPW_DEBUG_INFO("exit\n"); | ||
4194 | |||
4195 | return 0; | ||
4196 | } | ||
4197 | |||
4198 | static void status_queue_free(struct ipw2100_priv *priv) | ||
4199 | { | ||
4200 | IPW_DEBUG_INFO("enter\n"); | ||
4201 | |||
4202 | if (priv->status_queue.drv) { | ||
4203 | pci_free_consistent( | ||
4204 | priv->pci_dev, priv->status_queue.size, | ||
4205 | priv->status_queue.drv, priv->status_queue.nic); | ||
4206 | priv->status_queue.drv = NULL; | ||
4207 | } | ||
4208 | |||
4209 | IPW_DEBUG_INFO("exit\n"); | ||
4210 | } | ||
4211 | |||
4212 | static int bd_queue_allocate(struct ipw2100_priv *priv, | ||
4213 | struct ipw2100_bd_queue *q, int entries) | ||
4214 | { | ||
4215 | IPW_DEBUG_INFO("enter\n"); | ||
4216 | |||
4217 | memset(q, 0, sizeof(struct ipw2100_bd_queue)); | ||
4218 | |||
4219 | q->entries = entries; | ||
4220 | q->size = entries * sizeof(struct ipw2100_bd); | ||
4221 | q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic); | ||
4222 | if (!q->drv) { | ||
4223 | IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n"); | ||
4224 | return -ENOMEM; | ||
4225 | } | ||
4226 | memset(q->drv, 0, q->size); | ||
4227 | |||
4228 | IPW_DEBUG_INFO("exit\n"); | ||
4229 | |||
4230 | return 0; | ||
4231 | } | ||
4232 | |||
4233 | static void bd_queue_free(struct ipw2100_priv *priv, | ||
4234 | struct ipw2100_bd_queue *q) | ||
4235 | { | ||
4236 | IPW_DEBUG_INFO("enter\n"); | ||
4237 | |||
4238 | if (!q) | ||
4239 | return; | ||
4240 | |||
4241 | if (q->drv) { | ||
4242 | pci_free_consistent(priv->pci_dev, | ||
4243 | q->size, q->drv, q->nic); | ||
4244 | q->drv = NULL; | ||
4245 | } | ||
4246 | |||
4247 | IPW_DEBUG_INFO("exit\n"); | ||
4248 | } | ||
4249 | |||
4250 | static void bd_queue_initialize( | ||
4251 | struct ipw2100_priv *priv, struct ipw2100_bd_queue * q, | ||
4252 | u32 base, u32 size, u32 r, u32 w) | ||
4253 | { | ||
4254 | IPW_DEBUG_INFO("enter\n"); | ||
4255 | |||
4256 | IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic); | ||
4257 | |||
4258 | write_register(priv->net_dev, base, q->nic); | ||
4259 | write_register(priv->net_dev, size, q->entries); | ||
4260 | write_register(priv->net_dev, r, q->oldest); | ||
4261 | write_register(priv->net_dev, w, q->next); | ||
4262 | |||
4263 | IPW_DEBUG_INFO("exit\n"); | ||
4264 | } | ||
4265 | |||
4266 | static void ipw2100_kill_workqueue(struct ipw2100_priv *priv) | ||
4267 | { | ||
4268 | if (priv->workqueue) { | ||
4269 | priv->stop_rf_kill = 1; | ||
4270 | priv->stop_hang_check = 1; | ||
4271 | cancel_delayed_work(&priv->reset_work); | ||
4272 | cancel_delayed_work(&priv->security_work); | ||
4273 | cancel_delayed_work(&priv->wx_event_work); | ||
4274 | cancel_delayed_work(&priv->hang_check); | ||
4275 | cancel_delayed_work(&priv->rf_kill); | ||
4276 | destroy_workqueue(priv->workqueue); | ||
4277 | priv->workqueue = NULL; | ||
4278 | } | ||
4279 | } | ||
4280 | |||
4281 | static int ipw2100_tx_allocate(struct ipw2100_priv *priv) | ||
4282 | { | ||
4283 | int i, j, err = -EINVAL; | ||
4284 | void *v; | ||
4285 | dma_addr_t p; | ||
4286 | |||
4287 | IPW_DEBUG_INFO("enter\n"); | ||
4288 | |||
4289 | err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH); | ||
4290 | if (err) { | ||
4291 | IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n", | ||
4292 | priv->net_dev->name); | ||
4293 | return err; | ||
4294 | } | ||
4295 | |||
4296 | priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc( | ||
4297 | TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet), | ||
4298 | GFP_ATOMIC); | ||
4299 | if (!priv->tx_buffers) { | ||
4300 | printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n", | ||
4301 | priv->net_dev->name); | ||
4302 | bd_queue_free(priv, &priv->tx_queue); | ||
4303 | return -ENOMEM; | ||
4304 | } | ||
4305 | |||
4306 | for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { | ||
4307 | v = pci_alloc_consistent( | ||
4308 | priv->pci_dev, sizeof(struct ipw2100_data_header), &p); | ||
4309 | if (!v) { | ||
4310 | printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx " | ||
4311 | "buffers.\n", priv->net_dev->name); | ||
4312 | err = -ENOMEM; | ||
4313 | break; | ||
4314 | } | ||
4315 | |||
4316 | priv->tx_buffers[i].type = DATA; | ||
4317 | priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v; | ||
4318 | priv->tx_buffers[i].info.d_struct.data_phys = p; | ||
4319 | priv->tx_buffers[i].info.d_struct.txb = NULL; | ||
4320 | } | ||
4321 | |||
4322 | if (i == TX_PENDED_QUEUE_LENGTH) | ||
4323 | return 0; | ||
4324 | |||
4325 | for (j = 0; j < i; j++) { | ||
4326 | pci_free_consistent( | ||
4327 | priv->pci_dev, | ||
4328 | sizeof(struct ipw2100_data_header), | ||
4329 | priv->tx_buffers[j].info.d_struct.data, | ||
4330 | priv->tx_buffers[j].info.d_struct.data_phys); | ||
4331 | } | ||
4332 | |||
4333 | kfree(priv->tx_buffers); | ||
4334 | priv->tx_buffers = NULL; | ||
4335 | |||
4336 | return err; | ||
4337 | } | ||
4338 | |||
4339 | static void ipw2100_tx_initialize(struct ipw2100_priv *priv) | ||
4340 | { | ||
4341 | int i; | ||
4342 | |||
4343 | IPW_DEBUG_INFO("enter\n"); | ||
4344 | |||
4345 | /* | ||
4346 | * reinitialize packet info lists | ||
4347 | */ | ||
4348 | INIT_LIST_HEAD(&priv->fw_pend_list); | ||
4349 | INIT_STAT(&priv->fw_pend_stat); | ||
4350 | |||
4351 | /* | ||
4352 | * reinitialize lists | ||
4353 | */ | ||
4354 | INIT_LIST_HEAD(&priv->tx_pend_list); | ||
4355 | INIT_LIST_HEAD(&priv->tx_free_list); | ||
4356 | INIT_STAT(&priv->tx_pend_stat); | ||
4357 | INIT_STAT(&priv->tx_free_stat); | ||
4358 | |||
4359 | for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { | ||
4360 | /* We simply drop any SKBs that have been queued for | ||
4361 | * transmit */ | ||
4362 | if (priv->tx_buffers[i].info.d_struct.txb) { | ||
4363 | ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); | ||
4364 | priv->tx_buffers[i].info.d_struct.txb = NULL; | ||
4365 | } | ||
4366 | |||
4367 | list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list); | ||
4368 | } | ||
4369 | |||
4370 | SET_STAT(&priv->tx_free_stat, i); | ||
4371 | |||
4372 | priv->tx_queue.oldest = 0; | ||
4373 | priv->tx_queue.available = priv->tx_queue.entries; | ||
4374 | priv->tx_queue.next = 0; | ||
4375 | INIT_STAT(&priv->txq_stat); | ||
4376 | SET_STAT(&priv->txq_stat, priv->tx_queue.available); | ||
4377 | |||
4378 | bd_queue_initialize(priv, &priv->tx_queue, | ||
4379 | IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE, | ||
4380 | IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE, | ||
4381 | IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, | ||
4382 | IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX); | ||
4383 | |||
4384 | IPW_DEBUG_INFO("exit\n"); | ||
4385 | |||
4386 | } | ||
4387 | |||
4388 | static void ipw2100_tx_free(struct ipw2100_priv *priv) | ||
4389 | { | ||
4390 | int i; | ||
4391 | |||
4392 | IPW_DEBUG_INFO("enter\n"); | ||
4393 | |||
4394 | bd_queue_free(priv, &priv->tx_queue); | ||
4395 | |||
4396 | if (!priv->tx_buffers) | ||
4397 | return; | ||
4398 | |||
4399 | for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { | ||
4400 | if (priv->tx_buffers[i].info.d_struct.txb) { | ||
4401 | ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); | ||
4402 | priv->tx_buffers[i].info.d_struct.txb = NULL; | ||
4403 | } | ||
4404 | if (priv->tx_buffers[i].info.d_struct.data) | ||
4405 | pci_free_consistent( | ||
4406 | priv->pci_dev, | ||
4407 | sizeof(struct ipw2100_data_header), | ||
4408 | priv->tx_buffers[i].info.d_struct.data, | ||
4409 | priv->tx_buffers[i].info.d_struct.data_phys); | ||
4410 | } | ||
4411 | |||
4412 | kfree(priv->tx_buffers); | ||
4413 | priv->tx_buffers = NULL; | ||
4414 | |||
4415 | IPW_DEBUG_INFO("exit\n"); | ||
4416 | } | ||
4417 | |||
4418 | |||
4419 | |||
4420 | static int ipw2100_rx_allocate(struct ipw2100_priv *priv) | ||
4421 | { | ||
4422 | int i, j, err = -EINVAL; | ||
4423 | |||
4424 | IPW_DEBUG_INFO("enter\n"); | ||
4425 | |||
4426 | err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH); | ||
4427 | if (err) { | ||
4428 | IPW_DEBUG_INFO("failed bd_queue_allocate\n"); | ||
4429 | return err; | ||
4430 | } | ||
4431 | |||
4432 | err = status_queue_allocate(priv, RX_QUEUE_LENGTH); | ||
4433 | if (err) { | ||
4434 | IPW_DEBUG_INFO("failed status_queue_allocate\n"); | ||
4435 | bd_queue_free(priv, &priv->rx_queue); | ||
4436 | return err; | ||
4437 | } | ||
4438 | |||
4439 | /* | ||
4440 | * allocate packets | ||
4441 | */ | ||
4442 | priv->rx_buffers = (struct ipw2100_rx_packet *) | ||
4443 | kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet), | ||
4444 | GFP_KERNEL); | ||
4445 | if (!priv->rx_buffers) { | ||
4446 | IPW_DEBUG_INFO("can't allocate rx packet buffer table\n"); | ||
4447 | |||
4448 | bd_queue_free(priv, &priv->rx_queue); | ||
4449 | |||
4450 | status_queue_free(priv); | ||
4451 | |||
4452 | return -ENOMEM; | ||
4453 | } | ||
4454 | |||
4455 | for (i = 0; i < RX_QUEUE_LENGTH; i++) { | ||
4456 | struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; | ||
4457 | |||
4458 | err = ipw2100_alloc_skb(priv, packet); | ||
4459 | if (unlikely(err)) { | ||
4460 | err = -ENOMEM; | ||
4461 | break; | ||
4462 | } | ||
4463 | |||
4464 | /* The BD holds the cache aligned address */ | ||
4465 | priv->rx_queue.drv[i].host_addr = packet->dma_addr; | ||
4466 | priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH; | ||
4467 | priv->status_queue.drv[i].status_fields = 0; | ||
4468 | } | ||
4469 | |||
4470 | if (i == RX_QUEUE_LENGTH) | ||
4471 | return 0; | ||
4472 | |||
4473 | for (j = 0; j < i; j++) { | ||
4474 | pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr, | ||
4475 | sizeof(struct ipw2100_rx_packet), | ||
4476 | PCI_DMA_FROMDEVICE); | ||
4477 | dev_kfree_skb(priv->rx_buffers[j].skb); | ||
4478 | } | ||
4479 | |||
4480 | kfree(priv->rx_buffers); | ||
4481 | priv->rx_buffers = NULL; | ||
4482 | |||
4483 | bd_queue_free(priv, &priv->rx_queue); | ||
4484 | |||
4485 | status_queue_free(priv); | ||
4486 | |||
4487 | return err; | ||
4488 | } | ||
4489 | |||
4490 | static void ipw2100_rx_initialize(struct ipw2100_priv *priv) | ||
4491 | { | ||
4492 | IPW_DEBUG_INFO("enter\n"); | ||
4493 | |||
4494 | priv->rx_queue.oldest = 0; | ||
4495 | priv->rx_queue.available = priv->rx_queue.entries - 1; | ||
4496 | priv->rx_queue.next = priv->rx_queue.entries - 1; | ||
4497 | |||
4498 | INIT_STAT(&priv->rxq_stat); | ||
4499 | SET_STAT(&priv->rxq_stat, priv->rx_queue.available); | ||
4500 | |||
4501 | bd_queue_initialize(priv, &priv->rx_queue, | ||
4502 | IPW_MEM_HOST_SHARED_RX_BD_BASE, | ||
4503 | IPW_MEM_HOST_SHARED_RX_BD_SIZE, | ||
4504 | IPW_MEM_HOST_SHARED_RX_READ_INDEX, | ||
4505 | IPW_MEM_HOST_SHARED_RX_WRITE_INDEX); | ||
4506 | |||
4507 | /* set up the status queue */ | ||
4508 | write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE, | ||
4509 | priv->status_queue.nic); | ||
4510 | |||
4511 | IPW_DEBUG_INFO("exit\n"); | ||
4512 | } | ||
4513 | |||
4514 | static void ipw2100_rx_free(struct ipw2100_priv *priv) | ||
4515 | { | ||
4516 | int i; | ||
4517 | |||
4518 | IPW_DEBUG_INFO("enter\n"); | ||
4519 | |||
4520 | bd_queue_free(priv, &priv->rx_queue); | ||
4521 | status_queue_free(priv); | ||
4522 | |||
4523 | if (!priv->rx_buffers) | ||
4524 | return; | ||
4525 | |||
4526 | for (i = 0; i < RX_QUEUE_LENGTH; i++) { | ||
4527 | if (priv->rx_buffers[i].rxp) { | ||
4528 | pci_unmap_single(priv->pci_dev, | ||
4529 | priv->rx_buffers[i].dma_addr, | ||
4530 | sizeof(struct ipw2100_rx), | ||
4531 | PCI_DMA_FROMDEVICE); | ||
4532 | dev_kfree_skb(priv->rx_buffers[i].skb); | ||
4533 | } | ||
4534 | } | ||
4535 | |||
4536 | kfree(priv->rx_buffers); | ||
4537 | priv->rx_buffers = NULL; | ||
4538 | |||
4539 | IPW_DEBUG_INFO("exit\n"); | ||
4540 | } | ||
4541 | |||
4542 | static int ipw2100_read_mac_address(struct ipw2100_priv *priv) | ||
4543 | { | ||
4544 | u32 length = ETH_ALEN; | ||
4545 | u8 mac[ETH_ALEN]; | ||
4546 | |||
4547 | int err; | ||
4548 | |||
4549 | err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, | ||
4550 | mac, &length); | ||
4551 | if (err) { | ||
4552 | IPW_DEBUG_INFO("MAC address read failed\n"); | ||
4553 | return -EIO; | ||
4554 | } | ||
4555 | IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
4556 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
4557 | |||
4558 | memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN); | ||
4559 | |||
4560 | return 0; | ||
4561 | } | ||
4562 | |||
4563 | /******************************************************************** | ||
4564 | * | ||
4565 | * Firmware Commands | ||
4566 | * | ||
4567 | ********************************************************************/ | ||
4568 | |||
4569 | static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode) | ||
4570 | { | ||
4571 | struct host_command cmd = { | ||
4572 | .host_command = ADAPTER_ADDRESS, | ||
4573 | .host_command_sequence = 0, | ||
4574 | .host_command_length = ETH_ALEN | ||
4575 | }; | ||
4576 | int err; | ||
4577 | |||
4578 | IPW_DEBUG_HC("SET_MAC_ADDRESS\n"); | ||
4579 | |||
4580 | IPW_DEBUG_INFO("enter\n"); | ||
4581 | |||
4582 | if (priv->config & CFG_CUSTOM_MAC) { | ||
4583 | memcpy(cmd.host_command_parameters, priv->mac_addr, | ||
4584 | ETH_ALEN); | ||
4585 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); | ||
4586 | } else | ||
4587 | memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr, | ||
4588 | ETH_ALEN); | ||
4589 | |||
4590 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4591 | |||
4592 | IPW_DEBUG_INFO("exit\n"); | ||
4593 | return err; | ||
4594 | } | ||
4595 | |||
4596 | static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type, | ||
4597 | int batch_mode) | ||
4598 | { | ||
4599 | struct host_command cmd = { | ||
4600 | .host_command = PORT_TYPE, | ||
4601 | .host_command_sequence = 0, | ||
4602 | .host_command_length = sizeof(u32) | ||
4603 | }; | ||
4604 | int err; | ||
4605 | |||
4606 | switch (port_type) { | ||
4607 | case IW_MODE_INFRA: | ||
4608 | cmd.host_command_parameters[0] = IPW_BSS; | ||
4609 | break; | ||
4610 | case IW_MODE_ADHOC: | ||
4611 | cmd.host_command_parameters[0] = IPW_IBSS; | ||
4612 | break; | ||
4613 | } | ||
4614 | |||
4615 | IPW_DEBUG_HC("PORT_TYPE: %s\n", | ||
4616 | port_type == IPW_IBSS ? "Ad-Hoc" : "Managed"); | ||
4617 | |||
4618 | if (!batch_mode) { | ||
4619 | err = ipw2100_disable_adapter(priv); | ||
4620 | if (err) { | ||
4621 | printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", | ||
4622 | priv->net_dev->name, err); | ||
4623 | return err; | ||
4624 | } | ||
4625 | } | ||
4626 | |||
4627 | /* send cmd to firmware */ | ||
4628 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4629 | |||
4630 | if (!batch_mode) | ||
4631 | ipw2100_enable_adapter(priv); | ||
4632 | |||
4633 | return err; | ||
4634 | } | ||
4635 | |||
4636 | |||
4637 | static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel, | ||
4638 | int batch_mode) | ||
4639 | { | ||
4640 | struct host_command cmd = { | ||
4641 | .host_command = CHANNEL, | ||
4642 | .host_command_sequence = 0, | ||
4643 | .host_command_length = sizeof(u32) | ||
4644 | }; | ||
4645 | int err; | ||
4646 | |||
4647 | cmd.host_command_parameters[0] = channel; | ||
4648 | |||
4649 | IPW_DEBUG_HC("CHANNEL: %d\n", channel); | ||
4650 | |||
4651 | /* If BSS then we don't support channel selection */ | ||
4652 | if (priv->ieee->iw_mode == IW_MODE_INFRA) | ||
4653 | return 0; | ||
4654 | |||
4655 | if ((channel != 0) && | ||
4656 | ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL))) | ||
4657 | return -EINVAL; | ||
4658 | |||
4659 | if (!batch_mode) { | ||
4660 | err = ipw2100_disable_adapter(priv); | ||
4661 | if (err) | ||
4662 | return err; | ||
4663 | } | ||
4664 | |||
4665 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4666 | if (err) { | ||
4667 | IPW_DEBUG_INFO("Failed to set channel to %d", | ||
4668 | channel); | ||
4669 | return err; | ||
4670 | } | ||
4671 | |||
4672 | if (channel) | ||
4673 | priv->config |= CFG_STATIC_CHANNEL; | ||
4674 | else | ||
4675 | priv->config &= ~CFG_STATIC_CHANNEL; | ||
4676 | |||
4677 | priv->channel = channel; | ||
4678 | |||
4679 | if (!batch_mode) { | ||
4680 | err = ipw2100_enable_adapter(priv); | ||
4681 | if (err) | ||
4682 | return err; | ||
4683 | } | ||
4684 | |||
4685 | return 0; | ||
4686 | } | ||
4687 | |||
4688 | static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode) | ||
4689 | { | ||
4690 | struct host_command cmd = { | ||
4691 | .host_command = SYSTEM_CONFIG, | ||
4692 | .host_command_sequence = 0, | ||
4693 | .host_command_length = 12, | ||
4694 | }; | ||
4695 | u32 ibss_mask, len = sizeof(u32); | ||
4696 | int err; | ||
4697 | |||
4698 | /* Set system configuration */ | ||
4699 | |||
4700 | if (!batch_mode) { | ||
4701 | err = ipw2100_disable_adapter(priv); | ||
4702 | if (err) | ||
4703 | return err; | ||
4704 | } | ||
4705 | |||
4706 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | ||
4707 | cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START; | ||
4708 | |||
4709 | cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK | | ||
4710 | IPW_CFG_BSS_MASK | | ||
4711 | IPW_CFG_802_1x_ENABLE; | ||
4712 | |||
4713 | if (!(priv->config & CFG_LONG_PREAMBLE)) | ||
4714 | cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO; | ||
4715 | |||
4716 | err = ipw2100_get_ordinal(priv, | ||
4717 | IPW_ORD_EEPROM_IBSS_11B_CHANNELS, | ||
4718 | &ibss_mask, &len); | ||
4719 | if (err) | ||
4720 | ibss_mask = IPW_IBSS_11B_DEFAULT_MASK; | ||
4721 | |||
4722 | cmd.host_command_parameters[1] = REG_CHANNEL_MASK; | ||
4723 | cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask; | ||
4724 | |||
4725 | /* 11b only */ | ||
4726 | /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/ | ||
4727 | |||
4728 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4729 | if (err) | ||
4730 | return err; | ||
4731 | |||
4732 | /* If IPv6 is configured in the kernel then we don't want to filter out all | ||
4733 | * of the multicast packets as IPv6 needs some. */ | ||
4734 | #if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) | ||
4735 | cmd.host_command = ADD_MULTICAST; | ||
4736 | cmd.host_command_sequence = 0; | ||
4737 | cmd.host_command_length = 0; | ||
4738 | |||
4739 | ipw2100_hw_send_command(priv, &cmd); | ||
4740 | #endif | ||
4741 | if (!batch_mode) { | ||
4742 | err = ipw2100_enable_adapter(priv); | ||
4743 | if (err) | ||
4744 | return err; | ||
4745 | } | ||
4746 | |||
4747 | return 0; | ||
4748 | } | ||
4749 | |||
4750 | static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate, | ||
4751 | int batch_mode) | ||
4752 | { | ||
4753 | struct host_command cmd = { | ||
4754 | .host_command = BASIC_TX_RATES, | ||
4755 | .host_command_sequence = 0, | ||
4756 | .host_command_length = 4 | ||
4757 | }; | ||
4758 | int err; | ||
4759 | |||
4760 | cmd.host_command_parameters[0] = rate & TX_RATE_MASK; | ||
4761 | |||
4762 | if (!batch_mode) { | ||
4763 | err = ipw2100_disable_adapter(priv); | ||
4764 | if (err) | ||
4765 | return err; | ||
4766 | } | ||
4767 | |||
4768 | /* Set BASIC TX Rate first */ | ||
4769 | ipw2100_hw_send_command(priv, &cmd); | ||
4770 | |||
4771 | /* Set TX Rate */ | ||
4772 | cmd.host_command = TX_RATES; | ||
4773 | ipw2100_hw_send_command(priv, &cmd); | ||
4774 | |||
4775 | /* Set MSDU TX Rate */ | ||
4776 | cmd.host_command = MSDU_TX_RATES; | ||
4777 | ipw2100_hw_send_command(priv, &cmd); | ||
4778 | |||
4779 | if (!batch_mode) { | ||
4780 | err = ipw2100_enable_adapter(priv); | ||
4781 | if (err) | ||
4782 | return err; | ||
4783 | } | ||
4784 | |||
4785 | priv->tx_rates = rate; | ||
4786 | |||
4787 | return 0; | ||
4788 | } | ||
4789 | |||
4790 | static int ipw2100_set_power_mode(struct ipw2100_priv *priv, | ||
4791 | int power_level) | ||
4792 | { | ||
4793 | struct host_command cmd = { | ||
4794 | .host_command = POWER_MODE, | ||
4795 | .host_command_sequence = 0, | ||
4796 | .host_command_length = 4 | ||
4797 | }; | ||
4798 | int err; | ||
4799 | |||
4800 | cmd.host_command_parameters[0] = power_level; | ||
4801 | |||
4802 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4803 | if (err) | ||
4804 | return err; | ||
4805 | |||
4806 | if (power_level == IPW_POWER_MODE_CAM) | ||
4807 | priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); | ||
4808 | else | ||
4809 | priv->power_mode = IPW_POWER_ENABLED | power_level; | ||
4810 | |||
4811 | #ifdef CONFIG_IPW2100_TX_POWER | ||
4812 | if (priv->port_type == IBSS && | ||
4813 | priv->adhoc_power != DFTL_IBSS_TX_POWER) { | ||
4814 | /* Set beacon interval */ | ||
4815 | cmd.host_command = TX_POWER_INDEX; | ||
4816 | cmd.host_command_parameters[0] = (u32)priv->adhoc_power; | ||
4817 | |||
4818 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4819 | if (err) | ||
4820 | return err; | ||
4821 | } | ||
4822 | #endif | ||
4823 | |||
4824 | return 0; | ||
4825 | } | ||
4826 | |||
4827 | |||
4828 | static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold) | ||
4829 | { | ||
4830 | struct host_command cmd = { | ||
4831 | .host_command = RTS_THRESHOLD, | ||
4832 | .host_command_sequence = 0, | ||
4833 | .host_command_length = 4 | ||
4834 | }; | ||
4835 | int err; | ||
4836 | |||
4837 | if (threshold & RTS_DISABLED) | ||
4838 | cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD; | ||
4839 | else | ||
4840 | cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED; | ||
4841 | |||
4842 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4843 | if (err) | ||
4844 | return err; | ||
4845 | |||
4846 | priv->rts_threshold = threshold; | ||
4847 | |||
4848 | return 0; | ||
4849 | } | ||
4850 | |||
4851 | #if 0 | ||
4852 | int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv, | ||
4853 | u32 threshold, int batch_mode) | ||
4854 | { | ||
4855 | struct host_command cmd = { | ||
4856 | .host_command = FRAG_THRESHOLD, | ||
4857 | .host_command_sequence = 0, | ||
4858 | .host_command_length = 4, | ||
4859 | .host_command_parameters[0] = 0, | ||
4860 | }; | ||
4861 | int err; | ||
4862 | |||
4863 | if (!batch_mode) { | ||
4864 | err = ipw2100_disable_adapter(priv); | ||
4865 | if (err) | ||
4866 | return err; | ||
4867 | } | ||
4868 | |||
4869 | if (threshold == 0) | ||
4870 | threshold = DEFAULT_FRAG_THRESHOLD; | ||
4871 | else { | ||
4872 | threshold = max(threshold, MIN_FRAG_THRESHOLD); | ||
4873 | threshold = min(threshold, MAX_FRAG_THRESHOLD); | ||
4874 | } | ||
4875 | |||
4876 | cmd.host_command_parameters[0] = threshold; | ||
4877 | |||
4878 | IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold); | ||
4879 | |||
4880 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4881 | |||
4882 | if (!batch_mode) | ||
4883 | ipw2100_enable_adapter(priv); | ||
4884 | |||
4885 | if (!err) | ||
4886 | priv->frag_threshold = threshold; | ||
4887 | |||
4888 | return err; | ||
4889 | } | ||
4890 | #endif | ||
4891 | |||
4892 | static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry) | ||
4893 | { | ||
4894 | struct host_command cmd = { | ||
4895 | .host_command = SHORT_RETRY_LIMIT, | ||
4896 | .host_command_sequence = 0, | ||
4897 | .host_command_length = 4 | ||
4898 | }; | ||
4899 | int err; | ||
4900 | |||
4901 | cmd.host_command_parameters[0] = retry; | ||
4902 | |||
4903 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4904 | if (err) | ||
4905 | return err; | ||
4906 | |||
4907 | priv->short_retry_limit = retry; | ||
4908 | |||
4909 | return 0; | ||
4910 | } | ||
4911 | |||
4912 | static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry) | ||
4913 | { | ||
4914 | struct host_command cmd = { | ||
4915 | .host_command = LONG_RETRY_LIMIT, | ||
4916 | .host_command_sequence = 0, | ||
4917 | .host_command_length = 4 | ||
4918 | }; | ||
4919 | int err; | ||
4920 | |||
4921 | cmd.host_command_parameters[0] = retry; | ||
4922 | |||
4923 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4924 | if (err) | ||
4925 | return err; | ||
4926 | |||
4927 | priv->long_retry_limit = retry; | ||
4928 | |||
4929 | return 0; | ||
4930 | } | ||
4931 | |||
4932 | |||
4933 | static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid, | ||
4934 | int batch_mode) | ||
4935 | { | ||
4936 | struct host_command cmd = { | ||
4937 | .host_command = MANDATORY_BSSID, | ||
4938 | .host_command_sequence = 0, | ||
4939 | .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN | ||
4940 | }; | ||
4941 | int err; | ||
4942 | |||
4943 | #ifdef CONFIG_IPW_DEBUG | ||
4944 | if (bssid != NULL) | ||
4945 | IPW_DEBUG_HC( | ||
4946 | "MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
4947 | bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], | ||
4948 | bssid[5]); | ||
4949 | else | ||
4950 | IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n"); | ||
4951 | #endif | ||
4952 | /* if BSSID is empty then we disable mandatory bssid mode */ | ||
4953 | if (bssid != NULL) | ||
4954 | memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN); | ||
4955 | |||
4956 | if (!batch_mode) { | ||
4957 | err = ipw2100_disable_adapter(priv); | ||
4958 | if (err) | ||
4959 | return err; | ||
4960 | } | ||
4961 | |||
4962 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4963 | |||
4964 | if (!batch_mode) | ||
4965 | ipw2100_enable_adapter(priv); | ||
4966 | |||
4967 | return err; | ||
4968 | } | ||
4969 | |||
4970 | #ifdef CONFIG_IEEE80211_WPA | ||
4971 | static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv) | ||
4972 | { | ||
4973 | struct host_command cmd = { | ||
4974 | .host_command = DISASSOCIATION_BSSID, | ||
4975 | .host_command_sequence = 0, | ||
4976 | .host_command_length = ETH_ALEN | ||
4977 | }; | ||
4978 | int err; | ||
4979 | int len; | ||
4980 | |||
4981 | IPW_DEBUG_HC("DISASSOCIATION_BSSID\n"); | ||
4982 | |||
4983 | len = ETH_ALEN; | ||
4984 | /* The Firmware currently ignores the BSSID and just disassociates from | ||
4985 | * the currently associated AP -- but in the off chance that a future | ||
4986 | * firmware does use the BSSID provided here, we go ahead and try and | ||
4987 | * set it to the currently associated AP's BSSID */ | ||
4988 | memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN); | ||
4989 | |||
4990 | err = ipw2100_hw_send_command(priv, &cmd); | ||
4991 | |||
4992 | return err; | ||
4993 | } | ||
4994 | #endif | ||
4995 | |||
4996 | /* | ||
4997 | * Pseudo code for setting up wpa_frame: | ||
4998 | */ | ||
4999 | #if 0 | ||
5000 | void x(struct ieee80211_assoc_frame *wpa_assoc) | ||
5001 | { | ||
5002 | struct ipw2100_wpa_assoc_frame frame; | ||
5003 | frame->fixed_ie_mask = IPW_WPA_CAPABILTIES | | ||
5004 | IPW_WPA_LISTENINTERVAL | | ||
5005 | IPW_WPA_AP_ADDRESS; | ||
5006 | frame->capab_info = wpa_assoc->capab_info; | ||
5007 | frame->lisen_interval = wpa_assoc->listent_interval; | ||
5008 | memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN); | ||
5009 | |||
5010 | /* UNKNOWN -- I'm not postivive about this part; don't have any WPA | ||
5011 | * setup here to test it with. | ||
5012 | * | ||
5013 | * Walk the IEs in the wpa_assoc and figure out the total size of all | ||
5014 | * that data. Stick that into frame->var_ie_len. Then memcpy() all of | ||
5015 | * the IEs from wpa_frame into frame. | ||
5016 | */ | ||
5017 | frame->var_ie_len = calculate_ie_len(wpa_assoc); | ||
5018 | memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len); | ||
5019 | |||
5020 | ipw2100_set_wpa_ie(priv, &frame, 0); | ||
5021 | } | ||
5022 | #endif | ||
5023 | |||
5024 | |||
5025 | |||
5026 | |||
5027 | static int ipw2100_set_wpa_ie(struct ipw2100_priv *, | ||
5028 | struct ipw2100_wpa_assoc_frame *, int) | ||
5029 | __attribute__ ((unused)); | ||
5030 | |||
5031 | static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv, | ||
5032 | struct ipw2100_wpa_assoc_frame *wpa_frame, | ||
5033 | int batch_mode) | ||
5034 | { | ||
5035 | struct host_command cmd = { | ||
5036 | .host_command = SET_WPA_IE, | ||
5037 | .host_command_sequence = 0, | ||
5038 | .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame), | ||
5039 | }; | ||
5040 | int err; | ||
5041 | |||
5042 | IPW_DEBUG_HC("SET_WPA_IE\n"); | ||
5043 | |||
5044 | if (!batch_mode) { | ||
5045 | err = ipw2100_disable_adapter(priv); | ||
5046 | if (err) | ||
5047 | return err; | ||
5048 | } | ||
5049 | |||
5050 | memcpy(cmd.host_command_parameters, wpa_frame, | ||
5051 | sizeof(struct ipw2100_wpa_assoc_frame)); | ||
5052 | |||
5053 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5054 | |||
5055 | if (!batch_mode) { | ||
5056 | if (ipw2100_enable_adapter(priv)) | ||
5057 | err = -EIO; | ||
5058 | } | ||
5059 | |||
5060 | return err; | ||
5061 | } | ||
5062 | |||
5063 | struct security_info_params { | ||
5064 | u32 allowed_ciphers; | ||
5065 | u16 version; | ||
5066 | u8 auth_mode; | ||
5067 | u8 replay_counters_number; | ||
5068 | u8 unicast_using_group; | ||
5069 | } __attribute__ ((packed)); | ||
5070 | |||
5071 | static int ipw2100_set_security_information(struct ipw2100_priv *priv, | ||
5072 | int auth_mode, | ||
5073 | int security_level, | ||
5074 | int unicast_using_group, | ||
5075 | int batch_mode) | ||
5076 | { | ||
5077 | struct host_command cmd = { | ||
5078 | .host_command = SET_SECURITY_INFORMATION, | ||
5079 | .host_command_sequence = 0, | ||
5080 | .host_command_length = sizeof(struct security_info_params) | ||
5081 | }; | ||
5082 | struct security_info_params *security = | ||
5083 | (struct security_info_params *)&cmd.host_command_parameters; | ||
5084 | int err; | ||
5085 | memset(security, 0, sizeof(*security)); | ||
5086 | |||
5087 | /* If shared key AP authentication is turned on, then we need to | ||
5088 | * configure the firmware to try and use it. | ||
5089 | * | ||
5090 | * Actual data encryption/decryption is handled by the host. */ | ||
5091 | security->auth_mode = auth_mode; | ||
5092 | security->unicast_using_group = unicast_using_group; | ||
5093 | |||
5094 | switch (security_level) { | ||
5095 | default: | ||
5096 | case SEC_LEVEL_0: | ||
5097 | security->allowed_ciphers = IPW_NONE_CIPHER; | ||
5098 | break; | ||
5099 | case SEC_LEVEL_1: | ||
5100 | security->allowed_ciphers = IPW_WEP40_CIPHER | | ||
5101 | IPW_WEP104_CIPHER; | ||
5102 | break; | ||
5103 | case SEC_LEVEL_2: | ||
5104 | security->allowed_ciphers = IPW_WEP40_CIPHER | | ||
5105 | IPW_WEP104_CIPHER | IPW_TKIP_CIPHER; | ||
5106 | break; | ||
5107 | case SEC_LEVEL_2_CKIP: | ||
5108 | security->allowed_ciphers = IPW_WEP40_CIPHER | | ||
5109 | IPW_WEP104_CIPHER | IPW_CKIP_CIPHER; | ||
5110 | break; | ||
5111 | case SEC_LEVEL_3: | ||
5112 | security->allowed_ciphers = IPW_WEP40_CIPHER | | ||
5113 | IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER; | ||
5114 | break; | ||
5115 | } | ||
5116 | |||
5117 | IPW_DEBUG_HC( | ||
5118 | "SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n", | ||
5119 | security->auth_mode, security->allowed_ciphers, security_level); | ||
5120 | |||
5121 | security->replay_counters_number = 0; | ||
5122 | |||
5123 | if (!batch_mode) { | ||
5124 | err = ipw2100_disable_adapter(priv); | ||
5125 | if (err) | ||
5126 | return err; | ||
5127 | } | ||
5128 | |||
5129 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5130 | |||
5131 | if (!batch_mode) | ||
5132 | ipw2100_enable_adapter(priv); | ||
5133 | |||
5134 | return err; | ||
5135 | } | ||
5136 | |||
5137 | static int ipw2100_set_tx_power(struct ipw2100_priv *priv, | ||
5138 | u32 tx_power) | ||
5139 | { | ||
5140 | struct host_command cmd = { | ||
5141 | .host_command = TX_POWER_INDEX, | ||
5142 | .host_command_sequence = 0, | ||
5143 | .host_command_length = 4 | ||
5144 | }; | ||
5145 | int err = 0; | ||
5146 | |||
5147 | cmd.host_command_parameters[0] = tx_power; | ||
5148 | |||
5149 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | ||
5150 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5151 | if (!err) | ||
5152 | priv->tx_power = tx_power; | ||
5153 | |||
5154 | return 0; | ||
5155 | } | ||
5156 | |||
5157 | static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, | ||
5158 | u32 interval, int batch_mode) | ||
5159 | { | ||
5160 | struct host_command cmd = { | ||
5161 | .host_command = BEACON_INTERVAL, | ||
5162 | .host_command_sequence = 0, | ||
5163 | .host_command_length = 4 | ||
5164 | }; | ||
5165 | int err; | ||
5166 | |||
5167 | cmd.host_command_parameters[0] = interval; | ||
5168 | |||
5169 | IPW_DEBUG_INFO("enter\n"); | ||
5170 | |||
5171 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
5172 | if (!batch_mode) { | ||
5173 | err = ipw2100_disable_adapter(priv); | ||
5174 | if (err) | ||
5175 | return err; | ||
5176 | } | ||
5177 | |||
5178 | ipw2100_hw_send_command(priv, &cmd); | ||
5179 | |||
5180 | if (!batch_mode) { | ||
5181 | err = ipw2100_enable_adapter(priv); | ||
5182 | if (err) | ||
5183 | return err; | ||
5184 | } | ||
5185 | } | ||
5186 | |||
5187 | IPW_DEBUG_INFO("exit\n"); | ||
5188 | |||
5189 | return 0; | ||
5190 | } | ||
5191 | |||
5192 | |||
5193 | void ipw2100_queues_initialize(struct ipw2100_priv *priv) | ||
5194 | { | ||
5195 | ipw2100_tx_initialize(priv); | ||
5196 | ipw2100_rx_initialize(priv); | ||
5197 | ipw2100_msg_initialize(priv); | ||
5198 | } | ||
5199 | |||
5200 | void ipw2100_queues_free(struct ipw2100_priv *priv) | ||
5201 | { | ||
5202 | ipw2100_tx_free(priv); | ||
5203 | ipw2100_rx_free(priv); | ||
5204 | ipw2100_msg_free(priv); | ||
5205 | } | ||
5206 | |||
5207 | int ipw2100_queues_allocate(struct ipw2100_priv *priv) | ||
5208 | { | ||
5209 | if (ipw2100_tx_allocate(priv) || | ||
5210 | ipw2100_rx_allocate(priv) || | ||
5211 | ipw2100_msg_allocate(priv)) | ||
5212 | goto fail; | ||
5213 | |||
5214 | return 0; | ||
5215 | |||
5216 | fail: | ||
5217 | ipw2100_tx_free(priv); | ||
5218 | ipw2100_rx_free(priv); | ||
5219 | ipw2100_msg_free(priv); | ||
5220 | return -ENOMEM; | ||
5221 | } | ||
5222 | |||
5223 | #define IPW_PRIVACY_CAPABLE 0x0008 | ||
5224 | |||
5225 | static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags, | ||
5226 | int batch_mode) | ||
5227 | { | ||
5228 | struct host_command cmd = { | ||
5229 | .host_command = WEP_FLAGS, | ||
5230 | .host_command_sequence = 0, | ||
5231 | .host_command_length = 4 | ||
5232 | }; | ||
5233 | int err; | ||
5234 | |||
5235 | cmd.host_command_parameters[0] = flags; | ||
5236 | |||
5237 | IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags); | ||
5238 | |||
5239 | if (!batch_mode) { | ||
5240 | err = ipw2100_disable_adapter(priv); | ||
5241 | if (err) { | ||
5242 | printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", | ||
5243 | priv->net_dev->name, err); | ||
5244 | return err; | ||
5245 | } | ||
5246 | } | ||
5247 | |||
5248 | /* send cmd to firmware */ | ||
5249 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5250 | |||
5251 | if (!batch_mode) | ||
5252 | ipw2100_enable_adapter(priv); | ||
5253 | |||
5254 | return err; | ||
5255 | } | ||
5256 | |||
5257 | struct ipw2100_wep_key { | ||
5258 | u8 idx; | ||
5259 | u8 len; | ||
5260 | u8 key[13]; | ||
5261 | }; | ||
5262 | |||
5263 | /* Macros to ease up priting WEP keys */ | ||
5264 | #define WEP_FMT_64 "%02X%02X%02X%02X-%02X" | ||
5265 | #define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X" | ||
5266 | #define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4] | ||
5267 | #define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10] | ||
5268 | |||
5269 | |||
5270 | /** | ||
5271 | * Set a the wep key | ||
5272 | * | ||
5273 | * @priv: struct to work on | ||
5274 | * @idx: index of the key we want to set | ||
5275 | * @key: ptr to the key data to set | ||
5276 | * @len: length of the buffer at @key | ||
5277 | * @batch_mode: FIXME perform the operation in batch mode, not | ||
5278 | * disabling the device. | ||
5279 | * | ||
5280 | * @returns 0 if OK, < 0 errno code on error. | ||
5281 | * | ||
5282 | * Fill out a command structure with the new wep key, length an | ||
5283 | * index and send it down the wire. | ||
5284 | */ | ||
5285 | static int ipw2100_set_key(struct ipw2100_priv *priv, | ||
5286 | int idx, char *key, int len, int batch_mode) | ||
5287 | { | ||
5288 | int keylen = len ? (len <= 5 ? 5 : 13) : 0; | ||
5289 | struct host_command cmd = { | ||
5290 | .host_command = WEP_KEY_INFO, | ||
5291 | .host_command_sequence = 0, | ||
5292 | .host_command_length = sizeof(struct ipw2100_wep_key), | ||
5293 | }; | ||
5294 | struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters; | ||
5295 | int err; | ||
5296 | |||
5297 | IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n", | ||
5298 | idx, keylen, len); | ||
5299 | |||
5300 | /* NOTE: We don't check cached values in case the firmware was reset | ||
5301 | * or some other problem is occuring. If the user is setting the key, | ||
5302 | * then we push the change */ | ||
5303 | |||
5304 | wep_key->idx = idx; | ||
5305 | wep_key->len = keylen; | ||
5306 | |||
5307 | if (keylen) { | ||
5308 | memcpy(wep_key->key, key, len); | ||
5309 | memset(wep_key->key + len, 0, keylen - len); | ||
5310 | } | ||
5311 | |||
5312 | /* Will be optimized out on debug not being configured in */ | ||
5313 | if (keylen == 0) | ||
5314 | IPW_DEBUG_WEP("%s: Clearing key %d\n", | ||
5315 | priv->net_dev->name, wep_key->idx); | ||
5316 | else if (keylen == 5) | ||
5317 | IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n", | ||
5318 | priv->net_dev->name, wep_key->idx, wep_key->len, | ||
5319 | WEP_STR_64(wep_key->key)); | ||
5320 | else | ||
5321 | IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128 | ||
5322 | "\n", | ||
5323 | priv->net_dev->name, wep_key->idx, wep_key->len, | ||
5324 | WEP_STR_128(wep_key->key)); | ||
5325 | |||
5326 | if (!batch_mode) { | ||
5327 | err = ipw2100_disable_adapter(priv); | ||
5328 | /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */ | ||
5329 | if (err) { | ||
5330 | printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", | ||
5331 | priv->net_dev->name, err); | ||
5332 | return err; | ||
5333 | } | ||
5334 | } | ||
5335 | |||
5336 | /* send cmd to firmware */ | ||
5337 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5338 | |||
5339 | if (!batch_mode) { | ||
5340 | int err2 = ipw2100_enable_adapter(priv); | ||
5341 | if (err == 0) | ||
5342 | err = err2; | ||
5343 | } | ||
5344 | return err; | ||
5345 | } | ||
5346 | |||
5347 | static int ipw2100_set_key_index(struct ipw2100_priv *priv, | ||
5348 | int idx, int batch_mode) | ||
5349 | { | ||
5350 | struct host_command cmd = { | ||
5351 | .host_command = WEP_KEY_INDEX, | ||
5352 | .host_command_sequence = 0, | ||
5353 | .host_command_length = 4, | ||
5354 | .host_command_parameters = { idx }, | ||
5355 | }; | ||
5356 | int err; | ||
5357 | |||
5358 | IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx); | ||
5359 | |||
5360 | if (idx < 0 || idx > 3) | ||
5361 | return -EINVAL; | ||
5362 | |||
5363 | if (!batch_mode) { | ||
5364 | err = ipw2100_disable_adapter(priv); | ||
5365 | if (err) { | ||
5366 | printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", | ||
5367 | priv->net_dev->name, err); | ||
5368 | return err; | ||
5369 | } | ||
5370 | } | ||
5371 | |||
5372 | /* send cmd to firmware */ | ||
5373 | err = ipw2100_hw_send_command(priv, &cmd); | ||
5374 | |||
5375 | if (!batch_mode) | ||
5376 | ipw2100_enable_adapter(priv); | ||
5377 | |||
5378 | return err; | ||
5379 | } | ||
5380 | |||
5381 | |||
5382 | static int ipw2100_configure_security(struct ipw2100_priv *priv, | ||
5383 | int batch_mode) | ||
5384 | { | ||
5385 | int i, err, auth_mode, sec_level, use_group; | ||
5386 | |||
5387 | if (!(priv->status & STATUS_RUNNING)) | ||
5388 | return 0; | ||
5389 | |||
5390 | if (!batch_mode) { | ||
5391 | err = ipw2100_disable_adapter(priv); | ||
5392 | if (err) | ||
5393 | return err; | ||
5394 | } | ||
5395 | |||
5396 | if (!priv->sec.enabled) { | ||
5397 | err = ipw2100_set_security_information( | ||
5398 | priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1); | ||
5399 | } else { | ||
5400 | auth_mode = IPW_AUTH_OPEN; | ||
5401 | if ((priv->sec.flags & SEC_AUTH_MODE) && | ||
5402 | (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) | ||
5403 | auth_mode = IPW_AUTH_SHARED; | ||
5404 | |||
5405 | sec_level = SEC_LEVEL_0; | ||
5406 | if (priv->sec.flags & SEC_LEVEL) | ||
5407 | sec_level = priv->sec.level; | ||
5408 | |||
5409 | use_group = 0; | ||
5410 | if (priv->sec.flags & SEC_UNICAST_GROUP) | ||
5411 | use_group = priv->sec.unicast_uses_group; | ||
5412 | |||
5413 | err = ipw2100_set_security_information( | ||
5414 | priv, auth_mode, sec_level, use_group, 1); | ||
5415 | } | ||
5416 | |||
5417 | if (err) | ||
5418 | goto exit; | ||
5419 | |||
5420 | if (priv->sec.enabled) { | ||
5421 | for (i = 0; i < 4; i++) { | ||
5422 | if (!(priv->sec.flags & (1 << i))) { | ||
5423 | memset(priv->sec.keys[i], 0, WEP_KEY_LEN); | ||
5424 | priv->sec.key_sizes[i] = 0; | ||
5425 | } else { | ||
5426 | err = ipw2100_set_key(priv, i, | ||
5427 | priv->sec.keys[i], | ||
5428 | priv->sec.key_sizes[i], | ||
5429 | 1); | ||
5430 | if (err) | ||
5431 | goto exit; | ||
5432 | } | ||
5433 | } | ||
5434 | |||
5435 | ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1); | ||
5436 | } | ||
5437 | |||
5438 | /* Always enable privacy so the Host can filter WEP packets if | ||
5439 | * encrypted data is sent up */ | ||
5440 | err = ipw2100_set_wep_flags( | ||
5441 | priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1); | ||
5442 | if (err) | ||
5443 | goto exit; | ||
5444 | |||
5445 | priv->status &= ~STATUS_SECURITY_UPDATED; | ||
5446 | |||
5447 | exit: | ||
5448 | if (!batch_mode) | ||
5449 | ipw2100_enable_adapter(priv); | ||
5450 | |||
5451 | return err; | ||
5452 | } | ||
5453 | |||
5454 | static void ipw2100_security_work(struct ipw2100_priv *priv) | ||
5455 | { | ||
5456 | /* If we happen to have reconnected before we get a chance to | ||
5457 | * process this, then update the security settings--which causes | ||
5458 | * a disassociation to occur */ | ||
5459 | if (!(priv->status & STATUS_ASSOCIATED) && | ||
5460 | priv->status & STATUS_SECURITY_UPDATED) | ||
5461 | ipw2100_configure_security(priv, 0); | ||
5462 | } | ||
5463 | |||
5464 | static void shim__set_security(struct net_device *dev, | ||
5465 | struct ieee80211_security *sec) | ||
5466 | { | ||
5467 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5468 | int i, force_update = 0; | ||
5469 | |||
5470 | down(&priv->action_sem); | ||
5471 | if (!(priv->status & STATUS_INITIALIZED)) | ||
5472 | goto done; | ||
5473 | |||
5474 | for (i = 0; i < 4; i++) { | ||
5475 | if (sec->flags & (1 << i)) { | ||
5476 | priv->sec.key_sizes[i] = sec->key_sizes[i]; | ||
5477 | if (sec->key_sizes[i] == 0) | ||
5478 | priv->sec.flags &= ~(1 << i); | ||
5479 | else | ||
5480 | memcpy(priv->sec.keys[i], sec->keys[i], | ||
5481 | sec->key_sizes[i]); | ||
5482 | priv->sec.flags |= (1 << i); | ||
5483 | priv->status |= STATUS_SECURITY_UPDATED; | ||
5484 | } | ||
5485 | } | ||
5486 | |||
5487 | if ((sec->flags & SEC_ACTIVE_KEY) && | ||
5488 | priv->sec.active_key != sec->active_key) { | ||
5489 | if (sec->active_key <= 3) { | ||
5490 | priv->sec.active_key = sec->active_key; | ||
5491 | priv->sec.flags |= SEC_ACTIVE_KEY; | ||
5492 | } else | ||
5493 | priv->sec.flags &= ~SEC_ACTIVE_KEY; | ||
5494 | |||
5495 | priv->status |= STATUS_SECURITY_UPDATED; | ||
5496 | } | ||
5497 | |||
5498 | if ((sec->flags & SEC_AUTH_MODE) && | ||
5499 | (priv->sec.auth_mode != sec->auth_mode)) { | ||
5500 | priv->sec.auth_mode = sec->auth_mode; | ||
5501 | priv->sec.flags |= SEC_AUTH_MODE; | ||
5502 | priv->status |= STATUS_SECURITY_UPDATED; | ||
5503 | } | ||
5504 | |||
5505 | if (sec->flags & SEC_ENABLED && | ||
5506 | priv->sec.enabled != sec->enabled) { | ||
5507 | priv->sec.flags |= SEC_ENABLED; | ||
5508 | priv->sec.enabled = sec->enabled; | ||
5509 | priv->status |= STATUS_SECURITY_UPDATED; | ||
5510 | force_update = 1; | ||
5511 | } | ||
5512 | |||
5513 | if (sec->flags & SEC_LEVEL && | ||
5514 | priv->sec.level != sec->level) { | ||
5515 | priv->sec.level = sec->level; | ||
5516 | priv->sec.flags |= SEC_LEVEL; | ||
5517 | priv->status |= STATUS_SECURITY_UPDATED; | ||
5518 | } | ||
5519 | |||
5520 | IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n", | ||
5521 | priv->sec.flags & (1<<8) ? '1' : '0', | ||
5522 | priv->sec.flags & (1<<7) ? '1' : '0', | ||
5523 | priv->sec.flags & (1<<6) ? '1' : '0', | ||
5524 | priv->sec.flags & (1<<5) ? '1' : '0', | ||
5525 | priv->sec.flags & (1<<4) ? '1' : '0', | ||
5526 | priv->sec.flags & (1<<3) ? '1' : '0', | ||
5527 | priv->sec.flags & (1<<2) ? '1' : '0', | ||
5528 | priv->sec.flags & (1<<1) ? '1' : '0', | ||
5529 | priv->sec.flags & (1<<0) ? '1' : '0'); | ||
5530 | |||
5531 | /* As a temporary work around to enable WPA until we figure out why | ||
5532 | * wpa_supplicant toggles the security capability of the driver, which | ||
5533 | * forces a disassocation with force_update... | ||
5534 | * | ||
5535 | * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/ | ||
5536 | if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) | ||
5537 | ipw2100_configure_security(priv, 0); | ||
5538 | done: | ||
5539 | up(&priv->action_sem); | ||
5540 | } | ||
5541 | |||
5542 | static int ipw2100_adapter_setup(struct ipw2100_priv *priv) | ||
5543 | { | ||
5544 | int err; | ||
5545 | int batch_mode = 1; | ||
5546 | u8 *bssid; | ||
5547 | |||
5548 | IPW_DEBUG_INFO("enter\n"); | ||
5549 | |||
5550 | err = ipw2100_disable_adapter(priv); | ||
5551 | if (err) | ||
5552 | return err; | ||
5553 | #ifdef CONFIG_IPW2100_MONITOR | ||
5554 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | ||
5555 | err = ipw2100_set_channel(priv, priv->channel, batch_mode); | ||
5556 | if (err) | ||
5557 | return err; | ||
5558 | |||
5559 | IPW_DEBUG_INFO("exit\n"); | ||
5560 | |||
5561 | return 0; | ||
5562 | } | ||
5563 | #endif /* CONFIG_IPW2100_MONITOR */ | ||
5564 | |||
5565 | err = ipw2100_read_mac_address(priv); | ||
5566 | if (err) | ||
5567 | return -EIO; | ||
5568 | |||
5569 | err = ipw2100_set_mac_address(priv, batch_mode); | ||
5570 | if (err) | ||
5571 | return err; | ||
5572 | |||
5573 | err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode); | ||
5574 | if (err) | ||
5575 | return err; | ||
5576 | |||
5577 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
5578 | err = ipw2100_set_channel(priv, priv->channel, batch_mode); | ||
5579 | if (err) | ||
5580 | return err; | ||
5581 | } | ||
5582 | |||
5583 | err = ipw2100_system_config(priv, batch_mode); | ||
5584 | if (err) | ||
5585 | return err; | ||
5586 | |||
5587 | err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode); | ||
5588 | if (err) | ||
5589 | return err; | ||
5590 | |||
5591 | /* Default to power mode OFF */ | ||
5592 | err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); | ||
5593 | if (err) | ||
5594 | return err; | ||
5595 | |||
5596 | err = ipw2100_set_rts_threshold(priv, priv->rts_threshold); | ||
5597 | if (err) | ||
5598 | return err; | ||
5599 | |||
5600 | if (priv->config & CFG_STATIC_BSSID) | ||
5601 | bssid = priv->bssid; | ||
5602 | else | ||
5603 | bssid = NULL; | ||
5604 | err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode); | ||
5605 | if (err) | ||
5606 | return err; | ||
5607 | |||
5608 | if (priv->config & CFG_STATIC_ESSID) | ||
5609 | err = ipw2100_set_essid(priv, priv->essid, priv->essid_len, | ||
5610 | batch_mode); | ||
5611 | else | ||
5612 | err = ipw2100_set_essid(priv, NULL, 0, batch_mode); | ||
5613 | if (err) | ||
5614 | return err; | ||
5615 | |||
5616 | err = ipw2100_configure_security(priv, batch_mode); | ||
5617 | if (err) | ||
5618 | return err; | ||
5619 | |||
5620 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
5621 | err = ipw2100_set_ibss_beacon_interval( | ||
5622 | priv, priv->beacon_interval, batch_mode); | ||
5623 | if (err) | ||
5624 | return err; | ||
5625 | |||
5626 | err = ipw2100_set_tx_power(priv, priv->tx_power); | ||
5627 | if (err) | ||
5628 | return err; | ||
5629 | } | ||
5630 | |||
5631 | /* | ||
5632 | err = ipw2100_set_fragmentation_threshold( | ||
5633 | priv, priv->frag_threshold, batch_mode); | ||
5634 | if (err) | ||
5635 | return err; | ||
5636 | */ | ||
5637 | |||
5638 | IPW_DEBUG_INFO("exit\n"); | ||
5639 | |||
5640 | return 0; | ||
5641 | } | ||
5642 | |||
5643 | |||
5644 | /************************************************************************* | ||
5645 | * | ||
5646 | * EXTERNALLY CALLED METHODS | ||
5647 | * | ||
5648 | *************************************************************************/ | ||
5649 | |||
5650 | /* This method is called by the network layer -- not to be confused with | ||
5651 | * ipw2100_set_mac_address() declared above called by this driver (and this | ||
5652 | * method as well) to talk to the firmware */ | ||
5653 | static int ipw2100_set_address(struct net_device *dev, void *p) | ||
5654 | { | ||
5655 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5656 | struct sockaddr *addr = p; | ||
5657 | int err = 0; | ||
5658 | |||
5659 | if (!is_valid_ether_addr(addr->sa_data)) | ||
5660 | return -EADDRNOTAVAIL; | ||
5661 | |||
5662 | down(&priv->action_sem); | ||
5663 | |||
5664 | priv->config |= CFG_CUSTOM_MAC; | ||
5665 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); | ||
5666 | |||
5667 | err = ipw2100_set_mac_address(priv, 0); | ||
5668 | if (err) | ||
5669 | goto done; | ||
5670 | |||
5671 | priv->reset_backoff = 0; | ||
5672 | up(&priv->action_sem); | ||
5673 | ipw2100_reset_adapter(priv); | ||
5674 | return 0; | ||
5675 | |||
5676 | done: | ||
5677 | up(&priv->action_sem); | ||
5678 | return err; | ||
5679 | } | ||
5680 | |||
5681 | static int ipw2100_open(struct net_device *dev) | ||
5682 | { | ||
5683 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5684 | unsigned long flags; | ||
5685 | IPW_DEBUG_INFO("dev->open\n"); | ||
5686 | |||
5687 | spin_lock_irqsave(&priv->low_lock, flags); | ||
5688 | if (priv->status & STATUS_ASSOCIATED) { | ||
5689 | netif_carrier_on(dev); | ||
5690 | netif_start_queue(dev); | ||
5691 | } | ||
5692 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
5693 | |||
5694 | return 0; | ||
5695 | } | ||
5696 | |||
5697 | static int ipw2100_close(struct net_device *dev) | ||
5698 | { | ||
5699 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5700 | unsigned long flags; | ||
5701 | struct list_head *element; | ||
5702 | struct ipw2100_tx_packet *packet; | ||
5703 | |||
5704 | IPW_DEBUG_INFO("enter\n"); | ||
5705 | |||
5706 | spin_lock_irqsave(&priv->low_lock, flags); | ||
5707 | |||
5708 | if (priv->status & STATUS_ASSOCIATED) | ||
5709 | netif_carrier_off(dev); | ||
5710 | netif_stop_queue(dev); | ||
5711 | |||
5712 | /* Flush the TX queue ... */ | ||
5713 | while (!list_empty(&priv->tx_pend_list)) { | ||
5714 | element = priv->tx_pend_list.next; | ||
5715 | packet = list_entry(element, struct ipw2100_tx_packet, list); | ||
5716 | |||
5717 | list_del(element); | ||
5718 | DEC_STAT(&priv->tx_pend_stat); | ||
5719 | |||
5720 | ieee80211_txb_free(packet->info.d_struct.txb); | ||
5721 | packet->info.d_struct.txb = NULL; | ||
5722 | |||
5723 | list_add_tail(element, &priv->tx_free_list); | ||
5724 | INC_STAT(&priv->tx_free_stat); | ||
5725 | } | ||
5726 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
5727 | |||
5728 | IPW_DEBUG_INFO("exit\n"); | ||
5729 | |||
5730 | return 0; | ||
5731 | } | ||
5732 | |||
5733 | |||
5734 | |||
5735 | /* | ||
5736 | * TODO: Fix this function... its just wrong | ||
5737 | */ | ||
5738 | static void ipw2100_tx_timeout(struct net_device *dev) | ||
5739 | { | ||
5740 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5741 | |||
5742 | priv->ieee->stats.tx_errors++; | ||
5743 | |||
5744 | #ifdef CONFIG_IPW2100_MONITOR | ||
5745 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | ||
5746 | return; | ||
5747 | #endif | ||
5748 | |||
5749 | IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n", | ||
5750 | dev->name); | ||
5751 | schedule_reset(priv); | ||
5752 | } | ||
5753 | |||
5754 | |||
5755 | /* | ||
5756 | * TODO: reimplement it so that it reads statistics | ||
5757 | * from the adapter using ordinal tables | ||
5758 | * instead of/in addition to collecting them | ||
5759 | * in the driver | ||
5760 | */ | ||
5761 | static struct net_device_stats *ipw2100_stats(struct net_device *dev) | ||
5762 | { | ||
5763 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5764 | |||
5765 | return &priv->ieee->stats; | ||
5766 | } | ||
5767 | |||
5768 | /* Support for wpa_supplicant. Will be replaced with WEXT once | ||
5769 | * they get WPA support. */ | ||
5770 | #ifdef CONFIG_IEEE80211_WPA | ||
5771 | |||
5772 | /* following definitions must match definitions in driver_ipw2100.c */ | ||
5773 | |||
5774 | #define IPW2100_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 | ||
5775 | |||
5776 | #define IPW2100_CMD_SET_WPA_PARAM 1 | ||
5777 | #define IPW2100_CMD_SET_WPA_IE 2 | ||
5778 | #define IPW2100_CMD_SET_ENCRYPTION 3 | ||
5779 | #define IPW2100_CMD_MLME 4 | ||
5780 | |||
5781 | #define IPW2100_PARAM_WPA_ENABLED 1 | ||
5782 | #define IPW2100_PARAM_TKIP_COUNTERMEASURES 2 | ||
5783 | #define IPW2100_PARAM_DROP_UNENCRYPTED 3 | ||
5784 | #define IPW2100_PARAM_PRIVACY_INVOKED 4 | ||
5785 | #define IPW2100_PARAM_AUTH_ALGS 5 | ||
5786 | #define IPW2100_PARAM_IEEE_802_1X 6 | ||
5787 | |||
5788 | #define IPW2100_MLME_STA_DEAUTH 1 | ||
5789 | #define IPW2100_MLME_STA_DISASSOC 2 | ||
5790 | |||
5791 | #define IPW2100_CRYPT_ERR_UNKNOWN_ALG 2 | ||
5792 | #define IPW2100_CRYPT_ERR_UNKNOWN_ADDR 3 | ||
5793 | #define IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED 4 | ||
5794 | #define IPW2100_CRYPT_ERR_KEY_SET_FAILED 5 | ||
5795 | #define IPW2100_CRYPT_ERR_TX_KEY_SET_FAILED 6 | ||
5796 | #define IPW2100_CRYPT_ERR_CARD_CONF_FAILED 7 | ||
5797 | |||
5798 | #define IPW2100_CRYPT_ALG_NAME_LEN 16 | ||
5799 | |||
5800 | struct ipw2100_param { | ||
5801 | u32 cmd; | ||
5802 | u8 sta_addr[ETH_ALEN]; | ||
5803 | union { | ||
5804 | struct { | ||
5805 | u8 name; | ||
5806 | u32 value; | ||
5807 | } wpa_param; | ||
5808 | struct { | ||
5809 | u32 len; | ||
5810 | u8 *data; | ||
5811 | } wpa_ie; | ||
5812 | struct{ | ||
5813 | int command; | ||
5814 | int reason_code; | ||
5815 | } mlme; | ||
5816 | struct { | ||
5817 | u8 alg[IPW2100_CRYPT_ALG_NAME_LEN]; | ||
5818 | u8 set_tx; | ||
5819 | u32 err; | ||
5820 | u8 idx; | ||
5821 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
5822 | u16 key_len; | ||
5823 | u8 key[0]; | ||
5824 | } crypt; | ||
5825 | |||
5826 | } u; | ||
5827 | }; | ||
5828 | |||
5829 | /* end of driver_ipw2100.c code */ | ||
5830 | |||
5831 | static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){ | ||
5832 | |||
5833 | struct ieee80211_device *ieee = priv->ieee; | ||
5834 | struct ieee80211_security sec = { | ||
5835 | .flags = SEC_LEVEL | SEC_ENABLED, | ||
5836 | }; | ||
5837 | int ret = 0; | ||
5838 | |||
5839 | ieee->wpa_enabled = value; | ||
5840 | |||
5841 | if (value){ | ||
5842 | sec.level = SEC_LEVEL_3; | ||
5843 | sec.enabled = 1; | ||
5844 | } else { | ||
5845 | sec.level = SEC_LEVEL_0; | ||
5846 | sec.enabled = 0; | ||
5847 | } | ||
5848 | |||
5849 | if (ieee->set_security) | ||
5850 | ieee->set_security(ieee->dev, &sec); | ||
5851 | else | ||
5852 | ret = -EOPNOTSUPP; | ||
5853 | |||
5854 | return ret; | ||
5855 | } | ||
5856 | |||
5857 | #define AUTH_ALG_OPEN_SYSTEM 0x1 | ||
5858 | #define AUTH_ALG_SHARED_KEY 0x2 | ||
5859 | |||
5860 | static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){ | ||
5861 | |||
5862 | struct ieee80211_device *ieee = priv->ieee; | ||
5863 | struct ieee80211_security sec = { | ||
5864 | .flags = SEC_AUTH_MODE, | ||
5865 | }; | ||
5866 | int ret = 0; | ||
5867 | |||
5868 | if (value & AUTH_ALG_SHARED_KEY){ | ||
5869 | sec.auth_mode = WLAN_AUTH_SHARED_KEY; | ||
5870 | ieee->open_wep = 0; | ||
5871 | } else { | ||
5872 | sec.auth_mode = WLAN_AUTH_OPEN; | ||
5873 | ieee->open_wep = 1; | ||
5874 | } | ||
5875 | |||
5876 | if (ieee->set_security) | ||
5877 | ieee->set_security(ieee->dev, &sec); | ||
5878 | else | ||
5879 | ret = -EOPNOTSUPP; | ||
5880 | |||
5881 | return ret; | ||
5882 | } | ||
5883 | |||
5884 | |||
5885 | static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){ | ||
5886 | |||
5887 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5888 | int ret=0; | ||
5889 | |||
5890 | switch(name){ | ||
5891 | case IPW2100_PARAM_WPA_ENABLED: | ||
5892 | ret = ipw2100_wpa_enable(priv, value); | ||
5893 | break; | ||
5894 | |||
5895 | case IPW2100_PARAM_TKIP_COUNTERMEASURES: | ||
5896 | priv->ieee->tkip_countermeasures=value; | ||
5897 | break; | ||
5898 | |||
5899 | case IPW2100_PARAM_DROP_UNENCRYPTED: | ||
5900 | priv->ieee->drop_unencrypted=value; | ||
5901 | break; | ||
5902 | |||
5903 | case IPW2100_PARAM_PRIVACY_INVOKED: | ||
5904 | priv->ieee->privacy_invoked=value; | ||
5905 | break; | ||
5906 | |||
5907 | case IPW2100_PARAM_AUTH_ALGS: | ||
5908 | ret = ipw2100_wpa_set_auth_algs(priv, value); | ||
5909 | break; | ||
5910 | |||
5911 | case IPW2100_PARAM_IEEE_802_1X: | ||
5912 | priv->ieee->ieee802_1x=value; | ||
5913 | break; | ||
5914 | |||
5915 | default: | ||
5916 | printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n", | ||
5917 | dev->name, name); | ||
5918 | ret = -EOPNOTSUPP; | ||
5919 | } | ||
5920 | |||
5921 | return ret; | ||
5922 | } | ||
5923 | |||
5924 | static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){ | ||
5925 | |||
5926 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5927 | int ret=0; | ||
5928 | |||
5929 | switch(command){ | ||
5930 | case IPW2100_MLME_STA_DEAUTH: | ||
5931 | // silently ignore | ||
5932 | break; | ||
5933 | |||
5934 | case IPW2100_MLME_STA_DISASSOC: | ||
5935 | ipw2100_disassociate_bssid(priv); | ||
5936 | break; | ||
5937 | |||
5938 | default: | ||
5939 | printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n", | ||
5940 | dev->name, command); | ||
5941 | ret = -EOPNOTSUPP; | ||
5942 | } | ||
5943 | |||
5944 | return ret; | ||
5945 | } | ||
5946 | |||
5947 | |||
5948 | void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, | ||
5949 | char *wpa_ie, int wpa_ie_len){ | ||
5950 | |||
5951 | struct ipw2100_wpa_assoc_frame frame; | ||
5952 | |||
5953 | frame.fixed_ie_mask = 0; | ||
5954 | |||
5955 | /* copy WPA IE */ | ||
5956 | memcpy(frame.var_ie, wpa_ie, wpa_ie_len); | ||
5957 | frame.var_ie_len = wpa_ie_len; | ||
5958 | |||
5959 | /* make sure WPA is enabled */ | ||
5960 | ipw2100_wpa_enable(priv, 1); | ||
5961 | ipw2100_set_wpa_ie(priv, &frame, 0); | ||
5962 | } | ||
5963 | |||
5964 | |||
5965 | static int ipw2100_wpa_set_wpa_ie(struct net_device *dev, | ||
5966 | struct ipw2100_param *param, int plen){ | ||
5967 | |||
5968 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
5969 | struct ieee80211_device *ieee = priv->ieee; | ||
5970 | u8 *buf; | ||
5971 | |||
5972 | if (! ieee->wpa_enabled) | ||
5973 | return -EOPNOTSUPP; | ||
5974 | |||
5975 | if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || | ||
5976 | (param->u.wpa_ie.len && | ||
5977 | param->u.wpa_ie.data==NULL)) | ||
5978 | return -EINVAL; | ||
5979 | |||
5980 | if (param->u.wpa_ie.len){ | ||
5981 | buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); | ||
5982 | if (buf == NULL) | ||
5983 | return -ENOMEM; | ||
5984 | |||
5985 | memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); | ||
5986 | |||
5987 | kfree(ieee->wpa_ie); | ||
5988 | ieee->wpa_ie = buf; | ||
5989 | ieee->wpa_ie_len = param->u.wpa_ie.len; | ||
5990 | |||
5991 | } else { | ||
5992 | kfree(ieee->wpa_ie); | ||
5993 | ieee->wpa_ie = NULL; | ||
5994 | ieee->wpa_ie_len = 0; | ||
5995 | } | ||
5996 | |||
5997 | ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); | ||
5998 | |||
5999 | return 0; | ||
6000 | } | ||
6001 | |||
6002 | /* implementation borrowed from hostap driver */ | ||
6003 | |||
6004 | static int ipw2100_wpa_set_encryption(struct net_device *dev, | ||
6005 | struct ipw2100_param *param, int param_len){ | ||
6006 | |||
6007 | int ret = 0; | ||
6008 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
6009 | struct ieee80211_device *ieee = priv->ieee; | ||
6010 | struct ieee80211_crypto_ops *ops; | ||
6011 | struct ieee80211_crypt_data **crypt; | ||
6012 | |||
6013 | struct ieee80211_security sec = { | ||
6014 | .flags = 0, | ||
6015 | }; | ||
6016 | |||
6017 | param->u.crypt.err = 0; | ||
6018 | param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
6019 | |||
6020 | if (param_len != | ||
6021 | (int) ((char *) param->u.crypt.key - (char *) param) + | ||
6022 | param->u.crypt.key_len){ | ||
6023 | IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len); | ||
6024 | return -EINVAL; | ||
6025 | } | ||
6026 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
6027 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
6028 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
6029 | if (param->u.crypt.idx >= WEP_KEYS) | ||
6030 | return -EINVAL; | ||
6031 | crypt = &ieee->crypt[param->u.crypt.idx]; | ||
6032 | } else { | ||
6033 | return -EINVAL; | ||
6034 | } | ||
6035 | |||
6036 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
6037 | if (crypt){ | ||
6038 | sec.enabled = 0; | ||
6039 | sec.level = SEC_LEVEL_0; | ||
6040 | sec.flags |= SEC_ENABLED | SEC_LEVEL; | ||
6041 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
6042 | } | ||
6043 | goto done; | ||
6044 | } | ||
6045 | sec.enabled = 1; | ||
6046 | sec.flags |= SEC_ENABLED; | ||
6047 | |||
6048 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
6049 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
6050 | request_module("ieee80211_crypt_wep"); | ||
6051 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
6052 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
6053 | request_module("ieee80211_crypt_tkip"); | ||
6054 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
6055 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
6056 | request_module("ieee80211_crypt_ccmp"); | ||
6057 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
6058 | } | ||
6059 | if (ops == NULL) { | ||
6060 | IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", | ||
6061 | dev->name, param->u.crypt.alg); | ||
6062 | param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG; | ||
6063 | ret = -EINVAL; | ||
6064 | goto done; | ||
6065 | } | ||
6066 | |||
6067 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
6068 | struct ieee80211_crypt_data *new_crypt; | ||
6069 | |||
6070 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
6071 | |||
6072 | new_crypt = (struct ieee80211_crypt_data *) | ||
6073 | kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); | ||
6074 | if (new_crypt == NULL) { | ||
6075 | ret = -ENOMEM; | ||
6076 | goto done; | ||
6077 | } | ||
6078 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
6079 | new_crypt->ops = ops; | ||
6080 | if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | ||
6081 | new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); | ||
6082 | |||
6083 | if (new_crypt->priv == NULL) { | ||
6084 | kfree(new_crypt); | ||
6085 | param->u.crypt.err = | ||
6086 | IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
6087 | ret = -EINVAL; | ||
6088 | goto done; | ||
6089 | } | ||
6090 | |||
6091 | *crypt = new_crypt; | ||
6092 | } | ||
6093 | |||
6094 | if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && | ||
6095 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
6096 | param->u.crypt.key_len, param->u.crypt.seq, | ||
6097 | (*crypt)->priv) < 0) { | ||
6098 | IPW_DEBUG_INFO("%s: key setting failed\n", | ||
6099 | dev->name); | ||
6100 | param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED; | ||
6101 | ret = -EINVAL; | ||
6102 | goto done; | ||
6103 | } | ||
6104 | |||
6105 | if (param->u.crypt.set_tx){ | ||
6106 | ieee->tx_keyidx = param->u.crypt.idx; | ||
6107 | sec.active_key = param->u.crypt.idx; | ||
6108 | sec.flags |= SEC_ACTIVE_KEY; | ||
6109 | } | ||
6110 | |||
6111 | if (ops->name != NULL){ | ||
6112 | |||
6113 | if (strcmp(ops->name, "WEP") == 0) { | ||
6114 | memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len); | ||
6115 | sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; | ||
6116 | sec.flags |= (1 << param->u.crypt.idx); | ||
6117 | sec.flags |= SEC_LEVEL; | ||
6118 | sec.level = SEC_LEVEL_1; | ||
6119 | } else if (strcmp(ops->name, "TKIP") == 0) { | ||
6120 | sec.flags |= SEC_LEVEL; | ||
6121 | sec.level = SEC_LEVEL_2; | ||
6122 | } else if (strcmp(ops->name, "CCMP") == 0) { | ||
6123 | sec.flags |= SEC_LEVEL; | ||
6124 | sec.level = SEC_LEVEL_3; | ||
6125 | } | ||
6126 | } | ||
6127 | done: | ||
6128 | if (ieee->set_security) | ||
6129 | ieee->set_security(ieee->dev, &sec); | ||
6130 | |||
6131 | /* Do not reset port if card is in Managed mode since resetting will | ||
6132 | * generate new IEEE 802.11 authentication which may end up in looping | ||
6133 | * with IEEE 802.1X. If your hardware requires a reset after WEP | ||
6134 | * configuration (for example... Prism2), implement the reset_port in | ||
6135 | * the callbacks structures used to initialize the 802.11 stack. */ | ||
6136 | if (ieee->reset_on_keychange && | ||
6137 | ieee->iw_mode != IW_MODE_INFRA && | ||
6138 | ieee->reset_port && | ||
6139 | ieee->reset_port(dev)) { | ||
6140 | IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); | ||
6141 | param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED; | ||
6142 | return -EINVAL; | ||
6143 | } | ||
6144 | |||
6145 | return ret; | ||
6146 | } | ||
6147 | |||
6148 | |||
6149 | static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){ | ||
6150 | |||
6151 | struct ipw2100_param *param; | ||
6152 | int ret=0; | ||
6153 | |||
6154 | IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length); | ||
6155 | |||
6156 | if (p->length < sizeof(struct ipw2100_param) || !p->pointer) | ||
6157 | return -EINVAL; | ||
6158 | |||
6159 | param = (struct ipw2100_param *)kmalloc(p->length, GFP_KERNEL); | ||
6160 | if (param == NULL) | ||
6161 | return -ENOMEM; | ||
6162 | |||
6163 | if (copy_from_user(param, p->pointer, p->length)){ | ||
6164 | kfree(param); | ||
6165 | return -EFAULT; | ||
6166 | } | ||
6167 | |||
6168 | switch (param->cmd){ | ||
6169 | |||
6170 | case IPW2100_CMD_SET_WPA_PARAM: | ||
6171 | ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name, | ||
6172 | param->u.wpa_param.value); | ||
6173 | break; | ||
6174 | |||
6175 | case IPW2100_CMD_SET_WPA_IE: | ||
6176 | ret = ipw2100_wpa_set_wpa_ie(dev, param, p->length); | ||
6177 | break; | ||
6178 | |||
6179 | case IPW2100_CMD_SET_ENCRYPTION: | ||
6180 | ret = ipw2100_wpa_set_encryption(dev, param, p->length); | ||
6181 | break; | ||
6182 | |||
6183 | case IPW2100_CMD_MLME: | ||
6184 | ret = ipw2100_wpa_mlme(dev, param->u.mlme.command, | ||
6185 | param->u.mlme.reason_code); | ||
6186 | break; | ||
6187 | |||
6188 | default: | ||
6189 | printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n", | ||
6190 | dev->name, param->cmd); | ||
6191 | ret = -EOPNOTSUPP; | ||
6192 | |||
6193 | } | ||
6194 | |||
6195 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) | ||
6196 | ret = -EFAULT; | ||
6197 | |||
6198 | kfree(param); | ||
6199 | return ret; | ||
6200 | } | ||
6201 | #endif /* CONFIG_IEEE80211_WPA */ | ||
6202 | |||
6203 | static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
6204 | { | ||
6205 | #ifdef CONFIG_IEEE80211_WPA | ||
6206 | struct iwreq *wrq = (struct iwreq *) rq; | ||
6207 | int ret=-1; | ||
6208 | switch (cmd){ | ||
6209 | case IPW2100_IOCTL_WPA_SUPPLICANT: | ||
6210 | ret = ipw2100_wpa_supplicant(dev, &wrq->u.data); | ||
6211 | return ret; | ||
6212 | |||
6213 | default: | ||
6214 | return -EOPNOTSUPP; | ||
6215 | } | ||
6216 | |||
6217 | #endif /* CONFIG_IEEE80211_WPA */ | ||
6218 | |||
6219 | return -EOPNOTSUPP; | ||
6220 | } | ||
6221 | |||
6222 | |||
6223 | static void ipw_ethtool_get_drvinfo(struct net_device *dev, | ||
6224 | struct ethtool_drvinfo *info) | ||
6225 | { | ||
6226 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
6227 | char fw_ver[64], ucode_ver[64]; | ||
6228 | |||
6229 | strcpy(info->driver, DRV_NAME); | ||
6230 | strcpy(info->version, DRV_VERSION); | ||
6231 | |||
6232 | ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver)); | ||
6233 | ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver)); | ||
6234 | |||
6235 | snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s", | ||
6236 | fw_ver, priv->eeprom_version, ucode_ver); | ||
6237 | |||
6238 | strcpy(info->bus_info, pci_name(priv->pci_dev)); | ||
6239 | } | ||
6240 | |||
6241 | static u32 ipw2100_ethtool_get_link(struct net_device *dev) | ||
6242 | { | ||
6243 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
6244 | return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; | ||
6245 | } | ||
6246 | |||
6247 | |||
6248 | static struct ethtool_ops ipw2100_ethtool_ops = { | ||
6249 | .get_link = ipw2100_ethtool_get_link, | ||
6250 | .get_drvinfo = ipw_ethtool_get_drvinfo, | ||
6251 | }; | ||
6252 | |||
6253 | static void ipw2100_hang_check(void *adapter) | ||
6254 | { | ||
6255 | struct ipw2100_priv *priv = adapter; | ||
6256 | unsigned long flags; | ||
6257 | u32 rtc = 0xa5a5a5a5; | ||
6258 | u32 len = sizeof(rtc); | ||
6259 | int restart = 0; | ||
6260 | |||
6261 | spin_lock_irqsave(&priv->low_lock, flags); | ||
6262 | |||
6263 | if (priv->fatal_error != 0) { | ||
6264 | /* If fatal_error is set then we need to restart */ | ||
6265 | IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n", | ||
6266 | priv->net_dev->name); | ||
6267 | |||
6268 | restart = 1; | ||
6269 | } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) || | ||
6270 | (rtc == priv->last_rtc)) { | ||
6271 | /* Check if firmware is hung */ | ||
6272 | IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n", | ||
6273 | priv->net_dev->name); | ||
6274 | |||
6275 | restart = 1; | ||
6276 | } | ||
6277 | |||
6278 | if (restart) { | ||
6279 | /* Kill timer */ | ||
6280 | priv->stop_hang_check = 1; | ||
6281 | priv->hangs++; | ||
6282 | |||
6283 | /* Restart the NIC */ | ||
6284 | schedule_reset(priv); | ||
6285 | } | ||
6286 | |||
6287 | priv->last_rtc = rtc; | ||
6288 | |||
6289 | if (!priv->stop_hang_check) | ||
6290 | queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); | ||
6291 | |||
6292 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
6293 | } | ||
6294 | |||
6295 | |||
6296 | static void ipw2100_rf_kill(void *adapter) | ||
6297 | { | ||
6298 | struct ipw2100_priv *priv = adapter; | ||
6299 | unsigned long flags; | ||
6300 | |||
6301 | spin_lock_irqsave(&priv->low_lock, flags); | ||
6302 | |||
6303 | if (rf_kill_active(priv)) { | ||
6304 | IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); | ||
6305 | if (!priv->stop_rf_kill) | ||
6306 | queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); | ||
6307 | goto exit_unlock; | ||
6308 | } | ||
6309 | |||
6310 | /* RF Kill is now disabled, so bring the device back up */ | ||
6311 | |||
6312 | if (!(priv->status & STATUS_RF_KILL_MASK)) { | ||
6313 | IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " | ||
6314 | "device\n"); | ||
6315 | schedule_reset(priv); | ||
6316 | } else | ||
6317 | IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " | ||
6318 | "enabled\n"); | ||
6319 | |||
6320 | exit_unlock: | ||
6321 | spin_unlock_irqrestore(&priv->low_lock, flags); | ||
6322 | } | ||
6323 | |||
6324 | static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); | ||
6325 | |||
6326 | /* Look into using netdev destructor to shutdown ieee80211? */ | ||
6327 | |||
6328 | static struct net_device *ipw2100_alloc_device( | ||
6329 | struct pci_dev *pci_dev, | ||
6330 | char *base_addr, | ||
6331 | unsigned long mem_start, | ||
6332 | unsigned long mem_len) | ||
6333 | { | ||
6334 | struct ipw2100_priv *priv; | ||
6335 | struct net_device *dev; | ||
6336 | |||
6337 | dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); | ||
6338 | if (!dev) | ||
6339 | return NULL; | ||
6340 | priv = ieee80211_priv(dev); | ||
6341 | priv->ieee = netdev_priv(dev); | ||
6342 | priv->pci_dev = pci_dev; | ||
6343 | priv->net_dev = dev; | ||
6344 | |||
6345 | priv->ieee->hard_start_xmit = ipw2100_tx; | ||
6346 | priv->ieee->set_security = shim__set_security; | ||
6347 | |||
6348 | dev->open = ipw2100_open; | ||
6349 | dev->stop = ipw2100_close; | ||
6350 | dev->init = ipw2100_net_init; | ||
6351 | dev->do_ioctl = ipw2100_ioctl; | ||
6352 | dev->get_stats = ipw2100_stats; | ||
6353 | dev->ethtool_ops = &ipw2100_ethtool_ops; | ||
6354 | dev->tx_timeout = ipw2100_tx_timeout; | ||
6355 | dev->wireless_handlers = &ipw2100_wx_handler_def; | ||
6356 | dev->get_wireless_stats = ipw2100_wx_wireless_stats; | ||
6357 | dev->set_mac_address = ipw2100_set_address; | ||
6358 | dev->watchdog_timeo = 3*HZ; | ||
6359 | dev->irq = 0; | ||
6360 | |||
6361 | dev->base_addr = (unsigned long)base_addr; | ||
6362 | dev->mem_start = mem_start; | ||
6363 | dev->mem_end = dev->mem_start + mem_len - 1; | ||
6364 | |||
6365 | /* NOTE: We don't use the wireless_handlers hook | ||
6366 | * in dev as the system will start throwing WX requests | ||
6367 | * to us before we're actually initialized and it just | ||
6368 | * ends up causing problems. So, we just handle | ||
6369 | * the WX extensions through the ipw2100_ioctl interface */ | ||
6370 | |||
6371 | |||
6372 | /* memset() puts everything to 0, so we only have explicitely set | ||
6373 | * those values that need to be something else */ | ||
6374 | |||
6375 | /* If power management is turned on, default to AUTO mode */ | ||
6376 | priv->power_mode = IPW_POWER_AUTO; | ||
6377 | |||
6378 | |||
6379 | |||
6380 | #ifdef CONFIG_IEEE80211_WPA | ||
6381 | priv->ieee->wpa_enabled = 0; | ||
6382 | priv->ieee->tkip_countermeasures = 0; | ||
6383 | priv->ieee->drop_unencrypted = 0; | ||
6384 | priv->ieee->privacy_invoked = 0; | ||
6385 | priv->ieee->ieee802_1x = 1; | ||
6386 | #endif /* CONFIG_IEEE80211_WPA */ | ||
6387 | |||
6388 | /* Set module parameters */ | ||
6389 | switch (mode) { | ||
6390 | case 1: | ||
6391 | priv->ieee->iw_mode = IW_MODE_ADHOC; | ||
6392 | break; | ||
6393 | #ifdef CONFIG_IPW2100_MONITOR | ||
6394 | case 2: | ||
6395 | priv->ieee->iw_mode = IW_MODE_MONITOR; | ||
6396 | break; | ||
6397 | #endif | ||
6398 | default: | ||
6399 | case 0: | ||
6400 | priv->ieee->iw_mode = IW_MODE_INFRA; | ||
6401 | break; | ||
6402 | } | ||
6403 | |||
6404 | if (disable == 1) | ||
6405 | priv->status |= STATUS_RF_KILL_SW; | ||
6406 | |||
6407 | if (channel != 0 && | ||
6408 | ((channel >= REG_MIN_CHANNEL) && | ||
6409 | (channel <= REG_MAX_CHANNEL))) { | ||
6410 | priv->config |= CFG_STATIC_CHANNEL; | ||
6411 | priv->channel = channel; | ||
6412 | } | ||
6413 | |||
6414 | if (associate) | ||
6415 | priv->config |= CFG_ASSOCIATE; | ||
6416 | |||
6417 | priv->beacon_interval = DEFAULT_BEACON_INTERVAL; | ||
6418 | priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; | ||
6419 | priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; | ||
6420 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED; | ||
6421 | priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED; | ||
6422 | priv->tx_power = IPW_TX_POWER_DEFAULT; | ||
6423 | priv->tx_rates = DEFAULT_TX_RATES; | ||
6424 | |||
6425 | strcpy(priv->nick, "ipw2100"); | ||
6426 | |||
6427 | spin_lock_init(&priv->low_lock); | ||
6428 | sema_init(&priv->action_sem, 1); | ||
6429 | sema_init(&priv->adapter_sem, 1); | ||
6430 | |||
6431 | init_waitqueue_head(&priv->wait_command_queue); | ||
6432 | |||
6433 | netif_carrier_off(dev); | ||
6434 | |||
6435 | INIT_LIST_HEAD(&priv->msg_free_list); | ||
6436 | INIT_LIST_HEAD(&priv->msg_pend_list); | ||
6437 | INIT_STAT(&priv->msg_free_stat); | ||
6438 | INIT_STAT(&priv->msg_pend_stat); | ||
6439 | |||
6440 | INIT_LIST_HEAD(&priv->tx_free_list); | ||
6441 | INIT_LIST_HEAD(&priv->tx_pend_list); | ||
6442 | INIT_STAT(&priv->tx_free_stat); | ||
6443 | INIT_STAT(&priv->tx_pend_stat); | ||
6444 | |||
6445 | INIT_LIST_HEAD(&priv->fw_pend_list); | ||
6446 | INIT_STAT(&priv->fw_pend_stat); | ||
6447 | |||
6448 | |||
6449 | #ifdef CONFIG_SOFTWARE_SUSPEND2 | ||
6450 | priv->workqueue = create_workqueue(DRV_NAME, 0); | ||
6451 | #else | ||
6452 | priv->workqueue = create_workqueue(DRV_NAME); | ||
6453 | #endif | ||
6454 | INIT_WORK(&priv->reset_work, | ||
6455 | (void (*)(void *))ipw2100_reset_adapter, priv); | ||
6456 | INIT_WORK(&priv->security_work, | ||
6457 | (void (*)(void *))ipw2100_security_work, priv); | ||
6458 | INIT_WORK(&priv->wx_event_work, | ||
6459 | (void (*)(void *))ipw2100_wx_event_work, priv); | ||
6460 | INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv); | ||
6461 | INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv); | ||
6462 | |||
6463 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | ||
6464 | ipw2100_irq_tasklet, (unsigned long)priv); | ||
6465 | |||
6466 | /* NOTE: We do not start the deferred work for status checks yet */ | ||
6467 | priv->stop_rf_kill = 1; | ||
6468 | priv->stop_hang_check = 1; | ||
6469 | |||
6470 | return dev; | ||
6471 | } | ||
6472 | |||
6473 | static int ipw2100_pci_init_one(struct pci_dev *pci_dev, | ||
6474 | const struct pci_device_id *ent) | ||
6475 | { | ||
6476 | unsigned long mem_start, mem_len, mem_flags; | ||
6477 | char *base_addr = NULL; | ||
6478 | struct net_device *dev = NULL; | ||
6479 | struct ipw2100_priv *priv = NULL; | ||
6480 | int err = 0; | ||
6481 | int registered = 0; | ||
6482 | u32 val; | ||
6483 | |||
6484 | IPW_DEBUG_INFO("enter\n"); | ||
6485 | |||
6486 | mem_start = pci_resource_start(pci_dev, 0); | ||
6487 | mem_len = pci_resource_len(pci_dev, 0); | ||
6488 | mem_flags = pci_resource_flags(pci_dev, 0); | ||
6489 | |||
6490 | if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) { | ||
6491 | IPW_DEBUG_INFO("weird - resource type is not memory\n"); | ||
6492 | err = -ENODEV; | ||
6493 | goto fail; | ||
6494 | } | ||
6495 | |||
6496 | base_addr = ioremap_nocache(mem_start, mem_len); | ||
6497 | if (!base_addr) { | ||
6498 | printk(KERN_WARNING DRV_NAME | ||
6499 | "Error calling ioremap_nocache.\n"); | ||
6500 | err = -EIO; | ||
6501 | goto fail; | ||
6502 | } | ||
6503 | |||
6504 | /* allocate and initialize our net_device */ | ||
6505 | dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len); | ||
6506 | if (!dev) { | ||
6507 | printk(KERN_WARNING DRV_NAME | ||
6508 | "Error calling ipw2100_alloc_device.\n"); | ||
6509 | err = -ENOMEM; | ||
6510 | goto fail; | ||
6511 | } | ||
6512 | |||
6513 | /* set up PCI mappings for device */ | ||
6514 | err = pci_enable_device(pci_dev); | ||
6515 | if (err) { | ||
6516 | printk(KERN_WARNING DRV_NAME | ||
6517 | "Error calling pci_enable_device.\n"); | ||
6518 | return err; | ||
6519 | } | ||
6520 | |||
6521 | priv = ieee80211_priv(dev); | ||
6522 | |||
6523 | pci_set_master(pci_dev); | ||
6524 | pci_set_drvdata(pci_dev, priv); | ||
6525 | |||
6526 | err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); | ||
6527 | if (err) { | ||
6528 | printk(KERN_WARNING DRV_NAME | ||
6529 | "Error calling pci_set_dma_mask.\n"); | ||
6530 | pci_disable_device(pci_dev); | ||
6531 | return err; | ||
6532 | } | ||
6533 | |||
6534 | err = pci_request_regions(pci_dev, DRV_NAME); | ||
6535 | if (err) { | ||
6536 | printk(KERN_WARNING DRV_NAME | ||
6537 | "Error calling pci_request_regions.\n"); | ||
6538 | pci_disable_device(pci_dev); | ||
6539 | return err; | ||
6540 | } | ||
6541 | |||
6542 | /* We disable the RETRY_TIMEOUT register (0x41) to keep | ||
6543 | * PCI Tx retries from interfering with C3 CPU state */ | ||
6544 | pci_read_config_dword(pci_dev, 0x40, &val); | ||
6545 | if ((val & 0x0000ff00) != 0) | ||
6546 | pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); | ||
6547 | |||
6548 | pci_set_power_state(pci_dev, PCI_D0); | ||
6549 | |||
6550 | if (!ipw2100_hw_is_adapter_in_system(dev)) { | ||
6551 | printk(KERN_WARNING DRV_NAME | ||
6552 | "Device not found via register read.\n"); | ||
6553 | err = -ENODEV; | ||
6554 | goto fail; | ||
6555 | } | ||
6556 | |||
6557 | SET_NETDEV_DEV(dev, &pci_dev->dev); | ||
6558 | |||
6559 | /* Force interrupts to be shut off on the device */ | ||
6560 | priv->status |= STATUS_INT_ENABLED; | ||
6561 | ipw2100_disable_interrupts(priv); | ||
6562 | |||
6563 | /* Allocate and initialize the Tx/Rx queues and lists */ | ||
6564 | if (ipw2100_queues_allocate(priv)) { | ||
6565 | printk(KERN_WARNING DRV_NAME | ||
6566 | "Error calilng ipw2100_queues_allocate.\n"); | ||
6567 | err = -ENOMEM; | ||
6568 | goto fail; | ||
6569 | } | ||
6570 | ipw2100_queues_initialize(priv); | ||
6571 | |||
6572 | err = request_irq(pci_dev->irq, | ||
6573 | ipw2100_interrupt, SA_SHIRQ, | ||
6574 | dev->name, priv); | ||
6575 | if (err) { | ||
6576 | printk(KERN_WARNING DRV_NAME | ||
6577 | "Error calling request_irq: %d.\n", | ||
6578 | pci_dev->irq); | ||
6579 | goto fail; | ||
6580 | } | ||
6581 | dev->irq = pci_dev->irq; | ||
6582 | |||
6583 | IPW_DEBUG_INFO("Attempting to register device...\n"); | ||
6584 | |||
6585 | SET_MODULE_OWNER(dev); | ||
6586 | |||
6587 | printk(KERN_INFO DRV_NAME | ||
6588 | ": Detected Intel PRO/Wireless 2100 Network Connection\n"); | ||
6589 | |||
6590 | /* Bring up the interface. Pre 0.46, after we registered the | ||
6591 | * network device we would call ipw2100_up. This introduced a race | ||
6592 | * condition with newer hotplug configurations (network was coming | ||
6593 | * up and making calls before the device was initialized). | ||
6594 | * | ||
6595 | * If we called ipw2100_up before we registered the device, then the | ||
6596 | * device name wasn't registered. So, we instead use the net_dev->init | ||
6597 | * member to call a function that then just turns and calls ipw2100_up. | ||
6598 | * net_dev->init is called after name allocation but before the | ||
6599 | * notifier chain is called */ | ||
6600 | down(&priv->action_sem); | ||
6601 | err = register_netdev(dev); | ||
6602 | if (err) { | ||
6603 | printk(KERN_WARNING DRV_NAME | ||
6604 | "Error calling register_netdev.\n"); | ||
6605 | goto fail_unlock; | ||
6606 | } | ||
6607 | registered = 1; | ||
6608 | |||
6609 | IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev)); | ||
6610 | |||
6611 | /* perform this after register_netdev so that dev->name is set */ | ||
6612 | sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); | ||
6613 | netif_carrier_off(dev); | ||
6614 | |||
6615 | /* If the RF Kill switch is disabled, go ahead and complete the | ||
6616 | * startup sequence */ | ||
6617 | if (!(priv->status & STATUS_RF_KILL_MASK)) { | ||
6618 | /* Enable the adapter - sends HOST_COMPLETE */ | ||
6619 | if (ipw2100_enable_adapter(priv)) { | ||
6620 | printk(KERN_WARNING DRV_NAME | ||
6621 | ": %s: failed in call to enable adapter.\n", | ||
6622 | priv->net_dev->name); | ||
6623 | ipw2100_hw_stop_adapter(priv); | ||
6624 | err = -EIO; | ||
6625 | goto fail_unlock; | ||
6626 | } | ||
6627 | |||
6628 | /* Start a scan . . . */ | ||
6629 | ipw2100_set_scan_options(priv); | ||
6630 | ipw2100_start_scan(priv); | ||
6631 | } | ||
6632 | |||
6633 | IPW_DEBUG_INFO("exit\n"); | ||
6634 | |||
6635 | priv->status |= STATUS_INITIALIZED; | ||
6636 | |||
6637 | up(&priv->action_sem); | ||
6638 | |||
6639 | return 0; | ||
6640 | |||
6641 | fail_unlock: | ||
6642 | up(&priv->action_sem); | ||
6643 | |||
6644 | fail: | ||
6645 | if (dev) { | ||
6646 | if (registered) | ||
6647 | unregister_netdev(dev); | ||
6648 | |||
6649 | ipw2100_hw_stop_adapter(priv); | ||
6650 | |||
6651 | ipw2100_disable_interrupts(priv); | ||
6652 | |||
6653 | if (dev->irq) | ||
6654 | free_irq(dev->irq, priv); | ||
6655 | |||
6656 | ipw2100_kill_workqueue(priv); | ||
6657 | |||
6658 | /* These are safe to call even if they weren't allocated */ | ||
6659 | ipw2100_queues_free(priv); | ||
6660 | sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); | ||
6661 | |||
6662 | free_ieee80211(dev); | ||
6663 | pci_set_drvdata(pci_dev, NULL); | ||
6664 | } | ||
6665 | |||
6666 | if (base_addr) | ||
6667 | iounmap((char*)base_addr); | ||
6668 | |||
6669 | pci_release_regions(pci_dev); | ||
6670 | pci_disable_device(pci_dev); | ||
6671 | |||
6672 | return err; | ||
6673 | } | ||
6674 | |||
6675 | static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) | ||
6676 | { | ||
6677 | struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); | ||
6678 | struct net_device *dev; | ||
6679 | |||
6680 | if (priv) { | ||
6681 | down(&priv->action_sem); | ||
6682 | |||
6683 | priv->status &= ~STATUS_INITIALIZED; | ||
6684 | |||
6685 | dev = priv->net_dev; | ||
6686 | sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); | ||
6687 | |||
6688 | #ifdef CONFIG_PM | ||
6689 | if (ipw2100_firmware.version) | ||
6690 | ipw2100_release_firmware(priv, &ipw2100_firmware); | ||
6691 | #endif | ||
6692 | /* Take down the hardware */ | ||
6693 | ipw2100_down(priv); | ||
6694 | |||
6695 | /* Release the semaphore so that the network subsystem can | ||
6696 | * complete any needed calls into the driver... */ | ||
6697 | up(&priv->action_sem); | ||
6698 | |||
6699 | /* Unregister the device first - this results in close() | ||
6700 | * being called if the device is open. If we free storage | ||
6701 | * first, then close() will crash. */ | ||
6702 | unregister_netdev(dev); | ||
6703 | |||
6704 | /* ipw2100_down will ensure that there is no more pending work | ||
6705 | * in the workqueue's, so we can safely remove them now. */ | ||
6706 | ipw2100_kill_workqueue(priv); | ||
6707 | |||
6708 | ipw2100_queues_free(priv); | ||
6709 | |||
6710 | /* Free potential debugging firmware snapshot */ | ||
6711 | ipw2100_snapshot_free(priv); | ||
6712 | |||
6713 | if (dev->irq) | ||
6714 | free_irq(dev->irq, priv); | ||
6715 | |||
6716 | if (dev->base_addr) | ||
6717 | iounmap((unsigned char *)dev->base_addr); | ||
6718 | |||
6719 | free_ieee80211(dev); | ||
6720 | } | ||
6721 | |||
6722 | pci_release_regions(pci_dev); | ||
6723 | pci_disable_device(pci_dev); | ||
6724 | |||
6725 | IPW_DEBUG_INFO("exit\n"); | ||
6726 | } | ||
6727 | |||
6728 | |||
6729 | #ifdef CONFIG_PM | ||
6730 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) | ||
6731 | static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state) | ||
6732 | #else | ||
6733 | static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) | ||
6734 | #endif | ||
6735 | { | ||
6736 | struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); | ||
6737 | struct net_device *dev = priv->net_dev; | ||
6738 | |||
6739 | IPW_DEBUG_INFO("%s: Going into suspend...\n", | ||
6740 | dev->name); | ||
6741 | |||
6742 | down(&priv->action_sem); | ||
6743 | if (priv->status & STATUS_INITIALIZED) { | ||
6744 | /* Take down the device; powers it off, etc. */ | ||
6745 | ipw2100_down(priv); | ||
6746 | } | ||
6747 | |||
6748 | /* Remove the PRESENT state of the device */ | ||
6749 | netif_device_detach(dev); | ||
6750 | |||
6751 | pci_save_state(pci_dev); | ||
6752 | pci_disable_device (pci_dev); | ||
6753 | pci_set_power_state(pci_dev, PCI_D3hot); | ||
6754 | |||
6755 | up(&priv->action_sem); | ||
6756 | |||
6757 | return 0; | ||
6758 | } | ||
6759 | |||
6760 | static int ipw2100_resume(struct pci_dev *pci_dev) | ||
6761 | { | ||
6762 | struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); | ||
6763 | struct net_device *dev = priv->net_dev; | ||
6764 | u32 val; | ||
6765 | |||
6766 | if (IPW2100_PM_DISABLED) | ||
6767 | return 0; | ||
6768 | |||
6769 | down(&priv->action_sem); | ||
6770 | |||
6771 | IPW_DEBUG_INFO("%s: Coming out of suspend...\n", | ||
6772 | dev->name); | ||
6773 | |||
6774 | pci_set_power_state(pci_dev, PCI_D0); | ||
6775 | pci_enable_device(pci_dev); | ||
6776 | pci_restore_state(pci_dev); | ||
6777 | |||
6778 | /* | ||
6779 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
6780 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | ||
6781 | * from interfering with C3 CPU state. pci_restore_state won't help | ||
6782 | * here since it only restores the first 64 bytes pci config header. | ||
6783 | */ | ||
6784 | pci_read_config_dword(pci_dev, 0x40, &val); | ||
6785 | if ((val & 0x0000ff00) != 0) | ||
6786 | pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); | ||
6787 | |||
6788 | /* Set the device back into the PRESENT state; this will also wake | ||
6789 | * the queue of needed */ | ||
6790 | netif_device_attach(dev); | ||
6791 | |||
6792 | /* Bring the device back up */ | ||
6793 | if (!(priv->status & STATUS_RF_KILL_SW)) | ||
6794 | ipw2100_up(priv, 0); | ||
6795 | |||
6796 | up(&priv->action_sem); | ||
6797 | |||
6798 | return 0; | ||
6799 | } | ||
6800 | #endif | ||
6801 | |||
6802 | |||
6803 | #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } | ||
6804 | |||
6805 | static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { | ||
6806 | IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ | ||
6807 | IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ | ||
6808 | IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ | ||
6809 | IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */ | ||
6810 | IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */ | ||
6811 | IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */ | ||
6812 | IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */ | ||
6813 | IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */ | ||
6814 | IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */ | ||
6815 | IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */ | ||
6816 | IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */ | ||
6817 | IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */ | ||
6818 | IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */ | ||
6819 | |||
6820 | IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */ | ||
6821 | IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */ | ||
6822 | IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */ | ||
6823 | IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */ | ||
6824 | IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */ | ||
6825 | |||
6826 | IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */ | ||
6827 | IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */ | ||
6828 | IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */ | ||
6829 | IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */ | ||
6830 | IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */ | ||
6831 | IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */ | ||
6832 | IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */ | ||
6833 | |||
6834 | IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */ | ||
6835 | |||
6836 | IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */ | ||
6837 | IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */ | ||
6838 | IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */ | ||
6839 | IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */ | ||
6840 | IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */ | ||
6841 | IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */ | ||
6842 | IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */ | ||
6843 | |||
6844 | IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */ | ||
6845 | IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */ | ||
6846 | IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */ | ||
6847 | IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */ | ||
6848 | IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */ | ||
6849 | IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */ | ||
6850 | |||
6851 | IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */ | ||
6852 | {0,}, | ||
6853 | }; | ||
6854 | |||
6855 | MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table); | ||
6856 | |||
6857 | static struct pci_driver ipw2100_pci_driver = { | ||
6858 | .name = DRV_NAME, | ||
6859 | .id_table = ipw2100_pci_id_table, | ||
6860 | .probe = ipw2100_pci_init_one, | ||
6861 | .remove = __devexit_p(ipw2100_pci_remove_one), | ||
6862 | #ifdef CONFIG_PM | ||
6863 | .suspend = ipw2100_suspend, | ||
6864 | .resume = ipw2100_resume, | ||
6865 | #endif | ||
6866 | }; | ||
6867 | |||
6868 | |||
6869 | /** | ||
6870 | * Initialize the ipw2100 driver/module | ||
6871 | * | ||
6872 | * @returns 0 if ok, < 0 errno node con error. | ||
6873 | * | ||
6874 | * Note: we cannot init the /proc stuff until the PCI driver is there, | ||
6875 | * or we risk an unlikely race condition on someone accessing | ||
6876 | * uninitialized data in the PCI dev struct through /proc. | ||
6877 | */ | ||
6878 | static int __init ipw2100_init(void) | ||
6879 | { | ||
6880 | int ret; | ||
6881 | |||
6882 | printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); | ||
6883 | printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); | ||
6884 | |||
6885 | #ifdef CONFIG_IEEE80211_NOWEP | ||
6886 | IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n"); | ||
6887 | #endif | ||
6888 | |||
6889 | ret = pci_module_init(&ipw2100_pci_driver); | ||
6890 | |||
6891 | #ifdef CONFIG_IPW_DEBUG | ||
6892 | ipw2100_debug_level = debug; | ||
6893 | driver_create_file(&ipw2100_pci_driver.driver, | ||
6894 | &driver_attr_debug_level); | ||
6895 | #endif | ||
6896 | |||
6897 | return ret; | ||
6898 | } | ||
6899 | |||
6900 | |||
6901 | /** | ||
6902 | * Cleanup ipw2100 driver registration | ||
6903 | */ | ||
6904 | static void __exit ipw2100_exit(void) | ||
6905 | { | ||
6906 | /* FIXME: IPG: check that we have no instances of the devices open */ | ||
6907 | #ifdef CONFIG_IPW_DEBUG | ||
6908 | driver_remove_file(&ipw2100_pci_driver.driver, | ||
6909 | &driver_attr_debug_level); | ||
6910 | #endif | ||
6911 | pci_unregister_driver(&ipw2100_pci_driver); | ||
6912 | } | ||
6913 | |||
6914 | module_init(ipw2100_init); | ||
6915 | module_exit(ipw2100_exit); | ||
6916 | |||
6917 | #define WEXT_USECHANNELS 1 | ||
6918 | |||
6919 | static const long ipw2100_frequencies[] = { | ||
6920 | 2412, 2417, 2422, 2427, | ||
6921 | 2432, 2437, 2442, 2447, | ||
6922 | 2452, 2457, 2462, 2467, | ||
6923 | 2472, 2484 | ||
6924 | }; | ||
6925 | |||
6926 | #define FREQ_COUNT (sizeof(ipw2100_frequencies) / \ | ||
6927 | sizeof(ipw2100_frequencies[0])) | ||
6928 | |||
6929 | static const long ipw2100_rates_11b[] = { | ||
6930 | 1000000, | ||
6931 | 2000000, | ||
6932 | 5500000, | ||
6933 | 11000000 | ||
6934 | }; | ||
6935 | |||
6936 | #define RATE_COUNT (sizeof(ipw2100_rates_11b) / sizeof(ipw2100_rates_11b[0])) | ||
6937 | |||
6938 | static int ipw2100_wx_get_name(struct net_device *dev, | ||
6939 | struct iw_request_info *info, | ||
6940 | union iwreq_data *wrqu, char *extra) | ||
6941 | { | ||
6942 | /* | ||
6943 | * This can be called at any time. No action lock required | ||
6944 | */ | ||
6945 | |||
6946 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
6947 | if (!(priv->status & STATUS_ASSOCIATED)) | ||
6948 | strcpy(wrqu->name, "unassociated"); | ||
6949 | else | ||
6950 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); | ||
6951 | |||
6952 | IPW_DEBUG_WX("Name: %s\n", wrqu->name); | ||
6953 | return 0; | ||
6954 | } | ||
6955 | |||
6956 | |||
6957 | static int ipw2100_wx_set_freq(struct net_device *dev, | ||
6958 | struct iw_request_info *info, | ||
6959 | union iwreq_data *wrqu, char *extra) | ||
6960 | { | ||
6961 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
6962 | struct iw_freq *fwrq = &wrqu->freq; | ||
6963 | int err = 0; | ||
6964 | |||
6965 | if (priv->ieee->iw_mode == IW_MODE_INFRA) | ||
6966 | return -EOPNOTSUPP; | ||
6967 | |||
6968 | down(&priv->action_sem); | ||
6969 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
6970 | err = -EIO; | ||
6971 | goto done; | ||
6972 | } | ||
6973 | |||
6974 | /* if setting by freq convert to channel */ | ||
6975 | if (fwrq->e == 1) { | ||
6976 | if ((fwrq->m >= (int) 2.412e8 && | ||
6977 | fwrq->m <= (int) 2.487e8)) { | ||
6978 | int f = fwrq->m / 100000; | ||
6979 | int c = 0; | ||
6980 | |||
6981 | while ((c < REG_MAX_CHANNEL) && | ||
6982 | (f != ipw2100_frequencies[c])) | ||
6983 | c++; | ||
6984 | |||
6985 | /* hack to fall through */ | ||
6986 | fwrq->e = 0; | ||
6987 | fwrq->m = c + 1; | ||
6988 | } | ||
6989 | } | ||
6990 | |||
6991 | if (fwrq->e > 0 || fwrq->m > 1000) | ||
6992 | return -EOPNOTSUPP; | ||
6993 | else { /* Set the channel */ | ||
6994 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); | ||
6995 | err = ipw2100_set_channel(priv, fwrq->m, 0); | ||
6996 | } | ||
6997 | |||
6998 | done: | ||
6999 | up(&priv->action_sem); | ||
7000 | return err; | ||
7001 | } | ||
7002 | |||
7003 | |||
7004 | static int ipw2100_wx_get_freq(struct net_device *dev, | ||
7005 | struct iw_request_info *info, | ||
7006 | union iwreq_data *wrqu, char *extra) | ||
7007 | { | ||
7008 | /* | ||
7009 | * This can be called at any time. No action lock required | ||
7010 | */ | ||
7011 | |||
7012 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7013 | |||
7014 | wrqu->freq.e = 0; | ||
7015 | |||
7016 | /* If we are associated, trying to associate, or have a statically | ||
7017 | * configured CHANNEL then return that; otherwise return ANY */ | ||
7018 | if (priv->config & CFG_STATIC_CHANNEL || | ||
7019 | priv->status & STATUS_ASSOCIATED) | ||
7020 | wrqu->freq.m = priv->channel; | ||
7021 | else | ||
7022 | wrqu->freq.m = 0; | ||
7023 | |||
7024 | IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); | ||
7025 | return 0; | ||
7026 | |||
7027 | } | ||
7028 | |||
7029 | static int ipw2100_wx_set_mode(struct net_device *dev, | ||
7030 | struct iw_request_info *info, | ||
7031 | union iwreq_data *wrqu, char *extra) | ||
7032 | { | ||
7033 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7034 | int err = 0; | ||
7035 | |||
7036 | IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode); | ||
7037 | |||
7038 | if (wrqu->mode == priv->ieee->iw_mode) | ||
7039 | return 0; | ||
7040 | |||
7041 | down(&priv->action_sem); | ||
7042 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7043 | err = -EIO; | ||
7044 | goto done; | ||
7045 | } | ||
7046 | |||
7047 | switch (wrqu->mode) { | ||
7048 | #ifdef CONFIG_IPW2100_MONITOR | ||
7049 | case IW_MODE_MONITOR: | ||
7050 | err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); | ||
7051 | break; | ||
7052 | #endif /* CONFIG_IPW2100_MONITOR */ | ||
7053 | case IW_MODE_ADHOC: | ||
7054 | err = ipw2100_switch_mode(priv, IW_MODE_ADHOC); | ||
7055 | break; | ||
7056 | case IW_MODE_INFRA: | ||
7057 | case IW_MODE_AUTO: | ||
7058 | default: | ||
7059 | err = ipw2100_switch_mode(priv, IW_MODE_INFRA); | ||
7060 | break; | ||
7061 | } | ||
7062 | |||
7063 | done: | ||
7064 | up(&priv->action_sem); | ||
7065 | return err; | ||
7066 | } | ||
7067 | |||
7068 | static int ipw2100_wx_get_mode(struct net_device *dev, | ||
7069 | struct iw_request_info *info, | ||
7070 | union iwreq_data *wrqu, char *extra) | ||
7071 | { | ||
7072 | /* | ||
7073 | * This can be called at any time. No action lock required | ||
7074 | */ | ||
7075 | |||
7076 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7077 | |||
7078 | wrqu->mode = priv->ieee->iw_mode; | ||
7079 | IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode); | ||
7080 | |||
7081 | return 0; | ||
7082 | } | ||
7083 | |||
7084 | |||
7085 | #define POWER_MODES 5 | ||
7086 | |||
7087 | /* Values are in microsecond */ | ||
7088 | static const s32 timeout_duration[POWER_MODES] = { | ||
7089 | 350000, | ||
7090 | 250000, | ||
7091 | 75000, | ||
7092 | 37000, | ||
7093 | 25000, | ||
7094 | }; | ||
7095 | |||
7096 | static const s32 period_duration[POWER_MODES] = { | ||
7097 | 400000, | ||
7098 | 700000, | ||
7099 | 1000000, | ||
7100 | 1000000, | ||
7101 | 1000000 | ||
7102 | }; | ||
7103 | |||
7104 | static int ipw2100_wx_get_range(struct net_device *dev, | ||
7105 | struct iw_request_info *info, | ||
7106 | union iwreq_data *wrqu, char *extra) | ||
7107 | { | ||
7108 | /* | ||
7109 | * This can be called at any time. No action lock required | ||
7110 | */ | ||
7111 | |||
7112 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7113 | struct iw_range *range = (struct iw_range *)extra; | ||
7114 | u16 val; | ||
7115 | int i, level; | ||
7116 | |||
7117 | wrqu->data.length = sizeof(*range); | ||
7118 | memset(range, 0, sizeof(*range)); | ||
7119 | |||
7120 | /* Let's try to keep this struct in the same order as in | ||
7121 | * linux/include/wireless.h | ||
7122 | */ | ||
7123 | |||
7124 | /* TODO: See what values we can set, and remove the ones we can't | ||
7125 | * set, or fill them with some default data. | ||
7126 | */ | ||
7127 | |||
7128 | /* ~5 Mb/s real (802.11b) */ | ||
7129 | range->throughput = 5 * 1000 * 1000; | ||
7130 | |||
7131 | // range->sensitivity; /* signal level threshold range */ | ||
7132 | |||
7133 | range->max_qual.qual = 100; | ||
7134 | /* TODO: Find real max RSSI and stick here */ | ||
7135 | range->max_qual.level = 0; | ||
7136 | range->max_qual.noise = 0; | ||
7137 | range->max_qual.updated = 7; /* Updated all three */ | ||
7138 | |||
7139 | range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ | ||
7140 | /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ | ||
7141 | range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM; | ||
7142 | range->avg_qual.noise = 0; | ||
7143 | range->avg_qual.updated = 7; /* Updated all three */ | ||
7144 | |||
7145 | range->num_bitrates = RATE_COUNT; | ||
7146 | |||
7147 | for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { | ||
7148 | range->bitrate[i] = ipw2100_rates_11b[i]; | ||
7149 | } | ||
7150 | |||
7151 | range->min_rts = MIN_RTS_THRESHOLD; | ||
7152 | range->max_rts = MAX_RTS_THRESHOLD; | ||
7153 | range->min_frag = MIN_FRAG_THRESHOLD; | ||
7154 | range->max_frag = MAX_FRAG_THRESHOLD; | ||
7155 | |||
7156 | range->min_pmp = period_duration[0]; /* Minimal PM period */ | ||
7157 | range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */ | ||
7158 | range->min_pmt = timeout_duration[POWER_MODES-1]; /* Minimal PM timeout */ | ||
7159 | range->max_pmt = timeout_duration[0];/* Maximal PM timeout */ | ||
7160 | |||
7161 | /* How to decode max/min PM period */ | ||
7162 | range->pmp_flags = IW_POWER_PERIOD; | ||
7163 | /* How to decode max/min PM period */ | ||
7164 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
7165 | /* What PM options are supported */ | ||
7166 | range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD; | ||
7167 | |||
7168 | range->encoding_size[0] = 5; | ||
7169 | range->encoding_size[1] = 13; /* Different token sizes */ | ||
7170 | range->num_encoding_sizes = 2; /* Number of entry in the list */ | ||
7171 | range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */ | ||
7172 | // range->encoding_login_index; /* token index for login token */ | ||
7173 | |||
7174 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
7175 | range->txpower_capa = IW_TXPOW_DBM; | ||
7176 | range->num_txpower = IW_MAX_TXPOWER; | ||
7177 | for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER; | ||
7178 | i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) / | ||
7179 | (IW_MAX_TXPOWER - 1)) | ||
7180 | range->txpower[i] = level / 16; | ||
7181 | } else { | ||
7182 | range->txpower_capa = 0; | ||
7183 | range->num_txpower = 0; | ||
7184 | } | ||
7185 | |||
7186 | |||
7187 | /* Set the Wireless Extension versions */ | ||
7188 | range->we_version_compiled = WIRELESS_EXT; | ||
7189 | range->we_version_source = 16; | ||
7190 | |||
7191 | // range->retry_capa; /* What retry options are supported */ | ||
7192 | // range->retry_flags; /* How to decode max/min retry limit */ | ||
7193 | // range->r_time_flags; /* How to decode max/min retry life */ | ||
7194 | // range->min_retry; /* Minimal number of retries */ | ||
7195 | // range->max_retry; /* Maximal number of retries */ | ||
7196 | // range->min_r_time; /* Minimal retry lifetime */ | ||
7197 | // range->max_r_time; /* Maximal retry lifetime */ | ||
7198 | |||
7199 | range->num_channels = FREQ_COUNT; | ||
7200 | |||
7201 | val = 0; | ||
7202 | for (i = 0; i < FREQ_COUNT; i++) { | ||
7203 | // TODO: Include only legal frequencies for some countries | ||
7204 | // if (local->channel_mask & (1 << i)) { | ||
7205 | range->freq[val].i = i + 1; | ||
7206 | range->freq[val].m = ipw2100_frequencies[i] * 100000; | ||
7207 | range->freq[val].e = 1; | ||
7208 | val++; | ||
7209 | // } | ||
7210 | if (val == IW_MAX_FREQUENCIES) | ||
7211 | break; | ||
7212 | } | ||
7213 | range->num_frequency = val; | ||
7214 | |||
7215 | IPW_DEBUG_WX("GET Range\n"); | ||
7216 | |||
7217 | return 0; | ||
7218 | } | ||
7219 | |||
7220 | static int ipw2100_wx_set_wap(struct net_device *dev, | ||
7221 | struct iw_request_info *info, | ||
7222 | union iwreq_data *wrqu, char *extra) | ||
7223 | { | ||
7224 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7225 | int err = 0; | ||
7226 | |||
7227 | static const unsigned char any[] = { | ||
7228 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
7229 | }; | ||
7230 | static const unsigned char off[] = { | ||
7231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
7232 | }; | ||
7233 | |||
7234 | // sanity checks | ||
7235 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) | ||
7236 | return -EINVAL; | ||
7237 | |||
7238 | down(&priv->action_sem); | ||
7239 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7240 | err = -EIO; | ||
7241 | goto done; | ||
7242 | } | ||
7243 | |||
7244 | if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || | ||
7245 | !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { | ||
7246 | /* we disable mandatory BSSID association */ | ||
7247 | IPW_DEBUG_WX("exit - disable mandatory BSSID\n"); | ||
7248 | priv->config &= ~CFG_STATIC_BSSID; | ||
7249 | err = ipw2100_set_mandatory_bssid(priv, NULL, 0); | ||
7250 | goto done; | ||
7251 | } | ||
7252 | |||
7253 | priv->config |= CFG_STATIC_BSSID; | ||
7254 | memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN); | ||
7255 | |||
7256 | err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); | ||
7257 | |||
7258 | IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n", | ||
7259 | wrqu->ap_addr.sa_data[0] & 0xff, | ||
7260 | wrqu->ap_addr.sa_data[1] & 0xff, | ||
7261 | wrqu->ap_addr.sa_data[2] & 0xff, | ||
7262 | wrqu->ap_addr.sa_data[3] & 0xff, | ||
7263 | wrqu->ap_addr.sa_data[4] & 0xff, | ||
7264 | wrqu->ap_addr.sa_data[5] & 0xff); | ||
7265 | |||
7266 | done: | ||
7267 | up(&priv->action_sem); | ||
7268 | return err; | ||
7269 | } | ||
7270 | |||
7271 | static int ipw2100_wx_get_wap(struct net_device *dev, | ||
7272 | struct iw_request_info *info, | ||
7273 | union iwreq_data *wrqu, char *extra) | ||
7274 | { | ||
7275 | /* | ||
7276 | * This can be called at any time. No action lock required | ||
7277 | */ | ||
7278 | |||
7279 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7280 | |||
7281 | /* If we are associated, trying to associate, or have a statically | ||
7282 | * configured BSSID then return that; otherwise return ANY */ | ||
7283 | if (priv->config & CFG_STATIC_BSSID || | ||
7284 | priv->status & STATUS_ASSOCIATED) { | ||
7285 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | ||
7286 | memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); | ||
7287 | } else | ||
7288 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); | ||
7289 | |||
7290 | IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", | ||
7291 | MAC_ARG(wrqu->ap_addr.sa_data)); | ||
7292 | return 0; | ||
7293 | } | ||
7294 | |||
7295 | static int ipw2100_wx_set_essid(struct net_device *dev, | ||
7296 | struct iw_request_info *info, | ||
7297 | union iwreq_data *wrqu, char *extra) | ||
7298 | { | ||
7299 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7300 | char *essid = ""; /* ANY */ | ||
7301 | int length = 0; | ||
7302 | int err = 0; | ||
7303 | |||
7304 | down(&priv->action_sem); | ||
7305 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7306 | err = -EIO; | ||
7307 | goto done; | ||
7308 | } | ||
7309 | |||
7310 | if (wrqu->essid.flags && wrqu->essid.length) { | ||
7311 | length = wrqu->essid.length - 1; | ||
7312 | essid = extra; | ||
7313 | } | ||
7314 | |||
7315 | if (length == 0) { | ||
7316 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); | ||
7317 | priv->config &= ~CFG_STATIC_ESSID; | ||
7318 | err = ipw2100_set_essid(priv, NULL, 0, 0); | ||
7319 | goto done; | ||
7320 | } | ||
7321 | |||
7322 | length = min(length, IW_ESSID_MAX_SIZE); | ||
7323 | |||
7324 | priv->config |= CFG_STATIC_ESSID; | ||
7325 | |||
7326 | if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { | ||
7327 | IPW_DEBUG_WX("ESSID set to current ESSID.\n"); | ||
7328 | err = 0; | ||
7329 | goto done; | ||
7330 | } | ||
7331 | |||
7332 | IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), | ||
7333 | length); | ||
7334 | |||
7335 | priv->essid_len = length; | ||
7336 | memcpy(priv->essid, essid, priv->essid_len); | ||
7337 | |||
7338 | err = ipw2100_set_essid(priv, essid, length, 0); | ||
7339 | |||
7340 | done: | ||
7341 | up(&priv->action_sem); | ||
7342 | return err; | ||
7343 | } | ||
7344 | |||
7345 | static int ipw2100_wx_get_essid(struct net_device *dev, | ||
7346 | struct iw_request_info *info, | ||
7347 | union iwreq_data *wrqu, char *extra) | ||
7348 | { | ||
7349 | /* | ||
7350 | * This can be called at any time. No action lock required | ||
7351 | */ | ||
7352 | |||
7353 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7354 | |||
7355 | /* If we are associated, trying to associate, or have a statically | ||
7356 | * configured ESSID then return that; otherwise return ANY */ | ||
7357 | if (priv->config & CFG_STATIC_ESSID || | ||
7358 | priv->status & STATUS_ASSOCIATED) { | ||
7359 | IPW_DEBUG_WX("Getting essid: '%s'\n", | ||
7360 | escape_essid(priv->essid, priv->essid_len)); | ||
7361 | memcpy(extra, priv->essid, priv->essid_len); | ||
7362 | wrqu->essid.length = priv->essid_len; | ||
7363 | wrqu->essid.flags = 1; /* active */ | ||
7364 | } else { | ||
7365 | IPW_DEBUG_WX("Getting essid: ANY\n"); | ||
7366 | wrqu->essid.length = 0; | ||
7367 | wrqu->essid.flags = 0; /* active */ | ||
7368 | } | ||
7369 | |||
7370 | return 0; | ||
7371 | } | ||
7372 | |||
7373 | static int ipw2100_wx_set_nick(struct net_device *dev, | ||
7374 | struct iw_request_info *info, | ||
7375 | union iwreq_data *wrqu, char *extra) | ||
7376 | { | ||
7377 | /* | ||
7378 | * This can be called at any time. No action lock required | ||
7379 | */ | ||
7380 | |||
7381 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7382 | |||
7383 | if (wrqu->data.length > IW_ESSID_MAX_SIZE) | ||
7384 | return -E2BIG; | ||
7385 | |||
7386 | wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick)); | ||
7387 | memset(priv->nick, 0, sizeof(priv->nick)); | ||
7388 | memcpy(priv->nick, extra, wrqu->data.length); | ||
7389 | |||
7390 | IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick); | ||
7391 | |||
7392 | return 0; | ||
7393 | } | ||
7394 | |||
7395 | static int ipw2100_wx_get_nick(struct net_device *dev, | ||
7396 | struct iw_request_info *info, | ||
7397 | union iwreq_data *wrqu, char *extra) | ||
7398 | { | ||
7399 | /* | ||
7400 | * This can be called at any time. No action lock required | ||
7401 | */ | ||
7402 | |||
7403 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7404 | |||
7405 | wrqu->data.length = strlen(priv->nick) + 1; | ||
7406 | memcpy(extra, priv->nick, wrqu->data.length); | ||
7407 | wrqu->data.flags = 1; /* active */ | ||
7408 | |||
7409 | IPW_DEBUG_WX("GET Nickname -> %s \n", extra); | ||
7410 | |||
7411 | return 0; | ||
7412 | } | ||
7413 | |||
7414 | static int ipw2100_wx_set_rate(struct net_device *dev, | ||
7415 | struct iw_request_info *info, | ||
7416 | union iwreq_data *wrqu, char *extra) | ||
7417 | { | ||
7418 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7419 | u32 target_rate = wrqu->bitrate.value; | ||
7420 | u32 rate; | ||
7421 | int err = 0; | ||
7422 | |||
7423 | down(&priv->action_sem); | ||
7424 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7425 | err = -EIO; | ||
7426 | goto done; | ||
7427 | } | ||
7428 | |||
7429 | rate = 0; | ||
7430 | |||
7431 | if (target_rate == 1000000 || | ||
7432 | (!wrqu->bitrate.fixed && target_rate > 1000000)) | ||
7433 | rate |= TX_RATE_1_MBIT; | ||
7434 | if (target_rate == 2000000 || | ||
7435 | (!wrqu->bitrate.fixed && target_rate > 2000000)) | ||
7436 | rate |= TX_RATE_2_MBIT; | ||
7437 | if (target_rate == 5500000 || | ||
7438 | (!wrqu->bitrate.fixed && target_rate > 5500000)) | ||
7439 | rate |= TX_RATE_5_5_MBIT; | ||
7440 | if (target_rate == 11000000 || | ||
7441 | (!wrqu->bitrate.fixed && target_rate > 11000000)) | ||
7442 | rate |= TX_RATE_11_MBIT; | ||
7443 | if (rate == 0) | ||
7444 | rate = DEFAULT_TX_RATES; | ||
7445 | |||
7446 | err = ipw2100_set_tx_rates(priv, rate, 0); | ||
7447 | |||
7448 | IPW_DEBUG_WX("SET Rate -> %04X \n", rate); | ||
7449 | done: | ||
7450 | up(&priv->action_sem); | ||
7451 | return err; | ||
7452 | } | ||
7453 | |||
7454 | |||
7455 | static int ipw2100_wx_get_rate(struct net_device *dev, | ||
7456 | struct iw_request_info *info, | ||
7457 | union iwreq_data *wrqu, char *extra) | ||
7458 | { | ||
7459 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7460 | int val; | ||
7461 | int len = sizeof(val); | ||
7462 | int err = 0; | ||
7463 | |||
7464 | if (!(priv->status & STATUS_ENABLED) || | ||
7465 | priv->status & STATUS_RF_KILL_MASK || | ||
7466 | !(priv->status & STATUS_ASSOCIATED)) { | ||
7467 | wrqu->bitrate.value = 0; | ||
7468 | return 0; | ||
7469 | } | ||
7470 | |||
7471 | down(&priv->action_sem); | ||
7472 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7473 | err = -EIO; | ||
7474 | goto done; | ||
7475 | } | ||
7476 | |||
7477 | err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); | ||
7478 | if (err) { | ||
7479 | IPW_DEBUG_WX("failed querying ordinals.\n"); | ||
7480 | return err; | ||
7481 | } | ||
7482 | |||
7483 | switch (val & TX_RATE_MASK) { | ||
7484 | case TX_RATE_1_MBIT: | ||
7485 | wrqu->bitrate.value = 1000000; | ||
7486 | break; | ||
7487 | case TX_RATE_2_MBIT: | ||
7488 | wrqu->bitrate.value = 2000000; | ||
7489 | break; | ||
7490 | case TX_RATE_5_5_MBIT: | ||
7491 | wrqu->bitrate.value = 5500000; | ||
7492 | break; | ||
7493 | case TX_RATE_11_MBIT: | ||
7494 | wrqu->bitrate.value = 11000000; | ||
7495 | break; | ||
7496 | default: | ||
7497 | wrqu->bitrate.value = 0; | ||
7498 | } | ||
7499 | |||
7500 | IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); | ||
7501 | |||
7502 | done: | ||
7503 | up(&priv->action_sem); | ||
7504 | return err; | ||
7505 | } | ||
7506 | |||
7507 | static int ipw2100_wx_set_rts(struct net_device *dev, | ||
7508 | struct iw_request_info *info, | ||
7509 | union iwreq_data *wrqu, char *extra) | ||
7510 | { | ||
7511 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7512 | int value, err; | ||
7513 | |||
7514 | /* Auto RTS not yet supported */ | ||
7515 | if (wrqu->rts.fixed == 0) | ||
7516 | return -EINVAL; | ||
7517 | |||
7518 | down(&priv->action_sem); | ||
7519 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7520 | err = -EIO; | ||
7521 | goto done; | ||
7522 | } | ||
7523 | |||
7524 | if (wrqu->rts.disabled) | ||
7525 | value = priv->rts_threshold | RTS_DISABLED; | ||
7526 | else { | ||
7527 | if (wrqu->rts.value < 1 || | ||
7528 | wrqu->rts.value > 2304) { | ||
7529 | err = -EINVAL; | ||
7530 | goto done; | ||
7531 | } | ||
7532 | value = wrqu->rts.value; | ||
7533 | } | ||
7534 | |||
7535 | err = ipw2100_set_rts_threshold(priv, value); | ||
7536 | |||
7537 | IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value); | ||
7538 | done: | ||
7539 | up(&priv->action_sem); | ||
7540 | return err; | ||
7541 | } | ||
7542 | |||
7543 | static int ipw2100_wx_get_rts(struct net_device *dev, | ||
7544 | struct iw_request_info *info, | ||
7545 | union iwreq_data *wrqu, char *extra) | ||
7546 | { | ||
7547 | /* | ||
7548 | * This can be called at any time. No action lock required | ||
7549 | */ | ||
7550 | |||
7551 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7552 | |||
7553 | wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; | ||
7554 | wrqu->rts.fixed = 1; /* no auto select */ | ||
7555 | |||
7556 | /* If RTS is set to the default value, then it is disabled */ | ||
7557 | wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0; | ||
7558 | |||
7559 | IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value); | ||
7560 | |||
7561 | return 0; | ||
7562 | } | ||
7563 | |||
7564 | static int ipw2100_wx_set_txpow(struct net_device *dev, | ||
7565 | struct iw_request_info *info, | ||
7566 | union iwreq_data *wrqu, char *extra) | ||
7567 | { | ||
7568 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7569 | int err = 0, value; | ||
7570 | |||
7571 | if (priv->ieee->iw_mode != IW_MODE_ADHOC) | ||
7572 | return -EINVAL; | ||
7573 | |||
7574 | if (wrqu->txpower.disabled == 1 || wrqu->txpower.fixed == 0) | ||
7575 | value = IPW_TX_POWER_DEFAULT; | ||
7576 | else { | ||
7577 | if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM || | ||
7578 | wrqu->txpower.value > IPW_TX_POWER_MAX_DBM) | ||
7579 | return -EINVAL; | ||
7580 | |||
7581 | value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 / | ||
7582 | (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); | ||
7583 | } | ||
7584 | |||
7585 | down(&priv->action_sem); | ||
7586 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7587 | err = -EIO; | ||
7588 | goto done; | ||
7589 | } | ||
7590 | |||
7591 | err = ipw2100_set_tx_power(priv, value); | ||
7592 | |||
7593 | IPW_DEBUG_WX("SET TX Power -> %d \n", value); | ||
7594 | |||
7595 | done: | ||
7596 | up(&priv->action_sem); | ||
7597 | return err; | ||
7598 | } | ||
7599 | |||
7600 | static int ipw2100_wx_get_txpow(struct net_device *dev, | ||
7601 | struct iw_request_info *info, | ||
7602 | union iwreq_data *wrqu, char *extra) | ||
7603 | { | ||
7604 | /* | ||
7605 | * This can be called at any time. No action lock required | ||
7606 | */ | ||
7607 | |||
7608 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7609 | |||
7610 | if (priv->ieee->iw_mode != IW_MODE_ADHOC) { | ||
7611 | wrqu->power.disabled = 1; | ||
7612 | return 0; | ||
7613 | } | ||
7614 | |||
7615 | if (priv->tx_power == IPW_TX_POWER_DEFAULT) { | ||
7616 | wrqu->power.fixed = 0; | ||
7617 | wrqu->power.value = IPW_TX_POWER_MAX_DBM; | ||
7618 | wrqu->power.disabled = 1; | ||
7619 | } else { | ||
7620 | wrqu->power.disabled = 0; | ||
7621 | wrqu->power.fixed = 1; | ||
7622 | wrqu->power.value = | ||
7623 | (priv->tx_power * | ||
7624 | (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) / | ||
7625 | (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) + | ||
7626 | IPW_TX_POWER_MIN_DBM; | ||
7627 | } | ||
7628 | |||
7629 | wrqu->power.flags = IW_TXPOW_DBM; | ||
7630 | |||
7631 | IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->power.value); | ||
7632 | |||
7633 | return 0; | ||
7634 | } | ||
7635 | |||
7636 | static int ipw2100_wx_set_frag(struct net_device *dev, | ||
7637 | struct iw_request_info *info, | ||
7638 | union iwreq_data *wrqu, char *extra) | ||
7639 | { | ||
7640 | /* | ||
7641 | * This can be called at any time. No action lock required | ||
7642 | */ | ||
7643 | |||
7644 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7645 | |||
7646 | if (!wrqu->frag.fixed) | ||
7647 | return -EINVAL; | ||
7648 | |||
7649 | if (wrqu->frag.disabled) { | ||
7650 | priv->frag_threshold |= FRAG_DISABLED; | ||
7651 | priv->ieee->fts = DEFAULT_FTS; | ||
7652 | } else { | ||
7653 | if (wrqu->frag.value < MIN_FRAG_THRESHOLD || | ||
7654 | wrqu->frag.value > MAX_FRAG_THRESHOLD) | ||
7655 | return -EINVAL; | ||
7656 | |||
7657 | priv->ieee->fts = wrqu->frag.value & ~0x1; | ||
7658 | priv->frag_threshold = priv->ieee->fts; | ||
7659 | } | ||
7660 | |||
7661 | IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts); | ||
7662 | |||
7663 | return 0; | ||
7664 | } | ||
7665 | |||
7666 | static int ipw2100_wx_get_frag(struct net_device *dev, | ||
7667 | struct iw_request_info *info, | ||
7668 | union iwreq_data *wrqu, char *extra) | ||
7669 | { | ||
7670 | /* | ||
7671 | * This can be called at any time. No action lock required | ||
7672 | */ | ||
7673 | |||
7674 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7675 | wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED; | ||
7676 | wrqu->frag.fixed = 0; /* no auto select */ | ||
7677 | wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0; | ||
7678 | |||
7679 | IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); | ||
7680 | |||
7681 | return 0; | ||
7682 | } | ||
7683 | |||
7684 | static int ipw2100_wx_set_retry(struct net_device *dev, | ||
7685 | struct iw_request_info *info, | ||
7686 | union iwreq_data *wrqu, char *extra) | ||
7687 | { | ||
7688 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7689 | int err = 0; | ||
7690 | |||
7691 | if (wrqu->retry.flags & IW_RETRY_LIFETIME || | ||
7692 | wrqu->retry.disabled) | ||
7693 | return -EINVAL; | ||
7694 | |||
7695 | if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) | ||
7696 | return 0; | ||
7697 | |||
7698 | down(&priv->action_sem); | ||
7699 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7700 | err = -EIO; | ||
7701 | goto done; | ||
7702 | } | ||
7703 | |||
7704 | if (wrqu->retry.flags & IW_RETRY_MIN) { | ||
7705 | err = ipw2100_set_short_retry(priv, wrqu->retry.value); | ||
7706 | IPW_DEBUG_WX("SET Short Retry Limit -> %d \n", | ||
7707 | wrqu->retry.value); | ||
7708 | goto done; | ||
7709 | } | ||
7710 | |||
7711 | if (wrqu->retry.flags & IW_RETRY_MAX) { | ||
7712 | err = ipw2100_set_long_retry(priv, wrqu->retry.value); | ||
7713 | IPW_DEBUG_WX("SET Long Retry Limit -> %d \n", | ||
7714 | wrqu->retry.value); | ||
7715 | goto done; | ||
7716 | } | ||
7717 | |||
7718 | err = ipw2100_set_short_retry(priv, wrqu->retry.value); | ||
7719 | if (!err) | ||
7720 | err = ipw2100_set_long_retry(priv, wrqu->retry.value); | ||
7721 | |||
7722 | IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value); | ||
7723 | |||
7724 | done: | ||
7725 | up(&priv->action_sem); | ||
7726 | return err; | ||
7727 | } | ||
7728 | |||
7729 | static int ipw2100_wx_get_retry(struct net_device *dev, | ||
7730 | struct iw_request_info *info, | ||
7731 | union iwreq_data *wrqu, char *extra) | ||
7732 | { | ||
7733 | /* | ||
7734 | * This can be called at any time. No action lock required | ||
7735 | */ | ||
7736 | |||
7737 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7738 | |||
7739 | wrqu->retry.disabled = 0; /* can't be disabled */ | ||
7740 | |||
7741 | if ((wrqu->retry.flags & IW_RETRY_TYPE) == | ||
7742 | IW_RETRY_LIFETIME) | ||
7743 | return -EINVAL; | ||
7744 | |||
7745 | if (wrqu->retry.flags & IW_RETRY_MAX) { | ||
7746 | wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; | ||
7747 | wrqu->retry.value = priv->long_retry_limit; | ||
7748 | } else { | ||
7749 | wrqu->retry.flags = | ||
7750 | (priv->short_retry_limit != | ||
7751 | priv->long_retry_limit) ? | ||
7752 | IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT; | ||
7753 | |||
7754 | wrqu->retry.value = priv->short_retry_limit; | ||
7755 | } | ||
7756 | |||
7757 | IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value); | ||
7758 | |||
7759 | return 0; | ||
7760 | } | ||
7761 | |||
7762 | static int ipw2100_wx_set_scan(struct net_device *dev, | ||
7763 | struct iw_request_info *info, | ||
7764 | union iwreq_data *wrqu, char *extra) | ||
7765 | { | ||
7766 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7767 | int err = 0; | ||
7768 | |||
7769 | down(&priv->action_sem); | ||
7770 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7771 | err = -EIO; | ||
7772 | goto done; | ||
7773 | } | ||
7774 | |||
7775 | IPW_DEBUG_WX("Initiating scan...\n"); | ||
7776 | if (ipw2100_set_scan_options(priv) || | ||
7777 | ipw2100_start_scan(priv)) { | ||
7778 | IPW_DEBUG_WX("Start scan failed.\n"); | ||
7779 | |||
7780 | /* TODO: Mark a scan as pending so when hardware initialized | ||
7781 | * a scan starts */ | ||
7782 | } | ||
7783 | |||
7784 | done: | ||
7785 | up(&priv->action_sem); | ||
7786 | return err; | ||
7787 | } | ||
7788 | |||
7789 | static int ipw2100_wx_get_scan(struct net_device *dev, | ||
7790 | struct iw_request_info *info, | ||
7791 | union iwreq_data *wrqu, char *extra) | ||
7792 | { | ||
7793 | /* | ||
7794 | * This can be called at any time. No action lock required | ||
7795 | */ | ||
7796 | |||
7797 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7798 | return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); | ||
7799 | } | ||
7800 | |||
7801 | |||
7802 | /* | ||
7803 | * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c | ||
7804 | */ | ||
7805 | static int ipw2100_wx_set_encode(struct net_device *dev, | ||
7806 | struct iw_request_info *info, | ||
7807 | union iwreq_data *wrqu, char *key) | ||
7808 | { | ||
7809 | /* | ||
7810 | * No check of STATUS_INITIALIZED required | ||
7811 | */ | ||
7812 | |||
7813 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7814 | return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); | ||
7815 | } | ||
7816 | |||
7817 | static int ipw2100_wx_get_encode(struct net_device *dev, | ||
7818 | struct iw_request_info *info, | ||
7819 | union iwreq_data *wrqu, char *key) | ||
7820 | { | ||
7821 | /* | ||
7822 | * This can be called at any time. No action lock required | ||
7823 | */ | ||
7824 | |||
7825 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7826 | return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); | ||
7827 | } | ||
7828 | |||
7829 | static int ipw2100_wx_set_power(struct net_device *dev, | ||
7830 | struct iw_request_info *info, | ||
7831 | union iwreq_data *wrqu, char *extra) | ||
7832 | { | ||
7833 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7834 | int err = 0; | ||
7835 | |||
7836 | down(&priv->action_sem); | ||
7837 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7838 | err = -EIO; | ||
7839 | goto done; | ||
7840 | } | ||
7841 | |||
7842 | if (wrqu->power.disabled) { | ||
7843 | priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); | ||
7844 | err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); | ||
7845 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); | ||
7846 | goto done; | ||
7847 | } | ||
7848 | |||
7849 | switch (wrqu->power.flags & IW_POWER_MODE) { | ||
7850 | case IW_POWER_ON: /* If not specified */ | ||
7851 | case IW_POWER_MODE: /* If set all mask */ | ||
7852 | case IW_POWER_ALL_R: /* If explicitely state all */ | ||
7853 | break; | ||
7854 | default: /* Otherwise we don't support it */ | ||
7855 | IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", | ||
7856 | wrqu->power.flags); | ||
7857 | err = -EOPNOTSUPP; | ||
7858 | goto done; | ||
7859 | } | ||
7860 | |||
7861 | /* If the user hasn't specified a power management mode yet, default | ||
7862 | * to BATTERY */ | ||
7863 | priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; | ||
7864 | err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); | ||
7865 | |||
7866 | IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", | ||
7867 | priv->power_mode); | ||
7868 | |||
7869 | done: | ||
7870 | up(&priv->action_sem); | ||
7871 | return err; | ||
7872 | |||
7873 | } | ||
7874 | |||
7875 | static int ipw2100_wx_get_power(struct net_device *dev, | ||
7876 | struct iw_request_info *info, | ||
7877 | union iwreq_data *wrqu, char *extra) | ||
7878 | { | ||
7879 | /* | ||
7880 | * This can be called at any time. No action lock required | ||
7881 | */ | ||
7882 | |||
7883 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7884 | |||
7885 | if (!(priv->power_mode & IPW_POWER_ENABLED)) { | ||
7886 | wrqu->power.disabled = 1; | ||
7887 | } else { | ||
7888 | wrqu->power.disabled = 0; | ||
7889 | wrqu->power.flags = 0; | ||
7890 | } | ||
7891 | |||
7892 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); | ||
7893 | |||
7894 | return 0; | ||
7895 | } | ||
7896 | |||
7897 | |||
7898 | /* | ||
7899 | * | ||
7900 | * IWPRIV handlers | ||
7901 | * | ||
7902 | */ | ||
7903 | #ifdef CONFIG_IPW2100_MONITOR | ||
7904 | static int ipw2100_wx_set_promisc(struct net_device *dev, | ||
7905 | struct iw_request_info *info, | ||
7906 | union iwreq_data *wrqu, char *extra) | ||
7907 | { | ||
7908 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7909 | int *parms = (int *)extra; | ||
7910 | int enable = (parms[0] > 0); | ||
7911 | int err = 0; | ||
7912 | |||
7913 | down(&priv->action_sem); | ||
7914 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7915 | err = -EIO; | ||
7916 | goto done; | ||
7917 | } | ||
7918 | |||
7919 | if (enable) { | ||
7920 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | ||
7921 | err = ipw2100_set_channel(priv, parms[1], 0); | ||
7922 | goto done; | ||
7923 | } | ||
7924 | priv->channel = parms[1]; | ||
7925 | err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); | ||
7926 | } else { | ||
7927 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | ||
7928 | err = ipw2100_switch_mode(priv, priv->last_mode); | ||
7929 | } | ||
7930 | done: | ||
7931 | up(&priv->action_sem); | ||
7932 | return err; | ||
7933 | } | ||
7934 | |||
7935 | static int ipw2100_wx_reset(struct net_device *dev, | ||
7936 | struct iw_request_info *info, | ||
7937 | union iwreq_data *wrqu, char *extra) | ||
7938 | { | ||
7939 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7940 | if (priv->status & STATUS_INITIALIZED) | ||
7941 | schedule_reset(priv); | ||
7942 | return 0; | ||
7943 | } | ||
7944 | |||
7945 | #endif | ||
7946 | |||
7947 | static int ipw2100_wx_set_powermode(struct net_device *dev, | ||
7948 | struct iw_request_info *info, | ||
7949 | union iwreq_data *wrqu, char *extra) | ||
7950 | { | ||
7951 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7952 | int err = 0, mode = *(int *)extra; | ||
7953 | |||
7954 | down(&priv->action_sem); | ||
7955 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
7956 | err = -EIO; | ||
7957 | goto done; | ||
7958 | } | ||
7959 | |||
7960 | if ((mode < 1) || (mode > POWER_MODES)) | ||
7961 | mode = IPW_POWER_AUTO; | ||
7962 | |||
7963 | if (priv->power_mode != mode) | ||
7964 | err = ipw2100_set_power_mode(priv, mode); | ||
7965 | done: | ||
7966 | up(&priv->action_sem); | ||
7967 | return err; | ||
7968 | } | ||
7969 | |||
7970 | #define MAX_POWER_STRING 80 | ||
7971 | static int ipw2100_wx_get_powermode(struct net_device *dev, | ||
7972 | struct iw_request_info *info, | ||
7973 | union iwreq_data *wrqu, char *extra) | ||
7974 | { | ||
7975 | /* | ||
7976 | * This can be called at any time. No action lock required | ||
7977 | */ | ||
7978 | |||
7979 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
7980 | int level = IPW_POWER_LEVEL(priv->power_mode); | ||
7981 | s32 timeout, period; | ||
7982 | |||
7983 | if (!(priv->power_mode & IPW_POWER_ENABLED)) { | ||
7984 | snprintf(extra, MAX_POWER_STRING, | ||
7985 | "Power save level: %d (Off)", level); | ||
7986 | } else { | ||
7987 | switch (level) { | ||
7988 | case IPW_POWER_MODE_CAM: | ||
7989 | snprintf(extra, MAX_POWER_STRING, | ||
7990 | "Power save level: %d (None)", level); | ||
7991 | break; | ||
7992 | case IPW_POWER_AUTO: | ||
7993 | snprintf(extra, MAX_POWER_STRING, | ||
7994 | "Power save level: %d (Auto)", 0); | ||
7995 | break; | ||
7996 | default: | ||
7997 | timeout = timeout_duration[level - 1] / 1000; | ||
7998 | period = period_duration[level - 1] / 1000; | ||
7999 | snprintf(extra, MAX_POWER_STRING, | ||
8000 | "Power save level: %d " | ||
8001 | "(Timeout %dms, Period %dms)", | ||
8002 | level, timeout, period); | ||
8003 | } | ||
8004 | } | ||
8005 | |||
8006 | wrqu->data.length = strlen(extra) + 1; | ||
8007 | |||
8008 | return 0; | ||
8009 | } | ||
8010 | |||
8011 | |||
8012 | static int ipw2100_wx_set_preamble(struct net_device *dev, | ||
8013 | struct iw_request_info *info, | ||
8014 | union iwreq_data *wrqu, char *extra) | ||
8015 | { | ||
8016 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
8017 | int err, mode = *(int *)extra; | ||
8018 | |||
8019 | down(&priv->action_sem); | ||
8020 | if (!(priv->status & STATUS_INITIALIZED)) { | ||
8021 | err = -EIO; | ||
8022 | goto done; | ||
8023 | } | ||
8024 | |||
8025 | if (mode == 1) | ||
8026 | priv->config |= CFG_LONG_PREAMBLE; | ||
8027 | else if (mode == 0) | ||
8028 | priv->config &= ~CFG_LONG_PREAMBLE; | ||
8029 | else { | ||
8030 | err = -EINVAL; | ||
8031 | goto done; | ||
8032 | } | ||
8033 | |||
8034 | err = ipw2100_system_config(priv, 0); | ||
8035 | |||
8036 | done: | ||
8037 | up(&priv->action_sem); | ||
8038 | return err; | ||
8039 | } | ||
8040 | |||
8041 | static int ipw2100_wx_get_preamble(struct net_device *dev, | ||
8042 | struct iw_request_info *info, | ||
8043 | union iwreq_data *wrqu, char *extra) | ||
8044 | { | ||
8045 | /* | ||
8046 | * This can be called at any time. No action lock required | ||
8047 | */ | ||
8048 | |||
8049 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
8050 | |||
8051 | if (priv->config & CFG_LONG_PREAMBLE) | ||
8052 | snprintf(wrqu->name, IFNAMSIZ, "long (1)"); | ||
8053 | else | ||
8054 | snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); | ||
8055 | |||
8056 | return 0; | ||
8057 | } | ||
8058 | |||
8059 | static iw_handler ipw2100_wx_handlers[] = | ||
8060 | { | ||
8061 | NULL, /* SIOCSIWCOMMIT */ | ||
8062 | ipw2100_wx_get_name, /* SIOCGIWNAME */ | ||
8063 | NULL, /* SIOCSIWNWID */ | ||
8064 | NULL, /* SIOCGIWNWID */ | ||
8065 | ipw2100_wx_set_freq, /* SIOCSIWFREQ */ | ||
8066 | ipw2100_wx_get_freq, /* SIOCGIWFREQ */ | ||
8067 | ipw2100_wx_set_mode, /* SIOCSIWMODE */ | ||
8068 | ipw2100_wx_get_mode, /* SIOCGIWMODE */ | ||
8069 | NULL, /* SIOCSIWSENS */ | ||
8070 | NULL, /* SIOCGIWSENS */ | ||
8071 | NULL, /* SIOCSIWRANGE */ | ||
8072 | ipw2100_wx_get_range, /* SIOCGIWRANGE */ | ||
8073 | NULL, /* SIOCSIWPRIV */ | ||
8074 | NULL, /* SIOCGIWPRIV */ | ||
8075 | NULL, /* SIOCSIWSTATS */ | ||
8076 | NULL, /* SIOCGIWSTATS */ | ||
8077 | NULL, /* SIOCSIWSPY */ | ||
8078 | NULL, /* SIOCGIWSPY */ | ||
8079 | NULL, /* SIOCGIWTHRSPY */ | ||
8080 | NULL, /* SIOCWIWTHRSPY */ | ||
8081 | ipw2100_wx_set_wap, /* SIOCSIWAP */ | ||
8082 | ipw2100_wx_get_wap, /* SIOCGIWAP */ | ||
8083 | NULL, /* -- hole -- */ | ||
8084 | NULL, /* SIOCGIWAPLIST -- deprecated */ | ||
8085 | ipw2100_wx_set_scan, /* SIOCSIWSCAN */ | ||
8086 | ipw2100_wx_get_scan, /* SIOCGIWSCAN */ | ||
8087 | ipw2100_wx_set_essid, /* SIOCSIWESSID */ | ||
8088 | ipw2100_wx_get_essid, /* SIOCGIWESSID */ | ||
8089 | ipw2100_wx_set_nick, /* SIOCSIWNICKN */ | ||
8090 | ipw2100_wx_get_nick, /* SIOCGIWNICKN */ | ||
8091 | NULL, /* -- hole -- */ | ||
8092 | NULL, /* -- hole -- */ | ||
8093 | ipw2100_wx_set_rate, /* SIOCSIWRATE */ | ||
8094 | ipw2100_wx_get_rate, /* SIOCGIWRATE */ | ||
8095 | ipw2100_wx_set_rts, /* SIOCSIWRTS */ | ||
8096 | ipw2100_wx_get_rts, /* SIOCGIWRTS */ | ||
8097 | ipw2100_wx_set_frag, /* SIOCSIWFRAG */ | ||
8098 | ipw2100_wx_get_frag, /* SIOCGIWFRAG */ | ||
8099 | ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */ | ||
8100 | ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */ | ||
8101 | ipw2100_wx_set_retry, /* SIOCSIWRETRY */ | ||
8102 | ipw2100_wx_get_retry, /* SIOCGIWRETRY */ | ||
8103 | ipw2100_wx_set_encode, /* SIOCSIWENCODE */ | ||
8104 | ipw2100_wx_get_encode, /* SIOCGIWENCODE */ | ||
8105 | ipw2100_wx_set_power, /* SIOCSIWPOWER */ | ||
8106 | ipw2100_wx_get_power, /* SIOCGIWPOWER */ | ||
8107 | }; | ||
8108 | |||
8109 | #define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV | ||
8110 | #define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1 | ||
8111 | #define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2 | ||
8112 | #define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3 | ||
8113 | #define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4 | ||
8114 | #define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5 | ||
8115 | |||
8116 | static const struct iw_priv_args ipw2100_private_args[] = { | ||
8117 | |||
8118 | #ifdef CONFIG_IPW2100_MONITOR | ||
8119 | { | ||
8120 | IPW2100_PRIV_SET_MONITOR, | ||
8121 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor" | ||
8122 | }, | ||
8123 | { | ||
8124 | IPW2100_PRIV_RESET, | ||
8125 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset" | ||
8126 | }, | ||
8127 | #endif /* CONFIG_IPW2100_MONITOR */ | ||
8128 | |||
8129 | { | ||
8130 | IPW2100_PRIV_SET_POWER, | ||
8131 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power" | ||
8132 | }, | ||
8133 | { | ||
8134 | IPW2100_PRIV_GET_POWER, | ||
8135 | 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power" | ||
8136 | }, | ||
8137 | { | ||
8138 | IPW2100_PRIV_SET_LONGPREAMBLE, | ||
8139 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble" | ||
8140 | }, | ||
8141 | { | ||
8142 | IPW2100_PRIV_GET_LONGPREAMBLE, | ||
8143 | 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble" | ||
8144 | }, | ||
8145 | }; | ||
8146 | |||
8147 | static iw_handler ipw2100_private_handler[] = { | ||
8148 | #ifdef CONFIG_IPW2100_MONITOR | ||
8149 | ipw2100_wx_set_promisc, | ||
8150 | ipw2100_wx_reset, | ||
8151 | #else /* CONFIG_IPW2100_MONITOR */ | ||
8152 | NULL, | ||
8153 | NULL, | ||
8154 | #endif /* CONFIG_IPW2100_MONITOR */ | ||
8155 | ipw2100_wx_set_powermode, | ||
8156 | ipw2100_wx_get_powermode, | ||
8157 | ipw2100_wx_set_preamble, | ||
8158 | ipw2100_wx_get_preamble, | ||
8159 | }; | ||
8160 | |||
8161 | static struct iw_handler_def ipw2100_wx_handler_def = | ||
8162 | { | ||
8163 | .standard = ipw2100_wx_handlers, | ||
8164 | .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler), | ||
8165 | .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler), | ||
8166 | .num_private_args = sizeof(ipw2100_private_args) / | ||
8167 | sizeof(struct iw_priv_args), | ||
8168 | .private = (iw_handler *)ipw2100_private_handler, | ||
8169 | .private_args = (struct iw_priv_args *)ipw2100_private_args, | ||
8170 | }; | ||
8171 | |||
8172 | /* | ||
8173 | * Get wireless statistics. | ||
8174 | * Called by /proc/net/wireless | ||
8175 | * Also called by SIOCGIWSTATS | ||
8176 | */ | ||
8177 | static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) | ||
8178 | { | ||
8179 | enum { | ||
8180 | POOR = 30, | ||
8181 | FAIR = 60, | ||
8182 | GOOD = 80, | ||
8183 | VERY_GOOD = 90, | ||
8184 | EXCELLENT = 95, | ||
8185 | PERFECT = 100 | ||
8186 | }; | ||
8187 | int rssi_qual; | ||
8188 | int tx_qual; | ||
8189 | int beacon_qual; | ||
8190 | |||
8191 | struct ipw2100_priv *priv = ieee80211_priv(dev); | ||
8192 | struct iw_statistics *wstats; | ||
8193 | u32 rssi, quality, tx_retries, missed_beacons, tx_failures; | ||
8194 | u32 ord_len = sizeof(u32); | ||
8195 | |||
8196 | if (!priv) | ||
8197 | return (struct iw_statistics *) NULL; | ||
8198 | |||
8199 | wstats = &priv->wstats; | ||
8200 | |||
8201 | /* if hw is disabled, then ipw2100_get_ordinal() can't be called. | ||
8202 | * ipw2100_wx_wireless_stats seems to be called before fw is | ||
8203 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up | ||
8204 | * and associated; if not associcated, the values are all meaningless | ||
8205 | * anyway, so set them all to NULL and INVALID */ | ||
8206 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
8207 | wstats->miss.beacon = 0; | ||
8208 | wstats->discard.retries = 0; | ||
8209 | wstats->qual.qual = 0; | ||
8210 | wstats->qual.level = 0; | ||
8211 | wstats->qual.noise = 0; | ||
8212 | wstats->qual.updated = 7; | ||
8213 | wstats->qual.updated |= IW_QUAL_NOISE_INVALID | | ||
8214 | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; | ||
8215 | return wstats; | ||
8216 | } | ||
8217 | |||
8218 | if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS, | ||
8219 | &missed_beacons, &ord_len)) | ||
8220 | goto fail_get_ordinal; | ||
8221 | |||
8222 | /* If we don't have a connection the quality and level is 0*/ | ||
8223 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
8224 | wstats->qual.qual = 0; | ||
8225 | wstats->qual.level = 0; | ||
8226 | } else { | ||
8227 | if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR, | ||
8228 | &rssi, &ord_len)) | ||
8229 | goto fail_get_ordinal; | ||
8230 | wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; | ||
8231 | if (rssi < 10) | ||
8232 | rssi_qual = rssi * POOR / 10; | ||
8233 | else if (rssi < 15) | ||
8234 | rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR; | ||
8235 | else if (rssi < 20) | ||
8236 | rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR; | ||
8237 | else if (rssi < 30) | ||
8238 | rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) / | ||
8239 | 10 + GOOD; | ||
8240 | else | ||
8241 | rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) / | ||
8242 | 10 + VERY_GOOD; | ||
8243 | |||
8244 | if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES, | ||
8245 | &tx_retries, &ord_len)) | ||
8246 | goto fail_get_ordinal; | ||
8247 | |||
8248 | if (tx_retries > 75) | ||
8249 | tx_qual = (90 - tx_retries) * POOR / 15; | ||
8250 | else if (tx_retries > 70) | ||
8251 | tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; | ||
8252 | else if (tx_retries > 65) | ||
8253 | tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; | ||
8254 | else if (tx_retries > 50) | ||
8255 | tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / | ||
8256 | 15 + GOOD; | ||
8257 | else | ||
8258 | tx_qual = (50 - tx_retries) * | ||
8259 | (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; | ||
8260 | |||
8261 | if (missed_beacons > 50) | ||
8262 | beacon_qual = (60 - missed_beacons) * POOR / 10; | ||
8263 | else if (missed_beacons > 40) | ||
8264 | beacon_qual = (50 - missed_beacons) * (FAIR - POOR) / | ||
8265 | 10 + POOR; | ||
8266 | else if (missed_beacons > 32) | ||
8267 | beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) / | ||
8268 | 18 + FAIR; | ||
8269 | else if (missed_beacons > 20) | ||
8270 | beacon_qual = (32 - missed_beacons) * | ||
8271 | (VERY_GOOD - GOOD) / 20 + GOOD; | ||
8272 | else | ||
8273 | beacon_qual = (20 - missed_beacons) * | ||
8274 | (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; | ||
8275 | |||
8276 | quality = min(beacon_qual, min(tx_qual, rssi_qual)); | ||
8277 | |||
8278 | #ifdef CONFIG_IPW_DEBUG | ||
8279 | if (beacon_qual == quality) | ||
8280 | IPW_DEBUG_WX("Quality clamped by Missed Beacons\n"); | ||
8281 | else if (tx_qual == quality) | ||
8282 | IPW_DEBUG_WX("Quality clamped by Tx Retries\n"); | ||
8283 | else if (quality != 100) | ||
8284 | IPW_DEBUG_WX("Quality clamped by Signal Strength\n"); | ||
8285 | else | ||
8286 | IPW_DEBUG_WX("Quality not clamped.\n"); | ||
8287 | #endif | ||
8288 | |||
8289 | wstats->qual.qual = quality; | ||
8290 | wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; | ||
8291 | } | ||
8292 | |||
8293 | wstats->qual.noise = 0; | ||
8294 | wstats->qual.updated = 7; | ||
8295 | wstats->qual.updated |= IW_QUAL_NOISE_INVALID; | ||
8296 | |||
8297 | /* FIXME: this is percent and not a # */ | ||
8298 | wstats->miss.beacon = missed_beacons; | ||
8299 | |||
8300 | if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES, | ||
8301 | &tx_failures, &ord_len)) | ||
8302 | goto fail_get_ordinal; | ||
8303 | wstats->discard.retries = tx_failures; | ||
8304 | |||
8305 | return wstats; | ||
8306 | |||
8307 | fail_get_ordinal: | ||
8308 | IPW_DEBUG_WX("failed querying ordinals.\n"); | ||
8309 | |||
8310 | return (struct iw_statistics *) NULL; | ||
8311 | } | ||
8312 | |||
8313 | static void ipw2100_wx_event_work(struct ipw2100_priv *priv) | ||
8314 | { | ||
8315 | union iwreq_data wrqu; | ||
8316 | int len = ETH_ALEN; | ||
8317 | |||
8318 | if (priv->status & STATUS_STOPPING) | ||
8319 | return; | ||
8320 | |||
8321 | down(&priv->action_sem); | ||
8322 | |||
8323 | IPW_DEBUG_WX("enter\n"); | ||
8324 | |||
8325 | up(&priv->action_sem); | ||
8326 | |||
8327 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
8328 | |||
8329 | /* Fetch BSSID from the hardware */ | ||
8330 | if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) || | ||
8331 | priv->status & STATUS_RF_KILL_MASK || | ||
8332 | ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, | ||
8333 | &priv->bssid, &len)) { | ||
8334 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
8335 | } else { | ||
8336 | /* We now have the BSSID, so can finish setting to the full | ||
8337 | * associated state */ | ||
8338 | memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); | ||
8339 | memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN); | ||
8340 | priv->status &= ~STATUS_ASSOCIATING; | ||
8341 | priv->status |= STATUS_ASSOCIATED; | ||
8342 | netif_carrier_on(priv->net_dev); | ||
8343 | if (netif_queue_stopped(priv->net_dev)) { | ||
8344 | IPW_DEBUG_INFO("Waking net queue.\n"); | ||
8345 | netif_wake_queue(priv->net_dev); | ||
8346 | } else { | ||
8347 | IPW_DEBUG_INFO("Starting net queue.\n"); | ||
8348 | netif_start_queue(priv->net_dev); | ||
8349 | } | ||
8350 | } | ||
8351 | |||
8352 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
8353 | IPW_DEBUG_WX("Configuring ESSID\n"); | ||
8354 | down(&priv->action_sem); | ||
8355 | /* This is a disassociation event, so kick the firmware to | ||
8356 | * look for another AP */ | ||
8357 | if (priv->config & CFG_STATIC_ESSID) | ||
8358 | ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0); | ||
8359 | else | ||
8360 | ipw2100_set_essid(priv, NULL, 0, 0); | ||
8361 | up(&priv->action_sem); | ||
8362 | } | ||
8363 | |||
8364 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
8365 | } | ||
8366 | |||
8367 | #define IPW2100_FW_MAJOR_VERSION 1 | ||
8368 | #define IPW2100_FW_MINOR_VERSION 3 | ||
8369 | |||
8370 | #define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8) | ||
8371 | #define IPW2100_FW_MAJOR(x) (x & 0xff) | ||
8372 | |||
8373 | #define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \ | ||
8374 | IPW2100_FW_MAJOR_VERSION) | ||
8375 | |||
8376 | #define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \ | ||
8377 | "." __stringify(IPW2100_FW_MINOR_VERSION) | ||
8378 | |||
8379 | #define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw" | ||
8380 | |||
8381 | |||
8382 | /* | ||
8383 | |||
8384 | BINARY FIRMWARE HEADER FORMAT | ||
8385 | |||
8386 | offset length desc | ||
8387 | 0 2 version | ||
8388 | 2 2 mode == 0:BSS,1:IBSS,2:MONITOR | ||
8389 | 4 4 fw_len | ||
8390 | 8 4 uc_len | ||
8391 | C fw_len firmware data | ||
8392 | 12 + fw_len uc_len microcode data | ||
8393 | |||
8394 | */ | ||
8395 | |||
8396 | struct ipw2100_fw_header { | ||
8397 | short version; | ||
8398 | short mode; | ||
8399 | unsigned int fw_size; | ||
8400 | unsigned int uc_size; | ||
8401 | } __attribute__ ((packed)); | ||
8402 | |||
8403 | |||
8404 | |||
8405 | static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) | ||
8406 | { | ||
8407 | struct ipw2100_fw_header *h = | ||
8408 | (struct ipw2100_fw_header *)fw->fw_entry->data; | ||
8409 | |||
8410 | if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { | ||
8411 | printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " | ||
8412 | "(detected version id of %u). " | ||
8413 | "See Documentation/networking/README.ipw2100\n", | ||
8414 | h->version); | ||
8415 | return 1; | ||
8416 | } | ||
8417 | |||
8418 | fw->version = h->version; | ||
8419 | fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header); | ||
8420 | fw->fw.size = h->fw_size; | ||
8421 | fw->uc.data = fw->fw.data + h->fw_size; | ||
8422 | fw->uc.size = h->uc_size; | ||
8423 | |||
8424 | return 0; | ||
8425 | } | ||
8426 | |||
8427 | |||
8428 | static int ipw2100_get_firmware(struct ipw2100_priv *priv, | ||
8429 | struct ipw2100_fw *fw) | ||
8430 | { | ||
8431 | char *fw_name; | ||
8432 | int rc; | ||
8433 | |||
8434 | IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n", | ||
8435 | priv->net_dev->name); | ||
8436 | |||
8437 | switch (priv->ieee->iw_mode) { | ||
8438 | case IW_MODE_ADHOC: | ||
8439 | fw_name = IPW2100_FW_NAME("-i"); | ||
8440 | break; | ||
8441 | #ifdef CONFIG_IPW2100_MONITOR | ||
8442 | case IW_MODE_MONITOR: | ||
8443 | fw_name = IPW2100_FW_NAME("-p"); | ||
8444 | break; | ||
8445 | #endif | ||
8446 | case IW_MODE_INFRA: | ||
8447 | default: | ||
8448 | fw_name = IPW2100_FW_NAME(""); | ||
8449 | break; | ||
8450 | } | ||
8451 | |||
8452 | rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev); | ||
8453 | |||
8454 | if (rc < 0) { | ||
8455 | printk(KERN_ERR DRV_NAME ": " | ||
8456 | "%s: Firmware '%s' not available or load failed.\n", | ||
8457 | priv->net_dev->name, fw_name); | ||
8458 | return rc; | ||
8459 | } | ||
8460 | IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data, | ||
8461 | fw->fw_entry->size); | ||
8462 | |||
8463 | ipw2100_mod_firmware_load(fw); | ||
8464 | |||
8465 | return 0; | ||
8466 | } | ||
8467 | |||
8468 | static void ipw2100_release_firmware(struct ipw2100_priv *priv, | ||
8469 | struct ipw2100_fw *fw) | ||
8470 | { | ||
8471 | fw->version = 0; | ||
8472 | if (fw->fw_entry) | ||
8473 | release_firmware(fw->fw_entry); | ||
8474 | fw->fw_entry = NULL; | ||
8475 | } | ||
8476 | |||
8477 | |||
8478 | static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, | ||
8479 | size_t max) | ||
8480 | { | ||
8481 | char ver[MAX_FW_VERSION_LEN]; | ||
8482 | u32 len = MAX_FW_VERSION_LEN; | ||
8483 | u32 tmp; | ||
8484 | int i; | ||
8485 | /* firmware version is an ascii string (max len of 14) */ | ||
8486 | if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, | ||
8487 | ver, &len)) | ||
8488 | return -EIO; | ||
8489 | tmp = max; | ||
8490 | if (len >= max) | ||
8491 | len = max - 1; | ||
8492 | for (i = 0; i < len; i++) | ||
8493 | buf[i] = ver[i]; | ||
8494 | buf[i] = '\0'; | ||
8495 | return tmp; | ||
8496 | } | ||
8497 | |||
8498 | static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, | ||
8499 | size_t max) | ||
8500 | { | ||
8501 | u32 ver; | ||
8502 | u32 len = sizeof(ver); | ||
8503 | /* microcode version is a 32 bit integer */ | ||
8504 | if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, | ||
8505 | &ver, &len)) | ||
8506 | return -EIO; | ||
8507 | return snprintf(buf, max, "%08X", ver); | ||
8508 | } | ||
8509 | |||
8510 | /* | ||
8511 | * On exit, the firmware will have been freed from the fw list | ||
8512 | */ | ||
8513 | static int ipw2100_fw_download(struct ipw2100_priv *priv, | ||
8514 | struct ipw2100_fw *fw) | ||
8515 | { | ||
8516 | /* firmware is constructed of N contiguous entries, each entry is | ||
8517 | * structured as: | ||
8518 | * | ||
8519 | * offset sie desc | ||
8520 | * 0 4 address to write to | ||
8521 | * 4 2 length of data run | ||
8522 | * 6 length data | ||
8523 | */ | ||
8524 | unsigned int addr; | ||
8525 | unsigned short len; | ||
8526 | |||
8527 | const unsigned char *firmware_data = fw->fw.data; | ||
8528 | unsigned int firmware_data_left = fw->fw.size; | ||
8529 | |||
8530 | while (firmware_data_left > 0) { | ||
8531 | addr = *(u32 *)(firmware_data); | ||
8532 | firmware_data += 4; | ||
8533 | firmware_data_left -= 4; | ||
8534 | |||
8535 | len = *(u16 *)(firmware_data); | ||
8536 | firmware_data += 2; | ||
8537 | firmware_data_left -= 2; | ||
8538 | |||
8539 | if (len > 32) { | ||
8540 | printk(KERN_ERR DRV_NAME ": " | ||
8541 | "Invalid firmware run-length of %d bytes\n", | ||
8542 | len); | ||
8543 | return -EINVAL; | ||
8544 | } | ||
8545 | |||
8546 | write_nic_memory(priv->net_dev, addr, len, firmware_data); | ||
8547 | firmware_data += len; | ||
8548 | firmware_data_left -= len; | ||
8549 | } | ||
8550 | |||
8551 | return 0; | ||
8552 | } | ||
8553 | |||
8554 | struct symbol_alive_response { | ||
8555 | u8 cmd_id; | ||
8556 | u8 seq_num; | ||
8557 | u8 ucode_rev; | ||
8558 | u8 eeprom_valid; | ||
8559 | u16 valid_flags; | ||
8560 | u8 IEEE_addr[6]; | ||
8561 | u16 flags; | ||
8562 | u16 pcb_rev; | ||
8563 | u16 clock_settle_time; // 1us LSB | ||
8564 | u16 powerup_settle_time; // 1us LSB | ||
8565 | u16 hop_settle_time; // 1us LSB | ||
8566 | u8 date[3]; // month, day, year | ||
8567 | u8 time[2]; // hours, minutes | ||
8568 | u8 ucode_valid; | ||
8569 | }; | ||
8570 | |||
8571 | static int ipw2100_ucode_download(struct ipw2100_priv *priv, | ||
8572 | struct ipw2100_fw *fw) | ||
8573 | { | ||
8574 | struct net_device *dev = priv->net_dev; | ||
8575 | const unsigned char *microcode_data = fw->uc.data; | ||
8576 | unsigned int microcode_data_left = fw->uc.size; | ||
8577 | |||
8578 | struct symbol_alive_response response; | ||
8579 | int i, j; | ||
8580 | u8 data; | ||
8581 | |||
8582 | /* Symbol control */ | ||
8583 | write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); | ||
8584 | readl((void *)(dev->base_addr)); | ||
8585 | write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); | ||
8586 | readl((void *)(dev->base_addr)); | ||
8587 | |||
8588 | /* HW config */ | ||
8589 | write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ | ||
8590 | readl((void *)(dev->base_addr)); | ||
8591 | write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ | ||
8592 | readl((void *)(dev->base_addr)); | ||
8593 | |||
8594 | /* EN_CS_ACCESS bit to reset control store pointer */ | ||
8595 | write_nic_byte(dev, 0x210000, 0x40); | ||
8596 | readl((void *)(dev->base_addr)); | ||
8597 | write_nic_byte(dev, 0x210000, 0x0); | ||
8598 | readl((void *)(dev->base_addr)); | ||
8599 | write_nic_byte(dev, 0x210000, 0x40); | ||
8600 | readl((void *)(dev->base_addr)); | ||
8601 | |||
8602 | /* copy microcode from buffer into Symbol */ | ||
8603 | |||
8604 | while (microcode_data_left > 0) { | ||
8605 | write_nic_byte(dev, 0x210010, *microcode_data++); | ||
8606 | write_nic_byte(dev, 0x210010, *microcode_data++); | ||
8607 | microcode_data_left -= 2; | ||
8608 | } | ||
8609 | |||
8610 | /* EN_CS_ACCESS bit to reset the control store pointer */ | ||
8611 | write_nic_byte(dev, 0x210000, 0x0); | ||
8612 | readl((void *)(dev->base_addr)); | ||
8613 | |||
8614 | /* Enable System (Reg 0) | ||
8615 | * first enable causes garbage in RX FIFO */ | ||
8616 | write_nic_byte(dev, 0x210000, 0x0); | ||
8617 | readl((void *)(dev->base_addr)); | ||
8618 | write_nic_byte(dev, 0x210000, 0x80); | ||
8619 | readl((void *)(dev->base_addr)); | ||
8620 | |||
8621 | /* Reset External Baseband Reg */ | ||
8622 | write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); | ||
8623 | readl((void *)(dev->base_addr)); | ||
8624 | write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); | ||
8625 | readl((void *)(dev->base_addr)); | ||
8626 | |||
8627 | /* HW Config (Reg 5) */ | ||
8628 | write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 | ||
8629 | readl((void *)(dev->base_addr)); | ||
8630 | write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 | ||
8631 | readl((void *)(dev->base_addr)); | ||
8632 | |||
8633 | /* Enable System (Reg 0) | ||
8634 | * second enable should be OK */ | ||
8635 | write_nic_byte(dev, 0x210000, 0x00); // clear enable system | ||
8636 | readl((void *)(dev->base_addr)); | ||
8637 | write_nic_byte(dev, 0x210000, 0x80); // set enable system | ||
8638 | |||
8639 | /* check Symbol is enabled - upped this from 5 as it wasn't always | ||
8640 | * catching the update */ | ||
8641 | for (i = 0; i < 10; i++) { | ||
8642 | udelay(10); | ||
8643 | |||
8644 | /* check Dino is enabled bit */ | ||
8645 | read_nic_byte(dev, 0x210000, &data); | ||
8646 | if (data & 0x1) | ||
8647 | break; | ||
8648 | } | ||
8649 | |||
8650 | if (i == 10) { | ||
8651 | printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n", | ||
8652 | dev->name); | ||
8653 | return -EIO; | ||
8654 | } | ||
8655 | |||
8656 | /* Get Symbol alive response */ | ||
8657 | for (i = 0; i < 30; i++) { | ||
8658 | /* Read alive response structure */ | ||
8659 | for (j = 0; | ||
8660 | j < (sizeof(struct symbol_alive_response) >> 1); | ||
8661 | j++) | ||
8662 | read_nic_word(dev, 0x210004, | ||
8663 | ((u16 *)&response) + j); | ||
8664 | |||
8665 | if ((response.cmd_id == 1) && | ||
8666 | (response.ucode_valid == 0x1)) | ||
8667 | break; | ||
8668 | udelay(10); | ||
8669 | } | ||
8670 | |||
8671 | if (i == 30) { | ||
8672 | printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n", | ||
8673 | dev->name); | ||
8674 | printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response)); | ||
8675 | return -EIO; | ||
8676 | } | ||
8677 | |||
8678 | return 0; | ||
8679 | } | ||
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h new file mode 100644 index 000000000000..2a3cdbd50168 --- /dev/null +++ b/drivers/net/wireless/ipw2100.h | |||
@@ -0,0 +1,1167 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify it | ||
6 | under the terms of version 2 of the GNU General Public License as | ||
7 | published by the Free Software Foundation. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along with | ||
15 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
16 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | |||
18 | The full GNU General Public License is included in this distribution in the | ||
19 | file called LICENSE. | ||
20 | |||
21 | Contact Information: | ||
22 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
23 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | |||
25 | ******************************************************************************/ | ||
26 | #ifndef _IPW2100_H | ||
27 | #define _IPW2100_H | ||
28 | |||
29 | #include <linux/sched.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/netdevice.h> | ||
32 | #include <linux/etherdevice.h> | ||
33 | #include <linux/list.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | #include <asm/io.h> | ||
37 | #include <linux/socket.h> | ||
38 | #include <linux/if_arp.h> | ||
39 | #include <linux/wireless.h> | ||
40 | #include <linux/version.h> | ||
41 | #include <net/iw_handler.h> // new driver API | ||
42 | |||
43 | #include <net/ieee80211.h> | ||
44 | |||
45 | #include <linux/workqueue.h> | ||
46 | |||
47 | struct ipw2100_priv; | ||
48 | struct ipw2100_tx_packet; | ||
49 | struct ipw2100_rx_packet; | ||
50 | |||
51 | #define IPW_DL_UNINIT 0x80000000 | ||
52 | #define IPW_DL_NONE 0x00000000 | ||
53 | #define IPW_DL_ALL 0x7FFFFFFF | ||
54 | |||
55 | /* | ||
56 | * To use the debug system; | ||
57 | * | ||
58 | * If you are defining a new debug classification, simply add it to the #define | ||
59 | * list here in the form of: | ||
60 | * | ||
61 | * #define IPW_DL_xxxx VALUE | ||
62 | * | ||
63 | * shifting value to the left one bit from the previous entry. xxxx should be | ||
64 | * the name of the classification (for example, WEP) | ||
65 | * | ||
66 | * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your | ||
67 | * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want | ||
68 | * to send output to that classification. | ||
69 | * | ||
70 | * To add your debug level to the list of levels seen when you perform | ||
71 | * | ||
72 | * % cat /proc/net/ipw2100/debug_level | ||
73 | * | ||
74 | * you simply need to add your entry to the ipw2100_debug_levels array. | ||
75 | * | ||
76 | * If you do not see debug_level in /proc/net/ipw2100 then you do not have | ||
77 | * CONFIG_IPW_DEBUG defined in your kernel configuration | ||
78 | * | ||
79 | */ | ||
80 | |||
81 | #define IPW_DL_ERROR (1<<0) | ||
82 | #define IPW_DL_WARNING (1<<1) | ||
83 | #define IPW_DL_INFO (1<<2) | ||
84 | #define IPW_DL_WX (1<<3) | ||
85 | #define IPW_DL_HC (1<<5) | ||
86 | #define IPW_DL_STATE (1<<6) | ||
87 | |||
88 | #define IPW_DL_NOTIF (1<<10) | ||
89 | #define IPW_DL_SCAN (1<<11) | ||
90 | #define IPW_DL_ASSOC (1<<12) | ||
91 | #define IPW_DL_DROP (1<<13) | ||
92 | |||
93 | #define IPW_DL_IOCTL (1<<14) | ||
94 | #define IPW_DL_RF_KILL (1<<17) | ||
95 | |||
96 | |||
97 | #define IPW_DL_MANAGE (1<<15) | ||
98 | #define IPW_DL_FW (1<<16) | ||
99 | |||
100 | #define IPW_DL_FRAG (1<<21) | ||
101 | #define IPW_DL_WEP (1<<22) | ||
102 | #define IPW_DL_TX (1<<23) | ||
103 | #define IPW_DL_RX (1<<24) | ||
104 | #define IPW_DL_ISR (1<<25) | ||
105 | #define IPW_DL_IO (1<<26) | ||
106 | #define IPW_DL_TRACE (1<<28) | ||
107 | |||
108 | #define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) | ||
109 | #define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) | ||
110 | #define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f) | ||
111 | #define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f) | ||
112 | #define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f) | ||
113 | #define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f) | ||
114 | #define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f) | ||
115 | #define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f) | ||
116 | #define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f) | ||
117 | #define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f) | ||
118 | #define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f) | ||
119 | #define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f) | ||
120 | #define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f) | ||
121 | #define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f) | ||
122 | #define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f) | ||
123 | #define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f) | ||
124 | #define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f) | ||
125 | #define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f) | ||
126 | #define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f) | ||
127 | #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | ||
128 | #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | ||
129 | |||
130 | enum { | ||
131 | IPW_HW_STATE_DISABLED = 1, | ||
132 | IPW_HW_STATE_ENABLED = 0 | ||
133 | }; | ||
134 | |||
135 | struct ssid_context { | ||
136 | char ssid[IW_ESSID_MAX_SIZE + 1]; | ||
137 | int ssid_len; | ||
138 | unsigned char bssid[ETH_ALEN]; | ||
139 | int port_type; | ||
140 | int channel; | ||
141 | |||
142 | }; | ||
143 | |||
144 | extern const char *port_type_str[]; | ||
145 | extern const char *band_str[]; | ||
146 | |||
147 | #define NUMBER_OF_BD_PER_COMMAND_PACKET 1 | ||
148 | #define NUMBER_OF_BD_PER_DATA_PACKET 2 | ||
149 | |||
150 | #define IPW_MAX_BDS 6 | ||
151 | #define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2 | ||
152 | #define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1 | ||
153 | |||
154 | #define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \ | ||
155 | (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET) | ||
156 | |||
157 | struct bd_status { | ||
158 | union { | ||
159 | struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields; | ||
160 | u8 field; | ||
161 | } info; | ||
162 | } __attribute__ ((packed)); | ||
163 | |||
164 | struct ipw2100_bd { | ||
165 | u32 host_addr; | ||
166 | u32 buf_length; | ||
167 | struct bd_status status; | ||
168 | /* number of fragments for frame (should be set only for | ||
169 | * 1st TBD) */ | ||
170 | u8 num_fragments; | ||
171 | u8 reserved[6]; | ||
172 | } __attribute__ ((packed)); | ||
173 | |||
174 | #define IPW_BD_QUEUE_LENGTH(n) (1<<n) | ||
175 | #define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd)) | ||
176 | |||
177 | #define IPW_BD_STATUS_TX_FRAME_802_3 0x00 | ||
178 | #define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01 | ||
179 | #define IPW_BD_STATUS_TX_FRAME_COMMAND 0x02 | ||
180 | #define IPW_BD_STATUS_TX_FRAME_802_11 0x04 | ||
181 | #define IPW_BD_STATUS_TX_INTERRUPT_ENABLE 0x08 | ||
182 | |||
183 | struct ipw2100_bd_queue { | ||
184 | /* driver (virtual) pointer to queue */ | ||
185 | struct ipw2100_bd *drv; | ||
186 | |||
187 | /* firmware (physical) pointer to queue */ | ||
188 | dma_addr_t nic; | ||
189 | |||
190 | /* Length of phy memory allocated for BDs */ | ||
191 | u32 size; | ||
192 | |||
193 | /* Number of BDs in queue (and in array) */ | ||
194 | u32 entries; | ||
195 | |||
196 | /* Number of available BDs (invalid for NIC BDs) */ | ||
197 | u32 available; | ||
198 | |||
199 | /* Offset of oldest used BD in array (next one to | ||
200 | * check for completion) */ | ||
201 | u32 oldest; | ||
202 | |||
203 | /* Offset of next available (unused) BD */ | ||
204 | u32 next; | ||
205 | }; | ||
206 | |||
207 | #define RX_QUEUE_LENGTH 256 | ||
208 | #define TX_QUEUE_LENGTH 256 | ||
209 | #define HW_QUEUE_LENGTH 256 | ||
210 | |||
211 | #define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET) | ||
212 | |||
213 | #define STATUS_TYPE_MASK 0x0000000f | ||
214 | #define COMMAND_STATUS_VAL 0 | ||
215 | #define STATUS_CHANGE_VAL 1 | ||
216 | #define P80211_DATA_VAL 2 | ||
217 | #define P8023_DATA_VAL 3 | ||
218 | #define HOST_NOTIFICATION_VAL 4 | ||
219 | |||
220 | #define IPW2100_RSSI_TO_DBM (-98) | ||
221 | |||
222 | struct ipw2100_status { | ||
223 | u32 frame_size; | ||
224 | u16 status_fields; | ||
225 | u8 flags; | ||
226 | #define IPW_STATUS_FLAG_DECRYPTED (1<<0) | ||
227 | #define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1) | ||
228 | #define IPW_STATUS_FLAG_CRC_ERROR (1<<2) | ||
229 | u8 rssi; | ||
230 | } __attribute__ ((packed)); | ||
231 | |||
232 | struct ipw2100_status_queue { | ||
233 | /* driver (virtual) pointer to queue */ | ||
234 | struct ipw2100_status *drv; | ||
235 | |||
236 | /* firmware (physical) pointer to queue */ | ||
237 | dma_addr_t nic; | ||
238 | |||
239 | /* Length of phy memory allocated for BDs */ | ||
240 | u32 size; | ||
241 | }; | ||
242 | |||
243 | #define HOST_COMMAND_PARAMS_REG_LEN 100 | ||
244 | #define CMD_STATUS_PARAMS_REG_LEN 3 | ||
245 | |||
246 | #define IPW_WPA_CAPABILITIES 0x1 | ||
247 | #define IPW_WPA_LISTENINTERVAL 0x2 | ||
248 | #define IPW_WPA_AP_ADDRESS 0x4 | ||
249 | |||
250 | #define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32)) | ||
251 | |||
252 | struct ipw2100_wpa_assoc_frame { | ||
253 | u16 fixed_ie_mask; | ||
254 | struct { | ||
255 | u16 capab_info; | ||
256 | u16 listen_interval; | ||
257 | u8 current_ap[ETH_ALEN]; | ||
258 | } fixed_ies; | ||
259 | u32 var_ie_len; | ||
260 | u8 var_ie[IPW_MAX_VAR_IE_LEN]; | ||
261 | }; | ||
262 | |||
263 | #define IPW_BSS 1 | ||
264 | #define IPW_MONITOR 2 | ||
265 | #define IPW_IBSS 3 | ||
266 | |||
267 | /** | ||
268 | * @struct _tx_cmd - HWCommand | ||
269 | * @brief H/W command structure. | ||
270 | */ | ||
271 | struct ipw2100_cmd_header { | ||
272 | u32 host_command_reg; | ||
273 | u32 host_command_reg1; | ||
274 | u32 sequence; | ||
275 | u32 host_command_len_reg; | ||
276 | u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN]; | ||
277 | u32 cmd_status_reg; | ||
278 | u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN]; | ||
279 | u32 rxq_base_ptr; | ||
280 | u32 rxq_next_ptr; | ||
281 | u32 rxq_host_ptr; | ||
282 | u32 txq_base_ptr; | ||
283 | u32 txq_next_ptr; | ||
284 | u32 txq_host_ptr; | ||
285 | u32 tx_status_reg; | ||
286 | u32 reserved; | ||
287 | u32 status_change_reg; | ||
288 | u32 reserved1[3]; | ||
289 | u32 *ordinal1_ptr; | ||
290 | u32 *ordinal2_ptr; | ||
291 | } __attribute__ ((packed)); | ||
292 | |||
293 | struct ipw2100_data_header { | ||
294 | u32 host_command_reg; | ||
295 | u32 host_command_reg1; | ||
296 | u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver | ||
297 | u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC | ||
298 | u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key | ||
299 | u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV | ||
300 | u8 key[16]; | ||
301 | u8 reserved[10]; // f/w reserved | ||
302 | u8 src_addr[ETH_ALEN]; | ||
303 | u8 dst_addr[ETH_ALEN]; | ||
304 | u16 fragment_size; | ||
305 | } __attribute__ ((packed)); | ||
306 | |||
307 | /* Host command data structure */ | ||
308 | struct host_command { | ||
309 | u32 host_command; // COMMAND ID | ||
310 | u32 host_command1; // COMMAND ID | ||
311 | u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID) | ||
312 | u32 host_command_length; // LENGTH | ||
313 | u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS | ||
314 | } __attribute__ ((packed)); | ||
315 | |||
316 | |||
317 | typedef enum { | ||
318 | POWER_ON_RESET, | ||
319 | EXIT_POWER_DOWN_RESET, | ||
320 | SW_RESET, | ||
321 | EEPROM_RW, | ||
322 | SW_RE_INIT | ||
323 | } ipw2100_reset_event; | ||
324 | |||
325 | enum { | ||
326 | COMMAND = 0xCAFE, | ||
327 | DATA, | ||
328 | RX | ||
329 | }; | ||
330 | |||
331 | |||
332 | struct ipw2100_tx_packet { | ||
333 | int type; | ||
334 | int index; | ||
335 | union { | ||
336 | struct { /* COMMAND */ | ||
337 | struct ipw2100_cmd_header* cmd; | ||
338 | dma_addr_t cmd_phys; | ||
339 | } c_struct; | ||
340 | struct { /* DATA */ | ||
341 | struct ipw2100_data_header* data; | ||
342 | dma_addr_t data_phys; | ||
343 | struct ieee80211_txb *txb; | ||
344 | } d_struct; | ||
345 | } info; | ||
346 | int jiffy_start; | ||
347 | |||
348 | struct list_head list; | ||
349 | }; | ||
350 | |||
351 | |||
352 | struct ipw2100_rx_packet { | ||
353 | struct ipw2100_rx *rxp; | ||
354 | dma_addr_t dma_addr; | ||
355 | int jiffy_start; | ||
356 | struct sk_buff *skb; | ||
357 | struct list_head list; | ||
358 | }; | ||
359 | |||
360 | #define FRAG_DISABLED (1<<31) | ||
361 | #define RTS_DISABLED (1<<31) | ||
362 | #define MAX_RTS_THRESHOLD 2304U | ||
363 | #define MIN_RTS_THRESHOLD 1U | ||
364 | #define DEFAULT_RTS_THRESHOLD 1000U | ||
365 | |||
366 | #define DEFAULT_BEACON_INTERVAL 100U | ||
367 | #define DEFAULT_SHORT_RETRY_LIMIT 7U | ||
368 | #define DEFAULT_LONG_RETRY_LIMIT 4U | ||
369 | |||
370 | struct ipw2100_ordinals { | ||
371 | u32 table1_addr; | ||
372 | u32 table2_addr; | ||
373 | u32 table1_size; | ||
374 | u32 table2_size; | ||
375 | }; | ||
376 | |||
377 | /* Host Notification header */ | ||
378 | struct ipw2100_notification { | ||
379 | u32 hnhdr_subtype; /* type of host notification */ | ||
380 | u32 hnhdr_size; /* size in bytes of data | ||
381 | or number of entries, if table. | ||
382 | Does NOT include header */ | ||
383 | } __attribute__ ((packed)); | ||
384 | |||
385 | #define MAX_KEY_SIZE 16 | ||
386 | #define MAX_KEYS 8 | ||
387 | |||
388 | #define IPW2100_WEP_ENABLE (1<<1) | ||
389 | #define IPW2100_WEP_DROP_CLEAR (1<<2) | ||
390 | |||
391 | #define IPW_NONE_CIPHER (1<<0) | ||
392 | #define IPW_WEP40_CIPHER (1<<1) | ||
393 | #define IPW_TKIP_CIPHER (1<<2) | ||
394 | #define IPW_CCMP_CIPHER (1<<4) | ||
395 | #define IPW_WEP104_CIPHER (1<<5) | ||
396 | #define IPW_CKIP_CIPHER (1<<6) | ||
397 | |||
398 | #define IPW_AUTH_OPEN 0 | ||
399 | #define IPW_AUTH_SHARED 1 | ||
400 | |||
401 | struct statistic { | ||
402 | int value; | ||
403 | int hi; | ||
404 | int lo; | ||
405 | }; | ||
406 | |||
407 | #define INIT_STAT(x) do { \ | ||
408 | (x)->value = (x)->hi = 0; \ | ||
409 | (x)->lo = 0x7fffffff; \ | ||
410 | } while (0) | ||
411 | #define SET_STAT(x,y) do { \ | ||
412 | (x)->value = y; \ | ||
413 | if ((x)->value > (x)->hi) (x)->hi = (x)->value; \ | ||
414 | if ((x)->value < (x)->lo) (x)->lo = (x)->value; \ | ||
415 | } while (0) | ||
416 | #define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \ | ||
417 | while (0) | ||
418 | #define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \ | ||
419 | while (0) | ||
420 | |||
421 | #define IPW2100_ERROR_QUEUE 5 | ||
422 | |||
423 | /* Power management code: enable or disable? */ | ||
424 | enum { | ||
425 | #ifdef CONFIG_PM | ||
426 | IPW2100_PM_DISABLED = 0, | ||
427 | PM_STATE_SIZE = 16, | ||
428 | #else | ||
429 | IPW2100_PM_DISABLED = 1, | ||
430 | PM_STATE_SIZE = 0, | ||
431 | #endif | ||
432 | }; | ||
433 | |||
434 | #define STATUS_POWERED (1<<0) | ||
435 | #define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */ | ||
436 | #define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */ | ||
437 | #define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */ | ||
438 | #define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */ | ||
439 | #define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */ | ||
440 | #define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */ | ||
441 | #define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */ | ||
442 | #define STATUS_INT_ENABLED (1<<11) | ||
443 | #define STATUS_RF_KILL_HW (1<<12) | ||
444 | #define STATUS_RF_KILL_SW (1<<13) | ||
445 | #define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) | ||
446 | #define STATUS_EXIT_PENDING (1<<14) | ||
447 | |||
448 | #define STATUS_SCAN_PENDING (1<<23) | ||
449 | #define STATUS_SCANNING (1<<24) | ||
450 | #define STATUS_SCAN_ABORTING (1<<25) | ||
451 | #define STATUS_SCAN_COMPLETE (1<<26) | ||
452 | #define STATUS_WX_EVENT_PENDING (1<<27) | ||
453 | #define STATUS_RESET_PENDING (1<<29) | ||
454 | #define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */ | ||
455 | |||
456 | |||
457 | |||
458 | /* Internal NIC states */ | ||
459 | #define IPW_STATE_INITIALIZED (1<<0) | ||
460 | #define IPW_STATE_COUNTRY_FOUND (1<<1) | ||
461 | #define IPW_STATE_ASSOCIATED (1<<2) | ||
462 | #define IPW_STATE_ASSN_LOST (1<<3) | ||
463 | #define IPW_STATE_ASSN_CHANGED (1<<4) | ||
464 | #define IPW_STATE_SCAN_COMPLETE (1<<5) | ||
465 | #define IPW_STATE_ENTERED_PSP (1<<6) | ||
466 | #define IPW_STATE_LEFT_PSP (1<<7) | ||
467 | #define IPW_STATE_RF_KILL (1<<8) | ||
468 | #define IPW_STATE_DISABLED (1<<9) | ||
469 | #define IPW_STATE_POWER_DOWN (1<<10) | ||
470 | #define IPW_STATE_SCANNING (1<<11) | ||
471 | |||
472 | |||
473 | |||
474 | #define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ | ||
475 | #define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ | ||
476 | #define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ | ||
477 | #define CFG_CUSTOM_MAC (1<<3) | ||
478 | #define CFG_LONG_PREAMBLE (1<<4) | ||
479 | #define CFG_ASSOCIATE (1<<6) | ||
480 | #define CFG_FIXED_RATE (1<<7) | ||
481 | #define CFG_ADHOC_CREATE (1<<8) | ||
482 | #define CFG_C3_DISABLED (1<<9) | ||
483 | #define CFG_PASSIVE_SCAN (1<<10) | ||
484 | |||
485 | #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ | ||
486 | #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ | ||
487 | |||
488 | struct ipw2100_priv { | ||
489 | |||
490 | int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ | ||
491 | int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ | ||
492 | |||
493 | struct ieee80211_device *ieee; | ||
494 | unsigned long status; | ||
495 | unsigned long config; | ||
496 | unsigned long capability; | ||
497 | |||
498 | /* Statistics */ | ||
499 | int resets; | ||
500 | int reset_backoff; | ||
501 | |||
502 | /* Context */ | ||
503 | u8 essid[IW_ESSID_MAX_SIZE]; | ||
504 | u8 essid_len; | ||
505 | u8 bssid[ETH_ALEN]; | ||
506 | u8 channel; | ||
507 | int last_mode; | ||
508 | int cstate_limit; | ||
509 | |||
510 | unsigned long connect_start; | ||
511 | unsigned long last_reset; | ||
512 | |||
513 | u32 channel_mask; | ||
514 | u32 fatal_error; | ||
515 | u32 fatal_errors[IPW2100_ERROR_QUEUE]; | ||
516 | u32 fatal_index; | ||
517 | int eeprom_version; | ||
518 | int firmware_version; | ||
519 | unsigned long hw_features; | ||
520 | int hangs; | ||
521 | u32 last_rtc; | ||
522 | int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */ | ||
523 | u8* snapshot[0x30]; | ||
524 | |||
525 | u8 mandatory_bssid_mac[ETH_ALEN]; | ||
526 | u8 mac_addr[ETH_ALEN]; | ||
527 | |||
528 | int power_mode; | ||
529 | |||
530 | /* WEP data */ | ||
531 | struct ieee80211_security sec; | ||
532 | int messages_sent; | ||
533 | |||
534 | |||
535 | int short_retry_limit; | ||
536 | int long_retry_limit; | ||
537 | |||
538 | u32 rts_threshold; | ||
539 | u32 frag_threshold; | ||
540 | |||
541 | int in_isr; | ||
542 | |||
543 | u32 tx_rates; | ||
544 | int tx_power; | ||
545 | u32 beacon_interval; | ||
546 | |||
547 | char nick[IW_ESSID_MAX_SIZE + 1]; | ||
548 | |||
549 | struct ipw2100_status_queue status_queue; | ||
550 | |||
551 | struct statistic txq_stat; | ||
552 | struct statistic rxq_stat; | ||
553 | struct ipw2100_bd_queue rx_queue; | ||
554 | struct ipw2100_bd_queue tx_queue; | ||
555 | struct ipw2100_rx_packet *rx_buffers; | ||
556 | |||
557 | struct statistic fw_pend_stat; | ||
558 | struct list_head fw_pend_list; | ||
559 | |||
560 | struct statistic msg_free_stat; | ||
561 | struct statistic msg_pend_stat; | ||
562 | struct list_head msg_free_list; | ||
563 | struct list_head msg_pend_list; | ||
564 | struct ipw2100_tx_packet *msg_buffers; | ||
565 | |||
566 | struct statistic tx_free_stat; | ||
567 | struct statistic tx_pend_stat; | ||
568 | struct list_head tx_free_list; | ||
569 | struct list_head tx_pend_list; | ||
570 | struct ipw2100_tx_packet *tx_buffers; | ||
571 | |||
572 | struct ipw2100_ordinals ordinals; | ||
573 | |||
574 | struct pci_dev *pci_dev; | ||
575 | |||
576 | struct proc_dir_entry *dir_dev; | ||
577 | |||
578 | struct net_device *net_dev; | ||
579 | struct iw_statistics wstats; | ||
580 | |||
581 | struct tasklet_struct irq_tasklet; | ||
582 | |||
583 | struct workqueue_struct *workqueue; | ||
584 | struct work_struct reset_work; | ||
585 | struct work_struct security_work; | ||
586 | struct work_struct wx_event_work; | ||
587 | struct work_struct hang_check; | ||
588 | struct work_struct rf_kill; | ||
589 | |||
590 | u32 interrupts; | ||
591 | int tx_interrupts; | ||
592 | int rx_interrupts; | ||
593 | int inta_other; | ||
594 | |||
595 | spinlock_t low_lock; | ||
596 | struct semaphore action_sem; | ||
597 | struct semaphore adapter_sem; | ||
598 | |||
599 | wait_queue_head_t wait_command_queue; | ||
600 | }; | ||
601 | |||
602 | |||
603 | /********************************************************* | ||
604 | * Host Command -> From Driver to FW | ||
605 | *********************************************************/ | ||
606 | |||
607 | /** | ||
608 | * Host command identifiers | ||
609 | */ | ||
610 | #define HOST_COMPLETE 2 | ||
611 | #define SYSTEM_CONFIG 6 | ||
612 | #define SSID 8 | ||
613 | #define MANDATORY_BSSID 9 | ||
614 | #define AUTHENTICATION_TYPE 10 | ||
615 | #define ADAPTER_ADDRESS 11 | ||
616 | #define PORT_TYPE 12 | ||
617 | #define INTERNATIONAL_MODE 13 | ||
618 | #define CHANNEL 14 | ||
619 | #define RTS_THRESHOLD 15 | ||
620 | #define FRAG_THRESHOLD 16 | ||
621 | #define POWER_MODE 17 | ||
622 | #define TX_RATES 18 | ||
623 | #define BASIC_TX_RATES 19 | ||
624 | #define WEP_KEY_INFO 20 | ||
625 | #define WEP_KEY_INDEX 25 | ||
626 | #define WEP_FLAGS 26 | ||
627 | #define ADD_MULTICAST 27 | ||
628 | #define CLEAR_ALL_MULTICAST 28 | ||
629 | #define BEACON_INTERVAL 29 | ||
630 | #define ATIM_WINDOW 30 | ||
631 | #define CLEAR_STATISTICS 31 | ||
632 | #define SEND 33 | ||
633 | #define TX_POWER_INDEX 36 | ||
634 | #define BROADCAST_SCAN 43 | ||
635 | #define CARD_DISABLE 44 | ||
636 | #define PREFERRED_BSSID 45 | ||
637 | #define SET_SCAN_OPTIONS 46 | ||
638 | #define SCAN_DWELL_TIME 47 | ||
639 | #define SWEEP_TABLE 48 | ||
640 | #define AP_OR_STATION_TABLE 49 | ||
641 | #define GROUP_ORDINALS 50 | ||
642 | #define SHORT_RETRY_LIMIT 51 | ||
643 | #define LONG_RETRY_LIMIT 52 | ||
644 | |||
645 | #define HOST_PRE_POWER_DOWN 58 | ||
646 | #define CARD_DISABLE_PHY_OFF 61 | ||
647 | #define MSDU_TX_RATES 62 | ||
648 | |||
649 | |||
650 | /* Rogue AP Detection */ | ||
651 | #define SET_STATION_STAT_BITS 64 | ||
652 | #define CLEAR_STATIONS_STAT_BITS 65 | ||
653 | #define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP | ||
654 | #define SET_SECURITY_INFORMATION 67 | ||
655 | #define DISASSOCIATION_BSSID 68 | ||
656 | #define SET_WPA_IE 69 | ||
657 | |||
658 | |||
659 | |||
660 | /* system configuration bit mask: */ | ||
661 | #define IPW_CFG_MONITOR 0x00004 | ||
662 | #define IPW_CFG_PREAMBLE_AUTO 0x00010 | ||
663 | #define IPW_CFG_IBSS_AUTO_START 0x00020 | ||
664 | #define IPW_CFG_LOOPBACK 0x00100 | ||
665 | #define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800 | ||
666 | #define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000 | ||
667 | #define IPW_CFG_802_1x_ENABLE 0x04000 | ||
668 | #define IPW_CFG_BSS_MASK 0x08000 | ||
669 | #define IPW_CFG_IBSS_MASK 0x10000 | ||
670 | |||
671 | #define IPW_SCAN_NOASSOCIATE (1<<0) | ||
672 | #define IPW_SCAN_MIXED_CELL (1<<1) | ||
673 | /* RESERVED (1<<2) */ | ||
674 | #define IPW_SCAN_PASSIVE (1<<3) | ||
675 | |||
676 | #define IPW_NIC_FATAL_ERROR 0x2A7F0 | ||
677 | #define IPW_ERROR_ADDR(x) (x & 0x3FFFF) | ||
678 | #define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24) | ||
679 | #define IPW2100_ERR_C3_CORRUPTION (0x10 << 24) | ||
680 | #define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24) | ||
681 | #define IPW2100_ERR_FW_LOAD (0x12 << 24) | ||
682 | |||
683 | #define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200 | ||
684 | #define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80 | ||
685 | |||
686 | #define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40) | ||
687 | #define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44) | ||
688 | #define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48) | ||
689 | #define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0) | ||
690 | |||
691 | #define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00) | ||
692 | #define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04) | ||
693 | #define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80) | ||
694 | |||
695 | #define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \ | ||
696 | (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20) | ||
697 | |||
698 | #define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \ | ||
699 | (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND) | ||
700 | |||
701 | #define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180) | ||
702 | #define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184) | ||
703 | |||
704 | #define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB) | ||
705 | #define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1 | ||
706 | #define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2 | ||
707 | #define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3 | ||
708 | #define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4 | ||
709 | #define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5 | ||
710 | #define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16 | ||
711 | #define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24 | ||
712 | #define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25 | ||
713 | #define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30 | ||
714 | #define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB) | ||
715 | |||
716 | #define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001) | ||
717 | #define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002) | ||
718 | #define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004) | ||
719 | #define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008) | ||
720 | #define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080) | ||
721 | #define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100) | ||
722 | #define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200) | ||
723 | |||
724 | #define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB) | ||
725 | #define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1 | ||
726 | #define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2 | ||
727 | #define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10 | ||
728 | #define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9 | ||
729 | #define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10 | ||
730 | #define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29 | ||
731 | #define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30 | ||
732 | #define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB) | ||
733 | |||
734 | #define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C | ||
735 | #define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0 | ||
736 | #define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008 | ||
737 | #define IPW_BIT_GPIO_RF_KILL 0x00010000 | ||
738 | |||
739 | #define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1 | ||
740 | |||
741 | #define IPW_REG_DOMAIN_0_OFFSET 0x0000 | ||
742 | #define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND | ||
743 | |||
744 | #define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008 | ||
745 | #define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C | ||
746 | #define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010 | ||
747 | #define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014 | ||
748 | #define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018 | ||
749 | #define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C | ||
750 | #define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020 | ||
751 | #define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024 | ||
752 | #define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030 | ||
753 | #define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188 | ||
754 | #define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C | ||
755 | #define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 | ||
756 | |||
757 | #define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC | ||
758 | |||
759 | #define IPW_INTERRUPT_MASK 0xC1010013 | ||
760 | |||
761 | #define IPW2100_CONTROL_REG 0x220000 | ||
762 | #define IPW2100_CONTROL_PHY_OFF 0x8 | ||
763 | |||
764 | #define IPW2100_COMMAND 0x00300004 | ||
765 | #define IPW2100_COMMAND_PHY_ON 0x0 | ||
766 | #define IPW2100_COMMAND_PHY_OFF 0x1 | ||
767 | |||
768 | /* in DEBUG_AREA, values of memory always 0xd55555d5 */ | ||
769 | #define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090 | ||
770 | #define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF | ||
771 | #define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5 | ||
772 | |||
773 | #define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0 | ||
774 | |||
775 | #define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds | ||
776 | #define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds | ||
777 | #define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds | ||
778 | |||
779 | // BD ring queue read/write difference | ||
780 | #define IPW_BD_QUEUE_W_R_MIN_SPARE 2 | ||
781 | |||
782 | #define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80 | ||
783 | |||
784 | #define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli | ||
785 | #define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli | ||
786 | |||
787 | |||
788 | |||
789 | |||
790 | #define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) | ||
791 | #define IPW_MAX_80211_PAYLOAD_SIZE 2304U | ||
792 | #define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 | ||
793 | #define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536 | ||
794 | #define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60 | ||
795 | #define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \ | ||
796 | (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \ | ||
797 | sizeof(struct ethhdr)) | ||
798 | |||
799 | #define IPW_802_11_FCS_LENGTH 4 | ||
800 | #define IPW_RX_NIC_BUFFER_LENGTH \ | ||
801 | (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \ | ||
802 | IPW_802_11_FCS_LENGTH) | ||
803 | |||
804 | #define IPW_802_11_PAYLOAD_OFFSET \ | ||
805 | (sizeof(struct ieee80211_hdr_3addr) + \ | ||
806 | sizeof(struct ieee80211_snap_hdr)) | ||
807 | |||
808 | struct ipw2100_rx { | ||
809 | union { | ||
810 | unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; | ||
811 | struct ieee80211_hdr header; | ||
812 | u32 status; | ||
813 | struct ipw2100_notification notification; | ||
814 | struct ipw2100_cmd_header command; | ||
815 | } rx_data; | ||
816 | } __attribute__ ((packed)); | ||
817 | |||
818 | /* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */ | ||
819 | #define TX_RATE_1_MBIT 0x0001 | ||
820 | #define TX_RATE_2_MBIT 0x0002 | ||
821 | #define TX_RATE_5_5_MBIT 0x0004 | ||
822 | #define TX_RATE_11_MBIT 0x0008 | ||
823 | #define TX_RATE_MASK 0x000F | ||
824 | #define DEFAULT_TX_RATES 0x000F | ||
825 | |||
826 | #define IPW_POWER_MODE_CAM 0x00 //(always on) | ||
827 | #define IPW_POWER_INDEX_1 0x01 | ||
828 | #define IPW_POWER_INDEX_2 0x02 | ||
829 | #define IPW_POWER_INDEX_3 0x03 | ||
830 | #define IPW_POWER_INDEX_4 0x04 | ||
831 | #define IPW_POWER_INDEX_5 0x05 | ||
832 | #define IPW_POWER_AUTO 0x06 | ||
833 | #define IPW_POWER_MASK 0x0F | ||
834 | #define IPW_POWER_ENABLED 0x10 | ||
835 | #define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) | ||
836 | |||
837 | #define IPW_TX_POWER_AUTO 0 | ||
838 | #define IPW_TX_POWER_ENHANCED 1 | ||
839 | |||
840 | #define IPW_TX_POWER_DEFAULT 32 | ||
841 | #define IPW_TX_POWER_MIN 0 | ||
842 | #define IPW_TX_POWER_MAX 16 | ||
843 | #define IPW_TX_POWER_MIN_DBM (-12) | ||
844 | #define IPW_TX_POWER_MAX_DBM 16 | ||
845 | |||
846 | #define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan | ||
847 | #define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan | ||
848 | |||
849 | #define REG_MIN_CHANNEL 0 | ||
850 | #define REG_MAX_CHANNEL 14 | ||
851 | |||
852 | #define REG_CHANNEL_MASK 0x00003FFF | ||
853 | #define IPW_IBSS_11B_DEFAULT_MASK 0x87ff | ||
854 | |||
855 | #define DIVERSITY_EITHER 0 // Use both antennas | ||
856 | #define DIVERSITY_ANTENNA_A 1 // Use antenna A | ||
857 | #define DIVERSITY_ANTENNA_B 2 // Use antenna B | ||
858 | |||
859 | |||
860 | #define HOST_COMMAND_WAIT 0 | ||
861 | #define HOST_COMMAND_NO_WAIT 1 | ||
862 | |||
863 | #define LOCK_NONE 0 | ||
864 | #define LOCK_DRIVER 1 | ||
865 | #define LOCK_FW 2 | ||
866 | |||
867 | #define TYPE_SWEEP_ORD 0x000D | ||
868 | #define TYPE_IBSS_STTN_ORD 0x000E | ||
869 | #define TYPE_BSS_AP_ORD 0x000F | ||
870 | #define TYPE_RAW_BEACON_ENTRY 0x0010 | ||
871 | #define TYPE_CALIBRATION_DATA 0x0011 | ||
872 | #define TYPE_ROGUE_AP_DATA 0x0012 | ||
873 | #define TYPE_ASSOCIATION_REQUEST 0x0013 | ||
874 | #define TYPE_REASSOCIATION_REQUEST 0x0014 | ||
875 | |||
876 | |||
877 | #define HW_FEATURE_RFKILL (0x0001) | ||
878 | #define RF_KILLSWITCH_OFF (1) | ||
879 | #define RF_KILLSWITCH_ON (0) | ||
880 | |||
881 | #define IPW_COMMAND_POOL_SIZE 40 | ||
882 | |||
883 | #define IPW_START_ORD_TAB_1 1 | ||
884 | #define IPW_START_ORD_TAB_2 1000 | ||
885 | |||
886 | #define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32) | ||
887 | |||
888 | #define IS_ORDINAL_TABLE_ONE(mgr,id) \ | ||
889 | ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size)) | ||
890 | #define IS_ORDINAL_TABLE_TWO(mgr,id) \ | ||
891 | ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2))) | ||
892 | |||
893 | #define BSS_ID_LENGTH 6 | ||
894 | |||
895 | // Fixed size data: Ordinal Table 1 | ||
896 | typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW | ||
897 | // Transmit statistics | ||
898 | IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU) | ||
899 | IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU) | ||
900 | IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU) | ||
901 | |||
902 | IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB | ||
903 | IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB | ||
904 | IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB | ||
905 | IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB | ||
906 | IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB | ||
907 | |||
908 | IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB | ||
909 | IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB | ||
910 | IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB | ||
911 | IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB | ||
912 | |||
913 | IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's | ||
914 | IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS | ||
915 | IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS | ||
916 | IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK | ||
917 | IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's | ||
918 | IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's | ||
919 | IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's | ||
920 | IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's | ||
921 | IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted | ||
922 | IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted | ||
923 | IPW_ORD_STAT_TX_BEACON, // # of tx beacon | ||
924 | IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM | ||
925 | IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX | ||
926 | IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx | ||
927 | IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX | ||
928 | |||
929 | IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes | ||
930 | IPW_ORD_STAT_TX_RETRIES, // # of Tx retries | ||
931 | IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS | ||
932 | IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS | ||
933 | IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS | ||
934 | IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS | ||
935 | |||
936 | IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures | ||
937 | IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time | ||
938 | IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed | ||
939 | IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup | ||
940 | IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted | ||
941 | IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed | ||
942 | IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames | ||
943 | IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent | ||
944 | IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks | ||
945 | |||
946 | // Receive statistics | ||
947 | IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host | ||
948 | IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets | ||
949 | IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB | ||
950 | IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB | ||
951 | IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB | ||
952 | IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB | ||
953 | IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB | ||
954 | |||
955 | IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets | ||
956 | IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB | ||
957 | IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB | ||
958 | IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB | ||
959 | IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB | ||
960 | |||
961 | IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's | ||
962 | IPW_ORD_STAT_RX_POLL, //NS // # of poll rx | ||
963 | IPW_ORD_STAT_RX_RTS, // # of Rx RTS | ||
964 | IPW_ORD_STAT_RX_CTS, // # of Rx CTS | ||
965 | IPW_ORD_STAT_RX_ACK, // # of Rx ACK | ||
966 | IPW_ORD_STAT_RX_CFEND, // # of Rx CF End | ||
967 | IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack | ||
968 | IPW_ORD_STAT_RX_ASSN, // # of Association Rx's | ||
969 | IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's | ||
970 | IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's | ||
971 | IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's | ||
972 | IPW_ORD_STAT_RX_PROBE, // # of probe Rx's | ||
973 | IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's | ||
974 | IPW_ORD_STAT_RX_BEACON, // # of Rx beacon | ||
975 | IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM | ||
976 | IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx | ||
977 | IPW_ORD_STAT_RX_AUTH, // # of authentication Rx | ||
978 | IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx | ||
979 | |||
980 | IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received | ||
981 | IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error | ||
982 | IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB | ||
983 | IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB | ||
984 | IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB | ||
985 | IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB | ||
986 | |||
987 | IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB | ||
988 | IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB | ||
989 | IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB | ||
990 | IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB | ||
991 | IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets | ||
992 | |||
993 | IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db | ||
994 | IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db | ||
995 | IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db | ||
996 | IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol | ||
997 | IPW_ORD_SYS_BOOT_TIME, // # Boot time | ||
998 | IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer | ||
999 | IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late | ||
1000 | IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop | ||
1001 | IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment | ||
1002 | IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment | ||
1003 | IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame | ||
1004 | IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame | ||
1005 | IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused) | ||
1006 | IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption | ||
1007 | |||
1008 | // PSP Statistics | ||
1009 | IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended | ||
1010 | IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout | ||
1011 | IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts | ||
1012 | IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt | ||
1013 | IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received | ||
1014 | IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received | ||
1015 | IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID | ||
1016 | |||
1017 | // Association and roaming | ||
1018 | IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association | ||
1019 | IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons | ||
1020 | IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries | ||
1021 | IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated | ||
1022 | // AP table entry. set to 0 if not associated | ||
1023 | IPW_ORD_AVAILABLE_AP_CNT, // # of AP's decsribed in the AP table | ||
1024 | IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs | ||
1025 | IPW_ORD_STAT_AP_ASSNS, // # of associations | ||
1026 | IPW_ORD_STAT_ASSN_FAIL, // # of association failures | ||
1027 | IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail | ||
1028 | IPW_ORD_STAT_FULL_SCANS, // # of full scans | ||
1029 | |||
1030 | IPW_ORD_CARD_DISABLED, // # Card Disabled | ||
1031 | IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity | ||
1032 | IPW_FILLER_40, | ||
1033 | IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association | ||
1034 | IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N | ||
1035 | // hops or no prob_ responses in last 3 minutes | ||
1036 | IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality | ||
1037 | IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive | ||
1038 | // load at the AP | ||
1039 | IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below | ||
1040 | // eligible group | ||
1041 | IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling | ||
1042 | IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap | ||
1043 | IPW_FILLER_41, | ||
1044 | IPW_FILLER_42, | ||
1045 | IPW_FILLER_43, | ||
1046 | IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed | ||
1047 | IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed | ||
1048 | IPW_ORD_STATION_TABLE_CNT, // # of entries in association table | ||
1049 | |||
1050 | // Other statistics | ||
1051 | IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI | ||
1052 | IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word | ||
1053 | IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word | ||
1054 | IPW_ORD_SELF_TEST_STATUS, //NS // | ||
1055 | IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP | ||
1056 | IPW_ORD_POWER_MGMT_INDEX, //NS // | ||
1057 | IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon | ||
1058 | IPW_ORD_COUNTRY_CHANNELS, // channels suported by country | ||
1059 | // IPW_ORD_COUNTRY_CHANNELS: | ||
1060 | // For 11b the lower 2-byte are used for channels from 1-14 | ||
1061 | // and the higher 2-byte are not used. | ||
1062 | IPW_ORD_RESET_CNT, // # of adapter resets (warm) | ||
1063 | IPW_ORD_BEACON_INTERVAL, // Beacon interval | ||
1064 | |||
1065 | IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version | ||
1066 | IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled | ||
1067 | IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed) | ||
1068 | IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated | ||
1069 | IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs | ||
1070 | IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID | ||
1071 | |||
1072 | IPW_ORD_RTC_TIME = 190, // current RTC time | ||
1073 | IPW_ORD_PORT_TYPE, // operating mode | ||
1074 | IPW_ORD_CURRENT_TX_RATE, // current tx rate | ||
1075 | IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates | ||
1076 | IPW_ORD_ATIM_WINDOW, // current ATIM Window | ||
1077 | IPW_ORD_BASIC_RATES, // bitmap of basic tx rates | ||
1078 | IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates | ||
1079 | IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates | ||
1080 | IPW_ORD_CAPABILITIES, // Management frame capability field | ||
1081 | IPW_ORD_AUTH_TYPE, // Type of authentication | ||
1082 | IPW_ORD_RADIO_TYPE, // Adapter card platform type | ||
1083 | IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used | ||
1084 | IPW_ORD_INT_MODE, // International mode | ||
1085 | IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold | ||
1086 | IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM | ||
1087 | IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM | ||
1088 | IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 = | ||
1089 | IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set | ||
1090 | |||
1091 | IPW_ORD_MAC_VERSION = 209, // MAC Version | ||
1092 | IPW_ORD_MAC_REVISION, // MAC Revision | ||
1093 | IPW_ORD_RADIO_VERSION, // Radio Version | ||
1094 | IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP | ||
1095 | IPW_ORD_UCODE_VERSION, // Ucode Version | ||
1096 | IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State | ||
1097 | } ORDINALTABLE1; | ||
1098 | |||
1099 | // ordinal table 2 | ||
1100 | // Variable length data: | ||
1101 | #define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001 | ||
1102 | |||
1103 | typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW | ||
1104 | IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs | ||
1105 | IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address | ||
1106 | IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP | ||
1107 | IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP | ||
1108 | IPW_FILL_1, //NS // | ||
1109 | IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code | ||
1110 | IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String | ||
1111 | IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans) | ||
1112 | IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans) | ||
1113 | IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log | ||
1114 | IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log | ||
1115 | IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures | ||
1116 | IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011") | ||
1117 | IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002") | ||
1118 | IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP | ||
1119 | IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes: | ||
1120 | IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII | ||
1121 | IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date | ||
1122 | IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018, | ||
1123 | } ORDINALTABLE2; // NS - means Not Supported by FW | ||
1124 | |||
1125 | #define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018 | ||
1126 | |||
1127 | #ifndef WIRELESS_SPY | ||
1128 | #define WIRELESS_SPY // enable iwspy support | ||
1129 | #endif | ||
1130 | |||
1131 | #define IPW_HOST_FW_SHARED_AREA0 0x0002f200 | ||
1132 | #define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes | ||
1133 | |||
1134 | #define IPW_HOST_FW_SHARED_AREA1 0x0002f610 | ||
1135 | #define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes | ||
1136 | |||
1137 | #define IPW_HOST_FW_SHARED_AREA2 0x0002fa00 | ||
1138 | #define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes | ||
1139 | |||
1140 | #define IPW_HOST_FW_SHARED_AREA3 0x0002fc00 | ||
1141 | #define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes | ||
1142 | |||
1143 | #define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80 | ||
1144 | #define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes | ||
1145 | |||
1146 | struct ipw2100_fw_chunk { | ||
1147 | unsigned char *buf; | ||
1148 | long len; | ||
1149 | long pos; | ||
1150 | struct list_head list; | ||
1151 | }; | ||
1152 | |||
1153 | struct ipw2100_fw_chunk_set { | ||
1154 | const void *data; | ||
1155 | unsigned long size; | ||
1156 | }; | ||
1157 | |||
1158 | struct ipw2100_fw { | ||
1159 | int version; | ||
1160 | struct ipw2100_fw_chunk_set fw; | ||
1161 | struct ipw2100_fw_chunk_set uc; | ||
1162 | const struct firmware *fw_entry; | ||
1163 | }; | ||
1164 | |||
1165 | #define MAX_FW_VERSION_LEN 14 | ||
1166 | |||
1167 | #endif /* _IPW2100_H */ | ||
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c new file mode 100644 index 000000000000..6d0b6b1df4ca --- /dev/null +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -0,0 +1,7353 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. | ||
4 | |||
5 | 802.11 status code portion of this file from ethereal-0.10.6: | ||
6 | Copyright 2000, Axis Communications AB | ||
7 | Ethereal - Network traffic analyzer | ||
8 | By Gerald Combs <gerald@ethereal.com> | ||
9 | Copyright 1998 Gerald Combs | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify it | ||
12 | under the terms of version 2 of the GNU General Public License as | ||
13 | published by the Free Software Foundation. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License along with | ||
21 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
22 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | |||
24 | The full GNU General Public License is included in this distribution in the | ||
25 | file called LICENSE. | ||
26 | |||
27 | Contact Information: | ||
28 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
29 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | |||
31 | ******************************************************************************/ | ||
32 | |||
33 | #include "ipw2200.h" | ||
34 | |||
35 | #define IPW2200_VERSION "1.0.0" | ||
36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" | ||
37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" | ||
38 | #define DRV_VERSION IPW2200_VERSION | ||
39 | |||
40 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | ||
41 | MODULE_VERSION(DRV_VERSION); | ||
42 | MODULE_AUTHOR(DRV_COPYRIGHT); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | static int debug = 0; | ||
46 | static int channel = 0; | ||
47 | static char *ifname; | ||
48 | static int mode = 0; | ||
49 | |||
50 | static u32 ipw_debug_level; | ||
51 | static int associate = 1; | ||
52 | static int auto_create = 1; | ||
53 | static int disable = 0; | ||
54 | static const char ipw_modes[] = { | ||
55 | 'a', 'b', 'g', '?' | ||
56 | }; | ||
57 | |||
58 | static void ipw_rx(struct ipw_priv *priv); | ||
59 | static int ipw_queue_tx_reclaim(struct ipw_priv *priv, | ||
60 | struct clx2_tx_queue *txq, int qindex); | ||
61 | static int ipw_queue_reset(struct ipw_priv *priv); | ||
62 | |||
63 | static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, | ||
64 | int len, int sync); | ||
65 | |||
66 | static void ipw_tx_queue_free(struct ipw_priv *); | ||
67 | |||
68 | static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); | ||
69 | static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); | ||
70 | static void ipw_rx_queue_replenish(void *); | ||
71 | |||
72 | static int ipw_up(struct ipw_priv *); | ||
73 | static void ipw_down(struct ipw_priv *); | ||
74 | static int ipw_config(struct ipw_priv *); | ||
75 | static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); | ||
76 | |||
77 | static u8 band_b_active_channel[MAX_B_CHANNELS] = { | ||
78 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 | ||
79 | }; | ||
80 | static u8 band_a_active_channel[MAX_A_CHANNELS] = { | ||
81 | 36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0 | ||
82 | }; | ||
83 | |||
84 | static int is_valid_channel(int mode_mask, int channel) | ||
85 | { | ||
86 | int i; | ||
87 | |||
88 | if (!channel) | ||
89 | return 0; | ||
90 | |||
91 | if (mode_mask & IEEE_A) | ||
92 | for (i = 0; i < MAX_A_CHANNELS; i++) | ||
93 | if (band_a_active_channel[i] == channel) | ||
94 | return IEEE_A; | ||
95 | |||
96 | if (mode_mask & (IEEE_B | IEEE_G)) | ||
97 | for (i = 0; i < MAX_B_CHANNELS; i++) | ||
98 | if (band_b_active_channel[i] == channel) | ||
99 | return mode_mask & (IEEE_B | IEEE_G); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static char *snprint_line(char *buf, size_t count, | ||
105 | const u8 *data, u32 len, u32 ofs) | ||
106 | { | ||
107 | int out, i, j, l; | ||
108 | char c; | ||
109 | |||
110 | out = snprintf(buf, count, "%08X", ofs); | ||
111 | |||
112 | for (l = 0, i = 0; i < 2; i++) { | ||
113 | out += snprintf(buf + out, count - out, " "); | ||
114 | for (j = 0; j < 8 && l < len; j++, l++) | ||
115 | out += snprintf(buf + out, count - out, "%02X ", | ||
116 | data[(i * 8 + j)]); | ||
117 | for (; j < 8; j++) | ||
118 | out += snprintf(buf + out, count - out, " "); | ||
119 | } | ||
120 | |||
121 | out += snprintf(buf + out, count - out, " "); | ||
122 | for (l = 0, i = 0; i < 2; i++) { | ||
123 | out += snprintf(buf + out, count - out, " "); | ||
124 | for (j = 0; j < 8 && l < len; j++, l++) { | ||
125 | c = data[(i * 8 + j)]; | ||
126 | if (!isascii(c) || !isprint(c)) | ||
127 | c = '.'; | ||
128 | |||
129 | out += snprintf(buf + out, count - out, "%c", c); | ||
130 | } | ||
131 | |||
132 | for (; j < 8; j++) | ||
133 | out += snprintf(buf + out, count - out, " "); | ||
134 | } | ||
135 | |||
136 | return buf; | ||
137 | } | ||
138 | |||
139 | static void printk_buf(int level, const u8 *data, u32 len) | ||
140 | { | ||
141 | char line[81]; | ||
142 | u32 ofs = 0; | ||
143 | if (!(ipw_debug_level & level)) | ||
144 | return; | ||
145 | |||
146 | while (len) { | ||
147 | printk(KERN_DEBUG "%s\n", | ||
148 | snprint_line(line, sizeof(line), &data[ofs], | ||
149 | min(len, 16U), ofs)); | ||
150 | ofs += 16; | ||
151 | len -= min(len, 16U); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); | ||
156 | #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) | ||
157 | |||
158 | static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg); | ||
159 | #define ipw_read_reg8(a, b) _ipw_read_reg8(a, b) | ||
160 | |||
161 | static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value); | ||
162 | static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) | ||
163 | { | ||
164 | IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(b), (u32)(c)); | ||
165 | _ipw_write_reg8(a, b, c); | ||
166 | } | ||
167 | |||
168 | static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value); | ||
169 | static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) | ||
170 | { | ||
171 | IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(b), (u32)(c)); | ||
172 | _ipw_write_reg16(a, b, c); | ||
173 | } | ||
174 | |||
175 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value); | ||
176 | static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) | ||
177 | { | ||
178 | IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(b), (u32)(c)); | ||
179 | _ipw_write_reg32(a, b, c); | ||
180 | } | ||
181 | |||
182 | #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) | ||
183 | #define ipw_write8(ipw, ofs, val) \ | ||
184 | IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | ||
185 | _ipw_write8(ipw, ofs, val) | ||
186 | |||
187 | #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) | ||
188 | #define ipw_write16(ipw, ofs, val) \ | ||
189 | IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | ||
190 | _ipw_write16(ipw, ofs, val) | ||
191 | |||
192 | #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) | ||
193 | #define ipw_write32(ipw, ofs, val) \ | ||
194 | IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | ||
195 | _ipw_write32(ipw, ofs, val) | ||
196 | |||
197 | #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) | ||
198 | static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { | ||
199 | IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32)(ofs)); | ||
200 | return _ipw_read8(ipw, ofs); | ||
201 | } | ||
202 | #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) | ||
203 | |||
204 | #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) | ||
205 | static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { | ||
206 | IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32)(ofs)); | ||
207 | return _ipw_read16(ipw, ofs); | ||
208 | } | ||
209 | #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) | ||
210 | |||
211 | #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) | ||
212 | static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { | ||
213 | IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32)(ofs)); | ||
214 | return _ipw_read32(ipw, ofs); | ||
215 | } | ||
216 | #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) | ||
217 | |||
218 | static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); | ||
219 | #define ipw_read_indirect(a, b, c, d) \ | ||
220 | IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ | ||
221 | _ipw_read_indirect(a, b, c, d) | ||
222 | |||
223 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 *data, int num); | ||
224 | #define ipw_write_indirect(a, b, c, d) \ | ||
225 | IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ | ||
226 | _ipw_write_indirect(a, b, c, d) | ||
227 | |||
228 | /* indirect write s */ | ||
229 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, | ||
230 | u32 value) | ||
231 | { | ||
232 | IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", | ||
233 | priv, reg, value); | ||
234 | _ipw_write32(priv, CX2_INDIRECT_ADDR, reg); | ||
235 | _ipw_write32(priv, CX2_INDIRECT_DATA, value); | ||
236 | } | ||
237 | |||
238 | |||
239 | static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) | ||
240 | { | ||
241 | IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); | ||
242 | _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); | ||
243 | _ipw_write8(priv, CX2_INDIRECT_DATA, value); | ||
244 | IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n", | ||
245 | (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), | ||
246 | value); | ||
247 | } | ||
248 | |||
249 | static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, | ||
250 | u16 value) | ||
251 | { | ||
252 | IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); | ||
253 | _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); | ||
254 | _ipw_write16(priv, CX2_INDIRECT_DATA, value); | ||
255 | } | ||
256 | |||
257 | /* indirect read s */ | ||
258 | |||
259 | static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) | ||
260 | { | ||
261 | u32 word; | ||
262 | _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); | ||
263 | IPW_DEBUG_IO(" reg = 0x%8X : \n", reg); | ||
264 | word = _ipw_read32(priv, CX2_INDIRECT_DATA); | ||
265 | return (word >> ((reg & 0x3)*8)) & 0xff; | ||
266 | } | ||
267 | |||
268 | static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) | ||
269 | { | ||
270 | u32 value; | ||
271 | |||
272 | IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg); | ||
273 | |||
274 | _ipw_write32(priv, CX2_INDIRECT_ADDR, reg); | ||
275 | value = _ipw_read32(priv, CX2_INDIRECT_DATA); | ||
276 | IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value); | ||
277 | return value; | ||
278 | } | ||
279 | |||
280 | /* iterative/auto-increment 32 bit reads and writes */ | ||
281 | static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, | ||
282 | int num) | ||
283 | { | ||
284 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; | ||
285 | u32 dif_len = addr - aligned_addr; | ||
286 | u32 aligned_len; | ||
287 | u32 i; | ||
288 | |||
289 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); | ||
290 | |||
291 | /* Read the first nibble byte by byte */ | ||
292 | if (unlikely(dif_len)) { | ||
293 | /* Start reading at aligned_addr + dif_len */ | ||
294 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | ||
295 | for (i = dif_len; i < 4; i++, buf++) | ||
296 | *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i); | ||
297 | num -= dif_len; | ||
298 | aligned_addr += 4; | ||
299 | } | ||
300 | |||
301 | /* Read DWs through autoinc register */ | ||
302 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); | ||
303 | aligned_len = num & CX2_INDIRECT_ADDR_MASK; | ||
304 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | ||
305 | *(u32*)buf = ipw_read32(priv, CX2_AUTOINC_DATA); | ||
306 | |||
307 | /* Copy the last nibble */ | ||
308 | dif_len = num - aligned_len; | ||
309 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | ||
310 | for (i = 0; i < dif_len; i++, buf++) | ||
311 | *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i); | ||
312 | } | ||
313 | |||
314 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 *buf, | ||
315 | int num) | ||
316 | { | ||
317 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; | ||
318 | u32 dif_len = addr - aligned_addr; | ||
319 | u32 aligned_len; | ||
320 | u32 i; | ||
321 | |||
322 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); | ||
323 | |||
324 | /* Write the first nibble byte by byte */ | ||
325 | if (unlikely(dif_len)) { | ||
326 | /* Start writing at aligned_addr + dif_len */ | ||
327 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | ||
328 | for (i = dif_len; i < 4; i++, buf++) | ||
329 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); | ||
330 | num -= dif_len; | ||
331 | aligned_addr += 4; | ||
332 | } | ||
333 | |||
334 | /* Write DWs through autoinc register */ | ||
335 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); | ||
336 | aligned_len = num & CX2_INDIRECT_ADDR_MASK; | ||
337 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | ||
338 | _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32*)buf); | ||
339 | |||
340 | /* Copy the last nibble */ | ||
341 | dif_len = num - aligned_len; | ||
342 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | ||
343 | for (i = 0; i < dif_len; i++, buf++) | ||
344 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); | ||
345 | } | ||
346 | |||
347 | static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, | ||
348 | int num) | ||
349 | { | ||
350 | memcpy_toio((priv->hw_base + addr), buf, num); | ||
351 | } | ||
352 | |||
353 | static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask) | ||
354 | { | ||
355 | ipw_write32(priv, reg, ipw_read32(priv, reg) | mask); | ||
356 | } | ||
357 | |||
358 | static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) | ||
359 | { | ||
360 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); | ||
361 | } | ||
362 | |||
363 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | ||
364 | { | ||
365 | if (priv->status & STATUS_INT_ENABLED) | ||
366 | return; | ||
367 | priv->status |= STATUS_INT_ENABLED; | ||
368 | ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL); | ||
369 | } | ||
370 | |||
371 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | ||
372 | { | ||
373 | if (!(priv->status & STATUS_INT_ENABLED)) | ||
374 | return; | ||
375 | priv->status &= ~STATUS_INT_ENABLED; | ||
376 | ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); | ||
377 | } | ||
378 | |||
379 | static char *ipw_error_desc(u32 val) | ||
380 | { | ||
381 | switch (val) { | ||
382 | case IPW_FW_ERROR_OK: | ||
383 | return "ERROR_OK"; | ||
384 | case IPW_FW_ERROR_FAIL: | ||
385 | return "ERROR_FAIL"; | ||
386 | case IPW_FW_ERROR_MEMORY_UNDERFLOW: | ||
387 | return "MEMORY_UNDERFLOW"; | ||
388 | case IPW_FW_ERROR_MEMORY_OVERFLOW: | ||
389 | return "MEMORY_OVERFLOW"; | ||
390 | case IPW_FW_ERROR_BAD_PARAM: | ||
391 | return "ERROR_BAD_PARAM"; | ||
392 | case IPW_FW_ERROR_BAD_CHECKSUM: | ||
393 | return "ERROR_BAD_CHECKSUM"; | ||
394 | case IPW_FW_ERROR_NMI_INTERRUPT: | ||
395 | return "ERROR_NMI_INTERRUPT"; | ||
396 | case IPW_FW_ERROR_BAD_DATABASE: | ||
397 | return "ERROR_BAD_DATABASE"; | ||
398 | case IPW_FW_ERROR_ALLOC_FAIL: | ||
399 | return "ERROR_ALLOC_FAIL"; | ||
400 | case IPW_FW_ERROR_DMA_UNDERRUN: | ||
401 | return "ERROR_DMA_UNDERRUN"; | ||
402 | case IPW_FW_ERROR_DMA_STATUS: | ||
403 | return "ERROR_DMA_STATUS"; | ||
404 | case IPW_FW_ERROR_DINOSTATUS_ERROR: | ||
405 | return "ERROR_DINOSTATUS_ERROR"; | ||
406 | case IPW_FW_ERROR_EEPROMSTATUS_ERROR: | ||
407 | return "ERROR_EEPROMSTATUS_ERROR"; | ||
408 | case IPW_FW_ERROR_SYSASSERT: | ||
409 | return "ERROR_SYSASSERT"; | ||
410 | case IPW_FW_ERROR_FATAL_ERROR: | ||
411 | return "ERROR_FATALSTATUS_ERROR"; | ||
412 | default: | ||
413 | return "UNKNOWNSTATUS_ERROR"; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | static void ipw_dump_nic_error_log(struct ipw_priv *priv) | ||
418 | { | ||
419 | u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base; | ||
420 | |||
421 | base = ipw_read32(priv, IPWSTATUS_ERROR_LOG); | ||
422 | count = ipw_read_reg32(priv, base); | ||
423 | |||
424 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | ||
425 | IPW_ERROR("Start IPW Error Log Dump:\n"); | ||
426 | IPW_ERROR("Status: 0x%08X, Config: %08X\n", | ||
427 | priv->status, priv->config); | ||
428 | } | ||
429 | |||
430 | for (i = ERROR_START_OFFSET; | ||
431 | i <= count * ERROR_ELEM_SIZE; | ||
432 | i += ERROR_ELEM_SIZE) { | ||
433 | desc = ipw_read_reg32(priv, base + i); | ||
434 | time = ipw_read_reg32(priv, base + i + 1*sizeof(u32)); | ||
435 | blink1 = ipw_read_reg32(priv, base + i + 2*sizeof(u32)); | ||
436 | blink2 = ipw_read_reg32(priv, base + i + 3*sizeof(u32)); | ||
437 | ilink1 = ipw_read_reg32(priv, base + i + 4*sizeof(u32)); | ||
438 | ilink2 = ipw_read_reg32(priv, base + i + 5*sizeof(u32)); | ||
439 | idata = ipw_read_reg32(priv, base + i + 6*sizeof(u32)); | ||
440 | |||
441 | IPW_ERROR( | ||
442 | "%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
443 | ipw_error_desc(desc), time, blink1, blink2, | ||
444 | ilink1, ilink2, idata); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | static void ipw_dump_nic_event_log(struct ipw_priv *priv) | ||
449 | { | ||
450 | u32 ev, time, data, i, count, base; | ||
451 | |||
452 | base = ipw_read32(priv, IPW_EVENT_LOG); | ||
453 | count = ipw_read_reg32(priv, base); | ||
454 | |||
455 | if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE) | ||
456 | IPW_ERROR("Start IPW Event Log Dump:\n"); | ||
457 | |||
458 | for (i = EVENT_START_OFFSET; | ||
459 | i <= count * EVENT_ELEM_SIZE; | ||
460 | i += EVENT_ELEM_SIZE) { | ||
461 | ev = ipw_read_reg32(priv, base + i); | ||
462 | time = ipw_read_reg32(priv, base + i + 1*sizeof(u32)); | ||
463 | data = ipw_read_reg32(priv, base + i + 2*sizeof(u32)); | ||
464 | |||
465 | #ifdef CONFIG_IPW_DEBUG | ||
466 | IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev); | ||
467 | #endif | ||
468 | } | ||
469 | } | ||
470 | |||
471 | static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, | ||
472 | u32 *len) | ||
473 | { | ||
474 | u32 addr, field_info, field_len, field_count, total_len; | ||
475 | |||
476 | IPW_DEBUG_ORD("ordinal = %i\n", ord); | ||
477 | |||
478 | if (!priv || !val || !len) { | ||
479 | IPW_DEBUG_ORD("Invalid argument\n"); | ||
480 | return -EINVAL; | ||
481 | } | ||
482 | |||
483 | /* verify device ordinal tables have been initialized */ | ||
484 | if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) { | ||
485 | IPW_DEBUG_ORD("Access ordinals before initialization\n"); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | switch (IPW_ORD_TABLE_ID_MASK & ord) { | ||
490 | case IPW_ORD_TABLE_0_MASK: | ||
491 | /* | ||
492 | * TABLE 0: Direct access to a table of 32 bit values | ||
493 | * | ||
494 | * This is a very simple table with the data directly | ||
495 | * read from the table | ||
496 | */ | ||
497 | |||
498 | /* remove the table id from the ordinal */ | ||
499 | ord &= IPW_ORD_TABLE_VALUE_MASK; | ||
500 | |||
501 | /* boundary check */ | ||
502 | if (ord > priv->table0_len) { | ||
503 | IPW_DEBUG_ORD("ordinal value (%i) longer then " | ||
504 | "max (%i)\n", ord, priv->table0_len); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | /* verify we have enough room to store the value */ | ||
509 | if (*len < sizeof(u32)) { | ||
510 | IPW_DEBUG_ORD("ordinal buffer length too small, " | ||
511 | "need %zd\n", sizeof(u32)); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n", | ||
516 | ord, priv->table0_addr + (ord << 2)); | ||
517 | |||
518 | *len = sizeof(u32); | ||
519 | ord <<= 2; | ||
520 | *((u32 *)val) = ipw_read32(priv, priv->table0_addr + ord); | ||
521 | break; | ||
522 | |||
523 | case IPW_ORD_TABLE_1_MASK: | ||
524 | /* | ||
525 | * TABLE 1: Indirect access to a table of 32 bit values | ||
526 | * | ||
527 | * This is a fairly large table of u32 values each | ||
528 | * representing starting addr for the data (which is | ||
529 | * also a u32) | ||
530 | */ | ||
531 | |||
532 | /* remove the table id from the ordinal */ | ||
533 | ord &= IPW_ORD_TABLE_VALUE_MASK; | ||
534 | |||
535 | /* boundary check */ | ||
536 | if (ord > priv->table1_len) { | ||
537 | IPW_DEBUG_ORD("ordinal value too long\n"); | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
541 | /* verify we have enough room to store the value */ | ||
542 | if (*len < sizeof(u32)) { | ||
543 | IPW_DEBUG_ORD("ordinal buffer length too small, " | ||
544 | "need %zd\n", sizeof(u32)); | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | |||
548 | *((u32 *)val) = ipw_read_reg32(priv, (priv->table1_addr + (ord << 2))); | ||
549 | *len = sizeof(u32); | ||
550 | break; | ||
551 | |||
552 | case IPW_ORD_TABLE_2_MASK: | ||
553 | /* | ||
554 | * TABLE 2: Indirect access to a table of variable sized values | ||
555 | * | ||
556 | * This table consist of six values, each containing | ||
557 | * - dword containing the starting offset of the data | ||
558 | * - dword containing the lengh in the first 16bits | ||
559 | * and the count in the second 16bits | ||
560 | */ | ||
561 | |||
562 | /* remove the table id from the ordinal */ | ||
563 | ord &= IPW_ORD_TABLE_VALUE_MASK; | ||
564 | |||
565 | /* boundary check */ | ||
566 | if (ord > priv->table2_len) { | ||
567 | IPW_DEBUG_ORD("ordinal value too long\n"); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | /* get the address of statistic */ | ||
572 | addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3)); | ||
573 | |||
574 | /* get the second DW of statistics ; | ||
575 | * two 16-bit words - first is length, second is count */ | ||
576 | field_info = ipw_read_reg32(priv, priv->table2_addr + (ord << 3) + sizeof(u32)); | ||
577 | |||
578 | /* get each entry length */ | ||
579 | field_len = *((u16 *)&field_info); | ||
580 | |||
581 | /* get number of entries */ | ||
582 | field_count = *(((u16 *)&field_info) + 1); | ||
583 | |||
584 | /* abort if not enought memory */ | ||
585 | total_len = field_len * field_count; | ||
586 | if (total_len > *len) { | ||
587 | *len = total_len; | ||
588 | return -EINVAL; | ||
589 | } | ||
590 | |||
591 | *len = total_len; | ||
592 | if (!total_len) | ||
593 | return 0; | ||
594 | |||
595 | IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, " | ||
596 | "field_info = 0x%08x\n", | ||
597 | addr, total_len, field_info); | ||
598 | ipw_read_indirect(priv, addr, val, total_len); | ||
599 | break; | ||
600 | |||
601 | default: | ||
602 | IPW_DEBUG_ORD("Invalid ordinal!\n"); | ||
603 | return -EINVAL; | ||
604 | |||
605 | } | ||
606 | |||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static void ipw_init_ordinals(struct ipw_priv *priv) | ||
612 | { | ||
613 | priv->table0_addr = IPW_ORDINALS_TABLE_LOWER; | ||
614 | priv->table0_len = ipw_read32(priv, priv->table0_addr); | ||
615 | |||
616 | IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n", | ||
617 | priv->table0_addr, priv->table0_len); | ||
618 | |||
619 | priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1); | ||
620 | priv->table1_len = ipw_read_reg32(priv, priv->table1_addr); | ||
621 | |||
622 | IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n", | ||
623 | priv->table1_addr, priv->table1_len); | ||
624 | |||
625 | priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2); | ||
626 | priv->table2_len = ipw_read_reg32(priv, priv->table2_addr); | ||
627 | priv->table2_len &= 0x0000ffff; /* use first two bytes */ | ||
628 | |||
629 | IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n", | ||
630 | priv->table2_addr, priv->table2_len); | ||
631 | |||
632 | } | ||
633 | |||
634 | /* | ||
635 | * The following adds a new attribute to the sysfs representation | ||
636 | * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) | ||
637 | * used for controling the debug level. | ||
638 | * | ||
639 | * See the level definitions in ipw for details. | ||
640 | */ | ||
641 | static ssize_t show_debug_level(struct device_driver *d, char *buf) | ||
642 | { | ||
643 | return sprintf(buf, "0x%08X\n", ipw_debug_level); | ||
644 | } | ||
645 | static ssize_t store_debug_level(struct device_driver *d, | ||
646 | const char *buf, size_t count) | ||
647 | { | ||
648 | char *p = (char *)buf; | ||
649 | u32 val; | ||
650 | |||
651 | if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { | ||
652 | p++; | ||
653 | if (p[0] == 'x' || p[0] == 'X') | ||
654 | p++; | ||
655 | val = simple_strtoul(p, &p, 16); | ||
656 | } else | ||
657 | val = simple_strtoul(p, &p, 10); | ||
658 | if (p == buf) | ||
659 | printk(KERN_INFO DRV_NAME | ||
660 | ": %s is not in hex or decimal form.\n", buf); | ||
661 | else | ||
662 | ipw_debug_level = val; | ||
663 | |||
664 | return strnlen(buf, count); | ||
665 | } | ||
666 | |||
667 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, | ||
668 | show_debug_level, store_debug_level); | ||
669 | |||
670 | static ssize_t show_status(struct device *d, | ||
671 | struct device_attribute *attr, char *buf) | ||
672 | { | ||
673 | struct ipw_priv *p = d->driver_data; | ||
674 | return sprintf(buf, "0x%08x\n", (int)p->status); | ||
675 | } | ||
676 | static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); | ||
677 | |||
678 | static ssize_t show_cfg(struct device *d, struct device_attribute *attr, | ||
679 | char *buf) | ||
680 | { | ||
681 | struct ipw_priv *p = d->driver_data; | ||
682 | return sprintf(buf, "0x%08x\n", (int)p->config); | ||
683 | } | ||
684 | static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); | ||
685 | |||
686 | static ssize_t show_nic_type(struct device *d, | ||
687 | struct device_attribute *attr, char *buf) | ||
688 | { | ||
689 | struct ipw_priv *p = d->driver_data; | ||
690 | u8 type = p->eeprom[EEPROM_NIC_TYPE]; | ||
691 | |||
692 | switch (type) { | ||
693 | case EEPROM_NIC_TYPE_STANDARD: | ||
694 | return sprintf(buf, "STANDARD\n"); | ||
695 | case EEPROM_NIC_TYPE_DELL: | ||
696 | return sprintf(buf, "DELL\n"); | ||
697 | case EEPROM_NIC_TYPE_FUJITSU: | ||
698 | return sprintf(buf, "FUJITSU\n"); | ||
699 | case EEPROM_NIC_TYPE_IBM: | ||
700 | return sprintf(buf, "IBM\n"); | ||
701 | case EEPROM_NIC_TYPE_HP: | ||
702 | return sprintf(buf, "HP\n"); | ||
703 | } | ||
704 | |||
705 | return sprintf(buf, "UNKNOWN\n"); | ||
706 | } | ||
707 | static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); | ||
708 | |||
709 | static ssize_t dump_error_log(struct device *d, | ||
710 | struct device_attribute *attr, const char *buf, size_t count) | ||
711 | { | ||
712 | char *p = (char *)buf; | ||
713 | |||
714 | if (p[0] == '1') | ||
715 | ipw_dump_nic_error_log((struct ipw_priv*)d->driver_data); | ||
716 | |||
717 | return strnlen(buf, count); | ||
718 | } | ||
719 | static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); | ||
720 | |||
721 | static ssize_t dump_event_log(struct device *d, | ||
722 | struct device_attribute *attr, const char *buf, size_t count) | ||
723 | { | ||
724 | char *p = (char *)buf; | ||
725 | |||
726 | if (p[0] == '1') | ||
727 | ipw_dump_nic_event_log((struct ipw_priv*)d->driver_data); | ||
728 | |||
729 | return strnlen(buf, count); | ||
730 | } | ||
731 | static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); | ||
732 | |||
733 | static ssize_t show_ucode_version(struct device *d, | ||
734 | struct device_attribute *attr, char *buf) | ||
735 | { | ||
736 | u32 len = sizeof(u32), tmp = 0; | ||
737 | struct ipw_priv *p = d->driver_data; | ||
738 | |||
739 | if(ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len)) | ||
740 | return 0; | ||
741 | |||
742 | return sprintf(buf, "0x%08x\n", tmp); | ||
743 | } | ||
744 | static DEVICE_ATTR(ucode_version, S_IWUSR|S_IRUGO, show_ucode_version, NULL); | ||
745 | |||
746 | static ssize_t show_rtc(struct device *d, struct device_attribute *attr, | ||
747 | char *buf) | ||
748 | { | ||
749 | u32 len = sizeof(u32), tmp = 0; | ||
750 | struct ipw_priv *p = d->driver_data; | ||
751 | |||
752 | if(ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len)) | ||
753 | return 0; | ||
754 | |||
755 | return sprintf(buf, "0x%08x\n", tmp); | ||
756 | } | ||
757 | static DEVICE_ATTR(rtc, S_IWUSR|S_IRUGO, show_rtc, NULL); | ||
758 | |||
759 | /* | ||
760 | * Add a device attribute to view/control the delay between eeprom | ||
761 | * operations. | ||
762 | */ | ||
763 | static ssize_t show_eeprom_delay(struct device *d, | ||
764 | struct device_attribute *attr, char *buf) | ||
765 | { | ||
766 | int n = ((struct ipw_priv*)d->driver_data)->eeprom_delay; | ||
767 | return sprintf(buf, "%i\n", n); | ||
768 | } | ||
769 | static ssize_t store_eeprom_delay(struct device *d, | ||
770 | struct device_attribute *attr, const char *buf, | ||
771 | size_t count) | ||
772 | { | ||
773 | struct ipw_priv *p = d->driver_data; | ||
774 | sscanf(buf, "%i", &p->eeprom_delay); | ||
775 | return strnlen(buf, count); | ||
776 | } | ||
777 | static DEVICE_ATTR(eeprom_delay, S_IWUSR|S_IRUGO, | ||
778 | show_eeprom_delay,store_eeprom_delay); | ||
779 | |||
780 | static ssize_t show_command_event_reg(struct device *d, | ||
781 | struct device_attribute *attr, char *buf) | ||
782 | { | ||
783 | u32 reg = 0; | ||
784 | struct ipw_priv *p = d->driver_data; | ||
785 | |||
786 | reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT); | ||
787 | return sprintf(buf, "0x%08x\n", reg); | ||
788 | } | ||
789 | static ssize_t store_command_event_reg(struct device *d, | ||
790 | struct device_attribute *attr, const char *buf, | ||
791 | size_t count) | ||
792 | { | ||
793 | u32 reg; | ||
794 | struct ipw_priv *p = d->driver_data; | ||
795 | |||
796 | sscanf(buf, "%x", ®); | ||
797 | ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg); | ||
798 | return strnlen(buf, count); | ||
799 | } | ||
800 | static DEVICE_ATTR(command_event_reg, S_IWUSR|S_IRUGO, | ||
801 | show_command_event_reg,store_command_event_reg); | ||
802 | |||
803 | static ssize_t show_mem_gpio_reg(struct device *d, | ||
804 | struct device_attribute *attr, char *buf) | ||
805 | { | ||
806 | u32 reg = 0; | ||
807 | struct ipw_priv *p = d->driver_data; | ||
808 | |||
809 | reg = ipw_read_reg32(p, 0x301100); | ||
810 | return sprintf(buf, "0x%08x\n", reg); | ||
811 | } | ||
812 | static ssize_t store_mem_gpio_reg(struct device *d, | ||
813 | struct device_attribute *attr, const char *buf, | ||
814 | size_t count) | ||
815 | { | ||
816 | u32 reg; | ||
817 | struct ipw_priv *p = d->driver_data; | ||
818 | |||
819 | sscanf(buf, "%x", ®); | ||
820 | ipw_write_reg32(p, 0x301100, reg); | ||
821 | return strnlen(buf, count); | ||
822 | } | ||
823 | static DEVICE_ATTR(mem_gpio_reg, S_IWUSR|S_IRUGO, | ||
824 | show_mem_gpio_reg,store_mem_gpio_reg); | ||
825 | |||
826 | static ssize_t show_indirect_dword(struct device *d, | ||
827 | struct device_attribute *attr, char *buf) | ||
828 | { | ||
829 | u32 reg = 0; | ||
830 | struct ipw_priv *priv = d->driver_data; | ||
831 | if (priv->status & STATUS_INDIRECT_DWORD) | ||
832 | reg = ipw_read_reg32(priv, priv->indirect_dword); | ||
833 | else | ||
834 | reg = 0; | ||
835 | |||
836 | return sprintf(buf, "0x%08x\n", reg); | ||
837 | } | ||
838 | static ssize_t store_indirect_dword(struct device *d, | ||
839 | struct device_attribute *attr, const char *buf, | ||
840 | size_t count) | ||
841 | { | ||
842 | struct ipw_priv *priv = d->driver_data; | ||
843 | |||
844 | sscanf(buf, "%x", &priv->indirect_dword); | ||
845 | priv->status |= STATUS_INDIRECT_DWORD; | ||
846 | return strnlen(buf, count); | ||
847 | } | ||
848 | static DEVICE_ATTR(indirect_dword, S_IWUSR|S_IRUGO, | ||
849 | show_indirect_dword,store_indirect_dword); | ||
850 | |||
851 | static ssize_t show_indirect_byte(struct device *d, | ||
852 | struct device_attribute *attr, char *buf) | ||
853 | { | ||
854 | u8 reg = 0; | ||
855 | struct ipw_priv *priv = d->driver_data; | ||
856 | if (priv->status & STATUS_INDIRECT_BYTE) | ||
857 | reg = ipw_read_reg8(priv, priv->indirect_byte); | ||
858 | else | ||
859 | reg = 0; | ||
860 | |||
861 | return sprintf(buf, "0x%02x\n", reg); | ||
862 | } | ||
863 | static ssize_t store_indirect_byte(struct device *d, | ||
864 | struct device_attribute *attr, const char *buf, | ||
865 | size_t count) | ||
866 | { | ||
867 | struct ipw_priv *priv = d->driver_data; | ||
868 | |||
869 | sscanf(buf, "%x", &priv->indirect_byte); | ||
870 | priv->status |= STATUS_INDIRECT_BYTE; | ||
871 | return strnlen(buf, count); | ||
872 | } | ||
873 | static DEVICE_ATTR(indirect_byte, S_IWUSR|S_IRUGO, | ||
874 | show_indirect_byte, store_indirect_byte); | ||
875 | |||
876 | static ssize_t show_direct_dword(struct device *d, | ||
877 | struct device_attribute *attr, char *buf) | ||
878 | { | ||
879 | u32 reg = 0; | ||
880 | struct ipw_priv *priv = d->driver_data; | ||
881 | |||
882 | if (priv->status & STATUS_DIRECT_DWORD) | ||
883 | reg = ipw_read32(priv, priv->direct_dword); | ||
884 | else | ||
885 | reg = 0; | ||
886 | |||
887 | return sprintf(buf, "0x%08x\n", reg); | ||
888 | } | ||
889 | static ssize_t store_direct_dword(struct device *d, | ||
890 | struct device_attribute *attr, const char *buf, | ||
891 | size_t count) | ||
892 | { | ||
893 | struct ipw_priv *priv = d->driver_data; | ||
894 | |||
895 | sscanf(buf, "%x", &priv->direct_dword); | ||
896 | priv->status |= STATUS_DIRECT_DWORD; | ||
897 | return strnlen(buf, count); | ||
898 | } | ||
899 | static DEVICE_ATTR(direct_dword, S_IWUSR|S_IRUGO, | ||
900 | show_direct_dword,store_direct_dword); | ||
901 | |||
902 | |||
903 | static inline int rf_kill_active(struct ipw_priv *priv) | ||
904 | { | ||
905 | if (0 == (ipw_read32(priv, 0x30) & 0x10000)) | ||
906 | priv->status |= STATUS_RF_KILL_HW; | ||
907 | else | ||
908 | priv->status &= ~STATUS_RF_KILL_HW; | ||
909 | |||
910 | return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0; | ||
911 | } | ||
912 | |||
913 | static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, | ||
914 | char *buf) | ||
915 | { | ||
916 | /* 0 - RF kill not enabled | ||
917 | 1 - SW based RF kill active (sysfs) | ||
918 | 2 - HW based RF kill active | ||
919 | 3 - Both HW and SW baed RF kill active */ | ||
920 | struct ipw_priv *priv = d->driver_data; | ||
921 | int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | | ||
922 | (rf_kill_active(priv) ? 0x2 : 0x0); | ||
923 | return sprintf(buf, "%i\n", val); | ||
924 | } | ||
925 | |||
926 | static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) | ||
927 | { | ||
928 | if ((disable_radio ? 1 : 0) == | ||
929 | (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) | ||
930 | return 0 ; | ||
931 | |||
932 | IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", | ||
933 | disable_radio ? "OFF" : "ON"); | ||
934 | |||
935 | if (disable_radio) { | ||
936 | priv->status |= STATUS_RF_KILL_SW; | ||
937 | |||
938 | if (priv->workqueue) { | ||
939 | cancel_delayed_work(&priv->request_scan); | ||
940 | } | ||
941 | wake_up_interruptible(&priv->wait_command_queue); | ||
942 | queue_work(priv->workqueue, &priv->down); | ||
943 | } else { | ||
944 | priv->status &= ~STATUS_RF_KILL_SW; | ||
945 | if (rf_kill_active(priv)) { | ||
946 | IPW_DEBUG_RF_KILL("Can not turn radio back on - " | ||
947 | "disabled by HW switch\n"); | ||
948 | /* Make sure the RF_KILL check timer is running */ | ||
949 | cancel_delayed_work(&priv->rf_kill); | ||
950 | queue_delayed_work(priv->workqueue, &priv->rf_kill, | ||
951 | 2 * HZ); | ||
952 | } else | ||
953 | queue_work(priv->workqueue, &priv->up); | ||
954 | } | ||
955 | |||
956 | return 1; | ||
957 | } | ||
958 | |||
959 | static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, | ||
960 | const char *buf, size_t count) | ||
961 | { | ||
962 | struct ipw_priv *priv = d->driver_data; | ||
963 | |||
964 | ipw_radio_kill_sw(priv, buf[0] == '1'); | ||
965 | |||
966 | return count; | ||
967 | } | ||
968 | static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill); | ||
969 | |||
970 | static void ipw_irq_tasklet(struct ipw_priv *priv) | ||
971 | { | ||
972 | u32 inta, inta_mask, handled = 0; | ||
973 | unsigned long flags; | ||
974 | int rc = 0; | ||
975 | |||
976 | spin_lock_irqsave(&priv->lock, flags); | ||
977 | |||
978 | inta = ipw_read32(priv, CX2_INTA_RW); | ||
979 | inta_mask = ipw_read32(priv, CX2_INTA_MASK_R); | ||
980 | inta &= (CX2_INTA_MASK_ALL & inta_mask); | ||
981 | |||
982 | /* Add any cached INTA values that need to be handled */ | ||
983 | inta |= priv->isr_inta; | ||
984 | |||
985 | /* handle all the justifications for the interrupt */ | ||
986 | if (inta & CX2_INTA_BIT_RX_TRANSFER) { | ||
987 | ipw_rx(priv); | ||
988 | handled |= CX2_INTA_BIT_RX_TRANSFER; | ||
989 | } | ||
990 | |||
991 | if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) { | ||
992 | IPW_DEBUG_HC("Command completed.\n"); | ||
993 | rc = ipw_queue_tx_reclaim( priv, &priv->txq_cmd, -1); | ||
994 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
995 | wake_up_interruptible(&priv->wait_command_queue); | ||
996 | handled |= CX2_INTA_BIT_TX_CMD_QUEUE; | ||
997 | } | ||
998 | |||
999 | if (inta & CX2_INTA_BIT_TX_QUEUE_1) { | ||
1000 | IPW_DEBUG_TX("TX_QUEUE_1\n"); | ||
1001 | rc = ipw_queue_tx_reclaim( priv, &priv->txq[0], 0); | ||
1002 | handled |= CX2_INTA_BIT_TX_QUEUE_1; | ||
1003 | } | ||
1004 | |||
1005 | if (inta & CX2_INTA_BIT_TX_QUEUE_2) { | ||
1006 | IPW_DEBUG_TX("TX_QUEUE_2\n"); | ||
1007 | rc = ipw_queue_tx_reclaim( priv, &priv->txq[1], 1); | ||
1008 | handled |= CX2_INTA_BIT_TX_QUEUE_2; | ||
1009 | } | ||
1010 | |||
1011 | if (inta & CX2_INTA_BIT_TX_QUEUE_3) { | ||
1012 | IPW_DEBUG_TX("TX_QUEUE_3\n"); | ||
1013 | rc = ipw_queue_tx_reclaim( priv, &priv->txq[2], 2); | ||
1014 | handled |= CX2_INTA_BIT_TX_QUEUE_3; | ||
1015 | } | ||
1016 | |||
1017 | if (inta & CX2_INTA_BIT_TX_QUEUE_4) { | ||
1018 | IPW_DEBUG_TX("TX_QUEUE_4\n"); | ||
1019 | rc = ipw_queue_tx_reclaim( priv, &priv->txq[3], 3); | ||
1020 | handled |= CX2_INTA_BIT_TX_QUEUE_4; | ||
1021 | } | ||
1022 | |||
1023 | if (inta & CX2_INTA_BIT_STATUS_CHANGE) { | ||
1024 | IPW_WARNING("STATUS_CHANGE\n"); | ||
1025 | handled |= CX2_INTA_BIT_STATUS_CHANGE; | ||
1026 | } | ||
1027 | |||
1028 | if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) { | ||
1029 | IPW_WARNING("TX_PERIOD_EXPIRED\n"); | ||
1030 | handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED; | ||
1031 | } | ||
1032 | |||
1033 | if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { | ||
1034 | IPW_WARNING("HOST_CMD_DONE\n"); | ||
1035 | handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; | ||
1036 | } | ||
1037 | |||
1038 | if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) { | ||
1039 | IPW_WARNING("FW_INITIALIZATION_DONE\n"); | ||
1040 | handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE; | ||
1041 | } | ||
1042 | |||
1043 | if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { | ||
1044 | IPW_WARNING("PHY_OFF_DONE\n"); | ||
1045 | handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; | ||
1046 | } | ||
1047 | |||
1048 | if (inta & CX2_INTA_BIT_RF_KILL_DONE) { | ||
1049 | IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); | ||
1050 | priv->status |= STATUS_RF_KILL_HW; | ||
1051 | wake_up_interruptible(&priv->wait_command_queue); | ||
1052 | netif_carrier_off(priv->net_dev); | ||
1053 | netif_stop_queue(priv->net_dev); | ||
1054 | cancel_delayed_work(&priv->request_scan); | ||
1055 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); | ||
1056 | handled |= CX2_INTA_BIT_RF_KILL_DONE; | ||
1057 | } | ||
1058 | |||
1059 | if (inta & CX2_INTA_BIT_FATAL_ERROR) { | ||
1060 | IPW_ERROR("Firmware error detected. Restarting.\n"); | ||
1061 | #ifdef CONFIG_IPW_DEBUG | ||
1062 | if (ipw_debug_level & IPW_DL_FW_ERRORS) { | ||
1063 | ipw_dump_nic_error_log(priv); | ||
1064 | ipw_dump_nic_event_log(priv); | ||
1065 | } | ||
1066 | #endif | ||
1067 | queue_work(priv->workqueue, &priv->adapter_restart); | ||
1068 | handled |= CX2_INTA_BIT_FATAL_ERROR; | ||
1069 | } | ||
1070 | |||
1071 | if (inta & CX2_INTA_BIT_PARITY_ERROR) { | ||
1072 | IPW_ERROR("Parity error\n"); | ||
1073 | handled |= CX2_INTA_BIT_PARITY_ERROR; | ||
1074 | } | ||
1075 | |||
1076 | if (handled != inta) { | ||
1077 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", | ||
1078 | inta & ~handled); | ||
1079 | } | ||
1080 | |||
1081 | /* enable all interrupts */ | ||
1082 | ipw_enable_interrupts(priv); | ||
1083 | |||
1084 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1085 | } | ||
1086 | |||
1087 | #ifdef CONFIG_IPW_DEBUG | ||
1088 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x | ||
1089 | static char *get_cmd_string(u8 cmd) | ||
1090 | { | ||
1091 | switch (cmd) { | ||
1092 | IPW_CMD(HOST_COMPLETE); | ||
1093 | IPW_CMD(POWER_DOWN); | ||
1094 | IPW_CMD(SYSTEM_CONFIG); | ||
1095 | IPW_CMD(MULTICAST_ADDRESS); | ||
1096 | IPW_CMD(SSID); | ||
1097 | IPW_CMD(ADAPTER_ADDRESS); | ||
1098 | IPW_CMD(PORT_TYPE); | ||
1099 | IPW_CMD(RTS_THRESHOLD); | ||
1100 | IPW_CMD(FRAG_THRESHOLD); | ||
1101 | IPW_CMD(POWER_MODE); | ||
1102 | IPW_CMD(WEP_KEY); | ||
1103 | IPW_CMD(TGI_TX_KEY); | ||
1104 | IPW_CMD(SCAN_REQUEST); | ||
1105 | IPW_CMD(SCAN_REQUEST_EXT); | ||
1106 | IPW_CMD(ASSOCIATE); | ||
1107 | IPW_CMD(SUPPORTED_RATES); | ||
1108 | IPW_CMD(SCAN_ABORT); | ||
1109 | IPW_CMD(TX_FLUSH); | ||
1110 | IPW_CMD(QOS_PARAMETERS); | ||
1111 | IPW_CMD(DINO_CONFIG); | ||
1112 | IPW_CMD(RSN_CAPABILITIES); | ||
1113 | IPW_CMD(RX_KEY); | ||
1114 | IPW_CMD(CARD_DISABLE); | ||
1115 | IPW_CMD(SEED_NUMBER); | ||
1116 | IPW_CMD(TX_POWER); | ||
1117 | IPW_CMD(COUNTRY_INFO); | ||
1118 | IPW_CMD(AIRONET_INFO); | ||
1119 | IPW_CMD(AP_TX_POWER); | ||
1120 | IPW_CMD(CCKM_INFO); | ||
1121 | IPW_CMD(CCX_VER_INFO); | ||
1122 | IPW_CMD(SET_CALIBRATION); | ||
1123 | IPW_CMD(SENSITIVITY_CALIB); | ||
1124 | IPW_CMD(RETRY_LIMIT); | ||
1125 | IPW_CMD(IPW_PRE_POWER_DOWN); | ||
1126 | IPW_CMD(VAP_BEACON_TEMPLATE); | ||
1127 | IPW_CMD(VAP_DTIM_PERIOD); | ||
1128 | IPW_CMD(EXT_SUPPORTED_RATES); | ||
1129 | IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT); | ||
1130 | IPW_CMD(VAP_QUIET_INTERVALS); | ||
1131 | IPW_CMD(VAP_CHANNEL_SWITCH); | ||
1132 | IPW_CMD(VAP_MANDATORY_CHANNELS); | ||
1133 | IPW_CMD(VAP_CELL_PWR_LIMIT); | ||
1134 | IPW_CMD(VAP_CF_PARAM_SET); | ||
1135 | IPW_CMD(VAP_SET_BEACONING_STATE); | ||
1136 | IPW_CMD(MEASUREMENT); | ||
1137 | IPW_CMD(POWER_CAPABILITY); | ||
1138 | IPW_CMD(SUPPORTED_CHANNELS); | ||
1139 | IPW_CMD(TPC_REPORT); | ||
1140 | IPW_CMD(WME_INFO); | ||
1141 | IPW_CMD(PRODUCTION_COMMAND); | ||
1142 | default: | ||
1143 | return "UNKNOWN"; | ||
1144 | } | ||
1145 | } | ||
1146 | #endif /* CONFIG_IPW_DEBUG */ | ||
1147 | |||
1148 | #define HOST_COMPLETE_TIMEOUT HZ | ||
1149 | static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) | ||
1150 | { | ||
1151 | int rc = 0; | ||
1152 | |||
1153 | if (priv->status & STATUS_HCMD_ACTIVE) { | ||
1154 | IPW_ERROR("Already sending a command\n"); | ||
1155 | return -1; | ||
1156 | } | ||
1157 | |||
1158 | priv->status |= STATUS_HCMD_ACTIVE; | ||
1159 | |||
1160 | IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", | ||
1161 | get_cmd_string(cmd->cmd), cmd->cmd, cmd->len); | ||
1162 | printk_buf(IPW_DL_HOST_COMMAND, (u8*)cmd->param, cmd->len); | ||
1163 | |||
1164 | rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); | ||
1165 | if (rc) | ||
1166 | return rc; | ||
1167 | |||
1168 | rc = wait_event_interruptible_timeout( | ||
1169 | priv->wait_command_queue, !(priv->status & STATUS_HCMD_ACTIVE), | ||
1170 | HOST_COMPLETE_TIMEOUT); | ||
1171 | if (rc == 0) { | ||
1172 | IPW_DEBUG_INFO("Command completion failed out after %dms.\n", | ||
1173 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); | ||
1174 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
1175 | return -EIO; | ||
1176 | } | ||
1177 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
1178 | IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); | ||
1179 | return -EIO; | ||
1180 | } | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int ipw_send_host_complete(struct ipw_priv *priv) | ||
1186 | { | ||
1187 | struct host_cmd cmd = { | ||
1188 | .cmd = IPW_CMD_HOST_COMPLETE, | ||
1189 | .len = 0 | ||
1190 | }; | ||
1191 | |||
1192 | if (!priv) { | ||
1193 | IPW_ERROR("Invalid args\n"); | ||
1194 | return -1; | ||
1195 | } | ||
1196 | |||
1197 | if (ipw_send_cmd(priv, &cmd)) { | ||
1198 | IPW_ERROR("failed to send HOST_COMPLETE command\n"); | ||
1199 | return -1; | ||
1200 | } | ||
1201 | |||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | static int ipw_send_system_config(struct ipw_priv *priv, | ||
1206 | struct ipw_sys_config *config) | ||
1207 | { | ||
1208 | struct host_cmd cmd = { | ||
1209 | .cmd = IPW_CMD_SYSTEM_CONFIG, | ||
1210 | .len = sizeof(*config) | ||
1211 | }; | ||
1212 | |||
1213 | if (!priv || !config) { | ||
1214 | IPW_ERROR("Invalid args\n"); | ||
1215 | return -1; | ||
1216 | } | ||
1217 | |||
1218 | memcpy(&cmd.param,config,sizeof(*config)); | ||
1219 | if (ipw_send_cmd(priv, &cmd)) { | ||
1220 | IPW_ERROR("failed to send SYSTEM_CONFIG command\n"); | ||
1221 | return -1; | ||
1222 | } | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | static int ipw_send_ssid(struct ipw_priv *priv, u8 *ssid, int len) | ||
1228 | { | ||
1229 | struct host_cmd cmd = { | ||
1230 | .cmd = IPW_CMD_SSID, | ||
1231 | .len = min(len, IW_ESSID_MAX_SIZE) | ||
1232 | }; | ||
1233 | |||
1234 | if (!priv || !ssid) { | ||
1235 | IPW_ERROR("Invalid args\n"); | ||
1236 | return -1; | ||
1237 | } | ||
1238 | |||
1239 | memcpy(&cmd.param, ssid, cmd.len); | ||
1240 | if (ipw_send_cmd(priv, &cmd)) { | ||
1241 | IPW_ERROR("failed to send SSID command\n"); | ||
1242 | return -1; | ||
1243 | } | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | static int ipw_send_adapter_address(struct ipw_priv *priv, u8 *mac) | ||
1249 | { | ||
1250 | struct host_cmd cmd = { | ||
1251 | .cmd = IPW_CMD_ADAPTER_ADDRESS, | ||
1252 | .len = ETH_ALEN | ||
1253 | }; | ||
1254 | |||
1255 | if (!priv || !mac) { | ||
1256 | IPW_ERROR("Invalid args\n"); | ||
1257 | return -1; | ||
1258 | } | ||
1259 | |||
1260 | IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", | ||
1261 | priv->net_dev->name, MAC_ARG(mac)); | ||
1262 | |||
1263 | memcpy(&cmd.param, mac, ETH_ALEN); | ||
1264 | |||
1265 | if (ipw_send_cmd(priv, &cmd)) { | ||
1266 | IPW_ERROR("failed to send ADAPTER_ADDRESS command\n"); | ||
1267 | return -1; | ||
1268 | } | ||
1269 | |||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | static void ipw_adapter_restart(void *adapter) | ||
1274 | { | ||
1275 | struct ipw_priv *priv = adapter; | ||
1276 | |||
1277 | if (priv->status & STATUS_RF_KILL_MASK) | ||
1278 | return; | ||
1279 | |||
1280 | ipw_down(priv); | ||
1281 | if (ipw_up(priv)) { | ||
1282 | IPW_ERROR("Failed to up device\n"); | ||
1283 | return; | ||
1284 | } | ||
1285 | } | ||
1286 | |||
1287 | |||
1288 | |||
1289 | |||
1290 | #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) | ||
1291 | |||
1292 | static void ipw_scan_check(void *data) | ||
1293 | { | ||
1294 | struct ipw_priv *priv = data; | ||
1295 | if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { | ||
1296 | IPW_DEBUG_SCAN("Scan completion watchdog resetting " | ||
1297 | "adapter (%dms).\n", | ||
1298 | IPW_SCAN_CHECK_WATCHDOG / 100); | ||
1299 | ipw_adapter_restart(priv); | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | static int ipw_send_scan_request_ext(struct ipw_priv *priv, | ||
1304 | struct ipw_scan_request_ext *request) | ||
1305 | { | ||
1306 | struct host_cmd cmd = { | ||
1307 | .cmd = IPW_CMD_SCAN_REQUEST_EXT, | ||
1308 | .len = sizeof(*request) | ||
1309 | }; | ||
1310 | |||
1311 | if (!priv || !request) { | ||
1312 | IPW_ERROR("Invalid args\n"); | ||
1313 | return -1; | ||
1314 | } | ||
1315 | |||
1316 | memcpy(&cmd.param,request,sizeof(*request)); | ||
1317 | if (ipw_send_cmd(priv, &cmd)) { | ||
1318 | IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); | ||
1319 | return -1; | ||
1320 | } | ||
1321 | |||
1322 | queue_delayed_work(priv->workqueue, &priv->scan_check, | ||
1323 | IPW_SCAN_CHECK_WATCHDOG); | ||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | static int ipw_send_scan_abort(struct ipw_priv *priv) | ||
1328 | { | ||
1329 | struct host_cmd cmd = { | ||
1330 | .cmd = IPW_CMD_SCAN_ABORT, | ||
1331 | .len = 0 | ||
1332 | }; | ||
1333 | |||
1334 | if (!priv) { | ||
1335 | IPW_ERROR("Invalid args\n"); | ||
1336 | return -1; | ||
1337 | } | ||
1338 | |||
1339 | if (ipw_send_cmd(priv, &cmd)) { | ||
1340 | IPW_ERROR("failed to send SCAN_ABORT command\n"); | ||
1341 | return -1; | ||
1342 | } | ||
1343 | |||
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) | ||
1348 | { | ||
1349 | struct host_cmd cmd = { | ||
1350 | .cmd = IPW_CMD_SENSITIVITY_CALIB, | ||
1351 | .len = sizeof(struct ipw_sensitivity_calib) | ||
1352 | }; | ||
1353 | struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *) | ||
1354 | &cmd.param; | ||
1355 | calib->beacon_rssi_raw = sens; | ||
1356 | if (ipw_send_cmd(priv, &cmd)) { | ||
1357 | IPW_ERROR("failed to send SENSITIVITY CALIB command\n"); | ||
1358 | return -1; | ||
1359 | } | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | static int ipw_send_associate(struct ipw_priv *priv, | ||
1365 | struct ipw_associate *associate) | ||
1366 | { | ||
1367 | struct host_cmd cmd = { | ||
1368 | .cmd = IPW_CMD_ASSOCIATE, | ||
1369 | .len = sizeof(*associate) | ||
1370 | }; | ||
1371 | |||
1372 | if (!priv || !associate) { | ||
1373 | IPW_ERROR("Invalid args\n"); | ||
1374 | return -1; | ||
1375 | } | ||
1376 | |||
1377 | memcpy(&cmd.param,associate,sizeof(*associate)); | ||
1378 | if (ipw_send_cmd(priv, &cmd)) { | ||
1379 | IPW_ERROR("failed to send ASSOCIATE command\n"); | ||
1380 | return -1; | ||
1381 | } | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | static int ipw_send_supported_rates(struct ipw_priv *priv, | ||
1387 | struct ipw_supported_rates *rates) | ||
1388 | { | ||
1389 | struct host_cmd cmd = { | ||
1390 | .cmd = IPW_CMD_SUPPORTED_RATES, | ||
1391 | .len = sizeof(*rates) | ||
1392 | }; | ||
1393 | |||
1394 | if (!priv || !rates) { | ||
1395 | IPW_ERROR("Invalid args\n"); | ||
1396 | return -1; | ||
1397 | } | ||
1398 | |||
1399 | memcpy(&cmd.param,rates,sizeof(*rates)); | ||
1400 | if (ipw_send_cmd(priv, &cmd)) { | ||
1401 | IPW_ERROR("failed to send SUPPORTED_RATES command\n"); | ||
1402 | return -1; | ||
1403 | } | ||
1404 | |||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | static int ipw_set_random_seed(struct ipw_priv *priv) | ||
1409 | { | ||
1410 | struct host_cmd cmd = { | ||
1411 | .cmd = IPW_CMD_SEED_NUMBER, | ||
1412 | .len = sizeof(u32) | ||
1413 | }; | ||
1414 | |||
1415 | if (!priv) { | ||
1416 | IPW_ERROR("Invalid args\n"); | ||
1417 | return -1; | ||
1418 | } | ||
1419 | |||
1420 | get_random_bytes(&cmd.param, sizeof(u32)); | ||
1421 | |||
1422 | if (ipw_send_cmd(priv, &cmd)) { | ||
1423 | IPW_ERROR("failed to send SEED_NUMBER command\n"); | ||
1424 | return -1; | ||
1425 | } | ||
1426 | |||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | #if 0 | ||
1431 | static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) | ||
1432 | { | ||
1433 | struct host_cmd cmd = { | ||
1434 | .cmd = IPW_CMD_CARD_DISABLE, | ||
1435 | .len = sizeof(u32) | ||
1436 | }; | ||
1437 | |||
1438 | if (!priv) { | ||
1439 | IPW_ERROR("Invalid args\n"); | ||
1440 | return -1; | ||
1441 | } | ||
1442 | |||
1443 | *((u32*)&cmd.param) = phy_off; | ||
1444 | |||
1445 | if (ipw_send_cmd(priv, &cmd)) { | ||
1446 | IPW_ERROR("failed to send CARD_DISABLE command\n"); | ||
1447 | return -1; | ||
1448 | } | ||
1449 | |||
1450 | return 0; | ||
1451 | } | ||
1452 | #endif | ||
1453 | |||
1454 | static int ipw_send_tx_power(struct ipw_priv *priv, | ||
1455 | struct ipw_tx_power *power) | ||
1456 | { | ||
1457 | struct host_cmd cmd = { | ||
1458 | .cmd = IPW_CMD_TX_POWER, | ||
1459 | .len = sizeof(*power) | ||
1460 | }; | ||
1461 | |||
1462 | if (!priv || !power) { | ||
1463 | IPW_ERROR("Invalid args\n"); | ||
1464 | return -1; | ||
1465 | } | ||
1466 | |||
1467 | memcpy(&cmd.param,power,sizeof(*power)); | ||
1468 | if (ipw_send_cmd(priv, &cmd)) { | ||
1469 | IPW_ERROR("failed to send TX_POWER command\n"); | ||
1470 | return -1; | ||
1471 | } | ||
1472 | |||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) | ||
1477 | { | ||
1478 | struct ipw_rts_threshold rts_threshold = { | ||
1479 | .rts_threshold = rts, | ||
1480 | }; | ||
1481 | struct host_cmd cmd = { | ||
1482 | .cmd = IPW_CMD_RTS_THRESHOLD, | ||
1483 | .len = sizeof(rts_threshold) | ||
1484 | }; | ||
1485 | |||
1486 | if (!priv) { | ||
1487 | IPW_ERROR("Invalid args\n"); | ||
1488 | return -1; | ||
1489 | } | ||
1490 | |||
1491 | memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold)); | ||
1492 | if (ipw_send_cmd(priv, &cmd)) { | ||
1493 | IPW_ERROR("failed to send RTS_THRESHOLD command\n"); | ||
1494 | return -1; | ||
1495 | } | ||
1496 | |||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) | ||
1501 | { | ||
1502 | struct ipw_frag_threshold frag_threshold = { | ||
1503 | .frag_threshold = frag, | ||
1504 | }; | ||
1505 | struct host_cmd cmd = { | ||
1506 | .cmd = IPW_CMD_FRAG_THRESHOLD, | ||
1507 | .len = sizeof(frag_threshold) | ||
1508 | }; | ||
1509 | |||
1510 | if (!priv) { | ||
1511 | IPW_ERROR("Invalid args\n"); | ||
1512 | return -1; | ||
1513 | } | ||
1514 | |||
1515 | memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold)); | ||
1516 | if (ipw_send_cmd(priv, &cmd)) { | ||
1517 | IPW_ERROR("failed to send FRAG_THRESHOLD command\n"); | ||
1518 | return -1; | ||
1519 | } | ||
1520 | |||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) | ||
1525 | { | ||
1526 | struct host_cmd cmd = { | ||
1527 | .cmd = IPW_CMD_POWER_MODE, | ||
1528 | .len = sizeof(u32) | ||
1529 | }; | ||
1530 | u32 *param = (u32*)(&cmd.param); | ||
1531 | |||
1532 | if (!priv) { | ||
1533 | IPW_ERROR("Invalid args\n"); | ||
1534 | return -1; | ||
1535 | } | ||
1536 | |||
1537 | /* If on battery, set to 3, if AC set to CAM, else user | ||
1538 | * level */ | ||
1539 | switch (mode) { | ||
1540 | case IPW_POWER_BATTERY: | ||
1541 | *param = IPW_POWER_INDEX_3; | ||
1542 | break; | ||
1543 | case IPW_POWER_AC: | ||
1544 | *param = IPW_POWER_MODE_CAM; | ||
1545 | break; | ||
1546 | default: | ||
1547 | *param = mode; | ||
1548 | break; | ||
1549 | } | ||
1550 | |||
1551 | if (ipw_send_cmd(priv, &cmd)) { | ||
1552 | IPW_ERROR("failed to send POWER_MODE command\n"); | ||
1553 | return -1; | ||
1554 | } | ||
1555 | |||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | /* | ||
1560 | * The IPW device contains a Microwire compatible EEPROM that stores | ||
1561 | * various data like the MAC address. Usually the firmware has exclusive | ||
1562 | * access to the eeprom, but during device initialization (before the | ||
1563 | * device driver has sent the HostComplete command to the firmware) the | ||
1564 | * device driver has read access to the EEPROM by way of indirect addressing | ||
1565 | * through a couple of memory mapped registers. | ||
1566 | * | ||
1567 | * The following is a simplified implementation for pulling data out of the | ||
1568 | * the eeprom, along with some helper functions to find information in | ||
1569 | * the per device private data's copy of the eeprom. | ||
1570 | * | ||
1571 | * NOTE: To better understand how these functions work (i.e what is a chip | ||
1572 | * select and why do have to keep driving the eeprom clock?), read | ||
1573 | * just about any data sheet for a Microwire compatible EEPROM. | ||
1574 | */ | ||
1575 | |||
1576 | /* write a 32 bit value into the indirect accessor register */ | ||
1577 | static inline void eeprom_write_reg(struct ipw_priv *p, u32 data) | ||
1578 | { | ||
1579 | ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data); | ||
1580 | |||
1581 | /* the eeprom requires some time to complete the operation */ | ||
1582 | udelay(p->eeprom_delay); | ||
1583 | |||
1584 | return; | ||
1585 | } | ||
1586 | |||
1587 | /* perform a chip select operation */ | ||
1588 | static inline void eeprom_cs(struct ipw_priv* priv) | ||
1589 | { | ||
1590 | eeprom_write_reg(priv,0); | ||
1591 | eeprom_write_reg(priv,EEPROM_BIT_CS); | ||
1592 | eeprom_write_reg(priv,EEPROM_BIT_CS|EEPROM_BIT_SK); | ||
1593 | eeprom_write_reg(priv,EEPROM_BIT_CS); | ||
1594 | } | ||
1595 | |||
1596 | /* perform a chip select operation */ | ||
1597 | static inline void eeprom_disable_cs(struct ipw_priv* priv) | ||
1598 | { | ||
1599 | eeprom_write_reg(priv,EEPROM_BIT_CS); | ||
1600 | eeprom_write_reg(priv,0); | ||
1601 | eeprom_write_reg(priv,EEPROM_BIT_SK); | ||
1602 | } | ||
1603 | |||
1604 | /* push a single bit down to the eeprom */ | ||
1605 | static inline void eeprom_write_bit(struct ipw_priv *p,u8 bit) | ||
1606 | { | ||
1607 | int d = ( bit ? EEPROM_BIT_DI : 0); | ||
1608 | eeprom_write_reg(p,EEPROM_BIT_CS|d); | ||
1609 | eeprom_write_reg(p,EEPROM_BIT_CS|d|EEPROM_BIT_SK); | ||
1610 | } | ||
1611 | |||
1612 | /* push an opcode followed by an address down to the eeprom */ | ||
1613 | static void eeprom_op(struct ipw_priv* priv, u8 op, u8 addr) | ||
1614 | { | ||
1615 | int i; | ||
1616 | |||
1617 | eeprom_cs(priv); | ||
1618 | eeprom_write_bit(priv,1); | ||
1619 | eeprom_write_bit(priv,op&2); | ||
1620 | eeprom_write_bit(priv,op&1); | ||
1621 | for ( i=7; i>=0; i-- ) { | ||
1622 | eeprom_write_bit(priv,addr&(1<<i)); | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | /* pull 16 bits off the eeprom, one bit at a time */ | ||
1627 | static u16 eeprom_read_u16(struct ipw_priv* priv, u8 addr) | ||
1628 | { | ||
1629 | int i; | ||
1630 | u16 r=0; | ||
1631 | |||
1632 | /* Send READ Opcode */ | ||
1633 | eeprom_op(priv,EEPROM_CMD_READ,addr); | ||
1634 | |||
1635 | /* Send dummy bit */ | ||
1636 | eeprom_write_reg(priv,EEPROM_BIT_CS); | ||
1637 | |||
1638 | /* Read the byte off the eeprom one bit at a time */ | ||
1639 | for ( i=0; i<16; i++ ) { | ||
1640 | u32 data = 0; | ||
1641 | eeprom_write_reg(priv,EEPROM_BIT_CS|EEPROM_BIT_SK); | ||
1642 | eeprom_write_reg(priv,EEPROM_BIT_CS); | ||
1643 | data = ipw_read_reg32(priv,FW_MEM_REG_EEPROM_ACCESS); | ||
1644 | r = (r<<1) | ((data & EEPROM_BIT_DO)?1:0); | ||
1645 | } | ||
1646 | |||
1647 | /* Send another dummy bit */ | ||
1648 | eeprom_write_reg(priv,0); | ||
1649 | eeprom_disable_cs(priv); | ||
1650 | |||
1651 | return r; | ||
1652 | } | ||
1653 | |||
1654 | /* helper function for pulling the mac address out of the private */ | ||
1655 | /* data's copy of the eeprom data */ | ||
1656 | static void eeprom_parse_mac(struct ipw_priv* priv, u8* mac) | ||
1657 | { | ||
1658 | u8* ee = (u8*)priv->eeprom; | ||
1659 | memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6); | ||
1660 | } | ||
1661 | |||
1662 | /* | ||
1663 | * Either the device driver (i.e. the host) or the firmware can | ||
1664 | * load eeprom data into the designated region in SRAM. If neither | ||
1665 | * happens then the FW will shutdown with a fatal error. | ||
1666 | * | ||
1667 | * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE | ||
1668 | * bit needs region of shared SRAM needs to be non-zero. | ||
1669 | */ | ||
1670 | static void ipw_eeprom_init_sram(struct ipw_priv *priv) | ||
1671 | { | ||
1672 | int i; | ||
1673 | u16 *eeprom = (u16 *)priv->eeprom; | ||
1674 | |||
1675 | IPW_DEBUG_TRACE(">>\n"); | ||
1676 | |||
1677 | /* read entire contents of eeprom into private buffer */ | ||
1678 | for ( i=0; i<128; i++ ) | ||
1679 | eeprom[i] = eeprom_read_u16(priv,(u8)i); | ||
1680 | |||
1681 | /* | ||
1682 | If the data looks correct, then copy it to our private | ||
1683 | copy. Otherwise let the firmware know to perform the operation | ||
1684 | on it's own | ||
1685 | */ | ||
1686 | if ((priv->eeprom + EEPROM_VERSION) != 0) { | ||
1687 | IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); | ||
1688 | |||
1689 | /* write the eeprom data to sram */ | ||
1690 | for( i=0; i<CX2_EEPROM_IMAGE_SIZE; i++ ) | ||
1691 | ipw_write8(priv, IPW_EEPROM_DATA + i, | ||
1692 | priv->eeprom[i]); | ||
1693 | |||
1694 | /* Do not load eeprom data on fatal error or suspend */ | ||
1695 | ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); | ||
1696 | } else { | ||
1697 | IPW_DEBUG_INFO("Enabling FW initializationg of SRAM\n"); | ||
1698 | |||
1699 | /* Load eeprom data on fatal error or suspend */ | ||
1700 | ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1); | ||
1701 | } | ||
1702 | |||
1703 | IPW_DEBUG_TRACE("<<\n"); | ||
1704 | } | ||
1705 | |||
1706 | |||
1707 | static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count) | ||
1708 | { | ||
1709 | count >>= 2; | ||
1710 | if (!count) return; | ||
1711 | _ipw_write32(priv, CX2_AUTOINC_ADDR, start); | ||
1712 | while (count--) | ||
1713 | _ipw_write32(priv, CX2_AUTOINC_DATA, 0); | ||
1714 | } | ||
1715 | |||
1716 | static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv) | ||
1717 | { | ||
1718 | ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL, | ||
1719 | CB_NUMBER_OF_ELEMENTS_SMALL * | ||
1720 | sizeof(struct command_block)); | ||
1721 | } | ||
1722 | |||
1723 | static int ipw_fw_dma_enable(struct ipw_priv *priv) | ||
1724 | { /* start dma engine but no transfers yet*/ | ||
1725 | |||
1726 | IPW_DEBUG_FW(">> : \n"); | ||
1727 | |||
1728 | /* Start the dma */ | ||
1729 | ipw_fw_dma_reset_command_blocks(priv); | ||
1730 | |||
1731 | /* Write CB base address */ | ||
1732 | ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL); | ||
1733 | |||
1734 | IPW_DEBUG_FW("<< : \n"); | ||
1735 | return 0; | ||
1736 | } | ||
1737 | |||
1738 | static void ipw_fw_dma_abort(struct ipw_priv *priv) | ||
1739 | { | ||
1740 | u32 control = 0; | ||
1741 | |||
1742 | IPW_DEBUG_FW(">> :\n"); | ||
1743 | |||
1744 | //set the Stop and Abort bit | ||
1745 | control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; | ||
1746 | ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control); | ||
1747 | priv->sram_desc.last_cb_index = 0; | ||
1748 | |||
1749 | IPW_DEBUG_FW("<< \n"); | ||
1750 | } | ||
1751 | |||
1752 | static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index, struct command_block *cb) | ||
1753 | { | ||
1754 | u32 address = CX2_SHARED_SRAM_DMA_CONTROL + (sizeof(struct command_block) * index); | ||
1755 | IPW_DEBUG_FW(">> :\n"); | ||
1756 | |||
1757 | ipw_write_indirect(priv, address, (u8*)cb, (int)sizeof(struct command_block)); | ||
1758 | |||
1759 | IPW_DEBUG_FW("<< :\n"); | ||
1760 | return 0; | ||
1761 | |||
1762 | } | ||
1763 | |||
1764 | static int ipw_fw_dma_kick(struct ipw_priv *priv) | ||
1765 | { | ||
1766 | u32 control = 0; | ||
1767 | u32 index=0; | ||
1768 | |||
1769 | IPW_DEBUG_FW(">> :\n"); | ||
1770 | |||
1771 | for (index = 0; index < priv->sram_desc.last_cb_index; index++) | ||
1772 | ipw_fw_dma_write_command_block(priv, index, &priv->sram_desc.cb_list[index]); | ||
1773 | |||
1774 | /* Enable the DMA in the CSR register */ | ||
1775 | ipw_clear_bit(priv, CX2_RESET_REG,CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER); | ||
1776 | |||
1777 | /* Set the Start bit. */ | ||
1778 | control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START; | ||
1779 | ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control); | ||
1780 | |||
1781 | IPW_DEBUG_FW("<< :\n"); | ||
1782 | return 0; | ||
1783 | } | ||
1784 | |||
1785 | static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv) | ||
1786 | { | ||
1787 | u32 address; | ||
1788 | u32 register_value=0; | ||
1789 | u32 cb_fields_address=0; | ||
1790 | |||
1791 | IPW_DEBUG_FW(">> :\n"); | ||
1792 | address = ipw_read_reg32(priv,CX2_DMA_I_CURRENT_CB); | ||
1793 | IPW_DEBUG_FW_INFO("Current CB is 0x%x \n",address); | ||
1794 | |||
1795 | /* Read the DMA Controlor register */ | ||
1796 | register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL); | ||
1797 | IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n",register_value); | ||
1798 | |||
1799 | /* Print the CB values*/ | ||
1800 | cb_fields_address = address; | ||
1801 | register_value = ipw_read_reg32(priv, cb_fields_address); | ||
1802 | IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n",register_value); | ||
1803 | |||
1804 | cb_fields_address += sizeof(u32); | ||
1805 | register_value = ipw_read_reg32(priv, cb_fields_address); | ||
1806 | IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n",register_value); | ||
1807 | |||
1808 | cb_fields_address += sizeof(u32); | ||
1809 | register_value = ipw_read_reg32(priv, cb_fields_address); | ||
1810 | IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n", | ||
1811 | register_value); | ||
1812 | |||
1813 | cb_fields_address += sizeof(u32); | ||
1814 | register_value = ipw_read_reg32(priv, cb_fields_address); | ||
1815 | IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n",register_value); | ||
1816 | |||
1817 | IPW_DEBUG_FW(">> :\n"); | ||
1818 | } | ||
1819 | |||
1820 | static int ipw_fw_dma_command_block_index(struct ipw_priv *priv) | ||
1821 | { | ||
1822 | u32 current_cb_address = 0; | ||
1823 | u32 current_cb_index = 0; | ||
1824 | |||
1825 | IPW_DEBUG_FW("<< :\n"); | ||
1826 | current_cb_address= ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB); | ||
1827 | |||
1828 | current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL )/ | ||
1829 | sizeof (struct command_block); | ||
1830 | |||
1831 | IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n", | ||
1832 | current_cb_index, current_cb_address ); | ||
1833 | |||
1834 | IPW_DEBUG_FW(">> :\n"); | ||
1835 | return current_cb_index; | ||
1836 | |||
1837 | } | ||
1838 | |||
1839 | static int ipw_fw_dma_add_command_block(struct ipw_priv *priv, | ||
1840 | u32 src_address, | ||
1841 | u32 dest_address, | ||
1842 | u32 length, | ||
1843 | int interrupt_enabled, | ||
1844 | int is_last) | ||
1845 | { | ||
1846 | |||
1847 | u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC | | ||
1848 | CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG | | ||
1849 | CB_DEST_SIZE_LONG; | ||
1850 | struct command_block *cb; | ||
1851 | u32 last_cb_element=0; | ||
1852 | |||
1853 | IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n", | ||
1854 | src_address, dest_address, length); | ||
1855 | |||
1856 | if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL) | ||
1857 | return -1; | ||
1858 | |||
1859 | last_cb_element = priv->sram_desc.last_cb_index; | ||
1860 | cb = &priv->sram_desc.cb_list[last_cb_element]; | ||
1861 | priv->sram_desc.last_cb_index++; | ||
1862 | |||
1863 | /* Calculate the new CB control word */ | ||
1864 | if (interrupt_enabled ) | ||
1865 | control |= CB_INT_ENABLED; | ||
1866 | |||
1867 | if (is_last) | ||
1868 | control |= CB_LAST_VALID; | ||
1869 | |||
1870 | control |= length; | ||
1871 | |||
1872 | /* Calculate the CB Element's checksum value */ | ||
1873 | cb->status = control ^src_address ^dest_address; | ||
1874 | |||
1875 | /* Copy the Source and Destination addresses */ | ||
1876 | cb->dest_addr = dest_address; | ||
1877 | cb->source_addr = src_address; | ||
1878 | |||
1879 | /* Copy the Control Word last */ | ||
1880 | cb->control = control; | ||
1881 | |||
1882 | return 0; | ||
1883 | } | ||
1884 | |||
1885 | static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, | ||
1886 | u32 src_phys, | ||
1887 | u32 dest_address, | ||
1888 | u32 length) | ||
1889 | { | ||
1890 | u32 bytes_left = length; | ||
1891 | u32 src_offset=0; | ||
1892 | u32 dest_offset=0; | ||
1893 | int status = 0; | ||
1894 | IPW_DEBUG_FW(">> \n"); | ||
1895 | IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n", | ||
1896 | src_phys, dest_address, length); | ||
1897 | while (bytes_left > CB_MAX_LENGTH) { | ||
1898 | status = ipw_fw_dma_add_command_block( priv, | ||
1899 | src_phys + src_offset, | ||
1900 | dest_address + dest_offset, | ||
1901 | CB_MAX_LENGTH, 0, 0); | ||
1902 | if (status) { | ||
1903 | IPW_DEBUG_FW_INFO(": Failed\n"); | ||
1904 | return -1; | ||
1905 | } else | ||
1906 | IPW_DEBUG_FW_INFO(": Added new cb\n"); | ||
1907 | |||
1908 | src_offset += CB_MAX_LENGTH; | ||
1909 | dest_offset += CB_MAX_LENGTH; | ||
1910 | bytes_left -= CB_MAX_LENGTH; | ||
1911 | } | ||
1912 | |||
1913 | /* add the buffer tail */ | ||
1914 | if (bytes_left > 0) { | ||
1915 | status = ipw_fw_dma_add_command_block( | ||
1916 | priv, src_phys + src_offset, | ||
1917 | dest_address + dest_offset, | ||
1918 | bytes_left, 0, 0); | ||
1919 | if (status) { | ||
1920 | IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n"); | ||
1921 | return -1; | ||
1922 | } else | ||
1923 | IPW_DEBUG_FW_INFO(": Adding new cb - the buffer tail\n"); | ||
1924 | } | ||
1925 | |||
1926 | |||
1927 | IPW_DEBUG_FW("<< \n"); | ||
1928 | return 0; | ||
1929 | } | ||
1930 | |||
1931 | static int ipw_fw_dma_wait(struct ipw_priv *priv) | ||
1932 | { | ||
1933 | u32 current_index = 0; | ||
1934 | u32 watchdog = 0; | ||
1935 | |||
1936 | IPW_DEBUG_FW(">> : \n"); | ||
1937 | |||
1938 | current_index = ipw_fw_dma_command_block_index(priv); | ||
1939 | IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n", | ||
1940 | (int) priv->sram_desc.last_cb_index); | ||
1941 | |||
1942 | while (current_index < priv->sram_desc.last_cb_index) { | ||
1943 | udelay(50); | ||
1944 | current_index = ipw_fw_dma_command_block_index(priv); | ||
1945 | |||
1946 | watchdog++; | ||
1947 | |||
1948 | if (watchdog > 400) { | ||
1949 | IPW_DEBUG_FW_INFO("Timeout\n"); | ||
1950 | ipw_fw_dma_dump_command_block(priv); | ||
1951 | ipw_fw_dma_abort(priv); | ||
1952 | return -1; | ||
1953 | } | ||
1954 | } | ||
1955 | |||
1956 | ipw_fw_dma_abort(priv); | ||
1957 | |||
1958 | /*Disable the DMA in the CSR register*/ | ||
1959 | ipw_set_bit(priv, CX2_RESET_REG, | ||
1960 | CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER); | ||
1961 | |||
1962 | IPW_DEBUG_FW("<< dmaWaitSync \n"); | ||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1966 | static void ipw_remove_current_network(struct ipw_priv *priv) | ||
1967 | { | ||
1968 | struct list_head *element, *safe; | ||
1969 | struct ieee80211_network *network = NULL; | ||
1970 | list_for_each_safe(element, safe, &priv->ieee->network_list) { | ||
1971 | network = list_entry(element, struct ieee80211_network, list); | ||
1972 | if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { | ||
1973 | list_del(element); | ||
1974 | list_add_tail(&network->list, | ||
1975 | &priv->ieee->network_free_list); | ||
1976 | } | ||
1977 | } | ||
1978 | } | ||
1979 | |||
1980 | /** | ||
1981 | * Check that card is still alive. | ||
1982 | * Reads debug register from domain0. | ||
1983 | * If card is present, pre-defined value should | ||
1984 | * be found there. | ||
1985 | * | ||
1986 | * @param priv | ||
1987 | * @return 1 if card is present, 0 otherwise | ||
1988 | */ | ||
1989 | static inline int ipw_alive(struct ipw_priv *priv) | ||
1990 | { | ||
1991 | return ipw_read32(priv, 0x90) == 0xd55555d5; | ||
1992 | } | ||
1993 | |||
1994 | static inline int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask, | ||
1995 | int timeout) | ||
1996 | { | ||
1997 | int i = 0; | ||
1998 | |||
1999 | do { | ||
2000 | if ((ipw_read32(priv, addr) & mask) == mask) | ||
2001 | return i; | ||
2002 | mdelay(10); | ||
2003 | i += 10; | ||
2004 | } while (i < timeout); | ||
2005 | |||
2006 | return -ETIME; | ||
2007 | } | ||
2008 | |||
2009 | /* These functions load the firmware and micro code for the operation of | ||
2010 | * the ipw hardware. It assumes the buffer has all the bits for the | ||
2011 | * image and the caller is handling the memory allocation and clean up. | ||
2012 | */ | ||
2013 | |||
2014 | |||
2015 | static int ipw_stop_master(struct ipw_priv * priv) | ||
2016 | { | ||
2017 | int rc; | ||
2018 | |||
2019 | IPW_DEBUG_TRACE(">> \n"); | ||
2020 | /* stop master. typical delay - 0 */ | ||
2021 | ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER); | ||
2022 | |||
2023 | rc = ipw_poll_bit(priv, CX2_RESET_REG, | ||
2024 | CX2_RESET_REG_MASTER_DISABLED, 100); | ||
2025 | if (rc < 0) { | ||
2026 | IPW_ERROR("stop master failed in 10ms\n"); | ||
2027 | return -1; | ||
2028 | } | ||
2029 | |||
2030 | IPW_DEBUG_INFO("stop master %dms\n", rc); | ||
2031 | |||
2032 | return rc; | ||
2033 | } | ||
2034 | |||
2035 | static void ipw_arc_release(struct ipw_priv *priv) | ||
2036 | { | ||
2037 | IPW_DEBUG_TRACE(">> \n"); | ||
2038 | mdelay(5); | ||
2039 | |||
2040 | ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); | ||
2041 | |||
2042 | /* no one knows timing, for safety add some delay */ | ||
2043 | mdelay(5); | ||
2044 | } | ||
2045 | |||
2046 | struct fw_header { | ||
2047 | u32 version; | ||
2048 | u32 mode; | ||
2049 | }; | ||
2050 | |||
2051 | struct fw_chunk { | ||
2052 | u32 address; | ||
2053 | u32 length; | ||
2054 | }; | ||
2055 | |||
2056 | #define IPW_FW_MAJOR_VERSION 2 | ||
2057 | #define IPW_FW_MINOR_VERSION 2 | ||
2058 | |||
2059 | #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) | ||
2060 | #define IPW_FW_MAJOR(x) (x & 0xff) | ||
2061 | |||
2062 | #define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \ | ||
2063 | IPW_FW_MAJOR_VERSION) | ||
2064 | |||
2065 | #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ | ||
2066 | "." __stringify(IPW_FW_MINOR_VERSION) "-" | ||
2067 | |||
2068 | #if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0 | ||
2069 | #define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw" | ||
2070 | #else | ||
2071 | #define IPW_FW_NAME(x) "ipw2200_" x ".fw" | ||
2072 | #endif | ||
2073 | |||
2074 | static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, | ||
2075 | size_t len) | ||
2076 | { | ||
2077 | int rc = 0, i, addr; | ||
2078 | u8 cr = 0; | ||
2079 | u16 *image; | ||
2080 | |||
2081 | image = (u16 *)data; | ||
2082 | |||
2083 | IPW_DEBUG_TRACE(">> \n"); | ||
2084 | |||
2085 | rc = ipw_stop_master(priv); | ||
2086 | |||
2087 | if (rc < 0) | ||
2088 | return rc; | ||
2089 | |||
2090 | // spin_lock_irqsave(&priv->lock, flags); | ||
2091 | |||
2092 | for (addr = CX2_SHARED_LOWER_BOUND; | ||
2093 | addr < CX2_REGISTER_DOMAIN1_END; addr += 4) { | ||
2094 | ipw_write32(priv, addr, 0); | ||
2095 | } | ||
2096 | |||
2097 | /* no ucode (yet) */ | ||
2098 | memset(&priv->dino_alive, 0, sizeof(priv->dino_alive)); | ||
2099 | /* destroy DMA queues */ | ||
2100 | /* reset sequence */ | ||
2101 | |||
2102 | ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET ,CX2_BIT_HALT_RESET_ON); | ||
2103 | ipw_arc_release(priv); | ||
2104 | ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF); | ||
2105 | mdelay(1); | ||
2106 | |||
2107 | /* reset PHY */ | ||
2108 | ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN); | ||
2109 | mdelay(1); | ||
2110 | |||
2111 | ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0); | ||
2112 | mdelay(1); | ||
2113 | |||
2114 | /* enable ucode store */ | ||
2115 | ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0); | ||
2116 | ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS); | ||
2117 | mdelay(1); | ||
2118 | |||
2119 | /* write ucode */ | ||
2120 | /** | ||
2121 | * @bug | ||
2122 | * Do NOT set indirect address register once and then | ||
2123 | * store data to indirect data register in the loop. | ||
2124 | * It seems very reasonable, but in this case DINO do not | ||
2125 | * accept ucode. It is essential to set address each time. | ||
2126 | */ | ||
2127 | /* load new ipw uCode */ | ||
2128 | for (i = 0; i < len / 2; i++) | ||
2129 | ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]); | ||
2130 | |||
2131 | |||
2132 | /* enable DINO */ | ||
2133 | ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); | ||
2134 | ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, | ||
2135 | DINO_ENABLE_SYSTEM ); | ||
2136 | |||
2137 | /* this is where the igx / win driver deveates from the VAP driver.*/ | ||
2138 | |||
2139 | /* wait for alive response */ | ||
2140 | for (i = 0; i < 100; i++) { | ||
2141 | /* poll for incoming data */ | ||
2142 | cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS); | ||
2143 | if (cr & DINO_RXFIFO_DATA) | ||
2144 | break; | ||
2145 | mdelay(1); | ||
2146 | } | ||
2147 | |||
2148 | if (cr & DINO_RXFIFO_DATA) { | ||
2149 | /* alive_command_responce size is NOT multiple of 4 */ | ||
2150 | u32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4]; | ||
2151 | |||
2152 | for (i = 0; i < ARRAY_SIZE(response_buffer); i++) | ||
2153 | response_buffer[i] = | ||
2154 | ipw_read_reg32(priv, | ||
2155 | CX2_BASEBAND_RX_FIFO_READ); | ||
2156 | memcpy(&priv->dino_alive, response_buffer, | ||
2157 | sizeof(priv->dino_alive)); | ||
2158 | if (priv->dino_alive.alive_command == 1 | ||
2159 | && priv->dino_alive.ucode_valid == 1) { | ||
2160 | rc = 0; | ||
2161 | IPW_DEBUG_INFO( | ||
2162 | "Microcode OK, rev. %d (0x%x) dev. %d (0x%x) " | ||
2163 | "of %02d/%02d/%02d %02d:%02d\n", | ||
2164 | priv->dino_alive.software_revision, | ||
2165 | priv->dino_alive.software_revision, | ||
2166 | priv->dino_alive.device_identifier, | ||
2167 | priv->dino_alive.device_identifier, | ||
2168 | priv->dino_alive.time_stamp[0], | ||
2169 | priv->dino_alive.time_stamp[1], | ||
2170 | priv->dino_alive.time_stamp[2], | ||
2171 | priv->dino_alive.time_stamp[3], | ||
2172 | priv->dino_alive.time_stamp[4]); | ||
2173 | } else { | ||
2174 | IPW_DEBUG_INFO("Microcode is not alive\n"); | ||
2175 | rc = -EINVAL; | ||
2176 | } | ||
2177 | } else { | ||
2178 | IPW_DEBUG_INFO("No alive response from DINO\n"); | ||
2179 | rc = -ETIME; | ||
2180 | } | ||
2181 | |||
2182 | /* disable DINO, otherwise for some reason | ||
2183 | firmware have problem getting alive resp. */ | ||
2184 | ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); | ||
2185 | |||
2186 | // spin_unlock_irqrestore(&priv->lock, flags); | ||
2187 | |||
2188 | return rc; | ||
2189 | } | ||
2190 | |||
2191 | static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, | ||
2192 | size_t len) | ||
2193 | { | ||
2194 | int rc = -1; | ||
2195 | int offset = 0; | ||
2196 | struct fw_chunk *chunk; | ||
2197 | dma_addr_t shared_phys; | ||
2198 | u8 *shared_virt; | ||
2199 | |||
2200 | IPW_DEBUG_TRACE("<< : \n"); | ||
2201 | shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys); | ||
2202 | |||
2203 | if (!shared_virt) | ||
2204 | return -ENOMEM; | ||
2205 | |||
2206 | memmove(shared_virt, data, len); | ||
2207 | |||
2208 | /* Start the Dma */ | ||
2209 | rc = ipw_fw_dma_enable(priv); | ||
2210 | |||
2211 | if (priv->sram_desc.last_cb_index > 0) { | ||
2212 | /* the DMA is already ready this would be a bug. */ | ||
2213 | BUG(); | ||
2214 | goto out; | ||
2215 | } | ||
2216 | |||
2217 | do { | ||
2218 | chunk = (struct fw_chunk *)(data + offset); | ||
2219 | offset += sizeof(struct fw_chunk); | ||
2220 | /* build DMA packet and queue up for sending */ | ||
2221 | /* dma to chunk->address, the chunk->length bytes from data + | ||
2222 | * offeset*/ | ||
2223 | /* Dma loading */ | ||
2224 | rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, | ||
2225 | chunk->address, chunk->length); | ||
2226 | if (rc) { | ||
2227 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); | ||
2228 | goto out; | ||
2229 | } | ||
2230 | |||
2231 | offset += chunk->length; | ||
2232 | } while (offset < len); | ||
2233 | |||
2234 | /* Run the DMA and wait for the answer*/ | ||
2235 | rc = ipw_fw_dma_kick(priv); | ||
2236 | if (rc) { | ||
2237 | IPW_ERROR("dmaKick Failed\n"); | ||
2238 | goto out; | ||
2239 | } | ||
2240 | |||
2241 | rc = ipw_fw_dma_wait(priv); | ||
2242 | if (rc) { | ||
2243 | IPW_ERROR("dmaWaitSync Failed\n"); | ||
2244 | goto out; | ||
2245 | } | ||
2246 | out: | ||
2247 | pci_free_consistent( priv->pci_dev, len, shared_virt, shared_phys); | ||
2248 | return rc; | ||
2249 | } | ||
2250 | |||
2251 | /* stop nic */ | ||
2252 | static int ipw_stop_nic(struct ipw_priv *priv) | ||
2253 | { | ||
2254 | int rc = 0; | ||
2255 | |||
2256 | /* stop*/ | ||
2257 | ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER); | ||
2258 | |||
2259 | rc = ipw_poll_bit(priv, CX2_RESET_REG, | ||
2260 | CX2_RESET_REG_MASTER_DISABLED, 500); | ||
2261 | if (rc < 0) { | ||
2262 | IPW_ERROR("wait for reg master disabled failed\n"); | ||
2263 | return rc; | ||
2264 | } | ||
2265 | |||
2266 | ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); | ||
2267 | |||
2268 | return rc; | ||
2269 | } | ||
2270 | |||
2271 | static void ipw_start_nic(struct ipw_priv *priv) | ||
2272 | { | ||
2273 | IPW_DEBUG_TRACE(">>\n"); | ||
2274 | |||
2275 | /* prvHwStartNic release ARC*/ | ||
2276 | ipw_clear_bit(priv, CX2_RESET_REG, | ||
2277 | CX2_RESET_REG_MASTER_DISABLED | | ||
2278 | CX2_RESET_REG_STOP_MASTER | | ||
2279 | CBD_RESET_REG_PRINCETON_RESET); | ||
2280 | |||
2281 | /* enable power management */ | ||
2282 | ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); | ||
2283 | |||
2284 | IPW_DEBUG_TRACE("<<\n"); | ||
2285 | } | ||
2286 | |||
2287 | static int ipw_init_nic(struct ipw_priv *priv) | ||
2288 | { | ||
2289 | int rc; | ||
2290 | |||
2291 | IPW_DEBUG_TRACE(">>\n"); | ||
2292 | /* reset */ | ||
2293 | /*prvHwInitNic */ | ||
2294 | /* set "initialization complete" bit to move adapter to D0 state */ | ||
2295 | ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE); | ||
2296 | |||
2297 | /* low-level PLL activation */ | ||
2298 | ipw_write32(priv, CX2_READ_INT_REGISTER, CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER); | ||
2299 | |||
2300 | /* wait for clock stabilization */ | ||
2301 | rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW, | ||
2302 | CX2_GP_CNTRL_BIT_CLOCK_READY, 250); | ||
2303 | if (rc < 0 ) | ||
2304 | IPW_DEBUG_INFO("FAILED wait for clock stablization\n"); | ||
2305 | |||
2306 | /* assert SW reset */ | ||
2307 | ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET); | ||
2308 | |||
2309 | udelay(10); | ||
2310 | |||
2311 | /* set "initialization complete" bit to move adapter to D0 state */ | ||
2312 | ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE); | ||
2313 | |||
2314 | IPW_DEBUG_TRACE(">>\n"); | ||
2315 | return 0; | ||
2316 | } | ||
2317 | |||
2318 | |||
2319 | /* Call this function from process context, it will sleep in request_firmware. | ||
2320 | * Probe is an ok place to call this from. | ||
2321 | */ | ||
2322 | static int ipw_reset_nic(struct ipw_priv *priv) | ||
2323 | { | ||
2324 | int rc = 0; | ||
2325 | |||
2326 | IPW_DEBUG_TRACE(">>\n"); | ||
2327 | |||
2328 | rc = ipw_init_nic(priv); | ||
2329 | |||
2330 | /* Clear the 'host command active' bit... */ | ||
2331 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
2332 | wake_up_interruptible(&priv->wait_command_queue); | ||
2333 | |||
2334 | IPW_DEBUG_TRACE("<<\n"); | ||
2335 | return rc; | ||
2336 | } | ||
2337 | |||
2338 | static int ipw_get_fw(struct ipw_priv *priv, | ||
2339 | const struct firmware **fw, const char *name) | ||
2340 | { | ||
2341 | struct fw_header *header; | ||
2342 | int rc; | ||
2343 | |||
2344 | /* ask firmware_class module to get the boot firmware off disk */ | ||
2345 | rc = request_firmware(fw, name, &priv->pci_dev->dev); | ||
2346 | if (rc < 0) { | ||
2347 | IPW_ERROR("%s load failed: Reason %d\n", name, rc); | ||
2348 | return rc; | ||
2349 | } | ||
2350 | |||
2351 | header = (struct fw_header *)(*fw)->data; | ||
2352 | if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) { | ||
2353 | IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", | ||
2354 | name, | ||
2355 | IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION); | ||
2356 | return -EINVAL; | ||
2357 | } | ||
2358 | |||
2359 | IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", | ||
2360 | name, | ||
2361 | IPW_FW_MAJOR(header->version), | ||
2362 | IPW_FW_MINOR(header->version), | ||
2363 | (*fw)->size - sizeof(struct fw_header)); | ||
2364 | return 0; | ||
2365 | } | ||
2366 | |||
2367 | #define CX2_RX_BUF_SIZE (3000) | ||
2368 | |||
2369 | static inline void ipw_rx_queue_reset(struct ipw_priv *priv, | ||
2370 | struct ipw_rx_queue *rxq) | ||
2371 | { | ||
2372 | unsigned long flags; | ||
2373 | int i; | ||
2374 | |||
2375 | spin_lock_irqsave(&rxq->lock, flags); | ||
2376 | |||
2377 | INIT_LIST_HEAD(&rxq->rx_free); | ||
2378 | INIT_LIST_HEAD(&rxq->rx_used); | ||
2379 | |||
2380 | /* Fill the rx_used queue with _all_ of the Rx buffers */ | ||
2381 | for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { | ||
2382 | /* In the reset function, these buffers may have been allocated | ||
2383 | * to an SKB, so we need to unmap and free potential storage */ | ||
2384 | if (rxq->pool[i].skb != NULL) { | ||
2385 | pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, | ||
2386 | CX2_RX_BUF_SIZE, | ||
2387 | PCI_DMA_FROMDEVICE); | ||
2388 | dev_kfree_skb(rxq->pool[i].skb); | ||
2389 | } | ||
2390 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); | ||
2391 | } | ||
2392 | |||
2393 | /* Set us so that we have processed and used all buffers, but have | ||
2394 | * not restocked the Rx queue with fresh buffers */ | ||
2395 | rxq->read = rxq->write = 0; | ||
2396 | rxq->processed = RX_QUEUE_SIZE - 1; | ||
2397 | rxq->free_count = 0; | ||
2398 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
2399 | } | ||
2400 | |||
2401 | #ifdef CONFIG_PM | ||
2402 | static int fw_loaded = 0; | ||
2403 | static const struct firmware *bootfw = NULL; | ||
2404 | static const struct firmware *firmware = NULL; | ||
2405 | static const struct firmware *ucode = NULL; | ||
2406 | #endif | ||
2407 | |||
2408 | static int ipw_load(struct ipw_priv *priv) | ||
2409 | { | ||
2410 | #ifndef CONFIG_PM | ||
2411 | const struct firmware *bootfw = NULL; | ||
2412 | const struct firmware *firmware = NULL; | ||
2413 | const struct firmware *ucode = NULL; | ||
2414 | #endif | ||
2415 | int rc = 0, retries = 3; | ||
2416 | |||
2417 | #ifdef CONFIG_PM | ||
2418 | if (!fw_loaded) { | ||
2419 | #endif | ||
2420 | rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); | ||
2421 | if (rc) | ||
2422 | goto error; | ||
2423 | |||
2424 | switch (priv->ieee->iw_mode) { | ||
2425 | case IW_MODE_ADHOC: | ||
2426 | rc = ipw_get_fw(priv, &ucode, | ||
2427 | IPW_FW_NAME("ibss_ucode")); | ||
2428 | if (rc) | ||
2429 | goto error; | ||
2430 | |||
2431 | rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); | ||
2432 | break; | ||
2433 | |||
2434 | #ifdef CONFIG_IPW_PROMISC | ||
2435 | case IW_MODE_MONITOR: | ||
2436 | rc = ipw_get_fw(priv, &ucode, | ||
2437 | IPW_FW_NAME("ibss_ucode")); | ||
2438 | if (rc) | ||
2439 | goto error; | ||
2440 | |||
2441 | rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("sniffer")); | ||
2442 | break; | ||
2443 | #endif | ||
2444 | case IW_MODE_INFRA: | ||
2445 | rc = ipw_get_fw(priv, &ucode, | ||
2446 | IPW_FW_NAME("bss_ucode")); | ||
2447 | if (rc) | ||
2448 | goto error; | ||
2449 | |||
2450 | rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss")); | ||
2451 | break; | ||
2452 | |||
2453 | default: | ||
2454 | rc = -EINVAL; | ||
2455 | } | ||
2456 | |||
2457 | if (rc) | ||
2458 | goto error; | ||
2459 | |||
2460 | #ifdef CONFIG_PM | ||
2461 | fw_loaded = 1; | ||
2462 | } | ||
2463 | #endif | ||
2464 | |||
2465 | if (!priv->rxq) | ||
2466 | priv->rxq = ipw_rx_queue_alloc(priv); | ||
2467 | else | ||
2468 | ipw_rx_queue_reset(priv, priv->rxq); | ||
2469 | if (!priv->rxq) { | ||
2470 | IPW_ERROR("Unable to initialize Rx queue\n"); | ||
2471 | goto error; | ||
2472 | } | ||
2473 | |||
2474 | retry: | ||
2475 | /* Ensure interrupts are disabled */ | ||
2476 | ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); | ||
2477 | priv->status &= ~STATUS_INT_ENABLED; | ||
2478 | |||
2479 | /* ack pending interrupts */ | ||
2480 | ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); | ||
2481 | |||
2482 | ipw_stop_nic(priv); | ||
2483 | |||
2484 | rc = ipw_reset_nic(priv); | ||
2485 | if (rc) { | ||
2486 | IPW_ERROR("Unable to reset NIC\n"); | ||
2487 | goto error; | ||
2488 | } | ||
2489 | |||
2490 | ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND, | ||
2491 | CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND); | ||
2492 | |||
2493 | /* DMA the initial boot firmware into the device */ | ||
2494 | rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), | ||
2495 | bootfw->size - sizeof(struct fw_header)); | ||
2496 | if (rc < 0) { | ||
2497 | IPW_ERROR("Unable to load boot firmware\n"); | ||
2498 | goto error; | ||
2499 | } | ||
2500 | |||
2501 | /* kick start the device */ | ||
2502 | ipw_start_nic(priv); | ||
2503 | |||
2504 | /* wait for the device to finish it's initial startup sequence */ | ||
2505 | rc = ipw_poll_bit(priv, CX2_INTA_RW, | ||
2506 | CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500); | ||
2507 | if (rc < 0) { | ||
2508 | IPW_ERROR("device failed to boot initial fw image\n"); | ||
2509 | goto error; | ||
2510 | } | ||
2511 | IPW_DEBUG_INFO("initial device response after %dms\n", rc); | ||
2512 | |||
2513 | /* ack fw init done interrupt */ | ||
2514 | ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE); | ||
2515 | |||
2516 | /* DMA the ucode into the device */ | ||
2517 | rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), | ||
2518 | ucode->size - sizeof(struct fw_header)); | ||
2519 | if (rc < 0) { | ||
2520 | IPW_ERROR("Unable to load ucode\n"); | ||
2521 | goto error; | ||
2522 | } | ||
2523 | |||
2524 | /* stop nic */ | ||
2525 | ipw_stop_nic(priv); | ||
2526 | |||
2527 | /* DMA bss firmware into the device */ | ||
2528 | rc = ipw_load_firmware(priv, firmware->data + | ||
2529 | sizeof(struct fw_header), | ||
2530 | firmware->size - sizeof(struct fw_header)); | ||
2531 | if (rc < 0 ) { | ||
2532 | IPW_ERROR("Unable to load firmware\n"); | ||
2533 | goto error; | ||
2534 | } | ||
2535 | |||
2536 | ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); | ||
2537 | |||
2538 | rc = ipw_queue_reset(priv); | ||
2539 | if (rc) { | ||
2540 | IPW_ERROR("Unable to initialize queues\n"); | ||
2541 | goto error; | ||
2542 | } | ||
2543 | |||
2544 | /* Ensure interrupts are disabled */ | ||
2545 | ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); | ||
2546 | |||
2547 | /* kick start the device */ | ||
2548 | ipw_start_nic(priv); | ||
2549 | |||
2550 | if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) { | ||
2551 | if (retries > 0) { | ||
2552 | IPW_WARNING("Parity error. Retrying init.\n"); | ||
2553 | retries--; | ||
2554 | goto retry; | ||
2555 | } | ||
2556 | |||
2557 | IPW_ERROR("TODO: Handle parity error -- schedule restart?\n"); | ||
2558 | rc = -EIO; | ||
2559 | goto error; | ||
2560 | } | ||
2561 | |||
2562 | /* wait for the device */ | ||
2563 | rc = ipw_poll_bit(priv, CX2_INTA_RW, | ||
2564 | CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500); | ||
2565 | if (rc < 0) { | ||
2566 | IPW_ERROR("device failed to start after 500ms\n"); | ||
2567 | goto error; | ||
2568 | } | ||
2569 | IPW_DEBUG_INFO("device response after %dms\n", rc); | ||
2570 | |||
2571 | /* ack fw init done interrupt */ | ||
2572 | ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE); | ||
2573 | |||
2574 | /* read eeprom data and initialize the eeprom region of sram */ | ||
2575 | priv->eeprom_delay = 1; | ||
2576 | ipw_eeprom_init_sram(priv); | ||
2577 | |||
2578 | /* enable interrupts */ | ||
2579 | ipw_enable_interrupts(priv); | ||
2580 | |||
2581 | /* Ensure our queue has valid packets */ | ||
2582 | ipw_rx_queue_replenish(priv); | ||
2583 | |||
2584 | ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read); | ||
2585 | |||
2586 | /* ack pending interrupts */ | ||
2587 | ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); | ||
2588 | |||
2589 | #ifndef CONFIG_PM | ||
2590 | release_firmware(bootfw); | ||
2591 | release_firmware(ucode); | ||
2592 | release_firmware(firmware); | ||
2593 | #endif | ||
2594 | return 0; | ||
2595 | |||
2596 | error: | ||
2597 | if (priv->rxq) { | ||
2598 | ipw_rx_queue_free(priv, priv->rxq); | ||
2599 | priv->rxq = NULL; | ||
2600 | } | ||
2601 | ipw_tx_queue_free(priv); | ||
2602 | if (bootfw) | ||
2603 | release_firmware(bootfw); | ||
2604 | if (ucode) | ||
2605 | release_firmware(ucode); | ||
2606 | if (firmware) | ||
2607 | release_firmware(firmware); | ||
2608 | #ifdef CONFIG_PM | ||
2609 | fw_loaded = 0; | ||
2610 | bootfw = ucode = firmware = NULL; | ||
2611 | #endif | ||
2612 | |||
2613 | return rc; | ||
2614 | } | ||
2615 | |||
2616 | /** | ||
2617 | * DMA services | ||
2618 | * | ||
2619 | * Theory of operation | ||
2620 | * | ||
2621 | * A queue is a circular buffers with 'Read' and 'Write' pointers. | ||
2622 | * 2 empty entries always kept in the buffer to protect from overflow. | ||
2623 | * | ||
2624 | * For Tx queue, there are low mark and high mark limits. If, after queuing | ||
2625 | * the packet for Tx, free space become < low mark, Tx queue stopped. When | ||
2626 | * reclaiming packets (on 'tx done IRQ), if free space become > high mark, | ||
2627 | * Tx queue resumed. | ||
2628 | * | ||
2629 | * The IPW operates with six queues, one receive queue in the device's | ||
2630 | * sram, one transmit queue for sending commands to the device firmware, | ||
2631 | * and four transmit queues for data. | ||
2632 | * | ||
2633 | * The four transmit queues allow for performing quality of service (qos) | ||
2634 | * transmissions as per the 802.11 protocol. Currently Linux does not | ||
2635 | * provide a mechanism to the user for utilizing prioritized queues, so | ||
2636 | * we only utilize the first data transmit queue (queue1). | ||
2637 | */ | ||
2638 | |||
2639 | /** | ||
2640 | * Driver allocates buffers of this size for Rx | ||
2641 | */ | ||
2642 | |||
2643 | static inline int ipw_queue_space(const struct clx2_queue *q) | ||
2644 | { | ||
2645 | int s = q->last_used - q->first_empty; | ||
2646 | if (s <= 0) | ||
2647 | s += q->n_bd; | ||
2648 | s -= 2; /* keep some reserve to not confuse empty and full situations */ | ||
2649 | if (s < 0) | ||
2650 | s = 0; | ||
2651 | return s; | ||
2652 | } | ||
2653 | |||
2654 | static inline int ipw_queue_inc_wrap(int index, int n_bd) | ||
2655 | { | ||
2656 | return (++index == n_bd) ? 0 : index; | ||
2657 | } | ||
2658 | |||
2659 | /** | ||
2660 | * Initialize common DMA queue structure | ||
2661 | * | ||
2662 | * @param q queue to init | ||
2663 | * @param count Number of BD's to allocate. Should be power of 2 | ||
2664 | * @param read_register Address for 'read' register | ||
2665 | * (not offset within BAR, full address) | ||
2666 | * @param write_register Address for 'write' register | ||
2667 | * (not offset within BAR, full address) | ||
2668 | * @param base_register Address for 'base' register | ||
2669 | * (not offset within BAR, full address) | ||
2670 | * @param size Address for 'size' register | ||
2671 | * (not offset within BAR, full address) | ||
2672 | */ | ||
2673 | static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q, | ||
2674 | int count, u32 read, u32 write, | ||
2675 | u32 base, u32 size) | ||
2676 | { | ||
2677 | q->n_bd = count; | ||
2678 | |||
2679 | q->low_mark = q->n_bd / 4; | ||
2680 | if (q->low_mark < 4) | ||
2681 | q->low_mark = 4; | ||
2682 | |||
2683 | q->high_mark = q->n_bd / 8; | ||
2684 | if (q->high_mark < 2) | ||
2685 | q->high_mark = 2; | ||
2686 | |||
2687 | q->first_empty = q->last_used = 0; | ||
2688 | q->reg_r = read; | ||
2689 | q->reg_w = write; | ||
2690 | |||
2691 | ipw_write32(priv, base, q->dma_addr); | ||
2692 | ipw_write32(priv, size, count); | ||
2693 | ipw_write32(priv, read, 0); | ||
2694 | ipw_write32(priv, write, 0); | ||
2695 | |||
2696 | _ipw_read32(priv, 0x90); | ||
2697 | } | ||
2698 | |||
2699 | static int ipw_queue_tx_init(struct ipw_priv *priv, | ||
2700 | struct clx2_tx_queue *q, | ||
2701 | int count, u32 read, u32 write, | ||
2702 | u32 base, u32 size) | ||
2703 | { | ||
2704 | struct pci_dev *dev = priv->pci_dev; | ||
2705 | |||
2706 | q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL); | ||
2707 | if (!q->txb) { | ||
2708 | IPW_ERROR("vmalloc for auxilary BD structures failed\n"); | ||
2709 | return -ENOMEM; | ||
2710 | } | ||
2711 | |||
2712 | q->bd = pci_alloc_consistent(dev,sizeof(q->bd[0])*count, &q->q.dma_addr); | ||
2713 | if (!q->bd) { | ||
2714 | IPW_ERROR("pci_alloc_consistent(%zd) failed\n", | ||
2715 | sizeof(q->bd[0]) * count); | ||
2716 | kfree(q->txb); | ||
2717 | q->txb = NULL; | ||
2718 | return -ENOMEM; | ||
2719 | } | ||
2720 | |||
2721 | ipw_queue_init(priv, &q->q, count, read, write, base, size); | ||
2722 | return 0; | ||
2723 | } | ||
2724 | |||
2725 | /** | ||
2726 | * Free one TFD, those at index [txq->q.last_used]. | ||
2727 | * Do NOT advance any indexes | ||
2728 | * | ||
2729 | * @param dev | ||
2730 | * @param txq | ||
2731 | */ | ||
2732 | static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, | ||
2733 | struct clx2_tx_queue *txq) | ||
2734 | { | ||
2735 | struct tfd_frame *bd = &txq->bd[txq->q.last_used]; | ||
2736 | struct pci_dev *dev = priv->pci_dev; | ||
2737 | int i; | ||
2738 | |||
2739 | /* classify bd */ | ||
2740 | if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE) | ||
2741 | /* nothing to cleanup after for host commands */ | ||
2742 | return; | ||
2743 | |||
2744 | /* sanity check */ | ||
2745 | if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) { | ||
2746 | IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks); | ||
2747 | /** @todo issue fatal error, it is quite serious situation */ | ||
2748 | return; | ||
2749 | } | ||
2750 | |||
2751 | /* unmap chunks if any */ | ||
2752 | for (i = 0; i < bd->u.data.num_chunks; i++) { | ||
2753 | pci_unmap_single(dev, bd->u.data.chunk_ptr[i], | ||
2754 | bd->u.data.chunk_len[i], PCI_DMA_TODEVICE); | ||
2755 | if (txq->txb[txq->q.last_used]) { | ||
2756 | ieee80211_txb_free(txq->txb[txq->q.last_used]); | ||
2757 | txq->txb[txq->q.last_used] = NULL; | ||
2758 | } | ||
2759 | } | ||
2760 | } | ||
2761 | |||
2762 | /** | ||
2763 | * Deallocate DMA queue. | ||
2764 | * | ||
2765 | * Empty queue by removing and destroying all BD's. | ||
2766 | * Free all buffers. | ||
2767 | * | ||
2768 | * @param dev | ||
2769 | * @param q | ||
2770 | */ | ||
2771 | static void ipw_queue_tx_free(struct ipw_priv *priv, | ||
2772 | struct clx2_tx_queue *txq) | ||
2773 | { | ||
2774 | struct clx2_queue *q = &txq->q; | ||
2775 | struct pci_dev *dev = priv->pci_dev; | ||
2776 | |||
2777 | if (q->n_bd == 0) | ||
2778 | return; | ||
2779 | |||
2780 | /* first, empty all BD's */ | ||
2781 | for (; q->first_empty != q->last_used; | ||
2782 | q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { | ||
2783 | ipw_queue_tx_free_tfd(priv, txq); | ||
2784 | } | ||
2785 | |||
2786 | /* free buffers belonging to queue itself */ | ||
2787 | pci_free_consistent(dev, sizeof(txq->bd[0])*q->n_bd, txq->bd, | ||
2788 | q->dma_addr); | ||
2789 | kfree(txq->txb); | ||
2790 | |||
2791 | /* 0 fill whole structure */ | ||
2792 | memset(txq, 0, sizeof(*txq)); | ||
2793 | } | ||
2794 | |||
2795 | |||
2796 | /** | ||
2797 | * Destroy all DMA queues and structures | ||
2798 | * | ||
2799 | * @param priv | ||
2800 | */ | ||
2801 | static void ipw_tx_queue_free(struct ipw_priv *priv) | ||
2802 | { | ||
2803 | /* Tx CMD queue */ | ||
2804 | ipw_queue_tx_free(priv, &priv->txq_cmd); | ||
2805 | |||
2806 | /* Tx queues */ | ||
2807 | ipw_queue_tx_free(priv, &priv->txq[0]); | ||
2808 | ipw_queue_tx_free(priv, &priv->txq[1]); | ||
2809 | ipw_queue_tx_free(priv, &priv->txq[2]); | ||
2810 | ipw_queue_tx_free(priv, &priv->txq[3]); | ||
2811 | } | ||
2812 | |||
2813 | static void inline __maybe_wake_tx(struct ipw_priv *priv) | ||
2814 | { | ||
2815 | if (netif_running(priv->net_dev)) { | ||
2816 | switch (priv->port_type) { | ||
2817 | case DCR_TYPE_MU_BSS: | ||
2818 | case DCR_TYPE_MU_IBSS: | ||
2819 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
2820 | return; | ||
2821 | } | ||
2822 | } | ||
2823 | netif_wake_queue(priv->net_dev); | ||
2824 | } | ||
2825 | |||
2826 | } | ||
2827 | |||
2828 | static inline void ipw_create_bssid(struct ipw_priv *priv, u8 *bssid) | ||
2829 | { | ||
2830 | /* First 3 bytes are manufacturer */ | ||
2831 | bssid[0] = priv->mac_addr[0]; | ||
2832 | bssid[1] = priv->mac_addr[1]; | ||
2833 | bssid[2] = priv->mac_addr[2]; | ||
2834 | |||
2835 | /* Last bytes are random */ | ||
2836 | get_random_bytes(&bssid[3], ETH_ALEN-3); | ||
2837 | |||
2838 | bssid[0] &= 0xfe; /* clear multicast bit */ | ||
2839 | bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */ | ||
2840 | } | ||
2841 | |||
2842 | static inline u8 ipw_add_station(struct ipw_priv *priv, u8 *bssid) | ||
2843 | { | ||
2844 | struct ipw_station_entry entry; | ||
2845 | int i; | ||
2846 | |||
2847 | for (i = 0; i < priv->num_stations; i++) { | ||
2848 | if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { | ||
2849 | /* Another node is active in network */ | ||
2850 | priv->missed_adhoc_beacons = 0; | ||
2851 | if (!(priv->config & CFG_STATIC_CHANNEL)) | ||
2852 | /* when other nodes drop out, we drop out */ | ||
2853 | priv->config &= ~CFG_ADHOC_PERSIST; | ||
2854 | |||
2855 | return i; | ||
2856 | } | ||
2857 | } | ||
2858 | |||
2859 | if (i == MAX_STATIONS) | ||
2860 | return IPW_INVALID_STATION; | ||
2861 | |||
2862 | IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid)); | ||
2863 | |||
2864 | entry.reserved = 0; | ||
2865 | entry.support_mode = 0; | ||
2866 | memcpy(entry.mac_addr, bssid, ETH_ALEN); | ||
2867 | memcpy(priv->stations[i], bssid, ETH_ALEN); | ||
2868 | ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry), | ||
2869 | &entry, | ||
2870 | sizeof(entry)); | ||
2871 | priv->num_stations++; | ||
2872 | |||
2873 | return i; | ||
2874 | } | ||
2875 | |||
2876 | static inline u8 ipw_find_station(struct ipw_priv *priv, u8 *bssid) | ||
2877 | { | ||
2878 | int i; | ||
2879 | |||
2880 | for (i = 0; i < priv->num_stations; i++) | ||
2881 | if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) | ||
2882 | return i; | ||
2883 | |||
2884 | return IPW_INVALID_STATION; | ||
2885 | } | ||
2886 | |||
2887 | static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) | ||
2888 | { | ||
2889 | int err; | ||
2890 | |||
2891 | if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) { | ||
2892 | IPW_DEBUG_ASSOC("Disassociating while not associated.\n"); | ||
2893 | return; | ||
2894 | } | ||
2895 | |||
2896 | IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " " | ||
2897 | "on channel %d.\n", | ||
2898 | MAC_ARG(priv->assoc_request.bssid), | ||
2899 | priv->assoc_request.channel); | ||
2900 | |||
2901 | priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); | ||
2902 | priv->status |= STATUS_DISASSOCIATING; | ||
2903 | |||
2904 | if (quiet) | ||
2905 | priv->assoc_request.assoc_type = HC_DISASSOC_QUIET; | ||
2906 | else | ||
2907 | priv->assoc_request.assoc_type = HC_DISASSOCIATE; | ||
2908 | err = ipw_send_associate(priv, &priv->assoc_request); | ||
2909 | if (err) { | ||
2910 | IPW_DEBUG_HC("Attempt to send [dis]associate command " | ||
2911 | "failed.\n"); | ||
2912 | return; | ||
2913 | } | ||
2914 | |||
2915 | } | ||
2916 | |||
2917 | static void ipw_disassociate(void *data) | ||
2918 | { | ||
2919 | ipw_send_disassociate(data, 0); | ||
2920 | } | ||
2921 | |||
2922 | static void notify_wx_assoc_event(struct ipw_priv *priv) | ||
2923 | { | ||
2924 | union iwreq_data wrqu; | ||
2925 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
2926 | if (priv->status & STATUS_ASSOCIATED) | ||
2927 | memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); | ||
2928 | else | ||
2929 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
2930 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
2931 | } | ||
2932 | |||
2933 | struct ipw_status_code { | ||
2934 | u16 status; | ||
2935 | const char *reason; | ||
2936 | }; | ||
2937 | |||
2938 | static const struct ipw_status_code ipw_status_codes[] = { | ||
2939 | {0x00, "Successful"}, | ||
2940 | {0x01, "Unspecified failure"}, | ||
2941 | {0x0A, "Cannot support all requested capabilities in the " | ||
2942 | "Capability information field"}, | ||
2943 | {0x0B, "Reassociation denied due to inability to confirm that " | ||
2944 | "association exists"}, | ||
2945 | {0x0C, "Association denied due to reason outside the scope of this " | ||
2946 | "standard"}, | ||
2947 | {0x0D, "Responding station does not support the specified authentication " | ||
2948 | "algorithm"}, | ||
2949 | {0x0E, "Received an Authentication frame with authentication sequence " | ||
2950 | "transaction sequence number out of expected sequence"}, | ||
2951 | {0x0F, "Authentication rejected because of challenge failure"}, | ||
2952 | {0x10, "Authentication rejected due to timeout waiting for next " | ||
2953 | "frame in sequence"}, | ||
2954 | {0x11, "Association denied because AP is unable to handle additional " | ||
2955 | "associated stations"}, | ||
2956 | {0x12, "Association denied due to requesting station not supporting all " | ||
2957 | "of the datarates in the BSSBasicServiceSet Parameter"}, | ||
2958 | {0x13, "Association denied due to requesting station not supporting " | ||
2959 | "short preamble operation"}, | ||
2960 | {0x14, "Association denied due to requesting station not supporting " | ||
2961 | "PBCC encoding"}, | ||
2962 | {0x15, "Association denied due to requesting station not supporting " | ||
2963 | "channel agility"}, | ||
2964 | {0x19, "Association denied due to requesting station not supporting " | ||
2965 | "short slot operation"}, | ||
2966 | {0x1A, "Association denied due to requesting station not supporting " | ||
2967 | "DSSS-OFDM operation"}, | ||
2968 | {0x28, "Invalid Information Element"}, | ||
2969 | {0x29, "Group Cipher is not valid"}, | ||
2970 | {0x2A, "Pairwise Cipher is not valid"}, | ||
2971 | {0x2B, "AKMP is not valid"}, | ||
2972 | {0x2C, "Unsupported RSN IE version"}, | ||
2973 | {0x2D, "Invalid RSN IE Capabilities"}, | ||
2974 | {0x2E, "Cipher suite is rejected per security policy"}, | ||
2975 | }; | ||
2976 | |||
2977 | #ifdef CONFIG_IPW_DEBUG | ||
2978 | static const char *ipw_get_status_code(u16 status) | ||
2979 | { | ||
2980 | int i; | ||
2981 | for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) | ||
2982 | if (ipw_status_codes[i].status == status) | ||
2983 | return ipw_status_codes[i].reason; | ||
2984 | return "Unknown status value."; | ||
2985 | } | ||
2986 | #endif | ||
2987 | |||
2988 | static void inline average_init(struct average *avg) | ||
2989 | { | ||
2990 | memset(avg, 0, sizeof(*avg)); | ||
2991 | } | ||
2992 | |||
2993 | static void inline average_add(struct average *avg, s16 val) | ||
2994 | { | ||
2995 | avg->sum -= avg->entries[avg->pos]; | ||
2996 | avg->sum += val; | ||
2997 | avg->entries[avg->pos++] = val; | ||
2998 | if (unlikely(avg->pos == AVG_ENTRIES)) { | ||
2999 | avg->init = 1; | ||
3000 | avg->pos = 0; | ||
3001 | } | ||
3002 | } | ||
3003 | |||
3004 | static s16 inline average_value(struct average *avg) | ||
3005 | { | ||
3006 | if (!unlikely(avg->init)) { | ||
3007 | if (avg->pos) | ||
3008 | return avg->sum / avg->pos; | ||
3009 | return 0; | ||
3010 | } | ||
3011 | |||
3012 | return avg->sum / AVG_ENTRIES; | ||
3013 | } | ||
3014 | |||
3015 | static void ipw_reset_stats(struct ipw_priv *priv) | ||
3016 | { | ||
3017 | u32 len = sizeof(u32); | ||
3018 | |||
3019 | priv->quality = 0; | ||
3020 | |||
3021 | average_init(&priv->average_missed_beacons); | ||
3022 | average_init(&priv->average_rssi); | ||
3023 | average_init(&priv->average_noise); | ||
3024 | |||
3025 | priv->last_rate = 0; | ||
3026 | priv->last_missed_beacons = 0; | ||
3027 | priv->last_rx_packets = 0; | ||
3028 | priv->last_tx_packets = 0; | ||
3029 | priv->last_tx_failures = 0; | ||
3030 | |||
3031 | /* Firmware managed, reset only when NIC is restarted, so we have to | ||
3032 | * normalize on the current value */ | ||
3033 | ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, | ||
3034 | &priv->last_rx_err, &len); | ||
3035 | ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, | ||
3036 | &priv->last_tx_failures, &len); | ||
3037 | |||
3038 | /* Driver managed, reset with each association */ | ||
3039 | priv->missed_adhoc_beacons = 0; | ||
3040 | priv->missed_beacons = 0; | ||
3041 | priv->tx_packets = 0; | ||
3042 | priv->rx_packets = 0; | ||
3043 | |||
3044 | } | ||
3045 | |||
3046 | |||
3047 | static inline u32 ipw_get_max_rate(struct ipw_priv *priv) | ||
3048 | { | ||
3049 | u32 i = 0x80000000; | ||
3050 | u32 mask = priv->rates_mask; | ||
3051 | /* If currently associated in B mode, restrict the maximum | ||
3052 | * rate match to B rates */ | ||
3053 | if (priv->assoc_request.ieee_mode == IPW_B_MODE) | ||
3054 | mask &= IEEE80211_CCK_RATES_MASK; | ||
3055 | |||
3056 | /* TODO: Verify that the rate is supported by the current rates | ||
3057 | * list. */ | ||
3058 | |||
3059 | while (i && !(mask & i)) i >>= 1; | ||
3060 | switch (i) { | ||
3061 | case IEEE80211_CCK_RATE_1MB_MASK: return 1000000; | ||
3062 | case IEEE80211_CCK_RATE_2MB_MASK: return 2000000; | ||
3063 | case IEEE80211_CCK_RATE_5MB_MASK: return 5500000; | ||
3064 | case IEEE80211_OFDM_RATE_6MB_MASK: return 6000000; | ||
3065 | case IEEE80211_OFDM_RATE_9MB_MASK: return 9000000; | ||
3066 | case IEEE80211_CCK_RATE_11MB_MASK: return 11000000; | ||
3067 | case IEEE80211_OFDM_RATE_12MB_MASK: return 12000000; | ||
3068 | case IEEE80211_OFDM_RATE_18MB_MASK: return 18000000; | ||
3069 | case IEEE80211_OFDM_RATE_24MB_MASK: return 24000000; | ||
3070 | case IEEE80211_OFDM_RATE_36MB_MASK: return 36000000; | ||
3071 | case IEEE80211_OFDM_RATE_48MB_MASK: return 48000000; | ||
3072 | case IEEE80211_OFDM_RATE_54MB_MASK: return 54000000; | ||
3073 | } | ||
3074 | |||
3075 | if (priv->ieee->mode == IEEE_B) | ||
3076 | return 11000000; | ||
3077 | else | ||
3078 | return 54000000; | ||
3079 | } | ||
3080 | |||
3081 | static u32 ipw_get_current_rate(struct ipw_priv *priv) | ||
3082 | { | ||
3083 | u32 rate, len = sizeof(rate); | ||
3084 | int err; | ||
3085 | |||
3086 | if (!(priv->status & STATUS_ASSOCIATED)) | ||
3087 | return 0; | ||
3088 | |||
3089 | if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) { | ||
3090 | err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate, | ||
3091 | &len); | ||
3092 | if (err) { | ||
3093 | IPW_DEBUG_INFO("failed querying ordinals.\n"); | ||
3094 | return 0; | ||
3095 | } | ||
3096 | } else | ||
3097 | return ipw_get_max_rate(priv); | ||
3098 | |||
3099 | switch (rate) { | ||
3100 | case IPW_TX_RATE_1MB: return 1000000; | ||
3101 | case IPW_TX_RATE_2MB: return 2000000; | ||
3102 | case IPW_TX_RATE_5MB: return 5500000; | ||
3103 | case IPW_TX_RATE_6MB: return 6000000; | ||
3104 | case IPW_TX_RATE_9MB: return 9000000; | ||
3105 | case IPW_TX_RATE_11MB: return 11000000; | ||
3106 | case IPW_TX_RATE_12MB: return 12000000; | ||
3107 | case IPW_TX_RATE_18MB: return 18000000; | ||
3108 | case IPW_TX_RATE_24MB: return 24000000; | ||
3109 | case IPW_TX_RATE_36MB: return 36000000; | ||
3110 | case IPW_TX_RATE_48MB: return 48000000; | ||
3111 | case IPW_TX_RATE_54MB: return 54000000; | ||
3112 | } | ||
3113 | |||
3114 | return 0; | ||
3115 | } | ||
3116 | |||
3117 | #define PERFECT_RSSI (-50) | ||
3118 | #define WORST_RSSI (-85) | ||
3119 | #define IPW_STATS_INTERVAL (2 * HZ) | ||
3120 | static void ipw_gather_stats(struct ipw_priv *priv) | ||
3121 | { | ||
3122 | u32 rx_err, rx_err_delta, rx_packets_delta; | ||
3123 | u32 tx_failures, tx_failures_delta, tx_packets_delta; | ||
3124 | u32 missed_beacons_percent, missed_beacons_delta; | ||
3125 | u32 quality = 0; | ||
3126 | u32 len = sizeof(u32); | ||
3127 | s16 rssi; | ||
3128 | u32 beacon_quality, signal_quality, tx_quality, rx_quality, | ||
3129 | rate_quality; | ||
3130 | |||
3131 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
3132 | priv->quality = 0; | ||
3133 | return; | ||
3134 | } | ||
3135 | |||
3136 | /* Update the statistics */ | ||
3137 | ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS, | ||
3138 | &priv->missed_beacons, &len); | ||
3139 | missed_beacons_delta = priv->missed_beacons - | ||
3140 | priv->last_missed_beacons; | ||
3141 | priv->last_missed_beacons = priv->missed_beacons; | ||
3142 | if (priv->assoc_request.beacon_interval) { | ||
3143 | missed_beacons_percent = missed_beacons_delta * | ||
3144 | (HZ * priv->assoc_request.beacon_interval) / | ||
3145 | (IPW_STATS_INTERVAL * 10); | ||
3146 | } else { | ||
3147 | missed_beacons_percent = 0; | ||
3148 | } | ||
3149 | average_add(&priv->average_missed_beacons, missed_beacons_percent); | ||
3150 | |||
3151 | ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len); | ||
3152 | rx_err_delta = rx_err - priv->last_rx_err; | ||
3153 | priv->last_rx_err = rx_err; | ||
3154 | |||
3155 | ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len); | ||
3156 | tx_failures_delta = tx_failures - priv->last_tx_failures; | ||
3157 | priv->last_tx_failures = tx_failures; | ||
3158 | |||
3159 | rx_packets_delta = priv->rx_packets - priv->last_rx_packets; | ||
3160 | priv->last_rx_packets = priv->rx_packets; | ||
3161 | |||
3162 | tx_packets_delta = priv->tx_packets - priv->last_tx_packets; | ||
3163 | priv->last_tx_packets = priv->tx_packets; | ||
3164 | |||
3165 | /* Calculate quality based on the following: | ||
3166 | * | ||
3167 | * Missed beacon: 100% = 0, 0% = 70% missed | ||
3168 | * Rate: 60% = 1Mbs, 100% = Max | ||
3169 | * Rx and Tx errors represent a straight % of total Rx/Tx | ||
3170 | * RSSI: 100% = > -50, 0% = < -80 | ||
3171 | * Rx errors: 100% = 0, 0% = 50% missed | ||
3172 | * | ||
3173 | * The lowest computed quality is used. | ||
3174 | * | ||
3175 | */ | ||
3176 | #define BEACON_THRESHOLD 5 | ||
3177 | beacon_quality = 100 - missed_beacons_percent; | ||
3178 | if (beacon_quality < BEACON_THRESHOLD) | ||
3179 | beacon_quality = 0; | ||
3180 | else | ||
3181 | beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 / | ||
3182 | (100 - BEACON_THRESHOLD); | ||
3183 | IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n", | ||
3184 | beacon_quality, missed_beacons_percent); | ||
3185 | |||
3186 | priv->last_rate = ipw_get_current_rate(priv); | ||
3187 | rate_quality = priv->last_rate * 40 / priv->last_rate + 60; | ||
3188 | IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", | ||
3189 | rate_quality, priv->last_rate / 1000000); | ||
3190 | |||
3191 | if (rx_packets_delta > 100 && | ||
3192 | rx_packets_delta + rx_err_delta) | ||
3193 | rx_quality = 100 - (rx_err_delta * 100) / | ||
3194 | (rx_packets_delta + rx_err_delta); | ||
3195 | else | ||
3196 | rx_quality = 100; | ||
3197 | IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n", | ||
3198 | rx_quality, rx_err_delta, rx_packets_delta); | ||
3199 | |||
3200 | if (tx_packets_delta > 100 && | ||
3201 | tx_packets_delta + tx_failures_delta) | ||
3202 | tx_quality = 100 - (tx_failures_delta * 100) / | ||
3203 | (tx_packets_delta + tx_failures_delta); | ||
3204 | else | ||
3205 | tx_quality = 100; | ||
3206 | IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n", | ||
3207 | tx_quality, tx_failures_delta, tx_packets_delta); | ||
3208 | |||
3209 | rssi = average_value(&priv->average_rssi); | ||
3210 | if (rssi > PERFECT_RSSI) | ||
3211 | signal_quality = 100; | ||
3212 | else if (rssi < WORST_RSSI) | ||
3213 | signal_quality = 0; | ||
3214 | else | ||
3215 | signal_quality = (rssi - WORST_RSSI) * 100 / | ||
3216 | (PERFECT_RSSI - WORST_RSSI); | ||
3217 | IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", | ||
3218 | signal_quality, rssi); | ||
3219 | |||
3220 | quality = min(beacon_quality, | ||
3221 | min(rate_quality, | ||
3222 | min(tx_quality, min(rx_quality, signal_quality)))); | ||
3223 | if (quality == beacon_quality) | ||
3224 | IPW_DEBUG_STATS( | ||
3225 | "Quality (%d%%): Clamped to missed beacons.\n", | ||
3226 | quality); | ||
3227 | if (quality == rate_quality) | ||
3228 | IPW_DEBUG_STATS( | ||
3229 | "Quality (%d%%): Clamped to rate quality.\n", | ||
3230 | quality); | ||
3231 | if (quality == tx_quality) | ||
3232 | IPW_DEBUG_STATS( | ||
3233 | "Quality (%d%%): Clamped to Tx quality.\n", | ||
3234 | quality); | ||
3235 | if (quality == rx_quality) | ||
3236 | IPW_DEBUG_STATS( | ||
3237 | "Quality (%d%%): Clamped to Rx quality.\n", | ||
3238 | quality); | ||
3239 | if (quality == signal_quality) | ||
3240 | IPW_DEBUG_STATS( | ||
3241 | "Quality (%d%%): Clamped to signal quality.\n", | ||
3242 | quality); | ||
3243 | |||
3244 | priv->quality = quality; | ||
3245 | |||
3246 | queue_delayed_work(priv->workqueue, &priv->gather_stats, | ||
3247 | IPW_STATS_INTERVAL); | ||
3248 | } | ||
3249 | |||
3250 | /** | ||
3251 | * Handle host notification packet. | ||
3252 | * Called from interrupt routine | ||
3253 | */ | ||
3254 | static inline void ipw_rx_notification(struct ipw_priv* priv, | ||
3255 | struct ipw_rx_notification *notif) | ||
3256 | { | ||
3257 | IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", | ||
3258 | notif->subtype, notif->size); | ||
3259 | |||
3260 | switch (notif->subtype) { | ||
3261 | case HOST_NOTIFICATION_STATUS_ASSOCIATED: { | ||
3262 | struct notif_association *assoc = ¬if->u.assoc; | ||
3263 | |||
3264 | switch (assoc->state) { | ||
3265 | case CMAS_ASSOCIATED: { | ||
3266 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3267 | "associated: '%s' " MAC_FMT " \n", | ||
3268 | escape_essid(priv->essid, priv->essid_len), | ||
3269 | MAC_ARG(priv->bssid)); | ||
3270 | |||
3271 | switch (priv->ieee->iw_mode) { | ||
3272 | case IW_MODE_INFRA: | ||
3273 | memcpy(priv->ieee->bssid, priv->bssid, | ||
3274 | ETH_ALEN); | ||
3275 | break; | ||
3276 | |||
3277 | case IW_MODE_ADHOC: | ||
3278 | memcpy(priv->ieee->bssid, priv->bssid, | ||
3279 | ETH_ALEN); | ||
3280 | |||
3281 | /* clear out the station table */ | ||
3282 | priv->num_stations = 0; | ||
3283 | |||
3284 | IPW_DEBUG_ASSOC("queueing adhoc check\n"); | ||
3285 | queue_delayed_work(priv->workqueue, | ||
3286 | &priv->adhoc_check, | ||
3287 | priv->assoc_request.beacon_interval); | ||
3288 | break; | ||
3289 | } | ||
3290 | |||
3291 | priv->status &= ~STATUS_ASSOCIATING; | ||
3292 | priv->status |= STATUS_ASSOCIATED; | ||
3293 | |||
3294 | netif_carrier_on(priv->net_dev); | ||
3295 | if (netif_queue_stopped(priv->net_dev)) { | ||
3296 | IPW_DEBUG_NOTIF("waking queue\n"); | ||
3297 | netif_wake_queue(priv->net_dev); | ||
3298 | } else { | ||
3299 | IPW_DEBUG_NOTIF("starting queue\n"); | ||
3300 | netif_start_queue(priv->net_dev); | ||
3301 | } | ||
3302 | |||
3303 | ipw_reset_stats(priv); | ||
3304 | /* Ensure the rate is updated immediately */ | ||
3305 | priv->last_rate = ipw_get_current_rate(priv); | ||
3306 | schedule_work(&priv->gather_stats); | ||
3307 | notify_wx_assoc_event(priv); | ||
3308 | |||
3309 | /* queue_delayed_work(priv->workqueue, | ||
3310 | &priv->request_scan, | ||
3311 | SCAN_ASSOCIATED_INTERVAL); | ||
3312 | */ | ||
3313 | break; | ||
3314 | } | ||
3315 | |||
3316 | case CMAS_AUTHENTICATED: { | ||
3317 | if (priv->status & (STATUS_ASSOCIATED | STATUS_AUTH)) { | ||
3318 | #ifdef CONFIG_IPW_DEBUG | ||
3319 | struct notif_authenticate *auth = ¬if->u.auth; | ||
3320 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3321 | "deauthenticated: '%s' " MAC_FMT ": (0x%04X) - %s \n", | ||
3322 | escape_essid(priv->essid, priv->essid_len), | ||
3323 | MAC_ARG(priv->bssid), | ||
3324 | ntohs(auth->status), | ||
3325 | ipw_get_status_code(ntohs(auth->status))); | ||
3326 | #endif | ||
3327 | |||
3328 | priv->status &= ~(STATUS_ASSOCIATING | | ||
3329 | STATUS_AUTH | | ||
3330 | STATUS_ASSOCIATED); | ||
3331 | |||
3332 | netif_carrier_off(priv->net_dev); | ||
3333 | netif_stop_queue(priv->net_dev); | ||
3334 | queue_work(priv->workqueue, &priv->request_scan); | ||
3335 | notify_wx_assoc_event(priv); | ||
3336 | break; | ||
3337 | } | ||
3338 | |||
3339 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3340 | "authenticated: '%s' " MAC_FMT "\n", | ||
3341 | escape_essid(priv->essid, priv->essid_len), | ||
3342 | MAC_ARG(priv->bssid)); | ||
3343 | break; | ||
3344 | } | ||
3345 | |||
3346 | case CMAS_INIT: { | ||
3347 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3348 | "disassociated: '%s' " MAC_FMT " \n", | ||
3349 | escape_essid(priv->essid, priv->essid_len), | ||
3350 | MAC_ARG(priv->bssid)); | ||
3351 | |||
3352 | priv->status &= ~( | ||
3353 | STATUS_DISASSOCIATING | | ||
3354 | STATUS_ASSOCIATING | | ||
3355 | STATUS_ASSOCIATED | | ||
3356 | STATUS_AUTH); | ||
3357 | |||
3358 | netif_stop_queue(priv->net_dev); | ||
3359 | if (!(priv->status & STATUS_ROAMING)) { | ||
3360 | netif_carrier_off(priv->net_dev); | ||
3361 | notify_wx_assoc_event(priv); | ||
3362 | |||
3363 | /* Cancel any queued work ... */ | ||
3364 | cancel_delayed_work(&priv->request_scan); | ||
3365 | cancel_delayed_work(&priv->adhoc_check); | ||
3366 | |||
3367 | /* Queue up another scan... */ | ||
3368 | queue_work(priv->workqueue, | ||
3369 | &priv->request_scan); | ||
3370 | |||
3371 | cancel_delayed_work(&priv->gather_stats); | ||
3372 | } else { | ||
3373 | priv->status |= STATUS_ROAMING; | ||
3374 | queue_work(priv->workqueue, | ||
3375 | &priv->request_scan); | ||
3376 | } | ||
3377 | |||
3378 | ipw_reset_stats(priv); | ||
3379 | break; | ||
3380 | } | ||
3381 | |||
3382 | default: | ||
3383 | IPW_ERROR("assoc: unknown (%d)\n", | ||
3384 | assoc->state); | ||
3385 | break; | ||
3386 | } | ||
3387 | |||
3388 | break; | ||
3389 | } | ||
3390 | |||
3391 | case HOST_NOTIFICATION_STATUS_AUTHENTICATE: { | ||
3392 | struct notif_authenticate *auth = ¬if->u.auth; | ||
3393 | switch (auth->state) { | ||
3394 | case CMAS_AUTHENTICATED: | ||
3395 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3396 | "authenticated: '%s' " MAC_FMT " \n", | ||
3397 | escape_essid(priv->essid, priv->essid_len), | ||
3398 | MAC_ARG(priv->bssid)); | ||
3399 | priv->status |= STATUS_AUTH; | ||
3400 | break; | ||
3401 | |||
3402 | case CMAS_INIT: | ||
3403 | if (priv->status & STATUS_AUTH) { | ||
3404 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3405 | "authentication failed (0x%04X): %s\n", | ||
3406 | ntohs(auth->status), | ||
3407 | ipw_get_status_code(ntohs(auth->status))); | ||
3408 | } | ||
3409 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3410 | "deauthenticated: '%s' " MAC_FMT "\n", | ||
3411 | escape_essid(priv->essid, priv->essid_len), | ||
3412 | MAC_ARG(priv->bssid)); | ||
3413 | |||
3414 | priv->status &= ~(STATUS_ASSOCIATING | | ||
3415 | STATUS_AUTH | | ||
3416 | STATUS_ASSOCIATED); | ||
3417 | |||
3418 | netif_carrier_off(priv->net_dev); | ||
3419 | netif_stop_queue(priv->net_dev); | ||
3420 | queue_work(priv->workqueue, &priv->request_scan); | ||
3421 | notify_wx_assoc_event(priv); | ||
3422 | break; | ||
3423 | |||
3424 | case CMAS_TX_AUTH_SEQ_1: | ||
3425 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3426 | "AUTH_SEQ_1\n"); | ||
3427 | break; | ||
3428 | case CMAS_RX_AUTH_SEQ_2: | ||
3429 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3430 | "AUTH_SEQ_2\n"); | ||
3431 | break; | ||
3432 | case CMAS_AUTH_SEQ_1_PASS: | ||
3433 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3434 | "AUTH_SEQ_1_PASS\n"); | ||
3435 | break; | ||
3436 | case CMAS_AUTH_SEQ_1_FAIL: | ||
3437 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3438 | "AUTH_SEQ_1_FAIL\n"); | ||
3439 | break; | ||
3440 | case CMAS_TX_AUTH_SEQ_3: | ||
3441 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3442 | "AUTH_SEQ_3\n"); | ||
3443 | break; | ||
3444 | case CMAS_RX_AUTH_SEQ_4: | ||
3445 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3446 | "RX_AUTH_SEQ_4\n"); | ||
3447 | break; | ||
3448 | case CMAS_AUTH_SEQ_2_PASS: | ||
3449 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3450 | "AUTH_SEQ_2_PASS\n"); | ||
3451 | break; | ||
3452 | case CMAS_AUTH_SEQ_2_FAIL: | ||
3453 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3454 | "AUT_SEQ_2_FAIL\n"); | ||
3455 | break; | ||
3456 | case CMAS_TX_ASSOC: | ||
3457 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3458 | "TX_ASSOC\n"); | ||
3459 | break; | ||
3460 | case CMAS_RX_ASSOC_RESP: | ||
3461 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3462 | "RX_ASSOC_RESP\n"); | ||
3463 | break; | ||
3464 | case CMAS_ASSOCIATED: | ||
3465 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, | ||
3466 | "ASSOCIATED\n"); | ||
3467 | break; | ||
3468 | default: | ||
3469 | IPW_DEBUG_NOTIF("auth: failure - %d\n", auth->state); | ||
3470 | break; | ||
3471 | } | ||
3472 | break; | ||
3473 | } | ||
3474 | |||
3475 | case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT: { | ||
3476 | struct notif_channel_result *x = ¬if->u.channel_result; | ||
3477 | |||
3478 | if (notif->size == sizeof(*x)) { | ||
3479 | IPW_DEBUG_SCAN("Scan result for channel %d\n", | ||
3480 | x->channel_num); | ||
3481 | } else { | ||
3482 | IPW_DEBUG_SCAN("Scan result of wrong size %d " | ||
3483 | "(should be %zd)\n", | ||
3484 | notif->size, sizeof(*x)); | ||
3485 | } | ||
3486 | break; | ||
3487 | } | ||
3488 | |||
3489 | case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED: { | ||
3490 | struct notif_scan_complete* x = ¬if->u.scan_complete; | ||
3491 | if (notif->size == sizeof(*x)) { | ||
3492 | IPW_DEBUG_SCAN("Scan completed: type %d, %d channels, " | ||
3493 | "%d status\n", | ||
3494 | x->scan_type, | ||
3495 | x->num_channels, | ||
3496 | x->status); | ||
3497 | } else { | ||
3498 | IPW_ERROR("Scan completed of wrong size %d " | ||
3499 | "(should be %zd)\n", | ||
3500 | notif->size, sizeof(*x)); | ||
3501 | } | ||
3502 | |||
3503 | priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); | ||
3504 | |||
3505 | cancel_delayed_work(&priv->scan_check); | ||
3506 | |||
3507 | if (!(priv->status & (STATUS_ASSOCIATED | | ||
3508 | STATUS_ASSOCIATING | | ||
3509 | STATUS_ROAMING | | ||
3510 | STATUS_DISASSOCIATING))) | ||
3511 | queue_work(priv->workqueue, &priv->associate); | ||
3512 | else if (priv->status & STATUS_ROAMING) { | ||
3513 | /* If a scan completed and we are in roam mode, then | ||
3514 | * the scan that completed was the one requested as a | ||
3515 | * result of entering roam... so, schedule the | ||
3516 | * roam work */ | ||
3517 | queue_work(priv->workqueue, &priv->roam); | ||
3518 | } else if (priv->status & STATUS_SCAN_PENDING) | ||
3519 | queue_work(priv->workqueue, &priv->request_scan); | ||
3520 | |||
3521 | priv->ieee->scans++; | ||
3522 | break; | ||
3523 | } | ||
3524 | |||
3525 | case HOST_NOTIFICATION_STATUS_FRAG_LENGTH: { | ||
3526 | struct notif_frag_length *x = ¬if->u.frag_len; | ||
3527 | |||
3528 | if (notif->size == sizeof(*x)) { | ||
3529 | IPW_ERROR("Frag length: %d\n", x->frag_length); | ||
3530 | } else { | ||
3531 | IPW_ERROR("Frag length of wrong size %d " | ||
3532 | "(should be %zd)\n", | ||
3533 | notif->size, sizeof(*x)); | ||
3534 | } | ||
3535 | break; | ||
3536 | } | ||
3537 | |||
3538 | case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION: { | ||
3539 | struct notif_link_deterioration *x = | ||
3540 | ¬if->u.link_deterioration; | ||
3541 | if (notif->size==sizeof(*x)) { | ||
3542 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3543 | "link deterioration: '%s' " MAC_FMT " \n", | ||
3544 | escape_essid(priv->essid, priv->essid_len), | ||
3545 | MAC_ARG(priv->bssid)); | ||
3546 | memcpy(&priv->last_link_deterioration, x, sizeof(*x)); | ||
3547 | } else { | ||
3548 | IPW_ERROR("Link Deterioration of wrong size %d " | ||
3549 | "(should be %zd)\n", | ||
3550 | notif->size, sizeof(*x)); | ||
3551 | } | ||
3552 | break; | ||
3553 | } | ||
3554 | |||
3555 | case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE: { | ||
3556 | IPW_ERROR("Dino config\n"); | ||
3557 | if (priv->hcmd && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) { | ||
3558 | /* TODO: Do anything special? */ | ||
3559 | } else { | ||
3560 | IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); | ||
3561 | } | ||
3562 | break; | ||
3563 | } | ||
3564 | |||
3565 | case HOST_NOTIFICATION_STATUS_BEACON_STATE: { | ||
3566 | struct notif_beacon_state *x = ¬if->u.beacon_state; | ||
3567 | if (notif->size != sizeof(*x)) { | ||
3568 | IPW_ERROR("Beacon state of wrong size %d (should " | ||
3569 | "be %zd)\n", notif->size, sizeof(*x)); | ||
3570 | break; | ||
3571 | } | ||
3572 | |||
3573 | if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) { | ||
3574 | if (priv->status & STATUS_SCANNING) { | ||
3575 | /* Stop scan to keep fw from getting | ||
3576 | * stuck... */ | ||
3577 | queue_work(priv->workqueue, | ||
3578 | &priv->abort_scan); | ||
3579 | } | ||
3580 | |||
3581 | if (x->number > priv->missed_beacon_threshold && | ||
3582 | priv->status & STATUS_ASSOCIATED) { | ||
3583 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | ||
3584 | IPW_DL_STATE, | ||
3585 | "Missed beacon: %d - disassociate\n", | ||
3586 | x->number); | ||
3587 | queue_work(priv->workqueue, | ||
3588 | &priv->disassociate); | ||
3589 | } else if (x->number > priv->roaming_threshold) { | ||
3590 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3591 | "Missed beacon: %d - initiate " | ||
3592 | "roaming\n", | ||
3593 | x->number); | ||
3594 | queue_work(priv->workqueue, | ||
3595 | &priv->roam); | ||
3596 | } else { | ||
3597 | IPW_DEBUG_NOTIF("Missed beacon: %d\n", | ||
3598 | x->number); | ||
3599 | } | ||
3600 | |||
3601 | priv->notif_missed_beacons = x->number; | ||
3602 | |||
3603 | } | ||
3604 | |||
3605 | |||
3606 | break; | ||
3607 | } | ||
3608 | |||
3609 | case HOST_NOTIFICATION_STATUS_TGI_TX_KEY: { | ||
3610 | struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key; | ||
3611 | if (notif->size==sizeof(*x)) { | ||
3612 | IPW_ERROR("TGi Tx Key: state 0x%02x sec type " | ||
3613 | "0x%02x station %d\n", | ||
3614 | x->key_state,x->security_type, | ||
3615 | x->station_index); | ||
3616 | break; | ||
3617 | } | ||
3618 | |||
3619 | IPW_ERROR("TGi Tx Key of wrong size %d (should be %zd)\n", | ||
3620 | notif->size, sizeof(*x)); | ||
3621 | break; | ||
3622 | } | ||
3623 | |||
3624 | case HOST_NOTIFICATION_CALIB_KEEP_RESULTS: { | ||
3625 | struct notif_calibration *x = ¬if->u.calibration; | ||
3626 | |||
3627 | if (notif->size == sizeof(*x)) { | ||
3628 | memcpy(&priv->calib, x, sizeof(*x)); | ||
3629 | IPW_DEBUG_INFO("TODO: Calibration\n"); | ||
3630 | break; | ||
3631 | } | ||
3632 | |||
3633 | IPW_ERROR("Calibration of wrong size %d (should be %zd)\n", | ||
3634 | notif->size, sizeof(*x)); | ||
3635 | break; | ||
3636 | } | ||
3637 | |||
3638 | case HOST_NOTIFICATION_NOISE_STATS: { | ||
3639 | if (notif->size == sizeof(u32)) { | ||
3640 | priv->last_noise = (u8)(notif->u.noise.value & 0xff); | ||
3641 | average_add(&priv->average_noise, priv->last_noise); | ||
3642 | break; | ||
3643 | } | ||
3644 | |||
3645 | IPW_ERROR("Noise stat is wrong size %d (should be %zd)\n", | ||
3646 | notif->size, sizeof(u32)); | ||
3647 | break; | ||
3648 | } | ||
3649 | |||
3650 | default: | ||
3651 | IPW_ERROR("Unknown notification: " | ||
3652 | "subtype=%d,flags=0x%2x,size=%d\n", | ||
3653 | notif->subtype, notif->flags, notif->size); | ||
3654 | } | ||
3655 | } | ||
3656 | |||
3657 | /** | ||
3658 | * Destroys all DMA structures and initialise them again | ||
3659 | * | ||
3660 | * @param priv | ||
3661 | * @return error code | ||
3662 | */ | ||
3663 | static int ipw_queue_reset(struct ipw_priv *priv) | ||
3664 | { | ||
3665 | int rc = 0; | ||
3666 | /** @todo customize queue sizes */ | ||
3667 | int nTx = 64, nTxCmd = 8; | ||
3668 | ipw_tx_queue_free(priv); | ||
3669 | /* Tx CMD queue */ | ||
3670 | rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd, | ||
3671 | CX2_TX_CMD_QUEUE_READ_INDEX, | ||
3672 | CX2_TX_CMD_QUEUE_WRITE_INDEX, | ||
3673 | CX2_TX_CMD_QUEUE_BD_BASE, | ||
3674 | CX2_TX_CMD_QUEUE_BD_SIZE); | ||
3675 | if (rc) { | ||
3676 | IPW_ERROR("Tx Cmd queue init failed\n"); | ||
3677 | goto error; | ||
3678 | } | ||
3679 | /* Tx queue(s) */ | ||
3680 | rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx, | ||
3681 | CX2_TX_QUEUE_0_READ_INDEX, | ||
3682 | CX2_TX_QUEUE_0_WRITE_INDEX, | ||
3683 | CX2_TX_QUEUE_0_BD_BASE, | ||
3684 | CX2_TX_QUEUE_0_BD_SIZE); | ||
3685 | if (rc) { | ||
3686 | IPW_ERROR("Tx 0 queue init failed\n"); | ||
3687 | goto error; | ||
3688 | } | ||
3689 | rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx, | ||
3690 | CX2_TX_QUEUE_1_READ_INDEX, | ||
3691 | CX2_TX_QUEUE_1_WRITE_INDEX, | ||
3692 | CX2_TX_QUEUE_1_BD_BASE, | ||
3693 | CX2_TX_QUEUE_1_BD_SIZE); | ||
3694 | if (rc) { | ||
3695 | IPW_ERROR("Tx 1 queue init failed\n"); | ||
3696 | goto error; | ||
3697 | } | ||
3698 | rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx, | ||
3699 | CX2_TX_QUEUE_2_READ_INDEX, | ||
3700 | CX2_TX_QUEUE_2_WRITE_INDEX, | ||
3701 | CX2_TX_QUEUE_2_BD_BASE, | ||
3702 | CX2_TX_QUEUE_2_BD_SIZE); | ||
3703 | if (rc) { | ||
3704 | IPW_ERROR("Tx 2 queue init failed\n"); | ||
3705 | goto error; | ||
3706 | } | ||
3707 | rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx, | ||
3708 | CX2_TX_QUEUE_3_READ_INDEX, | ||
3709 | CX2_TX_QUEUE_3_WRITE_INDEX, | ||
3710 | CX2_TX_QUEUE_3_BD_BASE, | ||
3711 | CX2_TX_QUEUE_3_BD_SIZE); | ||
3712 | if (rc) { | ||
3713 | IPW_ERROR("Tx 3 queue init failed\n"); | ||
3714 | goto error; | ||
3715 | } | ||
3716 | /* statistics */ | ||
3717 | priv->rx_bufs_min = 0; | ||
3718 | priv->rx_pend_max = 0; | ||
3719 | return rc; | ||
3720 | |||
3721 | error: | ||
3722 | ipw_tx_queue_free(priv); | ||
3723 | return rc; | ||
3724 | } | ||
3725 | |||
3726 | /** | ||
3727 | * Reclaim Tx queue entries no more used by NIC. | ||
3728 | * | ||
3729 | * When FW adwances 'R' index, all entries between old and | ||
3730 | * new 'R' index need to be reclaimed. As result, some free space | ||
3731 | * forms. If there is enough free space (> low mark), wake Tx queue. | ||
3732 | * | ||
3733 | * @note Need to protect against garbage in 'R' index | ||
3734 | * @param priv | ||
3735 | * @param txq | ||
3736 | * @param qindex | ||
3737 | * @return Number of used entries remains in the queue | ||
3738 | */ | ||
3739 | static int ipw_queue_tx_reclaim(struct ipw_priv *priv, | ||
3740 | struct clx2_tx_queue *txq, int qindex) | ||
3741 | { | ||
3742 | u32 hw_tail; | ||
3743 | int used; | ||
3744 | struct clx2_queue *q = &txq->q; | ||
3745 | |||
3746 | hw_tail = ipw_read32(priv, q->reg_r); | ||
3747 | if (hw_tail >= q->n_bd) { | ||
3748 | IPW_ERROR | ||
3749 | ("Read index for DMA queue (%d) is out of range [0-%d)\n", | ||
3750 | hw_tail, q->n_bd); | ||
3751 | goto done; | ||
3752 | } | ||
3753 | for (; q->last_used != hw_tail; | ||
3754 | q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { | ||
3755 | ipw_queue_tx_free_tfd(priv, txq); | ||
3756 | priv->tx_packets++; | ||
3757 | } | ||
3758 | done: | ||
3759 | if (ipw_queue_space(q) > q->low_mark && qindex >= 0) { | ||
3760 | __maybe_wake_tx(priv); | ||
3761 | } | ||
3762 | used = q->first_empty - q->last_used; | ||
3763 | if (used < 0) | ||
3764 | used += q->n_bd; | ||
3765 | |||
3766 | return used; | ||
3767 | } | ||
3768 | |||
3769 | static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, | ||
3770 | int len, int sync) | ||
3771 | { | ||
3772 | struct clx2_tx_queue *txq = &priv->txq_cmd; | ||
3773 | struct clx2_queue *q = &txq->q; | ||
3774 | struct tfd_frame *tfd; | ||
3775 | |||
3776 | if (ipw_queue_space(q) < (sync ? 1 : 2)) { | ||
3777 | IPW_ERROR("No space for Tx\n"); | ||
3778 | return -EBUSY; | ||
3779 | } | ||
3780 | |||
3781 | tfd = &txq->bd[q->first_empty]; | ||
3782 | txq->txb[q->first_empty] = NULL; | ||
3783 | |||
3784 | memset(tfd, 0, sizeof(*tfd)); | ||
3785 | tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE; | ||
3786 | tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; | ||
3787 | priv->hcmd_seq++; | ||
3788 | tfd->u.cmd.index = hcmd; | ||
3789 | tfd->u.cmd.length = len; | ||
3790 | memcpy(tfd->u.cmd.payload, buf, len); | ||
3791 | q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); | ||
3792 | ipw_write32(priv, q->reg_w, q->first_empty); | ||
3793 | _ipw_read32(priv, 0x90); | ||
3794 | |||
3795 | return 0; | ||
3796 | } | ||
3797 | |||
3798 | |||
3799 | |||
3800 | /* | ||
3801 | * Rx theory of operation | ||
3802 | * | ||
3803 | * The host allocates 32 DMA target addresses and passes the host address | ||
3804 | * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is | ||
3805 | * 0 to 31 | ||
3806 | * | ||
3807 | * Rx Queue Indexes | ||
3808 | * The host/firmware share two index registers for managing the Rx buffers. | ||
3809 | * | ||
3810 | * The READ index maps to the first position that the firmware may be writing | ||
3811 | * to -- the driver can read up to (but not including) this position and get | ||
3812 | * good data. | ||
3813 | * The READ index is managed by the firmware once the card is enabled. | ||
3814 | * | ||
3815 | * The WRITE index maps to the last position the driver has read from -- the | ||
3816 | * position preceding WRITE is the last slot the firmware can place a packet. | ||
3817 | * | ||
3818 | * The queue is empty (no good data) if WRITE = READ - 1, and is full if | ||
3819 | * WRITE = READ. | ||
3820 | * | ||
3821 | * During initialization the host sets up the READ queue position to the first | ||
3822 | * INDEX position, and WRITE to the last (READ - 1 wrapped) | ||
3823 | * | ||
3824 | * When the firmware places a packet in a buffer it will advance the READ index | ||
3825 | * and fire the RX interrupt. The driver can then query the READ index and | ||
3826 | * process as many packets as possible, moving the WRITE index forward as it | ||
3827 | * resets the Rx queue buffers with new memory. | ||
3828 | * | ||
3829 | * The management in the driver is as follows: | ||
3830 | * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When | ||
3831 | * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled | ||
3832 | * to replensish the ipw->rxq->rx_free. | ||
3833 | * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the | ||
3834 | * ipw->rxq is replenished and the READ INDEX is updated (updating the | ||
3835 | * 'processed' and 'read' driver indexes as well) | ||
3836 | * + A received packet is processed and handed to the kernel network stack, | ||
3837 | * detached from the ipw->rxq. The driver 'processed' index is updated. | ||
3838 | * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free | ||
3839 | * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ | ||
3840 | * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there | ||
3841 | * were enough free buffers and RX_STALLED is set it is cleared. | ||
3842 | * | ||
3843 | * | ||
3844 | * Driver sequence: | ||
3845 | * | ||
3846 | * ipw_rx_queue_alloc() Allocates rx_free | ||
3847 | * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls | ||
3848 | * ipw_rx_queue_restock | ||
3849 | * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx | ||
3850 | * queue, updates firmware pointers, and updates | ||
3851 | * the WRITE index. If insufficient rx_free buffers | ||
3852 | * are available, schedules ipw_rx_queue_replenish | ||
3853 | * | ||
3854 | * -- enable interrupts -- | ||
3855 | * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the | ||
3856 | * READ INDEX, detaching the SKB from the pool. | ||
3857 | * Moves the packet buffer from queue to rx_used. | ||
3858 | * Calls ipw_rx_queue_restock to refill any empty | ||
3859 | * slots. | ||
3860 | * ... | ||
3861 | * | ||
3862 | */ | ||
3863 | |||
3864 | /* | ||
3865 | * If there are slots in the RX queue that need to be restocked, | ||
3866 | * and we have free pre-allocated buffers, fill the ranks as much | ||
3867 | * as we can pulling from rx_free. | ||
3868 | * | ||
3869 | * This moves the 'write' index forward to catch up with 'processed', and | ||
3870 | * also updates the memory address in the firmware to reference the new | ||
3871 | * target buffer. | ||
3872 | */ | ||
3873 | static void ipw_rx_queue_restock(struct ipw_priv *priv) | ||
3874 | { | ||
3875 | struct ipw_rx_queue *rxq = priv->rxq; | ||
3876 | struct list_head *element; | ||
3877 | struct ipw_rx_mem_buffer *rxb; | ||
3878 | unsigned long flags; | ||
3879 | int write; | ||
3880 | |||
3881 | spin_lock_irqsave(&rxq->lock, flags); | ||
3882 | write = rxq->write; | ||
3883 | while ((rxq->write != rxq->processed) && (rxq->free_count)) { | ||
3884 | element = rxq->rx_free.next; | ||
3885 | rxb = list_entry(element, struct ipw_rx_mem_buffer, list); | ||
3886 | list_del(element); | ||
3887 | |||
3888 | ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE, | ||
3889 | rxb->dma_addr); | ||
3890 | rxq->queue[rxq->write] = rxb; | ||
3891 | rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE; | ||
3892 | rxq->free_count--; | ||
3893 | } | ||
3894 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
3895 | |||
3896 | /* If the pre-allocated buffer pool is dropping low, schedule to | ||
3897 | * refill it */ | ||
3898 | if (rxq->free_count <= RX_LOW_WATERMARK) | ||
3899 | queue_work(priv->workqueue, &priv->rx_replenish); | ||
3900 | |||
3901 | /* If we've added more space for the firmware to place data, tell it */ | ||
3902 | if (write != rxq->write) | ||
3903 | ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write); | ||
3904 | } | ||
3905 | |||
3906 | /* | ||
3907 | * Move all used packet from rx_used to rx_free, allocating a new SKB for each. | ||
3908 | * Also restock the Rx queue via ipw_rx_queue_restock. | ||
3909 | * | ||
3910 | * This is called as a scheduled work item (except for during intialization) | ||
3911 | */ | ||
3912 | static void ipw_rx_queue_replenish(void *data) | ||
3913 | { | ||
3914 | struct ipw_priv *priv = data; | ||
3915 | struct ipw_rx_queue *rxq = priv->rxq; | ||
3916 | struct list_head *element; | ||
3917 | struct ipw_rx_mem_buffer *rxb; | ||
3918 | unsigned long flags; | ||
3919 | |||
3920 | spin_lock_irqsave(&rxq->lock, flags); | ||
3921 | while (!list_empty(&rxq->rx_used)) { | ||
3922 | element = rxq->rx_used.next; | ||
3923 | rxb = list_entry(element, struct ipw_rx_mem_buffer, list); | ||
3924 | rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC); | ||
3925 | if (!rxb->skb) { | ||
3926 | printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n", | ||
3927 | priv->net_dev->name); | ||
3928 | /* We don't reschedule replenish work here -- we will | ||
3929 | * call the restock method and if it still needs | ||
3930 | * more buffers it will schedule replenish */ | ||
3931 | break; | ||
3932 | } | ||
3933 | list_del(element); | ||
3934 | |||
3935 | rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data; | ||
3936 | rxb->dma_addr = pci_map_single( | ||
3937 | priv->pci_dev, rxb->skb->data, CX2_RX_BUF_SIZE, | ||
3938 | PCI_DMA_FROMDEVICE); | ||
3939 | |||
3940 | list_add_tail(&rxb->list, &rxq->rx_free); | ||
3941 | rxq->free_count++; | ||
3942 | } | ||
3943 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
3944 | |||
3945 | ipw_rx_queue_restock(priv); | ||
3946 | } | ||
3947 | |||
3948 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. | ||
3949 | * If an SKB has been detached, the POOL needs to have it's SKB set to NULL | ||
3950 | * This free routine walks the list of POOL entries and if SKB is set to | ||
3951 | * non NULL it is unmapped and freed | ||
3952 | */ | ||
3953 | static void ipw_rx_queue_free(struct ipw_priv *priv, | ||
3954 | struct ipw_rx_queue *rxq) | ||
3955 | { | ||
3956 | int i; | ||
3957 | |||
3958 | if (!rxq) | ||
3959 | return; | ||
3960 | |||
3961 | for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { | ||
3962 | if (rxq->pool[i].skb != NULL) { | ||
3963 | pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, | ||
3964 | CX2_RX_BUF_SIZE, | ||
3965 | PCI_DMA_FROMDEVICE); | ||
3966 | dev_kfree_skb(rxq->pool[i].skb); | ||
3967 | } | ||
3968 | } | ||
3969 | |||
3970 | kfree(rxq); | ||
3971 | } | ||
3972 | |||
3973 | static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) | ||
3974 | { | ||
3975 | struct ipw_rx_queue *rxq; | ||
3976 | int i; | ||
3977 | |||
3978 | rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL); | ||
3979 | memset(rxq, 0, sizeof(*rxq)); | ||
3980 | spin_lock_init(&rxq->lock); | ||
3981 | INIT_LIST_HEAD(&rxq->rx_free); | ||
3982 | INIT_LIST_HEAD(&rxq->rx_used); | ||
3983 | |||
3984 | /* Fill the rx_used queue with _all_ of the Rx buffers */ | ||
3985 | for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) | ||
3986 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); | ||
3987 | |||
3988 | /* Set us so that we have processed and used all buffers, but have | ||
3989 | * not restocked the Rx queue with fresh buffers */ | ||
3990 | rxq->read = rxq->write = 0; | ||
3991 | rxq->processed = RX_QUEUE_SIZE - 1; | ||
3992 | rxq->free_count = 0; | ||
3993 | |||
3994 | return rxq; | ||
3995 | } | ||
3996 | |||
3997 | static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) | ||
3998 | { | ||
3999 | rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
4000 | if (ieee_mode == IEEE_A) { | ||
4001 | switch (rate) { | ||
4002 | case IEEE80211_OFDM_RATE_6MB: | ||
4003 | return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? | ||
4004 | 1 : 0; | ||
4005 | case IEEE80211_OFDM_RATE_9MB: | ||
4006 | return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? | ||
4007 | 1 : 0; | ||
4008 | case IEEE80211_OFDM_RATE_12MB: | ||
4009 | return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? | ||
4010 | 1 : 0; | ||
4011 | case IEEE80211_OFDM_RATE_18MB: | ||
4012 | return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? | ||
4013 | 1 : 0; | ||
4014 | case IEEE80211_OFDM_RATE_24MB: | ||
4015 | return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? | ||
4016 | 1 : 0; | ||
4017 | case IEEE80211_OFDM_RATE_36MB: | ||
4018 | return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? | ||
4019 | 1 : 0; | ||
4020 | case IEEE80211_OFDM_RATE_48MB: | ||
4021 | return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? | ||
4022 | 1 : 0; | ||
4023 | case IEEE80211_OFDM_RATE_54MB: | ||
4024 | return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? | ||
4025 | 1 : 0; | ||
4026 | default: | ||
4027 | return 0; | ||
4028 | } | ||
4029 | } | ||
4030 | |||
4031 | /* B and G mixed */ | ||
4032 | switch (rate) { | ||
4033 | case IEEE80211_CCK_RATE_1MB: | ||
4034 | return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0; | ||
4035 | case IEEE80211_CCK_RATE_2MB: | ||
4036 | return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0; | ||
4037 | case IEEE80211_CCK_RATE_5MB: | ||
4038 | return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0; | ||
4039 | case IEEE80211_CCK_RATE_11MB: | ||
4040 | return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0; | ||
4041 | } | ||
4042 | |||
4043 | /* If we are limited to B modulations, bail at this point */ | ||
4044 | if (ieee_mode == IEEE_B) | ||
4045 | return 0; | ||
4046 | |||
4047 | /* G */ | ||
4048 | switch (rate) { | ||
4049 | case IEEE80211_OFDM_RATE_6MB: | ||
4050 | return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0; | ||
4051 | case IEEE80211_OFDM_RATE_9MB: | ||
4052 | return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0; | ||
4053 | case IEEE80211_OFDM_RATE_12MB: | ||
4054 | return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; | ||
4055 | case IEEE80211_OFDM_RATE_18MB: | ||
4056 | return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; | ||
4057 | case IEEE80211_OFDM_RATE_24MB: | ||
4058 | return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; | ||
4059 | case IEEE80211_OFDM_RATE_36MB: | ||
4060 | return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; | ||
4061 | case IEEE80211_OFDM_RATE_48MB: | ||
4062 | return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; | ||
4063 | case IEEE80211_OFDM_RATE_54MB: | ||
4064 | return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; | ||
4065 | } | ||
4066 | |||
4067 | return 0; | ||
4068 | } | ||
4069 | |||
4070 | static int ipw_compatible_rates(struct ipw_priv *priv, | ||
4071 | const struct ieee80211_network *network, | ||
4072 | struct ipw_supported_rates *rates) | ||
4073 | { | ||
4074 | int num_rates, i; | ||
4075 | |||
4076 | memset(rates, 0, sizeof(*rates)); | ||
4077 | num_rates = min(network->rates_len, (u8)IPW_MAX_RATES); | ||
4078 | rates->num_rates = 0; | ||
4079 | for (i = 0; i < num_rates; i++) { | ||
4080 | if (!ipw_is_rate_in_mask(priv, network->mode, network->rates[i])) { | ||
4081 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | ||
4082 | network->rates[i], priv->rates_mask); | ||
4083 | continue; | ||
4084 | } | ||
4085 | |||
4086 | rates->supported_rates[rates->num_rates++] = network->rates[i]; | ||
4087 | } | ||
4088 | |||
4089 | num_rates = min(network->rates_ex_len, (u8)(IPW_MAX_RATES - num_rates)); | ||
4090 | for (i = 0; i < num_rates; i++) { | ||
4091 | if (!ipw_is_rate_in_mask(priv, network->mode, network->rates_ex[i])) { | ||
4092 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | ||
4093 | network->rates_ex[i], priv->rates_mask); | ||
4094 | continue; | ||
4095 | } | ||
4096 | |||
4097 | rates->supported_rates[rates->num_rates++] = network->rates_ex[i]; | ||
4098 | } | ||
4099 | |||
4100 | return rates->num_rates; | ||
4101 | } | ||
4102 | |||
4103 | static inline void ipw_copy_rates(struct ipw_supported_rates *dest, | ||
4104 | const struct ipw_supported_rates *src) | ||
4105 | { | ||
4106 | u8 i; | ||
4107 | for (i = 0; i < src->num_rates; i++) | ||
4108 | dest->supported_rates[i] = src->supported_rates[i]; | ||
4109 | dest->num_rates = src->num_rates; | ||
4110 | } | ||
4111 | |||
4112 | /* TODO: Look at sniffed packets in the air to determine if the basic rate | ||
4113 | * mask should ever be used -- right now all callers to add the scan rates are | ||
4114 | * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */ | ||
4115 | static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates, | ||
4116 | u8 modulation, u32 rate_mask) | ||
4117 | { | ||
4118 | u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? | ||
4119 | IEEE80211_BASIC_RATE_MASK : 0; | ||
4120 | |||
4121 | if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK) | ||
4122 | rates->supported_rates[rates->num_rates++] = | ||
4123 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
4124 | |||
4125 | if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK) | ||
4126 | rates->supported_rates[rates->num_rates++] = | ||
4127 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
4128 | |||
4129 | if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK) | ||
4130 | rates->supported_rates[rates->num_rates++] = basic_mask | | ||
4131 | IEEE80211_CCK_RATE_5MB; | ||
4132 | |||
4133 | if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK) | ||
4134 | rates->supported_rates[rates->num_rates++] = basic_mask | | ||
4135 | IEEE80211_CCK_RATE_11MB; | ||
4136 | } | ||
4137 | |||
4138 | static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates, | ||
4139 | u8 modulation, u32 rate_mask) | ||
4140 | { | ||
4141 | u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? | ||
4142 | IEEE80211_BASIC_RATE_MASK : 0; | ||
4143 | |||
4144 | if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK) | ||
4145 | rates->supported_rates[rates->num_rates++] = basic_mask | | ||
4146 | IEEE80211_OFDM_RATE_6MB; | ||
4147 | |||
4148 | if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK) | ||
4149 | rates->supported_rates[rates->num_rates++] = | ||
4150 | IEEE80211_OFDM_RATE_9MB; | ||
4151 | |||
4152 | if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK) | ||
4153 | rates->supported_rates[rates->num_rates++] = basic_mask | | ||
4154 | IEEE80211_OFDM_RATE_12MB; | ||
4155 | |||
4156 | if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK) | ||
4157 | rates->supported_rates[rates->num_rates++] = | ||
4158 | IEEE80211_OFDM_RATE_18MB; | ||
4159 | |||
4160 | if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK) | ||
4161 | rates->supported_rates[rates->num_rates++] = basic_mask | | ||
4162 | IEEE80211_OFDM_RATE_24MB; | ||
4163 | |||
4164 | if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK) | ||
4165 | rates->supported_rates[rates->num_rates++] = | ||
4166 | IEEE80211_OFDM_RATE_36MB; | ||
4167 | |||
4168 | if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK) | ||
4169 | rates->supported_rates[rates->num_rates++] = | ||
4170 | IEEE80211_OFDM_RATE_48MB; | ||
4171 | |||
4172 | if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK) | ||
4173 | rates->supported_rates[rates->num_rates++] = | ||
4174 | IEEE80211_OFDM_RATE_54MB; | ||
4175 | } | ||
4176 | |||
4177 | struct ipw_network_match { | ||
4178 | struct ieee80211_network *network; | ||
4179 | struct ipw_supported_rates rates; | ||
4180 | }; | ||
4181 | |||
4182 | static int ipw_best_network( | ||
4183 | struct ipw_priv *priv, | ||
4184 | struct ipw_network_match *match, | ||
4185 | struct ieee80211_network *network, | ||
4186 | int roaming) | ||
4187 | { | ||
4188 | struct ipw_supported_rates rates; | ||
4189 | |||
4190 | /* Verify that this network's capability is compatible with the | ||
4191 | * current mode (AdHoc or Infrastructure) */ | ||
4192 | if ((priv->ieee->iw_mode == IW_MODE_INFRA && | ||
4193 | !(network->capability & WLAN_CAPABILITY_ESS)) || | ||
4194 | (priv->ieee->iw_mode == IW_MODE_ADHOC && | ||
4195 | !(network->capability & WLAN_CAPABILITY_IBSS))) { | ||
4196 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to " | ||
4197 | "capability mismatch.\n", | ||
4198 | escape_essid(network->ssid, network->ssid_len), | ||
4199 | MAC_ARG(network->bssid)); | ||
4200 | return 0; | ||
4201 | } | ||
4202 | |||
4203 | /* If we do not have an ESSID for this AP, we can not associate with | ||
4204 | * it */ | ||
4205 | if (network->flags & NETWORK_EMPTY_ESSID) { | ||
4206 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4207 | "because of hidden ESSID.\n", | ||
4208 | escape_essid(network->ssid, network->ssid_len), | ||
4209 | MAC_ARG(network->bssid)); | ||
4210 | return 0; | ||
4211 | } | ||
4212 | |||
4213 | if (unlikely(roaming)) { | ||
4214 | /* If we are roaming, then ensure check if this is a valid | ||
4215 | * network to try and roam to */ | ||
4216 | if ((network->ssid_len != match->network->ssid_len) || | ||
4217 | memcmp(network->ssid, match->network->ssid, | ||
4218 | network->ssid_len)) { | ||
4219 | IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded " | ||
4220 | "because of non-network ESSID.\n", | ||
4221 | escape_essid(network->ssid, | ||
4222 | network->ssid_len), | ||
4223 | MAC_ARG(network->bssid)); | ||
4224 | return 0; | ||
4225 | } | ||
4226 | } else { | ||
4227 | /* If an ESSID has been configured then compare the broadcast | ||
4228 | * ESSID to ours */ | ||
4229 | if ((priv->config & CFG_STATIC_ESSID) && | ||
4230 | ((network->ssid_len != priv->essid_len) || | ||
4231 | memcmp(network->ssid, priv->essid, | ||
4232 | min(network->ssid_len, priv->essid_len)))) { | ||
4233 | char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | ||
4234 | strncpy(escaped, escape_essid( | ||
4235 | network->ssid, network->ssid_len), | ||
4236 | sizeof(escaped)); | ||
4237 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4238 | "because of ESSID mismatch: '%s'.\n", | ||
4239 | escaped, MAC_ARG(network->bssid), | ||
4240 | escape_essid(priv->essid, priv->essid_len)); | ||
4241 | return 0; | ||
4242 | } | ||
4243 | } | ||
4244 | |||
4245 | /* If the old network rate is better than this one, don't bother | ||
4246 | * testing everything else. */ | ||
4247 | if (match->network && match->network->stats.rssi > | ||
4248 | network->stats.rssi) { | ||
4249 | char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | ||
4250 | strncpy(escaped, | ||
4251 | escape_essid(network->ssid, network->ssid_len), | ||
4252 | sizeof(escaped)); | ||
4253 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because " | ||
4254 | "'%s (" MAC_FMT ")' has a stronger signal.\n", | ||
4255 | escaped, MAC_ARG(network->bssid), | ||
4256 | escape_essid(match->network->ssid, | ||
4257 | match->network->ssid_len), | ||
4258 | MAC_ARG(match->network->bssid)); | ||
4259 | return 0; | ||
4260 | } | ||
4261 | |||
4262 | /* If this network has already had an association attempt within the | ||
4263 | * last 3 seconds, do not try and associate again... */ | ||
4264 | if (network->last_associate && | ||
4265 | time_after(network->last_associate + (HZ * 5UL), jiffies)) { | ||
4266 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4267 | "because of storming (%lu since last " | ||
4268 | "assoc attempt).\n", | ||
4269 | escape_essid(network->ssid, network->ssid_len), | ||
4270 | MAC_ARG(network->bssid), | ||
4271 | (jiffies - network->last_associate) / HZ); | ||
4272 | return 0; | ||
4273 | } | ||
4274 | |||
4275 | /* Now go through and see if the requested network is valid... */ | ||
4276 | if (priv->ieee->scan_age != 0 && | ||
4277 | jiffies - network->last_scanned > priv->ieee->scan_age) { | ||
4278 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4279 | "because of age: %lums.\n", | ||
4280 | escape_essid(network->ssid, network->ssid_len), | ||
4281 | MAC_ARG(network->bssid), | ||
4282 | (jiffies - network->last_scanned) / (HZ / 100)); | ||
4283 | return 0; | ||
4284 | } | ||
4285 | |||
4286 | if ((priv->config & CFG_STATIC_CHANNEL) && | ||
4287 | (network->channel != priv->channel)) { | ||
4288 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4289 | "because of channel mismatch: %d != %d.\n", | ||
4290 | escape_essid(network->ssid, network->ssid_len), | ||
4291 | MAC_ARG(network->bssid), | ||
4292 | network->channel, priv->channel); | ||
4293 | return 0; | ||
4294 | } | ||
4295 | |||
4296 | /* Verify privacy compatability */ | ||
4297 | if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != | ||
4298 | ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { | ||
4299 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4300 | "because of privacy mismatch: %s != %s.\n", | ||
4301 | escape_essid(network->ssid, network->ssid_len), | ||
4302 | MAC_ARG(network->bssid), | ||
4303 | priv->capability & CAP_PRIVACY_ON ? "on" : | ||
4304 | "off", | ||
4305 | network->capability & | ||
4306 | WLAN_CAPABILITY_PRIVACY ?"on" : "off"); | ||
4307 | return 0; | ||
4308 | } | ||
4309 | |||
4310 | if ((priv->config & CFG_STATIC_BSSID) && | ||
4311 | memcmp(network->bssid, priv->bssid, ETH_ALEN)) { | ||
4312 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4313 | "because of BSSID mismatch: " MAC_FMT ".\n", | ||
4314 | escape_essid(network->ssid, network->ssid_len), | ||
4315 | MAC_ARG(network->bssid), | ||
4316 | MAC_ARG(priv->bssid)); | ||
4317 | return 0; | ||
4318 | } | ||
4319 | |||
4320 | /* Filter out any incompatible freq / mode combinations */ | ||
4321 | if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { | ||
4322 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4323 | "because of invalid frequency/mode " | ||
4324 | "combination.\n", | ||
4325 | escape_essid(network->ssid, network->ssid_len), | ||
4326 | MAC_ARG(network->bssid)); | ||
4327 | return 0; | ||
4328 | } | ||
4329 | |||
4330 | ipw_compatible_rates(priv, network, &rates); | ||
4331 | if (rates.num_rates == 0) { | ||
4332 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4333 | "because of no compatible rates.\n", | ||
4334 | escape_essid(network->ssid, network->ssid_len), | ||
4335 | MAC_ARG(network->bssid)); | ||
4336 | return 0; | ||
4337 | } | ||
4338 | |||
4339 | /* TODO: Perform any further minimal comparititive tests. We do not | ||
4340 | * want to put too much policy logic here; intelligent scan selection | ||
4341 | * should occur within a generic IEEE 802.11 user space tool. */ | ||
4342 | |||
4343 | /* Set up 'new' AP to this network */ | ||
4344 | ipw_copy_rates(&match->rates, &rates); | ||
4345 | match->network = network; | ||
4346 | |||
4347 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n", | ||
4348 | escape_essid(network->ssid, network->ssid_len), | ||
4349 | MAC_ARG(network->bssid)); | ||
4350 | |||
4351 | return 1; | ||
4352 | } | ||
4353 | |||
4354 | |||
4355 | static void ipw_adhoc_create(struct ipw_priv *priv, | ||
4356 | struct ieee80211_network *network) | ||
4357 | { | ||
4358 | /* | ||
4359 | * For the purposes of scanning, we can set our wireless mode | ||
4360 | * to trigger scans across combinations of bands, but when it | ||
4361 | * comes to creating a new ad-hoc network, we have tell the FW | ||
4362 | * exactly which band to use. | ||
4363 | * | ||
4364 | * We also have the possibility of an invalid channel for the | ||
4365 | * chossen band. Attempting to create a new ad-hoc network | ||
4366 | * with an invalid channel for wireless mode will trigger a | ||
4367 | * FW fatal error. | ||
4368 | */ | ||
4369 | network->mode = is_valid_channel(priv->ieee->mode, priv->channel); | ||
4370 | if (network->mode) { | ||
4371 | network->channel = priv->channel; | ||
4372 | } else { | ||
4373 | IPW_WARNING("Overriding invalid channel\n"); | ||
4374 | if (priv->ieee->mode & IEEE_A) { | ||
4375 | network->mode = IEEE_A; | ||
4376 | priv->channel = band_a_active_channel[0]; | ||
4377 | } else if (priv->ieee->mode & IEEE_G) { | ||
4378 | network->mode = IEEE_G; | ||
4379 | priv->channel = band_b_active_channel[0]; | ||
4380 | } else { | ||
4381 | network->mode = IEEE_B; | ||
4382 | priv->channel = band_b_active_channel[0]; | ||
4383 | } | ||
4384 | } | ||
4385 | |||
4386 | network->channel = priv->channel; | ||
4387 | priv->config |= CFG_ADHOC_PERSIST; | ||
4388 | ipw_create_bssid(priv, network->bssid); | ||
4389 | network->ssid_len = priv->essid_len; | ||
4390 | memcpy(network->ssid, priv->essid, priv->essid_len); | ||
4391 | memset(&network->stats, 0, sizeof(network->stats)); | ||
4392 | network->capability = WLAN_CAPABILITY_IBSS; | ||
4393 | if (priv->capability & CAP_PRIVACY_ON) | ||
4394 | network->capability |= WLAN_CAPABILITY_PRIVACY; | ||
4395 | network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); | ||
4396 | memcpy(network->rates, priv->rates.supported_rates, | ||
4397 | network->rates_len); | ||
4398 | network->rates_ex_len = priv->rates.num_rates - network->rates_len; | ||
4399 | memcpy(network->rates_ex, | ||
4400 | &priv->rates.supported_rates[network->rates_len], | ||
4401 | network->rates_ex_len); | ||
4402 | network->last_scanned = 0; | ||
4403 | network->flags = 0; | ||
4404 | network->last_associate = 0; | ||
4405 | network->time_stamp[0] = 0; | ||
4406 | network->time_stamp[1] = 0; | ||
4407 | network->beacon_interval = 100; /* Default */ | ||
4408 | network->listen_interval = 10; /* Default */ | ||
4409 | network->atim_window = 0; /* Default */ | ||
4410 | #ifdef CONFIG_IEEE80211_WPA | ||
4411 | network->wpa_ie_len = 0; | ||
4412 | network->rsn_ie_len = 0; | ||
4413 | #endif /* CONFIG_IEEE80211_WPA */ | ||
4414 | } | ||
4415 | |||
4416 | static void ipw_send_wep_keys(struct ipw_priv *priv) | ||
4417 | { | ||
4418 | struct ipw_wep_key *key; | ||
4419 | int i; | ||
4420 | struct host_cmd cmd = { | ||
4421 | .cmd = IPW_CMD_WEP_KEY, | ||
4422 | .len = sizeof(*key) | ||
4423 | }; | ||
4424 | |||
4425 | key = (struct ipw_wep_key *)&cmd.param; | ||
4426 | key->cmd_id = DINO_CMD_WEP_KEY; | ||
4427 | key->seq_num = 0; | ||
4428 | |||
4429 | for (i = 0; i < 4; i++) { | ||
4430 | key->key_index = i; | ||
4431 | if (!(priv->sec.flags & (1 << i))) { | ||
4432 | key->key_size = 0; | ||
4433 | } else { | ||
4434 | key->key_size = priv->sec.key_sizes[i]; | ||
4435 | memcpy(key->key, priv->sec.keys[i], key->key_size); | ||
4436 | } | ||
4437 | |||
4438 | if (ipw_send_cmd(priv, &cmd)) { | ||
4439 | IPW_ERROR("failed to send WEP_KEY command\n"); | ||
4440 | return; | ||
4441 | } | ||
4442 | } | ||
4443 | } | ||
4444 | |||
4445 | static void ipw_adhoc_check(void *data) | ||
4446 | { | ||
4447 | struct ipw_priv *priv = data; | ||
4448 | |||
4449 | if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold && | ||
4450 | !(priv->config & CFG_ADHOC_PERSIST)) { | ||
4451 | IPW_DEBUG_SCAN("Disassociating due to missed beacons\n"); | ||
4452 | ipw_remove_current_network(priv); | ||
4453 | ipw_disassociate(priv); | ||
4454 | return; | ||
4455 | } | ||
4456 | |||
4457 | queue_delayed_work(priv->workqueue, &priv->adhoc_check, | ||
4458 | priv->assoc_request.beacon_interval); | ||
4459 | } | ||
4460 | |||
4461 | #ifdef CONFIG_IPW_DEBUG | ||
4462 | static void ipw_debug_config(struct ipw_priv *priv) | ||
4463 | { | ||
4464 | IPW_DEBUG_INFO("Scan completed, no valid APs matched " | ||
4465 | "[CFG 0x%08X]\n", priv->config); | ||
4466 | if (priv->config & CFG_STATIC_CHANNEL) | ||
4467 | IPW_DEBUG_INFO("Channel locked to %d\n", | ||
4468 | priv->channel); | ||
4469 | else | ||
4470 | IPW_DEBUG_INFO("Channel unlocked.\n"); | ||
4471 | if (priv->config & CFG_STATIC_ESSID) | ||
4472 | IPW_DEBUG_INFO("ESSID locked to '%s'\n", | ||
4473 | escape_essid(priv->essid, | ||
4474 | priv->essid_len)); | ||
4475 | else | ||
4476 | IPW_DEBUG_INFO("ESSID unlocked.\n"); | ||
4477 | if (priv->config & CFG_STATIC_BSSID) | ||
4478 | IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel); | ||
4479 | else | ||
4480 | IPW_DEBUG_INFO("BSSID unlocked.\n"); | ||
4481 | if (priv->capability & CAP_PRIVACY_ON) | ||
4482 | IPW_DEBUG_INFO("PRIVACY on\n"); | ||
4483 | else | ||
4484 | IPW_DEBUG_INFO("PRIVACY off\n"); | ||
4485 | IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask); | ||
4486 | } | ||
4487 | #else | ||
4488 | #define ipw_debug_config(x) do {} while (0) | ||
4489 | #endif | ||
4490 | |||
4491 | static inline void ipw_set_fixed_rate(struct ipw_priv *priv, | ||
4492 | struct ieee80211_network *network) | ||
4493 | { | ||
4494 | /* TODO: Verify that this works... */ | ||
4495 | struct ipw_fixed_rate fr = { | ||
4496 | .tx_rates = priv->rates_mask | ||
4497 | }; | ||
4498 | u32 reg; | ||
4499 | u16 mask = 0; | ||
4500 | |||
4501 | /* Identify 'current FW band' and match it with the fixed | ||
4502 | * Tx rates */ | ||
4503 | |||
4504 | switch (priv->ieee->freq_band) { | ||
4505 | case IEEE80211_52GHZ_BAND: /* A only */ | ||
4506 | /* IEEE_A */ | ||
4507 | if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { | ||
4508 | /* Invalid fixed rate mask */ | ||
4509 | fr.tx_rates = 0; | ||
4510 | break; | ||
4511 | } | ||
4512 | |||
4513 | fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; | ||
4514 | break; | ||
4515 | |||
4516 | default: /* 2.4Ghz or Mixed */ | ||
4517 | /* IEEE_B */ | ||
4518 | if (network->mode == IEEE_B) { | ||
4519 | if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { | ||
4520 | /* Invalid fixed rate mask */ | ||
4521 | fr.tx_rates = 0; | ||
4522 | } | ||
4523 | break; | ||
4524 | } | ||
4525 | |||
4526 | /* IEEE_G */ | ||
4527 | if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | | ||
4528 | IEEE80211_OFDM_RATES_MASK)) { | ||
4529 | /* Invalid fixed rate mask */ | ||
4530 | fr.tx_rates = 0; | ||
4531 | break; | ||
4532 | } | ||
4533 | |||
4534 | if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { | ||
4535 | mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); | ||
4536 | fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; | ||
4537 | } | ||
4538 | |||
4539 | if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { | ||
4540 | mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); | ||
4541 | fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; | ||
4542 | } | ||
4543 | |||
4544 | if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { | ||
4545 | mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); | ||
4546 | fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; | ||
4547 | } | ||
4548 | |||
4549 | fr.tx_rates |= mask; | ||
4550 | break; | ||
4551 | } | ||
4552 | |||
4553 | reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); | ||
4554 | ipw_write_reg32(priv, reg, *(u32*)&fr); | ||
4555 | } | ||
4556 | |||
4557 | static int ipw_associate_network(struct ipw_priv *priv, | ||
4558 | struct ieee80211_network *network, | ||
4559 | struct ipw_supported_rates *rates, | ||
4560 | int roaming) | ||
4561 | { | ||
4562 | int err; | ||
4563 | |||
4564 | if (priv->config & CFG_FIXED_RATE) | ||
4565 | ipw_set_fixed_rate(priv, network); | ||
4566 | |||
4567 | if (!(priv->config & CFG_STATIC_ESSID)) { | ||
4568 | priv->essid_len = min(network->ssid_len, | ||
4569 | (u8)IW_ESSID_MAX_SIZE); | ||
4570 | memcpy(priv->essid, network->ssid, priv->essid_len); | ||
4571 | } | ||
4572 | |||
4573 | network->last_associate = jiffies; | ||
4574 | |||
4575 | memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); | ||
4576 | priv->assoc_request.channel = network->channel; | ||
4577 | if ((priv->capability & CAP_PRIVACY_ON) && | ||
4578 | (priv->capability & CAP_SHARED_KEY)) { | ||
4579 | priv->assoc_request.auth_type = AUTH_SHARED_KEY; | ||
4580 | priv->assoc_request.auth_key = priv->sec.active_key; | ||
4581 | } else { | ||
4582 | priv->assoc_request.auth_type = AUTH_OPEN; | ||
4583 | priv->assoc_request.auth_key = 0; | ||
4584 | } | ||
4585 | |||
4586 | if (priv->capability & CAP_PRIVACY_ON) | ||
4587 | ipw_send_wep_keys(priv); | ||
4588 | |||
4589 | /* | ||
4590 | * It is valid for our ieee device to support multiple modes, but | ||
4591 | * when it comes to associating to a given network we have to choose | ||
4592 | * just one mode. | ||
4593 | */ | ||
4594 | if (network->mode & priv->ieee->mode & IEEE_A) | ||
4595 | priv->assoc_request.ieee_mode = IPW_A_MODE; | ||
4596 | else if (network->mode & priv->ieee->mode & IEEE_G) | ||
4597 | priv->assoc_request.ieee_mode = IPW_G_MODE; | ||
4598 | else if (network->mode & priv->ieee->mode & IEEE_B) | ||
4599 | priv->assoc_request.ieee_mode = IPW_B_MODE; | ||
4600 | |||
4601 | IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " | ||
4602 | "802.11%c [%d], enc=%s%s%s%c%c\n", | ||
4603 | roaming ? "Rea" : "A", | ||
4604 | escape_essid(priv->essid, priv->essid_len), | ||
4605 | network->channel, | ||
4606 | ipw_modes[priv->assoc_request.ieee_mode], | ||
4607 | rates->num_rates, | ||
4608 | priv->capability & CAP_PRIVACY_ON ? "on " : "off", | ||
4609 | priv->capability & CAP_PRIVACY_ON ? | ||
4610 | (priv->capability & CAP_SHARED_KEY ? "(shared)" : | ||
4611 | "(open)") : "", | ||
4612 | priv->capability & CAP_PRIVACY_ON ? " key=" : "", | ||
4613 | priv->capability & CAP_PRIVACY_ON ? | ||
4614 | '1' + priv->sec.active_key : '.', | ||
4615 | priv->capability & CAP_PRIVACY_ON ? | ||
4616 | '.' : ' '); | ||
4617 | |||
4618 | priv->assoc_request.beacon_interval = network->beacon_interval; | ||
4619 | if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && | ||
4620 | (network->time_stamp[0] == 0) && | ||
4621 | (network->time_stamp[1] == 0)) { | ||
4622 | priv->assoc_request.assoc_type = HC_IBSS_START; | ||
4623 | priv->assoc_request.assoc_tsf_msw = 0; | ||
4624 | priv->assoc_request.assoc_tsf_lsw = 0; | ||
4625 | } else { | ||
4626 | if (unlikely(roaming)) | ||
4627 | priv->assoc_request.assoc_type = HC_REASSOCIATE; | ||
4628 | else | ||
4629 | priv->assoc_request.assoc_type = HC_ASSOCIATE; | ||
4630 | priv->assoc_request.assoc_tsf_msw = network->time_stamp[1]; | ||
4631 | priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; | ||
4632 | } | ||
4633 | |||
4634 | memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN); | ||
4635 | |||
4636 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | ||
4637 | memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); | ||
4638 | priv->assoc_request.atim_window = network->atim_window; | ||
4639 | } else { | ||
4640 | memcpy(&priv->assoc_request.dest, network->bssid, | ||
4641 | ETH_ALEN); | ||
4642 | priv->assoc_request.atim_window = 0; | ||
4643 | } | ||
4644 | |||
4645 | priv->assoc_request.capability = network->capability; | ||
4646 | priv->assoc_request.listen_interval = network->listen_interval; | ||
4647 | |||
4648 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | ||
4649 | if (err) { | ||
4650 | IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); | ||
4651 | return err; | ||
4652 | } | ||
4653 | |||
4654 | rates->ieee_mode = priv->assoc_request.ieee_mode; | ||
4655 | rates->purpose = IPW_RATE_CONNECT; | ||
4656 | ipw_send_supported_rates(priv, rates); | ||
4657 | |||
4658 | if (priv->assoc_request.ieee_mode == IPW_G_MODE) | ||
4659 | priv->sys_config.dot11g_auto_detection = 1; | ||
4660 | else | ||
4661 | priv->sys_config.dot11g_auto_detection = 0; | ||
4662 | err = ipw_send_system_config(priv, &priv->sys_config); | ||
4663 | if (err) { | ||
4664 | IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); | ||
4665 | return err; | ||
4666 | } | ||
4667 | |||
4668 | IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); | ||
4669 | err = ipw_set_sensitivity(priv, network->stats.rssi); | ||
4670 | if (err) { | ||
4671 | IPW_DEBUG_HC("Attempt to send associate command failed.\n"); | ||
4672 | return err; | ||
4673 | } | ||
4674 | |||
4675 | /* | ||
4676 | * If preemption is enabled, it is possible for the association | ||
4677 | * to complete before we return from ipw_send_associate. Therefore | ||
4678 | * we have to be sure and update our priviate data first. | ||
4679 | */ | ||
4680 | priv->channel = network->channel; | ||
4681 | memcpy(priv->bssid, network->bssid, ETH_ALEN); | ||
4682 | priv->status |= STATUS_ASSOCIATING; | ||
4683 | priv->status &= ~STATUS_SECURITY_UPDATED; | ||
4684 | |||
4685 | priv->assoc_network = network; | ||
4686 | |||
4687 | err = ipw_send_associate(priv, &priv->assoc_request); | ||
4688 | if (err) { | ||
4689 | IPW_DEBUG_HC("Attempt to send associate command failed.\n"); | ||
4690 | return err; | ||
4691 | } | ||
4692 | |||
4693 | IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n", | ||
4694 | escape_essid(priv->essid, priv->essid_len), | ||
4695 | MAC_ARG(priv->bssid)); | ||
4696 | |||
4697 | return 0; | ||
4698 | } | ||
4699 | |||
4700 | static void ipw_roam(void *data) | ||
4701 | { | ||
4702 | struct ipw_priv *priv = data; | ||
4703 | struct ieee80211_network *network = NULL; | ||
4704 | struct ipw_network_match match = { | ||
4705 | .network = priv->assoc_network | ||
4706 | }; | ||
4707 | |||
4708 | /* The roaming process is as follows: | ||
4709 | * | ||
4710 | * 1. Missed beacon threshold triggers the roaming process by | ||
4711 | * setting the status ROAM bit and requesting a scan. | ||
4712 | * 2. When the scan completes, it schedules the ROAM work | ||
4713 | * 3. The ROAM work looks at all of the known networks for one that | ||
4714 | * is a better network than the currently associated. If none | ||
4715 | * found, the ROAM process is over (ROAM bit cleared) | ||
4716 | * 4. If a better network is found, a disassociation request is | ||
4717 | * sent. | ||
4718 | * 5. When the disassociation completes, the roam work is again | ||
4719 | * scheduled. The second time through, the driver is no longer | ||
4720 | * associated, and the newly selected network is sent an | ||
4721 | * association request. | ||
4722 | * 6. At this point ,the roaming process is complete and the ROAM | ||
4723 | * status bit is cleared. | ||
4724 | */ | ||
4725 | |||
4726 | /* If we are no longer associated, and the roaming bit is no longer | ||
4727 | * set, then we are not actively roaming, so just return */ | ||
4728 | if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING))) | ||
4729 | return; | ||
4730 | |||
4731 | if (priv->status & STATUS_ASSOCIATED) { | ||
4732 | /* First pass through ROAM process -- look for a better | ||
4733 | * network */ | ||
4734 | u8 rssi = priv->assoc_network->stats.rssi; | ||
4735 | priv->assoc_network->stats.rssi = -128; | ||
4736 | list_for_each_entry(network, &priv->ieee->network_list, list) { | ||
4737 | if (network != priv->assoc_network) | ||
4738 | ipw_best_network(priv, &match, network, 1); | ||
4739 | } | ||
4740 | priv->assoc_network->stats.rssi = rssi; | ||
4741 | |||
4742 | if (match.network == priv->assoc_network) { | ||
4743 | IPW_DEBUG_ASSOC("No better APs in this network to " | ||
4744 | "roam to.\n"); | ||
4745 | priv->status &= ~STATUS_ROAMING; | ||
4746 | ipw_debug_config(priv); | ||
4747 | return; | ||
4748 | } | ||
4749 | |||
4750 | ipw_send_disassociate(priv, 1); | ||
4751 | priv->assoc_network = match.network; | ||
4752 | |||
4753 | return; | ||
4754 | } | ||
4755 | |||
4756 | /* Second pass through ROAM process -- request association */ | ||
4757 | ipw_compatible_rates(priv, priv->assoc_network, &match.rates); | ||
4758 | ipw_associate_network(priv, priv->assoc_network, &match.rates, 1); | ||
4759 | priv->status &= ~STATUS_ROAMING; | ||
4760 | } | ||
4761 | |||
4762 | static void ipw_associate(void *data) | ||
4763 | { | ||
4764 | struct ipw_priv *priv = data; | ||
4765 | |||
4766 | struct ieee80211_network *network = NULL; | ||
4767 | struct ipw_network_match match = { | ||
4768 | .network = NULL | ||
4769 | }; | ||
4770 | struct ipw_supported_rates *rates; | ||
4771 | struct list_head *element; | ||
4772 | |||
4773 | if (!(priv->config & CFG_ASSOCIATE) && | ||
4774 | !(priv->config & (CFG_STATIC_ESSID | | ||
4775 | CFG_STATIC_CHANNEL | | ||
4776 | CFG_STATIC_BSSID))) { | ||
4777 | IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); | ||
4778 | return; | ||
4779 | } | ||
4780 | |||
4781 | list_for_each_entry(network, &priv->ieee->network_list, list) | ||
4782 | ipw_best_network(priv, &match, network, 0); | ||
4783 | |||
4784 | network = match.network; | ||
4785 | rates = &match.rates; | ||
4786 | |||
4787 | if (network == NULL && | ||
4788 | priv->ieee->iw_mode == IW_MODE_ADHOC && | ||
4789 | priv->config & CFG_ADHOC_CREATE && | ||
4790 | priv->config & CFG_STATIC_ESSID && | ||
4791 | !list_empty(&priv->ieee->network_free_list)) { | ||
4792 | element = priv->ieee->network_free_list.next; | ||
4793 | network = list_entry(element, struct ieee80211_network, | ||
4794 | list); | ||
4795 | ipw_adhoc_create(priv, network); | ||
4796 | rates = &priv->rates; | ||
4797 | list_del(element); | ||
4798 | list_add_tail(&network->list, &priv->ieee->network_list); | ||
4799 | } | ||
4800 | |||
4801 | /* If we reached the end of the list, then we don't have any valid | ||
4802 | * matching APs */ | ||
4803 | if (!network) { | ||
4804 | ipw_debug_config(priv); | ||
4805 | |||
4806 | queue_delayed_work(priv->workqueue, &priv->request_scan, | ||
4807 | SCAN_INTERVAL); | ||
4808 | |||
4809 | return; | ||
4810 | } | ||
4811 | |||
4812 | ipw_associate_network(priv, network, rates, 0); | ||
4813 | } | ||
4814 | |||
4815 | static inline void ipw_handle_data_packet(struct ipw_priv *priv, | ||
4816 | struct ipw_rx_mem_buffer *rxb, | ||
4817 | struct ieee80211_rx_stats *stats) | ||
4818 | { | ||
4819 | struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; | ||
4820 | |||
4821 | /* We received data from the HW, so stop the watchdog */ | ||
4822 | priv->net_dev->trans_start = jiffies; | ||
4823 | |||
4824 | /* We only process data packets if the | ||
4825 | * interface is open */ | ||
4826 | if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) > | ||
4827 | skb_tailroom(rxb->skb))) { | ||
4828 | priv->ieee->stats.rx_errors++; | ||
4829 | priv->wstats.discard.misc++; | ||
4830 | IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); | ||
4831 | return; | ||
4832 | } else if (unlikely(!netif_running(priv->net_dev))) { | ||
4833 | priv->ieee->stats.rx_dropped++; | ||
4834 | priv->wstats.discard.misc++; | ||
4835 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | ||
4836 | return; | ||
4837 | } | ||
4838 | |||
4839 | /* Advance skb->data to the start of the actual payload */ | ||
4840 | skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); | ||
4841 | |||
4842 | /* Set the size of the skb to the size of the frame */ | ||
4843 | skb_put(rxb->skb, pkt->u.frame.length); | ||
4844 | |||
4845 | IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); | ||
4846 | |||
4847 | if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) | ||
4848 | priv->ieee->stats.rx_errors++; | ||
4849 | else /* ieee80211_rx succeeded, so it now owns the SKB */ | ||
4850 | rxb->skb = NULL; | ||
4851 | } | ||
4852 | |||
4853 | |||
4854 | /* | ||
4855 | * Main entry function for recieving a packet with 80211 headers. This | ||
4856 | * should be called when ever the FW has notified us that there is a new | ||
4857 | * skb in the recieve queue. | ||
4858 | */ | ||
4859 | static void ipw_rx(struct ipw_priv *priv) | ||
4860 | { | ||
4861 | struct ipw_rx_mem_buffer *rxb; | ||
4862 | struct ipw_rx_packet *pkt; | ||
4863 | struct ieee80211_hdr *header; | ||
4864 | u32 r, w, i; | ||
4865 | u8 network_packet; | ||
4866 | |||
4867 | r = ipw_read32(priv, CX2_RX_READ_INDEX); | ||
4868 | w = ipw_read32(priv, CX2_RX_WRITE_INDEX); | ||
4869 | i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE; | ||
4870 | |||
4871 | while (i != r) { | ||
4872 | rxb = priv->rxq->queue[i]; | ||
4873 | #ifdef CONFIG_IPW_DEBUG | ||
4874 | if (unlikely(rxb == NULL)) { | ||
4875 | printk(KERN_CRIT "Queue not allocated!\n"); | ||
4876 | break; | ||
4877 | } | ||
4878 | #endif | ||
4879 | priv->rxq->queue[i] = NULL; | ||
4880 | |||
4881 | pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, | ||
4882 | CX2_RX_BUF_SIZE, | ||
4883 | PCI_DMA_FROMDEVICE); | ||
4884 | |||
4885 | pkt = (struct ipw_rx_packet *)rxb->skb->data; | ||
4886 | IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n", | ||
4887 | pkt->header.message_type, | ||
4888 | pkt->header.rx_seq_num, | ||
4889 | pkt->header.control_bits); | ||
4890 | |||
4891 | switch (pkt->header.message_type) { | ||
4892 | case RX_FRAME_TYPE: /* 802.11 frame */ { | ||
4893 | struct ieee80211_rx_stats stats = { | ||
4894 | .rssi = pkt->u.frame.rssi_dbm - | ||
4895 | IPW_RSSI_TO_DBM, | ||
4896 | .signal = pkt->u.frame.signal, | ||
4897 | .rate = pkt->u.frame.rate, | ||
4898 | .mac_time = jiffies, | ||
4899 | .received_channel = | ||
4900 | pkt->u.frame.received_channel, | ||
4901 | .freq = (pkt->u.frame.control & (1<<0)) ? | ||
4902 | IEEE80211_24GHZ_BAND : IEEE80211_52GHZ_BAND, | ||
4903 | .len = pkt->u.frame.length, | ||
4904 | }; | ||
4905 | |||
4906 | if (stats.rssi != 0) | ||
4907 | stats.mask |= IEEE80211_STATMASK_RSSI; | ||
4908 | if (stats.signal != 0) | ||
4909 | stats.mask |= IEEE80211_STATMASK_SIGNAL; | ||
4910 | if (stats.rate != 0) | ||
4911 | stats.mask |= IEEE80211_STATMASK_RATE; | ||
4912 | |||
4913 | priv->rx_packets++; | ||
4914 | |||
4915 | #ifdef CONFIG_IPW_PROMISC | ||
4916 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | ||
4917 | ipw_handle_data_packet(priv, rxb, &stats); | ||
4918 | break; | ||
4919 | } | ||
4920 | #endif | ||
4921 | |||
4922 | header = (struct ieee80211_hdr *)(rxb->skb->data + | ||
4923 | IPW_RX_FRAME_SIZE); | ||
4924 | /* TODO: Check Ad-Hoc dest/source and make sure | ||
4925 | * that we are actually parsing these packets | ||
4926 | * correctly -- we should probably use the | ||
4927 | * frame control of the packet and disregard | ||
4928 | * the current iw_mode */ | ||
4929 | switch (priv->ieee->iw_mode) { | ||
4930 | case IW_MODE_ADHOC: | ||
4931 | network_packet = | ||
4932 | !memcmp(header->addr1, | ||
4933 | priv->net_dev->dev_addr, | ||
4934 | ETH_ALEN) || | ||
4935 | !memcmp(header->addr3, | ||
4936 | priv->bssid, ETH_ALEN) || | ||
4937 | is_broadcast_ether_addr(header->addr1) || | ||
4938 | is_multicast_ether_addr(header->addr1); | ||
4939 | break; | ||
4940 | |||
4941 | case IW_MODE_INFRA: | ||
4942 | default: | ||
4943 | network_packet = | ||
4944 | !memcmp(header->addr3, | ||
4945 | priv->bssid, ETH_ALEN) || | ||
4946 | !memcmp(header->addr1, | ||
4947 | priv->net_dev->dev_addr, | ||
4948 | ETH_ALEN) || | ||
4949 | is_broadcast_ether_addr(header->addr1) || | ||
4950 | is_multicast_ether_addr(header->addr1); | ||
4951 | break; | ||
4952 | } | ||
4953 | |||
4954 | if (network_packet && priv->assoc_network) { | ||
4955 | priv->assoc_network->stats.rssi = stats.rssi; | ||
4956 | average_add(&priv->average_rssi, | ||
4957 | stats.rssi); | ||
4958 | priv->last_rx_rssi = stats.rssi; | ||
4959 | } | ||
4960 | |||
4961 | IPW_DEBUG_RX("Frame: len=%u\n", pkt->u.frame.length); | ||
4962 | |||
4963 | if (pkt->u.frame.length < frame_hdr_len(header)) { | ||
4964 | IPW_DEBUG_DROP("Received packet is too small. " | ||
4965 | "Dropping.\n"); | ||
4966 | priv->ieee->stats.rx_errors++; | ||
4967 | priv->wstats.discard.misc++; | ||
4968 | break; | ||
4969 | } | ||
4970 | |||
4971 | switch (WLAN_FC_GET_TYPE(header->frame_ctl)) { | ||
4972 | case IEEE80211_FTYPE_MGMT: | ||
4973 | ieee80211_rx_mgt(priv->ieee, header, &stats); | ||
4974 | if (priv->ieee->iw_mode == IW_MODE_ADHOC && | ||
4975 | ((WLAN_FC_GET_STYPE(header->frame_ctl) == | ||
4976 | IEEE80211_STYPE_PROBE_RESP) || | ||
4977 | (WLAN_FC_GET_STYPE(header->frame_ctl) == | ||
4978 | IEEE80211_STYPE_BEACON)) && | ||
4979 | !memcmp(header->addr3, priv->bssid, ETH_ALEN)) | ||
4980 | ipw_add_station(priv, header->addr2); | ||
4981 | break; | ||
4982 | |||
4983 | case IEEE80211_FTYPE_CTL: | ||
4984 | break; | ||
4985 | |||
4986 | case IEEE80211_FTYPE_DATA: | ||
4987 | if (network_packet) | ||
4988 | ipw_handle_data_packet(priv, rxb, &stats); | ||
4989 | else | ||
4990 | IPW_DEBUG_DROP("Dropping: " MAC_FMT | ||
4991 | ", " MAC_FMT ", " MAC_FMT "\n", | ||
4992 | MAC_ARG(header->addr1), MAC_ARG(header->addr2), | ||
4993 | MAC_ARG(header->addr3)); | ||
4994 | break; | ||
4995 | } | ||
4996 | break; | ||
4997 | } | ||
4998 | |||
4999 | case RX_HOST_NOTIFICATION_TYPE: { | ||
5000 | IPW_DEBUG_RX("Notification: subtype=%02X flags=%02X size=%d\n", | ||
5001 | pkt->u.notification.subtype, | ||
5002 | pkt->u.notification.flags, | ||
5003 | pkt->u.notification.size); | ||
5004 | ipw_rx_notification(priv, &pkt->u.notification); | ||
5005 | break; | ||
5006 | } | ||
5007 | |||
5008 | default: | ||
5009 | IPW_DEBUG_RX("Bad Rx packet of type %d\n", | ||
5010 | pkt->header.message_type); | ||
5011 | break; | ||
5012 | } | ||
5013 | |||
5014 | /* For now we just don't re-use anything. We can tweak this | ||
5015 | * later to try and re-use notification packets and SKBs that | ||
5016 | * fail to Rx correctly */ | ||
5017 | if (rxb->skb != NULL) { | ||
5018 | dev_kfree_skb_any(rxb->skb); | ||
5019 | rxb->skb = NULL; | ||
5020 | } | ||
5021 | |||
5022 | pci_unmap_single(priv->pci_dev, rxb->dma_addr, | ||
5023 | CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); | ||
5024 | list_add_tail(&rxb->list, &priv->rxq->rx_used); | ||
5025 | |||
5026 | i = (i + 1) % RX_QUEUE_SIZE; | ||
5027 | } | ||
5028 | |||
5029 | /* Backtrack one entry */ | ||
5030 | priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1; | ||
5031 | |||
5032 | ipw_rx_queue_restock(priv); | ||
5033 | } | ||
5034 | |||
5035 | static void ipw_abort_scan(struct ipw_priv *priv) | ||
5036 | { | ||
5037 | int err; | ||
5038 | |||
5039 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
5040 | IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); | ||
5041 | return; | ||
5042 | } | ||
5043 | priv->status |= STATUS_SCAN_ABORTING; | ||
5044 | |||
5045 | err = ipw_send_scan_abort(priv); | ||
5046 | if (err) | ||
5047 | IPW_DEBUG_HC("Request to abort scan failed.\n"); | ||
5048 | } | ||
5049 | |||
5050 | static int ipw_request_scan(struct ipw_priv *priv) | ||
5051 | { | ||
5052 | struct ipw_scan_request_ext scan; | ||
5053 | int channel_index = 0; | ||
5054 | int i, err, scan_type; | ||
5055 | |||
5056 | if (priv->status & STATUS_EXIT_PENDING) { | ||
5057 | IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); | ||
5058 | priv->status |= STATUS_SCAN_PENDING; | ||
5059 | return 0; | ||
5060 | } | ||
5061 | |||
5062 | if (priv->status & STATUS_SCANNING) { | ||
5063 | IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); | ||
5064 | priv->status |= STATUS_SCAN_PENDING; | ||
5065 | ipw_abort_scan(priv); | ||
5066 | return 0; | ||
5067 | } | ||
5068 | |||
5069 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
5070 | IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); | ||
5071 | priv->status |= STATUS_SCAN_PENDING; | ||
5072 | return 0; | ||
5073 | } | ||
5074 | |||
5075 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
5076 | IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); | ||
5077 | priv->status |= STATUS_SCAN_PENDING; | ||
5078 | return 0; | ||
5079 | } | ||
5080 | |||
5081 | memset(&scan, 0, sizeof(scan)); | ||
5082 | |||
5083 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; | ||
5084 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; | ||
5085 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; | ||
5086 | |||
5087 | scan.full_scan_index = ieee80211_get_scans(priv->ieee); | ||
5088 | /* If we are roaming, then make this a directed scan for the current | ||
5089 | * network. Otherwise, ensure that every other scan is a fast | ||
5090 | * channel hop scan */ | ||
5091 | if ((priv->status & STATUS_ROAMING) || ( | ||
5092 | !(priv->status & STATUS_ASSOCIATED) && | ||
5093 | (priv->config & CFG_STATIC_ESSID) && | ||
5094 | (scan.full_scan_index % 2))) { | ||
5095 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | ||
5096 | if (err) { | ||
5097 | IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); | ||
5098 | return err; | ||
5099 | } | ||
5100 | |||
5101 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; | ||
5102 | } else { | ||
5103 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; | ||
5104 | } | ||
5105 | |||
5106 | if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { | ||
5107 | int start = channel_index; | ||
5108 | for (i = 0; i < MAX_A_CHANNELS; i++) { | ||
5109 | if (band_a_active_channel[i] == 0) | ||
5110 | break; | ||
5111 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5112 | band_a_active_channel[i] == priv->channel) | ||
5113 | continue; | ||
5114 | channel_index++; | ||
5115 | scan.channels_list[channel_index] = | ||
5116 | band_a_active_channel[i]; | ||
5117 | ipw_set_scan_type(&scan, channel_index, scan_type); | ||
5118 | } | ||
5119 | |||
5120 | if (start != channel_index) { | ||
5121 | scan.channels_list[start] = (u8)(IPW_A_MODE << 6) | | ||
5122 | (channel_index - start); | ||
5123 | channel_index++; | ||
5124 | } | ||
5125 | } | ||
5126 | |||
5127 | if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { | ||
5128 | int start = channel_index; | ||
5129 | for (i = 0; i < MAX_B_CHANNELS; i++) { | ||
5130 | if (band_b_active_channel[i] == 0) | ||
5131 | break; | ||
5132 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5133 | band_b_active_channel[i] == priv->channel) | ||
5134 | continue; | ||
5135 | channel_index++; | ||
5136 | scan.channels_list[channel_index] = | ||
5137 | band_b_active_channel[i]; | ||
5138 | ipw_set_scan_type(&scan, channel_index, scan_type); | ||
5139 | } | ||
5140 | |||
5141 | if (start != channel_index) { | ||
5142 | scan.channels_list[start] = (u8)(IPW_B_MODE << 6) | | ||
5143 | (channel_index - start); | ||
5144 | } | ||
5145 | } | ||
5146 | |||
5147 | err = ipw_send_scan_request_ext(priv, &scan); | ||
5148 | if (err) { | ||
5149 | IPW_DEBUG_HC("Sending scan command failed: %08X\n", | ||
5150 | err); | ||
5151 | return -EIO; | ||
5152 | } | ||
5153 | |||
5154 | priv->status |= STATUS_SCANNING; | ||
5155 | priv->status &= ~STATUS_SCAN_PENDING; | ||
5156 | |||
5157 | return 0; | ||
5158 | } | ||
5159 | |||
5160 | /* | ||
5161 | * This file defines the Wireless Extension handlers. It does not | ||
5162 | * define any methods of hardware manipulation and relies on the | ||
5163 | * functions defined in ipw_main to provide the HW interaction. | ||
5164 | * | ||
5165 | * The exception to this is the use of the ipw_get_ordinal() | ||
5166 | * function used to poll the hardware vs. making unecessary calls. | ||
5167 | * | ||
5168 | */ | ||
5169 | |||
5170 | static int ipw_wx_get_name(struct net_device *dev, | ||
5171 | struct iw_request_info *info, | ||
5172 | union iwreq_data *wrqu, char *extra) | ||
5173 | { | ||
5174 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5175 | if (!(priv->status & STATUS_ASSOCIATED)) | ||
5176 | strcpy(wrqu->name, "unassociated"); | ||
5177 | else | ||
5178 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", | ||
5179 | ipw_modes[priv->assoc_request.ieee_mode]); | ||
5180 | IPW_DEBUG_WX("Name: %s\n", wrqu->name); | ||
5181 | return 0; | ||
5182 | } | ||
5183 | |||
5184 | static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | ||
5185 | { | ||
5186 | if (channel == 0) { | ||
5187 | IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); | ||
5188 | priv->config &= ~CFG_STATIC_CHANNEL; | ||
5189 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | ||
5190 | STATUS_ASSOCIATING))) { | ||
5191 | IPW_DEBUG_ASSOC("Attempting to associate with new " | ||
5192 | "parameters.\n"); | ||
5193 | ipw_associate(priv); | ||
5194 | } | ||
5195 | |||
5196 | return 0; | ||
5197 | } | ||
5198 | |||
5199 | priv->config |= CFG_STATIC_CHANNEL; | ||
5200 | |||
5201 | if (priv->channel == channel) { | ||
5202 | IPW_DEBUG_INFO( | ||
5203 | "Request to set channel to current value (%d)\n", | ||
5204 | channel); | ||
5205 | return 0; | ||
5206 | } | ||
5207 | |||
5208 | IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); | ||
5209 | priv->channel = channel; | ||
5210 | |||
5211 | /* If we are currently associated, or trying to associate | ||
5212 | * then see if this is a new channel (causing us to disassociate) */ | ||
5213 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5214 | IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); | ||
5215 | ipw_disassociate(priv); | ||
5216 | } else { | ||
5217 | ipw_associate(priv); | ||
5218 | } | ||
5219 | |||
5220 | return 0; | ||
5221 | } | ||
5222 | |||
5223 | static int ipw_wx_set_freq(struct net_device *dev, | ||
5224 | struct iw_request_info *info, | ||
5225 | union iwreq_data *wrqu, char *extra) | ||
5226 | { | ||
5227 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5228 | struct iw_freq *fwrq = &wrqu->freq; | ||
5229 | |||
5230 | /* if setting by freq convert to channel */ | ||
5231 | if (fwrq->e == 1) { | ||
5232 | if ((fwrq->m >= (int) 2.412e8 && | ||
5233 | fwrq->m <= (int) 2.487e8)) { | ||
5234 | int f = fwrq->m / 100000; | ||
5235 | int c = 0; | ||
5236 | |||
5237 | while ((c < REG_MAX_CHANNEL) && | ||
5238 | (f != ipw_frequencies[c])) | ||
5239 | c++; | ||
5240 | |||
5241 | /* hack to fall through */ | ||
5242 | fwrq->e = 0; | ||
5243 | fwrq->m = c + 1; | ||
5244 | } | ||
5245 | } | ||
5246 | |||
5247 | if (fwrq->e > 0 || fwrq->m > 1000) | ||
5248 | return -EOPNOTSUPP; | ||
5249 | |||
5250 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); | ||
5251 | return ipw_set_channel(priv, (u8)fwrq->m); | ||
5252 | |||
5253 | return 0; | ||
5254 | } | ||
5255 | |||
5256 | |||
5257 | static int ipw_wx_get_freq(struct net_device *dev, | ||
5258 | struct iw_request_info *info, | ||
5259 | union iwreq_data *wrqu, char *extra) | ||
5260 | { | ||
5261 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5262 | |||
5263 | wrqu->freq.e = 0; | ||
5264 | |||
5265 | /* If we are associated, trying to associate, or have a statically | ||
5266 | * configured CHANNEL then return that; otherwise return ANY */ | ||
5267 | if (priv->config & CFG_STATIC_CHANNEL || | ||
5268 | priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) | ||
5269 | wrqu->freq.m = priv->channel; | ||
5270 | else | ||
5271 | wrqu->freq.m = 0; | ||
5272 | |||
5273 | IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); | ||
5274 | return 0; | ||
5275 | } | ||
5276 | |||
5277 | static int ipw_wx_set_mode(struct net_device *dev, | ||
5278 | struct iw_request_info *info, | ||
5279 | union iwreq_data *wrqu, char *extra) | ||
5280 | { | ||
5281 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5282 | int err = 0; | ||
5283 | |||
5284 | IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); | ||
5285 | |||
5286 | if (wrqu->mode == priv->ieee->iw_mode) | ||
5287 | return 0; | ||
5288 | |||
5289 | switch (wrqu->mode) { | ||
5290 | #ifdef CONFIG_IPW_PROMISC | ||
5291 | case IW_MODE_MONITOR: | ||
5292 | #endif | ||
5293 | case IW_MODE_ADHOC: | ||
5294 | case IW_MODE_INFRA: | ||
5295 | break; | ||
5296 | case IW_MODE_AUTO: | ||
5297 | wrqu->mode = IW_MODE_INFRA; | ||
5298 | break; | ||
5299 | default: | ||
5300 | return -EINVAL; | ||
5301 | } | ||
5302 | |||
5303 | #ifdef CONFIG_IPW_PROMISC | ||
5304 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | ||
5305 | priv->net_dev->type = ARPHRD_ETHER; | ||
5306 | |||
5307 | if (wrqu->mode == IW_MODE_MONITOR) | ||
5308 | priv->net_dev->type = ARPHRD_IEEE80211; | ||
5309 | #endif /* CONFIG_IPW_PROMISC */ | ||
5310 | |||
5311 | #ifdef CONFIG_PM | ||
5312 | /* Free the existing firmware and reset the fw_loaded | ||
5313 | * flag so ipw_load() will bring in the new firmawre */ | ||
5314 | if (fw_loaded) { | ||
5315 | fw_loaded = 0; | ||
5316 | } | ||
5317 | |||
5318 | release_firmware(bootfw); | ||
5319 | release_firmware(ucode); | ||
5320 | release_firmware(firmware); | ||
5321 | bootfw = ucode = firmware = NULL; | ||
5322 | #endif | ||
5323 | |||
5324 | priv->ieee->iw_mode = wrqu->mode; | ||
5325 | ipw_adapter_restart(priv); | ||
5326 | |||
5327 | return err; | ||
5328 | } | ||
5329 | |||
5330 | static int ipw_wx_get_mode(struct net_device *dev, | ||
5331 | struct iw_request_info *info, | ||
5332 | union iwreq_data *wrqu, char *extra) | ||
5333 | { | ||
5334 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5335 | |||
5336 | wrqu->mode = priv->ieee->iw_mode; | ||
5337 | IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); | ||
5338 | |||
5339 | return 0; | ||
5340 | } | ||
5341 | |||
5342 | |||
5343 | #define DEFAULT_RTS_THRESHOLD 2304U | ||
5344 | #define MIN_RTS_THRESHOLD 1U | ||
5345 | #define MAX_RTS_THRESHOLD 2304U | ||
5346 | #define DEFAULT_BEACON_INTERVAL 100U | ||
5347 | #define DEFAULT_SHORT_RETRY_LIMIT 7U | ||
5348 | #define DEFAULT_LONG_RETRY_LIMIT 4U | ||
5349 | |||
5350 | /* Values are in microsecond */ | ||
5351 | static const s32 timeout_duration[] = { | ||
5352 | 350000, | ||
5353 | 250000, | ||
5354 | 75000, | ||
5355 | 37000, | ||
5356 | 25000, | ||
5357 | }; | ||
5358 | |||
5359 | static const s32 period_duration[] = { | ||
5360 | 400000, | ||
5361 | 700000, | ||
5362 | 1000000, | ||
5363 | 1000000, | ||
5364 | 1000000 | ||
5365 | }; | ||
5366 | |||
5367 | static int ipw_wx_get_range(struct net_device *dev, | ||
5368 | struct iw_request_info *info, | ||
5369 | union iwreq_data *wrqu, char *extra) | ||
5370 | { | ||
5371 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5372 | struct iw_range *range = (struct iw_range *)extra; | ||
5373 | u16 val; | ||
5374 | int i; | ||
5375 | |||
5376 | wrqu->data.length = sizeof(*range); | ||
5377 | memset(range, 0, sizeof(*range)); | ||
5378 | |||
5379 | /* 54Mbs == ~27 Mb/s real (802.11g) */ | ||
5380 | range->throughput = 27 * 1000 * 1000; | ||
5381 | |||
5382 | range->max_qual.qual = 100; | ||
5383 | /* TODO: Find real max RSSI and stick here */ | ||
5384 | range->max_qual.level = 0; | ||
5385 | range->max_qual.noise = 0; | ||
5386 | range->max_qual.updated = 7; /* Updated all three */ | ||
5387 | |||
5388 | range->avg_qual.qual = 70; | ||
5389 | /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ | ||
5390 | range->avg_qual.level = 0; /* FIXME to real average level */ | ||
5391 | range->avg_qual.noise = 0; | ||
5392 | range->avg_qual.updated = 7; /* Updated all three */ | ||
5393 | |||
5394 | range->num_bitrates = min(priv->rates.num_rates, (u8)IW_MAX_BITRATES); | ||
5395 | |||
5396 | for (i = 0; i < range->num_bitrates; i++) | ||
5397 | range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) * | ||
5398 | 500000; | ||
5399 | |||
5400 | range->max_rts = DEFAULT_RTS_THRESHOLD; | ||
5401 | range->min_frag = MIN_FRAG_THRESHOLD; | ||
5402 | range->max_frag = MAX_FRAG_THRESHOLD; | ||
5403 | |||
5404 | range->encoding_size[0] = 5; | ||
5405 | range->encoding_size[1] = 13; | ||
5406 | range->num_encoding_sizes = 2; | ||
5407 | range->max_encoding_tokens = WEP_KEYS; | ||
5408 | |||
5409 | /* Set the Wireless Extension versions */ | ||
5410 | range->we_version_compiled = WIRELESS_EXT; | ||
5411 | range->we_version_source = 16; | ||
5412 | |||
5413 | range->num_channels = FREQ_COUNT; | ||
5414 | |||
5415 | val = 0; | ||
5416 | for (i = 0; i < FREQ_COUNT; i++) { | ||
5417 | range->freq[val].i = i + 1; | ||
5418 | range->freq[val].m = ipw_frequencies[i] * 100000; | ||
5419 | range->freq[val].e = 1; | ||
5420 | val++; | ||
5421 | |||
5422 | if (val == IW_MAX_FREQUENCIES) | ||
5423 | break; | ||
5424 | } | ||
5425 | range->num_frequency = val; | ||
5426 | |||
5427 | IPW_DEBUG_WX("GET Range\n"); | ||
5428 | return 0; | ||
5429 | } | ||
5430 | |||
5431 | static int ipw_wx_set_wap(struct net_device *dev, | ||
5432 | struct iw_request_info *info, | ||
5433 | union iwreq_data *wrqu, char *extra) | ||
5434 | { | ||
5435 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5436 | |||
5437 | static const unsigned char any[] = { | ||
5438 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
5439 | }; | ||
5440 | static const unsigned char off[] = { | ||
5441 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
5442 | }; | ||
5443 | |||
5444 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) | ||
5445 | return -EINVAL; | ||
5446 | |||
5447 | if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || | ||
5448 | !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { | ||
5449 | /* we disable mandatory BSSID association */ | ||
5450 | IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); | ||
5451 | priv->config &= ~CFG_STATIC_BSSID; | ||
5452 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | ||
5453 | STATUS_ASSOCIATING))) { | ||
5454 | IPW_DEBUG_ASSOC("Attempting to associate with new " | ||
5455 | "parameters.\n"); | ||
5456 | ipw_associate(priv); | ||
5457 | } | ||
5458 | |||
5459 | return 0; | ||
5460 | } | ||
5461 | |||
5462 | priv->config |= CFG_STATIC_BSSID; | ||
5463 | if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { | ||
5464 | IPW_DEBUG_WX("BSSID set to current BSSID.\n"); | ||
5465 | return 0; | ||
5466 | } | ||
5467 | |||
5468 | IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n", | ||
5469 | MAC_ARG(wrqu->ap_addr.sa_data)); | ||
5470 | |||
5471 | memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); | ||
5472 | |||
5473 | /* If we are currently associated, or trying to associate | ||
5474 | * then see if this is a new BSSID (causing us to disassociate) */ | ||
5475 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5476 | IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); | ||
5477 | ipw_disassociate(priv); | ||
5478 | } else { | ||
5479 | ipw_associate(priv); | ||
5480 | } | ||
5481 | |||
5482 | return 0; | ||
5483 | } | ||
5484 | |||
5485 | static int ipw_wx_get_wap(struct net_device *dev, | ||
5486 | struct iw_request_info *info, | ||
5487 | union iwreq_data *wrqu, char *extra) | ||
5488 | { | ||
5489 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5490 | /* If we are associated, trying to associate, or have a statically | ||
5491 | * configured BSSID then return that; otherwise return ANY */ | ||
5492 | if (priv->config & CFG_STATIC_BSSID || | ||
5493 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5494 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | ||
5495 | memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); | ||
5496 | } else | ||
5497 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); | ||
5498 | |||
5499 | IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", | ||
5500 | MAC_ARG(wrqu->ap_addr.sa_data)); | ||
5501 | return 0; | ||
5502 | } | ||
5503 | |||
5504 | static int ipw_wx_set_essid(struct net_device *dev, | ||
5505 | struct iw_request_info *info, | ||
5506 | union iwreq_data *wrqu, char *extra) | ||
5507 | { | ||
5508 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5509 | char *essid = ""; /* ANY */ | ||
5510 | int length = 0; | ||
5511 | |||
5512 | if (wrqu->essid.flags && wrqu->essid.length) { | ||
5513 | length = wrqu->essid.length - 1; | ||
5514 | essid = extra; | ||
5515 | } | ||
5516 | if (length == 0) { | ||
5517 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); | ||
5518 | priv->config &= ~CFG_STATIC_ESSID; | ||
5519 | if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | | ||
5520 | STATUS_ASSOCIATING))) { | ||
5521 | IPW_DEBUG_ASSOC("Attempting to associate with new " | ||
5522 | "parameters.\n"); | ||
5523 | ipw_associate(priv); | ||
5524 | } | ||
5525 | |||
5526 | return 0; | ||
5527 | } | ||
5528 | |||
5529 | length = min(length, IW_ESSID_MAX_SIZE); | ||
5530 | |||
5531 | priv->config |= CFG_STATIC_ESSID; | ||
5532 | |||
5533 | if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { | ||
5534 | IPW_DEBUG_WX("ESSID set to current ESSID.\n"); | ||
5535 | return 0; | ||
5536 | } | ||
5537 | |||
5538 | IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), | ||
5539 | length); | ||
5540 | |||
5541 | priv->essid_len = length; | ||
5542 | memcpy(priv->essid, essid, priv->essid_len); | ||
5543 | |||
5544 | /* If we are currently associated, or trying to associate | ||
5545 | * then see if this is a new ESSID (causing us to disassociate) */ | ||
5546 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5547 | IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); | ||
5548 | ipw_disassociate(priv); | ||
5549 | } else { | ||
5550 | ipw_associate(priv); | ||
5551 | } | ||
5552 | |||
5553 | return 0; | ||
5554 | } | ||
5555 | |||
5556 | static int ipw_wx_get_essid(struct net_device *dev, | ||
5557 | struct iw_request_info *info, | ||
5558 | union iwreq_data *wrqu, char *extra) | ||
5559 | { | ||
5560 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5561 | |||
5562 | /* If we are associated, trying to associate, or have a statically | ||
5563 | * configured ESSID then return that; otherwise return ANY */ | ||
5564 | if (priv->config & CFG_STATIC_ESSID || | ||
5565 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5566 | IPW_DEBUG_WX("Getting essid: '%s'\n", | ||
5567 | escape_essid(priv->essid, priv->essid_len)); | ||
5568 | memcpy(extra, priv->essid, priv->essid_len); | ||
5569 | wrqu->essid.length = priv->essid_len; | ||
5570 | wrqu->essid.flags = 1; /* active */ | ||
5571 | } else { | ||
5572 | IPW_DEBUG_WX("Getting essid: ANY\n"); | ||
5573 | wrqu->essid.length = 0; | ||
5574 | wrqu->essid.flags = 0; /* active */ | ||
5575 | } | ||
5576 | |||
5577 | return 0; | ||
5578 | } | ||
5579 | |||
5580 | static int ipw_wx_set_nick(struct net_device *dev, | ||
5581 | struct iw_request_info *info, | ||
5582 | union iwreq_data *wrqu, char *extra) | ||
5583 | { | ||
5584 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5585 | |||
5586 | IPW_DEBUG_WX("Setting nick to '%s'\n", extra); | ||
5587 | if (wrqu->data.length > IW_ESSID_MAX_SIZE) | ||
5588 | return -E2BIG; | ||
5589 | |||
5590 | wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick)); | ||
5591 | memset(priv->nick, 0, sizeof(priv->nick)); | ||
5592 | memcpy(priv->nick, extra, wrqu->data.length); | ||
5593 | IPW_DEBUG_TRACE("<<\n"); | ||
5594 | return 0; | ||
5595 | |||
5596 | } | ||
5597 | |||
5598 | |||
5599 | static int ipw_wx_get_nick(struct net_device *dev, | ||
5600 | struct iw_request_info *info, | ||
5601 | union iwreq_data *wrqu, char *extra) | ||
5602 | { | ||
5603 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5604 | IPW_DEBUG_WX("Getting nick\n"); | ||
5605 | wrqu->data.length = strlen(priv->nick) + 1; | ||
5606 | memcpy(extra, priv->nick, wrqu->data.length); | ||
5607 | wrqu->data.flags = 1; /* active */ | ||
5608 | return 0; | ||
5609 | } | ||
5610 | |||
5611 | |||
5612 | static int ipw_wx_set_rate(struct net_device *dev, | ||
5613 | struct iw_request_info *info, | ||
5614 | union iwreq_data *wrqu, char *extra) | ||
5615 | { | ||
5616 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | ||
5617 | return -EOPNOTSUPP; | ||
5618 | } | ||
5619 | |||
5620 | static int ipw_wx_get_rate(struct net_device *dev, | ||
5621 | struct iw_request_info *info, | ||
5622 | union iwreq_data *wrqu, char *extra) | ||
5623 | { | ||
5624 | struct ipw_priv * priv = ieee80211_priv(dev); | ||
5625 | wrqu->bitrate.value = priv->last_rate; | ||
5626 | |||
5627 | IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); | ||
5628 | return 0; | ||
5629 | } | ||
5630 | |||
5631 | |||
5632 | static int ipw_wx_set_rts(struct net_device *dev, | ||
5633 | struct iw_request_info *info, | ||
5634 | union iwreq_data *wrqu, char *extra) | ||
5635 | { | ||
5636 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5637 | |||
5638 | if (wrqu->rts.disabled) | ||
5639 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; | ||
5640 | else { | ||
5641 | if (wrqu->rts.value < MIN_RTS_THRESHOLD || | ||
5642 | wrqu->rts.value > MAX_RTS_THRESHOLD) | ||
5643 | return -EINVAL; | ||
5644 | |||
5645 | priv->rts_threshold = wrqu->rts.value; | ||
5646 | } | ||
5647 | |||
5648 | ipw_send_rts_threshold(priv, priv->rts_threshold); | ||
5649 | IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); | ||
5650 | return 0; | ||
5651 | } | ||
5652 | |||
5653 | static int ipw_wx_get_rts(struct net_device *dev, | ||
5654 | struct iw_request_info *info, | ||
5655 | union iwreq_data *wrqu, char *extra) | ||
5656 | { | ||
5657 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5658 | wrqu->rts.value = priv->rts_threshold; | ||
5659 | wrqu->rts.fixed = 0; /* no auto select */ | ||
5660 | wrqu->rts.disabled = | ||
5661 | (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); | ||
5662 | |||
5663 | IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); | ||
5664 | return 0; | ||
5665 | } | ||
5666 | |||
5667 | |||
5668 | static int ipw_wx_set_txpow(struct net_device *dev, | ||
5669 | struct iw_request_info *info, | ||
5670 | union iwreq_data *wrqu, char *extra) | ||
5671 | { | ||
5672 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5673 | struct ipw_tx_power tx_power; | ||
5674 | int i; | ||
5675 | |||
5676 | if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) | ||
5677 | return -EINPROGRESS; | ||
5678 | |||
5679 | if (wrqu->power.flags != IW_TXPOW_DBM) | ||
5680 | return -EINVAL; | ||
5681 | |||
5682 | if ((wrqu->power.value > 20) || | ||
5683 | (wrqu->power.value < -12)) | ||
5684 | return -EINVAL; | ||
5685 | |||
5686 | priv->tx_power = wrqu->power.value; | ||
5687 | |||
5688 | memset(&tx_power, 0, sizeof(tx_power)); | ||
5689 | |||
5690 | /* configure device for 'G' band */ | ||
5691 | tx_power.ieee_mode = IPW_G_MODE; | ||
5692 | tx_power.num_channels = 11; | ||
5693 | for (i = 0; i < 11; i++) { | ||
5694 | tx_power.channels_tx_power[i].channel_number = i + 1; | ||
5695 | tx_power.channels_tx_power[i].tx_power = priv->tx_power; | ||
5696 | } | ||
5697 | if (ipw_send_tx_power(priv, &tx_power)) | ||
5698 | goto error; | ||
5699 | |||
5700 | /* configure device to also handle 'B' band */ | ||
5701 | tx_power.ieee_mode = IPW_B_MODE; | ||
5702 | if (ipw_send_tx_power(priv, &tx_power)) | ||
5703 | goto error; | ||
5704 | |||
5705 | return 0; | ||
5706 | |||
5707 | error: | ||
5708 | return -EIO; | ||
5709 | } | ||
5710 | |||
5711 | |||
5712 | static int ipw_wx_get_txpow(struct net_device *dev, | ||
5713 | struct iw_request_info *info, | ||
5714 | union iwreq_data *wrqu, char *extra) | ||
5715 | { | ||
5716 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5717 | |||
5718 | wrqu->power.value = priv->tx_power; | ||
5719 | wrqu->power.fixed = 1; | ||
5720 | wrqu->power.flags = IW_TXPOW_DBM; | ||
5721 | wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; | ||
5722 | |||
5723 | IPW_DEBUG_WX("GET TX Power -> %s %d \n", | ||
5724 | wrqu->power.disabled ? "ON" : "OFF", | ||
5725 | wrqu->power.value); | ||
5726 | |||
5727 | return 0; | ||
5728 | } | ||
5729 | |||
5730 | static int ipw_wx_set_frag(struct net_device *dev, | ||
5731 | struct iw_request_info *info, | ||
5732 | union iwreq_data *wrqu, char *extra) | ||
5733 | { | ||
5734 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5735 | |||
5736 | if (wrqu->frag.disabled) | ||
5737 | priv->ieee->fts = DEFAULT_FTS; | ||
5738 | else { | ||
5739 | if (wrqu->frag.value < MIN_FRAG_THRESHOLD || | ||
5740 | wrqu->frag.value > MAX_FRAG_THRESHOLD) | ||
5741 | return -EINVAL; | ||
5742 | |||
5743 | priv->ieee->fts = wrqu->frag.value & ~0x1; | ||
5744 | } | ||
5745 | |||
5746 | ipw_send_frag_threshold(priv, wrqu->frag.value); | ||
5747 | IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); | ||
5748 | return 0; | ||
5749 | } | ||
5750 | |||
5751 | static int ipw_wx_get_frag(struct net_device *dev, | ||
5752 | struct iw_request_info *info, | ||
5753 | union iwreq_data *wrqu, char *extra) | ||
5754 | { | ||
5755 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5756 | wrqu->frag.value = priv->ieee->fts; | ||
5757 | wrqu->frag.fixed = 0; /* no auto select */ | ||
5758 | wrqu->frag.disabled = | ||
5759 | (wrqu->frag.value == DEFAULT_FTS); | ||
5760 | |||
5761 | IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); | ||
5762 | |||
5763 | return 0; | ||
5764 | } | ||
5765 | |||
5766 | static int ipw_wx_set_retry(struct net_device *dev, | ||
5767 | struct iw_request_info *info, | ||
5768 | union iwreq_data *wrqu, char *extra) | ||
5769 | { | ||
5770 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | ||
5771 | return -EOPNOTSUPP; | ||
5772 | } | ||
5773 | |||
5774 | |||
5775 | static int ipw_wx_get_retry(struct net_device *dev, | ||
5776 | struct iw_request_info *info, | ||
5777 | union iwreq_data *wrqu, char *extra) | ||
5778 | { | ||
5779 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | ||
5780 | return -EOPNOTSUPP; | ||
5781 | } | ||
5782 | |||
5783 | |||
5784 | static int ipw_wx_set_scan(struct net_device *dev, | ||
5785 | struct iw_request_info *info, | ||
5786 | union iwreq_data *wrqu, char *extra) | ||
5787 | { | ||
5788 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5789 | IPW_DEBUG_WX("Start scan\n"); | ||
5790 | if (ipw_request_scan(priv)) | ||
5791 | return -EIO; | ||
5792 | return 0; | ||
5793 | } | ||
5794 | |||
5795 | static int ipw_wx_get_scan(struct net_device *dev, | ||
5796 | struct iw_request_info *info, | ||
5797 | union iwreq_data *wrqu, char *extra) | ||
5798 | { | ||
5799 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5800 | return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); | ||
5801 | } | ||
5802 | |||
5803 | static int ipw_wx_set_encode(struct net_device *dev, | ||
5804 | struct iw_request_info *info, | ||
5805 | union iwreq_data *wrqu, char *key) | ||
5806 | { | ||
5807 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5808 | return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); | ||
5809 | } | ||
5810 | |||
5811 | static int ipw_wx_get_encode(struct net_device *dev, | ||
5812 | struct iw_request_info *info, | ||
5813 | union iwreq_data *wrqu, char *key) | ||
5814 | { | ||
5815 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5816 | return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); | ||
5817 | } | ||
5818 | |||
5819 | static int ipw_wx_set_power(struct net_device *dev, | ||
5820 | struct iw_request_info *info, | ||
5821 | union iwreq_data *wrqu, char *extra) | ||
5822 | { | ||
5823 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5824 | int err; | ||
5825 | |||
5826 | if (wrqu->power.disabled) { | ||
5827 | priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); | ||
5828 | err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); | ||
5829 | if (err) { | ||
5830 | IPW_DEBUG_WX("failed setting power mode.\n"); | ||
5831 | return err; | ||
5832 | } | ||
5833 | |||
5834 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); | ||
5835 | |||
5836 | return 0; | ||
5837 | } | ||
5838 | |||
5839 | switch (wrqu->power.flags & IW_POWER_MODE) { | ||
5840 | case IW_POWER_ON: /* If not specified */ | ||
5841 | case IW_POWER_MODE: /* If set all mask */ | ||
5842 | case IW_POWER_ALL_R: /* If explicitely state all */ | ||
5843 | break; | ||
5844 | default: /* Otherwise we don't support it */ | ||
5845 | IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", | ||
5846 | wrqu->power.flags); | ||
5847 | return -EOPNOTSUPP; | ||
5848 | } | ||
5849 | |||
5850 | /* If the user hasn't specified a power management mode yet, default | ||
5851 | * to BATTERY */ | ||
5852 | if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC) | ||
5853 | priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; | ||
5854 | else | ||
5855 | priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; | ||
5856 | err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); | ||
5857 | if (err) { | ||
5858 | IPW_DEBUG_WX("failed setting power mode.\n"); | ||
5859 | return err; | ||
5860 | } | ||
5861 | |||
5862 | IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", | ||
5863 | priv->power_mode); | ||
5864 | |||
5865 | return 0; | ||
5866 | } | ||
5867 | |||
5868 | static int ipw_wx_get_power(struct net_device *dev, | ||
5869 | struct iw_request_info *info, | ||
5870 | union iwreq_data *wrqu, char *extra) | ||
5871 | { | ||
5872 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5873 | |||
5874 | if (!(priv->power_mode & IPW_POWER_ENABLED)) { | ||
5875 | wrqu->power.disabled = 1; | ||
5876 | } else { | ||
5877 | wrqu->power.disabled = 0; | ||
5878 | } | ||
5879 | |||
5880 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); | ||
5881 | |||
5882 | return 0; | ||
5883 | } | ||
5884 | |||
5885 | static int ipw_wx_set_powermode(struct net_device *dev, | ||
5886 | struct iw_request_info *info, | ||
5887 | union iwreq_data *wrqu, char *extra) | ||
5888 | { | ||
5889 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5890 | int mode = *(int *)extra; | ||
5891 | int err; | ||
5892 | |||
5893 | if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { | ||
5894 | mode = IPW_POWER_AC; | ||
5895 | priv->power_mode = mode; | ||
5896 | } else { | ||
5897 | priv->power_mode = IPW_POWER_ENABLED | mode; | ||
5898 | } | ||
5899 | |||
5900 | if (priv->power_mode != mode) { | ||
5901 | err = ipw_send_power_mode(priv, mode); | ||
5902 | |||
5903 | if (err) { | ||
5904 | IPW_DEBUG_WX("failed setting power mode.\n"); | ||
5905 | return err; | ||
5906 | } | ||
5907 | } | ||
5908 | |||
5909 | return 0; | ||
5910 | } | ||
5911 | |||
5912 | #define MAX_WX_STRING 80 | ||
5913 | static int ipw_wx_get_powermode(struct net_device *dev, | ||
5914 | struct iw_request_info *info, | ||
5915 | union iwreq_data *wrqu, char *extra) | ||
5916 | { | ||
5917 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5918 | int level = IPW_POWER_LEVEL(priv->power_mode); | ||
5919 | char *p = extra; | ||
5920 | |||
5921 | p += snprintf(p, MAX_WX_STRING, "Power save level: %d ", level); | ||
5922 | |||
5923 | switch (level) { | ||
5924 | case IPW_POWER_AC: | ||
5925 | p += snprintf(p, MAX_WX_STRING - (p - extra), "(AC)"); | ||
5926 | break; | ||
5927 | case IPW_POWER_BATTERY: | ||
5928 | p += snprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)"); | ||
5929 | break; | ||
5930 | default: | ||
5931 | p += snprintf(p, MAX_WX_STRING - (p - extra), | ||
5932 | "(Timeout %dms, Period %dms)", | ||
5933 | timeout_duration[level - 1] / 1000, | ||
5934 | period_duration[level - 1] / 1000); | ||
5935 | } | ||
5936 | |||
5937 | if (!(priv->power_mode & IPW_POWER_ENABLED)) | ||
5938 | p += snprintf(p, MAX_WX_STRING - (p - extra)," OFF"); | ||
5939 | |||
5940 | wrqu->data.length = p - extra + 1; | ||
5941 | |||
5942 | return 0; | ||
5943 | } | ||
5944 | |||
5945 | static int ipw_wx_set_wireless_mode(struct net_device *dev, | ||
5946 | struct iw_request_info *info, | ||
5947 | union iwreq_data *wrqu, char *extra) | ||
5948 | { | ||
5949 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5950 | int mode = *(int *)extra; | ||
5951 | u8 band = 0, modulation = 0; | ||
5952 | |||
5953 | if (mode == 0 || mode & ~IEEE_MODE_MASK) { | ||
5954 | IPW_WARNING("Attempt to set invalid wireless mode: %d\n", | ||
5955 | mode); | ||
5956 | return -EINVAL; | ||
5957 | } | ||
5958 | |||
5959 | if (priv->adapter == IPW_2915ABG) { | ||
5960 | priv->ieee->abg_ture = 1; | ||
5961 | if (mode & IEEE_A) { | ||
5962 | band |= IEEE80211_52GHZ_BAND; | ||
5963 | modulation |= IEEE80211_OFDM_MODULATION; | ||
5964 | } else | ||
5965 | priv->ieee->abg_ture = 0; | ||
5966 | } else { | ||
5967 | if (mode & IEEE_A) { | ||
5968 | IPW_WARNING("Attempt to set 2200BG into " | ||
5969 | "802.11a mode\n"); | ||
5970 | return -EINVAL; | ||
5971 | } | ||
5972 | |||
5973 | priv->ieee->abg_ture = 0; | ||
5974 | } | ||
5975 | |||
5976 | if (mode & IEEE_B) { | ||
5977 | band |= IEEE80211_24GHZ_BAND; | ||
5978 | modulation |= IEEE80211_CCK_MODULATION; | ||
5979 | } else | ||
5980 | priv->ieee->abg_ture = 0; | ||
5981 | |||
5982 | if (mode & IEEE_G) { | ||
5983 | band |= IEEE80211_24GHZ_BAND; | ||
5984 | modulation |= IEEE80211_OFDM_MODULATION; | ||
5985 | } else | ||
5986 | priv->ieee->abg_ture = 0; | ||
5987 | |||
5988 | priv->ieee->mode = mode; | ||
5989 | priv->ieee->freq_band = band; | ||
5990 | priv->ieee->modulation = modulation; | ||
5991 | init_supported_rates(priv, &priv->rates); | ||
5992 | |||
5993 | /* If we are currently associated, or trying to associate | ||
5994 | * then see if this is a new configuration (causing us to | ||
5995 | * disassociate) */ | ||
5996 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
5997 | /* The resulting association will trigger | ||
5998 | * the new rates to be sent to the device */ | ||
5999 | IPW_DEBUG_ASSOC("Disassociating due to mode change.\n"); | ||
6000 | ipw_disassociate(priv); | ||
6001 | } else | ||
6002 | ipw_send_supported_rates(priv, &priv->rates); | ||
6003 | |||
6004 | IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", | ||
6005 | mode & IEEE_A ? 'a' : '.', | ||
6006 | mode & IEEE_B ? 'b' : '.', | ||
6007 | mode & IEEE_G ? 'g' : '.'); | ||
6008 | return 0; | ||
6009 | } | ||
6010 | |||
6011 | static int ipw_wx_get_wireless_mode(struct net_device *dev, | ||
6012 | struct iw_request_info *info, | ||
6013 | union iwreq_data *wrqu, char *extra) | ||
6014 | { | ||
6015 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6016 | |||
6017 | switch (priv->ieee->freq_band) { | ||
6018 | case IEEE80211_24GHZ_BAND: | ||
6019 | switch (priv->ieee->modulation) { | ||
6020 | case IEEE80211_CCK_MODULATION: | ||
6021 | strncpy(extra, "802.11b (2)", MAX_WX_STRING); | ||
6022 | break; | ||
6023 | case IEEE80211_OFDM_MODULATION: | ||
6024 | strncpy(extra, "802.11g (4)", MAX_WX_STRING); | ||
6025 | break; | ||
6026 | default: | ||
6027 | strncpy(extra, "802.11bg (6)", MAX_WX_STRING); | ||
6028 | break; | ||
6029 | } | ||
6030 | break; | ||
6031 | |||
6032 | case IEEE80211_52GHZ_BAND: | ||
6033 | strncpy(extra, "802.11a (1)", MAX_WX_STRING); | ||
6034 | break; | ||
6035 | |||
6036 | default: /* Mixed Band */ | ||
6037 | switch (priv->ieee->modulation) { | ||
6038 | case IEEE80211_CCK_MODULATION: | ||
6039 | strncpy(extra, "802.11ab (3)", MAX_WX_STRING); | ||
6040 | break; | ||
6041 | case IEEE80211_OFDM_MODULATION: | ||
6042 | strncpy(extra, "802.11ag (5)", MAX_WX_STRING); | ||
6043 | break; | ||
6044 | default: | ||
6045 | strncpy(extra, "802.11abg (7)", MAX_WX_STRING); | ||
6046 | break; | ||
6047 | } | ||
6048 | break; | ||
6049 | } | ||
6050 | |||
6051 | IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); | ||
6052 | |||
6053 | wrqu->data.length = strlen(extra) + 1; | ||
6054 | |||
6055 | return 0; | ||
6056 | } | ||
6057 | |||
6058 | #ifdef CONFIG_IPW_PROMISC | ||
6059 | static int ipw_wx_set_promisc(struct net_device *dev, | ||
6060 | struct iw_request_info *info, | ||
6061 | union iwreq_data *wrqu, char *extra) | ||
6062 | { | ||
6063 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6064 | int *parms = (int *)extra; | ||
6065 | int enable = (parms[0] > 0); | ||
6066 | |||
6067 | IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]); | ||
6068 | if (enable) { | ||
6069 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | ||
6070 | priv->net_dev->type = ARPHRD_IEEE80211; | ||
6071 | ipw_adapter_restart(priv); | ||
6072 | } | ||
6073 | |||
6074 | ipw_set_channel(priv, parms[1]); | ||
6075 | } else { | ||
6076 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) | ||
6077 | return 0; | ||
6078 | priv->net_dev->type = ARPHRD_ETHER; | ||
6079 | ipw_adapter_restart(priv); | ||
6080 | } | ||
6081 | return 0; | ||
6082 | } | ||
6083 | |||
6084 | |||
6085 | static int ipw_wx_reset(struct net_device *dev, | ||
6086 | struct iw_request_info *info, | ||
6087 | union iwreq_data *wrqu, char *extra) | ||
6088 | { | ||
6089 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6090 | IPW_DEBUG_WX("RESET\n"); | ||
6091 | ipw_adapter_restart(priv); | ||
6092 | return 0; | ||
6093 | } | ||
6094 | #endif // CONFIG_IPW_PROMISC | ||
6095 | |||
6096 | /* Rebase the WE IOCTLs to zero for the handler array */ | ||
6097 | #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] | ||
6098 | static iw_handler ipw_wx_handlers[] = | ||
6099 | { | ||
6100 | IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, | ||
6101 | IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, | ||
6102 | IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, | ||
6103 | IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, | ||
6104 | IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, | ||
6105 | IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, | ||
6106 | IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, | ||
6107 | IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, | ||
6108 | IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, | ||
6109 | IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, | ||
6110 | IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, | ||
6111 | IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, | ||
6112 | IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, | ||
6113 | IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, | ||
6114 | IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, | ||
6115 | IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, | ||
6116 | IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, | ||
6117 | IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, | ||
6118 | IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, | ||
6119 | IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, | ||
6120 | IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, | ||
6121 | IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, | ||
6122 | IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, | ||
6123 | IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, | ||
6124 | IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, | ||
6125 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, | ||
6126 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, | ||
6127 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, | ||
6128 | }; | ||
6129 | |||
6130 | #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV | ||
6131 | #define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1 | ||
6132 | #define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2 | ||
6133 | #define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3 | ||
6134 | #define IPW_PRIV_SET_PROMISC SIOCIWFIRSTPRIV+4 | ||
6135 | #define IPW_PRIV_RESET SIOCIWFIRSTPRIV+5 | ||
6136 | |||
6137 | |||
6138 | static struct iw_priv_args ipw_priv_args[] = { | ||
6139 | { | ||
6140 | .cmd = IPW_PRIV_SET_POWER, | ||
6141 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
6142 | .name = "set_power" | ||
6143 | }, | ||
6144 | { | ||
6145 | .cmd = IPW_PRIV_GET_POWER, | ||
6146 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, | ||
6147 | .name = "get_power" | ||
6148 | }, | ||
6149 | { | ||
6150 | .cmd = IPW_PRIV_SET_MODE, | ||
6151 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
6152 | .name = "set_mode" | ||
6153 | }, | ||
6154 | { | ||
6155 | .cmd = IPW_PRIV_GET_MODE, | ||
6156 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, | ||
6157 | .name = "get_mode" | ||
6158 | }, | ||
6159 | #ifdef CONFIG_IPW_PROMISC | ||
6160 | { | ||
6161 | IPW_PRIV_SET_PROMISC, | ||
6162 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor" | ||
6163 | }, | ||
6164 | { | ||
6165 | IPW_PRIV_RESET, | ||
6166 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset" | ||
6167 | }, | ||
6168 | #endif /* CONFIG_IPW_PROMISC */ | ||
6169 | }; | ||
6170 | |||
6171 | static iw_handler ipw_priv_handler[] = { | ||
6172 | ipw_wx_set_powermode, | ||
6173 | ipw_wx_get_powermode, | ||
6174 | ipw_wx_set_wireless_mode, | ||
6175 | ipw_wx_get_wireless_mode, | ||
6176 | #ifdef CONFIG_IPW_PROMISC | ||
6177 | ipw_wx_set_promisc, | ||
6178 | ipw_wx_reset, | ||
6179 | #endif | ||
6180 | }; | ||
6181 | |||
6182 | static struct iw_handler_def ipw_wx_handler_def = | ||
6183 | { | ||
6184 | .standard = ipw_wx_handlers, | ||
6185 | .num_standard = ARRAY_SIZE(ipw_wx_handlers), | ||
6186 | .num_private = ARRAY_SIZE(ipw_priv_handler), | ||
6187 | .num_private_args = ARRAY_SIZE(ipw_priv_args), | ||
6188 | .private = ipw_priv_handler, | ||
6189 | .private_args = ipw_priv_args, | ||
6190 | }; | ||
6191 | |||
6192 | |||
6193 | |||
6194 | |||
6195 | /* | ||
6196 | * Get wireless statistics. | ||
6197 | * Called by /proc/net/wireless | ||
6198 | * Also called by SIOCGIWSTATS | ||
6199 | */ | ||
6200 | static struct iw_statistics *ipw_get_wireless_stats(struct net_device * dev) | ||
6201 | { | ||
6202 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6203 | struct iw_statistics *wstats; | ||
6204 | |||
6205 | wstats = &priv->wstats; | ||
6206 | |||
6207 | /* if hw is disabled, then ipw2100_get_ordinal() can't be called. | ||
6208 | * ipw2100_wx_wireless_stats seems to be called before fw is | ||
6209 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up | ||
6210 | * and associated; if not associcated, the values are all meaningless | ||
6211 | * anyway, so set them all to NULL and INVALID */ | ||
6212 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
6213 | wstats->miss.beacon = 0; | ||
6214 | wstats->discard.retries = 0; | ||
6215 | wstats->qual.qual = 0; | ||
6216 | wstats->qual.level = 0; | ||
6217 | wstats->qual.noise = 0; | ||
6218 | wstats->qual.updated = 7; | ||
6219 | wstats->qual.updated |= IW_QUAL_NOISE_INVALID | | ||
6220 | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; | ||
6221 | return wstats; | ||
6222 | } | ||
6223 | |||
6224 | wstats->qual.qual = priv->quality; | ||
6225 | wstats->qual.level = average_value(&priv->average_rssi); | ||
6226 | wstats->qual.noise = average_value(&priv->average_noise); | ||
6227 | wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | | ||
6228 | IW_QUAL_NOISE_UPDATED; | ||
6229 | |||
6230 | wstats->miss.beacon = average_value(&priv->average_missed_beacons); | ||
6231 | wstats->discard.retries = priv->last_tx_failures; | ||
6232 | wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable; | ||
6233 | |||
6234 | /* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len)) | ||
6235 | goto fail_get_ordinal; | ||
6236 | wstats->discard.retries += tx_retry; */ | ||
6237 | |||
6238 | return wstats; | ||
6239 | } | ||
6240 | |||
6241 | |||
6242 | /* net device stuff */ | ||
6243 | |||
6244 | static inline void init_sys_config(struct ipw_sys_config *sys_config) | ||
6245 | { | ||
6246 | memset(sys_config, 0, sizeof(struct ipw_sys_config)); | ||
6247 | sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */ | ||
6248 | sys_config->answer_broadcast_ssid_probe = 0; | ||
6249 | sys_config->accept_all_data_frames = 0; | ||
6250 | sys_config->accept_non_directed_frames = 1; | ||
6251 | sys_config->exclude_unicast_unencrypted = 0; | ||
6252 | sys_config->disable_unicast_decryption = 1; | ||
6253 | sys_config->exclude_multicast_unencrypted = 0; | ||
6254 | sys_config->disable_multicast_decryption = 1; | ||
6255 | sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH; | ||
6256 | sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */ | ||
6257 | sys_config->dot11g_auto_detection = 0; | ||
6258 | sys_config->enable_cts_to_self = 0; | ||
6259 | sys_config->bt_coexist_collision_thr = 0; | ||
6260 | sys_config->pass_noise_stats_to_host = 1; | ||
6261 | } | ||
6262 | |||
6263 | static int ipw_net_open(struct net_device *dev) | ||
6264 | { | ||
6265 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6266 | IPW_DEBUG_INFO("dev->open\n"); | ||
6267 | /* we should be verifying the device is ready to be opened */ | ||
6268 | if (!(priv->status & STATUS_RF_KILL_MASK) && | ||
6269 | (priv->status & STATUS_ASSOCIATED)) | ||
6270 | netif_start_queue(dev); | ||
6271 | return 0; | ||
6272 | } | ||
6273 | |||
6274 | static int ipw_net_stop(struct net_device *dev) | ||
6275 | { | ||
6276 | IPW_DEBUG_INFO("dev->close\n"); | ||
6277 | netif_stop_queue(dev); | ||
6278 | return 0; | ||
6279 | } | ||
6280 | |||
6281 | /* | ||
6282 | todo: | ||
6283 | |||
6284 | modify to send one tfd per fragment instead of using chunking. otherwise | ||
6285 | we need to heavily modify the ieee80211_skb_to_txb. | ||
6286 | */ | ||
6287 | |||
6288 | static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | ||
6289 | { | ||
6290 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) | ||
6291 | txb->fragments[0]->data; | ||
6292 | int i = 0; | ||
6293 | struct tfd_frame *tfd; | ||
6294 | struct clx2_tx_queue *txq = &priv->txq[0]; | ||
6295 | struct clx2_queue *q = &txq->q; | ||
6296 | u8 id, hdr_len, unicast; | ||
6297 | u16 remaining_bytes; | ||
6298 | |||
6299 | switch (priv->ieee->iw_mode) { | ||
6300 | case IW_MODE_ADHOC: | ||
6301 | hdr_len = IEEE80211_3ADDR_LEN; | ||
6302 | unicast = !is_broadcast_ether_addr(hdr->addr1) && | ||
6303 | !is_multicast_ether_addr(hdr->addr1); | ||
6304 | id = ipw_find_station(priv, hdr->addr1); | ||
6305 | if (id == IPW_INVALID_STATION) { | ||
6306 | id = ipw_add_station(priv, hdr->addr1); | ||
6307 | if (id == IPW_INVALID_STATION) { | ||
6308 | IPW_WARNING("Attempt to send data to " | ||
6309 | "invalid cell: " MAC_FMT "\n", | ||
6310 | MAC_ARG(hdr->addr1)); | ||
6311 | goto drop; | ||
6312 | } | ||
6313 | } | ||
6314 | break; | ||
6315 | |||
6316 | case IW_MODE_INFRA: | ||
6317 | default: | ||
6318 | unicast = !is_broadcast_ether_addr(hdr->addr3) && | ||
6319 | !is_multicast_ether_addr(hdr->addr3); | ||
6320 | hdr_len = IEEE80211_3ADDR_LEN; | ||
6321 | id = 0; | ||
6322 | break; | ||
6323 | } | ||
6324 | |||
6325 | tfd = &txq->bd[q->first_empty]; | ||
6326 | txq->txb[q->first_empty] = txb; | ||
6327 | memset(tfd, 0, sizeof(*tfd)); | ||
6328 | tfd->u.data.station_number = id; | ||
6329 | |||
6330 | tfd->control_flags.message_type = TX_FRAME_TYPE; | ||
6331 | tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; | ||
6332 | |||
6333 | tfd->u.data.cmd_id = DINO_CMD_TX; | ||
6334 | tfd->u.data.len = txb->payload_size; | ||
6335 | remaining_bytes = txb->payload_size; | ||
6336 | if (unlikely(!unicast)) | ||
6337 | tfd->u.data.tx_flags = DCT_FLAG_NO_WEP; | ||
6338 | else | ||
6339 | tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD; | ||
6340 | |||
6341 | if (priv->assoc_request.ieee_mode == IPW_B_MODE) | ||
6342 | tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK; | ||
6343 | else | ||
6344 | tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM; | ||
6345 | |||
6346 | if (priv->config & CFG_PREAMBLE) | ||
6347 | tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL; | ||
6348 | |||
6349 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); | ||
6350 | |||
6351 | /* payload */ | ||
6352 | tfd->u.data.num_chunks = min((u8)(NUM_TFD_CHUNKS - 2), txb->nr_frags); | ||
6353 | for (i = 0; i < tfd->u.data.num_chunks; i++) { | ||
6354 | IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", | ||
6355 | i, tfd->u.data.num_chunks, | ||
6356 | txb->fragments[i]->len - hdr_len); | ||
6357 | printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len, | ||
6358 | txb->fragments[i]->len - hdr_len); | ||
6359 | |||
6360 | tfd->u.data.chunk_ptr[i] = pci_map_single( | ||
6361 | priv->pci_dev, txb->fragments[i]->data + hdr_len, | ||
6362 | txb->fragments[i]->len - hdr_len, PCI_DMA_TODEVICE); | ||
6363 | tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len; | ||
6364 | } | ||
6365 | |||
6366 | if (i != txb->nr_frags) { | ||
6367 | struct sk_buff *skb; | ||
6368 | u16 remaining_bytes = 0; | ||
6369 | int j; | ||
6370 | |||
6371 | for (j = i; j < txb->nr_frags; j++) | ||
6372 | remaining_bytes += txb->fragments[j]->len - hdr_len; | ||
6373 | |||
6374 | printk(KERN_INFO "Trying to reallocate for %d bytes\n", | ||
6375 | remaining_bytes); | ||
6376 | skb = alloc_skb(remaining_bytes, GFP_ATOMIC); | ||
6377 | if (skb != NULL) { | ||
6378 | tfd->u.data.chunk_len[i] = remaining_bytes; | ||
6379 | for (j = i; j < txb->nr_frags; j++) { | ||
6380 | int size = txb->fragments[j]->len - hdr_len; | ||
6381 | printk(KERN_INFO "Adding frag %d %d...\n", | ||
6382 | j, size); | ||
6383 | memcpy(skb_put(skb, size), | ||
6384 | txb->fragments[j]->data + hdr_len, | ||
6385 | size); | ||
6386 | } | ||
6387 | dev_kfree_skb_any(txb->fragments[i]); | ||
6388 | txb->fragments[i] = skb; | ||
6389 | tfd->u.data.chunk_ptr[i] = pci_map_single( | ||
6390 | priv->pci_dev, skb->data, | ||
6391 | tfd->u.data.chunk_len[i], PCI_DMA_TODEVICE); | ||
6392 | tfd->u.data.num_chunks++; | ||
6393 | } | ||
6394 | } | ||
6395 | |||
6396 | /* kick DMA */ | ||
6397 | q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); | ||
6398 | ipw_write32(priv, q->reg_w, q->first_empty); | ||
6399 | |||
6400 | if (ipw_queue_space(q) < q->high_mark) | ||
6401 | netif_stop_queue(priv->net_dev); | ||
6402 | |||
6403 | return; | ||
6404 | |||
6405 | drop: | ||
6406 | IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); | ||
6407 | ieee80211_txb_free(txb); | ||
6408 | } | ||
6409 | |||
6410 | static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | ||
6411 | struct net_device *dev) | ||
6412 | { | ||
6413 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6414 | unsigned long flags; | ||
6415 | |||
6416 | IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); | ||
6417 | |||
6418 | spin_lock_irqsave(&priv->lock, flags); | ||
6419 | |||
6420 | if (!(priv->status & STATUS_ASSOCIATED)) { | ||
6421 | IPW_DEBUG_INFO("Tx attempt while not associated.\n"); | ||
6422 | priv->ieee->stats.tx_carrier_errors++; | ||
6423 | netif_stop_queue(dev); | ||
6424 | goto fail_unlock; | ||
6425 | } | ||
6426 | |||
6427 | ipw_tx_skb(priv, txb); | ||
6428 | |||
6429 | spin_unlock_irqrestore(&priv->lock, flags); | ||
6430 | return 0; | ||
6431 | |||
6432 | fail_unlock: | ||
6433 | spin_unlock_irqrestore(&priv->lock, flags); | ||
6434 | return 1; | ||
6435 | } | ||
6436 | |||
6437 | static struct net_device_stats *ipw_net_get_stats(struct net_device *dev) | ||
6438 | { | ||
6439 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6440 | |||
6441 | priv->ieee->stats.tx_packets = priv->tx_packets; | ||
6442 | priv->ieee->stats.rx_packets = priv->rx_packets; | ||
6443 | return &priv->ieee->stats; | ||
6444 | } | ||
6445 | |||
6446 | static void ipw_net_set_multicast_list(struct net_device *dev) | ||
6447 | { | ||
6448 | |||
6449 | } | ||
6450 | |||
6451 | static int ipw_net_set_mac_address(struct net_device *dev, void *p) | ||
6452 | { | ||
6453 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6454 | struct sockaddr *addr = p; | ||
6455 | if (!is_valid_ether_addr(addr->sa_data)) | ||
6456 | return -EADDRNOTAVAIL; | ||
6457 | priv->config |= CFG_CUSTOM_MAC; | ||
6458 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); | ||
6459 | printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", | ||
6460 | priv->net_dev->name, MAC_ARG(priv->mac_addr)); | ||
6461 | ipw_adapter_restart(priv); | ||
6462 | return 0; | ||
6463 | } | ||
6464 | |||
6465 | static void ipw_ethtool_get_drvinfo(struct net_device *dev, | ||
6466 | struct ethtool_drvinfo *info) | ||
6467 | { | ||
6468 | struct ipw_priv *p = ieee80211_priv(dev); | ||
6469 | char vers[64]; | ||
6470 | char date[32]; | ||
6471 | u32 len; | ||
6472 | |||
6473 | strcpy(info->driver, DRV_NAME); | ||
6474 | strcpy(info->version, DRV_VERSION); | ||
6475 | |||
6476 | len = sizeof(vers); | ||
6477 | ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len); | ||
6478 | len = sizeof(date); | ||
6479 | ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len); | ||
6480 | |||
6481 | snprintf(info->fw_version, sizeof(info->fw_version),"%s (%s)", | ||
6482 | vers, date); | ||
6483 | strcpy(info->bus_info, pci_name(p->pci_dev)); | ||
6484 | info->eedump_len = CX2_EEPROM_IMAGE_SIZE; | ||
6485 | } | ||
6486 | |||
6487 | static u32 ipw_ethtool_get_link(struct net_device *dev) | ||
6488 | { | ||
6489 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6490 | return (priv->status & STATUS_ASSOCIATED) != 0; | ||
6491 | } | ||
6492 | |||
6493 | static int ipw_ethtool_get_eeprom_len(struct net_device *dev) | ||
6494 | { | ||
6495 | return CX2_EEPROM_IMAGE_SIZE; | ||
6496 | } | ||
6497 | |||
6498 | static int ipw_ethtool_get_eeprom(struct net_device *dev, | ||
6499 | struct ethtool_eeprom *eeprom, u8 *bytes) | ||
6500 | { | ||
6501 | struct ipw_priv *p = ieee80211_priv(dev); | ||
6502 | |||
6503 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) | ||
6504 | return -EINVAL; | ||
6505 | |||
6506 | memcpy(bytes, &((u8 *)p->eeprom)[eeprom->offset], eeprom->len); | ||
6507 | return 0; | ||
6508 | } | ||
6509 | |||
6510 | static int ipw_ethtool_set_eeprom(struct net_device *dev, | ||
6511 | struct ethtool_eeprom *eeprom, u8 *bytes) | ||
6512 | { | ||
6513 | struct ipw_priv *p = ieee80211_priv(dev); | ||
6514 | int i; | ||
6515 | |||
6516 | if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) | ||
6517 | return -EINVAL; | ||
6518 | |||
6519 | memcpy(&((u8 *)p->eeprom)[eeprom->offset], bytes, eeprom->len); | ||
6520 | for (i = IPW_EEPROM_DATA; | ||
6521 | i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; | ||
6522 | i++) | ||
6523 | ipw_write8(p, i, p->eeprom[i]); | ||
6524 | |||
6525 | return 0; | ||
6526 | } | ||
6527 | |||
6528 | static struct ethtool_ops ipw_ethtool_ops = { | ||
6529 | .get_link = ipw_ethtool_get_link, | ||
6530 | .get_drvinfo = ipw_ethtool_get_drvinfo, | ||
6531 | .get_eeprom_len = ipw_ethtool_get_eeprom_len, | ||
6532 | .get_eeprom = ipw_ethtool_get_eeprom, | ||
6533 | .set_eeprom = ipw_ethtool_set_eeprom, | ||
6534 | }; | ||
6535 | |||
6536 | static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | ||
6537 | { | ||
6538 | struct ipw_priv *priv = data; | ||
6539 | u32 inta, inta_mask; | ||
6540 | |||
6541 | if (!priv) | ||
6542 | return IRQ_NONE; | ||
6543 | |||
6544 | spin_lock(&priv->lock); | ||
6545 | |||
6546 | if (!(priv->status & STATUS_INT_ENABLED)) { | ||
6547 | /* Shared IRQ */ | ||
6548 | goto none; | ||
6549 | } | ||
6550 | |||
6551 | inta = ipw_read32(priv, CX2_INTA_RW); | ||
6552 | inta_mask = ipw_read32(priv, CX2_INTA_MASK_R); | ||
6553 | |||
6554 | if (inta == 0xFFFFFFFF) { | ||
6555 | /* Hardware disappeared */ | ||
6556 | IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n"); | ||
6557 | goto none; | ||
6558 | } | ||
6559 | |||
6560 | if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) { | ||
6561 | /* Shared interrupt */ | ||
6562 | goto none; | ||
6563 | } | ||
6564 | |||
6565 | /* tell the device to stop sending interrupts */ | ||
6566 | ipw_disable_interrupts(priv); | ||
6567 | |||
6568 | /* ack current interrupts */ | ||
6569 | inta &= (CX2_INTA_MASK_ALL & inta_mask); | ||
6570 | ipw_write32(priv, CX2_INTA_RW, inta); | ||
6571 | |||
6572 | /* Cache INTA value for our tasklet */ | ||
6573 | priv->isr_inta = inta; | ||
6574 | |||
6575 | tasklet_schedule(&priv->irq_tasklet); | ||
6576 | |||
6577 | spin_unlock(&priv->lock); | ||
6578 | |||
6579 | return IRQ_HANDLED; | ||
6580 | none: | ||
6581 | spin_unlock(&priv->lock); | ||
6582 | return IRQ_NONE; | ||
6583 | } | ||
6584 | |||
6585 | static void ipw_rf_kill(void *adapter) | ||
6586 | { | ||
6587 | struct ipw_priv *priv = adapter; | ||
6588 | unsigned long flags; | ||
6589 | |||
6590 | spin_lock_irqsave(&priv->lock, flags); | ||
6591 | |||
6592 | if (rf_kill_active(priv)) { | ||
6593 | IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); | ||
6594 | if (priv->workqueue) | ||
6595 | queue_delayed_work(priv->workqueue, | ||
6596 | &priv->rf_kill, 2 * HZ); | ||
6597 | goto exit_unlock; | ||
6598 | } | ||
6599 | |||
6600 | /* RF Kill is now disabled, so bring the device back up */ | ||
6601 | |||
6602 | if (!(priv->status & STATUS_RF_KILL_MASK)) { | ||
6603 | IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " | ||
6604 | "device\n"); | ||
6605 | |||
6606 | /* we can not do an adapter restart while inside an irq lock */ | ||
6607 | queue_work(priv->workqueue, &priv->adapter_restart); | ||
6608 | } else | ||
6609 | IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " | ||
6610 | "enabled\n"); | ||
6611 | |||
6612 | exit_unlock: | ||
6613 | spin_unlock_irqrestore(&priv->lock, flags); | ||
6614 | } | ||
6615 | |||
6616 | static int ipw_setup_deferred_work(struct ipw_priv *priv) | ||
6617 | { | ||
6618 | int ret = 0; | ||
6619 | |||
6620 | priv->workqueue = create_workqueue(DRV_NAME); | ||
6621 | init_waitqueue_head(&priv->wait_command_queue); | ||
6622 | |||
6623 | INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv); | ||
6624 | INIT_WORK(&priv->associate, ipw_associate, priv); | ||
6625 | INIT_WORK(&priv->disassociate, ipw_disassociate, priv); | ||
6626 | INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv); | ||
6627 | INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv); | ||
6628 | INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv); | ||
6629 | INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv); | ||
6630 | INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv); | ||
6631 | INIT_WORK(&priv->request_scan, | ||
6632 | (void (*)(void *))ipw_request_scan, priv); | ||
6633 | INIT_WORK(&priv->gather_stats, | ||
6634 | (void (*)(void *))ipw_gather_stats, priv); | ||
6635 | INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); | ||
6636 | INIT_WORK(&priv->roam, ipw_roam, priv); | ||
6637 | INIT_WORK(&priv->scan_check, ipw_scan_check, priv); | ||
6638 | |||
6639 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | ||
6640 | ipw_irq_tasklet, (unsigned long)priv); | ||
6641 | |||
6642 | return ret; | ||
6643 | } | ||
6644 | |||
6645 | |||
6646 | static void shim__set_security(struct net_device *dev, | ||
6647 | struct ieee80211_security *sec) | ||
6648 | { | ||
6649 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6650 | int i; | ||
6651 | |||
6652 | for (i = 0; i < 4; i++) { | ||
6653 | if (sec->flags & (1 << i)) { | ||
6654 | priv->sec.key_sizes[i] = sec->key_sizes[i]; | ||
6655 | if (sec->key_sizes[i] == 0) | ||
6656 | priv->sec.flags &= ~(1 << i); | ||
6657 | else | ||
6658 | memcpy(priv->sec.keys[i], sec->keys[i], | ||
6659 | sec->key_sizes[i]); | ||
6660 | priv->sec.flags |= (1 << i); | ||
6661 | priv->status |= STATUS_SECURITY_UPDATED; | ||
6662 | } | ||
6663 | } | ||
6664 | |||
6665 | if ((sec->flags & SEC_ACTIVE_KEY) && | ||
6666 | priv->sec.active_key != sec->active_key) { | ||
6667 | if (sec->active_key <= 3) { | ||
6668 | priv->sec.active_key = sec->active_key; | ||
6669 | priv->sec.flags |= SEC_ACTIVE_KEY; | ||
6670 | } else | ||
6671 | priv->sec.flags &= ~SEC_ACTIVE_KEY; | ||
6672 | priv->status |= STATUS_SECURITY_UPDATED; | ||
6673 | } | ||
6674 | |||
6675 | if ((sec->flags & SEC_AUTH_MODE) && | ||
6676 | (priv->sec.auth_mode != sec->auth_mode)) { | ||
6677 | priv->sec.auth_mode = sec->auth_mode; | ||
6678 | priv->sec.flags |= SEC_AUTH_MODE; | ||
6679 | if (sec->auth_mode == WLAN_AUTH_SHARED_KEY) | ||
6680 | priv->capability |= CAP_SHARED_KEY; | ||
6681 | else | ||
6682 | priv->capability &= ~CAP_SHARED_KEY; | ||
6683 | priv->status |= STATUS_SECURITY_UPDATED; | ||
6684 | } | ||
6685 | |||
6686 | if (sec->flags & SEC_ENABLED && | ||
6687 | priv->sec.enabled != sec->enabled) { | ||
6688 | priv->sec.flags |= SEC_ENABLED; | ||
6689 | priv->sec.enabled = sec->enabled; | ||
6690 | priv->status |= STATUS_SECURITY_UPDATED; | ||
6691 | if (sec->enabled) | ||
6692 | priv->capability |= CAP_PRIVACY_ON; | ||
6693 | else | ||
6694 | priv->capability &= ~CAP_PRIVACY_ON; | ||
6695 | } | ||
6696 | |||
6697 | if (sec->flags & SEC_LEVEL && | ||
6698 | priv->sec.level != sec->level) { | ||
6699 | priv->sec.level = sec->level; | ||
6700 | priv->sec.flags |= SEC_LEVEL; | ||
6701 | priv->status |= STATUS_SECURITY_UPDATED; | ||
6702 | } | ||
6703 | |||
6704 | /* To match current functionality of ipw2100 (which works well w/ | ||
6705 | * various supplicants, we don't force a disassociate if the | ||
6706 | * privacy capability changes ... */ | ||
6707 | #if 0 | ||
6708 | if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) && | ||
6709 | (((priv->assoc_request.capability & | ||
6710 | WLAN_CAPABILITY_PRIVACY) && !sec->enabled) || | ||
6711 | (!(priv->assoc_request.capability & | ||
6712 | WLAN_CAPABILITY_PRIVACY) && sec->enabled))) { | ||
6713 | IPW_DEBUG_ASSOC("Disassociating due to capability " | ||
6714 | "change.\n"); | ||
6715 | ipw_disassociate(priv); | ||
6716 | } | ||
6717 | #endif | ||
6718 | } | ||
6719 | |||
6720 | static int init_supported_rates(struct ipw_priv *priv, | ||
6721 | struct ipw_supported_rates *rates) | ||
6722 | { | ||
6723 | /* TODO: Mask out rates based on priv->rates_mask */ | ||
6724 | |||
6725 | memset(rates, 0, sizeof(*rates)); | ||
6726 | /* configure supported rates */ | ||
6727 | switch (priv->ieee->freq_band) { | ||
6728 | case IEEE80211_52GHZ_BAND: | ||
6729 | rates->ieee_mode = IPW_A_MODE; | ||
6730 | rates->purpose = IPW_RATE_CAPABILITIES; | ||
6731 | ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, | ||
6732 | IEEE80211_OFDM_DEFAULT_RATES_MASK); | ||
6733 | break; | ||
6734 | |||
6735 | default: /* Mixed or 2.4Ghz */ | ||
6736 | rates->ieee_mode = IPW_G_MODE; | ||
6737 | rates->purpose = IPW_RATE_CAPABILITIES; | ||
6738 | ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION, | ||
6739 | IEEE80211_CCK_DEFAULT_RATES_MASK); | ||
6740 | if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) { | ||
6741 | ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, | ||
6742 | IEEE80211_OFDM_DEFAULT_RATES_MASK); | ||
6743 | } | ||
6744 | break; | ||
6745 | } | ||
6746 | |||
6747 | return 0; | ||
6748 | } | ||
6749 | |||
6750 | static int ipw_config(struct ipw_priv *priv) | ||
6751 | { | ||
6752 | int i; | ||
6753 | struct ipw_tx_power tx_power; | ||
6754 | |||
6755 | memset(&priv->sys_config, 0, sizeof(priv->sys_config)); | ||
6756 | memset(&tx_power, 0, sizeof(tx_power)); | ||
6757 | |||
6758 | /* This is only called from ipw_up, which resets/reloads the firmware | ||
6759 | so, we don't need to first disable the card before we configure | ||
6760 | it */ | ||
6761 | |||
6762 | /* configure device for 'G' band */ | ||
6763 | tx_power.ieee_mode = IPW_G_MODE; | ||
6764 | tx_power.num_channels = 11; | ||
6765 | for (i = 0; i < 11; i++) { | ||
6766 | tx_power.channels_tx_power[i].channel_number = i + 1; | ||
6767 | tx_power.channels_tx_power[i].tx_power = priv->tx_power; | ||
6768 | } | ||
6769 | if (ipw_send_tx_power(priv, &tx_power)) | ||
6770 | goto error; | ||
6771 | |||
6772 | /* configure device to also handle 'B' band */ | ||
6773 | tx_power.ieee_mode = IPW_B_MODE; | ||
6774 | if (ipw_send_tx_power(priv, &tx_power)) | ||
6775 | goto error; | ||
6776 | |||
6777 | /* initialize adapter address */ | ||
6778 | if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr)) | ||
6779 | goto error; | ||
6780 | |||
6781 | /* set basic system config settings */ | ||
6782 | init_sys_config(&priv->sys_config); | ||
6783 | if (ipw_send_system_config(priv, &priv->sys_config)) | ||
6784 | goto error; | ||
6785 | |||
6786 | init_supported_rates(priv, &priv->rates); | ||
6787 | if (ipw_send_supported_rates(priv, &priv->rates)) | ||
6788 | goto error; | ||
6789 | |||
6790 | /* Set request-to-send threshold */ | ||
6791 | if (priv->rts_threshold) { | ||
6792 | if (ipw_send_rts_threshold(priv, priv->rts_threshold)) | ||
6793 | goto error; | ||
6794 | } | ||
6795 | |||
6796 | if (ipw_set_random_seed(priv)) | ||
6797 | goto error; | ||
6798 | |||
6799 | /* final state transition to the RUN state */ | ||
6800 | if (ipw_send_host_complete(priv)) | ||
6801 | goto error; | ||
6802 | |||
6803 | /* If configured to try and auto-associate, kick off a scan */ | ||
6804 | if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) | ||
6805 | goto error; | ||
6806 | |||
6807 | return 0; | ||
6808 | |||
6809 | error: | ||
6810 | return -EIO; | ||
6811 | } | ||
6812 | |||
6813 | #define MAX_HW_RESTARTS 5 | ||
6814 | static int ipw_up(struct ipw_priv *priv) | ||
6815 | { | ||
6816 | int rc, i; | ||
6817 | |||
6818 | if (priv->status & STATUS_EXIT_PENDING) | ||
6819 | return -EIO; | ||
6820 | |||
6821 | for (i = 0; i < MAX_HW_RESTARTS; i++ ) { | ||
6822 | /* Load the microcode, firmware, and eeprom. | ||
6823 | * Also start the clocks. */ | ||
6824 | rc = ipw_load(priv); | ||
6825 | if (rc) { | ||
6826 | IPW_ERROR("Unable to load firmware: 0x%08X\n", | ||
6827 | rc); | ||
6828 | return rc; | ||
6829 | } | ||
6830 | |||
6831 | ipw_init_ordinals(priv); | ||
6832 | if (!(priv->config & CFG_CUSTOM_MAC)) | ||
6833 | eeprom_parse_mac(priv, priv->mac_addr); | ||
6834 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); | ||
6835 | |||
6836 | if (priv->status & STATUS_RF_KILL_MASK) | ||
6837 | return 0; | ||
6838 | |||
6839 | rc = ipw_config(priv); | ||
6840 | if (!rc) { | ||
6841 | IPW_DEBUG_INFO("Configured device on count %i\n", i); | ||
6842 | priv->notif_missed_beacons = 0; | ||
6843 | netif_start_queue(priv->net_dev); | ||
6844 | return 0; | ||
6845 | } else { | ||
6846 | IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", | ||
6847 | rc); | ||
6848 | } | ||
6849 | |||
6850 | IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", | ||
6851 | i, MAX_HW_RESTARTS); | ||
6852 | |||
6853 | /* We had an error bringing up the hardware, so take it | ||
6854 | * all the way back down so we can try again */ | ||
6855 | ipw_down(priv); | ||
6856 | } | ||
6857 | |||
6858 | /* tried to restart and config the device for as long as our | ||
6859 | * patience could withstand */ | ||
6860 | IPW_ERROR("Unable to initialize device after %d attempts.\n", | ||
6861 | i); | ||
6862 | return -EIO; | ||
6863 | } | ||
6864 | |||
6865 | static void ipw_down(struct ipw_priv *priv) | ||
6866 | { | ||
6867 | /* Attempt to disable the card */ | ||
6868 | #if 0 | ||
6869 | ipw_send_card_disable(priv, 0); | ||
6870 | #endif | ||
6871 | |||
6872 | /* tell the device to stop sending interrupts */ | ||
6873 | ipw_disable_interrupts(priv); | ||
6874 | |||
6875 | /* Clear all bits but the RF Kill */ | ||
6876 | priv->status &= STATUS_RF_KILL_MASK; | ||
6877 | |||
6878 | netif_carrier_off(priv->net_dev); | ||
6879 | netif_stop_queue(priv->net_dev); | ||
6880 | |||
6881 | ipw_stop_nic(priv); | ||
6882 | } | ||
6883 | |||
6884 | /* Called by register_netdev() */ | ||
6885 | static int ipw_net_init(struct net_device *dev) | ||
6886 | { | ||
6887 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6888 | |||
6889 | if (priv->status & STATUS_RF_KILL_SW) { | ||
6890 | IPW_WARNING("Radio disabled by module parameter.\n"); | ||
6891 | return 0; | ||
6892 | } else if (rf_kill_active(priv)) { | ||
6893 | IPW_WARNING("Radio Frequency Kill Switch is On:\n" | ||
6894 | "Kill switch must be turned off for " | ||
6895 | "wireless networking to work.\n"); | ||
6896 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); | ||
6897 | return 0; | ||
6898 | } | ||
6899 | |||
6900 | if (ipw_up(priv)) | ||
6901 | return -EIO; | ||
6902 | |||
6903 | return 0; | ||
6904 | } | ||
6905 | |||
6906 | /* PCI driver stuff */ | ||
6907 | static struct pci_device_id card_ids[] = { | ||
6908 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0}, | ||
6909 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0}, | ||
6910 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0}, | ||
6911 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0}, | ||
6912 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0}, | ||
6913 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0}, | ||
6914 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0}, | ||
6915 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0}, | ||
6916 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0}, | ||
6917 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0}, | ||
6918 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0}, | ||
6919 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0}, | ||
6920 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0}, | ||
6921 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0}, | ||
6922 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0}, | ||
6923 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0}, | ||
6924 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, | ||
6925 | {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
6926 | {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ | ||
6927 | {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */ | ||
6928 | {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ | ||
6929 | {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ | ||
6930 | |||
6931 | /* required last entry */ | ||
6932 | {0,} | ||
6933 | }; | ||
6934 | |||
6935 | MODULE_DEVICE_TABLE(pci, card_ids); | ||
6936 | |||
6937 | static struct attribute *ipw_sysfs_entries[] = { | ||
6938 | &dev_attr_rf_kill.attr, | ||
6939 | &dev_attr_direct_dword.attr, | ||
6940 | &dev_attr_indirect_byte.attr, | ||
6941 | &dev_attr_indirect_dword.attr, | ||
6942 | &dev_attr_mem_gpio_reg.attr, | ||
6943 | &dev_attr_command_event_reg.attr, | ||
6944 | &dev_attr_nic_type.attr, | ||
6945 | &dev_attr_status.attr, | ||
6946 | &dev_attr_cfg.attr, | ||
6947 | &dev_attr_dump_errors.attr, | ||
6948 | &dev_attr_dump_events.attr, | ||
6949 | &dev_attr_eeprom_delay.attr, | ||
6950 | &dev_attr_ucode_version.attr, | ||
6951 | &dev_attr_rtc.attr, | ||
6952 | NULL | ||
6953 | }; | ||
6954 | |||
6955 | static struct attribute_group ipw_attribute_group = { | ||
6956 | .name = NULL, /* put in device directory */ | ||
6957 | .attrs = ipw_sysfs_entries, | ||
6958 | }; | ||
6959 | |||
6960 | static int ipw_pci_probe(struct pci_dev *pdev, | ||
6961 | const struct pci_device_id *ent) | ||
6962 | { | ||
6963 | int err = 0; | ||
6964 | struct net_device *net_dev; | ||
6965 | void __iomem *base; | ||
6966 | u32 length, val; | ||
6967 | struct ipw_priv *priv; | ||
6968 | int band, modulation; | ||
6969 | |||
6970 | net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); | ||
6971 | if (net_dev == NULL) { | ||
6972 | err = -ENOMEM; | ||
6973 | goto out; | ||
6974 | } | ||
6975 | |||
6976 | priv = ieee80211_priv(net_dev); | ||
6977 | priv->ieee = netdev_priv(net_dev); | ||
6978 | priv->net_dev = net_dev; | ||
6979 | priv->pci_dev = pdev; | ||
6980 | #ifdef CONFIG_IPW_DEBUG | ||
6981 | ipw_debug_level = debug; | ||
6982 | #endif | ||
6983 | spin_lock_init(&priv->lock); | ||
6984 | |||
6985 | if (pci_enable_device(pdev)) { | ||
6986 | err = -ENODEV; | ||
6987 | goto out_free_ieee80211; | ||
6988 | } | ||
6989 | |||
6990 | pci_set_master(pdev); | ||
6991 | |||
6992 | err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
6993 | if (!err) | ||
6994 | err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | ||
6995 | if (err) { | ||
6996 | printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); | ||
6997 | goto out_pci_disable_device; | ||
6998 | } | ||
6999 | |||
7000 | pci_set_drvdata(pdev, priv); | ||
7001 | |||
7002 | err = pci_request_regions(pdev, DRV_NAME); | ||
7003 | if (err) | ||
7004 | goto out_pci_disable_device; | ||
7005 | |||
7006 | /* We disable the RETRY_TIMEOUT register (0x41) to keep | ||
7007 | * PCI Tx retries from interfering with C3 CPU state */ | ||
7008 | pci_read_config_dword(pdev, 0x40, &val); | ||
7009 | if ((val & 0x0000ff00) != 0) | ||
7010 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
7011 | |||
7012 | length = pci_resource_len(pdev, 0); | ||
7013 | priv->hw_len = length; | ||
7014 | |||
7015 | base = ioremap_nocache(pci_resource_start(pdev, 0), length); | ||
7016 | if (!base) { | ||
7017 | err = -ENODEV; | ||
7018 | goto out_pci_release_regions; | ||
7019 | } | ||
7020 | |||
7021 | priv->hw_base = base; | ||
7022 | IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length); | ||
7023 | IPW_DEBUG_INFO("pci_resource_base = %p\n", base); | ||
7024 | |||
7025 | err = ipw_setup_deferred_work(priv); | ||
7026 | if (err) { | ||
7027 | IPW_ERROR("Unable to setup deferred work\n"); | ||
7028 | goto out_iounmap; | ||
7029 | } | ||
7030 | |||
7031 | /* Initialize module parameter values here */ | ||
7032 | if (ifname) | ||
7033 | strncpy(net_dev->name, ifname, IFNAMSIZ); | ||
7034 | |||
7035 | if (associate) | ||
7036 | priv->config |= CFG_ASSOCIATE; | ||
7037 | else | ||
7038 | IPW_DEBUG_INFO("Auto associate disabled.\n"); | ||
7039 | |||
7040 | if (auto_create) | ||
7041 | priv->config |= CFG_ADHOC_CREATE; | ||
7042 | else | ||
7043 | IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); | ||
7044 | |||
7045 | if (disable) { | ||
7046 | priv->status |= STATUS_RF_KILL_SW; | ||
7047 | IPW_DEBUG_INFO("Radio disabled.\n"); | ||
7048 | } | ||
7049 | |||
7050 | if (channel != 0) { | ||
7051 | priv->config |= CFG_STATIC_CHANNEL; | ||
7052 | priv->channel = channel; | ||
7053 | IPW_DEBUG_INFO("Bind to static channel %d\n", channel); | ||
7054 | IPW_DEBUG_INFO("Bind to static channel %d\n", channel); | ||
7055 | /* TODO: Validate that provided channel is in range */ | ||
7056 | } | ||
7057 | |||
7058 | switch (mode) { | ||
7059 | case 1: | ||
7060 | priv->ieee->iw_mode = IW_MODE_ADHOC; | ||
7061 | break; | ||
7062 | #ifdef CONFIG_IPW_PROMISC | ||
7063 | case 2: | ||
7064 | priv->ieee->iw_mode = IW_MODE_MONITOR; | ||
7065 | break; | ||
7066 | #endif | ||
7067 | default: | ||
7068 | case 0: | ||
7069 | priv->ieee->iw_mode = IW_MODE_INFRA; | ||
7070 | break; | ||
7071 | } | ||
7072 | |||
7073 | if ((priv->pci_dev->device == 0x4223) || | ||
7074 | (priv->pci_dev->device == 0x4224)) { | ||
7075 | printk(KERN_INFO DRV_NAME | ||
7076 | ": Detected Intel PRO/Wireless 2915ABG Network " | ||
7077 | "Connection\n"); | ||
7078 | priv->ieee->abg_ture = 1; | ||
7079 | band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; | ||
7080 | modulation = IEEE80211_OFDM_MODULATION | | ||
7081 | IEEE80211_CCK_MODULATION; | ||
7082 | priv->adapter = IPW_2915ABG; | ||
7083 | priv->ieee->mode = IEEE_A|IEEE_G|IEEE_B; | ||
7084 | } else { | ||
7085 | if (priv->pci_dev->device == 0x4221) | ||
7086 | printk(KERN_INFO DRV_NAME | ||
7087 | ": Detected Intel PRO/Wireless 2225BG Network " | ||
7088 | "Connection\n"); | ||
7089 | else | ||
7090 | printk(KERN_INFO DRV_NAME | ||
7091 | ": Detected Intel PRO/Wireless 2200BG Network " | ||
7092 | "Connection\n"); | ||
7093 | |||
7094 | priv->ieee->abg_ture = 0; | ||
7095 | band = IEEE80211_24GHZ_BAND; | ||
7096 | modulation = IEEE80211_OFDM_MODULATION | | ||
7097 | IEEE80211_CCK_MODULATION; | ||
7098 | priv->adapter = IPW_2200BG; | ||
7099 | priv->ieee->mode = IEEE_G|IEEE_B; | ||
7100 | } | ||
7101 | |||
7102 | priv->ieee->freq_band = band; | ||
7103 | priv->ieee->modulation = modulation; | ||
7104 | |||
7105 | priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; | ||
7106 | |||
7107 | priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; | ||
7108 | priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; | ||
7109 | |||
7110 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; | ||
7111 | |||
7112 | /* If power management is turned on, default to AC mode */ | ||
7113 | priv->power_mode = IPW_POWER_AC; | ||
7114 | priv->tx_power = IPW_DEFAULT_TX_POWER; | ||
7115 | |||
7116 | err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, | ||
7117 | priv); | ||
7118 | if (err) { | ||
7119 | IPW_ERROR("Error allocating IRQ %d\n", pdev->irq); | ||
7120 | goto out_destroy_workqueue; | ||
7121 | } | ||
7122 | |||
7123 | SET_MODULE_OWNER(net_dev); | ||
7124 | SET_NETDEV_DEV(net_dev, &pdev->dev); | ||
7125 | |||
7126 | priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; | ||
7127 | priv->ieee->set_security = shim__set_security; | ||
7128 | |||
7129 | net_dev->open = ipw_net_open; | ||
7130 | net_dev->stop = ipw_net_stop; | ||
7131 | net_dev->init = ipw_net_init; | ||
7132 | net_dev->get_stats = ipw_net_get_stats; | ||
7133 | net_dev->set_multicast_list = ipw_net_set_multicast_list; | ||
7134 | net_dev->set_mac_address = ipw_net_set_mac_address; | ||
7135 | net_dev->get_wireless_stats = ipw_get_wireless_stats; | ||
7136 | net_dev->wireless_handlers = &ipw_wx_handler_def; | ||
7137 | net_dev->ethtool_ops = &ipw_ethtool_ops; | ||
7138 | net_dev->irq = pdev->irq; | ||
7139 | net_dev->base_addr = (unsigned long )priv->hw_base; | ||
7140 | net_dev->mem_start = pci_resource_start(pdev, 0); | ||
7141 | net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1; | ||
7142 | |||
7143 | err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); | ||
7144 | if (err) { | ||
7145 | IPW_ERROR("failed to create sysfs device attributes\n"); | ||
7146 | goto out_release_irq; | ||
7147 | } | ||
7148 | |||
7149 | err = register_netdev(net_dev); | ||
7150 | if (err) { | ||
7151 | IPW_ERROR("failed to register network device\n"); | ||
7152 | goto out_remove_group; | ||
7153 | } | ||
7154 | |||
7155 | return 0; | ||
7156 | |||
7157 | out_remove_group: | ||
7158 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); | ||
7159 | out_release_irq: | ||
7160 | free_irq(pdev->irq, priv); | ||
7161 | out_destroy_workqueue: | ||
7162 | destroy_workqueue(priv->workqueue); | ||
7163 | priv->workqueue = NULL; | ||
7164 | out_iounmap: | ||
7165 | iounmap(priv->hw_base); | ||
7166 | out_pci_release_regions: | ||
7167 | pci_release_regions(pdev); | ||
7168 | out_pci_disable_device: | ||
7169 | pci_disable_device(pdev); | ||
7170 | pci_set_drvdata(pdev, NULL); | ||
7171 | out_free_ieee80211: | ||
7172 | free_ieee80211(priv->net_dev); | ||
7173 | out: | ||
7174 | return err; | ||
7175 | } | ||
7176 | |||
7177 | static void ipw_pci_remove(struct pci_dev *pdev) | ||
7178 | { | ||
7179 | struct ipw_priv *priv = pci_get_drvdata(pdev); | ||
7180 | if (!priv) | ||
7181 | return; | ||
7182 | |||
7183 | priv->status |= STATUS_EXIT_PENDING; | ||
7184 | |||
7185 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); | ||
7186 | |||
7187 | ipw_down(priv); | ||
7188 | |||
7189 | unregister_netdev(priv->net_dev); | ||
7190 | |||
7191 | if (priv->rxq) { | ||
7192 | ipw_rx_queue_free(priv, priv->rxq); | ||
7193 | priv->rxq = NULL; | ||
7194 | } | ||
7195 | ipw_tx_queue_free(priv); | ||
7196 | |||
7197 | /* ipw_down will ensure that there is no more pending work | ||
7198 | * in the workqueue's, so we can safely remove them now. */ | ||
7199 | if (priv->workqueue) { | ||
7200 | cancel_delayed_work(&priv->adhoc_check); | ||
7201 | cancel_delayed_work(&priv->gather_stats); | ||
7202 | cancel_delayed_work(&priv->request_scan); | ||
7203 | cancel_delayed_work(&priv->rf_kill); | ||
7204 | cancel_delayed_work(&priv->scan_check); | ||
7205 | destroy_workqueue(priv->workqueue); | ||
7206 | priv->workqueue = NULL; | ||
7207 | } | ||
7208 | |||
7209 | free_irq(pdev->irq, priv); | ||
7210 | iounmap(priv->hw_base); | ||
7211 | pci_release_regions(pdev); | ||
7212 | pci_disable_device(pdev); | ||
7213 | pci_set_drvdata(pdev, NULL); | ||
7214 | free_ieee80211(priv->net_dev); | ||
7215 | |||
7216 | #ifdef CONFIG_PM | ||
7217 | if (fw_loaded) { | ||
7218 | release_firmware(bootfw); | ||
7219 | release_firmware(ucode); | ||
7220 | release_firmware(firmware); | ||
7221 | fw_loaded = 0; | ||
7222 | } | ||
7223 | #endif | ||
7224 | } | ||
7225 | |||
7226 | |||
7227 | #ifdef CONFIG_PM | ||
7228 | static int ipw_pci_suspend(struct pci_dev *pdev, u32 state) | ||
7229 | { | ||
7230 | struct ipw_priv *priv = pci_get_drvdata(pdev); | ||
7231 | struct net_device *dev = priv->net_dev; | ||
7232 | |||
7233 | printk(KERN_INFO "%s: Going into suspend...\n", dev->name); | ||
7234 | |||
7235 | /* Take down the device; powers it off, etc. */ | ||
7236 | ipw_down(priv); | ||
7237 | |||
7238 | /* Remove the PRESENT state of the device */ | ||
7239 | netif_device_detach(dev); | ||
7240 | |||
7241 | pci_save_state(pdev); | ||
7242 | pci_disable_device(pdev); | ||
7243 | pci_set_power_state(pdev, state); | ||
7244 | |||
7245 | return 0; | ||
7246 | } | ||
7247 | |||
7248 | static int ipw_pci_resume(struct pci_dev *pdev) | ||
7249 | { | ||
7250 | struct ipw_priv *priv = pci_get_drvdata(pdev); | ||
7251 | struct net_device *dev = priv->net_dev; | ||
7252 | u32 val; | ||
7253 | |||
7254 | printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); | ||
7255 | |||
7256 | pci_set_power_state(pdev, 0); | ||
7257 | pci_enable_device(pdev); | ||
7258 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) | ||
7259 | pci_restore_state(pdev, priv->pm_state); | ||
7260 | #else | ||
7261 | pci_restore_state(pdev); | ||
7262 | #endif | ||
7263 | /* | ||
7264 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
7265 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | ||
7266 | * from interfering with C3 CPU state. pci_restore_state won't help | ||
7267 | * here since it only restores the first 64 bytes pci config header. | ||
7268 | */ | ||
7269 | pci_read_config_dword(pdev, 0x40, &val); | ||
7270 | if ((val & 0x0000ff00) != 0) | ||
7271 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
7272 | |||
7273 | /* Set the device back into the PRESENT state; this will also wake | ||
7274 | * the queue of needed */ | ||
7275 | netif_device_attach(dev); | ||
7276 | |||
7277 | /* Bring the device back up */ | ||
7278 | queue_work(priv->workqueue, &priv->up); | ||
7279 | |||
7280 | return 0; | ||
7281 | } | ||
7282 | #endif | ||
7283 | |||
7284 | /* driver initialization stuff */ | ||
7285 | static struct pci_driver ipw_driver = { | ||
7286 | .name = DRV_NAME, | ||
7287 | .id_table = card_ids, | ||
7288 | .probe = ipw_pci_probe, | ||
7289 | .remove = __devexit_p(ipw_pci_remove), | ||
7290 | #ifdef CONFIG_PM | ||
7291 | .suspend = ipw_pci_suspend, | ||
7292 | .resume = ipw_pci_resume, | ||
7293 | #endif | ||
7294 | }; | ||
7295 | |||
7296 | static int __init ipw_init(void) | ||
7297 | { | ||
7298 | int ret; | ||
7299 | |||
7300 | printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); | ||
7301 | printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); | ||
7302 | |||
7303 | ret = pci_module_init(&ipw_driver); | ||
7304 | if (ret) { | ||
7305 | IPW_ERROR("Unable to initialize PCI module\n"); | ||
7306 | return ret; | ||
7307 | } | ||
7308 | |||
7309 | ret = driver_create_file(&ipw_driver.driver, | ||
7310 | &driver_attr_debug_level); | ||
7311 | if (ret) { | ||
7312 | IPW_ERROR("Unable to create driver sysfs file\n"); | ||
7313 | pci_unregister_driver(&ipw_driver); | ||
7314 | return ret; | ||
7315 | } | ||
7316 | |||
7317 | return ret; | ||
7318 | } | ||
7319 | |||
7320 | static void __exit ipw_exit(void) | ||
7321 | { | ||
7322 | driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level); | ||
7323 | pci_unregister_driver(&ipw_driver); | ||
7324 | } | ||
7325 | |||
7326 | module_param(disable, int, 0444); | ||
7327 | MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); | ||
7328 | |||
7329 | module_param(associate, int, 0444); | ||
7330 | MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); | ||
7331 | |||
7332 | module_param(auto_create, int, 0444); | ||
7333 | MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); | ||
7334 | |||
7335 | module_param(debug, int, 0444); | ||
7336 | MODULE_PARM_DESC(debug, "debug output mask"); | ||
7337 | |||
7338 | module_param(channel, int, 0444); | ||
7339 | MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); | ||
7340 | |||
7341 | module_param(ifname, charp, 0444); | ||
7342 | MODULE_PARM_DESC(ifname, "network device name (default eth%d)"); | ||
7343 | |||
7344 | #ifdef CONFIG_IPW_PROMISC | ||
7345 | module_param(mode, int, 0444); | ||
7346 | MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); | ||
7347 | #else | ||
7348 | module_param(mode, int, 0444); | ||
7349 | MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); | ||
7350 | #endif | ||
7351 | |||
7352 | module_exit(ipw_exit); | ||
7353 | module_init(ipw_init); | ||
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h new file mode 100644 index 000000000000..3bff09d93154 --- /dev/null +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -0,0 +1,1742 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify it | ||
6 | under the terms of version 2 of the GNU General Public License as | ||
7 | published by the Free Software Foundation. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along with | ||
15 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
16 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | |||
18 | The full GNU General Public License is included in this distribution in the | ||
19 | file called LICENSE. | ||
20 | |||
21 | Contact Information: | ||
22 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
23 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | |||
25 | ******************************************************************************/ | ||
26 | |||
27 | #ifndef __ipw2200_h__ | ||
28 | #define __ipw2200_h__ | ||
29 | |||
30 | #define WEXT_USECHANNELS 1 | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/moduleparam.h> | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include <linux/version.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/netdevice.h> | ||
40 | #include <linux/ethtool.h> | ||
41 | #include <linux/skbuff.h> | ||
42 | #include <linux/etherdevice.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/random.h> | ||
45 | |||
46 | #include <linux/firmware.h> | ||
47 | #include <linux/wireless.h> | ||
48 | #include <asm/io.h> | ||
49 | |||
50 | #include <net/ieee80211.h> | ||
51 | |||
52 | #define DRV_NAME "ipw2200" | ||
53 | |||
54 | #include <linux/workqueue.h> | ||
55 | |||
56 | /* Authentication and Association States */ | ||
57 | enum connection_manager_assoc_states | ||
58 | { | ||
59 | CMAS_INIT = 0, | ||
60 | CMAS_TX_AUTH_SEQ_1, | ||
61 | CMAS_RX_AUTH_SEQ_2, | ||
62 | CMAS_AUTH_SEQ_1_PASS, | ||
63 | CMAS_AUTH_SEQ_1_FAIL, | ||
64 | CMAS_TX_AUTH_SEQ_3, | ||
65 | CMAS_RX_AUTH_SEQ_4, | ||
66 | CMAS_AUTH_SEQ_2_PASS, | ||
67 | CMAS_AUTH_SEQ_2_FAIL, | ||
68 | CMAS_AUTHENTICATED, | ||
69 | CMAS_TX_ASSOC, | ||
70 | CMAS_RX_ASSOC_RESP, | ||
71 | CMAS_ASSOCIATED, | ||
72 | CMAS_LAST | ||
73 | }; | ||
74 | |||
75 | |||
76 | #define IPW_WAIT (1<<0) | ||
77 | #define IPW_QUIET (1<<1) | ||
78 | #define IPW_ROAMING (1<<2) | ||
79 | |||
80 | #define IPW_POWER_MODE_CAM 0x00 //(always on) | ||
81 | #define IPW_POWER_INDEX_1 0x01 | ||
82 | #define IPW_POWER_INDEX_2 0x02 | ||
83 | #define IPW_POWER_INDEX_3 0x03 | ||
84 | #define IPW_POWER_INDEX_4 0x04 | ||
85 | #define IPW_POWER_INDEX_5 0x05 | ||
86 | #define IPW_POWER_AC 0x06 | ||
87 | #define IPW_POWER_BATTERY 0x07 | ||
88 | #define IPW_POWER_LIMIT 0x07 | ||
89 | #define IPW_POWER_MASK 0x0F | ||
90 | #define IPW_POWER_ENABLED 0x10 | ||
91 | #define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) | ||
92 | |||
93 | #define IPW_CMD_HOST_COMPLETE 2 | ||
94 | #define IPW_CMD_POWER_DOWN 4 | ||
95 | #define IPW_CMD_SYSTEM_CONFIG 6 | ||
96 | #define IPW_CMD_MULTICAST_ADDRESS 7 | ||
97 | #define IPW_CMD_SSID 8 | ||
98 | #define IPW_CMD_ADAPTER_ADDRESS 11 | ||
99 | #define IPW_CMD_PORT_TYPE 12 | ||
100 | #define IPW_CMD_RTS_THRESHOLD 15 | ||
101 | #define IPW_CMD_FRAG_THRESHOLD 16 | ||
102 | #define IPW_CMD_POWER_MODE 17 | ||
103 | #define IPW_CMD_WEP_KEY 18 | ||
104 | #define IPW_CMD_TGI_TX_KEY 19 | ||
105 | #define IPW_CMD_SCAN_REQUEST 20 | ||
106 | #define IPW_CMD_ASSOCIATE 21 | ||
107 | #define IPW_CMD_SUPPORTED_RATES 22 | ||
108 | #define IPW_CMD_SCAN_ABORT 23 | ||
109 | #define IPW_CMD_TX_FLUSH 24 | ||
110 | #define IPW_CMD_QOS_PARAMETERS 25 | ||
111 | #define IPW_CMD_SCAN_REQUEST_EXT 26 | ||
112 | #define IPW_CMD_DINO_CONFIG 30 | ||
113 | #define IPW_CMD_RSN_CAPABILITIES 31 | ||
114 | #define IPW_CMD_RX_KEY 32 | ||
115 | #define IPW_CMD_CARD_DISABLE 33 | ||
116 | #define IPW_CMD_SEED_NUMBER 34 | ||
117 | #define IPW_CMD_TX_POWER 35 | ||
118 | #define IPW_CMD_COUNTRY_INFO 36 | ||
119 | #define IPW_CMD_AIRONET_INFO 37 | ||
120 | #define IPW_CMD_AP_TX_POWER 38 | ||
121 | #define IPW_CMD_CCKM_INFO 39 | ||
122 | #define IPW_CMD_CCX_VER_INFO 40 | ||
123 | #define IPW_CMD_SET_CALIBRATION 41 | ||
124 | #define IPW_CMD_SENSITIVITY_CALIB 42 | ||
125 | #define IPW_CMD_RETRY_LIMIT 51 | ||
126 | #define IPW_CMD_IPW_PRE_POWER_DOWN 58 | ||
127 | #define IPW_CMD_VAP_BEACON_TEMPLATE 60 | ||
128 | #define IPW_CMD_VAP_DTIM_PERIOD 61 | ||
129 | #define IPW_CMD_EXT_SUPPORTED_RATES 62 | ||
130 | #define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63 | ||
131 | #define IPW_CMD_VAP_QUIET_INTERVALS 64 | ||
132 | #define IPW_CMD_VAP_CHANNEL_SWITCH 65 | ||
133 | #define IPW_CMD_VAP_MANDATORY_CHANNELS 66 | ||
134 | #define IPW_CMD_VAP_CELL_PWR_LIMIT 67 | ||
135 | #define IPW_CMD_VAP_CF_PARAM_SET 68 | ||
136 | #define IPW_CMD_VAP_SET_BEACONING_STATE 69 | ||
137 | #define IPW_CMD_MEASUREMENT 80 | ||
138 | #define IPW_CMD_POWER_CAPABILITY 81 | ||
139 | #define IPW_CMD_SUPPORTED_CHANNELS 82 | ||
140 | #define IPW_CMD_TPC_REPORT 83 | ||
141 | #define IPW_CMD_WME_INFO 84 | ||
142 | #define IPW_CMD_PRODUCTION_COMMAND 85 | ||
143 | #define IPW_CMD_LINKSYS_EOU_INFO 90 | ||
144 | |||
145 | #define RFD_SIZE 4 | ||
146 | #define NUM_TFD_CHUNKS 6 | ||
147 | |||
148 | #define TX_QUEUE_SIZE 32 | ||
149 | #define RX_QUEUE_SIZE 32 | ||
150 | |||
151 | #define DINO_CMD_WEP_KEY 0x08 | ||
152 | #define DINO_CMD_TX 0x0B | ||
153 | #define DCT_ANTENNA_A 0x01 | ||
154 | #define DCT_ANTENNA_B 0x02 | ||
155 | |||
156 | #define IPW_A_MODE 0 | ||
157 | #define IPW_B_MODE 1 | ||
158 | #define IPW_G_MODE 2 | ||
159 | |||
160 | /* | ||
161 | * TX Queue Flag Definitions | ||
162 | */ | ||
163 | |||
164 | /* abort attempt if mgmt frame is rx'd */ | ||
165 | #define DCT_FLAG_ABORT_MGMT 0x01 | ||
166 | |||
167 | /* require CTS */ | ||
168 | #define DCT_FLAG_CTS_REQUIRED 0x02 | ||
169 | |||
170 | /* use short preamble */ | ||
171 | #define DCT_FLAG_SHORT_PREMBL 0x04 | ||
172 | |||
173 | /* RTS/CTS first */ | ||
174 | #define DCT_FLAG_RTS_REQD 0x08 | ||
175 | |||
176 | /* dont calculate duration field */ | ||
177 | #define DCT_FLAG_DUR_SET 0x10 | ||
178 | |||
179 | /* even if MAC WEP set (allows pre-encrypt) */ | ||
180 | #define DCT_FLAG_NO_WEP 0x20 | ||
181 | |||
182 | /* overwrite TSF field */ | ||
183 | #define DCT_FLAG_TSF_REQD 0x40 | ||
184 | |||
185 | /* ACK rx is expected to follow */ | ||
186 | #define DCT_FLAG_ACK_REQD 0x80 | ||
187 | |||
188 | #define DCT_FLAG_EXT_MODE_CCK 0x01 | ||
189 | #define DCT_FLAG_EXT_MODE_OFDM 0x00 | ||
190 | |||
191 | |||
192 | #define TX_RX_TYPE_MASK 0xFF | ||
193 | #define TX_FRAME_TYPE 0x00 | ||
194 | #define TX_HOST_COMMAND_TYPE 0x01 | ||
195 | #define RX_FRAME_TYPE 0x09 | ||
196 | #define RX_HOST_NOTIFICATION_TYPE 0x03 | ||
197 | #define RX_HOST_CMD_RESPONSE_TYPE 0x04 | ||
198 | #define RX_TX_FRAME_RESPONSE_TYPE 0x05 | ||
199 | #define TFD_NEED_IRQ_MASK 0x04 | ||
200 | |||
201 | #define HOST_CMD_DINO_CONFIG 30 | ||
202 | |||
203 | #define HOST_NOTIFICATION_STATUS_ASSOCIATED 10 | ||
204 | #define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11 | ||
205 | #define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12 | ||
206 | #define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13 | ||
207 | #define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14 | ||
208 | #define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15 | ||
209 | #define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16 | ||
210 | #define HOST_NOTIFICATION_STATUS_BEACON_STATE 17 | ||
211 | #define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18 | ||
212 | #define HOST_NOTIFICATION_TX_STATUS 19 | ||
213 | #define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20 | ||
214 | #define HOST_NOTIFICATION_MEASUREMENT_STARTED 21 | ||
215 | #define HOST_NOTIFICATION_MEASUREMENT_ENDED 22 | ||
216 | #define HOST_NOTIFICATION_CHANNEL_SWITCHED 23 | ||
217 | #define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24 | ||
218 | #define HOST_NOTIFICATION_NOISE_STATS 25 | ||
219 | #define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30 | ||
220 | #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 | ||
221 | |||
222 | #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 | ||
223 | #define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 24 | ||
224 | #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 | ||
225 | #define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 | ||
226 | |||
227 | #define MACADRR_BYTE_LEN 6 | ||
228 | |||
229 | #define DCR_TYPE_AP 0x01 | ||
230 | #define DCR_TYPE_WLAP 0x02 | ||
231 | #define DCR_TYPE_MU_ESS 0x03 | ||
232 | #define DCR_TYPE_MU_IBSS 0x04 | ||
233 | #define DCR_TYPE_MU_PIBSS 0x05 | ||
234 | #define DCR_TYPE_SNIFFER 0x06 | ||
235 | #define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS | ||
236 | |||
237 | /** | ||
238 | * Generic queue structure | ||
239 | * | ||
240 | * Contains common data for Rx and Tx queues | ||
241 | */ | ||
242 | struct clx2_queue { | ||
243 | int n_bd; /**< number of BDs in this queue */ | ||
244 | int first_empty; /**< 1-st empty entry (index) */ | ||
245 | int last_used; /**< last used entry (index) */ | ||
246 | u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */ | ||
247 | u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */ | ||
248 | dma_addr_t dma_addr; /**< physical addr for BD's */ | ||
249 | int low_mark; /**< low watermark, resume queue if free space more than this */ | ||
250 | int high_mark; /**< high watermark, stop queue if free space less than this */ | ||
251 | } __attribute__ ((packed)); | ||
252 | |||
253 | struct machdr32 | ||
254 | { | ||
255 | u16 frame_ctl; | ||
256 | u16 duration; // watch out for endians! | ||
257 | u8 addr1[ MACADRR_BYTE_LEN ]; | ||
258 | u8 addr2[ MACADRR_BYTE_LEN ]; | ||
259 | u8 addr3[ MACADRR_BYTE_LEN ]; | ||
260 | u16 seq_ctrl; // more endians! | ||
261 | u8 addr4[ MACADRR_BYTE_LEN ]; | ||
262 | u16 qos_ctrl; | ||
263 | } __attribute__ ((packed)) ; | ||
264 | |||
265 | struct machdr30 | ||
266 | { | ||
267 | u16 frame_ctl; | ||
268 | u16 duration; // watch out for endians! | ||
269 | u8 addr1[ MACADRR_BYTE_LEN ]; | ||
270 | u8 addr2[ MACADRR_BYTE_LEN ]; | ||
271 | u8 addr3[ MACADRR_BYTE_LEN ]; | ||
272 | u16 seq_ctrl; // more endians! | ||
273 | u8 addr4[ MACADRR_BYTE_LEN ]; | ||
274 | } __attribute__ ((packed)) ; | ||
275 | |||
276 | struct machdr26 | ||
277 | { | ||
278 | u16 frame_ctl; | ||
279 | u16 duration; // watch out for endians! | ||
280 | u8 addr1[ MACADRR_BYTE_LEN ]; | ||
281 | u8 addr2[ MACADRR_BYTE_LEN ]; | ||
282 | u8 addr3[ MACADRR_BYTE_LEN ]; | ||
283 | u16 seq_ctrl; // more endians! | ||
284 | u16 qos_ctrl; | ||
285 | } __attribute__ ((packed)) ; | ||
286 | |||
287 | struct machdr24 | ||
288 | { | ||
289 | u16 frame_ctl; | ||
290 | u16 duration; // watch out for endians! | ||
291 | u8 addr1[ MACADRR_BYTE_LEN ]; | ||
292 | u8 addr2[ MACADRR_BYTE_LEN ]; | ||
293 | u8 addr3[ MACADRR_BYTE_LEN ]; | ||
294 | u16 seq_ctrl; // more endians! | ||
295 | } __attribute__ ((packed)) ; | ||
296 | |||
297 | // TX TFD with 32 byte MAC Header | ||
298 | struct tx_tfd_32 | ||
299 | { | ||
300 | struct machdr32 mchdr; // 32 | ||
301 | u32 uivplaceholder[2]; // 8 | ||
302 | } __attribute__ ((packed)) ; | ||
303 | |||
304 | // TX TFD with 30 byte MAC Header | ||
305 | struct tx_tfd_30 | ||
306 | { | ||
307 | struct machdr30 mchdr; // 30 | ||
308 | u8 reserved[2]; // 2 | ||
309 | u32 uivplaceholder[2]; // 8 | ||
310 | } __attribute__ ((packed)) ; | ||
311 | |||
312 | // tx tfd with 26 byte mac header | ||
313 | struct tx_tfd_26 | ||
314 | { | ||
315 | struct machdr26 mchdr; // 26 | ||
316 | u8 reserved1[2]; // 2 | ||
317 | u32 uivplaceholder[2]; // 8 | ||
318 | u8 reserved2[4]; // 4 | ||
319 | } __attribute__ ((packed)) ; | ||
320 | |||
321 | // tx tfd with 24 byte mac header | ||
322 | struct tx_tfd_24 | ||
323 | { | ||
324 | struct machdr24 mchdr; // 24 | ||
325 | u32 uivplaceholder[2]; // 8 | ||
326 | u8 reserved[8]; // 8 | ||
327 | } __attribute__ ((packed)) ; | ||
328 | |||
329 | |||
330 | #define DCT_WEP_KEY_FIELD_LENGTH 16 | ||
331 | |||
332 | struct tfd_command | ||
333 | { | ||
334 | u8 index; | ||
335 | u8 length; | ||
336 | u16 reserved; | ||
337 | u8 payload[0]; | ||
338 | } __attribute__ ((packed)) ; | ||
339 | |||
340 | struct tfd_data { | ||
341 | /* Header */ | ||
342 | u32 work_area_ptr; | ||
343 | u8 station_number; /* 0 for BSS */ | ||
344 | u8 reserved1; | ||
345 | u16 reserved2; | ||
346 | |||
347 | /* Tx Parameters */ | ||
348 | u8 cmd_id; | ||
349 | u8 seq_num; | ||
350 | u16 len; | ||
351 | u8 priority; | ||
352 | u8 tx_flags; | ||
353 | u8 tx_flags_ext; | ||
354 | u8 key_index; | ||
355 | u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH]; | ||
356 | u8 rate; | ||
357 | u8 antenna; | ||
358 | u16 next_packet_duration; | ||
359 | u16 next_frag_len; | ||
360 | u16 back_off_counter; //////txop; | ||
361 | u8 retrylimit; | ||
362 | u16 cwcurrent; | ||
363 | u8 reserved3; | ||
364 | |||
365 | /* 802.11 MAC Header */ | ||
366 | union | ||
367 | { | ||
368 | struct tx_tfd_24 tfd_24; | ||
369 | struct tx_tfd_26 tfd_26; | ||
370 | struct tx_tfd_30 tfd_30; | ||
371 | struct tx_tfd_32 tfd_32; | ||
372 | } tfd; | ||
373 | |||
374 | /* Payload DMA info */ | ||
375 | u32 num_chunks; | ||
376 | u32 chunk_ptr[NUM_TFD_CHUNKS]; | ||
377 | u16 chunk_len[NUM_TFD_CHUNKS]; | ||
378 | } __attribute__ ((packed)); | ||
379 | |||
380 | struct txrx_control_flags | ||
381 | { | ||
382 | u8 message_type; | ||
383 | u8 rx_seq_num; | ||
384 | u8 control_bits; | ||
385 | u8 reserved; | ||
386 | } __attribute__ ((packed)); | ||
387 | |||
388 | #define TFD_SIZE 128 | ||
389 | #define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags)) | ||
390 | |||
391 | struct tfd_frame | ||
392 | { | ||
393 | struct txrx_control_flags control_flags; | ||
394 | union { | ||
395 | struct tfd_data data; | ||
396 | struct tfd_command cmd; | ||
397 | u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; | ||
398 | } u; | ||
399 | } __attribute__ ((packed)) ; | ||
400 | |||
401 | typedef void destructor_func(const void*); | ||
402 | |||
403 | /** | ||
404 | * Tx Queue for DMA. Queue consists of circular buffer of | ||
405 | * BD's and required locking structures. | ||
406 | */ | ||
407 | struct clx2_tx_queue { | ||
408 | struct clx2_queue q; | ||
409 | struct tfd_frame* bd; | ||
410 | struct ieee80211_txb **txb; | ||
411 | }; | ||
412 | |||
413 | /* | ||
414 | * RX related structures and functions | ||
415 | */ | ||
416 | #define RX_FREE_BUFFERS 32 | ||
417 | #define RX_LOW_WATERMARK 8 | ||
418 | |||
419 | #define SUP_RATE_11A_MAX_NUM_CHANNELS (8) | ||
420 | #define SUP_RATE_11B_MAX_NUM_CHANNELS (4) | ||
421 | #define SUP_RATE_11G_MAX_NUM_CHANNELS (12) | ||
422 | |||
423 | // Used for passing to driver number of successes and failures per rate | ||
424 | struct rate_histogram | ||
425 | { | ||
426 | union { | ||
427 | u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; | ||
428 | u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; | ||
429 | u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; | ||
430 | } success; | ||
431 | union { | ||
432 | u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; | ||
433 | u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; | ||
434 | u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; | ||
435 | } failed; | ||
436 | } __attribute__ ((packed)); | ||
437 | |||
438 | /* statistics command response */ | ||
439 | struct ipw_cmd_stats { | ||
440 | u8 cmd_id; | ||
441 | u8 seq_num; | ||
442 | u16 good_sfd; | ||
443 | u16 bad_plcp; | ||
444 | u16 wrong_bssid; | ||
445 | u16 valid_mpdu; | ||
446 | u16 bad_mac_header; | ||
447 | u16 reserved_frame_types; | ||
448 | u16 rx_ina; | ||
449 | u16 bad_crc32; | ||
450 | u16 invalid_cts; | ||
451 | u16 invalid_acks; | ||
452 | u16 long_distance_ina_fina; | ||
453 | u16 dsp_silence_unreachable; | ||
454 | u16 accumulated_rssi; | ||
455 | u16 rx_ovfl_frame_tossed; | ||
456 | u16 rssi_silence_threshold; | ||
457 | u16 rx_ovfl_frame_supplied; | ||
458 | u16 last_rx_frame_signal; | ||
459 | u16 last_rx_frame_noise; | ||
460 | u16 rx_autodetec_no_ofdm; | ||
461 | u16 rx_autodetec_no_barker; | ||
462 | u16 reserved; | ||
463 | } __attribute__ ((packed)); | ||
464 | |||
465 | struct notif_channel_result { | ||
466 | u8 channel_num; | ||
467 | struct ipw_cmd_stats stats; | ||
468 | u8 uReserved; | ||
469 | } __attribute__ ((packed)); | ||
470 | |||
471 | struct notif_scan_complete { | ||
472 | u8 scan_type; | ||
473 | u8 num_channels; | ||
474 | u8 status; | ||
475 | u8 reserved; | ||
476 | } __attribute__ ((packed)); | ||
477 | |||
478 | struct notif_frag_length { | ||
479 | u16 frag_length; | ||
480 | u16 reserved; | ||
481 | } __attribute__ ((packed)); | ||
482 | |||
483 | struct notif_beacon_state { | ||
484 | u32 state; | ||
485 | u32 number; | ||
486 | } __attribute__ ((packed)); | ||
487 | |||
488 | struct notif_tgi_tx_key { | ||
489 | u8 key_state; | ||
490 | u8 security_type; | ||
491 | u8 station_index; | ||
492 | u8 reserved; | ||
493 | } __attribute__ ((packed)); | ||
494 | |||
495 | struct notif_link_deterioration { | ||
496 | struct ipw_cmd_stats stats; | ||
497 | u8 rate; | ||
498 | u8 modulation; | ||
499 | struct rate_histogram histogram; | ||
500 | u8 reserved1; | ||
501 | u16 reserved2; | ||
502 | } __attribute__ ((packed)); | ||
503 | |||
504 | struct notif_association { | ||
505 | u8 state; | ||
506 | } __attribute__ ((packed)); | ||
507 | |||
508 | struct notif_authenticate { | ||
509 | u8 state; | ||
510 | struct machdr24 addr; | ||
511 | u16 status; | ||
512 | } __attribute__ ((packed)); | ||
513 | |||
514 | struct notif_calibration { | ||
515 | u8 data[104]; | ||
516 | } __attribute__ ((packed)); | ||
517 | |||
518 | struct notif_noise { | ||
519 | u32 value; | ||
520 | } __attribute__ ((packed)); | ||
521 | |||
522 | struct ipw_rx_notification { | ||
523 | u8 reserved[8]; | ||
524 | u8 subtype; | ||
525 | u8 flags; | ||
526 | u16 size; | ||
527 | union { | ||
528 | struct notif_association assoc; | ||
529 | struct notif_authenticate auth; | ||
530 | struct notif_channel_result channel_result; | ||
531 | struct notif_scan_complete scan_complete; | ||
532 | struct notif_frag_length frag_len; | ||
533 | struct notif_beacon_state beacon_state; | ||
534 | struct notif_tgi_tx_key tgi_tx_key; | ||
535 | struct notif_link_deterioration link_deterioration; | ||
536 | struct notif_calibration calibration; | ||
537 | struct notif_noise noise; | ||
538 | u8 raw[0]; | ||
539 | } u; | ||
540 | } __attribute__ ((packed)); | ||
541 | |||
542 | struct ipw_rx_frame { | ||
543 | u32 reserved1; | ||
544 | u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER | ||
545 | u8 received_channel; // The channel that this frame was received on. | ||
546 | // Note that for .11b this does not have to be | ||
547 | // the same as the channel that it was sent. | ||
548 | // Filled by LMAC | ||
549 | u8 frameStatus; | ||
550 | u8 rate; | ||
551 | u8 rssi; | ||
552 | u8 agc; | ||
553 | u8 rssi_dbm; | ||
554 | u16 signal; | ||
555 | u16 noise; | ||
556 | u8 antennaAndPhy; | ||
557 | u8 control; // control bit should be on in bg | ||
558 | u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate | ||
559 | // is identical) | ||
560 | u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen | ||
561 | u16 length; | ||
562 | u8 data[0]; | ||
563 | } __attribute__ ((packed)); | ||
564 | |||
565 | struct ipw_rx_header { | ||
566 | u8 message_type; | ||
567 | u8 rx_seq_num; | ||
568 | u8 control_bits; | ||
569 | u8 reserved; | ||
570 | } __attribute__ ((packed)); | ||
571 | |||
572 | struct ipw_rx_packet | ||
573 | { | ||
574 | struct ipw_rx_header header; | ||
575 | union { | ||
576 | struct ipw_rx_frame frame; | ||
577 | struct ipw_rx_notification notification; | ||
578 | } u; | ||
579 | } __attribute__ ((packed)); | ||
580 | |||
581 | #define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12 | ||
582 | #define IPW_RX_FRAME_SIZE sizeof(struct ipw_rx_header) + \ | ||
583 | sizeof(struct ipw_rx_frame) | ||
584 | |||
585 | struct ipw_rx_mem_buffer { | ||
586 | dma_addr_t dma_addr; | ||
587 | struct ipw_rx_buffer *rxb; | ||
588 | struct sk_buff *skb; | ||
589 | struct list_head list; | ||
590 | }; /* Not transferred over network, so not __attribute__ ((packed)) */ | ||
591 | |||
592 | struct ipw_rx_queue { | ||
593 | struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; | ||
594 | struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE]; | ||
595 | u32 processed; /* Internal index to last handled Rx packet */ | ||
596 | u32 read; /* Shared index to newest available Rx buffer */ | ||
597 | u32 write; /* Shared index to oldest written Rx packet */ | ||
598 | u32 free_count;/* Number of pre-allocated buffers in rx_free */ | ||
599 | /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */ | ||
600 | struct list_head rx_free; /* Own an SKBs */ | ||
601 | struct list_head rx_used; /* No SKB allocated */ | ||
602 | spinlock_t lock; | ||
603 | }; /* Not transferred over network, so not __attribute__ ((packed)) */ | ||
604 | |||
605 | |||
606 | struct alive_command_responce { | ||
607 | u8 alive_command; | ||
608 | u8 sequence_number; | ||
609 | u16 software_revision; | ||
610 | u8 device_identifier; | ||
611 | u8 reserved1[5]; | ||
612 | u16 reserved2; | ||
613 | u16 reserved3; | ||
614 | u16 clock_settle_time; | ||
615 | u16 powerup_settle_time; | ||
616 | u16 reserved4; | ||
617 | u8 time_stamp[5]; /* month, day, year, hours, minutes */ | ||
618 | u8 ucode_valid; | ||
619 | } __attribute__ ((packed)); | ||
620 | |||
621 | #define IPW_MAX_RATES 12 | ||
622 | |||
623 | struct ipw_rates { | ||
624 | u8 num_rates; | ||
625 | u8 rates[IPW_MAX_RATES]; | ||
626 | } __attribute__ ((packed)); | ||
627 | |||
628 | struct command_block | ||
629 | { | ||
630 | unsigned int control; | ||
631 | u32 source_addr; | ||
632 | u32 dest_addr; | ||
633 | unsigned int status; | ||
634 | } __attribute__ ((packed)); | ||
635 | |||
636 | #define CB_NUMBER_OF_ELEMENTS_SMALL 64 | ||
637 | struct fw_image_desc | ||
638 | { | ||
639 | unsigned long last_cb_index; | ||
640 | unsigned long current_cb_index; | ||
641 | struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL]; | ||
642 | void * v_addr; | ||
643 | unsigned long p_addr; | ||
644 | unsigned long len; | ||
645 | }; | ||
646 | |||
647 | struct ipw_sys_config | ||
648 | { | ||
649 | u8 bt_coexistence; | ||
650 | u8 reserved1; | ||
651 | u8 answer_broadcast_ssid_probe; | ||
652 | u8 accept_all_data_frames; | ||
653 | u8 accept_non_directed_frames; | ||
654 | u8 exclude_unicast_unencrypted; | ||
655 | u8 disable_unicast_decryption; | ||
656 | u8 exclude_multicast_unencrypted; | ||
657 | u8 disable_multicast_decryption; | ||
658 | u8 antenna_diversity; | ||
659 | u8 pass_crc_to_host; | ||
660 | u8 dot11g_auto_detection; | ||
661 | u8 enable_cts_to_self; | ||
662 | u8 enable_multicast_filtering; | ||
663 | u8 bt_coexist_collision_thr; | ||
664 | u8 reserved2; | ||
665 | u8 accept_all_mgmt_bcpr; | ||
666 | u8 accept_all_mgtm_frames; | ||
667 | u8 pass_noise_stats_to_host; | ||
668 | u8 reserved3; | ||
669 | } __attribute__ ((packed)); | ||
670 | |||
671 | struct ipw_multicast_addr | ||
672 | { | ||
673 | u8 num_of_multicast_addresses; | ||
674 | u8 reserved[3]; | ||
675 | u8 mac1[6]; | ||
676 | u8 mac2[6]; | ||
677 | u8 mac3[6]; | ||
678 | u8 mac4[6]; | ||
679 | } __attribute__ ((packed)); | ||
680 | |||
681 | struct ipw_wep_key | ||
682 | { | ||
683 | u8 cmd_id; | ||
684 | u8 seq_num; | ||
685 | u8 key_index; | ||
686 | u8 key_size; | ||
687 | u8 key[16]; | ||
688 | } __attribute__ ((packed)); | ||
689 | |||
690 | struct ipw_tgi_tx_key | ||
691 | { | ||
692 | u8 key_id; | ||
693 | u8 security_type; | ||
694 | u8 station_index; | ||
695 | u8 flags; | ||
696 | u8 key[16]; | ||
697 | u32 tx_counter[2]; | ||
698 | } __attribute__ ((packed)); | ||
699 | |||
700 | #define IPW_SCAN_CHANNELS 54 | ||
701 | |||
702 | struct ipw_scan_request | ||
703 | { | ||
704 | u8 scan_type; | ||
705 | u16 dwell_time; | ||
706 | u8 channels_list[IPW_SCAN_CHANNELS]; | ||
707 | u8 channels_reserved[3]; | ||
708 | } __attribute__ ((packed)); | ||
709 | |||
710 | enum { | ||
711 | IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0, | ||
712 | IPW_SCAN_PASSIVE_FULL_DWELL_SCAN, | ||
713 | IPW_SCAN_ACTIVE_DIRECT_SCAN, | ||
714 | IPW_SCAN_ACTIVE_BROADCAST_SCAN, | ||
715 | IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN, | ||
716 | IPW_SCAN_TYPES | ||
717 | }; | ||
718 | |||
719 | struct ipw_scan_request_ext | ||
720 | { | ||
721 | u32 full_scan_index; | ||
722 | u8 channels_list[IPW_SCAN_CHANNELS]; | ||
723 | u8 scan_type[IPW_SCAN_CHANNELS / 2]; | ||
724 | u8 reserved; | ||
725 | u16 dwell_time[IPW_SCAN_TYPES]; | ||
726 | } __attribute__ ((packed)); | ||
727 | |||
728 | extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) | ||
729 | { | ||
730 | if (index % 2) | ||
731 | return scan->scan_type[index / 2] & 0x0F; | ||
732 | else | ||
733 | return (scan->scan_type[index / 2] & 0xF0) >> 4; | ||
734 | } | ||
735 | |||
736 | extern inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, | ||
737 | u8 index, u8 scan_type) | ||
738 | { | ||
739 | if (index % 2) | ||
740 | scan->scan_type[index / 2] = | ||
741 | (scan->scan_type[index / 2] & 0xF0) | | ||
742 | (scan_type & 0x0F); | ||
743 | else | ||
744 | scan->scan_type[index / 2] = | ||
745 | (scan->scan_type[index / 2] & 0x0F) | | ||
746 | ((scan_type & 0x0F) << 4); | ||
747 | } | ||
748 | |||
749 | struct ipw_associate | ||
750 | { | ||
751 | u8 channel; | ||
752 | u8 auth_type:4, | ||
753 | auth_key:4; | ||
754 | u8 assoc_type; | ||
755 | u8 reserved; | ||
756 | u16 policy_support; | ||
757 | u8 preamble_length; | ||
758 | u8 ieee_mode; | ||
759 | u8 bssid[ETH_ALEN]; | ||
760 | u32 assoc_tsf_msw; | ||
761 | u32 assoc_tsf_lsw; | ||
762 | u16 capability; | ||
763 | u16 listen_interval; | ||
764 | u16 beacon_interval; | ||
765 | u8 dest[ETH_ALEN]; | ||
766 | u16 atim_window; | ||
767 | u8 smr; | ||
768 | u8 reserved1; | ||
769 | u16 reserved2; | ||
770 | } __attribute__ ((packed)); | ||
771 | |||
772 | struct ipw_supported_rates | ||
773 | { | ||
774 | u8 ieee_mode; | ||
775 | u8 num_rates; | ||
776 | u8 purpose; | ||
777 | u8 reserved; | ||
778 | u8 supported_rates[IPW_MAX_RATES]; | ||
779 | } __attribute__ ((packed)); | ||
780 | |||
781 | struct ipw_rts_threshold | ||
782 | { | ||
783 | u16 rts_threshold; | ||
784 | u16 reserved; | ||
785 | } __attribute__ ((packed)); | ||
786 | |||
787 | struct ipw_frag_threshold | ||
788 | { | ||
789 | u16 frag_threshold; | ||
790 | u16 reserved; | ||
791 | } __attribute__ ((packed)); | ||
792 | |||
793 | struct ipw_retry_limit | ||
794 | { | ||
795 | u8 short_retry_limit; | ||
796 | u8 long_retry_limit; | ||
797 | u16 reserved; | ||
798 | } __attribute__ ((packed)); | ||
799 | |||
800 | struct ipw_dino_config | ||
801 | { | ||
802 | u32 dino_config_addr; | ||
803 | u16 dino_config_size; | ||
804 | u8 dino_response; | ||
805 | u8 reserved; | ||
806 | } __attribute__ ((packed)); | ||
807 | |||
808 | struct ipw_aironet_info | ||
809 | { | ||
810 | u8 id; | ||
811 | u8 length; | ||
812 | u16 reserved; | ||
813 | } __attribute__ ((packed)); | ||
814 | |||
815 | struct ipw_rx_key | ||
816 | { | ||
817 | u8 station_index; | ||
818 | u8 key_type; | ||
819 | u8 key_id; | ||
820 | u8 key_flag; | ||
821 | u8 key[16]; | ||
822 | u8 station_address[6]; | ||
823 | u8 key_index; | ||
824 | u8 reserved; | ||
825 | } __attribute__ ((packed)); | ||
826 | |||
827 | struct ipw_country_channel_info | ||
828 | { | ||
829 | u8 first_channel; | ||
830 | u8 no_channels; | ||
831 | s8 max_tx_power; | ||
832 | } __attribute__ ((packed)); | ||
833 | |||
834 | struct ipw_country_info | ||
835 | { | ||
836 | u8 id; | ||
837 | u8 length; | ||
838 | u8 country_str[3]; | ||
839 | struct ipw_country_channel_info groups[7]; | ||
840 | } __attribute__ ((packed)); | ||
841 | |||
842 | struct ipw_channel_tx_power | ||
843 | { | ||
844 | u8 channel_number; | ||
845 | s8 tx_power; | ||
846 | } __attribute__ ((packed)); | ||
847 | |||
848 | #define SCAN_ASSOCIATED_INTERVAL (HZ) | ||
849 | #define SCAN_INTERVAL (HZ / 10) | ||
850 | #define MAX_A_CHANNELS 37 | ||
851 | #define MAX_B_CHANNELS 14 | ||
852 | |||
853 | struct ipw_tx_power | ||
854 | { | ||
855 | u8 num_channels; | ||
856 | u8 ieee_mode; | ||
857 | struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS]; | ||
858 | } __attribute__ ((packed)); | ||
859 | |||
860 | struct ipw_qos_parameters | ||
861 | { | ||
862 | u16 cw_min[4]; | ||
863 | u16 cw_max[4]; | ||
864 | u8 aifs[4]; | ||
865 | u8 flag[4]; | ||
866 | u16 tx_op_limit[4]; | ||
867 | } __attribute__ ((packed)); | ||
868 | |||
869 | struct ipw_rsn_capabilities | ||
870 | { | ||
871 | u8 id; | ||
872 | u8 length; | ||
873 | u16 version; | ||
874 | } __attribute__ ((packed)); | ||
875 | |||
876 | struct ipw_sensitivity_calib | ||
877 | { | ||
878 | u16 beacon_rssi_raw; | ||
879 | u16 reserved; | ||
880 | } __attribute__ ((packed)); | ||
881 | |||
882 | /** | ||
883 | * Host command structure. | ||
884 | * | ||
885 | * On input, the following fields should be filled: | ||
886 | * - cmd | ||
887 | * - len | ||
888 | * - status_len | ||
889 | * - param (if needed) | ||
890 | * | ||
891 | * On output, | ||
892 | * - \a status contains status; | ||
893 | * - \a param filled with status parameters. | ||
894 | */ | ||
895 | struct ipw_cmd { | ||
896 | u32 cmd; /**< Host command */ | ||
897 | u32 status; /**< Status */ | ||
898 | u32 status_len; /**< How many 32 bit parameters in the status */ | ||
899 | u32 len; /**< incoming parameters length, bytes */ | ||
900 | /** | ||
901 | * command parameters. | ||
902 | * There should be enough space for incoming and | ||
903 | * outcoming parameters. | ||
904 | * Incoming parameters listed 1-st, followed by outcoming params. | ||
905 | * nParams=(len+3)/4+status_len | ||
906 | */ | ||
907 | u32 param[0]; | ||
908 | } __attribute__ ((packed)); | ||
909 | |||
910 | #define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */ | ||
911 | |||
912 | #define STATUS_INT_ENABLED (1<<1) | ||
913 | #define STATUS_RF_KILL_HW (1<<2) | ||
914 | #define STATUS_RF_KILL_SW (1<<3) | ||
915 | #define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) | ||
916 | |||
917 | #define STATUS_INIT (1<<5) | ||
918 | #define STATUS_AUTH (1<<6) | ||
919 | #define STATUS_ASSOCIATED (1<<7) | ||
920 | #define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED) | ||
921 | |||
922 | #define STATUS_ASSOCIATING (1<<8) | ||
923 | #define STATUS_DISASSOCIATING (1<<9) | ||
924 | #define STATUS_ROAMING (1<<10) | ||
925 | #define STATUS_EXIT_PENDING (1<<11) | ||
926 | #define STATUS_DISASSOC_PENDING (1<<12) | ||
927 | #define STATUS_STATE_PENDING (1<<13) | ||
928 | |||
929 | #define STATUS_SCAN_PENDING (1<<20) | ||
930 | #define STATUS_SCANNING (1<<21) | ||
931 | #define STATUS_SCAN_ABORTING (1<<22) | ||
932 | |||
933 | #define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ | ||
934 | #define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ | ||
935 | #define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ | ||
936 | |||
937 | #define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */ | ||
938 | |||
939 | #define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ | ||
940 | #define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ | ||
941 | #define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ | ||
942 | #define CFG_CUSTOM_MAC (1<<3) | ||
943 | #define CFG_PREAMBLE (1<<4) | ||
944 | #define CFG_ADHOC_PERSIST (1<<5) | ||
945 | #define CFG_ASSOCIATE (1<<6) | ||
946 | #define CFG_FIXED_RATE (1<<7) | ||
947 | #define CFG_ADHOC_CREATE (1<<8) | ||
948 | |||
949 | #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ | ||
950 | #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ | ||
951 | |||
952 | #define MAX_STATIONS 32 | ||
953 | #define IPW_INVALID_STATION (0xff) | ||
954 | |||
955 | struct ipw_station_entry { | ||
956 | u8 mac_addr[ETH_ALEN]; | ||
957 | u8 reserved; | ||
958 | u8 support_mode; | ||
959 | }; | ||
960 | |||
961 | #define AVG_ENTRIES 8 | ||
962 | struct average { | ||
963 | s16 entries[AVG_ENTRIES]; | ||
964 | u8 pos; | ||
965 | u8 init; | ||
966 | s32 sum; | ||
967 | }; | ||
968 | |||
969 | struct ipw_priv { | ||
970 | /* ieee device used by generic ieee processing code */ | ||
971 | struct ieee80211_device *ieee; | ||
972 | struct ieee80211_security sec; | ||
973 | |||
974 | /* spinlock */ | ||
975 | spinlock_t lock; | ||
976 | |||
977 | /* basic pci-network driver stuff */ | ||
978 | struct pci_dev *pci_dev; | ||
979 | struct net_device *net_dev; | ||
980 | |||
981 | /* pci hardware address support */ | ||
982 | void __iomem *hw_base; | ||
983 | unsigned long hw_len; | ||
984 | |||
985 | struct fw_image_desc sram_desc; | ||
986 | |||
987 | /* result of ucode download */ | ||
988 | struct alive_command_responce dino_alive; | ||
989 | |||
990 | wait_queue_head_t wait_command_queue; | ||
991 | wait_queue_head_t wait_state; | ||
992 | |||
993 | /* Rx and Tx DMA processing queues */ | ||
994 | struct ipw_rx_queue *rxq; | ||
995 | struct clx2_tx_queue txq_cmd; | ||
996 | struct clx2_tx_queue txq[4]; | ||
997 | u32 status; | ||
998 | u32 config; | ||
999 | u32 capability; | ||
1000 | |||
1001 | u8 last_rx_rssi; | ||
1002 | u8 last_noise; | ||
1003 | struct average average_missed_beacons; | ||
1004 | struct average average_rssi; | ||
1005 | struct average average_noise; | ||
1006 | u32 port_type; | ||
1007 | int rx_bufs_min; /**< minimum number of bufs in Rx queue */ | ||
1008 | int rx_pend_max; /**< maximum pending buffers for one IRQ */ | ||
1009 | u32 hcmd_seq; /**< sequence number for hcmd */ | ||
1010 | u32 missed_beacon_threshold; | ||
1011 | u32 roaming_threshold; | ||
1012 | |||
1013 | struct ipw_associate assoc_request; | ||
1014 | struct ieee80211_network *assoc_network; | ||
1015 | |||
1016 | unsigned long ts_scan_abort; | ||
1017 | struct ipw_supported_rates rates; | ||
1018 | struct ipw_rates phy[3]; /**< PHY restrictions, per band */ | ||
1019 | struct ipw_rates supp; /**< software defined */ | ||
1020 | struct ipw_rates extended; /**< use for corresp. IE, AP only */ | ||
1021 | |||
1022 | struct notif_link_deterioration last_link_deterioration; /** for statistics */ | ||
1023 | struct ipw_cmd* hcmd; /**< host command currently executed */ | ||
1024 | |||
1025 | wait_queue_head_t hcmd_wq; /**< host command waits for execution */ | ||
1026 | u32 tsf_bcn[2]; /**< TSF from latest beacon */ | ||
1027 | |||
1028 | struct notif_calibration calib; /**< last calibration */ | ||
1029 | |||
1030 | /* ordinal interface with firmware */ | ||
1031 | u32 table0_addr; | ||
1032 | u32 table0_len; | ||
1033 | u32 table1_addr; | ||
1034 | u32 table1_len; | ||
1035 | u32 table2_addr; | ||
1036 | u32 table2_len; | ||
1037 | |||
1038 | /* context information */ | ||
1039 | u8 essid[IW_ESSID_MAX_SIZE]; | ||
1040 | u8 essid_len; | ||
1041 | u8 nick[IW_ESSID_MAX_SIZE]; | ||
1042 | u16 rates_mask; | ||
1043 | u8 channel; | ||
1044 | struct ipw_sys_config sys_config; | ||
1045 | u32 power_mode; | ||
1046 | u8 bssid[ETH_ALEN]; | ||
1047 | u16 rts_threshold; | ||
1048 | u8 mac_addr[ETH_ALEN]; | ||
1049 | u8 num_stations; | ||
1050 | u8 stations[MAX_STATIONS][ETH_ALEN]; | ||
1051 | |||
1052 | u32 notif_missed_beacons; | ||
1053 | |||
1054 | /* Statistics and counters normalized with each association */ | ||
1055 | u32 last_missed_beacons; | ||
1056 | u32 last_tx_packets; | ||
1057 | u32 last_rx_packets; | ||
1058 | u32 last_tx_failures; | ||
1059 | u32 last_rx_err; | ||
1060 | u32 last_rate; | ||
1061 | |||
1062 | u32 missed_adhoc_beacons; | ||
1063 | u32 missed_beacons; | ||
1064 | u32 rx_packets; | ||
1065 | u32 tx_packets; | ||
1066 | u32 quality; | ||
1067 | |||
1068 | /* eeprom */ | ||
1069 | u8 eeprom[0x100]; /* 256 bytes of eeprom */ | ||
1070 | int eeprom_delay; | ||
1071 | |||
1072 | struct iw_statistics wstats; | ||
1073 | |||
1074 | struct workqueue_struct *workqueue; | ||
1075 | |||
1076 | struct work_struct adhoc_check; | ||
1077 | struct work_struct associate; | ||
1078 | struct work_struct disassociate; | ||
1079 | struct work_struct rx_replenish; | ||
1080 | struct work_struct request_scan; | ||
1081 | struct work_struct adapter_restart; | ||
1082 | struct work_struct rf_kill; | ||
1083 | struct work_struct up; | ||
1084 | struct work_struct down; | ||
1085 | struct work_struct gather_stats; | ||
1086 | struct work_struct abort_scan; | ||
1087 | struct work_struct roam; | ||
1088 | struct work_struct scan_check; | ||
1089 | |||
1090 | struct tasklet_struct irq_tasklet; | ||
1091 | |||
1092 | |||
1093 | #define IPW_2200BG 1 | ||
1094 | #define IPW_2915ABG 2 | ||
1095 | u8 adapter; | ||
1096 | |||
1097 | #define IPW_DEFAULT_TX_POWER 0x14 | ||
1098 | u8 tx_power; | ||
1099 | |||
1100 | #ifdef CONFIG_PM | ||
1101 | u32 pm_state[16]; | ||
1102 | #endif | ||
1103 | |||
1104 | /* network state */ | ||
1105 | |||
1106 | /* Used to pass the current INTA value from ISR to Tasklet */ | ||
1107 | u32 isr_inta; | ||
1108 | |||
1109 | /* debugging info */ | ||
1110 | u32 indirect_dword; | ||
1111 | u32 direct_dword; | ||
1112 | u32 indirect_byte; | ||
1113 | }; /*ipw_priv */ | ||
1114 | |||
1115 | |||
1116 | /* debug macros */ | ||
1117 | |||
1118 | #ifdef CONFIG_IPW_DEBUG | ||
1119 | #define IPW_DEBUG(level, fmt, args...) \ | ||
1120 | do { if (ipw_debug_level & (level)) \ | ||
1121 | printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ | ||
1122 | in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) | ||
1123 | #else | ||
1124 | #define IPW_DEBUG(level, fmt, args...) do {} while (0) | ||
1125 | #endif /* CONFIG_IPW_DEBUG */ | ||
1126 | |||
1127 | /* | ||
1128 | * To use the debug system; | ||
1129 | * | ||
1130 | * If you are defining a new debug classification, simply add it to the #define | ||
1131 | * list here in the form of: | ||
1132 | * | ||
1133 | * #define IPW_DL_xxxx VALUE | ||
1134 | * | ||
1135 | * shifting value to the left one bit from the previous entry. xxxx should be | ||
1136 | * the name of the classification (for example, WEP) | ||
1137 | * | ||
1138 | * You then need to either add a IPW_xxxx_DEBUG() macro definition for your | ||
1139 | * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want | ||
1140 | * to send output to that classification. | ||
1141 | * | ||
1142 | * To add your debug level to the list of levels seen when you perform | ||
1143 | * | ||
1144 | * % cat /proc/net/ipw/debug_level | ||
1145 | * | ||
1146 | * you simply need to add your entry to the ipw_debug_levels array. | ||
1147 | * | ||
1148 | * If you do not see debug_level in /proc/net/ipw then you do not have | ||
1149 | * CONFIG_IPW_DEBUG defined in your kernel configuration | ||
1150 | * | ||
1151 | */ | ||
1152 | |||
1153 | #define IPW_DL_ERROR (1<<0) | ||
1154 | #define IPW_DL_WARNING (1<<1) | ||
1155 | #define IPW_DL_INFO (1<<2) | ||
1156 | #define IPW_DL_WX (1<<3) | ||
1157 | #define IPW_DL_HOST_COMMAND (1<<5) | ||
1158 | #define IPW_DL_STATE (1<<6) | ||
1159 | |||
1160 | #define IPW_DL_NOTIF (1<<10) | ||
1161 | #define IPW_DL_SCAN (1<<11) | ||
1162 | #define IPW_DL_ASSOC (1<<12) | ||
1163 | #define IPW_DL_DROP (1<<13) | ||
1164 | #define IPW_DL_IOCTL (1<<14) | ||
1165 | |||
1166 | #define IPW_DL_MANAGE (1<<15) | ||
1167 | #define IPW_DL_FW (1<<16) | ||
1168 | #define IPW_DL_RF_KILL (1<<17) | ||
1169 | #define IPW_DL_FW_ERRORS (1<<18) | ||
1170 | |||
1171 | |||
1172 | #define IPW_DL_ORD (1<<20) | ||
1173 | |||
1174 | #define IPW_DL_FRAG (1<<21) | ||
1175 | #define IPW_DL_WEP (1<<22) | ||
1176 | #define IPW_DL_TX (1<<23) | ||
1177 | #define IPW_DL_RX (1<<24) | ||
1178 | #define IPW_DL_ISR (1<<25) | ||
1179 | #define IPW_DL_FW_INFO (1<<26) | ||
1180 | #define IPW_DL_IO (1<<27) | ||
1181 | #define IPW_DL_TRACE (1<<28) | ||
1182 | |||
1183 | #define IPW_DL_STATS (1<<29) | ||
1184 | |||
1185 | |||
1186 | #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) | ||
1187 | #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) | ||
1188 | #define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a) | ||
1189 | |||
1190 | #define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a) | ||
1191 | #define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a) | ||
1192 | #define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a) | ||
1193 | #define IPW_DEBUG_TRACE(f, a...) IPW_DEBUG(IPW_DL_TRACE, f, ## a) | ||
1194 | #define IPW_DEBUG_RX(f, a...) IPW_DEBUG(IPW_DL_RX, f, ## a) | ||
1195 | #define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a) | ||
1196 | #define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a) | ||
1197 | #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) | ||
1198 | #define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a) | ||
1199 | #define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) | ||
1200 | #define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a) | ||
1201 | #define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a) | ||
1202 | #define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a) | ||
1203 | #define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a) | ||
1204 | #define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a) | ||
1205 | #define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a) | ||
1206 | #define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a) | ||
1207 | #define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a) | ||
1208 | #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | ||
1209 | #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) | ||
1210 | #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a) | ||
1211 | |||
1212 | #include <linux/ctype.h> | ||
1213 | |||
1214 | /* | ||
1215 | * Register bit definitions | ||
1216 | */ | ||
1217 | |||
1218 | /* Dino control registers bits */ | ||
1219 | |||
1220 | #define DINO_ENABLE_SYSTEM 0x80 | ||
1221 | #define DINO_ENABLE_CS 0x40 | ||
1222 | #define DINO_RXFIFO_DATA 0x01 | ||
1223 | #define DINO_CONTROL_REG 0x00200000 | ||
1224 | |||
1225 | #define CX2_INTA_RW 0x00000008 | ||
1226 | #define CX2_INTA_MASK_R 0x0000000C | ||
1227 | #define CX2_INDIRECT_ADDR 0x00000010 | ||
1228 | #define CX2_INDIRECT_DATA 0x00000014 | ||
1229 | #define CX2_AUTOINC_ADDR 0x00000018 | ||
1230 | #define CX2_AUTOINC_DATA 0x0000001C | ||
1231 | #define CX2_RESET_REG 0x00000020 | ||
1232 | #define CX2_GP_CNTRL_RW 0x00000024 | ||
1233 | |||
1234 | #define CX2_READ_INT_REGISTER 0xFF4 | ||
1235 | |||
1236 | #define CX2_GP_CNTRL_BIT_INIT_DONE 0x00000004 | ||
1237 | |||
1238 | #define CX2_REGISTER_DOMAIN1_END 0x00001000 | ||
1239 | #define CX2_SRAM_READ_INT_REGISTER 0x00000ff4 | ||
1240 | |||
1241 | #define CX2_SHARED_LOWER_BOUND 0x00000200 | ||
1242 | #define CX2_INTERRUPT_AREA_LOWER_BOUND 0x00000f80 | ||
1243 | |||
1244 | #define CX2_NIC_SRAM_LOWER_BOUND 0x00000000 | ||
1245 | #define CX2_NIC_SRAM_UPPER_BOUND 0x00030000 | ||
1246 | |||
1247 | #define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29) | ||
1248 | #define CX2_GP_CNTRL_BIT_CLOCK_READY 0x00000001 | ||
1249 | #define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002 | ||
1250 | |||
1251 | /* | ||
1252 | * RESET Register Bit Indexes | ||
1253 | */ | ||
1254 | #define CBD_RESET_REG_PRINCETON_RESET 0x00000001 /* Bit 0 (LSB) */ | ||
1255 | #define CX2_RESET_REG_SW_RESET 0x00000080 /* Bit 7 */ | ||
1256 | #define CX2_RESET_REG_MASTER_DISABLED 0x00000100 /* Bit 8 */ | ||
1257 | #define CX2_RESET_REG_STOP_MASTER 0x00000200 /* Bit 9 */ | ||
1258 | #define CX2_ARC_KESHET_CONFIG 0x08000000 /* Bit 27 */ | ||
1259 | #define CX2_START_STANDBY 0x00000004 /* Bit 2 */ | ||
1260 | |||
1261 | #define CX2_CSR_CIS_UPPER_BOUND 0x00000200 | ||
1262 | #define CX2_DOMAIN_0_END 0x1000 | ||
1263 | #define CLX_MEM_BAR_SIZE 0x1000 | ||
1264 | |||
1265 | #define CX2_BASEBAND_CONTROL_STATUS 0X00200000 | ||
1266 | #define CX2_BASEBAND_TX_FIFO_WRITE 0X00200004 | ||
1267 | #define CX2_BASEBAND_RX_FIFO_READ 0X00200004 | ||
1268 | #define CX2_BASEBAND_CONTROL_STORE 0X00200010 | ||
1269 | |||
1270 | #define CX2_INTERNAL_CMD_EVENT 0X00300004 | ||
1271 | #define CX2_BASEBAND_POWER_DOWN 0x00000001 | ||
1272 | |||
1273 | #define CX2_MEM_HALT_AND_RESET 0x003000e0 | ||
1274 | |||
1275 | /* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */ | ||
1276 | #define CX2_BIT_HALT_RESET_ON 0x80000000 | ||
1277 | #define CX2_BIT_HALT_RESET_OFF 0x00000000 | ||
1278 | |||
1279 | #define CB_LAST_VALID 0x20000000 | ||
1280 | #define CB_INT_ENABLED 0x40000000 | ||
1281 | #define CB_VALID 0x80000000 | ||
1282 | #define CB_SRC_LE 0x08000000 | ||
1283 | #define CB_DEST_LE 0x04000000 | ||
1284 | #define CB_SRC_AUTOINC 0x00800000 | ||
1285 | #define CB_SRC_IO_GATED 0x00400000 | ||
1286 | #define CB_DEST_AUTOINC 0x00080000 | ||
1287 | #define CB_SRC_SIZE_LONG 0x00200000 | ||
1288 | #define CB_DEST_SIZE_LONG 0x00020000 | ||
1289 | |||
1290 | |||
1291 | /* DMA DEFINES */ | ||
1292 | |||
1293 | #define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000 | ||
1294 | #define DMA_CB_STOP_AND_ABORT 0x00000C00 | ||
1295 | #define DMA_CB_START 0x00000100 | ||
1296 | |||
1297 | |||
1298 | #define CX2_SHARED_SRAM_SIZE 0x00030000 | ||
1299 | #define CX2_SHARED_SRAM_DMA_CONTROL 0x00027000 | ||
1300 | #define CB_MAX_LENGTH 0x1FFF | ||
1301 | |||
1302 | #define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18 | ||
1303 | #define CX2_EEPROM_IMAGE_SIZE 0x100 | ||
1304 | |||
1305 | |||
1306 | /* DMA defs */ | ||
1307 | #define CX2_DMA_I_CURRENT_CB 0x003000D0 | ||
1308 | #define CX2_DMA_O_CURRENT_CB 0x003000D4 | ||
1309 | #define CX2_DMA_I_DMA_CONTROL 0x003000A4 | ||
1310 | #define CX2_DMA_I_CB_BASE 0x003000A0 | ||
1311 | |||
1312 | #define CX2_TX_CMD_QUEUE_BD_BASE (0x00000200) | ||
1313 | #define CX2_TX_CMD_QUEUE_BD_SIZE (0x00000204) | ||
1314 | #define CX2_TX_QUEUE_0_BD_BASE (0x00000208) | ||
1315 | #define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C) | ||
1316 | #define CX2_TX_QUEUE_1_BD_BASE (0x00000210) | ||
1317 | #define CX2_TX_QUEUE_1_BD_SIZE (0x00000214) | ||
1318 | #define CX2_TX_QUEUE_2_BD_BASE (0x00000218) | ||
1319 | #define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C) | ||
1320 | #define CX2_TX_QUEUE_3_BD_BASE (0x00000220) | ||
1321 | #define CX2_TX_QUEUE_3_BD_SIZE (0x00000224) | ||
1322 | #define CX2_RX_BD_BASE (0x00000240) | ||
1323 | #define CX2_RX_BD_SIZE (0x00000244) | ||
1324 | #define CX2_RFDS_TABLE_LOWER (0x00000500) | ||
1325 | |||
1326 | #define CX2_TX_CMD_QUEUE_READ_INDEX (0x00000280) | ||
1327 | #define CX2_TX_QUEUE_0_READ_INDEX (0x00000284) | ||
1328 | #define CX2_TX_QUEUE_1_READ_INDEX (0x00000288) | ||
1329 | #define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C) | ||
1330 | #define CX2_TX_QUEUE_3_READ_INDEX (0x00000290) | ||
1331 | #define CX2_RX_READ_INDEX (0x000002A0) | ||
1332 | |||
1333 | #define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) | ||
1334 | #define CX2_TX_QUEUE_0_WRITE_INDEX (0x00000F84) | ||
1335 | #define CX2_TX_QUEUE_1_WRITE_INDEX (0x00000F88) | ||
1336 | #define CX2_TX_QUEUE_2_WRITE_INDEX (0x00000F8C) | ||
1337 | #define CX2_TX_QUEUE_3_WRITE_INDEX (0x00000F90) | ||
1338 | #define CX2_RX_WRITE_INDEX (0x00000FA0) | ||
1339 | |||
1340 | /* | ||
1341 | * EEPROM Related Definitions | ||
1342 | */ | ||
1343 | |||
1344 | #define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814) | ||
1345 | #define IPW_EEPROM_DATA_SRAM_SIZE (CX2_SHARED_LOWER_BOUND + 0x818) | ||
1346 | #define IPW_EEPROM_LOAD_DISABLE (CX2_SHARED_LOWER_BOUND + 0x81C) | ||
1347 | #define IPW_EEPROM_DATA (CX2_SHARED_LOWER_BOUND + 0x820) | ||
1348 | #define IPW_EEPROM_UPPER_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x9E0) | ||
1349 | |||
1350 | #define IPW_STATION_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0xA0C) | ||
1351 | #define IPW_STATION_TABLE_UPPER (CX2_SHARED_LOWER_BOUND + 0xB0C) | ||
1352 | #define IPW_REQUEST_ATIM (CX2_SHARED_LOWER_BOUND + 0xB0C) | ||
1353 | #define IPW_ATIM_SENT (CX2_SHARED_LOWER_BOUND + 0xB10) | ||
1354 | #define IPW_WHO_IS_AWAKE (CX2_SHARED_LOWER_BOUND + 0xB14) | ||
1355 | #define IPW_DURING_ATIM_WINDOW (CX2_SHARED_LOWER_BOUND + 0xB18) | ||
1356 | |||
1357 | |||
1358 | #define MSB 1 | ||
1359 | #define LSB 0 | ||
1360 | #define WORD_TO_BYTE(_word) ((_word) * sizeof(u16)) | ||
1361 | |||
1362 | #define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \ | ||
1363 | ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) ) | ||
1364 | |||
1365 | /* EEPROM access by BYTE */ | ||
1366 | #define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */ | ||
1367 | #define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */ | ||
1368 | #define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */ | ||
1369 | #define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */ | ||
1370 | #define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */ | ||
1371 | #define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */ | ||
1372 | #define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */ | ||
1373 | #define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */ | ||
1374 | #define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */ | ||
1375 | #define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ | ||
1376 | |||
1377 | /* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/ | ||
1378 | #define EEPROM_NIC_TYPE_STANDARD 0 | ||
1379 | #define EEPROM_NIC_TYPE_DELL 1 | ||
1380 | #define EEPROM_NIC_TYPE_FUJITSU 2 | ||
1381 | #define EEPROM_NIC_TYPE_IBM 3 | ||
1382 | #define EEPROM_NIC_TYPE_HP 4 | ||
1383 | |||
1384 | #define FW_MEM_REG_LOWER_BOUND 0x00300000 | ||
1385 | #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) | ||
1386 | |||
1387 | #define EEPROM_BIT_SK (1<<0) | ||
1388 | #define EEPROM_BIT_CS (1<<1) | ||
1389 | #define EEPROM_BIT_DI (1<<2) | ||
1390 | #define EEPROM_BIT_DO (1<<4) | ||
1391 | |||
1392 | #define EEPROM_CMD_READ 0x2 | ||
1393 | |||
1394 | /* Interrupts masks */ | ||
1395 | #define CX2_INTA_NONE 0x00000000 | ||
1396 | |||
1397 | #define CX2_INTA_BIT_RX_TRANSFER 0x00000002 | ||
1398 | #define CX2_INTA_BIT_STATUS_CHANGE 0x00000010 | ||
1399 | #define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020 | ||
1400 | |||
1401 | //Inta Bits for CF | ||
1402 | #define CX2_INTA_BIT_TX_CMD_QUEUE 0x00000800 | ||
1403 | #define CX2_INTA_BIT_TX_QUEUE_1 0x00001000 | ||
1404 | #define CX2_INTA_BIT_TX_QUEUE_2 0x00002000 | ||
1405 | #define CX2_INTA_BIT_TX_QUEUE_3 0x00004000 | ||
1406 | #define CX2_INTA_BIT_TX_QUEUE_4 0x00008000 | ||
1407 | |||
1408 | #define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000 | ||
1409 | |||
1410 | #define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000 | ||
1411 | #define CX2_INTA_BIT_POWER_DOWN 0x00200000 | ||
1412 | |||
1413 | #define CX2_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000 | ||
1414 | #define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000 | ||
1415 | #define CX2_INTA_BIT_RF_KILL_DONE 0x04000000 | ||
1416 | #define CX2_INTA_BIT_FATAL_ERROR 0x40000000 | ||
1417 | #define CX2_INTA_BIT_PARITY_ERROR 0x80000000 | ||
1418 | |||
1419 | /* Interrupts enabled at init time. */ | ||
1420 | #define CX2_INTA_MASK_ALL \ | ||
1421 | (CX2_INTA_BIT_TX_QUEUE_1 | \ | ||
1422 | CX2_INTA_BIT_TX_QUEUE_2 | \ | ||
1423 | CX2_INTA_BIT_TX_QUEUE_3 | \ | ||
1424 | CX2_INTA_BIT_TX_QUEUE_4 | \ | ||
1425 | CX2_INTA_BIT_TX_CMD_QUEUE | \ | ||
1426 | CX2_INTA_BIT_RX_TRANSFER | \ | ||
1427 | CX2_INTA_BIT_FATAL_ERROR | \ | ||
1428 | CX2_INTA_BIT_PARITY_ERROR | \ | ||
1429 | CX2_INTA_BIT_STATUS_CHANGE | \ | ||
1430 | CX2_INTA_BIT_FW_INITIALIZATION_DONE | \ | ||
1431 | CX2_INTA_BIT_BEACON_PERIOD_EXPIRED | \ | ||
1432 | CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \ | ||
1433 | CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN | \ | ||
1434 | CX2_INTA_BIT_POWER_DOWN | \ | ||
1435 | CX2_INTA_BIT_RF_KILL_DONE ) | ||
1436 | |||
1437 | #define IPWSTATUS_ERROR_LOG (CX2_SHARED_LOWER_BOUND + 0x410) | ||
1438 | #define IPW_EVENT_LOG (CX2_SHARED_LOWER_BOUND + 0x414) | ||
1439 | |||
1440 | /* FW event log definitions */ | ||
1441 | #define EVENT_ELEM_SIZE (3 * sizeof(u32)) | ||
1442 | #define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16)) | ||
1443 | |||
1444 | /* FW error log definitions */ | ||
1445 | #define ERROR_ELEM_SIZE (7 * sizeof(u32)) | ||
1446 | #define ERROR_START_OFFSET (1 * sizeof(u32)) | ||
1447 | |||
1448 | enum { | ||
1449 | IPW_FW_ERROR_OK = 0, | ||
1450 | IPW_FW_ERROR_FAIL, | ||
1451 | IPW_FW_ERROR_MEMORY_UNDERFLOW, | ||
1452 | IPW_FW_ERROR_MEMORY_OVERFLOW, | ||
1453 | IPW_FW_ERROR_BAD_PARAM, | ||
1454 | IPW_FW_ERROR_BAD_CHECKSUM, | ||
1455 | IPW_FW_ERROR_NMI_INTERRUPT, | ||
1456 | IPW_FW_ERROR_BAD_DATABASE, | ||
1457 | IPW_FW_ERROR_ALLOC_FAIL, | ||
1458 | IPW_FW_ERROR_DMA_UNDERRUN, | ||
1459 | IPW_FW_ERROR_DMA_STATUS, | ||
1460 | IPW_FW_ERROR_DINOSTATUS_ERROR, | ||
1461 | IPW_FW_ERROR_EEPROMSTATUS_ERROR, | ||
1462 | IPW_FW_ERROR_SYSASSERT, | ||
1463 | IPW_FW_ERROR_FATAL_ERROR | ||
1464 | }; | ||
1465 | |||
1466 | #define AUTH_OPEN 0 | ||
1467 | #define AUTH_SHARED_KEY 1 | ||
1468 | #define AUTH_IGNORE 3 | ||
1469 | |||
1470 | #define HC_ASSOCIATE 0 | ||
1471 | #define HC_REASSOCIATE 1 | ||
1472 | #define HC_DISASSOCIATE 2 | ||
1473 | #define HC_IBSS_START 3 | ||
1474 | #define HC_IBSS_RECONF 4 | ||
1475 | #define HC_DISASSOC_QUIET 5 | ||
1476 | |||
1477 | #define IPW_RATE_CAPABILITIES 1 | ||
1478 | #define IPW_RATE_CONNECT 0 | ||
1479 | |||
1480 | |||
1481 | /* | ||
1482 | * Rate values and masks | ||
1483 | */ | ||
1484 | #define IPW_TX_RATE_1MB 0x0A | ||
1485 | #define IPW_TX_RATE_2MB 0x14 | ||
1486 | #define IPW_TX_RATE_5MB 0x37 | ||
1487 | #define IPW_TX_RATE_6MB 0x0D | ||
1488 | #define IPW_TX_RATE_9MB 0x0F | ||
1489 | #define IPW_TX_RATE_11MB 0x6E | ||
1490 | #define IPW_TX_RATE_12MB 0x05 | ||
1491 | #define IPW_TX_RATE_18MB 0x07 | ||
1492 | #define IPW_TX_RATE_24MB 0x09 | ||
1493 | #define IPW_TX_RATE_36MB 0x0B | ||
1494 | #define IPW_TX_RATE_48MB 0x01 | ||
1495 | #define IPW_TX_RATE_54MB 0x03 | ||
1496 | |||
1497 | #define IPW_ORD_TABLE_ID_MASK 0x0000FF00 | ||
1498 | #define IPW_ORD_TABLE_VALUE_MASK 0x000000FF | ||
1499 | |||
1500 | #define IPW_ORD_TABLE_0_MASK 0x0000F000 | ||
1501 | #define IPW_ORD_TABLE_1_MASK 0x0000F100 | ||
1502 | #define IPW_ORD_TABLE_2_MASK 0x0000F200 | ||
1503 | #define IPW_ORD_TABLE_3_MASK 0x0000F300 | ||
1504 | #define IPW_ORD_TABLE_4_MASK 0x0000F400 | ||
1505 | #define IPW_ORD_TABLE_5_MASK 0x0000F500 | ||
1506 | #define IPW_ORD_TABLE_6_MASK 0x0000F600 | ||
1507 | #define IPW_ORD_TABLE_7_MASK 0x0000F700 | ||
1508 | |||
1509 | /* | ||
1510 | * Table 0 Entries (all entries are 32 bits) | ||
1511 | */ | ||
1512 | enum { | ||
1513 | IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1, | ||
1514 | IPW_ORD_STAT_FRAG_TRESHOLD, | ||
1515 | IPW_ORD_STAT_RTS_THRESHOLD, | ||
1516 | IPW_ORD_STAT_TX_HOST_REQUESTS, | ||
1517 | IPW_ORD_STAT_TX_HOST_COMPLETE, | ||
1518 | IPW_ORD_STAT_TX_DIR_DATA, | ||
1519 | IPW_ORD_STAT_TX_DIR_DATA_B_1, | ||
1520 | IPW_ORD_STAT_TX_DIR_DATA_B_2, | ||
1521 | IPW_ORD_STAT_TX_DIR_DATA_B_5_5, | ||
1522 | IPW_ORD_STAT_TX_DIR_DATA_B_11, | ||
1523 | /* Hole */ | ||
1524 | |||
1525 | |||
1526 | |||
1527 | |||
1528 | |||
1529 | |||
1530 | |||
1531 | IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19, | ||
1532 | IPW_ORD_STAT_TX_DIR_DATA_G_2, | ||
1533 | IPW_ORD_STAT_TX_DIR_DATA_G_5_5, | ||
1534 | IPW_ORD_STAT_TX_DIR_DATA_G_6, | ||
1535 | IPW_ORD_STAT_TX_DIR_DATA_G_9, | ||
1536 | IPW_ORD_STAT_TX_DIR_DATA_G_11, | ||
1537 | IPW_ORD_STAT_TX_DIR_DATA_G_12, | ||
1538 | IPW_ORD_STAT_TX_DIR_DATA_G_18, | ||
1539 | IPW_ORD_STAT_TX_DIR_DATA_G_24, | ||
1540 | IPW_ORD_STAT_TX_DIR_DATA_G_36, | ||
1541 | IPW_ORD_STAT_TX_DIR_DATA_G_48, | ||
1542 | IPW_ORD_STAT_TX_DIR_DATA_G_54, | ||
1543 | IPW_ORD_STAT_TX_NON_DIR_DATA, | ||
1544 | IPW_ORD_STAT_TX_NON_DIR_DATA_B_1, | ||
1545 | IPW_ORD_STAT_TX_NON_DIR_DATA_B_2, | ||
1546 | IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5, | ||
1547 | IPW_ORD_STAT_TX_NON_DIR_DATA_B_11, | ||
1548 | /* Hole */ | ||
1549 | |||
1550 | |||
1551 | |||
1552 | |||
1553 | |||
1554 | |||
1555 | |||
1556 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44, | ||
1557 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_2, | ||
1558 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5, | ||
1559 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_6, | ||
1560 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_9, | ||
1561 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_11, | ||
1562 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_12, | ||
1563 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_18, | ||
1564 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_24, | ||
1565 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_36, | ||
1566 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_48, | ||
1567 | IPW_ORD_STAT_TX_NON_DIR_DATA_G_54, | ||
1568 | IPW_ORD_STAT_TX_RETRY, | ||
1569 | IPW_ORD_STAT_TX_FAILURE, | ||
1570 | IPW_ORD_STAT_RX_ERR_CRC, | ||
1571 | IPW_ORD_STAT_RX_ERR_ICV, | ||
1572 | IPW_ORD_STAT_RX_NO_BUFFER, | ||
1573 | IPW_ORD_STAT_FULL_SCANS, | ||
1574 | IPW_ORD_STAT_PARTIAL_SCANS, | ||
1575 | IPW_ORD_STAT_TGH_ABORTED_SCANS, | ||
1576 | IPW_ORD_STAT_TX_TOTAL_BYTES, | ||
1577 | IPW_ORD_STAT_CURR_RSSI_RAW, | ||
1578 | IPW_ORD_STAT_RX_BEACON, | ||
1579 | IPW_ORD_STAT_MISSED_BEACONS, | ||
1580 | IPW_ORD_TABLE_0_LAST | ||
1581 | }; | ||
1582 | |||
1583 | #define IPW_RSSI_TO_DBM 112 | ||
1584 | |||
1585 | /* Table 1 Entries | ||
1586 | */ | ||
1587 | enum { | ||
1588 | IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1, | ||
1589 | }; | ||
1590 | |||
1591 | /* | ||
1592 | * Table 2 Entries | ||
1593 | * | ||
1594 | * FW_VERSION: 16 byte string | ||
1595 | * FW_DATE: 16 byte string (only 14 bytes used) | ||
1596 | * UCODE_VERSION: 4 byte version code | ||
1597 | * UCODE_DATE: 5 bytes code code | ||
1598 | * ADDAPTER_MAC: 6 byte MAC address | ||
1599 | * RTC: 4 byte clock | ||
1600 | */ | ||
1601 | enum { | ||
1602 | IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1, | ||
1603 | IPW_ORD_STAT_FW_DATE, | ||
1604 | IPW_ORD_STAT_UCODE_VERSION, | ||
1605 | IPW_ORD_STAT_UCODE_DATE, | ||
1606 | IPW_ORD_STAT_ADAPTER_MAC, | ||
1607 | IPW_ORD_STAT_RTC, | ||
1608 | IPW_ORD_TABLE_2_LAST | ||
1609 | }; | ||
1610 | |||
1611 | /* Table 3 */ | ||
1612 | enum { | ||
1613 | IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0, | ||
1614 | IPW_ORD_STAT_TX_PACKET_FAILURE, | ||
1615 | IPW_ORD_STAT_TX_PACKET_SUCCESS, | ||
1616 | IPW_ORD_STAT_TX_PACKET_ABORTED, | ||
1617 | IPW_ORD_TABLE_3_LAST | ||
1618 | }; | ||
1619 | |||
1620 | /* Table 4 */ | ||
1621 | enum { | ||
1622 | IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK | ||
1623 | }; | ||
1624 | |||
1625 | /* Table 5 */ | ||
1626 | enum { | ||
1627 | IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK, | ||
1628 | IPW_ORD_STAT_AP_ASSNS, | ||
1629 | IPW_ORD_STAT_ROAM, | ||
1630 | IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS, | ||
1631 | IPW_ORD_STAT_ROAM_CAUSE_UNASSOC, | ||
1632 | IPW_ORD_STAT_ROAM_CAUSE_RSSI, | ||
1633 | IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY, | ||
1634 | IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE, | ||
1635 | IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX, | ||
1636 | IPW_ORD_STAT_LINK_UP, | ||
1637 | IPW_ORD_STAT_LINK_DOWN, | ||
1638 | IPW_ORD_ANTENNA_DIVERSITY, | ||
1639 | IPW_ORD_CURR_FREQ, | ||
1640 | IPW_ORD_TABLE_5_LAST | ||
1641 | }; | ||
1642 | |||
1643 | /* Table 6 */ | ||
1644 | enum { | ||
1645 | IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK, | ||
1646 | IPW_ORD_CURR_BSSID, | ||
1647 | IPW_ORD_CURR_SSID, | ||
1648 | IPW_ORD_TABLE_6_LAST | ||
1649 | }; | ||
1650 | |||
1651 | /* Table 7 */ | ||
1652 | enum { | ||
1653 | IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK, | ||
1654 | IPW_ORD_STAT_PERCENT_TX_RETRIES, | ||
1655 | IPW_ORD_STAT_PERCENT_LINK_QUALITY, | ||
1656 | IPW_ORD_STAT_CURR_RSSI_DBM, | ||
1657 | IPW_ORD_TABLE_7_LAST | ||
1658 | }; | ||
1659 | |||
1660 | #define IPW_ORDINALS_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0x500) | ||
1661 | #define IPW_ORDINALS_TABLE_0 (CX2_SHARED_LOWER_BOUND + 0x180) | ||
1662 | #define IPW_ORDINALS_TABLE_1 (CX2_SHARED_LOWER_BOUND + 0x184) | ||
1663 | #define IPW_ORDINALS_TABLE_2 (CX2_SHARED_LOWER_BOUND + 0x188) | ||
1664 | #define IPW_MEM_FIXED_OVERRIDE (CX2_SHARED_LOWER_BOUND + 0x41C) | ||
1665 | |||
1666 | struct ipw_fixed_rate { | ||
1667 | u16 tx_rates; | ||
1668 | u16 reserved; | ||
1669 | } __attribute__ ((packed)); | ||
1670 | |||
1671 | #define CX2_INDIRECT_ADDR_MASK (~0x3ul) | ||
1672 | |||
1673 | struct host_cmd { | ||
1674 | u8 cmd; | ||
1675 | u8 len; | ||
1676 | u16 reserved; | ||
1677 | u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; | ||
1678 | } __attribute__ ((packed)); | ||
1679 | |||
1680 | #define CFG_BT_COEXISTENCE_MIN 0x00 | ||
1681 | #define CFG_BT_COEXISTENCE_DEFER 0x02 | ||
1682 | #define CFG_BT_COEXISTENCE_KILL 0x04 | ||
1683 | #define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 | ||
1684 | #define CFG_BT_COEXISTENCE_OOB 0x10 | ||
1685 | #define CFG_BT_COEXISTENCE_MAX 0xFF | ||
1686 | #define CFG_BT_COEXISTENCE_DEF 0x80 /* read Bt from EEPROM*/ | ||
1687 | |||
1688 | #define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x0 | ||
1689 | #define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x1 | ||
1690 | #define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN | ||
1691 | |||
1692 | #define CFG_SYS_ANTENNA_BOTH 0x000 | ||
1693 | #define CFG_SYS_ANTENNA_A 0x001 | ||
1694 | #define CFG_SYS_ANTENNA_B 0x003 | ||
1695 | |||
1696 | /* | ||
1697 | * The definitions below were lifted off the ipw2100 driver, which only | ||
1698 | * supports 'b' mode, so I'm sure these are not exactly correct. | ||
1699 | * | ||
1700 | * Somebody fix these!! | ||
1701 | */ | ||
1702 | #define REG_MIN_CHANNEL 0 | ||
1703 | #define REG_MAX_CHANNEL 14 | ||
1704 | |||
1705 | #define REG_CHANNEL_MASK 0x00003FFF | ||
1706 | #define IPW_IBSS_11B_DEFAULT_MASK 0x87ff | ||
1707 | |||
1708 | static const long ipw_frequencies[] = { | ||
1709 | 2412, 2417, 2422, 2427, | ||
1710 | 2432, 2437, 2442, 2447, | ||
1711 | 2452, 2457, 2462, 2467, | ||
1712 | 2472, 2484 | ||
1713 | }; | ||
1714 | |||
1715 | #define FREQ_COUNT ARRAY_SIZE(ipw_frequencies) | ||
1716 | |||
1717 | #define IPW_MAX_CONFIG_RETRIES 10 | ||
1718 | |||
1719 | static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr) | ||
1720 | { | ||
1721 | u32 retval; | ||
1722 | u16 fc; | ||
1723 | |||
1724 | retval = sizeof(struct ieee80211_hdr); | ||
1725 | fc = le16_to_cpu(hdr->frame_ctl); | ||
1726 | |||
1727 | /* | ||
1728 | * Function ToDS FromDS | ||
1729 | * IBSS 0 0 | ||
1730 | * To AP 1 0 | ||
1731 | * From AP 0 1 | ||
1732 | * WDS (bridge) 1 1 | ||
1733 | * | ||
1734 | * Only WDS frames use Address4 among them. --YZ | ||
1735 | */ | ||
1736 | if (!(fc & IEEE80211_FCTL_TODS) || !(fc & IEEE80211_FCTL_FROMDS)) | ||
1737 | retval -= ETH_ALEN; | ||
1738 | |||
1739 | return retval; | ||
1740 | } | ||
1741 | |||
1742 | #endif /* __ipw2200_h__ */ | ||
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 9c2d07cde010..d7947358e49d 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -94,6 +94,8 @@ | |||
94 | #include <net/iw_handler.h> | 94 | #include <net/iw_handler.h> |
95 | #include <net/ieee80211.h> | 95 | #include <net/ieee80211.h> |
96 | 96 | ||
97 | #include <net/ieee80211.h> | ||
98 | |||
97 | #include <asm/uaccess.h> | 99 | #include <asm/uaccess.h> |
98 | #include <asm/io.h> | 100 | #include <asm/io.h> |
99 | #include <asm/system.h> | 101 | #include <asm/system.h> |
@@ -101,7 +103,6 @@ | |||
101 | #include "hermes.h" | 103 | #include "hermes.h" |
102 | #include "hermes_rid.h" | 104 | #include "hermes_rid.h" |
103 | #include "orinoco.h" | 105 | #include "orinoco.h" |
104 | #include "ieee802_11.h" | ||
105 | 106 | ||
106 | /********************************************************************/ | 107 | /********************************************************************/ |
107 | /* Module information */ | 108 | /* Module information */ |
@@ -150,7 +151,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | |||
150 | #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) | 151 | #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) |
151 | 152 | ||
152 | #define ORINOCO_MIN_MTU 256 | 153 | #define ORINOCO_MIN_MTU 256 |
153 | #define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD) | 154 | #define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD) |
154 | 155 | ||
155 | #define SYMBOL_MAX_VER_LEN (14) | 156 | #define SYMBOL_MAX_VER_LEN (14) |
156 | #define USER_BAP 0 | 157 | #define USER_BAP 0 |
@@ -442,7 +443,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) | |||
442 | if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) | 443 | if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) |
443 | return -EINVAL; | 444 | return -EINVAL; |
444 | 445 | ||
445 | if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > | 446 | if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) > |
446 | (priv->nicbuf_size - ETH_HLEN) ) | 447 | (priv->nicbuf_size - ETH_HLEN) ) |
447 | return -EINVAL; | 448 | return -EINVAL; |
448 | 449 | ||
@@ -918,7 +919,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
918 | data. */ | 919 | data. */ |
919 | return; | 920 | return; |
920 | } | 921 | } |
921 | if (length > IEEE802_11_DATA_LEN) { | 922 | if (length > IEEE80211_DATA_LEN) { |
922 | printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", | 923 | printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", |
923 | dev->name, length); | 924 | dev->name, length); |
924 | stats->rx_length_errors++; | 925 | stats->rx_length_errors++; |
@@ -2272,7 +2273,7 @@ static int orinoco_init(struct net_device *dev) | |||
2272 | 2273 | ||
2273 | /* No need to lock, the hw_unavailable flag is already set in | 2274 | /* No need to lock, the hw_unavailable flag is already set in |
2274 | * alloc_orinocodev() */ | 2275 | * alloc_orinocodev() */ |
2275 | priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; | 2276 | priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; |
2276 | 2277 | ||
2277 | /* Initialize the firmware */ | 2278 | /* Initialize the firmware */ |
2278 | err = orinoco_reinit_firmware(dev); | 2279 | err = orinoco_reinit_firmware(dev); |
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 6c42b573a95a..4b0acae22b0d 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c | |||
@@ -209,7 +209,7 @@ enum { | |||
209 | NoStructure = 0, /* Really old firmware */ | 209 | NoStructure = 0, /* Really old firmware */ |
210 | StructuredMessages = 1, /* Parsable AT response msgs */ | 210 | StructuredMessages = 1, /* Parsable AT response msgs */ |
211 | ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ | 211 | ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ |
212 | } FirmwareLevel; | 212 | }; |
213 | 213 | ||
214 | struct strip { | 214 | struct strip { |
215 | int magic; | 215 | int magic; |
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index f6130a53b796..183c4732ef65 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c | |||
@@ -59,6 +59,12 @@ | |||
59 | /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ | 59 | /* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ |
60 | #include "wavelan_cs.p.h" /* Private header */ | 60 | #include "wavelan_cs.p.h" /* Private header */ |
61 | 61 | ||
62 | #ifdef WAVELAN_ROAMING | ||
63 | static void wl_cell_expiry(unsigned long data); | ||
64 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp); | ||
65 | static void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
66 | #endif /* WAVELAN_ROAMING */ | ||
67 | |||
62 | /************************* MISC SUBROUTINES **************************/ | 68 | /************************* MISC SUBROUTINES **************************/ |
63 | /* | 69 | /* |
64 | * Subroutines which won't fit in one of the following category | 70 | * Subroutines which won't fit in one of the following category |
@@ -500,9 +506,9 @@ fee_write(u_long base, /* i/o port of the card */ | |||
500 | 506 | ||
501 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ | 507 | #ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ |
502 | 508 | ||
503 | unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; | 509 | static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00}; |
504 | 510 | ||
505 | void wv_roam_init(struct net_device *dev) | 511 | static void wv_roam_init(struct net_device *dev) |
506 | { | 512 | { |
507 | net_local *lp= netdev_priv(dev); | 513 | net_local *lp= netdev_priv(dev); |
508 | 514 | ||
@@ -531,7 +537,7 @@ void wv_roam_init(struct net_device *dev) | |||
531 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); | 537 | printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); |
532 | } | 538 | } |
533 | 539 | ||
534 | void wv_roam_cleanup(struct net_device *dev) | 540 | static void wv_roam_cleanup(struct net_device *dev) |
535 | { | 541 | { |
536 | wavepoint_history *ptr,*old_ptr; | 542 | wavepoint_history *ptr,*old_ptr; |
537 | net_local *lp= netdev_priv(dev); | 543 | net_local *lp= netdev_priv(dev); |
@@ -550,7 +556,7 @@ void wv_roam_cleanup(struct net_device *dev) | |||
550 | } | 556 | } |
551 | 557 | ||
552 | /* Enable/Disable NWID promiscuous mode on a given device */ | 558 | /* Enable/Disable NWID promiscuous mode on a given device */ |
553 | void wv_nwid_filter(unsigned char mode, net_local *lp) | 559 | static void wv_nwid_filter(unsigned char mode, net_local *lp) |
554 | { | 560 | { |
555 | mm_t m; | 561 | mm_t m; |
556 | unsigned long flags; | 562 | unsigned long flags; |
@@ -575,7 +581,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp) | |||
575 | } | 581 | } |
576 | 582 | ||
577 | /* Find a record in the WavePoint table matching a given NWID */ | 583 | /* Find a record in the WavePoint table matching a given NWID */ |
578 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | 584 | static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) |
579 | { | 585 | { |
580 | wavepoint_history *ptr=lp->wavepoint_table.head; | 586 | wavepoint_history *ptr=lp->wavepoint_table.head; |
581 | 587 | ||
@@ -588,7 +594,7 @@ wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) | |||
588 | } | 594 | } |
589 | 595 | ||
590 | /* Create a new wavepoint table entry */ | 596 | /* Create a new wavepoint table entry */ |
591 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) | 597 | static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) |
592 | { | 598 | { |
593 | wavepoint_history *new_wavepoint; | 599 | wavepoint_history *new_wavepoint; |
594 | 600 | ||
@@ -624,7 +630,7 @@ wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_ | |||
624 | } | 630 | } |
625 | 631 | ||
626 | /* Remove a wavepoint entry from WavePoint table */ | 632 | /* Remove a wavepoint entry from WavePoint table */ |
627 | void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | 633 | static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) |
628 | { | 634 | { |
629 | if(wavepoint==NULL) | 635 | if(wavepoint==NULL) |
630 | return; | 636 | return; |
@@ -646,7 +652,7 @@ void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) | |||
646 | } | 652 | } |
647 | 653 | ||
648 | /* Timer callback function - checks WavePoint table for stale entries */ | 654 | /* Timer callback function - checks WavePoint table for stale entries */ |
649 | void wl_cell_expiry(unsigned long data) | 655 | static void wl_cell_expiry(unsigned long data) |
650 | { | 656 | { |
651 | net_local *lp=(net_local *)data; | 657 | net_local *lp=(net_local *)data; |
652 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; | 658 | wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; |
@@ -686,7 +692,7 @@ void wl_cell_expiry(unsigned long data) | |||
686 | } | 692 | } |
687 | 693 | ||
688 | /* Update SNR history of a wavepoint */ | 694 | /* Update SNR history of a wavepoint */ |
689 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) | 695 | static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) |
690 | { | 696 | { |
691 | int i=0,num_missed=0,ptr=0; | 697 | int i=0,num_missed=0,ptr=0; |
692 | int average_fast=0,average_slow=0; | 698 | int average_fast=0,average_slow=0; |
@@ -723,7 +729,7 @@ void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsi | |||
723 | } | 729 | } |
724 | 730 | ||
725 | /* Perform a handover to a new WavePoint */ | 731 | /* Perform a handover to a new WavePoint */ |
726 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) | 732 | static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) |
727 | { | 733 | { |
728 | kio_addr_t base = lp->dev->base_addr; | 734 | kio_addr_t base = lp->dev->base_addr; |
729 | mm_t m; | 735 | mm_t m; |
diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h index 29cff6daf860..fabc63ee153c 100644 --- a/drivers/net/wireless/wavelan_cs.h +++ b/drivers/net/wireless/wavelan_cs.h | |||
@@ -62,7 +62,7 @@ | |||
62 | * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this | 62 | * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this |
63 | * part to accommodate your hardware... | 63 | * part to accommodate your hardware... |
64 | */ | 64 | */ |
65 | const unsigned char MAC_ADDRESSES[][3] = | 65 | static const unsigned char MAC_ADDRESSES[][3] = |
66 | { | 66 | { |
67 | { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ | 67 | { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ |
68 | { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ | 68 | { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ |
@@ -79,14 +79,14 @@ const unsigned char MAC_ADDRESSES[][3] = | |||
79 | * (as read in the offset register of the dac area). | 79 | * (as read in the offset register of the dac area). |
80 | * Used to map channel numbers used by `wfreqsel' to frequencies | 80 | * Used to map channel numbers used by `wfreqsel' to frequencies |
81 | */ | 81 | */ |
82 | const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, | 82 | static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, |
83 | 0xD0, 0xF0, 0xF8, 0x150 }; | 83 | 0xD0, 0xF0, 0xF8, 0x150 }; |
84 | 84 | ||
85 | /* Frequencies of the 1.0 modem (fixed frequencies). | 85 | /* Frequencies of the 1.0 modem (fixed frequencies). |
86 | * Use to map the PSA `subband' to a frequency | 86 | * Use to map the PSA `subband' to a frequency |
87 | * Note : all frequencies apart from the first one need to be multiplied by 10 | 87 | * Note : all frequencies apart from the first one need to be multiplied by 10 |
88 | */ | 88 | */ |
89 | const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; | 89 | static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; |
90 | 90 | ||
91 | 91 | ||
92 | /*************************** PC INTERFACE ****************************/ | 92 | /*************************** PC INTERFACE ****************************/ |
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 677ff71883cb..01d882be8790 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h | |||
@@ -647,23 +647,6 @@ struct net_local | |||
647 | void __iomem *mem; | 647 | void __iomem *mem; |
648 | }; | 648 | }; |
649 | 649 | ||
650 | /**************************** PROTOTYPES ****************************/ | ||
651 | |||
652 | #ifdef WAVELAN_ROAMING | ||
653 | /* ---------------------- ROAMING SUBROUTINES -----------------------*/ | ||
654 | |||
655 | wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); | ||
656 | wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); | ||
657 | void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); | ||
658 | void wl_cell_expiry(unsigned long data); | ||
659 | wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); | ||
660 | void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); | ||
661 | void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); | ||
662 | void wv_nwid_filter(unsigned char mode, net_local *lp); | ||
663 | void wv_roam_init(struct net_device *dev); | ||
664 | void wv_roam_cleanup(struct net_device *dev); | ||
665 | #endif /* WAVELAN_ROAMING */ | ||
666 | |||
667 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ | 650 | /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ |
668 | static inline u_char /* data */ | 651 | static inline u_char /* data */ |
669 | hasr_read(u_long); /* Read the host interface : base address */ | 652 | hasr_read(u_long); /* Read the host interface : base address */ |
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 8636d9306785..b5719437e981 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define __WL3501_H__ | 2 | #define __WL3501_H__ |
3 | 3 | ||
4 | #include <linux/spinlock.h> | 4 | #include <linux/spinlock.h> |
5 | #include "ieee802_11.h" | 5 | #include <net/ieee80211.h> |
6 | 6 | ||
7 | /* define for WLA 2.0 */ | 7 | /* define for WLA 2.0 */ |
8 | #define WL3501_BLKSZ 256 | 8 | #define WL3501_BLKSZ 256 |
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { | |||
548 | 548 | ||
549 | struct wl3501_80211_tx_hdr { | 549 | struct wl3501_80211_tx_hdr { |
550 | struct wl3501_80211_tx_plcp_hdr pclp_hdr; | 550 | struct wl3501_80211_tx_plcp_hdr pclp_hdr; |
551 | struct ieee802_11_hdr mac_hdr; | 551 | struct ieee80211_hdr mac_hdr; |
552 | } __attribute__ ((packed)); | 552 | } __attribute__ ((packed)); |
553 | 553 | ||
554 | /* | 554 | /* |
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index dd902126d018..7cc5edbf6ede 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -296,7 +296,8 @@ static int wl3501_get_flash_mac_addr(struct wl3501_card *this) | |||
296 | * | 296 | * |
297 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) | 297 | * Move 'size' bytes from PC to card. (Shouldn't be interrupted) |
298 | */ | 298 | */ |
299 | void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | 299 | static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, |
300 | int size) | ||
300 | { | 301 | { |
301 | /* switch to SRAM Page 0 */ | 302 | /* switch to SRAM Page 0 */ |
302 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : | 303 | wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -317,8 +318,8 @@ void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size) | |||
317 | * | 318 | * |
318 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) | 319 | * Move 'size' bytes from card to PC. (Shouldn't be interrupted) |
319 | */ | 320 | */ |
320 | void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, | 321 | static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, |
321 | int size) | 322 | int size) |
322 | { | 323 | { |
323 | /* switch to SRAM Page 0 */ | 324 | /* switch to SRAM Page 0 */ |
324 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : | 325 | wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : |
@@ -1438,14 +1439,14 @@ fail: | |||
1438 | goto out; | 1439 | goto out; |
1439 | } | 1440 | } |
1440 | 1441 | ||
1441 | struct net_device_stats *wl3501_get_stats(struct net_device *dev) | 1442 | static struct net_device_stats *wl3501_get_stats(struct net_device *dev) |
1442 | { | 1443 | { |
1443 | struct wl3501_card *this = dev->priv; | 1444 | struct wl3501_card *this = dev->priv; |
1444 | 1445 | ||
1445 | return &this->stats; | 1446 | return &this->stats; |
1446 | } | 1447 | } |
1447 | 1448 | ||
1448 | struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) | 1449 | static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) |
1449 | { | 1450 | { |
1450 | struct wl3501_card *this = dev->priv; | 1451 | struct wl3501_card *this = dev->priv; |
1451 | struct iw_statistics *wstats = &this->wstats; | 1452 | struct iw_statistics *wstats = &this->wstats; |
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 16f352195512..fe3fd4115e1e 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile | |||
@@ -8,5 +8,3 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o | |||
8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o | 8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o |
9 | obj-$(CONFIG_USB_USBNET) += usbnet.o | 9 | obj-$(CONFIG_USB_USBNET) += usbnet.o |
10 | obj-$(CONFIG_USB_ZD1201) += zd1201.o | 10 | obj-$(CONFIG_USB_ZD1201) += zd1201.o |
11 | |||
12 | CFLAGS_zd1201.o = -Idrivers/net/wireless/ | ||
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index e32a80b39182..fc013978837e 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/if_arp.h> | 22 | #include <linux/if_arp.h> |
23 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
24 | #include <ieee802_11.h> | 24 | #include <net/ieee80211.h> |
25 | #include "zd1201.h" | 25 | #include "zd1201.h" |
26 | 26 | ||
27 | static struct usb_device_id zd1201_table[] = { | 27 | static struct usb_device_id zd1201_table[] = { |
@@ -338,24 +338,24 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) | |||
338 | goto resubmit; | 338 | goto resubmit; |
339 | } | 339 | } |
340 | 340 | ||
341 | if ((seq & IEEE802_11_SCTL_FRAG) || | 341 | if ((seq & IEEE80211_SCTL_FRAG) || |
342 | (fc & IEEE802_11_FCTL_MOREFRAGS)) { | 342 | (fc & IEEE80211_FCTL_MOREFRAGS)) { |
343 | struct zd1201_frag *frag = NULL; | 343 | struct zd1201_frag *frag = NULL; |
344 | char *ptr; | 344 | char *ptr; |
345 | 345 | ||
346 | if (datalen<14) | 346 | if (datalen<14) |
347 | goto resubmit; | 347 | goto resubmit; |
348 | if ((seq & IEEE802_11_SCTL_FRAG) == 0) { | 348 | if ((seq & IEEE80211_SCTL_FRAG) == 0) { |
349 | frag = kmalloc(sizeof(*frag), GFP_ATOMIC); | 349 | frag = kmalloc(sizeof(*frag), GFP_ATOMIC); |
350 | if (!frag) | 350 | if (!frag) |
351 | goto resubmit; | 351 | goto resubmit; |
352 | skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2); | 352 | skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2); |
353 | if (!skb) { | 353 | if (!skb) { |
354 | kfree(frag); | 354 | kfree(frag); |
355 | goto resubmit; | 355 | goto resubmit; |
356 | } | 356 | } |
357 | frag->skb = skb; | 357 | frag->skb = skb; |
358 | frag->seq = seq & IEEE802_11_SCTL_SEQ; | 358 | frag->seq = seq & IEEE80211_SCTL_SEQ; |
359 | skb_reserve(skb, 2); | 359 | skb_reserve(skb, 2); |
360 | memcpy(skb_put(skb, 12), &data[datalen-14], 12); | 360 | memcpy(skb_put(skb, 12), &data[datalen-14], 12); |
361 | memcpy(skb_put(skb, 2), &data[6], 2); | 361 | memcpy(skb_put(skb, 2), &data[6], 2); |
@@ -364,7 +364,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) | |||
364 | goto resubmit; | 364 | goto resubmit; |
365 | } | 365 | } |
366 | hlist_for_each_entry(frag, node, &zd->fraglist, fnode) | 366 | hlist_for_each_entry(frag, node, &zd->fraglist, fnode) |
367 | if(frag->seq == (seq&IEEE802_11_SCTL_SEQ)) | 367 | if(frag->seq == (seq&IEEE80211_SCTL_SEQ)) |
368 | break; | 368 | break; |
369 | if (!frag) | 369 | if (!frag) |
370 | goto resubmit; | 370 | goto resubmit; |
@@ -372,7 +372,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) | |||
372 | ptr = skb_put(skb, len); | 372 | ptr = skb_put(skb, len); |
373 | if (ptr) | 373 | if (ptr) |
374 | memcpy(ptr, data+8, len); | 374 | memcpy(ptr, data+8, len); |
375 | if (fc & IEEE802_11_FCTL_MOREFRAGS) | 375 | if (fc & IEEE80211_FCTL_MOREFRAGS) |
376 | goto resubmit; | 376 | goto resubmit; |
377 | hlist_del_init(&frag->fnode); | 377 | hlist_del_init(&frag->fnode); |
378 | kfree(frag); | 378 | kfree(frag); |