blob: 9a5408e7d94a1a3949fc35a5a12b0e206631d28d [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
Holger Schurig10078322007-11-15 18:05:47 -050046static u8 lbs_region_2_code(u8 *region)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020047{
48 u8 i;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020049
50 for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
51 region[i] = toupper(region[i]);
52
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +020053 for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020054 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
Holger Schurig10078322007-11-15 18:05:47 -050063static u8 *lbs_code_2_region(u8 code)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020064{
65 u8 i;
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +020066
67 for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020068 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*/
Holger Schurige98a88d2008-03-19 14:25:58 +010082static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020083/*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;
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +020090 cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020091
92 for (i = 0; i < cfp_no; i++) {
93 if ((cfp + i)->channel == firstchan) {
Holger Schurig9012b282007-05-25 11:27:16 -040094 lbs_deb_11d("firstchan found\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020095 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*/
Holger Schurig10078322007-11-15 18:05:47 -0500116static u8 lbs_channel_known_11d(u8 chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200117 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
Holger Schurigece56192007-08-02 11:53:06 -0400123 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200124 sizeof(struct chan_power_11d) * nr_chan);
125
126 for (i = 0; i < nr_chan; i++) {
127 if (chan == chanpwr[i].chan) {
Holger Schurigece56192007-08-02 11:53:06 -0400128 lbs_deb_11d("found chan %d\n", chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200129 return 1;
130 }
131 }
132
Holger Schurigece56192007-08-02 11:53:06 -0400133 lbs_deb_11d("chan %d not found\n", chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200134 return 0;
135}
136
Holger Schurige98a88d2008-03-19 14:25:58 +0100137u32 lbs_chan_2_freq(u8 chan)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200138{
139 struct chan_freq_power *cf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200140 u16 i;
141 u32 freq = 0;
142
143 cf = channel_freq_power_UN_BG;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200144
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +0200145 for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200146 if (chan == cf[i].channel)
147 freq = cf[i].freq;
148 }
149
150 return freq;
151}
152
153static int generate_domain_info_11d(struct parsed_region_chan_11d
154 *parsed_region_chan,
Holger Schurig10078322007-11-15 18:05:47 -0500155 struct lbs_802_11d_domain_reg *domaininfo)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156{
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
Holger Schurigece56192007-08-02 11:53:06 -0400169 lbs_deb_11d("nrchan %d\n", nr_chan);
170 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200171 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
Holger Schurig9012b282007-05-25 11:27:16 -0400207 lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
Holger Schurigece56192007-08-02 11:53:06 -0400208 lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200209 COUNTRY_CODE_LEN + 1 +
Dan Williams75b6a612009-05-22 20:03:09 -0400210 sizeof(struct ieee_subbandset) * nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200211 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*/
Holger Schurig10078322007-11-15 18:05:47 -0500220static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200221 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) {
Holger Schurigece56192007-08-02 11:53:06 -0400228 lbs_deb_11d("region_chan is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200229 return;
230 }
231
232 cfp = region_chan->CFP;
233 if (cfp == NULL) {
Holger Schurigece56192007-08-02 11:53:06 -0400234 lbs_deb_11d("cfp is NULL \n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200235 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,
Holger Schurig10078322007-11-15 18:05:47 -0500241 lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200242
Holger Schurigece56192007-08-02 11:53:06 -0400243 lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200244 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;
Holger Schurigece56192007-08-02 11:53:06 -0400249 lbs_deb_11d("chan %d, pwr %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200250 parsed_region_chan->chanpwr[i].chan,
251 parsed_region_chan->chanpwr[i].pwr);
252 }
253 parsed_region_chan->nr_chan = region_chan->nrcfp;
254
Holger Schurigece56192007-08-02 11:53:06 -0400255 lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200256
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*/
Holger Schurige98a88d2008-03-19 14:25:58 +0100267static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200268{
269 struct chan_freq_power *cfp;
270 int cfp_no;
271 u8 idx;
Holger Schurig9012b282007-05-25 11:27:16 -0400272 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200273
Holger Schurig9012b282007-05-25 11:27:16 -0400274 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200275
Holger Schurige98a88d2008-03-19 14:25:58 +0100276 cfp = lbs_get_region_cfp_table(region, &cfp_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200277 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) {
Holger Schurig9012b282007-05-25 11:27:16 -0400284 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200285 } else {
Holger Schurig9012b282007-05-25 11:27:16 -0400286 ret = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200287 }
Holger Schurig9012b282007-05-25 11:27:16 -0400288 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200289 }
290 }
291
292 /*chan is not in the region table */
Holger Schurig9012b282007-05-25 11:27:16 -0400293
294done:
295 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
296 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297}
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*/
Dan Williams75b6a612009-05-22 20:03:09 -0400305static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200306 u8 band,
Dan Williams75b6a612009-05-22 20:03:09 -0400307 struct parsed_region_chan_11d *parsed_region_chan)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200308{
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
Holger Schurig9012b282007-05-25 11:27:16 -0400318 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200319
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
Holger Schurigece56192007-08-02 11:53:06 -0400329 lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200330
331 if ((*(countryinfo->countrycode)) == 0
Dan Williams75b6a612009-05-22 20:03:09 -0400332 || (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200333 /* No region Info or Wrong region info: treat as No 11D info */
Holger Schurig9012b282007-05-25 11:27:16 -0400334 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200335 }
336
337 /*Step1: check region_code */
338 parsed_region_chan->region = region =
Holger Schurig10078322007-11-15 18:05:47 -0500339 lbs_region_2_code(countryinfo->countrycode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200340
Holger Schurig9012b282007-05-25 11:27:16 -0400341 lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
Holger Schurigece56192007-08-02 11:53:06 -0400342 lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200343 COUNTRY_CODE_LEN);
344
345 parsed_region_chan->band = band;
346
347 memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
348 COUNTRY_CODE_LEN);
349
Dan Williams75b6a612009-05-22 20:03:09 -0400350 nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
351 sizeof(struct ieee_subbandset);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200352
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 */
Holger Schurigece56192007-08-02 11:53:06 -0400357 lbs_deb_11d("chan %d>%d, overlap\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200358 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
Holger Schurige98a88d2008-03-19 14:25:58 +0100368 if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200369 /* Chan is not found in UN table */
Holger Schurig9012b282007-05-25 11:27:16 -0400370 lbs_deb_11d("chan is not supported: %d \n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200371 break;
372 }
373
374 lastchan = curchan;
375
Holger Schurige98a88d2008-03-19 14:25:58 +0100376 if (lbs_region_chan_supported_11d(region, curchan)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200377 /*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 */
Holger Schurig9012b282007-05-25 11:27:16 -0400384 lbs_deb_11d(
Holger Schurigece56192007-08-02 11:53:06 -0400385 "i %d, chan %d unsupported in region %x, band %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200386 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
Holger Schurig9012b282007-05-25 11:27:16 -0400396 lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
Holger Schurigece56192007-08-02 11:53:06 -0400397 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200398 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
399
Holger Schurig9012b282007-05-25 11:27:16 -0400400done:
401 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200402 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*/
Holger Schurig10078322007-11-15 18:05:47 -0500411u8 lbs_get_scan_type_11d(u8 chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200412 struct parsed_region_chan_11d * parsed_region_chan)
413{
Dan Williams0aef64d2007-08-02 11:31:18 -0400414 u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200415
Holger Schurig9012b282007-05-25 11:27:16 -0400416 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200417
Holger Schurig10078322007-11-15 18:05:47 -0500418 if (lbs_channel_known_11d(chan, parsed_region_chan)) {
Holger Schurigece56192007-08-02 11:53:06 -0400419 lbs_deb_11d("found, do active scan\n");
Dan Williams0aef64d2007-08-02 11:31:18 -0400420 scan_type = CMD_SCAN_TYPE_ACTIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200421 } else {
Holger Schurigece56192007-08-02 11:53:06 -0400422 lbs_deb_11d("not found, do passive scan\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200423 }
424
Holger Schurig9012b282007-05-25 11:27:16 -0400425 lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426 return scan_type;
427
428}
429
Holger Schurig69f90322007-11-23 15:43:44 +0100430void lbs_init_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200431{
David Woodhouseaa21c002007-12-08 20:04:36 +0000432 priv->enable11d = 0;
433 memset(&(priv->parsed_region_chan), 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200434 sizeof(struct parsed_region_chan_11d));
435 return;
436}
437
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438/**
439 * @brief This function sets DOMAIN INFO to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100440 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200441 * @return 0; -1
442*/
Holger Schurig69f90322007-11-23 15:43:44 +0100443static int set_domain_info_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200444{
445 int ret;
446
David Woodhouseaa21c002007-12-08 20:04:36 +0000447 if (!priv->enable11d) {
Holger Schurigece56192007-08-02 11:53:06 -0400448 lbs_deb_11d("dnld domain Info with 11d disabled\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449 return 0;
450 }
451
Holger Schurig10078322007-11-15 18:05:47 -0500452 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
Dan Williams0aef64d2007-08-02 11:31:18 -0400453 CMD_ACT_SET,
454 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200455 if (ret)
Holger Schurigece56192007-08-02 11:53:06 -0400456 lbs_deb_11d("fail to dnld domain info\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200457
458 return ret;
459}
460
461/**
462 * @brief This function setups scan channels
Holger Schurig69f90322007-11-23 15:43:44 +0100463 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200464 * @param band band
465 * @return 0
466*/
Holger Schurig69f90322007-11-23 15:43:44 +0100467int lbs_set_universaltable(struct lbs_private *priv, u8 band)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200469 u16 size = sizeof(struct chan_freq_power);
470 u16 i = 0;
471
David Woodhouseaa21c002007-12-08 20:04:36 +0000472 memset(priv->universal_channel, 0,
473 sizeof(priv->universal_channel));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200474
David Woodhouseaa21c002007-12-08 20:04:36 +0000475 priv->universal_channel[i].nrcfp =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200476 sizeof(channel_freq_power_UN_BG) / size;
Holger Schurigece56192007-08-02 11:53:06 -0400477 lbs_deb_11d("BG-band nrcfp %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000478 priv->universal_channel[i].nrcfp);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200479
David Woodhouseaa21c002007-12-08 20:04:36 +0000480 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;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200484 i++;
485
486 return 0;
487}
488
489/**
490 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
Holger Schurig69f90322007-11-23 15:43:44 +0100491 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200492 * @param cmd pointer to cmd buffer
493 * @param cmdno cmd ID
494 * @param cmdOption cmd action
495 * @return 0
496*/
Holger Schurig69f90322007-11-23 15:43:44 +0100497int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200498 struct cmd_ds_command *cmd, u16 cmdno,
499 u16 cmdoption)
500{
501 struct cmd_ds_802_11d_domain_info *pdomaininfo =
502 &cmd->params.domaininfo;
Dan Williams75b6a612009-05-22 20:03:09 -0400503 struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
David Woodhouseaa21c002007-12-08 20:04:36 +0000504 u8 nr_subband = priv->domainreg.nr_subband;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200505
Holger Schurig9012b282007-05-25 11:27:16 -0400506 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200507
Holger Schurig9012b282007-05-25 11:27:16 -0400508 lbs_deb_11d("nr_subband=%x\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509
510 cmd->command = cpu_to_le16(cmdno);
511 pdomaininfo->action = cpu_to_le16(cmdoption);
Dan Williams0aef64d2007-08-02 11:31:18 -0400512 if (cmdoption == CMD_ACT_GET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200513 cmd->size =
514 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
Holger Schurigece56192007-08-02 11:53:06 -0400515 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000516 le16_to_cpu(cmd->size));
Holger Schurig9012b282007-05-25 11:27:16 -0400517 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200518 }
519
520 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
David Woodhouseaa21c002007-12-08 20:04:36 +0000521 memcpy(domain->countrycode, priv->domainreg.countrycode,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200522 sizeof(domain->countrycode));
523
524 domain->header.len =
Dan Williams75b6a612009-05-22 20:03:09 -0400525 cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200526 sizeof(domain->countrycode));
527
528 if (nr_subband) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000529 memcpy(domain->subband, priv->domainreg.subband,
Dan Williams75b6a612009-05-22 20:03:09 -0400530 nr_subband * sizeof(struct ieee_subbandset));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200531
532 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
Dan Williams8362cd42007-08-03 09:40:55 -0400533 le16_to_cpu(domain->header.len) +
Dan Williams75b6a612009-05-22 20:03:09 -0400534 sizeof(struct mrvl_ie_header) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200535 S_DS_GEN);
536 } else {
537 cmd->size =
538 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
539 }
540
Holger Schurigece56192007-08-02 11:53:06 -0400541 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200542
Holger Schurig9012b282007-05-25 11:27:16 -0400543done:
544 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200545 return 0;
546}
547
548/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200549 * @brief This function parses countryinfo from AP and download country info to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100550 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200551 * @param resp pointer to command response buffer
552 * @return 0; -1
553 */
Holger Schurige98a88d2008-03-19 14:25:58 +0100554int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200555{
David Woodhouse981f1872007-05-25 23:36:54 -0400556 struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
Dan Williams75b6a612009-05-22 20:03:09 -0400557 struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200558 u16 action = le16_to_cpu(domaininfo->action);
559 s16 ret = 0;
560 u8 nr_subband = 0;
561
Holger Schurig9012b282007-05-25 11:27:16 -0400562 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200563
Holger Schurigece56192007-08-02 11:53:06 -0400564 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200565 (int)le16_to_cpu(resp->size));
566
David Woodhouse981f1872007-05-25 23:36:54 -0400567 nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
Dan Williams75b6a612009-05-22 20:03:09 -0400568 sizeof(struct ieee_subbandset);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200569
Holger Schurigece56192007-08-02 11:53:06 -0400570 lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200571
572 if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
Holger Schurig9012b282007-05-25 11:27:16 -0400573 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200574 return -1;
575 }
576
577 switch (action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400578 case CMD_ACT_SET: /*Proc Set action */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200579 break;
580
Dan Williams0aef64d2007-08-02 11:31:18 -0400581 case CMD_ACT_GET:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200582 break;
583 default:
Holger Schurig9012b282007-05-25 11:27:16 -0400584 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200585 ret = -1;
586 break;
587 }
588
Holger Schurig9012b282007-05-25 11:27:16 -0400589 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590 return ret;
591}
592
593/**
594 * @brief This function parses countryinfo from AP and download country info to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100595 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200596 * @return 0; -1
597 */
Holger Schurig69f90322007-11-23 15:43:44 +0100598int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
Dan Williamse76850d2007-05-25 17:09:41 -0400599 struct bss_descriptor * bss)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200600{
601 int ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200602
Holger Schurig9012b282007-05-25 11:27:16 -0400603 lbs_deb_enter(LBS_DEB_11D);
David Woodhouseaa21c002007-12-08 20:04:36 +0000604 if (priv->enable11d) {
605 memset(&priv->parsed_region_chan, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200606 sizeof(struct parsed_region_chan_11d));
Dan Williamse76850d2007-05-25 17:09:41 -0400607 ret = parse_domain_info_11d(&bss->countryinfo, 0,
David Woodhouseaa21c002007-12-08 20:04:36 +0000608 &priv->parsed_region_chan);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200609
610 if (ret == -1) {
Holger Schurigece56192007-08-02 11:53:06 -0400611 lbs_deb_11d("error parsing domain_info from AP\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400612 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200613 }
614
David Woodhouseaa21c002007-12-08 20:04:36 +0000615 memset(&priv->domainreg, 0,
Holger Schurig10078322007-11-15 18:05:47 -0500616 sizeof(struct lbs_802_11d_domain_reg));
David Woodhouseaa21c002007-12-08 20:04:36 +0000617 generate_domain_info_11d(&priv->parsed_region_chan,
618 &priv->domainreg);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200619
620 ret = set_domain_info_11d(priv);
621
622 if (ret) {
Holger Schurigece56192007-08-02 11:53:06 -0400623 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400624 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200625 }
626 }
Holger Schurig9012b282007-05-25 11:27:16 -0400627 ret = 0;
628
629done:
630 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
631 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200632}
633
634/**
635 * @brief This function generates 11D info from user specified regioncode and download to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100636 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200637 * @return 0; -1
638 */
Holger Schurig69f90322007-11-23 15:43:44 +0100639int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200640{
641 int ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200642 struct region_channel *region_chan;
643 u8 j;
644
Holger Schurig9012b282007-05-25 11:27:16 -0400645 lbs_deb_enter(LBS_DEB_11D);
David Woodhouseaa21c002007-12-08 20:04:36 +0000646 lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200647
David Woodhouseaa21c002007-12-08 20:04:36 +0000648 if (priv->enable11d) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200649 /* update parsed_region_chan_11; dnld domaininf to FW */
650
David Woodhouseaa21c002007-12-08 20:04:36 +0000651 for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
652 region_chan = &priv->region_channel[j];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200653
Holger Schurigece56192007-08-02 11:53:06 -0400654 lbs_deb_11d("%d region_chan->band %d\n", j,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655 region_chan->band);
656
657 if (!region_chan || !region_chan->valid
658 || !region_chan->CFP)
659 continue;
David Woodhouseaa21c002007-12-08 20:04:36 +0000660 if (region_chan->band != priv->curbssparams.band)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200661 continue;
662 break;
663 }
664
David Woodhouseaa21c002007-12-08 20:04:36 +0000665 if (j >= ARRAY_SIZE(priv->region_channel)) {
Holger Schurigece56192007-08-02 11:53:06 -0400666 lbs_deb_11d("region_chan not found, band %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000667 priv->curbssparams.band);
Holger Schurig9012b282007-05-25 11:27:16 -0400668 ret = -1;
669 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200670 }
671
David Woodhouseaa21c002007-12-08 20:04:36 +0000672 memset(&priv->parsed_region_chan, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200673 sizeof(struct parsed_region_chan_11d));
Holger Schurig10078322007-11-15 18:05:47 -0500674 lbs_generate_parsed_region_chan_11d(region_chan,
David Woodhouseaa21c002007-12-08 20:04:36 +0000675 &priv->
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200676 parsed_region_chan);
677
David Woodhouseaa21c002007-12-08 20:04:36 +0000678 memset(&priv->domainreg, 0,
Holger Schurig10078322007-11-15 18:05:47 -0500679 sizeof(struct lbs_802_11d_domain_reg));
David Woodhouseaa21c002007-12-08 20:04:36 +0000680 generate_domain_info_11d(&priv->parsed_region_chan,
681 &priv->domainreg);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200682
683 ret = set_domain_info_11d(priv);
684
685 if (ret) {
Holger Schurigece56192007-08-02 11:53:06 -0400686 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400687 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200688 }
689
690 }
Holger Schurig9012b282007-05-25 11:27:16 -0400691 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200692
Holger Schurig9012b282007-05-25 11:27:16 -0400693done:
694 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
695 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200696}