blob: 377dcb5b8f0ca6be329d833f7709efe8c3992351 [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 Schurig10078322007-11-15 18:05:47 -050082static u8 lbs_get_chan_11d(u8 band, 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 Schurig10078322007-11-15 18:05:47 -0500137u32 lbs_chan_2_freq(u8 chan, u8 band)
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 +
210 sizeof(struct ieeetypes_subbandset) * nr_subband);
211 return 0;
212}
213
214/**
215 * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
216 * @param region_chan pointer to struct region_channel
217 * @param *parsed_region_chan pointer to parsed_region_chan_11d
218 * @return N/A
219*/
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 Schurig10078322007-11-15 18:05:47 -0500267static u8 lbs_region_chan_supported_11d(u8 region, u8 band, 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 Schurig10078322007-11-15 18:05:47 -0500276 cfp = lbs_get_region_cfp_table(region, band, &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*/
305static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
306 countryinfo,
307 u8 band,
308 struct parsed_region_chan_11d *
309 parsed_region_chan)
310{
311 u8 nr_subband, nrchan;
312 u8 lastchan, firstchan;
313 u8 region;
314 u8 curchan = 0;
315
316 u8 idx = 0; /*chan index in parsed_region_chan */
317
318 u8 j, i;
319
Holger Schurig9012b282007-05-25 11:27:16 -0400320 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200321
322 /*validation Rules:
323 1. valid region Code
324 2. First Chan increment
325 3. channel range no overlap
326 4. channel is valid?
327 5. channel is supported by region?
328 6. Others
329 */
330
Holger Schurigece56192007-08-02 11:53:06 -0400331 lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200332
333 if ((*(countryinfo->countrycode)) == 0
334 || (countryinfo->len <= COUNTRY_CODE_LEN)) {
335 /* No region Info or Wrong region info: treat as No 11D info */
Holger Schurig9012b282007-05-25 11:27:16 -0400336 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200337 }
338
339 /*Step1: check region_code */
340 parsed_region_chan->region = region =
Holger Schurig10078322007-11-15 18:05:47 -0500341 lbs_region_2_code(countryinfo->countrycode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200342
Holger Schurig9012b282007-05-25 11:27:16 -0400343 lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
Holger Schurigece56192007-08-02 11:53:06 -0400344 lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200345 COUNTRY_CODE_LEN);
346
347 parsed_region_chan->band = band;
348
349 memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
350 COUNTRY_CODE_LEN);
351
352 nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
353 sizeof(struct ieeetypes_subbandset);
354
355 for (j = 0, lastchan = 0; j < nr_subband; j++) {
356
357 if (countryinfo->subband[j].firstchan <= lastchan) {
358 /*Step2&3. Check First Chan Num increment and no overlap */
Holger Schurigece56192007-08-02 11:53:06 -0400359 lbs_deb_11d("chan %d>%d, overlap\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200360 countryinfo->subband[j].firstchan, lastchan);
361 continue;
362 }
363
364 firstchan = countryinfo->subband[j].firstchan;
365 nrchan = countryinfo->subband[j].nrchan;
366
367 for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
368 /*step4: channel is supported? */
369
Holger Schurig10078322007-11-15 18:05:47 -0500370 if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200371 /* Chan is not found in UN table */
Holger Schurig9012b282007-05-25 11:27:16 -0400372 lbs_deb_11d("chan is not supported: %d \n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200373 break;
374 }
375
376 lastchan = curchan;
377
Holger Schurig10078322007-11-15 18:05:47 -0500378 if (lbs_region_chan_supported_11d
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200379 (region, band, curchan)) {
380 /*step5: Check if curchan is supported by mrvl in region */
381 parsed_region_chan->chanpwr[idx].chan = curchan;
382 parsed_region_chan->chanpwr[idx].pwr =
383 countryinfo->subband[j].maxtxpwr;
384 idx++;
385 } else {
386 /*not supported and ignore the chan */
Holger Schurig9012b282007-05-25 11:27:16 -0400387 lbs_deb_11d(
Holger Schurigece56192007-08-02 11:53:06 -0400388 "i %d, chan %d unsupported in region %x, band %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389 i, curchan, region, band);
390 }
391 }
392
393 /*Step6: Add other checking if any */
394
395 }
396
397 parsed_region_chan->nr_chan = idx;
398
Holger Schurig9012b282007-05-25 11:27:16 -0400399 lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
Holger Schurigece56192007-08-02 11:53:06 -0400400 lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200401 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
402
Holger Schurig9012b282007-05-25 11:27:16 -0400403done:
404 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200405 return 0;
406}
407
408/**
409 * @brief This function calculates the scan type for channels
410 * @param chan chan number
411 * @param parsed_region_chan pointer to parsed_region_chan_11d
412 * @return PASSIVE if chan is unknown; ACTIVE if chan is known
413*/
Holger Schurig10078322007-11-15 18:05:47 -0500414u8 lbs_get_scan_type_11d(u8 chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200415 struct parsed_region_chan_11d * parsed_region_chan)
416{
Dan Williams0aef64d2007-08-02 11:31:18 -0400417 u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200418
Holger Schurig9012b282007-05-25 11:27:16 -0400419 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200420
Holger Schurig10078322007-11-15 18:05:47 -0500421 if (lbs_channel_known_11d(chan, parsed_region_chan)) {
Holger Schurigece56192007-08-02 11:53:06 -0400422 lbs_deb_11d("found, do active scan\n");
Dan Williams0aef64d2007-08-02 11:31:18 -0400423 scan_type = CMD_SCAN_TYPE_ACTIVE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200424 } else {
Holger Schurigece56192007-08-02 11:53:06 -0400425 lbs_deb_11d("not found, do passive scan\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426 }
427
Holger Schurig9012b282007-05-25 11:27:16 -0400428 lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200429 return scan_type;
430
431}
432
Holger Schurig69f90322007-11-23 15:43:44 +0100433void lbs_init_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200434{
435 priv->adapter->enable11d = 0;
436 memset(&(priv->adapter->parsed_region_chan), 0,
437 sizeof(struct parsed_region_chan_11d));
438 return;
439}
440
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200441/**
442 * @brief This function sets DOMAIN INFO to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100443 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200444 * @return 0; -1
445*/
Holger Schurig69f90322007-11-23 15:43:44 +0100446static int set_domain_info_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200447{
448 int ret;
449
450 if (!priv->adapter->enable11d) {
Holger Schurigece56192007-08-02 11:53:06 -0400451 lbs_deb_11d("dnld domain Info with 11d disabled\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200452 return 0;
453 }
454
Holger Schurig10078322007-11-15 18:05:47 -0500455 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
Dan Williams0aef64d2007-08-02 11:31:18 -0400456 CMD_ACT_SET,
457 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200458 if (ret)
Holger Schurigece56192007-08-02 11:53:06 -0400459 lbs_deb_11d("fail to dnld domain info\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200460
461 return ret;
462}
463
464/**
465 * @brief This function setups scan channels
Holger Schurig69f90322007-11-23 15:43:44 +0100466 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467 * @param band band
468 * @return 0
469*/
Holger Schurig69f90322007-11-23 15:43:44 +0100470int lbs_set_universaltable(struct lbs_private *priv, u8 band)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200471{
Holger Schurig69f90322007-11-23 15:43:44 +0100472 struct lbs_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200473 u16 size = sizeof(struct chan_freq_power);
474 u16 i = 0;
475
476 memset(adapter->universal_channel, 0,
477 sizeof(adapter->universal_channel));
478
479 adapter->universal_channel[i].nrcfp =
480 sizeof(channel_freq_power_UN_BG) / size;
Holger Schurigece56192007-08-02 11:53:06 -0400481 lbs_deb_11d("BG-band nrcfp %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 adapter->universal_channel[i].nrcfp);
483
484 adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
485 adapter->universal_channel[i].valid = 1;
486 adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
487 adapter->universal_channel[i].band = band;
488 i++;
489
490 return 0;
491}
492
493/**
494 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
Holger Schurig69f90322007-11-23 15:43:44 +0100495 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200496 * @param cmd pointer to cmd buffer
497 * @param cmdno cmd ID
498 * @param cmdOption cmd action
499 * @return 0
500*/
Holger Schurig69f90322007-11-23 15:43:44 +0100501int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200502 struct cmd_ds_command *cmd, u16 cmdno,
503 u16 cmdoption)
504{
505 struct cmd_ds_802_11d_domain_info *pdomaininfo =
506 &cmd->params.domaininfo;
507 struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
Holger Schurig69f90322007-11-23 15:43:44 +0100508 struct lbs_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509 u8 nr_subband = adapter->domainreg.nr_subband;
510
Holger Schurig9012b282007-05-25 11:27:16 -0400511 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200512
Holger Schurig9012b282007-05-25 11:27:16 -0400513 lbs_deb_11d("nr_subband=%x\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200514
515 cmd->command = cpu_to_le16(cmdno);
516 pdomaininfo->action = cpu_to_le16(cmdoption);
Dan Williams0aef64d2007-08-02 11:31:18 -0400517 if (cmdoption == CMD_ACT_GET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200518 cmd->size =
519 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
Holger Schurigece56192007-08-02 11:53:06 -0400520 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200521 (int)(cmd->size));
Holger Schurig9012b282007-05-25 11:27:16 -0400522 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200523 }
524
525 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
526 memcpy(domain->countrycode, adapter->domainreg.countrycode,
527 sizeof(domain->countrycode));
528
529 domain->header.len =
530 cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
531 sizeof(domain->countrycode));
532
533 if (nr_subband) {
534 memcpy(domain->subband, adapter->domainreg.subband,
535 nr_subband * sizeof(struct ieeetypes_subbandset));
536
537 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
Dan Williams8362cd42007-08-03 09:40:55 -0400538 le16_to_cpu(domain->header.len) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200539 sizeof(struct mrvlietypesheader) +
540 S_DS_GEN);
541 } else {
542 cmd->size =
543 cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
544 }
545
Holger Schurigece56192007-08-02 11:53:06 -0400546 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200547
Holger Schurig9012b282007-05-25 11:27:16 -0400548done:
549 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200550 return 0;
551}
552
553/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200554 * @brief This function parses countryinfo from AP and download country info to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100555 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200556 * @param resp pointer to command response buffer
557 * @return 0; -1
558 */
Holger Schurig69f90322007-11-23 15:43:44 +0100559int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200560 struct cmd_ds_command *resp)
561{
David Woodhouse981f1872007-05-25 23:36:54 -0400562 struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200563 struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
564 u16 action = le16_to_cpu(domaininfo->action);
565 s16 ret = 0;
566 u8 nr_subband = 0;
567
Holger Schurig9012b282007-05-25 11:27:16 -0400568 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200569
Holger Schurigece56192007-08-02 11:53:06 -0400570 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200571 (int)le16_to_cpu(resp->size));
572
David Woodhouse981f1872007-05-25 23:36:54 -0400573 nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
574 sizeof(struct ieeetypes_subbandset);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200575
Holger Schurigece56192007-08-02 11:53:06 -0400576 lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200577
578 if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
Holger Schurig9012b282007-05-25 11:27:16 -0400579 lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200580 return -1;
581 }
582
583 switch (action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400584 case CMD_ACT_SET: /*Proc Set action */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200585 break;
586
Dan Williams0aef64d2007-08-02 11:31:18 -0400587 case CMD_ACT_GET:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588 break;
589 default:
Holger Schurig9012b282007-05-25 11:27:16 -0400590 lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200591 ret = -1;
592 break;
593 }
594
Holger Schurig9012b282007-05-25 11:27:16 -0400595 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200596 return ret;
597}
598
599/**
600 * @brief This function parses countryinfo from AP and download country info to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100601 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200602 * @return 0; -1
603 */
Holger Schurig69f90322007-11-23 15:43:44 +0100604int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
Dan Williamse76850d2007-05-25 17:09:41 -0400605 struct bss_descriptor * bss)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200606{
607 int ret;
Holger Schurig69f90322007-11-23 15:43:44 +0100608 struct lbs_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200609
Holger Schurig9012b282007-05-25 11:27:16 -0400610 lbs_deb_enter(LBS_DEB_11D);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200611 if (priv->adapter->enable11d) {
612 memset(&adapter->parsed_region_chan, 0,
613 sizeof(struct parsed_region_chan_11d));
Dan Williamse76850d2007-05-25 17:09:41 -0400614 ret = parse_domain_info_11d(&bss->countryinfo, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200615 &adapter->parsed_region_chan);
616
617 if (ret == -1) {
Holger Schurigece56192007-08-02 11:53:06 -0400618 lbs_deb_11d("error parsing domain_info from AP\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400619 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200620 }
621
622 memset(&adapter->domainreg, 0,
Holger Schurig10078322007-11-15 18:05:47 -0500623 sizeof(struct lbs_802_11d_domain_reg));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200624 generate_domain_info_11d(&adapter->parsed_region_chan,
625 &adapter->domainreg);
626
627 ret = set_domain_info_11d(priv);
628
629 if (ret) {
Holger Schurigece56192007-08-02 11:53:06 -0400630 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400631 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200632 }
633 }
Holger Schurig9012b282007-05-25 11:27:16 -0400634 ret = 0;
635
636done:
637 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
638 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200639}
640
641/**
642 * @brief This function generates 11D info from user specified regioncode and download to FW
Holger Schurig69f90322007-11-23 15:43:44 +0100643 * @param priv pointer to struct lbs_private
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200644 * @return 0; -1
645 */
Holger Schurig69f90322007-11-23 15:43:44 +0100646int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200647{
648 int ret;
Holger Schurig69f90322007-11-23 15:43:44 +0100649 struct lbs_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200650 struct region_channel *region_chan;
651 u8 j;
652
Holger Schurig9012b282007-05-25 11:27:16 -0400653 lbs_deb_enter(LBS_DEB_11D);
Holger Schurigece56192007-08-02 11:53:06 -0400654 lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655
656 if (priv->adapter->enable11d) {
657 /* update parsed_region_chan_11; dnld domaininf to FW */
658
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +0200659 for (j = 0; j < ARRAY_SIZE(adapter->region_channel); j++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200660 region_chan = &adapter->region_channel[j];
661
Holger Schurigece56192007-08-02 11:53:06 -0400662 lbs_deb_11d("%d region_chan->band %d\n", j,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200663 region_chan->band);
664
665 if (!region_chan || !region_chan->valid
666 || !region_chan->CFP)
667 continue;
668 if (region_chan->band != adapter->curbssparams.band)
669 continue;
670 break;
671 }
672
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +0200673 if (j >= ARRAY_SIZE(adapter->region_channel)) {
Holger Schurigece56192007-08-02 11:53:06 -0400674 lbs_deb_11d("region_chan not found, band %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200675 adapter->curbssparams.band);
Holger Schurig9012b282007-05-25 11:27:16 -0400676 ret = -1;
677 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200678 }
679
680 memset(&adapter->parsed_region_chan, 0,
681 sizeof(struct parsed_region_chan_11d));
Holger Schurig10078322007-11-15 18:05:47 -0500682 lbs_generate_parsed_region_chan_11d(region_chan,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200683 &adapter->
684 parsed_region_chan);
685
686 memset(&adapter->domainreg, 0,
Holger Schurig10078322007-11-15 18:05:47 -0500687 sizeof(struct lbs_802_11d_domain_reg));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200688 generate_domain_info_11d(&adapter->parsed_region_chan,
689 &adapter->domainreg);
690
691 ret = set_domain_info_11d(priv);
692
693 if (ret) {
Holger Schurigece56192007-08-02 11:53:06 -0400694 lbs_deb_11d("error setting domain info\n");
Holger Schurig9012b282007-05-25 11:27:16 -0400695 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200696 }
697
698 }
Holger Schurig9012b282007-05-25 11:27:16 -0400699 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200700
Holger Schurig9012b282007-05-25 11:27:16 -0400701done:
702 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
703 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200704}