diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/libertas/11d.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/libertas/11d.c')
-rw-r--r-- | drivers/net/wireless/libertas/11d.c | 696 |
1 files changed, 0 insertions, 696 deletions
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c deleted file mode 100644 index 5c6968101f0d..000000000000 --- a/drivers/net/wireless/libertas/11d.c +++ /dev/null | |||
@@ -1,696 +0,0 @@ | |||
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 | } | ||