cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

prism2mgmt.c (38974B)


      1// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
      2/*
      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 result;
    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}