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