Remove some left-over debugging options making the kerkenl exceed 768KB, resulting...
[openwrt.git] / package / libertas / src / 11d.c
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
16 static 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 */
29 static 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
46 static u8 lbs_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
65 static u8 *lbs_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 */
85 static u8 lbs_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_deb_11d("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 */
120 static u8 lbs_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_deb_hex(LBS_DEB_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_deb_11d("found chan %d\n", chan);
133                         return 1;
134                 }
135         }
136
137         lbs_deb_11d("chan %d not found\n", chan);
138         return 0;
139 }
140
141 u32 lbs_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
161 static int generate_domain_info_11d(struct parsed_region_chan_11d
162                                   *parsed_region_chan,
163                                   struct lbs_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_deb_11d("nrchan %d\n", nr_chan);
178         lbs_deb_hex(LBS_DEB_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_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
216         lbs_deb_hex(LBS_DEB_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 */
228 static void lbs_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_deb_11d("region_chan is NULL\n");
237                 return;
238         }
239
240         cfp = region_chan->CFP;
241         if (cfp == NULL) {
242                 lbs_deb_11d("cfp is 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                lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
250
251         lbs_deb_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_deb_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_deb_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 */
275 static u8 lbs_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         int ret = 0;
281
282         lbs_deb_enter(LBS_DEB_11D);
283
284         cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
285         if (cfp == NULL)
286                 return 0;
287
288         for (idx = 0; idx < cfp_no; idx++) {
289                 if (chan == (cfp + idx)->channel) {
290                         /* If Mrvl Chip Supported? */
291                         if ((cfp + idx)->unsupported) {
292                                 ret = 0;
293                         } else {
294                                 ret = 1;
295                         }
296                         goto done;
297                 }
298         }
299
300         /*chan is not in the region table */
301
302 done:
303         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
304         return ret;
305 }
306
307 /**
308  *  @brief This function checks if chan txpwr is learned from AP/IBSS
309  *  @param chan                 chan number
310  *  @param parsed_region_chan   pointer to parsed_region_chan_11d
311  *  @return                     0
312 */
313 static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
314                                  countryinfo,
315                                  u8 band,
316                                  struct parsed_region_chan_11d *
317                                  parsed_region_chan)
318 {
319         u8 nr_subband, nrchan;
320         u8 lastchan, firstchan;
321         u8 region;
322         u8 curchan = 0;
323
324         u8 idx = 0;             /*chan index in parsed_region_chan */
325
326         u8 j, i;
327
328         lbs_deb_enter(LBS_DEB_11D);
329
330         /*validation Rules:
331            1. valid region Code
332            2. First Chan increment
333            3. channel range no overlap
334            4. channel is valid?
335            5. channel is supported by region?
336            6. Others
337          */
338
339         lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
340
341         if ((*(countryinfo->countrycode)) == 0
342             || (countryinfo->len <= COUNTRY_CODE_LEN)) {
343                 /* No region Info or Wrong region info: treat as No 11D info */
344                 goto done;
345         }
346
347         /*Step1: check region_code */
348         parsed_region_chan->region = region =
349             lbs_region_2_code(countryinfo->countrycode);
350
351         lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
352         lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
353                 COUNTRY_CODE_LEN);
354
355         parsed_region_chan->band = band;
356
357         memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
358                COUNTRY_CODE_LEN);
359
360         nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
361             sizeof(struct ieeetypes_subbandset);
362
363         for (j = 0, lastchan = 0; j < nr_subband; j++) {
364
365                 if (countryinfo->subband[j].firstchan <= lastchan) {
366                         /*Step2&3. Check First Chan Num increment and no overlap */
367                         lbs_deb_11d("chan %d>%d, overlap\n",
368                                countryinfo->subband[j].firstchan, lastchan);
369                         continue;
370                 }
371
372                 firstchan = countryinfo->subband[j].firstchan;
373                 nrchan = countryinfo->subband[j].nrchan;
374
375                 for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
376                         /*step4: channel is supported? */
377
378                         if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) {
379                                 /* Chan is not found in UN table */
380                                 lbs_deb_11d("chan is not supported: %d \n", i);
381                                 break;
382                         }
383
384                         lastchan = curchan;
385
386                         if (lbs_region_chan_supported_11d
387                             (region, band, curchan)) {
388                                 /*step5: Check if curchan is supported by mrvl in region */
389                                 parsed_region_chan->chanpwr[idx].chan = curchan;
390                                 parsed_region_chan->chanpwr[idx].pwr =
391                                     countryinfo->subband[j].maxtxpwr;
392                                 idx++;
393                         } else {
394                                 /*not supported and ignore the chan */
395                                 lbs_deb_11d(
396                                        "i %d, chan %d unsupported in region %x, band %d\n",
397                                        i, curchan, region, band);
398                         }
399                 }
400
401                 /*Step6: Add other checking if any */
402
403         }
404
405         parsed_region_chan->nr_chan = idx;
406
407         lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
408         lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
409                 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
410
411 done:
412         lbs_deb_enter(LBS_DEB_11D);
413         return 0;
414 }
415
416 /**
417  *  @brief This function calculates the scan type for channels
418  *  @param chan                 chan number
419  *  @param parsed_region_chan   pointer to parsed_region_chan_11d
420  *  @return                     PASSIVE if chan is unknown; ACTIVE if chan is known
421 */
422 u8 lbs_get_scan_type_11d(u8 chan,
423                           struct parsed_region_chan_11d * parsed_region_chan)
424 {
425         u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
426
427         lbs_deb_enter(LBS_DEB_11D);
428
429         if (lbs_channel_known_11d(chan, parsed_region_chan)) {
430                 lbs_deb_11d("found, do active scan\n");
431                 scan_type = CMD_SCAN_TYPE_ACTIVE;
432         } else {
433                 lbs_deb_11d("not found, do passive scan\n");
434         }
435
436         lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
437         return scan_type;
438
439 }
440
441 void lbs_init_11d(struct lbs_private *priv)
442 {
443         priv->enable11d = 0;
444         memset(&(priv->parsed_region_chan), 0,
445                sizeof(struct parsed_region_chan_11d));
446         return;
447 }
448
449 /**
450  *  @brief This function sets DOMAIN INFO to FW
451  *  @param priv       pointer to struct lbs_private
452  *  @return           0; -1
453 */
454 static int set_domain_info_11d(struct lbs_private *priv)
455 {
456         int ret;
457
458         if (!priv->enable11d) {
459                 lbs_deb_11d("dnld domain Info with 11d disabled\n");
460                 return 0;
461         }
462
463         ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
464                                     CMD_ACT_SET,
465                                     CMD_OPTION_WAITFORRSP, 0, NULL);
466         if (ret)
467                 lbs_deb_11d("fail to dnld domain info\n");
468
469         return ret;
470 }
471
472 /**
473  *  @brief This function setups scan channels
474  *  @param priv       pointer to struct lbs_private
475  *  @param band       band
476  *  @return           0
477 */
478 int lbs_set_universaltable(struct lbs_private *priv, u8 band)
479 {
480         u16 size = sizeof(struct chan_freq_power);
481         u16 i = 0;
482
483         memset(priv->universal_channel, 0,
484                sizeof(priv->universal_channel));
485
486         priv->universal_channel[i].nrcfp =
487             sizeof(channel_freq_power_UN_BG) / size;
488         lbs_deb_11d("BG-band nrcfp %d\n",
489                priv->universal_channel[i].nrcfp);
490
491         priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
492         priv->universal_channel[i].valid = 1;
493         priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
494         priv->universal_channel[i].band = band;
495         i++;
496
497         return 0;
498 }
499
500 /**
501  *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
502  *  @param priv       pointer to struct lbs_private
503  *  @param cmd        pointer to cmd buffer
504  *  @param cmdno      cmd ID
505  *  @param cmdOption  cmd action
506  *  @return           0
507 */
508 int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
509                                  struct cmd_ds_command *cmd, u16 cmdno,
510                                  u16 cmdoption)
511 {
512         struct cmd_ds_802_11d_domain_info *pdomaininfo =
513             &cmd->params.domaininfo;
514         struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
515         u8 nr_subband = priv->domainreg.nr_subband;
516
517         lbs_deb_enter(LBS_DEB_11D);
518
519         lbs_deb_11d("nr_subband=%x\n", nr_subband);
520
521         cmd->command = cpu_to_le16(cmdno);
522         pdomaininfo->action = cpu_to_le16(cmdoption);
523         if (cmdoption == CMD_ACT_GET) {
524                 cmd->size =
525                     cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
526                 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
527                         le16_to_cpu(cmd->size));
528                 goto done;
529         }
530
531         domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
532         memcpy(domain->countrycode, priv->domainreg.countrycode,
533                sizeof(domain->countrycode));
534
535         domain->header.len =
536             cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
537                              sizeof(domain->countrycode));
538
539         if (nr_subband) {
540                 memcpy(domain->subband, priv->domainreg.subband,
541                        nr_subband * sizeof(struct ieeetypes_subbandset));
542
543                 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
544                                              le16_to_cpu(domain->header.len) +
545                                              sizeof(struct mrvlietypesheader) +
546                                              S_DS_GEN);
547         } else {
548                 cmd->size =
549                     cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
550         }
551
552         lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
553
554 done:
555         lbs_deb_enter(LBS_DEB_11D);
556         return 0;
557 }
558
559 /**
560  *  @brief This function parses countryinfo from AP and download country info to FW
561  *  @param priv    pointer to struct lbs_private
562  *  @param resp    pointer to command response buffer
563  *  @return        0; -1
564  */
565 int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
566                                  struct cmd_ds_command *resp)
567 {
568         struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
569         struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
570         u16 action = le16_to_cpu(domaininfo->action);
571         s16 ret = 0;
572         u8 nr_subband = 0;
573
574         lbs_deb_enter(LBS_DEB_11D);
575
576         lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
577                 (int)le16_to_cpu(resp->size));
578
579         nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
580                       sizeof(struct ieeetypes_subbandset);
581
582         lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
583
584         if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
585                 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
586                 return -1;
587         }
588
589         switch (action) {
590         case CMD_ACT_SET:       /*Proc Set action */
591                 break;
592
593         case CMD_ACT_GET:
594                 break;
595         default:
596                 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
597                 ret = -1;
598                 break;
599         }
600
601         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
602         return ret;
603 }
604
605 /**
606  *  @brief This function parses countryinfo from AP and download country info to FW
607  *  @param priv    pointer to struct lbs_private
608  *  @return        0; -1
609  */
610 int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
611                                         struct bss_descriptor * bss)
612 {
613         int ret;
614
615         lbs_deb_enter(LBS_DEB_11D);
616         if (priv->enable11d) {
617                 memset(&priv->parsed_region_chan, 0,
618                        sizeof(struct parsed_region_chan_11d));
619                 ret = parse_domain_info_11d(&bss->countryinfo, 0,
620                                                &priv->parsed_region_chan);
621
622                 if (ret == -1) {
623                         lbs_deb_11d("error parsing domain_info from AP\n");
624                         goto done;
625                 }
626
627                 memset(&priv->domainreg, 0,
628                        sizeof(struct lbs_802_11d_domain_reg));
629                 generate_domain_info_11d(&priv->parsed_region_chan,
630                                       &priv->domainreg);
631
632                 ret = set_domain_info_11d(priv);
633
634                 if (ret) {
635                         lbs_deb_11d("error setting domain info\n");
636                         goto done;
637                 }
638         }
639         ret = 0;
640
641 done:
642         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
643         return ret;
644 }
645
646 /**
647  *  @brief This function generates 11D info from user specified regioncode and download to FW
648  *  @param priv    pointer to struct lbs_private
649  *  @return        0; -1
650  */
651 int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
652 {
653         int ret;
654         struct region_channel *region_chan;
655         u8 j;
656
657         lbs_deb_enter(LBS_DEB_11D);
658         lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
659
660         if (priv->enable11d) {
661                 /* update parsed_region_chan_11; dnld domaininf to FW */
662
663                 for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
664                         region_chan = &priv->region_channel[j];
665
666                         lbs_deb_11d("%d region_chan->band %d\n", j,
667                                region_chan->band);
668
669                         if (!region_chan || !region_chan->valid
670                             || !region_chan->CFP)
671                                 continue;
672                         if (region_chan->band != priv->curbssparams.band)
673                                 continue;
674                         break;
675                 }
676
677                 if (j >= ARRAY_SIZE(priv->region_channel)) {
678                         lbs_deb_11d("region_chan not found, band %d\n",
679                                priv->curbssparams.band);
680                         ret = -1;
681                         goto done;
682                 }
683
684                 memset(&priv->parsed_region_chan, 0,
685                        sizeof(struct parsed_region_chan_11d));
686                 lbs_generate_parsed_region_chan_11d(region_chan,
687                                                      &priv->
688                                                      parsed_region_chan);
689
690                 memset(&priv->domainreg, 0,
691                        sizeof(struct lbs_802_11d_domain_reg));
692                 generate_domain_info_11d(&priv->parsed_region_chan,
693                                          &priv->domainreg);
694
695                 ret = set_domain_info_11d(priv);
696
697                 if (ret) {
698                         lbs_deb_11d("error setting domain info\n");
699                         goto done;
700                 }
701
702         }
703         ret = 0;
704
705 done:
706         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
707         return ret;
708 }