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