11d.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  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_pr_debug(1, "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_dbg_hex("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_pr_debug(1, "11D: Found Chan:%d\n", chan);
  116. return 1;
  117. }
  118. }
  119. lbs_pr_debug(1, "11D: Not Find Chan:%d\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_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
  150. lbs_dbg_hex("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_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
  184. lbs_dbg_hex("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_pr_debug(1, "11D: region_chan is NULL\n");
  203. return;
  204. }
  205. cfp = region_chan->CFP;
  206. if (cfp == NULL) {
  207. lbs_pr_debug(1, "11D: cfp equal 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_pr_debug(1, "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_pr_debug(1, "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_pr_debug(1, "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. ENTER();
  240. cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
  241. if (cfp == NULL)
  242. return 0;
  243. for (idx = 0; idx < cfp_no; idx++) {
  244. if (chan == (cfp + idx)->channel) {
  245. /* If Mrvl Chip Supported? */
  246. if ((cfp + idx)->unsupported) {
  247. return 0;
  248. } else {
  249. return 1;
  250. }
  251. }
  252. }
  253. /*chan is not in the region table */
  254. LEAVE();
  255. return 0;
  256. }
  257. /**
  258. * @brief This function checks if chan txpwr is learned from AP/IBSS
  259. * @param chan chan number
  260. * @param parsed_region_chan pointer to parsed_region_chan_11d
  261. * @return 0
  262. */
  263. static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
  264. countryinfo,
  265. u8 band,
  266. struct parsed_region_chan_11d *
  267. parsed_region_chan)
  268. {
  269. u8 nr_subband, nrchan;
  270. u8 lastchan, firstchan;
  271. u8 region;
  272. u8 curchan = 0;
  273. u8 idx = 0; /*chan index in parsed_region_chan */
  274. u8 j, i;
  275. ENTER();
  276. /*validation Rules:
  277. 1. valid region Code
  278. 2. First Chan increment
  279. 3. channel range no overlap
  280. 4. channel is valid?
  281. 5. channel is supported by region?
  282. 6. Others
  283. */
  284. lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
  285. if ((*(countryinfo->countrycode)) == 0
  286. || (countryinfo->len <= COUNTRY_CODE_LEN)) {
  287. /* No region Info or Wrong region info: treat as No 11D info */
  288. LEAVE();
  289. return 0;
  290. }
  291. /*Step1: check region_code */
  292. parsed_region_chan->region = region =
  293. wlan_region_2_code(countryinfo->countrycode);
  294. lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
  295. lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
  296. COUNTRY_CODE_LEN);
  297. parsed_region_chan->band = band;
  298. memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
  299. COUNTRY_CODE_LEN);
  300. nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
  301. sizeof(struct ieeetypes_subbandset);
  302. for (j = 0, lastchan = 0; j < nr_subband; j++) {
  303. if (countryinfo->subband[j].firstchan <= lastchan) {
  304. /*Step2&3. Check First Chan Num increment and no overlap */
  305. lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
  306. countryinfo->subband[j].firstchan, lastchan);
  307. continue;
  308. }
  309. firstchan = countryinfo->subband[j].firstchan;
  310. nrchan = countryinfo->subband[j].nrchan;
  311. for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
  312. /*step4: channel is supported? */
  313. if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
  314. /* Chan is not found in UN table */
  315. lbs_pr_debug(1, "chan is not supported: %d \n", i);
  316. break;
  317. }
  318. lastchan = curchan;
  319. if (wlan_region_chan_supported_11d
  320. (region, band, curchan)) {
  321. /*step5: Check if curchan is supported by mrvl in region */
  322. parsed_region_chan->chanpwr[idx].chan = curchan;
  323. parsed_region_chan->chanpwr[idx].pwr =
  324. countryinfo->subband[j].maxtxpwr;
  325. idx++;
  326. } else {
  327. /*not supported and ignore the chan */
  328. lbs_pr_debug(1,
  329. "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
  330. i, curchan, region, band);
  331. }
  332. }
  333. /*Step6: Add other checking if any */
  334. }
  335. parsed_region_chan->nr_chan = idx;
  336. lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
  337. lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
  338. 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
  339. LEAVE();
  340. return 0;
  341. }
  342. /**
  343. * @brief This function calculates the scan type for channels
  344. * @param chan chan number
  345. * @param parsed_region_chan pointer to parsed_region_chan_11d
  346. * @return PASSIVE if chan is unknown; ACTIVE if chan is known
  347. */
  348. u8 libertas_get_scan_type_11d(u8 chan,
  349. struct parsed_region_chan_11d * parsed_region_chan)
  350. {
  351. u8 scan_type = cmd_scan_type_passive;
  352. ENTER();
  353. if (wlan_channel_known_11d(chan, parsed_region_chan)) {
  354. lbs_pr_debug(1, "11D: Found and do Active Scan\n");
  355. scan_type = cmd_scan_type_active;
  356. } else {
  357. lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
  358. }
  359. LEAVE();
  360. return scan_type;
  361. }
  362. void libertas_init_11d(wlan_private * priv)
  363. {
  364. priv->adapter->enable11d = 0;
  365. memset(&(priv->adapter->parsed_region_chan), 0,
  366. sizeof(struct parsed_region_chan_11d));
  367. return;
  368. }
  369. static int wlan_enable_11d(wlan_private * priv, u8 flag)
  370. {
  371. int ret;
  372. priv->adapter->enable11d = flag;
  373. /* send cmd to FW to enable/disable 11D function in FW */
  374. ret = libertas_prepare_and_send_command(priv,
  375. cmd_802_11_snmp_mib,
  376. cmd_act_set,
  377. cmd_option_waitforrsp,
  378. OID_802_11D_ENABLE,
  379. &priv->adapter->enable11d);
  380. if (ret)
  381. lbs_pr_debug(1, "11D: Fail to enable 11D \n");
  382. return 0;
  383. }
  384. /**
  385. * @brief This function sets DOMAIN INFO to FW
  386. * @param priv pointer to wlan_private
  387. * @return 0; -1
  388. */
  389. static int set_domain_info_11d(wlan_private * priv)
  390. {
  391. int ret;
  392. if (!priv->adapter->enable11d) {
  393. lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
  394. return 0;
  395. }
  396. ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
  397. cmd_act_set,
  398. cmd_option_waitforrsp, 0, NULL);
  399. if (ret)
  400. lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
  401. return ret;
  402. }
  403. /**
  404. * @brief This function setups scan channels
  405. * @param priv pointer to wlan_private
  406. * @param band band
  407. * @return 0
  408. */
  409. int libertas_set_universaltable(wlan_private * priv, u8 band)
  410. {
  411. wlan_adapter *adapter = priv->adapter;
  412. u16 size = sizeof(struct chan_freq_power);
  413. u16 i = 0;
  414. memset(adapter->universal_channel, 0,
  415. sizeof(adapter->universal_channel));
  416. adapter->universal_channel[i].nrcfp =
  417. sizeof(channel_freq_power_UN_BG) / size;
  418. lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
  419. adapter->universal_channel[i].nrcfp);
  420. adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
  421. adapter->universal_channel[i].valid = 1;
  422. adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
  423. adapter->universal_channel[i].band = band;
  424. i++;
  425. return 0;
  426. }
  427. /**
  428. * @brief This function implements command CMD_802_11D_DOMAIN_INFO
  429. * @param priv pointer to wlan_private
  430. * @param cmd pointer to cmd buffer
  431. * @param cmdno cmd ID
  432. * @param cmdOption cmd action
  433. * @return 0
  434. */
  435. int libertas_cmd_802_11d_domain_info(wlan_private * priv,
  436. struct cmd_ds_command *cmd, u16 cmdno,
  437. u16 cmdoption)
  438. {
  439. struct cmd_ds_802_11d_domain_info *pdomaininfo =
  440. &cmd->params.domaininfo;
  441. struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
  442. wlan_adapter *adapter = priv->adapter;
  443. u8 nr_subband = adapter->domainreg.nr_subband;
  444. ENTER();
  445. lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
  446. cmd->command = cpu_to_le16(cmdno);
  447. pdomaininfo->action = cpu_to_le16(cmdoption);
  448. if (cmdoption == cmd_act_get) {
  449. cmd->size =
  450. cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
  451. lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
  452. (int)(cmd->size));
  453. LEAVE();
  454. return 0;
  455. }
  456. domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
  457. memcpy(domain->countrycode, adapter->domainreg.countrycode,
  458. sizeof(domain->countrycode));
  459. domain->header.len =
  460. cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
  461. sizeof(domain->countrycode));
  462. if (nr_subband) {
  463. memcpy(domain->subband, adapter->domainreg.subband,
  464. nr_subband * sizeof(struct ieeetypes_subbandset));
  465. cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
  466. domain->header.len +
  467. sizeof(struct mrvlietypesheader) +
  468. S_DS_GEN);
  469. } else {
  470. cmd->size =
  471. cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
  472. }
  473. lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
  474. LEAVE();
  475. return 0;
  476. }
  477. /**
  478. * @brief This function implements private cmd: enable/disable 11D
  479. * @param priv pointer to wlan_private
  480. * @param wrq pointer to user data
  481. * @return 0 or -1
  482. */
  483. int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
  484. {
  485. int data = 0;
  486. int *val;
  487. ENTER();
  488. data = SUBCMD_DATA(wrq);
  489. lbs_pr_debug(1, "enable 11D: %s\n",
  490. (data == 1) ? "enable" : "Disable");
  491. wlan_enable_11d(priv, data);
  492. val = (int *)wrq->u.name;
  493. *val = priv->adapter->enable11d;
  494. LEAVE();
  495. return 0;
  496. }
  497. /**
  498. * @brief This function parses countryinfo from AP and download country info to FW
  499. * @param priv pointer to wlan_private
  500. * @param resp pointer to command response buffer
  501. * @return 0; -1
  502. */
  503. int libertas_ret_802_11d_domain_info(wlan_private * priv,
  504. struct cmd_ds_command *resp)
  505. {
  506. struct cmd_ds_802_11d_domain_info
  507. *domaininfo = &resp->params.domaininforesp;
  508. struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
  509. u16 action = le16_to_cpu(domaininfo->action);
  510. s16 ret = 0;
  511. u8 nr_subband = 0;
  512. ENTER();
  513. lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
  514. (int)le16_to_cpu(resp->size));
  515. nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
  516. /* countrycode 3 bytes */
  517. lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
  518. if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
  519. lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
  520. return -1;
  521. }
  522. switch (action) {
  523. case cmd_act_set: /*Proc Set action */
  524. break;
  525. case cmd_act_get:
  526. break;
  527. default:
  528. lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
  529. ret = -1;
  530. break;
  531. }
  532. LEAVE();
  533. return ret;
  534. }
  535. /**
  536. * @brief This function parses countryinfo from AP and download country info to FW
  537. * @param priv pointer to wlan_private
  538. * @return 0; -1
  539. */
  540. int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
  541. {
  542. int ret;
  543. wlan_adapter *adapter = priv->adapter;
  544. ENTER();
  545. if (priv->adapter->enable11d) {
  546. memset(&adapter->parsed_region_chan, 0,
  547. sizeof(struct parsed_region_chan_11d));
  548. ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
  549. countryinfo, 0,
  550. &adapter->parsed_region_chan);
  551. if (ret == -1) {
  552. lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
  553. LEAVE();
  554. return ret;
  555. }
  556. memset(&adapter->domainreg, 0,
  557. sizeof(struct wlan_802_11d_domain_reg));
  558. generate_domain_info_11d(&adapter->parsed_region_chan,
  559. &adapter->domainreg);
  560. ret = set_domain_info_11d(priv);
  561. if (ret) {
  562. lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
  563. LEAVE();
  564. return ret;
  565. }
  566. }
  567. LEAVE();
  568. return 0;
  569. }
  570. /**
  571. * @brief This function generates 11D info from user specified regioncode and download to FW
  572. * @param priv pointer to wlan_private
  573. * @return 0; -1
  574. */
  575. int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
  576. {
  577. int ret;
  578. wlan_adapter *adapter = priv->adapter;
  579. struct region_channel *region_chan;
  580. u8 j;
  581. ENTER();
  582. lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
  583. if (priv->adapter->enable11d) {
  584. /* update parsed_region_chan_11; dnld domaininf to FW */
  585. for (j = 0; j < sizeof(adapter->region_channel) /
  586. sizeof(adapter->region_channel[0]); j++) {
  587. region_chan = &adapter->region_channel[j];
  588. lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
  589. region_chan->band);
  590. if (!region_chan || !region_chan->valid
  591. || !region_chan->CFP)
  592. continue;
  593. if (region_chan->band != adapter->curbssparams.band)
  594. continue;
  595. break;
  596. }
  597. if (j >= sizeof(adapter->region_channel) /
  598. sizeof(adapter->region_channel[0])) {
  599. lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
  600. adapter->curbssparams.band);
  601. LEAVE();
  602. return -1;
  603. }
  604. memset(&adapter->parsed_region_chan, 0,
  605. sizeof(struct parsed_region_chan_11d));
  606. wlan_generate_parsed_region_chan_11d(region_chan,
  607. &adapter->
  608. parsed_region_chan);
  609. memset(&adapter->domainreg, 0,
  610. sizeof(struct wlan_802_11d_domain_reg));
  611. generate_domain_info_11d(&adapter->parsed_region_chan,
  612. &adapter->domainreg);
  613. ret = set_domain_info_11d(priv);
  614. if (ret) {
  615. lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
  616. LEAVE();
  617. return ret;
  618. }
  619. }
  620. LEAVE();
  621. return 0;
  622. }