aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/11d.c
diff options
context:
space:
mode:
authorMarcelo Tosatti <marcelo@kvack.org>2007-02-10 09:25:27 -0500
committerJeff Garzik <jeff@garzik.org>2007-04-28 11:00:54 -0400
commit876c9d3aeb989cf1961f2c228d309ba5dcfb1172 (patch)
tree239e9db92d13abc799c1ffc5304d8ec1503dbc61 /drivers/net/wireless/libertas/11d.c
parent35c3404efa7407811b706453f83d39b2539dcbd0 (diff)
[PATCH] Marvell Libertas 8388 802.11b/g USB driver
Add the Marvell Libertas 8388 802.11 USB driver. Signed-off-by: Marcelo Tosatti <marcelo@kvack.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/11d.c')
-rw-r--r--drivers/net/wireless/libertas/11d.c754
1 files changed, 754 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}