]>
Commit | Line | Data |
---|---|---|
00b3ed16 GKH |
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 | ||
00b3ed16 GKH |
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> | |
00b3ed16 GKH |
66 | #include <linux/wireless.h> |
67 | #include <linux/netdevice.h> | |
68 | #include <linux/delay.h> | |
ef1a0ed7 | 69 | #include <linux/io.h> |
00b3ed16 GKH |
70 | #include <asm/byteorder.h> |
71 | #include <linux/random.h> | |
00b3ed16 | 72 | #include <linux/usb.h> |
7f6e0e44 | 73 | #include <linux/bitops.h> |
00b3ed16 | 74 | |
00b3ed16 GKH |
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 | ||
00b3ed16 | 86 | /* Converts 802.11 format rate specifications to prism2 */ |
7f6e0e44 MM |
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) | |
00b3ed16 | 91 | |
00b3ed16 GKH |
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 | ----------------------------------------------------------------*/ | |
297f06ce | 116 | int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 117 | { |
450238ea MM |
118 | int result = 0; |
119 | hfa384x_t *hw = wlandev->priv; | |
120 | p80211msg_dot11req_scan_t *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; | |
00b3ed16 GKH |
150 | goto exit; |
151 | } | |
152 | ||
450238ea MM |
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) | |
18c7f792 | 171 | word = cpu_to_le16(msg->maxchanneltime.data); |
450238ea MM |
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 | } | |
00b3ed16 GKH |
183 | |
184 | /* set up the txrate to be 2MBPS. Should be fastest basicrate... */ | |
185 | word = HFA384x_RATEBIT_2; | |
18c7f792 | 186 | scanreq.txRate = cpu_to_le16(word); |
00b3ed16 | 187 | |
450238ea MM |
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 | } | |
18c7f792 | 197 | scanreq.channelList = cpu_to_le16(word); |
00b3ed16 | 198 | |
450238ea | 199 | /* set up the ssid, if present. */ |
18c7f792 | 200 | scanreq.ssid.len = cpu_to_le16(msg->ssid.data.len); |
450238ea | 201 | memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len); |
00b3ed16 GKH |
202 | |
203 | /* Enable the MAC port if it's not already enabled */ | |
204 | result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word); | |
450238ea | 205 | if (result) { |
edbd606c | 206 | printk(KERN_ERR "getconfig(PORTSTATUS) failed. " |
450238ea | 207 | "result=%d\n", result); |
00b3ed16 | 208 | msg->resultcode.data = |
450238ea | 209 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
210 | goto exit; |
211 | } | |
212 | if (word == HFA384x_PORTSTATUS_DISABLED) { | |
aaad4303 | 213 | u16 wordbuf[17]; |
00b3ed16 GKH |
214 | |
215 | result = hfa384x_drvr_setconfig16(hw, | |
450238ea MM |
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); | |
00b3ed16 | 222 | msg->resultcode.data = |
450238ea | 223 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
224 | goto exit; |
225 | } | |
226 | /* Construct a bogus SSID and assign it to OwnSSID and | |
227 | * DesiredSSID | |
228 | */ | |
18c7f792 | 229 | wordbuf[0] = cpu_to_le16(WLAN_SSID_MAXLEN); |
00b3ed16 | 230 | get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN); |
450238ea MM |
231 | result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, |
232 | wordbuf, | |
233 | HFA384x_RID_CNFOWNSSID_LEN); | |
234 | if (result) { | |
edbd606c | 235 | printk(KERN_ERR "Failed to set OwnSSID.\n"); |
00b3ed16 | 236 | msg->resultcode.data = |
450238ea | 237 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
238 | goto exit; |
239 | } | |
450238ea MM |
240 | result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, |
241 | wordbuf, | |
242 | HFA384x_RID_CNFDESIREDSSID_LEN); | |
243 | if (result) { | |
edbd606c | 244 | printk(KERN_ERR "Failed to set DesiredSSID.\n"); |
00b3ed16 | 245 | msg->resultcode.data = |
450238ea | 246 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
247 | goto exit; |
248 | } | |
249 | /* bsstype */ | |
250 | result = hfa384x_drvr_setconfig16(hw, | |
450238ea MM |
251 | HFA384x_RID_CNFPORTTYPE, |
252 | HFA384x_PORTTYPE_IBSS); | |
253 | if (result) { | |
edbd606c | 254 | printk(KERN_ERR "Failed to set CNFPORTTYPE.\n"); |
00b3ed16 | 255 | msg->resultcode.data = |
450238ea | 256 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
257 | goto exit; |
258 | } | |
259 | /* ibss options */ | |
260 | result = hfa384x_drvr_setconfig16(hw, | |
450238ea MM |
261 | HFA384x_RID_CREATEIBSS, |
262 | HFA384x_CREATEIBSS_JOINCREATEIBSS); | |
263 | if (result) { | |
edbd606c | 264 | printk(KERN_ERR "Failed to set CREATEIBSS.\n"); |
00b3ed16 | 265 | msg->resultcode.data = |
450238ea | 266 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
267 | goto exit; |
268 | } | |
269 | result = hfa384x_drvr_enable(hw, 0); | |
450238ea | 270 | if (result) { |
edbd606c | 271 | printk(KERN_ERR "drvr_enable(0) failed. " |
450238ea | 272 | "result=%d\n", result); |
00b3ed16 | 273 | msg->resultcode.data = |
450238ea | 274 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
275 | goto exit; |
276 | } | |
277 | istmpenable = 1; | |
278 | } | |
279 | ||
450238ea MM |
280 | /* Figure out our timeout first Kus, then HZ */ |
281 | timeout = msg->channellist.data.len * msg->maxchanneltime.data; | |
282 | timeout = (timeout * HZ) / 1000; | |
00b3ed16 | 283 | |
450238ea MM |
284 | /* Issue the scan request */ |
285 | hw->scanflag = 0; | |
00b3ed16 | 286 | |
450238ea MM |
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 | } | |
00b3ed16 | 297 | |
450238ea MM |
298 | /* sleep until info frame arrives */ |
299 | wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout); | |
00b3ed16 GKH |
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 | ||
450238ea | 307 | hw->scanflag = 0; |
00b3ed16 GKH |
308 | |
309 | /* Disable port if we temporarily enabled it. */ | |
310 | if (istmpenable) { | |
311 | result = hfa384x_drvr_disable(hw, 0); | |
450238ea | 312 | if (result) { |
edbd606c | 313 | printk(KERN_ERR "drvr_disable(0) failed. " |
450238ea | 314 | "result=%d\n", result); |
00b3ed16 | 315 | msg->resultcode.data = |
450238ea | 316 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
317 | goto exit; |
318 | } | |
319 | } | |
320 | ||
321 | /* restore original roaming mode */ | |
322 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE, | |
323 | roamingmode); | |
450238ea MM |
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 | ||
335 | exit: | |
00b3ed16 GKH |
336 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
337 | ||
00b3ed16 GKH |
338 | return result; |
339 | } | |
340 | ||
00b3ed16 GKH |
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 | ----------------------------------------------------------------*/ | |
297f06ce | 361 | int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 362 | { |
450238ea MM |
363 | int result = 0; |
364 | p80211msg_dot11req_scan_results_t *req; | |
365 | hfa384x_t *hw = wlandev->priv; | |
00b3ed16 GKH |
366 | hfa384x_HScanResultSub_t *item = NULL; |
367 | ||
368 | int count; | |
369 | ||
450238ea | 370 | req = (p80211msg_dot11req_scan_results_t *) msgp; |
00b3ed16 GKH |
371 | |
372 | req->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
373 | ||
450238ea MM |
374 | if (!hw->scanresults) { |
375 | printk(KERN_ERR | |
376 | "dot11req_scan_results can only be used after a successful dot11req_scan.\n"); | |
00b3ed16 GKH |
377 | result = 2; |
378 | req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; | |
379 | goto exit; | |
380 | } | |
381 | ||
450238ea MM |
382 | count = (hw->scanresults->framelen - 3) / 32; |
383 | if (count > 32) | |
384 | count = 32; | |
00b3ed16 GKH |
385 | |
386 | if (req->bssindex.data >= count) { | |
a7cf7bae | 387 | pr_debug("requested index (%d) out of range (%d)\n", |
75f49e07 | 388 | req->bssindex.data, count); |
00b3ed16 GKH |
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; | |
18c7f792 MM |
398 | req->signal.data = le16_to_cpu(item->sl); |
399 | req->noise.data = le16_to_cpu(item->anl); | |
00b3ed16 GKH |
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; | |
18c7f792 | 408 | req->ssid.data.len = le16_to_cpu(item->ssid.len); |
00b3ed16 GKH |
409 | memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); |
410 | ||
411 | /* supported rates */ | |
450238ea MM |
412 | for (count = 0; count < 10; count++) |
413 | if (item->supprates[count] == 0) | |
414 | break; | |
00b3ed16 GKH |
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; | |
18c7f792 | 448 | req->beaconperiod.data = le16_to_cpu(item->bcnint); |
00b3ed16 GKH |
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; | |
18c7f792 | 458 | req->ibssatimwindow.data = le16_to_cpu(item->atim); |
00b3ed16 GKH |
459 | |
460 | /* Channel */ | |
461 | req->dschannel.status = P80211ENUM_msgitem_status_data_ok; | |
18c7f792 | 462 | req->dschannel.data = le16_to_cpu(item->chid); |
00b3ed16 GKH |
463 | |
464 | /* capinfo bits */ | |
18c7f792 | 465 | count = le16_to_cpu(item->capinfo); |
00b3ed16 GKH |
466 | |
467 | /* privacy flag */ | |
468 | req->privacy.status = P80211ENUM_msgitem_status_data_ok; | |
469 | req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count); | |
470 | ||
471 | /* cfpollable */ | |
472 | req->cfpollable.status = P80211ENUM_msgitem_status_data_ok; | |
473 | req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count); | |
474 | ||
475 | /* cfpollreq */ | |
476 | req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok; | |
477 | req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count); | |
478 | ||
479 | /* bsstype */ | |
450238ea | 480 | req->bsstype.status = P80211ENUM_msgitem_status_data_ok; |
00b3ed16 | 481 | req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ? |
450238ea | 482 | P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent; |
00b3ed16 GKH |
483 | |
484 | result = 0; | |
485 | req->resultcode.data = P80211ENUM_resultcode_success; | |
486 | ||
450238ea | 487 | exit: |
00b3ed16 GKH |
488 | return result; |
489 | } | |
490 | ||
00b3ed16 GKH |
491 | /*---------------------------------------------------------------- |
492 | * prism2mgmt_start | |
493 | * | |
494 | * Start a BSS. Any station can do this for IBSS, only AP for ESS. | |
495 | * | |
496 | * Arguments: | |
497 | * wlandev wlan device structure | |
498 | * msgp ptr to msg buffer | |
499 | * | |
500 | * Returns: | |
501 | * 0 success and done | |
502 | * <0 success, but we're waiting for something to finish. | |
503 | * >0 an error occurred while handling the message. | |
504 | * Side effects: | |
505 | * | |
506 | * Call context: | |
507 | * process thread (usually) | |
508 | * interrupt | |
509 | ----------------------------------------------------------------*/ | |
297f06ce | 510 | int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 511 | { |
450238ea MM |
512 | int result = 0; |
513 | hfa384x_t *hw = wlandev->priv; | |
514 | p80211msg_dot11req_start_t *msg = msgp; | |
00b3ed16 | 515 | |
450238ea MM |
516 | p80211pstrd_t *pstr; |
517 | u8 bytebuf[80]; | |
518 | hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t *) bytebuf; | |
519 | u16 word; | |
00b3ed16 GKH |
520 | |
521 | wlandev->macmode = WLAN_MACMODE_NONE; | |
522 | ||
523 | /* Set the SSID */ | |
524 | memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); | |
525 | ||
5db8dcc9 SP |
526 | /*** ADHOC IBSS ***/ |
527 | /* see if current f/w is less than 8c3 */ | |
528 | if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, | |
529 | hw->ident_sta_fw.minor, | |
530 | hw->ident_sta_fw.variant) < | |
450238ea | 531 | HFA384x_FIRMWARE_VERSION(0, 8, 3)) { |
5db8dcc9 SP |
532 | /* Ad-Hoc not quite supported on Prism2 */ |
533 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
534 | msg->resultcode.data = P80211ENUM_resultcode_not_supported; | |
00b3ed16 GKH |
535 | goto done; |
536 | } | |
537 | ||
00b3ed16 GKH |
538 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
539 | ||
5db8dcc9 | 540 | /*** STATION ***/ |
00b3ed16 GKH |
541 | /* Set the REQUIRED config items */ |
542 | /* SSID */ | |
ef1a0ed7 | 543 | pstr = (p80211pstrd_t *) &(msg->ssid.data); |
00b3ed16 | 544 | prism2mgmt_pstr2bytestr(p2bytestr, pstr); |
450238ea MM |
545 | result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, |
546 | bytebuf, HFA384x_RID_CNFOWNSSID_LEN); | |
547 | if (result) { | |
edbd606c | 548 | printk(KERN_ERR "Failed to set CnfOwnSSID\n"); |
5db8dcc9 SP |
549 | goto failed; |
550 | } | |
450238ea MM |
551 | result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, |
552 | bytebuf, | |
553 | HFA384x_RID_CNFDESIREDSSID_LEN); | |
554 | if (result) { | |
edbd606c | 555 | printk(KERN_ERR "Failed to set CnfDesiredSSID\n"); |
00b3ed16 GKH |
556 | goto failed; |
557 | } | |
558 | ||
559 | /* bsstype - we use the default in the ap firmware */ | |
5db8dcc9 SP |
560 | /* IBSS port */ |
561 | hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0); | |
00b3ed16 GKH |
562 | |
563 | /* beacon period */ | |
564 | word = msg->beaconperiod.data; | |
aaad4303 | 565 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNint, word); |
450238ea | 566 | if (result) { |
edbd606c | 567 | printk(KERN_ERR "Failed to set beacon period=%d.\n", word); |
00b3ed16 GKH |
568 | goto failed; |
569 | } | |
570 | ||
571 | /* dschannel */ | |
572 | word = msg->dschannel.data; | |
573 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); | |
450238ea | 574 | if (result) { |
edbd606c | 575 | printk(KERN_ERR "Failed to set channel=%d.\n", word); |
00b3ed16 GKH |
576 | goto failed; |
577 | } | |
578 | /* Basic rates */ | |
579 | word = p80211rate_to_p2bit(msg->basicrate1.data); | |
450238ea | 580 | if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok) |
00b3ed16 | 581 | word |= p80211rate_to_p2bit(msg->basicrate2.data); |
450238ea MM |
582 | |
583 | if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 584 | word |= p80211rate_to_p2bit(msg->basicrate3.data); |
450238ea MM |
585 | |
586 | if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 587 | word |= p80211rate_to_p2bit(msg->basicrate4.data); |
450238ea MM |
588 | |
589 | if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 590 | word |= p80211rate_to_p2bit(msg->basicrate5.data); |
450238ea MM |
591 | |
592 | if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 593 | word |= p80211rate_to_p2bit(msg->basicrate6.data); |
450238ea MM |
594 | |
595 | if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 596 | word |= p80211rate_to_p2bit(msg->basicrate7.data); |
450238ea MM |
597 | |
598 | if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 599 | word |= p80211rate_to_p2bit(msg->basicrate8.data); |
450238ea | 600 | |
00b3ed16 | 601 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); |
450238ea | 602 | if (result) { |
edbd606c | 603 | printk(KERN_ERR "Failed to set basicrates=%d.\n", word); |
00b3ed16 GKH |
604 | goto failed; |
605 | } | |
606 | ||
607 | /* Operational rates (supprates and txratecontrol) */ | |
608 | word = p80211rate_to_p2bit(msg->operationalrate1.data); | |
450238ea | 609 | if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok) |
00b3ed16 | 610 | word |= p80211rate_to_p2bit(msg->operationalrate2.data); |
450238ea MM |
611 | |
612 | if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 613 | word |= p80211rate_to_p2bit(msg->operationalrate3.data); |
450238ea MM |
614 | |
615 | if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 616 | word |= p80211rate_to_p2bit(msg->operationalrate4.data); |
450238ea MM |
617 | |
618 | if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 619 | word |= p80211rate_to_p2bit(msg->operationalrate5.data); |
450238ea MM |
620 | |
621 | if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 622 | word |= p80211rate_to_p2bit(msg->operationalrate6.data); |
450238ea MM |
623 | |
624 | if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 625 | word |= p80211rate_to_p2bit(msg->operationalrate7.data); |
450238ea MM |
626 | |
627 | if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok) | |
00b3ed16 | 628 | word |= p80211rate_to_p2bit(msg->operationalrate8.data); |
450238ea | 629 | |
00b3ed16 | 630 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); |
450238ea | 631 | if (result) { |
edbd606c | 632 | printk(KERN_ERR "Failed to set supprates=%d.\n", word); |
00b3ed16 GKH |
633 | goto failed; |
634 | } | |
00b3ed16 | 635 | |
5db8dcc9 | 636 | result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word); |
450238ea | 637 | if (result) { |
edbd606c | 638 | printk(KERN_ERR "Failed to set txrates=%d.\n", word); |
00b3ed16 GKH |
639 | goto failed; |
640 | } | |
641 | ||
00b3ed16 | 642 | /* Set the macmode so the frame setup code knows what to do */ |
450238ea | 643 | if (msg->bsstype.data == P80211ENUM_bsstype_independent) { |
5db8dcc9 | 644 | wlandev->macmode = WLAN_MACMODE_IBSS_STA; |
00b3ed16 GKH |
645 | /* lets extend the data length a bit */ |
646 | hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); | |
647 | } | |
648 | ||
00b3ed16 GKH |
649 | /* Enable the Port */ |
650 | result = hfa384x_drvr_enable(hw, 0); | |
450238ea | 651 | if (result) { |
edbd606c | 652 | printk(KERN_ERR "Enable macport failed, result=%d.\n", result); |
00b3ed16 GKH |
653 | goto failed; |
654 | } | |
655 | ||
656 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
657 | ||
658 | goto done; | |
659 | failed: | |
a7cf7bae | 660 | pr_debug("Failed to set a config option, result=%d\n", result); |
00b3ed16 GKH |
661 | msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; |
662 | ||
663 | done: | |
664 | result = 0; | |
665 | ||
00b3ed16 GKH |
666 | return result; |
667 | } | |
668 | ||
00b3ed16 GKH |
669 | /*---------------------------------------------------------------- |
670 | * prism2mgmt_readpda | |
671 | * | |
672 | * Collect the PDA data and put it in the message. | |
673 | * | |
674 | * Arguments: | |
675 | * wlandev wlan device structure | |
676 | * msgp ptr to msg buffer | |
677 | * | |
678 | * Returns: | |
679 | * 0 success and done | |
680 | * <0 success, but we're waiting for something to finish. | |
681 | * >0 an error occurred while handling the message. | |
682 | * Side effects: | |
683 | * | |
684 | * Call context: | |
685 | * process thread (usually) | |
686 | ----------------------------------------------------------------*/ | |
297f06ce | 687 | int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 688 | { |
450238ea MM |
689 | hfa384x_t *hw = wlandev->priv; |
690 | p80211msg_p2req_readpda_t *msg = msgp; | |
691 | int result; | |
00b3ed16 GKH |
692 | |
693 | /* We only support collecting the PDA when in the FWLOAD | |
694 | * state. | |
695 | */ | |
696 | if (wlandev->msdstate != WLAN_MSD_FWLOAD) { | |
edbd606c | 697 | printk(KERN_ERR |
450238ea | 698 | "PDA may only be read " "in the fwload state.\n"); |
00b3ed16 | 699 | msg->resultcode.data = |
450238ea | 700 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
701 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
702 | } else { | |
703 | /* Call drvr_readpda(), it handles the auxport enable | |
704 | * and validating the returned PDA. | |
705 | */ | |
450238ea MM |
706 | result = hfa384x_drvr_readpda(hw, |
707 | msg->pda.data, | |
708 | HFA384x_PDA_LEN_MAX); | |
00b3ed16 | 709 | if (result) { |
edbd606c | 710 | printk(KERN_ERR |
450238ea MM |
711 | "hfa384x_drvr_readpda() failed, " |
712 | "result=%d\n", result); | |
00b3ed16 GKH |
713 | |
714 | msg->resultcode.data = | |
450238ea | 715 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 | 716 | msg->resultcode.status = |
450238ea | 717 | P80211ENUM_msgitem_status_data_ok; |
00b3ed16 GKH |
718 | return 0; |
719 | } | |
720 | msg->pda.status = P80211ENUM_msgitem_status_data_ok; | |
721 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
722 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
723 | } | |
724 | ||
00b3ed16 GKH |
725 | return 0; |
726 | } | |
727 | ||
00b3ed16 GKH |
728 | /*---------------------------------------------------------------- |
729 | * prism2mgmt_ramdl_state | |
730 | * | |
731 | * Establishes the beginning/end of a card RAM download session. | |
732 | * | |
733 | * It is expected that the ramdl_write() function will be called | |
734 | * one or more times between the 'enable' and 'disable' calls to | |
735 | * this function. | |
736 | * | |
737 | * Note: This function should not be called when a mac comm port | |
738 | * is active. | |
739 | * | |
740 | * Arguments: | |
741 | * wlandev wlan device structure | |
742 | * msgp ptr to msg buffer | |
743 | * | |
744 | * Returns: | |
745 | * 0 success and done | |
746 | * <0 success, but we're waiting for something to finish. | |
747 | * >0 an error occurred while handling the message. | |
748 | * Side effects: | |
749 | * | |
750 | * Call context: | |
751 | * process thread (usually) | |
752 | ----------------------------------------------------------------*/ | |
297f06ce | 753 | int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 754 | { |
450238ea MM |
755 | hfa384x_t *hw = wlandev->priv; |
756 | p80211msg_p2req_ramdl_state_t *msg = msgp; | |
00b3ed16 GKH |
757 | |
758 | if (wlandev->msdstate != WLAN_MSD_FWLOAD) { | |
edbd606c | 759 | printk(KERN_ERR |
450238ea MM |
760 | "ramdl_state(): may only be called " |
761 | "in the fwload state.\n"); | |
00b3ed16 | 762 | msg->resultcode.data = |
450238ea | 763 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 | 764 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
00b3ed16 GKH |
765 | return 0; |
766 | } | |
767 | ||
768 | /* | |
450238ea MM |
769 | ** Note: Interrupts are locked out if this is an AP and are NOT |
770 | ** locked out if this is a station. | |
771 | */ | |
00b3ed16 GKH |
772 | |
773 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
450238ea MM |
774 | if (msg->enable.data == P80211ENUM_truth_true) { |
775 | if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) { | |
776 | msg->resultcode.data = | |
777 | P80211ENUM_resultcode_implementation_failure; | |
00b3ed16 GKH |
778 | } else { |
779 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
780 | } | |
781 | } else { | |
782 | hfa384x_drvr_ramdl_disable(hw); | |
783 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
784 | } | |
785 | ||
00b3ed16 GKH |
786 | return 0; |
787 | } | |
788 | ||
00b3ed16 GKH |
789 | /*---------------------------------------------------------------- |
790 | * prism2mgmt_ramdl_write | |
791 | * | |
792 | * Writes a buffer to the card RAM using the download state. This | |
793 | * is for writing code to card RAM. To just read or write raw data | |
794 | * use the aux functions. | |
795 | * | |
796 | * Arguments: | |
797 | * wlandev wlan device structure | |
798 | * msgp ptr to msg buffer | |
799 | * | |
800 | * Returns: | |
801 | * 0 success and done | |
802 | * <0 success, but we're waiting for something to finish. | |
803 | * >0 an error occurred while handling the message. | |
804 | * Side effects: | |
805 | * | |
806 | * Call context: | |
807 | * process thread (usually) | |
808 | ----------------------------------------------------------------*/ | |
297f06ce | 809 | int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 810 | { |
450238ea MM |
811 | hfa384x_t *hw = wlandev->priv; |
812 | p80211msg_p2req_ramdl_write_t *msg = msgp; | |
813 | u32 addr; | |
814 | u32 len; | |
815 | u8 *buf; | |
00b3ed16 GKH |
816 | |
817 | if (wlandev->msdstate != WLAN_MSD_FWLOAD) { | |
edbd606c | 818 | printk(KERN_ERR |
450238ea MM |
819 | "ramdl_write(): may only be called " |
820 | "in the fwload state.\n"); | |
00b3ed16 | 821 | msg->resultcode.data = |
450238ea | 822 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 | 823 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
00b3ed16 GKH |
824 | return 0; |
825 | } | |
826 | ||
827 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
828 | /* first validate the length */ | |
450238ea MM |
829 | if (msg->len.data > sizeof(msg->data.data)) { |
830 | msg->resultcode.status = | |
831 | P80211ENUM_resultcode_invalid_parameters; | |
00b3ed16 GKH |
832 | return 0; |
833 | } | |
834 | /* call the hfa384x function to do the write */ | |
835 | addr = msg->addr.data; | |
836 | len = msg->len.data; | |
837 | buf = msg->data.data; | |
450238ea | 838 | if (hfa384x_drvr_ramdl_write(hw, addr, buf, len)) |
00b3ed16 GKH |
839 | msg->resultcode.data = P80211ENUM_resultcode_refused; |
840 | ||
00b3ed16 GKH |
841 | msg->resultcode.data = P80211ENUM_resultcode_success; |
842 | ||
00b3ed16 GKH |
843 | return 0; |
844 | } | |
845 | ||
00b3ed16 GKH |
846 | /*---------------------------------------------------------------- |
847 | * prism2mgmt_flashdl_state | |
848 | * | |
849 | * Establishes the beginning/end of a card Flash download session. | |
850 | * | |
851 | * It is expected that the flashdl_write() function will be called | |
852 | * one or more times between the 'enable' and 'disable' calls to | |
853 | * this function. | |
854 | * | |
855 | * Note: This function should not be called when a mac comm port | |
856 | * is active. | |
857 | * | |
858 | * Arguments: | |
859 | * wlandev wlan device structure | |
860 | * msgp ptr to msg buffer | |
861 | * | |
862 | * Returns: | |
863 | * 0 success and done | |
864 | * <0 success, but we're waiting for something to finish. | |
865 | * >0 an error occurred while handling the message. | |
866 | * Side effects: | |
867 | * | |
868 | * Call context: | |
869 | * process thread (usually) | |
870 | ----------------------------------------------------------------*/ | |
297f06ce | 871 | int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 872 | { |
450238ea MM |
873 | int result = 0; |
874 | hfa384x_t *hw = wlandev->priv; | |
875 | p80211msg_p2req_flashdl_state_t *msg = msgp; | |
00b3ed16 GKH |
876 | |
877 | if (wlandev->msdstate != WLAN_MSD_FWLOAD) { | |
edbd606c | 878 | printk(KERN_ERR |
450238ea MM |
879 | "flashdl_state(): may only be called " |
880 | "in the fwload state.\n"); | |
00b3ed16 | 881 | msg->resultcode.data = |
450238ea | 882 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 | 883 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
00b3ed16 GKH |
884 | return 0; |
885 | } | |
886 | ||
887 | /* | |
450238ea MM |
888 | ** Note: Interrupts are locked out if this is an AP and are NOT |
889 | ** locked out if this is a station. | |
890 | */ | |
00b3ed16 GKH |
891 | |
892 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
450238ea MM |
893 | if (msg->enable.data == P80211ENUM_truth_true) { |
894 | if (hfa384x_drvr_flashdl_enable(hw)) { | |
895 | msg->resultcode.data = | |
896 | P80211ENUM_resultcode_implementation_failure; | |
00b3ed16 GKH |
897 | } else { |
898 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
899 | } | |
900 | } else { | |
901 | hfa384x_drvr_flashdl_disable(hw); | |
902 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
903 | /* NOTE: At this point, the MAC is in the post-reset | |
904 | * state and the driver is in the fwload state. | |
905 | * We need to get the MAC back into the fwload | |
906 | * state. To do this, we set the nsdstate to HWPRESENT | |
907 | * and then call the ifstate function to redo everything | |
908 | * that got us into the fwload state. | |
909 | */ | |
910 | wlandev->msdstate = WLAN_MSD_HWPRESENT; | |
911 | result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); | |
912 | if (result != P80211ENUM_resultcode_success) { | |
edbd606c | 913 | printk(KERN_ERR "prism2sta_ifstate(fwload) failed," |
450238ea | 914 | "P80211ENUM_resultcode=%d\n", result); |
00b3ed16 | 915 | msg->resultcode.data = |
450238ea | 916 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 GKH |
917 | result = -1; |
918 | } | |
919 | } | |
920 | ||
00b3ed16 GKH |
921 | return 0; |
922 | } | |
923 | ||
00b3ed16 GKH |
924 | /*---------------------------------------------------------------- |
925 | * prism2mgmt_flashdl_write | |
926 | * | |
927 | * | |
928 | * | |
929 | * Arguments: | |
930 | * wlandev wlan device structure | |
931 | * msgp ptr to msg buffer | |
932 | * | |
933 | * Returns: | |
934 | * 0 success and done | |
935 | * <0 success, but we're waiting for something to finish. | |
936 | * >0 an error occurred while handling the message. | |
937 | * Side effects: | |
938 | * | |
939 | * Call context: | |
940 | * process thread (usually) | |
941 | ----------------------------------------------------------------*/ | |
297f06ce | 942 | int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 943 | { |
450238ea MM |
944 | hfa384x_t *hw = wlandev->priv; |
945 | p80211msg_p2req_flashdl_write_t *msg = msgp; | |
946 | u32 addr; | |
947 | u32 len; | |
948 | u8 *buf; | |
00b3ed16 GKH |
949 | |
950 | if (wlandev->msdstate != WLAN_MSD_FWLOAD) { | |
edbd606c | 951 | printk(KERN_ERR |
450238ea MM |
952 | "flashdl_write(): may only be called " |
953 | "in the fwload state.\n"); | |
00b3ed16 | 954 | msg->resultcode.data = |
450238ea | 955 | P80211ENUM_resultcode_implementation_failure; |
00b3ed16 | 956 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
00b3ed16 GKH |
957 | return 0; |
958 | } | |
959 | ||
960 | /* | |
450238ea MM |
961 | ** Note: Interrupts are locked out if this is an AP and are NOT |
962 | ** locked out if this is a station. | |
963 | */ | |
00b3ed16 GKH |
964 | |
965 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
966 | /* first validate the length */ | |
450238ea | 967 | if (msg->len.data > sizeof(msg->data.data)) { |
00b3ed16 | 968 | msg->resultcode.status = |
450238ea | 969 | P80211ENUM_resultcode_invalid_parameters; |
00b3ed16 GKH |
970 | return 0; |
971 | } | |
972 | /* call the hfa384x function to do the write */ | |
973 | addr = msg->addr.data; | |
974 | len = msg->len.data; | |
975 | buf = msg->data.data; | |
450238ea | 976 | if (hfa384x_drvr_flashdl_write(hw, addr, buf, len)) |
00b3ed16 GKH |
977 | msg->resultcode.data = P80211ENUM_resultcode_refused; |
978 | ||
00b3ed16 GKH |
979 | msg->resultcode.data = P80211ENUM_resultcode_success; |
980 | ||
00b3ed16 GKH |
981 | return 0; |
982 | } | |
983 | ||
00b3ed16 GKH |
984 | /*---------------------------------------------------------------- |
985 | * prism2mgmt_autojoin | |
986 | * | |
987 | * Associate with an ESS. | |
988 | * | |
989 | * Arguments: | |
990 | * wlandev wlan device structure | |
991 | * msgp ptr to msg buffer | |
992 | * | |
993 | * Returns: | |
994 | * 0 success and done | |
995 | * <0 success, but we're waiting for something to finish. | |
996 | * >0 an error occurred while handling the message. | |
997 | * Side effects: | |
998 | * | |
999 | * Call context: | |
1000 | * process thread (usually) | |
1001 | * interrupt | |
1002 | ----------------------------------------------------------------*/ | |
297f06ce | 1003 | int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 1004 | { |
450238ea MM |
1005 | hfa384x_t *hw = wlandev->priv; |
1006 | int result = 0; | |
1007 | u16 reg; | |
1008 | u16 port_type; | |
1009 | p80211msg_lnxreq_autojoin_t *msg = msgp; | |
1010 | p80211pstrd_t *pstr; | |
1011 | u8 bytebuf[256]; | |
1012 | hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t *) bytebuf; | |
00b3ed16 GKH |
1013 | |
1014 | wlandev->macmode = WLAN_MACMODE_NONE; | |
1015 | ||
1016 | /* Set the SSID */ | |
1017 | memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); | |
1018 | ||
00b3ed16 GKH |
1019 | /* Disable the Port */ |
1020 | hfa384x_drvr_disable(hw, 0); | |
1021 | ||
1022 | /*** STATION ***/ | |
1023 | /* Set the TxRates */ | |
1024 | hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f); | |
1025 | ||
1026 | /* Set the auth type */ | |
450238ea | 1027 | if (msg->authtype.data == P80211ENUM_authalg_sharedkey) |
00b3ed16 | 1028 | reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY; |
450238ea | 1029 | else |
00b3ed16 | 1030 | reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; |
450238ea | 1031 | |
00b3ed16 GKH |
1032 | hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg); |
1033 | ||
1034 | /* Set the ssid */ | |
1035 | memset(bytebuf, 0, 256); | |
ef1a0ed7 | 1036 | pstr = (p80211pstrd_t *) &(msg->ssid.data); |
00b3ed16 | 1037 | prism2mgmt_pstr2bytestr(p2bytestr, pstr); |
450238ea MM |
1038 | result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, |
1039 | bytebuf, | |
1040 | HFA384x_RID_CNFDESIREDSSID_LEN); | |
00b3ed16 | 1041 | port_type = HFA384x_PORTTYPE_BSS; |
00b3ed16 GKH |
1042 | /* Set the PortType */ |
1043 | hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type); | |
1044 | ||
1045 | /* Enable the Port */ | |
1046 | hfa384x_drvr_enable(hw, 0); | |
1047 | ||
1048 | /* Set the resultcode */ | |
1049 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; | |
1050 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
1051 | ||
00b3ed16 GKH |
1052 | return result; |
1053 | } | |
1054 | ||
00b3ed16 GKH |
1055 | /*---------------------------------------------------------------- |
1056 | * prism2mgmt_wlansniff | |
1057 | * | |
1058 | * Start or stop sniffing. | |
1059 | * | |
1060 | * Arguments: | |
1061 | * wlandev wlan device structure | |
1062 | * msgp ptr to msg buffer | |
1063 | * | |
1064 | * Returns: | |
1065 | * 0 success and done | |
1066 | * <0 success, but we're waiting for something to finish. | |
1067 | * >0 an error occurred while handling the message. | |
1068 | * Side effects: | |
1069 | * | |
1070 | * Call context: | |
1071 | * process thread (usually) | |
1072 | * interrupt | |
1073 | ----------------------------------------------------------------*/ | |
297f06ce | 1074 | int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) |
00b3ed16 | 1075 | { |
450238ea MM |
1076 | int result = 0; |
1077 | p80211msg_lnxreq_wlansniff_t *msg = msgp; | |
00b3ed16 | 1078 | |
450238ea MM |
1079 | hfa384x_t *hw = wlandev->priv; |
1080 | u16 word; | |
00b3ed16 | 1081 | |
00b3ed16 | 1082 | msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; |
450238ea | 1083 | switch (msg->enable.data) { |
00b3ed16 GKH |
1084 | case P80211ENUM_truth_false: |
1085 | /* Confirm that we're in monitor mode */ | |
450238ea MM |
1086 | if (wlandev->netdev->type == ARPHRD_ETHER) { |
1087 | msg->resultcode.data = | |
1088 | P80211ENUM_resultcode_invalid_parameters; | |
00b3ed16 GKH |
1089 | result = 0; |
1090 | goto exit; | |
1091 | } | |
1092 | /* Disable monitor mode */ | |
1093 | result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); | |
450238ea | 1094 | if (result) { |
75f49e07 MT |
1095 | pr_debug("failed to disable monitor mode, result=%d\n", |
1096 | result); | |
00b3ed16 GKH |
1097 | goto failed; |
1098 | } | |
1099 | /* Disable port 0 */ | |
1100 | result = hfa384x_drvr_disable(hw, 0); | |
450238ea | 1101 | if (result) { |
75f49e07 MT |
1102 | pr_debug |
1103 | ("failed to disable port 0 after sniffing, result=%d\n", | |
1104 | result); | |
00b3ed16 GKH |
1105 | goto failed; |
1106 | } | |
1107 | /* Clear the driver state */ | |
1108 | wlandev->netdev->type = ARPHRD_ETHER; | |
1109 | ||
1110 | /* Restore the wepflags */ | |
1111 | result = hfa384x_drvr_setconfig16(hw, | |
450238ea MM |
1112 | HFA384x_RID_CNFWEPFLAGS, |
1113 | hw->presniff_wepflags); | |
1114 | if (result) { | |
75f49e07 MT |
1115 | pr_debug |
1116 | ("failed to restore wepflags=0x%04x, result=%d\n", | |
1117 | hw->presniff_wepflags, result); | |
00b3ed16 GKH |
1118 | goto failed; |
1119 | } | |
1120 | ||
1121 | /* Set the port to its prior type and enable (if necessary) */ | |
450238ea | 1122 | if (hw->presniff_port_type != 0) { |
00b3ed16 GKH |
1123 | word = hw->presniff_port_type; |
1124 | result = hfa384x_drvr_setconfig16(hw, | |
ef1a0ed7 AE |
1125 | HFA384x_RID_CNFPORTTYPE, |
1126 | word); | |
450238ea | 1127 | if (result) { |
75f49e07 MT |
1128 | pr_debug |
1129 | ("failed to restore porttype, result=%d\n", | |
1130 | result); | |
00b3ed16 GKH |
1131 | goto failed; |
1132 | } | |
1133 | ||
1134 | /* Enable the port */ | |
1135 | result = hfa384x_drvr_enable(hw, 0); | |
450238ea | 1136 | if (result) { |
75f49e07 MT |
1137 | pr_debug |
1138 | ("failed to enable port to presniff setting, result=%d\n", | |
1139 | result); | |
00b3ed16 GKH |
1140 | goto failed; |
1141 | } | |
1142 | } else { | |
1143 | result = hfa384x_drvr_disable(hw, 0); | |
1144 | ||
1145 | } | |
1146 | ||
350f2f4b | 1147 | printk(KERN_INFO "monitor mode disabled\n"); |
00b3ed16 GKH |
1148 | msg->resultcode.data = P80211ENUM_resultcode_success; |
1149 | result = 0; | |
1150 | goto exit; | |
1151 | break; | |
1152 | case P80211ENUM_truth_true: | |
1153 | /* Disable the port (if enabled), only check Port 0 */ | |
450238ea | 1154 | if (hw->port_enabled[0]) { |
00b3ed16 GKH |
1155 | if (wlandev->netdev->type == ARPHRD_ETHER) { |
1156 | /* Save macport 0 state */ | |
1157 | result = hfa384x_drvr_getconfig16(hw, | |
ef1a0ed7 AE |
1158 | HFA384x_RID_CNFPORTTYPE, |
1159 | &(hw->presniff_port_type)); | |
450238ea | 1160 | if (result) { |
75f49e07 MT |
1161 | pr_debug |
1162 | ("failed to read porttype, result=%d\n", | |
1163 | result); | |
00b3ed16 GKH |
1164 | goto failed; |
1165 | } | |
1166 | /* Save the wepflags state */ | |
1167 | result = hfa384x_drvr_getconfig16(hw, | |
ef1a0ed7 AE |
1168 | HFA384x_RID_CNFWEPFLAGS, |
1169 | &(hw->presniff_wepflags)); | |
450238ea | 1170 | if (result) { |
75f49e07 MT |
1171 | pr_debug |
1172 | ("failed to read wepflags, result=%d\n", | |
1173 | result); | |
00b3ed16 GKH |
1174 | goto failed; |
1175 | } | |
1176 | hfa384x_drvr_stop(hw); | |
1177 | result = hfa384x_drvr_start(hw); | |
450238ea | 1178 | if (result) { |
75f49e07 MT |
1179 | pr_debug |
1180 | ("failed to restart the card for sniffing, result=%d\n", | |
1181 | result); | |
00b3ed16 GKH |
1182 | goto failed; |
1183 | } | |
1184 | } else { | |
1185 | /* Disable the port */ | |
1186 | result = hfa384x_drvr_disable(hw, 0); | |
450238ea | 1187 | if (result) { |
75f49e07 MT |
1188 | pr_debug |
1189 | ("failed to enable port for sniffing, result=%d\n", | |
1190 | result); | |
00b3ed16 GKH |
1191 | goto failed; |
1192 | } | |
1193 | } | |
1194 | } else { | |
1195 | hw->presniff_port_type = 0; | |
1196 | } | |
1197 | ||
1198 | /* Set the channel we wish to sniff */ | |
1199 | word = msg->channel.data; | |
1200 | result = hfa384x_drvr_setconfig16(hw, | |
450238ea MM |
1201 | HFA384x_RID_CNFOWNCHANNEL, |
1202 | word); | |
1203 | hw->sniff_channel = word; | |
00b3ed16 | 1204 | |
450238ea | 1205 | if (result) { |
75f49e07 MT |
1206 | pr_debug("failed to set channel %d, result=%d\n", |
1207 | word, result); | |
00b3ed16 GKH |
1208 | goto failed; |
1209 | } | |
1210 | ||
1211 | /* Now if we're already sniffing, we can skip the rest */ | |
1212 | if (wlandev->netdev->type != ARPHRD_ETHER) { | |
1213 | /* Set the port type to pIbss */ | |
1214 | word = HFA384x_PORTTYPE_PSUEDOIBSS; | |
1215 | result = hfa384x_drvr_setconfig16(hw, | |
ef1a0ed7 AE |
1216 | HFA384x_RID_CNFPORTTYPE, |
1217 | word); | |
450238ea | 1218 | if (result) { |
75f49e07 MT |
1219 | pr_debug |
1220 | ("failed to set porttype %d, result=%d\n", | |
1221 | word, result); | |
00b3ed16 GKH |
1222 | goto failed; |
1223 | } | |
450238ea MM |
1224 | if ((msg->keepwepflags.status == |
1225 | P80211ENUM_msgitem_status_data_ok) | |
1226 | && (msg->keepwepflags.data != | |
1227 | P80211ENUM_truth_true)) { | |
00b3ed16 GKH |
1228 | /* Set the wepflags for no decryption */ |
1229 | word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | | |
450238ea MM |
1230 | HFA384x_WEPFLAGS_DISABLE_RXCRYPT; |
1231 | result = | |
1232 | hfa384x_drvr_setconfig16(hw, | |
ef1a0ed7 AE |
1233 | HFA384x_RID_CNFWEPFLAGS, |
1234 | word); | |
00b3ed16 GKH |
1235 | } |
1236 | ||
450238ea | 1237 | if (result) { |
75f49e07 MT |
1238 | pr_debug |
1239 | ("failed to set wepflags=0x%04x, result=%d\n", | |
1240 | word, result); | |
00b3ed16 GKH |
1241 | goto failed; |
1242 | } | |
1243 | } | |
1244 | ||
1245 | /* Do we want to strip the FCS in monitor mode? */ | |
450238ea MM |
1246 | if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok) |
1247 | && (msg->stripfcs.data == P80211ENUM_truth_true)) { | |
00b3ed16 GKH |
1248 | hw->sniff_fcs = 0; |
1249 | } else { | |
1250 | hw->sniff_fcs = 1; | |
1251 | } | |
1252 | ||
1253 | /* Do we want to truncate the packets? */ | |
450238ea MM |
1254 | if (msg->packet_trunc.status == |
1255 | P80211ENUM_msgitem_status_data_ok) { | |
00b3ed16 GKH |
1256 | hw->sniff_truncate = msg->packet_trunc.data; |
1257 | } else { | |
1258 | hw->sniff_truncate = 0; | |
1259 | } | |
1260 | ||
1261 | /* Enable the port */ | |
1262 | result = hfa384x_drvr_enable(hw, 0); | |
450238ea | 1263 | if (result) { |
75f49e07 MT |
1264 | pr_debug |
1265 | ("failed to enable port for sniffing, result=%d\n", | |
1266 | result); | |
00b3ed16 GKH |
1267 | goto failed; |
1268 | } | |
1269 | /* Enable monitor mode */ | |
1270 | result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); | |
450238ea | 1271 | if (result) { |
75f49e07 MT |
1272 | pr_debug("failed to enable monitor mode, result=%d\n", |
1273 | result); | |
00b3ed16 GKH |
1274 | goto failed; |
1275 | } | |
1276 | ||
450238ea | 1277 | if (wlandev->netdev->type == ARPHRD_ETHER) |
350f2f4b | 1278 | printk(KERN_INFO "monitor mode enabled\n"); |
00b3ed16 GKH |
1279 | |
1280 | /* Set the driver state */ | |
1281 | /* Do we want the prism2 header? */ | |
450238ea MM |
1282 | if ((msg->prismheader.status == |
1283 | P80211ENUM_msgitem_status_data_ok) | |
1284 | && (msg->prismheader.data == P80211ENUM_truth_true)) { | |
00b3ed16 GKH |
1285 | hw->sniffhdr = 0; |
1286 | wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; | |
450238ea MM |
1287 | } else |
1288 | if ((msg->wlanheader.status == | |
1289 | P80211ENUM_msgitem_status_data_ok) | |
1290 | && (msg->wlanheader.data == P80211ENUM_truth_true)) { | |
00b3ed16 GKH |
1291 | hw->sniffhdr = 1; |
1292 | wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; | |
1293 | } else { | |
1294 | wlandev->netdev->type = ARPHRD_IEEE80211; | |
1295 | } | |
1296 | ||
1297 | msg->resultcode.data = P80211ENUM_resultcode_success; | |
1298 | result = 0; | |
1299 | goto exit; | |
1300 | break; | |
1301 | default: | |
1302 | msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; | |
1303 | result = 0; | |
1304 | goto exit; | |
1305 | break; | |
1306 | } | |
1307 | ||
1308 | failed: | |
1309 | msg->resultcode.data = P80211ENUM_resultcode_refused; | |
1310 | result = 0; | |
1311 | exit: | |
00b3ed16 GKH |
1312 | return result; |
1313 | } |