• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/wlan-ng/
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 = P80211ENUM_msgitem_status_data_ok; \
420	}
421
422	REQBASICRATE(1);
423	REQBASICRATE(2);
424	REQBASICRATE(3);
425	REQBASICRATE(4);
426	REQBASICRATE(5);
427	REQBASICRATE(6);
428	REQBASICRATE(7);
429	REQBASICRATE(8);
430
431#define REQSUPPRATE(N) \
432	if (count >= N) { \
433		req->supprate ## N .data = item->supprates[(N)-1]; \
434		req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \
435	}
436
437	REQSUPPRATE(1);
438	REQSUPPRATE(2);
439	REQSUPPRATE(3);
440	REQSUPPRATE(4);
441	REQSUPPRATE(5);
442	REQSUPPRATE(6);
443	REQSUPPRATE(7);
444	REQSUPPRATE(8);
445
446	/* beacon period */
447	req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok;
448	req->beaconperiod.data = le16_to_cpu(item->bcnint);
449
450	/* timestamps */
451	req->timestamp.status = P80211ENUM_msgitem_status_data_ok;
452	req->timestamp.data = jiffies;
453	req->localtime.status = P80211ENUM_msgitem_status_data_ok;
454	req->localtime.data = jiffies;
455
456	/* atim window */
457	req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok;
458	req->ibssatimwindow.data = le16_to_cpu(item->atim);
459
460	/* Channel */
461	req->dschannel.status = P80211ENUM_msgitem_status_data_ok;
462	req->dschannel.data = le16_to_cpu(item->chid);
463
464	/* capinfo bits */
465	count = le16_to_cpu(item->capinfo);
466	req->capinfo.status = P80211ENUM_msgitem_status_data_ok;
467	req->capinfo.data = count;
468
469	/* privacy flag */
470	req->privacy.status = P80211ENUM_msgitem_status_data_ok;
471	req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count);
472
473	/* cfpollable */
474	req->cfpollable.status = P80211ENUM_msgitem_status_data_ok;
475	req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count);
476
477	/* cfpollreq */
478	req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok;
479	req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count);
480
481	/* bsstype */
482	req->bsstype.status = P80211ENUM_msgitem_status_data_ok;
483	req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ?
484	    P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent;
485
486	result = 0;
487	req->resultcode.data = P80211ENUM_resultcode_success;
488
489exit:
490	return result;
491}
492
493/*----------------------------------------------------------------
494* prism2mgmt_start
495*
496* Start a BSS.  Any station can do this for IBSS, only AP for ESS.
497*
498* Arguments:
499*	wlandev		wlan device structure
500*	msgp		ptr to msg buffer
501*
502* Returns:
503*	0	success and done
504*	<0	success, but we're waiting for something to finish.
505*	>0	an error occurred while handling the message.
506* Side effects:
507*
508* Call context:
509*	process thread  (usually)
510*	interrupt
511----------------------------------------------------------------*/
512int prism2mgmt_start(wlandevice_t *wlandev, void *msgp)
513{
514	int result = 0;
515	hfa384x_t *hw = wlandev->priv;
516	struct p80211msg_dot11req_start *msg = msgp;
517
518	p80211pstrd_t *pstr;
519	u8 bytebuf[80];
520	hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t *) bytebuf;
521	u16 word;
522
523	wlandev->macmode = WLAN_MACMODE_NONE;
524
525	/* Set the SSID */
526	memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
527
528	/*** ADHOC IBSS ***/
529	/* see if current f/w is less than 8c3 */
530	if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
531				     hw->ident_sta_fw.minor,
532				     hw->ident_sta_fw.variant) <
533	    HFA384x_FIRMWARE_VERSION(0, 8, 3)) {
534		/* Ad-Hoc not quite supported on Prism2 */
535		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
536		msg->resultcode.data = P80211ENUM_resultcode_not_supported;
537		goto done;
538	}
539
540	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
541
542	/*** STATION ***/
543	/* Set the REQUIRED config items */
544	/* SSID */
545	pstr = (p80211pstrd_t *) &(msg->ssid.data);
546	prism2mgmt_pstr2bytestr(p2bytestr, pstr);
547	result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
548					bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
549	if (result) {
550		printk(KERN_ERR "Failed to set CnfOwnSSID\n");
551		goto failed;
552	}
553	result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
554					bytebuf,
555					HFA384x_RID_CNFDESIREDSSID_LEN);
556	if (result) {
557		printk(KERN_ERR "Failed to set CnfDesiredSSID\n");
558		goto failed;
559	}
560
561	/* bsstype - we use the default in the ap firmware */
562	/* IBSS port */
563	hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0);
564
565	/* beacon period */
566	word = msg->beaconperiod.data;
567	result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNint, word);
568	if (result) {
569		printk(KERN_ERR "Failed to set beacon period=%d.\n", word);
570		goto failed;
571	}
572
573	/* dschannel */
574	word = msg->dschannel.data;
575	result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word);
576	if (result) {
577		printk(KERN_ERR "Failed to set channel=%d.\n", word);
578		goto failed;
579	}
580	/* Basic rates */
581	word = p80211rate_to_p2bit(msg->basicrate1.data);
582	if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok)
583		word |= p80211rate_to_p2bit(msg->basicrate2.data);
584
585	if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok)
586		word |= p80211rate_to_p2bit(msg->basicrate3.data);
587
588	if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok)
589		word |= p80211rate_to_p2bit(msg->basicrate4.data);
590
591	if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok)
592		word |= p80211rate_to_p2bit(msg->basicrate5.data);
593
594	if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok)
595		word |= p80211rate_to_p2bit(msg->basicrate6.data);
596
597	if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok)
598		word |= p80211rate_to_p2bit(msg->basicrate7.data);
599
600	if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok)
601		word |= p80211rate_to_p2bit(msg->basicrate8.data);
602
603	result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word);
604	if (result) {
605		printk(KERN_ERR "Failed to set basicrates=%d.\n", word);
606		goto failed;
607	}
608
609	/* Operational rates (supprates and txratecontrol) */
610	word = p80211rate_to_p2bit(msg->operationalrate1.data);
611	if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok)
612		word |= p80211rate_to_p2bit(msg->operationalrate2.data);
613
614	if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok)
615		word |= p80211rate_to_p2bit(msg->operationalrate3.data);
616
617	if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok)
618		word |= p80211rate_to_p2bit(msg->operationalrate4.data);
619
620	if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok)
621		word |= p80211rate_to_p2bit(msg->operationalrate5.data);
622
623	if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok)
624		word |= p80211rate_to_p2bit(msg->operationalrate6.data);
625
626	if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok)
627		word |= p80211rate_to_p2bit(msg->operationalrate7.data);
628
629	if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok)
630		word |= p80211rate_to_p2bit(msg->operationalrate8.data);
631
632	result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word);
633	if (result) {
634		printk(KERN_ERR "Failed to set supprates=%d.\n", word);
635		goto failed;
636	}
637
638	result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word);
639	if (result) {
640		printk(KERN_ERR "Failed to set txrates=%d.\n", word);
641		goto failed;
642	}
643
644	/* Set the macmode so the frame setup code knows what to do */
645	if (msg->bsstype.data == P80211ENUM_bsstype_independent) {
646		wlandev->macmode = WLAN_MACMODE_IBSS_STA;
647		/* lets extend the data length a bit */
648		hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304);
649	}
650
651	/* Enable the Port */
652	result = hfa384x_drvr_enable(hw, 0);
653	if (result) {
654		printk(KERN_ERR "Enable macport failed, result=%d.\n", result);
655		goto failed;
656	}
657
658	msg->resultcode.data = P80211ENUM_resultcode_success;
659
660	goto done;
661failed:
662	pr_debug("Failed to set a config option, result=%d\n", result);
663	msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
664
665done:
666	result = 0;
667
668	return result;
669}
670
671/*----------------------------------------------------------------
672* prism2mgmt_readpda
673*
674* Collect the PDA data and put it in the message.
675*
676* Arguments:
677*	wlandev		wlan device structure
678*	msgp		ptr to msg buffer
679*
680* Returns:
681*	0	success and done
682*	<0	success, but we're waiting for something to finish.
683*	>0	an error occurred while handling the message.
684* Side effects:
685*
686* Call context:
687*	process thread  (usually)
688----------------------------------------------------------------*/
689int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp)
690{
691	hfa384x_t *hw = wlandev->priv;
692	struct p80211msg_p2req_readpda *msg = msgp;
693	int result;
694
695	/* We only support collecting the PDA when in the FWLOAD
696	 * state.
697	 */
698	if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
699		printk(KERN_ERR
700		       "PDA may only be read " "in the fwload state.\n");
701		msg->resultcode.data =
702		    P80211ENUM_resultcode_implementation_failure;
703		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
704	} else {
705		/*  Call drvr_readpda(), it handles the auxport enable
706		 *  and validating the returned PDA.
707		 */
708		result = hfa384x_drvr_readpda(hw,
709					      msg->pda.data,
710					      HFA384x_PDA_LEN_MAX);
711		if (result) {
712			printk(KERN_ERR
713			       "hfa384x_drvr_readpda() failed, "
714			       "result=%d\n", result);
715
716			msg->resultcode.data =
717			    P80211ENUM_resultcode_implementation_failure;
718			msg->resultcode.status =
719			    P80211ENUM_msgitem_status_data_ok;
720			return 0;
721		}
722		msg->pda.status = P80211ENUM_msgitem_status_data_ok;
723		msg->resultcode.data = P80211ENUM_resultcode_success;
724		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
725	}
726
727	return 0;
728}
729
730/*----------------------------------------------------------------
731* prism2mgmt_ramdl_state
732*
733* Establishes the beginning/end of a card RAM download session.
734*
735* It is expected that the ramdl_write() function will be called
736* one or more times between the 'enable' and 'disable' calls to
737* this function.
738*
739* Note: This function should not be called when a mac comm port
740*       is active.
741*
742* Arguments:
743*	wlandev		wlan device structure
744*	msgp		ptr to msg buffer
745*
746* Returns:
747*	0	success and done
748*	<0	success, but we're waiting for something to finish.
749*	>0	an error occurred while handling the message.
750* Side effects:
751*
752* Call context:
753*	process thread  (usually)
754----------------------------------------------------------------*/
755int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp)
756{
757	hfa384x_t *hw = wlandev->priv;
758	struct p80211msg_p2req_ramdl_state *msg = msgp;
759
760	if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
761		printk(KERN_ERR
762		       "ramdl_state(): may only be called "
763		       "in the fwload state.\n");
764		msg->resultcode.data =
765		    P80211ENUM_resultcode_implementation_failure;
766		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
767		return 0;
768	}
769
770	/*
771	 ** Note: Interrupts are locked out if this is an AP and are NOT
772	 ** locked out if this is a station.
773	 */
774
775	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
776	if (msg->enable.data == P80211ENUM_truth_true) {
777		if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) {
778			msg->resultcode.data =
779			    P80211ENUM_resultcode_implementation_failure;
780		} else {
781			msg->resultcode.data = P80211ENUM_resultcode_success;
782		}
783	} else {
784		hfa384x_drvr_ramdl_disable(hw);
785		msg->resultcode.data = P80211ENUM_resultcode_success;
786	}
787
788	return 0;
789}
790
791/*----------------------------------------------------------------
792* prism2mgmt_ramdl_write
793*
794* Writes a buffer to the card RAM using the download state.  This
795* is for writing code to card RAM.  To just read or write raw data
796* use the aux functions.
797*
798* Arguments:
799*	wlandev		wlan device structure
800*	msgp		ptr to msg buffer
801*
802* Returns:
803*	0	success and done
804*	<0	success, but we're waiting for something to finish.
805*	>0	an error occurred while handling the message.
806* Side effects:
807*
808* Call context:
809*	process thread  (usually)
810----------------------------------------------------------------*/
811int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp)
812{
813	hfa384x_t *hw = wlandev->priv;
814	struct p80211msg_p2req_ramdl_write *msg = msgp;
815	u32 addr;
816	u32 len;
817	u8 *buf;
818
819	if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
820		printk(KERN_ERR
821		       "ramdl_write(): may only be called "
822		       "in the fwload state.\n");
823		msg->resultcode.data =
824		    P80211ENUM_resultcode_implementation_failure;
825		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
826		return 0;
827	}
828
829	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
830	/* first validate the length */
831	if (msg->len.data > sizeof(msg->data.data)) {
832		msg->resultcode.status =
833		    P80211ENUM_resultcode_invalid_parameters;
834		return 0;
835	}
836	/* call the hfa384x function to do the write */
837	addr = msg->addr.data;
838	len = msg->len.data;
839	buf = msg->data.data;
840	if (hfa384x_drvr_ramdl_write(hw, addr, buf, len))
841		msg->resultcode.data = P80211ENUM_resultcode_refused;
842
843	msg->resultcode.data = P80211ENUM_resultcode_success;
844
845	return 0;
846}
847
848/*----------------------------------------------------------------
849* prism2mgmt_flashdl_state
850*
851* Establishes the beginning/end of a card Flash download session.
852*
853* It is expected that the flashdl_write() function will be called
854* one or more times between the 'enable' and 'disable' calls to
855* this function.
856*
857* Note: This function should not be called when a mac comm port
858*       is active.
859*
860* Arguments:
861*	wlandev		wlan device structure
862*	msgp		ptr to msg buffer
863*
864* Returns:
865*	0	success and done
866*	<0	success, but we're waiting for something to finish.
867*	>0	an error occurred while handling the message.
868* Side effects:
869*
870* Call context:
871*	process thread  (usually)
872----------------------------------------------------------------*/
873int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp)
874{
875	int result = 0;
876	hfa384x_t *hw = wlandev->priv;
877	struct p80211msg_p2req_flashdl_state *msg = msgp;
878
879	if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
880		printk(KERN_ERR
881		       "flashdl_state(): may only be called "
882		       "in the fwload state.\n");
883		msg->resultcode.data =
884		    P80211ENUM_resultcode_implementation_failure;
885		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
886		return 0;
887	}
888
889	/*
890	 ** Note: Interrupts are locked out if this is an AP and are NOT
891	 ** locked out if this is a station.
892	 */
893
894	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
895	if (msg->enable.data == P80211ENUM_truth_true) {
896		if (hfa384x_drvr_flashdl_enable(hw)) {
897			msg->resultcode.data =
898			    P80211ENUM_resultcode_implementation_failure;
899		} else {
900			msg->resultcode.data = P80211ENUM_resultcode_success;
901		}
902	} else {
903		hfa384x_drvr_flashdl_disable(hw);
904		msg->resultcode.data = P80211ENUM_resultcode_success;
905		/* NOTE: At this point, the MAC is in the post-reset
906		 * state and the driver is in the fwload state.
907		 * We need to get the MAC back into the fwload
908		 * state.  To do this, we set the nsdstate to HWPRESENT
909		 * and then call the ifstate function to redo everything
910		 * that got us into the fwload state.
911		 */
912		wlandev->msdstate = WLAN_MSD_HWPRESENT;
913		result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
914		if (result != P80211ENUM_resultcode_success) {
915			printk(KERN_ERR "prism2sta_ifstate(fwload) failed,"
916			       "P80211ENUM_resultcode=%d\n", result);
917			msg->resultcode.data =
918			    P80211ENUM_resultcode_implementation_failure;
919			result = -1;
920		}
921	}
922
923	return 0;
924}
925
926/*----------------------------------------------------------------
927* prism2mgmt_flashdl_write
928*
929*
930*
931* Arguments:
932*	wlandev		wlan device structure
933*	msgp		ptr to msg buffer
934*
935* Returns:
936*	0	success and done
937*	<0	success, but we're waiting for something to finish.
938*	>0	an error occurred while handling the message.
939* Side effects:
940*
941* Call context:
942*	process thread  (usually)
943----------------------------------------------------------------*/
944int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp)
945{
946	hfa384x_t *hw = wlandev->priv;
947	struct p80211msg_p2req_flashdl_write *msg = msgp;
948	u32 addr;
949	u32 len;
950	u8 *buf;
951
952	if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
953		printk(KERN_ERR
954		       "flashdl_write(): may only be called "
955		       "in the fwload state.\n");
956		msg->resultcode.data =
957		    P80211ENUM_resultcode_implementation_failure;
958		msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
959		return 0;
960	}
961
962	/*
963	 ** Note: Interrupts are locked out if this is an AP and are NOT
964	 ** locked out if this is a station.
965	 */
966
967	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
968	/* first validate the length */
969	if (msg->len.data > sizeof(msg->data.data)) {
970		msg->resultcode.status =
971		    P80211ENUM_resultcode_invalid_parameters;
972		return 0;
973	}
974	/* call the hfa384x function to do the write */
975	addr = msg->addr.data;
976	len = msg->len.data;
977	buf = msg->data.data;
978	if (hfa384x_drvr_flashdl_write(hw, addr, buf, len))
979		msg->resultcode.data = P80211ENUM_resultcode_refused;
980
981	msg->resultcode.data = P80211ENUM_resultcode_success;
982
983	return 0;
984}
985
986/*----------------------------------------------------------------
987* prism2mgmt_autojoin
988*
989* Associate with an ESS.
990*
991* Arguments:
992*	wlandev		wlan device structure
993*	msgp		ptr to msg buffer
994*
995* Returns:
996*	0	success and done
997*	<0	success, but we're waiting for something to finish.
998*	>0	an error occurred while handling the message.
999* Side effects:
1000*
1001* Call context:
1002*	process thread  (usually)
1003*	interrupt
1004----------------------------------------------------------------*/
1005int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp)
1006{
1007	hfa384x_t *hw = wlandev->priv;
1008	int result = 0;
1009	u16 reg;
1010	u16 port_type;
1011	struct p80211msg_lnxreq_autojoin *msg = msgp;
1012	p80211pstrd_t *pstr;
1013	u8 bytebuf[256];
1014	hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t *) bytebuf;
1015
1016	wlandev->macmode = WLAN_MACMODE_NONE;
1017
1018	/* Set the SSID */
1019	memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
1020
1021	/* Disable the Port */
1022	hfa384x_drvr_disable(hw, 0);
1023
1024	/*** STATION ***/
1025	/* Set the TxRates */
1026	hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f);
1027
1028	/* Set the auth type */
1029	if (msg->authtype.data == P80211ENUM_authalg_sharedkey)
1030		reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY;
1031	else
1032		reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM;
1033
1034	hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg);
1035
1036	/* Set the ssid */
1037	memset(bytebuf, 0, 256);
1038	pstr = (p80211pstrd_t *) &(msg->ssid.data);
1039	prism2mgmt_pstr2bytestr(p2bytestr, pstr);
1040	result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
1041					bytebuf,
1042					HFA384x_RID_CNFDESIREDSSID_LEN);
1043	port_type = HFA384x_PORTTYPE_BSS;
1044	/* Set the PortType */
1045	hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type);
1046
1047	/* Enable the Port */
1048	hfa384x_drvr_enable(hw, 0);
1049
1050	/* Set the resultcode */
1051	msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1052	msg->resultcode.data = P80211ENUM_resultcode_success;
1053
1054	return result;
1055}
1056
1057/*----------------------------------------------------------------
1058* prism2mgmt_wlansniff
1059*
1060* Start or stop sniffing.
1061*
1062* Arguments:
1063*	wlandev		wlan device structure
1064*	msgp		ptr to msg buffer
1065*
1066* Returns:
1067*	0	success and done
1068*	<0	success, but we're waiting for something to finish.
1069*	>0	an error occurred while handling the message.
1070* Side effects:
1071*
1072* Call context:
1073*	process thread  (usually)
1074*	interrupt
1075----------------------------------------------------------------*/
1076int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
1077{
1078	int result = 0;
1079	struct p80211msg_lnxreq_wlansniff *msg = msgp;
1080
1081	hfa384x_t *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			result = 0;
1092			goto exit;
1093		}
1094		/* Disable monitor mode */
1095		result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE);
1096		if (result) {
1097			pr_debug("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			pr_debug
1105			    ("failed to disable port 0 after sniffing, result=%d\n",
1106			     result);
1107			goto failed;
1108		}
1109		/* Clear the driver state */
1110		wlandev->netdev->type = ARPHRD_ETHER;
1111
1112		/* Restore the wepflags */
1113		result = hfa384x_drvr_setconfig16(hw,
1114						  HFA384x_RID_CNFWEPFLAGS,
1115						  hw->presniff_wepflags);
1116		if (result) {
1117			pr_debug
1118			    ("failed to restore wepflags=0x%04x, result=%d\n",
1119			     hw->presniff_wepflags, result);
1120			goto failed;
1121		}
1122
1123		/* Set the port to its prior type and enable (if necessary) */
1124		if (hw->presniff_port_type != 0) {
1125			word = hw->presniff_port_type;
1126			result = hfa384x_drvr_setconfig16(hw,
1127						  HFA384x_RID_CNFPORTTYPE,
1128						  word);
1129			if (result) {
1130				pr_debug
1131				    ("failed to restore porttype, result=%d\n",
1132				     result);
1133				goto failed;
1134			}
1135
1136			/* Enable the port */
1137			result = hfa384x_drvr_enable(hw, 0);
1138			if (result) {
1139				pr_debug
1140				    ("failed to enable port to presniff setting, result=%d\n",
1141				     result);
1142				goto failed;
1143			}
1144		} else {
1145			result = hfa384x_drvr_disable(hw, 0);
1146
1147		}
1148
1149		printk(KERN_INFO "monitor mode disabled\n");
1150		msg->resultcode.data = P80211ENUM_resultcode_success;
1151		result = 0;
1152		goto exit;
1153		break;
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					pr_debug
1164					    ("failed to read porttype, result=%d\n",
1165					     result);
1166					goto failed;
1167				}
1168				/* Save the wepflags state */
1169				result = hfa384x_drvr_getconfig16(hw,
1170						  HFA384x_RID_CNFWEPFLAGS,
1171						  &(hw->presniff_wepflags));
1172				if (result) {
1173					pr_debug
1174					    ("failed to read wepflags, result=%d\n",
1175					     result);
1176					goto failed;
1177				}
1178				hfa384x_drvr_stop(hw);
1179				result = hfa384x_drvr_start(hw);
1180				if (result) {
1181					pr_debug
1182					    ("failed to restart the card for sniffing, result=%d\n",
1183					     result);
1184					goto failed;
1185				}
1186			} else {
1187				/* Disable the port */
1188				result = hfa384x_drvr_disable(hw, 0);
1189				if (result) {
1190					pr_debug
1191					    ("failed to enable port for sniffing, result=%d\n",
1192					     result);
1193					goto failed;
1194				}
1195			}
1196		} else {
1197			hw->presniff_port_type = 0;
1198		}
1199
1200		/* Set the channel we wish to sniff  */
1201		word = msg->channel.data;
1202		result = hfa384x_drvr_setconfig16(hw,
1203						  HFA384x_RID_CNFOWNCHANNEL,
1204						  word);
1205		hw->sniff_channel = word;
1206
1207		if (result) {
1208			pr_debug("failed to set channel %d, result=%d\n",
1209				 word, result);
1210			goto failed;
1211		}
1212
1213		/* Now if we're already sniffing, we can skip the rest */
1214		if (wlandev->netdev->type != ARPHRD_ETHER) {
1215			/* Set the port type to pIbss */
1216			word = HFA384x_PORTTYPE_PSUEDOIBSS;
1217			result = hfa384x_drvr_setconfig16(hw,
1218						  HFA384x_RID_CNFPORTTYPE,
1219						  word);
1220			if (result) {
1221				pr_debug
1222				    ("failed to set porttype %d, result=%d\n",
1223				     word, result);
1224				goto failed;
1225			}
1226			if ((msg->keepwepflags.status ==
1227			     P80211ENUM_msgitem_status_data_ok)
1228			    && (msg->keepwepflags.data !=
1229				P80211ENUM_truth_true)) {
1230				/* Set the wepflags for no decryption */
1231				word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT |
1232				    HFA384x_WEPFLAGS_DISABLE_RXCRYPT;
1233				result =
1234				    hfa384x_drvr_setconfig16(hw,
1235						     HFA384x_RID_CNFWEPFLAGS,
1236						     word);
1237			}
1238
1239			if (result) {
1240				pr_debug
1241				    ("failed to set wepflags=0x%04x, result=%d\n",
1242				     word, result);
1243				goto failed;
1244			}
1245		}
1246
1247		/* Do we want to strip the FCS in monitor mode? */
1248		if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok)
1249		    && (msg->stripfcs.data == P80211ENUM_truth_true)) {
1250			hw->sniff_fcs = 0;
1251		} else {
1252			hw->sniff_fcs = 1;
1253		}
1254
1255		/* Do we want to truncate the packets? */
1256		if (msg->packet_trunc.status ==
1257		    P80211ENUM_msgitem_status_data_ok) {
1258			hw->sniff_truncate = msg->packet_trunc.data;
1259		} else {
1260			hw->sniff_truncate = 0;
1261		}
1262
1263		/* Enable the port */
1264		result = hfa384x_drvr_enable(hw, 0);
1265		if (result) {
1266			pr_debug
1267			    ("failed to enable port for sniffing, result=%d\n",
1268			     result);
1269			goto failed;
1270		}
1271		/* Enable monitor mode */
1272		result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE);
1273		if (result) {
1274			pr_debug("failed to enable monitor mode, result=%d\n",
1275				 result);
1276			goto failed;
1277		}
1278
1279		if (wlandev->netdev->type == ARPHRD_ETHER)
1280			printk(KERN_INFO "monitor mode enabled\n");
1281
1282		/* Set the driver state */
1283		/* Do we want the prism2 header? */
1284		if ((msg->prismheader.status ==
1285		     P80211ENUM_msgitem_status_data_ok)
1286		    && (msg->prismheader.data == P80211ENUM_truth_true)) {
1287			hw->sniffhdr = 0;
1288			wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1289		} else
1290		    if ((msg->wlanheader.status ==
1291			 P80211ENUM_msgitem_status_data_ok)
1292			&& (msg->wlanheader.data == P80211ENUM_truth_true)) {
1293			hw->sniffhdr = 1;
1294			wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1295		} else {
1296			wlandev->netdev->type = ARPHRD_IEEE80211;
1297		}
1298
1299		msg->resultcode.data = P80211ENUM_resultcode_success;
1300		result = 0;
1301		goto exit;
1302		break;
1303	default:
1304		msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
1305		result = 0;
1306		goto exit;
1307		break;
1308	}
1309
1310failed:
1311	msg->resultcode.data = P80211ENUM_resultcode_refused;
1312	result = 0;
1313exit:
1314	return result;
1315}
1316