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