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