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