Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
0002 /*
0003  *
0004  * Management request handler functions.
0005  *
0006  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
0007  * --------------------------------------------------------------------
0008  *
0009  * linux-wlan
0010  *
0011  *   The contents of this file are subject to the Mozilla Public
0012  *   License Version 1.1 (the "License"); you may not use this file
0013  *   except in compliance with the License. You may obtain a copy of
0014  *   the License at http://www.mozilla.org/MPL/
0015  *
0016  *   Software distributed under the License is distributed on an "AS
0017  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0018  *   implied. See the License for the specific language governing
0019  *   rights and limitations under the License.
0020  *
0021  *   Alternatively, the contents of this file may be used under the
0022  *   terms of the GNU Public License version 2 (the "GPL"), in which
0023  *   case the provisions of the GPL are applicable instead of the
0024  *   above.  If you wish to allow the use of your version of this file
0025  *   only under the terms of the GPL and not to allow others to use
0026  *   your version of this file under the MPL, indicate your decision
0027  *   by deleting the provisions above and replace them with the notice
0028  *   and other provisions required by the GPL.  If you do not delete
0029  *   the provisions above, a recipient may use your version of this
0030  *   file under either the MPL or the GPL.
0031  *
0032  * --------------------------------------------------------------------
0033  *
0034  * Inquiries regarding the linux-wlan Open Source project can be
0035  * made directly to:
0036  *
0037  * AbsoluteValue Systems Inc.
0038  * info@linux-wlan.com
0039  * http://www.linux-wlan.com
0040  *
0041  * --------------------------------------------------------------------
0042  *
0043  * Portions of the development of this software were funded by
0044  * Intersil Corporation as part of PRISM(R) chipset product development.
0045  *
0046  * --------------------------------------------------------------------
0047  *
0048  * The functions in this file handle management requests sent from
0049  * user mode.
0050  *
0051  * Most of these functions have two separate blocks of code that are
0052  * conditional on whether this is a station or an AP.  This is used
0053  * to separate out the STA and AP responses to these management primitives.
0054  * It's a choice (good, bad, indifferent?) to have the code in the same
0055  * place so it's clear that the same primitive is implemented in both
0056  * cases but has different behavior.
0057  *
0058  * --------------------------------------------------------------------
0059  */
0060 
0061 #include <linux/if_arp.h>
0062 #include <linux/module.h>
0063 #include <linux/kernel.h>
0064 #include <linux/wait.h>
0065 #include <linux/sched.h>
0066 #include <linux/types.h>
0067 #include <linux/wireless.h>
0068 #include <linux/netdevice.h>
0069 #include <linux/delay.h>
0070 #include <linux/io.h>
0071 #include <asm/byteorder.h>
0072 #include <linux/random.h>
0073 #include <linux/usb.h>
0074 #include <linux/bitops.h>
0075 
0076 #include "p80211types.h"
0077 #include "p80211hdr.h"
0078 #include "p80211mgmt.h"
0079 #include "p80211conv.h"
0080 #include "p80211msg.h"
0081 #include "p80211netdev.h"
0082 #include "p80211metadef.h"
0083 #include "p80211metastruct.h"
0084 #include "hfa384x.h"
0085 #include "prism2mgmt.h"
0086 
0087 /* Converts 802.11 format rate specifications to prism2 */
0088 static inline u16 p80211rate_to_p2bit(u32 rate)
0089 {
0090     switch (rate & ~BIT(7)) {
0091     case 2:
0092         return BIT(0);
0093     case 4:
0094         return BIT(1);
0095     case 11:
0096         return BIT(2);
0097     case 22:
0098         return BIT(3);
0099     default:
0100         return 0;
0101     }
0102 }
0103 
0104 /*----------------------------------------------------------------
0105  * prism2mgmt_scan
0106  *
0107  * Initiate a scan for BSSs.
0108  *
0109  * This function corresponds to MLME-scan.request and part of
0110  * MLME-scan.confirm.  As far as I can tell in the standard, there
0111  * are no restrictions on when a scan.request may be issued.  We have
0112  * to handle in whatever state the driver/MAC happen to be.
0113  *
0114  * Arguments:
0115  *  wlandev     wlan device structure
0116  *  msgp        ptr to msg buffer
0117  *
0118  * Returns:
0119  *  0   success and done
0120  *  <0  success, but we're waiting for something to finish.
0121  *  >0  an error occurred while handling the message.
0122  * Side effects:
0123  *
0124  * Call context:
0125  *  process thread  (usually)
0126  *  interrupt
0127  *----------------------------------------------------------------
0128  */
0129 int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp)
0130 {
0131     int result = 0;
0132     struct hfa384x *hw = wlandev->priv;
0133     struct p80211msg_dot11req_scan *msg = msgp;
0134     u16 roamingmode, word;
0135     int i, timeout;
0136     int istmpenable = 0;
0137 
0138     struct hfa384x_host_scan_request_data scanreq;
0139 
0140     /* gatekeeper check */
0141     if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
0142                      hw->ident_sta_fw.minor,
0143                      hw->ident_sta_fw.variant) <
0144         HFA384x_FIRMWARE_VERSION(1, 3, 2)) {
0145         netdev_err(wlandev->netdev,
0146                "HostScan not supported with current firmware (<1.3.2).\n");
0147         result = 1;
0148         msg->resultcode.data = P80211ENUM_resultcode_not_supported;
0149         goto exit;
0150     }
0151 
0152     memset(&scanreq, 0, sizeof(scanreq));
0153 
0154     /* save current roaming mode */
0155     result = hfa384x_drvr_getconfig16(hw,
0156                       HFA384x_RID_CNFROAMINGMODE,
0157                       &roamingmode);
0158     if (result) {
0159         netdev_err(wlandev->netdev,
0160                "getconfig(ROAMMODE) failed. result=%d\n", result);
0161         msg->resultcode.data =
0162             P80211ENUM_resultcode_implementation_failure;
0163         goto exit;
0164     }
0165 
0166     /* drop into mode 3 for the scan */
0167     result = hfa384x_drvr_setconfig16(hw,
0168                       HFA384x_RID_CNFROAMINGMODE,
0169                       HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
0170     if (result) {
0171         netdev_err(wlandev->netdev,
0172                "setconfig(ROAMINGMODE) failed. result=%d\n",
0173                result);
0174         msg->resultcode.data =
0175             P80211ENUM_resultcode_implementation_failure;
0176         goto exit;
0177     }
0178 
0179     /* active or passive? */
0180     if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
0181                      hw->ident_sta_fw.minor,
0182                      hw->ident_sta_fw.variant) >
0183         HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
0184         if (msg->scantype.data != P80211ENUM_scantype_active)
0185             word = msg->maxchanneltime.data;
0186         else
0187             word = 0;
0188 
0189         result =
0190             hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL,
0191                          word);
0192         if (result) {
0193             netdev_warn(wlandev->netdev,
0194                     "Passive scan not supported with current firmware.  (<1.5.1)\n");
0195         }
0196     }
0197 
0198     /* set up the txrate to be 2MBPS. Should be fastest basicrate... */
0199     word = HFA384x_RATEBIT_2;
0200     scanreq.tx_rate = cpu_to_le16(word);
0201 
0202     /* set up the channel list */
0203     word = 0;
0204     for (i = 0; i < msg->channellist.data.len; i++) {
0205         u8 channel = msg->channellist.data.data[i];
0206 
0207         if (channel > 14)
0208             continue;
0209         /* channel 1 is BIT 0 ... channel 14 is BIT 13 */
0210         word |= (1 << (channel - 1));
0211     }
0212     scanreq.channel_list = cpu_to_le16(word);
0213 
0214     /* set up the ssid, if present. */
0215     scanreq.ssid.len = cpu_to_le16(msg->ssid.data.len);
0216     memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len);
0217 
0218     /* Enable the MAC port if it's not already enabled  */
0219     result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word);
0220     if (result) {
0221         netdev_err(wlandev->netdev,
0222                "getconfig(PORTSTATUS) failed. result=%d\n", result);
0223         msg->resultcode.data =
0224             P80211ENUM_resultcode_implementation_failure;
0225         goto exit;
0226     }
0227     if (word == HFA384x_PORTSTATUS_DISABLED) {
0228         __le16 wordbuf[17];
0229 
0230         result = hfa384x_drvr_setconfig16(hw,
0231                           HFA384x_RID_CNFROAMINGMODE,
0232                           HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
0233         if (result) {
0234             netdev_err(wlandev->netdev,
0235                    "setconfig(ROAMINGMODE) failed. result=%d\n",
0236                    result);
0237             msg->resultcode.data =
0238                 P80211ENUM_resultcode_implementation_failure;
0239             goto exit;
0240         }
0241         /* Construct a bogus SSID and assign it to OwnSSID and
0242          * DesiredSSID
0243          */
0244         wordbuf[0] = cpu_to_le16(WLAN_SSID_MAXLEN);
0245         get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN);
0246         result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
0247                         wordbuf,
0248                         HFA384x_RID_CNFOWNSSID_LEN);
0249         if (result) {
0250             netdev_err(wlandev->netdev, "Failed to set OwnSSID.\n");
0251             msg->resultcode.data =
0252                 P80211ENUM_resultcode_implementation_failure;
0253             goto exit;
0254         }
0255         result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
0256                         wordbuf,
0257                         HFA384x_RID_CNFDESIREDSSID_LEN);
0258         if (result) {
0259             netdev_err(wlandev->netdev,
0260                    "Failed to set DesiredSSID.\n");
0261             msg->resultcode.data =
0262                 P80211ENUM_resultcode_implementation_failure;
0263             goto exit;
0264         }
0265         /* bsstype */
0266         result = hfa384x_drvr_setconfig16(hw,
0267                           HFA384x_RID_CNFPORTTYPE,
0268                           HFA384x_PORTTYPE_IBSS);
0269         if (result) {
0270             netdev_err(wlandev->netdev,
0271                    "Failed to set CNFPORTTYPE.\n");
0272             msg->resultcode.data =
0273                 P80211ENUM_resultcode_implementation_failure;
0274             goto exit;
0275         }
0276         /* ibss options */
0277         result = hfa384x_drvr_setconfig16(hw,
0278                           HFA384x_RID_CREATEIBSS,
0279                           HFA384x_CREATEIBSS_JOINCREATEIBSS);
0280         if (result) {
0281             netdev_err(wlandev->netdev,
0282                    "Failed to set CREATEIBSS.\n");
0283             msg->resultcode.data =
0284                 P80211ENUM_resultcode_implementation_failure;
0285             goto exit;
0286         }
0287         result = hfa384x_drvr_enable(hw, 0);
0288         if (result) {
0289             netdev_err(wlandev->netdev,
0290                    "drvr_enable(0) failed. result=%d\n",
0291                    result);
0292             msg->resultcode.data =
0293                 P80211ENUM_resultcode_implementation_failure;
0294             goto exit;
0295         }
0296         istmpenable = 1;
0297     }
0298 
0299     /* Figure out our timeout first Kus, then HZ */
0300     timeout = msg->channellist.data.len * msg->maxchanneltime.data;
0301     timeout = (timeout * HZ) / 1000;
0302 
0303     /* Issue the scan request */
0304     hw->scanflag = 0;
0305 
0306     result = hfa384x_drvr_setconfig(hw,
0307                     HFA384x_RID_HOSTSCAN, &scanreq,
0308                     sizeof(scanreq));
0309     if (result) {
0310         netdev_err(wlandev->netdev,
0311                "setconfig(SCANREQUEST) failed. result=%d\n",
0312                result);
0313         msg->resultcode.data =
0314             P80211ENUM_resultcode_implementation_failure;
0315         goto exit;
0316     }
0317 
0318     /* sleep until info frame arrives */
0319     wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout);
0320 
0321     msg->numbss.status = P80211ENUM_msgitem_status_data_ok;
0322     if (hw->scanflag == -1)
0323         hw->scanflag = 0;
0324 
0325     msg->numbss.data = hw->scanflag;
0326 
0327     hw->scanflag = 0;
0328 
0329     /* Disable port if we temporarily enabled it. */
0330     if (istmpenable) {
0331         result = hfa384x_drvr_disable(hw, 0);
0332         if (result) {
0333             netdev_err(wlandev->netdev,
0334                    "drvr_disable(0) failed. result=%d\n",
0335                    result);
0336             msg->resultcode.data =
0337                 P80211ENUM_resultcode_implementation_failure;
0338             goto exit;
0339         }
0340     }
0341 
0342     /* restore original roaming mode */
0343     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE,
0344                       roamingmode);
0345     if (result) {
0346         netdev_err(wlandev->netdev,
0347                "setconfig(ROAMMODE) failed. result=%d\n", result);
0348         msg->resultcode.data =
0349             P80211ENUM_resultcode_implementation_failure;
0350         goto exit;
0351     }
0352 
0353     result = 0;
0354     msg->resultcode.data = P80211ENUM_resultcode_success;
0355 
0356 exit:
0357     msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0358 
0359     return result;
0360 }
0361 
0362 /*----------------------------------------------------------------
0363  * prism2mgmt_scan_results
0364  *
0365  * Retrieve the BSS description for one of the BSSs identified in
0366  * a scan.
0367  *
0368  * Arguments:
0369  *  wlandev     wlan device structure
0370  *  msgp        ptr to msg buffer
0371  *
0372  * Returns:
0373  *  0   success and done
0374  *  <0  success, but we're waiting for something to finish.
0375  *  >0  an error occurred while handling the message.
0376  * Side effects:
0377  *
0378  * Call context:
0379  *  process thread  (usually)
0380  *  interrupt
0381  *----------------------------------------------------------------
0382  */
0383 int prism2mgmt_scan_results(struct wlandevice *wlandev, void *msgp)
0384 {
0385     int result = 0;
0386     struct p80211msg_dot11req_scan_results *req;
0387     struct hfa384x *hw = wlandev->priv;
0388     struct hfa384x_hscan_result_sub *item = NULL;
0389 
0390     int count;
0391 
0392     req = msgp;
0393 
0394     req->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0395 
0396     if (!hw->scanresults) {
0397         netdev_err(wlandev->netdev,
0398                "dot11req_scan_results can only be used after a successful dot11req_scan.\n");
0399         result = 2;
0400         req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
0401         goto exit;
0402     }
0403 
0404     count = (hw->scanresults->framelen - 3) / 32;
0405     if (count > HFA384x_SCANRESULT_MAX)
0406         count = HFA384x_SCANRESULT_MAX;
0407 
0408     if (req->bssindex.data >= count) {
0409         netdev_dbg(wlandev->netdev,
0410                "requested index (%d) out of range (%d)\n",
0411                req->bssindex.data, count);
0412         result = 2;
0413         req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
0414         goto exit;
0415     }
0416 
0417     item = &hw->scanresults->info.hscanresult.result[req->bssindex.data];
0418     /* signal and noise */
0419     req->signal.status = P80211ENUM_msgitem_status_data_ok;
0420     req->noise.status = P80211ENUM_msgitem_status_data_ok;
0421     req->signal.data = le16_to_cpu(item->sl);
0422     req->noise.data = le16_to_cpu(item->anl);
0423 
0424     /* BSSID */
0425     req->bssid.status = P80211ENUM_msgitem_status_data_ok;
0426     req->bssid.data.len = WLAN_BSSID_LEN;
0427     memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN);
0428 
0429     /* SSID */
0430     req->ssid.status = P80211ENUM_msgitem_status_data_ok;
0431     req->ssid.data.len = le16_to_cpu(item->ssid.len);
0432     req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN);
0433     memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);
0434 
0435     /* supported rates */
0436     for (count = 0; count < 10; count++)
0437         if (item->supprates[count] == 0)
0438             break;
0439 
0440 #define REQBASICRATE(N) \
0441     do { \
0442         if ((count >= (N)) && DOT11_RATE5_ISBASIC_GET(  \
0443             item->supprates[(N) - 1])) { \
0444             req->basicrate ## N .data = item->supprates[(N) - 1]; \
0445             req->basicrate ## N .status = \
0446                 P80211ENUM_msgitem_status_data_ok; \
0447         } \
0448     } while (0)
0449 
0450     REQBASICRATE(1);
0451     REQBASICRATE(2);
0452     REQBASICRATE(3);
0453     REQBASICRATE(4);
0454     REQBASICRATE(5);
0455     REQBASICRATE(6);
0456     REQBASICRATE(7);
0457     REQBASICRATE(8);
0458 
0459 #define REQSUPPRATE(N) \
0460     do { \
0461         if (count >= (N)) {                 \
0462             req->supprate ## N .data = item->supprates[(N) - 1]; \
0463             req->supprate ## N .status = \
0464                 P80211ENUM_msgitem_status_data_ok; \
0465         } \
0466     } while (0)
0467 
0468     REQSUPPRATE(1);
0469     REQSUPPRATE(2);
0470     REQSUPPRATE(3);
0471     REQSUPPRATE(4);
0472     REQSUPPRATE(5);
0473     REQSUPPRATE(6);
0474     REQSUPPRATE(7);
0475     REQSUPPRATE(8);
0476 
0477     /* beacon period */
0478     req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok;
0479     req->beaconperiod.data = le16_to_cpu(item->bcnint);
0480 
0481     /* timestamps */
0482     req->timestamp.status = P80211ENUM_msgitem_status_data_ok;
0483     req->timestamp.data = jiffies;
0484     req->localtime.status = P80211ENUM_msgitem_status_data_ok;
0485     req->localtime.data = jiffies;
0486 
0487     /* atim window */
0488     req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok;
0489     req->ibssatimwindow.data = le16_to_cpu(item->atim);
0490 
0491     /* Channel */
0492     req->dschannel.status = P80211ENUM_msgitem_status_data_ok;
0493     req->dschannel.data = le16_to_cpu(item->chid);
0494 
0495     /* capinfo bits */
0496     count = le16_to_cpu(item->capinfo);
0497     req->capinfo.status = P80211ENUM_msgitem_status_data_ok;
0498     req->capinfo.data = count;
0499 
0500     /* privacy flag */
0501     req->privacy.status = P80211ENUM_msgitem_status_data_ok;
0502     req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count);
0503 
0504     /* cfpollable */
0505     req->cfpollable.status = P80211ENUM_msgitem_status_data_ok;
0506     req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count);
0507 
0508     /* cfpollreq */
0509     req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok;
0510     req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count);
0511 
0512     /* bsstype */
0513     req->bsstype.status = P80211ENUM_msgitem_status_data_ok;
0514     req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ?
0515         P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent;
0516 
0517     result = 0;
0518     req->resultcode.data = P80211ENUM_resultcode_success;
0519 
0520 exit:
0521     return result;
0522 }
0523 
0524 /*----------------------------------------------------------------
0525  * prism2mgmt_start
0526  *
0527  * Start a BSS.  Any station can do this for IBSS, only AP for ESS.
0528  *
0529  * Arguments:
0530  *  wlandev     wlan device structure
0531  *  msgp        ptr to msg buffer
0532  *
0533  * Returns:
0534  *  0   success and done
0535  *  <0  success, but we're waiting for something to finish.
0536  *  >0  an error occurred while handling the message.
0537  * Side effects:
0538  *
0539  * Call context:
0540  *  process thread  (usually)
0541  *  interrupt
0542  *----------------------------------------------------------------
0543  */
0544 int prism2mgmt_start(struct wlandevice *wlandev, void *msgp)
0545 {
0546     int result = 0;
0547     struct hfa384x *hw = wlandev->priv;
0548     struct p80211msg_dot11req_start *msg = msgp;
0549 
0550     struct p80211pstrd *pstr;
0551     u8 bytebuf[80];
0552     struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf;
0553     u16 word;
0554 
0555     wlandev->macmode = WLAN_MACMODE_NONE;
0556 
0557     /* Set the SSID */
0558     memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
0559 
0560     /*** ADHOC IBSS ***/
0561     /* see if current f/w is less than 8c3 */
0562     if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
0563                      hw->ident_sta_fw.minor,
0564                      hw->ident_sta_fw.variant) <
0565         HFA384x_FIRMWARE_VERSION(0, 8, 3)) {
0566         /* Ad-Hoc not quite supported on Prism2 */
0567         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0568         msg->resultcode.data = P80211ENUM_resultcode_not_supported;
0569         goto done;
0570     }
0571 
0572     msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0573 
0574     /*** STATION ***/
0575     /* Set the REQUIRED config items */
0576     /* SSID */
0577     pstr = (struct p80211pstrd *)&msg->ssid.data;
0578     prism2mgmt_pstr2bytestr(p2bytestr, pstr);
0579     result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
0580                     bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
0581     if (result) {
0582         netdev_err(wlandev->netdev, "Failed to set CnfOwnSSID\n");
0583         goto failed;
0584     }
0585     result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
0586                     bytebuf,
0587                     HFA384x_RID_CNFDESIREDSSID_LEN);
0588     if (result) {
0589         netdev_err(wlandev->netdev, "Failed to set CnfDesiredSSID\n");
0590         goto failed;
0591     }
0592 
0593     /* bsstype - we use the default in the ap firmware */
0594     /* IBSS port */
0595     hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0);
0596 
0597     /* beacon period */
0598     word = msg->beaconperiod.data;
0599     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word);
0600     if (result) {
0601         netdev_err(wlandev->netdev,
0602                "Failed to set beacon period=%d.\n", word);
0603         goto failed;
0604     }
0605 
0606     /* dschannel */
0607     word = msg->dschannel.data;
0608     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word);
0609     if (result) {
0610         netdev_err(wlandev->netdev,
0611                "Failed to set channel=%d.\n", word);
0612         goto failed;
0613     }
0614     /* Basic rates */
0615     word = p80211rate_to_p2bit(msg->basicrate1.data);
0616     if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok)
0617         word |= p80211rate_to_p2bit(msg->basicrate2.data);
0618 
0619     if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok)
0620         word |= p80211rate_to_p2bit(msg->basicrate3.data);
0621 
0622     if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok)
0623         word |= p80211rate_to_p2bit(msg->basicrate4.data);
0624 
0625     if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok)
0626         word |= p80211rate_to_p2bit(msg->basicrate5.data);
0627 
0628     if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok)
0629         word |= p80211rate_to_p2bit(msg->basicrate6.data);
0630 
0631     if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok)
0632         word |= p80211rate_to_p2bit(msg->basicrate7.data);
0633 
0634     if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok)
0635         word |= p80211rate_to_p2bit(msg->basicrate8.data);
0636 
0637     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word);
0638     if (result) {
0639         netdev_err(wlandev->netdev,
0640                "Failed to set basicrates=%d.\n", word);
0641         goto failed;
0642     }
0643 
0644     /* Operational rates (supprates and txratecontrol) */
0645     word = p80211rate_to_p2bit(msg->operationalrate1.data);
0646     if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok)
0647         word |= p80211rate_to_p2bit(msg->operationalrate2.data);
0648 
0649     if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok)
0650         word |= p80211rate_to_p2bit(msg->operationalrate3.data);
0651 
0652     if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok)
0653         word |= p80211rate_to_p2bit(msg->operationalrate4.data);
0654 
0655     if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok)
0656         word |= p80211rate_to_p2bit(msg->operationalrate5.data);
0657 
0658     if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok)
0659         word |= p80211rate_to_p2bit(msg->operationalrate6.data);
0660 
0661     if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok)
0662         word |= p80211rate_to_p2bit(msg->operationalrate7.data);
0663 
0664     if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok)
0665         word |= p80211rate_to_p2bit(msg->operationalrate8.data);
0666 
0667     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word);
0668     if (result) {
0669         netdev_err(wlandev->netdev,
0670                "Failed to set supprates=%d.\n", word);
0671         goto failed;
0672     }
0673 
0674     result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word);
0675     if (result) {
0676         netdev_err(wlandev->netdev, "Failed to set txrates=%d.\n",
0677                word);
0678         goto failed;
0679     }
0680 
0681     /* Set the macmode so the frame setup code knows what to do */
0682     if (msg->bsstype.data == P80211ENUM_bsstype_independent) {
0683         wlandev->macmode = WLAN_MACMODE_IBSS_STA;
0684         /* lets extend the data length a bit */
0685         hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304);
0686     }
0687 
0688     /* Enable the Port */
0689     result = hfa384x_drvr_enable(hw, 0);
0690     if (result) {
0691         netdev_err(wlandev->netdev,
0692                "Enable macport failed, result=%d.\n", result);
0693         goto failed;
0694     }
0695 
0696     msg->resultcode.data = P80211ENUM_resultcode_success;
0697 
0698     goto done;
0699 failed:
0700     netdev_dbg(wlandev->netdev,
0701            "Failed to set a config option, result=%d\n", result);
0702     msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
0703 
0704 done:
0705     return 0;
0706 }
0707 
0708 /*----------------------------------------------------------------
0709  * prism2mgmt_readpda
0710  *
0711  * Collect the PDA data and put it in the message.
0712  *
0713  * Arguments:
0714  *  wlandev     wlan device structure
0715  *  msgp        ptr to msg buffer
0716  *
0717  * Returns:
0718  *  0   success and done
0719  *  <0  success, but we're waiting for something to finish.
0720  *  >0  an error occurred while handling the message.
0721  * Side effects:
0722  *
0723  * Call context:
0724  *  process thread  (usually)
0725  *----------------------------------------------------------------
0726  */
0727 int prism2mgmt_readpda(struct wlandevice *wlandev, void *msgp)
0728 {
0729     struct hfa384x *hw = wlandev->priv;
0730     struct p80211msg_p2req_readpda *msg = msgp;
0731     int result;
0732 
0733     /* We only support collecting the PDA when in the FWLOAD
0734      * state.
0735      */
0736     if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
0737         netdev_err(wlandev->netdev,
0738                "PDA may only be read in the fwload state.\n");
0739         msg->resultcode.data =
0740             P80211ENUM_resultcode_implementation_failure;
0741         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0742     } else {
0743         /*  Call drvr_readpda(), it handles the auxport enable
0744          *  and validating the returned PDA.
0745          */
0746         result = hfa384x_drvr_readpda(hw,
0747                           msg->pda.data,
0748                           HFA384x_PDA_LEN_MAX);
0749         if (result) {
0750             netdev_err(wlandev->netdev,
0751                    "hfa384x_drvr_readpda() failed, result=%d\n",
0752                    result);
0753 
0754             msg->resultcode.data =
0755                 P80211ENUM_resultcode_implementation_failure;
0756             msg->resultcode.status =
0757                 P80211ENUM_msgitem_status_data_ok;
0758             return 0;
0759         }
0760         msg->pda.status = P80211ENUM_msgitem_status_data_ok;
0761         msg->resultcode.data = P80211ENUM_resultcode_success;
0762         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0763     }
0764 
0765     return 0;
0766 }
0767 
0768 /*----------------------------------------------------------------
0769  * prism2mgmt_ramdl_state
0770  *
0771  * Establishes the beginning/end of a card RAM download session.
0772  *
0773  * It is expected that the ramdl_write() function will be called
0774  * one or more times between the 'enable' and 'disable' calls to
0775  * this function.
0776  *
0777  * Note: This function should not be called when a mac comm port
0778  *       is active.
0779  *
0780  * Arguments:
0781  *  wlandev     wlan device structure
0782  *  msgp        ptr to msg buffer
0783  *
0784  * Returns:
0785  *  0   success and done
0786  *  <0  success, but we're waiting for something to finish.
0787  *  >0  an error occurred while handling the message.
0788  * Side effects:
0789  *
0790  * Call context:
0791  *  process thread  (usually)
0792  *----------------------------------------------------------------
0793  */
0794 int prism2mgmt_ramdl_state(struct wlandevice *wlandev, void *msgp)
0795 {
0796     struct hfa384x *hw = wlandev->priv;
0797     struct p80211msg_p2req_ramdl_state *msg = msgp;
0798 
0799     if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
0800         netdev_err(wlandev->netdev,
0801                "ramdl_state(): may only be called in the fwload state.\n");
0802         msg->resultcode.data =
0803             P80211ENUM_resultcode_implementation_failure;
0804         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0805         return 0;
0806     }
0807 
0808     /*
0809      ** Note: Interrupts are locked out if this is an AP and are NOT
0810      ** locked out if this is a station.
0811      */
0812 
0813     msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0814     if (msg->enable.data == P80211ENUM_truth_true) {
0815         if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) {
0816             msg->resultcode.data =
0817                 P80211ENUM_resultcode_implementation_failure;
0818         } else {
0819             msg->resultcode.data = P80211ENUM_resultcode_success;
0820         }
0821     } else {
0822         hfa384x_drvr_ramdl_disable(hw);
0823         msg->resultcode.data = P80211ENUM_resultcode_success;
0824     }
0825 
0826     return 0;
0827 }
0828 
0829 /*----------------------------------------------------------------
0830  * prism2mgmt_ramdl_write
0831  *
0832  * Writes a buffer to the card RAM using the download state.  This
0833  * is for writing code to card RAM.  To just read or write raw data
0834  * use the aux functions.
0835  *
0836  * Arguments:
0837  *  wlandev     wlan device structure
0838  *  msgp        ptr to msg buffer
0839  *
0840  * Returns:
0841  *  0   success and done
0842  *  <0  success, but we're waiting for something to finish.
0843  *  >0  an error occurred while handling the message.
0844  * Side effects:
0845  *
0846  * Call context:
0847  *  process thread  (usually)
0848  *----------------------------------------------------------------
0849  */
0850 int prism2mgmt_ramdl_write(struct wlandevice *wlandev, void *msgp)
0851 {
0852     struct hfa384x *hw = wlandev->priv;
0853     struct p80211msg_p2req_ramdl_write *msg = msgp;
0854     u32 addr;
0855     u32 len;
0856     u8 *buf;
0857 
0858     if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
0859         netdev_err(wlandev->netdev,
0860                "ramdl_write(): may only be called in the fwload state.\n");
0861         msg->resultcode.data =
0862             P80211ENUM_resultcode_implementation_failure;
0863         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0864         return 0;
0865     }
0866 
0867     msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0868     /* first validate the length */
0869     if (msg->len.data > sizeof(msg->data.data)) {
0870         msg->resultcode.status =
0871             P80211ENUM_resultcode_invalid_parameters;
0872         return 0;
0873     }
0874     /* call the hfa384x function to do the write */
0875     addr = msg->addr.data;
0876     len = msg->len.data;
0877     buf = msg->data.data;
0878     if (hfa384x_drvr_ramdl_write(hw, addr, buf, len))
0879         msg->resultcode.data = P80211ENUM_resultcode_refused;
0880 
0881     msg->resultcode.data = P80211ENUM_resultcode_success;
0882 
0883     return 0;
0884 }
0885 
0886 /*----------------------------------------------------------------
0887  * prism2mgmt_flashdl_state
0888  *
0889  * Establishes the beginning/end of a card Flash download session.
0890  *
0891  * It is expected that the flashdl_write() function will be called
0892  * one or more times between the 'enable' and 'disable' calls to
0893  * this function.
0894  *
0895  * Note: This function should not be called when a mac comm port
0896  *       is active.
0897  *
0898  * Arguments:
0899  *  wlandev     wlan device structure
0900  *  msgp        ptr to msg buffer
0901  *
0902  * Returns:
0903  *  0   success and done
0904  *  <0  success, but we're waiting for something to finish.
0905  *  >0  an error occurred while handling the message.
0906  * Side effects:
0907  *
0908  * Call context:
0909  *  process thread  (usually)
0910  *----------------------------------------------------------------
0911  */
0912 int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp)
0913 {
0914     int result = 0;
0915     struct hfa384x *hw = wlandev->priv;
0916     struct p80211msg_p2req_flashdl_state *msg = msgp;
0917 
0918     if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
0919         netdev_err(wlandev->netdev,
0920                "flashdl_state(): may only be called in the fwload state.\n");
0921         msg->resultcode.data =
0922             P80211ENUM_resultcode_implementation_failure;
0923         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0924         return 0;
0925     }
0926 
0927     /*
0928      ** Note: Interrupts are locked out if this is an AP and are NOT
0929      ** locked out if this is a station.
0930      */
0931 
0932     msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0933     if (msg->enable.data == P80211ENUM_truth_true) {
0934         if (hfa384x_drvr_flashdl_enable(hw)) {
0935             msg->resultcode.data =
0936                 P80211ENUM_resultcode_implementation_failure;
0937         } else {
0938             msg->resultcode.data = P80211ENUM_resultcode_success;
0939         }
0940     } else {
0941         hfa384x_drvr_flashdl_disable(hw);
0942         msg->resultcode.data = P80211ENUM_resultcode_success;
0943         /* NOTE: At this point, the MAC is in the post-reset
0944          * state and the driver is in the fwload state.
0945          * We need to get the MAC back into the fwload
0946          * state.  To do this, we set the nsdstate to HWPRESENT
0947          * and then call the ifstate function to redo everything
0948          * that got us into the fwload state.
0949          */
0950         wlandev->msdstate = WLAN_MSD_HWPRESENT;
0951         result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
0952         if (result != P80211ENUM_resultcode_success) {
0953             netdev_err(wlandev->netdev,
0954                    "prism2sta_ifstate(fwload) failed, P80211ENUM_resultcode=%d\n",
0955                    result);
0956             msg->resultcode.data =
0957                 P80211ENUM_resultcode_implementation_failure;
0958             result = -1;
0959         }
0960     }
0961 
0962     return result;
0963 }
0964 
0965 /*----------------------------------------------------------------
0966  * prism2mgmt_flashdl_write
0967  *
0968  *
0969  *
0970  * Arguments:
0971  *  wlandev     wlan device structure
0972  *  msgp        ptr to msg buffer
0973  *
0974  * Returns:
0975  *  0   success and done
0976  *  <0  success, but we're waiting for something to finish.
0977  *  >0  an error occurred while handling the message.
0978  * Side effects:
0979  *
0980  * Call context:
0981  *  process thread  (usually)
0982  *----------------------------------------------------------------
0983  */
0984 int prism2mgmt_flashdl_write(struct wlandevice *wlandev, void *msgp)
0985 {
0986     struct hfa384x *hw = wlandev->priv;
0987     struct p80211msg_p2req_flashdl_write *msg = msgp;
0988     u32 addr;
0989     u32 len;
0990     u8 *buf;
0991 
0992     if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
0993         netdev_err(wlandev->netdev,
0994                "flashdl_write(): may only be called in the fwload state.\n");
0995         msg->resultcode.data =
0996             P80211ENUM_resultcode_implementation_failure;
0997         msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
0998         return 0;
0999     }
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  */
1045 int 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  */
1117 int 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 
1353 failed:
1354     msg->resultcode.data = P80211ENUM_resultcode_refused;
1355     return 0;
1356 }