11d.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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. #include "host.h"
  8. #include "decl.h"
  9. #include "11d.h"
  10. #include "dev.h"
  11. #include "wext.h"
  12. #define TX_PWR_DEFAULT 10
  13. static struct region_code_mapping region_code_mapping[] = {
  14. {"US ", 0x10}, /* US FCC */
  15. {"CA ", 0x10}, /* IC Canada */
  16. {"SG ", 0x10}, /* Singapore */
  17. {"EU ", 0x30}, /* ETSI */
  18. {"AU ", 0x30}, /* Australia */
  19. {"KR ", 0x30}, /* Republic Of Korea */
  20. {"ES ", 0x31}, /* Spain */
  21. {"FR ", 0x32}, /* France */
  22. {"JP ", 0x40}, /* Japan */
  23. };
  24. /* Following 2 structure defines the supported channels */
  25. static struct chan_freq_power channel_freq_power_UN_BG[] = {
  26. {1, 2412, TX_PWR_DEFAULT},
  27. {2, 2417, TX_PWR_DEFAULT},
  28. {3, 2422, TX_PWR_DEFAULT},
  29. {4, 2427, TX_PWR_DEFAULT},
  30. {5, 2432, TX_PWR_DEFAULT},
  31. {6, 2437, TX_PWR_DEFAULT},
  32. {7, 2442, TX_PWR_DEFAULT},
  33. {8, 2447, TX_PWR_DEFAULT},
  34. {9, 2452, TX_PWR_DEFAULT},
  35. {10, 2457, TX_PWR_DEFAULT},
  36. {11, 2462, TX_PWR_DEFAULT},
  37. {12, 2467, TX_PWR_DEFAULT},
  38. {13, 2472, TX_PWR_DEFAULT},
  39. {14, 2484, TX_PWR_DEFAULT}
  40. };
  41. static u8 wlan_region_2_code(u8 * region)
  42. {
  43. u8 i;
  44. u8 size = sizeof(region_code_mapping)/
  45. sizeof(struct region_code_mapping);
  46. for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
  47. region[i] = toupper(region[i]);
  48. for (i = 0; i < size; i++) {
  49. if (!memcmp(region, region_code_mapping[i].region,
  50. COUNTRY_CODE_LEN))
  51. return (region_code_mapping[i].code);
  52. }
  53. /* default is US */
  54. return (region_code_mapping[0].code);
  55. }
  56. static u8 *wlan_code_2_region(u8 code)
  57. {
  58. u8 i;
  59. u8 size = sizeof(region_code_mapping)
  60. / sizeof(struct region_code_mapping);
  61. for (i = 0; i < size; i++) {
  62. if (region_code_mapping[i].code == code)
  63. return (region_code_mapping[i].region);
  64. }
  65. /* default is US */
  66. return (region_code_mapping[0].region);
  67. }
  68. /**
  69. * @brief This function finds the nrchan-th chan after the firstchan
  70. * @param band band
  71. * @param firstchan first channel number
  72. * @param nrchan number of channels
  73. * @return the nrchan-th chan number
  74. */
  75. static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
  76. /*find the nrchan-th chan after the firstchan*/
  77. {
  78. u8 i;
  79. struct chan_freq_power *cfp;
  80. u8 cfp_no;
  81. cfp = channel_freq_power_UN_BG;
  82. cfp_no = sizeof(channel_freq_power_UN_BG) /
  83. sizeof(struct chan_freq_power);
  84. for (i = 0; i < cfp_no; i++) {
  85. if ((cfp + i)->channel == firstchan) {
  86. lbs_deb_11d("firstchan found\n");
  87. break;
  88. }
  89. }
  90. if (i < cfp_no) {
  91. /*if beyond the boundary */
  92. if (i + nrchan < cfp_no) {
  93. *chan = (cfp + i + nrchan)->channel;
  94. return 1;
  95. }
  96. }
  97. return 0;
  98. }
  99. /**
  100. * @brief This function Checks if chan txpwr is learned from AP/IBSS
  101. * @param chan chan number
  102. * @param parsed_region_chan pointer to parsed_region_chan_11d
  103. * @return TRUE; FALSE
  104. */
  105. static u8 wlan_channel_known_11d(u8 chan,
  106. struct parsed_region_chan_11d * parsed_region_chan)
  107. {
  108. struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
  109. u8 nr_chan = parsed_region_chan->nr_chan;
  110. u8 i = 0;
  111. lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
  112. sizeof(struct chan_power_11d) * nr_chan);
  113. for (i = 0; i < nr_chan; i++) {
  114. if (chan == chanpwr[i].chan) {
  115. lbs_deb_11d("found chan %d\n", chan);
  116. return 1;
  117. }
  118. }
  119. lbs_deb_11d("chan %d not found\n", chan);
  120. return 0;
  121. }
  122. u32 libertas_chan_2_freq(u8 chan, u8 band)
  123. {
  124. struct chan_freq_power *cf;
  125. u16 cnt;
  126. u16 i;
  127. u32 freq = 0;
  128. cf = channel_freq_power_UN_BG;
  129. cnt =
  130. sizeof(channel_freq_power_UN_BG) /
  131. sizeof(struct chan_freq_power);
  132. for (i = 0; i < cnt; i++) {
  133. if (chan == cf[i].channel)
  134. freq = cf[i].freq;
  135. }
  136. return freq;
  137. }
  138. static int generate_domain_info_11d(struct parsed_region_chan_11d
  139. *parsed_region_chan,
  140. struct wlan_802_11d_domain_reg * domaininfo)
  141. {
  142. u8 nr_subband = 0;
  143. u8 nr_chan = parsed_region_chan->nr_chan;
  144. u8 nr_parsedchan = 0;
  145. u8 firstchan = 0, nextchan = 0, maxpwr = 0;
  146. u8 i, flag = 0;
  147. memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
  148. COUNTRY_CODE_LEN);
  149. lbs_deb_11d("nrchan %d\n", nr_chan);
  150. lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
  151. sizeof(struct parsed_region_chan_11d));
  152. for (i = 0; i < nr_chan; i++) {
  153. if (!flag) {
  154. flag = 1;
  155. nextchan = firstchan =
  156. parsed_region_chan->chanpwr[i].chan;
  157. maxpwr = parsed_region_chan->chanpwr[i].pwr;
  158. nr_parsedchan = 1;
  159. continue;
  160. }
  161. if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
  162. parsed_region_chan->chanpwr[i].pwr == maxpwr) {
  163. nextchan++;
  164. nr_parsedchan++;
  165. } else {
  166. domaininfo->subband[nr_subband].firstchan = firstchan;
  167. domaininfo->subband[nr_subband].nrchan =
  168. nr_parsedchan;
  169. domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
  170. nr_subband++;
  171. nextchan = firstchan =
  172. parsed_region_chan->chanpwr[i].chan;
  173. maxpwr = parsed_region_chan->chanpwr[i].pwr;
  174. }
  175. }
  176. if (flag) {
  177. domaininfo->subband[nr_subband].firstchan = firstchan;
  178. domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
  179. domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
  180. nr_subband++;
  181. }
  182. domaininfo->nr_subband = nr_subband;
  183. lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
  184. lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
  185. COUNTRY_CODE_LEN + 1 +
  186. sizeof(struct ieeetypes_subbandset) * nr_subband);
  187. return 0;
  188. }
  189. /**
  190. * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
  191. * @param region_chan pointer to struct region_channel
  192. * @param *parsed_region_chan pointer to parsed_region_chan_11d
  193. * @return N/A
  194. */
  195. static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
  196. struct parsed_region_chan_11d *
  197. parsed_region_chan)
  198. {
  199. u8 i;
  200. struct chan_freq_power *cfp;
  201. if (region_chan == NULL) {
  202. lbs_deb_11d("region_chan is NULL\n");
  203. return;
  204. }
  205. cfp = region_chan->CFP;
  206. if (cfp == NULL) {
  207. lbs_deb_11d("cfp is NULL \n");
  208. return;
  209. }
  210. parsed_region_chan->band = region_chan->band;
  211. parsed_region_chan->region = region_chan->region;
  212. memcpy(parsed_region_chan->countrycode,
  213. wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
  214. lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
  215. parsed_region_chan->band);
  216. for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
  217. parsed_region_chan->chanpwr[i].chan = cfp->channel;
  218. parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
  219. lbs_deb_11d("chan %d, pwr %d\n",
  220. parsed_region_chan->chanpwr[i].chan,
  221. parsed_region_chan->chanpwr[i].pwr);
  222. }
  223. parsed_region_chan->nr_chan = region_chan->nrcfp;
  224. lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
  225. return;
  226. }
  227. /**
  228. * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
  229. * @param region region ID
  230. * @param band band
  231. * @param chan chan
  232. * @return TRUE;FALSE
  233. */
  234. static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
  235. {
  236. struct chan_freq_power *cfp;
  237. int cfp_no;
  238. u8 idx;
  239. int ret = 0;
  240. lbs_deb_enter(LBS_DEB_11D);
  241. cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
  242. if (cfp == NULL)
  243. return 0;
  244. for (idx = 0; idx < cfp_no; idx++) {
  245. if (chan == (cfp + idx)->channel) {
  246. /* If Mrvl Chip Supported? */
  247. if ((cfp + idx)->unsupported) {
  248. ret = 0;
  249. } else {
  250. ret = 1;
  251. }
  252. goto done;
  253. }
  254. }
  255. /*chan is not in the region table */
  256. done:
  257. lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
  258. return ret;
  259. }
  260. /**
  261. * @brief This function checks if chan txpwr is learned from AP/IBSS
  262. * @param chan chan number
  263. * @param parsed_region_chan pointer to parsed_region_chan_11d
  264. * @return 0
  265. */
  266. static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
  267. countryinfo,
  268. u8 band,
  269. struct parsed_region_chan_11d *
  270. parsed_region_chan)
  271. {
  272. u8 nr_subband, nrchan;
  273. u8 lastchan, firstchan;
  274. u8 region;
  275. u8 curchan = 0;
  276. u8 idx = 0; /*chan index in parsed_region_chan */
  277. u8 j, i;
  278. lbs_deb_enter(LBS_DEB_11D);
  279. /*validation Rules:
  280. 1. valid region Code
  281. 2. First Chan increment
  282. 3. channel range no overlap
  283. 4. channel is valid?
  284. 5. channel is supported by region?
  285. 6. Others
  286. */
  287. lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
  288. if ((*(countryinfo->countrycode)) == 0
  289. || (countryinfo->len <= COUNTRY_CODE_LEN)) {
  290. /* No region Info or Wrong region info: treat as No 11D info */
  291. goto done;
  292. }
  293. /*Step1: check region_code */
  294. parsed_region_chan->region = region =
  295. wlan_region_2_code(countryinfo->countrycode);
  296. lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
  297. lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
  298. COUNTRY_CODE_LEN);
  299. parsed_region_chan->band = band;
  300. memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
  301. COUNTRY_CODE_LEN);
  302. nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
  303. sizeof(struct ieeetypes_subbandset);
  304. for (j = 0, lastchan = 0; j < nr_subband; j++) {
  305. if (countryinfo->subband[j].firstchan <= lastchan) {
  306. /*Step2&3. Check First Chan Num increment and no overlap */
  307. lbs_deb_11d("chan %d>%d, overlap\n",
  308. countryinfo->subband[j].firstchan, lastchan);
  309. continue;
  310. }
  311. firstchan = countryinfo->subband[j].firstchan;
  312. nrchan = countryinfo->subband[j].nrchan;
  313. for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
  314. /*step4: channel is supported? */
  315. if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
  316. /* Chan is not found in UN table */
  317. lbs_deb_11d("chan is not supported: %d \n", i);
  318. break;
  319. }
  320. lastchan = curchan;
  321. if (wlan_region_chan_supported_11d
  322. (region, band, curchan)) {
  323. /*step5: Check if curchan is supported by mrvl in region */
  324. parsed_region_chan->chanpwr[idx].chan = curchan;
  325. parsed_region_chan->chanpwr[idx].pwr =
  326. countryinfo->subband[j].maxtxpwr;
  327. idx++;
  328. } else {
  329. /*not supported and ignore the chan */
  330. lbs_deb_11d(
  331. "i %d, chan %d unsupported in region %x, band %d\n",
  332. i, curchan, region, band);
  333. }
  334. }
  335. /*Step6: Add other checking if any */
  336. }
  337. parsed_region_chan->nr_chan = idx;
  338. lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
  339. lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
  340. 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
  341. done:
  342. lbs_deb_enter(LBS_DEB_11D);
  343. return 0;
  344. }
  345. /**
  346. * @brief This function calculates the scan type for channels
  347. * @param chan chan number
  348. * @param parsed_region_chan pointer to parsed_region_chan_11d
  349. * @return PASSIVE if chan is unknown; ACTIVE if chan is known
  350. */
  351. u8 libertas_get_scan_type_11d(u8 chan,
  352. struct parsed_region_chan_11d * parsed_region_chan)
  353. {
  354. u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
  355. lbs_deb_enter(LBS_DEB_11D);
  356. if (wlan_channel_known_11d(chan, parsed_region_chan)) {
  357. lbs_deb_11d("found, do active scan\n");
  358. scan_type = CMD_SCAN_TYPE_ACTIVE;
  359. } else {
  360. lbs_deb_11d("not found, do passive scan\n");
  361. }
  362. lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
  363. return scan_type;
  364. }
  365. void libertas_init_11d(wlan_private * priv)
  366. {
  367. priv->adapter->enable11d = 0;
  368. memset(&(priv->adapter->parsed_region_chan), 0,
  369. sizeof(struct parsed_region_chan_11d));
  370. return;
  371. }
  372. /**
  373. * @brief This function sets DOMAIN INFO to FW
  374. * @param priv pointer to wlan_private
  375. * @return 0; -1
  376. */
  377. static int set_domain_info_11d(wlan_private * priv)
  378. {
  379. int ret;
  380. if (!priv->adapter->enable11d) {
  381. lbs_deb_11d("dnld domain Info with 11d disabled\n");
  382. return 0;
  383. }
  384. ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
  385. CMD_ACT_SET,
  386. CMD_OPTION_WAITFORRSP, 0, NULL);
  387. if (ret)
  388. lbs_deb_11d("fail to dnld domain info\n");
  389. return ret;
  390. }
  391. /**
  392. * @brief This function setups scan channels
  393. * @param priv pointer to wlan_private
  394. * @param band band
  395. * @return 0
  396. */
  397. int libertas_set_universaltable(wlan_private * priv, u8 band)
  398. {
  399. wlan_adapter *adapter = priv->adapter;
  400. u16 size = sizeof(struct chan_freq_power);
  401. u16 i = 0;
  402. memset(adapter->universal_channel, 0,
  403. sizeof(adapter->universal_channel));
  404. adapter->universal_channel[i].nrcfp =
  405. sizeof(channel_freq_power_UN_BG) / size;
  406. lbs_deb_11d("BG-band nrcfp %d\n",
  407. adapter->universal_channel[i].nrcfp);
  408. adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
  409. adapter->universal_channel[i].valid = 1;
  410. adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
  411. adapter->universal_channel[i].band = band;
  412. i++;
  413. return 0;
  414. }
  415. /**
  416. * @brief This function implements command CMD_802_11D_DOMAIN_INFO
  417. * @param priv pointer to wlan_private
  418. * @param cmd pointer to cmd buffer
  419. * @param cmdno cmd ID
  420. * @param cmdOption cmd action
  421. * @return 0
  422. */
  423. int libertas_cmd_802_11d_domain_info(wlan_private * priv,
  424. struct cmd_ds_command *cmd, u16 cmdno,
  425. u16 cmdoption)
  426. {
  427. struct cmd_ds_802_11d_domain_info *pdomaininfo =
  428. &cmd->params.domaininfo;
  429. struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
  430. wlan_adapter *adapter = priv->adapter;
  431. u8 nr_subband = adapter->domainreg.nr_subband;
  432. lbs_deb_enter(LBS_DEB_11D);
  433. lbs_deb_11d("nr_subband=%x\n", nr_subband);
  434. cmd->command = cpu_to_le16(cmdno);
  435. pdomaininfo->action = cpu_to_le16(cmdoption);
  436. if (cmdoption == CMD_ACT_GET) {
  437. cmd->size =
  438. cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
  439. lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
  440. (int)(cmd->size));
  441. goto done;
  442. }
  443. domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
  444. memcpy(domain->countrycode, adapter->domainreg.countrycode,
  445. sizeof(domain->countrycode));
  446. domain->header.len =
  447. cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
  448. sizeof(domain->countrycode));
  449. if (nr_subband) {
  450. memcpy(domain->subband, adapter->domainreg.subband,
  451. nr_subband * sizeof(struct ieeetypes_subbandset));
  452. cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
  453. le16_to_cpu(domain->header.len) +
  454. sizeof(struct mrvlietypesheader) +
  455. S_DS_GEN);
  456. } else {
  457. cmd->size =
  458. cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
  459. }
  460. lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
  461. done:
  462. lbs_deb_enter(LBS_DEB_11D);
  463. return 0;
  464. }
  465. /**
  466. * @brief This function parses countryinfo from AP and download country info to FW
  467. * @param priv pointer to wlan_private
  468. * @param resp pointer to command response buffer
  469. * @return 0; -1
  470. */
  471. int libertas_ret_802_11d_domain_info(wlan_private * priv,
  472. struct cmd_ds_command *resp)
  473. {
  474. struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
  475. struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
  476. u16 action = le16_to_cpu(domaininfo->action);
  477. s16 ret = 0;
  478. u8 nr_subband = 0;
  479. lbs_deb_enter(LBS_DEB_11D);
  480. lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
  481. (int)le16_to_cpu(resp->size));
  482. nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
  483. sizeof(struct ieeetypes_subbandset);
  484. lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
  485. if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
  486. lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
  487. return -1;
  488. }
  489. switch (action) {
  490. case CMD_ACT_SET: /*Proc Set action */
  491. break;
  492. case CMD_ACT_GET:
  493. break;
  494. default:
  495. lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
  496. ret = -1;
  497. break;
  498. }
  499. lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
  500. return ret;
  501. }
  502. /**
  503. * @brief This function parses countryinfo from AP and download country info to FW
  504. * @param priv pointer to wlan_private
  505. * @return 0; -1
  506. */
  507. int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
  508. struct bss_descriptor * bss)
  509. {
  510. int ret;
  511. wlan_adapter *adapter = priv->adapter;
  512. lbs_deb_enter(LBS_DEB_11D);
  513. if (priv->adapter->enable11d) {
  514. memset(&adapter->parsed_region_chan, 0,
  515. sizeof(struct parsed_region_chan_11d));
  516. ret = parse_domain_info_11d(&bss->countryinfo, 0,
  517. &adapter->parsed_region_chan);
  518. if (ret == -1) {
  519. lbs_deb_11d("error parsing domain_info from AP\n");
  520. goto done;
  521. }
  522. memset(&adapter->domainreg, 0,
  523. sizeof(struct wlan_802_11d_domain_reg));
  524. generate_domain_info_11d(&adapter->parsed_region_chan,
  525. &adapter->domainreg);
  526. ret = set_domain_info_11d(priv);
  527. if (ret) {
  528. lbs_deb_11d("error setting domain info\n");
  529. goto done;
  530. }
  531. }
  532. ret = 0;
  533. done:
  534. lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
  535. return ret;
  536. }
  537. /**
  538. * @brief This function generates 11D info from user specified regioncode and download to FW
  539. * @param priv pointer to wlan_private
  540. * @return 0; -1
  541. */
  542. int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
  543. {
  544. int ret;
  545. wlan_adapter *adapter = priv->adapter;
  546. struct region_channel *region_chan;
  547. u8 j;
  548. lbs_deb_enter(LBS_DEB_11D);
  549. lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
  550. if (priv->adapter->enable11d) {
  551. /* update parsed_region_chan_11; dnld domaininf to FW */
  552. for (j = 0; j < sizeof(adapter->region_channel) /
  553. sizeof(adapter->region_channel[0]); j++) {
  554. region_chan = &adapter->region_channel[j];
  555. lbs_deb_11d("%d region_chan->band %d\n", j,
  556. region_chan->band);
  557. if (!region_chan || !region_chan->valid
  558. || !region_chan->CFP)
  559. continue;
  560. if (region_chan->band != adapter->curbssparams.band)
  561. continue;
  562. break;
  563. }
  564. if (j >= sizeof(adapter->region_channel) /
  565. sizeof(adapter->region_channel[0])) {
  566. lbs_deb_11d("region_chan not found, band %d\n",
  567. adapter->curbssparams.band);
  568. ret = -1;
  569. goto done;
  570. }
  571. memset(&adapter->parsed_region_chan, 0,
  572. sizeof(struct parsed_region_chan_11d));
  573. wlan_generate_parsed_region_chan_11d(region_chan,
  574. &adapter->
  575. parsed_region_chan);
  576. memset(&adapter->domainreg, 0,
  577. sizeof(struct wlan_802_11d_domain_reg));
  578. generate_domain_info_11d(&adapter->parsed_region_chan,
  579. &adapter->domainreg);
  580. ret = set_domain_info_11d(priv);
  581. if (ret) {
  582. lbs_deb_11d("error setting domain info\n");
  583. goto done;
  584. }
  585. }
  586. ret = 0;
  587. done:
  588. lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
  589. return ret;
  590. }