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