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