Merge tag 'rust-fixes-6.9' of https://github.com/Rust-for-Linux/linux
[sfrench/cifs-2.6.git] / drivers / staging / wlan-ng / prism2sta.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2 /*
3  *
4  * Implements the station functionality for prism2
5  *
6  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
7  * --------------------------------------------------------------------
8  *
9  * linux-wlan
10  *
11  * --------------------------------------------------------------------
12  *
13  * Inquiries regarding the linux-wlan Open Source project can be
14  * made directly to:
15  *
16  * AbsoluteValue Systems Inc.
17  * info@linux-wlan.com
18  * http://www.linux-wlan.com
19  *
20  * --------------------------------------------------------------------
21  *
22  * Portions of the development of this software were funded by
23  * Intersil Corporation as part of PRISM(R) chipset product development.
24  *
25  * --------------------------------------------------------------------
26  *
27  * This file implements the module and linux pcmcia routines for the
28  * prism2 driver.
29  *
30  * --------------------------------------------------------------------
31  */
32
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/sched.h>
36 #include <linux/types.h>
37 #include <linux/slab.h>
38 #include <linux/wireless.h>
39 #include <linux/netdevice.h>
40 #include <linux/workqueue.h>
41 #include <linux/byteorder/generic.h>
42 #include <linux/etherdevice.h>
43
44 #include <linux/io.h>
45 #include <linux/delay.h>
46 #include <asm/byteorder.h>
47 #include <linux/if_arp.h>
48 #include <linux/if_ether.h>
49 #include <linux/bitops.h>
50
51 #include "p80211types.h"
52 #include "p80211hdr.h"
53 #include "p80211mgmt.h"
54 #include "p80211conv.h"
55 #include "p80211msg.h"
56 #include "p80211netdev.h"
57 #include "p80211req.h"
58 #include "p80211metadef.h"
59 #include "p80211metastruct.h"
60 #include "hfa384x.h"
61 #include "prism2mgmt.h"
62
63 static char *dev_info = "prism2_usb";
64 static struct wlandevice *create_wlan(void);
65
66 int prism2_reset_holdtime = 30; /* Reset hold time in ms */
67 int prism2_reset_settletime = 100;      /* Reset settle time in ms */
68
69 static int prism2_doreset;      /* Do a reset at init? */
70
71 module_param(prism2_doreset, int, 0644);
72 MODULE_PARM_DESC(prism2_doreset, "Issue a reset on initialization");
73
74 module_param(prism2_reset_holdtime, int, 0644);
75 MODULE_PARM_DESC(prism2_reset_holdtime, "reset hold time in ms");
76 module_param(prism2_reset_settletime, int, 0644);
77 MODULE_PARM_DESC(prism2_reset_settletime, "reset settle time in ms");
78
79 MODULE_LICENSE("Dual MPL/GPL");
80
81 static int prism2sta_open(struct wlandevice *wlandev);
82 static int prism2sta_close(struct wlandevice *wlandev);
83 static void prism2sta_reset(struct wlandevice *wlandev);
84 static int prism2sta_txframe(struct wlandevice *wlandev, struct sk_buff *skb,
85                              struct p80211_hdr *p80211_hdr,
86                              struct p80211_metawep *p80211_wep);
87 static int prism2sta_mlmerequest(struct wlandevice *wlandev,
88                                  struct p80211msg *msg);
89 static int prism2sta_getcardinfo(struct wlandevice *wlandev);
90 static int prism2sta_globalsetup(struct wlandevice *wlandev);
91 static int prism2sta_setmulticast(struct wlandevice *wlandev,
92                                   struct net_device *dev);
93 static void prism2sta_inf_tallies(struct wlandevice *wlandev,
94                                   struct hfa384x_inf_frame *inf);
95 static void prism2sta_inf_hostscanresults(struct wlandevice *wlandev,
96                                           struct hfa384x_inf_frame *inf);
97 static void prism2sta_inf_scanresults(struct wlandevice *wlandev,
98                                       struct hfa384x_inf_frame *inf);
99 static void prism2sta_inf_chinforesults(struct wlandevice *wlandev,
100                                         struct hfa384x_inf_frame *inf);
101 static void prism2sta_inf_linkstatus(struct wlandevice *wlandev,
102                                      struct hfa384x_inf_frame *inf);
103 static void prism2sta_inf_assocstatus(struct wlandevice *wlandev,
104                                       struct hfa384x_inf_frame *inf);
105 static void prism2sta_inf_authreq(struct wlandevice *wlandev,
106                                   struct hfa384x_inf_frame *inf);
107 static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev,
108                                         struct hfa384x_inf_frame *inf);
109 static void prism2sta_inf_psusercnt(struct wlandevice *wlandev,
110                                     struct hfa384x_inf_frame *inf);
111
112 /*
113  * prism2sta_open
114  *
115  * WLAN device open method.  Called from p80211netdev when kernel
116  * device open (start) method is called in response to the
117  * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
118  * from clear to set.
119  *
120  * Arguments:
121  *      wlandev         wlan device structure
122  *
123  * Returns:
124  *      0       success
125  *      >0      f/w reported error
126  *      <0      driver reported error
127  *
128  * Side effects:
129  *
130  * Call context:
131  *      process thread
132  */
133 static int prism2sta_open(struct wlandevice *wlandev)
134 {
135         /* We don't currently have to do anything else.
136          * The setup of the MAC should be subsequently completed via
137          * the mlme commands.
138          * Higher layers know we're ready from dev->start==1 and
139          * dev->tbusy==0.  Our rx path knows to pass up received/
140          * frames because of dev->flags&IFF_UP is true.
141          */
142
143         return 0;
144 }
145
146 /*
147  * prism2sta_close
148  *
149  * WLAN device close method.  Called from p80211netdev when kernel
150  * device close method is called in response to the
151  * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
152  * from set to clear.
153  *
154  * Arguments:
155  *      wlandev         wlan device structure
156  *
157  * Returns:
158  *      0       success
159  *      >0      f/w reported error
160  *      <0      driver reported error
161  *
162  * Side effects:
163  *
164  * Call context:
165  *      process thread
166  */
167 static int prism2sta_close(struct wlandevice *wlandev)
168 {
169         /* We don't currently have to do anything else.
170          * Higher layers know we're not ready from dev->start==0 and
171          * dev->tbusy==1.  Our rx path knows to not pass up received
172          * frames because of dev->flags&IFF_UP is false.
173          */
174
175         return 0;
176 }
177
178 /*
179  * prism2sta_reset
180  *
181  * Currently not implemented.
182  *
183  * Arguments:
184  *      wlandev         wlan device structure
185  *      none
186  *
187  * Returns:
188  *      nothing
189  *
190  * Side effects:
191  *
192  * Call context:
193  *      process thread
194  */
195 static void prism2sta_reset(struct wlandevice *wlandev)
196 {
197 }
198
199 /*
200  * prism2sta_txframe
201  *
202  * Takes a frame from p80211 and queues it for transmission.
203  *
204  * Arguments:
205  *      wlandev         wlan device structure
206  *      pb              packet buffer struct.  Contains an 802.11
207  *                      data frame.
208  *       p80211_hdr      points to the 802.11 header for the packet.
209  * Returns:
210  *      0               Success and more buffs available
211  *      1               Success but no more buffs
212  *      2               Allocation failure
213  *      4               Buffer full or queue busy
214  *
215  * Side effects:
216  *
217  * Call context:
218  *      process thread
219  */
220 static int prism2sta_txframe(struct wlandevice *wlandev, struct sk_buff *skb,
221                              struct p80211_hdr *p80211_hdr,
222                              struct p80211_metawep *p80211_wep)
223 {
224         struct hfa384x *hw = wlandev->priv;
225
226         /* If necessary, set the 802.11 WEP bit */
227         if ((wlandev->hostwep & (HOSTWEP_PRIVACYINVOKED | HOSTWEP_ENCRYPT)) ==
228             HOSTWEP_PRIVACYINVOKED) {
229                 p80211_hdr->frame_control |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
230         }
231
232         return hfa384x_drvr_txframe(hw, skb, p80211_hdr, p80211_wep);
233 }
234
235 /*
236  * prism2sta_mlmerequest
237  *
238  * wlan command message handler.  All we do here is pass the message
239  * over to the prism2sta_mgmt_handler.
240  *
241  * Arguments:
242  *      wlandev         wlan device structure
243  *      msg             wlan command message
244  * Returns:
245  *      0               success
246  *      <0              successful acceptance of message, but we're
247  *                      waiting for an async process to finish before
248  *                      we're done with the msg.  When the asynch
249  *                      process is done, we'll call the p80211
250  *                      function p80211req_confirm() .
251  *      >0              An error occurred while we were handling
252  *                      the message.
253  *
254  * Side effects:
255  *
256  * Call context:
257  *      process thread
258  */
259 static int prism2sta_mlmerequest(struct wlandevice *wlandev,
260                                  struct p80211msg *msg)
261 {
262         struct hfa384x *hw = wlandev->priv;
263
264         int result = 0;
265
266         switch (msg->msgcode) {
267         case DIDMSG_DOT11REQ_MIBGET:
268                 netdev_dbg(wlandev->netdev, "Received mibget request\n");
269                 result = prism2mgmt_mibset_mibget(wlandev, msg);
270                 break;
271         case DIDMSG_DOT11REQ_MIBSET:
272                 netdev_dbg(wlandev->netdev, "Received mibset request\n");
273                 result = prism2mgmt_mibset_mibget(wlandev, msg);
274                 break;
275         case DIDMSG_DOT11REQ_SCAN:
276                 netdev_dbg(wlandev->netdev, "Received scan request\n");
277                 result = prism2mgmt_scan(wlandev, msg);
278                 break;
279         case DIDMSG_DOT11REQ_SCAN_RESULTS:
280                 netdev_dbg(wlandev->netdev, "Received scan_results request\n");
281                 result = prism2mgmt_scan_results(wlandev, msg);
282                 break;
283         case DIDMSG_DOT11REQ_START:
284                 netdev_dbg(wlandev->netdev, "Received mlme start request\n");
285                 result = prism2mgmt_start(wlandev, msg);
286                 break;
287                 /*
288                  * Prism2 specific messages
289                  */
290         case DIDMSG_P2REQ_READPDA:
291                 netdev_dbg(wlandev->netdev, "Received mlme readpda request\n");
292                 result = prism2mgmt_readpda(wlandev, msg);
293                 break;
294         case DIDMSG_P2REQ_RAMDL_STATE:
295                 netdev_dbg(wlandev->netdev,
296                            "Received mlme ramdl_state request\n");
297                 result = prism2mgmt_ramdl_state(wlandev, msg);
298                 break;
299         case DIDMSG_P2REQ_RAMDL_WRITE:
300                 netdev_dbg(wlandev->netdev,
301                            "Received mlme ramdl_write request\n");
302                 result = prism2mgmt_ramdl_write(wlandev, msg);
303                 break;
304         case DIDMSG_P2REQ_FLASHDL_STATE:
305                 netdev_dbg(wlandev->netdev,
306                            "Received mlme flashdl_state request\n");
307                 result = prism2mgmt_flashdl_state(wlandev, msg);
308                 break;
309         case DIDMSG_P2REQ_FLASHDL_WRITE:
310                 netdev_dbg(wlandev->netdev,
311                            "Received mlme flashdl_write request\n");
312                 result = prism2mgmt_flashdl_write(wlandev, msg);
313                 break;
314                 /*
315                  * Linux specific messages
316                  */
317         case DIDMSG_LNXREQ_HOSTWEP:
318                 break;          /* ignore me. */
319         case DIDMSG_LNXREQ_IFSTATE: {
320                 struct p80211msg_lnxreq_ifstate *ifstatemsg;
321
322                 netdev_dbg(wlandev->netdev, "Received mlme ifstate request\n");
323                 ifstatemsg = (struct p80211msg_lnxreq_ifstate *)msg;
324                 result = prism2sta_ifstate(wlandev,
325                                            ifstatemsg->ifstate.data);
326                 ifstatemsg->resultcode.status =
327                         P80211ENUM_msgitem_status_data_ok;
328                 ifstatemsg->resultcode.data = result;
329                 result = 0;
330                 break;
331         }
332         case DIDMSG_LNXREQ_WLANSNIFF:
333                 netdev_dbg(wlandev->netdev,
334                            "Received mlme wlansniff request\n");
335                 result = prism2mgmt_wlansniff(wlandev, msg);
336                 break;
337         case DIDMSG_LNXREQ_AUTOJOIN:
338                 netdev_dbg(wlandev->netdev, "Received mlme autojoin request\n");
339                 result = prism2mgmt_autojoin(wlandev, msg);
340                 break;
341         case DIDMSG_LNXREQ_COMMSQUALITY: {
342                 struct p80211msg_lnxreq_commsquality *qualmsg;
343
344                 netdev_dbg(wlandev->netdev, "Received commsquality request\n");
345
346                 qualmsg = (struct p80211msg_lnxreq_commsquality *)msg;
347
348                 qualmsg->link.status = P80211ENUM_msgitem_status_data_ok;
349                 qualmsg->level.status = P80211ENUM_msgitem_status_data_ok;
350                 qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok;
351
352                 qualmsg->link.data = le16_to_cpu(hw->qual.cq_curr_bss);
353                 qualmsg->level.data = le16_to_cpu(hw->qual.asl_curr_bss);
354                 qualmsg->noise.data = le16_to_cpu(hw->qual.anl_curr_fc);
355                 qualmsg->txrate.data = hw->txrate;
356
357                 break;
358         }
359         default:
360                 netdev_warn(wlandev->netdev,
361                             "Unknown mgmt request message 0x%08x",
362                             msg->msgcode);
363                 break;
364         }
365
366         return result;
367 }
368
369 /*
370  * prism2sta_ifstate
371  *
372  * Interface state.  This is the primary WLAN interface enable/disable
373  * handler.  Following the driver/load/deviceprobe sequence, this
374  * function must be called with a state of "enable" before any other
375  * commands will be accepted.
376  *
377  * Arguments:
378  *      wlandev         wlan device structure
379  *      msgp            ptr to msg buffer
380  *
381  * Returns:
382  *      A p80211 message resultcode value.
383  *
384  * Side effects:
385  *
386  * Call context:
387  *      process thread  (usually)
388  *      interrupt
389  */
390 u32 prism2sta_ifstate(struct wlandevice *wlandev, u32 ifstate)
391 {
392         struct hfa384x *hw = wlandev->priv;
393         u32 result;
394
395         result = P80211ENUM_resultcode_implementation_failure;
396
397         netdev_dbg(wlandev->netdev, "Current MSD state(%d), requesting(%d)\n",
398                    wlandev->msdstate, ifstate);
399         switch (ifstate) {
400         case P80211ENUM_ifstate_fwload:
401                 switch (wlandev->msdstate) {
402                 case WLAN_MSD_HWPRESENT:
403                         wlandev->msdstate = WLAN_MSD_FWLOAD_PENDING;
404                         /*
405                          * Initialize the device+driver sufficiently
406                          * for firmware loading.
407                          */
408                         result = hfa384x_drvr_start(hw);
409                         if (result) {
410                                 netdev_err(wlandev->netdev,
411                                            "hfa384x_drvr_start() failed,result=%d\n",
412                                            (int)result);
413                                 result =
414                                  P80211ENUM_resultcode_implementation_failure;
415                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
416                                 break;
417                         }
418                         wlandev->msdstate = WLAN_MSD_FWLOAD;
419                         result = P80211ENUM_resultcode_success;
420                         break;
421                 case WLAN_MSD_FWLOAD:
422                         hfa384x_cmd_initialize(hw);
423                         result = P80211ENUM_resultcode_success;
424                         break;
425                 case WLAN_MSD_RUNNING:
426                         netdev_warn(wlandev->netdev,
427                                     "Cannot enter fwload state from enable state, you must disable first.\n");
428                         result = P80211ENUM_resultcode_invalid_parameters;
429                         break;
430                 case WLAN_MSD_HWFAIL:
431                 default:
432                         /* probe() had a problem or the msdstate contains
433                          * an unrecognized value, there's nothing we can do.
434                          */
435                         result = P80211ENUM_resultcode_implementation_failure;
436                         break;
437                 }
438                 break;
439         case P80211ENUM_ifstate_enable:
440                 switch (wlandev->msdstate) {
441                 case WLAN_MSD_HWPRESENT:
442                 case WLAN_MSD_FWLOAD:
443                         wlandev->msdstate = WLAN_MSD_RUNNING_PENDING;
444                         /* Initialize the device+driver for full
445                          * operation. Note that this might me an FWLOAD
446                          * to RUNNING transition so we must not do a chip
447                          * or board level reset.  Note that on failure,
448                          * the MSD state is set to HWPRESENT because we
449                          * can't make any assumptions about the state
450                          * of the hardware or a previous firmware load.
451                          */
452                         result = hfa384x_drvr_start(hw);
453                         if (result) {
454                                 netdev_err(wlandev->netdev,
455                                            "hfa384x_drvr_start() failed,result=%d\n",
456                                            (int)result);
457                                 result =
458                                   P80211ENUM_resultcode_implementation_failure;
459                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
460                                 break;
461                         }
462
463                         result = prism2sta_getcardinfo(wlandev);
464                         if (result) {
465                                 netdev_err(wlandev->netdev,
466                                            "prism2sta_getcardinfo() failed,result=%d\n",
467                                            (int)result);
468                                 result =
469                                   P80211ENUM_resultcode_implementation_failure;
470                                 hfa384x_drvr_stop(hw);
471                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
472                                 break;
473                         }
474                         result = prism2sta_globalsetup(wlandev);
475                         if (result) {
476                                 netdev_err(wlandev->netdev,
477                                            "prism2sta_globalsetup() failed,result=%d\n",
478                                            (int)result);
479                                 result =
480                                   P80211ENUM_resultcode_implementation_failure;
481                                 hfa384x_drvr_stop(hw);
482                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
483                                 break;
484                         }
485                         wlandev->msdstate = WLAN_MSD_RUNNING;
486                         hw->join_ap = 0;
487                         hw->join_retries = 60;
488                         result = P80211ENUM_resultcode_success;
489                         break;
490                 case WLAN_MSD_RUNNING:
491                         /* Do nothing, we're already in this state. */
492                         result = P80211ENUM_resultcode_success;
493                         break;
494                 case WLAN_MSD_HWFAIL:
495                 default:
496                         /* probe() had a problem or the msdstate contains
497                          * an unrecognized value, there's nothing we can do.
498                          */
499                         result = P80211ENUM_resultcode_implementation_failure;
500                         break;
501                 }
502                 break;
503         case P80211ENUM_ifstate_disable:
504                 switch (wlandev->msdstate) {
505                 case WLAN_MSD_HWPRESENT:
506                         /* Do nothing, we're already in this state. */
507                         result = P80211ENUM_resultcode_success;
508                         break;
509                 case WLAN_MSD_FWLOAD:
510                 case WLAN_MSD_RUNNING:
511                         wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING;
512                         /*
513                          * TODO: Shut down the MAC completely. Here a chip
514                          * or board level reset is probably called for.
515                          * After a "disable" _all_ results are lost, even
516                          * those from a fwload.
517                          */
518                         if (!wlandev->hwremoved)
519                                 netif_carrier_off(wlandev->netdev);
520
521                         hfa384x_drvr_stop(hw);
522
523                         wlandev->macmode = WLAN_MACMODE_NONE;
524                         wlandev->msdstate = WLAN_MSD_HWPRESENT;
525                         result = P80211ENUM_resultcode_success;
526                         break;
527                 case WLAN_MSD_HWFAIL:
528                 default:
529                         /* probe() had a problem or the msdstate contains
530                          * an unrecognized value, there's nothing we can do.
531                          */
532                         result = P80211ENUM_resultcode_implementation_failure;
533                         break;
534                 }
535                 break;
536         default:
537                 result = P80211ENUM_resultcode_invalid_parameters;
538                 break;
539         }
540
541         return result;
542 }
543
544 /*
545  * prism2sta_getcardinfo
546  *
547  * Collect the NICID, firmware version and any other identifiers
548  * we'd like to have in host-side data structures.
549  *
550  * Arguments:
551  *      wlandev         wlan device structure
552  *
553  * Returns:
554  *      0       success
555  *      >0      f/w reported error
556  *      <0      driver reported error
557  *
558  * Side effects:
559  *
560  * Call context:
561  *      Either.
562  */
563 static int prism2sta_getcardinfo(struct wlandevice *wlandev)
564 {
565         int result = 0;
566         struct hfa384x *hw = wlandev->priv;
567         u16 temp;
568         u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN];
569         u8 addr[ETH_ALEN];
570
571         /* Collect version and compatibility info */
572         /*  Some are critical, some are not */
573         /* NIC identity */
574         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICIDENTITY,
575                                         &hw->ident_nic,
576                                         sizeof(struct hfa384x_compident));
577         if (result) {
578                 netdev_err(wlandev->netdev, "Failed to retrieve NICIDENTITY\n");
579                 goto failed;
580         }
581
582         /* get all the nic id fields in host byte order */
583         le16_to_cpus(&hw->ident_nic.id);
584         le16_to_cpus(&hw->ident_nic.variant);
585         le16_to_cpus(&hw->ident_nic.major);
586         le16_to_cpus(&hw->ident_nic.minor);
587
588         netdev_info(wlandev->netdev, "ident: nic h/w: id=0x%02x %d.%d.%d\n",
589                     hw->ident_nic.id, hw->ident_nic.major,
590                     hw->ident_nic.minor, hw->ident_nic.variant);
591
592         /* Primary f/w identity */
593         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRIIDENTITY,
594                                         &hw->ident_pri_fw,
595                                         sizeof(struct hfa384x_compident));
596         if (result) {
597                 netdev_err(wlandev->netdev, "Failed to retrieve PRIIDENTITY\n");
598                 goto failed;
599         }
600
601         /* get all the private fw id fields in host byte order */
602         le16_to_cpus(&hw->ident_pri_fw.id);
603         le16_to_cpus(&hw->ident_pri_fw.variant);
604         le16_to_cpus(&hw->ident_pri_fw.major);
605         le16_to_cpus(&hw->ident_pri_fw.minor);
606
607         netdev_info(wlandev->netdev, "ident: pri f/w: id=0x%02x %d.%d.%d\n",
608                     hw->ident_pri_fw.id, hw->ident_pri_fw.major,
609                     hw->ident_pri_fw.minor, hw->ident_pri_fw.variant);
610
611         /* Station (Secondary?) f/w identity */
612         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STAIDENTITY,
613                                         &hw->ident_sta_fw,
614                                         sizeof(struct hfa384x_compident));
615         if (result) {
616                 netdev_err(wlandev->netdev, "Failed to retrieve STAIDENTITY\n");
617                 goto failed;
618         }
619
620         if (hw->ident_nic.id < 0x8000) {
621                 netdev_err(wlandev->netdev,
622                            "FATAL: Card is not an Intersil Prism2/2.5/3\n");
623                 result = -1;
624                 goto failed;
625         }
626
627         /* get all the station fw id fields in host byte order */
628         le16_to_cpus(&hw->ident_sta_fw.id);
629         le16_to_cpus(&hw->ident_sta_fw.variant);
630         le16_to_cpus(&hw->ident_sta_fw.major);
631         le16_to_cpus(&hw->ident_sta_fw.minor);
632
633         /* strip out the 'special' variant bits */
634         hw->mm_mods = hw->ident_sta_fw.variant & GENMASK(15, 14);
635         hw->ident_sta_fw.variant &= ~((u16)GENMASK(15, 14));
636
637         if (hw->ident_sta_fw.id == 0x1f) {
638                 netdev_info(wlandev->netdev,
639                             "ident: sta f/w: id=0x%02x %d.%d.%d\n",
640                             hw->ident_sta_fw.id, hw->ident_sta_fw.major,
641                             hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
642         } else {
643                 netdev_info(wlandev->netdev,
644                             "ident:  ap f/w: id=0x%02x %d.%d.%d\n",
645                             hw->ident_sta_fw.id, hw->ident_sta_fw.major,
646                             hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
647                 netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmware loaded!\n");
648                 goto failed;
649         }
650
651         /* Compatibility range, Modem supplier */
652         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_MFISUPRANGE,
653                                         &hw->cap_sup_mfi,
654                                         sizeof(struct hfa384x_caplevel));
655         if (result) {
656                 netdev_err(wlandev->netdev, "Failed to retrieve MFISUPRANGE\n");
657                 goto failed;
658         }
659
660         /* get all the Compatibility range, modem interface supplier
661          * fields in byte order
662          */
663         le16_to_cpus(&hw->cap_sup_mfi.role);
664         le16_to_cpus(&hw->cap_sup_mfi.id);
665         le16_to_cpus(&hw->cap_sup_mfi.variant);
666         le16_to_cpus(&hw->cap_sup_mfi.bottom);
667         le16_to_cpus(&hw->cap_sup_mfi.top);
668
669         netdev_info(wlandev->netdev,
670                     "MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
671                     hw->cap_sup_mfi.role, hw->cap_sup_mfi.id,
672                     hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom,
673                     hw->cap_sup_mfi.top);
674
675         /* Compatibility range, Controller supplier */
676         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CFISUPRANGE,
677                                         &hw->cap_sup_cfi,
678                                         sizeof(struct hfa384x_caplevel));
679         if (result) {
680                 netdev_err(wlandev->netdev, "Failed to retrieve CFISUPRANGE\n");
681                 goto failed;
682         }
683
684         /* get all the Compatibility range, controller interface supplier
685          * fields in byte order
686          */
687         le16_to_cpus(&hw->cap_sup_cfi.role);
688         le16_to_cpus(&hw->cap_sup_cfi.id);
689         le16_to_cpus(&hw->cap_sup_cfi.variant);
690         le16_to_cpus(&hw->cap_sup_cfi.bottom);
691         le16_to_cpus(&hw->cap_sup_cfi.top);
692
693         netdev_info(wlandev->netdev,
694                     "CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
695                     hw->cap_sup_cfi.role, hw->cap_sup_cfi.id,
696                     hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom,
697                     hw->cap_sup_cfi.top);
698
699         /* Compatibility range, Primary f/w supplier */
700         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRISUPRANGE,
701                                         &hw->cap_sup_pri,
702                                         sizeof(struct hfa384x_caplevel));
703         if (result) {
704                 netdev_err(wlandev->netdev, "Failed to retrieve PRISUPRANGE\n");
705                 goto failed;
706         }
707
708         /* get all the Compatibility range, primary firmware supplier
709          * fields in byte order
710          */
711         le16_to_cpus(&hw->cap_sup_pri.role);
712         le16_to_cpus(&hw->cap_sup_pri.id);
713         le16_to_cpus(&hw->cap_sup_pri.variant);
714         le16_to_cpus(&hw->cap_sup_pri.bottom);
715         le16_to_cpus(&hw->cap_sup_pri.top);
716
717         netdev_info(wlandev->netdev,
718                     "PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
719                     hw->cap_sup_pri.role, hw->cap_sup_pri.id,
720                     hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom,
721                     hw->cap_sup_pri.top);
722
723         /* Compatibility range, Station f/w supplier */
724         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STASUPRANGE,
725                                         &hw->cap_sup_sta,
726                                         sizeof(struct hfa384x_caplevel));
727         if (result) {
728                 netdev_err(wlandev->netdev, "Failed to retrieve STASUPRANGE\n");
729                 goto failed;
730         }
731
732         /* get all the Compatibility range, station firmware supplier
733          * fields in byte order
734          */
735         le16_to_cpus(&hw->cap_sup_sta.role);
736         le16_to_cpus(&hw->cap_sup_sta.id);
737         le16_to_cpus(&hw->cap_sup_sta.variant);
738         le16_to_cpus(&hw->cap_sup_sta.bottom);
739         le16_to_cpus(&hw->cap_sup_sta.top);
740
741         if (hw->cap_sup_sta.id == 0x04) {
742                 netdev_info(wlandev->netdev,
743                             "STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
744                             hw->cap_sup_sta.role, hw->cap_sup_sta.id,
745                             hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
746                             hw->cap_sup_sta.top);
747         } else {
748                 netdev_info(wlandev->netdev,
749                             "AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
750                             hw->cap_sup_sta.role, hw->cap_sup_sta.id,
751                             hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
752                             hw->cap_sup_sta.top);
753         }
754
755         /* Compatibility range, primary f/w actor, CFI supplier */
756         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRI_CFIACTRANGES,
757                                         &hw->cap_act_pri_cfi,
758                                         sizeof(struct hfa384x_caplevel));
759         if (result) {
760                 netdev_err(wlandev->netdev, "Failed to retrieve PRI_CFIACTRANGES\n");
761                 goto failed;
762         }
763
764         /* get all the Compatibility range, primary f/w actor, CFI supplier
765          * fields in byte order
766          */
767         le16_to_cpus(&hw->cap_act_pri_cfi.role);
768         le16_to_cpus(&hw->cap_act_pri_cfi.id);
769         le16_to_cpus(&hw->cap_act_pri_cfi.variant);
770         le16_to_cpus(&hw->cap_act_pri_cfi.bottom);
771         le16_to_cpus(&hw->cap_act_pri_cfi.top);
772
773         netdev_info(wlandev->netdev,
774                     "PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
775                     hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id,
776                     hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom,
777                     hw->cap_act_pri_cfi.top);
778
779         /* Compatibility range, sta f/w actor, CFI supplier */
780         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_CFIACTRANGES,
781                                         &hw->cap_act_sta_cfi,
782                                         sizeof(struct hfa384x_caplevel));
783         if (result) {
784                 netdev_err(wlandev->netdev, "Failed to retrieve STA_CFIACTRANGES\n");
785                 goto failed;
786         }
787
788         /* get all the Compatibility range, station f/w actor, CFI supplier
789          * fields in byte order
790          */
791         le16_to_cpus(&hw->cap_act_sta_cfi.role);
792         le16_to_cpus(&hw->cap_act_sta_cfi.id);
793         le16_to_cpus(&hw->cap_act_sta_cfi.variant);
794         le16_to_cpus(&hw->cap_act_sta_cfi.bottom);
795         le16_to_cpus(&hw->cap_act_sta_cfi.top);
796
797         netdev_info(wlandev->netdev,
798                     "STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
799                     hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id,
800                     hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom,
801                     hw->cap_act_sta_cfi.top);
802
803         /* Compatibility range, sta f/w actor, MFI supplier */
804         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_MFIACTRANGES,
805                                         &hw->cap_act_sta_mfi,
806                                         sizeof(struct hfa384x_caplevel));
807         if (result) {
808                 netdev_err(wlandev->netdev, "Failed to retrieve STA_MFIACTRANGES\n");
809                 goto failed;
810         }
811
812         /* get all the Compatibility range, station f/w actor, MFI supplier
813          * fields in byte order
814          */
815         le16_to_cpus(&hw->cap_act_sta_mfi.role);
816         le16_to_cpus(&hw->cap_act_sta_mfi.id);
817         le16_to_cpus(&hw->cap_act_sta_mfi.variant);
818         le16_to_cpus(&hw->cap_act_sta_mfi.bottom);
819         le16_to_cpus(&hw->cap_act_sta_mfi.top);
820
821         netdev_info(wlandev->netdev,
822                     "STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
823                     hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id,
824                     hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom,
825                     hw->cap_act_sta_mfi.top);
826
827         /* Serial Number */
828         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
829                                         snum, HFA384x_RID_NICSERIALNUMBER_LEN);
830         if (!result) {
831                 netdev_info(wlandev->netdev, "Prism2 card SN: %*pE\n",
832                             HFA384x_RID_NICSERIALNUMBER_LEN, snum);
833         } else {
834                 netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
835                 goto failed;
836         }
837
838         /* Collect the MAC address */
839         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR,
840                                         addr, ETH_ALEN);
841         if (result != 0) {
842                 netdev_err(wlandev->netdev, "Failed to retrieve mac address\n");
843                 goto failed;
844         }
845         eth_hw_addr_set(wlandev->netdev, addr);
846
847         /* short preamble is always implemented */
848         wlandev->nsdcaps |= P80211_NSDCAP_SHORT_PREAMBLE;
849
850         /* find out if hardware wep is implemented */
851         hfa384x_drvr_getconfig16(hw, HFA384x_RID_PRIVACYOPTIMP, &temp);
852         if (temp)
853                 wlandev->nsdcaps |= P80211_NSDCAP_HARDWAREWEP;
854
855         /* get the dBm Scaling constant */
856         hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFDBMADJUST, &temp);
857         hw->dbmadjust = temp;
858
859         /* Only enable scan by default on newer firmware */
860         if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
861                                      hw->ident_sta_fw.minor,
862                                      hw->ident_sta_fw.variant) <
863             HFA384x_FIRMWARE_VERSION(1, 5, 5)) {
864                 wlandev->nsdcaps |= P80211_NSDCAP_NOSCAN;
865         }
866
867         /* TODO: Set any internally managed config items */
868
869         goto done;
870 failed:
871         netdev_err(wlandev->netdev, "Failed, result=%d\n", result);
872 done:
873         return result;
874 }
875
876 /*
877  * prism2sta_globalsetup
878  *
879  * Set any global RIDs that we want to set at device activation.
880  *
881  * Arguments:
882  *      wlandev         wlan device structure
883  *
884  * Returns:
885  *      0       success
886  *      >0      f/w reported error
887  *      <0      driver reported error
888  *
889  * Side effects:
890  *
891  * Call context:
892  *      process thread
893  */
894 static int prism2sta_globalsetup(struct wlandevice *wlandev)
895 {
896         struct hfa384x *hw = wlandev->priv;
897
898         /* Set the maximum frame size */
899         return hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN,
900                                         WLAN_DATA_MAXLEN);
901 }
902
903 static int prism2sta_setmulticast(struct wlandevice *wlandev,
904                                   struct net_device *dev)
905 {
906         int result = 0;
907         struct hfa384x *hw = wlandev->priv;
908
909         u16 promisc;
910
911         /* If we're not ready, what's the point? */
912         if (hw->state != HFA384x_STATE_RUNNING)
913                 goto exit;
914
915         if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
916                 promisc = P80211ENUM_truth_true;
917         else
918                 promisc = P80211ENUM_truth_false;
919
920         result =
921             hfa384x_drvr_setconfig16_async(hw, HFA384x_RID_PROMISCMODE,
922                                            promisc);
923 exit:
924         return result;
925 }
926
927 /*
928  * prism2sta_inf_tallies
929  *
930  * Handles the receipt of a CommTallies info frame.
931  *
932  * Arguments:
933  *      wlandev         wlan device structure
934  *      inf             ptr to info frame (contents in hfa384x order)
935  *
936  * Returns:
937  *      nothing
938  *
939  * Side effects:
940  *
941  * Call context:
942  *      interrupt
943  */
944 static void prism2sta_inf_tallies(struct wlandevice *wlandev,
945                                   struct hfa384x_inf_frame *inf)
946 {
947         struct hfa384x *hw = wlandev->priv;
948         __le16 *src16;
949         u32 *dst;
950         __le32 *src32;
951         int i;
952         int cnt;
953
954         /*
955          * Determine if these are 16-bit or 32-bit tallies, based on the
956          * record length of the info record.
957          */
958
959         cnt = sizeof(struct hfa384x_comm_tallies_32) / sizeof(u32);
960         if (inf->framelen > 22) {
961                 dst = (u32 *)&hw->tallies;
962                 src32 = (__le32 *)&inf->info.commtallies32;
963                 for (i = 0; i < cnt; i++, dst++, src32++)
964                         *dst += le32_to_cpu(*src32);
965         } else {
966                 dst = (u32 *)&hw->tallies;
967                 src16 = (__le16 *)&inf->info.commtallies16;
968                 for (i = 0; i < cnt; i++, dst++, src16++)
969                         *dst += le16_to_cpu(*src16);
970         }
971 }
972
973 /*
974  * prism2sta_inf_scanresults
975  *
976  * Handles the receipt of a Scan Results info frame.
977  *
978  * Arguments:
979  *      wlandev         wlan device structure
980  *      inf             ptr to info frame (contents in hfa384x order)
981  *
982  * Returns:
983  *      nothing
984  *
985  * Side effects:
986  *
987  * Call context:
988  *      interrupt
989  */
990 static void prism2sta_inf_scanresults(struct wlandevice *wlandev,
991                                       struct hfa384x_inf_frame *inf)
992 {
993         struct hfa384x *hw = wlandev->priv;
994         int nbss;
995         struct hfa384x_scan_result *sr = &inf->info.scanresult;
996         int i;
997         struct hfa384x_join_request_data joinreq;
998         int result;
999
1000         /* Get the number of results, first in bytes, then in results */
1001         nbss = (inf->framelen * sizeof(u16)) -
1002             sizeof(inf->infotype) - sizeof(inf->info.scanresult.scanreason);
1003         nbss /= sizeof(struct hfa384x_scan_result_sub);
1004
1005         /* Print em */
1006         netdev_dbg(wlandev->netdev, "rx scanresults, reason=%d, nbss=%d:\n",
1007                    inf->info.scanresult.scanreason, nbss);
1008         for (i = 0; i < nbss; i++) {
1009                 netdev_dbg(wlandev->netdev, "chid=%d anl=%d sl=%d bcnint=%d\n",
1010                            sr->result[i].chid, sr->result[i].anl,
1011                            sr->result[i].sl, sr->result[i].bcnint);
1012                 netdev_dbg(wlandev->netdev,
1013                            "  capinfo=0x%04x proberesp_rate=%d\n",
1014                            sr->result[i].capinfo, sr->result[i].proberesp_rate);
1015         }
1016         /* issue a join request */
1017         joinreq.channel = sr->result[0].chid;
1018         memcpy(joinreq.bssid, sr->result[0].bssid, WLAN_BSSID_LEN);
1019         result = hfa384x_drvr_setconfig(hw,
1020                                         HFA384x_RID_JOINREQUEST,
1021                                         &joinreq, HFA384x_RID_JOINREQUEST_LEN);
1022         if (result) {
1023                 netdev_err(wlandev->netdev, "setconfig(joinreq) failed, result=%d\n",
1024                            result);
1025         }
1026 }
1027
1028 /*
1029  * prism2sta_inf_hostscanresults
1030  *
1031  * Handles the receipt of a Scan Results info frame.
1032  *
1033  * Arguments:
1034  *      wlandev         wlan device structure
1035  *      inf             ptr to info frame (contents in hfa384x order)
1036  *
1037  * Returns:
1038  *      nothing
1039  *
1040  * Side effects:
1041  *
1042  * Call context:
1043  *      interrupt
1044  */
1045 static void prism2sta_inf_hostscanresults(struct wlandevice *wlandev,
1046                                           struct hfa384x_inf_frame *inf)
1047 {
1048         struct hfa384x *hw = wlandev->priv;
1049         int nbss;
1050
1051         nbss = (inf->framelen - 3) / 32;
1052         netdev_dbg(wlandev->netdev, "Received %d hostscan results\n", nbss);
1053
1054         if (nbss > 32)
1055                 nbss = 32;
1056
1057         kfree(hw->scanresults);
1058
1059         hw->scanresults = kmemdup(inf, sizeof(*inf), GFP_ATOMIC);
1060
1061         if (nbss == 0)
1062                 nbss = -1;
1063
1064         /* Notify/wake the sleeping caller. */
1065         hw->scanflag = nbss;
1066         wake_up_interruptible(&hw->cmdq);
1067 };
1068
1069 /*
1070  * prism2sta_inf_chinforesults
1071  *
1072  * Handles the receipt of a Channel Info Results info frame.
1073  *
1074  * Arguments:
1075  *      wlandev         wlan device structure
1076  *      inf             ptr to info frame (contents in hfa384x order)
1077  *
1078  * Returns:
1079  *      nothing
1080  *
1081  * Side effects:
1082  *
1083  * Call context:
1084  *      interrupt
1085  */
1086 static void prism2sta_inf_chinforesults(struct wlandevice *wlandev,
1087                                         struct hfa384x_inf_frame *inf)
1088 {
1089         struct hfa384x *hw = wlandev->priv;
1090         unsigned int i, n;
1091
1092         hw->channel_info.results.scanchannels =
1093             inf->info.chinforesult.scanchannels;
1094
1095         for (i = 0, n = 0; i < HFA384x_CHINFORESULT_MAX; i++) {
1096                 struct hfa384x_ch_info_result_sub *result;
1097                 struct hfa384x_ch_info_result_sub *chinforesult;
1098                 int chan;
1099
1100                 if (!(hw->channel_info.results.scanchannels & (1 << i)))
1101                         continue;
1102
1103                 result = &inf->info.chinforesult.result[n];
1104                 chan = result->chid - 1;
1105
1106                 if (chan < 0 || chan >= HFA384x_CHINFORESULT_MAX)
1107                         continue;
1108
1109                 chinforesult = &hw->channel_info.results.result[chan];
1110                 chinforesult->chid = chan;
1111                 chinforesult->anl = result->anl;
1112                 chinforesult->pnl = result->pnl;
1113                 chinforesult->active = result->active;
1114
1115                 netdev_dbg(wlandev->netdev,
1116                            "chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n",
1117                            chan + 1,
1118                            (chinforesult->active & HFA384x_CHINFORESULT_BSSACTIVE) ?
1119                            "signal" : "noise",
1120                            chinforesult->anl,
1121                            chinforesult->pnl,
1122                            (chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE) ? 1 : 0);
1123                 n++;
1124         }
1125         atomic_set(&hw->channel_info.done, 2);
1126
1127         hw->channel_info.count = n;
1128 }
1129
1130 void prism2sta_processing_defer(struct work_struct *data)
1131 {
1132         struct hfa384x *hw = container_of(data, struct hfa384x, link_bh);
1133         struct wlandevice *wlandev = hw->wlandev;
1134         struct hfa384x_bytestr32 ssid;
1135         int result;
1136
1137         /* First let's process the auth frames */
1138         {
1139                 struct sk_buff *skb;
1140                 struct hfa384x_inf_frame *inf;
1141
1142                 while ((skb = skb_dequeue(&hw->authq))) {
1143                         inf = (struct hfa384x_inf_frame *)skb->data;
1144                         prism2sta_inf_authreq_defer(wlandev, inf);
1145                 }
1146         }
1147
1148         /* Now let's handle the linkstatus stuff */
1149         if (hw->link_status == hw->link_status_new)
1150                 return;
1151
1152         hw->link_status = hw->link_status_new;
1153
1154         switch (hw->link_status) {
1155         case HFA384x_LINK_NOTCONNECTED:
1156                 /* I'm currently assuming that this is the initial link
1157                  * state.  It should only be possible immediately
1158                  * following an Enable command.
1159                  * Response:
1160                  * Block Transmits, Ignore receives of data frames
1161                  */
1162                 netif_carrier_off(wlandev->netdev);
1163
1164                 netdev_info(wlandev->netdev, "linkstatus=NOTCONNECTED (unhandled)\n");
1165                 break;
1166
1167         case HFA384x_LINK_CONNECTED:
1168                 /* This one indicates a successful scan/join/auth/assoc.
1169                  * When we have the full MLME complement, this event will
1170                  * signify successful completion of both mlme_authenticate
1171                  * and mlme_associate.  State management will get a little
1172                  * ugly here.
1173                  * Response:
1174                  * Indicate authentication and/or association
1175                  * Enable Transmits, Receives and pass up data frames
1176                  */
1177
1178                 netif_carrier_on(wlandev->netdev);
1179
1180                 /* If we are joining a specific AP, set our
1181                  * state and reset retries
1182                  */
1183                 if (hw->join_ap == 1)
1184                         hw->join_ap = 2;
1185                 hw->join_retries = 60;
1186
1187                 /* Don't call this in monitor mode */
1188                 if (wlandev->netdev->type == ARPHRD_ETHER) {
1189                         u16 portstatus;
1190
1191                         netdev_info(wlandev->netdev, "linkstatus=CONNECTED\n");
1192
1193                         /* For non-usb devices, we can use the sync versions */
1194                         /* Collect the BSSID, and set state to allow tx */
1195
1196                         result = hfa384x_drvr_getconfig(hw,
1197                                                         HFA384x_RID_CURRENTBSSID,
1198                                                         wlandev->bssid,
1199                                                         WLAN_BSSID_LEN);
1200                         if (result) {
1201                                 netdev_dbg(wlandev->netdev,
1202                                            "getconfig(0x%02x) failed, result = %d\n",
1203                                            HFA384x_RID_CURRENTBSSID, result);
1204                                 return;
1205                         }
1206
1207                         result = hfa384x_drvr_getconfig(hw,
1208                                                         HFA384x_RID_CURRENTSSID,
1209                                                         &ssid, sizeof(ssid));
1210                         if (result) {
1211                                 netdev_dbg(wlandev->netdev,
1212                                            "getconfig(0x%02x) failed, result = %d\n",
1213                                            HFA384x_RID_CURRENTSSID, result);
1214                                 return;
1215                         }
1216                         prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid,
1217                                                 (struct p80211pstrd *)&wlandev->ssid);
1218
1219                         /* Collect the port status */
1220                         result = hfa384x_drvr_getconfig16(hw,
1221                                                           HFA384x_RID_PORTSTATUS,
1222                                                           &portstatus);
1223                         if (result) {
1224                                 netdev_dbg(wlandev->netdev,
1225                                            "getconfig(0x%02x) failed, result = %d\n",
1226                                            HFA384x_RID_PORTSTATUS, result);
1227                                 return;
1228                         }
1229                         wlandev->macmode =
1230                             (portstatus == HFA384x_PSTATUS_CONN_IBSS) ?
1231                             WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA;
1232
1233                         /* signal back up to cfg80211 layer */
1234                         prism2_connect_result(wlandev, P80211ENUM_truth_false);
1235
1236                         /* Get the ball rolling on the comms quality stuff */
1237                         prism2sta_commsqual_defer(&hw->commsqual_bh);
1238                 }
1239                 break;
1240
1241         case HFA384x_LINK_DISCONNECTED:
1242                 /* This one indicates that our association is gone.  We've
1243                  * lost connection with the AP and/or been disassociated.
1244                  * This indicates that the MAC has completely cleared it's
1245                  * associated state.  We * should send a deauth indication
1246                  * (implying disassoc) up * to the MLME.
1247                  * Response:
1248                  * Indicate Deauthentication
1249                  * Block Transmits, Ignore receives of data frames
1250                  */
1251                 if (wlandev->netdev->type == ARPHRD_ETHER)
1252                         netdev_info(wlandev->netdev,
1253                                     "linkstatus=DISCONNECTED (unhandled)\n");
1254                 wlandev->macmode = WLAN_MACMODE_NONE;
1255
1256                 netif_carrier_off(wlandev->netdev);
1257
1258                 /* signal back up to cfg80211 layer */
1259                 prism2_disconnected(wlandev);
1260
1261                 break;
1262
1263         case HFA384x_LINK_AP_CHANGE:
1264                 /* This one indicates that the MAC has decided to and
1265                  * successfully completed a change to another AP.  We
1266                  * should probably implement a reassociation indication
1267                  * in response to this one.  I'm thinking that the
1268                  * p80211 layer needs to be notified in case of
1269                  * buffering/queueing issues.  User mode also needs to be
1270                  * notified so that any BSS dependent elements can be
1271                  * updated.
1272                  * associated state.  We * should send a deauth indication
1273                  * (implying disassoc) up * to the MLME.
1274                  * Response:
1275                  * Indicate Reassociation
1276                  * Enable Transmits, Receives and pass up data frames
1277                  */
1278                 netdev_info(wlandev->netdev, "linkstatus=AP_CHANGE\n");
1279
1280                 result = hfa384x_drvr_getconfig(hw,
1281                                                 HFA384x_RID_CURRENTBSSID,
1282                                                 wlandev->bssid, WLAN_BSSID_LEN);
1283                 if (result) {
1284                         netdev_dbg(wlandev->netdev,
1285                                    "getconfig(0x%02x) failed, result = %d\n",
1286                                    HFA384x_RID_CURRENTBSSID, result);
1287                         return;
1288                 }
1289
1290                 result = hfa384x_drvr_getconfig(hw,
1291                                                 HFA384x_RID_CURRENTSSID,
1292                                                 &ssid, sizeof(ssid));
1293                 if (result) {
1294                         netdev_dbg(wlandev->netdev,
1295                                    "getconfig(0x%02x) failed, result = %d\n",
1296                                    HFA384x_RID_CURRENTSSID, result);
1297                         return;
1298                 }
1299                 prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid,
1300                                         (struct p80211pstrd *)&wlandev->ssid);
1301
1302                 hw->link_status = HFA384x_LINK_CONNECTED;
1303                 netif_carrier_on(wlandev->netdev);
1304
1305                 /* signal back up to cfg80211 layer */
1306                 prism2_roamed(wlandev);
1307
1308                 break;
1309
1310         case HFA384x_LINK_AP_OUTOFRANGE:
1311                 /* This one indicates that the MAC has decided that the
1312                  * AP is out of range, but hasn't found a better candidate
1313                  * so the MAC maintains its "associated" state in case
1314                  * we get back in range.  We should block transmits and
1315                  * receives in this state.  Do we need an indication here?
1316                  * Probably not since a polling user-mode element would
1317                  * get this status from p2PortStatus(FD40). What about
1318                  * p80211?
1319                  * Response:
1320                  * Block Transmits, Ignore receives of data frames
1321                  */
1322                 netdev_info(wlandev->netdev, "linkstatus=AP_OUTOFRANGE (unhandled)\n");
1323
1324                 netif_carrier_off(wlandev->netdev);
1325
1326                 break;
1327
1328         case HFA384x_LINK_AP_INRANGE:
1329                 /* This one indicates that the MAC has decided that the
1330                  * AP is back in range.  We continue working with our
1331                  * existing association.
1332                  * Response:
1333                  * Enable Transmits, Receives and pass up data frames
1334                  */
1335                 netdev_info(wlandev->netdev, "linkstatus=AP_INRANGE\n");
1336
1337                 hw->link_status = HFA384x_LINK_CONNECTED;
1338                 netif_carrier_on(wlandev->netdev);
1339
1340                 break;
1341
1342         case HFA384x_LINK_ASSOCFAIL:
1343                 /* This one is actually a peer to CONNECTED.  We've
1344                  * requested a join for a given SSID and optionally BSSID.
1345                  * We can use this one to indicate authentication and
1346                  * association failures.  The trick is going to be
1347                  * 1) identifying the failure, and 2) state management.
1348                  * Response:
1349                  * Disable Transmits, Ignore receives of data frames
1350                  */
1351                 if (hw->join_ap && --hw->join_retries > 0) {
1352                         struct hfa384x_join_request_data joinreq;
1353
1354                         joinreq = hw->joinreq;
1355                         /* Send the join request */
1356                         hfa384x_drvr_setconfig(hw,
1357                                                HFA384x_RID_JOINREQUEST,
1358                                                &joinreq,
1359                                                HFA384x_RID_JOINREQUEST_LEN);
1360                         netdev_info(wlandev->netdev,
1361                                     "linkstatus=ASSOCFAIL (re-submitting join)\n");
1362                 } else {
1363                         netdev_info(wlandev->netdev, "linkstatus=ASSOCFAIL (unhandled)\n");
1364                 }
1365
1366                 netif_carrier_off(wlandev->netdev);
1367
1368                 /* signal back up to cfg80211 layer */
1369                 prism2_connect_result(wlandev, P80211ENUM_truth_true);
1370
1371                 break;
1372
1373         default:
1374                 /* This is bad, IO port problems? */
1375                 netdev_warn(wlandev->netdev,
1376                             "unknown linkstatus=0x%02x\n", hw->link_status);
1377                 return;
1378         }
1379
1380         wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED);
1381 }
1382
1383 /*
1384  * prism2sta_inf_linkstatus
1385  *
1386  * Handles the receipt of a Link Status info frame.
1387  *
1388  * Arguments:
1389  *      wlandev         wlan device structure
1390  *      inf             ptr to info frame (contents in hfa384x order)
1391  *
1392  * Returns:
1393  *      nothing
1394  *
1395  * Side effects:
1396  *
1397  * Call context:
1398  *      interrupt
1399  */
1400 static void prism2sta_inf_linkstatus(struct wlandevice *wlandev,
1401                                      struct hfa384x_inf_frame *inf)
1402 {
1403         struct hfa384x *hw = wlandev->priv;
1404
1405         hw->link_status_new = le16_to_cpu(inf->info.linkstatus.linkstatus);
1406
1407         schedule_work(&hw->link_bh);
1408 }
1409
1410 /*
1411  * prism2sta_inf_assocstatus
1412  *
1413  * Handles the receipt of an Association Status info frame. Should
1414  * be present in APs only.
1415  *
1416  * Arguments:
1417  *      wlandev         wlan device structure
1418  *      inf             ptr to info frame (contents in hfa384x order)
1419  *
1420  * Returns:
1421  *      nothing
1422  *
1423  * Side effects:
1424  *
1425  * Call context:
1426  *      interrupt
1427  */
1428 static void prism2sta_inf_assocstatus(struct wlandevice *wlandev,
1429                                       struct hfa384x_inf_frame *inf)
1430 {
1431         struct hfa384x *hw = wlandev->priv;
1432         struct hfa384x_assoc_status rec;
1433         int i;
1434
1435         memcpy(&rec, &inf->info.assocstatus, sizeof(rec));
1436         le16_to_cpus(&rec.assocstatus);
1437         le16_to_cpus(&rec.reason);
1438
1439         /*
1440          * Find the address in the list of authenticated stations.
1441          * If it wasn't found, then this address has not been previously
1442          * authenticated and something weird has happened if this is
1443          * anything other than an "authentication failed" message.
1444          * If the address was found, then set the "associated" flag for
1445          * that station, based on whether the station is associating or
1446          * losing its association.  Something weird has also happened
1447          * if we find the address in the list of authenticated stations
1448          * but we are getting an "authentication failed" message.
1449          */
1450
1451         for (i = 0; i < hw->authlist.cnt; i++)
1452                 if (ether_addr_equal(rec.sta_addr, hw->authlist.addr[i]))
1453                         break;
1454
1455         if (i >= hw->authlist.cnt) {
1456                 if (rec.assocstatus != HFA384x_ASSOCSTATUS_AUTHFAIL)
1457                         netdev_warn(wlandev->netdev,
1458                                     "assocstatus info frame received for non-authenticated station.\n");
1459         } else {
1460                 hw->authlist.assoc[i] =
1461                     (rec.assocstatus == HFA384x_ASSOCSTATUS_STAASSOC ||
1462                      rec.assocstatus == HFA384x_ASSOCSTATUS_REASSOC);
1463
1464                 if (rec.assocstatus == HFA384x_ASSOCSTATUS_AUTHFAIL)
1465                         netdev_warn(wlandev->netdev,
1466                                     "authfail assocstatus info frame received for authenticated station.\n");
1467         }
1468 }
1469
1470 /*
1471  * prism2sta_inf_authreq
1472  *
1473  * Handles the receipt of an Authentication Request info frame. Should
1474  * be present in APs only.
1475  *
1476  * Arguments:
1477  *      wlandev         wlan device structure
1478  *      inf             ptr to info frame (contents in hfa384x order)
1479  *
1480  * Returns:
1481  *      nothing
1482  *
1483  * Side effects:
1484  *
1485  * Call context:
1486  *      interrupt
1487  *
1488  */
1489 static void prism2sta_inf_authreq(struct wlandevice *wlandev,
1490                                   struct hfa384x_inf_frame *inf)
1491 {
1492         struct hfa384x *hw = wlandev->priv;
1493         struct sk_buff *skb;
1494
1495         skb = dev_alloc_skb(sizeof(*inf));
1496         if (skb) {
1497                 skb_put(skb, sizeof(*inf));
1498                 memcpy(skb->data, inf, sizeof(*inf));
1499                 skb_queue_tail(&hw->authq, skb);
1500                 schedule_work(&hw->link_bh);
1501         }
1502 }
1503
1504 static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev,
1505                                         struct hfa384x_inf_frame *inf)
1506 {
1507         struct hfa384x *hw = wlandev->priv;
1508         struct hfa384x_authenticate_station_data rec;
1509
1510         int i, added, result, cnt;
1511         u8 *addr;
1512
1513         /*
1514          * Build the AuthenticateStation record.  Initialize it for denying
1515          * authentication.
1516          */
1517
1518         ether_addr_copy(rec.address, inf->info.authreq.sta_addr);
1519         rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure);
1520
1521         /*
1522          * Authenticate based on the access mode.
1523          */
1524
1525         switch (hw->accessmode) {
1526         case WLAN_ACCESS_NONE:
1527
1528                 /*
1529                  * Deny all new authentications.  However, if a station
1530                  * is ALREADY authenticated, then accept it.
1531                  */
1532
1533                 for (i = 0; i < hw->authlist.cnt; i++)
1534                         if (ether_addr_equal(rec.address,
1535                                              hw->authlist.addr[i])) {
1536                                 rec.status = cpu_to_le16(P80211ENUM_status_successful);
1537                                 break;
1538                         }
1539
1540                 break;
1541
1542         case WLAN_ACCESS_ALL:
1543
1544                 /*
1545                  * Allow all authentications.
1546                  */
1547
1548                 rec.status = cpu_to_le16(P80211ENUM_status_successful);
1549                 break;
1550
1551         case WLAN_ACCESS_ALLOW:
1552
1553                 /*
1554                  * Only allow the authentication if the MAC address
1555                  * is in the list of allowed addresses.
1556                  *
1557                  * Since this is the interrupt handler, we may be here
1558                  * while the access list is in the middle of being
1559                  * updated.  Choose the list which is currently okay.
1560                  * See "prism2mib_priv_accessallow()" for details.
1561                  */
1562
1563                 if (hw->allow.modify == 0) {
1564                         cnt = hw->allow.cnt;
1565                         addr = hw->allow.addr[0];
1566                 } else {
1567                         cnt = hw->allow.cnt1;
1568                         addr = hw->allow.addr1[0];
1569                 }
1570
1571                 for (i = 0; i < cnt; i++, addr += ETH_ALEN)
1572                         if (ether_addr_equal(rec.address, addr)) {
1573                                 rec.status = cpu_to_le16(P80211ENUM_status_successful);
1574                                 break;
1575                         }
1576
1577                 break;
1578
1579         case WLAN_ACCESS_DENY:
1580
1581                 /*
1582                  * Allow the authentication UNLESS the MAC address is
1583                  * in the list of denied addresses.
1584                  *
1585                  * Since this is the interrupt handler, we may be here
1586                  * while the access list is in the middle of being
1587                  * updated.  Choose the list which is currently okay.
1588                  * See "prism2mib_priv_accessdeny()" for details.
1589                  */
1590
1591                 if (hw->deny.modify == 0) {
1592                         cnt = hw->deny.cnt;
1593                         addr = hw->deny.addr[0];
1594                 } else {
1595                         cnt = hw->deny.cnt1;
1596                         addr = hw->deny.addr1[0];
1597                 }
1598
1599                 rec.status = cpu_to_le16(P80211ENUM_status_successful);
1600
1601                 for (i = 0; i < cnt; i++, addr += ETH_ALEN)
1602                         if (ether_addr_equal(rec.address, addr)) {
1603                                 rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure);
1604                                 break;
1605                         }
1606
1607                 break;
1608         }
1609
1610         /*
1611          * If the authentication is okay, then add the MAC address to the
1612          * list of authenticated stations.  Don't add the address if it
1613          * is already in the list. (802.11b does not seem to disallow
1614          * a station from issuing an authentication request when the
1615          * station is already authenticated. Does this sort of thing
1616          * ever happen?  We might as well do the check just in case.)
1617          */
1618
1619         added = 0;
1620
1621         if (rec.status == cpu_to_le16(P80211ENUM_status_successful)) {
1622                 for (i = 0; i < hw->authlist.cnt; i++)
1623                         if (ether_addr_equal(rec.address,
1624                                              hw->authlist.addr[i]))
1625                                 break;
1626
1627                 if (i >= hw->authlist.cnt) {
1628                         if (hw->authlist.cnt >= WLAN_AUTH_MAX) {
1629                                 rec.status = cpu_to_le16(P80211ENUM_status_ap_full);
1630                         } else {
1631                                 ether_addr_copy(hw->authlist.addr[hw->authlist.cnt],
1632                                                 rec.address);
1633                                 hw->authlist.cnt++;
1634                                 added = 1;
1635                         }
1636                 }
1637         }
1638
1639         /*
1640          * Send back the results of the authentication.  If this doesn't work,
1641          * then make sure to remove the address from the authenticated list if
1642          * it was added.
1643          */
1644
1645         rec.algorithm = inf->info.authreq.algorithm;
1646
1647         result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA,
1648                                         &rec, sizeof(rec));
1649         if (result) {
1650                 if (added)
1651                         hw->authlist.cnt--;
1652                 netdev_err(wlandev->netdev,
1653                            "setconfig(authenticatestation) failed, result=%d\n",
1654                            result);
1655         }
1656 }
1657
1658 /*
1659  * prism2sta_inf_psusercnt
1660  *
1661  * Handles the receipt of a PowerSaveUserCount info frame. Should
1662  * be present in APs only.
1663  *
1664  * Arguments:
1665  *      wlandev         wlan device structure
1666  *      inf             ptr to info frame (contents in hfa384x order)
1667  *
1668  * Returns:
1669  *      nothing
1670  *
1671  * Side effects:
1672  *
1673  * Call context:
1674  *      interrupt
1675  */
1676 static void prism2sta_inf_psusercnt(struct wlandevice *wlandev,
1677                                     struct hfa384x_inf_frame *inf)
1678 {
1679         struct hfa384x *hw = wlandev->priv;
1680
1681         hw->psusercount = le16_to_cpu(inf->info.psusercnt.usercnt);
1682 }
1683
1684 /*
1685  * prism2sta_ev_info
1686  *
1687  * Handles the Info event.
1688  *
1689  * Arguments:
1690  *      wlandev         wlan device structure
1691  *      inf             ptr to a generic info frame
1692  *
1693  * Returns:
1694  *      nothing
1695  *
1696  * Side effects:
1697  *
1698  * Call context:
1699  *      interrupt
1700  */
1701 void prism2sta_ev_info(struct wlandevice *wlandev,
1702                        struct hfa384x_inf_frame *inf)
1703 {
1704         le16_to_cpus(&inf->infotype);
1705         /* Dispatch */
1706         switch (inf->infotype) {
1707         case HFA384x_IT_HANDOVERADDR:
1708                 netdev_dbg(wlandev->netdev,
1709                            "received infoframe:HANDOVER (unhandled)\n");
1710                 break;
1711         case HFA384x_IT_COMMTALLIES:
1712                 prism2sta_inf_tallies(wlandev, inf);
1713                 break;
1714         case HFA384x_IT_HOSTSCANRESULTS:
1715                 prism2sta_inf_hostscanresults(wlandev, inf);
1716                 break;
1717         case HFA384x_IT_SCANRESULTS:
1718                 prism2sta_inf_scanresults(wlandev, inf);
1719                 break;
1720         case HFA384x_IT_CHINFORESULTS:
1721                 prism2sta_inf_chinforesults(wlandev, inf);
1722                 break;
1723         case HFA384x_IT_LINKSTATUS:
1724                 prism2sta_inf_linkstatus(wlandev, inf);
1725                 break;
1726         case HFA384x_IT_ASSOCSTATUS:
1727                 prism2sta_inf_assocstatus(wlandev, inf);
1728                 break;
1729         case HFA384x_IT_AUTHREQ:
1730                 prism2sta_inf_authreq(wlandev, inf);
1731                 break;
1732         case HFA384x_IT_PSUSERCNT:
1733                 prism2sta_inf_psusercnt(wlandev, inf);
1734                 break;
1735         case HFA384x_IT_KEYIDCHANGED:
1736                 netdev_warn(wlandev->netdev, "Unhandled IT_KEYIDCHANGED\n");
1737                 break;
1738         case HFA384x_IT_ASSOCREQ:
1739                 netdev_warn(wlandev->netdev, "Unhandled IT_ASSOCREQ\n");
1740                 break;
1741         case HFA384x_IT_MICFAILURE:
1742                 netdev_warn(wlandev->netdev, "Unhandled IT_MICFAILURE\n");
1743                 break;
1744         default:
1745                 netdev_warn(wlandev->netdev,
1746                             "Unknown info type=0x%02x\n", inf->infotype);
1747                 break;
1748         }
1749 }
1750
1751 /*
1752  * prism2sta_ev_tx
1753  *
1754  * Handles the Tx event.
1755  *
1756  * Arguments:
1757  *      wlandev         wlan device structure
1758  *      status          tx frame status word
1759  * Returns:
1760  *      nothing
1761  *
1762  * Side effects:
1763  *
1764  * Call context:
1765  *      interrupt
1766  */
1767 void prism2sta_ev_tx(struct wlandevice *wlandev, u16 status)
1768 {
1769         netdev_dbg(wlandev->netdev, "Tx Complete, status=0x%04x\n", status);
1770         /* update linux network stats */
1771         wlandev->netdev->stats.tx_packets++;
1772 }
1773
1774 /*
1775  * prism2sta_ev_alloc
1776  *
1777  * Handles the Alloc event.
1778  *
1779  * Arguments:
1780  *      wlandev         wlan device structure
1781  *
1782  * Returns:
1783  *      nothing
1784  *
1785  * Side effects:
1786  *
1787  * Call context:
1788  *      interrupt
1789  */
1790 void prism2sta_ev_alloc(struct wlandevice *wlandev)
1791 {
1792         netif_wake_queue(wlandev->netdev);
1793 }
1794
1795 /*
1796  * create_wlan
1797  *
1798  * Called at module init time.  This creates the struct wlandevice structure
1799  * and initializes it with relevant bits.
1800  *
1801  * Arguments:
1802  *      none
1803  *
1804  * Returns:
1805  *      the created struct wlandevice structure.
1806  *
1807  * Side effects:
1808  *      also allocates the priv/hw structures.
1809  *
1810  * Call context:
1811  *      process thread
1812  *
1813  */
1814 static struct wlandevice *create_wlan(void)
1815 {
1816         struct wlandevice *wlandev = NULL;
1817         struct hfa384x *hw = NULL;
1818
1819         /* Alloc our structures */
1820         wlandev = kzalloc(sizeof(*wlandev), GFP_KERNEL);
1821         hw = kzalloc(sizeof(*hw), GFP_KERNEL);
1822
1823         if (!wlandev || !hw) {
1824                 kfree(wlandev);
1825                 kfree(hw);
1826                 return NULL;
1827         }
1828
1829         /* Initialize the network device object. */
1830         wlandev->nsdname = dev_info;
1831         wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING;
1832         wlandev->priv = hw;
1833         wlandev->open = prism2sta_open;
1834         wlandev->close = prism2sta_close;
1835         wlandev->reset = prism2sta_reset;
1836         wlandev->txframe = prism2sta_txframe;
1837         wlandev->mlmerequest = prism2sta_mlmerequest;
1838         wlandev->set_multicast_list = prism2sta_setmulticast;
1839         wlandev->tx_timeout = hfa384x_tx_timeout;
1840
1841         wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT | P80211_NSDCAP_AUTOJOIN;
1842
1843         /* Initialize the device private data structure. */
1844         hw->dot11_desired_bss_type = 1;
1845
1846         return wlandev;
1847 }
1848
1849 void prism2sta_commsqual_defer(struct work_struct *data)
1850 {
1851         struct hfa384x *hw = container_of(data, struct hfa384x, commsqual_bh);
1852         struct wlandevice *wlandev = hw->wlandev;
1853         struct hfa384x_bytestr32 ssid;
1854         struct p80211msg_dot11req_mibget msg;
1855         struct p80211item_uint32 *mibitem = (struct p80211item_uint32 *)
1856                                                 &msg.mibattribute.data;
1857         int result = 0;
1858
1859         if (hw->wlandev->hwremoved)
1860                 return;
1861
1862         /* we don't care if we're in AP mode */
1863         if ((wlandev->macmode == WLAN_MACMODE_NONE) ||
1864             (wlandev->macmode == WLAN_MACMODE_ESS_AP)) {
1865                 return;
1866         }
1867
1868         /* It only makes sense to poll these in non-IBSS */
1869         if (wlandev->macmode != WLAN_MACMODE_IBSS_STA) {
1870                 result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DBMCOMMSQUALITY,
1871                                                 &hw->qual, HFA384x_RID_DBMCOMMSQUALITY_LEN);
1872
1873                 if (result) {
1874                         netdev_err(wlandev->netdev, "error fetching commsqual\n");
1875                         return;
1876                 }
1877
1878                 netdev_dbg(wlandev->netdev, "commsqual %d %d %d\n",
1879                            le16_to_cpu(hw->qual.cq_curr_bss),
1880                            le16_to_cpu(hw->qual.asl_curr_bss),
1881                            le16_to_cpu(hw->qual.anl_curr_fc));
1882         }
1883
1884         /* Get the signal rate */
1885         msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
1886         mibitem->did = DIDMIB_P2_MAC_CURRENTTXRATE;
1887         result = p80211req_dorequest(wlandev, (u8 *)&msg);
1888
1889         if (result) {
1890                 netdev_dbg(wlandev->netdev,
1891                            "get signal rate failed, result = %d\n", result);
1892                 return;
1893         }
1894
1895         switch (mibitem->data) {
1896         case HFA384x_RATEBIT_1:
1897                 hw->txrate = 10;
1898                 break;
1899         case HFA384x_RATEBIT_2:
1900                 hw->txrate = 20;
1901                 break;
1902         case HFA384x_RATEBIT_5dot5:
1903                 hw->txrate = 55;
1904                 break;
1905         case HFA384x_RATEBIT_11:
1906                 hw->txrate = 110;
1907                 break;
1908         default:
1909                 netdev_dbg(wlandev->netdev, "Bad ratebit (%d)\n",
1910                            mibitem->data);
1911         }
1912
1913         /* Lastly, we need to make sure the BSSID didn't change on us */
1914         result = hfa384x_drvr_getconfig(hw,
1915                                         HFA384x_RID_CURRENTBSSID,
1916                                         wlandev->bssid, WLAN_BSSID_LEN);
1917         if (result) {
1918                 netdev_dbg(wlandev->netdev,
1919                            "getconfig(0x%02x) failed, result = %d\n",
1920                            HFA384x_RID_CURRENTBSSID, result);
1921                 return;
1922         }
1923
1924         result = hfa384x_drvr_getconfig(hw,
1925                                         HFA384x_RID_CURRENTSSID,
1926                                         &ssid, sizeof(ssid));
1927         if (result) {
1928                 netdev_dbg(wlandev->netdev,
1929                            "getconfig(0x%02x) failed, result = %d\n",
1930                            HFA384x_RID_CURRENTSSID, result);
1931                 return;
1932         }
1933         prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid,
1934                                 (struct p80211pstrd *)&wlandev->ssid);
1935
1936         /* Reschedule timer */
1937         mod_timer(&hw->commsqual_timer, jiffies + HZ);
1938 }
1939
1940 void prism2sta_commsqual_timer(struct timer_list *t)
1941 {
1942         struct hfa384x *hw = from_timer(hw, t, commsqual_timer);
1943
1944         schedule_work(&hw->commsqual_bh);
1945 }