aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/11d.c754
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/LICENSE16
-rw-r--r--drivers/net/wireless/libertas/Makefile21
-rw-r--r--drivers/net/wireless/libertas/README1044
-rw-r--r--drivers/net/wireless/libertas/assoc.c588
-rw-r--r--drivers/net/wireless/libertas/assoc.h30
-rw-r--r--drivers/net/wireless/libertas/cmd.c1958
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c1031
-rw-r--r--drivers/net/wireless/libertas/debugfs.c1968
-rw-r--r--drivers/net/wireless/libertas/debugfs.h6
-rw-r--r--drivers/net/wireless/libertas/decl.h83
-rw-r--r--drivers/net/wireless/libertas/defs.h369
-rw-r--r--drivers/net/wireless/libertas/dev.h403
-rw-r--r--drivers/net/wireless/libertas/ethtool.c184
-rw-r--r--drivers/net/wireless/libertas/fw.c361
-rw-r--r--drivers/net/wireless/libertas/fw.h13
-rw-r--r--drivers/net/wireless/libertas/host.h338
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h693
-rw-r--r--drivers/net/wireless/libertas/if_bootcmd.c38
-rw-r--r--drivers/net/wireless/libertas/if_usb.c952
-rw-r--r--drivers/net/wireless/libertas/if_usb.h109
-rw-r--r--drivers/net/wireless/libertas/ioctl.c2500
-rw-r--r--drivers/net/wireless/libertas/join.c1055
-rw-r--r--drivers/net/wireless/libertas/join.h64
-rw-r--r--drivers/net/wireless/libertas/main.c1258
-rw-r--r--drivers/net/wireless/libertas/radiotap.h57
-rw-r--r--drivers/net/wireless/libertas/rx.c459
-rw-r--r--drivers/net/wireless/libertas/sbi.h40
-rw-r--r--drivers/net/wireless/libertas/scan.c2044
-rw-r--r--drivers/net/wireless/libertas/scan.h216
-rw-r--r--drivers/net/wireless/libertas/thread.h52
-rw-r--r--drivers/net/wireless/libertas/tx.c285
-rw-r--r--drivers/net/wireless/libertas/types.h289
-rw-r--r--drivers/net/wireless/libertas/version.h8
-rw-r--r--drivers/net/wireless/libertas/wext.c2769
-rw-r--r--drivers/net/wireless/libertas/wext.h147
37 files changed, 22307 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644
index 000000000000..e0ecc4d483bb
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.c
@@ -0,0 +1,754 @@
1/**
2 * This file contains functions for 802.11D.
3 */
4#include <linux/ctype.h>
5#include <linux/kernel.h>
6#include <linux/wireless.h>
7
8#include "host.h"
9#include "decl.h"
10#include "11d.h"
11#include "dev.h"
12#include "wext.h"
13
14#define TX_PWR_DEFAULT 10
15
16static struct region_code_mapping region_code_mapping[] = {
17 {"US ", 0x10}, /* US FCC */
18 {"CA ", 0x10}, /* IC Canada */
19 {"SG ", 0x10}, /* Singapore */
20 {"EU ", 0x30}, /* ETSI */
21 {"AU ", 0x30}, /* Australia */
22 {"KR ", 0x30}, /* Republic Of Korea */
23 {"ES ", 0x31}, /* Spain */
24 {"FR ", 0x32}, /* France */
25 {"JP ", 0x40}, /* Japan */
26};
27
28/* Following 2 structure defines the supported channels */
29static struct chan_freq_power channel_freq_power_UN_BG[] = {
30 {1, 2412, TX_PWR_DEFAULT},
31 {2, 2417, TX_PWR_DEFAULT},
32 {3, 2422, TX_PWR_DEFAULT},
33 {4, 2427, TX_PWR_DEFAULT},
34 {5, 2432, TX_PWR_DEFAULT},
35 {6, 2437, TX_PWR_DEFAULT},
36 {7, 2442, TX_PWR_DEFAULT},
37 {8, 2447, TX_PWR_DEFAULT},
38 {9, 2452, TX_PWR_DEFAULT},
39 {10, 2457, TX_PWR_DEFAULT},
40 {11, 2462, TX_PWR_DEFAULT},
41 {12, 2467, TX_PWR_DEFAULT},
42 {13, 2472, TX_PWR_DEFAULT},
43 {14, 2484, TX_PWR_DEFAULT}
44};
45
46static u8 wlan_region_2_code(u8 * region)
47{
48 u8 i;
49 u8 size = sizeof(region_code_mapping)/
50 sizeof(struct region_code_mapping);
51
52 for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
53 region[i] = toupper(region[i]);
54
55 for (i = 0; i < size; i++) {
56 if (!memcmp(region, region_code_mapping[i].region,
57 COUNTRY_CODE_LEN))
58 return (region_code_mapping[i].code);
59 }
60
61 /* default is US */
62 return (region_code_mapping[0].code);
63}
64
65static u8 *wlan_code_2_region(u8 code)
66{
67 u8 i;
68 u8 size = sizeof(region_code_mapping)
69 / sizeof(struct region_code_mapping);
70 for (i = 0; i < size; i++) {
71 if (region_code_mapping[i].code == code)
72 return (region_code_mapping[i].region);
73 }
74 /* default is US */
75 return (region_code_mapping[0].region);
76}
77
78/**
79 * @brief This function finds the nrchan-th chan after the firstchan
80 * @param band band
81 * @param firstchan first channel number
82 * @param nrchan number of channels
83 * @return the nrchan-th chan number
84*/
85static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
86/*find the nrchan-th chan after the firstchan*/
87{
88 u8 i;
89 struct chan_freq_power *cfp;
90 u8 cfp_no;
91
92 cfp = channel_freq_power_UN_BG;
93 cfp_no = sizeof(channel_freq_power_UN_BG) /
94 sizeof(struct chan_freq_power);
95
96 for (i = 0; i < cfp_no; i++) {
97 if ((cfp + i)->channel == firstchan) {
98 lbs_pr_debug(1, "firstchan found\n");
99 break;
100 }
101 }
102
103 if (i < cfp_no) {
104 /*if beyond the boundary */
105 if (i + nrchan < cfp_no) {
106 *chan = (cfp + i + nrchan)->channel;
107 return 1;
108 }
109 }
110
111 return 0;
112}
113
114/**
115 * @brief This function Checks if chan txpwr is learned from AP/IBSS
116 * @param chan chan number
117 * @param parsed_region_chan pointer to parsed_region_chan_11d
118 * @return TRUE; FALSE
119*/
120static u8 wlan_channel_known_11d(u8 chan,
121 struct parsed_region_chan_11d * parsed_region_chan)
122{
123 struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
124 u8 nr_chan = parsed_region_chan->nr_chan;
125 u8 i = 0;
126
127 lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
128 sizeof(struct chan_power_11d) * nr_chan);
129
130 for (i = 0; i < nr_chan; i++) {
131 if (chan == chanpwr[i].chan) {
132 lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
133 return 1;
134 }
135 }
136
137 lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
138 return 0;
139}
140
141u32 libertas_chan_2_freq(u8 chan, u8 band)
142{
143 struct chan_freq_power *cf;
144 u16 cnt;
145 u16 i;
146 u32 freq = 0;
147
148 cf = channel_freq_power_UN_BG;
149 cnt =
150 sizeof(channel_freq_power_UN_BG) /
151 sizeof(struct chan_freq_power);
152
153 for (i = 0; i < cnt; i++) {
154 if (chan == cf[i].channel)
155 freq = cf[i].freq;
156 }
157
158 return freq;
159}
160
161static int generate_domain_info_11d(struct parsed_region_chan_11d
162 *parsed_region_chan,
163 struct wlan_802_11d_domain_reg * domaininfo)
164{
165 u8 nr_subband = 0;
166
167 u8 nr_chan = parsed_region_chan->nr_chan;
168 u8 nr_parsedchan = 0;
169
170 u8 firstchan = 0, nextchan = 0, maxpwr = 0;
171
172 u8 i, flag = 0;
173
174 memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
175 COUNTRY_CODE_LEN);
176
177 lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
178 lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
179 sizeof(struct parsed_region_chan_11d));
180
181 for (i = 0; i < nr_chan; i++) {
182 if (!flag) {
183 flag = 1;
184 nextchan = firstchan =
185 parsed_region_chan->chanpwr[i].chan;
186 maxpwr = parsed_region_chan->chanpwr[i].pwr;
187 nr_parsedchan = 1;
188 continue;
189 }
190
191 if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
192 parsed_region_chan->chanpwr[i].pwr == maxpwr) {
193 nextchan++;
194 nr_parsedchan++;
195 } else {
196 domaininfo->subband[nr_subband].firstchan = firstchan;
197 domaininfo->subband[nr_subband].nrchan =
198 nr_parsedchan;
199 domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
200 nr_subband++;
201 nextchan = firstchan =
202 parsed_region_chan->chanpwr[i].chan;
203 maxpwr = parsed_region_chan->chanpwr[i].pwr;
204 }
205 }
206
207 if (flag) {
208 domaininfo->subband[nr_subband].firstchan = firstchan;
209 domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
210 domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
211 nr_subband++;
212 }
213 domaininfo->nr_subband = nr_subband;
214
215 lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
216 lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
217 COUNTRY_CODE_LEN + 1 +
218 sizeof(struct ieeetypes_subbandset) * nr_subband);
219 return 0;
220}
221
222/**
223 * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
224 * @param region_chan pointer to struct region_channel
225 * @param *parsed_region_chan pointer to parsed_region_chan_11d
226 * @return N/A
227*/
228static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
229 struct parsed_region_chan_11d *
230 parsed_region_chan)
231{
232 u8 i;
233 struct chan_freq_power *cfp;
234
235 if (region_chan == NULL) {
236 lbs_pr_debug(1, "11D: region_chan is NULL\n");
237 return;
238 }
239
240 cfp = region_chan->CFP;
241 if (cfp == NULL) {
242 lbs_pr_debug(1, "11D: cfp equal NULL \n");
243 return;
244 }
245
246 parsed_region_chan->band = region_chan->band;
247 parsed_region_chan->region = region_chan->region;
248 memcpy(parsed_region_chan->countrycode,
249 wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
250
251 lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
252 parsed_region_chan->band);
253
254 for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
255 parsed_region_chan->chanpwr[i].chan = cfp->channel;
256 parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
257 lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
258 parsed_region_chan->chanpwr[i].chan,
259 parsed_region_chan->chanpwr[i].pwr);
260 }
261 parsed_region_chan->nr_chan = region_chan->nrcfp;
262
263 lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
264
265 return;
266}
267
268/**
269 * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
270 * @param region region ID
271 * @param band band
272 * @param chan chan
273 * @return TRUE;FALSE
274*/
275static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
276{
277 struct chan_freq_power *cfp;
278 int cfp_no;
279 u8 idx;
280
281 ENTER();
282
283 cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
284 if (cfp == NULL)
285 return 0;
286
287 for (idx = 0; idx < cfp_no; idx++) {
288 if (chan == (cfp + idx)->channel) {
289 /* If Mrvl Chip Supported? */
290 if ((cfp + idx)->unsupported) {
291 return 0;
292 } else {
293 return 1;
294 }
295 }
296 }
297
298 /*chan is not in the region table */
299 LEAVE();
300 return 0;
301}
302
303/**
304 * @brief This function checks if chan txpwr is learned from AP/IBSS
305 * @param chan chan number
306 * @param parsed_region_chan pointer to parsed_region_chan_11d
307 * @return 0
308*/
309static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
310 countryinfo,
311 u8 band,
312 struct parsed_region_chan_11d *
313 parsed_region_chan)
314{
315 u8 nr_subband, nrchan;
316 u8 lastchan, firstchan;
317 u8 region;
318 u8 curchan = 0;
319
320 u8 idx = 0; /*chan index in parsed_region_chan */
321
322 u8 j, i;
323
324 ENTER();
325
326 /*validation Rules:
327 1. valid region Code
328 2. First Chan increment
329 3. channel range no overlap
330 4. channel is valid?
331 5. channel is supported by region?
332 6. Others
333 */
334
335 lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
336
337 if ((*(countryinfo->countrycode)) == 0
338 || (countryinfo->len <= COUNTRY_CODE_LEN)) {
339 /* No region Info or Wrong region info: treat as No 11D info */
340 LEAVE();
341 return 0;
342 }
343
344 /*Step1: check region_code */
345 parsed_region_chan->region = region =
346 wlan_region_2_code(countryinfo->countrycode);
347
348 lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
349 lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
350 COUNTRY_CODE_LEN);
351
352 parsed_region_chan->band = band;
353
354 memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
355 COUNTRY_CODE_LEN);
356
357 nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
358 sizeof(struct ieeetypes_subbandset);
359
360 for (j = 0, lastchan = 0; j < nr_subband; j++) {
361
362 if (countryinfo->subband[j].firstchan <= lastchan) {
363 /*Step2&3. Check First Chan Num increment and no overlap */
364 lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
365 countryinfo->subband[j].firstchan, lastchan);
366 continue;
367 }
368
369 firstchan = countryinfo->subband[j].firstchan;
370 nrchan = countryinfo->subband[j].nrchan;
371
372 for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
373 /*step4: channel is supported? */
374
375 if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
376 /* Chan is not found in UN table */
377 lbs_pr_debug(1, "chan is not supported: %d \n", i);
378 break;
379 }
380
381 lastchan = curchan;
382
383 if (wlan_region_chan_supported_11d
384 (region, band, curchan)) {
385 /*step5: Check if curchan is supported by mrvl in region */
386 parsed_region_chan->chanpwr[idx].chan = curchan;
387 parsed_region_chan->chanpwr[idx].pwr =
388 countryinfo->subband[j].maxtxpwr;
389 idx++;
390 } else {
391 /*not supported and ignore the chan */
392 lbs_pr_debug(1,
393 "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
394 i, curchan, region, band);
395 }
396 }
397
398 /*Step6: Add other checking if any */
399
400 }
401
402 parsed_region_chan->nr_chan = idx;
403
404 lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
405 lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
406 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
407
408 LEAVE();
409 return 0;
410}
411
412/**
413 * @brief This function calculates the scan type for channels
414 * @param chan chan number
415 * @param parsed_region_chan pointer to parsed_region_chan_11d
416 * @return PASSIVE if chan is unknown; ACTIVE if chan is known
417*/
418u8 libertas_get_scan_type_11d(u8 chan,
419 struct parsed_region_chan_11d * parsed_region_chan)
420{
421 u8 scan_type = cmd_scan_type_passive;
422
423 ENTER();
424
425 if (wlan_channel_known_11d(chan, parsed_region_chan)) {
426 lbs_pr_debug(1, "11D: Found and do Active Scan\n");
427 scan_type = cmd_scan_type_active;
428 } else {
429 lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
430 }
431
432 LEAVE();
433 return scan_type;
434
435}
436
437void libertas_init_11d(wlan_private * priv)
438{
439 priv->adapter->enable11d = 0;
440 memset(&(priv->adapter->parsed_region_chan), 0,
441 sizeof(struct parsed_region_chan_11d));
442 return;
443}
444
445static int wlan_enable_11d(wlan_private * priv, u8 flag)
446{
447 int ret;
448
449 priv->adapter->enable11d = flag;
450
451 /* send cmd to FW to enable/disable 11D function in FW */
452 ret = libertas_prepare_and_send_command(priv,
453 cmd_802_11_snmp_mib,
454 cmd_act_set,
455 cmd_option_waitforrsp,
456 OID_802_11D_ENABLE,
457 &priv->adapter->enable11d);
458 if (ret)
459 lbs_pr_debug(1, "11D: Fail to enable 11D \n");
460
461 return 0;
462}
463
464/**
465 * @brief This function sets DOMAIN INFO to FW
466 * @param priv pointer to wlan_private
467 * @return 0; -1
468*/
469static int set_domain_info_11d(wlan_private * priv)
470{
471 int ret;
472
473 if (!priv->adapter->enable11d) {
474 lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
475 return 0;
476 }
477
478 ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
479 cmd_act_set,
480 cmd_option_waitforrsp, 0, NULL);
481 if (ret)
482 lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
483
484 return ret;
485}
486
487/**
488 * @brief This function setups scan channels
489 * @param priv pointer to wlan_private
490 * @param band band
491 * @return 0
492*/
493int libertas_set_universaltable(wlan_private * priv, u8 band)
494{
495 wlan_adapter *adapter = priv->adapter;
496 u16 size = sizeof(struct chan_freq_power);
497 u16 i = 0;
498
499 memset(adapter->universal_channel, 0,
500 sizeof(adapter->universal_channel));
501
502 adapter->universal_channel[i].nrcfp =
503 sizeof(channel_freq_power_UN_BG) / size;
504 lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
505 adapter->universal_channel[i].nrcfp);
506
507 adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
508 adapter->universal_channel[i].valid = 1;
509 adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
510 adapter->universal_channel[i].band = band;
511 i++;
512
513 return 0;
514}
515
516/**
517 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
518 * @param priv pointer to wlan_private
519 * @param cmd pointer to cmd buffer
520 * @param cmdno cmd ID
521 * @param cmdOption cmd action
522 * @return 0
523*/
524int libertas_cmd_802_11d_domain_info(wlan_private * priv,
525 struct cmd_ds_command *cmd, u16 cmdno,
526 u16 cmdoption)
527{
528 struct cmd_ds_802_11d_domain_info *pdomaininfo =
529 &cmd->params.domaininfo;
530 struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
531 wlan_adapter *adapter = priv->adapter;
532 u8 nr_subband = adapter->domainreg.nr_subband;
533
534 ENTER();
535
536 lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
537
538 cmd->command = cpu_to_le16(cmdno);
539 pdomaininfo->action = cpu_to_le16(cmdoption);
540 if (cmdoption == cmd_act_get) {
541 cmd->size =
542 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
543 lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
544 (int)(cmd->size));
545 LEAVE();
546 return 0;
547 }
548
549 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
550 memcpy(domain->countrycode, adapter->domainreg.countrycode,
551 sizeof(domain->countrycode));
552
553 domain->header.len =
554 cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
555 sizeof(domain->countrycode));
556
557 if (nr_subband) {
558 memcpy(domain->subband, adapter->domainreg.subband,
559 nr_subband * sizeof(struct ieeetypes_subbandset));
560
561 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
562 domain->header.len +
563 sizeof(struct mrvlietypesheader) +
564 S_DS_GEN);
565 } else {
566 cmd->size =
567 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
568 }
569
570 lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
571
572 LEAVE();
573
574 return 0;
575}
576
577/**
578 * @brief This function implements private cmd: enable/disable 11D
579 * @param priv pointer to wlan_private
580 * @param wrq pointer to user data
581 * @return 0 or -1
582 */
583int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
584{
585 int data = 0;
586 int *val;
587
588 ENTER();
589 data = SUBCMD_DATA(wrq);
590
591 lbs_pr_debug(1, "enable 11D: %s\n",
592 (data == 1) ? "enable" : "Disable");
593
594 wlan_enable_11d(priv, data);
595 val = (int *)wrq->u.name;
596 *val = priv->adapter->enable11d;
597
598 LEAVE();
599 return 0;
600}
601
602/**
603 * @brief This function parses countryinfo from AP and download country info to FW
604 * @param priv pointer to wlan_private
605 * @param resp pointer to command response buffer
606 * @return 0; -1
607 */
608int libertas_ret_802_11d_domain_info(wlan_private * priv,
609 struct cmd_ds_command *resp)
610{
611 struct cmd_ds_802_11d_domain_info
612 *domaininfo = &resp->params.domaininforesp;
613 struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
614 u16 action = le16_to_cpu(domaininfo->action);
615 s16 ret = 0;
616 u8 nr_subband = 0;
617
618 ENTER();
619
620 lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
621 (int)le16_to_cpu(resp->size));
622
623 nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
624 /* countrycode 3 bytes */
625
626 lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
627
628 if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
629 lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
630 return -1;
631 }
632
633 switch (action) {
634 case cmd_act_set: /*Proc Set action */
635 break;
636
637 case cmd_act_get:
638 break;
639 default:
640 lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
641 ret = -1;
642 break;
643 }
644
645 LEAVE();
646 return ret;
647}
648
649/**
650 * @brief This function parses countryinfo from AP and download country info to FW
651 * @param priv pointer to wlan_private
652 * @return 0; -1
653 */
654int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
655{
656 int ret;
657 wlan_adapter *adapter = priv->adapter;
658
659 ENTER();
660 if (priv->adapter->enable11d) {
661 memset(&adapter->parsed_region_chan, 0,
662 sizeof(struct parsed_region_chan_11d));
663 ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
664 countryinfo, 0,
665 &adapter->parsed_region_chan);
666
667 if (ret == -1) {
668 lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
669 LEAVE();
670 return ret;
671 }
672
673 memset(&adapter->domainreg, 0,
674 sizeof(struct wlan_802_11d_domain_reg));
675 generate_domain_info_11d(&adapter->parsed_region_chan,
676 &adapter->domainreg);
677
678 ret = set_domain_info_11d(priv);
679
680 if (ret) {
681 lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
682 LEAVE();
683 return ret;
684 }
685 }
686 LEAVE();
687 return 0;
688}
689
690/**
691 * @brief This function generates 11D info from user specified regioncode and download to FW
692 * @param priv pointer to wlan_private
693 * @return 0; -1
694 */
695int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
696{
697 int ret;
698 wlan_adapter *adapter = priv->adapter;
699 struct region_channel *region_chan;
700 u8 j;
701
702 ENTER();
703 lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
704
705 if (priv->adapter->enable11d) {
706 /* update parsed_region_chan_11; dnld domaininf to FW */
707
708 for (j = 0; j < sizeof(adapter->region_channel) /
709 sizeof(adapter->region_channel[0]); j++) {
710 region_chan = &adapter->region_channel[j];
711
712 lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
713 region_chan->band);
714
715 if (!region_chan || !region_chan->valid
716 || !region_chan->CFP)
717 continue;
718 if (region_chan->band != adapter->curbssparams.band)
719 continue;
720 break;
721 }
722
723 if (j >= sizeof(adapter->region_channel) /
724 sizeof(adapter->region_channel[0])) {
725 lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
726 adapter->curbssparams.band);
727 LEAVE();
728 return -1;
729 }
730
731 memset(&adapter->parsed_region_chan, 0,
732 sizeof(struct parsed_region_chan_11d));
733 wlan_generate_parsed_region_chan_11d(region_chan,
734 &adapter->
735 parsed_region_chan);
736
737 memset(&adapter->domainreg, 0,
738 sizeof(struct wlan_802_11d_domain_reg));
739 generate_domain_info_11d(&adapter->parsed_region_chan,
740 &adapter->domainreg);
741
742 ret = set_domain_info_11d(priv);
743
744 if (ret) {
745 lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
746 LEAVE();
747 return ret;
748 }
749
750 }
751
752 LEAVE();
753 return 0;
754}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644
index 000000000000..db2ebea9f231
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.h
@@ -0,0 +1,105 @@
1/**
2 * This header file contains data structures and
3 * function declarations of 802.11d
4 */
5#ifndef _WLAN_11D_
6#define _WLAN_11D_
7
8#include "types.h"
9#include "defs.h"
10
11#define UNIVERSAL_REGION_CODE 0xff
12
13/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
14 */
15#define MRVDRV_MAX_SUBBAND_802_11D 83
16
17#define COUNTRY_CODE_LEN 3
18#define MAX_NO_OF_CHAN 40
19
20struct cmd_ds_command;
21
22/** Data structure for Country IE*/
23struct ieeetypes_subbandset {
24 u8 firstchan;
25 u8 nrchan;
26 u8 maxtxpwr;
27} __attribute__ ((packed));
28
29struct ieeetypes_countryinfoset {
30 u8 element_id;
31 u8 len;
32 u8 countrycode[COUNTRY_CODE_LEN];
33 struct ieeetypes_subbandset subband[1];
34};
35
36struct ieeetypes_countryinfofullset {
37 u8 element_id;
38 u8 len;
39 u8 countrycode[COUNTRY_CODE_LEN];
40 struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
41} __attribute__ ((packed));
42
43struct mrvlietypes_domainparamset {
44 struct mrvlietypesheader header;
45 u8 countrycode[COUNTRY_CODE_LEN];
46 struct ieeetypes_subbandset subband[1];
47} __attribute__ ((packed));
48
49struct cmd_ds_802_11d_domain_info {
50 u16 action;
51 struct mrvlietypes_domainparamset domain;
52} __attribute__ ((packed));
53
54/** domain regulatory information */
55struct wlan_802_11d_domain_reg {
56 /** country Code*/
57 u8 countrycode[COUNTRY_CODE_LEN];
58 /** No. of subband*/
59 u8 nr_subband;
60 struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
61};
62
63struct chan_power_11d {
64 u8 chan;
65 u8 pwr;
66} __attribute__ ((packed));
67
68struct parsed_region_chan_11d {
69 u8 band;
70 u8 region;
71 s8 countrycode[COUNTRY_CODE_LEN];
72 struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
73 u8 nr_chan;
74} __attribute__ ((packed));
75
76struct region_code_mapping {
77 u8 region[COUNTRY_CODE_LEN];
78 u8 code;
79};
80
81u8 libertas_get_scan_type_11d(u8 chan,
82 struct parsed_region_chan_11d *parsed_region_chan);
83
84u32 libertas_chan_2_freq(u8 chan, u8 band);
85
86enum state_11d libertas_get_state_11d(wlan_private * priv);
87
88void libertas_init_11d(wlan_private * priv);
89
90int libertas_set_universaltable(wlan_private * priv, u8 band);
91
92int libertas_cmd_802_11d_domain_info(wlan_private * priv,
93 struct cmd_ds_command *cmd, u16 cmdno,
94 u16 cmdOption);
95
96int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
97
98int libertas_ret_802_11d_domain_info(wlan_private * priv,
99 struct cmd_ds_command *resp);
100
101int libertas_parse_dnld_countryinfo_11d(wlan_private * priv);
102
103int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
104
105#endif /* _WLAN_11D_ */
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644
index 000000000000..8862742213b9
--- /dev/null
+++ b/drivers/net/wireless/libertas/LICENSE
@@ -0,0 +1,16 @@
1 Copyright (c) 2003-2006, Marvell International Ltd.
2 All Rights Reserved
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of version 2 of the GNU General Public License as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 more details.
12
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 59
15 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644
index 000000000000..19c935071d8e
--- /dev/null
+++ b/drivers/net/wireless/libertas/Makefile
@@ -0,0 +1,21 @@
1# EXTRA_CFLAGS += -Wpacked
2
3usb8xxx-objs := main.o fw.o wext.o \
4 rx.o tx.o cmd.o \
5 cmdresp.o scan.o \
6 join.o 11d.o \
7 ioctl.o debugfs.o \
8 ethtool.o assoc.o
9
10ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
11EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
12endif
13
14
15# This is needed to support the newer boot2 bootloader (v >= 3104)
16EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
17usb8xxx-objs += if_bootcmd.o
18usb8xxx-objs += if_usb.o
19
20obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
21
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644
index 000000000000..688da4c784b1
--- /dev/null
+++ b/drivers/net/wireless/libertas/README
@@ -0,0 +1,1044 @@
1================================================================================
2 README for USB8388
3
4 (c) Copyright © 2003-2006, Marvell International Ltd.
5 All Rights Reserved
6
7 This software file (the "File") is distributed by Marvell International
8 Ltd. under the terms of the GNU General Public License Version 2, June 1991
9 (the "License"). You may use, redistribute and/or modify this File in
10 accordance with the terms and conditions of the License, a copy of which
11 is available along with the File in the license.txt file or by writing to
12 the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
14
15 THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 this warranty disclaimer.
19================================================================================
20
21=====================
22DRIVER LOADING
23=====================
24
25 o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
26
27 o. Load driver by using the following command:
28
29 insmod usb8388.ko [fw_name=usb8388.bin]
30
31=====================
32IWPRIV COMMAND
33=====================
34
35NAME
36 This manual describes the usage of private commands used in Marvell WLAN
37 Linux Driver. All the commands available in Wlanconfig will not be available
38 in the iwpriv.
39
40SYNOPSIS
41 iwpriv <ethX> <command> [sub-command] ...
42
43 iwpriv ethX version
44 iwpriv ethX scantype [sub-command]
45 iwpriv ethX getSNR <n>
46 iwpriv ethX getNF <n>
47 iwpriv ethX getRSSI <n>
48 iwpriv ethX setrxant <n>
49 iwpriv ethX getrxant
50 iwpriv ethX settxant <n>
51 iwpriv ethX gettxant
52 iwpriv ethX authalgs <n>
53 iwpriv ethX pre-TBTT <n>
54 iwpriv ethX 8021xauthalgs <n>
55 iwpriv ethX encryptionmode <n>
56 iwpriv ethX setregioncode <n>
57 iwpriv ethX getregioncode
58 iwpriv ethX setbcnavg <n>
59 iwpriv ethX getbcnavg
60 iwpriv ethX setdataavg <n>
61 iwpriv ethX setlisteninter <n>
62 iwpriv ethX getlisteninter
63 iwpriv ethX setmultipledtim <n>
64 iwpriv ethX getmultipledtim
65 iwpriv ethX atimwindow <n>
66 iwpriv ethX deauth
67 iwpriv ethX adhocstop
68 iwpriv ethX radioon
69 iwpriv ethX radiooff
70 iwpriv ethX reasso-on
71 iwpriv ethX reasso-off
72 iwpriv ethX scanmode [sub-command]
73 iwpriv ethX setwpaie <n>
74 iwpriv ethX wlanidle-off
75 iwpriv ethX wlanidle-on
76 iwpriv ethX getcis
77 iwpriv ethX getlog
78 iwpriv ethX getadhocstatus
79 iwpriv ethX adhocgrate <n>
80
81Version 4 Command:
82 iwpriv ethX inactvityto <n>
83 iwpriv ethX sleeppd <n>
84 iwpriv ethX enable11d <n>
85 iwpriv ethX tpccfg <n>
86 iwpriv ethX powercfg <n>
87 iwpriv ethX setafc <n>
88 iwpriv ethX getafc
89
90Version 5 Command:
91 iwpriv ethX ledgpio <n>
92 iwpriv ethX scanprobes <n>
93 iwpriv ethX lolisteninter <n>
94 iwpriv ethX rateadapt <n> <m>
95 iwpriv ethX txcontrol <n>
96 iwpriv ethX psnullinterval <n>
97 iwpriv ethX prescan <n>
98 iwpriv ethX getrxinfo
99 iwpriv ethX gettxrate
100 iwpriv ethX beaconinterval
101
102BT Commands:
103 The blinding table (BT) contains a list of mac addresses that should be
104 ignored by the firmware. It is primarily used for debugging and
105 testing networks. It can be edited and inspected with the following
106 commands:
107
108 iwpriv ethX bt_reset
109 iwpriv ethX bt_add <mac_address>
110 iwpriv ethX bt_del <mac_address>
111 iwpriv ethX bt_list <id>
112
113FWT Commands:
114 The forwarding table (FWT) is a feature used to manage mesh network
115 routing in the firmware. The FWT is essentially a routing table that
116 associates a destination mac address (da) with a next hop receiver
117 address (ra). The FWT can be inspected and edited with the following
118 iwpriv commands, which are described in greater detail below.
119 Eventually, the table will be automatically maintained by a custom
120 routing protocol.
121
122 NOTE: FWT commands replace the previous DFT commands. What were the DFT
123 commands?, you might ask. They were an earlier API to the firmware that
124 implemented a simple MAC-layer forwarding mechanism. In the unlikely
125 event that you were using these commands, you must migrate to the new
126 FWT commands which can be used to achieve the same functionality.
127
128 iwpriv ethX fwt_add [parameters]
129 iwpriv ethX fwt_del [parameters]
130 iwpriv ethX fwt_lookup [parameters]
131 iwpriv ethX fwt_list [parameters]
132 iwpriv ethX fwt_list_route [parameters]
133 iwpriv ethX fwt_list_neigh [parameters]
134 iwpriv ethX fwt_reset [parameters]
135 iwpriv ethX fwt_cleanup
136 iwpriv ethX fwt_time
137
138MESH Commands:
139
140 The MESH commands are used to configure various features of the mesh
141 routing protocol. The following commands are supported:
142
143 iwpriv ethX mesh_get_ttl
144 iwpriv ethX mesh_set_ttl ttl
145
146DESCRIPTION
147 Those commands are used to send additional commands to the Marvell WLAN
148 card via the Linux device driver.
149
150 The ethX parameter specifies the network device that is to be used to
151 perform this command on. it could be eth0, eth1 etc.
152
153version
154 This is used to get the current version of the driver and the firmware.
155
156scantype
157 This command is used to set the scan type to be used by the driver in
158 the scan command. This setting will not be used while performing a scan
159 for a specific SSID, as it is always done with scan type being active.
160
161 where the sub-commands are: -
162 active -- to set the scan type to active
163 passive -- to set the scan type to passive
164 get -- to get the scan type set in the driver
165
166getSNR
167 This command gets the average and non average value of Signal to Noise
168 Ratio of Beacon and Data.
169
170 where value is:-
171 0 -- Beacon non-average.
172 1 -- Beacon average.
173 2 -- Data non-average.
174 3 -- Data average.
175
176 If no value is given, all four values are returned in the order mentioned
177 above.
178
179 Note: This command is available only when STA is connected.
180
181getRSSI
182 This command gets the average and non average value os Receive Signal
183 Strength of Beacon and Data.
184
185 where value is:-
186 0 -- Beacon non-average.
187 1 -- Beacon average.
188 2 -- Data non-average.
189 3 -- Data average.
190
191 Note: This command is available only when STA is connected.
192
193getNF
194 This command gets the average and non average value of Noise Floor of
195 Beacon and Data.
196
197 where value is:-
198 0 -- Beacon non-average.
199 1 -- Beacon average.
200 2 -- Data non-average.
201 3 -- Data average.
202
203 Note: This command is available only when STA is connected.
204
205setrxant
206 This command is used to set the mode for Rx antenna.
207
208 The options that can be sent are:-
209 1 -- Antenna 1.
210 2 -- Antenna 2.
211 0xFFFF -- Diversity.
212
213 Usage:
214 iwpriv ethX setrxant 0x01: select Antenna 1.
215
216getrxant
217 This command is used to get the mode for Rx antenna.
218
219
220settxant
221 This command is used to set the mode for Tx antenna.
222 The options that can be sent are:-
223 1 -- Antenna 1.
224 2 -- Antenna 2.
225 0xFFFF -- Diversity.
226 Usage:
227 iwpriv ethX settxant 0x01: select Antenna 1.
228
229gettxant
230 This command is used to get the mode for Tx antenna.
231
232authalgs
233 This command is used by the WPA supplicant to set the authentication
234 algorithms in the station.
235
2368021xauthalgs
237 This command is used by the WPA supplicant to set the 8021.x authentication algorithm type
238 station.
239
240 where values can be:-
241 1 -- None
242 2 -- LEAP
243 4 -- TLS
244 8 -- TTLs
245 16 -- MD5
246
247
248encryptionmode
249 This command is used by the WPA supplicant to set the encryption algorithm.
250
251 where values can be:-
252 0 -- NONE
253 1 -- WEP40
254 2 -- TKIP
255 3 -- CCMP
256 4 -- WEP104
257
258pre-TBTT
259 This command is used to set pre-TBTT time period where value is in microseconds.
260
261setregioncode
262 This command is used to set the region code in the station.
263 where value is 'region code' for various regions like
264 USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
265
266 Usage:
267 iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
268
269getregioncode
270 This command is used to get the region code information set in the
271 station.
272
273setbcnavg
274 Set the weighting factor for calculating RSSI.
275
276getbcnavg
277 Get weighting factor for calculating RSSI.
278
279setdataavg
280 Set the weighting factor for calculating SNR.
281
282setlisteninter
283 This command is used to set the listen interval in the
284 station.
285
286 where the value ranges between 1 - 255
287
288getlisteninter
289 This command is used to get the listen interval value set in the
290 station.
291
292setmultipledtim
293 This command is used to set the multiple dtim value in the
294 station.
295 where the value is 1,2,3,4,5,0xfffe
296 0xfffe means the firmware will use listen interval in association
297 command for waking up
298
299getmultipledtim
300 This command is used to get the multiple dtim value set in the station.
301
302atimwindow
303 This command is used to set the atim value in the
304 station.
305
306 where the value ranges between 0 - 50
307
308deauth
309 This command is used to send the de-authentication to the AP with which
310 the station is associated. This command is valid only when
311 station is in Infrastructure mode.
312
313 Note: This command is available only when STA is connected.
314
315adhocstop
316 This command is used to stop beacon transmission from the station and
317 go into idle state in ad-hoc mode.
318
319 Note: This command is available only when STA is connected.
320
321radioon
322 This command is used to turn on the RF antenna.
323
324radiooff
325 This command is sued to turn off the RF antenna.
326
327scanmode
328 This command is used to set the station to scan for either IBSS
329 networks or BSS networks or both BSS and IBSS networks. This
330 command can be used with sub commands,
331
332 where the value for
333 bss -- Scan All the BSS networks.
334 ibss -- Scan All the IBSS networks.
335 any -- Scan both BSS and IBSS networks.
336
337
338
339setwpaie
340 This command is used by WPA supplicant to send the WPA-IE to the driver.
341
342wlanidle-off
343 This command is used to get into idle state.
344
345 Note: This command is available only when STA is connected.
346
347wlanidle-on
348 This command is used to get off the idle state.
349
350 Note: This command is available only when STA is connected.
351
352
353getlog
354 This command is used to get the 802.11 statistics available in the
355 station.
356
357 Note: This command is available only when STA is connected.
358
359getadhocstatus
360 This command is used to get the ad-hoc Network Status.
361
362 The various status codes are:
363 AdhocStarted
364 AdhocJoined
365 AdhocIdle
366 InfraMode
367 AutoUnknownMode
368
369 Note: This command is available only when STA is connected.
370
371adhocgrate
372 This command is used to enable(1) g_rate, Disable(0) g_rate
373 and request(2) the status which g_rate is disabled/enabled,
374 for Ad-hoc creator.
375
376 where value is:-
377 0 -- Disabled
378 1 -- Enabled
379 2 -- Get
380
381ledgpio
382 This command is used to set/get LEDs.
383
384 iwpriv ethX ledgpio <LEDs>
385 will set the corresponding LED for the GPIO Line.
386
387 iwpriv ethX ledgpio
388 will give u which LEDs are Enabled.
389
390 Usage:
391 iwpriv eth1 ledgpio 1 0 2 1 3 4
392 will enable
393 LED 1 -> GPIO 0
394 LED 2 -> GPIO 1
395 LED 3 -> GPIO 4
396
397 iwpriv eth1 ledgpio
398 shows LED information in the format as mentioned above.
399
400 Note: LED0 is invalid
401 Note: Maximum Number of LEDs are 16.
402
403inactivityto
404 This command is used by the host to set/get the inactivity timeout value,
405 which specifies when WLAN device is put to sleep.
406
407 Usage:
408 iwpriv ethX inactivityto [<timeout>]
409
410 where the parameter are:
411 timeout: timeout value in milliseconds.
412
413 Example:
414 iwpriv eth1 inactivityto
415 "get the timeout value"
416
417 iwpriv eth1 inactivityto X
418 "set timeout value to X ms"
419
420
421sleeppd
422 This command is used to configure the sleep period of the WLAN device.
423
424 Usage:
425 iwpriv ethX sleeppd [<sleep period>]
426
427 where the parameter are:
428 Period: sleep period in milliseconds. Range 10~60.
429
430 Example:
431 iwpriv eth1 sleeppd 10
432 "set period as 10 ms"
433 iwpriv eth1 sleeppd
434 "get the sleep period configuration"
435
436enable11d
437 This command is used to control 11d
438 where value is:-
439 1 -- Enabled
440 0 -- Disabled
441 2 -- Get
442
443
444
445
446tpccfg
447 Enables or disables automatic transmit power control.
448
449 The first parameter turns this feature on (1) or off (0). When turning
450 on, the user must also supply four more parameters in the following
451 order:
452 -UseSNR (Use SNR (in addition to PER) for TPC algorithm),
453 -P0 (P0 power level for TPC),
454 -P1 (P1 power level for TPC),
455 -P2 (P2 power level for TPC).
456
457 Usage:
458 iwpriv ethX tpccfg: Get current configuration
459 iwpriv ethX tpccfg 0: disable auto TPC
460 iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
461 P0=0x05; P1=0x0a; P2=0x0d;
462 iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
463 P0=0x05; P1=0x0a; P2=0x0d.
464
465powercfg
466 Enables or disables power adaptation.
467
468 The first parameter turns this feature on (1) or off (0). When turning
469 on, the user must also supply three more parameters in the following
470 order:
471 -P0 (P0 power level for Power Adaptation),
472 -P1 (P1 power level for Power Adaptation),
473 -P2 (P2 power level for Power Adaptation).
474
475 Usage:
476 iwpriv ethX powercfg: Get current configuration
477 iwpriv ethX powercfg 0: disable power adaptation
478 iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation;
479 P0=0x0d; P1=0x0f; P2=0x12.
480
481getafc
482 This command returns automatic frequency control parameters. It returns
483 three integers:
484 -P0: automatic is on (1), or off (0),
485 -P1: current timing offset in PPM (part per million), and
486 -P2: current frequency offset in PPM.
487
488setafc
489 Set automatic frequency control options.
490
491 The first parameter turns automatic on (1) or off (0).
492 The user must supply two more parameters in either case, in the following
493 order:
494
495 When auto is on:
496
497 -P0 (automatic adjustment frequency threshold in PPM),
498 -P1 (automatic adjustment period in beacon period),
499
500 When auto is off:
501
502 -P0 (manual adjustment timing offset in PPM), and
503 -P1 (manual adjustment frequency offset in PPM).
504
505 Usage:
506 iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy
507 offset are 10 PPM.
508
509 iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment,
510 frequency threshold 10 PPM, for every 10 beacon periods.
511
512
513
514scanprobes
515 This command sets number of probe requests per channel.
516
517 Usage:
518 iwpriv ethX scanprobes 3 (set scan probes to 3)
519 iwpriv ethX scanprobes (get scan probes)
520
521lolisteninter
522 This command sets the value of listen interval.
523
524 Usage:
525 iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
526 iwpriv ethX lolisteninter (get the lolisteninter value)
527
528rateadapt
529 This command sets the data rates bitmap.
530 Where <n>
531 0: Disable auto rate adapt
532 1: Enable auto rate adapt
533
534 <m>
535 data rate bitmap
536 Bit Data rate
537 0 1 Mbps
538 1 2 Mbps
539 2 5.5 Mbps
540 3 11 Mbps
541 4 Reserved
542 5 6 Mbps
543 6 9 Mbps
544 7 12 Mbps
545 8 18 Mbps
546 9 24 Mbps
547 10 36 Mbps
548 11 48 Mbps
549 12 54 Mbps
550 12-15 Reserved
551
552 Usage:
553 iwpriv ethX rateadapt
554 read the currect data rate setting
555 iwpriv ethX rateadapt 1 0x07
556 enable auto data rate adapt and
557 data rates are 1Mbps, 2Mbsp and 5.5Mbps
558
559
560txcontrol
561 This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis.
562
563 Where value <n> is:
564 if bit[4] == 1:
565 bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16
566 Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv
567
568 bit[12:8]
569 if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
570
571 bit[14:13] specifies per packet ack policy:
572 bit[14:13]
573 1 0 use immediate ack policy for this packet
574 1 1 use no ack policy for this packet
575 0 x use the per-packet ack policy setting
576
577 Usage:
578 iwpriv ethX txcontrol 0x7513
579 Use no-ack policy, 5 retires for Tx, 11Mbps rate
580
581
582
583psnullinterval
584 This command is used to set/request NULL package interval for Power Save
585 under infrastructure mode.
586
587 where value is:-
588 -1 -- Disabled
589 n>0 -- Set interval as n (seconds)
590
591prescan
592 This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap
593
594 where value is:-
595 0 -- Disabled
596 1 -- Enabled
597 2 -- Get
598
599getrxinfo
600 This command gets non average value of Signal to Noise Ratio of Data and rate index.
601
602 The following table shows RateIndex and Rate
603
604 RateIndex Data rate
605 0 1 Mbps
606 1 2 Mbps
607 2 5.5 Mbps
608 3 11 Mbps
609 4 Reserved
610 5 6 Mbps
611 6 9 Mbps
612 7 12 Mbps
613 8 18 Mbps
614 9 24 Mbps
615 10 36 Mbps
616 11 48 Mbps
617 12 54 Mbps
618 13-15 Reserved
619
620gettxrate
621 This command gets current Tx rate index of the first packet associated with Rate Adaptation.
622
623 The following table shows RateIndex and Rate
624
625 RateIndex Data rate
626 0 1 Mbps
627 1 2 Mbps
628 2 5.5 Mbps
629 3 11 Mbps
630 4 Reserved
631 5 6 Mbps
632 6 9 Mbps
633 7 12 Mbps
634 8 18 Mbps
635 9 24 Mbps
636 10 36 Mbps
637 11 48 Mbps
638 12 54 Mbps
639 13-15 Reserved
640
641bcninterval
642 This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc
643 beacon interval when no argument is given. The valid beacon interval is between 20 - 1000,
644 default beacon interval is 100.
645
646 Usage:
647 iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100)
648 iwpriv ethX bcninterval (get adhoc beacon interval)
649
650fwt_add
651 This command is used to insert an entry into the FWT table. The list of
652 parameters must follow the following structure:
653
654 iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
655
656 The parameters between brackets are optional, but they must appear in
657 the order specified. For example, if you want to specify the metric,
658 you must also specify the dir, ssn, and dsn but you need not specify the
659 hopcount, expiration, sleepmode, or snr. Any unspecified parameters
660 will be assigned the defaults specified below.
661
662 The different parameters are:-
663 da -- DA MAC address in the form 00:11:22:33:44:55
664 ra -- RA MAC address in the form 00:11:22:33:44:55
665 metric -- route metric (cost: smaller-metric routes are
666 preferred, default is 0)
667 dir -- direction (1 for direct, 0 for reverse,
668 default is 1)
669 ssn -- Source Sequence Number (time at the RA for
670 reverse routes. Default is 0)
671 dsn -- Destination Sequence Number (time at the DA
672 for direct routes. Default is 0)
673 hopcount -- hop count (currently unused, default is 0)
674 ttl -- TTL (Only used in reverse entries)
675 expiration -- entry expiration (in ticks, where a tick is
676 1024us, or ~ 1ms. Use 0 for an indefinite
677 entry, default is 0)
678 sleepmode -- RA's sleep mode (currently unused, default is
679 0)
680 snr -- SNR in the link to RA (currently unused,
681 default is 0)
682
683 The command does not return anything.
684
685fwt_del
686 This command is used to remove an entry to the FWT table. The list of
687 parameters must follow the following structure:
688
689 iwpriv ethX fwt_del da ra [dir]
690
691 where the different parameters are:-
692 da -- DA MAC address (in the form "00:11:22:33:44:55")
693 ra -- RA MAC address (in the form "00:11:22:33:44:55")
694 dir -- direction (1 for direct, 0 for reverse,
695 default is 1)
696
697 The command does not return anything.
698
699fwt_lookup
700 This command is used to get the best route in the FWT table to a given
701 host. The only parameter is the MAC address of the host that is being
702 looked for.
703
704 iwpriv ethX fwt_lookup da
705
706 where:-
707 da -- DA MAC address (in the form "00:11:22:33:44:55")
708
709 The command returns an output string identical to the one returned by
710 fwt_list described below.
711
712
713fwt_list
714 This command is used to list a route from the FWT table. The only
715 parameter is the index into the table. If you want to list all the
716 routes in a table, start with index=0, and keep listing until you get a
717 "(null)" string. Note that the indicies may change as the fwt is
718 updated. It is expected that most users will not use fwt_list directly,
719 but that a utility similar to the traditional route command will be used
720 to invoke fwt_list over and over.
721
722 iwpriv ethX fwt_list index
723
724 The output is a string of the following form:
725
726 da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
727
728 where the different fields are:-
729 da -- DA MAC address (in the form "00:11:22:33:44:55")
730 ra -- RA MAC address (in the form "00:11:22:33:44:55")
731 metric -- route metric (cost: smaller-metric routes are preferred)
732 dir -- direction (1 for direct, 0 for reverse)
733 ssn -- Source Sequence Number (time at the RA for reverse routes)
734 dsn -- Destination Sequence Number (time at the DA for direct routes)
735 hopcount -- hop count (currently unused)
736 ttl -- TTL (only used in reverse entries)
737 expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
738 sleepmode -- RA's sleep mode (currently unused)
739 snr -- SNR in the link to RA (currently unused)
740
741fwt_list_route
742 This command is used to list a route from the FWT table. The only
743 parameter is the route ID. If you want to list all the routes in a
744 table, start with rid=0, and keep incrementing rid until you get a
745 "(null)" string. This function is similar to fwt_list. The only
746 difference is the output format. Also note that this command is meant
747 for debugging. It is expected that users will use fwt_lookup and
748 fwt_list. One important reason for this is that the route id may change
749 as the route table is altered.
750
751 iwpriv ethX fwt_list_route rid
752
753 The output is a string of the following form:
754
755 da metric dir nid ssn dsn hopcount ttl expiration
756
757 where the different fields are:-
758 da -- DA MAC address (in the form "00:11:22:33:44:55")
759 metric -- route metric (cost: smaller-metric routes are preferred)
760 dir -- direction (1 for direct, 0 for reverse)
761 nid -- Next-hop (neighbor) host ID (nid)
762 ssn -- Source Sequence Number (time at the RA for reverse routes)
763 dsn -- Destination Sequence Number (time at the DA for direct routes)
764 hopcount -- hop count (currently unused)
765 ttl -- TTL count (only used in reverse entries)
766 expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
767
768fwt_list_neigh
769 This command is used to list a neighbor from the FWT table. The only
770 parameter is the neighbor ID. If you want to list all the neighbors in a
771 table, start with nid=0, and keep incrementing nid until you get a
772 "(null)" string. Note that the nid from a fwt_list_route command can be
773 used as an input to this command. Also note that this command is meant
774 mostly for debugging. It is expected that users will use fwt_lookup.
775 One important reason for this is that the neighbor id may change as the
776 neighbor table is altered.
777
778 iwpriv ethX fwt_list_neigh nid
779
780 The output is a string of the following form:
781
782 ra sleepmode snr references
783
784 where the different fields are:-
785 ra -- RA MAC address (in the form "00:11:22:33:44:55")
786 sleepmode -- RA's sleep mode (currently unused)
787 snr -- SNR in the link to RA (currently unused)
788 references -- RA's reference counter
789
790fwt_reset
791 This command is used to reset the FWT table, getting rid of all the
792 entries. There are no input parameters.
793
794 iwpriv ethX fwt_reset
795
796 The command does not return anything.
797
798fwt_cleanup
799 This command is used to perform user-based garbage recollection. The
800 FWT table is checked, and all the entries that are expired or invalid
801 are cleaned. Note that this is exported to the driver for debugging
802 purposes, as garbage collection is also fired by the firmware when in
803 space problems. There are no input parameters.
804
805 iwpriv ethX fwt_cleanup
806
807 The command does returns the number of invalid/expired routes deleted.
808
809fwt_time
810 This command returns a card's internal time representation. It is this
811 time that is used to represent the expiration times of FWT entries. The
812 number is not consistent from card to card; it is simply a timer count.
813 The fwt_time command is used to inspect the timer so that expiration
814 times reported by fwt_list can be properly interpreted.
815
816 iwpriv ethX fwt_time
817
818mesh_get_ttl
819
820 The mesh ttl is the number of hops a mesh packet can traverse before it
821 is dropped. This parameter is used to prevent infinite loops in the
822 mesh network. The value returned by this function is the ttl assigned
823 to all mesh packets. Currently there is no way to control the ttl on a
824 per packet or per socket basis.
825
826 iwpriv ethX mesh_get_ttl
827
828mesh_set_ttl ttl
829
830 Set the ttl. The argument must be between 0 and 255.
831
832 iwpriv ethX mesh_set_ttl <ttl>
833
834=========================
835ETHTOOL
836=========================
837
838
839Use the -i option to retrieve version information from the driver.
840
841# ethtool -i eth0
842driver: libertas
843version: COMM-USB8388-318.p4
844firmware-version: 5.110.7
845bus-info:
846
847Use the -e option to read the EEPROM contents of the card.
848
849 Usage:
850 ethtool -e ethX [raw on|off] [offset N] [length N]
851
852 -e retrieves and prints an EEPROM dump for the specified ethernet
853 device. When raw is enabled, then it dumps the raw EEPROM data
854 to stdout. The length and offset parameters allow dumping cer-
855 tain portions of the EEPROM. Default is to dump the entire EEP-
856 ROM.
857
858# ethtool -e eth0 offset 0 length 16
859Offset Values
860------ ------
8610x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
862
863========================
864DEBUGFS COMMANDS
865========================
866
867those commands are used via debugfs interface
868
869===========
870rdmac
871rdbbp
872rdrf
873 These commands are used to read the MAC, BBP and RF registers from the
874 card. These commands take one parameter that specifies the offset
875 location that is to be read. This parameter must be specified in
876 hexadecimal (its possible to preceed preceding the number with a "0x").
877
878 Path: /debugfs/libertas_wireless/ethX/registers/
879
880 Usage:
881 echo "0xa123" > rdmac ; cat rdmac
882 echo "0xa123" > rdbbp ; cat rdbbp
883 echo "0xa123" > rdrf ; cat rdrf
884wrmac
885wrbbp
886wrrf
887 These commands are used to write the MAC, BBP and RF registers in the
888 card. These commands take two parameters that specify the offset
889 location and the value that is to be written. This parameters must
890 be specified in hexadecimal (its possible to preceed the number
891 with a "0x").
892
893 Usage:
894 echo "0xa123 0xaa" > wrmac
895 echo "0xa123 0xaa" > wrbbp
896 echo "0xa123 0xaa" > wrrf
897
898sleepparams
899 This command is used to set the sleepclock configurations
900
901 Path: /debugfs/libertas_wireless/ethX/
902
903 Usage:
904 cat sleepparams: reads the current sleepclock configuration
905
906 echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
907
908 where:
909 p1 is Sleep clock error in ppm (0-65535)
910 p2 is Wakeup offset in usec (0-65535)
911 p3 is Clock stabilization time in usec (0-65535)
912 p4 is Control periodic calibration (0-2)
913 p5 is Control the use of external sleep clock (0-2)
914 p6 is reserved for debug (0-65535)
915
916subscribed_events
917
918 The subscribed_events directory contains the interface for the
919 subscribed events API.
920
921 Path: /debugfs/libertas_wireless/ethX/subscribed_events/
922
923 Each event is represented by a filename. Each filename consists of the
924 following three fields:
925 Value Frequency Subscribed
926
927 To read the current values for a given event, do:
928 cat event
929 To set the current values, do:
930 echo "60 2 1" > event
931
932 Frequency field specifies the reporting frequency for this event.
933 If it is set to 0, then the event is reported only once, and then
934 automatically unsubscribed. If it is set to 1, then the event is
935 reported every time it occurs. If it is set to N, then the event is
936 reported every Nth time it occurs.
937
938 beacon_missed
939 Value field specifies the number of consecutive missing beacons which
940 triggers the LINK_LOSS event. This event is generated only once after
941 which the firmware resets its state. At initialization, the LINK_LOSS
942 event is subscribed by default. The default value of MissedBeacons is
943 60.
944
945 failure_count
946 Value field specifies the consecutive failure count threshold which
947 triggers the generation of the MAX_FAIL event. Once this event is
948 generated, the consecutive failure count is reset to 0.
949 At initialization, the MAX_FAIL event is NOT subscribed by
950 default.
951
952 high_rssi
953 This event is generated when the average received RSSI in beacons goes
954 above a threshold, specified by Value.
955
956 low_rssi
957 This event is generated when the average received RSSI in beacons goes
958 below a threshold, specified by Value.
959
960 high_snr
961 This event is generated when the average received SNR in beacons goes
962 above a threshold, specified by Value.
963
964 low_snr
965 This event is generated when the average received SNR in beacons goes
966 below a threshold, specified by Value.
967
968extscan
969 This command is used to do a specific scan.
970
971 Path: /debugfs/libertas_wireless/ethX/
972
973 Usage: echo "SSID" > extscan
974
975 Example:
976 echo "LINKSYS-AP" > extscan
977
978 To see the results of use getscantable command.
979
980getscantable
981
982 Display the current contents of the driver scan table (ie. get the
983 scan results).
984
985 Path: /debugfs/libertas_wireless/ethX/
986
987 Usage:
988 cat getscantable
989
990setuserscan
991 Initiate a customized scan and retrieve the results
992
993
994 Path: /debugfs/libertas_wireless/ethX/
995
996 Usage:
997 echo "[ARGS]" > setuserscan
998
999 where [ARGS]:
1000
1001 chan=[chan#][band][mode] where band is [a,b,g] and mode is
1002 blank for active or 'p' for passive
1003 bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
1004 ssid="[SSID]" specify a SSID filter for the scan
1005 keep=[0 or 1] keep the previous scan results (1), discard (0)
1006 dur=[scan time] time to scan for each channel in milliseconds
1007 probes=[#] number of probe requests to send on each chan
1008 type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
1009
1010 Any combination of the above arguments can be supplied on the command line.
1011 If the chan token is absent, a full channel scan will be completed by
1012 the driver. If the dur or probes tokens are absent, the driver default
1013 setting will be used. The bssid and ssid fields, if blank,
1014 will produce an unfiltered scan. The type field will default to 3 (Any)
1015 and the keep field will default to 0 (Discard).
1016
1017 Examples:
1018 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
1019 echo "chan=1g,6g,11g" > setuserscan
1020
1021 2) Perform a passive scan on channel 11 for 20 ms:
1022 echo "chan=11gp dur=20" > setuserscan
1023
1024 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
1025 channel 36 in the 'a' band:
1026
1027 echo "chan=1g,6g,11g,36ap" > setuserscan
1028
1029 4) Perform an active scan on channel 6 and 36 for a specific SSID:
1030 echo "chan=6g,36a ssid="TestAP"" > setuserscan
1031
1032 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
1033 the current scan table intact, update existing or append new scan data:
1034 echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
1035
1036 6) Scan channel 6, for all infrastructure networks, sending two probe
1037 requests. Keep the previous scan table intact. Update any duplicate
1038 BSSID/SSID matches with the new scan data:
1039 echo "chan=6g type=1 probes=2 keep=1" > setuserscan
1040
1041 All entries in the scan table (not just the new scan data when keep=1)
1042 will be displayed upon completion by use of the getscantable ioctl.
1043
1044==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644
index 000000000000..b55c7f57aca8
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -0,0 +1,588 @@
1/* Copyright (C) 2006, Red Hat, Inc. */
2
3#include <linux/bitops.h>
4#include <net/ieee80211.h>
5
6#include "assoc.h"
7#include "join.h"
8#include "decl.h"
9#include "hostcmd.h"
10#include "host.h"
11
12
13static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
14static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
15
16static int assoc_helper_essid(wlan_private *priv,
17 struct assoc_request * assoc_req)
18{
19 wlan_adapter *adapter = priv->adapter;
20 int ret = 0;
21 int i;
22
23 ENTER();
24
25 lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
26 if (assoc_req->mode == wlan802_11infrastructure) {
27 if (adapter->prescan) {
28 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
29 }
30
31 i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
32 NULL, wlan802_11infrastructure);
33 if (i >= 0) {
34 lbs_pr_debug(1,
35 "SSID found in scan list ... associating...\n");
36
37 ret = wlan_associate(priv, &adapter->scantable[i]);
38 if (ret == 0) {
39 memcpy(&assoc_req->bssid,
40 &adapter->scantable[i].macaddress,
41 ETH_ALEN);
42 }
43 } else {
44 lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
45 assoc_req->ssid.ssid);
46 }
47 } else if (assoc_req->mode == wlan802_11ibss) {
48 /* Scan for the network, do not save previous results. Stale
49 * scan data will cause us to join a non-existant adhoc network
50 */
51 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
52
53 /* Search for the requested SSID in the scan table */
54 i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
55 wlan802_11ibss);
56 if (i >= 0) {
57 lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
58 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
59 } else {
60 /* else send START command */
61 lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
62 " with SSID '%s'\n", assoc_req->ssid.ssid);
63 libertas_start_adhoc_network(priv, &assoc_req->ssid);
64 }
65 memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
66 }
67
68 LEAVE();
69 return ret;
70}
71
72
73static int assoc_helper_bssid(wlan_private *priv,
74 struct assoc_request * assoc_req)
75{
76 wlan_adapter *adapter = priv->adapter;
77 int i, ret = 0;
78
79 ENTER();
80
81 lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
82 MAC_ARG(assoc_req->bssid));
83
84 /* Search for index position in list for requested MAC */
85 i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
86 assoc_req->mode);
87 if (i < 0) {
88 lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
89 "cannot associate.\n", MAC_ARG(assoc_req->bssid));
90 goto out;
91 }
92
93 if (assoc_req->mode == wlan802_11infrastructure) {
94 ret = wlan_associate(priv, &adapter->scantable[i]);
95 lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
96 } else if (assoc_req->mode == wlan802_11ibss) {
97 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
98 }
99 memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
100 sizeof(struct WLAN_802_11_SSID));
101
102out:
103 LEAVE();
104 return ret;
105}
106
107
108static int assoc_helper_associate(wlan_private *priv,
109 struct assoc_request * assoc_req)
110{
111 int ret = 0, done = 0;
112
113 /* If we're given and 'any' BSSID, try associating based on SSID */
114
115 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
116 if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
117 && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
118 ret = assoc_helper_bssid(priv, assoc_req);
119 done = 1;
120 if (ret) {
121 lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
122 }
123 }
124 }
125
126 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
127 ret = assoc_helper_essid(priv, assoc_req);
128 if (ret) {
129 lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
130 }
131 }
132
133 return ret;
134}
135
136
137static int assoc_helper_mode(wlan_private *priv,
138 struct assoc_request * assoc_req)
139{
140 wlan_adapter *adapter = priv->adapter;
141 int ret = 0;
142
143 ENTER();
144
145 if (assoc_req->mode == adapter->inframode) {
146 LEAVE();
147 return 0;
148 }
149
150 if (assoc_req->mode == wlan802_11infrastructure) {
151 if (adapter->psstate != PS_STATE_FULL_POWER)
152 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
153 adapter->psmode = wlan802_11powermodecam;
154 }
155
156 adapter->inframode = assoc_req->mode;
157 ret = libertas_prepare_and_send_command(priv,
158 cmd_802_11_snmp_mib,
159 0, cmd_option_waitforrsp,
160 OID_802_11_INFRASTRUCTURE_MODE,
161 (void *) assoc_req->mode);
162
163 LEAVE();
164 return ret;
165}
166
167
168static int assoc_helper_wep_keys(wlan_private *priv,
169 struct assoc_request * assoc_req)
170{
171 wlan_adapter *adapter = priv->adapter;
172 int i;
173 int ret = 0;
174
175 ENTER();
176
177 /* Set or remove WEP keys */
178 if ( assoc_req->wep_keys[0].len
179 || assoc_req->wep_keys[1].len
180 || assoc_req->wep_keys[2].len
181 || assoc_req->wep_keys[3].len) {
182 ret = libertas_prepare_and_send_command(priv,
183 cmd_802_11_set_wep,
184 cmd_act_add,
185 cmd_option_waitforrsp,
186 0, assoc_req);
187 } else {
188 ret = libertas_prepare_and_send_command(priv,
189 cmd_802_11_set_wep,
190 cmd_act_remove,
191 cmd_option_waitforrsp,
192 0, NULL);
193 }
194
195 if (ret)
196 goto out;
197
198 /* enable/disable the MAC's WEP packet filter */
199 if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
200 adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
201 else
202 adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
203 ret = libertas_set_mac_packet_filter(priv);
204 if (ret)
205 goto out;
206
207 mutex_lock(&adapter->lock);
208
209 /* Copy WEP keys into adapter wep key fields */
210 for (i = 0; i < 4; i++) {
211 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
212 sizeof(struct WLAN_802_11_KEY));
213 }
214 adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
215
216 mutex_unlock(&adapter->lock);
217
218out:
219 LEAVE();
220 return ret;
221}
222
223static int assoc_helper_secinfo(wlan_private *priv,
224 struct assoc_request * assoc_req)
225{
226 wlan_adapter *adapter = priv->adapter;
227 int ret = 0;
228
229 ENTER();
230
231 memcpy(&adapter->secinfo, &assoc_req->secinfo,
232 sizeof(struct wlan_802_11_security));
233
234 ret = libertas_set_mac_packet_filter(priv);
235
236 LEAVE();
237 return ret;
238}
239
240
241static int assoc_helper_wpa_keys(wlan_private *priv,
242 struct assoc_request * assoc_req)
243{
244 int ret = 0;
245
246 ENTER();
247
248 /* enable/Disable RSN */
249 ret = libertas_prepare_and_send_command(priv,
250 cmd_802_11_enable_rsn,
251 cmd_act_set,
252 cmd_option_waitforrsp,
253 0, assoc_req);
254 if (ret)
255 goto out;
256
257 ret = libertas_prepare_and_send_command(priv,
258 cmd_802_11_key_material,
259 cmd_act_set,
260 cmd_option_waitforrsp,
261 0, assoc_req);
262
263out:
264 LEAVE();
265 return ret;
266}
267
268
269static int assoc_helper_wpa_ie(wlan_private *priv,
270 struct assoc_request * assoc_req)
271{
272 wlan_adapter *adapter = priv->adapter;
273 int ret = 0;
274
275 ENTER();
276
277 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
278 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
279 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
280 } else {
281 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
282 adapter->wpa_ie_len = 0;
283 }
284
285 LEAVE();
286 return ret;
287}
288
289
290static int should_deauth_infrastructure(wlan_adapter *adapter,
291 struct assoc_request * assoc_req)
292{
293 if (adapter->connect_status != libertas_connected)
294 return 0;
295
296 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
297 lbs_pr_debug(1, "Deauthenticating due to new SSID in "
298 " configuration request.\n");
299 return 1;
300 }
301
302 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
303 if (adapter->secinfo.authmode !=
304 assoc_req->secinfo.authmode) {
305 lbs_pr_debug(1, "Deauthenticating due to updated security "
306 "info in configuration request.\n");
307 return 1;
308 }
309 }
310
311 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
312 lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
313 " configuration request.\n");
314 return 1;
315 }
316
317 /* FIXME: deal with 'auto' mode somehow */
318 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
319 if (assoc_req->mode != wlan802_11infrastructure)
320 return 1;
321 }
322
323 return 0;
324}
325
326
327static int should_stop_adhoc(wlan_adapter *adapter,
328 struct assoc_request * assoc_req)
329{
330 if (adapter->connect_status != libertas_connected)
331 return 0;
332
333 if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
334 return 1;
335 if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
336 sizeof(struct WLAN_802_11_SSID)))
337 return 1;
338
339 /* FIXME: deal with 'auto' mode somehow */
340 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
341 if (assoc_req->mode != wlan802_11ibss)
342 return 1;
343 }
344
345 return 0;
346}
347
348
349void wlan_association_worker(struct work_struct *work)
350{
351 wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
352 wlan_adapter *adapter = priv->adapter;
353 struct assoc_request * assoc_req = NULL;
354 int ret = 0;
355 int find_any_ssid = 0;
356
357 ENTER();
358
359 mutex_lock(&adapter->lock);
360 assoc_req = adapter->assoc_req;
361 adapter->assoc_req = NULL;
362 mutex_unlock(&adapter->lock);
363
364 if (!assoc_req) {
365 LEAVE();
366 return;
367 }
368
369 lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
370 assoc_req->flags);
371
372 /* If 'any' SSID was specified, find an SSID to associate with */
373 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
374 && !assoc_req->ssid.ssidlength)
375 find_any_ssid = 1;
376
377 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
378 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
379 if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
380 && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
381 find_any_ssid = 0;
382 }
383
384 if (find_any_ssid) {
385 enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
386
387 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
388 assoc_req->mode, &new_mode);
389 if (ret) {
390 lbs_pr_debug(1, "Could not find best network\n");
391 ret = -ENETUNREACH;
392 goto out;
393 }
394
395 /* Ensure we switch to the mode of the AP */
396 if (assoc_req->mode == wlan802_11autounknown) {
397 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
398 assoc_req->mode = new_mode;
399 }
400 }
401
402 /*
403 * Check if the attributes being changing require deauthentication
404 * from the currently associated infrastructure access point.
405 */
406 if (adapter->inframode == wlan802_11infrastructure) {
407 if (should_deauth_infrastructure(adapter, assoc_req)) {
408 ret = libertas_send_deauthentication(priv);
409 if (ret) {
410 lbs_pr_debug(1, "Deauthentication due to new "
411 "configuration request failed: %d\n",
412 ret);
413 }
414 }
415 } else if (adapter->inframode == wlan802_11ibss) {
416 if (should_stop_adhoc(adapter, assoc_req)) {
417 ret = libertas_stop_adhoc_network(priv);
418 if (ret) {
419 lbs_pr_debug(1, "Teardown of AdHoc network due to "
420 "new configuration request failed: %d\n",
421 ret);
422 }
423
424 }
425 }
426
427 /* Send the various configuration bits to the firmware */
428 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
429 ret = assoc_helper_mode(priv, assoc_req);
430 if (ret) {
431lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
432 goto out;
433 }
434 }
435
436 if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
437 || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
438 ret = assoc_helper_wep_keys(priv, assoc_req);
439 if (ret) {
440lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
441 goto out;
442 }
443 }
444
445 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
446 ret = assoc_helper_secinfo(priv, assoc_req);
447 if (ret) {
448lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
449 goto out;
450 }
451 }
452
453 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
454 ret = assoc_helper_wpa_ie(priv, assoc_req);
455 if (ret) {
456lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
457 goto out;
458 }
459 }
460
461 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
462 || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
463 ret = assoc_helper_wpa_keys(priv, assoc_req);
464 if (ret) {
465lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
466 goto out;
467 }
468 }
469
470 /* SSID/BSSID should be the _last_ config option set, because they
471 * trigger the association attempt.
472 */
473 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
474 || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
475 int success = 1;
476
477 ret = assoc_helper_associate(priv, assoc_req);
478 if (ret) {
479 lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
480 ret);
481 success = 0;
482 }
483
484 if (adapter->connect_status != libertas_connected) {
485 lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
486 "not connected.\n");
487 success = 0;
488 }
489
490 if (success) {
491 lbs_pr_debug(1, "ASSOC: association attempt successful. "
492 "Associated to '%s' (" MAC_FMT ")\n",
493 assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
494 libertas_prepare_and_send_command(priv,
495 cmd_802_11_rssi,
496 0, cmd_option_waitforrsp, 0, NULL);
497
498 libertas_prepare_and_send_command(priv,
499 cmd_802_11_get_log,
500 0, cmd_option_waitforrsp, 0, NULL);
501 } else {
502
503 ret = -1;
504 }
505 }
506
507out:
508 if (ret) {
509 lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
510 ret);
511 }
512 kfree(assoc_req);
513 LEAVE();
514}
515
516
517/*
518 * Caller MUST hold any necessary locks
519 */
520struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
521{
522 struct assoc_request * assoc_req;
523
524 if (!adapter->assoc_req) {
525 adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
526 if (!adapter->assoc_req) {
527 lbs_pr_info("Not enough memory to allocate association"
528 " request!\n");
529 return NULL;
530 }
531 }
532
533 /* Copy current configuration attributes to the association request,
534 * but don't overwrite any that are already set.
535 */
536 assoc_req = adapter->assoc_req;
537 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
538 memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
539 adapter->curbssparams.ssid.ssidlength);
540 }
541
542 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
543 assoc_req->channel = adapter->curbssparams.channel;
544
545 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
546 assoc_req->mode = adapter->inframode;
547
548 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
549 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
550 ETH_ALEN);
551 }
552
553 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
554 int i;
555 for (i = 0; i < 4; i++) {
556 memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
557 sizeof(struct WLAN_802_11_KEY));
558 }
559 }
560
561 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
562 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
563
564 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
565 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
566 sizeof(struct WLAN_802_11_KEY));
567 }
568
569 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
570 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
571 sizeof(struct WLAN_802_11_KEY));
572 }
573
574 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
575 memcpy(&assoc_req->secinfo, &adapter->secinfo,
576 sizeof(struct wlan_802_11_security));
577 }
578
579 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
580 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
581 MAX_WPA_IE_LEN);
582 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
583 }
584
585 return assoc_req;
586}
587
588
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644
index 000000000000..2ffd82d99b34
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -0,0 +1,30 @@
1/* Copyright (C) 2006, Red Hat, Inc. */
2
3#ifndef _WLAN_ASSOC_H_
4#define _WLAN_ASSOC_H_
5
6#include "dev.h"
7
8void wlan_association_worker(struct work_struct *work);
9
10struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
11
12#define ASSOC_DELAY (HZ / 2)
13static inline void wlan_postpone_association_work(wlan_private *priv)
14{
15 if (priv->adapter->surpriseremoved)
16 return;
17 cancel_delayed_work(&priv->assoc_work);
18 queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
19}
20
21static inline void wlan_cancel_association_work(wlan_private *priv)
22{
23 cancel_delayed_work(&priv->assoc_work);
24 if (priv->adapter->assoc_req) {
25 kfree(priv->adapter->assoc_req);
26 priv->adapter->assoc_req = NULL;
27 }
28}
29
30#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644
index 000000000000..bfdac58b5c06
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -0,0 +1,1958 @@
1/**
2 * This file contains the handling of command.
3 * It prepares command and sends it to firmware when it is ready.
4 */
5
6#include <net/iw_handler.h>
7#include "host.h"
8#include "hostcmd.h"
9#include "sbi.h"
10#include "decl.h"
11#include "defs.h"
12#include "dev.h"
13#include "join.h"
14#include "wext.h"
15
16static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
17
18static u16 commands_allowed_in_ps[] = {
19 cmd_802_11_rssi,
20};
21
22/**
23 * @brief This function checks if the commans is allowed
24 * in PS mode not.
25 *
26 * @param command the command ID
27 * @return TRUE or FALSE
28 */
29static u8 is_command_allowed_in_ps(u16 command)
30{
31 int count = sizeof(commands_allowed_in_ps)
32 / sizeof(commands_allowed_in_ps[0]);
33 int i;
34
35 for (i = 0; i < count; i++) {
36 if (command == cpu_to_le16(commands_allowed_in_ps[i]))
37 return 1;
38 }
39
40 return 0;
41}
42
43static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
44{
45 struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
46
47 ENTER();
48
49 cmd->command = cpu_to_le16(cmd_get_hw_spec);
50 cmd->size =
51 cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
52 memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
53
54 LEAVE();
55 return 0;
56}
57
58static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
59 struct cmd_ds_command *cmd,
60 u16 cmd_action)
61{
62 struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
63 u16 action = cmd_action;
64 wlan_adapter *adapter = priv->adapter;
65
66 ENTER();
67
68 cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
69 cmd->size =
70 cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
71 S_DS_GEN);
72 psm->action = cpu_to_le16(cmd_action);
73 psm->multipledtim = 0;
74 switch (action) {
75 case cmd_subcmd_enter_ps:
76 lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
77 lbs_pr_debug(1, "locallisteninterval = %d\n",
78 adapter->locallisteninterval);
79
80 psm->locallisteninterval =
81 cpu_to_le16(adapter->locallisteninterval);
82 psm->nullpktinterval =
83 cpu_to_le16(adapter->nullpktinterval);
84 psm->multipledtim =
85 cpu_to_le16(priv->adapter->multipledtim);
86 break;
87
88 case cmd_subcmd_exit_ps:
89 lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
90 break;
91
92 case cmd_subcmd_sleep_confirmed:
93 lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
94 break;
95
96 default:
97 break;
98 }
99
100 LEAVE();
101 return 0;
102}
103
104static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
105 struct cmd_ds_command *cmd,
106 u16 cmd_action, void *pdata_buf)
107{
108 u16 *timeout = pdata_buf;
109
110 cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
111 cmd->size =
112 cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
113 + S_DS_GEN);
114
115 cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
116
117 if (cmd_action)
118 cmd->params.inactivity_timeout.timeout =
119 cpu_to_le16(*timeout);
120 else
121 cmd->params.inactivity_timeout.timeout = 0;
122
123 return 0;
124}
125
126static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
127 struct cmd_ds_command *cmd,
128 u16 cmd_action)
129{
130 wlan_adapter *adapter = priv->adapter;
131 struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
132
133 ENTER();
134
135 cmd->size =
136 cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
137 S_DS_GEN);
138 cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
139
140 if (cmd_action == cmd_act_get) {
141 memset(&adapter->sp, 0, sizeof(struct sleep_params));
142 memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
143 sp->action = cpu_to_le16(cmd_action);
144 } else if (cmd_action == cmd_act_set) {
145 sp->action = cpu_to_le16(cmd_action);
146 sp->error = cpu_to_le16(adapter->sp.sp_error);
147 sp->offset = cpu_to_le16(adapter->sp.sp_offset);
148 sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
149 sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
150 sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
151 sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
152 }
153
154 LEAVE();
155 return 0;
156}
157
158static int wlan_cmd_802_11_set_wep(wlan_private * priv,
159 struct cmd_ds_command *cmd,
160 u32 cmd_act,
161 void * pdata_buf)
162{
163 struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
164 wlan_adapter *adapter = priv->adapter;
165 int ret = 0;
166 struct assoc_request * assoc_req = pdata_buf;
167
168 ENTER();
169
170 cmd->command = cpu_to_le16(cmd_802_11_set_wep);
171 cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
172 + S_DS_GEN);
173
174 if (cmd_act == cmd_act_add) {
175 int i;
176
177 if (!assoc_req) {
178 lbs_pr_debug(1, "Invalid association request!");
179 ret = -1;
180 goto done;
181 }
182
183 wep->action = cpu_to_le16(cmd_act_add);
184
185 /* default tx key index */
186 wep->keyindex = cpu_to_le16((u16)
187 (assoc_req->wep_tx_keyidx &
188 (u32)cmd_WEP_KEY_INDEX_MASK));
189
190 lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
191
192 /* Copy key types and material to host command structure */
193 for (i = 0; i < 4; i++) {
194 struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
195
196 switch (pkey->len) {
197 case KEY_LEN_WEP_40:
198 wep->keytype[i] = cmd_type_wep_40_bit;
199 memmove(&wep->keymaterial[i], pkey->key,
200 pkey->len);
201 break;
202 case KEY_LEN_WEP_104:
203 wep->keytype[i] = cmd_type_wep_104_bit;
204 memmove(&wep->keymaterial[i], pkey->key,
205 pkey->len);
206 break;
207 case 0:
208 break;
209 default:
210 lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
211 i, pkey->len);
212 ret = -1;
213 goto done;
214 break;
215 }
216 }
217 } else if (cmd_act == cmd_act_remove) {
218 /* ACT_REMOVE clears _all_ WEP keys */
219 wep->action = cpu_to_le16(cmd_act_remove);
220
221 /* default tx key index */
222 wep->keyindex = cpu_to_le16((u16)
223 (adapter->wep_tx_keyidx &
224 (u32)cmd_WEP_KEY_INDEX_MASK));
225 }
226
227 ret = 0;
228
229done:
230 LEAVE();
231 return ret;
232}
233
234static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
235 struct cmd_ds_command *cmd,
236 u16 cmd_action)
237{
238 struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
239 wlan_adapter *adapter = priv->adapter;
240
241 cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
242 cmd->size =
243 cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
244 S_DS_GEN);
245 penableRSN->action = cpu_to_le16(cmd_action);
246 if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
247 penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
248 } else {
249 penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
250 }
251
252 return 0;
253}
254
255
256static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
257 struct WLAN_802_11_KEY * pkey)
258{
259 pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
260
261 if (pkey->flags & KEY_INFO_WPA_ENABLED) {
262 pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
263 } else {
264 pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
265 }
266
267 if (pkey->flags & KEY_INFO_WPA_UNICAST) {
268 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
269 } else if (pkey->flags & KEY_INFO_WPA_MCAST) {
270 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
271 }
272
273 pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
274 pkeyparamset->keylen = cpu_to_le16(pkey->len);
275 memcpy(pkeyparamset->key, pkey->key, pkey->len);
276 pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
277 + sizeof(pkeyparamset->keyinfo)
278 + sizeof(pkeyparamset->keylen)
279 + sizeof(pkeyparamset->key));
280}
281
282static int wlan_cmd_802_11_key_material(wlan_private * priv,
283 struct cmd_ds_command *cmd,
284 u16 cmd_action,
285 u32 cmd_oid, void *pdata_buf)
286{
287 wlan_adapter *adapter = priv->adapter;
288 struct cmd_ds_802_11_key_material *pkeymaterial =
289 &cmd->params.keymaterial;
290 int ret = 0;
291 int index = 0;
292
293 ENTER();
294
295 cmd->command = cpu_to_le16(cmd_802_11_key_material);
296 pkeymaterial->action = cpu_to_le16(cmd_action);
297
298 if (cmd_action == cmd_act_get) {
299 cmd->size = cpu_to_le16( S_DS_GEN
300 + sizeof (pkeymaterial->action));
301 ret = 0;
302 goto done;
303 }
304
305 memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
306
307 if (adapter->wpa_unicast_key.len) {
308 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
309 &adapter->wpa_unicast_key);
310 index++;
311 }
312
313 if (adapter->wpa_mcast_key.len) {
314 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
315 &adapter->wpa_mcast_key);
316 index++;
317 }
318
319 cmd->size = cpu_to_le16( S_DS_GEN
320 + sizeof (pkeymaterial->action)
321 + index * sizeof(struct MrvlIEtype_keyParamSet));
322
323 ret = 0;
324
325done:
326 LEAVE();
327 return ret;
328}
329
330static int wlan_cmd_802_11_reset(wlan_private * priv,
331 struct cmd_ds_command *cmd, int cmd_action)
332{
333 struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
334
335 cmd->command = cpu_to_le16(cmd_802_11_reset);
336 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
337 reset->action = cpu_to_le16(cmd_action);
338
339 return 0;
340}
341
342static int wlan_cmd_802_11_get_log(wlan_private * priv,
343 struct cmd_ds_command *cmd)
344{
345 cmd->command = cpu_to_le16(cmd_802_11_get_log);
346 cmd->size =
347 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
348
349 return 0;
350}
351
352static int wlan_cmd_802_11_get_stat(wlan_private * priv,
353 struct cmd_ds_command *cmd)
354{
355 cmd->command = cpu_to_le16(cmd_802_11_get_stat);
356 cmd->size =
357 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
358 S_DS_GEN);
359
360 return 0;
361}
362
363static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
364 struct cmd_ds_command *cmd,
365 int cmd_action,
366 int cmd_oid, void *pdata_buf)
367{
368 struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
369 wlan_adapter *adapter = priv->adapter;
370 u8 ucTemp;
371
372 ENTER();
373
374 lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
375
376 cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
377 cmd->size =
378 cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
379 S_DS_GEN);
380
381 switch (cmd_oid) {
382 case OID_802_11_INFRASTRUCTURE_MODE:
383 {
384 enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
385 (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
386 pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
387 pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
388 pSNMPMIB->bufsize = sizeof(u8);
389 if (mode == wlan802_11infrastructure)
390 ucTemp = SNMP_MIB_VALUE_INFRA;
391 else
392 ucTemp = SNMP_MIB_VALUE_ADHOC;
393
394 memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
395
396 break;
397 }
398
399 case OID_802_11D_ENABLE:
400 {
401 u32 ulTemp;
402
403 pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
404
405 if (cmd_action == cmd_act_set) {
406 pSNMPMIB->querytype = cmd_act_set;
407 pSNMPMIB->bufsize = sizeof(u16);
408 ulTemp = *(u32 *)pdata_buf;
409 *((unsigned short *)(pSNMPMIB->value)) =
410 cpu_to_le16((u16) ulTemp);
411 }
412 break;
413 }
414
415 case OID_802_11_FRAGMENTATION_THRESHOLD:
416 {
417 u32 ulTemp;
418
419 pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
420
421 if (cmd_action == cmd_act_get) {
422 pSNMPMIB->querytype =
423 cpu_to_le16(cmd_act_get);
424 } else if (cmd_action == cmd_act_set) {
425 pSNMPMIB->querytype =
426 cpu_to_le16(cmd_act_set);
427 pSNMPMIB->bufsize =
428 cpu_to_le16(sizeof(u16));
429 ulTemp = *((u32 *) pdata_buf);
430 *((unsigned short *)(pSNMPMIB->value)) =
431 cpu_to_le16((u16) ulTemp);
432
433 }
434
435 break;
436 }
437
438 case OID_802_11_RTS_THRESHOLD:
439 {
440
441 u32 ulTemp;
442 pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
443
444 if (cmd_action == cmd_act_get) {
445 pSNMPMIB->querytype =
446 cpu_to_le16(cmd_act_get);
447 } else if (cmd_action == cmd_act_set) {
448 pSNMPMIB->querytype =
449 cpu_to_le16(cmd_act_set);
450 pSNMPMIB->bufsize =
451 cpu_to_le16(sizeof(u16));
452 ulTemp = *((u32 *)
453 pdata_buf);
454 *(unsigned short *)(pSNMPMIB->value) =
455 cpu_to_le16((u16) ulTemp);
456
457 }
458 break;
459 }
460 case OID_802_11_TX_RETRYCOUNT:
461 pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
462
463 if (cmd_action == cmd_act_get) {
464 pSNMPMIB->querytype =
465 cpu_to_le16(cmd_act_get);
466 } else if (cmd_action == cmd_act_set) {
467 pSNMPMIB->querytype =
468 cpu_to_le16(cmd_act_set);
469 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
470 *((unsigned short *)(pSNMPMIB->value)) =
471 cpu_to_le16((u16) adapter->txretrycount);
472 }
473
474 break;
475 default:
476 break;
477 }
478
479 lbs_pr_debug(1,
480 "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
481 cmd->command, cmd->size, cmd->seqnum, cmd->result);
482
483 lbs_pr_debug(1,
484 "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
485 pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize,
486 *(u16 *) pSNMPMIB->value);
487
488 LEAVE();
489 return 0;
490}
491
492static int wlan_cmd_802_11_radio_control(wlan_private * priv,
493 struct cmd_ds_command *cmd,
494 int cmd_action)
495{
496 wlan_adapter *adapter = priv->adapter;
497 struct cmd_ds_802_11_radio_control *pradiocontrol =
498 &cmd->params.radio;
499
500 ENTER();
501
502 cmd->size =
503 cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
504 S_DS_GEN);
505 cmd->command = cpu_to_le16(cmd_802_11_radio_control);
506
507 pradiocontrol->action = cpu_to_le16(cmd_action);
508
509 switch (adapter->preamble) {
510 case cmd_type_short_preamble:
511 pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
512 break;
513
514 case cmd_type_long_preamble:
515 pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
516 break;
517
518 case cmd_type_auto_preamble:
519 default:
520 pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
521 break;
522 }
523
524 if (adapter->radioon)
525 pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
526 else
527 pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
528
529 LEAVE();
530 return 0;
531}
532
533static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
534 struct cmd_ds_command *cmd,
535 u16 cmd_action, void *pdata_buf)
536{
537
538 struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
539
540 ENTER();
541
542 cmd->size =
543 cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
544 S_DS_GEN);
545 cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
546 prtp->action = cmd_action;
547
548 lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
549 cmd->command, prtp->action);
550
551 switch (cmd_action) {
552 case cmd_act_tx_power_opt_get:
553 prtp->action = cpu_to_le16(cmd_act_get);
554 prtp->currentlevel = 0;
555 break;
556
557 case cmd_act_tx_power_opt_set_high:
558 prtp->action = cpu_to_le16(cmd_act_set);
559 prtp->currentlevel =
560 cpu_to_le16(cmd_act_tx_power_index_high);
561 break;
562
563 case cmd_act_tx_power_opt_set_mid:
564 prtp->action = cpu_to_le16(cmd_act_set);
565 prtp->currentlevel =
566 cpu_to_le16(cmd_act_tx_power_index_mid);
567 break;
568
569 case cmd_act_tx_power_opt_set_low:
570 prtp->action = cpu_to_le16(cmd_act_set);
571 prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
572 break;
573 }
574 LEAVE();
575 return 0;
576}
577
578static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
579 struct cmd_ds_command *cmd,
580 u16 cmd_action, void *pdata_buf)
581{
582 struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
583
584 cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
585 cmd->size =
586 cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
587 S_DS_GEN);
588
589 rant->action = cpu_to_le16(cmd_action);
590 if ((cmd_action == cmd_act_set_rx) ||
591 (cmd_action == cmd_act_set_tx)) {
592 rant->antennamode =
593 cpu_to_le16((u16) (*(u32 *) pdata_buf));
594 }
595
596 return 0;
597}
598
599static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
600 struct cmd_ds_command *cmd,
601 u16 cmd_action)
602{
603 struct cmd_ds_802_11_rate_adapt_rateset
604 *rateadapt = &cmd->params.rateset;
605 wlan_adapter *adapter = priv->adapter;
606
607 cmd->size =
608 cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
609 + S_DS_GEN);
610 cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
611
612 ENTER();
613
614 rateadapt->action = cmd_action;
615 rateadapt->enablehwauto = adapter->enablehwauto;
616 rateadapt->bitmap = adapter->ratebitmap;
617
618 LEAVE();
619 return 0;
620}
621
622static int wlan_cmd_802_11_data_rate(wlan_private * priv,
623 struct cmd_ds_command *cmd,
624 u16 cmd_action)
625{
626 struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
627 wlan_adapter *adapter = priv->adapter;
628 u16 action = cmd_action;
629
630 ENTER();
631
632 cmd->size =
633 cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
634 S_DS_GEN);
635
636 cmd->command = cpu_to_le16(cmd_802_11_data_rate);
637
638 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
639
640 pdatarate->action = cpu_to_le16(cmd_action);
641
642 if (action == cmd_act_set_tx_fix_rate) {
643 pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
644 lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
645 adapter->datarate);
646 } else if (action == cmd_act_set_tx_auto) {
647 lbs_pr_debug(1, "Setting FW for AUTO rate\n");
648 }
649
650 LEAVE();
651 return 0;
652}
653
654static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
655 struct cmd_ds_command *cmd,
656 u16 cmd_action)
657{
658 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
659 wlan_adapter *adapter = priv->adapter;
660
661 cmd->size =
662 cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
663 S_DS_GEN);
664 cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
665
666 pMCastAdr->action = cpu_to_le16(cmd_action);
667 pMCastAdr->nr_of_adrs =
668 cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
669 memcpy(pMCastAdr->maclist, adapter->multicastlist,
670 adapter->nr_of_multicastmacaddr * ETH_ALEN);
671
672 return 0;
673}
674
675static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
676 struct cmd_ds_command *cmd,
677 int option, void *pdata_buf)
678{
679 struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
680
681 cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
682 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
683 + S_DS_GEN);
684
685 if (option == cmd_opt_802_11_rf_channel_set) {
686 rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
687 }
688
689 rfchan->action = cpu_to_le16(option);
690
691 return 0;
692}
693
694static int wlan_cmd_802_11_rssi(wlan_private * priv,
695 struct cmd_ds_command *cmd)
696{
697 wlan_adapter *adapter = priv->adapter;
698
699 cmd->command = cpu_to_le16(cmd_802_11_rssi);
700 cmd->size =
701 cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
702 cmd->params.rssi.N = priv->adapter->bcn_avg_factor;
703
704 /* reset Beacon SNR/NF/RSSI values */
705 adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
706 adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
707 adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
708 adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
709 adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
710 adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
711
712 return 0;
713}
714
715static int wlan_cmd_reg_access(wlan_private * priv,
716 struct cmd_ds_command *cmdptr,
717 u8 cmd_action, void *pdata_buf)
718{
719 struct wlan_offset_value *offval;
720
721 ENTER();
722
723 offval = (struct wlan_offset_value *)pdata_buf;
724
725 switch (cmdptr->command) {
726 case cmd_mac_reg_access:
727 {
728 struct cmd_ds_mac_reg_access *macreg;
729
730 cmdptr->size =
731 cpu_to_le16(sizeof
732 (struct cmd_ds_mac_reg_access)
733 + S_DS_GEN);
734 macreg =
735 (struct cmd_ds_mac_reg_access *)&cmdptr->params.
736 macreg;
737
738 macreg->action = cpu_to_le16(cmd_action);
739 macreg->offset = cpu_to_le16((u16) offval->offset);
740 macreg->value = cpu_to_le32(offval->value);
741
742 break;
743 }
744
745 case cmd_bbp_reg_access:
746 {
747 struct cmd_ds_bbp_reg_access *bbpreg;
748
749 cmdptr->size =
750 cpu_to_le16(sizeof
751 (struct cmd_ds_bbp_reg_access)
752 + S_DS_GEN);
753 bbpreg =
754 (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
755 bbpreg;
756
757 bbpreg->action = cpu_to_le16(cmd_action);
758 bbpreg->offset = cpu_to_le16((u16) offval->offset);
759 bbpreg->value = (u8) offval->value;
760
761 break;
762 }
763
764 case cmd_rf_reg_access:
765 {
766 struct cmd_ds_rf_reg_access *rfreg;
767
768 cmdptr->size =
769 cpu_to_le16(sizeof
770 (struct cmd_ds_rf_reg_access) +
771 S_DS_GEN);
772 rfreg =
773 (struct cmd_ds_rf_reg_access *)&cmdptr->params.
774 rfreg;
775
776 rfreg->action = cpu_to_le16(cmd_action);
777 rfreg->offset = cpu_to_le16((u16) offval->offset);
778 rfreg->value = (u8) offval->value;
779
780 break;
781 }
782
783 default:
784 break;
785 }
786
787 LEAVE();
788 return 0;
789}
790
791static int wlan_cmd_802_11_mac_address(wlan_private * priv,
792 struct cmd_ds_command *cmd,
793 u16 cmd_action)
794{
795 wlan_adapter *adapter = priv->adapter;
796
797 cmd->command = cpu_to_le16(cmd_802_11_mac_address);
798 cmd->size =
799 cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
800 S_DS_GEN);
801 cmd->result = 0;
802
803 cmd->params.macadd.action = cpu_to_le16(cmd_action);
804
805 if (cmd_action == cmd_act_set) {
806 memcpy(cmd->params.macadd.macadd,
807 adapter->current_addr, ETH_ALEN);
808 lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
809 }
810
811 return 0;
812}
813
814static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
815 struct cmd_ds_command *cmd,
816 int cmd_action, void *pdata_buf)
817{
818 struct wlan_ioctl_regrdwr *ea = pdata_buf;
819
820 ENTER();
821
822 cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
823 cmd->size =
824 cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
825 S_DS_GEN);
826 cmd->result = 0;
827
828 cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
829 cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
830 cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
831 cmd->params.rdeeprom.value = 0;
832
833 return 0;
834}
835
836static int wlan_cmd_bt_access(wlan_private * priv,
837 struct cmd_ds_command *cmd,
838 u16 cmd_action, void *pdata_buf)
839{
840 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
841 lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
842
843 cmd->command = cpu_to_le16(cmd_bt_access);
844 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
845 + S_DS_GEN);
846 cmd->result = 0;
847 bt_access->action = cpu_to_le16(cmd_action);
848
849 switch (cmd_action) {
850 case cmd_act_bt_access_add:
851 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
852 lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
853 break;
854 case cmd_act_bt_access_del:
855 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
856 lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
857 break;
858 case cmd_act_bt_access_list:
859 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
860 break;
861 case cmd_act_bt_access_reset:
862 break;
863 default:
864 break;
865 }
866 return 0;
867}
868
869static int wlan_cmd_fwt_access(wlan_private * priv,
870 struct cmd_ds_command *cmd,
871 u16 cmd_action, void *pdata_buf)
872{
873 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
874 lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
875
876 cmd->command = cpu_to_le16(cmd_fwt_access);
877 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
878 + S_DS_GEN);
879 cmd->result = 0;
880
881 if (pdata_buf)
882 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
883 else
884 memset(fwt_access, 0, sizeof(*fwt_access));
885
886 fwt_access->action = cpu_to_le16(cmd_action);
887
888 return 0;
889}
890
891static int wlan_cmd_mesh_access(wlan_private * priv,
892 struct cmd_ds_command *cmd,
893 u16 cmd_action, void *pdata_buf)
894{
895 struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
896 lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
897
898 cmd->command = cpu_to_le16(cmd_mesh_access);
899 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
900 + S_DS_GEN);
901 cmd->result = 0;
902
903 if (pdata_buf)
904 memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
905 else
906 memset(mesh_access, 0, sizeof(*mesh_access));
907
908 mesh_access->action = cpu_to_le16(cmd_action);
909
910 return 0;
911}
912
913void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
914{
915 unsigned long flags;
916 struct cmd_ds_command *cmdptr;
917
918 ENTER();
919
920 if (!cmdnode) {
921 lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
922 goto done;
923 }
924
925 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
926 if (!cmdptr) {
927 lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
928 goto done;
929 }
930
931 /* Exit_PS command needs to be queued in the header always. */
932 if (cmdptr->command == cmd_802_11_ps_mode) {
933 struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
934 if (psm->action == cmd_subcmd_exit_ps) {
935 if (adapter->psstate != PS_STATE_FULL_POWER)
936 addtail = 0;
937 }
938 }
939
940 spin_lock_irqsave(&adapter->driver_lock, flags);
941
942 if (addtail)
943 list_add_tail((struct list_head *)cmdnode,
944 &adapter->cmdpendingq);
945 else
946 list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
947
948 spin_unlock_irqrestore(&adapter->driver_lock, flags);
949
950 lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
951 (u32) cmdnode,
952 ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command);
953
954done:
955 LEAVE();
956 return;
957}
958
959/*
960 * TODO: Fix the issue when DownloadcommandToStation is being called the
961 * second time when the command timesout. All the cmdptr->xxx are in little
962 * endian and therefore all the comparissions will fail.
963 * For now - we are not performing the endian conversion the second time - but
964 * for PS and DEEP_SLEEP we need to worry
965 */
966static int DownloadcommandToStation(wlan_private * priv,
967 struct cmd_ctrl_node *cmdnode)
968{
969 unsigned long flags;
970 struct cmd_ds_command *cmdptr;
971 wlan_adapter *adapter = priv->adapter;
972 int ret = 0;
973 u16 cmdsize;
974 u16 command;
975
976 ENTER();
977
978 if (!adapter || !cmdnode) {
979 lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
980 (int)adapter, (int)cmdnode);
981 if (cmdnode) {
982 spin_lock_irqsave(&adapter->driver_lock, flags);
983 __libertas_cleanup_and_insert_cmd(priv, cmdnode);
984 spin_unlock_irqrestore(&adapter->driver_lock, flags);
985 }
986 ret = -1;
987 goto done;
988 }
989
990 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
991
992
993 spin_lock_irqsave(&adapter->driver_lock, flags);
994 if (!cmdptr || !cmdptr->size) {
995 lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
996 "Not sending\n");
997 __libertas_cleanup_and_insert_cmd(priv, cmdnode);
998 spin_unlock_irqrestore(&adapter->driver_lock, flags);
999 ret = -1;
1000 goto done;
1001 }
1002
1003 adapter->cur_cmd = cmdnode;
1004 adapter->cur_cmd_retcode = 0;
1005 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1006 lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
1007 cmdptr->size);
1008
1009 cmdsize = cmdptr->size;
1010
1011 command = cpu_to_le16(cmdptr->command);
1012
1013 cmdnode->cmdwaitqwoken = 0;
1014 cmdsize = cpu_to_le16(cmdsize);
1015
1016 ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
1017
1018 if (ret != 0) {
1019 lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
1020 spin_lock_irqsave(&adapter->driver_lock, flags);
1021 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
1022 adapter->cur_cmd = NULL;
1023 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1024 ret = -1;
1025 goto done;
1026 }
1027
1028 lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
1029 lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
1030
1031 /* Setup the timer after transmit command */
1032 if (command == cmd_802_11_scan
1033 || command == cmd_802_11_authenticate
1034 || command == cmd_802_11_associate)
1035 mod_timer(&adapter->command_timer, jiffies + (10*HZ));
1036 else
1037 mod_timer(&adapter->command_timer, jiffies + (5*HZ));
1038
1039 ret = 0;
1040
1041 done:
1042 LEAVE();
1043 return ret;
1044}
1045
1046static int wlan_cmd_mac_control(wlan_private * priv,
1047 struct cmd_ds_command *cmd)
1048{
1049 struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
1050
1051 ENTER();
1052
1053 cmd->command = cpu_to_le16(cmd_mac_control);
1054 cmd->size =
1055 cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
1056 mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
1057
1058 lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
1059 mac->action, cmd->size);
1060
1061 LEAVE();
1062 return 0;
1063}
1064
1065/**
1066 * This function inserts command node to cmdfreeq
1067 * after cleans it. Requires adapter->driver_lock held.
1068 */
1069void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
1070{
1071 wlan_adapter *adapter = priv->adapter;
1072
1073 if (!ptempcmd)
1074 goto done;
1075
1076 cleanup_cmdnode(ptempcmd);
1077 list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
1078done:
1079 return;
1080}
1081
1082void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
1083{
1084 unsigned long flags;
1085
1086 spin_lock_irqsave(&priv->adapter->driver_lock, flags);
1087 __libertas_cleanup_and_insert_cmd(priv, ptempcmd);
1088 spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
1089}
1090
1091int libertas_set_radio_control(wlan_private * priv)
1092{
1093 int ret = 0;
1094
1095 ENTER();
1096
1097 ret = libertas_prepare_and_send_command(priv,
1098 cmd_802_11_radio_control,
1099 cmd_act_set,
1100 cmd_option_waitforrsp, 0, NULL);
1101
1102 lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
1103 priv->adapter->radioon, priv->adapter->preamble);
1104
1105 LEAVE();
1106 return ret;
1107}
1108
1109int libertas_set_mac_packet_filter(wlan_private * priv)
1110{
1111 int ret = 0;
1112
1113 ENTER();
1114
1115 lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
1116 priv->adapter->currentpacketfilter);
1117
1118 /* Send MAC control command to station */
1119 ret = libertas_prepare_and_send_command(priv,
1120 cmd_mac_control, 0, 0, 0, NULL);
1121
1122 LEAVE();
1123 return ret;
1124}
1125
1126/**
1127 * @brief This function prepare the command before send to firmware.
1128 *
1129 * @param priv A pointer to wlan_private structure
1130 * @param cmd_no command number
1131 * @param cmd_action command action: GET or SET
1132 * @param wait_option wait option: wait response or not
1133 * @param cmd_oid cmd oid: treated as sub command
1134 * @param pdata_buf A pointer to informaion buffer
1135 * @return 0 or -1
1136 */
1137int libertas_prepare_and_send_command(wlan_private * priv,
1138 u16 cmd_no,
1139 u16 cmd_action,
1140 u16 wait_option, u32 cmd_oid, void *pdata_buf)
1141{
1142 int ret = 0;
1143 wlan_adapter *adapter = priv->adapter;
1144 struct cmd_ctrl_node *cmdnode;
1145 struct cmd_ds_command *cmdptr;
1146 unsigned long flags;
1147
1148 ENTER();
1149
1150 if (!adapter) {
1151 lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
1152 ret = -1;
1153 goto done;
1154 }
1155
1156 if (adapter->surpriseremoved) {
1157 lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
1158 ret = -1;
1159 goto done;
1160 }
1161
1162 cmdnode = libertas_get_free_cmd_ctrl_node(priv);
1163
1164 if (cmdnode == NULL) {
1165 lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
1166
1167 /* Wake up main thread to execute next command */
1168 wake_up_interruptible(&priv->mainthread.waitq);
1169 ret = -1;
1170 goto done;
1171 }
1172
1173 libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
1174
1175 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1176
1177 lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
1178 (u32) cmdptr, cmd_no);
1179
1180 if (!cmdptr) {
1181 lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
1182 libertas_cleanup_and_insert_cmd(priv, cmdnode);
1183 ret = -1;
1184 goto done;
1185 }
1186
1187 /* Set sequence number, command and INT option */
1188 adapter->seqnum++;
1189 cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
1190
1191 cmdptr->command = cmd_no;
1192 cmdptr->result = 0;
1193
1194 switch (cmd_no) {
1195 case cmd_get_hw_spec:
1196 ret = wlan_cmd_hw_spec(priv, cmdptr);
1197 break;
1198 case cmd_802_11_ps_mode:
1199 ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
1200 break;
1201
1202 case cmd_802_11_scan:
1203 ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
1204 break;
1205
1206 case cmd_mac_control:
1207 ret = wlan_cmd_mac_control(priv, cmdptr);
1208 break;
1209
1210 case cmd_802_11_associate:
1211 case cmd_802_11_reassociate:
1212 ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
1213 break;
1214
1215 case cmd_802_11_deauthenticate:
1216 ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
1217 break;
1218
1219 case cmd_802_11_set_wep:
1220 ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
1221 break;
1222
1223 case cmd_802_11_ad_hoc_start:
1224 ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
1225 break;
1226 case cmd_code_dnld:
1227 break;
1228
1229 case cmd_802_11_reset:
1230 ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
1231 break;
1232
1233 case cmd_802_11_get_log:
1234 ret = wlan_cmd_802_11_get_log(priv, cmdptr);
1235 break;
1236
1237 case cmd_802_11_authenticate:
1238 ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
1239 break;
1240
1241 case cmd_802_11_get_stat:
1242 ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
1243 break;
1244
1245 case cmd_802_11_snmp_mib:
1246 ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
1247 cmd_action, cmd_oid, pdata_buf);
1248 break;
1249
1250 case cmd_mac_reg_access:
1251 case cmd_bbp_reg_access:
1252 case cmd_rf_reg_access:
1253 ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
1254 break;
1255
1256 case cmd_802_11_rf_channel:
1257 ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
1258 cmd_action, pdata_buf);
1259 break;
1260
1261 case cmd_802_11_rf_tx_power:
1262 ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
1263 cmd_action, pdata_buf);
1264 break;
1265
1266 case cmd_802_11_radio_control:
1267 ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
1268 break;
1269
1270 case cmd_802_11_rf_antenna:
1271 ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
1272 cmd_action, pdata_buf);
1273 break;
1274
1275 case cmd_802_11_data_rate:
1276 ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
1277 break;
1278 case cmd_802_11_rate_adapt_rateset:
1279 ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
1280 cmdptr, cmd_action);
1281 break;
1282
1283 case cmd_mac_multicast_adr:
1284 ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1285 break;
1286
1287 case cmd_802_11_ad_hoc_join:
1288 ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
1289 break;
1290
1291 case cmd_802_11_rssi:
1292 ret = wlan_cmd_802_11_rssi(priv, cmdptr);
1293 break;
1294
1295 case cmd_802_11_ad_hoc_stop:
1296 ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
1297 break;
1298
1299 case cmd_802_11_enable_rsn:
1300 ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
1301 break;
1302
1303 case cmd_802_11_key_material:
1304 ret = wlan_cmd_802_11_key_material(priv, cmdptr,
1305 cmd_action, cmd_oid,
1306 pdata_buf);
1307 break;
1308
1309 case cmd_802_11_pairwise_tsc:
1310 break;
1311 case cmd_802_11_group_tsc:
1312 break;
1313
1314 case cmd_802_11_mac_address:
1315 ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
1316 break;
1317
1318 case cmd_802_11_eeprom_access:
1319 ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
1320 cmd_action, pdata_buf);
1321 break;
1322
1323 case cmd_802_11_set_afc:
1324 case cmd_802_11_get_afc:
1325
1326 cmdptr->command = cpu_to_le16(cmd_no);
1327 cmdptr->size =
1328 cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1329 S_DS_GEN);
1330
1331 memmove(&cmdptr->params.afc,
1332 pdata_buf, sizeof(struct cmd_ds_802_11_afc));
1333
1334 ret = 0;
1335 goto done;
1336
1337 case cmd_802_11d_domain_info:
1338 ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
1339 cmd_no, cmd_action);
1340 break;
1341
1342 case cmd_802_11_sleep_params:
1343 ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
1344 break;
1345 case cmd_802_11_inactivity_timeout:
1346 ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
1347 cmd_action, pdata_buf);
1348 libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
1349 break;
1350
1351 case cmd_802_11_tpc_cfg:
1352 cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
1353 cmdptr->size =
1354 cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
1355 S_DS_GEN);
1356
1357 memmove(&cmdptr->params.tpccfg,
1358 pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
1359
1360 ret = 0;
1361 break;
1362 case cmd_802_11_led_gpio_ctrl:
1363 {
1364 struct mrvlietypes_ledgpio *gpio =
1365 (struct mrvlietypes_ledgpio*)
1366 cmdptr->params.ledgpio.data;
1367
1368 memmove(&cmdptr->params.ledgpio,
1369 pdata_buf,
1370 sizeof(struct cmd_ds_802_11_led_ctrl));
1371
1372 cmdptr->command =
1373 cpu_to_le16(cmd_802_11_led_gpio_ctrl);
1374
1375#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
1376 cmdptr->size =
1377 cpu_to_le16(gpio->header.len + S_DS_GEN +
1378 ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
1379 gpio->header.len = cpu_to_le16(gpio->header.len);
1380
1381 ret = 0;
1382 break;
1383 }
1384 case cmd_802_11_pwr_cfg:
1385 cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
1386 cmdptr->size =
1387 cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
1388 S_DS_GEN);
1389 memmove(&cmdptr->params.pwrcfg, pdata_buf,
1390 sizeof(struct cmd_ds_802_11_pwr_cfg));
1391
1392 ret = 0;
1393 break;
1394 case cmd_bt_access:
1395 ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
1396 break;
1397
1398 case cmd_fwt_access:
1399 ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
1400 break;
1401
1402 case cmd_mesh_access:
1403 ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
1404 break;
1405
1406 case cmd_get_tsf:
1407 cmdptr->command = cpu_to_le16(cmd_get_tsf);
1408 cmdptr->size =
1409 cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
1410 + S_DS_GEN);
1411 ret = 0;
1412 break;
1413 case cmd_802_11_tx_rate_query:
1414 cmdptr->command =
1415 cpu_to_le16(cmd_802_11_tx_rate_query);
1416 cmdptr->size =
1417 cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
1418 S_DS_GEN);
1419 adapter->txrate = 0;
1420 ret = 0;
1421 break;
1422 default:
1423 lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
1424 ret = -1;
1425 break;
1426 }
1427
1428 /* return error, since the command preparation failed */
1429 if (ret != 0) {
1430 lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
1431 libertas_cleanup_and_insert_cmd(priv, cmdnode);
1432 ret = -1;
1433 goto done;
1434 }
1435
1436 cmdnode->cmdwaitqwoken = 0;
1437
1438 libertas_queue_cmd(adapter, cmdnode, 1);
1439 adapter->nr_cmd_pending++;
1440 wake_up_interruptible(&priv->mainthread.waitq);
1441
1442 if (wait_option & cmd_option_waitforrsp) {
1443 lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
1444 might_sleep();
1445 wait_event_interruptible(cmdnode->cmdwait_q,
1446 cmdnode->cmdwaitqwoken);
1447 }
1448
1449 spin_lock_irqsave(&adapter->driver_lock, flags);
1450 if (adapter->cur_cmd_retcode) {
1451 lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
1452 adapter->cur_cmd_retcode);
1453 adapter->cur_cmd_retcode = 0;
1454 ret = -1;
1455 }
1456 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1457
1458done:
1459 LEAVE();
1460 return ret;
1461}
1462
1463/**
1464 * @brief This function allocates the command buffer and link
1465 * it to command free queue.
1466 *
1467 * @param priv A pointer to wlan_private structure
1468 * @return 0 or -1
1469 */
1470int libertas_allocate_cmd_buffer(wlan_private * priv)
1471{
1472 int ret = 0;
1473 u32 ulbufsize;
1474 u32 i;
1475 struct cmd_ctrl_node *tempcmd_array;
1476 u8 *ptempvirtualaddr;
1477 wlan_adapter *adapter = priv->adapter;
1478
1479 ENTER();
1480
1481 /* Allocate and initialize cmdCtrlNode */
1482 ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
1483
1484 if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
1485 lbs_pr_debug(1,
1486 "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
1487 ret = -1;
1488 goto done;
1489 }
1490
1491 adapter->cmd_array = tempcmd_array;
1492 memset(adapter->cmd_array, 0, ulbufsize);
1493
1494 /* Allocate and initialize command buffers */
1495 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1496 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1497 if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) {
1498 lbs_pr_debug(1,
1499 "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
1500 ret = -1;
1501 goto done;
1502 }
1503
1504 memset(ptempvirtualaddr, 0, ulbufsize);
1505
1506 /* Update command buffer virtual */
1507 tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
1508 }
1509
1510 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1511 init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
1512 libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
1513 }
1514
1515 ret = 0;
1516 done:
1517 LEAVE();
1518 return ret;
1519}
1520
1521/**
1522 * @brief This function frees the command buffer.
1523 *
1524 * @param priv A pointer to wlan_private structure
1525 * @return 0 or -1
1526 */
1527int libertas_free_cmd_buffer(wlan_private * priv)
1528{
1529 u32 ulbufsize;
1530 unsigned int i;
1531 struct cmd_ctrl_node *tempcmd_array;
1532 wlan_adapter *adapter = priv->adapter;
1533
1534 ENTER();
1535
1536 /* need to check if cmd array is allocated or not */
1537 if (adapter->cmd_array == NULL) {
1538 lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
1539 goto done;
1540 }
1541
1542 tempcmd_array = adapter->cmd_array;
1543
1544 /* Release shared memory buffers */
1545 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1546 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1547 if (tempcmd_array[i].bufvirtualaddr) {
1548 lbs_pr_debug(1, "Free all the array\n");
1549 kfree(tempcmd_array[i].bufvirtualaddr);
1550 tempcmd_array[i].bufvirtualaddr = NULL;
1551 }
1552 }
1553
1554 /* Release cmd_ctrl_node */
1555 if (adapter->cmd_array) {
1556 lbs_pr_debug(1, "Free cmd_array\n");
1557 kfree(adapter->cmd_array);
1558 adapter->cmd_array = NULL;
1559 }
1560
1561done:
1562 LEAVE();
1563 return 0;
1564}
1565
1566/**
1567 * @brief This function gets a free command node if available in
1568 * command free queue.
1569 *
1570 * @param priv A pointer to wlan_private structure
1571 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1572 */
1573struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
1574{
1575 struct cmd_ctrl_node *tempnode;
1576 wlan_adapter *adapter = priv->adapter;
1577 unsigned long flags;
1578
1579 if (!adapter)
1580 return NULL;
1581
1582 spin_lock_irqsave(&adapter->driver_lock, flags);
1583
1584 if (!list_empty(&adapter->cmdfreeq)) {
1585 tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
1586 list_del((struct list_head *)tempnode);
1587 } else {
1588 lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
1589 tempnode = NULL;
1590 }
1591
1592 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1593
1594 if (tempnode) {
1595 lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
1596 lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
1597 tempnode);
1598 cleanup_cmdnode(tempnode);
1599 }
1600
1601 return tempnode;
1602}
1603
1604/**
1605 * @brief This function cleans command node.
1606 *
1607 * @param ptempnode A pointer to cmdCtrlNode structure
1608 * @return n/a
1609 */
1610static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
1611{
1612 if (!ptempnode)
1613 return;
1614 ptempnode->cmdwaitqwoken = 1;
1615 wake_up_interruptible(&ptempnode->cmdwait_q);
1616 ptempnode->status = 0;
1617 ptempnode->cmd_oid = (u32) 0;
1618 ptempnode->wait_option = 0;
1619 ptempnode->pdata_buf = NULL;
1620
1621 if (ptempnode->bufvirtualaddr != NULL)
1622 memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
1623 return;
1624}
1625
1626/**
1627 * @brief This function initializes the command node.
1628 *
1629 * @param priv A pointer to wlan_private structure
1630 * @param ptempnode A pointer to cmd_ctrl_node structure
1631 * @param cmd_oid cmd oid: treated as sub command
1632 * @param wait_option wait option: wait response or not
1633 * @param pdata_buf A pointer to informaion buffer
1634 * @return 0 or -1
1635 */
1636void libertas_set_cmd_ctrl_node(wlan_private * priv,
1637 struct cmd_ctrl_node *ptempnode,
1638 u32 cmd_oid, u16 wait_option, void *pdata_buf)
1639{
1640 ENTER();
1641
1642 if (!ptempnode)
1643 return;
1644
1645 ptempnode->cmd_oid = cmd_oid;
1646 ptempnode->wait_option = wait_option;
1647 ptempnode->pdata_buf = pdata_buf;
1648
1649 LEAVE();
1650}
1651
1652/**
1653 * @brief This function executes next command in command
1654 * pending queue. It will put fimware back to PS mode
1655 * if applicable.
1656 *
1657 * @param priv A pointer to wlan_private structure
1658 * @return 0 or -1
1659 */
1660int libertas_execute_next_command(wlan_private * priv)
1661{
1662 wlan_adapter *adapter = priv->adapter;
1663 struct cmd_ctrl_node *cmdnode = NULL;
1664 struct cmd_ds_command *cmdptr;
1665 unsigned long flags;
1666 int ret = 0;
1667
1668 lbs_pr_debug(1, "libertas_execute_next_command\n");
1669
1670 spin_lock_irqsave(&adapter->driver_lock, flags);
1671
1672 if (adapter->cur_cmd) {
1673 lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
1674 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1675 ret = -1;
1676 goto done;
1677 }
1678
1679 if (!list_empty(&adapter->cmdpendingq)) {
1680 cmdnode = (struct cmd_ctrl_node *)
1681 adapter->cmdpendingq.next;
1682 }
1683
1684 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1685
1686 if (cmdnode) {
1687 lbs_pr_debug(1,
1688 "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
1689 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1690
1691 if (is_command_allowed_in_ps(cmdptr->command)) {
1692 if ((adapter->psstate == PS_STATE_SLEEP)
1693 || (adapter->psstate == PS_STATE_PRE_SLEEP)
1694 ) {
1695 lbs_pr_debug(1,
1696 "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
1697 cmdptr->command, adapter->psstate);
1698 ret = -1;
1699 goto done;
1700 }
1701 lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command "
1702 "0x%x in psstate %d\n",
1703 cmdptr->command, adapter->psstate);
1704 } else if (adapter->psstate != PS_STATE_FULL_POWER) {
1705 /*
1706 * 1. Non-PS command:
1707 * Queue it. set needtowakeup to TRUE if current state
1708 * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
1709 * 2. PS command but not Exit_PS:
1710 * Ignore it.
1711 * 3. PS command Exit_PS:
1712 * Set needtowakeup to TRUE if current state is SLEEP,
1713 * otherwise send this command down to firmware
1714 * immediately.
1715 */
1716 if (cmdptr->command !=
1717 cpu_to_le16(cmd_802_11_ps_mode)) {
1718 /* Prepare to send Exit PS,
1719 * this non PS command will be sent later */
1720 if ((adapter->psstate == PS_STATE_SLEEP)
1721 || (adapter->psstate == PS_STATE_PRE_SLEEP)
1722 ) {
1723 /* w/ new scheme, it will not reach here.
1724 since it is blocked in main_thread. */
1725 adapter->needtowakeup = 1;
1726 } else
1727 libertas_ps_wakeup(priv, 0);
1728
1729 ret = 0;
1730 goto done;
1731 } else {
1732 /*
1733 * PS command. Ignore it if it is not Exit_PS.
1734 * otherwise send it down immediately.
1735 */
1736 struct cmd_ds_802_11_ps_mode *psm =
1737 &cmdptr->params.psmode;
1738
1739 lbs_pr_debug(1,
1740 "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
1741 psm->action);
1742 if (psm->action !=
1743 cpu_to_le16(cmd_subcmd_exit_ps)) {
1744 lbs_pr_debug(1,
1745 "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
1746 list_del((struct list_head *)cmdnode);
1747 libertas_cleanup_and_insert_cmd(priv, cmdnode);
1748
1749 ret = 0;
1750 goto done;
1751 }
1752
1753 if ((adapter->psstate == PS_STATE_SLEEP)
1754 || (adapter->psstate == PS_STATE_PRE_SLEEP)
1755 ) {
1756 lbs_pr_debug(1,
1757 "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
1758 list_del((struct list_head *)cmdnode);
1759 libertas_cleanup_and_insert_cmd(priv, cmdnode);
1760 adapter->needtowakeup = 1;
1761
1762 ret = 0;
1763 goto done;
1764 }
1765
1766 lbs_pr_debug(1,
1767 "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
1768 }
1769 }
1770 list_del((struct list_head *)cmdnode);
1771 lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n",
1772 cmdptr->command);
1773 DownloadcommandToStation(priv, cmdnode);
1774 } else {
1775 /*
1776 * check if in power save mode, if yes, put the device back
1777 * to PS mode
1778 */
1779 if ((adapter->psmode != wlan802_11powermodecam) &&
1780 (adapter->psstate == PS_STATE_FULL_POWER) &&
1781 (adapter->connect_status == libertas_connected)) {
1782 if (adapter->secinfo.WPAenabled
1783 || adapter->secinfo.WPA2enabled) {
1784 /* check for valid WPA group keys */
1785 if (adapter->wpa_mcast_key.len
1786 || adapter->wpa_unicast_key.len) {
1787 lbs_pr_debug(1,
1788 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1789 " go back to PS_SLEEP");
1790 libertas_ps_sleep(priv, 0);
1791 }
1792 } else {
1793 lbs_pr_debug(1,
1794 "EXEC_NEXT_CMD: command PendQ is empty,"
1795 " go back to PS_SLEEP");
1796 libertas_ps_sleep(priv, 0);
1797 }
1798 }
1799 }
1800
1801 ret = 0;
1802done:
1803 return ret;
1804}
1805
1806void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
1807{
1808 union iwreq_data iwrq;
1809 u8 buf[50];
1810
1811 ENTER();
1812
1813 memset(&iwrq, 0, sizeof(union iwreq_data));
1814 memset(buf, 0, sizeof(buf));
1815
1816 snprintf(buf, sizeof(buf) - 1, "%s", str);
1817
1818 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
1819
1820 /* Send Event to upper layer */
1821 lbs_pr_debug(1, "Event Indication string = %s\n",
1822 (char *)buf);
1823 lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
1824
1825 lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
1826 wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
1827
1828 LEAVE();
1829 return;
1830}
1831
1832static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
1833{
1834 unsigned long flags;
1835 wlan_adapter *adapter = priv->adapter;
1836 int ret = 0;
1837
1838 ENTER();
1839
1840 lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
1841 size);
1842
1843 lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
1844
1845 ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size);
1846 priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
1847
1848 spin_lock_irqsave(&adapter->driver_lock, flags);
1849 if (adapter->intcounter || adapter->currenttxskb)
1850 lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
1851 adapter->intcounter, adapter->currenttxskb);
1852 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1853
1854 if (ret) {
1855 lbs_pr_alert(
1856 "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
1857 } else {
1858 spin_lock_irqsave(&adapter->driver_lock, flags);
1859 if (!adapter->intcounter) {
1860 adapter->psstate = PS_STATE_SLEEP;
1861 } else {
1862 lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
1863 adapter->intcounter);
1864 }
1865 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1866
1867 lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
1868 lbs_pr_debug(1, "+");
1869 }
1870
1871 LEAVE();
1872 return ret;
1873}
1874
1875void libertas_ps_sleep(wlan_private * priv, int wait_option)
1876{
1877
1878 ENTER();
1879
1880 /*
1881 * PS is currently supported only in Infrastructure mode
1882 * Remove this check if it is to be supported in IBSS mode also
1883 */
1884
1885 libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
1886 cmd_subcmd_enter_ps, wait_option, 0, NULL);
1887
1888 LEAVE();
1889 return;
1890}
1891
1892/**
1893 * @brief This function sends Eixt_PS command to firmware.
1894 *
1895 * @param priv A pointer to wlan_private structure
1896 * @param wait_option wait response or not
1897 * @return n/a
1898 */
1899void libertas_ps_wakeup(wlan_private * priv, int wait_option)
1900{
1901 enum WLAN_802_11_POWER_MODE Localpsmode;
1902
1903 ENTER();
1904
1905 Localpsmode = wlan802_11powermodecam;
1906
1907 lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
1908
1909 libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
1910 cmd_subcmd_exit_ps,
1911 wait_option, 0, &Localpsmode);
1912
1913 LEAVE();
1914 return;
1915}
1916
1917/**
1918 * @brief This function checks condition and prepares to
1919 * send sleep confirm command to firmware if ok.
1920 *
1921 * @param priv A pointer to wlan_private structure
1922 * @param psmode Power Saving mode
1923 * @return n/a
1924 */
1925void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
1926{
1927 unsigned long flags =0;
1928 wlan_adapter *adapter = priv->adapter;
1929 u8 allowed = 1;
1930
1931 ENTER();
1932
1933 if (priv->wlan_dev.dnld_sent) {
1934 allowed = 0;
1935 lbs_pr_debug(1, "D");
1936 }
1937
1938 spin_lock_irqsave(&adapter->driver_lock, flags);
1939 if (adapter->cur_cmd) {
1940 allowed = 0;
1941 lbs_pr_debug(1, "C");
1942 }
1943 if (adapter->intcounter > 0) {
1944 allowed = 0;
1945 lbs_pr_debug(1, "I%d", adapter->intcounter);
1946 }
1947 spin_unlock_irqrestore(&adapter->driver_lock, flags);
1948
1949 if (allowed) {
1950 lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
1951 sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
1952 sizeof(struct PS_CMD_ConfirmSleep));
1953 } else {
1954 lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
1955 }
1956
1957 LEAVE();
1958}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644
index 000000000000..cdb012c7e9cf
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -0,0 +1,1031 @@
1/**
2 * This file contains the handling of command
3 * responses as well as events generated by firmware.
4 */
5#include <linux/delay.h>
6#include <linux/if_arp.h>
7#include <linux/netdevice.h>
8
9#include <net/iw_handler.h>
10
11#include "host.h"
12#include "sbi.h"
13#include "decl.h"
14#include "defs.h"
15#include "dev.h"
16#include "join.h"
17#include "wext.h"
18
19/**
20 * @brief This function handles disconnect event. it
21 * reports disconnect to upper layer, clean tx/rx packets,
22 * reset link state etc.
23 *
24 * @param priv A pointer to wlan_private structure
25 * @return n/a
26 */
27void libertas_mac_event_disconnected(wlan_private * priv)
28{
29 wlan_adapter *adapter = priv->adapter;
30 union iwreq_data wrqu;
31
32 if (adapter->connect_status != libertas_connected)
33 return;
34
35 lbs_pr_debug(1, "Handles disconnect event.\n");
36
37 memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
38 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
39
40 /*
41 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
42 * It causes problem in the Supplicant
43 */
44
45 msleep_interruptible(1000);
46 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
47
48 /* Free Tx and Rx packets */
49 kfree_skb(priv->adapter->currenttxskb);
50 priv->adapter->currenttxskb = NULL;
51
52 /* report disconnect to upper layer */
53 netif_stop_queue(priv->wlan_dev.netdev);
54 netif_carrier_off(priv->wlan_dev.netdev);
55
56 /* reset SNR/NF/RSSI values */
57 memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
58 memset(adapter->NF, 0x00, sizeof(adapter->NF));
59 memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
60 memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
61 memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
62 adapter->nextSNRNF = 0;
63 adapter->numSNRNF = 0;
64 adapter->rxpd_rate = 0;
65 lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
66 adapter->curbssparams.ssid.ssid,
67 adapter->curbssparams.ssid.ssidlength);
68 lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
69 adapter->previousssid.ssid, adapter->previousssid.ssidlength);
70
71 /* reset internal flags */
72 adapter->secinfo.WPAenabled = 0;
73 adapter->secinfo.WPA2enabled = 0;
74 adapter->wpa_ie_len = 0;
75 adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
76 adapter->secinfo.Encryptionmode = CIPHER_NONE;
77
78 adapter->connect_status = libertas_disconnected;
79
80 /*
81 * memorize the previous SSID and BSSID
82 * it could be used for re-assoc
83 */
84 memcpy(&adapter->previousssid,
85 &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
86 memcpy(adapter->previousbssid,
87 adapter->curbssparams.bssid, ETH_ALEN);
88
89 /* need to erase the current SSID and BSSID info */
90 adapter->pattemptedbssdesc = NULL;
91 memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
92
93 if (adapter->psstate != PS_STATE_FULL_POWER) {
94 /* make firmware to exit PS mode */
95 lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
96 libertas_ps_wakeup(priv, 0);
97 }
98}
99
100/**
101 * @brief This function handles MIC failure event.
102 *
103 * @param priv A pointer to wlan_private structure
104 * @para event the event id
105 * @return n/a
106 */
107static void handle_mic_failureevent(wlan_private * priv, u32 event)
108{
109 char buf[50];
110
111 memset(buf, 0, sizeof(buf));
112
113 sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
114
115 if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
116 strcat(buf, "unicast ");
117 } else {
118 strcat(buf, "multicast ");
119 }
120
121 libertas_send_iwevcustom_event(priv, buf);
122}
123
124static int wlan_ret_reg_access(wlan_private * priv,
125 u16 type, struct cmd_ds_command *resp)
126{
127 wlan_adapter *adapter = priv->adapter;
128
129 ENTER();
130
131 switch (type) {
132 case cmd_ret_mac_reg_access:
133 {
134 struct cmd_ds_mac_reg_access *reg;
135
136 reg =
137 (struct cmd_ds_mac_reg_access *)&resp->params.
138 macreg;
139
140 adapter->offsetvalue.offset = reg->offset;
141 adapter->offsetvalue.value = reg->value;
142 break;
143 }
144
145 case cmd_ret_bbp_reg_access:
146 {
147 struct cmd_ds_bbp_reg_access *reg;
148 reg =
149 (struct cmd_ds_bbp_reg_access *)&resp->params.
150 bbpreg;
151
152 adapter->offsetvalue.offset = reg->offset;
153 adapter->offsetvalue.value = reg->value;
154 break;
155 }
156
157 case cmd_ret_rf_reg_access:
158 {
159 struct cmd_ds_rf_reg_access *reg;
160 reg =
161 (struct cmd_ds_rf_reg_access *)&resp->params.
162 rfreg;
163
164 adapter->offsetvalue.offset = reg->offset;
165 adapter->offsetvalue.value = reg->value;
166 break;
167 }
168
169 default:
170 LEAVE();
171 return -1;
172 }
173
174 LEAVE();
175 return 0;
176}
177
178static int wlan_ret_get_hw_spec(wlan_private * priv,
179 struct cmd_ds_command *resp)
180{
181 u32 i;
182 struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
183 wlan_adapter *adapter = priv->adapter;
184 int ret = 0;
185
186 ENTER();
187
188 adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
189
190 adapter->fwreleasenumber = hwspec->fwreleasenumber;
191
192 lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
193 adapter->fwreleasenumber);
194 lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
195 hwspec->permanentaddr[0], hwspec->permanentaddr[1],
196 hwspec->permanentaddr[2], hwspec->permanentaddr[3],
197 hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
198 lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
199 hwspec->hwifversion, hwspec->version);
200
201 adapter->regioncode = le16_to_cpu(hwspec->regioncode);
202
203 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
204 /* use the region code to search for the index */
205 if (adapter->regioncode == libertas_region_code_to_index[i]) {
206 adapter->regiontableindex = (u16) i;
207 break;
208 }
209 }
210
211 /* if it's unidentified region code, use the default (USA) */
212 if (i >= MRVDRV_MAX_REGION_CODE) {
213 adapter->regioncode = 0x10;
214 adapter->regiontableindex = 0;
215 lbs_pr_info(
216 "unidentified region code, use the default (USA)\n");
217 }
218
219 if (adapter->current_addr[0] == 0xff) {
220 memmove(adapter->current_addr, hwspec->permanentaddr,
221 ETH_ALEN);
222 }
223
224 memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
225 memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
226
227 if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
228 ret = -1;
229 goto done;
230 }
231
232 if (libertas_set_universaltable(priv, 0)) {
233 ret = -1;
234 goto done;
235 }
236
237 done:
238 LEAVE();
239 return ret;
240}
241
242static int wlan_ret_802_11_sleep_params(wlan_private * priv,
243 struct cmd_ds_command *resp)
244{
245 struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
246 wlan_adapter *adapter = priv->adapter;
247
248 ENTER();
249
250 lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
251 " extsleepclk=%x\n", sp->error, sp->offset,
252 sp->stabletime, sp->calcontrol, sp->externalsleepclk);
253 adapter->sp.sp_error = le16_to_cpu(sp->error);
254 adapter->sp.sp_offset = le16_to_cpu(sp->offset);
255 adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
256 adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
257 adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
258 adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
259
260 LEAVE();
261 return 0;
262}
263
264static int wlan_ret_802_11_stat(wlan_private * priv,
265 struct cmd_ds_command *resp)
266{
267/* currently adapter->wlan802_11Stat is unused
268
269 struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
270 wlan_adapter *adapter = priv->adapter;
271
272 // TODO Convert it to Big endian befor copy
273 memcpy(&adapter->wlan802_11Stat,
274 p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
275*/
276 return 0;
277}
278
279static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
280 struct cmd_ds_command *resp)
281{
282 struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
283 u16 oid = le16_to_cpu(smib->oid);
284 u16 querytype = le16_to_cpu(smib->querytype);
285
286 ENTER();
287
288 lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
289 querytype);
290 lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n",
291 le16_to_cpu(smib->bufsize));
292
293 if (querytype == cmd_act_get) {
294 switch (oid) {
295 case fragthresh_i:
296 priv->adapter->fragthsd =
297 le16_to_cpu(*
298 ((unsigned short *)(smib->value)));
299 lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
300 priv->adapter->fragthsd);
301 break;
302 case rtsthresh_i:
303 priv->adapter->rtsthsd =
304 le16_to_cpu(*
305 ((unsigned short *)(smib->value)));
306 lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
307 priv->adapter->rtsthsd);
308 break;
309 case short_retrylim_i:
310 priv->adapter->txretrycount =
311 le16_to_cpu(*
312 ((unsigned short *)(smib->value)));
313 lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
314 priv->adapter->rtsthsd);
315 break;
316 default:
317 break;
318 }
319 }
320
321 LEAVE();
322 return 0;
323}
324
325static int wlan_ret_802_11_key_material(wlan_private * priv,
326 struct cmd_ds_command *resp)
327{
328 struct cmd_ds_802_11_key_material *pkeymaterial =
329 &resp->params.keymaterial;
330 wlan_adapter *adapter = priv->adapter;
331 u16 action = le16_to_cpu(pkeymaterial->action);
332
333 ENTER();
334
335 /* Copy the returned key to driver private data */
336 if (action == cmd_act_get) {
337 u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
338 u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
339
340 while (buf_ptr < resp_end) {
341 struct MrvlIEtype_keyParamSet * pkeyparamset =
342 (struct MrvlIEtype_keyParamSet *) buf_ptr;
343 struct WLAN_802_11_KEY * pkey;
344 u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
345 u16 param_set_len = le16_to_cpu(pkeyparamset->length);
346 u8 * end;
347 u16 key_len = le16_to_cpu(pkeyparamset->keylen);
348
349 end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
350 + sizeof (pkeyparamset->length)
351 + param_set_len;
352 /* Make sure we don't access past the end of the IEs */
353 if (end > resp_end)
354 break;
355
356 if (key_info & KEY_INFO_WPA_UNICAST)
357 pkey = &adapter->wpa_unicast_key;
358 else if (key_info & KEY_INFO_WPA_MCAST)
359 pkey = &adapter->wpa_mcast_key;
360 else
361 break;
362
363 /* Copy returned key into driver */
364 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
365 if (key_len > sizeof(pkey->key))
366 break;
367 pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
368 pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
369 pkey->len = le16_to_cpu(pkeyparamset->keylen);
370 memcpy(pkey->key, pkeyparamset->key, pkey->len);
371
372 buf_ptr = end + 1;
373 }
374 }
375
376 LEAVE();
377 return 0;
378}
379
380static int wlan_ret_802_11_mac_address(wlan_private * priv,
381 struct cmd_ds_command *resp)
382{
383 struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
384 wlan_adapter *adapter = priv->adapter;
385
386 ENTER();
387
388 memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
389
390 LEAVE();
391 return 0;
392}
393
394static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
395 struct cmd_ds_command *resp)
396{
397 struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
398 wlan_adapter *adapter = priv->adapter;
399
400 ENTER();
401
402 adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
403
404 lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
405
406 LEAVE();
407 return 0;
408}
409
410static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
411 struct cmd_ds_command *resp)
412{
413 struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
414 wlan_adapter *adapter = priv->adapter;
415 u16 action = le16_to_cpu(pAntenna->action);
416
417 if (action == cmd_act_get_rx)
418 adapter->rxantennamode =
419 le16_to_cpu(pAntenna->antennamode);
420
421 if (action == cmd_act_get_tx)
422 adapter->txantennamode =
423 le16_to_cpu(pAntenna->antennamode);
424
425 lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
426 action, le16_to_cpu(pAntenna->antennamode));
427
428 return 0;
429}
430
431static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
432 struct cmd_ds_command *resp)
433{
434 struct cmd_ds_802_11_rate_adapt_rateset *rates =
435 &resp->params.rateset;
436 wlan_adapter *adapter = priv->adapter;
437
438 ENTER();
439
440 if (rates->action == cmd_act_get) {
441 adapter->enablehwauto = rates->enablehwauto;
442 adapter->ratebitmap = rates->bitmap;
443 }
444
445 LEAVE();
446
447 return 0;
448}
449
450static int wlan_ret_802_11_data_rate(wlan_private * priv,
451 struct cmd_ds_command *resp)
452{
453 struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
454 wlan_adapter *adapter = priv->adapter;
455 u8 dot11datarate;
456
457 ENTER();
458
459 lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
460 (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
461
462 dot11datarate = pdatarate->datarate[0];
463 if (pdatarate->action == cmd_act_get_tx_rate) {
464 memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
465 sizeof(adapter->libertas_supported_rates));
466 }
467 adapter->datarate = libertas_index_to_data_rate(dot11datarate);
468
469 LEAVE();
470 return 0;
471}
472
473static int wlan_ret_802_11_rf_channel(wlan_private * priv,
474 struct cmd_ds_command *resp)
475{
476 struct cmd_ds_802_11_rf_channel *rfchannel =
477 &resp->params.rfchannel;
478 wlan_adapter *adapter = priv->adapter;
479 u16 action = le16_to_cpu(rfchannel->action);
480 u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
481
482 ENTER();
483
484 if (action == cmd_opt_802_11_rf_channel_get
485 && adapter->curbssparams.channel != newchannel) {
486 lbs_pr_debug(1, "channel Switch: %d to %d\n",
487 adapter->curbssparams.channel, newchannel);
488
489 /* Update the channel again */
490 adapter->curbssparams.channel = newchannel;
491 }
492
493 LEAVE();
494 return 0;
495}
496
497static int wlan_ret_802_11_rssi(wlan_private * priv,
498 struct cmd_ds_command *resp)
499{
500 struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
501 wlan_adapter *adapter = priv->adapter;
502
503 /* store the non average value */
504 adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
505 adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
506 le16_to_cpu(rssirsp->noisefloor);
507
508 adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
509 adapter->NF[TYPE_BEACON][TYPE_AVG] =
510 le16_to_cpu(rssirsp->avgnoisefloor);
511
512 adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
513 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
514 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
515
516 adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
517 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
518 adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
519
520 lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
521 adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
522
523 return 0;
524}
525
526static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
527 struct cmd_ds_command *resp)
528{
529 wlan_adapter *adapter = priv->adapter;
530 struct wlan_ioctl_regrdwr *pbuf;
531 pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
532
533 lbs_pr_debug(1, "eeprom read len=%x\n",
534 le16_to_cpu(resp->params.rdeeprom.bytecount));
535 if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
536 pbuf->NOB = 0;
537 lbs_pr_debug(1, "eeprom read return length is too big\n");
538 return -1;
539 }
540 pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
541 if (pbuf->NOB > 0) {
542
543 memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
544 le16_to_cpu(resp->params.rdeeprom.bytecount));
545 lbs_dbg_hex("adapter", (char *)&pbuf->value,
546 le16_to_cpu(resp->params.rdeeprom.bytecount));
547 }
548 return 0;
549}
550
551static int wlan_ret_get_log(wlan_private * priv,
552 struct cmd_ds_command *resp)
553{
554 struct cmd_ds_802_11_get_log *logmessage =
555 (struct cmd_ds_802_11_get_log *)&resp->params.glog;
556 wlan_adapter *adapter = priv->adapter;
557
558 ENTER();
559
560 /* TODO Convert it to Big Endian before copy */
561 memcpy(&adapter->logmsg, logmessage,
562 sizeof(struct cmd_ds_802_11_get_log));
563
564 LEAVE();
565 return 0;
566}
567
568static inline int handle_cmd_response(u16 respcmd,
569 struct cmd_ds_command *resp,
570 wlan_private *priv)
571{
572 int ret = 0;
573 unsigned long flags;
574 wlan_adapter *adapter = priv->adapter;
575
576 switch (respcmd) {
577 case cmd_ret_mac_reg_access:
578 case cmd_ret_bbp_reg_access:
579 case cmd_ret_rf_reg_access:
580 ret = wlan_ret_reg_access(priv, respcmd, resp);
581 break;
582
583 case cmd_ret_hw_spec_info:
584 ret = wlan_ret_get_hw_spec(priv, resp);
585 break;
586
587 case cmd_ret_802_11_scan:
588 ret = libertas_ret_80211_scan(priv, resp);
589 break;
590
591 case cmd_ret_802_11_get_log:
592 ret = wlan_ret_get_log(priv, resp);
593 break;
594
595 case cmd_ret_802_11_associate:
596 case cmd_ret_802_11_reassociate:
597 ret = libertas_ret_80211_associate(priv, resp);
598 break;
599
600 case cmd_ret_802_11_disassociate:
601 case cmd_ret_802_11_deauthenticate:
602 ret = libertas_ret_80211_disassociate(priv, resp);
603 break;
604
605 case cmd_ret_802_11_ad_hoc_start:
606 case cmd_ret_802_11_ad_hoc_join:
607 ret = libertas_ret_80211_ad_hoc_start(priv, resp);
608 break;
609
610 case cmd_ret_802_11_stat:
611 ret = wlan_ret_802_11_stat(priv, resp);
612 break;
613
614 case cmd_ret_802_11_snmp_mib:
615 ret = wlan_ret_802_11_snmp_mib(priv, resp);
616 break;
617
618 case cmd_ret_802_11_rf_tx_power:
619 ret = wlan_ret_802_11_rf_tx_power(priv, resp);
620 break;
621
622 case cmd_ret_802_11_set_afc:
623 case cmd_ret_802_11_get_afc:
624 spin_lock_irqsave(&adapter->driver_lock, flags);
625 memmove(adapter->cur_cmd->pdata_buf,
626 &resp->params.afc,
627 sizeof(struct cmd_ds_802_11_afc));
628 spin_unlock_irqrestore(&adapter->driver_lock, flags);
629
630 break;
631 case cmd_ret_802_11_rf_antenna:
632 ret = wlan_ret_802_11_rf_antenna(priv, resp);
633 break;
634
635 case cmd_ret_mac_multicast_adr:
636 case cmd_ret_mac_control:
637 case cmd_ret_802_11_set_wep:
638 case cmd_ret_802_11_reset:
639 case cmd_ret_802_11_authenticate:
640 case cmd_ret_802_11_radio_control:
641 case cmd_ret_802_11_beacon_stop:
642 case cmd_ret_802_11_enable_rsn:
643 break;
644
645 case cmd_ret_802_11_data_rate:
646 ret = wlan_ret_802_11_data_rate(priv, resp);
647 break;
648 case cmd_ret_802_11_rate_adapt_rateset:
649 ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
650 break;
651 case cmd_ret_802_11_rf_channel:
652 ret = wlan_ret_802_11_rf_channel(priv, resp);
653 break;
654
655 case cmd_ret_802_11_rssi:
656 ret = wlan_ret_802_11_rssi(priv, resp);
657 break;
658
659 case cmd_ret_802_11_mac_address:
660 ret = wlan_ret_802_11_mac_address(priv, resp);
661 break;
662
663 case cmd_ret_802_11_ad_hoc_stop:
664 ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
665 break;
666
667 case cmd_ret_802_11_key_material:
668 lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
669 ret = wlan_ret_802_11_key_material(priv, resp);
670 break;
671
672 case cmd_ret_802_11_eeprom_access:
673 ret = wlan_ret_802_11_eeprom_access(priv, resp);
674 break;
675
676 case cmd_ret_802_11d_domain_info:
677 ret = libertas_ret_802_11d_domain_info(priv, resp);
678 break;
679
680 case cmd_ret_802_11_sleep_params:
681 ret = wlan_ret_802_11_sleep_params(priv, resp);
682 break;
683 case cmd_ret_802_11_inactivity_timeout:
684 spin_lock_irqsave(&adapter->driver_lock, flags);
685 *((u16 *) adapter->cur_cmd->pdata_buf) =
686 le16_to_cpu(resp->params.inactivity_timeout.timeout);
687 spin_unlock_irqrestore(&adapter->driver_lock, flags);
688 break;
689
690 case cmd_ret_802_11_tpc_cfg:
691 spin_lock_irqsave(&adapter->driver_lock, flags);
692 memmove(adapter->cur_cmd->pdata_buf,
693 &resp->params.tpccfg,
694 sizeof(struct cmd_ds_802_11_tpc_cfg));
695 spin_unlock_irqrestore(&adapter->driver_lock, flags);
696 break;
697 case cmd_ret_802_11_led_gpio_ctrl:
698 spin_lock_irqsave(&adapter->driver_lock, flags);
699 memmove(adapter->cur_cmd->pdata_buf,
700 &resp->params.ledgpio,
701 sizeof(struct cmd_ds_802_11_led_ctrl));
702 spin_unlock_irqrestore(&adapter->driver_lock, flags);
703 break;
704 case cmd_ret_802_11_pwr_cfg:
705 spin_lock_irqsave(&adapter->driver_lock, flags);
706 memmove(adapter->cur_cmd->pdata_buf,
707 &resp->params.pwrcfg,
708 sizeof(struct cmd_ds_802_11_pwr_cfg));
709 spin_unlock_irqrestore(&adapter->driver_lock, flags);
710
711 break;
712
713 case cmd_ret_get_tsf:
714 spin_lock_irqsave(&adapter->driver_lock, flags);
715 memcpy(priv->adapter->cur_cmd->pdata_buf,
716 &resp->params.gettsf.tsfvalue, sizeof(u64));
717 spin_unlock_irqrestore(&adapter->driver_lock, flags);
718 break;
719 case cmd_ret_bt_access:
720 spin_lock_irqsave(&adapter->driver_lock, flags);
721 if (adapter->cur_cmd->pdata_buf)
722 memcpy(adapter->cur_cmd->pdata_buf,
723 &resp->params.bt.addr1, 2 * ETH_ALEN);
724 spin_unlock_irqrestore(&adapter->driver_lock, flags);
725 break;
726 case cmd_ret_fwt_access:
727 spin_lock_irqsave(&adapter->driver_lock, flags);
728 if (adapter->cur_cmd->pdata_buf)
729 memcpy(adapter->cur_cmd->pdata_buf,
730 &resp->params.fwt,
731 sizeof(resp->params.fwt));
732 spin_unlock_irqrestore(&adapter->driver_lock, flags);
733 break;
734 case cmd_ret_mesh_access:
735 if (adapter->cur_cmd->pdata_buf)
736 memcpy(adapter->cur_cmd->pdata_buf,
737 &resp->params.mesh,
738 sizeof(resp->params.mesh));
739 break;
740 case cmd_rte_802_11_tx_rate_query:
741 priv->adapter->txrate = resp->params.txrate.txrate;
742 break;
743 default:
744 lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
745 resp->command);
746 break;
747 }
748 return ret;
749}
750
751int libertas_process_rx_command(wlan_private * priv)
752{
753 u16 respcmd;
754 struct cmd_ds_command *resp;
755 wlan_adapter *adapter = priv->adapter;
756 int ret = 0;
757 ulong flags;
758 u16 result;
759
760 ENTER();
761
762 lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
763
764 /* Now we got response from FW, cancel the command timer */
765 del_timer(&adapter->command_timer);
766
767 mutex_lock(&adapter->lock);
768 spin_lock_irqsave(&adapter->driver_lock, flags);
769
770 if (!adapter->cur_cmd) {
771 lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
772 ret = -1;
773 spin_unlock_irqrestore(&adapter->driver_lock, flags);
774 goto done;
775 }
776 resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
777
778 lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
779 priv->wlan_dev.upld_len);
780
781 respcmd = le16_to_cpu(resp->command);
782
783 result = le16_to_cpu(resp->result);
784
785 lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
786 result, priv->wlan_dev.upld_len);
787
788 if (!(respcmd & 0x8000)) {
789 lbs_pr_debug(1, "Invalid response to command!");
790 adapter->cur_cmd_retcode = -1;
791 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
792 adapter->nr_cmd_pending--;
793 adapter->cur_cmd = NULL;
794 spin_unlock_irqrestore(&adapter->driver_lock, flags);
795 ret = -1;
796 goto done;
797 }
798
799 /* Store the response code to cur_cmd_retcode. */
800 adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
801
802 if (respcmd == cmd_ret_802_11_ps_mode) {
803 struct cmd_ds_802_11_ps_mode *psmode;
804
805 psmode = &resp->params.psmode;
806 lbs_pr_debug(1,
807 "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
808 resp->result, psmode->action);
809 psmode->action = cpu_to_le16(psmode->action);
810
811 if (result) {
812 lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
813 resp->result);
814 if (adapter->inframode == wlan802_11ibss) {
815 /*
816 * We should not re-try enter-ps command in
817 * ad-hoc mode. It takes place in
818 * libertas_execute_next_command().
819 */
820 if (psmode->action == cmd_subcmd_enter_ps)
821 adapter->psmode =
822 wlan802_11powermodecam;
823 }
824 } else if (psmode->action == cmd_subcmd_enter_ps) {
825 adapter->needtowakeup = 0;
826 adapter->psstate = PS_STATE_AWAKE;
827
828 lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
829 if (adapter->connect_status != libertas_connected) {
830 /*
831 * When Deauth Event received before Enter_PS command
832 * response, We need to wake up the firmware.
833 */
834 lbs_pr_debug(1,
835 "Disconnected, Going to invoke libertas_ps_wakeup\n");
836
837 mutex_unlock(&adapter->lock);
838 spin_unlock_irqrestore(&adapter->driver_lock, flags);
839 libertas_ps_wakeup(priv, 0);
840 mutex_lock(&adapter->lock);
841 spin_lock_irqsave(&adapter->driver_lock, flags);
842 }
843 } else if (psmode->action == cmd_subcmd_exit_ps) {
844 adapter->needtowakeup = 0;
845 adapter->psstate = PS_STATE_FULL_POWER;
846 lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
847 } else {
848 lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
849 psmode->action);
850 }
851
852 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
853 adapter->nr_cmd_pending--;
854 adapter->cur_cmd = NULL;
855 spin_unlock_irqrestore(&adapter->driver_lock, flags);
856
857 ret = 0;
858 goto done;
859 }
860
861 if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
862 /* Copy the response back to response buffer */
863 memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
864
865 adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
866 }
867
868 /* If the command is not successful, cleanup and return failure */
869 if ((result != 0 || !(respcmd & 0x8000))) {
870 lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
871 resp->command, resp->result);
872 /*
873 * Handling errors here
874 */
875 switch (respcmd) {
876 case cmd_ret_hw_spec_info:
877 case cmd_ret_802_11_reset:
878 lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
879 break;
880
881 }
882
883 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
884 adapter->nr_cmd_pending--;
885 adapter->cur_cmd = NULL;
886 spin_unlock_irqrestore(&adapter->driver_lock, flags);
887
888 ret = -1;
889 goto done;
890 }
891
892 spin_unlock_irqrestore(&adapter->driver_lock, flags);
893
894 ret = handle_cmd_response(respcmd, resp, priv);
895
896 spin_lock_irqsave(&adapter->driver_lock, flags);
897 if (adapter->cur_cmd) {
898 /* Clean up and Put current command back to cmdfreeq */
899 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
900 adapter->nr_cmd_pending--;
901 WARN_ON(adapter->nr_cmd_pending > 128);
902 adapter->cur_cmd = NULL;
903 }
904 spin_unlock_irqrestore(&adapter->driver_lock, flags);
905
906done:
907 mutex_unlock(&adapter->lock);
908 LEAVE();
909 return ret;
910}
911
912int libertas_process_event(wlan_private * priv)
913{
914 int ret = 0;
915 wlan_adapter *adapter = priv->adapter;
916 u32 eventcause;
917
918 spin_lock_irq(&adapter->driver_lock);
919 eventcause = adapter->eventcause;
920 spin_unlock_irq(&adapter->driver_lock);
921
922 ENTER();
923
924 lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
925
926 switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
927 case MACREG_INT_CODE_LINK_SENSED:
928 lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
929 break;
930
931 case MACREG_INT_CODE_DEAUTHENTICATED:
932 lbs_pr_debug(1, "EVENT: Deauthenticated\n");
933 libertas_mac_event_disconnected(priv);
934 break;
935
936 case MACREG_INT_CODE_DISASSOCIATED:
937 lbs_pr_debug(1, "EVENT: Disassociated\n");
938 libertas_mac_event_disconnected(priv);
939 break;
940
941 case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
942 lbs_pr_debug(1, "EVENT: Link lost\n");
943 libertas_mac_event_disconnected(priv);
944 break;
945
946 case MACREG_INT_CODE_PS_SLEEP:
947 lbs_pr_debug(1, "EVENT: SLEEP\n");
948 lbs_pr_debug(1, "_");
949
950 /* handle unexpected PS SLEEP event */
951 if (adapter->psstate == PS_STATE_FULL_POWER) {
952 lbs_pr_debug(1,
953 "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
954 break;
955 }
956 adapter->psstate = PS_STATE_PRE_SLEEP;
957
958 libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
959
960 break;
961
962 case MACREG_INT_CODE_PS_AWAKE:
963 lbs_pr_debug(1, "EVENT: AWAKE \n");
964 lbs_pr_debug(1, "|");
965
966 /* handle unexpected PS AWAKE event */
967 if (adapter->psstate == PS_STATE_FULL_POWER) {
968 lbs_pr_debug(1,
969 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
970 break;
971 }
972
973 adapter->psstate = PS_STATE_AWAKE;
974
975 if (adapter->needtowakeup) {
976 /*
977 * wait for the command processing to finish
978 * before resuming sending
979 * adapter->needtowakeup will be set to FALSE
980 * in libertas_ps_wakeup()
981 */
982 lbs_pr_debug(1, "Waking up...\n");
983 libertas_ps_wakeup(priv, 0);
984 }
985 break;
986
987 case MACREG_INT_CODE_MIC_ERR_UNICAST:
988 lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
989 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
990 break;
991
992 case MACREG_INT_CODE_MIC_ERR_MULTICAST:
993 lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
994 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
995 break;
996 case MACREG_INT_CODE_MIB_CHANGED:
997 case MACREG_INT_CODE_INIT_DONE:
998 break;
999
1000 case MACREG_INT_CODE_ADHOC_BCN_LOST:
1001 lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
1002 break;
1003
1004 case MACREG_INT_CODE_RSSI_LOW:
1005 lbs_pr_alert( "EVENT: RSSI_LOW\n");
1006 break;
1007 case MACREG_INT_CODE_SNR_LOW:
1008 lbs_pr_alert( "EVENT: SNR_LOW\n");
1009 break;
1010 case MACREG_INT_CODE_MAX_FAIL:
1011 lbs_pr_alert( "EVENT: MAX_FAIL\n");
1012 break;
1013 case MACREG_INT_CODE_RSSI_HIGH:
1014 lbs_pr_alert( "EVENT: RSSI_HIGH\n");
1015 break;
1016 case MACREG_INT_CODE_SNR_HIGH:
1017 lbs_pr_alert( "EVENT: SNR_HIGH\n");
1018 break;
1019
1020 default:
1021 lbs_pr_alert( "EVENT: unknown event id: %#x\n",
1022 eventcause >> SBI_EVENT_CAUSE_SHIFT);
1023 break;
1024 }
1025
1026 spin_lock_irq(&adapter->driver_lock);
1027 adapter->eventcause = 0;
1028 spin_unlock_irq(&adapter->driver_lock);
1029 LEAVE();
1030 return ret;
1031}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644
index 000000000000..3ad1e0339ed0
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -0,0 +1,1968 @@
1#include <linux/module.h>
2#include <linux/dcache.h>
3#include <linux/debugfs.h>
4#include <linux/delay.h>
5#include <linux/mm.h>
6#include <net/iw_handler.h>
7#include "dev.h"
8#include "decl.h"
9#include "host.h"
10
11static struct dentry *libertas_dir = NULL;
12static char *szStates[] = {
13 "Connected",
14 "Disconnected"
15};
16
17void libertas_debug_init(wlan_private * priv, struct net_device *dev);
18
19static int open_file_generic(struct inode *inode, struct file *file)
20{
21 file->private_data = inode->i_private;
22 return 0;
23}
24
25static ssize_t write_file_dummy(struct file *file, const char __user *buf,
26 size_t count, loff_t *ppos)
27{
28 return -EINVAL;
29}
30
31static const size_t len = PAGE_SIZE;
32
33static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
34 size_t count, loff_t *ppos)
35{
36 wlan_private *priv = file->private_data;
37 size_t pos = 0;
38 unsigned long addr = get_zeroed_page(GFP_KERNEL);
39 char *buf = (char *)addr;
40 ssize_t res;
41
42 pos += snprintf(buf+pos, len-pos, "state = %s\n",
43 szStates[priv->adapter->connect_status]);
44 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
45 (u32) priv->adapter->regioncode);
46
47 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
48
49 free_page(addr);
50 return res;
51}
52
53
54static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
55 size_t count, loff_t *ppos)
56{
57 wlan_private *priv = file->private_data;
58 size_t pos = 0;
59 int numscansdone = 0, res;
60 unsigned long addr = get_zeroed_page(GFP_KERNEL);
61 char *buf = (char *)addr;
62
63 pos += snprintf(buf+pos, len-pos,
64 "---------------------------------------");
65 pos += snprintf(buf+pos, len-pos,
66 "---------------------------------------\n");
67 pos += snprintf(buf+pos, len-pos,
68 "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
69 pos += snprintf(buf+pos, len-pos,
70 "---------------------------------------");
71 pos += snprintf(buf+pos, len-pos,
72 "---------------------------------------\n");
73
74 while (numscansdone < priv->adapter->numinscantable) {
75 struct bss_descriptor *pbssinfo;
76 u16 cap;
77
78 pbssinfo = &priv->adapter->scantable[numscansdone];
79 memcpy(&cap, &pbssinfo->cap, sizeof(cap));
80 pos += snprintf(buf+pos, len-pos,
81 "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
82 numscansdone, pbssinfo->channel, pbssinfo->rssi,
83 pbssinfo->macaddress[0], pbssinfo->macaddress[1],
84 pbssinfo->macaddress[2], pbssinfo->macaddress[3],
85 pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
86 pos += snprintf(buf+pos, len-pos, " %04x-", cap);
87 pos += snprintf(buf+pos, len-pos, "%c%c%c |",
88 pbssinfo->cap.ibss ? 'A' : 'I',
89 pbssinfo->cap.privacy ? 'P' : ' ',
90 pbssinfo->cap.spectrummgmt ? 'S' : ' ');
91 pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
92 pos += snprintf(buf+pos, len-pos, " %d |",
93 SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
94
95 pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
96
97 numscansdone++;
98 }
99
100 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
101
102 free_page(addr);
103 return res;
104}
105
106static ssize_t libertas_sleepparams_write(struct file *file,
107 const char __user *user_buf, size_t count,
108 loff_t *ppos)
109{
110 wlan_private *priv = file->private_data;
111 ssize_t buf_size, res;
112 int p1, p2, p3, p4, p5, p6;
113 struct sleep_params sp;
114 unsigned long addr = get_zeroed_page(GFP_KERNEL);
115 char *buf = (char *)addr;
116
117 buf_size = min(count, len - 1);
118 if (copy_from_user(buf, user_buf, buf_size)) {
119 res = -EFAULT;
120 goto out_unlock;
121 }
122 res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
123 if (res != 6) {
124 res = -EFAULT;
125 goto out_unlock;
126 }
127 sp.sp_error = p1;
128 sp.sp_offset = p2;
129 sp.sp_stabletime = p3;
130 sp.sp_calcontrol = p4;
131 sp.sp_extsleepclk = p5;
132 sp.sp_reserved = p6;
133
134 memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
135
136 res = libertas_prepare_and_send_command(priv,
137 cmd_802_11_sleep_params,
138 cmd_act_set,
139 cmd_option_waitforrsp, 0, NULL);
140
141 if (!res)
142 res = count;
143 else
144 res = -EINVAL;
145
146out_unlock:
147 free_page(addr);
148 return res;
149}
150
151static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
152 size_t count, loff_t *ppos)
153{
154 wlan_private *priv = file->private_data;
155 wlan_adapter *adapter = priv->adapter;
156 ssize_t res;
157 size_t pos = 0;
158 unsigned long addr = get_zeroed_page(GFP_KERNEL);
159 char *buf = (char *)addr;
160
161 res = libertas_prepare_and_send_command(priv,
162 cmd_802_11_sleep_params,
163 cmd_act_get,
164 cmd_option_waitforrsp, 0, NULL);
165 if (res) {
166 res = -EFAULT;
167 goto out_unlock;
168 }
169
170 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
171 adapter->sp.sp_offset, adapter->sp.sp_stabletime,
172 adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
173 adapter->sp.sp_reserved);
174
175 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
176
177out_unlock:
178 free_page(addr);
179 return res;
180}
181
182static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
183 size_t count, loff_t *ppos)
184{
185 wlan_private *priv = file->private_data;
186 ssize_t res, buf_size;
187 struct WLAN_802_11_SSID extscan_ssid;
188 union iwreq_data wrqu;
189 unsigned long addr = get_zeroed_page(GFP_KERNEL);
190 char *buf = (char *)addr;
191
192 buf_size = min(count, len - 1);
193 if (copy_from_user(buf, userbuf, buf_size)) {
194 res = -EFAULT;
195 goto out_unlock;
196 }
197
198 memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
199 extscan_ssid.ssidlength = strlen(buf)-1;
200
201 libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
202
203 memset(&wrqu, 0, sizeof(union iwreq_data));
204 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
205
206out_unlock:
207 free_page(addr);
208 return count;
209}
210
211static int libertas_parse_chan(char *buf, size_t count,
212 struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
213{
214 char *start, *end, *hold, *str;
215 int i = 0;
216
217 start = strstr(buf, "chan=");
218 if (!start)
219 return -EINVAL;
220 start += 5;
221 end = strstr(start, " ");
222 if (!end)
223 end = buf + count;
224 hold = kzalloc((end - start)+1, GFP_KERNEL);
225 if (!hold)
226 return -ENOMEM;
227 strncpy(hold, start, end - start);
228 hold[(end-start)+1] = '\0';
229 while(hold && (str = strsep(&hold, ","))) {
230 int chan;
231 char band, passive = 0;
232 sscanf(str, "%d%c%c", &chan, &band, &passive);
233 scan_cfg->chanlist[i].channumber = chan;
234 scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
235 if (band == 'b' || band == 'g')
236 scan_cfg->chanlist[i].radiotype = 0;
237 else if (band == 'a')
238 scan_cfg->chanlist[i].radiotype = 1;
239
240 scan_cfg->chanlist[i].scantime = dur;
241 i++;
242 }
243
244 kfree(hold);
245 return i;
246}
247
248static void libertas_parse_bssid(char *buf, size_t count,
249 struct wlan_ioctl_user_scan_cfg *scan_cfg)
250{
251 char *hold;
252 unsigned int mac[ETH_ALEN];
253 int i;
254
255 hold = strstr(buf, "bssid=");
256 if (!hold)
257 return;
258 hold += 6;
259 sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
260 mac+4, mac+5);
261 for(i=0;i<ETH_ALEN;i++)
262 scan_cfg->specificBSSID[i] = mac[i];
263}
264
265static void libertas_parse_ssid(char *buf, size_t count,
266 struct wlan_ioctl_user_scan_cfg *scan_cfg)
267{
268 char *hold, *end;
269 ssize_t size;
270
271 hold = strstr(buf, "ssid=");
272 if (!hold)
273 return;
274 hold += 5;
275 end = strstr(hold, " ");
276 if (!end)
277 end = buf + count - 1;
278
279 size = min(IW_ESSID_MAX_SIZE, end - hold);
280 strncpy(scan_cfg->specificSSID, hold, size);
281
282 return;
283}
284
285static void libertas_parse_keep(char *buf, size_t count,
286 struct wlan_ioctl_user_scan_cfg *scan_cfg)
287{
288 char *hold;
289 int val;
290
291 hold = strstr(buf, "keep=");
292 if (!hold)
293 return;
294 hold += 5;
295 sscanf(hold, "%d", &val);
296
297 if (val != 0)
298 val = 1;
299
300 scan_cfg->keeppreviousscan = val;
301 return;
302}
303
304static int libertas_parse_dur(char *buf, size_t count,
305 struct wlan_ioctl_user_scan_cfg *scan_cfg)
306{
307 char *hold;
308 int val;
309
310 hold = strstr(buf, "dur=");
311 if (!hold)
312 return 0;
313 hold += 4;
314 sscanf(hold, "%d", &val);
315
316 return val;
317}
318
319static void libertas_parse_probes(char *buf, size_t count,
320 struct wlan_ioctl_user_scan_cfg *scan_cfg)
321{
322 char *hold;
323 int val;
324
325 hold = strstr(buf, "probes=");
326 if (!hold)
327 return;
328 hold += 7;
329 sscanf(hold, "%d", &val);
330
331 scan_cfg->numprobes = val;
332
333 return;
334}
335
336static void libertas_parse_type(char *buf, size_t count,
337 struct wlan_ioctl_user_scan_cfg *scan_cfg)
338{
339 char *hold;
340 int val;
341
342 hold = strstr(buf, "type=");
343 if (!hold)
344 return;
345 hold += 5;
346 sscanf(hold, "%d", &val);
347
348 /* type=1,2 or 3 */
349 if (val < 1 || val > 3)
350 return;
351
352 scan_cfg->bsstype = val;
353
354 return;
355}
356
357static ssize_t libertas_setuserscan(struct file *file,
358 const char __user *userbuf,
359 size_t count, loff_t *ppos)
360{
361 wlan_private *priv = file->private_data;
362 ssize_t res, buf_size;
363 struct wlan_ioctl_user_scan_cfg *scan_cfg;
364 union iwreq_data wrqu;
365 int dur;
366 unsigned long addr = get_zeroed_page(GFP_KERNEL);
367 char *buf = (char *)addr;
368
369 scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
370 if (!scan_cfg)
371 return -ENOMEM;
372
373 buf_size = min(count, len - 1);
374 if (copy_from_user(buf, userbuf, buf_size)) {
375 res = -EFAULT;
376 goto out_unlock;
377 }
378
379 scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
380
381 dur = libertas_parse_dur(buf, count, scan_cfg);
382 libertas_parse_chan(buf, count, scan_cfg, dur);
383 libertas_parse_bssid(buf, count, scan_cfg);
384 libertas_parse_ssid(buf, count, scan_cfg);
385 libertas_parse_keep(buf, count, scan_cfg);
386 libertas_parse_probes(buf, count, scan_cfg);
387 libertas_parse_type(buf, count, scan_cfg);
388
389 wlan_scan_networks(priv, scan_cfg);
390 wait_event_interruptible(priv->adapter->cmd_pending,
391 !priv->adapter->nr_cmd_pending);
392
393 memset(&wrqu, 0x00, sizeof(union iwreq_data));
394 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
395
396out_unlock:
397 free_page(addr);
398 kfree(scan_cfg);
399 return count;
400}
401
402static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
403 struct cmd_ctrl_node **cmdnode,
404 struct cmd_ds_command **cmd)
405{
406 u16 wait_option = cmd_option_waitforrsp;
407
408 if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
409 lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
410 return -ENOMEM;
411 }
412 if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
413 lbs_pr_debug(1, "failed to allocate response buffer!\n");
414 return -ENOMEM;
415 }
416 libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
417 init_waitqueue_head(&(*cmdnode)->cmdwait_q);
418 (*cmdnode)->pdata_buf = *response_buf;
419 (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
420 (*cmdnode)->cmdwaitqwoken = 0;
421 *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
422 (*cmd)->command = cmd_802_11_subscribe_event;
423 (*cmd)->seqnum = ++priv->adapter->seqnum;
424 (*cmd)->result = 0;
425 return 0;
426}
427
428static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
429 size_t count, loff_t *ppos)
430{
431 wlan_private *priv = file->private_data;
432 wlan_adapter *adapter = priv->adapter;
433 struct cmd_ctrl_node *pcmdnode;
434 struct cmd_ds_command *pcmdptr;
435 struct cmd_ds_802_11_subscribe_event *event;
436 void *response_buf;
437 int res, cmd_len;
438 ssize_t pos = 0;
439 unsigned long addr = get_zeroed_page(GFP_KERNEL);
440 char *buf = (char *)addr;
441
442 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
443 if (res < 0) {
444 free_page(addr);
445 return res;
446 }
447
448 event = &pcmdptr->params.subscribe_event;
449 event->action = cmd_act_get;
450 pcmdptr->size =
451 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
452 libertas_queue_cmd(adapter, pcmdnode, 1);
453 wake_up_interruptible(&priv->mainthread.waitq);
454
455 /* Sleep until response is generated by FW */
456 wait_event_interruptible(pcmdnode->cmdwait_q,
457 pcmdnode->cmdwaitqwoken);
458
459 pcmdptr = response_buf;
460 if (pcmdptr->result) {
461 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
462 pcmdptr->result);
463 kfree(response_buf);
464 free_page(addr);
465 return 0;
466 }
467
468 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
469 lbs_pr_err("command response incorrect!\n");
470 kfree(response_buf);
471 free_page(addr);
472 return 0;
473 }
474
475 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
476 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
477 while (cmd_len < pcmdptr->size) {
478 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
479 switch(header->type) {
480 struct mrvlietypes_rssithreshold *Lowrssi;
481 case TLV_TYPE_RSSI_LOW:
482 Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
483 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
484 Lowrssi->rssivalue,
485 Lowrssi->rssifreq,
486 (event->events & 0x0001)?1:0);
487 default:
488 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
489 break;
490 }
491 }
492
493 kfree(response_buf);
494 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
495 free_page(addr);
496 return res;
497}
498
499static u16 libertas_get_events_bitmap(wlan_private *priv)
500{
501 wlan_adapter *adapter = priv->adapter;
502 struct cmd_ctrl_node *pcmdnode;
503 struct cmd_ds_command *pcmdptr;
504 struct cmd_ds_802_11_subscribe_event *event;
505 void *response_buf;
506 int res;
507 u16 event_bitmap;
508
509 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
510 if (res < 0)
511 return res;
512
513 event = &pcmdptr->params.subscribe_event;
514 event->action = cmd_act_get;
515 pcmdptr->size =
516 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
517 libertas_queue_cmd(adapter, pcmdnode, 1);
518 wake_up_interruptible(&priv->mainthread.waitq);
519
520 /* Sleep until response is generated by FW */
521 wait_event_interruptible(pcmdnode->cmdwait_q,
522 pcmdnode->cmdwaitqwoken);
523
524 pcmdptr = response_buf;
525
526 if (pcmdptr->result) {
527 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
528 pcmdptr->result);
529 kfree(response_buf);
530 return 0;
531 }
532
533 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
534 lbs_pr_err("command response incorrect!\n");
535 kfree(response_buf);
536 return 0;
537 }
538
539 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
540 event_bitmap = event->events;
541 kfree(response_buf);
542 return event_bitmap;
543}
544
545static ssize_t libertas_lowrssi_write(struct file *file,
546 const char __user *userbuf,
547 size_t count, loff_t *ppos)
548{
549 wlan_private *priv = file->private_data;
550 wlan_adapter *adapter = priv->adapter;
551 ssize_t res, buf_size;
552 int value, freq, subscribed, cmd_len;
553 struct cmd_ctrl_node *pcmdnode;
554 struct cmd_ds_command *pcmdptr;
555 struct cmd_ds_802_11_subscribe_event *event;
556 struct mrvlietypes_rssithreshold *rssi_threshold;
557 void *response_buf;
558 u16 event_bitmap;
559 u8 *ptr;
560 unsigned long addr = get_zeroed_page(GFP_KERNEL);
561 char *buf = (char *)addr;
562
563 buf_size = min(count, len - 1);
564 if (copy_from_user(buf, userbuf, buf_size)) {
565 res = -EFAULT;
566 goto out_unlock;
567 }
568 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
569 if (res != 3) {
570 res = -EFAULT;
571 goto out_unlock;
572 }
573
574 event_bitmap = libertas_get_events_bitmap(priv);
575
576 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
577 if (res < 0)
578 goto out_unlock;
579
580 event = &pcmdptr->params.subscribe_event;
581 event->action = cmd_act_set;
582 pcmdptr->size = cpu_to_le16(S_DS_GEN +
583 sizeof(struct cmd_ds_802_11_subscribe_event) +
584 sizeof(struct mrvlietypes_rssithreshold));
585
586 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
587 ptr = (u8*) pcmdptr+cmd_len;
588 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
589 rssi_threshold->header.type = cpu_to_le16(0x0104);
590 rssi_threshold->header.len = 2;
591 rssi_threshold->rssivalue = cpu_to_le16(value);
592 rssi_threshold->rssifreq = cpu_to_le16(freq);
593 event_bitmap |= subscribed ? 0x0001 : 0x0;
594 event->events = event_bitmap;
595
596 libertas_queue_cmd(adapter, pcmdnode, 1);
597 wake_up_interruptible(&priv->mainthread.waitq);
598
599 /* Sleep until response is generated by FW */
600 wait_event_interruptible(pcmdnode->cmdwait_q,
601 pcmdnode->cmdwaitqwoken);
602
603 pcmdptr = response_buf;
604
605 if (pcmdptr->result) {
606 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
607 pcmdptr->result);
608 kfree(response_buf);
609 free_page(addr);
610 return 0;
611 }
612
613 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
614 lbs_pr_err("command response incorrect!\n");
615 kfree(response_buf);
616 free_page(addr);
617 return 0;
618 }
619
620 res = count;
621out_unlock:
622 free_page(addr);
623 return res;
624}
625
626static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
627 size_t count, loff_t *ppos)
628{
629 wlan_private *priv = file->private_data;
630 wlan_adapter *adapter = priv->adapter;
631 struct cmd_ctrl_node *pcmdnode;
632 struct cmd_ds_command *pcmdptr;
633 struct cmd_ds_802_11_subscribe_event *event;
634 void *response_buf;
635 int res, cmd_len;
636 ssize_t pos = 0;
637 unsigned long addr = get_zeroed_page(GFP_KERNEL);
638 char *buf = (char *)addr;
639
640 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
641 if (res < 0) {
642 free_page(addr);
643 return res;
644 }
645
646 event = &pcmdptr->params.subscribe_event;
647 event->action = cmd_act_get;
648 pcmdptr->size =
649 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
650 libertas_queue_cmd(adapter, pcmdnode, 1);
651 wake_up_interruptible(&priv->mainthread.waitq);
652
653 /* Sleep until response is generated by FW */
654 wait_event_interruptible(pcmdnode->cmdwait_q,
655 pcmdnode->cmdwaitqwoken);
656
657 pcmdptr = response_buf;
658
659 if (pcmdptr->result) {
660 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
661 pcmdptr->result);
662 kfree(response_buf);
663 free_page(addr);
664 return 0;
665 }
666
667 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
668 lbs_pr_err("command response incorrect!\n");
669 kfree(response_buf);
670 free_page(addr);
671 return 0;
672 }
673
674 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
675 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
676 while (cmd_len < pcmdptr->size) {
677 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
678 switch(header->type) {
679 struct mrvlietypes_snrthreshold *LowSnr;
680 case TLV_TYPE_SNR_LOW:
681 LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
682 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
683 LowSnr->snrvalue,
684 LowSnr->snrfreq,
685 (event->events & 0x0002)?1:0);
686 default:
687 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
688 break;
689 }
690 }
691
692 kfree(response_buf);
693
694 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
695 free_page(addr);
696 return res;
697}
698
699static ssize_t libertas_lowsnr_write(struct file *file,
700 const char __user *userbuf,
701 size_t count, loff_t *ppos)
702{
703 wlan_private *priv = file->private_data;
704 wlan_adapter *adapter = priv->adapter;
705 ssize_t res, buf_size;
706 int value, freq, subscribed, cmd_len;
707 struct cmd_ctrl_node *pcmdnode;
708 struct cmd_ds_command *pcmdptr;
709 struct cmd_ds_802_11_subscribe_event *event;
710 struct mrvlietypes_snrthreshold *snr_threshold;
711 void *response_buf;
712 u16 event_bitmap;
713 u8 *ptr;
714 unsigned long addr = get_zeroed_page(GFP_KERNEL);
715 char *buf = (char *)addr;
716
717 buf_size = min(count, len - 1);
718 if (copy_from_user(buf, userbuf, buf_size)) {
719 res = -EFAULT;
720 goto out_unlock;
721 }
722 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
723 if (res != 3) {
724 res = -EFAULT;
725 goto out_unlock;
726 }
727
728 event_bitmap = libertas_get_events_bitmap(priv);
729
730 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
731 if (res < 0)
732 goto out_unlock;
733
734 event = &pcmdptr->params.subscribe_event;
735 event->action = cmd_act_set;
736 pcmdptr->size = cpu_to_le16(S_DS_GEN +
737 sizeof(struct cmd_ds_802_11_subscribe_event) +
738 sizeof(struct mrvlietypes_snrthreshold));
739 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
740 ptr = (u8*) pcmdptr+cmd_len;
741 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
742 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
743 snr_threshold->header.len = 2;
744 snr_threshold->snrvalue = cpu_to_le16(value);
745 snr_threshold->snrfreq = cpu_to_le16(freq);
746 event_bitmap |= subscribed ? 0x0002 : 0x0;
747 event->events = event_bitmap;
748
749 libertas_queue_cmd(adapter, pcmdnode, 1);
750 wake_up_interruptible(&priv->mainthread.waitq);
751
752 /* Sleep until response is generated by FW */
753 wait_event_interruptible(pcmdnode->cmdwait_q,
754 pcmdnode->cmdwaitqwoken);
755
756 pcmdptr = response_buf;
757
758 if (pcmdptr->result) {
759 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
760 pcmdptr->result);
761 kfree(response_buf);
762 free_page(addr);
763 return 0;
764 }
765
766 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
767 lbs_pr_err("command response incorrect!\n");
768 kfree(response_buf);
769 free_page(addr);
770 return 0;
771 }
772
773 res = count;
774
775out_unlock:
776 free_page(addr);
777 return res;
778}
779
780static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
781 size_t count, loff_t *ppos)
782{
783 wlan_private *priv = file->private_data;
784 wlan_adapter *adapter = priv->adapter;
785 struct cmd_ctrl_node *pcmdnode;
786 struct cmd_ds_command *pcmdptr;
787 struct cmd_ds_802_11_subscribe_event *event;
788 void *response_buf;
789 int res, cmd_len;
790 ssize_t pos = 0;
791 unsigned long addr = get_zeroed_page(GFP_KERNEL);
792 char *buf = (char *)addr;
793
794 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
795 if (res < 0) {
796 free_page(addr);
797 return res;
798 }
799
800 event = &pcmdptr->params.subscribe_event;
801 event->action = cmd_act_get;
802 pcmdptr->size =
803 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
804 libertas_queue_cmd(adapter, pcmdnode, 1);
805 wake_up_interruptible(&priv->mainthread.waitq);
806
807 /* Sleep until response is generated by FW */
808 wait_event_interruptible(pcmdnode->cmdwait_q,
809 pcmdnode->cmdwaitqwoken);
810
811 pcmdptr = response_buf;
812
813 if (pcmdptr->result) {
814 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
815 pcmdptr->result);
816 kfree(response_buf);
817 free_page(addr);
818 return 0;
819 }
820
821 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
822 lbs_pr_err("command response incorrect!\n");
823 kfree(response_buf);
824 free_page(addr);
825 return 0;
826 }
827
828 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
829 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
830 while (cmd_len < pcmdptr->size) {
831 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
832 switch(header->type) {
833 struct mrvlietypes_failurecount *failcount;
834 case TLV_TYPE_FAILCOUNT:
835 failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
836 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
837 failcount->failvalue,
838 failcount->Failfreq,
839 (event->events & 0x0004)?1:0);
840 default:
841 cmd_len += sizeof(struct mrvlietypes_failurecount);
842 break;
843 }
844 }
845
846 kfree(response_buf);
847 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
848 free_page(addr);
849 return res;
850}
851
852static ssize_t libertas_failcount_write(struct file *file,
853 const char __user *userbuf,
854 size_t count, loff_t *ppos)
855{
856 wlan_private *priv = file->private_data;
857 wlan_adapter *adapter = priv->adapter;
858 ssize_t res, buf_size;
859 int value, freq, subscribed, cmd_len;
860 struct cmd_ctrl_node *pcmdnode;
861 struct cmd_ds_command *pcmdptr;
862 struct cmd_ds_802_11_subscribe_event *event;
863 struct mrvlietypes_failurecount *failcount;
864 void *response_buf;
865 u16 event_bitmap;
866 u8 *ptr;
867 unsigned long addr = get_zeroed_page(GFP_KERNEL);
868 char *buf = (char *)addr;
869
870 buf_size = min(count, len - 1);
871 if (copy_from_user(buf, userbuf, buf_size)) {
872 res = -EFAULT;
873 goto out_unlock;
874 }
875 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
876 if (res != 3) {
877 res = -EFAULT;
878 goto out_unlock;
879 }
880
881 event_bitmap = libertas_get_events_bitmap(priv);
882
883 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
884 if (res < 0)
885 goto out_unlock;
886
887 event = &pcmdptr->params.subscribe_event;
888 event->action = cmd_act_set;
889 pcmdptr->size = cpu_to_le16(S_DS_GEN +
890 sizeof(struct cmd_ds_802_11_subscribe_event) +
891 sizeof(struct mrvlietypes_failurecount));
892 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
893 ptr = (u8*) pcmdptr+cmd_len;
894 failcount = (struct mrvlietypes_failurecount *)(ptr);
895 failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
896 failcount->header.len = 2;
897 failcount->failvalue = cpu_to_le16(value);
898 failcount->Failfreq = cpu_to_le16(freq);
899 event_bitmap |= subscribed ? 0x0004 : 0x0;
900 event->events = event_bitmap;
901
902 libertas_queue_cmd(adapter, pcmdnode, 1);
903 wake_up_interruptible(&priv->mainthread.waitq);
904
905 /* Sleep until response is generated by FW */
906 wait_event_interruptible(pcmdnode->cmdwait_q,
907 pcmdnode->cmdwaitqwoken);
908
909 pcmdptr = (struct cmd_ds_command *)response_buf;
910
911 if (pcmdptr->result) {
912 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
913 pcmdptr->result);
914 kfree(response_buf);
915 free_page(addr);
916 return 0;
917 }
918
919 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
920 lbs_pr_err("command response incorrect!\n");
921 kfree(response_buf);
922 free_page(addr);
923 return 0;
924 }
925
926 res = count;
927out_unlock:
928 free_page(addr);
929 return res;
930}
931
932static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
933 size_t count, loff_t *ppos)
934{
935 wlan_private *priv = file->private_data;
936 wlan_adapter *adapter = priv->adapter;
937 struct cmd_ctrl_node *pcmdnode;
938 struct cmd_ds_command *pcmdptr;
939 struct cmd_ds_802_11_subscribe_event *event;
940 void *response_buf;
941 int res, cmd_len;
942 ssize_t pos = 0;
943 unsigned long addr = get_zeroed_page(GFP_KERNEL);
944 char *buf = (char *)addr;
945
946 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
947 if (res < 0) {
948 free_page(addr);
949 return res;
950 }
951
952 event = &pcmdptr->params.subscribe_event;
953 event->action = cmd_act_get;
954 pcmdptr->size =
955 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
956 libertas_queue_cmd(adapter, pcmdnode, 1);
957 wake_up_interruptible(&priv->mainthread.waitq);
958
959 /* Sleep until response is generated by FW */
960 wait_event_interruptible(pcmdnode->cmdwait_q,
961 pcmdnode->cmdwaitqwoken);
962
963 pcmdptr = response_buf;
964
965 if (pcmdptr->result) {
966 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
967 pcmdptr->result);
968 free_page(addr);
969 kfree(response_buf);
970 return 0;
971 }
972
973 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
974 lbs_pr_err("command response incorrect!\n");
975 free_page(addr);
976 kfree(response_buf);
977 return 0;
978 }
979
980 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
981 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
982 while (cmd_len < pcmdptr->size) {
983 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
984 switch(header->type) {
985 struct mrvlietypes_beaconsmissed *bcnmiss;
986 case TLV_TYPE_BCNMISS:
987 bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
988 pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
989 bcnmiss->beaconmissed,
990 (event->events & 0x0008)?1:0);
991 default:
992 cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
993 break;
994 }
995 }
996
997 kfree(response_buf);
998
999 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1000 free_page(addr);
1001 return res;
1002}
1003
1004static ssize_t libertas_bcnmiss_write(struct file *file,
1005 const char __user *userbuf,
1006 size_t count, loff_t *ppos)
1007{
1008 wlan_private *priv = file->private_data;
1009 wlan_adapter *adapter = priv->adapter;
1010 ssize_t res, buf_size;
1011 int value, freq, subscribed, cmd_len;
1012 struct cmd_ctrl_node *pcmdnode;
1013 struct cmd_ds_command *pcmdptr;
1014 struct cmd_ds_802_11_subscribe_event *event;
1015 struct mrvlietypes_beaconsmissed *bcnmiss;
1016 void *response_buf;
1017 u16 event_bitmap;
1018 u8 *ptr;
1019 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1020 char *buf = (char *)addr;
1021
1022 buf_size = min(count, len - 1);
1023 if (copy_from_user(buf, userbuf, buf_size)) {
1024 res = -EFAULT;
1025 goto out_unlock;
1026 }
1027 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1028 if (res != 3) {
1029 res = -EFAULT;
1030 goto out_unlock;
1031 }
1032
1033 event_bitmap = libertas_get_events_bitmap(priv);
1034
1035 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1036 if (res < 0)
1037 goto out_unlock;
1038
1039 event = &pcmdptr->params.subscribe_event;
1040 event->action = cmd_act_set;
1041 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1042 sizeof(struct cmd_ds_802_11_subscribe_event) +
1043 sizeof(struct mrvlietypes_beaconsmissed));
1044 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1045 ptr = (u8*) pcmdptr+cmd_len;
1046 bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
1047 bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
1048 bcnmiss->header.len = 2;
1049 bcnmiss->beaconmissed = cpu_to_le16(value);
1050 event_bitmap |= subscribed ? 0x0008 : 0x0;
1051 event->events = event_bitmap;
1052
1053 libertas_queue_cmd(adapter, pcmdnode, 1);
1054 wake_up_interruptible(&priv->mainthread.waitq);
1055
1056 /* Sleep until response is generated by FW */
1057 wait_event_interruptible(pcmdnode->cmdwait_q,
1058 pcmdnode->cmdwaitqwoken);
1059
1060 pcmdptr = response_buf;
1061
1062 if (pcmdptr->result) {
1063 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
1064 pcmdptr->result);
1065 kfree(response_buf);
1066 free_page(addr);
1067 return 0;
1068 }
1069
1070 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
1071 lbs_pr_err("command response incorrect!\n");
1072 free_page(addr);
1073 kfree(response_buf);
1074 return 0;
1075 }
1076
1077 res = count;
1078out_unlock:
1079 free_page(addr);
1080 return res;
1081}
1082
1083static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
1084 size_t count, loff_t *ppos)
1085{
1086 wlan_private *priv = file->private_data;
1087 wlan_adapter *adapter = priv->adapter;
1088 struct cmd_ctrl_node *pcmdnode;
1089 struct cmd_ds_command *pcmdptr;
1090 struct cmd_ds_802_11_subscribe_event *event;
1091 void *response_buf;
1092 int res, cmd_len;
1093 ssize_t pos = 0;
1094 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1095 char *buf = (char *)addr;
1096
1097 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1098 if (res < 0) {
1099 free_page(addr);
1100 return res;
1101 }
1102
1103 event = &pcmdptr->params.subscribe_event;
1104 event->action = cmd_act_get;
1105 pcmdptr->size =
1106 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
1107 libertas_queue_cmd(adapter, pcmdnode, 1);
1108 wake_up_interruptible(&priv->mainthread.waitq);
1109
1110 /* Sleep until response is generated by FW */
1111 wait_event_interruptible(pcmdnode->cmdwait_q,
1112 pcmdnode->cmdwaitqwoken);
1113
1114 pcmdptr = response_buf;
1115
1116 if (pcmdptr->result) {
1117 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
1118 pcmdptr->result);
1119 kfree(response_buf);
1120 free_page(addr);
1121 return 0;
1122 }
1123
1124 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
1125 lbs_pr_err("command response incorrect!\n");
1126 kfree(response_buf);
1127 free_page(addr);
1128 return 0;
1129 }
1130
1131 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1132 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
1133 while (cmd_len < pcmdptr->size) {
1134 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
1135 switch(header->type) {
1136 struct mrvlietypes_rssithreshold *Highrssi;
1137 case TLV_TYPE_RSSI_HIGH:
1138 Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
1139 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1140 Highrssi->rssivalue,
1141 Highrssi->rssifreq,
1142 (event->events & 0x0010)?1:0);
1143 default:
1144 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1145 break;
1146 }
1147 }
1148
1149 kfree(response_buf);
1150
1151 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1152 free_page(addr);
1153 return res;
1154}
1155
1156static ssize_t libertas_highrssi_write(struct file *file,
1157 const char __user *userbuf,
1158 size_t count, loff_t *ppos)
1159{
1160 wlan_private *priv = file->private_data;
1161 wlan_adapter *adapter = priv->adapter;
1162 ssize_t res, buf_size;
1163 int value, freq, subscribed, cmd_len;
1164 struct cmd_ctrl_node *pcmdnode;
1165 struct cmd_ds_command *pcmdptr;
1166 struct cmd_ds_802_11_subscribe_event *event;
1167 struct mrvlietypes_rssithreshold *rssi_threshold;
1168 void *response_buf;
1169 u16 event_bitmap;
1170 u8 *ptr;
1171 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1172 char *buf = (char *)addr;
1173
1174 buf_size = min(count, len - 1);
1175 if (copy_from_user(buf, userbuf, buf_size)) {
1176 res = -EFAULT;
1177 goto out_unlock;
1178 }
1179 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1180 if (res != 3) {
1181 res = -EFAULT;
1182 goto out_unlock;
1183 }
1184
1185 event_bitmap = libertas_get_events_bitmap(priv);
1186
1187 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1188 if (res < 0)
1189 goto out_unlock;
1190
1191 event = &pcmdptr->params.subscribe_event;
1192 event->action = cmd_act_set;
1193 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1194 sizeof(struct cmd_ds_802_11_subscribe_event) +
1195 sizeof(struct mrvlietypes_rssithreshold));
1196 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1197 ptr = (u8*) pcmdptr+cmd_len;
1198 rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
1199 rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
1200 rssi_threshold->header.len = 2;
1201 rssi_threshold->rssivalue = cpu_to_le16(value);
1202 rssi_threshold->rssifreq = cpu_to_le16(freq);
1203 event_bitmap |= subscribed ? 0x0010 : 0x0;
1204 event->events = event_bitmap;
1205
1206 libertas_queue_cmd(adapter, pcmdnode, 1);
1207 wake_up_interruptible(&priv->mainthread.waitq);
1208
1209 /* Sleep until response is generated by FW */
1210 wait_event_interruptible(pcmdnode->cmdwait_q,
1211 pcmdnode->cmdwaitqwoken);
1212
1213 pcmdptr = response_buf;
1214
1215 if (pcmdptr->result) {
1216 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
1217 pcmdptr->result);
1218 kfree(response_buf);
1219 return 0;
1220 }
1221
1222 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
1223 lbs_pr_err("command response incorrect!\n");
1224 kfree(response_buf);
1225 return 0;
1226 }
1227
1228 res = count;
1229out_unlock:
1230 free_page(addr);
1231 return res;
1232}
1233
1234static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
1235 size_t count, loff_t *ppos)
1236{
1237 wlan_private *priv = file->private_data;
1238 wlan_adapter *adapter = priv->adapter;
1239 struct cmd_ctrl_node *pcmdnode;
1240 struct cmd_ds_command *pcmdptr;
1241 struct cmd_ds_802_11_subscribe_event *event;
1242 void *response_buf;
1243 int res, cmd_len;
1244 ssize_t pos = 0;
1245 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1246 char *buf = (char *)addr;
1247
1248 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1249 if (res < 0) {
1250 free_page(addr);
1251 return res;
1252 }
1253
1254 event = &pcmdptr->params.subscribe_event;
1255 event->action = cmd_act_get;
1256 pcmdptr->size =
1257 cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
1258 libertas_queue_cmd(adapter, pcmdnode, 1);
1259 wake_up_interruptible(&priv->mainthread.waitq);
1260
1261 /* Sleep until response is generated by FW */
1262 wait_event_interruptible(pcmdnode->cmdwait_q,
1263 pcmdnode->cmdwaitqwoken);
1264
1265 pcmdptr = response_buf;
1266
1267 if (pcmdptr->result) {
1268 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
1269 pcmdptr->result);
1270 kfree(response_buf);
1271 free_page(addr);
1272 return 0;
1273 }
1274
1275 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
1276 lbs_pr_err("command response incorrect!\n");
1277 kfree(response_buf);
1278 free_page(addr);
1279 return 0;
1280 }
1281
1282 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1283 event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
1284 while (cmd_len < pcmdptr->size) {
1285 struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
1286 switch(header->type) {
1287 struct mrvlietypes_snrthreshold *HighSnr;
1288 case TLV_TYPE_SNR_HIGH:
1289 HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
1290 pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1291 HighSnr->snrvalue,
1292 HighSnr->snrfreq,
1293 (event->events & 0x0020)?1:0);
1294 default:
1295 cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1296 break;
1297 }
1298 }
1299
1300 kfree(response_buf);
1301
1302 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1303 free_page(addr);
1304 return res;
1305}
1306
1307static ssize_t libertas_highsnr_write(struct file *file,
1308 const char __user *userbuf,
1309 size_t count, loff_t *ppos)
1310{
1311 wlan_private *priv = file->private_data;
1312 wlan_adapter *adapter = priv->adapter;
1313 ssize_t res, buf_size;
1314 int value, freq, subscribed, cmd_len;
1315 struct cmd_ctrl_node *pcmdnode;
1316 struct cmd_ds_command *pcmdptr;
1317 struct cmd_ds_802_11_subscribe_event *event;
1318 struct mrvlietypes_snrthreshold *snr_threshold;
1319 void *response_buf;
1320 u16 event_bitmap;
1321 u8 *ptr;
1322 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1323 char *buf = (char *)addr;
1324
1325 buf_size = min(count, len - 1);
1326 if (copy_from_user(buf, userbuf, buf_size)) {
1327 res = -EFAULT;
1328 goto out_unlock;
1329 }
1330 res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1331 if (res != 3) {
1332 res = -EFAULT;
1333 goto out_unlock;
1334 }
1335
1336 event_bitmap = libertas_get_events_bitmap(priv);
1337
1338 res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1339 if (res < 0)
1340 goto out_unlock;
1341
1342 event = &pcmdptr->params.subscribe_event;
1343 event->action = cmd_act_set;
1344 pcmdptr->size = cpu_to_le16(S_DS_GEN +
1345 sizeof(struct cmd_ds_802_11_subscribe_event) +
1346 sizeof(struct mrvlietypes_snrthreshold));
1347 cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1348 ptr = (u8*) pcmdptr+cmd_len;
1349 snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
1350 snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
1351 snr_threshold->header.len = 2;
1352 snr_threshold->snrvalue = cpu_to_le16(value);
1353 snr_threshold->snrfreq = cpu_to_le16(freq);
1354 event_bitmap |= subscribed ? 0x0020 : 0x0;
1355 event->events = event_bitmap;
1356
1357 libertas_queue_cmd(adapter, pcmdnode, 1);
1358 wake_up_interruptible(&priv->mainthread.waitq);
1359
1360 /* Sleep until response is generated by FW */
1361 wait_event_interruptible(pcmdnode->cmdwait_q,
1362 pcmdnode->cmdwaitqwoken);
1363
1364 pcmdptr = response_buf;
1365
1366 if (pcmdptr->result) {
1367 lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
1368 pcmdptr->result);
1369 kfree(response_buf);
1370 free_page(addr);
1371 return 0;
1372 }
1373
1374 if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
1375 lbs_pr_err("command response incorrect!\n");
1376 kfree(response_buf);
1377 free_page(addr);
1378 return 0;
1379 }
1380
1381 res = count;
1382out_unlock:
1383 free_page(addr);
1384 return res;
1385}
1386
1387static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
1388 size_t count, loff_t *ppos)
1389{
1390 wlan_private *priv = file->private_data;
1391 wlan_adapter *adapter = priv->adapter;
1392 struct wlan_offset_value offval;
1393 ssize_t pos = 0;
1394 int ret;
1395 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1396 char *buf = (char *)addr;
1397
1398 offval.offset = priv->mac_offset;
1399 offval.value = 0;
1400
1401 ret = libertas_prepare_and_send_command(priv,
1402 cmd_mac_reg_access, 0,
1403 cmd_option_waitforrsp, 0, &offval);
1404 mdelay(10);
1405 pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
1406 priv->mac_offset, adapter->offsetvalue.value);
1407
1408 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1409 free_page(addr);
1410 return ret;
1411}
1412
1413static ssize_t libertas_rdmac_write(struct file *file,
1414 const char __user *userbuf,
1415 size_t count, loff_t *ppos)
1416{
1417 wlan_private *priv = file->private_data;
1418 ssize_t res, buf_size;
1419 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1420 char *buf = (char *)addr;
1421
1422 buf_size = min(count, len - 1);
1423 if (copy_from_user(buf, userbuf, buf_size)) {
1424 res = -EFAULT;
1425 goto out_unlock;
1426 }
1427 priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
1428 res = count;
1429out_unlock:
1430 free_page(addr);
1431 return res;
1432}
1433
1434static ssize_t libertas_wrmac_write(struct file *file,
1435 const char __user *userbuf,
1436 size_t count, loff_t *ppos)
1437{
1438
1439 wlan_private *priv = file->private_data;
1440 ssize_t res, buf_size;
1441 u32 offset, value;
1442 struct wlan_offset_value offval;
1443 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1444 char *buf = (char *)addr;
1445
1446 buf_size = min(count, len - 1);
1447 if (copy_from_user(buf, userbuf, buf_size)) {
1448 res = -EFAULT;
1449 goto out_unlock;
1450 }
1451 res = sscanf(buf, "%x %x", &offset, &value);
1452 if (res != 2) {
1453 res = -EFAULT;
1454 goto out_unlock;
1455 }
1456
1457 offval.offset = offset;
1458 offval.value = value;
1459 res = libertas_prepare_and_send_command(priv,
1460 cmd_mac_reg_access, 1,
1461 cmd_option_waitforrsp, 0, &offval);
1462 mdelay(10);
1463
1464 res = count;
1465out_unlock:
1466 free_page(addr);
1467 return res;
1468}
1469
1470static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
1471 size_t count, loff_t *ppos)
1472{
1473 wlan_private *priv = file->private_data;
1474 wlan_adapter *adapter = priv->adapter;
1475 struct wlan_offset_value offval;
1476 ssize_t pos = 0;
1477 int ret;
1478 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1479 char *buf = (char *)addr;
1480
1481 offval.offset = priv->bbp_offset;
1482 offval.value = 0;
1483
1484 ret = libertas_prepare_and_send_command(priv,
1485 cmd_bbp_reg_access, 0,
1486 cmd_option_waitforrsp, 0, &offval);
1487 mdelay(10);
1488 pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
1489 priv->bbp_offset, adapter->offsetvalue.value);
1490
1491 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1492 free_page(addr);
1493
1494 return ret;
1495}
1496
1497static ssize_t libertas_rdbbp_write(struct file *file,
1498 const char __user *userbuf,
1499 size_t count, loff_t *ppos)
1500{
1501 wlan_private *priv = file->private_data;
1502 ssize_t res, buf_size;
1503 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1504 char *buf = (char *)addr;
1505
1506 buf_size = min(count, len - 1);
1507 if (copy_from_user(buf, userbuf, buf_size)) {
1508 res = -EFAULT;
1509 goto out_unlock;
1510 }
1511 priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
1512 res = count;
1513out_unlock:
1514 free_page(addr);
1515 return res;
1516}
1517
1518static ssize_t libertas_wrbbp_write(struct file *file,
1519 const char __user *userbuf,
1520 size_t count, loff_t *ppos)
1521{
1522
1523 wlan_private *priv = file->private_data;
1524 ssize_t res, buf_size;
1525 u32 offset, value;
1526 struct wlan_offset_value offval;
1527 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1528 char *buf = (char *)addr;
1529
1530 buf_size = min(count, len - 1);
1531 if (copy_from_user(buf, userbuf, buf_size)) {
1532 res = -EFAULT;
1533 goto out_unlock;
1534 }
1535 res = sscanf(buf, "%x %x", &offset, &value);
1536 if (res != 2) {
1537 res = -EFAULT;
1538 goto out_unlock;
1539 }
1540
1541 offval.offset = offset;
1542 offval.value = value;
1543 res = libertas_prepare_and_send_command(priv,
1544 cmd_bbp_reg_access, 1,
1545 cmd_option_waitforrsp, 0, &offval);
1546 mdelay(10);
1547
1548 res = count;
1549out_unlock:
1550 free_page(addr);
1551 return res;
1552}
1553
1554static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
1555 size_t count, loff_t *ppos)
1556{
1557 wlan_private *priv = file->private_data;
1558 wlan_adapter *adapter = priv->adapter;
1559 struct wlan_offset_value offval;
1560 ssize_t pos = 0;
1561 int ret;
1562 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1563 char *buf = (char *)addr;
1564
1565 offval.offset = priv->rf_offset;
1566 offval.value = 0;
1567
1568 ret = libertas_prepare_and_send_command(priv,
1569 cmd_rf_reg_access, 0,
1570 cmd_option_waitforrsp, 0, &offval);
1571 mdelay(10);
1572 pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
1573 priv->rf_offset, adapter->offsetvalue.value);
1574
1575 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1576 free_page(addr);
1577
1578 return ret;
1579}
1580
1581static ssize_t libertas_rdrf_write(struct file *file,
1582 const char __user *userbuf,
1583 size_t count, loff_t *ppos)
1584{
1585 wlan_private *priv = file->private_data;
1586 ssize_t res, buf_size;
1587 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1588 char *buf = (char *)addr;
1589
1590 buf_size = min(count, len - 1);
1591 if (copy_from_user(buf, userbuf, buf_size)) {
1592 res = -EFAULT;
1593 goto out_unlock;
1594 }
1595 priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
1596 res = count;
1597out_unlock:
1598 free_page(addr);
1599 return res;
1600}
1601
1602static ssize_t libertas_wrrf_write(struct file *file,
1603 const char __user *userbuf,
1604 size_t count, loff_t *ppos)
1605{
1606
1607 wlan_private *priv = file->private_data;
1608 ssize_t res, buf_size;
1609 u32 offset, value;
1610 struct wlan_offset_value offval;
1611 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1612 char *buf = (char *)addr;
1613
1614 buf_size = min(count, len - 1);
1615 if (copy_from_user(buf, userbuf, buf_size)) {
1616 res = -EFAULT;
1617 goto out_unlock;
1618 }
1619 res = sscanf(buf, "%x %x", &offset, &value);
1620 if (res != 2) {
1621 res = -EFAULT;
1622 goto out_unlock;
1623 }
1624
1625 offval.offset = offset;
1626 offval.value = value;
1627 res = libertas_prepare_and_send_command(priv,
1628 cmd_rf_reg_access, 1,
1629 cmd_option_waitforrsp, 0, &offval);
1630 mdelay(10);
1631
1632 res = count;
1633out_unlock:
1634 free_page(addr);
1635 return res;
1636}
1637
1638#define FOPS(fread, fwrite) { \
1639 .owner = THIS_MODULE, \
1640 .open = open_file_generic, \
1641 .read = (fread), \
1642 .write = (fwrite), \
1643}
1644
1645struct libertas_debugfs_files {
1646 char *name;
1647 int perm;
1648 struct file_operations fops;
1649};
1650
1651struct libertas_debugfs_files debugfs_files[] = {
1652 { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
1653 { "getscantable", 0444, FOPS(libertas_getscantable,
1654 write_file_dummy), },
1655 { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
1656 libertas_sleepparams_write), },
1657 { "extscan", 0600, FOPS(NULL, libertas_extscan), },
1658 { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
1659};
1660
1661struct libertas_debugfs_files debugfs_events_files[] = {
1662 {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
1663 libertas_lowrssi_write), },
1664 {"low_snr", 0644, FOPS(libertas_lowsnr_read,
1665 libertas_lowsnr_write), },
1666 {"failure_count", 0644, FOPS(libertas_failcount_read,
1667 libertas_failcount_write), },
1668 {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
1669 libertas_bcnmiss_write), },
1670 {"high_rssi", 0644, FOPS(libertas_highrssi_read,
1671 libertas_highrssi_write), },
1672 {"high_snr", 0644, FOPS(libertas_highsnr_read,
1673 libertas_highsnr_write), },
1674};
1675
1676struct libertas_debugfs_files debugfs_regs_files[] = {
1677 {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
1678 {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
1679 {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
1680 {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
1681 {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
1682 {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
1683};
1684
1685void libertas_debugfs_init(void)
1686{
1687 if (!libertas_dir)
1688 libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
1689
1690 return;
1691}
1692
1693void libertas_debugfs_remove(void)
1694{
1695 if (libertas_dir)
1696 debugfs_remove(libertas_dir);
1697 return;
1698}
1699
1700void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
1701{
1702 int i;
1703 struct libertas_debugfs_files *files;
1704 if (!libertas_dir)
1705 goto exit;
1706
1707 priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
1708 if (!priv->debugfs_dir)
1709 goto exit;
1710
1711 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
1712 files = &debugfs_files[i];
1713 priv->debugfs_files[i] = debugfs_create_file(files->name,
1714 files->perm,
1715 priv->debugfs_dir,
1716 priv,
1717 &files->fops);
1718 }
1719
1720 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
1721 if (!priv->events_dir)
1722 goto exit;
1723
1724 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
1725 files = &debugfs_events_files[i];
1726 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
1727 files->perm,
1728 priv->events_dir,
1729 priv,
1730 &files->fops);
1731 }
1732
1733 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
1734 if (!priv->regs_dir)
1735 goto exit;
1736
1737 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
1738 files = &debugfs_regs_files[i];
1739 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
1740 files->perm,
1741 priv->regs_dir,
1742 priv,
1743 &files->fops);
1744 }
1745
1746#ifdef PROC_DEBUG
1747 libertas_debug_init(priv, dev);
1748#endif
1749exit:
1750 return;
1751}
1752
1753void libertas_debugfs_remove_one(wlan_private *priv)
1754{
1755 int i;
1756
1757 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
1758 debugfs_remove(priv->debugfs_regs_files[i]);
1759
1760 debugfs_remove(priv->regs_dir);
1761
1762 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
1763 debugfs_remove(priv->debugfs_events_files[i]);
1764
1765 debugfs_remove(priv->events_dir);
1766#ifdef PROC_DEBUG
1767 debugfs_remove(priv->debugfs_debug);
1768#endif
1769 for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
1770 debugfs_remove(priv->debugfs_files[i]);
1771}
1772
1773/* debug entry */
1774
1775#define item_size(n) (sizeof ((wlan_adapter *)0)->n)
1776#define item_addr(n) ((u32) &((wlan_adapter *)0)->n)
1777
1778struct debug_data {
1779 char name[32];
1780 u32 size;
1781 u32 addr;
1782};
1783
1784/* To debug any member of wlan_adapter, simply add one line here.
1785 */
1786static struct debug_data items[] = {
1787 {"intcounter", item_size(intcounter), item_addr(intcounter)},
1788 {"psmode", item_size(psmode), item_addr(psmode)},
1789 {"psstate", item_size(psstate), item_addr(psstate)},
1790};
1791
1792static int num_of_items = sizeof(items) / sizeof(items[0]);
1793
1794/**
1795 * @brief convert string to number
1796 *
1797 * @param s pointer to numbered string
1798 * @return converted number from string s
1799 */
1800static int string_to_number(char *s)
1801{
1802 int r = 0;
1803 int base = 0;
1804
1805 if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0))
1806 base = 16;
1807 else
1808 base = 10;
1809
1810 if (base == 16)
1811 s += 2;
1812
1813 for (s = s; *s != 0; s++) {
1814 if ((*s >= 48) && (*s <= 57))
1815 r = (r * base) + (*s - 48);
1816 else if ((*s >= 65) && (*s <= 70))
1817 r = (r * base) + (*s - 55);
1818 else if ((*s >= 97) && (*s <= 102))
1819 r = (r * base) + (*s - 87);
1820 else
1821 break;
1822 }
1823
1824 return r;
1825}
1826
1827/**
1828 * @brief proc read function
1829 *
1830 * @param page pointer to buffer
1831 * @param s read data starting position
1832 * @param off offset
1833 * @param cnt counter
1834 * @param eof end of file flag
1835 * @param data data to output
1836 * @return number of output data
1837 */
1838static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
1839 size_t count, loff_t *ppos)
1840{
1841 int val = 0;
1842 size_t pos = 0;
1843 ssize_t res;
1844 char *p;
1845 int i;
1846 struct debug_data *d;
1847 unsigned long addr = get_zeroed_page(GFP_KERNEL);
1848 char *buf = (char *)addr;
1849
1850 p = buf;
1851
1852 d = (struct debug_data *)file->private_data;
1853
1854 for (i = 0; i < num_of_items; i++) {
1855 if (d[i].size == 1)
1856 val = *((u8 *) d[i].addr);
1857 else if (d[i].size == 2)
1858 val = *((u16 *) d[i].addr);
1859 else if (d[i].size == 4)
1860 val = *((u32 *) d[i].addr);
1861
1862 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
1863 }
1864
1865 res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
1866
1867 free_page(addr);
1868 return res;
1869}
1870
1871/**
1872 * @brief proc write function
1873 *
1874 * @param f file pointer
1875 * @param buf pointer to data buffer
1876 * @param cnt data number to write
1877 * @param data data to write
1878 * @return number of data
1879 */
1880static int wlan_debugfs_write(struct file *f, const char __user *buf,
1881 size_t cnt, loff_t *ppos)
1882{
1883 int r, i;
1884 char *pdata;
1885 char *p;
1886 char *p0;
1887 char *p1;
1888 char *p2;
1889 struct debug_data *d = (struct debug_data *)f->private_data;
1890
1891 pdata = (char *)kmalloc(cnt, GFP_KERNEL);
1892 if (pdata == NULL)
1893 return 0;
1894
1895 if (copy_from_user(pdata, buf, cnt)) {
1896 lbs_pr_debug(1, "Copy from user failed\n");
1897 kfree(pdata);
1898 return 0;
1899 }
1900
1901 p0 = pdata;
1902 for (i = 0; i < num_of_items; i++) {
1903 do {
1904 p = strstr(p0, d[i].name);
1905 if (p == NULL)
1906 break;
1907 p1 = strchr(p, '\n');
1908 if (p1 == NULL)
1909 break;
1910 p0 = p1++;
1911 p2 = strchr(p, '=');
1912 if (!p2)
1913 break;
1914 p2++;
1915 r = string_to_number(p2);
1916 if (d[i].size == 1)
1917 *((u8 *) d[i].addr) = (u8) r;
1918 else if (d[i].size == 2)
1919 *((u16 *) d[i].addr) = (u16) r;
1920 else if (d[i].size == 4)
1921 *((u32 *) d[i].addr) = (u32) r;
1922 break;
1923 } while (1);
1924 }
1925 kfree(pdata);
1926
1927 return cnt;
1928}
1929
1930static struct file_operations libertas_debug_fops = {
1931 .owner = THIS_MODULE,
1932 .open = open_file_generic,
1933 .write = wlan_debugfs_write,
1934 .read = wlan_debugfs_read,
1935};
1936
1937/**
1938 * @brief create debug proc file
1939 *
1940 * @param priv pointer wlan_private
1941 * @param dev pointer net_device
1942 * @return N/A
1943 */
1944void libertas_debug_init(wlan_private * priv, struct net_device *dev)
1945{
1946 int i;
1947
1948 if (!priv->debugfs_dir)
1949 return;
1950
1951 for (i = 0; i < num_of_items; i++)
1952 items[i].addr += (u32) priv->adapter;
1953
1954 priv->debugfs_debug = debugfs_create_file("debug", 0644,
1955 priv->debugfs_dir, &items[0],
1956 &libertas_debug_fops);
1957}
1958
1959/**
1960 * @brief remove proc file
1961 *
1962 * @param priv pointer wlan_private
1963 * @return N/A
1964 */
1965void libertas_debug_remove(wlan_private * priv)
1966{
1967 debugfs_remove(priv->debugfs_debug);
1968}
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644
index 000000000000..880a11b95d26
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -0,0 +1,6 @@
1void libertas_debugfs_init(void);
2void libertas_debugfs_remove(void);
3
4void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
5void libertas_debugfs_remove_one(wlan_private *priv);
6
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644
index 000000000000..606bdd002be7
--- /dev/null
+++ b/drivers/net/wireless/libertas/decl.h
@@ -0,0 +1,83 @@
1/**
2 * This file contains declaration referring to
3 * functions defined in other source files
4 */
5
6#ifndef _WLAN_DECL_H_
7#define _WLAN_DECL_H_
8
9#include "defs.h"
10
11/** Function Prototype Declaration */
12struct wlan_private;
13struct sk_buff;
14struct net_device;
15
16extern char *libertas_fw_name;
17
18void libertas_free_adapter(wlan_private * priv);
19int libertas_set_mac_packet_filter(wlan_private * priv);
20
21int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
22void libertas_send_tx_feedback(wlan_private * priv);
23u8 libertas_check_last_packet_indication(wlan_private * priv);
24
25int libertas_free_cmd_buffer(wlan_private * priv);
26struct cmd_ctrl_node;
27struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
28
29void libertas_set_cmd_ctrl_node(wlan_private * priv,
30 struct cmd_ctrl_node *ptempnode,
31 u32 cmd_oid, u16 wait_option, void *pdata_buf);
32
33int libertas_prepare_and_send_command(wlan_private * priv,
34 u16 cmd_no,
35 u16 cmd_action,
36 u16 wait_option, u32 cmd_oid, void *pdata_buf);
37
38void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
39
40int libertas_allocate_cmd_buffer(wlan_private * priv);
41int libertas_execute_next_command(wlan_private * priv);
42int libertas_process_event(wlan_private * priv);
43void libertas_interrupt(struct net_device *);
44int libertas_set_radio_control(wlan_private * priv);
45u32 libertas_index_to_data_rate(u8 index);
46u8 libertas_data_rate_to_index(u32 rate);
47void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
48
49int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
50
51/** The proc fs interface */
52int libertas_process_rx_command(wlan_private * priv);
53int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
54void libertas_cleanup_and_insert_cmd(wlan_private * priv,
55 struct cmd_ctrl_node *ptempcmd);
56void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
57 struct cmd_ctrl_node *ptempcmd);
58
59int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
60
61int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
62
63void libertas_ps_sleep(wlan_private * priv, int wait_option);
64void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
65void libertas_ps_wakeup(wlan_private * priv, int wait_option);
66
67void libertas_tx_runqueue(wlan_private *priv);
68
69extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
70 wlan_adapter * adapter, u8 band, u16 channel);
71
72extern void libertas_mac_event_disconnected(wlan_private * priv);
73
74void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
75
76int reset_device(wlan_private *priv);
77/* main.c */
78extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
79 int *cfp_no);
80wlan_private *wlan_add_card(void *card);
81int wlan_remove_card(void *card);
82
83#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644
index 000000000000..fb1478c1b87d
--- /dev/null
+++ b/drivers/net/wireless/libertas/defs.h
@@ -0,0 +1,369 @@
1/**
2 * This header file contains global constant/enum definitions,
3 * global variable declaration.
4 */
5#ifndef _WLAN_DEFS_H_
6#define _WLAN_DEFS_H_
7
8#include <linux/spinlock.h>
9
10extern unsigned int libertas_debug;
11
12#define DRV_NAME "usb8xxx"
13
14#define lbs_pr_info(format, args...) \
15 printk(KERN_INFO DRV_NAME": " format, ## args)
16#define lbs_pr_err(format, args...) \
17 printk(KERN_ERR DRV_NAME": " format, ## args)
18#define lbs_pr_alert(format, args...) \
19 printk(KERN_ALERT DRV_NAME": " format, ## args)
20
21#ifdef DEBUG
22#define lbs_pr_debug(level, format, args...) \
23 do { if (libertas_debug >= level) \
24 printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
25#define lbs_dev_dbg(level, device, format, args...) \
26 lbs_pr_debug(level, "%s: " format, \
27 (device)->bus_id , ## args)
28
29static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
30{
31 int i = 0;
32
33 if (!libertas_debug)
34 return;
35
36 printk(KERN_DEBUG "%s: ", prompt);
37 for (i = 1; i <= len; i++) {
38 printk(KERN_DEBUG "%02x ", (u8) * buf);
39 buf++;
40 }
41 printk("\n");
42}
43#else
44#define lbs_pr_debug(level, format, args...) do {} while (0)
45#define lbs_dev_dbg(level, device, format, args...) do {} while (0)
46#define lbs_dbg_hex(x,y,z) do {} while (0)
47#endif
48
49#define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
50 __FUNCTION__, __FILE__, __LINE__)
51#define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
52 __FUNCTION__, __FILE__, __LINE__)
53
54/** Buffer Constants */
55
56/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
57* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
58* driver has more local TxPDs. Each TxPD on the host memory is associated
59* with a Tx control node. The driver maintains 8 RxPD descriptors for
60* station firmware to store Rx packet information.
61*
62* Current version of MAC has a 32x6 multicast address buffer.
63*
64* 802.11b can have up to 14 channels, the driver keeps the
65* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
66*/
67
68#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
69#define MRVDRV_NUM_OF_CMD_BUFFER 10
70#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
71#define MRVDRV_MAX_CHANNEL_SIZE 14
72#define MRVDRV_MAX_BSSID_LIST 64
73#define MRVDRV_ASSOCIATION_TIME_OUT 255
74#define MRVDRV_SNAP_HEADER_LEN 8
75
76#define WLAN_UPLD_SIZE 2312
77#define DEV_NAME_LEN 32
78
79/** Misc constants */
80/* This section defines 802.11 specific contants */
81
82#define MRVDRV_MAX_BSS_DESCRIPTS 16
83#define MRVDRV_MAX_REGION_CODE 6
84
85#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
86#define MRVDRV_MIN_MULTIPLE_DTIM 1
87#define MRVDRV_MAX_MULTIPLE_DTIM 5
88#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
89
90#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
91
92#define MRVDRV_CHANNELS_PER_SCAN 4
93#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
94
95#define MRVDRV_DEBUG_RX_PATH 0x00000001
96#define MRVDRV_DEBUG_TX_PATH 0x00000002
97
98#define MRVDRV_MIN_BEACON_INTERVAL 20
99#define MRVDRV_MAX_BEACON_INTERVAL 1000
100#define MRVDRV_BEACON_INTERVAL 100
101
102/** TxPD status */
103
104/* Station firmware use TxPD status field to report final Tx transmit
105* result, Bit masks are used to present combined situations.
106*/
107
108#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
109#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
110
111/** Tx mesh flag */
112/* Currently we are using normal WDS flag as mesh flag.
113 * TODO: change to proper mesh flag when MAC understands it.
114 */
115#define TxPD_CONTROL_WDS_FRAME (1<<17)
116#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
117
118/** RxPD status */
119
120#define MRVDRV_RXPD_STATUS_OK 0x0001
121
122/** RxPD status - Received packet types */
123/** Rx mesh flag */
124/* Currently we are using normal WDS flag as mesh flag.
125 * TODO: change to proper mesh flag when MAC understands it.
126 */
127#define RxPD_CONTROL_WDS_FRAME (0x40)
128#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
129
130/** RSSI-related defines */
131/* RSSI constants are used to implement 802.11 RSSI threshold
132* indication. if the Rx packet signal got too weak for 5 consecutive
133* times, miniport driver (driver) will report this event to wrapper
134*/
135
136#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
137
138/** RTS/FRAG related defines */
139#define MRVDRV_RTS_MIN_VALUE 0
140#define MRVDRV_RTS_MAX_VALUE 2347
141#define MRVDRV_FRAG_MIN_VALUE 256
142#define MRVDRV_FRAG_MAX_VALUE 2346
143
144/* This is for firmware specific length */
145#define EXTRA_LEN 36
146
147#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
148 (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
149
150#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
151 (ETH_FRAME_LEN + sizeof(struct rxpd) \
152 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
153
154#define CMD_F_HOSTCMD (1 << 0)
155#define FW_CAPINFO_WPA (1 << 0)
156
157/** WPA key LENGTH*/
158#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
159
160#define KEY_LEN_WPA_AES 16
161#define KEY_LEN_WPA_TKIP 32
162#define KEY_LEN_WEP_104 13
163#define KEY_LEN_WEP_40 5
164
165#define RF_ANTENNA_1 0x1
166#define RF_ANTENNA_2 0x2
167#define RF_ANTENNA_AUTO 0xFFFF
168
169#define BAND_B (0x01)
170#define BAND_G (0x02)
171#define ALL_802_11_BANDS (BAND_B | BAND_G)
172
173/** MACRO DEFINITIONS */
174#define CAL_NF(NF) ((s32)(-(s32)(NF)))
175#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
176#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
177
178#define DEFAULT_BCN_AVG_FACTOR 8
179#define DEFAULT_DATA_AVG_FACTOR 8
180#define AVG_SCALE 100
181#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
182 (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
183 ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
184 AVG_SCALE)) / N))
185
186#define B_SUPPORTED_RATES 8
187#define G_SUPPORTED_RATES 14
188
189#define WLAN_SUPPORTED_RATES 14
190
191#define MAX_LEDS 8
192
193#define IS_MESH_FRAME(x) (x->cb[6])
194#define SET_MESH_FRAME(x) (x->cb[6]=1)
195#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
196
197/** Global Variable Declaration */
198typedef struct _wlan_private wlan_private;
199typedef struct _wlan_adapter wlan_adapter;
200extern const char libertas_driver_version[];
201extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
202
203extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES];
204
205extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
206
207extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
208
209extern u8 libertas_adhoc_rates_b[4];
210
211/** ENUM definition*/
212/** SNRNF_TYPE */
213enum SNRNF_TYPE {
214 TYPE_BEACON = 0,
215 TYPE_RXPD,
216 MAX_TYPE_B
217};
218
219/** SNRNF_DATA*/
220enum SNRNF_DATA {
221 TYPE_NOAVG = 0,
222 TYPE_AVG,
223 MAX_TYPE_AVG
224};
225
226/** WLAN_802_11_AUTH_ALG*/
227enum WLAN_802_11_AUTH_ALG {
228 AUTH_ALG_OPEN_SYSTEM = 1,
229 AUTH_ALG_SHARED_KEY = 2,
230 AUTH_ALG_NETWORK_EAP = 8,
231};
232
233/** WLAN_802_1X_AUTH_ALG */
234enum WLAN_802_1X_AUTH_ALG {
235 WLAN_1X_AUTH_ALG_NONE = 1,
236 WLAN_1X_AUTH_ALG_LEAP = 2,
237 WLAN_1X_AUTH_ALG_TLS = 4,
238 WLAN_1X_AUTH_ALG_TTLS = 8,
239 WLAN_1X_AUTH_ALG_MD5 = 16,
240};
241
242/** WLAN_802_11_ENCRYPTION_MODE */
243enum WLAN_802_11_ENCRYPTION_MODE {
244 CIPHER_NONE,
245 CIPHER_WEP40,
246 CIPHER_TKIP,
247 CIPHER_CCMP,
248 CIPHER_WEP104,
249};
250
251/** WLAN_802_11_POWER_MODE */
252enum WLAN_802_11_POWER_MODE {
253 wlan802_11powermodecam,
254 wlan802_11powermodemax_psp,
255 wlan802_11Powermodefast_psp,
256 /*not a real mode, defined as an upper bound */
257 wlan802_11powemodemax
258};
259
260/** PS_STATE */
261enum PS_STATE {
262 PS_STATE_FULL_POWER,
263 PS_STATE_AWAKE,
264 PS_STATE_PRE_SLEEP,
265 PS_STATE_SLEEP
266};
267
268/** DNLD_STATE */
269enum DNLD_STATE {
270 DNLD_RES_RECEIVED,
271 DNLD_DATA_SENT,
272 DNLD_CMD_SENT
273};
274
275/** WLAN_MEDIA_STATE */
276enum WLAN_MEDIA_STATE {
277 libertas_connected,
278 libertas_disconnected
279};
280
281/** WLAN_802_11_PRIVACY_FILTER */
282enum WLAN_802_11_PRIVACY_FILTER {
283 wlan802_11privfilteracceptall,
284 wlan802_11privfilter8021xWEP
285};
286
287/** mv_ms_type */
288enum mv_ms_type {
289 MVMS_DAT = 0,
290 MVMS_CMD = 1,
291 MVMS_TXDONE = 2,
292 MVMS_EVENT
293};
294
295/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
296enum WLAN_802_11_NETWORK_INFRASTRUCTURE {
297 wlan802_11ibss,
298 wlan802_11infrastructure,
299 wlan802_11autounknown,
300 /*defined as upper bound */
301 wlan802_11infrastructuremax
302};
303
304/** WLAN_802_11_AUTHENTICATION_MODE */
305enum WLAN_802_11_AUTHENTICATION_MODE {
306 wlan802_11authmodeopen = 0x00,
307 wlan802_11authmodeshared = 0x01,
308 wlan802_11authmodenetworkEAP = 0x80,
309};
310
311/** WLAN_802_11_WEP_STATUS */
312enum WLAN_802_11_WEP_STATUS {
313 wlan802_11WEPenabled,
314 wlan802_11WEPdisabled,
315};
316
317/** SNMP_MIB_INDEX_e */
318enum SNMP_MIB_INDEX_e {
319 desired_bsstype_i = 0,
320 op_rateset_i,
321 bcnperiod_i,
322 dtimperiod_i,
323 assocrsp_timeout_i,
324 rtsthresh_i,
325 short_retrylim_i,
326 long_retrylim_i,
327 fragthresh_i,
328 dot11d_i,
329 dot11h_i,
330 manufid_i,
331 prodID_i,
332 manuf_oui_i,
333 manuf_name_i,
334 manuf_prodname_i,
335 manuf_prodver_i,
336};
337
338/** KEY_TYPE_ID */
339enum KEY_TYPE_ID {
340 KEY_TYPE_ID_WEP = 0,
341 KEY_TYPE_ID_TKIP,
342 KEY_TYPE_ID_AES
343};
344
345/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
346enum KEY_INFO_WPA {
347 KEY_INFO_WPA_MCAST = 0x01,
348 KEY_INFO_WPA_UNICAST = 0x02,
349 KEY_INFO_WPA_ENABLED = 0x04
350};
351
352/** SNMP_MIB_VALUE_e */
353enum SNMP_MIB_VALUE_e {
354 SNMP_MIB_VALUE_INFRA = 1,
355 SNMP_MIB_VALUE_ADHOC
356};
357
358/* Default values for fwt commands. */
359#define FWT_DEFAULT_METRIC 0
360#define FWT_DEFAULT_DIR 1
361#define FWT_DEFAULT_SSN 0xffffffff
362#define FWT_DEFAULT_DSN 0
363#define FWT_DEFAULT_HOPCOUNT 0
364#define FWT_DEFAULT_TTL 0
365#define FWT_DEFAULT_EXPIRATION 0
366#define FWT_DEFAULT_SLEEPMODE 0
367#define FWT_DEFAULT_SNR 0
368
369#endif /* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644
index 000000000000..b1f876f9693b
--- /dev/null
+++ b/drivers/net/wireless/libertas/dev.h
@@ -0,0 +1,403 @@
1/**
2 * This file contains definitions and data structures specific
3 * to Marvell 802.11 NIC. It contains the Device Information
4 * structure wlan_adapter.
5 */
6#ifndef _WLAN_DEV_H_
7#define _WLAN_DEV_H_
8
9#include <linux/netdevice.h>
10#include <linux/wireless.h>
11#include <linux/ethtool.h>
12#include <linux/debugfs.h>
13
14#include "defs.h"
15#include "scan.h"
16#include "thread.h"
17
18extern struct ethtool_ops libertas_ethtool_ops;
19
20#define MAX_BSSID_PER_CHANNEL 16
21
22#define NR_TX_QUEUE 3
23
24/* For the extended Scan */
25#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
26 MRVDRV_MAX_CHANNEL_SIZE + 1
27
28#define MAX_REGION_CHANNEL_NUM 2
29
30/** Chan-freq-TxPower mapping table*/
31struct chan_freq_power {
32 /** channel Number */
33 u16 channel;
34 /** frequency of this channel */
35 u32 freq;
36 /** Max allowed Tx power level */
37 u16 maxtxpower;
38 /** TRUE:channel unsupported; FLASE:supported*/
39 u8 unsupported;
40};
41
42/** region-band mapping table*/
43struct region_channel {
44 /** TRUE if this entry is valid */
45 u8 valid;
46 /** region code for US, Japan ... */
47 u8 region;
48 /** band B/G/A, used for BAND_CONFIG cmd */
49 u8 band;
50 /** Actual No. of elements in the array below */
51 u8 nrcfp;
52 /** chan-freq-txpower mapping table*/
53 struct chan_freq_power *CFP;
54};
55
56struct wlan_802_11_security {
57 u8 WPAenabled;
58 u8 WPA2enabled;
59 enum WLAN_802_11_WEP_STATUS WEPstatus;
60 enum WLAN_802_11_AUTHENTICATION_MODE authmode;
61 enum WLAN_802_1X_AUTH_ALG auth1xalg;
62 enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode;
63};
64
65/** Current Basic Service Set State Structure */
66struct current_bss_params {
67 struct bss_descriptor bssdescriptor;
68 /** bssid */
69 u8 bssid[ETH_ALEN];
70 /** ssid */
71 struct WLAN_802_11_SSID ssid;
72
73 /** band */
74 u8 band;
75 /** channel */
76 u8 channel;
77 /** number of rates supported */
78 int numofrates;
79 /** supported rates*/
80 u8 datarates[WLAN_SUPPORTED_RATES];
81};
82
83/** sleep_params */
84struct sleep_params {
85 u16 sp_error;
86 u16 sp_offset;
87 u16 sp_stabletime;
88 u8 sp_calcontrol;
89 u8 sp_extsleepclk;
90 u16 sp_reserved;
91};
92
93/** Data structure for the Marvell WLAN device */
94typedef struct _wlan_dev {
95 /** device name */
96 char name[DEV_NAME_LEN];
97 /** card pointer */
98 void *card;
99 /** IO port */
100 u32 ioport;
101 /** Upload received */
102 u32 upld_rcv;
103 /** Upload type */
104 u32 upld_typ;
105 /** Upload length */
106 u32 upld_len;
107 /** netdev pointer */
108 struct net_device *netdev;
109 /* Upload buffer */
110 u8 upld_buf[WLAN_UPLD_SIZE];
111 /* Download sent:
112 bit0 1/0=data_sent/data_tx_done,
113 bit1 1/0=cmd_sent/cmd_tx_done,
114 all other bits reserved 0 */
115 u8 dnld_sent;
116} wlan_dev_t, *pwlan_dev_t;
117
118/* Mesh statistics */
119struct wlan_mesh_stats {
120 u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
121 u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
122 u32 fwd_drop_ttl; /* Fwd: TTL zero */
123 u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
124 u32 fwd_drop_noroute; /* Fwd: No route to Destination */
125 u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
126 u32 drop_blind; /* Rx: Dropped by blinding table */
127};
128
129/** Private structure for the MV device */
130struct _wlan_private {
131 int open;
132 int mesh_open;
133 int infra_open;
134
135 wlan_adapter *adapter;
136 wlan_dev_t wlan_dev;
137
138 struct net_device_stats stats;
139 struct net_device *mesh_dev ; /* Virtual device */
140
141 struct iw_statistics wstats;
142 struct wlan_mesh_stats mstats;
143 struct dentry *debugfs_dir;
144 struct dentry *debugfs_debug;
145 struct dentry *debugfs_files[6];
146
147 struct dentry *events_dir;
148 struct dentry *debugfs_events_files[6];
149
150 struct dentry *regs_dir;
151 struct dentry *debugfs_regs_files[6];
152
153 u32 mac_offset;
154 u32 bbp_offset;
155 u32 rf_offset;
156
157 const struct firmware *firmware;
158 struct device *hotplug_device;
159
160 /** thread to service interrupts */
161 struct wlan_thread mainthread;
162
163 struct delayed_work assoc_work;
164 struct workqueue_struct *assoc_thread;
165};
166
167/** Association request
168 *
169 * Encapsulates all the options that describe a specific assocation request
170 * or configuration of the wireless card's radio, mode, and security settings.
171 */
172struct assoc_request {
173#define ASSOC_FLAG_SSID 1
174#define ASSOC_FLAG_CHANNEL 2
175#define ASSOC_FLAG_MODE 3
176#define ASSOC_FLAG_BSSID 4
177#define ASSOC_FLAG_WEP_KEYS 5
178#define ASSOC_FLAG_WEP_TX_KEYIDX 6
179#define ASSOC_FLAG_WPA_MCAST_KEY 7
180#define ASSOC_FLAG_WPA_UCAST_KEY 8
181#define ASSOC_FLAG_SECINFO 9
182#define ASSOC_FLAG_WPA_IE 10
183 unsigned long flags;
184
185 struct WLAN_802_11_SSID ssid;
186 u8 channel;
187 enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
188 u8 bssid[ETH_ALEN];
189
190 /** WEP keys */
191 struct WLAN_802_11_KEY wep_keys[4];
192 u16 wep_tx_keyidx;
193
194 /** WPA keys */
195 struct WLAN_802_11_KEY wpa_mcast_key;
196 struct WLAN_802_11_KEY wpa_unicast_key;
197
198 struct wlan_802_11_security secinfo;
199
200 /** WPA Information Elements*/
201#define MAX_WPA_IE_LEN 64
202 u8 wpa_ie[MAX_WPA_IE_LEN];
203 u8 wpa_ie_len;
204};
205
206/** Wlan adapter data structure*/
207struct _wlan_adapter {
208 /** STATUS variables */
209 u32 fwreleasenumber;
210 u32 fwcapinfo;
211 /* protected with big lock */
212
213 struct mutex lock;
214
215 u8 tmptxbuf[WLAN_UPLD_SIZE];
216 /* protected by hard_start_xmit serialization */
217
218 /** command-related variables */
219 u16 seqnum;
220 /* protected by big lock */
221
222 struct cmd_ctrl_node *cmd_array;
223 /** Current command */
224 struct cmd_ctrl_node *cur_cmd;
225 int cur_cmd_retcode;
226 /** command Queues */
227 /** Free command buffers */
228 struct list_head cmdfreeq;
229 /** Pending command buffers */
230 struct list_head cmdpendingq;
231
232 wait_queue_head_t cmd_pending;
233 u8 nr_cmd_pending;
234 /* command related variables protected by adapter->driver_lock */
235
236 /** Async and Sync Event variables */
237 u32 intcounter;
238 u32 eventcause;
239 u8 nodename[16]; /* nickname */
240
241 /** spin locks */
242 spinlock_t driver_lock;
243
244 /** Timers */
245 struct timer_list command_timer;
246
247 /* TX queue used in PS mode */
248 spinlock_t txqueue_lock;
249 struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
250 unsigned int tx_queue_idx;
251
252 u8 hisregcpy;
253
254 /** current ssid/bssid related parameters*/
255 struct current_bss_params curbssparams;
256
257 enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
258
259 struct bss_descriptor *pattemptedbssdesc;
260
261 struct WLAN_802_11_SSID previousssid;
262 u8 previousbssid[ETH_ALEN];
263
264 struct bss_descriptor *scantable;
265 u32 numinscantable;
266
267 u8 scantype;
268 u32 scanmode;
269
270 u16 beaconperiod;
271 u8 adhoccreate;
272
273 /** capability Info used in Association, start, join */
274 struct ieeetypes_capinfo capinfo;
275
276 /** MAC address information */
277 u8 current_addr[ETH_ALEN];
278 u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
279 u32 nr_of_multicastmacaddr;
280
281 /** 802.11 statistics */
282// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
283
284 u16 enablehwauto;
285 u16 ratebitmap;
286 /** control G rates */
287 u8 adhoc_grate_enabled;
288
289 u32 txantenna;
290 u32 rxantenna;
291
292 u8 adhocchannel;
293 u32 fragthsd;
294 u32 rtsthsd;
295
296 u32 datarate;
297 u8 is_datarate_auto;
298
299 u16 listeninterval;
300 u16 prescan;
301 u8 txretrycount;
302
303 /** Tx-related variables (for single packet tx) */
304 struct sk_buff *currenttxskb;
305 u16 TxLockFlag;
306
307 /** NIC Operation characteristics */
308 u16 currentpacketfilter;
309 u32 connect_status;
310 u16 regioncode;
311 u16 regiontableindex;
312 u16 txpowerlevel;
313
314 /** POWER MANAGEMENT AND PnP SUPPORT */
315 u8 surpriseremoved;
316 u16 atimwindow;
317
318 u16 psmode; /* Wlan802_11PowermodeCAM=disable
319 Wlan802_11PowermodeMAX_PSP=enable */
320 u16 multipledtim;
321 u32 psstate;
322 u8 needtowakeup;
323
324 struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
325 u16 locallisteninterval;
326 u16 nullpktinterval;
327
328 struct assoc_request * assoc_req;
329
330 /** Encryption parameter */
331 struct wlan_802_11_security secinfo;
332
333 /** WEP keys */
334 struct WLAN_802_11_KEY wep_keys[4];
335 u16 wep_tx_keyidx;
336
337 /** WPA keys */
338 struct WLAN_802_11_KEY wpa_mcast_key;
339 struct WLAN_802_11_KEY wpa_unicast_key;
340
341 /** WPA Information Elements*/
342#define MAX_WPA_IE_LEN 64
343 u8 wpa_ie[MAX_WPA_IE_LEN];
344 u8 wpa_ie_len;
345
346 u16 rxantennamode;
347 u16 txantennamode;
348
349 /** Requested Signal Strength*/
350 u16 bcn_avg_factor;
351 u16 data_avg_factor;
352 u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
353 u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
354 u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
355 u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
356 u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
357 u16 nextSNRNF;
358 u16 numSNRNF;
359 u16 rxpd_rate;
360
361 u8 radioon;
362 u32 preamble;
363
364 /** Multi bands Parameter*/
365 u8 libertas_supported_rates[G_SUPPORTED_RATES];
366
367 /** Blue Tooth Co-existence Arbitration */
368
369 /** sleep_params */
370 struct sleep_params sp;
371
372 /** RF calibration data */
373
374#define MAX_REGION_CHANNEL_NUM 2
375 /** region channel data */
376 struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
377
378 struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
379
380 /** 11D and Domain Regulatory Data */
381 struct wlan_802_11d_domain_reg domainreg;
382 struct parsed_region_chan_11d parsed_region_chan;
383
384 /** FSM variable for 11d support */
385 u32 enable11d;
386
387 /** MISCELLANEOUS */
388 u8 *prdeeprom;
389 struct wlan_offset_value offsetvalue;
390
391 struct cmd_ds_802_11_get_log logmsg;
392 u16 scanprobes;
393
394 u32 pkttxctrl;
395
396 u16 txrate;
397 u32 linkmode;
398 u32 radiomode;
399 u32 debugmode;
400 u8 fw_ready;
401};
402
403#endif /* _WLAN_DEV_H_ */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644
index 000000000000..0064de542963
--- /dev/null
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -0,0 +1,184 @@
1
2#include <linux/netdevice.h>
3#include <linux/ethtool.h>
4#include <linux/delay.h>
5
6#include "host.h"
7#include "sbi.h"
8#include "decl.h"
9#include "defs.h"
10#include "dev.h"
11#include "join.h"
12#include "wext.h"
13static const char * mesh_stat_strings[]= {
14 "drop_duplicate_bcast",
15 "drop_ttl_zero",
16 "drop_no_fwd_route",
17 "drop_no_buffers",
18 "fwded_unicast_cnt",
19 "fwded_bcast_cnt",
20 "drop_blind_table"
21};
22
23static void libertas_ethtool_get_drvinfo(struct net_device *dev,
24 struct ethtool_drvinfo *info)
25{
26 wlan_private *priv = (wlan_private *) dev->priv;
27 char fwver[32];
28
29 libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
30
31 strcpy(info->driver, "libertas");
32 strcpy(info->version, libertas_driver_version);
33 strcpy(info->fw_version, fwver);
34}
35
36/* All 8388 parts have 16KiB EEPROM size at the time of writing.
37 * In case that changes this needs fixing.
38 */
39#define LIBERTAS_EEPROM_LEN 16384
40
41static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
42{
43 return LIBERTAS_EEPROM_LEN;
44}
45
46static int libertas_ethtool_get_eeprom(struct net_device *dev,
47 struct ethtool_eeprom *eeprom, u8 * bytes)
48{
49 wlan_private *priv = (wlan_private *) dev->priv;
50 wlan_adapter *adapter = priv->adapter;
51 struct wlan_ioctl_regrdwr regctrl;
52 char *ptr;
53 int ret;
54
55 regctrl.action = 0;
56 regctrl.offset = eeprom->offset;
57 regctrl.NOB = eeprom->len;
58
59 if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
60 return -EINVAL;
61
62// mutex_lock(&priv->mutex);
63
64 adapter->prdeeprom =
65 (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
66 if (!adapter->prdeeprom)
67 return -ENOMEM;
68 memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
69
70 /* +14 is for action, offset, and NOB in
71 * response */
72 lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
73 regctrl.action, regctrl.offset, regctrl.NOB);
74
75 ret = libertas_prepare_and_send_command(priv,
76 cmd_802_11_eeprom_access,
77 regctrl.action,
78 cmd_option_waitforrsp, 0,
79 &regctrl);
80
81 if (ret) {
82 if (adapter->prdeeprom)
83 kfree(adapter->prdeeprom);
84 LEAVE();
85 return ret;
86 }
87
88 mdelay(10);
89
90 ptr = (char *)adapter->prdeeprom;
91
92 /* skip the command header, but include the "value" u32 variable */
93 ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
94
95 /*
96 * Return the result back to the user
97 */
98 memcpy(bytes, ptr, eeprom->len);
99
100 if (adapter->prdeeprom)
101 kfree(adapter->prdeeprom);
102// mutex_unlock(&priv->mutex);
103
104 return 0;
105}
106
107static void libertas_ethtool_get_stats(struct net_device * dev,
108 struct ethtool_stats * stats, u64 * data)
109{
110 wlan_private *priv = dev->priv;
111
112 ENTER();
113
114 stats->cmd = ETHTOOL_GSTATS;
115 BUG_ON(stats->n_stats != MESH_STATS_NUM);
116
117 data[0] = priv->mstats.fwd_drop_rbt;
118 data[1] = priv->mstats.fwd_drop_ttl;
119 data[2] = priv->mstats.fwd_drop_noroute;
120 data[3] = priv->mstats.fwd_drop_nobuf;
121 data[4] = priv->mstats.fwd_unicast_cnt;
122 data[5] = priv->mstats.fwd_bcast_cnt;
123 data[6] = priv->mstats.drop_blind;
124
125 LEAVE();
126}
127
128static int libertas_ethtool_get_stats_count(struct net_device * dev)
129{
130 int ret;
131 wlan_private *priv = dev->priv;
132 struct cmd_ds_mesh_access mesh_access;
133
134 ENTER();
135 /* Get Mesh Statistics */
136 ret = libertas_prepare_and_send_command(priv,
137 cmd_mesh_access, cmd_act_mesh_get_stats,
138 cmd_option_waitforrsp, 0, &mesh_access);
139
140 if (ret) {
141 LEAVE();
142 return 0;
143 }
144
145 priv->mstats.fwd_drop_rbt = mesh_access.data[0];
146 priv->mstats.fwd_drop_ttl = mesh_access.data[1];
147 priv->mstats.fwd_drop_noroute = mesh_access.data[2];
148 priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
149 priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
150 priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
151 priv->mstats.drop_blind = mesh_access.data[6];
152
153 LEAVE();
154 return MESH_STATS_NUM;
155}
156
157static void libertas_ethtool_get_strings (struct net_device * dev,
158 u32 stringset,
159 u8 * s)
160{
161 int i;
162
163 ENTER();
164 switch (stringset) {
165 case ETH_SS_STATS:
166 for (i=0; i < MESH_STATS_NUM; i++) {
167 memcpy(s + i * ETH_GSTRING_LEN,
168 mesh_stat_strings[i],
169 ETH_GSTRING_LEN);
170 }
171 break;
172 }
173 LEAVE();
174}
175
176struct ethtool_ops libertas_ethtool_ops = {
177 .get_drvinfo = libertas_ethtool_get_drvinfo,
178 .get_eeprom = libertas_ethtool_get_eeprom,
179 .get_eeprom_len = libertas_ethtool_get_eeprom_len,
180 .get_stats_count = libertas_ethtool_get_stats_count,
181 .get_ethtool_stats = libertas_ethtool_get_stats,
182 .get_strings = libertas_ethtool_get_strings,
183};
184
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644
index 000000000000..b194a4570791
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.c
@@ -0,0 +1,361 @@
1/**
2 * This file contains the initialization for FW and HW
3 */
4#include <linux/module.h>
5#include <linux/moduleparam.h>
6
7#include <linux/vmalloc.h>
8#include <linux/firmware.h>
9#include <linux/version.h>
10
11#include "host.h"
12#include "sbi.h"
13#include "defs.h"
14#include "decl.h"
15#include "dev.h"
16#include "fw.h"
17#include "wext.h"
18#include "if_usb.h"
19
20char *libertas_fw_name = NULL;
21module_param_named(fw_name, libertas_fw_name, charp, 0644);
22
23unsigned int libertas_debug = 0;
24module_param(libertas_debug, int, 0);
25
26/**
27 * @brief This function checks the validity of Boot2/FW image.
28 *
29 * @param data pointer to image
30 * len image length
31 * @return 0 or -1
32 */
33static int check_fwfile_format(u8 *data, u32 totlen)
34{
35 u8 bincmd, exit;
36 u32 blksize, offset, len;
37 int ret;
38
39 ret = 1;
40 exit = len = 0;
41
42 do {
43 bincmd = *data;
44 blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
45 switch (bincmd) {
46 case FW_HAS_DATA_TO_RECV:
47 offset = sizeof(struct fwheader) + blksize;
48 data += offset;
49 len += offset;
50 if (len >= totlen)
51 exit = 1;
52 break;
53 case FW_HAS_LAST_BLOCK:
54 exit = 1;
55 ret = 0;
56 break;
57 default:
58 exit = 1;
59 break;
60 }
61 } while (!exit);
62
63 if (ret)
64 lbs_pr_err("bin file format check FAIL...\n");
65 else
66 lbs_pr_debug(1, "bin file format check PASS...\n");
67
68 return ret;
69}
70
71/**
72 * @brief This function downloads firmware image, gets
73 * HW spec from firmware and set basic parameters to
74 * firmware.
75 *
76 * @param priv A pointer to wlan_private structure
77 * @return 0 or -1
78 */
79static int wlan_setup_station_hw(wlan_private * priv)
80{
81 int ret = -1;
82 wlan_adapter *adapter = priv->adapter;
83
84 ENTER();
85
86 if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
87 priv->hotplug_device)) < 0) {
88 lbs_pr_err("request_firmware() failed, error code = %#x\n",
89 ret);
90 lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
91 goto done;
92 }
93
94 if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
95 release_firmware(priv->firmware);
96 goto done;
97 }
98
99 ret = libertas_sbi_prog_firmware(priv);
100
101 release_firmware(priv->firmware);
102
103 if (ret) {
104 lbs_pr_debug(1, "Bootloader in invalid state!\n");
105 ret = -1;
106 goto done;
107 }
108
109 /*
110 * Read MAC address from HW
111 */
112 memset(adapter->current_addr, 0xff, ETH_ALEN);
113
114 ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
115 0, cmd_option_waitforrsp, 0, NULL);
116
117 if (ret) {
118 ret = -1;
119 goto done;
120 }
121
122 libertas_set_mac_packet_filter(priv);
123
124 /* Get the supported Data rates */
125 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
126 cmd_act_get_tx_rate,
127 cmd_option_waitforrsp, 0, NULL);
128
129 if (ret) {
130 ret = -1;
131 goto done;
132 }
133
134 ret = 0;
135done:
136 LEAVE();
137
138 return (ret);
139}
140
141static int wlan_allocate_adapter(wlan_private * priv)
142{
143 u32 ulbufsize;
144 wlan_adapter *adapter = priv->adapter;
145
146 struct bss_descriptor *ptempscantable;
147
148 /* Allocate buffer to store the BSSID list */
149 ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST;
150 if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) {
151 libertas_free_adapter(priv);
152 return -1;
153 }
154
155 adapter->scantable = ptempscantable;
156 memset(adapter->scantable, 0, ulbufsize);
157
158 /* Allocate the command buffers */
159 libertas_allocate_cmd_buffer(priv);
160
161 memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
162 adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
163 adapter->libertas_ps_confirm_sleep.command =
164 cpu_to_le16(cmd_802_11_ps_mode);
165 adapter->libertas_ps_confirm_sleep.size =
166 cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
167 adapter->libertas_ps_confirm_sleep.result = 0;
168 adapter->libertas_ps_confirm_sleep.action =
169 cpu_to_le16(cmd_subcmd_sleep_confirmed);
170
171 return 0;
172}
173
174static void wlan_init_adapter(wlan_private * priv)
175{
176 wlan_adapter *adapter = priv->adapter;
177 int i;
178
179 adapter->scanprobes = 0;
180
181 adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
182 adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
183
184 /* ATIM params */
185 adapter->atimwindow = 0;
186
187 adapter->connect_status = libertas_disconnected;
188 memset(adapter->current_addr, 0xff, ETH_ALEN);
189
190 /* scan type */
191 adapter->scantype = cmd_scan_type_active;
192
193 /* scan mode */
194 adapter->scanmode = cmd_bss_type_any;
195
196 /* 802.11 specific */
197 adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
198 for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
199 i++)
200 memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
201 adapter->wep_tx_keyidx = 0;
202 adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
203 adapter->secinfo.authmode = wlan802_11authmodeopen;
204 adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
205 adapter->secinfo.Encryptionmode = CIPHER_NONE;
206 adapter->inframode = wlan802_11infrastructure;
207
208 adapter->assoc_req = NULL;
209
210 adapter->numinscantable = 0;
211 adapter->pattemptedbssdesc = NULL;
212 mutex_init(&adapter->lock);
213
214 adapter->prescan = 1;
215
216 memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
217
218 /* PnP and power profile */
219 adapter->surpriseremoved = 0;
220
221 adapter->currentpacketfilter =
222 cmd_act_mac_rx_on | cmd_act_mac_tx_on;
223
224 adapter->radioon = RADIO_ON;
225 adapter->txantenna = RF_ANTENNA_2;
226 adapter->rxantenna = RF_ANTENNA_AUTO;
227
228 adapter->is_datarate_auto = 1;
229 adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
230
231 // set default value of capinfo.
232#define SHORT_PREAMBLE_ALLOWED 1
233 memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
234 adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
235
236 adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
237
238 adapter->psmode = wlan802_11powermodecam;
239 adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
240
241 adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
242
243 adapter->psstate = PS_STATE_FULL_POWER;
244 adapter->needtowakeup = 0;
245 adapter->locallisteninterval = 0; /* default value in firmware will be used */
246
247 adapter->datarate = 0; // Initially indicate the rate as auto
248
249 adapter->adhoc_grate_enabled = 0;
250
251 adapter->intcounter = 0;
252
253 adapter->currenttxskb = NULL;
254 adapter->pkttxctrl = 0;
255
256 memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
257 adapter->tx_queue_idx = 0;
258 spin_lock_init(&adapter->txqueue_lock);
259
260 return;
261}
262
263static void command_timer_fn(unsigned long data);
264
265int libertas_init_fw(wlan_private * priv)
266{
267 int ret = -1;
268 wlan_adapter *adapter = priv->adapter;
269
270 ENTER();
271
272 /* Allocate adapter structure */
273 if ((ret = wlan_allocate_adapter(priv)) != 0)
274 goto done;
275
276 /* init adapter structure */
277 wlan_init_adapter(priv);
278
279 /* init timer etc. */
280 setup_timer(&adapter->command_timer, command_timer_fn,
281 (unsigned long)priv);
282
283 /* download fimrware etc. */
284 if ((ret = wlan_setup_station_hw(priv)) != 0) {
285 del_timer_sync(&adapter->command_timer);
286 goto done;
287 }
288
289 /* init 802.11d */
290 libertas_init_11d(priv);
291
292 ret = 0;
293done:
294 LEAVE();
295 return ret;
296}
297
298void libertas_free_adapter(wlan_private * priv)
299{
300 wlan_adapter *adapter = priv->adapter;
301
302 if (!adapter) {
303 lbs_pr_debug(1, "Why double free adapter?:)\n");
304 return;
305 }
306
307 lbs_pr_debug(1, "Free command buffer\n");
308 libertas_free_cmd_buffer(priv);
309
310 lbs_pr_debug(1, "Free commandTimer\n");
311 del_timer(&adapter->command_timer);
312
313 lbs_pr_debug(1, "Free scantable\n");
314 if (adapter->scantable) {
315 kfree(adapter->scantable);
316 adapter->scantable = NULL;
317 }
318
319 lbs_pr_debug(1, "Free adapter\n");
320
321 /* Free the adapter object itself */
322 kfree(adapter);
323 priv->adapter = NULL;
324}
325
326/**
327 * This function handles the timeout of command sending.
328 * It will re-send the same command again.
329 */
330static void command_timer_fn(unsigned long data)
331{
332 wlan_private *priv = (wlan_private *)data;
333 wlan_adapter *adapter = priv->adapter;
334 struct cmd_ctrl_node *ptempnode;
335 struct cmd_ds_command *cmd;
336 unsigned long flags;
337
338 ptempnode = adapter->cur_cmd;
339 cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
340
341 lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
342
343 if (!adapter->fw_ready)
344 return;
345
346 if (ptempnode == NULL) {
347 lbs_pr_debug(1, "PTempnode Empty\n");
348 return;
349 }
350
351 spin_lock_irqsave(&adapter->driver_lock, flags);
352 adapter->cur_cmd = NULL;
353 spin_unlock_irqrestore(&adapter->driver_lock, flags);
354
355 lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
356 libertas_queue_cmd(adapter, ptempnode, 0);
357
358 wake_up_interruptible(&priv->mainthread.waitq);
359
360 return;
361}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644
index 000000000000..1f9ae267a9e0
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.h
@@ -0,0 +1,13 @@
1/**
2 * This header file contains FW interface related definitions.
3 */
4#ifndef _WLAN_FW_H_
5#define _WLAN_FW_H_
6
7#ifndef DEV_NAME_LEN
8#define DEV_NAME_LEN 32
9#endif
10
11int libertas_init_fw(wlan_private * priv);
12
13#endif /* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644
index 000000000000..c0faaecaf5be
--- /dev/null
+++ b/drivers/net/wireless/libertas/host.h
@@ -0,0 +1,338 @@
1/**
2 * This file contains definitions of WLAN commands.
3 */
4
5#ifndef _HOST_H_
6#define _HOST_H_
7
8/** PUBLIC DEFINITIONS */
9#define DEFAULT_AD_HOC_CHANNEL 6
10#define DEFAULT_AD_HOC_CHANNEL_A 36
11
12/** IEEE 802.11 oids */
13#define OID_802_11_SSID 0x00008002
14#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
15#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
16#define OID_802_11_RTS_THRESHOLD 0x0000800A
17#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
18#define OID_802_11_SUPPORTED_RATES 0x0000800E
19#define OID_802_11_STATISTICS 0x00008012
20#define OID_802_11_TX_RETRYCOUNT 0x0000801D
21#define OID_802_11D_ENABLE 0x00008020
22
23#define cmd_option_waitforrsp 0x0002
24
25/** Host command ID */
26#define cmd_code_dnld 0x0002
27#define cmd_get_hw_spec 0x0003
28#define cmd_eeprom_update 0x0004
29#define cmd_802_11_reset 0x0005
30#define cmd_802_11_scan 0x0006
31#define cmd_802_11_get_log 0x000b
32#define cmd_mac_multicast_adr 0x0010
33#define cmd_802_11_authenticate 0x0011
34#define cmd_802_11_eeprom_access 0x0059
35#define cmd_802_11_associate 0x0050
36#define cmd_802_11_set_wep 0x0013
37#define cmd_802_11_get_stat 0x0014
38#define cmd_802_3_get_stat 0x0015
39#define cmd_802_11_snmp_mib 0x0016
40#define cmd_mac_reg_map 0x0017
41#define cmd_bbp_reg_map 0x0018
42#define cmd_mac_reg_access 0x0019
43#define cmd_bbp_reg_access 0x001a
44#define cmd_rf_reg_access 0x001b
45#define cmd_802_11_radio_control 0x001c
46#define cmd_802_11_rf_channel 0x001d
47#define cmd_802_11_rf_tx_power 0x001e
48#define cmd_802_11_rssi 0x001f
49#define cmd_802_11_rf_antenna 0x0020
50
51#define cmd_802_11_ps_mode 0x0021
52
53#define cmd_802_11_data_rate 0x0022
54#define cmd_rf_reg_map 0x0023
55#define cmd_802_11_deauthenticate 0x0024
56#define cmd_802_11_reassociate 0x0025
57#define cmd_802_11_disassociate 0x0026
58#define cmd_mac_control 0x0028
59#define cmd_802_11_ad_hoc_start 0x002b
60#define cmd_802_11_ad_hoc_join 0x002c
61
62#define cmd_802_11_query_tkip_reply_cntrs 0x002e
63#define cmd_802_11_enable_rsn 0x002f
64#define cmd_802_11_pairwise_tsc 0x0036
65#define cmd_802_11_group_tsc 0x0037
66#define cmd_802_11_key_material 0x005e
67
68#define cmd_802_11_set_afc 0x003c
69#define cmd_802_11_get_afc 0x003d
70
71#define cmd_802_11_ad_hoc_stop 0x0040
72
73#define cmd_802_11_beacon_stop 0x0049
74
75#define cmd_802_11_mac_address 0x004D
76#define cmd_802_11_eeprom_access 0x0059
77
78#define cmd_802_11_band_config 0x0058
79
80#define cmd_802_11d_domain_info 0x005b
81
82#define cmd_802_11_sleep_params 0x0066
83
84#define cmd_802_11_inactivity_timeout 0x0067
85
86#define cmd_802_11_tpc_cfg 0x0072
87#define cmd_802_11_pwr_cfg 0x0073
88
89#define cmd_802_11_led_gpio_ctrl 0x004e
90
91#define cmd_802_11_subscribe_event 0x0075
92
93#define cmd_802_11_rate_adapt_rateset 0x0076
94
95#define cmd_802_11_tx_rate_query 0x007f
96
97#define cmd_get_tsf 0x0080
98
99#define cmd_bt_access 0x0087
100#define cmd_ret_bt_access 0x8087
101
102#define cmd_fwt_access 0x0088
103#define cmd_ret_fwt_access 0x8088
104
105#define cmd_mesh_access 0x0090
106#define cmd_ret_mesh_access 0x8090
107
108/* For the IEEE Power Save */
109#define cmd_subcmd_enter_ps 0x0030
110#define cmd_subcmd_exit_ps 0x0031
111#define cmd_subcmd_sleep_confirmed 0x0034
112#define cmd_subcmd_full_powerdown 0x0035
113#define cmd_subcmd_full_powerup 0x0036
114
115/* command RET code, MSB is set to 1 */
116#define cmd_ret_hw_spec_info 0x8003
117#define cmd_ret_eeprom_update 0x8004
118#define cmd_ret_802_11_reset 0x8005
119#define cmd_ret_802_11_scan 0x8006
120#define cmd_ret_802_11_get_log 0x800b
121#define cmd_ret_mac_control 0x8028
122#define cmd_ret_mac_multicast_adr 0x8010
123#define cmd_ret_802_11_authenticate 0x8011
124#define cmd_ret_802_11_deauthenticate 0x8024
125#define cmd_ret_802_11_associate 0x8012
126#define cmd_ret_802_11_reassociate 0x8025
127#define cmd_ret_802_11_disassociate 0x8026
128#define cmd_ret_802_11_set_wep 0x8013
129#define cmd_ret_802_11_stat 0x8014
130#define cmd_ret_802_3_stat 0x8015
131#define cmd_ret_802_11_snmp_mib 0x8016
132#define cmd_ret_mac_reg_map 0x8017
133#define cmd_ret_bbp_reg_map 0x8018
134#define cmd_ret_rf_reg_map 0x8023
135#define cmd_ret_mac_reg_access 0x8019
136#define cmd_ret_bbp_reg_access 0x801a
137#define cmd_ret_rf_reg_access 0x801b
138#define cmd_ret_802_11_radio_control 0x801c
139#define cmd_ret_802_11_rf_channel 0x801d
140#define cmd_ret_802_11_rssi 0x801f
141#define cmd_ret_802_11_rf_tx_power 0x801e
142#define cmd_ret_802_11_rf_antenna 0x8020
143#define cmd_ret_802_11_ps_mode 0x8021
144#define cmd_ret_802_11_data_rate 0x8022
145
146#define cmd_ret_802_11_ad_hoc_start 0x802B
147#define cmd_ret_802_11_ad_hoc_join 0x802C
148
149#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
150#define cmd_ret_802_11_enable_rsn 0x802f
151#define cmd_ret_802_11_pairwise_tsc 0x8036
152#define cmd_ret_802_11_group_tsc 0x8037
153#define cmd_ret_802_11_key_material 0x805e
154
155#define cmd_enable_rsn 0x0001
156#define cmd_disable_rsn 0x0000
157
158#define cmd_act_set 0x0001
159#define cmd_act_get 0x0000
160
161#define cmd_act_get_AES (cmd_act_get + 2)
162#define cmd_act_set_AES (cmd_act_set + 2)
163#define cmd_act_remove_aes (cmd_act_set + 3)
164
165#define cmd_ret_802_11_set_afc 0x803c
166#define cmd_ret_802_11_get_afc 0x803d
167
168#define cmd_ret_802_11_ad_hoc_stop 0x8040
169
170#define cmd_ret_802_11_beacon_stop 0x8049
171
172#define cmd_ret_802_11_mac_address 0x804D
173#define cmd_ret_802_11_eeprom_access 0x8059
174
175#define cmd_ret_802_11_band_config 0x8058
176
177#define cmd_ret_802_11_sleep_params 0x8066
178
179#define cmd_ret_802_11_inactivity_timeout 0x8067
180
181#define cmd_ret_802_11d_domain_info (0x8000 | \
182 cmd_802_11d_domain_info)
183
184#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
185#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
186
187#define cmd_ret_802_11_led_gpio_ctrl 0x804e
188
189#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
190
191#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
192
193#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
194
195#define cmd_ret_get_tsf 0x8080
196
197/* Define action or option for cmd_802_11_set_wep */
198#define cmd_act_add 0x0002
199#define cmd_act_remove 0x0004
200#define cmd_act_use_default 0x0008
201
202#define cmd_type_wep_40_bit 0x0001
203#define cmd_type_wep_104_bit 0x0002
204
205#define cmd_NUM_OF_WEP_KEYS 4
206
207#define cmd_WEP_KEY_INDEX_MASK 0x3fff
208
209/* Define action or option for cmd_802_11_reset */
210#define cmd_act_halt 0x0003
211
212/* Define action or option for cmd_802_11_scan */
213#define cmd_bss_type_bss 0x0001
214#define cmd_bss_type_ibss 0x0002
215#define cmd_bss_type_any 0x0003
216
217/* Define action or option for cmd_802_11_scan */
218#define cmd_scan_type_active 0x0000
219#define cmd_scan_type_passive 0x0001
220
221#define cmd_scan_radio_type_bg 0
222
223#define cmd_scan_probe_delay_time 0
224
225/* Define action or option for cmd_mac_control */
226#define cmd_act_mac_rx_on 0x0001
227#define cmd_act_mac_tx_on 0x0002
228#define cmd_act_mac_loopback_on 0x0004
229#define cmd_act_mac_wep_enable 0x0008
230#define cmd_act_mac_int_enable 0x0010
231#define cmd_act_mac_multicast_enable 0x0020
232#define cmd_act_mac_broadcast_enable 0x0040
233#define cmd_act_mac_promiscuous_enable 0x0080
234#define cmd_act_mac_all_multicast_enable 0x0100
235#define cmd_act_mac_strict_protection_enable 0x0400
236
237/* Define action or option for cmd_802_11_radio_control */
238#define cmd_type_auto_preamble 0x0001
239#define cmd_type_short_preamble 0x0002
240#define cmd_type_long_preamble 0x0003
241
242#define TURN_ON_RF 0x01
243#define RADIO_ON 0x01
244#define RADIO_OFF 0x00
245
246#define SET_AUTO_PREAMBLE 0x05
247#define SET_SHORT_PREAMBLE 0x03
248#define SET_LONG_PREAMBLE 0x01
249
250/* Define action or option for CMD_802_11_RF_CHANNEL */
251#define cmd_opt_802_11_rf_channel_get 0x00
252#define cmd_opt_802_11_rf_channel_set 0x01
253
254/* Define action or option for cmd_802_11_rf_tx_power */
255#define cmd_act_tx_power_opt_get 0x0000
256#define cmd_act_tx_power_opt_set_high 0x8007
257#define cmd_act_tx_power_opt_set_mid 0x8004
258#define cmd_act_tx_power_opt_set_low 0x8000
259
260#define cmd_act_tx_power_index_high 0x0007
261#define cmd_act_tx_power_index_mid 0x0004
262#define cmd_act_tx_power_index_low 0x0000
263
264/* Define action or option for cmd_802_11_data_rate */
265#define cmd_act_set_tx_auto 0x0000
266#define cmd_act_set_tx_fix_rate 0x0001
267#define cmd_act_get_tx_rate 0x0002
268
269#define cmd_act_set_rx 0x0001
270#define cmd_act_set_tx 0x0002
271#define cmd_act_set_both 0x0003
272#define cmd_act_get_rx 0x0004
273#define cmd_act_get_tx 0x0008
274#define cmd_act_get_both 0x000c
275
276/* Define action or option for cmd_802_11_ps_mode */
277#define cmd_type_cam 0x0000
278#define cmd_type_max_psp 0x0001
279#define cmd_type_fast_psp 0x0002
280
281/* Define action or option for cmd_bt_access */
282enum cmd_bt_access_opts {
283 /* The bt commands start at 5 instead of 1 because the old dft commands
284 * are mapped to 1-4. These old commands are no longer maintained and
285 * should not be called.
286 */
287 cmd_act_bt_access_add = 5,
288 cmd_act_bt_access_del,
289 cmd_act_bt_access_list,
290 cmd_act_bt_access_reset
291};
292
293/* Define action or option for cmd_fwt_access */
294enum cmd_fwt_access_opts {
295 cmd_act_fwt_access_add = 1,
296 cmd_act_fwt_access_del,
297 cmd_act_fwt_access_lookup,
298 cmd_act_fwt_access_list,
299 cmd_act_fwt_access_list_route,
300 cmd_act_fwt_access_list_neighbor,
301 cmd_act_fwt_access_reset,
302 cmd_act_fwt_access_cleanup,
303 cmd_act_fwt_access_time,
304};
305
306/* Define action or option for cmd_mesh_access */
307enum cmd_mesh_access_opts {
308 cmd_act_mesh_get_ttl = 1,
309 cmd_act_mesh_set_ttl,
310 cmd_act_mesh_get_stats,
311 cmd_act_mesh_get_mpp,
312 cmd_act_mesh_set_mpp,
313};
314
315/** Card Event definition */
316#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000
317#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001
318#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002
319#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003
320#define MACREG_INT_CODE_LINK_SENSED 0x00000004
321#define MACREG_INT_CODE_CMD_FINISHED 0x00000005
322#define MACREG_INT_CODE_MIB_CHANGED 0x00000006
323#define MACREG_INT_CODE_INIT_DONE 0x00000007
324#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008
325#define MACREG_INT_CODE_DISASSOCIATED 0x00000009
326#define MACREG_INT_CODE_PS_AWAKE 0x0000000a
327#define MACREG_INT_CODE_PS_SLEEP 0x0000000b
328#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d
329#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e
330#define MACREG_INT_CODE_WM_AWAKE 0x0000000f
331#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011
332#define MACREG_INT_CODE_RSSI_LOW 0x00000019
333#define MACREG_INT_CODE_SNR_LOW 0x0000001a
334#define MACREG_INT_CODE_MAX_FAIL 0x0000001b
335#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c
336#define MACREG_INT_CODE_SNR_HIGH 0x0000001d
337
338#endif /* _HOST_H_ */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644
index 000000000000..f239e5d2435b
--- /dev/null
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -0,0 +1,693 @@
1/*
2 * This file contains the function prototypes, data structure
3 * and defines for all the host/station commands
4 */
5#ifndef __HOSTCMD__H
6#define __HOSTCMD__H
7
8#include <linux/wireless.h>
9#include "11d.h"
10#include "types.h"
11
12/* 802.11-related definitions */
13
14/* TxPD descriptor */
15struct txpd {
16 /* Current Tx packet status */
17 u32 tx_status;
18 /* Tx control */
19 u32 tx_control;
20 u32 tx_packet_location;
21 /* Tx packet length */
22 u16 tx_packet_length;
23 /* First 2 byte of destination MAC address */
24 u8 tx_dest_addr_high[2];
25 /* Last 4 byte of destination MAC address */
26 u8 tx_dest_addr_low[4];
27 /* Pkt Priority */
28 u8 priority;
29 /* Pkt Trasnit Power control */
30 u8 powermgmt;
31 /* Amount of time the packet has been queued in the driver (units = 2ms) */
32 u8 pktdelay_2ms;
33 /* reserved */
34 u8 reserved1;
35};
36
37/* RxPD Descriptor */
38struct rxpd {
39 /* Current Rx packet status */
40 u16 status;
41
42 /* SNR */
43 u8 snr;
44
45 /* Tx control */
46 u8 rx_control;
47
48 /* Pkt length */
49 u16 pkt_len;
50
51 /* Noise Floor */
52 u8 nf;
53
54 /* Rx Packet Rate */
55 u8 rx_rate;
56
57 /* Pkt addr */
58 u32 pkt_ptr;
59
60 /* Next Rx RxPD addr */
61 u32 next_rxpd_ptr;
62
63 /* Pkt Priority */
64 u8 priority;
65 u8 reserved[3];
66};
67
68struct cmd_ctrl_node {
69 /* CMD link list */
70 struct list_head list;
71 u32 status;
72 /* CMD ID */
73 u32 cmd_oid;
74 /*CMD wait option: wait for finish or no wait */
75 u16 wait_option;
76 /* command parameter */
77 void *pdata_buf;
78 /*command data */
79 u8 *bufvirtualaddr;
80 u16 cmdflags;
81 /* wait queue */
82 u16 cmdwaitqwoken;
83 wait_queue_head_t cmdwait_q;
84};
85
86/* WLAN_802_11_KEY
87 *
88 * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
89 * is determined from the keylength field.
90 */
91struct WLAN_802_11_KEY {
92 u32 len;
93 u32 flags; /* KEY_INFO_* from wlan_defs.h */
94 u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
95 u16 type; /* KEY_TYPE_* from wlan_defs.h */
96};
97
98struct IE_WPA {
99 u8 elementid;
100 u8 len;
101 u8 oui[4];
102 u16 version;
103};
104
105struct WLAN_802_11_SSID {
106 /* SSID length */
107 u32 ssidlength;
108
109 /* SSID information field */
110 u8 ssid[IW_ESSID_MAX_SIZE];
111};
112
113struct WPA_SUPPLICANT {
114 u8 wpa_ie[256];
115 u8 wpa_ie_len;
116};
117
118/* wlan_offset_value */
119struct wlan_offset_value {
120 u32 offset;
121 u32 value;
122};
123
124struct WLAN_802_11_FIXED_IEs {
125 u8 timestamp[8];
126 u16 beaconinterval;
127 u16 capabilities;
128};
129
130struct WLAN_802_11_VARIABLE_IEs {
131 u8 elementid;
132 u8 length;
133 u8 data[1];
134};
135
136/* Define general data structure */
137/* cmd_DS_GEN */
138struct cmd_ds_gen {
139 u16 command;
140 u16 size;
141 u16 seqnum;
142 u16 result;
143};
144
145#define S_DS_GEN sizeof(struct cmd_ds_gen)
146/*
147 * Define data structure for cmd_get_hw_spec
148 * This structure defines the response for the GET_HW_SPEC command
149 */
150struct cmd_ds_get_hw_spec {
151 /* HW Interface version number */
152 u16 hwifversion;
153 /* HW version number */
154 u16 version;
155 /* Max number of TxPD FW can handle */
156 u16 nr_txpd;
157 /* Max no of Multicast address */
158 u16 nr_mcast_adr;
159 /* MAC address */
160 u8 permanentaddr[6];
161
162 /* region Code */
163 u16 regioncode;
164
165 /* Number of antenna used */
166 u16 nr_antenna;
167
168 /* FW release number, example 0x1234=1.2.3.4 */
169 u32 fwreleasenumber;
170
171 /* Base Address of TxPD queue */
172 u32 wcb_base;
173 /* Read Pointer of RxPd queue */
174 u32 rxpd_rdptr;
175
176 /* Write Pointer of RxPd queue */
177 u32 rxpd_wrptr;
178
179 /*FW/HW capability */
180 u32 fwcapinfo;
181} __attribute__ ((packed));
182
183struct cmd_ds_802_11_reset {
184 u16 action;
185};
186
187struct cmd_ds_802_11_subscribe_event {
188 u16 action;
189 u16 events;
190};
191
192/*
193 * This scan handle Country Information IE(802.11d compliant)
194 * Define data structure for cmd_802_11_scan
195 */
196struct cmd_ds_802_11_scan {
197 u8 bsstype;
198 u8 BSSID[ETH_ALEN];
199 u8 tlvbuffer[1];
200#if 0
201 mrvlietypes_ssidparamset_t ssidParamSet;
202 mrvlietypes_chanlistparamset_t ChanListParamSet;
203 mrvlietypes_ratesparamset_t OpRateSet;
204#endif
205};
206
207struct cmd_ds_802_11_scan_rsp {
208 u16 bssdescriptsize;
209 u8 nr_sets;
210 u8 bssdesc_and_tlvbuffer[1];
211};
212
213struct cmd_ds_802_11_get_log {
214 u32 mcasttxframe;
215 u32 failed;
216 u32 retry;
217 u32 multiretry;
218 u32 framedup;
219 u32 rtssuccess;
220 u32 rtsfailure;
221 u32 ackfailure;
222 u32 rxfrag;
223 u32 mcastrxframe;
224 u32 fcserror;
225 u32 txframe;
226 u32 wepundecryptable;
227};
228
229struct cmd_ds_mac_control {
230 u16 action;
231 u16 reserved;
232};
233
234struct cmd_ds_mac_multicast_adr {
235 u16 action;
236 u16 nr_of_adrs;
237 u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
238};
239
240struct cmd_ds_802_11_authenticate {
241 u8 macaddr[ETH_ALEN];
242 u8 authtype;
243 u8 reserved[10];
244};
245
246struct cmd_ds_802_11_deauthenticate {
247 u8 macaddr[6];
248 u16 reasoncode;
249};
250
251struct cmd_ds_802_11_associate {
252 u8 peerstaaddr[6];
253 struct ieeetypes_capinfo capinfo;
254 u16 listeninterval;
255 u16 bcnperiod;
256 u8 dtimperiod;
257
258#if 0
259 mrvlietypes_ssidparamset_t ssidParamSet;
260 mrvlietypes_phyparamset_t phyparamset;
261 mrvlietypes_ssparamset_t ssparamset;
262 mrvlietypes_ratesparamset_t ratesParamSet;
263#endif
264} __attribute__ ((packed));
265
266struct cmd_ds_802_11_disassociate {
267 u8 destmacaddr[6];
268 u16 reasoncode;
269};
270
271struct cmd_ds_802_11_associate_rsp {
272 struct ieeetypes_assocrsp assocRsp;
273};
274
275struct cmd_ds_802_11_ad_hoc_result {
276 u8 PAD[3];
277 u8 BSSID[ETH_ALEN];
278};
279
280struct cmd_ds_802_11_set_wep {
281 /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
282 u16 action;
283
284 /* key Index selected for Tx */
285 u16 keyindex;
286
287 /* 40, 128bit or TXWEP */
288 u8 keytype[4];
289 u8 keymaterial[4][16];
290};
291
292struct cmd_ds_802_3_get_stat {
293 u32 xmitok;
294 u32 rcvok;
295 u32 xmiterror;
296 u32 rcverror;
297 u32 rcvnobuffer;
298 u32 rcvcrcerror;
299};
300
301struct cmd_ds_802_11_get_stat {
302 u32 txfragmentcnt;
303 u32 mcasttxframecnt;
304 u32 failedcnt;
305 u32 retrycnt;
306 u32 Multipleretrycnt;
307 u32 rtssuccesscnt;
308 u32 rtsfailurecnt;
309 u32 ackfailurecnt;
310 u32 frameduplicatecnt;
311 u32 rxfragmentcnt;
312 u32 mcastrxframecnt;
313 u32 fcserrorcnt;
314 u32 bcasttxframecnt;
315 u32 bcastrxframecnt;
316 u32 txbeacon;
317 u32 rxbeacon;
318 u32 wepundecryptable;
319};
320
321struct cmd_ds_802_11_snmp_mib {
322 u16 querytype;
323 u16 oid;
324 u16 bufsize;
325 u8 value[128];
326};
327
328struct cmd_ds_mac_reg_map {
329 u16 buffersize;
330 u8 regmap[128];
331 u16 reserved;
332};
333
334struct cmd_ds_bbp_reg_map {
335 u16 buffersize;
336 u8 regmap[128];
337 u16 reserved;
338};
339
340struct cmd_ds_rf_reg_map {
341 u16 buffersize;
342 u8 regmap[64];
343 u16 reserved;
344};
345
346struct cmd_ds_mac_reg_access {
347 u16 action;
348 u16 offset;
349 u32 value;
350};
351
352struct cmd_ds_bbp_reg_access {
353 u16 action;
354 u16 offset;
355 u8 value;
356 u8 reserved[3];
357};
358
359struct cmd_ds_rf_reg_access {
360 u16 action;
361 u16 offset;
362 u8 value;
363 u8 reserved[3];
364};
365
366struct cmd_ds_802_11_radio_control {
367 u16 action;
368 u16 control;
369};
370
371struct cmd_ds_802_11_sleep_params {
372 /* ACT_GET/ACT_SET */
373 u16 action;
374
375 /* Sleep clock error in ppm */
376 u16 error;
377
378 /* Wakeup offset in usec */
379 u16 offset;
380
381 /* Clock stabilization time in usec */
382 u16 stabletime;
383
384 /* control periodic calibration */
385 u8 calcontrol;
386
387 /* control the use of external sleep clock */
388 u8 externalsleepclk;
389
390 /* reserved field, should be set to zero */
391 u16 reserved;
392};
393
394struct cmd_ds_802_11_inactivity_timeout {
395 /* ACT_GET/ACT_SET */
396 u16 action;
397
398 /* Inactivity timeout in msec */
399 u16 timeout;
400};
401
402struct cmd_ds_802_11_rf_channel {
403 u16 action;
404 u16 currentchannel;
405 u16 rftype;
406 u16 reserved;
407 u8 channellist[32];
408};
409
410struct cmd_ds_802_11_rssi {
411 /* weighting factor */
412 u16 N;
413
414 u16 reserved_0;
415 u16 reserved_1;
416 u16 reserved_2;
417};
418
419struct cmd_ds_802_11_rssi_rsp {
420 u16 SNR;
421 u16 noisefloor;
422 u16 avgSNR;
423 u16 avgnoisefloor;
424};
425
426struct cmd_ds_802_11_mac_address {
427 u16 action;
428 u8 macadd[ETH_ALEN];
429};
430
431struct cmd_ds_802_11_rf_tx_power {
432 u16 action;
433 u16 currentlevel;
434};
435
436struct cmd_ds_802_11_rf_antenna {
437 u16 action;
438
439 /* Number of antennas or 0xffff(diversity) */
440 u16 antennamode;
441
442};
443
444struct cmd_ds_802_11_ps_mode {
445 u16 action;
446 u16 nullpktinterval;
447 u16 multipledtim;
448 u16 reserved;
449 u16 locallisteninterval;
450};
451
452struct PS_CMD_ConfirmSleep {
453 u16 command;
454 u16 size;
455 u16 seqnum;
456 u16 result;
457
458 u16 action;
459 u16 reserved1;
460 u16 multipledtim;
461 u16 reserved;
462 u16 locallisteninterval;
463};
464
465struct cmd_ds_802_11_data_rate {
466 u16 action;
467 u16 reserverd;
468 u8 datarate[G_SUPPORTED_RATES];
469};
470
471struct cmd_ds_802_11_rate_adapt_rateset {
472 u16 action;
473 u16 enablehwauto;
474 u16 bitmap;
475};
476
477struct cmd_ds_802_11_ad_hoc_start {
478 u8 SSID[IW_ESSID_MAX_SIZE];
479 u8 bsstype;
480 u16 beaconperiod;
481 u8 dtimperiod;
482 union IEEEtypes_ssparamset ssparamset;
483 union ieeetypes_phyparamset phyparamset;
484 u16 probedelay;
485 struct ieeetypes_capinfo cap;
486 u8 datarate[G_SUPPORTED_RATES];
487 u8 tlv_memory_size_pad[100];
488} __attribute__ ((packed));
489
490struct adhoc_bssdesc {
491 u8 BSSID[6];
492 u8 SSID[32];
493 u8 bsstype;
494 u16 beaconperiod;
495 u8 dtimperiod;
496 u8 timestamp[8];
497 u8 localtime[8];
498 union ieeetypes_phyparamset phyparamset;
499 union IEEEtypes_ssparamset ssparamset;
500 struct ieeetypes_capinfo cap;
501 u8 datarates[G_SUPPORTED_RATES];
502
503 /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
504 * Adhoc join command and will cause a binary layout mismatch with
505 * the firmware
506 */
507} __attribute__ ((packed));
508
509struct cmd_ds_802_11_ad_hoc_join {
510 struct adhoc_bssdesc bssdescriptor;
511 u16 failtimeout;
512 u16 probedelay;
513
514} __attribute__ ((packed));
515
516struct cmd_ds_802_11_enable_rsn {
517 u16 action;
518 u16 enable;
519};
520
521struct MrvlIEtype_keyParamSet {
522 /* type ID */
523 u16 type;
524
525 /* length of Payload */
526 u16 length;
527
528 /* type of key: WEP=0, TKIP=1, AES=2 */
529 u16 keytypeid;
530
531 /* key control Info specific to a keytypeid */
532 u16 keyinfo;
533
534 /* length of key */
535 u16 keylen;
536
537 /* key material of size keylen */
538 u8 key[32];
539};
540
541struct cmd_ds_802_11_key_material {
542 u16 action;
543 struct MrvlIEtype_keyParamSet keyParamSet[2];
544} __attribute__ ((packed));
545
546struct cmd_ds_802_11_eeprom_access {
547 u16 action;
548
549 /* multiple 4 */
550 u16 offset;
551 u16 bytecount;
552 u8 value;
553} __attribute__ ((packed));
554
555struct cmd_ds_802_11_tpc_cfg {
556 u16 action;
557 u8 enable;
558 s8 P0;
559 s8 P1;
560 s8 P2;
561 u8 usesnr;
562} __attribute__ ((packed));
563
564struct cmd_ds_802_11_led_ctrl {
565 u16 action;
566 u16 numled;
567 u8 data[256];
568} __attribute__ ((packed));
569
570struct cmd_ds_802_11_pwr_cfg {
571 u16 action;
572 u8 enable;
573 s8 PA_P0;
574 s8 PA_P1;
575 s8 PA_P2;
576} __attribute__ ((packed));
577
578struct cmd_ds_802_11_afc {
579 u16 afc_auto;
580 union {
581 struct {
582 u16 threshold;
583 u16 period;
584 };
585 struct {
586 s16 timing_offset;
587 s16 carrier_offset;
588 };
589 };
590} __attribute__ ((packed));
591
592struct cmd_tx_rate_query {
593 u16 txrate;
594} __attribute__ ((packed));
595
596struct cmd_ds_get_tsf {
597 __le64 tsfvalue;
598} __attribute__ ((packed));
599
600struct cmd_ds_bt_access {
601 u16 action;
602 u32 id;
603 u8 addr1[ETH_ALEN];
604 u8 addr2[ETH_ALEN];
605} __attribute__ ((packed));
606
607struct cmd_ds_fwt_access {
608 u16 action;
609 u32 id;
610 u8 da[ETH_ALEN];
611 u8 dir;
612 u8 ra[ETH_ALEN];
613 u32 ssn;
614 u32 dsn;
615 u32 metric;
616 u8 hopcount;
617 u8 ttl;
618 u32 expiration;
619 u8 sleepmode;
620 u32 snr;
621 u32 references;
622} __attribute__ ((packed));
623
624#define MESH_STATS_NUM 7
625struct cmd_ds_mesh_access {
626 u16 action;
627 u32 data[MESH_STATS_NUM + 1]; /* last position reserved */
628} __attribute__ ((packed));
629
630struct cmd_ds_command {
631 /* command header */
632 u16 command;
633 u16 size;
634 u16 seqnum;
635 u16 result;
636
637 /* command Body */
638 union {
639 struct cmd_ds_get_hw_spec hwspec;
640 struct cmd_ds_802_11_ps_mode psmode;
641 struct cmd_ds_802_11_scan scan;
642 struct cmd_ds_802_11_scan_rsp scanresp;
643 struct cmd_ds_mac_control macctrl;
644 struct cmd_ds_802_11_associate associate;
645 struct cmd_ds_802_11_deauthenticate deauth;
646 struct cmd_ds_802_11_set_wep wep;
647 struct cmd_ds_802_11_ad_hoc_start ads;
648 struct cmd_ds_802_11_reset reset;
649 struct cmd_ds_802_11_ad_hoc_result result;
650 struct cmd_ds_802_11_get_log glog;
651 struct cmd_ds_802_11_authenticate auth;
652 struct cmd_ds_802_11_get_stat gstat;
653 struct cmd_ds_802_3_get_stat gstat_8023;
654 struct cmd_ds_802_11_snmp_mib smib;
655 struct cmd_ds_802_11_rf_tx_power txp;
656 struct cmd_ds_802_11_rf_antenna rant;
657 struct cmd_ds_802_11_data_rate drate;
658 struct cmd_ds_802_11_rate_adapt_rateset rateset;
659 struct cmd_ds_mac_multicast_adr madr;
660 struct cmd_ds_802_11_ad_hoc_join adj;
661 struct cmd_ds_802_11_radio_control radio;
662 struct cmd_ds_802_11_rf_channel rfchannel;
663 struct cmd_ds_802_11_rssi rssi;
664 struct cmd_ds_802_11_rssi_rsp rssirsp;
665 struct cmd_ds_802_11_disassociate dassociate;
666 struct cmd_ds_802_11_mac_address macadd;
667 struct cmd_ds_802_11_enable_rsn enbrsn;
668 struct cmd_ds_802_11_key_material keymaterial;
669 struct cmd_ds_mac_reg_access macreg;
670 struct cmd_ds_bbp_reg_access bbpreg;
671 struct cmd_ds_rf_reg_access rfreg;
672 struct cmd_ds_802_11_eeprom_access rdeeprom;
673
674 struct cmd_ds_802_11d_domain_info domaininfo;
675 struct cmd_ds_802_11d_domain_info domaininforesp;
676
677 struct cmd_ds_802_11_sleep_params sleep_params;
678 struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
679 struct cmd_ds_802_11_tpc_cfg tpccfg;
680 struct cmd_ds_802_11_pwr_cfg pwrcfg;
681 struct cmd_ds_802_11_afc afc;
682 struct cmd_ds_802_11_led_ctrl ledgpio;
683
684 struct cmd_tx_rate_query txrate;
685 struct cmd_ds_bt_access bt;
686 struct cmd_ds_fwt_access fwt;
687 struct cmd_ds_mesh_access mesh;
688 struct cmd_ds_get_tsf gettsf;
689 struct cmd_ds_802_11_subscribe_event subscribe_event;
690 } params;
691} __attribute__ ((packed));
692
693#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644
index 000000000000..567000c3e87b
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_bootcmd.c
@@ -0,0 +1,38 @@
1/**
2 * This file contains functions used in USB Boot command
3 * and Boot2/FW update
4 */
5
6#include <linux/delay.h>
7#include <linux/firmware.h>
8#include <linux/netdevice.h>
9#include <linux/usb.h>
10
11#include "defs.h"
12#include "dev.h"
13#include "if_usb.h"
14
15/**
16 * @brief This function issues Boot command to the Boot2 code
17 * @param ivalue 1:Boot from FW by USB-Download
18 * 2:Boot from FW in EEPROM
19 * @return 0
20 */
21int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
22{
23 struct usb_card_rec *cardp = priv->wlan_dev.card;
24 struct bootcmdstr sbootcmd;
25 int i;
26
27 /* Prepare command */
28 sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
29 sbootcmd.u8cmd_tag = ivalue;
30 for (i=0; i<11; i++)
31 sbootcmd.au8dumy[i]=0x00;
32 memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
33
34 /* Issue command */
35 usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
36
37 return 0;
38}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644
index 000000000000..695fb6a66ffe
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -0,0 +1,952 @@
1/**
2 * This file contains functions used in USB interface module.
3 */
4#include <linux/delay.h>
5#include <linux/firmware.h>
6#include <linux/netdevice.h>
7#include <linux/usb.h>
8
9#include "host.h"
10#include "sbi.h"
11#include "decl.h"
12#include "defs.h"
13#include "dev.h"
14#include "if_usb.h"
15
16#define MESSAGE_HEADER_LEN 4
17
18static const char usbdriver_name[] = "usb8xxx";
19
20static struct usb_device_id if_usb_table[] = {
21 /* Enter the device signature inside */
22 {
23 USB_DEVICE(USB8388_VID_1, USB8388_PID_1),
24 },
25 {
26 USB_DEVICE(USB8388_VID_2, USB8388_PID_2),
27 },
28 {} /* Terminating entry */
29};
30
31MODULE_DEVICE_TABLE(usb, if_usb_table);
32
33static void if_usb_receive(struct urb *urb);
34static void if_usb_receive_fwload(struct urb *urb);
35
36/**
37 * @brief call back function to handle the status of the URB
38 * @param urb pointer to urb structure
39 * @return N/A
40 */
41static void if_usb_write_bulk_callback(struct urb *urb)
42{
43 wlan_private *priv = (wlan_private *) (urb->context);
44 wlan_adapter *adapter = priv->adapter;
45 struct net_device *dev = priv->wlan_dev.netdev;
46
47 /* handle the transmission complete validations */
48
49 if (urb->status != 0) {
50 /* print the failure status number for debug */
51 lbs_pr_info("URB in failure status\n");
52 } else {
53 lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
54 lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
55 urb->actual_length);
56 priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
57 /* Wake main thread if commands are pending */
58 if (!adapter->cur_cmd)
59 wake_up_interruptible(&priv->mainthread.waitq);
60 if ((adapter->connect_status == libertas_connected))
61 netif_wake_queue(dev);
62 }
63
64 return;
65}
66
67/**
68 * @brief free tx/rx urb, skb and rx buffer
69 * @param cardp pointer usb_card_rec
70 * @return N/A
71 */
72void if_usb_free(struct usb_card_rec *cardp)
73{
74 ENTER();
75
76 /* Unlink tx & rx urb */
77 usb_kill_urb(cardp->tx_urb);
78 usb_kill_urb(cardp->rx_urb);
79
80 usb_free_urb(cardp->tx_urb);
81 cardp->tx_urb = NULL;
82
83 usb_free_urb(cardp->rx_urb);
84 cardp->rx_urb = NULL;
85
86 kfree(cardp->bulk_out_buffer);
87 cardp->bulk_out_buffer = NULL;
88
89 LEAVE();
90 return;
91}
92
93/**
94 * @brief sets the configuration values
95 * @param ifnum interface number
96 * @param id pointer to usb_device_id
97 * @return 0 on success, error code on failure
98 */
99static int if_usb_probe(struct usb_interface *intf,
100 const struct usb_device_id *id)
101{
102 struct usb_device *udev;
103 struct usb_host_interface *iface_desc;
104 struct usb_endpoint_descriptor *endpoint;
105 wlan_private *pwlanpriv;
106 struct usb_card_rec *usb_cardp;
107 int i;
108
109 udev = interface_to_usbdev(intf);
110
111 usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
112 if (!usb_cardp) {
113 lbs_pr_err("Out of memory allocating private data.\n");
114 goto error;
115 }
116
117 usb_cardp->udev = udev;
118 iface_desc = intf->cur_altsetting;
119
120 lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
121 " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
122 udev->descriptor.bcdUSB,
123 udev->descriptor.bDeviceClass,
124 udev->descriptor.bDeviceSubClass,
125 udev->descriptor.bDeviceProtocol);
126
127 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
128 endpoint = &iface_desc->endpoint[i].desc;
129 if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
130 && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
131 USB_ENDPOINT_XFER_BULK)) {
132 /* we found a bulk in endpoint */
133 lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
134 endpoint->wMaxPacketSize);
135 if (!
136 (usb_cardp->rx_urb =
137 usb_alloc_urb(0, GFP_KERNEL))) {
138 lbs_dev_dbg(1, &udev->dev,
139 "Rx URB allocation failed\n");
140 goto dealloc;
141 }
142 usb_cardp->rx_urb_recall = 0;
143
144 usb_cardp->bulk_in_size =
145 endpoint->wMaxPacketSize;
146 usb_cardp->bulk_in_endpointAddr =
147 (endpoint->
148 bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
149 lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
150 endpoint->bEndpointAddress);
151 }
152
153 if (((endpoint->
154 bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
155 USB_DIR_OUT)
156 && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
157 USB_ENDPOINT_XFER_BULK)) {
158 /* We found bulk out endpoint */
159 if (!
160 (usb_cardp->tx_urb =
161 usb_alloc_urb(0, GFP_KERNEL))) {
162 lbs_dev_dbg(1,&udev->dev,
163 "Tx URB allocation failed\n");
164 goto dealloc;
165 }
166
167 usb_cardp->bulk_out_size =
168 endpoint->wMaxPacketSize;
169 lbs_dev_dbg(1, &udev->dev,
170 "Bulk out size is %d\n",
171 endpoint->wMaxPacketSize);
172 usb_cardp->bulk_out_endpointAddr =
173 endpoint->bEndpointAddress;
174 lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
175 endpoint->bEndpointAddress);
176 usb_cardp->bulk_out_buffer =
177 kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
178 GFP_KERNEL);
179
180 if (!usb_cardp->bulk_out_buffer) {
181 lbs_dev_dbg(1, &udev->dev,
182 "Could not allocate buffer\n");
183 goto dealloc;
184 }
185 }
186 }
187
188
189 /* At this point wlan_add_card() will be called. Don't worry
190 * about keeping pwlanpriv around since it will be set on our
191 * usb device data in -> add() -> libertas_sbi_register_dev().
192 */
193 if (!(pwlanpriv = wlan_add_card(usb_cardp)))
194 goto dealloc;
195
196 usb_get_dev(udev);
197 usb_set_intfdata(intf, usb_cardp);
198
199 /*
200 * return card structure, which can be got back in the
201 * diconnect function as the ptr
202 * argument.
203 */
204 return 0;
205
206dealloc:
207 if_usb_free(usb_cardp);
208
209error:
210 return -ENOMEM;
211}
212
213/**
214 * @brief free resource and cleanup
215 * @param udev pointer to usb_device
216 * @param ptr pointer to usb_cardp
217 * @return N/A
218 */
219static void if_usb_disconnect(struct usb_interface *intf)
220{
221 struct usb_card_rec *cardp = usb_get_intfdata(intf);
222 wlan_private *priv = (wlan_private *) cardp->priv;
223 wlan_adapter *adapter = NULL;
224
225 adapter = priv->adapter;
226
227 /*
228 * Update Surprise removed to TRUE
229 */
230 adapter->surpriseremoved = 1;
231
232 /* card is removed and we can call wlan_remove_card */
233 lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
234 wlan_remove_card(cardp);
235
236 /* Unlink and free urb */
237 if_usb_free(cardp);
238
239 usb_set_intfdata(intf, NULL);
240 usb_put_dev(interface_to_usbdev(intf));
241
242 return;
243}
244
245/**
246 * @brief This function download FW
247 * @param priv pointer to wlan_private
248 * @return 0
249 */
250static int if_prog_firmware(wlan_private * priv)
251{
252 struct usb_card_rec *cardp = priv->wlan_dev.card;
253 struct FWData *fwdata;
254 struct fwheader *fwheader;
255 u8 *firmware = priv->firmware->data;
256
257 fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
258
259 if (!fwdata)
260 return -1;
261
262 fwheader = &fwdata->fwheader;
263
264 if (!cardp->CRC_OK) {
265 cardp->totalbytes = cardp->fwlastblksent;
266 cardp->fwseqnum = cardp->lastseqnum - 1;
267 }
268
269 lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
270 cardp->totalbytes);
271
272 memcpy(fwheader, &firmware[cardp->totalbytes],
273 sizeof(struct fwheader));
274
275 cardp->fwlastblksent = cardp->totalbytes;
276 cardp->totalbytes += sizeof(struct fwheader);
277
278 lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
279 memcpy(fwdata->data, &firmware[cardp->totalbytes],
280 fwdata->fwheader.datalength);
281
282 lbs_dev_dbg(2, &cardp->udev->dev,
283 "Data length = %d\n", fwdata->fwheader.datalength);
284
285 cardp->fwseqnum = cardp->fwseqnum + 1;
286
287 fwdata->seqnum = cardp->fwseqnum;
288 cardp->lastseqnum = fwdata->seqnum;
289 cardp->totalbytes += fwdata->fwheader.datalength;
290
291 if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) {
292 lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
293 lbs_dev_dbg(2, &cardp->udev->dev,
294 "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
295 cardp->totalbytes);
296 memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
297 usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
298
299 } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) {
300 lbs_dev_dbg(2, &cardp->udev->dev,
301 "Host has finished FW downloading\n");
302 lbs_dev_dbg(2, &cardp->udev->dev,
303 "Donwloading FW JUMP BLOCK\n");
304 memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
305 usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
306 cardp->fwfinalblk = 1;
307 }
308
309 lbs_dev_dbg(2, &cardp->udev->dev,
310 "The firmware download is done size is %d\n",
311 cardp->totalbytes);
312
313 kfree(fwdata);
314
315 return 0;
316}
317
318static int libertas_do_reset(wlan_private *priv)
319{
320 int ret;
321 struct usb_card_rec *cardp = priv->wlan_dev.card;
322
323 ret = usb_reset_device(cardp->udev);
324 if (!ret) {
325 msleep(10);
326 reset_device(priv);
327 msleep(10);
328 }
329 return ret;
330}
331
332/**
333 * @brief This function transfer the data to the device.
334 * @param priv pointer to wlan_private
335 * @param payload pointer to payload data
336 * @param nb data length
337 * @return 0 or -1
338 */
339int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
340{
341 /* pointer to card structure */
342 struct usb_card_rec *cardp = priv->wlan_dev.card;
343 int ret = -1;
344
345 /* check if device is removed */
346 if (priv->adapter->surpriseremoved) {
347 lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
348 goto tx_ret;
349 }
350
351 usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
352 usb_sndbulkpipe(cardp->udev,
353 cardp->bulk_out_endpointAddr),
354 payload, nb, if_usb_write_bulk_callback, priv);
355
356 cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
357
358 if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
359 /* transfer failed */
360 lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
361 ret = -1;
362 } else {
363 lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
364 ret = 0;
365 }
366
367tx_ret:
368 return ret;
369}
370
371static int __if_usb_submit_rx_urb(wlan_private * priv,
372 void (*callbackfn)
373 (struct urb *urb))
374{
375 struct usb_card_rec *cardp = priv->wlan_dev.card;
376 struct sk_buff *skb;
377 struct read_cb_info *rinfo = &cardp->rinfo;
378 int ret = -1;
379
380 if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
381 lbs_pr_err("No free skb\n");
382 goto rx_ret;
383 }
384
385 rinfo->skb = skb;
386
387 /* Fill the receive configuration URB and initialise the Rx call back */
388 usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
389 usb_rcvbulkpipe(cardp->udev,
390 cardp->bulk_in_endpointAddr),
391 skb->tail + IPFIELD_ALIGN_OFFSET,
392 MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
393 rinfo);
394
395 cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
396
397 lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
398 if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
399 /* handle failure conditions */
400 lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
401 ret = -1;
402 } else {
403 lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
404 ret = 0;
405 }
406
407rx_ret:
408 return ret;
409}
410
411static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
412{
413 return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
414}
415
416static inline int if_usb_submit_rx_urb(wlan_private * priv)
417{
418 return __if_usb_submit_rx_urb(priv, &if_usb_receive);
419}
420
421static void if_usb_receive_fwload(struct urb *urb)
422{
423 struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
424 wlan_private *priv = rinfo->priv;
425 struct sk_buff *skb = rinfo->skb;
426 struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
427 struct fwsyncheader *syncfwheader;
428 struct bootcmdrespStr bootcmdresp;
429
430 if (urb->status) {
431 lbs_dev_dbg(1, &cardp->udev->dev,
432 "URB status is failed during fw load\n");
433 kfree_skb(skb);
434 return;
435 }
436
437 if (cardp->bootcmdresp == 0) {
438 memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
439 sizeof(bootcmdresp));
440 if (cardp->udev->descriptor.bcdDevice < 0x3106) {
441 kfree_skb(skb);
442 if_usb_submit_rx_urb_fwload(priv);
443 cardp->bootcmdresp = 1;
444 lbs_dev_dbg(1, &cardp->udev->dev,
445 "Received valid boot command response\n");
446 return;
447 }
448 if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
449 lbs_pr_info(
450 "boot cmd response wrong magic number (0x%x)\n",
451 bootcmdresp.u32magicnumber);
452 } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
453 lbs_pr_info(
454 "boot cmd response cmd_tag error (%d)\n",
455 bootcmdresp.u8cmd_tag);
456 } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
457 lbs_pr_info(
458 "boot cmd response result error (%d)\n",
459 bootcmdresp.u8result);
460 } else {
461 cardp->bootcmdresp = 1;
462 lbs_dev_dbg(1, &cardp->udev->dev,
463 "Received valid boot command response\n");
464 }
465 kfree_skb(skb);
466 if_usb_submit_rx_urb_fwload(priv);
467 return;
468 }
469
470 syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
471 if (!syncfwheader) {
472 lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
473 kfree_skb(skb);
474 return;
475 }
476
477 memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
478 sizeof(struct fwsyncheader));
479
480 if (!syncfwheader->cmd) {
481 lbs_dev_dbg(2, &cardp->udev->dev,
482 "FW received Blk with correct CRC\n");
483 lbs_dev_dbg(2, &cardp->udev->dev,
484 "FW received Blk seqnum = %d\n",
485 syncfwheader->seqnum);
486 cardp->CRC_OK = 1;
487 } else {
488 lbs_dev_dbg(1, &cardp->udev->dev,
489 "FW received Blk with CRC error\n");
490 cardp->CRC_OK = 0;
491 }
492
493 kfree_skb(skb);
494
495 if (cardp->fwfinalblk) {
496 cardp->fwdnldover = 1;
497 goto exit;
498 }
499
500 if_prog_firmware(priv);
501
502 if_usb_submit_rx_urb_fwload(priv);
503exit:
504 kfree(syncfwheader);
505
506 return;
507
508}
509
510#define MRVDRV_MIN_PKT_LEN 30
511
512static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
513 struct usb_card_rec *cardp,
514 wlan_private *priv)
515{
516 if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
517 MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
518 lbs_dev_dbg(1, &cardp->udev->dev,
519 "Packet length is Invalid\n");
520 kfree_skb(skb);
521 return;
522 }
523
524 skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
525 skb_put(skb, recvlength);
526 skb_pull(skb, MESSAGE_HEADER_LEN);
527 libertas_process_rxed_packet(priv, skb);
528 priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
529}
530
531static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
532 struct sk_buff *skb,
533 struct usb_card_rec *cardp,
534 wlan_private *priv)
535{
536 u8 *cmdbuf;
537 if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
538 lbs_dev_dbg(1, &cardp->udev->dev,
539 "The receive buffer is too large\n");
540 kfree_skb(skb);
541 return;
542 }
543
544 if (!in_interrupt())
545 BUG();
546
547 spin_lock(&priv->adapter->driver_lock);
548 /* take care of cur_cmd = NULL case by reading the
549 * data to clear the interrupt */
550 if (!priv->adapter->cur_cmd) {
551 cmdbuf = priv->wlan_dev.upld_buf;
552 priv->adapter->hisregcpy &= ~his_cmdupldrdy;
553 } else
554 cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
555
556 cardp->usb_int_cause |= his_cmdupldrdy;
557 priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
558 memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
559 priv->wlan_dev.upld_len);
560
561 kfree_skb(skb);
562 libertas_interrupt(priv->wlan_dev.netdev);
563 spin_unlock(&priv->adapter->driver_lock);
564
565 lbs_dev_dbg(1, &cardp->udev->dev,
566 "Wake up main thread to handle cmd response\n");
567
568 return;
569}
570
571/**
572 * @brief This function reads of the packet into the upload buff,
573 * wake up the main thread and initialise the Rx callack.
574 *
575 * @param urb pointer to struct urb
576 * @return N/A
577 */
578static void if_usb_receive(struct urb *urb)
579{
580 struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
581 wlan_private *priv = rinfo->priv;
582 struct sk_buff *skb = rinfo->skb;
583 struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
584
585 int recvlength = urb->actual_length;
586 u8 *recvbuff = NULL;
587 u32 recvtype;
588
589 ENTER();
590
591 if (recvlength) {
592 if (urb->status) {
593 lbs_dev_dbg(1, &cardp->udev->dev,
594 "URB status is failed\n");
595 kfree_skb(skb);
596 goto setup_for_next;
597 }
598
599 recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
600 memcpy(&recvtype, recvbuff, sizeof(u32));
601 lbs_dev_dbg(1, &cardp->udev->dev,
602 "Recv length = 0x%x\n", recvlength);
603 lbs_dev_dbg(1, &cardp->udev->dev,
604 "Receive type = 0x%X\n", recvtype);
605 recvtype = le32_to_cpu(recvtype);
606 lbs_dev_dbg(1, &cardp->udev->dev,
607 "Receive type after = 0x%X\n", recvtype);
608 } else if (urb->status)
609 goto rx_exit;
610
611
612 switch (recvtype) {
613 case CMD_TYPE_DATA:
614 process_cmdtypedata(recvlength, skb, cardp, priv);
615 break;
616
617 case CMD_TYPE_REQUEST:
618 process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
619 break;
620
621 case CMD_TYPE_INDICATION:
622 /* Event cause handling */
623 spin_lock(&priv->adapter->driver_lock);
624 cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
625 lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
626 cardp->usb_event_cause);
627 if (cardp->usb_event_cause & 0xffff0000) {
628 libertas_send_tx_feedback(priv);
629 break;
630 }
631 cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
632 cardp->usb_int_cause |= his_cardevent;
633 kfree_skb(skb);
634 libertas_interrupt(priv->wlan_dev.netdev);
635 spin_unlock(&priv->adapter->driver_lock);
636 goto rx_exit;
637 default:
638 kfree_skb(skb);
639 break;
640 }
641
642setup_for_next:
643 if_usb_submit_rx_urb(priv);
644rx_exit:
645 LEAVE();
646 return;
647}
648
649/**
650 * @brief This function downloads data to FW
651 * @param priv pointer to wlan_private structure
652 * @param type type of data
653 * @param buf pointer to data buffer
654 * @param len number of bytes
655 * @return 0 or -1
656 */
657int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
658{
659 int ret = -1;
660 u32 tmp;
661 struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
662
663 lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
664 lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
665
666 if (type == MVMS_CMD) {
667 tmp = cpu_to_le32(CMD_TYPE_REQUEST);
668 priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
669 memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
670 MESSAGE_HEADER_LEN);
671
672 } else {
673 tmp = cpu_to_le32(CMD_TYPE_DATA);
674 priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
675 memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
676 MESSAGE_HEADER_LEN);
677 }
678
679 memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
680
681 ret =
682 usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
683
684 return ret;
685}
686
687/* called with adapter->driver_lock held */
688int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
689{
690 struct usb_card_rec *cardp = priv->wlan_dev.card;
691
692 *ireg = cardp->usb_int_cause;
693 cardp->usb_int_cause = 0;
694
695 lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
696
697 return 0;
698}
699
700int libertas_sbi_read_event_cause(wlan_private * priv)
701{
702 struct usb_card_rec *cardp = priv->wlan_dev.card;
703 priv->adapter->eventcause = cardp->usb_event_cause;
704 /* Re-submit rx urb here to avoid event lost issue */
705 if_usb_submit_rx_urb(priv);
706 return 0;
707}
708
709int reset_device(wlan_private *priv)
710{
711 int ret;
712
713 ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
714 cmd_act_halt, 0, 0, NULL);
715 msleep_interruptible(10);
716
717 return ret;
718}
719
720int libertas_sbi_unregister_dev(wlan_private * priv)
721{
722 int ret = 0;
723
724 /* Need to send a Reset command to device before USB resources freed
725 * and wlan_remove_card() called, then device can handle FW download
726 * again.
727 */
728 if (priv)
729 reset_device(priv);
730
731 return ret;
732}
733
734
735/**
736 * @brief This function register usb device and initialize parameter
737 * @param priv pointer to wlan_private
738 * @return 0 or -1
739 */
740int libertas_sbi_register_dev(wlan_private * priv)
741{
742
743 struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
744 ENTER();
745
746 cardp->priv = priv;
747 cardp->eth_dev = priv->wlan_dev.netdev;
748 priv->hotplug_device = &(cardp->udev->dev);
749
750 SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev));
751
752 lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
753 cardp->udev);
754
755 LEAVE();
756 return 0;
757}
758
759
760
761int libertas_sbi_prog_firmware(wlan_private * priv)
762{
763 struct usb_card_rec *cardp = priv->wlan_dev.card;
764 int i = 0;
765 static int reset_count = 10;
766
767 ENTER();
768
769 cardp->rinfo.priv = priv;
770
771restart:
772 if (if_usb_submit_rx_urb_fwload(priv) < 0) {
773 lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
774 LEAVE();
775 return -1;
776 }
777
778#ifdef SUPPORT_BOOT_COMMAND
779 cardp->bootcmdresp = 0;
780 do {
781 int j = 0;
782 i++;
783 /* Issue Boot command = 1, Boot from Download-FW */
784 if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
785 /* wait for command response */
786 do {
787 j++;
788 msleep_interruptible(100);
789 } while (cardp->bootcmdresp == 0 && j < 10);
790 } while (cardp->bootcmdresp == 0 && i < 5);
791
792 if (cardp->bootcmdresp == 0) {
793 if (--reset_count >= 0) {
794 libertas_do_reset(priv);
795 goto restart;
796 }
797 return -1;
798 }
799#endif
800
801 i = 0;
802 priv->adapter->fw_ready = 0;
803
804 cardp->totalbytes = 0;
805 cardp->fwlastblksent = 0;
806 cardp->CRC_OK = 1;
807 cardp->fwdnldover = 0;
808 cardp->fwseqnum = -1;
809 cardp->totalbytes = 0;
810 cardp->fwfinalblk = 0;
811
812 if_prog_firmware(priv);
813
814 do {
815 lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
816 i++;
817 msleep_interruptible(100);
818 if (priv->adapter->surpriseremoved || i >= 20)
819 break;
820 } while (!cardp->fwdnldover);
821
822 if (!cardp->fwdnldover) {
823 lbs_pr_info("failed to load fw, resetting device!\n");
824 if (--reset_count >= 0) {
825 libertas_do_reset(priv);
826 goto restart;
827 }
828
829 lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
830 LEAVE();
831 return -1;
832 }
833
834 if_usb_submit_rx_urb(priv);
835
836 /* Delay 200 ms to waiting for the FW ready */
837 msleep_interruptible(200);
838
839 priv->adapter->fw_ready = 1;
840
841 LEAVE();
842 return 0;
843}
844
845/**
846 * @brief Given a usb_card_rec return its wlan_private
847 * @param card pointer to a usb_card_rec
848 * @return pointer to wlan_private
849 */
850wlan_private *libertas_sbi_get_priv(void *card)
851{
852 struct usb_card_rec *cardp = card;
853 return cardp->priv;
854}
855
856#ifdef ENABLE_PM
857int libertas_sbi_suspend(wlan_private * priv)
858{
859 return 0;
860}
861
862int libertas_sbi_resume(wlan_private * priv)
863{
864 return 0;
865}
866#endif
867
868#ifdef CONFIG_PM
869static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
870{
871 struct usb_card_rec *cardp = usb_get_intfdata(intf);
872 wlan_private *priv = cardp->priv;
873
874 ENTER();
875
876 if (priv->adapter->psstate != PS_STATE_FULL_POWER)
877 return -1;
878
879 netif_device_detach(cardp->eth_dev);
880
881 /* Unlink tx & rx urb */
882 usb_kill_urb(cardp->tx_urb);
883 usb_kill_urb(cardp->rx_urb);
884
885 cardp->rx_urb_recall = 1;
886
887 LEAVE();
888 return 0;
889}
890
891static int if_usb_resume(struct usb_interface *intf)
892{
893 struct usb_card_rec *cardp = usb_get_intfdata(intf);
894
895 ENTER();
896
897 cardp->rx_urb_recall = 0;
898
899 if_usb_submit_rx_urb(cardp->priv);
900
901 netif_device_attach(cardp->eth_dev);
902
903 LEAVE();
904 return 0;
905}
906#else
907#define if_usb_suspend NULL
908#define if_usb_resume NULL
909#endif
910
911static struct usb_driver if_usb_driver = {
912 /* driver name */
913 .name = usbdriver_name,
914 /* probe function name */
915 .probe = if_usb_probe,
916 /* disconnect function name */
917 .disconnect = if_usb_disconnect,
918 /* device signature table */
919 .id_table = if_usb_table,
920 .suspend = if_usb_suspend,
921 .resume = if_usb_resume,
922};
923
924/**
925 * @brief This function registers driver.
926 * @param add pointer to add_card callback function
927 * @param remove pointer to remove card callback function
928 * @param arg pointer to call back function parameter
929 * @return dummy success variable
930 */
931int libertas_sbi_register(void)
932{
933 /*
934 * API registers the Marvell USB driver
935 * to the USB system
936 */
937 usb_register(&if_usb_driver);
938
939 /* Return success to wlan layer */
940 return 0;
941}
942
943/**
944 * @brief This function removes usb driver.
945 * @return N/A
946 */
947void libertas_sbi_unregister(void)
948{
949 /* API unregisters the driver from USB subsystem */
950 usb_deregister(&if_usb_driver);
951 return;
952}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644
index 000000000000..785116720bc6
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -0,0 +1,109 @@
1/**
2 * This file contains definition for USB interface.
3 */
4#define CMD_TYPE_REQUEST 0xF00DFACE
5#define CMD_TYPE_DATA 0xBEADC0DE
6#define CMD_TYPE_INDICATION 0xBEEFFACE
7
8#define IPFIELD_ALIGN_OFFSET 2
9
10#define USB8388_VID_1 0x1286
11#define USB8388_PID_1 0x2001
12#define USB8388_VID_2 0x05a3
13#define USB8388_PID_2 0x8388
14
15#ifdef SUPPORT_BOOT_COMMAND
16#define BOOT_CMD_FW_BY_USB 0x01
17#define BOOT_CMD_FW_IN_EEPROM 0x02
18#define BOOT_CMD_UPDATE_BOOT2 0x03
19#define BOOT_CMD_UPDATE_FW 0x04
20#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
21
22struct bootcmdstr
23{
24 u32 u32magicnumber;
25 u8 u8cmd_tag;
26 u8 au8dumy[11];
27};
28
29#define BOOT_CMD_RESP_OK 0x0001
30#define BOOT_CMD_RESP_FAIL 0x0000
31
32struct bootcmdrespStr
33{
34 u32 u32magicnumber;
35 u8 u8cmd_tag;
36 u8 u8result;
37 u8 au8dumy[2];
38};
39#endif /* SUPPORT_BOOT_COMMAND */
40
41/* read callback private data */
42struct read_cb_info {
43 wlan_private *priv;
44 struct sk_buff *skb;
45};
46
47/** USB card description structure*/
48struct usb_card_rec {
49 struct net_device *eth_dev;
50 struct usb_device *udev;
51 struct urb *rx_urb, *tx_urb;
52 void *priv;
53 struct read_cb_info rinfo;
54
55 int bulk_in_size;
56 u8 bulk_in_endpointAddr;
57
58 u8 *bulk_out_buffer;
59 int bulk_out_size;
60 u8 bulk_out_endpointAddr;
61
62 u8 CRC_OK;
63 u32 fwseqnum;
64 u32 lastseqnum;
65 u32 totalbytes;
66 u32 fwlastblksent;
67 u8 fwdnldover;
68 u8 fwfinalblk;
69
70 u32 usb_event_cause;
71 u8 usb_int_cause;
72
73 u8 rx_urb_recall;
74
75 u8 bootcmdresp;
76};
77
78/** fwheader */
79struct fwheader {
80 u32 dnldcmd;
81 u32 baseaddr;
82 u32 datalength;
83 u32 CRC;
84};
85
86#define FW_MAX_DATA_BLK_SIZE 600
87/** FWData */
88struct FWData {
89 struct fwheader fwheader;
90 u32 seqnum;
91 u8 data[FW_MAX_DATA_BLK_SIZE];
92};
93
94/** fwsyncheader */
95struct fwsyncheader {
96 u32 cmd;
97 u32 seqnum;
98};
99
100#define FW_HAS_DATA_TO_RECV 0x00000001
101#define FW_HAS_LAST_BLOCK 0x00000004
102
103#define FW_DATA_XMIT_SIZE \
104 sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32)
105
106int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
107void if_usb_free(struct usb_card_rec *cardp);
108int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
109
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644
index 000000000000..82b39642423a
--- /dev/null
+++ b/drivers/net/wireless/libertas/ioctl.c
@@ -0,0 +1,2500 @@
1/**
2 * This file contains ioctl functions
3 */
4
5#include <linux/ctype.h>
6#include <linux/delay.h>
7#include <linux/if.h>
8#include <linux/if_arp.h>
9#include <linux/wireless.h>
10
11#include <net/iw_handler.h>
12#include <net/ieee80211.h>
13
14#include "host.h"
15#include "radiotap.h"
16#include "decl.h"
17#include "defs.h"
18#include "dev.h"
19#include "join.h"
20#include "wext.h"
21
22#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
23 IW_ESSID_MAX_SIZE + \
24 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
25 IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
26 IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
27
28#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
29
30static int setrxantenna(wlan_private * priv, int mode)
31{
32 int ret = 0;
33 wlan_adapter *adapter = priv->adapter;
34
35 if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2
36 && mode != RF_ANTENNA_AUTO) {
37 return -EINVAL;
38 }
39
40 adapter->rxantennamode = mode;
41
42 lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
43
44 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
45 cmd_act_set_rx,
46 cmd_option_waitforrsp, 0,
47 &adapter->rxantennamode);
48 return ret;
49}
50
51static int settxantenna(wlan_private * priv, int mode)
52{
53 int ret = 0;
54 wlan_adapter *adapter = priv->adapter;
55
56 if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2)
57 && (mode != RF_ANTENNA_AUTO)) {
58 return -EINVAL;
59 }
60
61 adapter->txantennamode = mode;
62
63 lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
64
65 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
66 cmd_act_set_tx,
67 cmd_option_waitforrsp, 0,
68 &adapter->txantennamode);
69
70 return ret;
71}
72
73static int getrxantenna(wlan_private * priv, char *buf)
74{
75 int ret = 0;
76 wlan_adapter *adapter = priv->adapter;
77
78 // clear it, so we will know if the value
79 // returned below is correct or not.
80 adapter->rxantennamode = 0;
81
82 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
83 cmd_act_get_rx,
84 cmd_option_waitforrsp, 0, NULL);
85
86 if (ret) {
87 LEAVE();
88 return ret;
89 }
90
91 lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
92
93 return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
94}
95
96static int gettxantenna(wlan_private * priv, char *buf)
97{
98 int ret = 0;
99 wlan_adapter *adapter = priv->adapter;
100
101 // clear it, so we will know if the value
102 // returned below is correct or not.
103 adapter->txantennamode = 0;
104
105 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
106 cmd_act_get_tx,
107 cmd_option_waitforrsp, 0, NULL);
108
109 if (ret) {
110 LEAVE();
111 return ret;
112 }
113
114 lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
115
116 return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
117}
118
119static int wlan_set_region(wlan_private * priv, u16 region_code)
120{
121 int i;
122
123 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
124 // use the region code to search for the index
125 if (region_code == libertas_region_code_to_index[i]) {
126 priv->adapter->regiontableindex = (u16) i;
127 priv->adapter->regioncode = region_code;
128 break;
129 }
130 }
131
132 // if it's unidentified region code
133 if (i >= MRVDRV_MAX_REGION_CODE) {
134 lbs_pr_debug(1, "region Code not identified\n");
135 LEAVE();
136 return -1;
137 }
138
139 if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
140 LEAVE();
141 return -EINVAL;
142 }
143
144 return 0;
145}
146
147/**
148 * @brief Get/Set Firmware wakeup method
149 *
150 * @param priv A pointer to wlan_private structure
151 * @param wrq A pointer to user data
152 * @return 0--success, otherwise fail
153 */
154static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
155{
156 wlan_adapter *adapter = priv->adapter;
157 int data;
158 ENTER();
159
160 if ((int)wrq->u.data.length == 0) {
161 if (copy_to_user
162 (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) {
163 lbs_pr_alert("copy_to_user failed!\n");
164 return -EFAULT;
165 }
166 } else {
167 if ((int)wrq->u.data.length > 1) {
168 lbs_pr_alert("ioctl too many args!\n");
169 return -EFAULT;
170 }
171 if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
172 lbs_pr_alert("Copy from user failed\n");
173 return -EFAULT;
174 }
175
176 adapter->pkttxctrl = (u32) data;
177 }
178
179 wrq->u.data.length = 1;
180
181 LEAVE();
182 return 0;
183}
184
185/**
186 * @brief Get/Set NULL Package generation interval
187 *
188 * @param priv A pointer to wlan_private structure
189 * @param wrq A pointer to user data
190 * @return 0--success, otherwise fail
191 */
192static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
193{
194 wlan_adapter *adapter = priv->adapter;
195 int data;
196 ENTER();
197
198 if ((int)wrq->u.data.length == 0) {
199 data = adapter->nullpktinterval;
200
201 if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
202 lbs_pr_alert( "copy_to_user failed!\n");
203 return -EFAULT;
204 }
205 } else {
206 if ((int)wrq->u.data.length > 1) {
207 lbs_pr_alert( "ioctl too many args!\n");
208 return -EFAULT;
209 }
210 if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
211 lbs_pr_debug(1, "Copy from user failed\n");
212 return -EFAULT;
213 }
214
215 adapter->nullpktinterval = data;
216 }
217
218 wrq->u.data.length = 1;
219
220 LEAVE();
221 return 0;
222}
223
224static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
225{
226 wlan_adapter *adapter = priv->adapter;
227 int data[2];
228 ENTER();
229 data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
230 data[1] = adapter->rxpd_rate;
231 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
232 lbs_pr_debug(1, "Copy to user failed\n");
233 return -EFAULT;
234 }
235 wrq->u.data.length = 2;
236 LEAVE();
237 return 0;
238}
239
240static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
241{
242 int ret = 0;
243 wlan_adapter *adapter = priv->adapter;
244 int data[4];
245
246 ENTER();
247 memset(data, 0, sizeof(data));
248 if (wrq->u.data.length) {
249 if (copy_from_user(data, wrq->u.data.pointer,
250 min_t(size_t, wrq->u.data.length, 4) * sizeof(int)))
251 return -EFAULT;
252 }
253 if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
254 if (adapter->connect_status == libertas_connected) {
255 ret = libertas_prepare_and_send_command(priv,
256 cmd_802_11_rssi,
257 0,
258 cmd_option_waitforrsp,
259 0, NULL);
260
261 if (ret) {
262 LEAVE();
263 return ret;
264 }
265 }
266 }
267
268 if (wrq->u.data.length == 0) {
269 data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
270 data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
271 data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
272 data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
273 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4))
274 return -EFAULT;
275 wrq->u.data.length = 4;
276 } else if (data[0] == 0) {
277 data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
278 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
279 return -EFAULT;
280 wrq->u.data.length = 1;
281 } else if (data[0] == 1) {
282 data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
283 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
284 return -EFAULT;
285 wrq->u.data.length = 1;
286 } else if (data[0] == 2) {
287 data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
288 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
289 return -EFAULT;
290 wrq->u.data.length = 1;
291 } else if (data[0] == 3) {
292 data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
293 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
294 return -EFAULT;
295 wrq->u.data.length = 1;
296 } else
297 return -ENOTSUPP;
298
299 LEAVE();
300 return 0;
301}
302
303static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
304{
305 int data;
306 wlan_adapter *adapter = priv->adapter;
307
308 if (wrq->u.data.length > 0) {
309 if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
310 return -EFAULT;
311
312 lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data);
313 if ((data > MRVDRV_MAX_BEACON_INTERVAL)
314 || (data < MRVDRV_MIN_BEACON_INTERVAL))
315 return -ENOTSUPP;
316 adapter->beaconperiod = data;
317 }
318 data = adapter->beaconperiod;
319 if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int)))
320 return -EFAULT;
321
322 wrq->u.data.length = 1;
323
324 return 0;
325}
326
327static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
328{
329 int ret = 0;
330 wlan_adapter *adapter = priv->adapter;
331 int temp;
332 int data = 0;
333 int *val;
334
335 ENTER();
336 data = SUBCMD_DATA(wrq);
337 if ((data == 0) || (data == 1)) {
338 ret = libertas_prepare_and_send_command(priv,
339 cmd_802_11_rssi,
340 0, cmd_option_waitforrsp,
341 0, NULL);
342 if (ret) {
343 LEAVE();
344 return ret;
345 }
346 }
347
348 switch (data) {
349 case 0:
350
351 temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
352 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
353 break;
354 case 1:
355 temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG],
356 adapter->NF[TYPE_BEACON][TYPE_AVG]);
357 break;
358 case 2:
359 temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
360 adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
361 break;
362 case 3:
363 temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
364 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
365 break;
366 default:
367 return -ENOTSUPP;
368 }
369 val = (int *)wrq->u.name;
370 *val = temp;
371
372 LEAVE();
373 return 0;
374}
375
376static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
377{
378 int ret = 0;
379 wlan_adapter *adapter = priv->adapter;
380 int temp;
381 int data = 0;
382 int *val;
383
384 data = SUBCMD_DATA(wrq);
385 if ((data == 0) || (data == 1)) {
386 ret = libertas_prepare_and_send_command(priv,
387 cmd_802_11_rssi,
388 0, cmd_option_waitforrsp,
389 0, NULL);
390
391 if (ret) {
392 LEAVE();
393 return ret;
394 }
395 }
396
397 switch (data) {
398 case 0:
399 temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG];
400 break;
401 case 1:
402 temp = adapter->NF[TYPE_BEACON][TYPE_AVG];
403 break;
404 case 2:
405 temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG];
406 break;
407 case 3:
408 temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
409 break;
410 default:
411 return -ENOTSUPP;
412 }
413
414 temp = CAL_NF(temp);
415
416 lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
417 val = (int *)wrq->u.name;
418 *val = temp;
419 return 0;
420}
421
422static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
423{
424 wlan_adapter *adapter = priv->adapter;
425 int *pdata;
426 struct iwreq *wrq = (struct iwreq *)req;
427 int ret = 0;
428 adapter->txrate = 0;
429 lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
430 ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
431 cmd_act_get, cmd_option_waitforrsp,
432 0, NULL);
433 if (ret)
434 return ret;
435
436 pdata = (int *)wrq->u.name;
437 *pdata = (int)adapter->txrate;
438 return 0;
439}
440
441static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
442{
443 char status[64];
444 wlan_adapter *adapter = priv->adapter;
445
446 memset(status, 0, sizeof(status));
447
448 switch (adapter->inframode) {
449 case wlan802_11ibss:
450 if (adapter->connect_status == libertas_connected) {
451 if (adapter->adhoccreate)
452 memcpy(&status, "AdhocStarted", sizeof(status));
453 else
454 memcpy(&status, "AdhocJoined", sizeof(status));
455 } else {
456 memcpy(&status, "AdhocIdle", sizeof(status));
457 }
458 break;
459 case wlan802_11infrastructure:
460 memcpy(&status, "Inframode", sizeof(status));
461 break;
462 default:
463 memcpy(&status, "AutoUnknownmode", sizeof(status));
464 break;
465 }
466
467 lbs_pr_debug(1, "status = %s\n", status);
468 wrq->u.data.length = strlen(status) + 1;
469
470 if (wrq->u.data.pointer) {
471 if (copy_to_user(wrq->u.data.pointer,
472 &status, wrq->u.data.length))
473 return -EFAULT;
474 }
475
476 LEAVE();
477 return 0;
478}
479
480/**
481 * @brief Set/Get WPA IE
482 * @param priv A pointer to wlan_private structure
483 * @param req A pointer to ifreq structure
484 * @return 0 --success, otherwise fail
485 */
486static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req)
487{
488 struct iwreq *wrq = (struct iwreq *)req;
489 wlan_adapter *adapter = priv->adapter;
490 int ret = 0;
491
492 ENTER();
493
494 if (wrq->u.data.length) {
495 if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
496 lbs_pr_debug(1, "failed to copy WPA IE, too big \n");
497 return -EFAULT;
498 }
499 if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer,
500 wrq->u.data.length)) {
501 lbs_pr_debug(1, "failed to copy WPA IE \n");
502 return -EFAULT;
503 }
504 adapter->wpa_ie_len = wrq->u.data.length;
505 lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
506 adapter->wpa_ie[0]);
507 lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len);
508 if (adapter->wpa_ie[0] == WPA_IE)
509 adapter->secinfo.WPAenabled = 1;
510 else if (adapter->wpa_ie[0] == WPA2_IE)
511 adapter->secinfo.WPA2enabled = 1;
512 else {
513 adapter->secinfo.WPAenabled = 0;
514 adapter->secinfo.WPA2enabled = 0;
515 }
516 } else {
517 memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie));
518 adapter->wpa_ie_len = wrq->u.data.length;
519 lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n",
520 adapter->wpa_ie_len, adapter->wpa_ie[0]);
521 adapter->secinfo.WPAenabled = 0;
522 adapter->secinfo.WPA2enabled = 0;
523 }
524
525 // enable/disable RSN in firmware if WPA is enabled/disabled
526 // depending on variable adapter->secinfo.WPAenabled is set or not
527 ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn,
528 cmd_act_set, cmd_option_waitforrsp,
529 0, NULL);
530
531 LEAVE();
532 return ret;
533}
534
535/**
536 * @brief Set Auto prescan
537 * @param priv A pointer to wlan_private structure
538 * @param wrq A pointer to iwreq structure
539 * @return 0 --success, otherwise fail
540 */
541static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
542{
543 int data;
544 wlan_adapter *adapter = priv->adapter;
545 int *val;
546
547 data = SUBCMD_DATA(wrq);
548 lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
549 adapter->prescan = data;
550
551 val = (int *)wrq->u.name;
552 *val = data;
553 return 0;
554}
555
556static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
557{
558 struct iwreq *wrq = (struct iwreq *)req;
559 u32 mdtim;
560 int idata;
561 int ret = -EINVAL;
562
563 ENTER();
564
565 idata = SUBCMD_DATA(wrq);
566 mdtim = (u32) idata;
567 if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
568 && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
569 || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
570 priv->adapter->multipledtim = mdtim;
571 ret = 0;
572 }
573 if (ret)
574 lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n");
575
576 LEAVE();
577 return ret;
578}
579
580/**
581 * @brief Set authentication mode
582 * @param priv A pointer to wlan_private structure
583 * @param req A pointer to ifreq structure
584 * @return 0 --success, otherwise fail
585 */
586static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
587{
588 int alg;
589 struct iwreq *wrq = (struct iwreq *)req;
590 wlan_adapter *adapter = priv->adapter;
591
592 if (wrq->u.data.flags == 0) {
593 //from iwpriv subcmd
594 alg = SUBCMD_DATA(wrq);
595 } else {
596 //from wpa_supplicant subcmd
597 if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
598 lbs_pr_debug(1, "Copy from user failed\n");
599 return -EFAULT;
600 }
601 }
602
603 lbs_pr_debug(1, "auth alg is %#x\n", alg);
604
605 switch (alg) {
606 case AUTH_ALG_SHARED_KEY:
607 adapter->secinfo.authmode = wlan802_11authmodeshared;
608 break;
609 case AUTH_ALG_NETWORK_EAP:
610 adapter->secinfo.authmode =
611 wlan802_11authmodenetworkEAP;
612 break;
613 case AUTH_ALG_OPEN_SYSTEM:
614 default:
615 adapter->secinfo.authmode = wlan802_11authmodeopen;
616 break;
617 }
618 return 0;
619}
620
621/**
622 * @brief Set 802.1x authentication mode
623 * @param priv A pointer to wlan_private structure
624 * @param req A pointer to ifreq structure
625 * @return 0 --success, otherwise fail
626 */
627static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
628{
629 int alg;
630 struct iwreq *wrq = (struct iwreq *)req;
631
632 if (wrq->u.data.flags == 0) {
633 //from iwpriv subcmd
634 alg = SUBCMD_DATA(wrq);
635 } else {
636 //from wpa_supplicant subcmd
637 if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
638 lbs_pr_debug(1, "Copy from user failed\n");
639 return -EFAULT;
640 }
641 }
642 lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
643 priv->adapter->secinfo.auth1xalg = alg;
644 return 0;
645}
646
647static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
648{
649 int mode;
650 struct iwreq *wrq = (struct iwreq *)req;
651
652 ENTER();
653
654 if (wrq->u.data.flags == 0) {
655 //from iwpriv subcmd
656 mode = SUBCMD_DATA(wrq);
657 } else {
658 //from wpa_supplicant subcmd
659 if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
660 lbs_pr_debug(1, "Copy from user failed\n");
661 return -EFAULT;
662 }
663 }
664 lbs_pr_debug(1, "encryption mode is %#x\n", mode);
665 priv->adapter->secinfo.Encryptionmode = mode;
666
667 LEAVE();
668 return 0;
669}
670
671static void adjust_mtu(wlan_private * priv)
672{
673 int mtu_increment = 0;
674
675 if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
676 mtu_increment += sizeof(struct ieee80211_hdr_4addr);
677
678 if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
679 mtu_increment += max(sizeof(struct tx_radiotap_hdr),
680 sizeof(struct rx_radiotap_hdr));
681 priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
682 - sizeof(struct ethhdr)
683 + mtu_increment;
684}
685
686/**
687 * @brief Set Link-Layer Layer mode
688 * @param priv A pointer to wlan_private structure
689 * @param req A pointer to ifreq structure
690 * @return 0 --success, otherwise fail
691 */
692static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
693{
694 int mode;
695
696 mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
697
698 switch (mode) {
699 case WLAN_LINKMODE_802_3:
700 priv->adapter->linkmode = mode;
701 break;
702 case WLAN_LINKMODE_802_11:
703 priv->adapter->linkmode = mode;
704 break;
705 default:
706 lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
707 mode);
708 return -EINVAL;
709 break;
710 }
711 lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
712
713 adjust_mtu(priv);
714
715 return 0;
716}
717
718/**
719 * @brief Set Radio header mode
720 * @param priv A pointer to wlan_private structure
721 * @param req A pointer to ifreq structure
722 * @return 0 --success, otherwise fail
723 */
724static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
725{
726 int mode;
727
728 mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
729
730 switch (mode) {
731 case WLAN_RADIOMODE_NONE:
732 priv->adapter->radiomode = mode;
733 break;
734 case WLAN_RADIOMODE_RADIOTAP:
735 priv->adapter->radiomode = mode;
736 break;
737 default:
738 lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
739 mode);
740 return -EINVAL;
741 }
742 lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
743
744 adjust_mtu(priv);
745 return 0;
746}
747
748/**
749 * @brief Set Debug header mode
750 * @param priv A pointer to wlan_private structure
751 * @param req A pointer to ifreq structure
752 * @return 0 --success, otherwise fail
753 */
754static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
755{
756 priv->adapter->debugmode = (int)((struct ifreq *)
757 ((u8 *) req + 4))->ifr_data;
758 return 0;
759}
760
761static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
762 struct ifreq *req)
763{
764 int len;
765 char buf[8];
766 struct iwreq *wrq = (struct iwreq *)req;
767
768 lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n");
769 len = getrxantenna(priv, buf);
770
771 wrq->u.data.length = len;
772 if (wrq->u.data.pointer) {
773 if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
774 lbs_pr_debug(1, "CopyToUser failed\n");
775 return -EFAULT;
776 }
777 }
778
779 return 0;
780}
781
782static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
783 struct ifreq *req)
784{
785 int len;
786 char buf[8];
787 struct iwreq *wrq = (struct iwreq *)req;
788
789 lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n");
790 len = gettxantenna(priv, buf);
791
792 wrq->u.data.length = len;
793 if (wrq->u.data.pointer) {
794 if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
795 lbs_pr_debug(1, "CopyToUser failed\n");
796 return -EFAULT;
797 }
798 }
799 return 0;
800}
801
802/**
803 * @brief Get the MAC TSF value from the firmware
804 *
805 * @param priv A pointer to wlan_private structure
806 * @param wrq A pointer to iwreq structure containing buffer
807 * space to store a TSF value retrieved from the firmware
808 *
809 * @return 0 if successful; IOCTL error code otherwise
810 */
811static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
812{
813 u64 tsfval;
814 int ret;
815
816 ret = libertas_prepare_and_send_command(priv,
817 cmd_get_tsf,
818 0, cmd_option_waitforrsp, 0, &tsfval);
819
820 lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
821
822 if (ret != 0) {
823 lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n");
824 ret = -EFAULT;
825 } else {
826 if (copy_to_user(wrq->u.data.pointer,
827 &tsfval,
828 min_t(size_t, wrq->u.data.length,
829 sizeof(tsfval))) != 0) {
830
831 lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
832 ret = -EFAULT;
833 } else {
834 ret = 0;
835 }
836 }
837 return ret;
838}
839
840/**
841 * @brief Get/Set adapt rate
842 * @param priv A pointer to wlan_private structure
843 * @param wrq A pointer to iwreq structure
844 * @return 0 --success, otherwise fail
845 */
846static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
847{
848 int ret;
849 wlan_adapter *adapter = priv->adapter;
850 int data[2];
851
852 memset(data, 0, sizeof(data));
853 if (!wrq->u.data.length) {
854 lbs_pr_debug(1, "Get ADAPT RATE SET\n");
855 ret = libertas_prepare_and_send_command(priv,
856 cmd_802_11_rate_adapt_rateset,
857 cmd_act_get,
858 cmd_option_waitforrsp, 0, NULL);
859 data[0] = adapter->enablehwauto;
860 data[1] = adapter->ratebitmap;
861 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
862 lbs_pr_debug(1, "Copy to user failed\n");
863 return -EFAULT;
864 }
865#define GET_TWO_INT 2
866 wrq->u.data.length = GET_TWO_INT;
867 } else {
868 lbs_pr_debug(1, "Set ADAPT RATE SET\n");
869 if (wrq->u.data.length > 2)
870 return -EINVAL;
871 if (copy_from_user
872 (data, wrq->u.data.pointer,
873 sizeof(int) * wrq->u.data.length)) {
874 lbs_pr_debug(1, "Copy from user failed\n");
875 return -EFAULT;
876 }
877
878 adapter->enablehwauto = data[0];
879 adapter->ratebitmap = data[1];
880 ret = libertas_prepare_and_send_command(priv,
881 cmd_802_11_rate_adapt_rateset,
882 cmd_act_set,
883 cmd_option_waitforrsp, 0, NULL);
884 }
885 return ret;
886}
887
888/**
889 * @brief Get/Set inactivity timeout
890 * @param priv A pointer to wlan_private structure
891 * @param wrq A pointer to iwreq structure
892 * @return 0 --success, otherwise fail
893 */
894static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
895{
896 int ret;
897 int data = 0;
898 u16 timeout = 0;
899
900 ENTER();
901 if (wrq->u.data.length > 1)
902 return -ENOTSUPP;
903
904 if (wrq->u.data.length == 0) {
905 /* Get */
906 ret = libertas_prepare_and_send_command(priv,
907 cmd_802_11_inactivity_timeout,
908 cmd_act_get,
909 cmd_option_waitforrsp, 0,
910 &timeout);
911 data = timeout;
912 if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
913 lbs_pr_debug(1, "Copy to user failed\n");
914 return -EFAULT;
915 }
916 } else {
917 /* Set */
918 if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
919 lbs_pr_debug(1, "Copy from user failed\n");
920 return -EFAULT;
921 }
922
923 timeout = data;
924 ret = libertas_prepare_and_send_command(priv,
925 cmd_802_11_inactivity_timeout,
926 cmd_act_set,
927 cmd_option_waitforrsp, 0,
928 &timeout);
929 }
930
931 wrq->u.data.length = 1;
932
933 LEAVE();
934 return ret;
935}
936
937static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
938{
939 int ret;
940 char buf[GETLOG_BUFSIZE - 1];
941 wlan_adapter *adapter = priv->adapter;
942
943 lbs_pr_debug(1, " GET STATS\n");
944
945 ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
946 0, cmd_option_waitforrsp, 0, NULL);
947
948 if (ret) {
949 return ret;
950 }
951
952 if (wrq->u.data.pointer) {
953 sprintf(buf, "\n mcasttxframe %u failed %u retry %u "
954 "multiretry %u framedup %u "
955 "rtssuccess %u rtsfailure %u ackfailure %u\n"
956 "rxfrag %u mcastrxframe %u fcserror %u "
957 "txframe %u wepundecryptable %u ",
958 adapter->logmsg.mcasttxframe,
959 adapter->logmsg.failed,
960 adapter->logmsg.retry,
961 adapter->logmsg.multiretry,
962 adapter->logmsg.framedup,
963 adapter->logmsg.rtssuccess,
964 adapter->logmsg.rtsfailure,
965 adapter->logmsg.ackfailure,
966 adapter->logmsg.rxfrag,
967 adapter->logmsg.mcastrxframe,
968 adapter->logmsg.fcserror,
969 adapter->logmsg.txframe,
970 adapter->logmsg.wepundecryptable);
971 wrq->u.data.length = strlen(buf) + 1;
972 if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
973 lbs_pr_debug(1, "Copy to user failed\n");
974 return -EFAULT;
975 }
976 }
977
978 return 0;
979}
980
981static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
982{
983 u8 buf[12];
984 u8 *option[] = { "active", "passive", "get", };
985 int i, max_options = (sizeof(option) / sizeof(option[0]));
986 int ret = 0;
987 wlan_adapter *adapter = priv->adapter;
988
989 if (priv->adapter->enable11d) {
990 lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n");
991 return -EFAULT;
992 }
993
994 memset(buf, 0, sizeof(buf));
995
996 if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
997 wrq->u.data.length)))
998 return -EFAULT;
999
1000 lbs_pr_debug(1, "Scan type Option = %s\n", buf);
1001
1002 buf[sizeof(buf) - 1] = '\0';
1003
1004 for (i = 0; i < max_options; i++) {
1005 if (!strcmp(buf, option[i]))
1006 break;
1007 }
1008
1009 switch (i) {
1010 case 0:
1011 adapter->scantype = cmd_scan_type_active;
1012 break;
1013 case 1:
1014 adapter->scantype = cmd_scan_type_passive;
1015 break;
1016 case 2:
1017 wrq->u.data.length = strlen(option[adapter->scantype]) + 1;
1018
1019 if (copy_to_user(wrq->u.data.pointer,
1020 option[adapter->scantype],
1021 wrq->u.data.length)) {
1022 lbs_pr_debug(1, "Copy to user failed\n");
1023 ret = -EFAULT;
1024 }
1025
1026 break;
1027 default:
1028 lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
1029 ret = -EINVAL;
1030 break;
1031 }
1032
1033 return ret;
1034}
1035
1036static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
1037{
1038 wlan_adapter *adapter = priv->adapter;
1039 u8 buf[12];
1040 u8 *option[] = { "bss", "ibss", "any", "get" };
1041 int i, max_options = (sizeof(option) / sizeof(option[0]));
1042 int ret = 0;
1043
1044 ENTER();
1045
1046 memset(buf, 0, sizeof(buf));
1047
1048 if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
1049 wrq->u.data.length))) {
1050 lbs_pr_debug(1, "Copy from user failed\n");
1051 return -EFAULT;
1052 }
1053
1054 lbs_pr_debug(1, "Scan mode Option = %s\n", buf);
1055
1056 buf[sizeof(buf) - 1] = '\0';
1057
1058 for (i = 0; i < max_options; i++) {
1059 if (!strcmp(buf, option[i]))
1060 break;
1061 }
1062
1063 switch (i) {
1064
1065 case 0:
1066 adapter->scanmode = cmd_bss_type_bss;
1067 break;
1068 case 1:
1069 adapter->scanmode = cmd_bss_type_ibss;
1070 break;
1071 case 2:
1072 adapter->scanmode = cmd_bss_type_any;
1073 break;
1074 case 3:
1075
1076 wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
1077
1078 lbs_pr_debug(1, "Get Scan mode Option = %s\n",
1079 option[adapter->scanmode - 1]);
1080
1081 lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length);
1082
1083 if (copy_to_user(wrq->u.data.pointer,
1084 option[adapter->scanmode - 1],
1085 wrq->u.data.length)) {
1086 lbs_pr_debug(1, "Copy to user failed\n");
1087 ret = -EFAULT;
1088 }
1089 lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
1090 (char *)wrq->u.data.pointer);
1091
1092 break;
1093
1094 default:
1095 lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n");
1096 ret = -EINVAL;
1097 break;
1098 }
1099
1100 LEAVE();
1101 return ret;
1102}
1103
1104/**
1105 * @brief Get/Set Adhoc G Rate
1106 *
1107 * @param priv A pointer to wlan_private structure
1108 * @param wrq A pointer to user data
1109 * @return 0--success, otherwise fail
1110 */
1111static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
1112{
1113 wlan_adapter *adapter = priv->adapter;
1114 int data, data1;
1115 int *val;
1116
1117 ENTER();
1118
1119 data1 = SUBCMD_DATA(wrq);
1120 switch (data1) {
1121 case 0:
1122 adapter->adhoc_grate_enabled = 0;
1123 break;
1124 case 1:
1125 adapter->adhoc_grate_enabled = 1;
1126 break;
1127 case 2:
1128 break;
1129 default:
1130 return -EINVAL;
1131 }
1132 data = adapter->adhoc_grate_enabled;
1133 val = (int *)wrq->u.name;
1134 *val = data;
1135 LEAVE();
1136 return 0;
1137}
1138
1139static inline int hex2int(char c)
1140{
1141 if (c >= '0' && c <= '9')
1142 return (c - '0');
1143 if (c >= 'a' && c <= 'f')
1144 return (c - 'a' + 10);
1145 if (c >= 'A' && c <= 'F')
1146 return (c - 'A' + 10);
1147 return -1;
1148}
1149
1150/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
1151 into binary format (6 bytes).
1152
1153 This function expects that each byte is represented with 2 characters
1154 (e.g., 11:2:11:11:11:11 is invalid)
1155
1156 */
1157static char *eth_str2addr(char *ethstr, u8 * addr)
1158{
1159 int i, val, val2;
1160 char *pos = ethstr;
1161
1162 /* get rid of initial blanks */
1163 while (*pos == ' ' || *pos == '\t')
1164 ++pos;
1165
1166 for (i = 0; i < 6; i++) {
1167 val = hex2int(*pos++);
1168 if (val < 0)
1169 return NULL;
1170 val2 = hex2int(*pos++);
1171 if (val2 < 0)
1172 return NULL;
1173 addr[i] = (val * 16 + val2) & 0xff;
1174
1175 if (i < 5 && *pos++ != ':')
1176 return NULL;
1177 }
1178 return pos;
1179}
1180
1181/* this writes xx:xx:xx:xx:xx:xx into ethstr
1182 (ethstr must have space for 18 chars) */
1183static int eth_addr2str(u8 * addr, char *ethstr)
1184{
1185 int i;
1186 char *pos = ethstr;
1187
1188 for (i = 0; i < 6; i++) {
1189 sprintf(pos, "%02x", addr[i] & 0xff);
1190 pos += 2;
1191 if (i < 5)
1192 *pos++ = ':';
1193 }
1194 return 17;
1195}
1196
1197/**
1198 * @brief Add an entry to the BT table
1199 * @param priv A pointer to wlan_private structure
1200 * @param req A pointer to ifreq structure
1201 * @return 0 --success, otherwise fail
1202 */
1203static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
1204{
1205 struct iwreq *wrq = (struct iwreq *)req;
1206 char ethaddrs_str[18];
1207 char *pos;
1208 u8 ethaddr[ETH_ALEN];
1209
1210 ENTER();
1211 if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
1212 sizeof(ethaddrs_str)))
1213 return -EFAULT;
1214
1215 if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
1216 lbs_pr_info("BT_ADD: Invalid MAC address\n");
1217 return -EINVAL;
1218 }
1219
1220 lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
1221 LEAVE();
1222 return (libertas_prepare_and_send_command(priv, cmd_bt_access,
1223 cmd_act_bt_access_add,
1224 cmd_option_waitforrsp, 0, ethaddr));
1225}
1226
1227/**
1228 * @brief Delete an entry from the BT table
1229 * @param priv A pointer to wlan_private structure
1230 * @param req A pointer to ifreq structure
1231 * @return 0 --success, otherwise fail
1232 */
1233static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
1234{
1235 struct iwreq *wrq = (struct iwreq *)req;
1236 char ethaddrs_str[18];
1237 u8 ethaddr[ETH_ALEN];
1238 char *pos;
1239
1240 ENTER();
1241 if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
1242 sizeof(ethaddrs_str)))
1243 return -EFAULT;
1244
1245 if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
1246 lbs_pr_info("Invalid MAC address\n");
1247 return -EINVAL;
1248 }
1249
1250 lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
1251
1252 return (libertas_prepare_and_send_command(priv,
1253 cmd_bt_access,
1254 cmd_act_bt_access_del,
1255 cmd_option_waitforrsp, 0, ethaddr));
1256 LEAVE();
1257 return 0;
1258}
1259
1260/**
1261 * @brief Reset all entries from the BT table
1262 * @param priv A pointer to wlan_private structure
1263 * @return 0 --success, otherwise fail
1264 */
1265static int wlan_bt_reset_ioctl(wlan_private * priv)
1266{
1267 ENTER();
1268
1269 lbs_pr_alert( "BT: resetting\n");
1270
1271 return (libertas_prepare_and_send_command(priv,
1272 cmd_bt_access,
1273 cmd_act_bt_access_reset,
1274 cmd_option_waitforrsp, 0, NULL));
1275
1276 LEAVE();
1277 return 0;
1278}
1279
1280/**
1281 * @brief List an entry from the BT table
1282 * @param priv A pointer to wlan_private structure
1283 * @param req A pointer to ifreq structure
1284 * @return 0 --success, otherwise fail
1285 */
1286static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
1287{
1288 int pos;
1289 char *addr1;
1290 struct iwreq *wrq = (struct iwreq *)req;
1291 /* used to pass id and store the bt entry returned by the FW */
1292 union {
1293 int id;
1294 char addr1addr2[2 * ETH_ALEN];
1295 } param;
1296 static char outstr[64];
1297 char *pbuf = outstr;
1298 int ret;
1299
1300 ENTER();
1301
1302 if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
1303 lbs_pr_debug(1, "Copy from user failed\n");
1304 return -1;
1305 }
1306 param.id = simple_strtoul(outstr, NULL, 10);
1307 pos = sprintf(pbuf, "%d: ", param.id);
1308 pbuf += pos;
1309
1310 ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
1311 cmd_act_bt_access_list,
1312 cmd_option_waitforrsp, 0,
1313 (char *)&param);
1314
1315 if (ret == 0) {
1316 addr1 = param.addr1addr2;
1317
1318 pos = sprintf(pbuf, "ignoring traffic from ");
1319 pbuf += pos;
1320 pos = eth_addr2str(addr1, pbuf);
1321 pbuf += pos;
1322 } else {
1323 sprintf(pbuf, "(null)");
1324 pbuf += pos;
1325 }
1326
1327 wrq->u.data.length = strlen(outstr);
1328 if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
1329 wrq->u.data.length)) {
1330 lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
1331 return -EFAULT;
1332 }
1333
1334 LEAVE();
1335 return 0;
1336}
1337
1338/**
1339 * @brief Find the next parameter in an input string
1340 * @param ptr A pointer to the input parameter string
1341 * @return A pointer to the next parameter, or 0 if no parameters left.
1342 */
1343static char * next_param(char * ptr)
1344{
1345 if (!ptr) return NULL;
1346 while (*ptr == ' ' || *ptr == '\t') ++ptr;
1347 return (*ptr == '\0') ? NULL : ptr;
1348}
1349
1350/**
1351 * @brief Add an entry to the FWT table
1352 * @param priv A pointer to wlan_private structure
1353 * @param req A pointer to ifreq structure
1354 * @return 0 --success, otherwise fail
1355 */
1356static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
1357{
1358 struct iwreq *wrq = (struct iwreq *)req;
1359 char in_str[128];
1360 static struct cmd_ds_fwt_access fwt_access;
1361 char *ptr;
1362
1363 ENTER();
1364 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1365 return -EFAULT;
1366
1367 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
1368 lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
1369 return -EINVAL;
1370 }
1371
1372 if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
1373 lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
1374 return -EINVAL;
1375 }
1376
1377 if ((ptr = next_param(ptr)))
1378 fwt_access.metric =
1379 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1380 else
1381 fwt_access.metric = FWT_DEFAULT_METRIC;
1382
1383 if ((ptr = next_param(ptr)))
1384 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
1385 else
1386 fwt_access.dir = FWT_DEFAULT_DIR;
1387
1388 if ((ptr = next_param(ptr)))
1389 fwt_access.ssn =
1390 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1391 else
1392 fwt_access.ssn = FWT_DEFAULT_SSN;
1393
1394 if ((ptr = next_param(ptr)))
1395 fwt_access.dsn =
1396 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1397 else
1398 fwt_access.dsn = FWT_DEFAULT_DSN;
1399
1400 if ((ptr = next_param(ptr)))
1401 fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
1402 else
1403 fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
1404
1405 if ((ptr = next_param(ptr)))
1406 fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
1407 else
1408 fwt_access.ttl = FWT_DEFAULT_TTL;
1409
1410 if ((ptr = next_param(ptr)))
1411 fwt_access.expiration =
1412 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1413 else
1414 fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
1415
1416 if ((ptr = next_param(ptr)))
1417 fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
1418 else
1419 fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
1420
1421 if ((ptr = next_param(ptr)))
1422 fwt_access.snr =
1423 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1424 else
1425 fwt_access.snr = FWT_DEFAULT_SNR;
1426
1427#ifdef DEBUG
1428 {
1429 char ethaddr1_str[18], ethaddr2_str[18];
1430 eth_addr2str(fwt_access.da, ethaddr1_str);
1431 eth_addr2str(fwt_access.ra, ethaddr2_str);
1432 lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
1433 fwt_access.dir, ethaddr2_str);
1434 lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
1435 fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
1436 fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
1437 fwt_access.sleepmode, fwt_access.snr);
1438 }
1439#endif
1440
1441 LEAVE();
1442 return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
1443 cmd_act_fwt_access_add,
1444 cmd_option_waitforrsp, 0,
1445 (void *)&fwt_access));
1446}
1447
1448/**
1449 * @brief Delete an entry from the FWT table
1450 * @param priv A pointer to wlan_private structure
1451 * @param req A pointer to ifreq structure
1452 * @return 0 --success, otherwise fail
1453 */
1454static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
1455{
1456 struct iwreq *wrq = (struct iwreq *)req;
1457 char in_str[64];
1458 static struct cmd_ds_fwt_access fwt_access;
1459 char *ptr;
1460
1461 ENTER();
1462 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1463 return -EFAULT;
1464
1465 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
1466 lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
1467 return -EINVAL;
1468 }
1469
1470 if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
1471 lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
1472 return -EINVAL;
1473 }
1474
1475 if ((ptr = next_param(ptr)))
1476 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
1477 else
1478 fwt_access.dir = FWT_DEFAULT_DIR;
1479
1480#ifdef DEBUG
1481 {
1482 char ethaddr1_str[18], ethaddr2_str[18];
1483 lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
1484 eth_addr2str(fwt_access.da, ethaddr1_str);
1485 eth_addr2str(fwt_access.ra, ethaddr2_str);
1486 lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
1487 ethaddr2_str, fwt_access.dir);
1488 }
1489#endif
1490
1491 LEAVE();
1492 return (libertas_prepare_and_send_command(priv,
1493 cmd_fwt_access,
1494 cmd_act_fwt_access_del,
1495 cmd_option_waitforrsp, 0,
1496 (void *)&fwt_access));
1497}
1498
1499
1500/**
1501 * @brief Print route parameters
1502 * @param fwt_access struct cmd_ds_fwt_access with route info
1503 * @param buf destination buffer for route info
1504 */
1505static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
1506{
1507 buf += sprintf(buf, " ");
1508 buf += eth_addr2str(fwt_access.da, buf);
1509 buf += sprintf(buf, " ");
1510 buf += eth_addr2str(fwt_access.ra, buf);
1511 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
1512 buf += sprintf(buf, " %u", fwt_access.dir);
1513 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
1514 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
1515 buf += sprintf(buf, " %u", fwt_access.hopcount);
1516 buf += sprintf(buf, " %u", fwt_access.ttl);
1517 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
1518 buf += sprintf(buf, " %u", fwt_access.sleepmode);
1519 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
1520}
1521
1522/**
1523 * @brief Lookup an entry in the FWT table
1524 * @param priv A pointer to wlan_private structure
1525 * @param req A pointer to ifreq structure
1526 * @return 0 --success, otherwise fail
1527 */
1528static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
1529{
1530 struct iwreq *wrq = (struct iwreq *)req;
1531 char in_str[64];
1532 char *ptr;
1533 static struct cmd_ds_fwt_access fwt_access;
1534 static char out_str[128];
1535 int ret;
1536
1537 ENTER();
1538 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1539 return -EFAULT;
1540
1541 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
1542 lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
1543 return -EINVAL;
1544 }
1545
1546#ifdef DEBUG
1547 {
1548 char ethaddr1_str[18];
1549 lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
1550 eth_addr2str(fwt_access.da, ethaddr1_str);
1551 lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
1552 }
1553#endif
1554
1555 ret = libertas_prepare_and_send_command(priv,
1556 cmd_fwt_access,
1557 cmd_act_fwt_access_lookup,
1558 cmd_option_waitforrsp, 0,
1559 (void *)&fwt_access);
1560
1561 if (ret == 0)
1562 print_route(fwt_access, out_str);
1563 else
1564 sprintf(out_str, "(null)");
1565
1566 wrq->u.data.length = strlen(out_str);
1567 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
1568 wrq->u.data.length)) {
1569 lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
1570 return -EFAULT;
1571 }
1572
1573 LEAVE();
1574 return 0;
1575}
1576
1577/**
1578 * @brief Reset all entries from the FWT table
1579 * @param priv A pointer to wlan_private structure
1580 * @return 0 --success, otherwise fail
1581 */
1582static int wlan_fwt_reset_ioctl(wlan_private * priv)
1583{
1584 lbs_pr_debug(1, "FWT: resetting\n");
1585
1586 return (libertas_prepare_and_send_command(priv,
1587 cmd_fwt_access,
1588 cmd_act_fwt_access_reset,
1589 cmd_option_waitforrsp, 0, NULL));
1590}
1591
1592/**
1593 * @brief List an entry from the FWT table
1594 * @param priv A pointer to wlan_private structure
1595 * @param req A pointer to ifreq structure
1596 * @return 0 --success, otherwise fail
1597 */
1598static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
1599{
1600 struct iwreq *wrq = (struct iwreq *)req;
1601 char in_str[8];
1602 static struct cmd_ds_fwt_access fwt_access;
1603 char *ptr = in_str;
1604 static char out_str[128];
1605 char *pbuf = out_str;
1606 int ret;
1607
1608 ENTER();
1609 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1610 return -EFAULT;
1611
1612 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1613
1614#ifdef DEBUG
1615 {
1616 lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
1617 lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
1618 }
1619#endif
1620
1621 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
1622 cmd_act_fwt_access_list,
1623 cmd_option_waitforrsp, 0, (void *)&fwt_access);
1624
1625 if (ret == 0)
1626 print_route(fwt_access, pbuf);
1627 else
1628 pbuf += sprintf(pbuf, " (null)");
1629
1630 wrq->u.data.length = strlen(out_str);
1631 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
1632 wrq->u.data.length)) {
1633 lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
1634 return -EFAULT;
1635 }
1636
1637 LEAVE();
1638 return 0;
1639}
1640
1641/**
1642 * @brief List an entry from the FRT table
1643 * @param priv A pointer to wlan_private structure
1644 * @param req A pointer to ifreq structure
1645 * @return 0 --success, otherwise fail
1646 */
1647static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
1648{
1649 struct iwreq *wrq = (struct iwreq *)req;
1650 char in_str[64];
1651 static struct cmd_ds_fwt_access fwt_access;
1652 char *ptr = in_str;
1653 static char out_str[128];
1654 char *pbuf = out_str;
1655 int ret;
1656
1657 ENTER();
1658 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1659 return -EFAULT;
1660
1661 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1662
1663#ifdef DEBUG
1664 {
1665 lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
1666 lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
1667 }
1668#endif
1669
1670 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
1671 cmd_act_fwt_access_list_route,
1672 cmd_option_waitforrsp, 0, (void *)&fwt_access);
1673
1674 if (ret == 0) {
1675 pbuf += sprintf(pbuf, " ");
1676 pbuf += eth_addr2str(fwt_access.da, pbuf);
1677 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
1678 pbuf += sprintf(pbuf, " %u", fwt_access.dir);
1679 /* note that the firmware returns the nid in the id field */
1680 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
1681 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
1682 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
1683 pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount);
1684 pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl);
1685 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
1686 } else
1687 pbuf += sprintf(pbuf, " (null)");
1688
1689 wrq->u.data.length = strlen(out_str);
1690 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
1691 wrq->u.data.length)) {
1692 lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
1693 return -EFAULT;
1694 }
1695
1696 LEAVE();
1697 return 0;
1698}
1699
1700/**
1701 * @brief List an entry from the FNT table
1702 * @param priv A pointer to wlan_private structure
1703 * @param req A pointer to ifreq structure
1704 * @return 0 --success, otherwise fail
1705 */
1706static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
1707{
1708 struct iwreq *wrq = (struct iwreq *)req;
1709 char in_str[8];
1710 static struct cmd_ds_fwt_access fwt_access;
1711 char *ptr = in_str;
1712 static char out_str[128];
1713 char *pbuf = out_str;
1714 int ret;
1715
1716 ENTER();
1717 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
1718 return -EFAULT;
1719
1720 memset(&fwt_access, 0, sizeof(fwt_access));
1721 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
1722
1723#ifdef DEBUG
1724 {
1725 lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
1726 lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
1727 }
1728#endif
1729
1730 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
1731 cmd_act_fwt_access_list_neighbor,
1732 cmd_option_waitforrsp, 0,
1733 (void *)&fwt_access);
1734
1735 if (ret == 0) {
1736 pbuf += sprintf(pbuf, " ra ");
1737 pbuf += eth_addr2str(fwt_access.ra, pbuf);
1738 pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
1739 pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
1740 pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
1741 } else
1742 pbuf += sprintf(pbuf, " (null)");
1743
1744 wrq->u.data.length = strlen(out_str);
1745 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
1746 wrq->u.data.length)) {
1747 lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
1748 return -EFAULT;
1749 }
1750
1751 LEAVE();
1752 return 0;
1753}
1754
1755/**
1756 * @brief Cleans up the route (FRT) and neighbor (FNT) tables
1757 * (Garbage Collection)
1758 * @param priv A pointer to wlan_private structure
1759 * @param req A pointer to ifreq structure
1760 * @return 0 --success, otherwise fail
1761 */
1762static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
1763{
1764 static struct cmd_ds_fwt_access fwt_access;
1765 int ret;
1766
1767 ENTER();
1768
1769 lbs_pr_debug(1, "FWT: cleaning up\n");
1770
1771 memset(&fwt_access, 0, sizeof(fwt_access));
1772
1773 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
1774 cmd_act_fwt_access_cleanup,
1775 cmd_option_waitforrsp, 0,
1776 (void *)&fwt_access);
1777
1778 if (ret == 0)
1779 req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
1780 else
1781 return -EFAULT;
1782
1783 LEAVE();
1784 return 0;
1785}
1786
1787/**
1788 * @brief Gets firmware internal time (debug purposes)
1789 * @param priv A pointer to wlan_private structure
1790 * @param req A pointer to ifreq structure
1791 * @return 0 --success, otherwise fail
1792 */
1793static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
1794{
1795 static struct cmd_ds_fwt_access fwt_access;
1796 int ret;
1797
1798 ENTER();
1799
1800 lbs_pr_debug(1, "FWT: getting time\n");
1801
1802 memset(&fwt_access, 0, sizeof(fwt_access));
1803
1804 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
1805 cmd_act_fwt_access_time,
1806 cmd_option_waitforrsp, 0,
1807 (void *)&fwt_access);
1808
1809 if (ret == 0)
1810 req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
1811 else
1812 return -EFAULT;
1813
1814 LEAVE();
1815 return 0;
1816}
1817
1818/**
1819 * @brief Gets mesh ttl from firmware
1820 * @param priv A pointer to wlan_private structure
1821 * @param req A pointer to ifreq structure
1822 * @return 0 --success, otherwise fail
1823 */
1824static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
1825{
1826 struct cmd_ds_mesh_access mesh_access;
1827 int ret;
1828
1829 ENTER();
1830
1831 memset(&mesh_access, 0, sizeof(mesh_access));
1832
1833 ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
1834 cmd_act_mesh_get_ttl,
1835 cmd_option_waitforrsp, 0,
1836 (void *)&mesh_access);
1837
1838 if (ret == 0) {
1839 req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
1840 }
1841 else
1842 return -EFAULT;
1843
1844 LEAVE();
1845 return 0;
1846}
1847
1848/**
1849 * @brief Gets mesh ttl from firmware
1850 * @param priv A pointer to wlan_private structure
1851 * @param ttl New ttl value
1852 * @return 0 --success, otherwise fail
1853 */
1854static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
1855{
1856 struct cmd_ds_mesh_access mesh_access;
1857 int ret;
1858
1859 ENTER();
1860
1861 if( (ttl > 0xff) || (ttl < 0) )
1862 return -EINVAL;
1863
1864 memset(&mesh_access, 0, sizeof(mesh_access));
1865 mesh_access.data[0] = ttl;
1866
1867 ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
1868 cmd_act_mesh_set_ttl,
1869 cmd_option_waitforrsp, 0,
1870 (void *)&mesh_access);
1871
1872 if (ret != 0)
1873 ret = -EFAULT;
1874
1875 LEAVE();
1876 return ret;
1877}
1878
1879/**
1880 * @brief ioctl function - entry point
1881 *
1882 * @param dev A pointer to net_device structure
1883 * @param req A pointer to ifreq structure
1884 * @param cmd command
1885 * @return 0--success, otherwise fail
1886 */
1887int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
1888{
1889 int subcmd = 0;
1890 int idata = 0;
1891 int *pdata;
1892 int ret = 0;
1893 wlan_private *priv = dev->priv;
1894 wlan_adapter *adapter = priv->adapter;
1895 struct iwreq *wrq = (struct iwreq *)req;
1896
1897 ENTER();
1898
1899 lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
1900 switch (cmd) {
1901 case WLANSCAN_TYPE:
1902 lbs_pr_debug(1, "Scan type Ioctl\n");
1903 ret = wlan_scan_type_ioctl(priv, wrq);
1904 break;
1905
1906 case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
1907 switch (wrq->u.data.flags) {
1908 case WLANDEAUTH:
1909 lbs_pr_debug(1, "Deauth\n");
1910 libertas_send_deauth(priv);
1911 break;
1912
1913 case WLANADHOCSTOP:
1914 lbs_pr_debug(1, "Adhoc stop\n");
1915 ret = libertas_do_adhocstop_ioctl(priv);
1916 break;
1917
1918 case WLANRADIOON:
1919 wlan_radio_ioctl(priv, 1);
1920 break;
1921
1922 case WLANRADIOOFF:
1923 wlan_radio_ioctl(priv, 0);
1924 break;
1925 case WLANWLANIDLEON:
1926 libertas_idle_on(priv);
1927 break;
1928 case WLANWLANIDLEOFF:
1929 libertas_idle_off(priv);
1930 break;
1931 case WLAN_SUBCMD_BT_RESET: /* bt_reset */
1932 wlan_bt_reset_ioctl(priv);
1933 break;
1934 case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
1935 wlan_fwt_reset_ioctl(priv);
1936 break;
1937 } /* End of switch */
1938 break;
1939
1940 case WLANSETWPAIE:
1941 ret = wlan_setwpaie_ioctl(priv, req);
1942 break;
1943 case WLAN_SETINT_GETINT:
1944 /* The first 4 bytes of req->ifr_data is sub-ioctl number
1945 * after 4 bytes sits the payload.
1946 */
1947 subcmd = (int)req->ifr_data; //from iwpriv subcmd
1948 switch (subcmd) {
1949 case WLANNF:
1950 ret = wlan_get_nf(priv, wrq);
1951 break;
1952 case WLANRSSI:
1953 ret = wlan_get_rssi(priv, wrq);
1954 break;
1955 case WLANENABLE11D:
1956 ret = libertas_cmd_enable_11d(priv, wrq);
1957 break;
1958 case WLANADHOCGRATE:
1959 ret = wlan_do_set_grate_ioctl(priv, wrq);
1960 break;
1961 case WLAN_SUBCMD_SET_PRESCAN:
1962 ret = wlan_subcmd_setprescan_ioctl(priv, wrq);
1963 break;
1964 }
1965 break;
1966
1967 case WLAN_SETONEINT_GETONEINT:
1968 switch (wrq->u.data.flags) {
1969 case WLAN_BEACON_INTERVAL:
1970 ret = wlan_beacon_interval(priv, wrq);
1971 break;
1972
1973 case WLAN_LISTENINTRVL:
1974 if (!wrq->u.data.length) {
1975 int data;
1976 lbs_pr_debug(1, "Get locallisteninterval value\n");
1977#define GET_ONE_INT 1
1978 data = adapter->locallisteninterval;
1979 if (copy_to_user(wrq->u.data.pointer,
1980 &data, sizeof(int))) {
1981 lbs_pr_debug(1, "Copy to user failed\n");
1982 return -EFAULT;
1983 }
1984
1985 wrq->u.data.length = GET_ONE_INT;
1986 } else {
1987 int data;
1988 if (copy_from_user
1989 (&data, wrq->u.data.pointer, sizeof(int))) {
1990 lbs_pr_debug(1, "Copy from user failed\n");
1991 return -EFAULT;
1992 }
1993
1994 lbs_pr_debug(1, "Set locallisteninterval = %d\n",
1995 data);
1996#define MAX_U16_VAL 65535
1997 if (data > MAX_U16_VAL) {
1998 lbs_pr_debug(1, "Exceeds U16 value\n");
1999 return -EINVAL;
2000 }
2001 adapter->locallisteninterval = data;
2002 }
2003 break;
2004 case WLAN_TXCONTROL:
2005 ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl
2006 break;
2007
2008 case WLAN_NULLPKTINTERVAL:
2009 ret = wlan_null_pkt_interval(priv, wrq);
2010 break;
2011
2012 default:
2013 ret = -EOPNOTSUPP;
2014 break;
2015 }
2016 break;
2017
2018 case WLAN_SETONEINT_GETNONE:
2019 /* The first 4 bytes of req->ifr_data is sub-ioctl number
2020 * after 4 bytes sits the payload.
2021 */
2022 subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd
2023
2024 if (!subcmd)
2025 subcmd = (int)req->ifr_data; //from iwpriv subcmd
2026
2027 switch (subcmd) {
2028 case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
2029 idata = SUBCMD_DATA(wrq);
2030 ret = setrxantenna(priv, idata);
2031 break;
2032 case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
2033 idata = SUBCMD_DATA(wrq);
2034 ret = settxantenna(priv, idata);
2035 break;
2036 case WLAN_SET_ATIM_WINDOW:
2037 adapter->atimwindow = SUBCMD_DATA(wrq);
2038 adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
2039 break;
2040 case WLANSETBCNAVG:
2041 adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
2042 if (adapter->bcn_avg_factor == 0)
2043 adapter->bcn_avg_factor =
2044 DEFAULT_BCN_AVG_FACTOR;
2045 if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR)
2046 adapter->bcn_avg_factor =
2047 DEFAULT_BCN_AVG_FACTOR;
2048 break;
2049 case WLANSETDATAAVG:
2050 adapter->data_avg_factor = SUBCMD_DATA(wrq);
2051 if (adapter->data_avg_factor == 0)
2052 adapter->data_avg_factor =
2053 DEFAULT_DATA_AVG_FACTOR;
2054 if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR)
2055 adapter->data_avg_factor =
2056 DEFAULT_DATA_AVG_FACTOR;
2057 break;
2058 case WLANSETREGION:
2059 idata = SUBCMD_DATA(wrq);
2060 ret = wlan_set_region(priv, (u16) idata);
2061 break;
2062
2063 case WLAN_SET_LISTEN_INTERVAL:
2064 idata = SUBCMD_DATA(wrq);
2065 adapter->listeninterval = (u16) idata;
2066 break;
2067
2068 case WLAN_SET_MULTIPLE_DTIM:
2069 ret = wlan_set_multiple_dtim_ioctl(priv, req);
2070 break;
2071
2072 case WLANSETAUTHALG:
2073 ret = wlan_setauthalg_ioctl(priv, req);
2074 break;
2075
2076 case WLANSET8021XAUTHALG:
2077 ret = wlan_set8021xauthalg_ioctl(priv, req);
2078 break;
2079
2080 case WLANSETENCRYPTIONMODE:
2081 ret = wlan_setencryptionmode_ioctl(priv, req);
2082 break;
2083
2084 case WLAN_SET_LINKMODE:
2085 ret = wlan_set_linkmode_ioctl(priv, req);
2086 break;
2087
2088 case WLAN_SET_RADIOMODE:
2089 ret = wlan_set_radiomode_ioctl(priv, req);
2090 break;
2091
2092 case WLAN_SET_DEBUGMODE:
2093 ret = wlan_set_debugmode_ioctl(priv, req);
2094 break;
2095
2096 case WLAN_SUBCMD_MESH_SET_TTL:
2097 idata = SUBCMD_DATA(wrq);
2098 ret = wlan_mesh_set_ttl_ioctl(priv, idata);
2099 break;
2100
2101 default:
2102 ret = -EOPNOTSUPP;
2103 break;
2104 }
2105
2106 break;
2107
2108 case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */
2109 /*
2110 * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
2111 * in flags of iwreq structure, otherwise it will be in
2112 * mode member of iwreq structure.
2113 */
2114 switch ((int)wrq->u.data.flags) {
2115 case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
2116 ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
2117 break;
2118
2119 case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
2120 ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
2121 break;
2122
2123 case WLAN_GET_TSF:
2124 ret = wlan_get_tsf_ioctl(priv, wrq);
2125 break;
2126 }
2127 break;
2128
2129 case WLAN_SET128CHAR_GET128CHAR:
2130 switch ((int)wrq->u.data.flags) {
2131
2132 case WLANSCAN_MODE:
2133 lbs_pr_debug(1, "Scan mode Ioctl\n");
2134 ret = wlan_scan_mode_ioctl(priv, wrq);
2135 break;
2136
2137 case WLAN_GET_ADHOC_STATUS:
2138 ret = wlan_get_adhoc_status_ioctl(priv, wrq);
2139 break;
2140 case WLAN_SUBCMD_BT_ADD:
2141 ret = wlan_bt_add_ioctl(priv, req);
2142 break;
2143 case WLAN_SUBCMD_BT_DEL:
2144 ret = wlan_bt_del_ioctl(priv, req);
2145 break;
2146 case WLAN_SUBCMD_BT_LIST:
2147 ret = wlan_bt_list_ioctl(priv, req);
2148 break;
2149 case WLAN_SUBCMD_FWT_ADD:
2150 ret = wlan_fwt_add_ioctl(priv, req);
2151 break;
2152 case WLAN_SUBCMD_FWT_DEL:
2153 ret = wlan_fwt_del_ioctl(priv, req);
2154 break;
2155 case WLAN_SUBCMD_FWT_LOOKUP:
2156 ret = wlan_fwt_lookup_ioctl(priv, req);
2157 break;
2158 case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
2159 ret = wlan_fwt_list_neighbor_ioctl(priv, req);
2160 break;
2161 case WLAN_SUBCMD_FWT_LIST:
2162 ret = wlan_fwt_list_ioctl(priv, req);
2163 break;
2164 case WLAN_SUBCMD_FWT_LIST_ROUTE:
2165 ret = wlan_fwt_list_route_ioctl(priv, req);
2166 break;
2167 }
2168 break;
2169
2170 case WLAN_SETNONE_GETONEINT:
2171 switch ((int)req->ifr_data) {
2172 case WLANGETBCNAVG:
2173 pdata = (int *)wrq->u.name;
2174 *pdata = (int)adapter->bcn_avg_factor;
2175 break;
2176
2177 case WLANGETREGION:
2178 pdata = (int *)wrq->u.name;
2179 *pdata = (int)adapter->regioncode;
2180 break;
2181
2182 case WLAN_GET_LISTEN_INTERVAL:
2183 pdata = (int *)wrq->u.name;
2184 *pdata = (int)adapter->listeninterval;
2185 break;
2186
2187 case WLAN_GET_LINKMODE:
2188 req->ifr_data = (char *)((u32) adapter->linkmode);
2189 break;
2190
2191 case WLAN_GET_RADIOMODE:
2192 req->ifr_data = (char *)((u32) adapter->radiomode);
2193 break;
2194
2195 case WLAN_GET_DEBUGMODE:
2196 req->ifr_data = (char *)((u32) adapter->debugmode);
2197 break;
2198
2199 case WLAN_GET_MULTIPLE_DTIM:
2200 pdata = (int *)wrq->u.name;
2201 *pdata = (int)adapter->multipledtim;
2202 break;
2203 case WLAN_GET_TX_RATE:
2204 ret = wlan_get_txrate_ioctl(priv, req);
2205 break;
2206 case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
2207 ret = wlan_fwt_cleanup_ioctl(priv, req);
2208 break;
2209
2210 case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
2211 ret = wlan_fwt_time_ioctl(priv, req);
2212 break;
2213
2214 case WLAN_SUBCMD_MESH_GET_TTL:
2215 ret = wlan_mesh_get_ttl_ioctl(priv, req);
2216 break;
2217
2218 default:
2219 ret = -EOPNOTSUPP;
2220
2221 }
2222
2223 break;
2224
2225 case WLANGETLOG:
2226 ret = wlan_do_getlog_ioctl(priv, wrq);
2227 break;
2228
2229 case WLAN_SET_GET_SIXTEEN_INT:
2230 switch ((int)wrq->u.data.flags) {
2231 case WLAN_TPCCFG:
2232 {
2233 int data[5];
2234 struct cmd_ds_802_11_tpc_cfg cfg;
2235 memset(&cfg, 0, sizeof(cfg));
2236 if ((wrq->u.data.length > 1)
2237 && (wrq->u.data.length != 5))
2238 return -1;
2239
2240 if (wrq->u.data.length == 0) {
2241 cfg.action =
2242 cpu_to_le16
2243 (cmd_act_get);
2244 } else {
2245 if (copy_from_user
2246 (data, wrq->u.data.pointer,
2247 sizeof(int) * 5)) {
2248 lbs_pr_debug(1,
2249 "Copy from user failed\n");
2250 return -EFAULT;
2251 }
2252
2253 cfg.action =
2254 cpu_to_le16
2255 (cmd_act_set);
2256 cfg.enable = data[0];
2257 cfg.usesnr = data[1];
2258 cfg.P0 = data[2];
2259 cfg.P1 = data[3];
2260 cfg.P2 = data[4];
2261 }
2262
2263 ret =
2264 libertas_prepare_and_send_command(priv,
2265 cmd_802_11_tpc_cfg,
2266 0,
2267 cmd_option_waitforrsp,
2268 0, (void *)&cfg);
2269
2270 data[0] = cfg.enable;
2271 data[1] = cfg.usesnr;
2272 data[2] = cfg.P0;
2273 data[3] = cfg.P1;
2274 data[4] = cfg.P2;
2275 if (copy_to_user
2276 (wrq->u.data.pointer, data,
2277 sizeof(int) * 5)) {
2278 lbs_pr_debug(1, "Copy to user failed\n");
2279 return -EFAULT;
2280 }
2281
2282 wrq->u.data.length = 5;
2283 }
2284 break;
2285
2286 case WLAN_POWERCFG:
2287 {
2288 int data[4];
2289 struct cmd_ds_802_11_pwr_cfg cfg;
2290 memset(&cfg, 0, sizeof(cfg));
2291 if ((wrq->u.data.length > 1)
2292 && (wrq->u.data.length != 4))
2293 return -1;
2294 if (wrq->u.data.length == 0) {
2295 cfg.action =
2296 cpu_to_le16
2297 (cmd_act_get);
2298 } else {
2299 if (copy_from_user
2300 (data, wrq->u.data.pointer,
2301 sizeof(int) * 4)) {
2302 lbs_pr_debug(1,
2303 "Copy from user failed\n");
2304 return -EFAULT;
2305 }
2306
2307 cfg.action =
2308 cpu_to_le16
2309 (cmd_act_set);
2310 cfg.enable = data[0];
2311 cfg.PA_P0 = data[1];
2312 cfg.PA_P1 = data[2];
2313 cfg.PA_P2 = data[3];
2314 }
2315 ret =
2316 libertas_prepare_and_send_command(priv,
2317 cmd_802_11_pwr_cfg,
2318 0,
2319 cmd_option_waitforrsp,
2320 0, (void *)&cfg);
2321 data[0] = cfg.enable;
2322 data[1] = cfg.PA_P0;
2323 data[2] = cfg.PA_P1;
2324 data[3] = cfg.PA_P2;
2325 if (copy_to_user
2326 (wrq->u.data.pointer, data,
2327 sizeof(int) * 4)) {
2328 lbs_pr_debug(1, "Copy to user failed\n");
2329 return -EFAULT;
2330 }
2331
2332 wrq->u.data.length = 4;
2333 }
2334 break;
2335 case WLAN_AUTO_FREQ_SET:
2336 {
2337 int data[3];
2338 struct cmd_ds_802_11_afc afc;
2339 memset(&afc, 0, sizeof(afc));
2340 if (wrq->u.data.length != 3)
2341 return -1;
2342 if (copy_from_user
2343 (data, wrq->u.data.pointer,
2344 sizeof(int) * 3)) {
2345 lbs_pr_debug(1, "Copy from user failed\n");
2346 return -EFAULT;
2347 }
2348 afc.afc_auto = data[0];
2349
2350 if (afc.afc_auto != 0) {
2351 afc.threshold = data[1];
2352 afc.period = data[2];
2353 } else {
2354 afc.timing_offset = data[1];
2355 afc.carrier_offset = data[2];
2356 }
2357 ret =
2358 libertas_prepare_and_send_command(priv,
2359 cmd_802_11_set_afc,
2360 0,
2361 cmd_option_waitforrsp,
2362 0, (void *)&afc);
2363 }
2364 break;
2365 case WLAN_AUTO_FREQ_GET:
2366 {
2367 int data[3];
2368 struct cmd_ds_802_11_afc afc;
2369 memset(&afc, 0, sizeof(afc));
2370 ret =
2371 libertas_prepare_and_send_command(priv,
2372 cmd_802_11_get_afc,
2373 0,
2374 cmd_option_waitforrsp,
2375 0, (void *)&afc);
2376 data[0] = afc.afc_auto;
2377 data[1] = afc.timing_offset;
2378 data[2] = afc.carrier_offset;
2379 if (copy_to_user
2380 (wrq->u.data.pointer, data,
2381 sizeof(int) * 3)) {
2382 lbs_pr_debug(1, "Copy to user failed\n");
2383 return -EFAULT;
2384 }
2385
2386 wrq->u.data.length = 3;
2387 }
2388 break;
2389 case WLAN_SCANPROBES:
2390 {
2391 int data;
2392 if (wrq->u.data.length > 0) {
2393 if (copy_from_user
2394 (&data, wrq->u.data.pointer,
2395 sizeof(int))) {
2396 lbs_pr_debug(1,
2397 "Copy from user failed\n");
2398 return -EFAULT;
2399 }
2400
2401 adapter->scanprobes = data;
2402 } else {
2403 data = adapter->scanprobes;
2404 if (copy_to_user
2405 (wrq->u.data.pointer, &data,
2406 sizeof(int))) {
2407 lbs_pr_debug(1,
2408 "Copy to user failed\n");
2409 return -EFAULT;
2410 }
2411 }
2412 wrq->u.data.length = 1;
2413 }
2414 break;
2415 case WLAN_LED_GPIO_CTRL:
2416 {
2417 int i;
2418 int data[16];
2419
2420 struct cmd_ds_802_11_led_ctrl ctrl;
2421 struct mrvlietypes_ledgpio *gpio =
2422 (struct mrvlietypes_ledgpio *) ctrl.data;
2423
2424 memset(&ctrl, 0, sizeof(ctrl));
2425 if (wrq->u.data.length > MAX_LEDS * 2)
2426 return -ENOTSUPP;
2427 if ((wrq->u.data.length % 2) != 0)
2428 return -ENOTSUPP;
2429 if (wrq->u.data.length == 0) {
2430 ctrl.action =
2431 cpu_to_le16
2432 (cmd_act_get);
2433 } else {
2434 if (copy_from_user
2435 (data, wrq->u.data.pointer,
2436 sizeof(int) *
2437 wrq->u.data.length)) {
2438 lbs_pr_debug(1,
2439 "Copy from user failed\n");
2440 return -EFAULT;
2441 }
2442
2443 ctrl.action =
2444 cpu_to_le16
2445 (cmd_act_set);
2446 ctrl.numled = cpu_to_le16(0);
2447 gpio->header.type =
2448 cpu_to_le16(TLV_TYPE_LED_GPIO);
2449 gpio->header.len = wrq->u.data.length;
2450 for (i = 0; i < wrq->u.data.length;
2451 i += 2) {
2452 gpio->ledpin[i / 2].led =
2453 data[i];
2454 gpio->ledpin[i / 2].pin =
2455 data[i + 1];
2456 }
2457 }
2458 ret =
2459 libertas_prepare_and_send_command(priv,
2460 cmd_802_11_led_gpio_ctrl,
2461 0,
2462 cmd_option_waitforrsp,
2463 0, (void *)&ctrl);
2464 for (i = 0; i < gpio->header.len; i += 2) {
2465 data[i] = gpio->ledpin[i / 2].led;
2466 data[i + 1] = gpio->ledpin[i / 2].pin;
2467 }
2468 if (copy_to_user(wrq->u.data.pointer, data,
2469 sizeof(int) *
2470 gpio->header.len)) {
2471 lbs_pr_debug(1, "Copy to user failed\n");
2472 return -EFAULT;
2473 }
2474
2475 wrq->u.data.length = gpio->header.len;
2476 }
2477 break;
2478 case WLAN_ADAPT_RATESET:
2479 ret = wlan_adapt_rateset(priv, wrq);
2480 break;
2481 case WLAN_INACTIVITY_TIMEOUT:
2482 ret = wlan_inactivity_timeout(priv, wrq);
2483 break;
2484 case WLANSNR:
2485 ret = wlan_get_snr(priv, wrq);
2486 break;
2487 case WLAN_GET_RXINFO:
2488 ret = wlan_get_rxinfo(priv, wrq);
2489 }
2490 break;
2491
2492 default:
2493 ret = -EINVAL;
2494 break;
2495 }
2496 LEAVE();
2497 return ret;
2498}
2499
2500
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644
index 000000000000..11682cbe752b
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.c
@@ -0,0 +1,1055 @@
1/**
2 * Functions implementing wlan infrastructure and adhoc join routines,
3 * IOCTL handlers as well as command preperation and response routines
4 * for sending adhoc start, adhoc join, and association commands
5 * to the firmware.
6 */
7#include <linux/netdevice.h>
8#include <linux/if_arp.h>
9#include <linux/wireless.h>
10
11#include <net/iw_handler.h>
12
13#include "host.h"
14#include "decl.h"
15#include "join.h"
16#include "dev.h"
17
18/**
19 * @brief This function finds out the common rates between rate1 and rate2.
20 *
21 * It will fill common rates in rate1 as output if found.
22 *
23 * NOTE: Setting the MSB of the basic rates need to be taken
24 * care, either before or after calling this function
25 *
26 * @param adapter A pointer to wlan_adapter structure
27 * @param rate1 the buffer which keeps input and output
28 * @param rate1_size the size of rate1 buffer
29 * @param rate2 the buffer which keeps rate2
30 * @param rate2_size the size of rate2 buffer.
31 *
32 * @return 0 or -1
33 */
34static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
35 int rate1_size, u8 * rate2, int rate2_size)
36{
37 u8 *ptr = rate1;
38 int ret = 0;
39 u8 tmp[30];
40 int i;
41
42 memset(&tmp, 0, sizeof(tmp));
43 memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
44 memset(rate1, 0, rate1_size);
45
46 /* Mask the top bit of the original values */
47 for (i = 0; tmp[i] && i < sizeof(tmp); i++)
48 tmp[i] &= 0x7F;
49
50 for (i = 0; rate2[i] && i < rate2_size; i++) {
51 /* Check for Card Rate in tmp, excluding the top bit */
52 if (strchr(tmp, rate2[i] & 0x7F)) {
53 /* values match, so copy the Card Rate to rate1 */
54 *rate1++ = rate2[i];
55 }
56 }
57
58 lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
59 lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
60 lbs_dbg_hex("Common rates:", ptr, rate1_size);
61 lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
62
63 if (!adapter->is_datarate_auto) {
64 while (*ptr) {
65 if ((*ptr & 0x7f) == adapter->datarate) {
66 ret = 0;
67 goto done;
68 }
69 ptr++;
70 }
71 lbs_pr_alert( "Previously set fixed data rate %#x isn't "
72 "compatible with the network.\n", adapter->datarate);
73
74 ret = -1;
75 goto done;
76 }
77
78 ret = 0;
79done:
80 return ret;
81}
82
83int libertas_send_deauth(wlan_private * priv)
84{
85 wlan_adapter *adapter = priv->adapter;
86 int ret = 0;
87
88 if (adapter->inframode == wlan802_11infrastructure &&
89 adapter->connect_status == libertas_connected)
90 ret = libertas_send_deauthentication(priv);
91 else
92 ret = -ENOTSUPP;
93
94 return ret;
95}
96
97int libertas_do_adhocstop_ioctl(wlan_private * priv)
98{
99 wlan_adapter *adapter = priv->adapter;
100 int ret = 0;
101
102 if (adapter->inframode == wlan802_11ibss &&
103 adapter->connect_status == libertas_connected)
104 ret = libertas_stop_adhoc_network(priv);
105 else
106 ret = -ENOTSUPP;
107
108 return ret;
109}
110
111/**
112 * @brief Associate to a specific BSS discovered in a scan
113 *
114 * @param priv A pointer to wlan_private structure
115 * @param pbssdesc Pointer to the BSS descriptor to associate with.
116 *
117 * @return 0-success, otherwise fail
118 */
119int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
120{
121 wlan_adapter *adapter = priv->adapter;
122 int ret;
123
124 ENTER();
125
126 ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
127 0, cmd_option_waitforrsp,
128 0, pbssdesc->macaddress);
129
130 if (ret) {
131 LEAVE();
132 return ret;
133 }
134
135 /* set preamble to firmware */
136 if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
137 adapter->preamble = cmd_type_short_preamble;
138 else
139 adapter->preamble = cmd_type_long_preamble;
140
141 libertas_set_radio_control(priv);
142
143 ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
144 0, cmd_option_waitforrsp, 0, pbssdesc);
145
146 LEAVE();
147 return ret;
148}
149
150/**
151 * @brief Start an Adhoc Network
152 *
153 * @param priv A pointer to wlan_private structure
154 * @param adhocssid The ssid of the Adhoc Network
155 * @return 0--success, -1--fail
156 */
157int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
158{
159 wlan_adapter *adapter = priv->adapter;
160 int ret = 0;
161
162 adapter->adhoccreate = 1;
163
164 if (!adapter->capinfo.shortpreamble) {
165 lbs_pr_debug(1, "AdhocStart: Long preamble\n");
166 adapter->preamble = cmd_type_long_preamble;
167 } else {
168 lbs_pr_debug(1, "AdhocStart: Short preamble\n");
169 adapter->preamble = cmd_type_short_preamble;
170 }
171
172 libertas_set_radio_control(priv);
173
174 lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
175 lbs_pr_debug(1, "curbssparams.channel = %d\n",
176 adapter->curbssparams.channel);
177 lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
178
179 ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
180 0, cmd_option_waitforrsp, 0, adhocssid);
181
182 return ret;
183}
184
185/**
186 * @brief Join an adhoc network found in a previous scan
187 *
188 * @param priv A pointer to wlan_private structure
189 * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
190 * to attempt to join
191 *
192 * @return 0--success, -1--fail
193 */
194int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
195{
196 wlan_adapter *adapter = priv->adapter;
197 int ret = 0;
198
199 lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
200 adapter->curbssparams.ssid.ssid);
201 lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
202 adapter->curbssparams.ssid.ssidlength);
203 lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
204 lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n",
205 pbssdesc->ssid.ssidlength);
206
207 /* check if the requested SSID is already joined */
208 if (adapter->curbssparams.ssid.ssidlength
209 && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid)
210 && (adapter->curbssparams.bssdescriptor.inframode ==
211 wlan802_11ibss)) {
212
213 lbs_pr_debug(1,
214 "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
215 "not attempting to re-join");
216
217 return -1;
218 }
219
220 /*Use shortpreamble only when both creator and card supports
221 short preamble */
222 if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
223 lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
224 adapter->preamble = cmd_type_long_preamble;
225 } else {
226 lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
227 adapter->preamble = cmd_type_short_preamble;
228 }
229
230 libertas_set_radio_control(priv);
231
232 lbs_pr_debug(1, "curbssparams.channel = %d\n",
233 adapter->curbssparams.channel);
234 lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
235
236 adapter->adhoccreate = 0;
237
238 ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
239 0, cmd_option_waitforrsp,
240 OID_802_11_SSID, pbssdesc);
241
242 return ret;
243}
244
245int libertas_stop_adhoc_network(wlan_private * priv)
246{
247 return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
248 0, cmd_option_waitforrsp, 0, NULL);
249}
250
251/**
252 * @brief Send Deauthentication Request
253 *
254 * @param priv A pointer to wlan_private structure
255 * @return 0--success, -1--fail
256 */
257int libertas_send_deauthentication(wlan_private * priv)
258{
259 return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
260 0, cmd_option_waitforrsp, 0, NULL);
261}
262
263/**
264 * @brief Set Idle Off
265 *
266 * @param priv A pointer to wlan_private structure
267 * @return 0 --success, otherwise fail
268 */
269int libertas_idle_off(wlan_private * priv)
270{
271 wlan_adapter *adapter = priv->adapter;
272 int ret = 0;
273 const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
274 int i;
275
276 ENTER();
277
278 if (adapter->connect_status == libertas_disconnected) {
279 if (adapter->inframode == wlan802_11infrastructure) {
280 if (memcmp(adapter->previousbssid, zeromac,
281 sizeof(zeromac)) != 0) {
282
283 lbs_pr_debug(1, "Previous SSID = %s\n",
284 adapter->previousssid.ssid);
285 lbs_pr_debug(1, "Previous BSSID = "
286 "%02x:%02x:%02x:%02x:%02x:%02x:\n",
287 adapter->previousbssid[0],
288 adapter->previousbssid[1],
289 adapter->previousbssid[2],
290 adapter->previousbssid[3],
291 adapter->previousbssid[4],
292 adapter->previousbssid[5]);
293
294 i = libertas_find_SSID_in_list(adapter,
295 &adapter->previousssid,
296 adapter->previousbssid,
297 adapter->inframode);
298
299 if (i < 0) {
300 libertas_send_specific_BSSID_scan(priv,
301 adapter->
302 previousbssid,
303 1);
304 i = libertas_find_SSID_in_list(adapter,
305 &adapter->
306 previousssid,
307 adapter->
308 previousbssid,
309 adapter->
310 inframode);
311 }
312
313 if (i < 0) {
314 /* If the BSSID could not be found, try just the SSID */
315 i = libertas_find_SSID_in_list(adapter,
316 &adapter->
317 previousssid, NULL,
318 adapter->
319 inframode);
320 }
321
322 if (i < 0) {
323 libertas_send_specific_SSID_scan(priv,
324 &adapter->
325 previousssid,
326 1);
327 i = libertas_find_SSID_in_list(adapter,
328 &adapter->
329 previousssid, NULL,
330 adapter->
331 inframode);
332 }
333
334 if (i >= 0) {
335 ret =
336 wlan_associate(priv,
337 &adapter->
338 scantable[i]);
339 }
340 }
341 } else if (adapter->inframode == wlan802_11ibss) {
342 ret = libertas_prepare_and_send_command(priv,
343 cmd_802_11_ad_hoc_start,
344 0,
345 cmd_option_waitforrsp,
346 0, &adapter->previousssid);
347 }
348 }
349 /* else it is connected */
350
351 lbs_pr_debug(1, "\nwlanidle is off");
352 LEAVE();
353 return ret;
354}
355
356/**
357 * @brief Set Idle On
358 *
359 * @param priv A pointer to wlan_private structure
360 * @return 0 --success, otherwise fail
361 */
362int libertas_idle_on(wlan_private * priv)
363{
364 wlan_adapter *adapter = priv->adapter;
365 int ret = 0;
366
367 if (adapter->connect_status == libertas_connected) {
368 if (adapter->inframode == wlan802_11infrastructure) {
369 lbs_pr_debug(1, "Previous SSID = %s\n",
370 adapter->previousssid.ssid);
371 memmove(&adapter->previousssid,
372 &adapter->curbssparams.ssid,
373 sizeof(struct WLAN_802_11_SSID));
374 libertas_send_deauth(priv);
375
376 } else if (adapter->inframode == wlan802_11ibss) {
377 ret = libertas_stop_adhoc_network(priv);
378 }
379
380 }
381
382 lbs_pr_debug(1, "\nwlanidle is on");
383
384 return ret;
385}
386
387/**
388 * @brief This function prepares command of authenticate.
389 *
390 * @param priv A pointer to wlan_private structure
391 * @param cmd A pointer to cmd_ds_command structure
392 * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
393 *
394 * @return 0 or -1
395 */
396int libertas_cmd_80211_authenticate(wlan_private * priv,
397 struct cmd_ds_command *cmd,
398 void *pdata_buf)
399{
400 wlan_adapter *adapter = priv->adapter;
401 struct cmd_ds_802_11_authenticate *pauthenticate =
402 &cmd->params.auth;
403 u8 *bssid = pdata_buf;
404
405 cmd->command = cpu_to_le16(cmd_802_11_authenticate);
406 cmd->size =
407 cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
408 + S_DS_GEN);
409
410 pauthenticate->authtype = adapter->secinfo.authmode;
411 memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
412
413 lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
414 bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
415
416 return 0;
417}
418
419int libertas_cmd_80211_deauthenticate(wlan_private * priv,
420 struct cmd_ds_command *cmd)
421{
422 wlan_adapter *adapter = priv->adapter;
423 struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
424
425 ENTER();
426
427 cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
428 cmd->size =
429 cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
430 S_DS_GEN);
431
432 /* set AP MAC address */
433 memmove(dauth->macaddr, adapter->curbssparams.bssid,
434 ETH_ALEN);
435
436 /* Reason code 3 = Station is leaving */
437#define REASON_CODE_STA_LEAVING 3
438 dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
439
440 LEAVE();
441 return 0;
442}
443
444int libertas_cmd_80211_associate(wlan_private * priv,
445 struct cmd_ds_command *cmd, void *pdata_buf)
446{
447 wlan_adapter *adapter = priv->adapter;
448 struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
449 int ret = 0;
450 struct bss_descriptor *pbssdesc;
451 u8 *card_rates;
452 u8 *pos;
453 int card_rates_size;
454 u16 tmpcap;
455 struct mrvlietypes_ssidparamset *ssid;
456 struct mrvlietypes_phyparamset *phy;
457 struct mrvlietypes_ssparamset *ss;
458 struct mrvlietypes_ratesparamset *rates;
459 struct mrvlietypes_rsnparamset *rsn;
460
461 ENTER();
462
463 pbssdesc = pdata_buf;
464 pos = (u8 *) passo;
465
466 if (!adapter) {
467 ret = -1;
468 goto done;
469 }
470
471 cmd->command = cpu_to_le16(cmd_802_11_associate);
472
473 /* Save so we know which BSS Desc to use in the response handler */
474 adapter->pattemptedbssdesc = pbssdesc;
475
476 memcpy(passo->peerstaaddr,
477 pbssdesc->macaddress, sizeof(passo->peerstaaddr));
478 pos += sizeof(passo->peerstaaddr);
479
480 /* set the listen interval */
481 passo->listeninterval = adapter->listeninterval;
482
483 pos += sizeof(passo->capinfo);
484 pos += sizeof(passo->listeninterval);
485 pos += sizeof(passo->bcnperiod);
486 pos += sizeof(passo->dtimperiod);
487
488 ssid = (struct mrvlietypes_ssidparamset *) pos;
489 ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
490 ssid->header.len = pbssdesc->ssid.ssidlength;
491 memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
492 pos += sizeof(ssid->header) + ssid->header.len;
493 ssid->header.len = cpu_to_le16(ssid->header.len);
494
495 phy = (struct mrvlietypes_phyparamset *) pos;
496 phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
497 phy->header.len = sizeof(phy->fh_ds.dsparamset);
498 memcpy(&phy->fh_ds.dsparamset,
499 &pbssdesc->phyparamset.dsparamset.currentchan,
500 sizeof(phy->fh_ds.dsparamset));
501 pos += sizeof(phy->header) + phy->header.len;
502 phy->header.len = cpu_to_le16(phy->header.len);
503
504 ss = (struct mrvlietypes_ssparamset *) pos;
505 ss->header.type = cpu_to_le16(TLV_TYPE_CF);
506 ss->header.len = sizeof(ss->cf_ibss.cfparamset);
507 pos += sizeof(ss->header) + ss->header.len;
508 ss->header.len = cpu_to_le16(ss->header.len);
509
510 rates = (struct mrvlietypes_ratesparamset *) pos;
511 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
512
513 memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
514
515 card_rates = libertas_supported_rates;
516 card_rates_size = sizeof(libertas_supported_rates);
517
518 if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
519 card_rates, card_rates_size)) {
520 ret = -1;
521 goto done;
522 }
523
524 rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
525 adapter->curbssparams.numofrates = rates->header.len;
526
527 pos += sizeof(rates->header) + rates->header.len;
528 rates->header.len = cpu_to_le16(rates->header.len);
529
530 if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
531 rsn = (struct mrvlietypes_rsnparamset *) pos;
532 rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */
533 rsn->header.type = cpu_to_le16(rsn->header.type);
534 rsn->header.len = (u16) adapter->wpa_ie[1];
535 memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
536 lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
537 sizeof(rsn->header) + rsn->header.len);
538 pos += sizeof(rsn->header) + rsn->header.len;
539 rsn->header.len = cpu_to_le16(rsn->header.len);
540 }
541
542 /* update curbssparams */
543 adapter->curbssparams.channel =
544 (pbssdesc->phyparamset.dsparamset.currentchan);
545
546 /* Copy the infra. association rates into Current BSS state structure */
547 memcpy(&adapter->curbssparams.datarates, &rates->rates,
548 min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
549
550 lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
551
552 /* set IBSS field */
553 if (pbssdesc->inframode == wlan802_11infrastructure) {
554#define CAPINFO_ESS_MODE 1
555 passo->capinfo.ess = CAPINFO_ESS_MODE;
556 }
557
558 if (libertas_parse_dnld_countryinfo_11d(priv)) {
559 ret = -1;
560 goto done;
561 }
562
563 cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
564
565 /* set the capability info at last */
566 memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
567 tmpcap &= CAPINFO_MASK;
568 lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
569 tmpcap, CAPINFO_MASK);
570 tmpcap = cpu_to_le16(tmpcap);
571 memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
572
573 done:
574 LEAVE();
575 return ret;
576}
577
578int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
579 struct cmd_ds_command *cmd, void *pssid)
580{
581 wlan_adapter *adapter = priv->adapter;
582 struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
583 int ret = 0;
584 int cmdappendsize = 0;
585 int i;
586 u16 tmpcap;
587 struct bss_descriptor *pbssdesc;
588 struct WLAN_802_11_SSID *ssid = pssid;
589
590 ENTER();
591
592 if (!adapter) {
593 ret = -1;
594 goto done;
595 }
596
597 cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
598
599 pbssdesc = &adapter->curbssparams.bssdescriptor;
600 adapter->pattemptedbssdesc = pbssdesc;
601
602 /*
603 * Fill in the parameters for 2 data structures:
604 * 1. cmd_ds_802_11_ad_hoc_start command
605 * 2. adapter->scantable[i]
606 *
607 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
608 * probe delay, and cap info.
609 *
610 * Firmware will fill up beacon period, DTIM, Basic rates
611 * and operational rates.
612 */
613
614 memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
615
616 memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
617
618 lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
619
620 memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
621 memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
622
623 pbssdesc->ssid.ssidlength = ssid->ssidlength;
624
625 /* set the BSS type */
626 adhs->bsstype = cmd_bss_type_ibss;
627 pbssdesc->inframode = wlan802_11ibss;
628 adhs->beaconperiod = adapter->beaconperiod;
629
630 /* set Physical param set */
631#define DS_PARA_IE_ID 3
632#define DS_PARA_IE_LEN 1
633
634 adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
635 adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
636
637 WARN_ON(!adapter->adhocchannel);
638
639 lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
640 adapter->adhocchannel);
641
642 adapter->curbssparams.channel = adapter->adhocchannel;
643
644 pbssdesc->channel = adapter->adhocchannel;
645 adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
646
647 memcpy(&pbssdesc->phyparamset,
648 &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
649
650 /* set IBSS param set */
651#define IBSS_PARA_IE_ID 6
652#define IBSS_PARA_IE_LEN 2
653
654 adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
655 adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
656 adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
657 memcpy(&pbssdesc->ssparamset,
658 &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
659
660 /* set capability info */
661 adhs->cap.ess = 0;
662 adhs->cap.ibss = 1;
663 pbssdesc->cap.ibss = 1;
664
665 /* probedelay */
666 adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
667
668 /* set up privacy in adapter->scantable[i] */
669 if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
670
671#define AD_HOC_CAP_PRIVACY_ON 1
672 lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
673 pbssdesc->privacy = wlan802_11privfilter8021xWEP;
674 adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
675 } else {
676 lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
677 "privacy to ACCEPT ALL\n");
678 pbssdesc->privacy = wlan802_11privfilteracceptall;
679 }
680
681 memset(adhs->datarate, 0, sizeof(adhs->datarate));
682
683 if (adapter->adhoc_grate_enabled) {
684 memcpy(adhs->datarate, libertas_adhoc_rates_g,
685 min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
686 } else {
687 memcpy(adhs->datarate, libertas_adhoc_rates_b,
688 min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
689 }
690
691 /* Find the last non zero */
692 for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
693
694 adapter->curbssparams.numofrates = i;
695
696 /* Copy the ad-hoc creating rates into Current BSS state structure */
697 memcpy(&adapter->curbssparams.datarates,
698 &adhs->datarate, adapter->curbssparams.numofrates);
699
700 lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
701 adhs->datarate[0], adhs->datarate[1],
702 adhs->datarate[2], adhs->datarate[3]);
703
704 lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
705
706 if (libertas_create_dnld_countryinfo_11d(priv)) {
707 lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
708 ret = -1;
709 goto done;
710 }
711
712 cmd->size =
713 cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
714 + S_DS_GEN + cmdappendsize);
715
716 memcpy(&tmpcap, &adhs->cap, sizeof(u16));
717 tmpcap = cpu_to_le16(tmpcap);
718 memcpy(&adhs->cap, &tmpcap, sizeof(u16));
719
720 ret = 0;
721done:
722 LEAVE();
723 return ret;
724}
725
726int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
727 struct cmd_ds_command *cmd)
728{
729 cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
730 cmd->size = cpu_to_le16(S_DS_GEN);
731
732 return 0;
733}
734
735int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
736 struct cmd_ds_command *cmd, void *pdata_buf)
737{
738 wlan_adapter *adapter = priv->adapter;
739 struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
740 struct bss_descriptor *pbssdesc = pdata_buf;
741 int cmdappendsize = 0;
742 int ret = 0;
743 u8 *card_rates;
744 int card_rates_size;
745 u16 tmpcap;
746 int i;
747
748 ENTER();
749
750 adapter->pattemptedbssdesc = pbssdesc;
751
752 cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
753
754 padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
755
756 padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
757
758 memcpy(&padhocjoin->bssdescriptor.BSSID,
759 &pbssdesc->macaddress, ETH_ALEN);
760
761 memcpy(&padhocjoin->bssdescriptor.SSID,
762 &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
763
764 memcpy(&padhocjoin->bssdescriptor.phyparamset,
765 &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
766
767 memcpy(&padhocjoin->bssdescriptor.ssparamset,
768 &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
769
770 memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
771 tmpcap &= CAPINFO_MASK;
772
773 lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
774 tmpcap, CAPINFO_MASK);
775 memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
776 sizeof(struct ieeetypes_capinfo));
777
778 /* information on BSSID descriptor passed to FW */
779 lbs_pr_debug(1,
780 "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
781 padhocjoin->bssdescriptor.BSSID[0],
782 padhocjoin->bssdescriptor.BSSID[1],
783 padhocjoin->bssdescriptor.BSSID[2],
784 padhocjoin->bssdescriptor.BSSID[3],
785 padhocjoin->bssdescriptor.BSSID[4],
786 padhocjoin->bssdescriptor.BSSID[5],
787 padhocjoin->bssdescriptor.SSID);
788
789 lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
790 (u32) padhocjoin->bssdescriptor.datarates);
791
792 /* failtimeout */
793 padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
794
795 /* probedelay */
796 padhocjoin->probedelay =
797 cpu_to_le16(cmd_scan_probe_delay_time);
798
799 /* Copy Data rates from the rates recorded in scan response */
800 memset(padhocjoin->bssdescriptor.datarates, 0,
801 sizeof(padhocjoin->bssdescriptor.datarates));
802 memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
803 min(sizeof(padhocjoin->bssdescriptor.datarates),
804 sizeof(pbssdesc->datarates)));
805
806 card_rates = libertas_supported_rates;
807 card_rates_size = sizeof(libertas_supported_rates);
808
809 adapter->curbssparams.channel = pbssdesc->channel;
810
811 if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
812 sizeof(padhocjoin->bssdescriptor.datarates),
813 card_rates, card_rates_size)) {
814 lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
815 ret = -1;
816 goto done;
817 }
818
819 /* Find the last non zero */
820 for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
821 && padhocjoin->bssdescriptor.datarates[i]; i++) ;
822
823 adapter->curbssparams.numofrates = i;
824
825 /*
826 * Copy the adhoc joining rates to Current BSS State structure
827 */
828 memcpy(adapter->curbssparams.datarates,
829 padhocjoin->bssdescriptor.datarates,
830 adapter->curbssparams.numofrates);
831
832 padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
833 cpu_to_le16(pbssdesc->atimwindow);
834
835 if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
836 padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
837 }
838
839 if (adapter->psmode == wlan802_11powermodemax_psp) {
840 /* wake up first */
841 enum WLAN_802_11_POWER_MODE Localpsmode;
842
843 Localpsmode = wlan802_11powermodecam;
844 ret = libertas_prepare_and_send_command(priv,
845 cmd_802_11_ps_mode,
846 cmd_act_set,
847 0, 0, &Localpsmode);
848
849 if (ret) {
850 ret = -1;
851 goto done;
852 }
853 }
854
855 if (libertas_parse_dnld_countryinfo_11d(priv)) {
856 ret = -1;
857 goto done;
858 }
859
860 cmd->size =
861 cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
862 + S_DS_GEN + cmdappendsize);
863
864 memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
865 sizeof(struct ieeetypes_capinfo));
866 tmpcap = cpu_to_le16(tmpcap);
867
868 memcpy(&padhocjoin->bssdescriptor.cap,
869 &tmpcap, sizeof(struct ieeetypes_capinfo));
870
871 done:
872 LEAVE();
873 return ret;
874}
875
876int libertas_ret_80211_associate(wlan_private * priv,
877 struct cmd_ds_command *resp)
878{
879 wlan_adapter *adapter = priv->adapter;
880 int ret = 0;
881 union iwreq_data wrqu;
882 struct ieeetypes_assocrsp *passocrsp;
883 struct bss_descriptor *pbssdesc;
884
885 ENTER();
886
887 passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
888
889 if (passocrsp->statuscode) {
890
891 libertas_mac_event_disconnected(priv);
892
893 lbs_pr_debug(1,
894 "ASSOC_RESP: Association failed, status code = %d\n",
895 passocrsp->statuscode);
896
897 ret = -1;
898 goto done;
899 }
900
901 lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
902 le16_to_cpu(resp->size) - S_DS_GEN);
903
904 /* Send a Media Connected event, according to the Spec */
905 adapter->connect_status = libertas_connected;
906
907 /* Set the attempted BSSID Index to current */
908 pbssdesc = adapter->pattemptedbssdesc;
909
910 lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
911
912 /* Set the new SSID to current SSID */
913 memcpy(&adapter->curbssparams.ssid,
914 &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
915
916 /* Set the new BSSID (AP's MAC address) to current BSSID */
917 memcpy(adapter->curbssparams.bssid,
918 pbssdesc->macaddress, ETH_ALEN);
919
920 /* Make a copy of current BSSID descriptor */
921 memcpy(&adapter->curbssparams.bssdescriptor,
922 pbssdesc, sizeof(struct bss_descriptor));
923
924 lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
925 adapter->currentpacketfilter);
926
927 adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
928 adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
929
930 memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
931 memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
932 adapter->nextSNRNF = 0;
933 adapter->numSNRNF = 0;
934
935 netif_carrier_on(priv->wlan_dev.netdev);
936 netif_wake_queue(priv->wlan_dev.netdev);
937
938 lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
939
940 memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
941 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
942 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
943
944 done:
945 LEAVE();
946 return ret;
947}
948
949int libertas_ret_80211_disassociate(wlan_private * priv,
950 struct cmd_ds_command *resp)
951{
952 ENTER();
953
954 libertas_mac_event_disconnected(priv);
955
956 LEAVE();
957 return 0;
958}
959
960int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
961 struct cmd_ds_command *resp)
962{
963 wlan_adapter *adapter = priv->adapter;
964 int ret = 0;
965 u16 command = le16_to_cpu(resp->command);
966 u16 result = le16_to_cpu(resp->result);
967 struct cmd_ds_802_11_ad_hoc_result *padhocresult;
968 union iwreq_data wrqu;
969 struct bss_descriptor *pbssdesc;
970
971 ENTER();
972
973 padhocresult = &resp->params.result;
974
975 lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
976 lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
977 lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
978
979 pbssdesc = adapter->pattemptedbssdesc;
980
981 /*
982 * Join result code 0 --> SUCCESS
983 */
984 if (result) {
985 lbs_pr_debug(1, "ADHOC_RESP failed\n");
986 if (adapter->connect_status == libertas_connected) {
987 libertas_mac_event_disconnected(priv);
988 }
989
990 memset(&adapter->curbssparams.bssdescriptor,
991 0x00, sizeof(adapter->curbssparams.bssdescriptor));
992
993 LEAVE();
994 return -1;
995 }
996
997 /*
998 * Now the join cmd should be successful
999 * If BSSID has changed use SSID to compare instead of BSSID
1000 */
1001 lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid);
1002
1003 /* Send a Media Connected event, according to the Spec */
1004 adapter->connect_status = libertas_connected;
1005
1006 if (command == cmd_ret_802_11_ad_hoc_start) {
1007 /* Update the created network descriptor with the new BSSID */
1008 memcpy(pbssdesc->macaddress,
1009 padhocresult->BSSID, ETH_ALEN);
1010 } else {
1011
1012 /* Make a copy of current BSSID descriptor, only needed for join since
1013 * the current descriptor is already being used for adhoc start
1014 */
1015 memmove(&adapter->curbssparams.bssdescriptor,
1016 pbssdesc, sizeof(struct bss_descriptor));
1017 }
1018
1019 /* Set the BSSID from the joined/started descriptor */
1020 memcpy(&adapter->curbssparams.bssid,
1021 pbssdesc->macaddress, ETH_ALEN);
1022
1023 /* Set the new SSID to current SSID */
1024 memcpy(&adapter->curbssparams.ssid,
1025 &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
1026
1027 netif_carrier_on(priv->wlan_dev.netdev);
1028 netif_wake_queue(priv->wlan_dev.netdev);
1029
1030 memset(&wrqu, 0, sizeof(wrqu));
1031 memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
1032 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1033 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
1034
1035 lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
1036 lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
1037 lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
1038 padhocresult->BSSID[0], padhocresult->BSSID[1],
1039 padhocresult->BSSID[2], padhocresult->BSSID[3],
1040 padhocresult->BSSID[4], padhocresult->BSSID[5]);
1041
1042 LEAVE();
1043 return ret;
1044}
1045
1046int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
1047 struct cmd_ds_command *resp)
1048{
1049 ENTER();
1050
1051 libertas_mac_event_disconnected(priv);
1052
1053 LEAVE();
1054 return 0;
1055}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644
index 000000000000..8efa2455af9a
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.h
@@ -0,0 +1,64 @@
1/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
2/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
3
4/**
5 * Interface for the wlan infrastructure and adhoc join routines
6 *
7 * Driver interface functions and type declarations for the join module
8 * implemented in wlan_join.c. Process all start/join requests for
9 * both adhoc and infrastructure networks
10 */
11#ifndef _WLAN_JOIN_H
12#define _WLAN_JOIN_H
13
14#include "defs.h"
15
16struct cmd_ds_command;
17extern int libertas_cmd_80211_authenticate(wlan_private * priv,
18 struct cmd_ds_command *cmd,
19 void *pdata_buf);
20extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
21 struct cmd_ds_command *cmd,
22 void *pdata_buf);
23extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
24 struct cmd_ds_command *cmd);
25extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
26 struct cmd_ds_command *cmd,
27 void *pssid);
28extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
29 struct cmd_ds_command *cmd);
30extern int libertas_cmd_80211_associate(wlan_private * priv,
31 struct cmd_ds_command *cmd,
32 void *pdata_buf);
33
34extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
35 struct cmd_ds_command *resp);
36extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
37 struct cmd_ds_command *resp);
38extern int libertas_ret_80211_disassociate(wlan_private * priv,
39 struct cmd_ds_command *resp);
40extern int libertas_ret_80211_associate(wlan_private * priv,
41 struct cmd_ds_command *resp);
42
43extern int libertas_idle_on(wlan_private * priv);
44extern int libertas_idle_off(wlan_private * priv);
45
46extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
47extern int libertas_reassociation_thread(void *data);
48
49struct WLAN_802_11_SSID;
50struct bss_descriptor;
51
52extern int libertas_start_adhoc_network(wlan_private * priv,
53 struct WLAN_802_11_SSID *adhocssid);
54extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc);
55extern int libertas_stop_adhoc_network(wlan_private * priv);
56
57extern int libertas_send_deauthentication(wlan_private * priv);
58extern int libertas_send_deauth(wlan_private * priv);
59
60extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
61
62int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
63
64#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644
index 000000000000..497046530117
--- /dev/null
+++ b/drivers/net/wireless/libertas/main.c
@@ -0,0 +1,1258 @@
1/**
2 * This file contains the major functions in WLAN
3 * driver. It includes init, exit, open, close and main
4 * thread etc..
5 */
6
7#include <linux/delay.h>
8#include <linux/freezer.h>
9#include <linux/etherdevice.h>
10#include <linux/netdevice.h>
11#include <linux/if_arp.h>
12
13#include <net/iw_handler.h>
14
15#include "host.h"
16#include "sbi.h"
17#include "decl.h"
18#include "dev.h"
19#include "fw.h"
20#include "wext.h"
21#include "debugfs.h"
22#include "assoc.h"
23
24#ifdef ENABLE_PM
25static struct pm_dev *wlan_pm_dev = NULL;
26#endif
27
28#define WLAN_TX_PWR_DEFAULT 20 /*100mW */
29#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
30#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
31#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */
32#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
33
34/* Format { channel, frequency (MHz), maxtxpower } */
35/* band: 'B/G', region: USA FCC/Canada IC */
36static struct chan_freq_power channel_freq_power_US_BG[] = {
37 {1, 2412, WLAN_TX_PWR_US_DEFAULT},
38 {2, 2417, WLAN_TX_PWR_US_DEFAULT},
39 {3, 2422, WLAN_TX_PWR_US_DEFAULT},
40 {4, 2427, WLAN_TX_PWR_US_DEFAULT},
41 {5, 2432, WLAN_TX_PWR_US_DEFAULT},
42 {6, 2437, WLAN_TX_PWR_US_DEFAULT},
43 {7, 2442, WLAN_TX_PWR_US_DEFAULT},
44 {8, 2447, WLAN_TX_PWR_US_DEFAULT},
45 {9, 2452, WLAN_TX_PWR_US_DEFAULT},
46 {10, 2457, WLAN_TX_PWR_US_DEFAULT},
47 {11, 2462, WLAN_TX_PWR_US_DEFAULT}
48};
49
50/* band: 'B/G', region: Europe ETSI */
51static struct chan_freq_power channel_freq_power_EU_BG[] = {
52 {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
53 {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
54 {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
55 {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
56 {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
57 {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
58 {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
59 {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
60 {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
61 {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
62 {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
63 {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
64 {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
65};
66
67/* band: 'B/G', region: Spain */
68static struct chan_freq_power channel_freq_power_SPN_BG[] = {
69 {10, 2457, WLAN_TX_PWR_DEFAULT},
70 {11, 2462, WLAN_TX_PWR_DEFAULT}
71};
72
73/* band: 'B/G', region: France */
74static struct chan_freq_power channel_freq_power_FR_BG[] = {
75 {10, 2457, WLAN_TX_PWR_FR_DEFAULT},
76 {11, 2462, WLAN_TX_PWR_FR_DEFAULT},
77 {12, 2467, WLAN_TX_PWR_FR_DEFAULT},
78 {13, 2472, WLAN_TX_PWR_FR_DEFAULT}
79};
80
81/* band: 'B/G', region: Japan */
82static struct chan_freq_power channel_freq_power_JPN_BG[] = {
83 {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
84 {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
85 {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
86 {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
87 {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
88 {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
89 {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
90 {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
91 {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
92 {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
93 {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
94 {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
95 {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
96 {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
97};
98
99/**
100 * the structure for channel, frequency and power
101 */
102struct region_cfp_table {
103 u8 region;
104 struct chan_freq_power *cfp_BG;
105 int cfp_no_BG;
106};
107
108/**
109 * the structure for the mapping between region and CFP
110 */
111static struct region_cfp_table region_cfp_table[] = {
112 {0x10, /*US FCC */
113 channel_freq_power_US_BG,
114 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
115 }
116 ,
117 {0x20, /*CANADA IC */
118 channel_freq_power_US_BG,
119 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
120 }
121 ,
122 {0x30, /*EU*/ channel_freq_power_EU_BG,
123 sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
124 }
125 ,
126 {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
127 sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
128 }
129 ,
130 {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
131 sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
132 }
133 ,
134 {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
135 sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
136 }
137 ,
138/*Add new region here */
139};
140
141/**
142 * the rates supported by the card
143 */
144u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
145 { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
146 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
147};
148
149/**
150 * the rates supported
151 */
152u8 libertas_supported_rates[G_SUPPORTED_RATES] =
153 { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1540 };
155
156/**
157 * the rates supported for ad-hoc G mode
158 */
159u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
160 { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1610 };
162
163/**
164 * the rates supported for ad-hoc B mode
165 */
166u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
167
168/**
169 * the global variable of a pointer to wlan_private
170 * structure variable
171 */
172static wlan_private *wlanpriv = NULL;
173
174#define MAX_DEVS 5
175static struct net_device *libertas_devs[MAX_DEVS];
176static int libertas_found = 0;
177
178/**
179 * the table to keep region code
180 */
181u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
182 { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
183
184static u8 *default_fw_name = "usb8388.bin";
185
186/**
187 * Attributes exported through sysfs
188 */
189#define to_net_dev(class) container_of(class, struct net_device, class_dev)
190
191/**
192 * @brief Get function for sysfs attribute libertas_mpp
193 */
194static ssize_t libertas_mpp_get(struct class_device * dev, char * buf) {
195 struct cmd_ds_mesh_access mesh_access;
196
197 memset(&mesh_access, 0, sizeof(mesh_access));
198 libertas_prepare_and_send_command(to_net_dev(dev)->priv,
199 cmd_mesh_access,
200 cmd_act_mesh_get_mpp,
201 cmd_option_waitforrsp, 0, (void *)&mesh_access);
202
203 return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
204}
205
206/**
207 * @brief Set function for sysfs attribute libertas_mpp
208 */
209static ssize_t libertas_mpp_set(struct class_device * dev, const char * buf,
210 size_t count) {
211 struct cmd_ds_mesh_access mesh_access;
212
213
214 memset(&mesh_access, 0, sizeof(mesh_access));
215 sscanf(buf, "%d", &(mesh_access.data[0]));
216 libertas_prepare_and_send_command((to_net_dev(dev))->priv,
217 cmd_mesh_access,
218 cmd_act_mesh_set_mpp,
219 cmd_option_waitforrsp, 0, (void *)&mesh_access);
220 return strlen(buf);
221}
222
223/**
224 * libertas_mpp attribute to be exported per mshX interface
225 * through sysfs (/sys/class/net/mshX/libertas-mpp)
226 */
227static CLASS_DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
228 libertas_mpp_set );
229
230/**
231 * @brief Check if the device can be open and wait if necessary.
232 *
233 * @param dev A pointer to net_device structure
234 * @return 0
235 *
236 * For USB adapter, on some systems the device open handler will be
237 * called before FW ready. Use the following flag check and wait
238 * function to work around the issue.
239 *
240 */
241static int pre_open_check(struct net_device *dev) {
242 wlan_private *priv = (wlan_private *) dev->priv;
243 wlan_adapter *adapter = priv->adapter;
244 int i = 0;
245
246 while (!adapter->fw_ready && i < 20) {
247 i++;
248 msleep_interruptible(100);
249 }
250 if (!adapter->fw_ready) {
251 lbs_pr_info("FW not ready, pre_open_check() return failure\n");
252 LEAVE();
253 return -1;
254 }
255
256 return 0;
257}
258
259/**
260 * @brief This function opens the device
261 *
262 * @param dev A pointer to net_device structure
263 * @return 0
264 */
265static int wlan_dev_open(struct net_device *dev)
266{
267 wlan_private *priv = (wlan_private *) dev->priv;
268 wlan_adapter *adapter = priv->adapter;
269
270 ENTER();
271
272
273 priv->open = 1;
274
275 if (adapter->connect_status == libertas_connected) {
276 netif_carrier_on(priv->wlan_dev.netdev);
277 } else
278 netif_carrier_off(priv->wlan_dev.netdev);
279
280 LEAVE();
281 return 0;
282}
283/**
284 * @brief This function opens the mshX interface
285 *
286 * @param dev A pointer to net_device structure
287 * @return 0
288 */
289static int mesh_open(struct net_device *dev)
290{
291 wlan_private *priv = (wlan_private *) dev->priv ;
292
293 if(pre_open_check(dev) == -1)
294 return -1;
295 priv->mesh_open = 1 ;
296 netif_start_queue(priv->mesh_dev);
297 if (priv->infra_open == 0)
298 return wlan_dev_open(priv->wlan_dev.netdev) ;
299 return 0;
300}
301
302/**
303 * @brief This function opens the ethX interface
304 *
305 * @param dev A pointer to net_device structure
306 * @return 0
307 */
308static int wlan_open(struct net_device *dev)
309{
310 wlan_private *priv = (wlan_private *) dev->priv ;
311
312 if(pre_open_check(dev) == -1)
313 return -1;
314 priv->infra_open = 1 ;
315 netif_wake_queue(priv->wlan_dev.netdev);
316 if (priv->open == 0)
317 return wlan_dev_open(priv->wlan_dev.netdev) ;
318 return 0;
319}
320
321static int wlan_dev_close(struct net_device *dev)
322{
323 wlan_private *priv = dev->priv;
324
325 ENTER();
326
327 netif_carrier_off(priv->wlan_dev.netdev);
328 priv->open = 0;
329
330 LEAVE();
331 return 0;
332}
333
334/**
335 * @brief This function closes the mshX interface
336 *
337 * @param dev A pointer to net_device structure
338 * @return 0
339 */
340static int mesh_close(struct net_device *dev)
341{
342 wlan_private *priv = (wlan_private *) (dev->priv);
343
344 priv->mesh_open = 0;
345 netif_stop_queue(priv->mesh_dev);
346 if (priv->infra_open == 0)
347 return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
348 else
349 return 0;
350}
351
352/**
353 * @brief This function closes the ethX interface
354 *
355 * @param dev A pointer to net_device structure
356 * @return 0
357 */
358static int wlan_close(struct net_device *dev) {
359 wlan_private *priv = (wlan_private *) dev->priv;
360
361 netif_stop_queue(priv->wlan_dev.netdev);
362 priv->infra_open = 0;
363 if (priv->mesh_open == 0)
364 return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
365 else
366 return 0;
367}
368
369
370#ifdef ENABLE_PM
371
372/**
373 * @brief This function is a callback function. it is called by
374 * kernel to enter or exit power saving mode.
375 *
376 * @param pmdev A pointer to pm_dev
377 * @param pmreq pm_request_t
378 * @param pmdata A pointer to pmdata
379 * @return 0 or -1
380 */
381static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq,
382 void *pmdata)
383{
384 wlan_private *priv = wlanpriv;
385 wlan_adapter *adapter = priv->adapter;
386 struct net_device *dev = priv->wlan_dev.netdev;
387
388 lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
389
390 switch (pmreq) {
391 case PM_SUSPEND:
392 lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
393
394 /* in associated mode */
395 if (adapter->connect_status == libertas_connected) {
396 if ((adapter->psstate != PS_STATE_SLEEP)
397 ) {
398 lbs_pr_debug(1,
399 "wlan_pm_callback: can't enter sleep mode\n");
400 return -1;
401 } else {
402
403 /*
404 * Detach the network interface
405 * if the network is running
406 */
407 if (netif_running(dev)) {
408 netif_device_detach(dev);
409 lbs_pr_debug(1,
410 "netif_device_detach().\n");
411 }
412 libertas_sbi_suspend(priv);
413 }
414 break;
415 }
416
417 /* in non associated mode */
418
419 /*
420 * Detach the network interface
421 * if the network is running
422 */
423 if (netif_running(dev))
424 netif_device_detach(dev);
425
426 /*
427 * Storing and restoring of the regs be taken care
428 * at the driver rest will be done at wlan driver
429 * this makes driver independent of the card
430 */
431
432 libertas_sbi_suspend(priv);
433
434 break;
435
436 case PM_RESUME:
437 /* in associated mode */
438 if (adapter->connect_status == libertas_connected) {
439 {
440 /*
441 * Bring the inteface up first
442 * This case should not happen still ...
443 */
444 libertas_sbi_resume(priv);
445
446 /*
447 * Attach the network interface
448 * if the network is running
449 */
450 if (netif_running(dev)) {
451 netif_device_attach(dev);
452 lbs_pr_debug(1,
453 "after netif_device_attach().\n");
454 }
455 lbs_pr_debug(1,
456 "After netif attach, in associated mode.\n");
457 }
458 break;
459 }
460
461 /* in non associated mode */
462
463 /*
464 * Bring the inteface up first
465 * This case should not happen still ...
466 */
467
468 libertas_sbi_resume(priv);
469
470 if (netif_running(dev))
471 netif_device_attach(dev);
472
473 lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
474 break;
475 }
476
477 return 0;
478}
479#endif /* ENABLE_PM */
480
481static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
482{
483 int ret = 0;
484 wlan_private *priv = dev->priv;
485
486 ENTER();
487
488 if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
489 priv->stats.tx_dropped++;
490 goto done;
491 }
492
493 netif_stop_queue(priv->wlan_dev.netdev);
494
495 if (libertas_process_tx(priv, skb) == 0)
496 dev->trans_start = jiffies;
497done:
498 LEAVE();
499 return ret;
500}
501
502/**
503 * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
504 *
505 */
506static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
507{
508 wlan_private *priv = dev->priv;
509 ENTER();
510 SET_MESH_FRAME(skb);
511 LEAVE();
512
513 return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
514}
515
516/**
517 * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
518 *
519 */
520static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
521 ENTER();
522 UNSET_MESH_FRAME(skb);
523 LEAVE();
524 return wlan_hard_start_xmit(skb, dev);
525}
526
527static void wlan_tx_timeout(struct net_device *dev)
528{
529 wlan_private *priv = (wlan_private *) dev->priv;
530
531 ENTER();
532
533 lbs_pr_err("tx watch dog timeout!\n");
534
535 priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
536 dev->trans_start = jiffies;
537
538 if (priv->adapter->currenttxskb) {
539 if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
540 /* If we are here, we have not received feedback from
541 the previous packet. Assume TX_FAIL and move on. */
542 priv->adapter->eventcause = 0x01000000;
543 libertas_send_tx_feedback(priv);
544 } else
545 wake_up_interruptible(&priv->mainthread.waitq);
546 } else if (priv->adapter->connect_status == libertas_connected)
547 netif_wake_queue(priv->wlan_dev.netdev);
548
549 LEAVE();
550}
551
552/**
553 * @brief This function returns the network statistics
554 *
555 * @param dev A pointer to wlan_private structure
556 * @return A pointer to net_device_stats structure
557 */
558static struct net_device_stats *wlan_get_stats(struct net_device *dev)
559{
560 wlan_private *priv = (wlan_private *) dev->priv;
561
562 return &priv->stats;
563}
564
565static int wlan_set_mac_address(struct net_device *dev, void *addr)
566{
567 int ret = 0;
568 wlan_private *priv = (wlan_private *) dev->priv;
569 wlan_adapter *adapter = priv->adapter;
570 struct sockaddr *phwaddr = addr;
571
572 ENTER();
573
574 memset(adapter->current_addr, 0, ETH_ALEN);
575
576 /* dev->dev_addr is 8 bytes */
577 lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
578
579 lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
580 memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
581
582 ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
583 cmd_act_set,
584 cmd_option_waitforrsp, 0, NULL);
585
586 if (ret) {
587 lbs_pr_debug(1, "set mac address failed.\n");
588 ret = -1;
589 goto done;
590 }
591
592 lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
593 memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
594 memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
595
596done:
597 LEAVE();
598 return ret;
599}
600
601static int wlan_copy_multicast_address(wlan_adapter * adapter,
602 struct net_device *dev)
603{
604 int i = 0;
605 struct dev_mc_list *mcptr = dev->mc_list;
606
607 for (i = 0; i < dev->mc_count; i++) {
608 memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
609 mcptr = mcptr->next;
610 }
611
612 return i;
613
614}
615
616static void wlan_set_multicast_list(struct net_device *dev)
617{
618 wlan_private *priv = dev->priv;
619 wlan_adapter *adapter = priv->adapter;
620 int oldpacketfilter;
621
622 ENTER();
623
624 oldpacketfilter = adapter->currentpacketfilter;
625
626 if (dev->flags & IFF_PROMISC) {
627 lbs_pr_debug(1, "enable Promiscuous mode\n");
628 adapter->currentpacketfilter |=
629 cmd_act_mac_promiscuous_enable;
630 adapter->currentpacketfilter &=
631 ~(cmd_act_mac_all_multicast_enable |
632 cmd_act_mac_multicast_enable);
633 } else {
634 /* Multicast */
635 adapter->currentpacketfilter &=
636 ~cmd_act_mac_promiscuous_enable;
637
638 if (dev->flags & IFF_ALLMULTI || dev->mc_count >
639 MRVDRV_MAX_MULTICAST_LIST_SIZE) {
640 lbs_pr_debug(1, "Enabling All Multicast!\n");
641 adapter->currentpacketfilter |=
642 cmd_act_mac_all_multicast_enable;
643 adapter->currentpacketfilter &=
644 ~cmd_act_mac_multicast_enable;
645 } else {
646 adapter->currentpacketfilter &=
647 ~cmd_act_mac_all_multicast_enable;
648
649 if (!dev->mc_count) {
650 lbs_pr_debug(1, "No multicast addresses - "
651 "disabling multicast!\n");
652 adapter->currentpacketfilter &=
653 ~cmd_act_mac_multicast_enable;
654 } else {
655 int i;
656
657 adapter->currentpacketfilter |=
658 cmd_act_mac_multicast_enable;
659
660 adapter->nr_of_multicastmacaddr =
661 wlan_copy_multicast_address(adapter, dev);
662
663 lbs_pr_debug(1, "Multicast addresses: %d\n",
664 dev->mc_count);
665
666 for (i = 0; i < dev->mc_count; i++) {
667 lbs_pr_debug(1, "Multicast address %d:"
668 "%x %x %x %x %x %x\n", i,
669 adapter->multicastlist[i][0],
670 adapter->multicastlist[i][1],
671 adapter->multicastlist[i][2],
672 adapter->multicastlist[i][3],
673 adapter->multicastlist[i][4],
674 adapter->multicastlist[i][5]);
675 }
676 /* set multicast addresses to firmware */
677 libertas_prepare_and_send_command(priv,
678 cmd_mac_multicast_adr,
679 cmd_act_set, 0, 0,
680 NULL);
681 }
682 }
683 }
684
685 if (adapter->currentpacketfilter != oldpacketfilter) {
686 libertas_set_mac_packet_filter(priv);
687 }
688
689 LEAVE();
690}
691
692/**
693 * @brief This function hanldes the major job in WLAN driver.
694 * it handles the event generated by firmware, rx data received
695 * from firmware and tx data sent from kernel.
696 *
697 * @param data A pointer to wlan_thread structure
698 * @return 0
699 */
700static int wlan_service_main_thread(void *data)
701{
702 struct wlan_thread *thread = data;
703 wlan_private *priv = thread->priv;
704 wlan_adapter *adapter = priv->adapter;
705 wait_queue_t wait;
706 u8 ireg = 0;
707
708 ENTER();
709
710 wlan_activate_thread(thread);
711
712 init_waitqueue_entry(&wait, current);
713
714 for (;;) {
715 lbs_pr_debug(1, "main-thread 111: intcounter=%d "
716 "currenttxskb=%p dnld_sent=%d\n",
717 adapter->intcounter,
718 adapter->currenttxskb, priv->wlan_dev.dnld_sent);
719
720 add_wait_queue(&thread->waitq, &wait);
721 set_current_state(TASK_INTERRUPTIBLE);
722 spin_lock_irq(&adapter->driver_lock);
723 if ((adapter->psstate == PS_STATE_SLEEP) ||
724 (!adapter->intcounter
725 && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
726 list_empty(&adapter->cmdpendingq)))) {
727 lbs_pr_debug(1,
728 "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
729 adapter->connect_status, adapter->intcounter,
730 adapter->psmode, adapter->psstate);
731 spin_unlock_irq(&adapter->driver_lock);
732 schedule();
733 } else
734 spin_unlock_irq(&adapter->driver_lock);
735
736
737 lbs_pr_debug(1,
738 "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
739 "dnld_sent=%d\n", adapter->intcounter,
740 adapter->currenttxskb, priv->wlan_dev.dnld_sent);
741
742 set_current_state(TASK_RUNNING);
743 remove_wait_queue(&thread->waitq, &wait);
744 try_to_freeze();
745
746 lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p "
747 "dnld_sent=%d\n",
748 adapter->intcounter,
749 adapter->currenttxskb, priv->wlan_dev.dnld_sent);
750
751 if (kthread_should_stop()
752 || adapter->surpriseremoved) {
753 lbs_pr_debug(1,
754 "main-thread: break from main thread: surpriseremoved=0x%x\n",
755 adapter->surpriseremoved);
756 break;
757 }
758
759
760 spin_lock_irq(&adapter->driver_lock);
761 if (adapter->intcounter) {
762 u8 int_status;
763 adapter->intcounter = 0;
764 int_status = libertas_sbi_get_int_status(priv, &ireg);
765
766 if (int_status) {
767 lbs_pr_debug(1,
768 "main-thread: reading HOST_INT_STATUS_REG failed\n");
769 spin_unlock_irq(&adapter->driver_lock);
770 continue;
771 }
772 adapter->hisregcpy |= ireg;
773 }
774
775 lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p "
776 "dnld_sent=%d\n",
777 adapter->intcounter,
778 adapter->currenttxskb, priv->wlan_dev.dnld_sent);
779
780 /* command response? */
781 if (adapter->hisregcpy & his_cmdupldrdy) {
782 lbs_pr_debug(1, "main-thread: cmd response ready.\n");
783
784 adapter->hisregcpy &= ~his_cmdupldrdy;
785 spin_unlock_irq(&adapter->driver_lock);
786 libertas_process_rx_command(priv);
787 spin_lock_irq(&adapter->driver_lock);
788 }
789
790 /* Any Card Event */
791 if (adapter->hisregcpy & his_cardevent) {
792 lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
793
794 adapter->hisregcpy &= ~his_cardevent;
795
796 if (libertas_sbi_read_event_cause(priv)) {
797 lbs_pr_alert(
798 "main-thread: libertas_sbi_read_event_cause failed.\n");
799 spin_unlock_irq(&adapter->driver_lock);
800 continue;
801 }
802 spin_unlock_irq(&adapter->driver_lock);
803 libertas_process_event(priv);
804 } else
805 spin_unlock_irq(&adapter->driver_lock);
806
807 /* Check if we need to confirm Sleep Request received previously */
808 if (adapter->psstate == PS_STATE_PRE_SLEEP) {
809 if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
810 if (adapter->connect_status ==
811 libertas_connected) {
812 lbs_pr_debug(1,
813 "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
814 "dnld_sent=%d cur_cmd=%p, confirm now\n",
815 adapter->intcounter,
816 adapter->currenttxskb,
817 priv->wlan_dev.dnld_sent,
818 adapter->cur_cmd);
819
820 libertas_ps_confirm_sleep(priv,
821 (u16) adapter->psmode);
822 } else {
823 /* workaround for firmware sending
824 * deauth/linkloss event immediately
825 * after sleep request, remove this
826 * after firmware fixes it
827 */
828 adapter->psstate = PS_STATE_AWAKE;
829 lbs_pr_alert(
830 "main-thread: ignore PS_SleepConfirm in non-connected state\n");
831 }
832 }
833 }
834
835 /* The PS state is changed during processing of Sleep Request
836 * event above
837 */
838 if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
839 (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
840 continue;
841
842 /* Execute the next command */
843 if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd)
844 libertas_execute_next_command(priv);
845
846 /* Wake-up command waiters which can't sleep in
847 * libertas_prepare_and_send_command
848 */
849 if (!adapter->nr_cmd_pending)
850 wake_up_all(&adapter->cmd_pending);
851
852 libertas_tx_runqueue(priv);
853 }
854
855 del_timer(&adapter->command_timer);
856 adapter->nr_cmd_pending = 0;
857 wake_up_all(&adapter->cmd_pending);
858 wlan_deactivate_thread(thread);
859
860 LEAVE();
861 return 0;
862}
863
864/**
865 * @brief This function adds the card. it will probe the
866 * card, allocate the wlan_priv and initialize the device.
867 *
868 * @param card A pointer to card
869 * @return A pointer to wlan_private structure
870 */
871wlan_private *wlan_add_card(void *card)
872{
873 struct net_device *dev = NULL;
874 struct net_device *mesh_dev = NULL;
875 wlan_private *priv = NULL;
876
877 ENTER();
878
879 /* Allocate an Ethernet device and register it */
880 if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
881 lbs_pr_alert( "Init ethernet device failed!\n");
882 return NULL;
883 }
884
885 priv = dev->priv;
886
887 /* allocate buffer for wlan_adapter */
888 if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
889 lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
890 goto err_kmalloc;
891 }
892
893 /* Allocate a virtual mesh device */
894 if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
895 lbs_pr_debug(1, "Init ethernet device failed!\n");
896 return NULL;
897 }
898
899 /* Both intervaces share the priv structure */
900 mesh_dev->priv = priv;
901
902 /* init wlan_adapter */
903 memset(priv->adapter, 0, sizeof(wlan_adapter));
904
905 priv->wlan_dev.netdev = dev;
906 priv->wlan_dev.card = card;
907 priv->mesh_open = 0;
908 priv->infra_open = 0;
909 priv->mesh_dev = mesh_dev;
910 wlanpriv = priv;
911
912 SET_MODULE_OWNER(dev);
913 SET_MODULE_OWNER(mesh_dev);
914
915 /* Setup the OS Interface to our functions */
916 dev->open = wlan_open;
917 dev->hard_start_xmit = wlan_pre_start_xmit;
918 dev->stop = wlan_close;
919 dev->do_ioctl = libertas_do_ioctl;
920 dev->set_mac_address = wlan_set_mac_address;
921 mesh_dev->open = mesh_open;
922 mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
923 mesh_dev->stop = mesh_close;
924 mesh_dev->do_ioctl = libertas_do_ioctl;
925 memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
926 sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
927
928#define WLAN_WATCHDOG_TIMEOUT (5 * HZ)
929
930 dev->tx_timeout = wlan_tx_timeout;
931 dev->get_stats = wlan_get_stats;
932 dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
933 dev->ethtool_ops = &libertas_ethtool_ops;
934 mesh_dev->get_stats = wlan_get_stats;
935 mesh_dev->ethtool_ops = &libertas_ethtool_ops;
936
937#ifdef WIRELESS_EXT
938 dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
939 mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
940#endif
941#define NETIF_F_DYNALLOC 16
942 dev->features |= NETIF_F_DYNALLOC;
943 dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
944 dev->set_multicast_list = wlan_set_multicast_list;
945
946 INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
947 INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
948
949 spin_lock_init(&priv->adapter->driver_lock);
950 init_waitqueue_head(&priv->adapter->cmd_pending);
951 priv->adapter->nr_cmd_pending = 0;
952
953 lbs_pr_debug(1, "Starting kthread...\n");
954 priv->mainthread.priv = priv;
955 wlan_create_thread(wlan_service_main_thread,
956 &priv->mainthread, "wlan_main_service");
957
958 priv->assoc_thread =
959 create_singlethread_workqueue("libertas_assoc");
960 INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
961
962 /*
963 * Register the device. Fillup the private data structure with
964 * relevant information from the card and request for the required
965 * IRQ.
966 */
967 if (libertas_sbi_register_dev(priv) < 0) {
968 lbs_pr_info("failed to register wlan device!\n");
969 goto err_registerdev;
970 }
971
972 /* init FW and HW */
973 if (libertas_init_fw(priv)) {
974 lbs_pr_debug(1, "Firmware Init failed\n");
975 goto err_registerdev;
976 }
977
978 if (register_netdev(dev)) {
979 lbs_pr_err("Cannot register network device!\n");
980 goto err_init_fw;
981 }
982
983 /* Register virtual mesh interface */
984 if (register_netdev(mesh_dev)) {
985 lbs_pr_info("Cannot register mesh virtual interface!\n");
986 goto err_init_fw;
987 }
988
989 lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
990
991 libertas_debugfs_init_one(priv, dev);
992
993 if (libertas_found == MAX_DEVS)
994 goto err_init_fw;
995 libertas_devs[libertas_found] = dev;
996 libertas_found++;
997#ifdef ENABLE_PM
998 if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
999 lbs_pr_alert( "failed to register PM callback\n");
1000#endif
1001 if (class_device_create_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp))
1002 goto err_create_file;
1003
1004 LEAVE();
1005 return priv;
1006
1007err_create_file:
1008 class_device_remove_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp);
1009err_init_fw:
1010 libertas_sbi_unregister_dev(priv);
1011err_registerdev:
1012 destroy_workqueue(priv->assoc_thread);
1013 /* Stop the thread servicing the interrupts */
1014 wake_up_interruptible(&priv->mainthread.waitq);
1015 wlan_terminate_thread(&priv->mainthread);
1016 kfree(priv->adapter);
1017err_kmalloc:
1018 free_netdev(dev);
1019 free_netdev(mesh_dev);
1020 wlanpriv = NULL;
1021
1022 LEAVE();
1023 return NULL;
1024}
1025
1026static void wake_pending_cmdnodes(wlan_private *priv)
1027{
1028 struct cmd_ctrl_node *cmdnode;
1029 unsigned long flags;
1030
1031 spin_lock_irqsave(&priv->adapter->driver_lock, flags);
1032 list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
1033 cmdnode->cmdwaitqwoken = 1;
1034 wake_up_interruptible(&cmdnode->cmdwait_q);
1035 }
1036 spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
1037}
1038
1039
1040int wlan_remove_card(void *card)
1041{
1042 wlan_private *priv = libertas_sbi_get_priv(card);
1043 wlan_adapter *adapter;
1044 struct net_device *dev;
1045 struct net_device *mesh_dev;
1046 union iwreq_data wrqu;
1047 int i;
1048
1049 ENTER();
1050
1051 if (!priv) {
1052 LEAVE();
1053 return 0;
1054 }
1055
1056 adapter = priv->adapter;
1057
1058 if (!adapter) {
1059 LEAVE();
1060 return 0;
1061 }
1062
1063 dev = priv->wlan_dev.netdev;
1064 mesh_dev = priv->mesh_dev;
1065
1066 netif_stop_queue(mesh_dev);
1067 netif_stop_queue(priv->wlan_dev.netdev);
1068 netif_carrier_off(priv->wlan_dev.netdev);
1069
1070 wake_pending_cmdnodes(priv);
1071
1072 class_device_remove_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp);
1073 unregister_netdev(mesh_dev);
1074 unregister_netdev(dev);
1075
1076 cancel_delayed_work(&priv->assoc_work);
1077 destroy_workqueue(priv->assoc_thread);
1078
1079 if (adapter->psmode == wlan802_11powermodemax_psp) {
1080 adapter->psmode = wlan802_11powermodecam;
1081 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
1082 }
1083
1084 memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
1085 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1086 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
1087
1088#ifdef ENABLE_PM
1089 pm_unregister(wlan_pm_dev);
1090#endif
1091
1092 adapter->surpriseremoved = 1;
1093
1094 /* Stop the thread servicing the interrupts */
1095 wlan_terminate_thread(&priv->mainthread);
1096
1097 libertas_debugfs_remove_one(priv);
1098
1099 lbs_pr_debug(1, "Free adapter\n");
1100 libertas_free_adapter(priv);
1101
1102 for (i = 0; i<libertas_found; i++) {
1103 if (libertas_devs[i]==priv->wlan_dev.netdev) {
1104 libertas_devs[i] = libertas_devs[--libertas_found];
1105 libertas_devs[libertas_found] = NULL ;
1106 break ;
1107 }
1108 }
1109
1110 lbs_pr_debug(1, "Unregister finish\n");
1111
1112 priv->wlan_dev.netdev = NULL;
1113 priv->mesh_dev = NULL ;
1114 free_netdev(mesh_dev);
1115 free_netdev(dev);
1116 wlanpriv = NULL;
1117
1118 LEAVE();
1119 return 0;
1120}
1121
1122/**
1123 * @brief This function finds the CFP in
1124 * region_cfp_table based on region and band parameter.
1125 *
1126 * @param region The region code
1127 * @param band The band
1128 * @param cfp_no A pointer to CFP number
1129 * @return A pointer to CFP
1130 */
1131struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
1132{
1133 int i, end;
1134
1135 ENTER();
1136
1137 end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
1138
1139 for (i = 0; i < end ; i++) {
1140 lbs_pr_debug(1, "region_cfp_table[i].region=%d\n",
1141 region_cfp_table[i].region);
1142 if (region_cfp_table[i].region == region) {
1143 *cfp_no = region_cfp_table[i].cfp_no_BG;
1144 LEAVE();
1145 return region_cfp_table[i].cfp_BG;
1146 }
1147 }
1148
1149 LEAVE();
1150 return NULL;
1151}
1152
1153int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
1154{
1155 wlan_adapter *adapter = priv->adapter;
1156 int i = 0;
1157
1158 struct chan_freq_power *cfp;
1159 int cfp_no;
1160
1161 ENTER();
1162
1163 memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
1164
1165 {
1166 cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
1167 if (cfp != NULL) {
1168 adapter->region_channel[i].nrcfp = cfp_no;
1169 adapter->region_channel[i].CFP = cfp;
1170 } else {
1171 lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
1172 region);
1173 return -1;
1174 }
1175 adapter->region_channel[i].valid = 1;
1176 adapter->region_channel[i].region = region;
1177 adapter->region_channel[i].band = band;
1178 i++;
1179 }
1180 LEAVE();
1181 return 0;
1182}
1183
1184/**
1185 * @brief This function handles the interrupt. it will change PS
1186 * state if applicable. it will wake up main_thread to handle
1187 * the interrupt event as well.
1188 *
1189 * @param dev A pointer to net_device structure
1190 * @return n/a
1191 */
1192void libertas_interrupt(struct net_device *dev)
1193{
1194 wlan_private *priv = dev->priv;
1195
1196 ENTER();
1197
1198 lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n",
1199 priv->adapter->intcounter);
1200
1201 priv->adapter->intcounter++;
1202
1203 if (priv->adapter->psstate == PS_STATE_SLEEP) {
1204 priv->adapter->psstate = PS_STATE_AWAKE;
1205 netif_wake_queue(dev);
1206 }
1207
1208 wake_up_interruptible(&priv->mainthread.waitq);
1209
1210 LEAVE();
1211}
1212
1213static int wlan_init_module(void)
1214{
1215 int ret = 0;
1216
1217 ENTER();
1218
1219 if (libertas_fw_name == NULL) {
1220 libertas_fw_name = default_fw_name;
1221 }
1222
1223 libertas_debugfs_init();
1224
1225 if (libertas_sbi_register()) {
1226 ret = -1;
1227 libertas_debugfs_remove();
1228 goto done;
1229 }
1230
1231done:
1232 LEAVE();
1233 return ret;
1234}
1235
1236static void wlan_cleanup_module(void)
1237{
1238 int i;
1239
1240 ENTER();
1241
1242 for (i = 0; i<libertas_found; i++) {
1243 wlan_private *priv = libertas_devs[i]->priv;
1244 reset_device(priv);
1245 }
1246
1247 libertas_sbi_unregister();
1248 libertas_debugfs_remove();
1249
1250 LEAVE();
1251}
1252
1253module_init(wlan_init_module);
1254module_exit(wlan_cleanup_module);
1255
1256MODULE_DESCRIPTION("M-WLAN Driver");
1257MODULE_AUTHOR("Marvell International Ltd.");
1258MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644
index 000000000000..5d118f40cfbc
--- /dev/null
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -0,0 +1,57 @@
1#include <net/ieee80211_radiotap.h>
2
3struct tx_radiotap_hdr {
4 struct ieee80211_radiotap_header hdr;
5 u8 rate;
6 u8 txpower;
7 u8 rts_retries;
8 u8 data_retries;
9#if 0
10 u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
11#endif
12} __attribute__ ((packed));
13
14#define TX_RADIOTAP_PRESENT ( \
15 (1 << IEEE80211_RADIOTAP_RATE) | \
16 (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
17 (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
18 (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
19 0)
20
21#define IEEE80211_FC_VERSION_MASK 0x0003
22#define IEEE80211_FC_TYPE_MASK 0x000c
23#define IEEE80211_FC_TYPE_MGT 0x0000
24#define IEEE80211_FC_TYPE_CTL 0x0004
25#define IEEE80211_FC_TYPE_DATA 0x0008
26#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
27#define IEEE80211_FC_TOFROMDS_MASK 0x0300
28#define IEEE80211_FC_TODS_MASK 0x0100
29#define IEEE80211_FC_FROMDS_MASK 0x0200
30#define IEEE80211_FC_NODS 0x0000
31#define IEEE80211_FC_TODS 0x0100
32#define IEEE80211_FC_FROMDS 0x0200
33#define IEEE80211_FC_DSTODS 0x0300
34
35struct rx_radiotap_hdr {
36 struct ieee80211_radiotap_header hdr;
37 u8 flags;
38 u8 rate;
39 u16 chan_freq;
40 u16 chan_flags;
41 u8 antenna;
42 u8 antsignal;
43 u16 rx_flags;
44#if 0
45 u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
46#endif
47} __attribute__ ((packed));
48
49#define RX_RADIOTAP_PRESENT ( \
50 (1 << IEEE80211_RADIOTAP_FLAGS) | \
51 (1 << IEEE80211_RADIOTAP_RATE) | \
52 (1 << IEEE80211_RADIOTAP_CHANNEL) | \
53 (1 << IEEE80211_RADIOTAP_ANTENNA) | \
54 (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
55 (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \
56 0)
57
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 000000000000..7e3f78f092dc
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
1/**
2 * This file contains the handling of RX in wlan driver.
3 */
4#include <linux/etherdevice.h>
5#include <linux/types.h>
6
7#include "hostcmd.h"
8#include "radiotap.h"
9#include "decl.h"
10#include "dev.h"
11#include "wext.h"
12
13struct eth803hdr {
14 u8 dest_addr[6];
15 u8 src_addr[6];
16 u16 h803_len;
17} __attribute__ ((packed));
18
19struct rfc1042hdr {
20 u8 llc_dsap;
21 u8 llc_ssap;
22 u8 llc_ctrl;
23 u8 snap_oui[3];
24 u16 snap_type;
25} __attribute__ ((packed));
26
27struct rxpackethdr {
28 struct rxpd rx_pd;
29 struct eth803hdr eth803_hdr;
30 struct rfc1042hdr rfc1042_hdr;
31} __attribute__ ((packed));
32
33struct rx80211packethdr {
34 struct rxpd rx_pd;
35 void *eth80211_hdr;
36} __attribute__ ((packed));
37
38static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
39
40/**
41 * @brief This function computes the avgSNR .
42 *
43 * @param priv A pointer to wlan_private structure
44 * @return avgSNR
45 */
46static u8 wlan_getavgsnr(wlan_private * priv)
47{
48 u8 i;
49 u16 temp = 0;
50 wlan_adapter *adapter = priv->adapter;
51 if (adapter->numSNRNF == 0)
52 return 0;
53 for (i = 0; i < adapter->numSNRNF; i++)
54 temp += adapter->rawSNR[i];
55 return (u8) (temp / adapter->numSNRNF);
56
57}
58
59/**
60 * @brief This function computes the AvgNF
61 *
62 * @param priv A pointer to wlan_private structure
63 * @return AvgNF
64 */
65static u8 wlan_getavgnf(wlan_private * priv)
66{
67 u8 i;
68 u16 temp = 0;
69 wlan_adapter *adapter = priv->adapter;
70 if (adapter->numSNRNF == 0)
71 return 0;
72 for (i = 0; i < adapter->numSNRNF; i++)
73 temp += adapter->rawNF[i];
74 return (u8) (temp / adapter->numSNRNF);
75
76}
77
78/**
79 * @brief This function save the raw SNR/NF to our internel buffer
80 *
81 * @param priv A pointer to wlan_private structure
82 * @param prxpd A pointer to rxpd structure of received packet
83 * @return n/a
84 */
85static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
86{
87 wlan_adapter *adapter = priv->adapter;
88 if (adapter->numSNRNF < adapter->data_avg_factor)
89 adapter->numSNRNF++;
90 adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
91 adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
92 adapter->nextSNRNF++;
93 if (adapter->nextSNRNF >= adapter->data_avg_factor)
94 adapter->nextSNRNF = 0;
95 return;
96}
97
98/**
99 * @brief This function computes the RSSI in received packet.
100 *
101 * @param priv A pointer to wlan_private structure
102 * @param prxpd A pointer to rxpd structure of received packet
103 * @return n/a
104 */
105static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
106{
107 wlan_adapter *adapter = priv->adapter;
108
109 ENTER();
110
111 lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
112 lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
113 adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
114 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
115
116 adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
117 adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
118 wlan_save_rawSNRNF(priv, p_rx_pd);
119
120 adapter->rxpd_rate = p_rx_pd->rx_rate;
121
122 adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
123 adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
124 lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
125 adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
126 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
127
128 adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
129 CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
130 adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
131
132 adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
133 CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
134 adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
135
136 LEAVE();
137}
138
139int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
140{
141 lbs_pr_debug(1, "skb->data=%p\n", skb->data);
142
143 if(IS_MESH_FRAME(skb))
144 skb->dev = priv->mesh_dev;
145 else
146 skb->dev = priv->wlan_dev.netdev;
147 skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
148 skb->ip_summed = CHECKSUM_UNNECESSARY;
149
150 netif_rx(skb);
151
152 return 0;
153}
154
155/**
156 * @brief This function processes received packet and forwards it
157 * to kernel/upper layer
158 *
159 * @param priv A pointer to wlan_private
160 * @param skb A pointer to skb which includes the received packet
161 * @return 0 or -1
162 */
163int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
164{
165 wlan_adapter *adapter = priv->adapter;
166 int ret = 0;
167
168 struct rxpackethdr *p_rx_pkt;
169 struct rxpd *p_rx_pd;
170
171 int hdrchop;
172 struct ethhdr *p_ethhdr;
173
174 const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
175
176 ENTER();
177
178 if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
179 lbs_dbg_hex("RX packet: ", skb->data,
180 min_t(unsigned int, skb->len, 100));
181
182 if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
183 return process_rxed_802_11_packet(priv, skb);
184
185 p_rx_pkt = (struct rxpackethdr *) skb->data;
186 p_rx_pd = &p_rx_pkt->rx_pd;
187 if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
188 SET_MESH_FRAME(skb);
189 else
190 UNSET_MESH_FRAME(skb);
191
192 lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
193 min_t(unsigned int, skb->len, 100));
194
195 if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
196 lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
197 priv->stats.rx_length_errors++;
198 ret = 0;
199 goto done;
200 }
201
202 /*
203 * Check rxpd status and update 802.3 stat,
204 */
205 if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
206 lbs_pr_debug(1, "RX error: frame received with bad status\n");
207 lbs_pr_alert("rxpd Not OK\n");
208 priv->stats.rx_errors++;
209 ret = 0;
210 goto done;
211 }
212
213 lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
214 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
215
216 lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
217 sizeof(p_rx_pkt->eth803_hdr.dest_addr));
218 lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
219 sizeof(p_rx_pkt->eth803_hdr.src_addr));
220
221 if (memcmp(&p_rx_pkt->rfc1042_hdr,
222 rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
223 /*
224 * Replace the 803 header and rfc1042 header (llc/snap) with an
225 * EthernetII header, keep the src/dst and snap_type (ethertype)
226 *
227 * The firmware only passes up SNAP frames converting
228 * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
229 *
230 * To create the Ethernet II, just move the src, dst address right
231 * before the snap_type.
232 */
233 p_ethhdr = (struct ethhdr *)
234 ((u8 *) & p_rx_pkt->eth803_hdr
235 + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
236 - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
237 - sizeof(p_rx_pkt->eth803_hdr.src_addr)
238 - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
239
240 memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
241 sizeof(p_ethhdr->h_source));
242 memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
243 sizeof(p_ethhdr->h_dest));
244
245 /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
246 * that was removed
247 */
248 hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
249 } else {
250 lbs_dbg_hex("RX Data: LLC/SNAP",
251 (u8 *) & p_rx_pkt->rfc1042_hdr,
252 sizeof(p_rx_pkt->rfc1042_hdr));
253
254 /* Chop off the rxpd */
255 hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
256 }
257
258 /* Chop off the leading header bytes so the skb points to the start of
259 * either the reconstructed EthII frame or the 802.2/llc/snap frame
260 */
261 skb_pull(skb, hdrchop);
262
263 /* Take the data rate from the rxpd structure
264 * only if the rate is auto
265 */
266 if (adapter->is_datarate_auto)
267 adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
268
269 wlan_compute_rssi(priv, p_rx_pd);
270
271 lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
272 if (libertas_upload_rx_packet(priv, skb)) {
273 lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
274 " returns failure\n");
275 ret = -1;
276 goto done;
277 }
278 priv->stats.rx_bytes += skb->len;
279 priv->stats.rx_packets++;
280
281 ret = 0;
282done:
283 LEAVE();
284
285 return ret;
286}
287
288/**
289 * @brief This function converts Tx/Rx rates from the Marvell WLAN format
290 * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
291 *
292 * @param rate Input rate
293 * @return Output Rate (0 if invalid)
294 */
295static u8 convert_mv_rate_to_radiotap(u8 rate)
296{
297 switch (rate) {
298 case 0: /* 1 Mbps */
299 return 2;
300 case 1: /* 2 Mbps */
301 return 4;
302 case 2: /* 5.5 Mbps */
303 return 11;
304 case 3: /* 11 Mbps */
305 return 22;
306 case 4: /* 6 Mbps */
307 return 12;
308 case 5: /* 9 Mbps */
309 return 18;
310 case 6: /* 12 Mbps */
311 return 24;
312 case 7: /* 18 Mbps */
313 return 36;
314 case 8: /* 24 Mbps */
315 return 48;
316 case 9: /* 36 Mbps */
317 return 72;
318 case 10: /* 48 Mbps */
319 return 96;
320 case 11: /* 54 Mbps */
321 return 108;
322 }
323 lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
324 return 0;
325}
326
327/**
328 * @brief This function processes a received 802.11 packet and forwards it
329 * to kernel/upper layer
330 *
331 * @param priv A pointer to wlan_private
332 * @param skb A pointer to skb which includes the received packet
333 * @return 0 or -1
334 */
335static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
336{
337 wlan_adapter *adapter = priv->adapter;
338 int ret = 0;
339
340 struct rx80211packethdr *p_rx_pkt;
341 struct rxpd *prxpd;
342 struct rx_radiotap_hdr radiotap_hdr;
343 struct rx_radiotap_hdr *pradiotap_hdr;
344
345 ENTER();
346
347 p_rx_pkt = (struct rx80211packethdr *) skb->data;
348 prxpd = &p_rx_pkt->rx_pd;
349
350 // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
351
352 if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
353 lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
354 priv->stats.rx_length_errors++;
355 ret = 0;
356 goto done;
357 }
358
359 /*
360 * Check rxpd status and update 802.3 stat,
361 */
362 if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
363 //lbs_pr_debug(1, "RX error: frame received with bad status\n");
364 priv->stats.rx_errors++;
365 }
366
367 lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
368 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
369
370 /* create the exported radio header */
371 switch (priv->adapter->radiomode) {
372 case WLAN_RADIOMODE_NONE:
373 /* no radio header */
374 /* chop the rxpd */
375 skb_pull(skb, sizeof(struct rxpd));
376 break;
377
378 case WLAN_RADIOMODE_RADIOTAP:
379 /* radiotap header */
380 radiotap_hdr.hdr.it_version = 0;
381 /* XXX must check this value for pad */
382 radiotap_hdr.hdr.it_pad = 0;
383 radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
384 radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
385 /* unknown values */
386 radiotap_hdr.flags = 0;
387 radiotap_hdr.chan_freq = 0;
388 radiotap_hdr.chan_flags = 0;
389 radiotap_hdr.antenna = 0;
390 /* known values */
391 radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
392 /* XXX must check no carryout */
393 radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
394 radiotap_hdr.rx_flags = 0;
395 if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
396 radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
397 //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
398
399 // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
400
401 /* chop the rxpd */
402 skb_pull(skb, sizeof(struct rxpd));
403
404 /* add space for the new radio header */
405 if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
406 pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
407 GFP_ATOMIC)) {
408 lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
409 __func__);
410 }
411
412 pradiotap_hdr =
413 (struct rx_radiotap_hdr *)skb_push(skb,
414 sizeof(struct
415 rx_radiotap_hdr));
416 memcpy(pradiotap_hdr, &radiotap_hdr,
417 sizeof(struct rx_radiotap_hdr));
418 //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
419 break;
420
421 default:
422 /* unknown header */
423 lbs_pr_alert( "Unknown radiomode (%i)\n",
424 priv->adapter->radiomode);
425 /* don't export any header */
426 /* chop the rxpd */
427 skb_pull(skb, sizeof(struct rxpd));
428 break;
429 }
430
431 /* Take the data rate from the rxpd structure
432 * only if the rate is auto
433 */
434 if (adapter->is_datarate_auto) {
435 adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
436 }
437
438 wlan_compute_rssi(priv, prxpd);
439
440 lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
441
442 if (libertas_upload_rx_packet(priv, skb)) {
443 lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
444 "returns failure\n");
445 ret = -1;
446 goto done;
447 }
448
449 priv->stats.rx_bytes += skb->len;
450 priv->stats.rx_packets++;
451
452 ret = 0;
453done:
454 LEAVE();
455
456 skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
457
458 return (ret);
459}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644
index 000000000000..59d3a59ccef0
--- /dev/null
+++ b/drivers/net/wireless/libertas/sbi.h
@@ -0,0 +1,40 @@
1/**
2 * This file contains IF layer definitions.
3 */
4
5#ifndef _SBI_H_
6#define _SBI_H_
7
8#include <linux/interrupt.h>
9
10#include "defs.h"
11
12/** INT status Bit Definition*/
13#define his_cmddnldrdy 0x01
14#define his_cardevent 0x02
15#define his_cmdupldrdy 0x04
16
17#ifndef DEV_NAME_LEN
18#define DEV_NAME_LEN 32
19#endif
20
21#define SBI_EVENT_CAUSE_SHIFT 3
22
23/* Probe and Check if the card is present*/
24int libertas_sbi_register_dev(wlan_private * priv);
25int libertas_sbi_unregister_dev(wlan_private *);
26int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
27int libertas_sbi_register(void);
28void libertas_sbi_unregister(void);
29int libertas_sbi_prog_firmware(wlan_private *);
30
31int libertas_sbi_read_event_cause(wlan_private *);
32int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
33wlan_private *libertas_sbi_get_priv(void *card);
34
35#ifdef ENABLE_PM
36int libertas_sbi_suspend(wlan_private *);
37int libertas_sbi_resume(wlan_private *);
38#endif
39
40#endif /* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644
index 000000000000..e18706238951
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.c
@@ -0,0 +1,2044 @@
1/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
2/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
3
4/**
5 * Functions implementing wlan scan IOCTL and firmware command APIs
6 *
7 * IOCTL handlers as well as command preperation and response routines
8 * for sending scan commands to the firmware.
9 */
10#include <linux/ctype.h>
11#include <linux/if.h>
12#include <linux/netdevice.h>
13#include <linux/wireless.h>
14
15#include <net/ieee80211.h>
16#include <net/iw_handler.h>
17
18#include "host.h"
19#include "decl.h"
20#include "dev.h"
21#include "scan.h"
22
23//! Approximate amount of data needed to pass a scan result back to iwlist
24#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
25 + IW_ESSID_MAX_SIZE \
26 + IW_EV_UINT_LEN \
27 + IW_EV_FREQ_LEN \
28 + IW_EV_QUAL_LEN \
29 + IW_ESSID_MAX_SIZE \
30 + IW_EV_PARAM_LEN \
31 + 40) /* 40 for WPAIE */
32
33//! Memory needed to store a max sized channel List TLV for a firmware scan
34#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \
35 + (MRVDRV_MAX_CHANNELS_PER_SCAN \
36 * sizeof(struct chanscanparamset)))
37
38//! Memory needed to store a max number/size SSID TLV for a firmware scan
39#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
40
41//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
42#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \
43 + sizeof(struct mrvlietypes_numprobes) \
44 + CHAN_TLV_MAX_SIZE \
45 + SSID_TLV_MAX_SIZE)
46
47//! The maximum number of channels the firmware can scan per command
48#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
49
50/**
51 * @brief Number of channels to scan per firmware scan command issuance.
52 *
53 * Number restricted to prevent hitting the limit on the amount of scan data
54 * returned in a single firmware scan command.
55 */
56#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
57
58//! Scan time specified in the channel TLV for each channel for passive scans
59#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
60
61//! Scan time specified in the channel TLV for each channel for active scans
62#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
63
64//! Macro to enable/disable SSID checking before storing a scan table
65#ifdef DISCARD_BAD_SSID
66#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
67#else
68#define CHECK_SSID_IS_VALID(x) 1
69#endif
70
71/**
72 * @brief Check if a scanned network compatible with the driver settings
73 *
74 * WEP WPA WPA2 ad-hoc encrypt Network
75 * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
76 * 0 0 0 0 NONE 0 0 0 yes No security
77 * 1 0 0 0 NONE 1 0 0 yes Static WEP
78 * 0 1 0 0 x 1x 1 x yes WPA
79 * 0 0 1 0 x 1x x 1 yes WPA2
80 * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
81 * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
82 *
83 *
84 * @param adapter A pointer to wlan_adapter
85 * @param index Index in scantable to check against current driver settings
86 * @param mode Network mode: Infrastructure or IBSS
87 *
88 * @return Index in scantable, or error code if negative
89 */
90static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
91{
92 ENTER();
93
94 if (adapter->scantable[index].inframode == mode) {
95 if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
96 && !adapter->secinfo.WPAenabled
97 && !adapter->secinfo.WPA2enabled
98 && adapter->scantable[index].wpa_supplicant.wpa_ie[0] !=
99 WPA_IE
100 && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] !=
101 WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE
102 && !adapter->scantable[index].privacy) {
103 /* no security */
104 LEAVE();
105 return index;
106 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
107 && !adapter->secinfo.WPAenabled
108 && !adapter->secinfo.WPA2enabled
109 && adapter->scantable[index].privacy) {
110 /* static WEP enabled */
111 LEAVE();
112 return index;
113 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
114 && adapter->secinfo.WPAenabled
115 && !adapter->secinfo.WPA2enabled
116 && (adapter->scantable[index].wpa_supplicant.
117 wpa_ie[0]
118 == WPA_IE)
119 /* privacy bit may NOT be set in some APs like LinkSys WRT54G
120 && adapter->scantable[index].privacy */
121 ) {
122 /* WPA enabled */
123 lbs_pr_debug(1,
124 "is_network_compatible() WPA: index=%d wpa_ie=%#x "
125 "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
126 "privacy=%#x\n", index,
127 adapter->scantable[index].wpa_supplicant.
128 wpa_ie[0],
129 adapter->scantable[index].wpa2_supplicant.
130 wpa_ie[0],
131 (adapter->secinfo.WEPstatus ==
132 wlan802_11WEPenabled) ? "e" : "d",
133 (adapter->secinfo.WPAenabled) ? "e" : "d",
134 (adapter->secinfo.WPA2enabled) ? "e" : "d",
135 adapter->secinfo.Encryptionmode,
136 adapter->scantable[index].privacy);
137 LEAVE();
138 return index;
139 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
140 && !adapter->secinfo.WPAenabled
141 && adapter->secinfo.WPA2enabled
142 && (adapter->scantable[index].wpa2_supplicant.
143 wpa_ie[0]
144 == WPA2_IE)
145 /* privacy bit may NOT be set in some APs like LinkSys WRT54G
146 && adapter->scantable[index].privacy */
147 ) {
148 /* WPA2 enabled */
149 lbs_pr_debug(1,
150 "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
151 "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
152 "privacy=%#x\n", index,
153 adapter->scantable[index].wpa_supplicant.
154 wpa_ie[0],
155 adapter->scantable[index].wpa2_supplicant.
156 wpa_ie[0],
157 (adapter->secinfo.WEPstatus ==
158 wlan802_11WEPenabled) ? "e" : "d",
159 (adapter->secinfo.WPAenabled) ? "e" : "d",
160 (adapter->secinfo.WPA2enabled) ? "e" : "d",
161 adapter->secinfo.Encryptionmode,
162 adapter->scantable[index].privacy);
163 LEAVE();
164 return index;
165 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
166 && !adapter->secinfo.WPAenabled
167 && !adapter->secinfo.WPA2enabled
168 && (adapter->scantable[index].wpa_supplicant.
169 wpa_ie[0]
170 != WPA_IE)
171 && (adapter->scantable[index].wpa2_supplicant.
172 wpa_ie[0]
173 != WPA2_IE)
174 && adapter->secinfo.Encryptionmode != CIPHER_NONE
175 && adapter->scantable[index].privacy) {
176 /* dynamic WEP enabled */
177 lbs_pr_debug(1,
178 "is_network_compatible() dynamic WEP: index=%d "
179 "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
180 index,
181 adapter->scantable[index].wpa_supplicant.
182 wpa_ie[0],
183 adapter->scantable[index].wpa2_supplicant.
184 wpa_ie[0], adapter->secinfo.Encryptionmode,
185 adapter->scantable[index].privacy);
186 LEAVE();
187 return index;
188 }
189
190 /* security doesn't match */
191 lbs_pr_debug(1,
192 "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
193 "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
194 index,
195 adapter->scantable[index].wpa_supplicant.wpa_ie[0],
196 adapter->scantable[index].wpa2_supplicant.wpa_ie[0],
197 (adapter->secinfo.WEPstatus ==
198 wlan802_11WEPenabled) ? "e" : "d",
199 (adapter->secinfo.WPAenabled) ? "e" : "d",
200 (adapter->secinfo.WPA2enabled) ? "e" : "d",
201 adapter->secinfo.Encryptionmode,
202 adapter->scantable[index].privacy);
203 LEAVE();
204 return -ECONNREFUSED;
205 }
206
207 /* mode doesn't match */
208 LEAVE();
209 return -ENETUNREACH;
210}
211
212/**
213 * @brief This function validates a SSID as being able to be printed
214 *
215 * @param pssid SSID structure to validate
216 *
217 * @return TRUE or FALSE
218 */
219static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
220{
221 int ssididx;
222
223 for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
224 if (!isprint(pssid->ssid[ssididx])) {
225 return 0;
226 }
227 }
228
229 return 1;
230}
231
232/**
233 * @brief Post process the scan table after a new scan command has completed
234 *
235 * Inspect each entry of the scan table and try to find an entry that
236 * matches our current associated/joined network from the scan. If
237 * one is found, update the stored copy of the bssdescriptor for our
238 * current network.
239 *
240 * Debug dump the current scan table contents if compiled accordingly.
241 *
242 * @param priv A pointer to wlan_private structure
243 *
244 * @return void
245 */
246static void wlan_scan_process_results(wlan_private * priv)
247{
248 wlan_adapter *adapter = priv->adapter;
249 int foundcurrent;
250 int i;
251
252 foundcurrent = 0;
253
254 if (adapter->connect_status == libertas_connected) {
255 /* try to find the current BSSID in the new scan list */
256 for (i = 0; i < adapter->numinscantable; i++) {
257 if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
258 &adapter->curbssparams.ssid) &&
259 !memcmp(adapter->curbssparams.bssid,
260 adapter->scantable[i].macaddress,
261 ETH_ALEN)) {
262 foundcurrent = 1;
263 }
264 }
265
266 if (foundcurrent) {
267 /* Make a copy of current BSSID descriptor */
268 memcpy(&adapter->curbssparams.bssdescriptor,
269 &adapter->scantable[i],
270 sizeof(adapter->curbssparams.bssdescriptor));
271 }
272 }
273
274 for (i = 0; i < adapter->numinscantable; i++) {
275 lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
276 "RSSI[%03d], SSID[%s]\n",
277 i,
278 adapter->scantable[i].macaddress[0],
279 adapter->scantable[i].macaddress[1],
280 adapter->scantable[i].macaddress[2],
281 adapter->scantable[i].macaddress[3],
282 adapter->scantable[i].macaddress[4],
283 adapter->scantable[i].macaddress[5],
284 (s32) adapter->scantable[i].rssi,
285 adapter->scantable[i].ssid.ssid);
286 }
287}
288
289/**
290 * @brief Create a channel list for the driver to scan based on region info
291 *
292 * Use the driver region/band information to construct a comprehensive list
293 * of channels to scan. This routine is used for any scan that is not
294 * provided a specific channel list to scan.
295 *
296 * @param priv A pointer to wlan_private structure
297 * @param scanchanlist Output parameter: resulting channel list to scan
298 * @param filteredscan Flag indicating whether or not a BSSID or SSID filter
299 * is being sent in the command to firmware. Used to
300 * increase the number of channels sent in a scan
301 * command and to disable the firmware channel scan
302 * filter.
303 *
304 * @return void
305 */
306static void wlan_scan_create_channel_list(wlan_private * priv,
307 struct chanscanparamset * scanchanlist,
308 u8 filteredscan)
309{
310
311 wlan_adapter *adapter = priv->adapter;
312 struct region_channel *scanregion;
313 struct chan_freq_power *cfp;
314 int rgnidx;
315 int chanidx;
316 int nextchan;
317 u8 scantype;
318
319 chanidx = 0;
320
321 /* Set the default scan type to the user specified type, will later
322 * be changed to passive on a per channel basis if restricted by
323 * regulatory requirements (11d or 11h)
324 */
325 scantype = adapter->scantype;
326
327 for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
328 if (priv->adapter->enable11d &&
329 adapter->connect_status != libertas_connected) {
330 /* Scan all the supported chan for the first scan */
331 if (!adapter->universal_channel[rgnidx].valid)
332 continue;
333 scanregion = &adapter->universal_channel[rgnidx];
334
335 /* clear the parsed_region_chan for the first scan */
336 memset(&adapter->parsed_region_chan, 0x00,
337 sizeof(adapter->parsed_region_chan));
338 } else {
339 if (!adapter->region_channel[rgnidx].valid)
340 continue;
341 scanregion = &adapter->region_channel[rgnidx];
342 }
343
344 for (nextchan = 0;
345 nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
346
347 cfp = scanregion->CFP + nextchan;
348
349 if (priv->adapter->enable11d) {
350 scantype =
351 libertas_get_scan_type_11d(cfp->channel,
352 &adapter->
353 parsed_region_chan);
354 }
355
356 switch (scanregion->band) {
357 case BAND_B:
358 case BAND_G:
359 default:
360 scanchanlist[chanidx].radiotype =
361 cmd_scan_radio_type_bg;
362 break;
363 }
364
365 if (scantype == cmd_scan_type_passive) {
366 scanchanlist[chanidx].maxscantime =
367 cpu_to_le16
368 (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
369 scanchanlist[chanidx].chanscanmode.passivescan =
370 1;
371 } else {
372 scanchanlist[chanidx].maxscantime =
373 cpu_to_le16
374 (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
375 scanchanlist[chanidx].chanscanmode.passivescan =
376 0;
377 }
378
379 scanchanlist[chanidx].channumber = cfp->channel;
380
381 if (filteredscan) {
382 scanchanlist[chanidx].chanscanmode.
383 disablechanfilt = 1;
384 }
385 }
386 }
387}
388
389/**
390 * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
391 *
392 * Application layer or other functions can invoke wlan_scan_networks
393 * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
394 * This structure is used as the basis of one or many wlan_scan_cmd_config
395 * commands that are sent to the command processing module and sent to
396 * firmware.
397 *
398 * Create a wlan_scan_cmd_config based on the following user supplied
399 * parameters (if present):
400 * - SSID filter
401 * - BSSID filter
402 * - Number of Probes to be sent
403 * - channel list
404 *
405 * If the SSID or BSSID filter is not present, disable/clear the filter.
406 * If the number of probes is not set, use the adapter default setting
407 * Qualify the channel
408 *
409 * @param priv A pointer to wlan_private structure
410 * @param puserscanin NULL or pointer to scan configuration parameters
411 * @param ppchantlvout Output parameter: Pointer to the start of the
412 * channel TLV portion of the output scan config
413 * @param pscanchanlist Output parameter: Pointer to the resulting channel
414 * list to scan
415 * @param pmaxchanperscan Output parameter: Number of channels to scan for
416 * each issuance of the firmware scan command
417 * @param pfilteredscan Output parameter: Flag indicating whether or not
418 * a BSSID or SSID filter is being sent in the
419 * command to firmware. Used to increase the number
420 * of channels sent in a scan command and to
421 * disable the firmware channel scan filter.
422 * @param pscancurrentonly Output parameter: Flag indicating whether or not
423 * we are only scanning our current active channel
424 *
425 * @return resulting scan configuration
426 */
427static struct wlan_scan_cmd_config *
428wlan_scan_setup_scan_config(wlan_private * priv,
429 const struct wlan_ioctl_user_scan_cfg * puserscanin,
430 struct mrvlietypes_chanlistparamset ** ppchantlvout,
431 struct chanscanparamset * pscanchanlist,
432 int *pmaxchanperscan,
433 u8 * pfilteredscan,
434 u8 * pscancurrentonly)
435{
436 wlan_adapter *adapter = priv->adapter;
437 const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
438 struct mrvlietypes_numprobes *pnumprobestlv;
439 struct mrvlietypes_ssidparamset *pssidtlv;
440 struct wlan_scan_cmd_config * pscancfgout = NULL;
441 u8 *ptlvpos;
442 u16 numprobes;
443 u16 ssidlen;
444 int chanidx;
445 int scantype;
446 int scandur;
447 int channel;
448 int radiotype;
449
450 pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
451 if (pscancfgout == NULL)
452 goto out;
453
454 /* The tlvbufferlen is calculated for each scan command. The TLVs added
455 * in this routine will be preserved since the routine that sends
456 * the command will append channelTLVs at *ppchantlvout. The difference
457 * between the *ppchantlvout and the tlvbuffer start will be used
458 * to calculate the size of anything we add in this routine.
459 */
460 pscancfgout->tlvbufferlen = 0;
461
462 /* Running tlv pointer. Assigned to ppchantlvout at end of function
463 * so later routines know where channels can be added to the command buf
464 */
465 ptlvpos = pscancfgout->tlvbuffer;
466
467 /*
468 * Set the initial scan paramters for progressive scanning. If a specific
469 * BSSID or SSID is used, the number of channels in the scan command
470 * will be increased to the absolute maximum
471 */
472 *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
473
474 /* Initialize the scan as un-filtered by firmware, set to TRUE below if
475 * a SSID or BSSID filter is sent in the command
476 */
477 *pfilteredscan = 0;
478
479 /* Initialize the scan as not being only on the current channel. If
480 * the channel list is customized, only contains one channel, and
481 * is the active channel, this is set true and data flow is not halted.
482 */
483 *pscancurrentonly = 0;
484
485 if (puserscanin) {
486
487 /* Set the bss type scan filter, use adapter setting if unset */
488 pscancfgout->bsstype =
489 (puserscanin->bsstype ? puserscanin->bsstype : adapter->
490 scanmode);
491
492 /* Set the number of probes to send, use adapter setting if unset */
493 numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
494 adapter->scanprobes);
495
496 /*
497 * Set the BSSID filter to the incoming configuration,
498 * if non-zero. If not set, it will remain disabled (all zeros).
499 */
500 memcpy(pscancfgout->specificBSSID,
501 puserscanin->specificBSSID,
502 sizeof(pscancfgout->specificBSSID));
503
504 ssidlen = strlen(puserscanin->specificSSID);
505
506 if (ssidlen) {
507 pssidtlv =
508 (struct mrvlietypes_ssidparamset *) pscancfgout->
509 tlvbuffer;
510 pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
511 pssidtlv->header.len = cpu_to_le16(ssidlen);
512 memcpy(pssidtlv->ssid, puserscanin->specificSSID,
513 ssidlen);
514 ptlvpos += sizeof(pssidtlv->header) + ssidlen;
515 }
516
517 /*
518 * The default number of channels sent in the command is low to
519 * ensure the response buffer from the firmware does not truncate
520 * scan results. That is not an issue with an SSID or BSSID
521 * filter applied to the scan results in the firmware.
522 */
523 if (ssidlen || (memcmp(pscancfgout->specificBSSID,
524 &zeromac, sizeof(zeromac)) != 0)) {
525 *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
526 *pfilteredscan = 1;
527 }
528 } else {
529 pscancfgout->bsstype = adapter->scanmode;
530 numprobes = adapter->scanprobes;
531 }
532
533 /* If the input config or adapter has the number of Probes set, add tlv */
534 if (numprobes) {
535 pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
536 pnumprobestlv->header.type =
537 cpu_to_le16(TLV_TYPE_NUMPROBES);
538 pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
539 pnumprobestlv->numprobes = cpu_to_le16(numprobes);
540
541 ptlvpos +=
542 sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
543
544 pnumprobestlv->header.len =
545 cpu_to_le16(pnumprobestlv->header.len);
546 }
547
548 /*
549 * Set the output for the channel TLV to the address in the tlv buffer
550 * past any TLVs that were added in this fuction (SSID, numprobes).
551 * channel TLVs will be added past this for each scan command, preserving
552 * the TLVs that were previously added.
553 */
554 *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
555
556 if (puserscanin && puserscanin->chanlist[0].channumber) {
557
558 lbs_pr_debug(1, "Scan: Using supplied channel list\n");
559
560 for (chanidx = 0;
561 chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
562 && puserscanin->chanlist[chanidx].channumber; chanidx++) {
563
564 channel = puserscanin->chanlist[chanidx].channumber;
565 (pscanchanlist + chanidx)->channumber = channel;
566
567 radiotype = puserscanin->chanlist[chanidx].radiotype;
568 (pscanchanlist + chanidx)->radiotype = radiotype;
569
570 scantype = puserscanin->chanlist[chanidx].scantype;
571
572 if (scantype == cmd_scan_type_passive) {
573 (pscanchanlist +
574 chanidx)->chanscanmode.passivescan = 1;
575 } else {
576 (pscanchanlist +
577 chanidx)->chanscanmode.passivescan = 0;
578 }
579
580 if (puserscanin->chanlist[chanidx].scantime) {
581 scandur =
582 puserscanin->chanlist[chanidx].scantime;
583 } else {
584 if (scantype == cmd_scan_type_passive) {
585 scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
586 } else {
587 scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
588 }
589 }
590
591 (pscanchanlist + chanidx)->minscantime =
592 cpu_to_le16(scandur);
593 (pscanchanlist + chanidx)->maxscantime =
594 cpu_to_le16(scandur);
595 }
596
597 /* Check if we are only scanning the current channel */
598 if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
599 ==
600 priv->adapter->curbssparams.channel)) {
601 *pscancurrentonly = 1;
602 lbs_pr_debug(1, "Scan: Scanning current channel only");
603 }
604
605 } else {
606 lbs_pr_debug(1, "Scan: Creating full region channel list\n");
607 wlan_scan_create_channel_list(priv, pscanchanlist,
608 *pfilteredscan);
609 }
610
611out:
612 return pscancfgout;
613}
614
615/**
616 * @brief Construct and send multiple scan config commands to the firmware
617 *
618 * Previous routines have created a wlan_scan_cmd_config with any requested
619 * TLVs. This function splits the channel TLV into maxchanperscan lists
620 * and sends the portion of the channel TLV along with the other TLVs
621 * to the wlan_cmd routines for execution in the firmware.
622 *
623 * @param priv A pointer to wlan_private structure
624 * @param maxchanperscan Maximum number channels to be included in each
625 * scan command sent to firmware
626 * @param filteredscan Flag indicating whether or not a BSSID or SSID
627 * filter is being used for the firmware command
628 * scan command sent to firmware
629 * @param pscancfgout Scan configuration used for this scan.
630 * @param pchantlvout Pointer in the pscancfgout where the channel TLV
631 * should start. This is past any other TLVs that
632 * must be sent down in each firmware command.
633 * @param pscanchanlist List of channels to scan in maxchanperscan segments
634 *
635 * @return 0 or error return otherwise
636 */
637static int wlan_scan_channel_list(wlan_private * priv,
638 int maxchanperscan,
639 u8 filteredscan,
640 struct wlan_scan_cmd_config * pscancfgout,
641 struct mrvlietypes_chanlistparamset * pchantlvout,
642 struct chanscanparamset * pscanchanlist)
643{
644 struct chanscanparamset *ptmpchan;
645 struct chanscanparamset *pstartchan;
646 u8 scanband;
647 int doneearly;
648 int tlvidx;
649 int ret = 0;
650
651 ENTER();
652
653 if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
654 lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
655 pscancfgout, pchantlvout, pscanchanlist);
656 return -1;
657 }
658
659 pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
660
661 /* Set the temp channel struct pointer to the start of the desired list */
662 ptmpchan = pscanchanlist;
663
664 /* Loop through the desired channel list, sending a new firmware scan
665 * commands for each maxchanperscan channels (or for 1,6,11 individually
666 * if configured accordingly)
667 */
668 while (ptmpchan->channumber) {
669
670 tlvidx = 0;
671 pchantlvout->header.len = 0;
672 scanband = ptmpchan->radiotype;
673 pstartchan = ptmpchan;
674 doneearly = 0;
675
676 /* Construct the channel TLV for the scan command. Continue to
677 * insert channel TLVs until:
678 * - the tlvidx hits the maximum configured per scan command
679 * - the next channel to insert is 0 (end of desired channel list)
680 * - doneearly is set (controlling individual scanning of 1,6,11)
681 */
682 while (tlvidx < maxchanperscan && ptmpchan->channumber
683 && !doneearly) {
684
685 lbs_pr_debug(1,
686 "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
687 ptmpchan->channumber, ptmpchan->radiotype,
688 ptmpchan->chanscanmode.passivescan,
689 ptmpchan->chanscanmode.disablechanfilt,
690 ptmpchan->maxscantime);
691
692 /* Copy the current channel TLV to the command being prepared */
693 memcpy(pchantlvout->chanscanparam + tlvidx,
694 ptmpchan, sizeof(pchantlvout->chanscanparam));
695
696 /* Increment the TLV header length by the size appended */
697 pchantlvout->header.len +=
698 sizeof(pchantlvout->chanscanparam);
699
700 /*
701 * The tlv buffer length is set to the number of bytes of the
702 * between the channel tlv pointer and the start of the
703 * tlv buffer. This compensates for any TLVs that were appended
704 * before the channel list.
705 */
706 pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
707 - pscancfgout->tlvbuffer);
708
709 /* Add the size of the channel tlv header and the data length */
710 pscancfgout->tlvbufferlen +=
711 (sizeof(pchantlvout->header)
712 + pchantlvout->header.len);
713
714 /* Increment the index to the channel tlv we are constructing */
715 tlvidx++;
716
717 doneearly = 0;
718
719 /* Stop the loop if the *current* channel is in the 1,6,11 set
720 * and we are not filtering on a BSSID or SSID.
721 */
722 if (!filteredscan && (ptmpchan->channumber == 1
723 || ptmpchan->channumber == 6
724 || ptmpchan->channumber == 11)) {
725 doneearly = 1;
726 }
727
728 /* Increment the tmp pointer to the next channel to be scanned */
729 ptmpchan++;
730
731 /* Stop the loop if the *next* channel is in the 1,6,11 set.
732 * This will cause it to be the only channel scanned on the next
733 * interation
734 */
735 if (!filteredscan && (ptmpchan->channumber == 1
736 || ptmpchan->channumber == 6
737 || ptmpchan->channumber == 11)) {
738 doneearly = 1;
739 }
740 }
741
742 /* Send the scan command to the firmware with the specified cfg */
743 ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
744 0, 0, pscancfgout);
745 }
746
747 LEAVE();
748 return ret;
749}
750
751/**
752 * @brief Internal function used to start a scan based on an input config
753 *
754 * Use the input user scan configuration information when provided in
755 * order to send the appropriate scan commands to firmware to populate or
756 * update the internal driver scan table
757 *
758 * @param priv A pointer to wlan_private structure
759 * @param puserscanin Pointer to the input configuration for the requested
760 * scan.
761 *
762 * @return 0 or < 0 if error
763 */
764int wlan_scan_networks(wlan_private * priv,
765 const struct wlan_ioctl_user_scan_cfg * puserscanin)
766{
767 wlan_adapter *adapter = priv->adapter;
768 struct mrvlietypes_chanlistparamset *pchantlvout;
769 struct chanscanparamset * scan_chan_list = NULL;
770 struct wlan_scan_cmd_config * scan_cfg = NULL;
771 u8 keeppreviousscan;
772 u8 filteredscan;
773 u8 scancurrentchanonly;
774 int maxchanperscan;
775 int ret;
776
777 ENTER();
778
779 scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
780 WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
781 if (scan_chan_list == NULL) {
782 ret = -ENOMEM;
783 goto out;
784 }
785
786 scan_cfg = wlan_scan_setup_scan_config(priv,
787 puserscanin,
788 &pchantlvout,
789 scan_chan_list,
790 &maxchanperscan,
791 &filteredscan,
792 &scancurrentchanonly);
793 if (scan_cfg == NULL) {
794 ret = -ENOMEM;
795 goto out;
796 }
797
798 keeppreviousscan = 0;
799
800 if (puserscanin) {
801 keeppreviousscan = puserscanin->keeppreviousscan;
802 }
803
804 if (!keeppreviousscan) {
805 memset(adapter->scantable, 0x00,
806 sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
807 adapter->numinscantable = 0;
808 }
809
810 /* Keep the data path active if we are only scanning our current channel */
811 if (!scancurrentchanonly) {
812 netif_stop_queue(priv->wlan_dev.netdev);
813 netif_carrier_off(priv->wlan_dev.netdev);
814 }
815
816 ret = wlan_scan_channel_list(priv,
817 maxchanperscan,
818 filteredscan,
819 scan_cfg,
820 pchantlvout,
821 scan_chan_list);
822
823 /* Process the resulting scan table:
824 * - Remove any bad ssids
825 * - Update our current BSS information from scan data
826 */
827 wlan_scan_process_results(priv);
828
829 if (priv->adapter->connect_status == libertas_connected) {
830 netif_carrier_on(priv->wlan_dev.netdev);
831 netif_wake_queue(priv->wlan_dev.netdev);
832 }
833
834out:
835 if (scan_cfg)
836 kfree(scan_cfg);
837
838 if (scan_chan_list)
839 kfree(scan_chan_list);
840
841 LEAVE();
842 return ret;
843}
844
845/**
846 * @brief Inspect the scan response buffer for pointers to expected TLVs
847 *
848 * TLVs can be included at the end of the scan response BSS information.
849 * Parse the data in the buffer for pointers to TLVs that can potentially
850 * be passed back in the response
851 *
852 * @param ptlv Pointer to the start of the TLV buffer to parse
853 * @param tlvbufsize size of the TLV buffer
854 * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
855 *
856 * @return void
857 */
858static
859void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
860 int tlvbufsize,
861 struct mrvlietypes_tsftimestamp ** ptsftlv)
862{
863 struct mrvlietypes_data *pcurrenttlv;
864 int tlvbufleft;
865 u16 tlvtype;
866 u16 tlvlen;
867
868 pcurrenttlv = ptlv;
869 tlvbufleft = tlvbufsize;
870 *ptsftlv = NULL;
871
872 lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
873 lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
874
875 while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
876 tlvtype = le16_to_cpu(pcurrenttlv->header.type);
877 tlvlen = le16_to_cpu(pcurrenttlv->header.len);
878
879 switch (tlvtype) {
880 case TLV_TYPE_TSFTIMESTAMP:
881 *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
882 break;
883
884 default:
885 lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
886 tlvtype);
887 /* Give up, this seems corrupted */
888 return;
889 } /* switch */
890
891 tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
892 pcurrenttlv =
893 (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
894 } /* while */
895}
896
897/**
898 * @brief Interpret a BSS scan response returned from the firmware
899 *
900 * Parse the various fixed fields and IEs passed back for a a BSS probe
901 * response or beacon from the scan command. Record information as needed
902 * in the scan table struct bss_descriptor for that entry.
903 *
904 * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry
905 *
906 * @return 0 or -1
907 */
908static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
909 u8 ** pbeaconinfo, int *bytesleft)
910{
911 enum ieeetypes_elementid elemID;
912 struct ieeetypes_fhparamset *pFH;
913 struct ieeetypes_dsparamset *pDS;
914 struct ieeetypes_cfparamset *pCF;
915 struct ieeetypes_ibssparamset *pibss;
916 struct ieeetypes_capinfo *pcap;
917 struct WLAN_802_11_FIXED_IEs fixedie;
918 u8 *pcurrentptr;
919 u8 *pRate;
920 u8 elemlen;
921 u8 bytestocopy;
922 u8 ratesize;
923 u16 beaconsize;
924 u8 founddatarateie;
925 int bytesleftforcurrentbeacon;
926
927 struct WPA_SUPPLICANT *pwpa_supplicant;
928 struct WPA_SUPPLICANT *pwpa2_supplicant;
929 struct IE_WPA *pIe;
930 const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
931
932 struct ieeetypes_countryinfoset *pcountryinfo;
933
934 ENTER();
935
936 founddatarateie = 0;
937 ratesize = 0;
938 beaconsize = 0;
939
940 if (*bytesleft >= sizeof(beaconsize)) {
941 /* Extract & convert beacon size from the command buffer */
942 memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
943 beaconsize = le16_to_cpu(beaconsize);
944 *bytesleft -= sizeof(beaconsize);
945 *pbeaconinfo += sizeof(beaconsize);
946 }
947
948 if (beaconsize == 0 || beaconsize > *bytesleft) {
949
950 *pbeaconinfo += *bytesleft;
951 *bytesleft = 0;
952
953 return -1;
954 }
955
956 /* Initialize the current working beacon pointer for this BSS iteration */
957 pcurrentptr = *pbeaconinfo;
958
959 /* Advance the return beacon pointer past the current beacon */
960 *pbeaconinfo += beaconsize;
961 *bytesleft -= beaconsize;
962
963 bytesleftforcurrentbeacon = beaconsize;
964
965 pwpa_supplicant = &pBSSEntry->wpa_supplicant;
966 pwpa2_supplicant = &pBSSEntry->wpa2_supplicant;
967
968 memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
969 lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
970 pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
971 pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
972 pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
973
974 pcurrentptr += ETH_ALEN;
975 bytesleftforcurrentbeacon -= ETH_ALEN;
976
977 if (bytesleftforcurrentbeacon < 12) {
978 lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
979 return -1;
980 }
981
982 /*
983 * next 4 fields are RSSI, time stamp, beacon interval,
984 * and capability information
985 */
986
987 /* RSSI is 1 byte long */
988 pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
989 lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
990 pcurrentptr += 1;
991 bytesleftforcurrentbeacon -= 1;
992
993 /* time stamp is 8 bytes long */
994 memcpy(fixedie.timestamp, pcurrentptr, 8);
995 memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
996 pcurrentptr += 8;
997 bytesleftforcurrentbeacon -= 8;
998
999 /* beacon interval is 2 bytes long */
1000 memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
1001 pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
1002 pcurrentptr += 2;
1003 bytesleftforcurrentbeacon -= 2;
1004
1005 /* capability information is 2 bytes long */
1006 memcpy(&fixedie.capabilities, pcurrentptr, 2);
1007 lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
1008 fixedie.capabilities);
1009 fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
1010 pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
1011 memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
1012 pcurrentptr += 2;
1013 bytesleftforcurrentbeacon -= 2;
1014
1015 /* rest of the current buffer are IE's */
1016 lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
1017 bytesleftforcurrentbeacon);
1018
1019 lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
1020 bytesleftforcurrentbeacon);
1021
1022 if (pcap->privacy) {
1023 lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
1024 pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
1025 } else {
1026 pBSSEntry->privacy = wlan802_11privfilteracceptall;
1027 }
1028
1029 if (pcap->ibss == 1) {
1030 pBSSEntry->inframode = wlan802_11ibss;
1031 } else {
1032 pBSSEntry->inframode = wlan802_11infrastructure;
1033 }
1034
1035 /* process variable IE */
1036 while (bytesleftforcurrentbeacon >= 2) {
1037 elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
1038 elemlen = *((u8 *) pcurrentptr + 1);
1039
1040 if (bytesleftforcurrentbeacon < elemlen) {
1041 lbs_pr_debug(1, "InterpretIE: error in processing IE, "
1042 "bytes left < IE length\n");
1043 bytesleftforcurrentbeacon = 0;
1044 continue;
1045 }
1046
1047 switch (elemID) {
1048
1049 case SSID:
1050 pBSSEntry->ssid.ssidlength = elemlen;
1051 memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
1052 elemlen);
1053 lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
1054 break;
1055
1056 case SUPPORTED_RATES:
1057 memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
1058 elemlen);
1059 memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
1060 elemlen);
1061 ratesize = elemlen;
1062 founddatarateie = 1;
1063 break;
1064
1065 case EXTRA_IE:
1066 lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
1067 pBSSEntry->extra_ie = 1;
1068 break;
1069
1070 case FH_PARAM_SET:
1071 pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
1072 memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
1073 sizeof(struct ieeetypes_fhparamset));
1074 pBSSEntry->phyparamset.fhparamset.dwelltime
1075 =
1076 le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
1077 dwelltime);
1078 break;
1079
1080 case DS_PARAM_SET:
1081 pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
1082
1083 pBSSEntry->channel = pDS->currentchan;
1084
1085 memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
1086 sizeof(struct ieeetypes_dsparamset));
1087 break;
1088
1089 case CF_PARAM_SET:
1090 pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
1091
1092 memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
1093 sizeof(struct ieeetypes_cfparamset));
1094 break;
1095
1096 case IBSS_PARAM_SET:
1097 pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
1098 pBSSEntry->atimwindow =
1099 le32_to_cpu(pibss->atimwindow);
1100
1101 memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
1102 sizeof(struct ieeetypes_ibssparamset));
1103
1104 pBSSEntry->ssparamset.ibssparamset.atimwindow
1105 =
1106 le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
1107 atimwindow);
1108 break;
1109
1110 /* Handle Country Info IE */
1111 case COUNTRY_INFO:
1112 pcountryinfo =
1113 (struct ieeetypes_countryinfoset *) pcurrentptr;
1114
1115 if (pcountryinfo->len <
1116 sizeof(pcountryinfo->countrycode)
1117 || pcountryinfo->len > 254) {
1118 lbs_pr_debug(1, "InterpretIE: 11D- Err "
1119 "CountryInfo len =%d min=%d max=254\n",
1120 pcountryinfo->len,
1121 sizeof(pcountryinfo->countrycode));
1122 LEAVE();
1123 return -1;
1124 }
1125
1126 memcpy(&pBSSEntry->countryinfo,
1127 pcountryinfo, pcountryinfo->len + 2);
1128 lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
1129 (u8 *) pcountryinfo,
1130 (u32) (pcountryinfo->len + 2));
1131 break;
1132
1133 case EXTENDED_SUPPORTED_RATES:
1134 /*
1135 * only process extended supported rate
1136 * if data rate is already found.
1137 * data rate IE should come before
1138 * extended supported rate IE
1139 */
1140 if (founddatarateie) {
1141 if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
1142 bytestocopy =
1143 (WLAN_SUPPORTED_RATES - ratesize);
1144 } else {
1145 bytestocopy = elemlen;
1146 }
1147
1148 pRate = (u8 *) pBSSEntry->datarates;
1149 pRate += ratesize;
1150 memmove(pRate, (pcurrentptr + 2), bytestocopy);
1151
1152 pRate = (u8 *) pBSSEntry->libertas_supported_rates;
1153
1154 pRate += ratesize;
1155 memmove(pRate, (pcurrentptr + 2), bytestocopy);
1156 }
1157 break;
1158
1159 case VENDOR_SPECIFIC_221:
1160#define IE_ID_LEN_FIELDS_BYTES 2
1161 pIe = (struct IE_WPA *)pcurrentptr;
1162
1163 if (!memcmp(pIe->oui, oui01, sizeof(oui01))) {
1164 pwpa_supplicant->wpa_ie_len
1165 = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
1166 sizeof(pwpa_supplicant->wpa_ie));
1167 memcpy(pwpa_supplicant->wpa_ie,
1168 pcurrentptr,
1169 pwpa_supplicant->wpa_ie_len);
1170 lbs_dbg_hex("InterpretIE: Resp WPA_IE",
1171 pwpa_supplicant->wpa_ie, elemlen);
1172 }
1173 break;
1174 case WPA2_IE:
1175 pIe = (struct IE_WPA *)pcurrentptr;
1176 pwpa2_supplicant->wpa_ie_len
1177 = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
1178 sizeof(pwpa2_supplicant->wpa_ie));
1179 memcpy(pwpa2_supplicant->wpa_ie,
1180 pcurrentptr, pwpa2_supplicant->wpa_ie_len);
1181
1182 lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
1183 pwpa2_supplicant->wpa_ie, elemlen);
1184 break;
1185 case TIM:
1186 break;
1187
1188 case CHALLENGE_TEXT:
1189 break;
1190 }
1191
1192 pcurrentptr += elemlen + 2;
1193
1194 /* need to account for IE ID and IE len */
1195 bytesleftforcurrentbeacon -= (elemlen + 2);
1196
1197 } /* while (bytesleftforcurrentbeacon > 2) */
1198
1199 return 0;
1200}
1201
1202/**
1203 * @brief Compare two SSIDs
1204 *
1205 * @param ssid1 A pointer to ssid to compare
1206 * @param ssid2 A pointer to ssid to compare
1207 *
1208 * @return 0--ssid is same, otherwise is different
1209 */
1210int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
1211{
1212 if (!ssid1 || !ssid2)
1213 return -1;
1214
1215 if (ssid1->ssidlength != ssid2->ssidlength)
1216 return -1;
1217
1218 return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
1219}
1220
1221/**
1222 * @brief This function finds a specific compatible BSSID in the scan list
1223 *
1224 * @param adapter A pointer to wlan_adapter
1225 * @param bssid BSSID to find in the scan list
1226 * @param mode Network mode: Infrastructure or IBSS
1227 *
1228 * @return index in BSSID list, or error return code (< 0)
1229 */
1230int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
1231{
1232 int ret = -ENETUNREACH;
1233 int i;
1234
1235 if (!bssid)
1236 return -EFAULT;
1237
1238 lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
1239 adapter->numinscantable);
1240
1241 /* Look through the scan table for a compatible match. The ret return
1242 * variable will be equal to the index in the scan table (greater
1243 * than zero) if the network is compatible. The loop will continue
1244 * past a matched bssid that is not compatible in case there is an
1245 * AP with multiple SSIDs assigned to the same BSSID
1246 */
1247 for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
1248 if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
1249 switch (mode) {
1250 case wlan802_11infrastructure:
1251 case wlan802_11ibss:
1252 ret = is_network_compatible(adapter, i, mode);
1253 break;
1254 default:
1255 ret = i;
1256 break;
1257 }
1258 }
1259 }
1260
1261 return ret;
1262}
1263
1264/**
1265 * @brief This function finds ssid in ssid list.
1266 *
1267 * @param adapter A pointer to wlan_adapter
1268 * @param ssid SSID to find in the list
1269 * @param bssid BSSID to qualify the SSID selection (if provided)
1270 * @param mode Network mode: Infrastructure or IBSS
1271 *
1272 * @return index in BSSID list
1273 */
1274int libertas_find_SSID_in_list(wlan_adapter * adapter,
1275 struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
1276{
1277 int net = -ENETUNREACH;
1278 u8 bestrssi = 0;
1279 int i;
1280 int j;
1281
1282 lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
1283
1284 for (i = 0; i < adapter->numinscantable; i++) {
1285 if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
1286 (!bssid ||
1287 !memcmp(adapter->scantable[i].
1288 macaddress, bssid, ETH_ALEN))) {
1289 switch (mode) {
1290 case wlan802_11infrastructure:
1291 case wlan802_11ibss:
1292 j = is_network_compatible(adapter, i, mode);
1293
1294 if (j >= 0) {
1295 if (bssid) {
1296 return i;
1297 }
1298
1299 if (SCAN_RSSI
1300 (adapter->scantable[i].rssi)
1301 > bestrssi) {
1302 bestrssi =
1303 SCAN_RSSI(adapter->
1304 scantable[i].
1305 rssi);
1306 net = i;
1307 }
1308 } else {
1309 if (net == -ENETUNREACH) {
1310 net = j;
1311 }
1312 }
1313 break;
1314 case wlan802_11autounknown:
1315 default:
1316 if (SCAN_RSSI(adapter->scantable[i].rssi)
1317 > bestrssi) {
1318 bestrssi =
1319 SCAN_RSSI(adapter->scantable[i].
1320 rssi);
1321 net = i;
1322 }
1323 break;
1324 }
1325 }
1326 }
1327
1328 return net;
1329}
1330
1331/**
1332 * @brief This function finds the best SSID in the Scan List
1333 *
1334 * Search the scan table for the best SSID that also matches the current
1335 * adapter network preference (infrastructure or adhoc)
1336 *
1337 * @param adapter A pointer to wlan_adapter
1338 *
1339 * @return index in BSSID list
1340 */
1341int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
1342 enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
1343{
1344 int bestnet = -ENETUNREACH;
1345 u8 bestrssi = 0;
1346 int i;
1347
1348 ENTER();
1349
1350 lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
1351
1352 for (i = 0; i < adapter->numinscantable; i++) {
1353 switch (mode) {
1354 case wlan802_11infrastructure:
1355 case wlan802_11ibss:
1356 if (is_network_compatible(adapter, i, mode) >= 0) {
1357 if (SCAN_RSSI(adapter->scantable[i].rssi) >
1358 bestrssi) {
1359 bestrssi =
1360 SCAN_RSSI(adapter->scantable[i].
1361 rssi);
1362 bestnet = i;
1363 }
1364 }
1365 break;
1366 case wlan802_11autounknown:
1367 default:
1368 if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
1369 bestrssi =
1370 SCAN_RSSI(adapter->scantable[i].rssi);
1371 bestnet = i;
1372 }
1373 break;
1374 }
1375 }
1376
1377 LEAVE();
1378 return bestnet;
1379}
1380
1381/**
1382 * @brief Find the AP with specific ssid in the scan list
1383 *
1384 * @param priv A pointer to wlan_private structure
1385 * @param pSSID A pointer to AP's ssid
1386 *
1387 * @return 0--success, otherwise--fail
1388 */
1389int libertas_find_best_network_SSID(wlan_private * priv,
1390 struct WLAN_802_11_SSID *pSSID,
1391 enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
1392 enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
1393{
1394 wlan_adapter *adapter = priv->adapter;
1395 int ret = 0;
1396 struct bss_descriptor *preqbssid;
1397 int i;
1398
1399 ENTER();
1400
1401 memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
1402
1403 wlan_scan_networks(priv, NULL);
1404 if (adapter->surpriseremoved)
1405 return -1;
1406 wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
1407
1408 i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
1409 if (i < 0) {
1410 ret = -1;
1411 goto out;
1412 }
1413
1414 preqbssid = &adapter->scantable[i];
1415 memcpy(pSSID, &preqbssid->ssid,
1416 sizeof(struct WLAN_802_11_SSID));
1417 *out_mode = preqbssid->inframode;
1418
1419 if (!pSSID->ssidlength) {
1420 ret = -1;
1421 }
1422
1423out:
1424 LEAVE();
1425 return ret;
1426}
1427
1428/**
1429 * @brief Scan Network
1430 *
1431 * @param dev A pointer to net_device structure
1432 * @param info A pointer to iw_request_info structure
1433 * @param vwrq A pointer to iw_param structure
1434 * @param extra A pointer to extra data buf
1435 *
1436 * @return 0 --success, otherwise fail
1437 */
1438int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
1439 struct iw_param *vwrq, char *extra)
1440{
1441 wlan_private *priv = dev->priv;
1442 wlan_adapter *adapter = priv->adapter;
1443 union iwreq_data wrqu;
1444
1445 ENTER();
1446
1447 if (!wlan_scan_networks(priv, NULL)) {
1448 memset(&wrqu, 0, sizeof(union iwreq_data));
1449 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
1450 NULL);
1451 }
1452
1453 if (adapter->surpriseremoved)
1454 return -1;
1455
1456 LEAVE();
1457 return 0;
1458}
1459
1460/**
1461 * @brief Send a scan command for all available channels filtered on a spec
1462 *
1463 * @param priv A pointer to wlan_private structure
1464 * @param prequestedssid A pointer to AP's ssid
1465 * @param keeppreviousscan Flag used to save/clear scan table before scan
1466 *
1467 * @return 0-success, otherwise fail
1468 */
1469int libertas_send_specific_SSID_scan(wlan_private * priv,
1470 struct WLAN_802_11_SSID *prequestedssid,
1471 u8 keeppreviousscan)
1472{
1473 wlan_adapter *adapter = priv->adapter;
1474 struct wlan_ioctl_user_scan_cfg scancfg;
1475
1476 ENTER();
1477
1478 if (prequestedssid == NULL) {
1479 return -1;
1480 }
1481
1482 memset(&scancfg, 0x00, sizeof(scancfg));
1483
1484 memcpy(scancfg.specificSSID, prequestedssid->ssid,
1485 prequestedssid->ssidlength);
1486 scancfg.keeppreviousscan = keeppreviousscan;
1487
1488 wlan_scan_networks(priv, &scancfg);
1489 if (adapter->surpriseremoved)
1490 return -1;
1491 wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
1492
1493 LEAVE();
1494 return 0;
1495}
1496
1497/**
1498 * @brief scan an AP with specific BSSID
1499 *
1500 * @param priv A pointer to wlan_private structure
1501 * @param bssid A pointer to AP's bssid
1502 * @param keeppreviousscan Flag used to save/clear scan table before scan
1503 *
1504 * @return 0-success, otherwise fail
1505 */
1506int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
1507{
1508 struct wlan_ioctl_user_scan_cfg scancfg;
1509
1510 ENTER();
1511
1512 if (bssid == NULL) {
1513 return -1;
1514 }
1515
1516 memset(&scancfg, 0x00, sizeof(scancfg));
1517 memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
1518 scancfg.keeppreviousscan = keeppreviousscan;
1519
1520 wlan_scan_networks(priv, &scancfg);
1521 if (priv->adapter->surpriseremoved)
1522 return -1;
1523 wait_event_interruptible(priv->adapter->cmd_pending,
1524 !priv->adapter->nr_cmd_pending);
1525
1526 LEAVE();
1527 return 0;
1528}
1529
1530/**
1531 * @brief Retrieve the scan table entries via wireless tools IOCTL call
1532 *
1533 * @param dev A pointer to net_device structure
1534 * @param info A pointer to iw_request_info structure
1535 * @param dwrq A pointer to iw_point structure
1536 * @param extra A pointer to extra data buf
1537 *
1538 * @return 0 --success, otherwise fail
1539 */
1540int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
1541 struct iw_point *dwrq, char *extra)
1542{
1543 wlan_private *priv = dev->priv;
1544 wlan_adapter *adapter = priv->adapter;
1545 int ret = 0;
1546 char *current_ev = extra;
1547 char *end_buf = extra + IW_SCAN_MAX_DATA;
1548 struct chan_freq_power *cfp;
1549 struct bss_descriptor *pscantable;
1550 char *current_val; /* For rates */
1551 struct iw_event iwe; /* Temporary buffer */
1552 int i;
1553 int j;
1554 int rate;
1555#define PERFECT_RSSI ((u8)50)
1556#define WORST_RSSI ((u8)0)
1557#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
1558 u8 rssi;
1559
1560 u8 buf[16 + 256 * 2];
1561 u8 *ptr;
1562
1563 ENTER();
1564
1565 /*
1566 * if there's either commands in the queue or one being
1567 * processed return -EAGAIN for iwlist to retry later.
1568 */
1569 if (adapter->nr_cmd_pending)
1570 return -EAGAIN;
1571
1572 if (adapter->connect_status == libertas_connected)
1573 lbs_pr_debug(1, "Current ssid: %32s\n",
1574 adapter->curbssparams.ssid.ssid);
1575
1576 lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
1577 adapter->numinscantable);
1578
1579 /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
1580 * The new API using SIOCGIWSCAN is only limited by buffer size
1581 * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
1582 * which is 4096.
1583 */
1584 for (i = 0; i < adapter->numinscantable; i++) {
1585 if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
1586 lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
1587 "MAX_SCAN_CELL_SIZE=%d\n",
1588 i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
1589 break;
1590 }
1591
1592 pscantable = &adapter->scantable[i];
1593
1594 lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid);
1595
1596 cfp =
1597 libertas_find_cfp_by_band_and_channel(adapter, 0,
1598 pscantable->channel);
1599 if (!cfp) {
1600 lbs_pr_debug(1, "Invalid channel number %d\n",
1601 pscantable->channel);
1602 continue;
1603 }
1604
1605 if (!ssid_valid(&adapter->scantable[i].ssid)) {
1606 continue;
1607 }
1608
1609 /* First entry *MUST* be the AP MAC address */
1610 iwe.cmd = SIOCGIWAP;
1611 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1612 memcpy(iwe.u.ap_addr.sa_data,
1613 &adapter->scantable[i].macaddress, ETH_ALEN);
1614
1615 iwe.len = IW_EV_ADDR_LEN;
1616 current_ev =
1617 iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1618
1619 //Add the ESSID
1620 iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
1621
1622 if (iwe.u.data.length > 32) {
1623 iwe.u.data.length = 32;
1624 }
1625
1626 iwe.cmd = SIOCGIWESSID;
1627 iwe.u.data.flags = 1;
1628 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1629 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
1630 adapter->scantable[i].ssid.
1631 ssid);
1632
1633 //Add mode
1634 iwe.cmd = SIOCGIWMODE;
1635 iwe.u.mode = adapter->scantable[i].inframode + 1;
1636 iwe.len = IW_EV_UINT_LEN;
1637 current_ev =
1638 iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1639
1640 //frequency
1641 iwe.cmd = SIOCGIWFREQ;
1642 iwe.u.freq.m = (long)cfp->freq * 100000;
1643 iwe.u.freq.e = 1;
1644 iwe.len = IW_EV_FREQ_LEN;
1645 current_ev =
1646 iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1647
1648 /* Add quality statistics */
1649 iwe.cmd = IWEVQUAL;
1650 iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
1651 iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
1652
1653 rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
1654 iwe.u.qual.qual =
1655 (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
1656 (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
1657 (RSSI_DIFF * RSSI_DIFF);
1658 if (iwe.u.qual.qual > 100)
1659 iwe.u.qual.qual = 100;
1660 else if (iwe.u.qual.qual < 1)
1661 iwe.u.qual.qual = 0;
1662
1663 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1664 iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1665 } else {
1666 iwe.u.qual.noise =
1667 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1668 }
1669 if ((adapter->inframode == wlan802_11ibss) &&
1670 !libertas_SSID_cmp(&adapter->curbssparams.ssid,
1671 &adapter->scantable[i].ssid)
1672 && adapter->adhoccreate) {
1673 ret = libertas_prepare_and_send_command(priv,
1674 cmd_802_11_rssi,
1675 0,
1676 cmd_option_waitforrsp,
1677 0, NULL);
1678
1679 if (!ret) {
1680 iwe.u.qual.level =
1681 CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
1682 AVG_SCALE,
1683 adapter->NF[TYPE_RXPD][TYPE_AVG] /
1684 AVG_SCALE);
1685 }
1686 }
1687 iwe.len = IW_EV_QUAL_LEN;
1688 current_ev =
1689 iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1690
1691 /* Add encryption capability */
1692 iwe.cmd = SIOCGIWENCODE;
1693 if (adapter->scantable[i].privacy) {
1694 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1695 } else {
1696 iwe.u.data.flags = IW_ENCODE_DISABLED;
1697 }
1698 iwe.u.data.length = 0;
1699 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1700 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
1701 adapter->scantable->ssid.
1702 ssid);
1703
1704 current_val = current_ev + IW_EV_LCP_LEN;
1705
1706 iwe.cmd = SIOCGIWRATE;
1707
1708 iwe.u.bitrate.fixed = 0;
1709 iwe.u.bitrate.disabled = 0;
1710 iwe.u.bitrate.value = 0;
1711
1712 /* Bit rate given in 500 kb/s units (+ 0x80) */
1713 for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
1714 j++) {
1715 if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
1716 break;
1717 }
1718 rate =
1719 (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
1720 500000;
1721 if (rate > iwe.u.bitrate.value) {
1722 iwe.u.bitrate.value = rate;
1723 }
1724
1725 iwe.u.bitrate.value =
1726 (adapter->scantable[i].libertas_supported_rates[j]
1727 & 0x7f) * 500000;
1728 iwe.len = IW_EV_PARAM_LEN;
1729 current_ev =
1730 iwe_stream_add_value(current_ev, current_val,
1731 end_buf, &iwe, iwe.len);
1732
1733 }
1734 if ((adapter->scantable[i].inframode == wlan802_11ibss)
1735 && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
1736 &adapter->scantable[i].ssid)
1737 && adapter->adhoccreate) {
1738 iwe.u.bitrate.value = 22 * 500000;
1739 }
1740 iwe.len = IW_EV_PARAM_LEN;
1741 current_ev =
1742 iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
1743 iwe.len);
1744
1745 /* Add new value to event */
1746 current_val = current_ev + IW_EV_LCP_LEN;
1747
1748 if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) {
1749 memset(&iwe, 0, sizeof(iwe));
1750 memset(buf, 0, sizeof(buf));
1751 memcpy(buf, adapter->scantable[i].
1752 wpa2_supplicant.wpa_ie,
1753 adapter->scantable[i].wpa2_supplicant.
1754 wpa_ie_len);
1755 iwe.cmd = IWEVGENIE;
1756 iwe.u.data.length = adapter->scantable[i].
1757 wpa2_supplicant.wpa_ie_len;
1758 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1759 current_ev = iwe_stream_add_point(current_ev, end_buf,
1760 &iwe, buf);
1761 }
1762 if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) {
1763 memset(&iwe, 0, sizeof(iwe));
1764 memset(buf, 0, sizeof(buf));
1765 memcpy(buf, adapter->scantable[i].
1766 wpa_supplicant.wpa_ie,
1767 adapter->scantable[i].wpa_supplicant.
1768 wpa_ie_len);
1769 iwe.cmd = IWEVGENIE;
1770 iwe.u.data.length = adapter->scantable[i].
1771 wpa_supplicant.wpa_ie_len;
1772 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1773 current_ev = iwe_stream_add_point(current_ev, end_buf,
1774 &iwe, buf);
1775 }
1776
1777
1778 if (adapter->scantable[i].extra_ie != 0) {
1779 memset(&iwe, 0, sizeof(iwe));
1780 memset(buf, 0, sizeof(buf));
1781 ptr = buf;
1782 ptr += sprintf(ptr, "extra_ie");
1783 iwe.u.data.length = strlen(buf);
1784
1785 lbs_pr_debug(1, "iwe.u.data.length %d\n",
1786 iwe.u.data.length);
1787 lbs_pr_debug(1, "BUF: %s \n", buf);
1788
1789 iwe.cmd = IWEVCUSTOM;
1790 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1791 current_ev =
1792 iwe_stream_add_point(current_ev, end_buf, &iwe,
1793 buf);
1794 }
1795
1796 current_val = current_ev + IW_EV_LCP_LEN;
1797
1798 /*
1799 * Check if we added any event
1800 */
1801 if ((current_val - current_ev) > IW_EV_LCP_LEN)
1802 current_ev = current_val;
1803 }
1804
1805 dwrq->length = (current_ev - extra);
1806 dwrq->flags = 0;
1807
1808 LEAVE();
1809 return 0;
1810}
1811
1812/**
1813 * @brief Prepare a scan command to be sent to the firmware
1814 *
1815 * Use the wlan_scan_cmd_config sent to the command processing module in
1816 * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
1817 * struct to send to firmware.
1818 *
1819 * The fixed fields specifying the BSS type and BSSID filters as well as a
1820 * variable number/length of TLVs are sent in the command to firmware.
1821 *
1822 * @param priv A pointer to wlan_private structure
1823 * @param cmd A pointer to cmd_ds_command structure to be sent to
1824 * firmware with the cmd_DS_801_11_SCAN structure
1825 * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
1826 * to set the fields/TLVs for the command sent to firmware
1827 *
1828 * @return 0 or -1
1829 *
1830 * @sa wlan_scan_create_channel_list
1831 */
1832int libertas_cmd_80211_scan(wlan_private * priv,
1833 struct cmd_ds_command *cmd, void *pdata_buf)
1834{
1835 struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
1836 struct wlan_scan_cmd_config *pscancfg;
1837
1838 ENTER();
1839
1840 pscancfg = pdata_buf;
1841
1842 /* Set fixed field variables in scan command */
1843 pscan->bsstype = pscancfg->bsstype;
1844 memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
1845 memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
1846
1847 cmd->command = cpu_to_le16(cmd_802_11_scan);
1848
1849 /* size is equal to the sizeof(fixed portions) + the TLV len + header */
1850 cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
1851 + sizeof(pscan->BSSID)
1852 + pscancfg->tlvbufferlen + S_DS_GEN);
1853
1854 lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
1855 cmd->command, cmd->size, cmd->seqnum);
1856 LEAVE();
1857 return 0;
1858}
1859
1860/**
1861 * @brief This function handles the command response of scan
1862 *
1863 * The response buffer for the scan command has the following
1864 * memory layout:
1865 *
1866 * .-----------------------------------------------------------.
1867 * | header (4 * sizeof(u16)): Standard command response hdr |
1868 * .-----------------------------------------------------------.
1869 * | bufsize (u16) : sizeof the BSS Description data |
1870 * .-----------------------------------------------------------.
1871 * | NumOfSet (u8) : Number of BSS Descs returned |
1872 * .-----------------------------------------------------------.
1873 * | BSSDescription data (variable, size given in bufsize) |
1874 * .-----------------------------------------------------------.
1875 * | TLV data (variable, size calculated using header->size, |
1876 * | bufsize and sizeof the fixed fields above) |
1877 * .-----------------------------------------------------------.
1878 *
1879 * @param priv A pointer to wlan_private structure
1880 * @param resp A pointer to cmd_ds_command
1881 *
1882 * @return 0 or -1
1883 */
1884int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
1885{
1886 wlan_adapter *adapter = priv->adapter;
1887 struct cmd_ds_802_11_scan_rsp *pscan;
1888 struct bss_descriptor newbssentry;
1889 struct mrvlietypes_data *ptlv;
1890 struct mrvlietypes_tsftimestamp *ptsftlv;
1891 u8 *pbssinfo;
1892 u16 scanrespsize;
1893 int bytesleft;
1894 int numintable;
1895 int bssIdx;
1896 int idx;
1897 int tlvbufsize;
1898 u64 tsfval;
1899
1900 ENTER();
1901
1902 pscan = &resp->params.scanresp;
1903
1904 if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
1905 lbs_pr_debug(1,
1906 "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
1907 pscan->nr_sets);
1908 LEAVE();
1909 return -1;
1910 }
1911
1912 bytesleft = le16_to_cpu(pscan->bssdescriptsize);
1913 lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
1914
1915 scanrespsize = le16_to_cpu(resp->size);
1916 lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
1917 pscan->nr_sets);
1918
1919 numintable = adapter->numinscantable;
1920 pbssinfo = pscan->bssdesc_and_tlvbuffer;
1921
1922 /* The size of the TLV buffer is equal to the entire command response
1923 * size (scanrespsize) minus the fixed fields (sizeof()'s), the
1924 * BSS Descriptions (bssdescriptsize as bytesLef) and the command
1925 * response header (S_DS_GEN)
1926 */
1927 tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
1928 + sizeof(pscan->nr_sets)
1929 + S_DS_GEN);
1930
1931 ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
1932
1933 /* Search the TLV buffer space in the scan response for any valid TLVs */
1934 wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
1935
1936 /*
1937 * Process each scan response returned (pscan->nr_sets). Save
1938 * the information in the newbssentry and then insert into the
1939 * driver scan table either as an update to an existing entry
1940 * or as an addition at the end of the table
1941 */
1942 for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
1943 /* Zero out the newbssentry we are about to store info in */
1944 memset(&newbssentry, 0x00, sizeof(newbssentry));
1945
1946 /* Process the data fields and IEs returned for this BSS */
1947 if ((InterpretBSSDescriptionWithIE(&newbssentry,
1948 &pbssinfo,
1949 &bytesleft) ==
1950 0)
1951 && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
1952
1953 lbs_pr_debug(1,
1954 "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
1955 newbssentry.macaddress[0],
1956 newbssentry.macaddress[1],
1957 newbssentry.macaddress[2],
1958 newbssentry.macaddress[3],
1959 newbssentry.macaddress[4],
1960 newbssentry.macaddress[5]);
1961
1962 /*
1963 * Search the scan table for the same bssid
1964 */
1965 for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
1966 if (memcmp(newbssentry.macaddress,
1967 adapter->scantable[bssIdx].
1968 macaddress,
1969 sizeof(newbssentry.macaddress)) ==
1970 0) {
1971 /*
1972 * If the SSID matches as well, it is a duplicate of
1973 * this entry. Keep the bssIdx set to this
1974 * entry so we replace the old contents in the table
1975 */
1976 if ((newbssentry.ssid.ssidlength ==
1977 adapter->scantable[bssIdx].ssid.
1978 ssidlength)
1979 &&
1980 (memcmp
1981 (newbssentry.ssid.ssid,
1982 adapter->scantable[bssIdx].ssid.
1983 ssid,
1984 newbssentry.ssid.ssidlength) ==
1985 0)) {
1986 lbs_pr_debug(1,
1987 "SCAN_RESP: Duplicate of index: %d\n",
1988 bssIdx);
1989 break;
1990 }
1991 }
1992 }
1993 /*
1994 * If the bssIdx is equal to the number of entries in the table,
1995 * the new entry was not a duplicate; append it to the scan
1996 * table
1997 */
1998 if (bssIdx == numintable) {
1999 /* Range check the bssIdx, keep it limited to the last entry */
2000 if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
2001 bssIdx--;
2002 } else {
2003 numintable++;
2004 }
2005 }
2006
2007 /*
2008 * If the TSF TLV was appended to the scan results, save the
2009 * this entries TSF value in the networktsf field. The
2010 * networktsf is the firmware's TSF value at the time the
2011 * beacon or probe response was received.
2012 */
2013 if (ptsftlv) {
2014 memcpy(&tsfval, &ptsftlv->tsftable[idx],
2015 sizeof(tsfval));
2016 tsfval = le64_to_cpu(tsfval);
2017
2018 memcpy(&newbssentry.networktsf,
2019 &tsfval, sizeof(newbssentry.networktsf));
2020 }
2021
2022 /* Copy the locally created newbssentry to the scan table */
2023 memcpy(&adapter->scantable[bssIdx],
2024 &newbssentry,
2025 sizeof(adapter->scantable[bssIdx]));
2026
2027 } else {
2028
2029 /* error parsing/interpreting the scan response, skipped */
2030 lbs_pr_debug(1, "SCAN_RESP: "
2031 "InterpretBSSDescriptionWithIE returned ERROR\n");
2032 }
2033 }
2034
2035 lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
2036 pscan->nr_sets, numintable - adapter->numinscantable,
2037 numintable);
2038
2039 /* Update the total number of BSSIDs in the scan table */
2040 adapter->numinscantable = numintable;
2041
2042 LEAVE();
2043 return 0;
2044}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644
index 000000000000..d93aa7fa44fd
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.h
@@ -0,0 +1,216 @@
1/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
2/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
3
4/**
5 * Interface for the wlan network scan routines
6 *
7 * Driver interface functions and type declarations for the scan module
8 * implemented in wlan_scan.c.
9 */
10#ifndef _WLAN_SCAN_H
11#define _WLAN_SCAN_H
12
13#include "hostcmd.h"
14
15/**
16 * @brief Maximum number of channels that can be sent in a setuserscan ioctl
17 *
18 * @sa wlan_ioctl_user_scan_cfg
19 */
20#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
21
22//! Infrastructure BSS scan type in wlan_scan_cmd_config
23#define WLAN_SCAN_BSS_TYPE_BSS 1
24
25//! Adhoc BSS scan type in wlan_scan_cmd_config
26#define WLAN_SCAN_BSS_TYPE_IBSS 2
27
28//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
29#define WLAN_SCAN_BSS_TYPE_ANY 3
30
31/**
32 * @brief Structure used internally in the wlan driver to configure a scan.
33 *
34 * Sent to the command processing module to configure the firmware
35 * scan command prepared by libertas_cmd_80211_scan.
36 *
37 * @sa wlan_scan_networks
38 *
39 */
40struct wlan_scan_cmd_config {
41 /**
42 * @brief BSS type to be sent in the firmware command
43 *
44 * Field can be used to restrict the types of networks returned in the
45 * scan. valid settings are:
46 *
47 * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
48 * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
49 * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
50 */
51 u8 bsstype;
52
53 /**
54 * @brief Specific BSSID used to filter scan results in the firmware
55 */
56 u8 specificBSSID[ETH_ALEN];
57
58 /**
59 * @brief length of TLVs sent in command starting at tlvBuffer
60 */
61 int tlvbufferlen;
62
63 /**
64 * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
65 *
66 * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
67 * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
68 */
69 u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
70};
71
72/**
73 * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
74 *
75 * Multiple instances of this structure are included in the IOCTL command
76 * to configure a instance of a scan on the specific channel.
77 */
78struct wlan_ioctl_user_scan_chan {
79 u8 channumber; //!< channel Number to scan
80 u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
81 u8 scantype; //!< Scan type: Active = 0, Passive = 1
82 u16 scantime; //!< Scan duration in milliseconds; if 0 default used
83};
84
85/**
86 * @brief IOCTL input structure to configure an immediate scan cmd to firmware
87 *
88 * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies
89 * a number of parameters to be used in general for the scan as well
90 * as a channel list (wlan_ioctl_user_scan_chan) for each scan period
91 * desired.
92 *
93 * @sa libertas_set_user_scan_ioctl
94 */
95struct wlan_ioctl_user_scan_cfg {
96
97 /**
98 * @brief Flag set to keep the previous scan table intact
99 *
100 * If set, the scan results will accumulate, replacing any previous
101 * matched entries for a BSS with the new scan data
102 */
103 u8 keeppreviousscan; //!< Do not erase the existing scan results
104
105 /**
106 * @brief BSS type to be sent in the firmware command
107 *
108 * Field can be used to restrict the types of networks returned in the
109 * scan. valid settings are:
110 *
111 * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
112 * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
113 * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
114 */
115 u8 bsstype;
116
117 /**
118 * @brief Configure the number of probe requests for active chan scans
119 */
120 u8 numprobes;
121
122 /**
123 * @brief BSSID filter sent in the firmware command to limit the results
124 */
125 u8 specificBSSID[ETH_ALEN];
126
127 /**
128 * @brief SSID filter sent in the firmware command to limit the results
129 */
130 char specificSSID[IW_ESSID_MAX_SIZE + 1];
131
132 /**
133 * @brief Variable number (fixed maximum) of channels to scan up
134 */
135 struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
136};
137
138/**
139 * @brief Structure used to store information for each beacon/probe response
140 */
141struct bss_descriptor {
142 u8 macaddress[ETH_ALEN];
143
144 struct WLAN_802_11_SSID ssid;
145
146 /* WEP encryption requirement */
147 u32 privacy;
148
149 /* receive signal strength in dBm */
150 long rssi;
151
152 u32 channel;
153
154 u16 beaconperiod;
155
156 u32 atimwindow;
157
158 enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
159 u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
160
161 int extra_ie;
162
163 u8 timestamp[8]; //!< TSF value included in the beacon/probe response
164 union ieeetypes_phyparamset phyparamset;
165 union IEEEtypes_ssparamset ssparamset;
166 struct ieeetypes_capinfo cap;
167 u8 datarates[WLAN_SUPPORTED_RATES];
168
169 __le64 networktsf; //!< TSF timestamp from the current firmware TSF
170
171 struct ieeetypes_countryinfofullset countryinfo;
172
173 struct WPA_SUPPLICANT wpa_supplicant;
174 struct WPA_SUPPLICANT wpa2_supplicant;
175
176};
177
178extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
179 struct WLAN_802_11_SSID *ssid2);
180extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
181 u8 * bssid, int mode);
182int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
183extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
184
185int libertas_find_best_network_SSID(wlan_private * priv,
186 struct WLAN_802_11_SSID *pSSID,
187 enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
188 enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
189
190extern int libertas_send_specific_SSID_scan(wlan_private * priv,
191 struct WLAN_802_11_SSID *prequestedssid,
192 u8 keeppreviousscan);
193extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
194 u8 * bssid, u8 keeppreviousscan);
195
196extern int libertas_cmd_80211_scan(wlan_private * priv,
197 struct cmd_ds_command *cmd,
198 void *pdata_buf);
199
200extern int libertas_ret_80211_scan(wlan_private * priv,
201 struct cmd_ds_command *resp);
202
203int wlan_scan_networks(wlan_private * priv,
204 const struct wlan_ioctl_user_scan_cfg * puserscanin);
205
206struct ifreq;
207
208struct iw_point;
209struct iw_param;
210struct iw_request_info;
211extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
212 struct iw_point *dwrq, char *extra);
213extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
214 struct iw_param *vwrq, char *extra);
215
216#endif /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644
index 000000000000..207b8a6cc33d
--- /dev/null
+++ b/drivers/net/wireless/libertas/thread.h
@@ -0,0 +1,52 @@
1#ifndef __WLAN_THREAD_H_
2#define __WLAN_THREAD_H_
3
4#include <linux/kthread.h>
5
6struct wlan_thread {
7 struct task_struct *task;
8 wait_queue_head_t waitq;
9 pid_t pid;
10 void *priv;
11};
12
13static inline void wlan_activate_thread(struct wlan_thread * thr)
14{
15 /** Record the thread pid */
16 thr->pid = current->pid;
17
18 /** Initialize the wait queue */
19 init_waitqueue_head(&thr->waitq);
20}
21
22static inline void wlan_deactivate_thread(struct wlan_thread * thr)
23{
24 ENTER();
25
26 thr->pid = 0;
27
28 LEAVE();
29}
30
31static inline void wlan_create_thread(int (*wlanfunc) (void *),
32 struct wlan_thread * thr, char *name)
33{
34 thr->task = kthread_run(wlanfunc, thr, "%s", name);
35}
36
37static inline int wlan_terminate_thread(struct wlan_thread * thr)
38{
39 ENTER();
40
41 /* Check if the thread is active or not */
42 if (!thr->pid) {
43 printk(KERN_ERR "Thread does not exist\n");
44 return -1;
45 }
46 kthread_stop(thr->task);
47
48 LEAVE();
49 return 0;
50}
51
52#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644
index 000000000000..82d06223043e
--- /dev/null
+++ b/drivers/net/wireless/libertas/tx.c
@@ -0,0 +1,285 @@
1/**
2 * This file contains the handling of TX in wlan driver.
3 */
4#include <linux/netdevice.h>
5
6#include "hostcmd.h"
7#include "radiotap.h"
8#include "sbi.h"
9#include "decl.h"
10#include "defs.h"
11#include "dev.h"
12#include "wext.h"
13
14/**
15 * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
16 * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
17 *
18 * @param rate Input rate
19 * @return Output Rate (0 if invalid)
20 */
21static u32 convert_radiotap_rate_to_mv(u8 rate)
22{
23 switch (rate) {
24 case 2: /* 1 Mbps */
25 return 0 | (1 << 4);
26 case 4: /* 2 Mbps */
27 return 1 | (1 << 4);
28 case 11: /* 5.5 Mbps */
29 return 2 | (1 << 4);
30 case 22: /* 11 Mbps */
31 return 3 | (1 << 4);
32 case 12: /* 6 Mbps */
33 return 4 | (1 << 4);
34 case 18: /* 9 Mbps */
35 return 5 | (1 << 4);
36 case 24: /* 12 Mbps */
37 return 6 | (1 << 4);
38 case 36: /* 18 Mbps */
39 return 7 | (1 << 4);
40 case 48: /* 24 Mbps */
41 return 8 | (1 << 4);
42 case 72: /* 36 Mbps */
43 return 9 | (1 << 4);
44 case 96: /* 48 Mbps */
45 return 10 | (1 << 4);
46 case 108: /* 54 Mbps */
47 return 11 | (1 << 4);
48 }
49 return 0;
50}
51
52/**
53 * @brief This function processes a single packet and sends
54 * to IF layer
55 *
56 * @param priv A pointer to wlan_private structure
57 * @param skb A pointer to skb which includes TX packet
58 * @return 0 or -1
59 */
60static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
61{
62 wlan_adapter *adapter = priv->adapter;
63 int ret = 0;
64 struct txpd localtxpd;
65 struct txpd *plocaltxpd = &localtxpd;
66 u8 *p802x_hdr;
67 struct tx_radiotap_hdr *pradiotap_hdr;
68 u32 new_rate;
69 u8 *ptr = priv->adapter->tmptxbuf;
70
71 ENTER();
72
73 if (priv->adapter->surpriseremoved)
74 return -1;
75
76 if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
77 lbs_dbg_hex("TX packet: ", skb->data,
78 min_t(unsigned int, skb->len, 100));
79
80 if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
81 lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
82 skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
83 ret = -1;
84 goto done;
85 }
86
87 memset(plocaltxpd, 0, sizeof(struct txpd));
88
89 plocaltxpd->tx_packet_length = skb->len;
90
91 /* offset of actual data */
92 plocaltxpd->tx_packet_location = sizeof(struct txpd);
93
94 /* TxCtrl set by user or default */
95 plocaltxpd->tx_control = adapter->pkttxctrl;
96
97 p802x_hdr = skb->data;
98 if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
99
100 /* locate radiotap header */
101 pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
102
103 /* set txpd fields from the radiotap header */
104 new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
105 if (new_rate != 0) {
106 /* erase tx_control[4:0] */
107 plocaltxpd->tx_control &= ~0x1f;
108 /* write new tx_control[4:0] */
109 plocaltxpd->tx_control |= new_rate;
110 }
111
112 /* skip the radiotap header */
113 p802x_hdr += sizeof(struct tx_radiotap_hdr);
114 plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
115
116 }
117 /* copy destination address from 802.3 or 802.11 header */
118 if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
119 memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
120 else
121 memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
122
123 lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
124
125 if (IS_MESH_FRAME(skb)) {
126 plocaltxpd->tx_control |= TxPD_MESH_FRAME;
127 }
128
129 memcpy(ptr, plocaltxpd, sizeof(struct txpd));
130
131 ptr += sizeof(struct txpd);
132
133 lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
134 memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
135 ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
136 priv->adapter->tmptxbuf,
137 plocaltxpd->tx_packet_length +
138 sizeof(struct txpd));
139
140 if (ret) {
141 lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
142 goto done;
143 }
144
145 lbs_pr_debug(1, "SendSinglePacket succeeds\n");
146
147 done:
148 if (!ret) {
149 priv->stats.tx_packets++;
150 priv->stats.tx_bytes += skb->len;
151 } else {
152 priv->stats.tx_dropped++;
153 priv->stats.tx_errors++;
154 }
155
156 if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
157 /* Keep the skb to echo it back once Tx feedback is
158 received from FW */
159 skb_orphan(skb);
160 /* stop processing outgoing pkts */
161 netif_stop_queue(priv->wlan_dev.netdev);
162 /* freeze any packets already in our queues */
163 priv->adapter->TxLockFlag = 1;
164 } else {
165 dev_kfree_skb_any(skb);
166 priv->adapter->currenttxskb = NULL;
167 }
168
169 LEAVE();
170 return ret;
171}
172
173
174void libertas_tx_runqueue(wlan_private *priv)
175{
176 wlan_adapter *adapter = priv->adapter;
177 int i;
178
179 spin_lock(&adapter->txqueue_lock);
180 for (i = 0; i < adapter->tx_queue_idx; i++) {
181 struct sk_buff *skb = adapter->tx_queue_ps[i];
182 spin_unlock(&adapter->txqueue_lock);
183 SendSinglePacket(priv, skb);
184 spin_lock(&adapter->txqueue_lock);
185 }
186 adapter->tx_queue_idx = 0;
187 spin_unlock(&adapter->txqueue_lock);
188}
189
190static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
191{
192 wlan_adapter *adapter = priv->adapter;
193
194 spin_lock(&adapter->txqueue_lock);
195
196 WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
197 adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
198 if (adapter->tx_queue_idx == NR_TX_QUEUE)
199 netif_stop_queue(priv->wlan_dev.netdev);
200 else
201 netif_start_queue(priv->wlan_dev.netdev);
202
203 spin_unlock(&adapter->txqueue_lock);
204}
205
206/**
207 * @brief This function checks the conditions and sends packet to IF
208 * layer if everything is ok.
209 *
210 * @param priv A pointer to wlan_private structure
211 * @return n/a
212 */
213int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
214{
215 int ret = -1;
216
217 ENTER();
218
219 lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
220
221 if (priv->wlan_dev.dnld_sent) {
222 lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
223 priv->wlan_dev.dnld_sent);
224 goto done;
225 }
226
227 if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
228 (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
229 wlan_tx_queue(priv, skb);
230 return ret;
231 }
232
233 priv->adapter->currenttxskb = skb;
234
235 ret = SendSinglePacket(priv, skb);
236done:
237 LEAVE();
238 return ret;
239}
240
241/**
242 * @brief This function sends to the host the last transmitted packet,
243 * filling the radiotap headers with transmission information.
244 *
245 * @param priv A pointer to wlan_private structure
246 * @param status A 32 bit value containing transmission status.
247 *
248 * @returns void
249 */
250void libertas_send_tx_feedback(wlan_private * priv)
251{
252 wlan_adapter *adapter = priv->adapter;
253 struct tx_radiotap_hdr *radiotap_hdr;
254 u32 status = adapter->eventcause;
255 int txfail;
256 int try_count;
257
258 if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
259 adapter->currenttxskb == NULL)
260 return;
261
262 radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
263
264 if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
265 lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
266 min_t(unsigned int, adapter->currenttxskb->len, 100));
267
268 txfail = (status >> 24);
269
270#if 0
271 /* The version of roofnet that we've tested does not use this yet
272 * But it may be used in the future.
273 */
274 if (txfail)
275 radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
276#endif
277 try_count = (status >> 16) & 0xff;
278 radiotap_hdr->data_retries = (try_count) ?
279 (1 + adapter->txretrycount - try_count) : 0;
280 libertas_upload_rx_packet(priv, adapter->currenttxskb);
281 adapter->currenttxskb = NULL;
282 priv->adapter->TxLockFlag = 0;
283 if (priv->adapter->connect_status == libertas_connected)
284 netif_wake_queue(priv->wlan_dev.netdev);
285}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644
index 000000000000..09d62f8b1a16
--- /dev/null
+++ b/drivers/net/wireless/libertas/types.h
@@ -0,0 +1,289 @@
1/**
2 * This header file contains definition for global types
3 */
4#ifndef _WLAN_TYPES_
5#define _WLAN_TYPES_
6
7#include <linux/if_ether.h>
8
9/** IEEE type definitions */
10enum ieeetypes_elementid {
11 SSID = 0,
12 SUPPORTED_RATES,
13 FH_PARAM_SET,
14 DS_PARAM_SET,
15 CF_PARAM_SET,
16 TIM,
17 IBSS_PARAM_SET,
18 COUNTRY_INFO = 7,
19
20 CHALLENGE_TEXT = 16,
21
22 EXTENDED_SUPPORTED_RATES = 50,
23
24 VENDOR_SPECIFIC_221 = 221,
25
26 WPA_IE = 221,
27 WPA2_IE = 48,
28
29 EXTRA_IE = 133,
30} __attribute__ ((packed));
31
32#define CAPINFO_MASK (~(0xda00))
33
34struct ieeetypes_capinfo {
35 u8 ess:1;
36 u8 ibss:1;
37 u8 cfpollable:1;
38 u8 cfpollrqst:1;
39 u8 privacy:1;
40 u8 shortpreamble:1;
41 u8 pbcc:1;
42 u8 chanagility:1;
43 u8 spectrummgmt:1;
44 u8 rsrvd3:1;
45 u8 shortslottime:1;
46 u8 apsd:1;
47 u8 rsvrd2:1;
48 u8 dsssofdm:1;
49 u8 rsrvd1:2;
50} __attribute__ ((packed));
51
52struct ieeetypes_cfparamset {
53 u8 elementid;
54 u8 len;
55 u8 cfpcnt;
56 u8 cfpperiod;
57 u16 cfpmaxduration;
58 u16 cfpdurationremaining;
59} __attribute__ ((packed));
60
61
62struct ieeetypes_ibssparamset {
63 u8 elementid;
64 u8 len;
65 u16 atimwindow;
66} __attribute__ ((packed));
67
68union IEEEtypes_ssparamset {
69 struct ieeetypes_cfparamset cfparamset;
70 struct ieeetypes_ibssparamset ibssparamset;
71} __attribute__ ((packed));
72
73struct ieeetypes_fhparamset {
74 u8 elementid;
75 u8 len;
76 u16 dwelltime;
77 u8 hopset;
78 u8 hoppattern;
79 u8 hopindex;
80} __attribute__ ((packed));
81
82struct ieeetypes_dsparamset {
83 u8 elementid;
84 u8 len;
85 u8 currentchan;
86} __attribute__ ((packed));
87
88union ieeetypes_phyparamset {
89 struct ieeetypes_fhparamset fhparamset;
90 struct ieeetypes_dsparamset dsparamset;
91} __attribute__ ((packed));
92
93struct ieeetypes_assocrsp {
94 struct ieeetypes_capinfo capability;
95 u16 statuscode;
96 u16 aid;
97 u8 iebuffer[1];
98} __attribute__ ((packed));
99
100/** TLV type ID definition */
101#define PROPRIETARY_TLV_BASE_ID 0x0100
102
103/* Terminating TLV type */
104#define MRVL_TERMINATE_TLV_ID 0xffff
105
106#define TLV_TYPE_SSID 0x0000
107#define TLV_TYPE_RATES 0x0001
108#define TLV_TYPE_PHY_FH 0x0002
109#define TLV_TYPE_PHY_DS 0x0003
110#define TLV_TYPE_CF 0x0004
111#define TLV_TYPE_IBSS 0x0006
112
113#define TLV_TYPE_DOMAIN 0x0007
114
115#define TLV_TYPE_POWER_CAPABILITY 0x0021
116
117#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
118#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
119#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
120#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
121#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
122#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
123#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
124#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
125#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
126#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
127#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11)
128#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
129#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
130#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14)
131#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15)
132#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
133#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17)
134#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
135#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
136#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
137#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
138
139/** TLV related data structures*/
140struct mrvlietypesheader {
141 u16 type;
142 u16 len;
143} __attribute__ ((packed));
144
145struct mrvlietypes_data {
146 struct mrvlietypesheader header;
147 u8 Data[1];
148} __attribute__ ((packed));
149
150struct mrvlietypes_ratesparamset {
151 struct mrvlietypesheader header;
152 u8 rates[1];
153} __attribute__ ((packed));
154
155struct mrvlietypes_ssidparamset {
156 struct mrvlietypesheader header;
157 u8 ssid[1];
158} __attribute__ ((packed));
159
160struct mrvlietypes_wildcardssidparamset {
161 struct mrvlietypesheader header;
162 u8 MaxSsidlength;
163 u8 ssid[1];
164} __attribute__ ((packed));
165
166struct chanscanmode {
167 u8 passivescan:1;
168 u8 disablechanfilt:1;
169 u8 reserved_2_7:6;
170} __attribute__ ((packed));
171
172struct chanscanparamset {
173 u8 radiotype;
174 u8 channumber;
175 struct chanscanmode chanscanmode;
176 u16 minscantime;
177 u16 maxscantime;
178} __attribute__ ((packed));
179
180struct mrvlietypes_chanlistparamset {
181 struct mrvlietypesheader header;
182 struct chanscanparamset chanscanparam[1];
183} __attribute__ ((packed));
184
185struct cfparamset {
186 u8 cfpcnt;
187 u8 cfpperiod;
188 u16 cfpmaxduration;
189 u16 cfpdurationremaining;
190} __attribute__ ((packed));
191
192struct ibssparamset {
193 u16 atimwindow;
194} __attribute__ ((packed));
195
196struct mrvlietypes_ssparamset {
197 struct mrvlietypesheader header;
198 union {
199 struct cfparamset cfparamset[1];
200 struct ibssparamset ibssparamset[1];
201 } cf_ibss;
202} __attribute__ ((packed));
203
204struct fhparamset {
205 u16 dwelltime;
206 u8 hopset;
207 u8 hoppattern;
208 u8 hopindex;
209} __attribute__ ((packed));
210
211struct dsparamset {
212 u8 currentchan;
213} __attribute__ ((packed));
214
215struct mrvlietypes_phyparamset {
216 struct mrvlietypesheader header;
217 union {
218 struct fhparamset fhparamset[1];
219 struct dsparamset dsparamset[1];
220 } fh_ds;
221} __attribute__ ((packed));
222
223struct mrvlietypes_rsnparamset {
224 struct mrvlietypesheader header;
225 u8 rsnie[1];
226} __attribute__ ((packed));
227
228struct mrvlietypes_tsftimestamp {
229 struct mrvlietypesheader header;
230 __le64 tsftable[1];
231} __attribute__ ((packed));
232
233/** Local Power capability */
234struct mrvlietypes_powercapability {
235 struct mrvlietypesheader header;
236 s8 minpower;
237 s8 maxpower;
238} __attribute__ ((packed));
239
240struct mrvlietypes_rssithreshold {
241 struct mrvlietypesheader header;
242 u8 rssivalue;
243 u8 rssifreq;
244} __attribute__ ((packed));
245
246struct mrvlietypes_snrthreshold {
247 struct mrvlietypesheader header;
248 u8 snrvalue;
249 u8 snrfreq;
250} __attribute__ ((packed));
251
252struct mrvlietypes_failurecount {
253 struct mrvlietypesheader header;
254 u8 failvalue;
255 u8 Failfreq;
256} __attribute__ ((packed));
257
258struct mrvlietypes_beaconsmissed {
259 struct mrvlietypesheader header;
260 u8 beaconmissed;
261 u8 reserved;
262} __attribute__ ((packed));
263
264struct mrvlietypes_numprobes {
265 struct mrvlietypesheader header;
266 u16 numprobes;
267} __attribute__ ((packed));
268
269struct mrvlietypes_bcastprobe {
270 struct mrvlietypesheader header;
271 u16 bcastprobe;
272} __attribute__ ((packed));
273
274struct mrvlietypes_numssidprobe {
275 struct mrvlietypesheader header;
276 u16 numssidprobe;
277} __attribute__ ((packed));
278
279struct led_pin {
280 u8 led;
281 u8 pin;
282} __attribute__ ((packed));
283
284struct mrvlietypes_ledgpio {
285 struct mrvlietypesheader header;
286 struct led_pin ledpin[1];
287} __attribute__ ((packed));
288
289#endif /* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644
index 000000000000..e86f65ae79b8
--- /dev/null
+++ b/drivers/net/wireless/libertas/version.h
@@ -0,0 +1,8 @@
1#define DRIVER_RELEASE_VERSION "320.p0"
2const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
3#ifdef DEBUG
4 "-dbg"
5#endif
6 "";
7
8
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644
index 000000000000..4a52336bc0f6
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.c
@@ -0,0 +1,2769 @@
1/**
2 * This file contains ioctl functions
3 */
4#include <linux/ctype.h>
5#include <linux/delay.h>
6#include <linux/if.h>
7#include <linux/if_arp.h>
8#include <linux/wireless.h>
9#include <linux/bitops.h>
10
11#include <net/ieee80211.h>
12#include <net/iw_handler.h>
13
14#include "host.h"
15#include "radiotap.h"
16#include "decl.h"
17#include "defs.h"
18#include "dev.h"
19#include "join.h"
20#include "version.h"
21#include "wext.h"
22#include "assoc.h"
23
24
25/**
26 * @brief Convert mw value to dbm value
27 *
28 * @param mw the value of mw
29 * @return the value of dbm
30 */
31static int mw_to_dbm(int mw)
32{
33 if (mw < 2)
34 return 0;
35 else if (mw < 3)
36 return 3;
37 else if (mw < 4)
38 return 5;
39 else if (mw < 6)
40 return 7;
41 else if (mw < 7)
42 return 8;
43 else if (mw < 8)
44 return 9;
45 else if (mw < 10)
46 return 10;
47 else if (mw < 13)
48 return 11;
49 else if (mw < 16)
50 return 12;
51 else if (mw < 20)
52 return 13;
53 else if (mw < 25)
54 return 14;
55 else if (mw < 32)
56 return 15;
57 else if (mw < 40)
58 return 16;
59 else if (mw < 50)
60 return 17;
61 else if (mw < 63)
62 return 18;
63 else if (mw < 79)
64 return 19;
65 else if (mw < 100)
66 return 20;
67 else
68 return 21;
69}
70
71/**
72 * @brief Find the channel frequency power info with specific channel
73 *
74 * @param adapter A pointer to wlan_adapter structure
75 * @param band it can be BAND_A, BAND_G or BAND_B
76 * @param channel the channel for looking
77 * @return A pointer to struct chan_freq_power structure or NULL if not find.
78 */
79struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
80 u8 band, u16 channel)
81{
82 struct chan_freq_power *cfp = NULL;
83 struct region_channel *rc;
84 int count = sizeof(adapter->region_channel) /
85 sizeof(adapter->region_channel[0]);
86 int i, j;
87
88 for (j = 0; !cfp && (j < count); j++) {
89 rc = &adapter->region_channel[j];
90
91 if (adapter->enable11d)
92 rc = &adapter->universal_channel[j];
93 if (!rc->valid || !rc->CFP)
94 continue;
95 if (rc->band != band)
96 continue;
97 for (i = 0; i < rc->nrcfp; i++) {
98 if (rc->CFP[i].channel == channel) {
99 cfp = &rc->CFP[i];
100 break;
101 }
102 }
103 }
104
105 if (!cfp && channel)
106 lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
107 "cfp by band %d & channel %d\n", band, channel);
108
109 return cfp;
110}
111
112/**
113 * @brief Find the channel frequency power info with specific frequency
114 *
115 * @param adapter A pointer to wlan_adapter structure
116 * @param band it can be BAND_A, BAND_G or BAND_B
117 * @param freq the frequency for looking
118 * @return A pointer to struct chan_freq_power structure or NULL if not find.
119 */
120static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
121 u8 band, u32 freq)
122{
123 struct chan_freq_power *cfp = NULL;
124 struct region_channel *rc;
125 int count = sizeof(adapter->region_channel) /
126 sizeof(adapter->region_channel[0]);
127 int i, j;
128
129 for (j = 0; !cfp && (j < count); j++) {
130 rc = &adapter->region_channel[j];
131
132 if (adapter->enable11d)
133 rc = &adapter->universal_channel[j];
134 if (!rc->valid || !rc->CFP)
135 continue;
136 if (rc->band != band)
137 continue;
138 for (i = 0; i < rc->nrcfp; i++) {
139 if (rc->CFP[i].freq == freq) {
140 cfp = &rc->CFP[i];
141 break;
142 }
143 }
144 }
145
146 if (!cfp && freq)
147 lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
148 "band %d & freq %d\n", band, freq);
149
150 return cfp;
151}
152
153static int updatecurrentchannel(wlan_private * priv)
154{
155 int ret;
156
157 /*
158 ** the channel in f/w could be out of sync, get the current channel
159 */
160 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
161 cmd_opt_802_11_rf_channel_get,
162 cmd_option_waitforrsp, 0, NULL);
163
164 lbs_pr_debug(1, "Current channel = %d\n",
165 priv->adapter->curbssparams.channel);
166
167 return ret;
168}
169
170static int setcurrentchannel(wlan_private * priv, int channel)
171{
172 lbs_pr_debug(1, "Set channel = %d\n", channel);
173
174 /*
175 ** Current channel is not set to adhocchannel requested, set channel
176 */
177 return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
178 cmd_opt_802_11_rf_channel_set,
179 cmd_option_waitforrsp, 0, &channel));
180}
181
182static int changeadhocchannel(wlan_private * priv, int channel)
183{
184 int ret = 0;
185 wlan_adapter *adapter = priv->adapter;
186
187 adapter->adhocchannel = channel;
188
189 updatecurrentchannel(priv);
190
191 if (adapter->curbssparams.channel == adapter->adhocchannel) {
192 /* adhocchannel is set to the current channel already */
193 LEAVE();
194 return 0;
195 }
196
197 lbs_pr_debug(1, "Updating channel from %d to %d\n",
198 adapter->curbssparams.channel, adapter->adhocchannel);
199
200 setcurrentchannel(priv, adapter->adhocchannel);
201
202 updatecurrentchannel(priv);
203
204 if (adapter->curbssparams.channel != adapter->adhocchannel) {
205 lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
206 adapter->adhocchannel, adapter->curbssparams.channel);
207 LEAVE();
208 return -1;
209 }
210
211 if (adapter->connect_status == libertas_connected) {
212 int i;
213 struct WLAN_802_11_SSID curadhocssid;
214
215 lbs_pr_debug(1, "channel Changed while in an IBSS\n");
216
217 /* Copy the current ssid */
218 memcpy(&curadhocssid, &adapter->curbssparams.ssid,
219 sizeof(struct WLAN_802_11_SSID));
220
221 /* Exit Adhoc mode */
222 lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
223 ret = libertas_stop_adhoc_network(priv);
224
225 if (ret) {
226 LEAVE();
227 return ret;
228 }
229 /* Scan for the network, do not save previous results. Stale
230 * scan data will cause us to join a non-existant adhoc network
231 */
232 libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
233
234 // find out the BSSID that matches the current SSID
235 i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
236 wlan802_11ibss);
237
238 if (i >= 0) {
239 lbs_pr_debug(1, "SSID found at %d in List,"
240 "so join\n", i);
241 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
242 } else {
243 // else send START command
244 lbs_pr_debug(1, "SSID not found in list, "
245 "so creating adhoc with ssid = %s\n",
246 curadhocssid.ssid);
247 libertas_start_adhoc_network(priv, &curadhocssid);
248 } // end of else (START command)
249 }
250
251 LEAVE();
252 return 0;
253}
254
255/**
256 * @brief Set Radio On/OFF
257 *
258 * @param priv A pointer to wlan_private structure
259 * @option Radio Option
260 * @return 0 --success, otherwise fail
261 */
262int wlan_radio_ioctl(wlan_private * priv, u8 option)
263{
264 int ret = 0;
265 wlan_adapter *adapter = priv->adapter;
266
267 ENTER();
268
269 if (adapter->radioon != option) {
270 lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
271 adapter->radioon = option;
272
273 ret = libertas_prepare_and_send_command(priv,
274 cmd_802_11_radio_control,
275 cmd_act_set,
276 cmd_option_waitforrsp, 0, NULL);
277 }
278
279 LEAVE();
280 return ret;
281}
282
283/**
284 * @brief Copy rates
285 *
286 * @param dest A pointer to Dest Buf
287 * @param src A pointer to Src Buf
288 * @param len The len of Src Buf
289 * @return Number of rates copyed
290 */
291static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
292{
293 int i;
294
295 for (i = 0; i < len && src[i]; i++, pos++) {
296 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
297 break;
298 dest[pos] = src[i];
299 }
300
301 return pos;
302}
303
304/**
305 * @brief Get active data rates
306 *
307 * @param adapter A pointer to wlan_adapter structure
308 * @param rate The buf to return the active rates
309 * @return The number of rates
310 */
311static int get_active_data_rates(wlan_adapter * adapter,
312 u8* rates)
313{
314 int k = 0;
315
316 ENTER();
317
318 if (adapter->connect_status != libertas_connected) {
319 if (adapter->inframode == wlan802_11infrastructure) {
320 //Infra. mode
321 lbs_pr_debug(1, "Infra\n");
322 k = copyrates(rates, k, libertas_supported_rates,
323 sizeof(libertas_supported_rates));
324 } else {
325 //ad-hoc mode
326 lbs_pr_debug(1, "Adhoc G\n");
327 k = copyrates(rates, k, libertas_adhoc_rates_g,
328 sizeof(libertas_adhoc_rates_g));
329 }
330 } else {
331 k = copyrates(rates, 0, adapter->curbssparams.datarates,
332 adapter->curbssparams.numofrates);
333 }
334
335 LEAVE();
336
337 return k;
338}
339
340static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
341 char *cwrq, char *extra)
342{
343 const char *cp;
344 char comm[6] = { "COMM-" };
345 char mrvl[6] = { "MRVL-" };
346 int cnt;
347
348 ENTER();
349
350 strcpy(cwrq, mrvl);
351
352 cp = strstr(libertas_driver_version, comm);
353 if (cp == libertas_driver_version) //skip leading "COMM-"
354 cp = libertas_driver_version + strlen(comm);
355 else
356 cp = libertas_driver_version;
357
358 cnt = strlen(mrvl);
359 cwrq += cnt;
360 while (cnt < 16 && (*cp != '-')) {
361 *cwrq++ = toupper(*cp++);
362 cnt++;
363 }
364 *cwrq = '\0';
365
366 LEAVE();
367
368 return 0;
369}
370
371static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
372 struct iw_freq *fwrq, char *extra)
373{
374 wlan_private *priv = dev->priv;
375 wlan_adapter *adapter = priv->adapter;
376 struct chan_freq_power *cfp;
377
378 ENTER();
379
380 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
381 adapter->curbssparams.channel);
382
383 if (!cfp) {
384 if (adapter->curbssparams.channel)
385 lbs_pr_debug(1, "Invalid channel=%d\n",
386 adapter->curbssparams.channel);
387 return -EINVAL;
388 }
389
390 fwrq->m = (long)cfp->freq * 100000;
391 fwrq->e = 1;
392
393 lbs_pr_debug(1, "freq=%u\n", fwrq->m);
394
395 LEAVE();
396 return 0;
397}
398
399static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
400 struct sockaddr *awrq, char *extra)
401{
402 wlan_private *priv = dev->priv;
403 wlan_adapter *adapter = priv->adapter;
404
405 ENTER();
406
407 if (adapter->connect_status == libertas_connected) {
408 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
409 } else {
410 memset(awrq->sa_data, 0, ETH_ALEN);
411 }
412 awrq->sa_family = ARPHRD_ETHER;
413
414 LEAVE();
415 return 0;
416}
417
418static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
419 struct iw_point *dwrq, char *extra)
420{
421 wlan_private *priv = dev->priv;
422 wlan_adapter *adapter = priv->adapter;
423
424 ENTER();
425
426 /*
427 * Check the size of the string
428 */
429
430 if (dwrq->length > 16) {
431 return -E2BIG;
432 }
433
434 mutex_lock(&adapter->lock);
435 memset(adapter->nodename, 0, sizeof(adapter->nodename));
436 memcpy(adapter->nodename, extra, dwrq->length);
437 mutex_unlock(&adapter->lock);
438
439 LEAVE();
440 return 0;
441}
442
443static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
444 struct iw_point *dwrq, char *extra)
445{
446 wlan_private *priv = dev->priv;
447 wlan_adapter *adapter = priv->adapter;
448
449 ENTER();
450
451 /*
452 * Get the Nick Name saved
453 */
454
455 mutex_lock(&adapter->lock);
456 strncpy(extra, adapter->nodename, 16);
457 mutex_unlock(&adapter->lock);
458
459 extra[16] = '\0';
460
461 /*
462 * If none, we may want to get the one that was set
463 */
464
465 /*
466 * Push it out !
467 */
468 dwrq->length = strlen(extra) + 1;
469
470 LEAVE();
471 return 0;
472}
473
474static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
475 struct iw_param *vwrq, char *extra)
476{
477 int ret = 0;
478 wlan_private *priv = dev->priv;
479 wlan_adapter *adapter = priv->adapter;
480 int rthr = vwrq->value;
481
482 ENTER();
483
484 if (vwrq->disabled) {
485 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
486 } else {
487 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
488 return -EINVAL;
489 adapter->rtsthsd = rthr;
490 }
491
492 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
493 cmd_act_set, cmd_option_waitforrsp,
494 OID_802_11_RTS_THRESHOLD, &rthr);
495
496 LEAVE();
497 return ret;
498}
499
500static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
501 struct iw_param *vwrq, char *extra)
502{
503 int ret = 0;
504 wlan_private *priv = dev->priv;
505 wlan_adapter *adapter = priv->adapter;
506
507 ENTER();
508
509 adapter->rtsthsd = 0;
510 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
511 cmd_act_get, cmd_option_waitforrsp,
512 OID_802_11_RTS_THRESHOLD, NULL);
513 if (ret) {
514 LEAVE();
515 return ret;
516 }
517
518 vwrq->value = adapter->rtsthsd;
519 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
520 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
521 vwrq->fixed = 1;
522
523 LEAVE();
524 return 0;
525}
526
527static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
528 struct iw_param *vwrq, char *extra)
529{
530 int ret = 0;
531 int fthr = vwrq->value;
532 wlan_private *priv = dev->priv;
533 wlan_adapter *adapter = priv->adapter;
534
535 ENTER();
536
537 if (vwrq->disabled) {
538 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
539 } else {
540 if (fthr < MRVDRV_FRAG_MIN_VALUE
541 || fthr > MRVDRV_FRAG_MAX_VALUE)
542 return -EINVAL;
543 adapter->fragthsd = fthr;
544 }
545
546 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
547 cmd_act_set, cmd_option_waitforrsp,
548 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
549 LEAVE();
550 return ret;
551}
552
553static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
554 struct iw_param *vwrq, char *extra)
555{
556 int ret = 0;
557 wlan_private *priv = dev->priv;
558 wlan_adapter *adapter = priv->adapter;
559
560 ENTER();
561
562 adapter->fragthsd = 0;
563 ret = libertas_prepare_and_send_command(priv,
564 cmd_802_11_snmp_mib,
565 cmd_act_get, cmd_option_waitforrsp,
566 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
567 if (ret) {
568 LEAVE();
569 return ret;
570 }
571
572 vwrq->value = adapter->fragthsd;
573 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
574 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
575 vwrq->fixed = 1;
576
577 LEAVE();
578 return ret;
579}
580
581static int wlan_get_mode(struct net_device *dev,
582 struct iw_request_info *info, u32 * uwrq, char *extra)
583{
584 wlan_private *priv = dev->priv;
585 wlan_adapter *adapter = priv->adapter;
586
587 ENTER();
588
589 switch (adapter->inframode) {
590 case wlan802_11ibss:
591 *uwrq = IW_MODE_ADHOC;
592 break;
593
594 case wlan802_11infrastructure:
595 *uwrq = IW_MODE_INFRA;
596 break;
597
598 default:
599 case wlan802_11autounknown:
600 *uwrq = IW_MODE_AUTO;
601 break;
602 }
603
604 LEAVE();
605 return 0;
606}
607
608static int wlan_get_txpow(struct net_device *dev,
609 struct iw_request_info *info,
610 struct iw_param *vwrq, char *extra)
611{
612 int ret = 0;
613 wlan_private *priv = dev->priv;
614 wlan_adapter *adapter = priv->adapter;
615
616 ENTER();
617
618 ret = libertas_prepare_and_send_command(priv,
619 cmd_802_11_rf_tx_power,
620 cmd_act_tx_power_opt_get,
621 cmd_option_waitforrsp, 0, NULL);
622
623 if (ret) {
624 LEAVE();
625 return ret;
626 }
627
628 lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
629 vwrq->value = adapter->txpowerlevel;
630 vwrq->fixed = 1;
631 if (adapter->radioon) {
632 vwrq->disabled = 0;
633 vwrq->flags = IW_TXPOW_DBM;
634 } else {
635 vwrq->disabled = 1;
636 }
637
638 LEAVE();
639 return 0;
640}
641
642static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
643 struct iw_param *vwrq, char *extra)
644{
645 int ret = 0;
646 wlan_private *priv = dev->priv;
647 wlan_adapter *adapter = priv->adapter;
648
649 ENTER();
650
651 if (vwrq->flags == IW_RETRY_LIMIT) {
652 /* The MAC has a 4-bit Total_Tx_Count register
653 Total_Tx_Count = 1 + Tx_Retry_Count */
654#define TX_RETRY_MIN 0
655#define TX_RETRY_MAX 14
656 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
657 return -EINVAL;
658
659 /* Adding 1 to convert retry count to try count */
660 adapter->txretrycount = vwrq->value + 1;
661
662 ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
663 cmd_act_set,
664 cmd_option_waitforrsp,
665 OID_802_11_TX_RETRYCOUNT, NULL);
666
667 if (ret) {
668 LEAVE();
669 return ret;
670 }
671 } else {
672 return -EOPNOTSUPP;
673 }
674
675 LEAVE();
676 return 0;
677}
678
679static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
680 struct iw_param *vwrq, char *extra)
681{
682 wlan_private *priv = dev->priv;
683 wlan_adapter *adapter = priv->adapter;
684 int ret = 0;
685
686 ENTER();
687 adapter->txretrycount = 0;
688 ret = libertas_prepare_and_send_command(priv,
689 cmd_802_11_snmp_mib,
690 cmd_act_get, cmd_option_waitforrsp,
691 OID_802_11_TX_RETRYCOUNT, NULL);
692 if (ret) {
693 LEAVE();
694 return ret;
695 }
696 vwrq->disabled = 0;
697 if (!vwrq->flags) {
698 vwrq->flags = IW_RETRY_LIMIT;
699 /* Subtract 1 to convert try count to retry count */
700 vwrq->value = adapter->txretrycount - 1;
701 }
702
703 LEAVE();
704 return 0;
705}
706
707static inline void sort_channels(struct iw_freq *freq, int num)
708{
709 int i, j;
710 struct iw_freq temp;
711
712 for (i = 0; i < num; i++)
713 for (j = i + 1; j < num; j++)
714 if (freq[i].i > freq[j].i) {
715 temp.i = freq[i].i;
716 temp.m = freq[i].m;
717
718 freq[i].i = freq[j].i;
719 freq[i].m = freq[j].m;
720
721 freq[j].i = temp.i;
722 freq[j].m = temp.m;
723 }
724}
725
726/* data rate listing
727 MULTI_BANDS:
728 abg a b b/g
729 Infra G(12) A(8) B(4) G(12)
730 Adhoc A+B(12) A(8) B(4) B(4)
731
732 non-MULTI_BANDS:
733 b b/g
734 Infra B(4) G(12)
735 Adhoc B(4) B(4)
736 */
737/**
738 * @brief Get Range Info
739 *
740 * @param dev A pointer to net_device structure
741 * @param info A pointer to iw_request_info structure
742 * @param vwrq A pointer to iw_param structure
743 * @param extra A pointer to extra data buf
744 * @return 0 --success, otherwise fail
745 */
746static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
747 struct iw_point *dwrq, char *extra)
748{
749 int i, j;
750 wlan_private *priv = dev->priv;
751 wlan_adapter *adapter = priv->adapter;
752 struct iw_range *range = (struct iw_range *)extra;
753 struct chan_freq_power *cfp;
754 u8 rates[WLAN_SUPPORTED_RATES];
755
756 u8 flag = 0;
757
758 ENTER();
759
760 dwrq->length = sizeof(struct iw_range);
761 memset(range, 0, sizeof(struct iw_range));
762
763 range->min_nwid = 0;
764 range->max_nwid = 0;
765
766 memset(rates, 0, sizeof(rates));
767 range->num_bitrates = get_active_data_rates(adapter, rates);
768
769 for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
770 i++) {
771 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
772 }
773 range->num_bitrates = i;
774 lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
775 range->num_bitrates);
776
777 range->num_frequency = 0;
778 if (priv->adapter->enable11d &&
779 adapter->connect_status == libertas_connected) {
780 u8 chan_no;
781 u8 band;
782
783 struct parsed_region_chan_11d *parsed_region_chan =
784 &adapter->parsed_region_chan;
785
786 if (parsed_region_chan == NULL) {
787 lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
788 LEAVE();
789 return 0;
790 }
791 band = parsed_region_chan->band;
792 lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
793 parsed_region_chan->nr_chan);
794
795 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
796 && (i < parsed_region_chan->nr_chan); i++) {
797 chan_no = parsed_region_chan->chanpwr[i].chan;
798 lbs_pr_debug(1, "chan_no=%d\n", chan_no);
799 range->freq[range->num_frequency].i = (long)chan_no;
800 range->freq[range->num_frequency].m =
801 (long)libertas_chan_2_freq(chan_no, band) * 100000;
802 range->freq[range->num_frequency].e = 1;
803 range->num_frequency++;
804 }
805 flag = 1;
806 }
807 if (!flag) {
808 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
809 && (j < sizeof(adapter->region_channel)
810 / sizeof(adapter->region_channel[0])); j++) {
811 cfp = adapter->region_channel[j].CFP;
812 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
813 && adapter->region_channel[j].valid
814 && cfp
815 && (i < adapter->region_channel[j].nrcfp); i++) {
816 range->freq[range->num_frequency].i =
817 (long)cfp->channel;
818 range->freq[range->num_frequency].m =
819 (long)cfp->freq * 100000;
820 range->freq[range->num_frequency].e = 1;
821 cfp++;
822 range->num_frequency++;
823 }
824 }
825 }
826
827 lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
828 IW_MAX_FREQUENCIES, range->num_frequency);
829
830 range->num_channels = range->num_frequency;
831
832 sort_channels(&range->freq[0], range->num_frequency);
833
834 /*
835 * Set an indication of the max TCP throughput in bit/s that we can
836 * expect using this interface
837 */
838 if (i > 2)
839 range->throughput = 5000 * 1000;
840 else
841 range->throughput = 1500 * 1000;
842
843 range->min_rts = MRVDRV_RTS_MIN_VALUE;
844 range->max_rts = MRVDRV_RTS_MAX_VALUE;
845 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
846 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
847
848 range->encoding_size[0] = 5;
849 range->encoding_size[1] = 13;
850 range->num_encoding_sizes = 2;
851 range->max_encoding_tokens = 4;
852
853 range->min_pmp = 1000000;
854 range->max_pmp = 120000000;
855 range->min_pmt = 1000;
856 range->max_pmt = 1000000;
857 range->pmp_flags = IW_POWER_PERIOD;
858 range->pmt_flags = IW_POWER_TIMEOUT;
859 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
860
861 /*
862 * Minimum version we recommend
863 */
864 range->we_version_source = 15;
865
866 /*
867 * Version we are compiled with
868 */
869 range->we_version_compiled = WIRELESS_EXT;
870
871 range->retry_capa = IW_RETRY_LIMIT;
872 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
873
874 range->min_retry = TX_RETRY_MIN;
875 range->max_retry = TX_RETRY_MAX;
876
877 /*
878 * Set the qual, level and noise range values
879 */
880 range->max_qual.qual = 100;
881 range->max_qual.level = 0;
882 range->max_qual.noise = 0;
883 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
884
885 range->avg_qual.qual = 70;
886 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
887 range->avg_qual.level = 0;
888 range->avg_qual.noise = 0;
889 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
890
891 range->sensitivity = 0;
892
893 /*
894 * Setup the supported power level ranges
895 */
896 memset(range->txpower, 0, sizeof(range->txpower));
897 range->txpower[0] = 5;
898 range->txpower[1] = 7;
899 range->txpower[2] = 9;
900 range->txpower[3] = 11;
901 range->txpower[4] = 13;
902 range->txpower[5] = 15;
903 range->txpower[6] = 17;
904 range->txpower[7] = 19;
905
906 range->num_txpower = 8;
907 range->txpower_capa = IW_TXPOW_DBM;
908 range->txpower_capa |= IW_TXPOW_RANGE;
909
910 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
911 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
912 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
913 range->event_capa[1] = IW_EVENT_CAPA_K_1;
914
915 if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
916 range->enc_capa = IW_ENC_CAPA_WPA
917 | IW_ENC_CAPA_WPA2
918 | IW_ENC_CAPA_CIPHER_TKIP
919 | IW_ENC_CAPA_CIPHER_CCMP;
920 }
921
922 LEAVE();
923 return 0;
924}
925
926static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
927 struct iw_param *vwrq, char *extra)
928{
929 wlan_private *priv = dev->priv;
930 wlan_adapter *adapter = priv->adapter;
931
932 ENTER();
933
934 /* PS is currently supported only in Infrastructure mode
935 * Remove this check if it is to be supported in IBSS mode also
936 */
937
938 if (vwrq->disabled) {
939 adapter->psmode = wlan802_11powermodecam;
940 if (adapter->psstate != PS_STATE_FULL_POWER) {
941 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
942 }
943
944 return 0;
945 }
946
947 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
948 lbs_pr_debug(1,
949 "Setting power timeout command is not supported\n");
950 return -EINVAL;
951 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
952 lbs_pr_debug(1, "Setting power period command is not supported\n");
953 return -EINVAL;
954 }
955
956 if (adapter->psmode != wlan802_11powermodecam) {
957 return 0;
958 }
959
960 adapter->psmode = wlan802_11powermodemax_psp;
961
962 if (adapter->connect_status == libertas_connected) {
963 libertas_ps_sleep(priv, cmd_option_waitforrsp);
964 }
965
966 LEAVE();
967 return 0;
968}
969
970static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
971 struct iw_param *vwrq, char *extra)
972{
973 wlan_private *priv = dev->priv;
974 wlan_adapter *adapter = priv->adapter;
975 int mode;
976
977 ENTER();
978
979 mode = adapter->psmode;
980
981 if ((vwrq->disabled = (mode == wlan802_11powermodecam))
982 || adapter->connect_status == libertas_disconnected) {
983 LEAVE();
984 return 0;
985 }
986
987 vwrq->value = 0;
988
989 LEAVE();
990 return 0;
991}
992
993/*
994 * iwpriv settable callbacks
995 */
996
997static const iw_handler wlan_private_handler[] = {
998 NULL, /* SIOCIWFIRSTPRIV */
999};
1000
1001static const struct iw_priv_args wlan_private_args[] = {
1002 /*
1003 * { cmd, set_args, get_args, name }
1004 */
1005 {
1006 WLANSCAN_TYPE,
1007 IW_PRIV_TYPE_CHAR | 8,
1008 IW_PRIV_TYPE_CHAR | 8,
1009 "scantype"},
1010
1011 {
1012 WLAN_SETINT_GETINT,
1013 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1014 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1015 ""},
1016 {
1017 WLANNF,
1018 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1019 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1020 "getNF"},
1021 {
1022 WLANRSSI,
1023 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1024 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1025 "getRSSI"},
1026 {
1027 WLANENABLE11D,
1028 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1029 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1030 "enable11d"},
1031 {
1032 WLANADHOCGRATE,
1033 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1034 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1035 "adhocgrate"},
1036
1037 {
1038 WLAN_SUBCMD_SET_PRESCAN,
1039 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1040 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1041 "prescan"},
1042 {
1043 WLAN_SETONEINT_GETONEINT,
1044 IW_PRIV_TYPE_INT | 1,
1045 IW_PRIV_TYPE_INT | 1,
1046 ""},
1047 {
1048 WLAN_BEACON_INTERVAL,
1049 IW_PRIV_TYPE_INT | 1,
1050 IW_PRIV_TYPE_INT | 1,
1051 "bcninterval"},
1052 {
1053 WLAN_LISTENINTRVL,
1054 IW_PRIV_TYPE_INT | 1,
1055 IW_PRIV_TYPE_INT | 1,
1056 "lolisteninter"},
1057 {
1058 WLAN_TXCONTROL,
1059 IW_PRIV_TYPE_INT | 1,
1060 IW_PRIV_TYPE_INT | 1,
1061 "txcontrol"},
1062 {
1063 WLAN_NULLPKTINTERVAL,
1064 IW_PRIV_TYPE_INT | 1,
1065 IW_PRIV_TYPE_INT | 1,
1066 "psnullinterval"},
1067 /* Using iwpriv sub-command feature */
1068 {
1069 WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
1070 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1071 IW_PRIV_TYPE_NONE,
1072 ""},
1073
1074 {
1075 WLAN_SUBCMD_SETRXANTENNA,
1076 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1077 IW_PRIV_TYPE_NONE,
1078 "setrxant"},
1079 {
1080 WLAN_SUBCMD_SETTXANTENNA,
1081 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1082 IW_PRIV_TYPE_NONE,
1083 "settxant"},
1084 {
1085 WLANSETAUTHALG,
1086 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1087 IW_PRIV_TYPE_NONE,
1088 "authalgs",
1089 },
1090 {
1091 WLANSET8021XAUTHALG,
1092 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1093 IW_PRIV_TYPE_NONE,
1094 "8021xauthalgs",
1095 },
1096 {
1097 WLANSETENCRYPTIONMODE,
1098 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1099 IW_PRIV_TYPE_NONE,
1100 "encryptionmode",
1101 },
1102 {
1103 WLANSETREGION,
1104 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1105 IW_PRIV_TYPE_NONE,
1106 "setregioncode"},
1107 {
1108 WLAN_SET_LISTEN_INTERVAL,
1109 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1110 IW_PRIV_TYPE_NONE,
1111 "setlisteninter"},
1112 {
1113 WLAN_SET_MULTIPLE_DTIM,
1114 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1115 IW_PRIV_TYPE_NONE,
1116 "setmultipledtim"},
1117 {
1118 WLAN_SET_ATIM_WINDOW,
1119 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1120 IW_PRIV_TYPE_NONE,
1121 "atimwindow"},
1122 {
1123 WLANSETBCNAVG,
1124 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1125 IW_PRIV_TYPE_NONE,
1126 "setbcnavg"},
1127 {
1128 WLANSETDATAAVG,
1129 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1130 IW_PRIV_TYPE_NONE,
1131 "setdataavg"},
1132 {
1133 WLAN_SET_LINKMODE,
1134 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1135 IW_PRIV_TYPE_NONE,
1136 "linkmode"},
1137 {
1138 WLAN_SET_RADIOMODE,
1139 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1140 IW_PRIV_TYPE_NONE,
1141 "radiomode"},
1142 {
1143 WLAN_SET_DEBUGMODE,
1144 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1145 IW_PRIV_TYPE_NONE,
1146 "debugmode"},
1147 {
1148 WLAN_SUBCMD_MESH_SET_TTL,
1149 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1150 IW_PRIV_TYPE_NONE,
1151 "mesh_set_ttl"},
1152 {
1153 WLAN_SETNONE_GETONEINT,
1154 IW_PRIV_TYPE_NONE,
1155 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1156 ""},
1157 {
1158 WLANGETREGION,
1159 IW_PRIV_TYPE_NONE,
1160 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1161 "getregioncode"},
1162 {
1163 WLAN_GET_LISTEN_INTERVAL,
1164 IW_PRIV_TYPE_NONE,
1165 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1166 "getlisteninter"},
1167 {
1168 WLAN_GET_MULTIPLE_DTIM,
1169 IW_PRIV_TYPE_NONE,
1170 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1171 "getmultipledtim"},
1172 {
1173 WLAN_GET_TX_RATE,
1174 IW_PRIV_TYPE_NONE,
1175 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1176 "gettxrate"},
1177 {
1178 WLANGETBCNAVG,
1179 IW_PRIV_TYPE_NONE,
1180 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1181 "getbcnavg"},
1182 {
1183 WLAN_GET_LINKMODE,
1184 IW_PRIV_TYPE_NONE,
1185 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1186 "get_linkmode"},
1187 {
1188 WLAN_GET_RADIOMODE,
1189 IW_PRIV_TYPE_NONE,
1190 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1191 "get_radiomode"},
1192 {
1193 WLAN_GET_DEBUGMODE,
1194 IW_PRIV_TYPE_NONE,
1195 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1196 "get_debugmode"},
1197 {
1198 WLAN_SUBCMD_FWT_CLEANUP,
1199 IW_PRIV_TYPE_NONE,
1200 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1201 "fwt_cleanup"},
1202 {
1203 WLAN_SUBCMD_FWT_TIME,
1204 IW_PRIV_TYPE_NONE,
1205 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1206 "fwt_time"},
1207 {
1208 WLAN_SUBCMD_MESH_GET_TTL,
1209 IW_PRIV_TYPE_NONE,
1210 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1211 "mesh_get_ttl"},
1212 {
1213 WLAN_SETNONE_GETTWELVE_CHAR,
1214 IW_PRIV_TYPE_NONE,
1215 IW_PRIV_TYPE_CHAR | 12,
1216 ""},
1217 {
1218 WLAN_SUBCMD_GETRXANTENNA,
1219 IW_PRIV_TYPE_NONE,
1220 IW_PRIV_TYPE_CHAR | 12,
1221 "getrxant"},
1222 {
1223 WLAN_SUBCMD_GETTXANTENNA,
1224 IW_PRIV_TYPE_NONE,
1225 IW_PRIV_TYPE_CHAR | 12,
1226 "gettxant"},
1227 {
1228 WLAN_GET_TSF,
1229 IW_PRIV_TYPE_NONE,
1230 IW_PRIV_TYPE_CHAR | 12,
1231 "gettsf"},
1232 {
1233 WLAN_SETNONE_GETNONE,
1234 IW_PRIV_TYPE_NONE,
1235 IW_PRIV_TYPE_NONE,
1236 ""},
1237 {
1238 WLANDEAUTH,
1239 IW_PRIV_TYPE_NONE,
1240 IW_PRIV_TYPE_NONE,
1241 "deauth"},
1242 {
1243 WLANADHOCSTOP,
1244 IW_PRIV_TYPE_NONE,
1245 IW_PRIV_TYPE_NONE,
1246 "adhocstop"},
1247 {
1248 WLANRADIOON,
1249 IW_PRIV_TYPE_NONE,
1250 IW_PRIV_TYPE_NONE,
1251 "radioon"},
1252 {
1253 WLANRADIOOFF,
1254 IW_PRIV_TYPE_NONE,
1255 IW_PRIV_TYPE_NONE,
1256 "radiooff"},
1257 {
1258 WLANWLANIDLEON,
1259 IW_PRIV_TYPE_NONE,
1260 IW_PRIV_TYPE_NONE,
1261 "wlanidle-on"},
1262 {
1263 WLANWLANIDLEOFF,
1264 IW_PRIV_TYPE_NONE,
1265 IW_PRIV_TYPE_NONE,
1266 "wlanidle-off"},
1267 {
1268 WLAN_SUBCMD_FWT_RESET,
1269 IW_PRIV_TYPE_NONE,
1270 IW_PRIV_TYPE_NONE,
1271 "fwt_reset"},
1272 {
1273 WLAN_SUBCMD_BT_RESET,
1274 IW_PRIV_TYPE_NONE,
1275 IW_PRIV_TYPE_NONE,
1276 "bt_reset"},
1277 {
1278 WLAN_SET128CHAR_GET128CHAR,
1279 IW_PRIV_TYPE_CHAR | 128,
1280 IW_PRIV_TYPE_CHAR | 128,
1281 ""},
1282 /* BT Management */
1283 {
1284 WLAN_SUBCMD_BT_ADD,
1285 IW_PRIV_TYPE_CHAR | 128,
1286 IW_PRIV_TYPE_CHAR | 128,
1287 "bt_add"},
1288 {
1289 WLAN_SUBCMD_BT_DEL,
1290 IW_PRIV_TYPE_CHAR | 128,
1291 IW_PRIV_TYPE_CHAR | 128,
1292 "bt_del"},
1293 {
1294 WLAN_SUBCMD_BT_LIST,
1295 IW_PRIV_TYPE_CHAR | 128,
1296 IW_PRIV_TYPE_CHAR | 128,
1297 "bt_list"},
1298 /* FWT Management */
1299 {
1300 WLAN_SUBCMD_FWT_ADD,
1301 IW_PRIV_TYPE_CHAR | 128,
1302 IW_PRIV_TYPE_CHAR | 128,
1303 "fwt_add"},
1304 {
1305 WLAN_SUBCMD_FWT_DEL,
1306 IW_PRIV_TYPE_CHAR | 128,
1307 IW_PRIV_TYPE_CHAR | 128,
1308 "fwt_del"},
1309 {
1310 WLAN_SUBCMD_FWT_LOOKUP,
1311 IW_PRIV_TYPE_CHAR | 128,
1312 IW_PRIV_TYPE_CHAR | 128,
1313 "fwt_lookup"},
1314 {
1315 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
1316 IW_PRIV_TYPE_CHAR | 128,
1317 IW_PRIV_TYPE_CHAR | 128,
1318 "fwt_list_neigh"},
1319 {
1320 WLAN_SUBCMD_FWT_LIST,
1321 IW_PRIV_TYPE_CHAR | 128,
1322 IW_PRIV_TYPE_CHAR | 128,
1323 "fwt_list"},
1324 {
1325 WLAN_SUBCMD_FWT_LIST_ROUTE,
1326 IW_PRIV_TYPE_CHAR | 128,
1327 IW_PRIV_TYPE_CHAR | 128,
1328 "fwt_list_route"},
1329 {
1330 WLANSCAN_MODE,
1331 IW_PRIV_TYPE_CHAR | 128,
1332 IW_PRIV_TYPE_CHAR | 128,
1333 "scanmode"},
1334 {
1335 WLAN_GET_ADHOC_STATUS,
1336 IW_PRIV_TYPE_CHAR | 128,
1337 IW_PRIV_TYPE_CHAR | 128,
1338 "getadhocstatus"},
1339 {
1340 WLAN_SETNONE_GETWORDCHAR,
1341 IW_PRIV_TYPE_NONE,
1342 IW_PRIV_TYPE_CHAR | 128,
1343 ""},
1344 {
1345 WLANSETWPAIE,
1346 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
1347 IW_PRIV_TYPE_NONE,
1348 "setwpaie"},
1349 {
1350 WLANGETLOG,
1351 IW_PRIV_TYPE_NONE,
1352 IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
1353 "getlog"},
1354 {
1355 WLAN_SET_GET_SIXTEEN_INT,
1356 IW_PRIV_TYPE_INT | 16,
1357 IW_PRIV_TYPE_INT | 16,
1358 ""},
1359 {
1360 WLAN_TPCCFG,
1361 IW_PRIV_TYPE_INT | 16,
1362 IW_PRIV_TYPE_INT | 16,
1363 "tpccfg"},
1364 {
1365 WLAN_POWERCFG,
1366 IW_PRIV_TYPE_INT | 16,
1367 IW_PRIV_TYPE_INT | 16,
1368 "powercfg"},
1369 {
1370 WLAN_AUTO_FREQ_SET,
1371 IW_PRIV_TYPE_INT | 16,
1372 IW_PRIV_TYPE_INT | 16,
1373 "setafc"},
1374 {
1375 WLAN_AUTO_FREQ_GET,
1376 IW_PRIV_TYPE_INT | 16,
1377 IW_PRIV_TYPE_INT | 16,
1378 "getafc"},
1379 {
1380 WLAN_SCANPROBES,
1381 IW_PRIV_TYPE_INT | 16,
1382 IW_PRIV_TYPE_INT | 16,
1383 "scanprobes"},
1384 {
1385 WLAN_LED_GPIO_CTRL,
1386 IW_PRIV_TYPE_INT | 16,
1387 IW_PRIV_TYPE_INT | 16,
1388 "ledgpio"},
1389 {
1390 WLAN_ADAPT_RATESET,
1391 IW_PRIV_TYPE_INT | 16,
1392 IW_PRIV_TYPE_INT | 16,
1393 "rateadapt"},
1394 {
1395 WLAN_INACTIVITY_TIMEOUT,
1396 IW_PRIV_TYPE_INT | 16,
1397 IW_PRIV_TYPE_INT | 16,
1398 "inactivityto"},
1399 {
1400 WLANSNR,
1401 IW_PRIV_TYPE_INT | 16,
1402 IW_PRIV_TYPE_INT | 16,
1403 "getSNR"},
1404 {
1405 WLAN_GET_RATE,
1406 IW_PRIV_TYPE_INT | 16,
1407 IW_PRIV_TYPE_INT | 16,
1408 "getrate"},
1409 {
1410 WLAN_GET_RXINFO,
1411 IW_PRIV_TYPE_INT | 16,
1412 IW_PRIV_TYPE_INT | 16,
1413 "getrxinfo"},
1414};
1415
1416static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
1417{
1418 enum {
1419 POOR = 30,
1420 FAIR = 60,
1421 GOOD = 80,
1422 VERY_GOOD = 90,
1423 EXCELLENT = 95,
1424 PERFECT = 100
1425 };
1426 wlan_private *priv = dev->priv;
1427 wlan_adapter *adapter = priv->adapter;
1428 u32 rssi_qual;
1429 u32 tx_qual;
1430 u32 quality = 0;
1431 int stats_valid = 0;
1432 u8 rssi;
1433 u32 tx_retries;
1434
1435 ENTER();
1436
1437 priv->wstats.status = adapter->inframode;
1438
1439 /* If we're not associated, all quality values are meaningless */
1440 if (adapter->connect_status != libertas_connected)
1441 goto out;
1442
1443 /* Quality by RSSI */
1444 priv->wstats.qual.level =
1445 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
1446 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1447
1448 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1449 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1450 } else {
1451 priv->wstats.qual.noise =
1452 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1453 }
1454
1455 lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
1456 lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
1457
1458 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
1459 if (rssi < 15)
1460 rssi_qual = rssi * POOR / 10;
1461 else if (rssi < 20)
1462 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
1463 else if (rssi < 30)
1464 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
1465 else if (rssi < 40)
1466 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
1467 10 + GOOD;
1468 else
1469 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
1470 10 + VERY_GOOD;
1471 quality = rssi_qual;
1472
1473 /* Quality by TX errors */
1474 priv->wstats.discard.retries = priv->stats.tx_errors;
1475
1476 tx_retries = adapter->logmsg.retry;
1477
1478 if (tx_retries > 75)
1479 tx_qual = (90 - tx_retries) * POOR / 15;
1480 else if (tx_retries > 70)
1481 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
1482 else if (tx_retries > 65)
1483 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
1484 else if (tx_retries > 50)
1485 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
1486 15 + GOOD;
1487 else
1488 tx_qual = (50 - tx_retries) *
1489 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
1490 quality = min(quality, tx_qual);
1491
1492 priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
1493 priv->wstats.discard.fragment = adapter->logmsg.fcserror;
1494 priv->wstats.discard.retries = tx_retries;
1495 priv->wstats.discard.misc = adapter->logmsg.ackfailure;
1496
1497 /* Calculate quality */
1498 priv->wstats.qual.qual = max(quality, (u32)100);
1499 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1500 stats_valid = 1;
1501
1502 /* update stats asynchronously for future calls */
1503 libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1504 0, 0, NULL);
1505 libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1506 0, 0, NULL);
1507out:
1508 if (!stats_valid) {
1509 priv->wstats.miss.beacon = 0;
1510 priv->wstats.discard.retries = 0;
1511 priv->wstats.qual.qual = 0;
1512 priv->wstats.qual.level = 0;
1513 priv->wstats.qual.noise = 0;
1514 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1515 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1516 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1517 }
1518
1519 LEAVE ();
1520 return &priv->wstats;
1521
1522
1523}
1524
1525static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1526 struct iw_freq *fwrq, char *extra)
1527{
1528 int ret = 0;
1529 wlan_private *priv = dev->priv;
1530 wlan_adapter *adapter = priv->adapter;
1531 int rc = -EINPROGRESS; /* Call commit handler */
1532 struct chan_freq_power *cfp;
1533
1534 ENTER();
1535
1536 /*
1537 * If setting by frequency, convert to a channel
1538 */
1539 if (fwrq->e == 1) {
1540
1541 long f = fwrq->m / 100000;
1542 int c = 0;
1543
1544 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1545 if (!cfp) {
1546 lbs_pr_debug(1, "Invalid freq=%ld\n", f);
1547 return -EINVAL;
1548 }
1549
1550 c = (int)cfp->channel;
1551
1552 if (c < 0)
1553 return -EINVAL;
1554
1555 fwrq->e = 0;
1556 fwrq->m = c;
1557 }
1558
1559 /*
1560 * Setting by channel number
1561 */
1562 if (fwrq->m > 1000 || fwrq->e > 0) {
1563 rc = -EOPNOTSUPP;
1564 } else {
1565 int channel = fwrq->m;
1566
1567 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
1568 if (!cfp) {
1569 rc = -EINVAL;
1570 } else {
1571 if (adapter->inframode == wlan802_11ibss) {
1572 rc = changeadhocchannel(priv, channel);
1573 /* If station is WEP enabled, send the
1574 * command to set WEP in firmware
1575 */
1576 if (adapter->secinfo.WEPstatus ==
1577 wlan802_11WEPenabled) {
1578 lbs_pr_debug(1, "set_freq: WEP enabled\n");
1579 ret = libertas_prepare_and_send_command(priv,
1580 cmd_802_11_set_wep,
1581 cmd_act_add,
1582 cmd_option_waitforrsp,
1583 0,
1584 NULL);
1585
1586 if (ret) {
1587 LEAVE();
1588 return ret;
1589 }
1590
1591 adapter->currentpacketfilter |=
1592 cmd_act_mac_wep_enable;
1593
1594 libertas_set_mac_packet_filter(priv);
1595 }
1596 } else {
1597 rc = -EOPNOTSUPP;
1598 }
1599 }
1600 }
1601
1602 LEAVE();
1603 return rc;
1604}
1605
1606/**
1607 * @brief use index to get the data rate
1608 *
1609 * @param index The index of data rate
1610 * @return data rate or 0
1611 */
1612u32 libertas_index_to_data_rate(u8 index)
1613{
1614 if (index >= sizeof(libertas_wlan_data_rates))
1615 index = 0;
1616
1617 return libertas_wlan_data_rates[index];
1618}
1619
1620/**
1621 * @brief use rate to get the index
1622 *
1623 * @param rate data rate
1624 * @return index or 0
1625 */
1626u8 libertas_data_rate_to_index(u32 rate)
1627{
1628 u8 *ptr;
1629
1630 if (rate)
1631 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1632 sizeof(libertas_wlan_data_rates))))
1633 return (ptr - libertas_wlan_data_rates);
1634
1635 return 0;
1636}
1637
1638static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1639 struct iw_param *vwrq, char *extra)
1640{
1641 wlan_private *priv = dev->priv;
1642 wlan_adapter *adapter = priv->adapter;
1643 u32 data_rate;
1644 u16 action;
1645 int ret = 0;
1646 u8 rates[WLAN_SUPPORTED_RATES];
1647 u8 *rate;
1648
1649 ENTER();
1650
1651 lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
1652
1653 if (vwrq->value == -1) {
1654 action = cmd_act_set_tx_auto; // Auto
1655 adapter->is_datarate_auto = 1;
1656 adapter->datarate = 0;
1657 } else {
1658 if (vwrq->value % 100000) {
1659 return -EINVAL;
1660 }
1661
1662 data_rate = vwrq->value / 500000;
1663
1664 memset(rates, 0, sizeof(rates));
1665 get_active_data_rates(adapter, rates);
1666 rate = rates;
1667 while (*rate) {
1668 lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate,
1669 data_rate);
1670 if ((*rate & 0x7f) == (data_rate & 0x7f))
1671 break;
1672 rate++;
1673 }
1674 if (!*rate) {
1675 lbs_pr_alert( "The fixed data rate 0x%X is out "
1676 "of range.\n", data_rate);
1677 return -EINVAL;
1678 }
1679
1680 adapter->datarate = data_rate;
1681 action = cmd_act_set_tx_fix_rate;
1682 adapter->is_datarate_auto = 0;
1683 }
1684
1685 ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1686 action, cmd_option_waitforrsp, 0, NULL);
1687
1688 LEAVE();
1689 return ret;
1690}
1691
1692static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1693 struct iw_param *vwrq, char *extra)
1694{
1695 wlan_private *priv = dev->priv;
1696 wlan_adapter *adapter = priv->adapter;
1697
1698 ENTER();
1699
1700 if (adapter->is_datarate_auto) {
1701 vwrq->fixed = 0;
1702 } else {
1703 vwrq->fixed = 1;
1704 }
1705
1706 vwrq->value = adapter->datarate * 500000;
1707
1708 LEAVE();
1709 return 0;
1710}
1711
1712static int wlan_set_mode(struct net_device *dev,
1713 struct iw_request_info *info, u32 * uwrq, char *extra)
1714{
1715 int ret = 0;
1716 wlan_private *priv = dev->priv;
1717 wlan_adapter *adapter = priv->adapter;
1718 struct assoc_request * assoc_req;
1719 enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
1720
1721 ENTER();
1722
1723 switch (*uwrq) {
1724 case IW_MODE_ADHOC:
1725 lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
1726 adapter->datarate);
1727 new_mode = wlan802_11ibss;
1728 adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
1729 break;
1730
1731 case IW_MODE_INFRA:
1732 lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
1733 new_mode = wlan802_11infrastructure;
1734 break;
1735
1736 case IW_MODE_AUTO:
1737 lbs_pr_debug(1, "Wanted mode is Auto\n");
1738 new_mode = wlan802_11autounknown;
1739 break;
1740
1741 default:
1742 lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
1743 return -EINVAL;
1744 }
1745
1746 mutex_lock(&adapter->lock);
1747 assoc_req = wlan_get_association_request(adapter);
1748 if (!assoc_req) {
1749 ret = -ENOMEM;
1750 } else {
1751 assoc_req->mode = new_mode;
1752 }
1753
1754 if (ret == 0) {
1755 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1756 wlan_postpone_association_work(priv);
1757 } else {
1758 wlan_cancel_association_work(priv);
1759 }
1760 mutex_unlock(&adapter->lock);
1761
1762 LEAVE();
1763 return ret;
1764}
1765
1766
1767/**
1768 * @brief Get Encryption key
1769 *
1770 * @param dev A pointer to net_device structure
1771 * @param info A pointer to iw_request_info structure
1772 * @param vwrq A pointer to iw_param structure
1773 * @param extra A pointer to extra data buf
1774 * @return 0 --success, otherwise fail
1775 */
1776static int wlan_get_encode(struct net_device *dev,
1777 struct iw_request_info *info,
1778 struct iw_point *dwrq, u8 * extra)
1779{
1780 wlan_private *priv = dev->priv;
1781 wlan_adapter *adapter = priv->adapter;
1782 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1783
1784 ENTER();
1785
1786 lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
1787 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1788
1789 dwrq->flags = 0;
1790
1791 /* Authentication method */
1792 switch (adapter->secinfo.authmode) {
1793 case wlan802_11authmodeopen:
1794 dwrq->flags = IW_ENCODE_OPEN;
1795 break;
1796
1797 case wlan802_11authmodeshared:
1798 case wlan802_11authmodenetworkEAP:
1799 dwrq->flags = IW_ENCODE_RESTRICTED;
1800 break;
1801 default:
1802 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1803 break;
1804 }
1805
1806 if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
1807 || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
1808 dwrq->flags &= ~IW_ENCODE_DISABLED;
1809 } else {
1810 dwrq->flags |= IW_ENCODE_DISABLED;
1811 }
1812
1813 memset(extra, 0, 16);
1814
1815 mutex_lock(&adapter->lock);
1816
1817 /* Default to returning current transmit key */
1818 if (index < 0)
1819 index = adapter->wep_tx_keyidx;
1820
1821 if ((adapter->wep_keys[index].len) &&
1822 (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
1823 memcpy(extra, adapter->wep_keys[index].key,
1824 adapter->wep_keys[index].len);
1825 dwrq->length = adapter->wep_keys[index].len;
1826
1827 dwrq->flags |= (index + 1);
1828 /* Return WEP enabled */
1829 dwrq->flags &= ~IW_ENCODE_DISABLED;
1830 } else if ((adapter->secinfo.WPAenabled)
1831 || (adapter->secinfo.WPA2enabled)) {
1832 /* return WPA enabled */
1833 dwrq->flags &= ~IW_ENCODE_DISABLED;
1834 } else {
1835 dwrq->flags |= IW_ENCODE_DISABLED;
1836 }
1837
1838 mutex_unlock(&adapter->lock);
1839
1840 dwrq->flags |= IW_ENCODE_NOKEY;
1841
1842 lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
1843 extra[0], extra[1], extra[2],
1844 extra[3], extra[4], extra[5], dwrq->length);
1845
1846 lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
1847
1848 LEAVE();
1849 return 0;
1850}
1851
1852/**
1853 * @brief Set Encryption key (internal)
1854 *
1855 * @param priv A pointer to private card structure
1856 * @param key_material A pointer to key material
1857 * @param key_length length of key material
1858 * @param index key index to set
1859 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1860 * @return 0 --success, otherwise fail
1861 */
1862static int wlan_set_wep_key(struct assoc_request *assoc_req,
1863 const char *key_material,
1864 u16 key_length,
1865 u16 index,
1866 int set_tx_key)
1867{
1868 struct WLAN_802_11_KEY *pkey;
1869
1870 ENTER();
1871
1872 /* Paranoid validation of key index */
1873 if (index > 3) {
1874 LEAVE();
1875 return -EINVAL;
1876 }
1877
1878 /* validate max key length */
1879 if (key_length > KEY_LEN_WEP_104) {
1880 LEAVE();
1881 return -EINVAL;
1882 }
1883
1884 pkey = &assoc_req->wep_keys[index];
1885
1886 if (key_length > 0) {
1887 memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1888 pkey->type = KEY_TYPE_ID_WEP;
1889
1890 /* Standardize the key length */
1891 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1892 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1893 memcpy(pkey->key, key_material, key_length);
1894 }
1895
1896 if (set_tx_key) {
1897 /* Ensure the chosen key is valid */
1898 if (!pkey->len) {
1899 lbs_pr_debug(1, "key not set, so cannot enable it\n");
1900 LEAVE();
1901 return -EINVAL;
1902 }
1903 assoc_req->wep_tx_keyidx = index;
1904 }
1905
1906 assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
1907
1908 LEAVE();
1909 return 0;
1910}
1911
1912static int validate_key_index(u16 def_index, u16 raw_index,
1913 u16 *out_index, u16 *is_default)
1914{
1915 if (!out_index || !is_default)
1916 return -EINVAL;
1917
1918 /* Verify index if present, otherwise use default TX key index */
1919 if (raw_index > 0) {
1920 if (raw_index > 4)
1921 return -EINVAL;
1922 *out_index = raw_index - 1;
1923 } else {
1924 *out_index = def_index;
1925 *is_default = 1;
1926 }
1927 return 0;
1928}
1929
1930static void disable_wep(struct assoc_request *assoc_req)
1931{
1932 int i;
1933
1934 /* Set Open System auth mode */
1935 assoc_req->secinfo.authmode = wlan802_11authmodeopen;
1936
1937 /* Clear WEP keys and mark WEP as disabled */
1938 assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
1939 for (i = 0; i < 4; i++)
1940 assoc_req->wep_keys[i].len = 0;
1941
1942 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1943 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1944}
1945
1946/**
1947 * @brief Set Encryption key
1948 *
1949 * @param dev A pointer to net_device structure
1950 * @param info A pointer to iw_request_info structure
1951 * @param vwrq A pointer to iw_param structure
1952 * @param extra A pointer to extra data buf
1953 * @return 0 --success, otherwise fail
1954 */
1955static int wlan_set_encode(struct net_device *dev,
1956 struct iw_request_info *info,
1957 struct iw_point *dwrq, char *extra)
1958{
1959 int ret = 0;
1960 wlan_private *priv = dev->priv;
1961 wlan_adapter *adapter = priv->adapter;
1962 struct assoc_request * assoc_req;
1963 u16 is_default = 0, index = 0, set_tx_key = 0;
1964
1965 ENTER();
1966
1967 mutex_lock(&adapter->lock);
1968 assoc_req = wlan_get_association_request(adapter);
1969 if (!assoc_req) {
1970 ret = -ENOMEM;
1971 goto out;
1972 }
1973
1974 if (dwrq->flags & IW_ENCODE_DISABLED) {
1975 disable_wep (assoc_req);
1976 goto out;
1977 }
1978
1979 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1980 (dwrq->flags & IW_ENCODE_INDEX),
1981 &index, &is_default);
1982 if (ret) {
1983 ret = -EINVAL;
1984 goto out;
1985 }
1986
1987 /* If WEP isn't enabled, or if there is no key data but a valid
1988 * index, set the TX key.
1989 */
1990 if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
1991 || (dwrq->length == 0 && !is_default))
1992 set_tx_key = 1;
1993
1994 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1995 if (ret)
1996 goto out;
1997
1998 if (dwrq->length)
1999 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
2000 if (set_tx_key)
2001 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
2002
2003 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
2004 assoc_req->secinfo.authmode = wlan802_11authmodeshared;
2005 } else if (dwrq->flags & IW_ENCODE_OPEN) {
2006 assoc_req->secinfo.authmode = wlan802_11authmodeopen;
2007 }
2008
2009out:
2010 if (ret == 0) {
2011 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2012 wlan_postpone_association_work(priv);
2013 } else {
2014 wlan_cancel_association_work(priv);
2015 }
2016 mutex_unlock(&adapter->lock);
2017
2018 LEAVE();
2019 return ret;
2020}
2021
2022/**
2023 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
2024 *
2025 * @param dev A pointer to net_device structure
2026 * @param info A pointer to iw_request_info structure
2027 * @param vwrq A pointer to iw_param structure
2028 * @param extra A pointer to extra data buf
2029 * @return 0 on success, otherwise failure
2030 */
2031static int wlan_get_encodeext(struct net_device *dev,
2032 struct iw_request_info *info,
2033 struct iw_point *dwrq,
2034 char *extra)
2035{
2036 int ret = -EINVAL;
2037 wlan_private *priv = dev->priv;
2038 wlan_adapter *adapter = priv->adapter;
2039 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
2040 int index, max_key_len;
2041
2042 ENTER();
2043
2044 max_key_len = dwrq->length - sizeof(*ext);
2045 if (max_key_len < 0)
2046 goto out;
2047
2048 index = dwrq->flags & IW_ENCODE_INDEX;
2049 if (index) {
2050 if (index < 1 || index > 4)
2051 goto out;
2052 index--;
2053 } else {
2054 index = adapter->wep_tx_keyidx;
2055 }
2056
2057 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
2058 ext->alg != IW_ENCODE_ALG_WEP) {
2059 if (index != 0 || adapter->inframode != wlan802_11infrastructure)
2060 goto out;
2061 }
2062
2063 dwrq->flags = index + 1;
2064 memset(ext, 0, sizeof(*ext));
2065
2066 if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
2067 && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
2068 ext->alg = IW_ENCODE_ALG_NONE;
2069 ext->key_len = 0;
2070 dwrq->flags |= IW_ENCODE_DISABLED;
2071 } else {
2072 u8 *key = NULL;
2073
2074 if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
2075 && !adapter->secinfo.WPAenabled
2076 && !adapter->secinfo.WPA2enabled) {
2077 ext->alg = IW_ENCODE_ALG_WEP;
2078 ext->key_len = adapter->wep_keys[index].len;
2079 key = &adapter->wep_keys[index].key[0];
2080 } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
2081 (adapter->secinfo.WPAenabled ||
2082 adapter->secinfo.WPA2enabled)) {
2083 /* WPA */
2084 ext->alg = IW_ENCODE_ALG_TKIP;
2085 ext->key_len = 0;
2086 } else {
2087 goto out;
2088 }
2089
2090 if (ext->key_len > max_key_len) {
2091 ret = -E2BIG;
2092 goto out;
2093 }
2094
2095 if (ext->key_len)
2096 memcpy(ext->key, key, ext->key_len);
2097 else
2098 dwrq->flags |= IW_ENCODE_NOKEY;
2099 dwrq->flags |= IW_ENCODE_ENABLED;
2100 }
2101 ret = 0;
2102
2103out:
2104 LEAVE();
2105 return ret;
2106}
2107
2108/**
2109 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
2110 *
2111 * @param dev A pointer to net_device structure
2112 * @param info A pointer to iw_request_info structure
2113 * @param vwrq A pointer to iw_param structure
2114 * @param extra A pointer to extra data buf
2115 * @return 0 --success, otherwise fail
2116 */
2117static int wlan_set_encodeext(struct net_device *dev,
2118 struct iw_request_info *info,
2119 struct iw_point *dwrq,
2120 char *extra)
2121{
2122 int ret = 0;
2123 wlan_private *priv = dev->priv;
2124 wlan_adapter *adapter = priv->adapter;
2125 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
2126 int alg = ext->alg;
2127 struct assoc_request * assoc_req;
2128
2129 ENTER();
2130
2131 mutex_lock(&adapter->lock);
2132 assoc_req = wlan_get_association_request(adapter);
2133 if (!assoc_req) {
2134 ret = -ENOMEM;
2135 goto out;
2136 }
2137
2138 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
2139 disable_wep (assoc_req);
2140 } else if (alg == IW_ENCODE_ALG_WEP) {
2141 u16 is_default = 0, index, set_tx_key = 0;
2142
2143 ret = validate_key_index(assoc_req->wep_tx_keyidx,
2144 (dwrq->flags & IW_ENCODE_INDEX),
2145 &index, &is_default);
2146 if (ret)
2147 goto out;
2148
2149 /* If WEP isn't enabled, or if there is no key data but a valid
2150 * index, or if the set-TX-key flag was passed, set the TX key.
2151 */
2152 if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
2153 || (dwrq->length == 0 && !is_default)
2154 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
2155 set_tx_key = 1;
2156
2157 /* Copy key to driver */
2158 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
2159 set_tx_key);
2160 if (ret)
2161 goto out;
2162
2163 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
2164 assoc_req->secinfo.authmode =
2165 wlan802_11authmodeshared;
2166 } else if (dwrq->flags & IW_ENCODE_OPEN) {
2167 assoc_req->secinfo.authmode =
2168 wlan802_11authmodeopen;
2169 }
2170
2171 /* Mark the various WEP bits as modified */
2172 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2173 if (dwrq->length)
2174 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
2175 if (set_tx_key)
2176 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
2177
2178 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
2179 struct WLAN_802_11_KEY * pkey;
2180
2181 /* validate key length */
2182 if (((alg == IW_ENCODE_ALG_TKIP)
2183 && (ext->key_len != KEY_LEN_WPA_TKIP))
2184 || ((alg == IW_ENCODE_ALG_CCMP)
2185 && (ext->key_len != KEY_LEN_WPA_AES))) {
2186 lbs_pr_debug(1, "Invalid size %d for key of alg"
2187 "type %d.\n",
2188 ext->key_len,
2189 alg);
2190 ret = -EINVAL;
2191 goto out;
2192 }
2193
2194 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
2195 pkey = &assoc_req->wpa_mcast_key;
2196 else
2197 pkey = &assoc_req->wpa_unicast_key;
2198
2199 memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
2200 memcpy(pkey->key, ext->key, ext->key_len);
2201 pkey->len = ext->key_len;
2202 pkey->flags = KEY_INFO_WPA_ENABLED;
2203
2204 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
2205 pkey->flags |= KEY_INFO_WPA_MCAST;
2206 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
2207 } else {
2208 pkey->flags |= KEY_INFO_WPA_UNICAST;
2209 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
2210 }
2211
2212 if (alg == IW_ENCODE_ALG_TKIP)
2213 pkey->type = KEY_TYPE_ID_TKIP;
2214 else if (alg == IW_ENCODE_ALG_CCMP)
2215 pkey->type = KEY_TYPE_ID_AES;
2216
2217 /* If WPA isn't enabled yet, do that now */
2218 if ( assoc_req->secinfo.WPAenabled == 0
2219 && assoc_req->secinfo.WPA2enabled == 0) {
2220 assoc_req->secinfo.WPAenabled = 1;
2221 assoc_req->secinfo.WPA2enabled = 1;
2222 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2223 }
2224
2225 disable_wep (assoc_req);
2226 }
2227
2228out:
2229 if (ret == 0) {
2230 wlan_postpone_association_work(priv);
2231 } else {
2232 wlan_cancel_association_work(priv);
2233 }
2234 mutex_unlock(&adapter->lock);
2235
2236 LEAVE();
2237 return ret;
2238}
2239
2240
2241static int wlan_set_genie(struct net_device *dev,
2242 struct iw_request_info *info,
2243 struct iw_point *dwrq,
2244 char *extra)
2245{
2246 wlan_private *priv = dev->priv;
2247 wlan_adapter *adapter = priv->adapter;
2248 int ret = 0;
2249 struct assoc_request * assoc_req;
2250
2251 ENTER();
2252
2253 mutex_lock(&adapter->lock);
2254 assoc_req = wlan_get_association_request(adapter);
2255 if (!assoc_req) {
2256 ret = -ENOMEM;
2257 goto out;
2258 }
2259
2260 if (dwrq->length > MAX_WPA_IE_LEN ||
2261 (dwrq->length && extra == NULL)) {
2262 ret = -EINVAL;
2263 goto out;
2264 }
2265
2266 if (dwrq->length) {
2267 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
2268 assoc_req->wpa_ie_len = dwrq->length;
2269 } else {
2270 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
2271 assoc_req->wpa_ie_len = 0;
2272 }
2273
2274out:
2275 if (ret == 0) {
2276 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
2277 wlan_postpone_association_work(priv);
2278 } else {
2279 wlan_cancel_association_work(priv);
2280 }
2281 mutex_unlock(&adapter->lock);
2282
2283 LEAVE();
2284 return ret;
2285}
2286
2287static int wlan_get_genie(struct net_device *dev,
2288 struct iw_request_info *info,
2289 struct iw_point *dwrq,
2290 char *extra)
2291{
2292 wlan_private *priv = dev->priv;
2293 wlan_adapter *adapter = priv->adapter;
2294
2295 ENTER();
2296
2297 if (adapter->wpa_ie_len == 0) {
2298 dwrq->length = 0;
2299 LEAVE();
2300 return 0;
2301 }
2302
2303 if (dwrq->length < adapter->wpa_ie_len) {
2304 LEAVE();
2305 return -E2BIG;
2306 }
2307
2308 dwrq->length = adapter->wpa_ie_len;
2309 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
2310
2311 LEAVE();
2312 return 0;
2313}
2314
2315
2316static int wlan_set_auth(struct net_device *dev,
2317 struct iw_request_info *info,
2318 struct iw_param *dwrq,
2319 char *extra)
2320{
2321 wlan_private *priv = dev->priv;
2322 wlan_adapter *adapter = priv->adapter;
2323 struct assoc_request * assoc_req;
2324 int ret = 0;
2325 int updated = 0;
2326
2327 ENTER();
2328
2329 mutex_lock(&adapter->lock);
2330 assoc_req = wlan_get_association_request(adapter);
2331 if (!assoc_req) {
2332 ret = -ENOMEM;
2333 goto out;
2334 }
2335
2336 switch (dwrq->flags & IW_AUTH_INDEX) {
2337 case IW_AUTH_TKIP_COUNTERMEASURES:
2338 case IW_AUTH_CIPHER_PAIRWISE:
2339 case IW_AUTH_CIPHER_GROUP:
2340 case IW_AUTH_KEY_MGMT:
2341 /*
2342 * libertas does not use these parameters
2343 */
2344 break;
2345
2346 case IW_AUTH_WPA_VERSION:
2347 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
2348 assoc_req->secinfo.WPAenabled = 0;
2349 assoc_req->secinfo.WPA2enabled = 0;
2350 }
2351 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
2352 assoc_req->secinfo.WPAenabled = 1;
2353 assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
2354 assoc_req->secinfo.authmode =
2355 wlan802_11authmodeopen;
2356 }
2357 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
2358 assoc_req->secinfo.WPA2enabled = 1;
2359 assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
2360 assoc_req->secinfo.authmode =
2361 wlan802_11authmodeopen;
2362 }
2363 updated = 1;
2364 break;
2365
2366 case IW_AUTH_DROP_UNENCRYPTED:
2367 if (dwrq->value) {
2368 adapter->currentpacketfilter |=
2369 cmd_act_mac_strict_protection_enable;
2370 } else {
2371 adapter->currentpacketfilter &=
2372 ~cmd_act_mac_strict_protection_enable;
2373 }
2374 updated = 1;
2375 break;
2376
2377 case IW_AUTH_80211_AUTH_ALG:
2378 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
2379 assoc_req->secinfo.authmode =
2380 wlan802_11authmodeshared;
2381 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
2382 assoc_req->secinfo.authmode =
2383 wlan802_11authmodeopen;
2384 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
2385 assoc_req->secinfo.authmode =
2386 wlan802_11authmodenetworkEAP;
2387 } else {
2388 ret = -EINVAL;
2389 }
2390 updated = 1;
2391 break;
2392
2393 case IW_AUTH_WPA_ENABLED:
2394 if (dwrq->value) {
2395 if (!assoc_req->secinfo.WPAenabled &&
2396 !assoc_req->secinfo.WPA2enabled) {
2397 assoc_req->secinfo.WPAenabled = 1;
2398 assoc_req->secinfo.WPA2enabled = 1;
2399 assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
2400 assoc_req->secinfo.authmode =
2401 wlan802_11authmodeopen;
2402 }
2403 } else {
2404 assoc_req->secinfo.WPAenabled = 0;
2405 assoc_req->secinfo.WPA2enabled = 0;
2406 }
2407 updated = 1;
2408 break;
2409
2410 default:
2411 ret = -EOPNOTSUPP;
2412 break;
2413 }
2414
2415out:
2416 if (ret == 0) {
2417 if (updated)
2418 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
2419 wlan_postpone_association_work(priv);
2420 } else if (ret != -EOPNOTSUPP) {
2421 wlan_cancel_association_work(priv);
2422 }
2423 mutex_unlock(&adapter->lock);
2424
2425 LEAVE();
2426 return ret;
2427}
2428
2429static int wlan_get_auth(struct net_device *dev,
2430 struct iw_request_info *info,
2431 struct iw_param *dwrq,
2432 char *extra)
2433{
2434 wlan_private *priv = dev->priv;
2435 wlan_adapter *adapter = priv->adapter;
2436
2437 ENTER();
2438
2439 switch (dwrq->flags & IW_AUTH_INDEX) {
2440 case IW_AUTH_WPA_VERSION:
2441 dwrq->value = 0;
2442 if (adapter->secinfo.WPAenabled)
2443 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
2444 if (adapter->secinfo.WPA2enabled)
2445 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
2446 if (!dwrq->value)
2447 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
2448 break;
2449
2450 case IW_AUTH_DROP_UNENCRYPTED:
2451 dwrq->value = 0;
2452 if (adapter->currentpacketfilter &
2453 cmd_act_mac_strict_protection_enable)
2454 dwrq->value = 1;
2455 break;
2456
2457 case IW_AUTH_80211_AUTH_ALG:
2458 switch (adapter->secinfo.authmode) {
2459 case wlan802_11authmodeshared:
2460 dwrq->value = IW_AUTH_ALG_SHARED_KEY;
2461 break;
2462 case wlan802_11authmodeopen:
2463 dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
2464 break;
2465 case wlan802_11authmodenetworkEAP:
2466 dwrq->value = IW_AUTH_ALG_LEAP;
2467 break;
2468 default:
2469 break;
2470 }
2471 break;
2472
2473 case IW_AUTH_WPA_ENABLED:
2474 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
2475 dwrq->value = 1;
2476 break;
2477
2478 default:
2479 LEAVE();
2480 return -EOPNOTSUPP;
2481 }
2482
2483 LEAVE();
2484 return 0;
2485}
2486
2487
2488static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
2489 struct iw_param *vwrq, char *extra)
2490{
2491 int ret = 0;
2492 wlan_private *priv = dev->priv;
2493 wlan_adapter *adapter = priv->adapter;
2494
2495 u16 dbm;
2496
2497 ENTER();
2498
2499 if (vwrq->disabled) {
2500 wlan_radio_ioctl(priv, RADIO_OFF);
2501 return 0;
2502 }
2503
2504 adapter->preamble = cmd_type_auto_preamble;
2505
2506 wlan_radio_ioctl(priv, RADIO_ON);
2507
2508 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
2509 dbm = (u16) mw_to_dbm(vwrq->value);
2510 } else
2511 dbm = (u16) vwrq->value;
2512
2513 /* auto tx power control */
2514
2515 if (vwrq->fixed == 0)
2516 dbm = 0xffff;
2517
2518 lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
2519
2520 ret = libertas_prepare_and_send_command(priv,
2521 cmd_802_11_rf_tx_power,
2522 cmd_act_tx_power_opt_set_low,
2523 cmd_option_waitforrsp, 0, (void *)&dbm);
2524
2525 LEAVE();
2526 return ret;
2527}
2528
2529static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2530 struct iw_point *dwrq, char *extra)
2531{
2532 wlan_private *priv = dev->priv;
2533 wlan_adapter *adapter = priv->adapter;
2534
2535 ENTER();
2536 /*
2537 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2538 * the SSID list...
2539 */
2540
2541 /*
2542 * Get the current SSID
2543 */
2544 if (adapter->connect_status == libertas_connected) {
2545 memcpy(extra, adapter->curbssparams.ssid.ssid,
2546 adapter->curbssparams.ssid.ssidlength);
2547 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2548 } else {
2549 memset(extra, 0, 32);
2550 extra[adapter->curbssparams.ssid.ssidlength] = '\0';
2551 }
2552 /*
2553 * If none, we may want to get the one that was set
2554 */
2555
2556 /* To make the driver backward compatible with WPA supplicant v0.2.4 */
2557 if (dwrq->length == 32) /* check with WPA supplicant buffer size */
2558 dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
2559 IW_ESSID_MAX_SIZE);
2560 else
2561 dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
2562
2563 dwrq->flags = 1; /* active */
2564
2565 LEAVE();
2566 return 0;
2567}
2568
2569static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2570 struct iw_point *dwrq, char *extra)
2571{
2572 wlan_private *priv = dev->priv;
2573 wlan_adapter *adapter = priv->adapter;
2574 int ret = 0;
2575 struct WLAN_802_11_SSID ssid;
2576 struct assoc_request * assoc_req;
2577 int ssid_len = dwrq->length;
2578
2579 ENTER();
2580
2581 /*
2582 * WE-20 and earlier NULL pad the end of the SSID and increment
2583 * SSID length so it can be used like a string. WE-21 and later don't,
2584 * but some userspace tools aren't able to cope with the change.
2585 */
2586 if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
2587 ssid_len--;
2588
2589 /* Check the size of the string */
2590 if (ssid_len > IW_ESSID_MAX_SIZE) {
2591 ret = -E2BIG;
2592 goto out;
2593 }
2594
2595 memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
2596
2597 if (!dwrq->flags || !ssid_len) {
2598 /* "any" SSID requested; leave SSID blank */
2599 } else {
2600 /* Specific SSID requested */
2601 memcpy(&ssid.ssid, extra, ssid_len);
2602 ssid.ssidlength = ssid_len;
2603 }
2604
2605 lbs_pr_debug(1, "Requested new SSID = %s\n",
2606 (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
2607
2608out:
2609 mutex_lock(&adapter->lock);
2610 if (ret == 0) {
2611 /* Get or create the current association request */
2612 assoc_req = wlan_get_association_request(adapter);
2613 if (!assoc_req) {
2614 ret = -ENOMEM;
2615 } else {
2616 /* Copy the SSID to the association request */
2617 memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
2618 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2619 wlan_postpone_association_work(priv);
2620 }
2621 }
2622
2623 /* Cancel the association request if there was an error */
2624 if (ret != 0) {
2625 wlan_cancel_association_work(priv);
2626 }
2627
2628 mutex_unlock(&adapter->lock);
2629
2630 LEAVE();
2631 return ret;
2632}
2633
2634/**
2635 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2636 *
2637 * @param dev A pointer to net_device structure
2638 * @param info A pointer to iw_request_info structure
2639 * @param awrq A pointer to iw_param structure
2640 * @param extra A pointer to extra data buf
2641 * @return 0 --success, otherwise fail
2642 */
2643static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2644 struct sockaddr *awrq, char *extra)
2645{
2646 wlan_private *priv = dev->priv;
2647 wlan_adapter *adapter = priv->adapter;
2648 struct assoc_request * assoc_req;
2649 int ret = 0;
2650
2651 ENTER();
2652
2653 if (awrq->sa_family != ARPHRD_ETHER)
2654 return -EINVAL;
2655
2656 lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
2657
2658 mutex_lock(&adapter->lock);
2659
2660 /* Get or create the current association request */
2661 assoc_req = wlan_get_association_request(adapter);
2662 if (!assoc_req) {
2663 wlan_cancel_association_work(priv);
2664 ret = -ENOMEM;
2665 } else {
2666 /* Copy the BSSID to the association request */
2667 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2668 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2669 wlan_postpone_association_work(priv);
2670 }
2671
2672 mutex_unlock(&adapter->lock);
2673
2674 return ret;
2675}
2676
2677void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2678{
2679 union {
2680 u32 l;
2681 u8 c[4];
2682 } ver;
2683 char fwver[32];
2684
2685 mutex_lock(&adapter->lock);
2686 ver.l = adapter->fwreleasenumber;
2687 mutex_unlock(&adapter->lock);
2688
2689 if (ver.c[3] == 0)
2690 sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
2691 else
2692 sprintf(fwver, "%u.%u.%u.p%u",
2693 ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
2694
2695 snprintf(fwversion, maxlen, fwver);
2696}
2697
2698
2699/*
2700 * iwconfig settable callbacks
2701 */
2702static const iw_handler wlan_handler[] = {
2703 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2704 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2705 (iw_handler) NULL, /* SIOCSIWNWID */
2706 (iw_handler) NULL, /* SIOCGIWNWID */
2707 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2708 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2709 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2710 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2711 (iw_handler) NULL, /* SIOCSIWSENS */
2712 (iw_handler) NULL, /* SIOCGIWSENS */
2713 (iw_handler) NULL, /* SIOCSIWRANGE */
2714 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2715 (iw_handler) NULL, /* SIOCSIWPRIV */
2716 (iw_handler) NULL, /* SIOCGIWPRIV */
2717 (iw_handler) NULL, /* SIOCSIWSTATS */
2718 (iw_handler) NULL, /* SIOCGIWSTATS */
2719 iw_handler_set_spy, /* SIOCSIWSPY */
2720 iw_handler_get_spy, /* SIOCGIWSPY */
2721 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2722 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2723 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2724 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2725 (iw_handler) NULL, /* SIOCSIWMLME */
2726 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2727 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2728 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2729 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2730 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2731 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2732 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2733 (iw_handler) NULL, /* -- hole -- */
2734 (iw_handler) NULL, /* -- hole -- */
2735 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2736 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2737 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2738 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2739 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2740 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2741 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2742 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2743 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2744 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2745 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2746 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2747 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2748 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2749 (iw_handler) NULL, /* -- hole -- */
2750 (iw_handler) NULL, /* -- hole -- */
2751 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2752 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2753 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2754 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2755 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2756 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2757 (iw_handler) NULL, /* SIOCSIWPMKSA */
2758};
2759
2760struct iw_handler_def libertas_handler_def = {
2761 .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
2762 .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
2763 .num_private_args = sizeof(wlan_private_args) /
2764 sizeof(struct iw_priv_args),
2765 .standard = (iw_handler *) wlan_handler,
2766 .private = (iw_handler *) wlan_private_handler,
2767 .private_args = (struct iw_priv_args *)wlan_private_args,
2768 .get_wireless_stats = wlan_get_wireless_stats,
2769};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644
index 000000000000..39f367c38d90
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.h
@@ -0,0 +1,147 @@
1/**
2 * This file contains definition for IOCTL call.
3 */
4#ifndef _WLAN_WEXT_H_
5#define _WLAN_WEXT_H_
6
7#define SUBCMD_OFFSET 4
8#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
9
10/** PRIVATE CMD ID */
11#define WLANIOCTL SIOCIWFIRSTPRIV
12
13#define WLANSETWPAIE (WLANIOCTL + 0)
14
15#define WLAN_SETINT_GETINT (WLANIOCTL + 7)
16#define WLANNF 1
17#define WLANRSSI 2
18#define WLANENABLE11D 5
19#define WLANADHOCGRATE 6
20#define WLAN_SUBCMD_SET_PRESCAN 11
21
22#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8)
23#define WLANDEAUTH 1
24#define WLANRADIOON 2
25#define WLANRADIOOFF 3
26#define WLANREMOVEADHOCAES 4
27#define WLANADHOCSTOP 5
28#define WLANCIPHERTEST 6
29#define WLANCRYPTOTEST 7
30
31#define WLANWLANIDLEON 10
32#define WLANWLANIDLEOFF 11
33#define WLAN_SUBCMD_BT_RESET 13
34#define WLAN_SUBCMD_FWT_RESET 14
35
36#define WLANGETLOG (WLANIOCTL + 9)
37#define GETLOG_BUFSIZE 300
38
39#define WLANSCAN_TYPE (WLANIOCTL + 11)
40
41#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15)
42#define WLANGETREGION 1
43#define WLAN_GET_LISTEN_INTERVAL 2
44#define WLAN_GET_MULTIPLE_DTIM 3
45#define WLAN_GET_TX_RATE 4
46#define WLANGETBCNAVG 5
47
48#define WLAN_GET_LINKMODE 6
49#define WLAN_GET_RADIOMODE 7
50#define WLAN_GET_DEBUGMODE 8
51#define WLAN_SUBCMD_FWT_CLEANUP 15
52#define WLAN_SUBCMD_FWT_TIME 16
53#define WLAN_SUBCMD_MESH_GET_TTL 17
54
55#define WLANREGCFRDWR (WLANIOCTL + 18)
56
57#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
58#define WLAN_SUBCMD_GETRXANTENNA 1
59#define WLAN_SUBCMD_GETTXANTENNA 2
60#define WLAN_GET_TSF 3
61
62#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21)
63#define WLANGETADHOCAES 1
64
65#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23)
66#define WLAN_BEACON_INTERVAL 1
67#define WLAN_LISTENINTRVL 4
68
69#define WLAN_TXCONTROL 6
70#define WLAN_NULLPKTINTERVAL 7
71
72#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24)
73#define WLAN_SUBCMD_SETRXANTENNA 1
74#define WLAN_SUBCMD_SETTXANTENNA 2
75#define WLANSETAUTHALG 5
76#define WLANSET8021XAUTHALG 6
77#define WLANSETENCRYPTIONMODE 7
78#define WLANSETREGION 8
79#define WLAN_SET_LISTEN_INTERVAL 9
80
81#define WLAN_SET_MULTIPLE_DTIM 10
82#define WLAN_SET_ATIM_WINDOW 11
83#define WLANSETBCNAVG 13
84#define WLANSETDATAAVG 14
85#define WLAN_SET_LINKMODE 15
86#define WLAN_SET_RADIOMODE 16
87#define WLAN_SET_DEBUGMODE 17
88#define WLAN_SUBCMD_MESH_SET_TTL 18
89
90#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25)
91#define WLANSCAN_MODE 6
92
93#define WLAN_GET_ADHOC_STATUS 9
94
95#define WLAN_SUBCMD_BT_ADD 18
96#define WLAN_SUBCMD_BT_DEL 19
97#define WLAN_SUBCMD_BT_LIST 20
98#define WLAN_SUBCMD_FWT_ADD 21
99#define WLAN_SUBCMD_FWT_DEL 22
100#define WLAN_SUBCMD_FWT_LOOKUP 23
101#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24
102#define WLAN_SUBCMD_FWT_LIST 25
103#define WLAN_SUBCMD_FWT_LIST_ROUTE 26
104
105#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29)
106#define WLAN_TPCCFG 1
107#define WLAN_POWERCFG 2
108
109#define WLAN_AUTO_FREQ_SET 3
110#define WLAN_AUTO_FREQ_GET 4
111#define WLAN_LED_GPIO_CTRL 5
112#define WLAN_SCANPROBES 6
113#define WLAN_ADAPT_RATESET 8
114#define WLAN_INACTIVITY_TIMEOUT 9
115#define WLANSNR 10
116#define WLAN_GET_RATE 11
117#define WLAN_GET_RXINFO 12
118
119#define WLANCMD52RDWR (WLANIOCTL + 30)
120#define WLANCMD53RDWR (WLANIOCTL + 31)
121#define CMD53BUFLEN 32
122
123#define REG_MAC 0x19
124#define REG_BBP 0x1a
125#define REG_RF 0x1b
126#define REG_EEPROM 0x59
127#define WLAN_LINKMODE_802_3 0
128#define WLAN_LINKMODE_802_11 2
129#define WLAN_RADIOMODE_NONE 0
130#define WLAN_RADIOMODE_RADIOTAP 2
131
132/** wlan_ioctl_regrdwr */
133struct wlan_ioctl_regrdwr {
134 /** Which register to access */
135 u16 whichreg;
136 /** Read or Write */
137 u16 action;
138 u32 offset;
139 u16 NOB;
140 u32 value;
141};
142
143extern struct iw_handler_def libertas_handler_def;
144int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
145int wlan_radio_ioctl(wlan_private * priv, u8 option);
146
147#endif /* _WLAN_WEXT_H_ */