zd1211rw: Fix TX status reporting in order to have proper rate control
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / wireless / libertas / 11d.c
CommitLineData
876c9d3a
MT
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"
bca61f8a 9#include "cmd.h"
876c9d3a
MT
10#include "decl.h"
11#include "11d.h"
12#include "dev.h"
13#include "wext.h"
14
15#define TX_PWR_DEFAULT 10
16
17static struct region_code_mapping region_code_mapping[] = {
18 {"US ", 0x10}, /* US FCC */
19 {"CA ", 0x10}, /* IC Canada */
20 {"SG ", 0x10}, /* Singapore */
21 {"EU ", 0x30}, /* ETSI */
22 {"AU ", 0x30}, /* Australia */
23 {"KR ", 0x30}, /* Republic Of Korea */
24 {"ES ", 0x31}, /* Spain */
25 {"FR ", 0x32}, /* France */
26 {"JP ", 0x40}, /* Japan */
27};
28
29/* Following 2 structure defines the supported channels */
30static struct chan_freq_power channel_freq_power_UN_BG[] = {
31 {1, 2412, TX_PWR_DEFAULT},
32 {2, 2417, TX_PWR_DEFAULT},
33 {3, 2422, TX_PWR_DEFAULT},
34 {4, 2427, TX_PWR_DEFAULT},
35 {5, 2432, TX_PWR_DEFAULT},
36 {6, 2437, TX_PWR_DEFAULT},
37 {7, 2442, TX_PWR_DEFAULT},
38 {8, 2447, TX_PWR_DEFAULT},
39 {9, 2452, TX_PWR_DEFAULT},
40 {10, 2457, TX_PWR_DEFAULT},
41 {11, 2462, TX_PWR_DEFAULT},
42 {12, 2467, TX_PWR_DEFAULT},
43 {13, 2472, TX_PWR_DEFAULT},
44 {14, 2484, TX_PWR_DEFAULT}
45};
46
10078321 47static u8 lbs_region_2_code(u8 *region)
876c9d3a
MT
48{
49 u8 i;
876c9d3a 50
b929c633 51 for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
876c9d3a
MT
52 region[i] = toupper(region[i]);
53
c00acf46 54 for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
876c9d3a
MT
55 if (!memcmp(region, region_code_mapping[i].region,
56 COUNTRY_CODE_LEN))
57 return (region_code_mapping[i].code);
58 }
59
60 /* default is US */
61 return (region_code_mapping[0].code);
62}
63
10078321 64static u8 *lbs_code_2_region(u8 code)
876c9d3a
MT
65{
66 u8 i;
c00acf46
AMR
67
68 for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
876c9d3a
MT
69 if (region_code_mapping[i].code == code)
70 return (region_code_mapping[i].region);
71 }
72 /* default is US */
73 return (region_code_mapping[0].region);
74}
75
76/**
77 * @brief This function finds the nrchan-th chan after the firstchan
78 * @param band band
79 * @param firstchan first channel number
80 * @param nrchan number of channels
81 * @return the nrchan-th chan number
82*/
e98a88dd 83static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
876c9d3a
MT
84/*find the nrchan-th chan after the firstchan*/
85{
86 u8 i;
87 struct chan_freq_power *cfp;
88 u8 cfp_no;
89
90 cfp = channel_freq_power_UN_BG;
c00acf46 91 cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
876c9d3a
MT
92
93 for (i = 0; i < cfp_no; i++) {
94 if ((cfp + i)->channel == firstchan) {
9012b28a 95 lbs_deb_11d("firstchan found\n");
876c9d3a
MT
96 break;
97 }
98 }
99
100 if (i < cfp_no) {
101 /*if beyond the boundary */
102 if (i + nrchan < cfp_no) {
103 *chan = (cfp + i + nrchan)->channel;
104 return 1;
105 }
106 }
107
108 return 0;
109}
110
111/**
112 * @brief This function Checks if chan txpwr is learned from AP/IBSS
113 * @param chan chan number
114 * @param parsed_region_chan pointer to parsed_region_chan_11d
115 * @return TRUE; FALSE
116*/
10078321 117static u8 lbs_channel_known_11d(u8 chan,
876c9d3a
MT
118 struct parsed_region_chan_11d * parsed_region_chan)
119{
120 struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
121 u8 nr_chan = parsed_region_chan->nr_chan;
122 u8 i = 0;
123
ece56191 124 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
876c9d3a
MT
125 sizeof(struct chan_power_11d) * nr_chan);
126
127 for (i = 0; i < nr_chan; i++) {
128 if (chan == chanpwr[i].chan) {
ece56191 129 lbs_deb_11d("found chan %d\n", chan);
876c9d3a
MT
130 return 1;
131 }
132 }
133
ece56191 134 lbs_deb_11d("chan %d not found\n", chan);
876c9d3a
MT
135 return 0;
136}
137
e98a88dd 138u32 lbs_chan_2_freq(u8 chan)
876c9d3a
MT
139{
140 struct chan_freq_power *cf;
876c9d3a
MT
141 u16 i;
142 u32 freq = 0;
143
144 cf = channel_freq_power_UN_BG;
876c9d3a 145
c00acf46 146 for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
876c9d3a
MT
147 if (chan == cf[i].channel)
148 freq = cf[i].freq;
149 }
150
151 return freq;
152}
153
154static int generate_domain_info_11d(struct parsed_region_chan_11d
155 *parsed_region_chan,
10078321 156 struct lbs_802_11d_domain_reg *domaininfo)
876c9d3a
MT
157{
158 u8 nr_subband = 0;
159
160 u8 nr_chan = parsed_region_chan->nr_chan;
161 u8 nr_parsedchan = 0;
162
163 u8 firstchan = 0, nextchan = 0, maxpwr = 0;
164
165 u8 i, flag = 0;
166
167 memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
168 COUNTRY_CODE_LEN);
169
ece56191
HS
170 lbs_deb_11d("nrchan %d\n", nr_chan);
171 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
876c9d3a
MT
172 sizeof(struct parsed_region_chan_11d));
173
174 for (i = 0; i < nr_chan; i++) {
175 if (!flag) {
176 flag = 1;
177 nextchan = firstchan =
178 parsed_region_chan->chanpwr[i].chan;
179 maxpwr = parsed_region_chan->chanpwr[i].pwr;
180 nr_parsedchan = 1;
181 continue;
182 }
183
184 if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
185 parsed_region_chan->chanpwr[i].pwr == maxpwr) {
186 nextchan++;
187 nr_parsedchan++;
188 } else {
189 domaininfo->subband[nr_subband].firstchan = firstchan;
190 domaininfo->subband[nr_subband].nrchan =
191 nr_parsedchan;
192 domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
193 nr_subband++;
194 nextchan = firstchan =
195 parsed_region_chan->chanpwr[i].chan;
196 maxpwr = parsed_region_chan->chanpwr[i].pwr;
197 }
198 }
199
200 if (flag) {
201 domaininfo->subband[nr_subband].firstchan = firstchan;
202 domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
203 domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
204 nr_subband++;
205 }
206 domaininfo->nr_subband = nr_subband;
207
9012b28a 208 lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
ece56191 209 lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
876c9d3a 210 COUNTRY_CODE_LEN + 1 +
75b6a61a 211 sizeof(struct ieee_subbandset) * nr_subband);
876c9d3a
MT
212 return 0;
213}
214
215/**
216 * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
217 * @param region_chan pointer to struct region_channel
218 * @param *parsed_region_chan pointer to parsed_region_chan_11d
219 * @return N/A
220*/
10078321 221static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
876c9d3a
MT
222 struct parsed_region_chan_11d *
223 parsed_region_chan)
224{
225 u8 i;
226 struct chan_freq_power *cfp;
227
228 if (region_chan == NULL) {
ece56191 229 lbs_deb_11d("region_chan is NULL\n");
876c9d3a
MT
230 return;
231 }
232
233 cfp = region_chan->CFP;
234 if (cfp == NULL) {
ece56191 235 lbs_deb_11d("cfp is NULL \n");
876c9d3a
MT
236 return;
237 }
238
239 parsed_region_chan->band = region_chan->band;
240 parsed_region_chan->region = region_chan->region;
241 memcpy(parsed_region_chan->countrycode,
10078321 242 lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
876c9d3a 243
ece56191 244 lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
876c9d3a
MT
245 parsed_region_chan->band);
246
247 for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
248 parsed_region_chan->chanpwr[i].chan = cfp->channel;
249 parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
ece56191 250 lbs_deb_11d("chan %d, pwr %d\n",
876c9d3a
MT
251 parsed_region_chan->chanpwr[i].chan,
252 parsed_region_chan->chanpwr[i].pwr);
253 }
254 parsed_region_chan->nr_chan = region_chan->nrcfp;
255
ece56191 256 lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
876c9d3a
MT
257
258 return;
259}
260
261/**
262 * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
263 * @param region region ID
264 * @param band band
265 * @param chan chan
266 * @return TRUE;FALSE
267*/
e98a88dd 268static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
876c9d3a
MT
269{
270 struct chan_freq_power *cfp;
271 int cfp_no;
272 u8 idx;
9012b28a 273 int ret = 0;
876c9d3a 274
9012b28a 275 lbs_deb_enter(LBS_DEB_11D);
876c9d3a 276
e98a88dd 277 cfp = lbs_get_region_cfp_table(region, &cfp_no);
876c9d3a
MT
278 if (cfp == NULL)
279 return 0;
280
281 for (idx = 0; idx < cfp_no; idx++) {
282 if (chan == (cfp + idx)->channel) {
283 /* If Mrvl Chip Supported? */
284 if ((cfp + idx)->unsupported) {
9012b28a 285 ret = 0;
876c9d3a 286 } else {
9012b28a 287 ret = 1;
876c9d3a 288 }
9012b28a 289 goto done;
876c9d3a
MT
290 }
291 }
292
293 /*chan is not in the region table */
9012b28a
HS
294
295done:
296 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
297 return ret;
876c9d3a
MT
298}
299
300/**
301 * @brief This function checks if chan txpwr is learned from AP/IBSS
302 * @param chan chan number
303 * @param parsed_region_chan pointer to parsed_region_chan_11d
304 * @return 0
305*/
75b6a61a 306static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
876c9d3a 307 u8 band,
75b6a61a 308 struct parsed_region_chan_11d *parsed_region_chan)
876c9d3a
MT
309{
310 u8 nr_subband, nrchan;
311 u8 lastchan, firstchan;
312 u8 region;
313 u8 curchan = 0;
314
315 u8 idx = 0; /*chan index in parsed_region_chan */
316
317 u8 j, i;
318
9012b28a 319 lbs_deb_enter(LBS_DEB_11D);
876c9d3a
MT
320
321 /*validation Rules:
322 1. valid region Code
323 2. First Chan increment
324 3. channel range no overlap
325 4. channel is valid?
326 5. channel is supported by region?
327 6. Others
328 */
329
ece56191 330 lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
876c9d3a
MT
331
332 if ((*(countryinfo->countrycode)) == 0
75b6a61a 333 || (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
876c9d3a 334 /* No region Info or Wrong region info: treat as No 11D info */
9012b28a 335 goto done;
876c9d3a
MT
336 }
337
338 /*Step1: check region_code */
339 parsed_region_chan->region = region =
10078321 340 lbs_region_2_code(countryinfo->countrycode);
876c9d3a 341
9012b28a 342 lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
ece56191 343 lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
876c9d3a
MT
344 COUNTRY_CODE_LEN);
345
346 parsed_region_chan->band = band;
347
348 memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
349 COUNTRY_CODE_LEN);
350
75b6a61a
DW
351 nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
352 sizeof(struct ieee_subbandset);
876c9d3a
MT
353
354 for (j = 0, lastchan = 0; j < nr_subband; j++) {
355
356 if (countryinfo->subband[j].firstchan <= lastchan) {
357 /*Step2&3. Check First Chan Num increment and no overlap */
ece56191 358 lbs_deb_11d("chan %d>%d, overlap\n",
876c9d3a
MT
359 countryinfo->subband[j].firstchan, lastchan);
360 continue;
361 }
362
363 firstchan = countryinfo->subband[j].firstchan;
364 nrchan = countryinfo->subband[j].nrchan;
365
366 for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
367 /*step4: channel is supported? */
368
e98a88dd 369 if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
876c9d3a 370 /* Chan is not found in UN table */
9012b28a 371 lbs_deb_11d("chan is not supported: %d \n", i);
876c9d3a
MT
372 break;
373 }
374
375 lastchan = curchan;
376
e98a88dd 377 if (lbs_region_chan_supported_11d(region, curchan)) {
876c9d3a
MT
378 /*step5: Check if curchan is supported by mrvl in region */
379 parsed_region_chan->chanpwr[idx].chan = curchan;
380 parsed_region_chan->chanpwr[idx].pwr =
381 countryinfo->subband[j].maxtxpwr;
382 idx++;
383 } else {
384 /*not supported and ignore the chan */
9012b28a 385 lbs_deb_11d(
ece56191 386 "i %d, chan %d unsupported in region %x, band %d\n",
876c9d3a
MT
387 i, curchan, region, band);
388 }
389 }
390
391 /*Step6: Add other checking if any */
392
393 }
394
395 parsed_region_chan->nr_chan = idx;
396
9012b28a 397 lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
ece56191 398 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
876c9d3a
MT
399 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
400
9012b28a
HS
401done:
402 lbs_deb_enter(LBS_DEB_11D);
876c9d3a
MT
403 return 0;
404}
405
406/**
407 * @brief This function calculates the scan type for channels
408 * @param chan chan number
409 * @param parsed_region_chan pointer to parsed_region_chan_11d
410 * @return PASSIVE if chan is unknown; ACTIVE if chan is known
411*/
10078321 412u8 lbs_get_scan_type_11d(u8 chan,
876c9d3a
MT
413 struct parsed_region_chan_11d * parsed_region_chan)
414{
0aef64d7 415 u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
876c9d3a 416
9012b28a 417 lbs_deb_enter(LBS_DEB_11D);
876c9d3a 418
10078321 419 if (lbs_channel_known_11d(chan, parsed_region_chan)) {
ece56191 420 lbs_deb_11d("found, do active scan\n");
0aef64d7 421 scan_type = CMD_SCAN_TYPE_ACTIVE;
876c9d3a 422 } else {
ece56191 423 lbs_deb_11d("not found, do passive scan\n");
876c9d3a
MT
424 }
425
9012b28a 426 lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
876c9d3a
MT
427 return scan_type;
428
429}
430
69f9032d 431void lbs_init_11d(struct lbs_private *priv)
876c9d3a 432{
aa21c004
DW
433 priv->enable11d = 0;
434 memset(&(priv->parsed_region_chan), 0,
876c9d3a
MT
435 sizeof(struct parsed_region_chan_11d));
436 return;
437}
438
876c9d3a
MT
439/**
440 * @brief This function sets DOMAIN INFO to FW
69f9032d 441 * @param priv pointer to struct lbs_private
876c9d3a
MT
442 * @return 0; -1
443*/
69f9032d 444static int set_domain_info_11d(struct lbs_private *priv)
876c9d3a
MT
445{
446 int ret;
447
aa21c004 448 if (!priv->enable11d) {
ece56191 449 lbs_deb_11d("dnld domain Info with 11d disabled\n");
876c9d3a
MT
450 return 0;
451 }
452
10078321 453 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
0aef64d7
DW
454 CMD_ACT_SET,
455 CMD_OPTION_WAITFORRSP, 0, NULL);
876c9d3a 456 if (ret)
ece56191 457 lbs_deb_11d("fail to dnld domain info\n");
876c9d3a
MT
458
459 return ret;
460}
461
462/**
463 * @brief This function setups scan channels
69f9032d 464 * @param priv pointer to struct lbs_private
876c9d3a
MT
465 * @param band band
466 * @return 0
467*/
69f9032d 468int lbs_set_universaltable(struct lbs_private *priv, u8 band)
876c9d3a 469{
876c9d3a
MT
470 u16 size = sizeof(struct chan_freq_power);
471 u16 i = 0;
472
aa21c004
DW
473 memset(priv->universal_channel, 0,
474 sizeof(priv->universal_channel));
876c9d3a 475
aa21c004 476 priv->universal_channel[i].nrcfp =
876c9d3a 477 sizeof(channel_freq_power_UN_BG) / size;
ece56191 478 lbs_deb_11d("BG-band nrcfp %d\n",
aa21c004 479 priv->universal_channel[i].nrcfp);
876c9d3a 480
aa21c004
DW
481 priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
482 priv->universal_channel[i].valid = 1;
483 priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
484 priv->universal_channel[i].band = band;
876c9d3a
MT
485 i++;
486
487 return 0;
488}
489
490/**
491 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
69f9032d 492 * @param priv pointer to struct lbs_private
876c9d3a
MT
493 * @param cmd pointer to cmd buffer
494 * @param cmdno cmd ID
495 * @param cmdOption cmd action
496 * @return 0
497*/
69f9032d 498int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
876c9d3a
MT
499 struct cmd_ds_command *cmd, u16 cmdno,
500 u16 cmdoption)
501{
502 struct cmd_ds_802_11d_domain_info *pdomaininfo =
503 &cmd->params.domaininfo;
75b6a61a 504 struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
aa21c004 505 u8 nr_subband = priv->domainreg.nr_subband;
876c9d3a 506
9012b28a 507 lbs_deb_enter(LBS_DEB_11D);
876c9d3a 508
9012b28a 509 lbs_deb_11d("nr_subband=%x\n", nr_subband);
876c9d3a
MT
510
511 cmd->command = cpu_to_le16(cmdno);
512 pdomaininfo->action = cpu_to_le16(cmdoption);
0aef64d7 513 if (cmdoption == CMD_ACT_GET) {
876c9d3a
MT
514 cmd->size =
515 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
ece56191 516 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
c2df2efe 517 le16_to_cpu(cmd->size));
9012b28a 518 goto done;
876c9d3a
MT
519 }
520
521 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
aa21c004 522 memcpy(domain->countrycode, priv->domainreg.countrycode,
876c9d3a
MT
523 sizeof(domain->countrycode));
524
525 domain->header.len =
75b6a61a 526 cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
876c9d3a
MT
527 sizeof(domain->countrycode));
528
529 if (nr_subband) {
aa21c004 530 memcpy(domain->subband, priv->domainreg.subband,
75b6a61a 531 nr_subband * sizeof(struct ieee_subbandset));
876c9d3a
MT
532
533 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
8362cd41 534 le16_to_cpu(domain->header.len) +
75b6a61a 535 sizeof(struct mrvl_ie_header) +
876c9d3a
MT
536 S_DS_GEN);
537 } else {
538 cmd->size =
539 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
540 }
541
ece56191 542 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
876c9d3a 543
9012b28a
HS
544done:
545 lbs_deb_enter(LBS_DEB_11D);
876c9d3a
MT
546 return 0;
547}
548
876c9d3a
MT
549/**
550 * @brief This function parses countryinfo from AP and download country info to FW
69f9032d 551 * @param priv pointer to struct lbs_private
876c9d3a
MT
552 * @param resp pointer to command response buffer
553 * @return 0; -1
554 */
e98a88dd 555int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
876c9d3a 556{
981f187b 557 struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
75b6a61a 558 struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
876c9d3a
MT
559 u16 action = le16_to_cpu(domaininfo->action);
560 s16 ret = 0;
561 u8 nr_subband = 0;
562
9012b28a 563 lbs_deb_enter(LBS_DEB_11D);
876c9d3a 564
ece56191 565 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
876c9d3a
MT
566 (int)le16_to_cpu(resp->size));
567
981f187b 568 nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
75b6a61a 569 sizeof(struct ieee_subbandset);
876c9d3a 570
ece56191 571 lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
876c9d3a
MT
572
573 if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
9012b28a 574 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
876c9d3a
MT
575 return -1;
576 }
577
578 switch (action) {
0aef64d7 579 case CMD_ACT_SET: /*Proc Set action */
876c9d3a
MT
580 break;
581
0aef64d7 582 case CMD_ACT_GET:
876c9d3a
MT
583 break;
584 default:
9012b28a 585 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
876c9d3a
MT
586 ret = -1;
587 break;
588 }
589
9012b28a 590 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
876c9d3a
MT
591 return ret;
592}
593
594/**
595 * @brief This function parses countryinfo from AP and download country info to FW
69f9032d 596 * @param priv pointer to struct lbs_private
876c9d3a
MT
597 * @return 0; -1
598 */
69f9032d 599int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
e76850d6 600 struct bss_descriptor * bss)
876c9d3a
MT
601{
602 int ret;
876c9d3a 603
9012b28a 604 lbs_deb_enter(LBS_DEB_11D);
aa21c004
DW
605 if (priv->enable11d) {
606 memset(&priv->parsed_region_chan, 0,
876c9d3a 607 sizeof(struct parsed_region_chan_11d));
e76850d6 608 ret = parse_domain_info_11d(&bss->countryinfo, 0,
aa21c004 609 &priv->parsed_region_chan);
876c9d3a
MT
610
611 if (ret == -1) {
ece56191 612 lbs_deb_11d("error parsing domain_info from AP\n");
9012b28a 613 goto done;
876c9d3a
MT
614 }
615
aa21c004 616 memset(&priv->domainreg, 0,
10078321 617 sizeof(struct lbs_802_11d_domain_reg));
aa21c004
DW
618 generate_domain_info_11d(&priv->parsed_region_chan,
619 &priv->domainreg);
876c9d3a
MT
620
621 ret = set_domain_info_11d(priv);
622
623 if (ret) {
ece56191 624 lbs_deb_11d("error setting domain info\n");
9012b28a 625 goto done;
876c9d3a
MT
626 }
627 }
9012b28a
HS
628 ret = 0;
629
630done:
631 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
632 return ret;
876c9d3a
MT
633}
634
635/**
636 * @brief This function generates 11D info from user specified regioncode and download to FW
69f9032d 637 * @param priv pointer to struct lbs_private
876c9d3a
MT
638 * @return 0; -1
639 */
69f9032d 640int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
876c9d3a
MT
641{
642 int ret;
876c9d3a
MT
643 struct region_channel *region_chan;
644 u8 j;
645
9012b28a 646 lbs_deb_enter(LBS_DEB_11D);
aa21c004 647 lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
876c9d3a 648
aa21c004 649 if (priv->enable11d) {
876c9d3a
MT
650 /* update parsed_region_chan_11; dnld domaininf to FW */
651
aa21c004
DW
652 for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
653 region_chan = &priv->region_channel[j];
876c9d3a 654
ece56191 655 lbs_deb_11d("%d region_chan->band %d\n", j,
876c9d3a
MT
656 region_chan->band);
657
658 if (!region_chan || !region_chan->valid
659 || !region_chan->CFP)
660 continue;
aa21c004 661 if (region_chan->band != priv->curbssparams.band)
876c9d3a
MT
662 continue;
663 break;
664 }
665
aa21c004 666 if (j >= ARRAY_SIZE(priv->region_channel)) {
ece56191 667 lbs_deb_11d("region_chan not found, band %d\n",
aa21c004 668 priv->curbssparams.band);
9012b28a
HS
669 ret = -1;
670 goto done;
876c9d3a
MT
671 }
672
aa21c004 673 memset(&priv->parsed_region_chan, 0,
876c9d3a 674 sizeof(struct parsed_region_chan_11d));
10078321 675 lbs_generate_parsed_region_chan_11d(region_chan,
aa21c004 676 &priv->
876c9d3a
MT
677 parsed_region_chan);
678
aa21c004 679 memset(&priv->domainreg, 0,
10078321 680 sizeof(struct lbs_802_11d_domain_reg));
aa21c004
DW
681 generate_domain_info_11d(&priv->parsed_region_chan,
682 &priv->domainreg);
876c9d3a
MT
683
684 ret = set_domain_info_11d(priv);
685
686 if (ret) {
ece56191 687 lbs_deb_11d("error setting domain info\n");
9012b28a 688 goto done;
876c9d3a
MT
689 }
690
691 }
9012b28a 692 ret = 0;
876c9d3a 693
9012b28a
HS
694done:
695 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
696 return ret;
876c9d3a 697}