gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / staging / wlan-ng / prism2mgmt.c
bloba8860d2aee6836a55f28889ea327a0c35bfc78c4
1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2 /* src/prism2/driver/prism2mgmt.c
4 * Management request handler functions.
6 * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
7 * --------------------------------------------------------------------
9 * linux-wlan
11 * The contents of this file are subject to the Mozilla Public
12 * License Version 1.1 (the "License"); you may not use this file
13 * except in compliance with the License. You may obtain a copy of
14 * the License at http://www.mozilla.org/MPL/
16 * Software distributed under the License is distributed on an "AS
17 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
18 * implied. See the License for the specific language governing
19 * rights and limitations under the License.
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU Public License version 2 (the "GPL"), in which
23 * case the provisions of the GPL are applicable instead of the
24 * above. If you wish to allow the use of your version of this file
25 * only under the terms of the GPL and not to allow others to use
26 * your version of this file under the MPL, indicate your decision
27 * by deleting the provisions above and replace them with the notice
28 * and other provisions required by the GPL. If you do not delete
29 * the provisions above, a recipient may use your version of this
30 * file under either the MPL or the GPL.
32 * --------------------------------------------------------------------
34 * Inquiries regarding the linux-wlan Open Source project can be
35 * made directly to:
37 * AbsoluteValue Systems Inc.
38 * info@linux-wlan.com
39 * http://www.linux-wlan.com
41 * --------------------------------------------------------------------
43 * Portions of the development of this software were funded by
44 * Intersil Corporation as part of PRISM(R) chipset product development.
46 * --------------------------------------------------------------------
48 * The functions in this file handle management requests sent from
49 * user mode.
51 * Most of these functions have two separate blocks of code that are
52 * conditional on whether this is a station or an AP. This is used
53 * to separate out the STA and AP responses to these management primitives.
54 * It's a choice (good, bad, indifferent?) to have the code in the same
55 * place so it's clear that the same primitive is implemented in both
56 * cases but has different behavior.
58 * --------------------------------------------------------------------
61 #include <linux/if_arp.h>
62 #include <linux/module.h>
63 #include <linux/kernel.h>
64 #include <linux/wait.h>
65 #include <linux/sched.h>
66 #include <linux/types.h>
67 #include <linux/wireless.h>
68 #include <linux/netdevice.h>
69 #include <linux/delay.h>
70 #include <linux/io.h>
71 #include <asm/byteorder.h>
72 #include <linux/random.h>
73 #include <linux/usb.h>
74 #include <linux/bitops.h>
76 #include "p80211types.h"
77 #include "p80211hdr.h"
78 #include "p80211mgmt.h"
79 #include "p80211conv.h"
80 #include "p80211msg.h"
81 #include "p80211netdev.h"
82 #include "p80211metadef.h"
83 #include "p80211metastruct.h"
84 #include "hfa384x.h"
85 #include "prism2mgmt.h"
87 /* Converts 802.11 format rate specifications to prism2 */
88 static inline u16 p80211rate_to_p2bit(u32 rate)
90 switch (rate & ~BIT(7)) {
91 case 2:
92 return BIT(0);
93 case 4:
94 return BIT(1);
95 case 11:
96 return BIT(2);
97 case 22:
98 return BIT(3);
99 default:
100 return 0;
104 /*----------------------------------------------------------------
105 * prism2mgmt_scan
107 * Initiate a scan for BSSs.
109 * This function corresponds to MLME-scan.request and part of
110 * MLME-scan.confirm. As far as I can tell in the standard, there
111 * are no restrictions on when a scan.request may be issued. We have
112 * to handle in whatever state the driver/MAC happen to be.
114 * Arguments:
115 * wlandev wlan device structure
116 * msgp ptr to msg buffer
118 * Returns:
119 * 0 success and done
120 * <0 success, but we're waiting for something to finish.
121 * >0 an error occurred while handling the message.
122 * Side effects:
124 * Call context:
125 * process thread (usually)
126 * interrupt
127 *----------------------------------------------------------------
129 int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp)
131 int result = 0;
132 struct hfa384x *hw = wlandev->priv;
133 struct p80211msg_dot11req_scan *msg = msgp;
134 u16 roamingmode, word;
135 int i, timeout;
136 int istmpenable = 0;
138 struct hfa384x_host_scan_request_data scanreq;
140 /* gatekeeper check */
141 if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
142 hw->ident_sta_fw.minor,
143 hw->ident_sta_fw.variant) <
144 HFA384x_FIRMWARE_VERSION(1, 3, 2)) {
145 netdev_err(wlandev->netdev,
146 "HostScan not supported with current firmware (<1.3.2).\n");
147 result = 1;
148 msg->resultcode.data = P80211ENUM_resultcode_not_supported;
149 goto exit;
152 memset(&scanreq, 0, sizeof(scanreq));
154 /* save current roaming mode */
155 result = hfa384x_drvr_getconfig16(hw,
156 HFA384x_RID_CNFROAMINGMODE,
157 &roamingmode);
158 if (result) {
159 netdev_err(wlandev->netdev,
160 "getconfig(ROAMMODE) failed. result=%d\n", result);
161 msg->resultcode.data =
162 P80211ENUM_resultcode_implementation_failure;
163 goto exit;
166 /* drop into mode 3 for the scan */
167 result = hfa384x_drvr_setconfig16(hw,
168 HFA384x_RID_CNFROAMINGMODE,
169 HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
170 if (result) {
171 netdev_err(wlandev->netdev,
172 "setconfig(ROAMINGMODE) failed. result=%d\n",
173 result);
174 msg->resultcode.data =
175 P80211ENUM_resultcode_implementation_failure;
176 goto exit;
179 /* active or passive? */
180 if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
181 hw->ident_sta_fw.minor,
182 hw->ident_sta_fw.variant) >
183 HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
184 if (msg->scantype.data != P80211ENUM_scantype_active)
185 word = msg->maxchanneltime.data;
186 else
187 word = 0;
189 result =
190 hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL,
191 word);
192 if (result) {
193 netdev_warn(wlandev->netdev,
194 "Passive scan not supported with current firmware. (<1.5.1)\n");
198 /* set up the txrate to be 2MBPS. Should be fastest basicrate... */
199 word = HFA384x_RATEBIT_2;
200 scanreq.tx_rate = cpu_to_le16(word);
202 /* set up the channel list */
203 word = 0;
204 for (i = 0; i < msg->channellist.data.len; i++) {
205 u8 channel = msg->channellist.data.data[i];
207 if (channel > 14)
208 continue;
209 /* channel 1 is BIT 0 ... channel 14 is BIT 13 */
210 word |= (1 << (channel - 1));
212 scanreq.channel_list = cpu_to_le16(word);
214 /* set up the ssid, if present. */
215 scanreq.ssid.len = cpu_to_le16(msg->ssid.data.len);
216 memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len);
218 /* Enable the MAC port if it's not already enabled */
219 result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word);
220 if (result) {
221 netdev_err(wlandev->netdev,
222 "getconfig(PORTSTATUS) failed. result=%d\n", result);
223 msg->resultcode.data =
224 P80211ENUM_resultcode_implementation_failure;
225 goto exit;
227 if (word == HFA384x_PORTSTATUS_DISABLED) {
228 __le16 wordbuf[17];
230 result = hfa384x_drvr_setconfig16(hw,
231 HFA384x_RID_CNFROAMINGMODE,
232 HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
233 if (result) {
234 netdev_err(wlandev->netdev,
235 "setconfig(ROAMINGMODE) failed. result=%d\n",
236 result);
237 msg->resultcode.data =
238 P80211ENUM_resultcode_implementation_failure;
239 goto exit;
241 /* Construct a bogus SSID and assign it to OwnSSID and
242 * DesiredSSID
244 wordbuf[0] = cpu_to_le16(WLAN_SSID_MAXLEN);
245 get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN);
246 result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
247 wordbuf,
248 HFA384x_RID_CNFOWNSSID_LEN);
249 if (result) {
250 netdev_err(wlandev->netdev, "Failed to set OwnSSID.\n");
251 msg->resultcode.data =
252 P80211ENUM_resultcode_implementation_failure;
253 goto exit;
255 result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
256 wordbuf,
257 HFA384x_RID_CNFDESIREDSSID_LEN);
258 if (result) {
259 netdev_err(wlandev->netdev,
260 "Failed to set DesiredSSID.\n");
261 msg->resultcode.data =
262 P80211ENUM_resultcode_implementation_failure;
263 goto exit;
265 /* bsstype */
266 result = hfa384x_drvr_setconfig16(hw,
267 HFA384x_RID_CNFPORTTYPE,
268 HFA384x_PORTTYPE_IBSS);
269 if (result) {
270 netdev_err(wlandev->netdev,
271 "Failed to set CNFPORTTYPE.\n");
272 msg->resultcode.data =
273 P80211ENUM_resultcode_implementation_failure;
274 goto exit;
276 /* ibss options */
277 result = hfa384x_drvr_setconfig16(hw,
278 HFA384x_RID_CREATEIBSS,
279 HFA384x_CREATEIBSS_JOINCREATEIBSS);
280 if (result) {
281 netdev_err(wlandev->netdev,
282 "Failed to set CREATEIBSS.\n");
283 msg->resultcode.data =
284 P80211ENUM_resultcode_implementation_failure;
285 goto exit;
287 result = hfa384x_drvr_enable(hw, 0);
288 if (result) {
289 netdev_err(wlandev->netdev,
290 "drvr_enable(0) failed. result=%d\n",
291 result);
292 msg->resultcode.data =
293 P80211ENUM_resultcode_implementation_failure;
294 goto exit;
296 istmpenable = 1;
299 /* Figure out our timeout first Kus, then HZ */
300 timeout = msg->channellist.data.len * msg->maxchanneltime.data;
301 timeout = (timeout * HZ) / 1000;
303 /* Issue the scan request */
304 hw->scanflag = 0;
306 result = hfa384x_drvr_setconfig(hw,
307 HFA384x_RID_HOSTSCAN, &scanreq,
308 sizeof(scanreq));
309 if (result) {
310 netdev_err(wlandev->netdev,
311 "setconfig(SCANREQUEST) failed. result=%d\n",
312 result);
313 msg->resultcode.data =
314 P80211ENUM_resultcode_implementation_failure;
315 goto exit;
318 /* sleep until info frame arrives */
319 wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout);
321 msg->numbss.status = P80211ENUM_msgitem_status_data_ok;
322 if (hw->scanflag == -1)
323 hw->scanflag = 0;
325 msg->numbss.data = hw->scanflag;
327 hw->scanflag = 0;
329 /* Disable port if we temporarily enabled it. */
330 if (istmpenable) {
331 result = hfa384x_drvr_disable(hw, 0);
332 if (result) {
333 netdev_err(wlandev->netdev,
334 "drvr_disable(0) failed. result=%d\n",
335 result);
336 msg->resultcode.data =
337 P80211ENUM_resultcode_implementation_failure;
338 goto exit;
342 /* restore original roaming mode */
343 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE,
344 roamingmode);
345 if (result) {
346 netdev_err(wlandev->netdev,
347 "setconfig(ROAMMODE) failed. result=%d\n", result);
348 msg->resultcode.data =
349 P80211ENUM_resultcode_implementation_failure;
350 goto exit;
353 result = 0;
354 msg->resultcode.data = P80211ENUM_resultcode_success;
356 exit:
357 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
359 return result;
362 /*----------------------------------------------------------------
363 * prism2mgmt_scan_results
365 * Retrieve the BSS description for one of the BSSs identified in
366 * a scan.
368 * Arguments:
369 * wlandev wlan device structure
370 * msgp ptr to msg buffer
372 * Returns:
373 * 0 success and done
374 * <0 success, but we're waiting for something to finish.
375 * >0 an error occurred while handling the message.
376 * Side effects:
378 * Call context:
379 * process thread (usually)
380 * interrupt
381 *----------------------------------------------------------------
383 int prism2mgmt_scan_results(struct wlandevice *wlandev, void *msgp)
385 int result = 0;
386 struct p80211msg_dot11req_scan_results *req;
387 struct hfa384x *hw = wlandev->priv;
388 struct hfa384x_hscan_result_sub *item = NULL;
390 int count;
392 req = msgp;
394 req->resultcode.status = P80211ENUM_msgitem_status_data_ok;
396 if (!hw->scanresults) {
397 netdev_err(wlandev->netdev,
398 "dot11req_scan_results can only be used after a successful dot11req_scan.\n");
399 result = 2;
400 req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
401 goto exit;
404 count = (hw->scanresults->framelen - 3) / 32;
405 if (count > HFA384x_SCANRESULT_MAX)
406 count = HFA384x_SCANRESULT_MAX;
408 if (req->bssindex.data >= count) {
409 netdev_dbg(wlandev->netdev,
410 "requested index (%d) out of range (%d)\n",
411 req->bssindex.data, count);
412 result = 2;
413 req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
414 goto exit;
417 item = &hw->scanresults->info.hscanresult.result[req->bssindex.data];
418 /* signal and noise */
419 req->signal.status = P80211ENUM_msgitem_status_data_ok;
420 req->noise.status = P80211ENUM_msgitem_status_data_ok;
421 req->signal.data = le16_to_cpu(item->sl);
422 req->noise.data = le16_to_cpu(item->anl);
424 /* BSSID */
425 req->bssid.status = P80211ENUM_msgitem_status_data_ok;
426 req->bssid.data.len = WLAN_BSSID_LEN;
427 memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN);
429 /* SSID */
430 req->ssid.status = P80211ENUM_msgitem_status_data_ok;
431 req->ssid.data.len = le16_to_cpu(item->ssid.len);
432 req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN);
433 memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);
435 /* supported rates */
436 for (count = 0; count < 10; count++)
437 if (item->supprates[count] == 0)
438 break;
440 #define REQBASICRATE(N) \
441 do { \
442 if ((count >= (N)) && DOT11_RATE5_ISBASIC_GET( \
443 item->supprates[(N) - 1])) { \
444 req->basicrate ## N .data = item->supprates[(N) - 1]; \
445 req->basicrate ## N .status = \
446 P80211ENUM_msgitem_status_data_ok; \
448 } while (0)
450 REQBASICRATE(1);
451 REQBASICRATE(2);
452 REQBASICRATE(3);
453 REQBASICRATE(4);
454 REQBASICRATE(5);
455 REQBASICRATE(6);
456 REQBASICRATE(7);
457 REQBASICRATE(8);
459 #define REQSUPPRATE(N) \
460 do { \
461 if (count >= (N)) { \
462 req->supprate ## N .data = item->supprates[(N) - 1]; \
463 req->supprate ## N .status = \
464 P80211ENUM_msgitem_status_data_ok; \
466 } while (0)
468 REQSUPPRATE(1);
469 REQSUPPRATE(2);
470 REQSUPPRATE(3);
471 REQSUPPRATE(4);
472 REQSUPPRATE(5);
473 REQSUPPRATE(6);
474 REQSUPPRATE(7);
475 REQSUPPRATE(8);
477 /* beacon period */
478 req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok;
479 req->beaconperiod.data = le16_to_cpu(item->bcnint);
481 /* timestamps */
482 req->timestamp.status = P80211ENUM_msgitem_status_data_ok;
483 req->timestamp.data = jiffies;
484 req->localtime.status = P80211ENUM_msgitem_status_data_ok;
485 req->localtime.data = jiffies;
487 /* atim window */
488 req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok;
489 req->ibssatimwindow.data = le16_to_cpu(item->atim);
491 /* Channel */
492 req->dschannel.status = P80211ENUM_msgitem_status_data_ok;
493 req->dschannel.data = le16_to_cpu(item->chid);
495 /* capinfo bits */
496 count = le16_to_cpu(item->capinfo);
497 req->capinfo.status = P80211ENUM_msgitem_status_data_ok;
498 req->capinfo.data = count;
500 /* privacy flag */
501 req->privacy.status = P80211ENUM_msgitem_status_data_ok;
502 req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count);
504 /* cfpollable */
505 req->cfpollable.status = P80211ENUM_msgitem_status_data_ok;
506 req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count);
508 /* cfpollreq */
509 req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok;
510 req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count);
512 /* bsstype */
513 req->bsstype.status = P80211ENUM_msgitem_status_data_ok;
514 req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ?
515 P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent;
517 result = 0;
518 req->resultcode.data = P80211ENUM_resultcode_success;
520 exit:
521 return result;
524 /*----------------------------------------------------------------
525 * prism2mgmt_start
527 * Start a BSS. Any station can do this for IBSS, only AP for ESS.
529 * Arguments:
530 * wlandev wlan device structure
531 * msgp ptr to msg buffer
533 * Returns:
534 * 0 success and done
535 * <0 success, but we're waiting for something to finish.
536 * >0 an error occurred while handling the message.
537 * Side effects:
539 * Call context:
540 * process thread (usually)
541 * interrupt
542 *----------------------------------------------------------------
544 int prism2mgmt_start(struct wlandevice *wlandev, void *msgp)
546 int result = 0;
547 struct hfa384x *hw = wlandev->priv;
548 struct p80211msg_dot11req_start *msg = msgp;
550 struct p80211pstrd *pstr;
551 u8 bytebuf[80];
552 struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf;
553 u16 word;
555 wlandev->macmode = WLAN_MACMODE_NONE;
557 /* Set the SSID */
558 memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
560 /*** ADHOC IBSS ***/
561 /* see if current f/w is less than 8c3 */
562 if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
563 hw->ident_sta_fw.minor,
564 hw->ident_sta_fw.variant) <
565 HFA384x_FIRMWARE_VERSION(0, 8, 3)) {
566 /* Ad-Hoc not quite supported on Prism2 */
567 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
568 msg->resultcode.data = P80211ENUM_resultcode_not_supported;
569 goto done;
572 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
574 /*** STATION ***/
575 /* Set the REQUIRED config items */
576 /* SSID */
577 pstr = (struct p80211pstrd *)&msg->ssid.data;
578 prism2mgmt_pstr2bytestr(p2bytestr, pstr);
579 result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
580 bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
581 if (result) {
582 netdev_err(wlandev->netdev, "Failed to set CnfOwnSSID\n");
583 goto failed;
585 result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
586 bytebuf,
587 HFA384x_RID_CNFDESIREDSSID_LEN);
588 if (result) {
589 netdev_err(wlandev->netdev, "Failed to set CnfDesiredSSID\n");
590 goto failed;
593 /* bsstype - we use the default in the ap firmware */
594 /* IBSS port */
595 hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0);
597 /* beacon period */
598 word = msg->beaconperiod.data;
599 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word);
600 if (result) {
601 netdev_err(wlandev->netdev,
602 "Failed to set beacon period=%d.\n", word);
603 goto failed;
606 /* dschannel */
607 word = msg->dschannel.data;
608 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word);
609 if (result) {
610 netdev_err(wlandev->netdev,
611 "Failed to set channel=%d.\n", word);
612 goto failed;
614 /* Basic rates */
615 word = p80211rate_to_p2bit(msg->basicrate1.data);
616 if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok)
617 word |= p80211rate_to_p2bit(msg->basicrate2.data);
619 if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok)
620 word |= p80211rate_to_p2bit(msg->basicrate3.data);
622 if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok)
623 word |= p80211rate_to_p2bit(msg->basicrate4.data);
625 if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok)
626 word |= p80211rate_to_p2bit(msg->basicrate5.data);
628 if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok)
629 word |= p80211rate_to_p2bit(msg->basicrate6.data);
631 if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok)
632 word |= p80211rate_to_p2bit(msg->basicrate7.data);
634 if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok)
635 word |= p80211rate_to_p2bit(msg->basicrate8.data);
637 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word);
638 if (result) {
639 netdev_err(wlandev->netdev,
640 "Failed to set basicrates=%d.\n", word);
641 goto failed;
644 /* Operational rates (supprates and txratecontrol) */
645 word = p80211rate_to_p2bit(msg->operationalrate1.data);
646 if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok)
647 word |= p80211rate_to_p2bit(msg->operationalrate2.data);
649 if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok)
650 word |= p80211rate_to_p2bit(msg->operationalrate3.data);
652 if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok)
653 word |= p80211rate_to_p2bit(msg->operationalrate4.data);
655 if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok)
656 word |= p80211rate_to_p2bit(msg->operationalrate5.data);
658 if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok)
659 word |= p80211rate_to_p2bit(msg->operationalrate6.data);
661 if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok)
662 word |= p80211rate_to_p2bit(msg->operationalrate7.data);
664 if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok)
665 word |= p80211rate_to_p2bit(msg->operationalrate8.data);
667 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word);
668 if (result) {
669 netdev_err(wlandev->netdev,
670 "Failed to set supprates=%d.\n", word);
671 goto failed;
674 result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word);
675 if (result) {
676 netdev_err(wlandev->netdev, "Failed to set txrates=%d.\n",
677 word);
678 goto failed;
681 /* Set the macmode so the frame setup code knows what to do */
682 if (msg->bsstype.data == P80211ENUM_bsstype_independent) {
683 wlandev->macmode = WLAN_MACMODE_IBSS_STA;
684 /* lets extend the data length a bit */
685 hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304);
688 /* Enable the Port */
689 result = hfa384x_drvr_enable(hw, 0);
690 if (result) {
691 netdev_err(wlandev->netdev,
692 "Enable macport failed, result=%d.\n", result);
693 goto failed;
696 msg->resultcode.data = P80211ENUM_resultcode_success;
698 goto done;
699 failed:
700 netdev_dbg(wlandev->netdev,
701 "Failed to set a config option, result=%d\n", result);
702 msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
704 done:
705 return 0;
708 /*----------------------------------------------------------------
709 * prism2mgmt_readpda
711 * Collect the PDA data and put it in the message.
713 * Arguments:
714 * wlandev wlan device structure
715 * msgp ptr to msg buffer
717 * Returns:
718 * 0 success and done
719 * <0 success, but we're waiting for something to finish.
720 * >0 an error occurred while handling the message.
721 * Side effects:
723 * Call context:
724 * process thread (usually)
725 *----------------------------------------------------------------
727 int prism2mgmt_readpda(struct wlandevice *wlandev, void *msgp)
729 struct hfa384x *hw = wlandev->priv;
730 struct p80211msg_p2req_readpda *msg = msgp;
731 int result;
733 /* We only support collecting the PDA when in the FWLOAD
734 * state.
736 if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
737 netdev_err(wlandev->netdev,
738 "PDA may only be read in the fwload state.\n");
739 msg->resultcode.data =
740 P80211ENUM_resultcode_implementation_failure;
741 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
742 } else {
743 /* Call drvr_readpda(), it handles the auxport enable
744 * and validating the returned PDA.
746 result = hfa384x_drvr_readpda(hw,
747 msg->pda.data,
748 HFA384x_PDA_LEN_MAX);
749 if (result) {
750 netdev_err(wlandev->netdev,
751 "hfa384x_drvr_readpda() failed, result=%d\n",
752 result);
754 msg->resultcode.data =
755 P80211ENUM_resultcode_implementation_failure;
756 msg->resultcode.status =
757 P80211ENUM_msgitem_status_data_ok;
758 return 0;
760 msg->pda.status = P80211ENUM_msgitem_status_data_ok;
761 msg->resultcode.data = P80211ENUM_resultcode_success;
762 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
765 return 0;
768 /*----------------------------------------------------------------
769 * prism2mgmt_ramdl_state
771 * Establishes the beginning/end of a card RAM download session.
773 * It is expected that the ramdl_write() function will be called
774 * one or more times between the 'enable' and 'disable' calls to
775 * this function.
777 * Note: This function should not be called when a mac comm port
778 * is active.
780 * Arguments:
781 * wlandev wlan device structure
782 * msgp ptr to msg buffer
784 * Returns:
785 * 0 success and done
786 * <0 success, but we're waiting for something to finish.
787 * >0 an error occurred while handling the message.
788 * Side effects:
790 * Call context:
791 * process thread (usually)
792 *----------------------------------------------------------------
794 int prism2mgmt_ramdl_state(struct wlandevice *wlandev, void *msgp)
796 struct hfa384x *hw = wlandev->priv;
797 struct p80211msg_p2req_ramdl_state *msg = msgp;
799 if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
800 netdev_err(wlandev->netdev,
801 "ramdl_state(): may only be called in the fwload state.\n");
802 msg->resultcode.data =
803 P80211ENUM_resultcode_implementation_failure;
804 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
805 return 0;
809 ** Note: Interrupts are locked out if this is an AP and are NOT
810 ** locked out if this is a station.
813 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
814 if (msg->enable.data == P80211ENUM_truth_true) {
815 if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) {
816 msg->resultcode.data =
817 P80211ENUM_resultcode_implementation_failure;
818 } else {
819 msg->resultcode.data = P80211ENUM_resultcode_success;
821 } else {
822 hfa384x_drvr_ramdl_disable(hw);
823 msg->resultcode.data = P80211ENUM_resultcode_success;
826 return 0;
829 /*----------------------------------------------------------------
830 * prism2mgmt_ramdl_write
832 * Writes a buffer to the card RAM using the download state. This
833 * is for writing code to card RAM. To just read or write raw data
834 * use the aux functions.
836 * Arguments:
837 * wlandev wlan device structure
838 * msgp ptr to msg buffer
840 * Returns:
841 * 0 success and done
842 * <0 success, but we're waiting for something to finish.
843 * >0 an error occurred while handling the message.
844 * Side effects:
846 * Call context:
847 * process thread (usually)
848 *----------------------------------------------------------------
850 int prism2mgmt_ramdl_write(struct wlandevice *wlandev, void *msgp)
852 struct hfa384x *hw = wlandev->priv;
853 struct p80211msg_p2req_ramdl_write *msg = msgp;
854 u32 addr;
855 u32 len;
856 u8 *buf;
858 if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
859 netdev_err(wlandev->netdev,
860 "ramdl_write(): may only be called in the fwload state.\n");
861 msg->resultcode.data =
862 P80211ENUM_resultcode_implementation_failure;
863 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
864 return 0;
867 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
868 /* first validate the length */
869 if (msg->len.data > sizeof(msg->data.data)) {
870 msg->resultcode.status =
871 P80211ENUM_resultcode_invalid_parameters;
872 return 0;
874 /* call the hfa384x function to do the write */
875 addr = msg->addr.data;
876 len = msg->len.data;
877 buf = msg->data.data;
878 if (hfa384x_drvr_ramdl_write(hw, addr, buf, len))
879 msg->resultcode.data = P80211ENUM_resultcode_refused;
881 msg->resultcode.data = P80211ENUM_resultcode_success;
883 return 0;
886 /*----------------------------------------------------------------
887 * prism2mgmt_flashdl_state
889 * Establishes the beginning/end of a card Flash download session.
891 * It is expected that the flashdl_write() function will be called
892 * one or more times between the 'enable' and 'disable' calls to
893 * this function.
895 * Note: This function should not be called when a mac comm port
896 * is active.
898 * Arguments:
899 * wlandev wlan device structure
900 * msgp ptr to msg buffer
902 * Returns:
903 * 0 success and done
904 * <0 success, but we're waiting for something to finish.
905 * >0 an error occurred while handling the message.
906 * Side effects:
908 * Call context:
909 * process thread (usually)
910 *----------------------------------------------------------------
912 int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp)
914 int result = 0;
915 struct hfa384x *hw = wlandev->priv;
916 struct p80211msg_p2req_flashdl_state *msg = msgp;
918 if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
919 netdev_err(wlandev->netdev,
920 "flashdl_state(): may only be called in the fwload state.\n");
921 msg->resultcode.data =
922 P80211ENUM_resultcode_implementation_failure;
923 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
924 return 0;
928 ** Note: Interrupts are locked out if this is an AP and are NOT
929 ** locked out if this is a station.
932 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
933 if (msg->enable.data == P80211ENUM_truth_true) {
934 if (hfa384x_drvr_flashdl_enable(hw)) {
935 msg->resultcode.data =
936 P80211ENUM_resultcode_implementation_failure;
937 } else {
938 msg->resultcode.data = P80211ENUM_resultcode_success;
940 } else {
941 hfa384x_drvr_flashdl_disable(hw);
942 msg->resultcode.data = P80211ENUM_resultcode_success;
943 /* NOTE: At this point, the MAC is in the post-reset
944 * state and the driver is in the fwload state.
945 * We need to get the MAC back into the fwload
946 * state. To do this, we set the nsdstate to HWPRESENT
947 * and then call the ifstate function to redo everything
948 * that got us into the fwload state.
950 wlandev->msdstate = WLAN_MSD_HWPRESENT;
951 result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
952 if (result != P80211ENUM_resultcode_success) {
953 netdev_err(wlandev->netdev,
954 "prism2sta_ifstate(fwload) failed, P80211ENUM_resultcode=%d\n",
955 result);
956 msg->resultcode.data =
957 P80211ENUM_resultcode_implementation_failure;
958 result = -1;
962 return result;
965 /*----------------------------------------------------------------
966 * prism2mgmt_flashdl_write
970 * Arguments:
971 * wlandev wlan device structure
972 * msgp ptr to msg buffer
974 * Returns:
975 * 0 success and done
976 * <0 success, but we're waiting for something to finish.
977 * >0 an error occurred while handling the message.
978 * Side effects:
980 * Call context:
981 * process thread (usually)
982 *----------------------------------------------------------------
984 int prism2mgmt_flashdl_write(struct wlandevice *wlandev, void *msgp)
986 struct hfa384x *hw = wlandev->priv;
987 struct p80211msg_p2req_flashdl_write *msg = msgp;
988 u32 addr;
989 u32 len;
990 u8 *buf;
992 if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
993 netdev_err(wlandev->netdev,
994 "flashdl_write(): may only be called in the fwload state.\n");
995 msg->resultcode.data =
996 P80211ENUM_resultcode_implementation_failure;
997 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
998 return 0;
1002 ** Note: Interrupts are locked out if this is an AP and are NOT
1003 ** locked out if this is a station.
1006 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1007 /* first validate the length */
1008 if (msg->len.data > sizeof(msg->data.data)) {
1009 msg->resultcode.status =
1010 P80211ENUM_resultcode_invalid_parameters;
1011 return 0;
1013 /* call the hfa384x function to do the write */
1014 addr = msg->addr.data;
1015 len = msg->len.data;
1016 buf = msg->data.data;
1017 if (hfa384x_drvr_flashdl_write(hw, addr, buf, len))
1018 msg->resultcode.data = P80211ENUM_resultcode_refused;
1020 msg->resultcode.data = P80211ENUM_resultcode_success;
1022 return 0;
1025 /*----------------------------------------------------------------
1026 * prism2mgmt_autojoin
1028 * Associate with an ESS.
1030 * Arguments:
1031 * wlandev wlan device structure
1032 * msgp ptr to msg buffer
1034 * Returns:
1035 * 0 success and done
1036 * <0 success, but we're waiting for something to finish.
1037 * >0 an error occurred while handling the message.
1038 * Side effects:
1040 * Call context:
1041 * process thread (usually)
1042 * interrupt
1043 *----------------------------------------------------------------
1045 int prism2mgmt_autojoin(struct wlandevice *wlandev, void *msgp)
1047 struct hfa384x *hw = wlandev->priv;
1048 int result = 0;
1049 u16 reg;
1050 u16 port_type;
1051 struct p80211msg_lnxreq_autojoin *msg = msgp;
1052 struct p80211pstrd *pstr;
1053 u8 bytebuf[256];
1054 struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf;
1056 wlandev->macmode = WLAN_MACMODE_NONE;
1058 /* Set the SSID */
1059 memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));
1061 /* Disable the Port */
1062 hfa384x_drvr_disable(hw, 0);
1064 /*** STATION ***/
1065 /* Set the TxRates */
1066 hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f);
1068 /* Set the auth type */
1069 if (msg->authtype.data == P80211ENUM_authalg_sharedkey)
1070 reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY;
1071 else
1072 reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM;
1074 hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg);
1076 /* Set the ssid */
1077 memset(bytebuf, 0, 256);
1078 pstr = (struct p80211pstrd *)&msg->ssid.data;
1079 prism2mgmt_pstr2bytestr(p2bytestr, pstr);
1080 result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID,
1081 bytebuf,
1082 HFA384x_RID_CNFDESIREDSSID_LEN);
1083 port_type = HFA384x_PORTTYPE_BSS;
1084 /* Set the PortType */
1085 hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type);
1087 /* Enable the Port */
1088 hfa384x_drvr_enable(hw, 0);
1090 /* Set the resultcode */
1091 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1092 msg->resultcode.data = P80211ENUM_resultcode_success;
1094 return result;
1097 /*----------------------------------------------------------------
1098 * prism2mgmt_wlansniff
1100 * Start or stop sniffing.
1102 * Arguments:
1103 * wlandev wlan device structure
1104 * msgp ptr to msg buffer
1106 * Returns:
1107 * 0 success and done
1108 * <0 success, but we're waiting for something to finish.
1109 * >0 an error occurred while handling the message.
1110 * Side effects:
1112 * Call context:
1113 * process thread (usually)
1114 * interrupt
1115 *----------------------------------------------------------------
1117 int prism2mgmt_wlansniff(struct wlandevice *wlandev, void *msgp)
1119 int result = 0;
1120 struct p80211msg_lnxreq_wlansniff *msg = msgp;
1122 struct hfa384x *hw = wlandev->priv;
1123 u16 word;
1125 msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
1126 switch (msg->enable.data) {
1127 case P80211ENUM_truth_false:
1128 /* Confirm that we're in monitor mode */
1129 if (wlandev->netdev->type == ARPHRD_ETHER) {
1130 msg->resultcode.data =
1131 P80211ENUM_resultcode_invalid_parameters;
1132 return 0;
1134 /* Disable monitor mode */
1135 result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE);
1136 if (result) {
1137 netdev_dbg(wlandev->netdev,
1138 "failed to disable monitor mode, result=%d\n",
1139 result);
1140 goto failed;
1142 /* Disable port 0 */
1143 result = hfa384x_drvr_disable(hw, 0);
1144 if (result) {
1145 netdev_dbg
1146 (wlandev->netdev,
1147 "failed to disable port 0 after sniffing, result=%d\n",
1148 result);
1149 goto failed;
1151 /* Clear the driver state */
1152 wlandev->netdev->type = ARPHRD_ETHER;
1154 /* Restore the wepflags */
1155 result = hfa384x_drvr_setconfig16(hw,
1156 HFA384x_RID_CNFWEPFLAGS,
1157 hw->presniff_wepflags);
1158 if (result) {
1159 netdev_dbg
1160 (wlandev->netdev,
1161 "failed to restore wepflags=0x%04x, result=%d\n",
1162 hw->presniff_wepflags, result);
1163 goto failed;
1166 /* Set the port to its prior type and enable (if necessary) */
1167 if (hw->presniff_port_type != 0) {
1168 word = hw->presniff_port_type;
1169 result = hfa384x_drvr_setconfig16(hw,
1170 HFA384x_RID_CNFPORTTYPE,
1171 word);
1172 if (result) {
1173 netdev_dbg
1174 (wlandev->netdev,
1175 "failed to restore porttype, result=%d\n",
1176 result);
1177 goto failed;
1180 /* Enable the port */
1181 result = hfa384x_drvr_enable(hw, 0);
1182 if (result) {
1183 netdev_dbg(wlandev->netdev,
1184 "failed to enable port to presniff setting, result=%d\n",
1185 result);
1186 goto failed;
1188 } else {
1189 result = hfa384x_drvr_disable(hw, 0);
1192 netdev_info(wlandev->netdev, "monitor mode disabled\n");
1193 msg->resultcode.data = P80211ENUM_resultcode_success;
1194 return 0;
1195 case P80211ENUM_truth_true:
1196 /* Disable the port (if enabled), only check Port 0 */
1197 if (hw->port_enabled[0]) {
1198 if (wlandev->netdev->type == ARPHRD_ETHER) {
1199 /* Save macport 0 state */
1200 result = hfa384x_drvr_getconfig16(hw,
1201 HFA384x_RID_CNFPORTTYPE,
1202 &hw->presniff_port_type);
1203 if (result) {
1204 netdev_dbg
1205 (wlandev->netdev,
1206 "failed to read porttype, result=%d\n",
1207 result);
1208 goto failed;
1210 /* Save the wepflags state */
1211 result = hfa384x_drvr_getconfig16(hw,
1212 HFA384x_RID_CNFWEPFLAGS,
1213 &hw->presniff_wepflags);
1214 if (result) {
1215 netdev_dbg
1216 (wlandev->netdev,
1217 "failed to read wepflags, result=%d\n",
1218 result);
1219 goto failed;
1221 hfa384x_drvr_stop(hw);
1222 result = hfa384x_drvr_start(hw);
1223 if (result) {
1224 netdev_dbg(wlandev->netdev,
1225 "failed to restart the card for sniffing, result=%d\n",
1226 result);
1227 goto failed;
1229 } else {
1230 /* Disable the port */
1231 result = hfa384x_drvr_disable(hw, 0);
1232 if (result) {
1233 netdev_dbg(wlandev->netdev,
1234 "failed to enable port for sniffing, result=%d\n",
1235 result);
1236 goto failed;
1239 } else {
1240 hw->presniff_port_type = 0;
1243 /* Set the channel we wish to sniff */
1244 word = msg->channel.data;
1245 result = hfa384x_drvr_setconfig16(hw,
1246 HFA384x_RID_CNFOWNCHANNEL,
1247 word);
1248 hw->sniff_channel = word;
1250 if (result) {
1251 netdev_dbg(wlandev->netdev,
1252 "failed to set channel %d, result=%d\n",
1253 word, result);
1254 goto failed;
1257 /* Now if we're already sniffing, we can skip the rest */
1258 if (wlandev->netdev->type != ARPHRD_ETHER) {
1259 /* Set the port type to pIbss */
1260 word = HFA384x_PORTTYPE_PSUEDOIBSS;
1261 result = hfa384x_drvr_setconfig16(hw,
1262 HFA384x_RID_CNFPORTTYPE,
1263 word);
1264 if (result) {
1265 netdev_dbg
1266 (wlandev->netdev,
1267 "failed to set porttype %d, result=%d\n",
1268 word, result);
1269 goto failed;
1271 if ((msg->keepwepflags.status ==
1272 P80211ENUM_msgitem_status_data_ok) &&
1273 (msg->keepwepflags.data != P80211ENUM_truth_true)) {
1274 /* Set the wepflags for no decryption */
1275 word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT |
1276 HFA384x_WEPFLAGS_DISABLE_RXCRYPT;
1277 result =
1278 hfa384x_drvr_setconfig16(hw,
1279 HFA384x_RID_CNFWEPFLAGS,
1280 word);
1283 if (result) {
1284 netdev_dbg
1285 (wlandev->netdev,
1286 "failed to set wepflags=0x%04x, result=%d\n",
1287 word, result);
1288 goto failed;
1292 /* Do we want to strip the FCS in monitor mode? */
1293 if ((msg->stripfcs.status ==
1294 P80211ENUM_msgitem_status_data_ok) &&
1295 (msg->stripfcs.data == P80211ENUM_truth_true)) {
1296 hw->sniff_fcs = 0;
1297 } else {
1298 hw->sniff_fcs = 1;
1301 /* Do we want to truncate the packets? */
1302 if (msg->packet_trunc.status ==
1303 P80211ENUM_msgitem_status_data_ok) {
1304 hw->sniff_truncate = msg->packet_trunc.data;
1305 } else {
1306 hw->sniff_truncate = 0;
1309 /* Enable the port */
1310 result = hfa384x_drvr_enable(hw, 0);
1311 if (result) {
1312 netdev_dbg
1313 (wlandev->netdev,
1314 "failed to enable port for sniffing, result=%d\n",
1315 result);
1316 goto failed;
1318 /* Enable monitor mode */
1319 result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE);
1320 if (result) {
1321 netdev_dbg(wlandev->netdev,
1322 "failed to enable monitor mode, result=%d\n",
1323 result);
1324 goto failed;
1327 if (wlandev->netdev->type == ARPHRD_ETHER)
1328 netdev_info(wlandev->netdev, "monitor mode enabled\n");
1330 /* Set the driver state */
1331 /* Do we want the prism2 header? */
1332 if ((msg->prismheader.status ==
1333 P80211ENUM_msgitem_status_data_ok) &&
1334 (msg->prismheader.data == P80211ENUM_truth_true)) {
1335 hw->sniffhdr = 0;
1336 wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1337 } else if ((msg->wlanheader.status ==
1338 P80211ENUM_msgitem_status_data_ok) &&
1339 (msg->wlanheader.data == P80211ENUM_truth_true)) {
1340 hw->sniffhdr = 1;
1341 wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
1342 } else {
1343 wlandev->netdev->type = ARPHRD_IEEE80211;
1346 msg->resultcode.data = P80211ENUM_resultcode_success;
1347 return 0;
1348 default:
1349 msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
1350 return 0;
1353 failed:
1354 msg->resultcode.data = P80211ENUM_resultcode_refused;
1355 return 0;