blob: 8b366ef2fe953e024fcce99415ebc2313c51ef86 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
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
16static 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 */
29static 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
46static 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
65static 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*/
85static 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) {
Holger Schurig9012b282007-05-25 11:27:16 -040098 lbs_deb_11d("firstchan found\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020099 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*/
120static 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
Holger Schurigece56192007-08-02 11:53:06 -0400127 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200128 sizeof(struct chan_power_11d) * nr_chan);
129
130 for (i = 0; i < nr_chan; i++) {
131 if (chan == chanpwr[i].chan) {
Holger Schurigece56192007-08-02 11:53:06 -0400132 lbs_deb_11d("found chan %d\n", chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200133 return 1;
134 }
135 }
136
Holger Schurigece56192007-08-02 11:53:06 -0400137 lbs_deb_11d("chan %d not found\n", chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200138 return 0;
139}
140
141u32 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
161static 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
Holger Schurigece56192007-08-02 11:53:06 -0400177 lbs_deb_11d("nrchan %d\n", nr_chan);
178 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200179 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
Holger Schurig9012b282007-05-25 11:27:16 -0400215 lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
Holger Schurigece56192007-08-02 11:53:06 -0400216 lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200217 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*/
228static 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) {
Holger Schurigece56192007-08-02 11:53:06 -0400236 lbs_deb_11d("region_chan is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200237 return;
238 }
239
240 cfp = region_chan->CFP;
241 if (cfp == NULL) {
Holger Schurigece56192007-08-02 11:53:06 -0400242 lbs_deb_11d("cfp is NULL \n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200243 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
Holger Schurigece56192007-08-02 11:53:06 -0400251 lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200252 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;
Holger Schurigece56192007-08-02 11:53:06 -0400257 lbs_deb_11d("chan %d, pwr %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200258 parsed_region_chan->chanpwr[i].chan,
259 parsed_region_chan->chanpwr[i].pwr);
260 }
261 parsed_region_chan->nr_chan = region_chan->nrcfp;
262
Holger Schurigece56192007-08-02 11:53:06 -0400263 lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200264
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*/
275static 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;
Holger Schurig9012b282007-05-25 11:27:16 -0400280 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200281
Holger Schurig9012b282007-05-25 11:27:16 -0400282 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200283
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) {
Holger Schurig9012b282007-05-25 11:27:16 -0400292 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200293 } else {
Holger Schurig9012b282007-05-25 11:27:16 -0400294 ret = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200295 }
Holger Schurig9012b282007-05-25 11:27:16 -0400296 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297 }
298 }
299
300 /*chan is not in the region table */
Holger Schurig9012b282007-05-25 11:27:16 -0400301
302done:
303 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
304 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200305}
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*/
313static 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
Holger Schurig9012b282007-05-25 11:27:16 -0400328 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200329
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
Holger Schurigece56192007-08-02 11:53:06 -0400339 lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200340
341 if ((*(countryinfo->countrycode)) == 0
342 || (countryinfo->len <= COUNTRY_CODE_LEN)) {
343 /* No region Info or Wrong region info: treat as No 11D info */
Holger Schurig9012b282007-05-25 11:27:16 -0400344 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200345 }
346
347 /*Step1: check region_code */
348 parsed_region_chan->region = region =
349 wlan_region_2_code(countryinfo->countrycode);
350
Holger Schurig9012b282007-05-25 11:27:16 -0400351 lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
Holger Schurigece56192007-08-02 11:53:06 -0400352 lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200353 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 */
Holger Schurigece56192007-08-02 11:53:06 -0400367 lbs_deb_11d("chan %d>%d, overlap\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200368 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 */
Holger Schurig9012b282007-05-25 11:27:16 -0400380 lbs_deb_11d("chan is not supported: %d \n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200381 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 */
Holger Schurig9012b282007-05-25 11:27:16 -0400395 lbs_deb_11d(
Holger Schurigece56192007-08-02 11:53:06 -0400396 "i %d, chan %d unsupported in region %x, band %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200397 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
Holger Schurig9012b282007-05-25 11:27:16 -0400407 lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
Holger Schurigece56192007-08-02 11:53:06 -0400408 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200409 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
410
Holger Schurig9012b282007-05-25 11:27:16 -0400411done:
412 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200413 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*/
422u8 libertas_get_scan_type_11d(u8 chan,
423 struct parsed_region_chan_11d * parsed_region_chan)
424{
Dan Williams0aef64d2007-08-02 11:31:18 -0400425 u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426
Holger Schurig9012b282007-05-25 11:27:16 -0400427 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200428
429 if (wlan_channel_known_11d(chan, parsed_region_chan)) {
Holger Schurigece56192007-08-02 11:53:06 -0400430 lbs_deb_11d("found, do active scan\n");
Dan Williams0aef64d2007-08-02 11:31:18 -0400431 scan_type = CMD_SCAN_TYPE_ACTIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432 } else {
Holger Schurigece56192007-08-02 11:53:06 -0400433 lbs_deb_11d("not found, do passive scan\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200434 }
435
Holger Schurig9012b282007-05-25 11:27:16 -0400436 lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200437 return scan_type;
438
439}
440
441void 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
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449/**
450 * @brief This function sets DOMAIN INFO to FW
451 * @param priv pointer to wlan_private
452 * @return 0; -1
453*/
454static int set_domain_info_11d(wlan_private * priv)
455{
456 int ret;
457
458 if (!priv->adapter->enable11d) {
Holger Schurigece56192007-08-02 11:53:06 -0400459 lbs_deb_11d("dnld domain Info with 11d disabled\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200460 return 0;
461 }
462
Dan Williams0aef64d2007-08-02 11:31:18 -0400463 ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
464 CMD_ACT_SET,
465 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200466 if (ret)
Holger Schurigece56192007-08-02 11:53:06 -0400467 lbs_deb_11d("fail to dnld domain info\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468
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*/
478int 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;
Holger Schurigece56192007-08-02 11:53:06 -0400489 lbs_deb_11d("BG-band nrcfp %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200490 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*/
509int 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
Holger Schurig9012b282007-05-25 11:27:16 -0400519 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200520
Holger Schurig9012b282007-05-25 11:27:16 -0400521 lbs_deb_11d("nr_subband=%x\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200522
523 cmd->command = cpu_to_le16(cmdno);
524 pdomaininfo->action = cpu_to_le16(cmdoption);
Dan Williams0aef64d2007-08-02 11:31:18 -0400525 if (cmdoption == CMD_ACT_GET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200526 cmd->size =
527 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
Holger Schurigece56192007-08-02 11:53:06 -0400528 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200529 (int)(cmd->size));
Holger Schurig9012b282007-05-25 11:27:16 -0400530 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200531 }
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 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
Holger Schurigece56192007-08-02 11:53:06 -0400554 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200555
Holger Schurig9012b282007-05-25 11:27:16 -0400556done:
557 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200558 return 0;
559}
560
561/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200562 * @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 */
567int libertas_ret_802_11d_domain_info(wlan_private * priv,
568 struct cmd_ds_command *resp)
569{
David Woodhouse981f1872007-05-25 23:36:54 -0400570 struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200571 struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
572 u16 action = le16_to_cpu(domaininfo->action);
573 s16 ret = 0;
574 u8 nr_subband = 0;
575
Holger Schurig9012b282007-05-25 11:27:16 -0400576 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200577
Holger Schurigece56192007-08-02 11:53:06 -0400578 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200579 (int)le16_to_cpu(resp->size));
580
David Woodhouse981f1872007-05-25 23:36:54 -0400581 nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
582 sizeof(struct ieeetypes_subbandset);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200583
Holger Schurigece56192007-08-02 11:53:06 -0400584 lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200585
586 if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
Holger Schurig9012b282007-05-25 11:27:16 -0400587 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588 return -1;
589 }
590
591 switch (action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400592 case CMD_ACT_SET: /*Proc Set action */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200593 break;
594
Dan Williams0aef64d2007-08-02 11:31:18 -0400595 case CMD_ACT_GET:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200596 break;
597 default:
Holger Schurig9012b282007-05-25 11:27:16 -0400598 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200599 ret = -1;
600 break;
601 }
602
Holger Schurig9012b282007-05-25 11:27:16 -0400603 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 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 */
Dan Williamse76850d2007-05-25 17:09:41 -0400612int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
613 struct bss_descriptor * bss)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200614{
615 int ret;
616 wlan_adapter *adapter = priv->adapter;
617
Holger Schurig9012b282007-05-25 11:27:16 -0400618 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200619 if (priv->adapter->enable11d) {
620 memset(&adapter->parsed_region_chan, 0,
621 sizeof(struct parsed_region_chan_11d));
Dan Williamse76850d2007-05-25 17:09:41 -0400622 ret = parse_domain_info_11d(&bss->countryinfo, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200623 &adapter->parsed_region_chan);
624
625 if (ret == -1) {
Holger Schurigece56192007-08-02 11:53:06 -0400626 lbs_deb_11d("error parsing domain_info from AP\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400627 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200628 }
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) {
Holger Schurigece56192007-08-02 11:53:06 -0400638 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400639 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200640 }
641 }
Holger Schurig9012b282007-05-25 11:27:16 -0400642 ret = 0;
643
644done:
645 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
646 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200647}
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 */
654int 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
Holger Schurig9012b282007-05-25 11:27:16 -0400661 lbs_deb_enter(LBS_DEB_11D);
Holger Schurigece56192007-08-02 11:53:06 -0400662 lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200663
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
Holger Schurigece56192007-08-02 11:53:06 -0400671 lbs_deb_11d("%d region_chan->band %d\n", j,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200672 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])) {
Holger Schurigece56192007-08-02 11:53:06 -0400684 lbs_deb_11d("region_chan not found, band %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200685 adapter->curbssparams.band);
Holger Schurig9012b282007-05-25 11:27:16 -0400686 ret = -1;
687 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200688 }
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) {
Holger Schurigece56192007-08-02 11:53:06 -0400704 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400705 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200706 }
707
708 }
Holger Schurig9012b282007-05-25 11:27:16 -0400709 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200710
Holger Schurig9012b282007-05-25 11:27:16 -0400711done:
712 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
713 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200714}