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