1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2 /* src/prism2/driver/prism2mgmt.c
3  *
4  * Management request handler functions.
5  *
6  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
7  * --------------------------------------------------------------------
8  *
9  * linux-wlan
10  *
11  *   The contents of this file are subject to the Mozilla Public
12  *   License Version 1.1 (the "License"); you may not use this file
13  *   except in compliance with the License. You may obtain a copy of
14  *   the License at http://www.mozilla.org/MPL/
15  *
16  *   Software distributed under the License is distributed on an "AS
17  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
18  *   implied. See the License for the specific language governing
19  *   rights and limitations under the License.
20  *
21  *   Alternatively, the contents of this file may be used under the
22  *   terms of the GNU Public License version 2 (the "GPL"), in which
23  *   case the provisions of the GPL are applicable instead of the
24  *   above.  If you wish to allow the use of your version of this file
25  *   only under the terms of the GPL and not to allow others to use
26  *   your version of this file under the MPL, indicate your decision
27  *   by deleting the provisions above and replace them with the notice
28  *   and other provisions required by the GPL.  If you do not delete
29  *   the provisions above, a recipient may use your version of this
30  *   file under either the MPL or the GPL.
31  *
32  * --------------------------------------------------------------------
33  *
34  * Inquiries regarding the linux-wlan Open Source project can be
35  * made directly to:
36  *
37  * AbsoluteValue Systems Inc.
38  * info@linux-wlan.com
39  * http://www.linux-wlan.com
40  *
41  * --------------------------------------------------------------------
42  *
43  * Portions of the development of this software were funded by
44  * Intersil Corporation as part of PRISM(R) chipset product development.
45  *
46  * --------------------------------------------------------------------
47  *
48  * The functions in this file handle management requests sent from
49  * user mode.
50  *
51  * Most of these functions have two separate blocks of code that are
52  * conditional on whether this is a station or an AP.  This is used
53  * to separate out the STA and AP responses to these management primitives.
54  * It's a choice (good, bad, indifferent?) to have the code in the same
55  * place so it's clear that the same primitive is implemented in both
56  * cases but has different behavior.
57  *
58  * --------------------------------------------------------------------
59  */
60 
61 #include <linux/if_arp.h>
62 #include <linux/module.h>
63 #include <linux/kernel.h>
64 #include <linux/wait.h>
65 #include <linux/sched.h>
66 #include <linux/types.h>
67 #include <linux/wireless.h>
68 #include <linux/netdevice.h>
69 #include <linux/delay.h>
70 #include <linux/io.h>
71 #include <asm/byteorder.h>
72 #include <linux/random.h>
73 #include <linux/usb.h>
74 #include <linux/bitops.h>
75 
76 #include "p80211types.h"
77 #include "p80211hdr.h"
78 #include "p80211mgmt.h"
79 #include "p80211conv.h"
80 #include "p80211msg.h"
81 #include "p80211netdev.h"
82 #include "p80211metadef.h"
83 #include "p80211metastruct.h"
84 #include "hfa384x.h"
85 #include "prism2mgmt.h"
86 
87 /* Converts 802.11 format rate specifications to prism2 */
p80211rate_to_p2bit(u32 rate)88 static 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  */
prism2mgmt_scan(struct wlandevice * wlandev,void * msgp)129 int 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 
356 exit:
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  */
prism2mgmt_scan_results(struct wlandevice * wlandev,void * msgp)383 int 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 
520 exit:
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  */
prism2mgmt_start(struct wlandevice * wlandev,void * msgp)544 int 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;
699 failed:
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 
704 done:
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  */
prism2mgmt_readpda(struct wlandevice * wlandev,void * msgp)727 int 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  */
prism2mgmt_ramdl_state(struct wlandevice * wlandev,void * msgp)794 int 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  */
prism2mgmt_ramdl_write(struct wlandevice * wlandev,void * msgp)850 int 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  */
prism2mgmt_flashdl_state(struct wlandevice * wlandev,void * msgp)912 int 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  */
prism2mgmt_flashdl_write(struct wlandevice * wlandev,void * msgp)984 int 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  */
prism2mgmt_autojoin(struct wlandevice * wlandev,void * msgp)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  */
prism2mgmt_wlansniff(struct wlandevice * wlandev,void * msgp)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 }
1357