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