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