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