linux/drivers/staging/wlan-ng/prism2mgmt.c
<<
>>
Prefs
   1/* src/prism2/driver/prism2mgmt.c
   2 *
   3 * Management request handler functions.
   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 * The functions in this file handle management requests sent from
  48 * user mode.
  49 *
  50 * Most of these functions have two separate blocks of code that are
  51 * conditional on whether this is a station or an AP.  This is used
  52 * to separate out the STA and AP responses to these management primitives.
  53 * It's a choice (good, bad, indifferent?) to have the code in the same
  54 * place so it's clear that the same primitive is implemented in both
  55 * cases but has different behavior.
  56 *
  57 * --------------------------------------------------------------------
  58 */
  59
  60#include <linux/if_arp.h>
  61#include <linux/module.h>
  62#include <linux/kernel.h>
  63#include <linux/wait.h>
  64#include <linux/sched.h>
  65#include <linux/types.h>
  66#include <linux/wireless.h>
  67#include <linux/netdevice.h>
  68#include <linux/delay.h>
  69#include <linux/io.h>
  70#include <asm/byteorder.h>
  71#include <linux/random.h>
  72#include <linux/usb.h>
  73#include <linux/bitops.h>
  74
  75#include "p80211types.h"
  76#include "p80211hdr.h"
  77#include "p80211mgmt.h"
  78#include "p80211conv.h"
  79#include "p80211msg.h"
  80#include "p80211netdev.h"
  81#include "p80211metadef.h"
  82#include "p80211metastruct.h"
  83#include "hfa384x.h"
  84#include "prism2mgmt.h"
  85
  86/* Converts 802.11 format rate specifications to prism2 */
  87#define p80211rate_to_p2bit(n)  ((((n) & ~BIT(7)) == 2) ? BIT(0) :  \
  88                                 (((n) & ~BIT(7)) == 4) ? BIT(1) : \
  89                                 (((n) & ~BIT(7)) == 11) ? BIT(2) : \
  90                                 (((n) & ~BIT(7)) == 22) ? BIT(3) : 0)
  91
  92/*----------------------------------------------------------------
  93 * prism2mgmt_scan
  94 *
  95 * Initiate a scan for BSSs.
  96 *
  97 * This function corresponds to MLME-scan.request and part of
  98 * MLME-scan.confirm.  As far as I can tell in the standard, there
  99 * are no restrictions on when a scan.request may be issued.  We have
 100 * to handle in whatever state the driver/MAC happen to be.
 101 *
 102 * Arguments:
 103 *      wlandev         wlan device structure
 104 *      msgp            ptr to msg buffer
 105 *
 106 * Returns:
 107 *      0       success and done
 108 *      <0      success, but we're waiting for something to finish.
 109 *      >0      an error occurred while handling the message.
 110 * Side effects:
 111 *
 112 * Call context:
 113 *      process thread  (usually)
 114 *      interrupt
 115 *----------------------------------------------------------------
 116 */
 117int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp)
 118{
 119        int result = 0;
 120        struct hfa384x *hw = wlandev->priv;
 121        struct p80211msg_dot11req_scan *msg = msgp;
 122        u16 roamingmode, word;
 123        int i, timeout;
 124        int istmpenable = 0;
 125
 126        struct hfa384x_host_scan_request_data scanreq;
 127
 128        /* gatekeeper check */
 129        if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
 130                                     hw->ident_sta_fw.minor,
 131                                     hw->ident_sta_fw.variant) <
 132            HFA384x_FIRMWARE_VERSION(1, 3, 2)) {
 133                netdev_err(wlandev->netdev,
 134                           "HostScan not supported with current firmware (<1.3.2).\n");
 135                result = 1;
 136                msg->resultcode.data = P80211ENUM_resultcode_not_supported;
 137                goto exit;
 138        }
 139
 140        memset(&scanreq, 0, sizeof(scanreq));
 141
 142        /* save current roaming mode */
 143        result = hfa384x_drvr_getconfig16(hw,
 144                                          HFA384x_RID_CNFROAMINGMODE,
 145                                          &roamingmode);
 146        if (result) {
 147                netdev_err(wlandev->netdev,
 148                           "getconfig(ROAMMODE) failed. result=%d\n", result);
 149                msg->resultcode.data =
 150                    P80211ENUM_resultcode_implementation_failure;
 151                goto exit;
 152        }
 153
 154        /* drop into mode 3 for the scan */
 155        result = hfa384x_drvr_setconfig16(hw,
 156                                          HFA384x_RID_CNFROAMINGMODE,
 157                                          HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
 158        if (result) {
 159                netdev_err(wlandev->netdev,
 160                           "setconfig(ROAMINGMODE) failed. result=%d\n",
 161                           result);
 162                msg->resultcode.data =
 163                    P80211ENUM_resultcode_implementation_failure;
 164                goto exit;
 165        }
 166
 167        /* active or passive? */
 168        if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
 169                                     hw->ident_sta_fw.minor,
 170                                     hw->ident_sta_fw.variant) >
 171            HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
 172                if (msg->scantype.data != P80211ENUM_scantype_active)
 173                        word = msg->maxchanneltime.data;
 174                else
 175                        word = 0;
 176
 177                result =
 178                    hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL,
 179                                             word);
 180                if (result) {
 181                        netdev_warn(wlandev->netdev,
 182                                    "Passive scan not supported with current firmware.  (<1.5.1)\n");
 183                }
 184        }
 185
 186        /* set up the txrate to be 2MBPS. Should be fastest basicrate... */
 187        word = HFA384x_RATEBIT_2;
 188        scanreq.tx_rate = cpu_to_le16(word);
 189
 190        /* set up the channel list */
 191        word = 0;
 192        for (i = 0; i < msg->channellist.data.len; i++) {
 193                u8 channel = msg->channellist.data.data[i];
 194
 195                if (channel > 14)
 196                        continue;
 197                /* channel 1 is BIT 0 ... channel 14 is BIT 13 */
 198                word |= (1 << (channel - 1));
 199        }
 200        scanreq.channel_list = cpu_to_le16(word);
 201
 202        /* set up the ssid, if present. */
 203        scanreq.ssid.len = cpu_to_le16(msg->ssid.data.len);
 204        memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len);
 205
 206        /* Enable the MAC port if it's not already enabled  */
 207        result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word);
 208        if (result) {
 209                netdev_err(wlandev->netdev,
 210                           "getconfig(PORTSTATUS) failed. result=%d\n", result);
 211                msg->resultcode.data =
 212                    P80211ENUM_resultcode_implementation_failure;
 213                goto exit;
 214        }
 215        if (word == HFA384x_PORTSTATUS_DISABLED) {
 216                __le16 wordbuf[17];
 217
 218                result = hfa384x_drvr_setconfig16(hw,
 219                                        HFA384x_RID_CNFROAMINGMODE,
 220                                        HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
 221                if (result) {
 222                        netdev_err(wlandev->netdev,
 223                                   "setconfig(ROAMINGMODE) failed. result=%d\n",
 224                                   result);
 225                        msg->resultcode.data =
 226                            P80211ENUM_resultcode_implementation_failure;
 227                        goto exit;
 228                }
 229                /* Construct a bogus SSID and assign it to OwnSSID and
 230                 * DesiredSSID
 231                 */
 232                wordbuf[0] = cpu_to_le16(WLAN_SSID_MAXLEN);
 233                get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN);
 234                result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
 235                                                wordbuf,
 236                                                HFA384x_RID_CNFOWNSSID_LEN);
 237                if (result) {
 238                        netdev_err(wlandev->netdev, "Failed to set OwnSSID.\n");
 239                        msg->resultcode.data =
 240                            P80211ENUM_resultcode_implementation_failure;
 241                        goto exit;
 242                }
 243                result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
 244                                                wordbuf,
 245                                                HFA384x_RID_CNFDESIREDSSID_LEN);
 246                if (result) {
 247                        netdev_err(wlandev->netdev,
 248                                   "Failed to set DesiredSSID.\n");
 249                        msg->resultcode.data =
 250                            P80211ENUM_resultcode_implementation_failure;
 251                        goto exit;
 252                }
 253                /* bsstype */
 254                result = hfa384x_drvr_setconfig16(hw,
 255                                                  HFA384x_RID_CNFPORTTYPE,
 256                                                  HFA384x_PORTTYPE_IBSS);
 257                if (result) {
 258                        netdev_err(wlandev->netdev,
 259                                   "Failed to set CNFPORTTYPE.\n");
 260                        msg->resultcode.data =
 261                            P80211ENUM_resultcode_implementation_failure;
 262                        goto exit;
 263                }
 264                /* ibss options */
 265                result = hfa384x_drvr_setconfig16(hw,
 266                                        HFA384x_RID_CREATEIBSS,
 267                                        HFA384x_CREATEIBSS_JOINCREATEIBSS);
 268                if (result) {
 269                        netdev_err(wlandev->netdev,
 270                                   "Failed to set CREATEIBSS.\n");
 271                        msg->resultcode.data =
 272                            P80211ENUM_resultcode_implementation_failure;
 273                        goto exit;
 274                }
 275                result = hfa384x_drvr_enable(hw, 0);
 276                if (result) {
 277                        netdev_err(wlandev->netdev,
 278                                   "drvr_enable(0) failed. result=%d\n",
 279                                   result);
 280                        msg->resultcode.data =
 281                            P80211ENUM_resultcode_implementation_failure;
 282                        goto exit;
 283                }
 284                istmpenable = 1;
 285        }
 286
 287        /* Figure out our timeout first Kus, then HZ */
 288        timeout = msg->channellist.data.len * msg->maxchanneltime.data;
 289        timeout = (timeout * HZ) / 1000;
 290
 291        /* Issue the scan request */
 292        hw->scanflag = 0;
 293
 294        result = hfa384x_drvr_setconfig(hw,
 295                                        HFA384x_RID_HOSTSCAN, &scanreq,
 296                                        sizeof(scanreq));
 297        if (result) {
 298                netdev_err(wlandev->netdev,
 299                           "setconfig(SCANREQUEST) failed. result=%d\n",
 300                           result);
 301                msg->resultcode.data =
 302                    P80211ENUM_resultcode_implementation_failure;
 303                goto exit;
 304        }
 305
 306        /* sleep until info frame arrives */
 307        wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout);
 308
 309        msg->numbss.status = P80211ENUM_msgitem_status_data_ok;
 310        if (hw->scanflag == -1)
 311                hw->scanflag = 0;
 312
 313        msg->numbss.data = hw->scanflag;
 314
 315        hw->scanflag = 0;
 316
 317        /* Disable port if we temporarily enabled it. */
 318        if (istmpenable) {
 319                result = hfa384x_drvr_disable(hw, 0);
 320                if (result) {
 321                        netdev_err(wlandev->netdev,
 322                                   "drvr_disable(0) failed. result=%d\n",
 323                                   result);
 324                        msg->resultcode.data =
 325                            P80211ENUM_resultcode_implementation_failure;
 326                        goto exit;
 327                }
 328        }
 329
 330        /* restore original roaming mode */
 331        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE,
 332                                          roamingmode);
 333        if (result) {
 334                netdev_err(wlandev->netdev,
 335                           "setconfig(ROAMMODE) failed. result=%d\n", result);
 336                msg->resultcode.data =
 337                    P80211ENUM_resultcode_implementation_failure;
 338                goto exit;
 339        }
 340
 341        result = 0;
 342        msg->resultcode.data = P80211ENUM_resultcode_success;
 343
 344exit:
 345        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 346
 347        return result;
 348}
 349
 350/*----------------------------------------------------------------
 351 * prism2mgmt_scan_results
 352 *
 353 * Retrieve the BSS description for one of the BSSs identified in
 354 * a scan.
 355 *
 356 * Arguments:
 357 *      wlandev         wlan device structure
 358 *      msgp            ptr to msg buffer
 359 *
 360 * Returns:
 361 *      0       success and done
 362 *      <0      success, but we're waiting for something to finish.
 363 *      >0      an error occurred while handling the message.
 364 * Side effects:
 365 *
 366 * Call context:
 367 *      process thread  (usually)
 368 *      interrupt
 369 *----------------------------------------------------------------
 370 */
 371int prism2mgmt_scan_results(struct wlandevice *wlandev, void *msgp)
 372{
 373        int result = 0;
 374        struct p80211msg_dot11req_scan_results *req;
 375        struct hfa384x *hw = wlandev->priv;
 376        struct hfa384x_hscan_result_sub *item = NULL;
 377
 378        int count;
 379
 380        req = msgp;
 381
 382        req->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 383
 384        if (!hw->scanresults) {
 385                netdev_err(wlandev->netdev,
 386                           "dot11req_scan_results can only be used after a successful dot11req_scan.\n");
 387                result = 2;
 388                req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
 389                goto exit;
 390        }
 391
 392        count = (hw->scanresults->framelen - 3) / 32;
 393        if (count > HFA384x_SCANRESULT_MAX)
 394                count = HFA384x_SCANRESULT_MAX;
 395
 396        if (req->bssindex.data >= count) {
 397                netdev_dbg(wlandev->netdev,
 398                           "requested index (%d) out of range (%d)\n",
 399                           req->bssindex.data, count);
 400                result = 2;
 401                req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
 402                goto exit;
 403        }
 404
 405        item = &(hw->scanresults->info.hscanresult.result[req->bssindex.data]);
 406        /* signal and noise */
 407        req->signal.status = P80211ENUM_msgitem_status_data_ok;
 408        req->noise.status = P80211ENUM_msgitem_status_data_ok;
 409        req->signal.data = le16_to_cpu(item->sl);
 410        req->noise.data = le16_to_cpu(item->anl);
 411
 412        /* BSSID */
 413        req->bssid.status = P80211ENUM_msgitem_status_data_ok;
 414        req->bssid.data.len = WLAN_BSSID_LEN;
 415        memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN);
 416
 417        /* SSID */
 418        req->ssid.status = P80211ENUM_msgitem_status_data_ok;
 419        req->ssid.data.len = le16_to_cpu(item->ssid.len);
 420        req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN);
 421        memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);
 422
 423        /* supported rates */
 424        for (count = 0; count < 10; count++)
 425                if (item->supprates[count] == 0)
 426                        break;
 427
 428#define REQBASICRATE(N) \
 429        do { \
 430                if ((count >= N) && DOT11_RATE5_ISBASIC_GET( \
 431                        item->supprates[(N) - 1])) { \
 432                        req->basicrate ## N .data = item->supprates[(N) - 1]; \
 433                        req->basicrate ## N .status = \
 434                                P80211ENUM_msgitem_status_data_ok; \
 435                } \
 436        } while (0)
 437
 438        REQBASICRATE(1);
 439        REQBASICRATE(2);
 440        REQBASICRATE(3);
 441        REQBASICRATE(4);
 442        REQBASICRATE(5);
 443        REQBASICRATE(6);
 444        REQBASICRATE(7);
 445        REQBASICRATE(8);
 446
 447#define REQSUPPRATE(N) \
 448        do { \
 449                if (count >= N) { \
 450                        req->supprate ## N .data = item->supprates[(N) - 1]; \
 451                        req->supprate ## N .status = \
 452                                P80211ENUM_msgitem_status_data_ok; \
 453                } \
 454        } while (0)
 455
 456        REQSUPPRATE(1);
 457        REQSUPPRATE(2);
 458        REQSUPPRATE(3);
 459        REQSUPPRATE(4);
 460        REQSUPPRATE(5);
 461        REQSUPPRATE(6);
 462        REQSUPPRATE(7);
 463        REQSUPPRATE(8);
 464
 465        /* beacon period */
 466        req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok;
 467        req->beaconperiod.data = le16_to_cpu(item->bcnint);
 468
 469        /* timestamps */
 470        req->timestamp.status = P80211ENUM_msgitem_status_data_ok;
 471        req->timestamp.data = jiffies;
 472        req->localtime.status = P80211ENUM_msgitem_status_data_ok;
 473        req->localtime.data = jiffies;
 474
 475        /* atim window */
 476        req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok;
 477        req->ibssatimwindow.data = le16_to_cpu(item->atim);
 478
 479        /* Channel */
 480        req->dschannel.status = P80211ENUM_msgitem_status_data_ok;
 481        req->dschannel.data = le16_to_cpu(item->chid);
 482
 483        /* capinfo bits */
 484        count = le16_to_cpu(item->capinfo);
 485        req->capinfo.status = P80211ENUM_msgitem_status_data_ok;
 486        req->capinfo.data = count;
 487
 488        /* privacy flag */
 489        req->privacy.status = P80211ENUM_msgitem_status_data_ok;
 490        req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count);
 491
 492        /* cfpollable */
 493        req->cfpollable.status = P80211ENUM_msgitem_status_data_ok;
 494        req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count);
 495
 496        /* cfpollreq */
 497        req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok;
 498        req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count);
 499
 500        /* bsstype */
 501        req->bsstype.status = P80211ENUM_msgitem_status_data_ok;
 502        req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ?
 503            P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent;
 504
 505        result = 0;
 506        req->resultcode.data = P80211ENUM_resultcode_success;
 507
 508exit:
 509        return result;
 510}
 511
 512/*----------------------------------------------------------------
 513 * prism2mgmt_start
 514 *
 515 * Start a BSS.  Any station can do this for IBSS, only AP for ESS.
 516 *
 517 * Arguments:
 518 *      wlandev         wlan device structure
 519 *      msgp            ptr to msg buffer
 520 *
 521 * Returns:
 522 *      0       success and done
 523 *      <0      success, but we're waiting for something to finish.
 524 *      >0      an error occurred while handling the message.
 525 * Side effects:
 526 *
 527 * Call context:
 528 *      process thread  (usually)
 529 *      interrupt
 530 *----------------------------------------------------------------
 531 */
 532int prism2mgmt_start(struct wlandevice *wlandev, void *msgp)
 533{
 534        int result = 0;
 535        struct hfa384x *hw = wlandev->priv;
 536        struct p80211msg_dot11req_start *msg = msgp;
 537
 538        struct p80211pstrd *pstr;
 539        u8 bytebuf[80];
 540        struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf;
 541        u16 word;
 542
 543        wlandev->macmode = WLAN_MACMODE_NONE;
 544
 545        /* Set the SSID */
 546        memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
 547
 548        /*** ADHOC IBSS ***/
 549        /* see if current f/w is less than 8c3 */
 550        if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
 551                                     hw->ident_sta_fw.minor,
 552                                     hw->ident_sta_fw.variant) <
 553            HFA384x_FIRMWARE_VERSION(0, 8, 3)) {
 554                /* Ad-Hoc not quite supported on Prism2 */
 555                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 556                msg->resultcode.data = P80211ENUM_resultcode_not_supported;
 557                goto done;
 558        }
 559
 560        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 561
 562        /*** STATION ***/
 563        /* Set the REQUIRED config items */
 564        /* SSID */
 565        pstr = (struct p80211pstrd *)&(msg->ssid.data);
 566        prism2mgmt_pstr2bytestr(p2bytestr, pstr);
 567        result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
 568                                        bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
 569        if (result) {
 570                netdev_err(wlandev->netdev, "Failed to set CnfOwnSSID\n");
 571                goto failed;
 572        }
 573        result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
 574                                        bytebuf,
 575                                        HFA384x_RID_CNFDESIREDSSID_LEN);
 576        if (result) {
 577                netdev_err(wlandev->netdev, "Failed to set CnfDesiredSSID\n");
 578                goto failed;
 579        }
 580
 581        /* bsstype - we use the default in the ap firmware */
 582        /* IBSS port */
 583        hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0);
 584
 585        /* beacon period */
 586        word = msg->beaconperiod.data;
 587        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word);
 588        if (result) {
 589                netdev_err(wlandev->netdev,
 590                           "Failed to set beacon period=%d.\n", word);
 591                goto failed;
 592        }
 593
 594        /* dschannel */
 595        word = msg->dschannel.data;
 596        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word);
 597        if (result) {
 598                netdev_err(wlandev->netdev,
 599                           "Failed to set channel=%d.\n", word);
 600                goto failed;
 601        }
 602        /* Basic rates */
 603        word = p80211rate_to_p2bit(msg->basicrate1.data);
 604        if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok)
 605                word |= p80211rate_to_p2bit(msg->basicrate2.data);
 606
 607        if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok)
 608                word |= p80211rate_to_p2bit(msg->basicrate3.data);
 609
 610        if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok)
 611                word |= p80211rate_to_p2bit(msg->basicrate4.data);
 612
 613        if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok)
 614                word |= p80211rate_to_p2bit(msg->basicrate5.data);
 615
 616        if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok)
 617                word |= p80211rate_to_p2bit(msg->basicrate6.data);
 618
 619        if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok)
 620                word |= p80211rate_to_p2bit(msg->basicrate7.data);
 621
 622        if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok)
 623                word |= p80211rate_to_p2bit(msg->basicrate8.data);
 624
 625        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word);
 626        if (result) {
 627                netdev_err(wlandev->netdev,
 628                           "Failed to set basicrates=%d.\n", word);
 629                goto failed;
 630        }
 631
 632        /* Operational rates (supprates and txratecontrol) */
 633        word = p80211rate_to_p2bit(msg->operationalrate1.data);
 634        if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok)
 635                word |= p80211rate_to_p2bit(msg->operationalrate2.data);
 636
 637        if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok)
 638                word |= p80211rate_to_p2bit(msg->operationalrate3.data);
 639
 640        if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok)
 641                word |= p80211rate_to_p2bit(msg->operationalrate4.data);
 642
 643        if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok)
 644                word |= p80211rate_to_p2bit(msg->operationalrate5.data);
 645
 646        if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok)
 647                word |= p80211rate_to_p2bit(msg->operationalrate6.data);
 648
 649        if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok)
 650                word |= p80211rate_to_p2bit(msg->operationalrate7.data);
 651
 652        if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok)
 653                word |= p80211rate_to_p2bit(msg->operationalrate8.data);
 654
 655        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word);
 656        if (result) {
 657                netdev_err(wlandev->netdev,
 658                           "Failed to set supprates=%d.\n", word);
 659                goto failed;
 660        }
 661
 662        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word);
 663        if (result) {
 664                netdev_err(wlandev->netdev, "Failed to set txrates=%d.\n",
 665                           word);
 666                goto failed;
 667        }
 668
 669        /* Set the macmode so the frame setup code knows what to do */
 670        if (msg->bsstype.data == P80211ENUM_bsstype_independent) {
 671                wlandev->macmode = WLAN_MACMODE_IBSS_STA;
 672                /* lets extend the data length a bit */
 673                hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304);
 674        }
 675
 676        /* Enable the Port */
 677        result = hfa384x_drvr_enable(hw, 0);
 678        if (result) {
 679                netdev_err(wlandev->netdev,
 680                           "Enable macport failed, result=%d.\n", result);
 681                goto failed;
 682        }
 683
 684        msg->resultcode.data = P80211ENUM_resultcode_success;
 685
 686        goto done;
 687failed:
 688        netdev_dbg(wlandev->netdev,
 689                   "Failed to set a config option, result=%d\n", result);
 690        msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
 691
 692done:
 693        return 0;
 694}
 695
 696/*----------------------------------------------------------------
 697 * prism2mgmt_readpda
 698 *
 699 * Collect the PDA data and put it in the message.
 700 *
 701 * Arguments:
 702 *      wlandev         wlan device structure
 703 *      msgp            ptr to msg buffer
 704 *
 705 * Returns:
 706 *      0       success and done
 707 *      <0      success, but we're waiting for something to finish.
 708 *      >0      an error occurred while handling the message.
 709 * Side effects:
 710 *
 711 * Call context:
 712 *      process thread  (usually)
 713 *----------------------------------------------------------------
 714 */
 715int prism2mgmt_readpda(struct wlandevice *wlandev, void *msgp)
 716{
 717        struct hfa384x *hw = wlandev->priv;
 718        struct p80211msg_p2req_readpda *msg = msgp;
 719        int result;
 720
 721        /* We only support collecting the PDA when in the FWLOAD
 722         * state.
 723         */
 724        if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
 725                netdev_err(wlandev->netdev,
 726                           "PDA may only be read in the fwload state.\n");
 727                msg->resultcode.data =
 728                    P80211ENUM_resultcode_implementation_failure;
 729                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 730        } else {
 731                /*  Call drvr_readpda(), it handles the auxport enable
 732                 *  and validating the returned PDA.
 733                 */
 734                result = hfa384x_drvr_readpda(hw,
 735                                              msg->pda.data,
 736                                              HFA384x_PDA_LEN_MAX);
 737                if (result) {
 738                        netdev_err(wlandev->netdev,
 739                                   "hfa384x_drvr_readpda() failed, result=%d\n",
 740                                   result);
 741
 742                        msg->resultcode.data =
 743                            P80211ENUM_resultcode_implementation_failure;
 744                        msg->resultcode.status =
 745                            P80211ENUM_msgitem_status_data_ok;
 746                        return 0;
 747                }
 748                msg->pda.status = P80211ENUM_msgitem_status_data_ok;
 749                msg->resultcode.data = P80211ENUM_resultcode_success;
 750                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 751        }
 752
 753        return 0;
 754}
 755
 756/*----------------------------------------------------------------
 757 * prism2mgmt_ramdl_state
 758 *
 759 * Establishes the beginning/end of a card RAM download session.
 760 *
 761 * It is expected that the ramdl_write() function will be called
 762 * one or more times between the 'enable' and 'disable' calls to
 763 * this function.
 764 *
 765 * Note: This function should not be called when a mac comm port
 766 *       is active.
 767 *
 768 * Arguments:
 769 *      wlandev         wlan device structure
 770 *      msgp            ptr to msg buffer
 771 *
 772 * Returns:
 773 *      0       success and done
 774 *      <0      success, but we're waiting for something to finish.
 775 *      >0      an error occurred while handling the message.
 776 * Side effects:
 777 *
 778 * Call context:
 779 *      process thread  (usually)
 780 *----------------------------------------------------------------
 781 */
 782int prism2mgmt_ramdl_state(struct wlandevice *wlandev, void *msgp)
 783{
 784        struct hfa384x *hw = wlandev->priv;
 785        struct p80211msg_p2req_ramdl_state *msg = msgp;
 786
 787        if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
 788                netdev_err(wlandev->netdev,
 789                           "ramdl_state(): may only be called in the fwload state.\n");
 790                msg->resultcode.data =
 791                    P80211ENUM_resultcode_implementation_failure;
 792                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 793                return 0;
 794        }
 795
 796        /*
 797         ** Note: Interrupts are locked out if this is an AP and are NOT
 798         ** locked out if this is a station.
 799         */
 800
 801        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 802        if (msg->enable.data == P80211ENUM_truth_true) {
 803                if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) {
 804                        msg->resultcode.data =
 805                            P80211ENUM_resultcode_implementation_failure;
 806                } else {
 807                        msg->resultcode.data = P80211ENUM_resultcode_success;
 808                }
 809        } else {
 810                hfa384x_drvr_ramdl_disable(hw);
 811                msg->resultcode.data = P80211ENUM_resultcode_success;
 812        }
 813
 814        return 0;
 815}
 816
 817/*----------------------------------------------------------------
 818 * prism2mgmt_ramdl_write
 819 *
 820 * Writes a buffer to the card RAM using the download state.  This
 821 * is for writing code to card RAM.  To just read or write raw data
 822 * use the aux functions.
 823 *
 824 * Arguments:
 825 *      wlandev         wlan device structure
 826 *      msgp            ptr to msg buffer
 827 *
 828 * Returns:
 829 *      0       success and done
 830 *      <0      success, but we're waiting for something to finish.
 831 *      >0      an error occurred while handling the message.
 832 * Side effects:
 833 *
 834 * Call context:
 835 *      process thread  (usually)
 836 *----------------------------------------------------------------
 837 */
 838int prism2mgmt_ramdl_write(struct wlandevice *wlandev, void *msgp)
 839{
 840        struct hfa384x *hw = wlandev->priv;
 841        struct p80211msg_p2req_ramdl_write *msg = msgp;
 842        u32 addr;
 843        u32 len;
 844        u8 *buf;
 845
 846        if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
 847                netdev_err(wlandev->netdev,
 848                           "ramdl_write(): may only be called in the fwload state.\n");
 849                msg->resultcode.data =
 850                    P80211ENUM_resultcode_implementation_failure;
 851                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 852                return 0;
 853        }
 854
 855        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 856        /* first validate the length */
 857        if (msg->len.data > sizeof(msg->data.data)) {
 858                msg->resultcode.status =
 859                    P80211ENUM_resultcode_invalid_parameters;
 860                return 0;
 861        }
 862        /* call the hfa384x function to do the write */
 863        addr = msg->addr.data;
 864        len = msg->len.data;
 865        buf = msg->data.data;
 866        if (hfa384x_drvr_ramdl_write(hw, addr, buf, len))
 867                msg->resultcode.data = P80211ENUM_resultcode_refused;
 868
 869        msg->resultcode.data = P80211ENUM_resultcode_success;
 870
 871        return 0;
 872}
 873
 874/*----------------------------------------------------------------
 875 * prism2mgmt_flashdl_state
 876 *
 877 * Establishes the beginning/end of a card Flash download session.
 878 *
 879 * It is expected that the flashdl_write() function will be called
 880 * one or more times between the 'enable' and 'disable' calls to
 881 * this function.
 882 *
 883 * Note: This function should not be called when a mac comm port
 884 *       is active.
 885 *
 886 * Arguments:
 887 *      wlandev         wlan device structure
 888 *      msgp            ptr to msg buffer
 889 *
 890 * Returns:
 891 *      0       success and done
 892 *      <0      success, but we're waiting for something to finish.
 893 *      >0      an error occurred while handling the message.
 894 * Side effects:
 895 *
 896 * Call context:
 897 *      process thread  (usually)
 898 *----------------------------------------------------------------
 899 */
 900int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp)
 901{
 902        int result = 0;
 903        struct hfa384x *hw = wlandev->priv;
 904        struct p80211msg_p2req_flashdl_state *msg = msgp;
 905
 906        if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
 907                netdev_err(wlandev->netdev,
 908                           "flashdl_state(): may only be called in the fwload state.\n");
 909                msg->resultcode.data =
 910                    P80211ENUM_resultcode_implementation_failure;
 911                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 912                return 0;
 913        }
 914
 915        /*
 916         ** Note: Interrupts are locked out if this is an AP and are NOT
 917         ** locked out if this is a station.
 918         */
 919
 920        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 921        if (msg->enable.data == P80211ENUM_truth_true) {
 922                if (hfa384x_drvr_flashdl_enable(hw)) {
 923                        msg->resultcode.data =
 924                            P80211ENUM_resultcode_implementation_failure;
 925                } else {
 926                        msg->resultcode.data = P80211ENUM_resultcode_success;
 927                }
 928        } else {
 929                hfa384x_drvr_flashdl_disable(hw);
 930                msg->resultcode.data = P80211ENUM_resultcode_success;
 931                /* NOTE: At this point, the MAC is in the post-reset
 932                 * state and the driver is in the fwload state.
 933                 * We need to get the MAC back into the fwload
 934                 * state.  To do this, we set the nsdstate to HWPRESENT
 935                 * and then call the ifstate function to redo everything
 936                 * that got us into the fwload state.
 937                 */
 938                wlandev->msdstate = WLAN_MSD_HWPRESENT;
 939                result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
 940                if (result != P80211ENUM_resultcode_success) {
 941                        netdev_err(wlandev->netdev,
 942                                   "prism2sta_ifstate(fwload) failed, P80211ENUM_resultcode=%d\n",
 943                                   result);
 944                        msg->resultcode.data =
 945                            P80211ENUM_resultcode_implementation_failure;
 946                        result = -1;
 947                }
 948        }
 949
 950        return 0;
 951}
 952
 953/*----------------------------------------------------------------
 954 * prism2mgmt_flashdl_write
 955 *
 956 *
 957 *
 958 * Arguments:
 959 *      wlandev         wlan device structure
 960 *      msgp            ptr to msg buffer
 961 *
 962 * Returns:
 963 *      0       success and done
 964 *      <0      success, but we're waiting for something to finish.
 965 *      >0      an error occurred while handling the message.
 966 * Side effects:
 967 *
 968 * Call context:
 969 *      process thread  (usually)
 970 *----------------------------------------------------------------
 971 */
 972int prism2mgmt_flashdl_write(struct wlandevice *wlandev, void *msgp)
 973{
 974        struct hfa384x *hw = wlandev->priv;
 975        struct p80211msg_p2req_flashdl_write *msg = msgp;
 976        u32 addr;
 977        u32 len;
 978        u8 *buf;
 979
 980        if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
 981                netdev_err(wlandev->netdev,
 982                           "flashdl_write(): may only be called in the fwload state.\n");
 983                msg->resultcode.data =
 984                    P80211ENUM_resultcode_implementation_failure;
 985                msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 986                return 0;
 987        }
 988
 989        /*
 990         ** Note: Interrupts are locked out if this is an AP and are NOT
 991         ** locked out if this is a station.
 992         */
 993
 994        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
 995        /* first validate the length */
 996        if (msg->len.data > sizeof(msg->data.data)) {
 997                msg->resultcode.status =
 998                    P80211ENUM_resultcode_invalid_parameters;
 999                return 0;
1000        }
1001        /* call the hfa384x function to do the write */
1002        addr = msg->addr.data;
1003        len = msg->len.data;
1004        buf = msg->data.data;
1005        if (hfa384x_drvr_flashdl_write(hw, addr, buf, len))
1006                msg->resultcode.data = P80211ENUM_resultcode_refused;
1007
1008        msg->resultcode.data = P80211ENUM_resultcode_success;
1009
1010        return 0;
1011}
1012
1013/*----------------------------------------------------------------
1014 * prism2mgmt_autojoin
1015 *
1016 * Associate with an ESS.
1017 *
1018 * Arguments:
1019 *      wlandev         wlan device structure
1020 *      msgp            ptr to msg buffer
1021 *
1022 * Returns:
1023 *      0       success and done
1024 *      <0      success, but we're waiting for something to finish.
1025 *      >0      an error occurred while handling the message.
1026 * Side effects:
1027 *
1028 * Call context:
1029 *      process thread  (usually)
1030 *      interrupt
1031 *----------------------------------------------------------------
1032 */
1033int prism2mgmt_autojoin(struct wlandevice *wlandev, void *msgp)
1034{
1035        struct hfa384x *hw = wlandev->priv;
1036        int result = 0;
1037        u16 reg;
1038        u16 port_type;
1039        struct p80211msg_lnxreq_autojoin *msg = msgp;
1040        struct p80211pstrd *pstr;
1041        u8 bytebuf[256];
1042        struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf;
1043
1044        wlandev->macmode = WLAN_MACMODE_NONE;
1045
1046        /* Set the SSID */
1047        memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
1048
1049        /* Disable the Port */
1050        hfa384x_drvr_disable(hw, 0);
1051
1052        /*** STATION ***/
1053        /* Set the TxRates */
1054        hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f);
1055
1056        /* Set the auth type */
1057        if (msg->authtype.data == P80211ENUM_authalg_sharedkey)
1058                reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY;
1059        else
1060                reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM;
1061
1062        hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg);
1063
1064        /* Set the ssid */
1065        memset(bytebuf, 0, 256);
1066        pstr = (struct p80211pstrd *)&(msg->ssid.data);
1067        prism2mgmt_pstr2bytestr(p2bytestr, pstr);
1068        result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
1069                                        bytebuf,
1070                                        HFA384x_RID_CNFDESIREDSSID_LEN);
1071        port_type = HFA384x_PORTTYPE_BSS;
1072        /* Set the PortType */
1073        hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type);
1074
1075        /* Enable the Port */
1076        hfa384x_drvr_enable(hw, 0);
1077
1078        /* Set the resultcode */
1079        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1080        msg->resultcode.data = P80211ENUM_resultcode_success;
1081
1082        return result;
1083}
1084
1085/*----------------------------------------------------------------
1086 * prism2mgmt_wlansniff
1087 *
1088 * Start or stop sniffing.
1089 *
1090 * Arguments:
1091 *      wlandev         wlan device structure
1092 *      msgp            ptr to msg buffer
1093 *
1094 * Returns:
1095 *      0       success and done
1096 *      <0      success, but we're waiting for something to finish.
1097 *      >0      an error occurred while handling the message.
1098 * Side effects:
1099 *
1100 * Call context:
1101 *      process thread  (usually)
1102 *      interrupt
1103 *----------------------------------------------------------------
1104 */
1105int prism2mgmt_wlansniff(struct wlandevice *wlandev, void *msgp)
1106{
1107        int result = 0;
1108        struct p80211msg_lnxreq_wlansniff *msg = msgp;
1109
1110        struct hfa384x *hw = wlandev->priv;
1111        u16 word;
1112
1113        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1114        switch (msg->enable.data) {
1115        case P80211ENUM_truth_false:
1116                /* Confirm that we're in monitor mode */
1117                if (wlandev->netdev->type == ARPHRD_ETHER) {
1118                        msg->resultcode.data =
1119                            P80211ENUM_resultcode_invalid_parameters;
1120                        return 0;
1121                }
1122                /* Disable monitor mode */
1123                result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE);
1124                if (result) {
1125                        netdev_dbg(wlandev->netdev,
1126                                   "failed to disable monitor mode, result=%d\n",
1127                                   result);
1128                        goto failed;
1129                }
1130                /* Disable port 0 */
1131                result = hfa384x_drvr_disable(hw, 0);
1132                if (result) {
1133                        netdev_dbg
1134                        (wlandev->netdev,
1135                             "failed to disable port 0 after sniffing, result=%d\n",
1136                             result);
1137                        goto failed;
1138                }
1139                /* Clear the driver state */
1140                wlandev->netdev->type = ARPHRD_ETHER;
1141
1142                /* Restore the wepflags */
1143                result = hfa384x_drvr_setconfig16(hw,
1144                                                  HFA384x_RID_CNFWEPFLAGS,
1145                                                  hw->presniff_wepflags);
1146                if (result) {
1147                        netdev_dbg
1148                            (wlandev->netdev,
1149                             "failed to restore wepflags=0x%04x, result=%d\n",
1150                             hw->presniff_wepflags, result);
1151                        goto failed;
1152                }
1153
1154                /* Set the port to its prior type and enable (if necessary) */
1155                if (hw->presniff_port_type != 0) {
1156                        word = hw->presniff_port_type;
1157                        result = hfa384x_drvr_setconfig16(hw,
1158                                                  HFA384x_RID_CNFPORTTYPE,
1159                                                  word);
1160                        if (result) {
1161                                netdev_dbg
1162                                    (wlandev->netdev,
1163                                     "failed to restore porttype, result=%d\n",
1164                                     result);
1165                                goto failed;
1166                        }
1167
1168                        /* Enable the port */
1169                        result = hfa384x_drvr_enable(hw, 0);
1170                        if (result) {
1171                                netdev_dbg(wlandev->netdev,
1172                                           "failed to enable port to presniff setting, result=%d\n",
1173                                           result);
1174                                goto failed;
1175                        }
1176                } else {
1177                        result = hfa384x_drvr_disable(hw, 0);
1178                }
1179
1180                netdev_info(wlandev->netdev, "monitor mode disabled\n");
1181                msg->resultcode.data = P80211ENUM_resultcode_success;
1182                return 0;
1183        case P80211ENUM_truth_true:
1184                /* Disable the port (if enabled), only check Port 0 */
1185                if (hw->port_enabled[0]) {
1186                        if (wlandev->netdev->type == ARPHRD_ETHER) {
1187                                /* Save macport 0 state */
1188                                result = hfa384x_drvr_getconfig16(hw,
1189                                                  HFA384x_RID_CNFPORTTYPE,
1190                                                  &(hw->presniff_port_type));
1191                                if (result) {
1192                                        netdev_dbg
1193                                        (wlandev->netdev,
1194                                             "failed to read porttype, result=%d\n",
1195                                             result);
1196                                        goto failed;
1197                                }
1198                                /* Save the wepflags state */
1199                                result = hfa384x_drvr_getconfig16(hw,
1200                                                  HFA384x_RID_CNFWEPFLAGS,
1201                                                  &(hw->presniff_wepflags));
1202                                if (result) {
1203                                        netdev_dbg
1204                                        (wlandev->netdev,
1205                                             "failed to read wepflags, result=%d\n",
1206                                             result);
1207                                        goto failed;
1208                                }
1209                                hfa384x_drvr_stop(hw);
1210                                result = hfa384x_drvr_start(hw);
1211                                if (result) {
1212                                        netdev_dbg(wlandev->netdev,
1213                                                   "failed to restart the card for sniffing, result=%d\n",
1214                                                   result);
1215                                        goto failed;
1216                                }
1217                        } else {
1218                                /* Disable the port */
1219                                result = hfa384x_drvr_disable(hw, 0);
1220                                if (result) {
1221                                        netdev_dbg(wlandev->netdev,
1222                                                   "failed to enable port for sniffing, result=%d\n",
1223                                                   result);
1224                                        goto failed;
1225                                }
1226                        }
1227                } else {
1228                        hw->presniff_port_type = 0;
1229                }
1230
1231                /* Set the channel we wish to sniff  */
1232                word = msg->channel.data;
1233                result = hfa384x_drvr_setconfig16(hw,
1234                                                  HFA384x_RID_CNFOWNCHANNEL,
1235                                                  word);
1236                hw->sniff_channel = word;
1237
1238                if (result) {
1239                        netdev_dbg(wlandev->netdev,
1240                                   "failed to set channel %d, result=%d\n",
1241                                   word, result);
1242                        goto failed;
1243                }
1244
1245                /* Now if we're already sniffing, we can skip the rest */
1246                if (wlandev->netdev->type != ARPHRD_ETHER) {
1247                        /* Set the port type to pIbss */
1248                        word = HFA384x_PORTTYPE_PSUEDOIBSS;
1249                        result = hfa384x_drvr_setconfig16(hw,
1250                                                  HFA384x_RID_CNFPORTTYPE,
1251                                                  word);
1252                        if (result) {
1253                                netdev_dbg
1254                                    (wlandev->netdev,
1255                                     "failed to set porttype %d, result=%d\n",
1256                                     word, result);
1257                                goto failed;
1258                        }
1259                        if ((msg->keepwepflags.status ==
1260                             P80211ENUM_msgitem_status_data_ok)
1261                            && (msg->keepwepflags.data !=
1262                                P80211ENUM_truth_true)) {
1263                                /* Set the wepflags for no decryption */
1264                                word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT |
1265                                    HFA384x_WEPFLAGS_DISABLE_RXCRYPT;
1266                                result =
1267                                    hfa384x_drvr_setconfig16(hw,
1268                                                     HFA384x_RID_CNFWEPFLAGS,
1269                                                     word);
1270                        }
1271
1272                        if (result) {
1273                                netdev_dbg
1274                                  (wlandev->netdev,
1275                                   "failed to set wepflags=0x%04x, result=%d\n",
1276                                   word, result);
1277                                goto failed;
1278                        }
1279                }
1280
1281                /* Do we want to strip the FCS in monitor mode? */
1282                if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok)
1283                    && (msg->stripfcs.data == P80211ENUM_truth_true)) {
1284                        hw->sniff_fcs = 0;
1285                } else {
1286                        hw->sniff_fcs = 1;
1287                }
1288
1289                /* Do we want to truncate the packets? */
1290                if (msg->packet_trunc.status ==
1291                    P80211ENUM_msgitem_status_data_ok) {
1292                        hw->sniff_truncate = msg->packet_trunc.data;
1293                } else {
1294                        hw->sniff_truncate = 0;
1295                }
1296
1297                /* Enable the port */
1298                result = hfa384x_drvr_enable(hw, 0);
1299                if (result) {
1300                        netdev_dbg
1301                            (wlandev->netdev,
1302                             "failed to enable port for sniffing, result=%d\n",
1303                             result);
1304                        goto failed;
1305                }
1306                /* Enable monitor mode */
1307                result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE);
1308                if (result) {
1309                        netdev_dbg(wlandev->netdev,
1310                                   "failed to enable monitor mode, result=%d\n",
1311                                   result);
1312                        goto failed;
1313                }
1314
1315                if (wlandev->netdev->type == ARPHRD_ETHER)
1316                        netdev_info(wlandev->netdev, "monitor mode enabled\n");
1317
1318                /* Set the driver state */
1319                /* Do we want the prism2 header? */
1320                if ((msg->prismheader.status ==
1321                     P80211ENUM_msgitem_status_data_ok) &&
1322                    (msg->prismheader.data == P80211ENUM_truth_true)) {
1323                        hw->sniffhdr = 0;
1324                        wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1325                } else if ((msg->wlanheader.status ==
1326                            P80211ENUM_msgitem_status_data_ok) &&
1327                           (msg->wlanheader.data == P80211ENUM_truth_true)) {
1328                        hw->sniffhdr = 1;
1329                        wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1330                } else {
1331                        wlandev->netdev->type = ARPHRD_IEEE80211;
1332                }
1333
1334                msg->resultcode.data = P80211ENUM_resultcode_success;
1335                return 0;
1336        default:
1337                msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
1338                return 0;
1339        }
1340
1341failed:
1342        msg->resultcode.data = P80211ENUM_resultcode_refused;
1343        return 0;
1344}
1345