Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[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 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
65 static 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 */
85 static 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_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 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_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 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
161 static 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_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 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_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                wlan_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 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         int ret = 0;
281
282         lbs_deb_enter(LBS_DEB_11D);
283
284         cfp = libertas_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             wlan_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 (!wlan_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 (wlan_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 libertas_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 (wlan_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 libertas_init_11d(wlan_private * priv)
442 {
443         priv->adapter->enable11d = 0;
444         memset(&(priv->adapter->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 wlan_private
452  *  @return           0; -1
453 */
454 static int set_domain_info_11d(wlan_private * priv)
455 {
456         int ret;
457
458         if (!priv->adapter->enable11d) {
459                 lbs_deb_11d("dnld domain Info with 11d disabled\n");
460                 return 0;
461         }
462
463         ret = libertas_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 wlan_private
475  *  @param band       band
476  *  @return           0
477 */
478 int libertas_set_universaltable(wlan_private * priv, u8 band)
479 {
480         wlan_adapter *adapter = priv->adapter;
481         u16 size = sizeof(struct chan_freq_power);
482         u16 i = 0;
483
484         memset(adapter->universal_channel, 0,
485                sizeof(adapter->universal_channel));
486
487         adapter->universal_channel[i].nrcfp =
488             sizeof(channel_freq_power_UN_BG) / size;
489         lbs_deb_11d("BG-band nrcfp %d\n",
490                adapter->universal_channel[i].nrcfp);
491
492         adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
493         adapter->universal_channel[i].valid = 1;
494         adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
495         adapter->universal_channel[i].band = band;
496         i++;
497
498         return 0;
499 }
500
501 /**
502  *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
503  *  @param priv       pointer to wlan_private
504  *  @param cmd        pointer to cmd buffer
505  *  @param cmdno      cmd ID
506  *  @param cmdOption  cmd action
507  *  @return           0
508 */
509 int libertas_cmd_802_11d_domain_info(wlan_private * priv,
510                                  struct cmd_ds_command *cmd, u16 cmdno,
511                                  u16 cmdoption)
512 {
513         struct cmd_ds_802_11d_domain_info *pdomaininfo =
514             &cmd->params.domaininfo;
515         struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
516         wlan_adapter *adapter = priv->adapter;
517         u8 nr_subband = adapter->domainreg.nr_subband;
518
519         lbs_deb_enter(LBS_DEB_11D);
520
521         lbs_deb_11d("nr_subband=%x\n", nr_subband);
522
523         cmd->command = cpu_to_le16(cmdno);
524         pdomaininfo->action = cpu_to_le16(cmdoption);
525         if (cmdoption == CMD_ACT_GET) {
526                 cmd->size =
527                     cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
528                 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
529                         (int)(cmd->size));
530                 goto done;
531         }
532
533         domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
534         memcpy(domain->countrycode, adapter->domainreg.countrycode,
535                sizeof(domain->countrycode));
536
537         domain->header.len =
538             cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
539                              sizeof(domain->countrycode));
540
541         if (nr_subband) {
542                 memcpy(domain->subband, adapter->domainreg.subband,
543                        nr_subband * sizeof(struct ieeetypes_subbandset));
544
545                 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
546                                              le16_to_cpu(domain->header.len) +
547                                              sizeof(struct mrvlietypesheader) +
548                                              S_DS_GEN);
549         } else {
550                 cmd->size =
551                     cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
552         }
553
554         lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
555
556 done:
557         lbs_deb_enter(LBS_DEB_11D);
558         return 0;
559 }
560
561 /**
562  *  @brief This function parses countryinfo from AP and download country info to FW
563  *  @param priv    pointer to wlan_private
564  *  @param resp    pointer to command response buffer
565  *  @return        0; -1
566  */
567 int libertas_ret_802_11d_domain_info(wlan_private * priv,
568                                  struct cmd_ds_command *resp)
569 {
570         struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
571         struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
572         u16 action = le16_to_cpu(domaininfo->action);
573         s16 ret = 0;
574         u8 nr_subband = 0;
575
576         lbs_deb_enter(LBS_DEB_11D);
577
578         lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
579                 (int)le16_to_cpu(resp->size));
580
581         nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
582                       sizeof(struct ieeetypes_subbandset);
583
584         lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
585
586         if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
587                 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
588                 return -1;
589         }
590
591         switch (action) {
592         case CMD_ACT_SET:       /*Proc Set action */
593                 break;
594
595         case CMD_ACT_GET:
596                 break;
597         default:
598                 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
599                 ret = -1;
600                 break;
601         }
602
603         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
604         return ret;
605 }
606
607 /**
608  *  @brief This function parses countryinfo from AP and download country info to FW
609  *  @param priv    pointer to wlan_private
610  *  @return        0; -1
611  */
612 int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
613                                         struct bss_descriptor * bss)
614 {
615         int ret;
616         wlan_adapter *adapter = priv->adapter;
617
618         lbs_deb_enter(LBS_DEB_11D);
619         if (priv->adapter->enable11d) {
620                 memset(&adapter->parsed_region_chan, 0,
621                        sizeof(struct parsed_region_chan_11d));
622                 ret = parse_domain_info_11d(&bss->countryinfo, 0,
623                                                &adapter->parsed_region_chan);
624
625                 if (ret == -1) {
626                         lbs_deb_11d("error parsing domain_info from AP\n");
627                         goto done;
628                 }
629
630                 memset(&adapter->domainreg, 0,
631                        sizeof(struct wlan_802_11d_domain_reg));
632                 generate_domain_info_11d(&adapter->parsed_region_chan,
633                                       &adapter->domainreg);
634
635                 ret = set_domain_info_11d(priv);
636
637                 if (ret) {
638                         lbs_deb_11d("error setting domain info\n");
639                         goto done;
640                 }
641         }
642         ret = 0;
643
644 done:
645         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
646         return ret;
647 }
648
649 /**
650  *  @brief This function generates 11D info from user specified regioncode and download to FW
651  *  @param priv    pointer to wlan_private
652  *  @return        0; -1
653  */
654 int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
655 {
656         int ret;
657         wlan_adapter *adapter = priv->adapter;
658         struct region_channel *region_chan;
659         u8 j;
660
661         lbs_deb_enter(LBS_DEB_11D);
662         lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
663
664         if (priv->adapter->enable11d) {
665                 /* update parsed_region_chan_11; dnld domaininf to FW */
666
667                 for (j = 0; j < sizeof(adapter->region_channel) /
668                      sizeof(adapter->region_channel[0]); j++) {
669                         region_chan = &adapter->region_channel[j];
670
671                         lbs_deb_11d("%d region_chan->band %d\n", j,
672                                region_chan->band);
673
674                         if (!region_chan || !region_chan->valid
675                             || !region_chan->CFP)
676                                 continue;
677                         if (region_chan->band != adapter->curbssparams.band)
678                                 continue;
679                         break;
680                 }
681
682                 if (j >= sizeof(adapter->region_channel) /
683                     sizeof(adapter->region_channel[0])) {
684                         lbs_deb_11d("region_chan not found, band %d\n",
685                                adapter->curbssparams.band);
686                         ret = -1;
687                         goto done;
688                 }
689
690                 memset(&adapter->parsed_region_chan, 0,
691                        sizeof(struct parsed_region_chan_11d));
692                 wlan_generate_parsed_region_chan_11d(region_chan,
693                                                      &adapter->
694                                                      parsed_region_chan);
695
696                 memset(&adapter->domainreg, 0,
697                        sizeof(struct wlan_802_11d_domain_reg));
698                 generate_domain_info_11d(&adapter->parsed_region_chan,
699                                          &adapter->domainreg);
700
701                 ret = set_domain_info_11d(priv);
702
703                 if (ret) {
704                         lbs_deb_11d("error setting domain info\n");
705                         goto done;
706                 }
707
708         }
709         ret = 0;
710
711 done:
712         lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
713         return ret;
714 }