ie.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * NXP Wireless LAN device driver: management IE handling- setting and
  4. * deleting IE.
  5. *
  6. * Copyright 2011-2020 NXP
  7. */
  8. #include "main.h"
  9. /* This function checks if current IE index is used by any on other interface.
  10. * Return: -1: yes, current IE index is used by someone else.
  11. * 0: no, current IE index is NOT used by other interface.
  12. */
  13. static int
  14. mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
  15. {
  16. int i;
  17. struct mwifiex_adapter *adapter = priv->adapter;
  18. struct mwifiex_ie *ie;
  19. for (i = 0; i < adapter->priv_num; i++) {
  20. if (adapter->priv[i] != priv) {
  21. ie = &adapter->priv[i]->mgmt_ie[idx];
  22. if (ie->mgmt_subtype_mask && ie->ie_length)
  23. return -1;
  24. }
  25. }
  26. return 0;
  27. }
  28. /* Get unused IE index. This index will be used for setting new IE */
  29. static int
  30. mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
  31. struct mwifiex_ie *ie, u16 *index)
  32. {
  33. u16 mask, len, i;
  34. for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
  35. mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
  36. len = le16_to_cpu(ie->ie_length);
  37. if (mask == MWIFIEX_AUTO_IDX_MASK)
  38. continue;
  39. if (mask == subtype_mask) {
  40. if (len > IEEE_MAX_IE_SIZE)
  41. continue;
  42. *index = i;
  43. return 0;
  44. }
  45. if (!priv->mgmt_ie[i].ie_length) {
  46. if (mwifiex_ie_index_used_by_other_intf(priv, i))
  47. continue;
  48. *index = i;
  49. return 0;
  50. }
  51. }
  52. return -1;
  53. }
  54. /* This function prepares IE data buffer for command to be sent to FW */
  55. static int
  56. mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
  57. struct mwifiex_ie_list *ie_list)
  58. {
  59. u16 travel_len, index, mask;
  60. s16 input_len, tlv_len;
  61. struct mwifiex_ie *ie;
  62. u8 *tmp;
  63. input_len = le16_to_cpu(ie_list->len);
  64. travel_len = sizeof(struct mwifiex_ie_types_header);
  65. ie_list->len = 0;
  66. while (input_len >= sizeof(struct mwifiex_ie_types_header)) {
  67. ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
  68. tlv_len = le16_to_cpu(ie->ie_length);
  69. travel_len += tlv_len + MWIFIEX_IE_HDR_SIZE;
  70. if (input_len < tlv_len + MWIFIEX_IE_HDR_SIZE)
  71. return -1;
  72. index = le16_to_cpu(ie->ie_index);
  73. mask = le16_to_cpu(ie->mgmt_subtype_mask);
  74. if (index == MWIFIEX_AUTO_IDX_MASK) {
  75. /* automatic addition */
  76. if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
  77. return -1;
  78. if (index == MWIFIEX_AUTO_IDX_MASK)
  79. return -1;
  80. tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
  81. memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
  82. priv->mgmt_ie[index].ie_length = ie->ie_length;
  83. priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
  84. priv->mgmt_ie[index].mgmt_subtype_mask =
  85. cpu_to_le16(mask);
  86. ie->ie_index = cpu_to_le16(index);
  87. } else {
  88. if (mask != MWIFIEX_DELETE_MASK)
  89. return -1;
  90. /*
  91. * Check if this index is being used on any
  92. * other interface.
  93. */
  94. if (mwifiex_ie_index_used_by_other_intf(priv, index))
  95. return -1;
  96. ie->ie_length = 0;
  97. memcpy(&priv->mgmt_ie[index], ie,
  98. sizeof(struct mwifiex_ie));
  99. }
  100. le16_unaligned_add_cpu(&ie_list->len,
  101. le16_to_cpu(
  102. priv->mgmt_ie[index].ie_length) +
  103. MWIFIEX_IE_HDR_SIZE);
  104. input_len -= tlv_len + MWIFIEX_IE_HDR_SIZE;
  105. }
  106. if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
  107. return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
  108. HostCmd_ACT_GEN_SET,
  109. UAP_CUSTOM_IE_I, ie_list, true);
  110. return 0;
  111. }
  112. /* Copy individual custom IEs for beacon, probe response and assoc response
  113. * and prepare single structure for IE setting.
  114. * This function also updates allocated IE indices from driver.
  115. */
  116. static int
  117. mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
  118. struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
  119. struct mwifiex_ie *pr_ie, u16 *probe_idx,
  120. struct mwifiex_ie *ar_ie, u16 *assoc_idx)
  121. {
  122. struct mwifiex_ie_list *ap_custom_ie;
  123. u8 *pos;
  124. u16 len;
  125. int ret;
  126. ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL);
  127. if (!ap_custom_ie)
  128. return -ENOMEM;
  129. ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
  130. pos = (u8 *)ap_custom_ie->ie_list;
  131. if (beacon_ie) {
  132. len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
  133. le16_to_cpu(beacon_ie->ie_length);
  134. memcpy(pos, beacon_ie, len);
  135. pos += len;
  136. le16_unaligned_add_cpu(&ap_custom_ie->len, len);
  137. }
  138. if (pr_ie) {
  139. len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
  140. le16_to_cpu(pr_ie->ie_length);
  141. memcpy(pos, pr_ie, len);
  142. pos += len;
  143. le16_unaligned_add_cpu(&ap_custom_ie->len, len);
  144. }
  145. if (ar_ie) {
  146. len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
  147. le16_to_cpu(ar_ie->ie_length);
  148. memcpy(pos, ar_ie, len);
  149. pos += len;
  150. le16_unaligned_add_cpu(&ap_custom_ie->len, len);
  151. }
  152. ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
  153. pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
  154. if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
  155. /* save beacon ie index after auto-indexing */
  156. *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
  157. len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
  158. le16_to_cpu(beacon_ie->ie_length);
  159. pos += len;
  160. }
  161. if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
  162. /* save probe resp ie index after auto-indexing */
  163. *probe_idx = *((u16 *)pos);
  164. len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
  165. le16_to_cpu(pr_ie->ie_length);
  166. pos += len;
  167. }
  168. if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
  169. /* save assoc resp ie index after auto-indexing */
  170. *assoc_idx = *((u16 *)pos);
  171. kfree(ap_custom_ie);
  172. return ret;
  173. }
  174. /* This function checks if the vendor specified IE is present in passed buffer
  175. * and copies it to mwifiex_ie structure.
  176. * Function takes pointer to struct mwifiex_ie pointer as argument.
  177. * If the vendor specified IE is present then memory is allocated for
  178. * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
  179. * this memory.
  180. */
  181. static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
  182. struct mwifiex_ie **ie_ptr, u16 mask,
  183. unsigned int oui, u8 oui_type)
  184. {
  185. struct ieee_types_header *vs_ie;
  186. struct mwifiex_ie *ie = *ie_ptr;
  187. const u8 *vendor_ie;
  188. vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len);
  189. if (vendor_ie) {
  190. if (!*ie_ptr) {
  191. *ie_ptr = kzalloc(sizeof(struct mwifiex_ie),
  192. GFP_KERNEL);
  193. if (!*ie_ptr)
  194. return -ENOMEM;
  195. ie = *ie_ptr;
  196. }
  197. vs_ie = (struct ieee_types_header *)vendor_ie;
  198. if (le16_to_cpu(ie->ie_length) + vs_ie->len + 2 >
  199. IEEE_MAX_IE_SIZE)
  200. return -EINVAL;
  201. memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
  202. vs_ie, vs_ie->len + 2);
  203. le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2);
  204. ie->mgmt_subtype_mask = cpu_to_le16(mask);
  205. ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK);
  206. }
  207. *ie_ptr = ie;
  208. return 0;
  209. }
  210. /* This function parses beacon IEs, probe response IEs, association response IEs
  211. * from cfg80211_ap_settings->beacon and sets these IE to FW.
  212. */
  213. static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv,
  214. struct cfg80211_beacon_data *data)
  215. {
  216. struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL;
  217. u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
  218. u16 ar_idx = MWIFIEX_AUTO_IDX_MASK;
  219. int ret = 0;
  220. if (data->beacon_ies && data->beacon_ies_len) {
  221. mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
  222. &beacon_ie, MGMT_MASK_BEACON,
  223. WLAN_OUI_MICROSOFT,
  224. WLAN_OUI_TYPE_MICROSOFT_WPS);
  225. mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
  226. &beacon_ie, MGMT_MASK_BEACON,
  227. WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
  228. }
  229. if (data->proberesp_ies && data->proberesp_ies_len) {
  230. mwifiex_update_vs_ie(data->proberesp_ies,
  231. data->proberesp_ies_len, &pr_ie,
  232. MGMT_MASK_PROBE_RESP, WLAN_OUI_MICROSOFT,
  233. WLAN_OUI_TYPE_MICROSOFT_WPS);
  234. mwifiex_update_vs_ie(data->proberesp_ies,
  235. data->proberesp_ies_len, &pr_ie,
  236. MGMT_MASK_PROBE_RESP,
  237. WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
  238. }
  239. if (data->assocresp_ies && data->assocresp_ies_len) {
  240. mwifiex_update_vs_ie(data->assocresp_ies,
  241. data->assocresp_ies_len, &ar_ie,
  242. MGMT_MASK_ASSOC_RESP |
  243. MGMT_MASK_REASSOC_RESP,
  244. WLAN_OUI_MICROSOFT,
  245. WLAN_OUI_TYPE_MICROSOFT_WPS);
  246. mwifiex_update_vs_ie(data->assocresp_ies,
  247. data->assocresp_ies_len, &ar_ie,
  248. MGMT_MASK_ASSOC_RESP |
  249. MGMT_MASK_REASSOC_RESP, WLAN_OUI_WFA,
  250. WLAN_OUI_TYPE_WFA_P2P);
  251. }
  252. if (beacon_ie || pr_ie || ar_ie) {
  253. ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
  254. &beacon_idx, pr_ie,
  255. &pr_idx, ar_ie, &ar_idx);
  256. if (ret)
  257. goto done;
  258. }
  259. priv->beacon_idx = beacon_idx;
  260. priv->proberesp_idx = pr_idx;
  261. priv->assocresp_idx = ar_idx;
  262. done:
  263. kfree(beacon_ie);
  264. kfree(pr_ie);
  265. kfree(ar_ie);
  266. return ret;
  267. }
  268. /* This function parses head and tail IEs, from cfg80211_beacon_data and sets
  269. * these IE to FW.
  270. */
  271. static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
  272. struct cfg80211_beacon_data *info)
  273. {
  274. struct mwifiex_ie *gen_ie;
  275. struct ieee_types_header *hdr;
  276. struct ieee80211_vendor_ie *vendorhdr;
  277. u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
  278. int left_len, parsed_len = 0;
  279. unsigned int token_len;
  280. int err = 0;
  281. if (!info->tail || !info->tail_len)
  282. return 0;
  283. gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
  284. if (!gen_ie)
  285. return -ENOMEM;
  286. left_len = info->tail_len;
  287. /* Many IEs are generated in FW by parsing bss configuration.
  288. * Let's not add them here; else we may end up duplicating these IEs
  289. */
  290. while (left_len > sizeof(struct ieee_types_header)) {
  291. hdr = (void *)(info->tail + parsed_len);
  292. token_len = hdr->len + sizeof(struct ieee_types_header);
  293. if (token_len > left_len) {
  294. err = -EINVAL;
  295. goto out;
  296. }
  297. switch (hdr->element_id) {
  298. case WLAN_EID_SSID:
  299. case WLAN_EID_SUPP_RATES:
  300. case WLAN_EID_COUNTRY:
  301. case WLAN_EID_PWR_CONSTRAINT:
  302. case WLAN_EID_ERP_INFO:
  303. case WLAN_EID_EXT_SUPP_RATES:
  304. case WLAN_EID_HT_CAPABILITY:
  305. case WLAN_EID_HT_OPERATION:
  306. case WLAN_EID_VHT_CAPABILITY:
  307. case WLAN_EID_VHT_OPERATION:
  308. break;
  309. case WLAN_EID_VENDOR_SPECIFIC:
  310. /* Skip only Microsoft WMM IE */
  311. if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
  312. WLAN_OUI_TYPE_MICROSOFT_WMM,
  313. (const u8 *)hdr,
  314. token_len))
  315. break;
  316. fallthrough;
  317. default:
  318. if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
  319. err = -EINVAL;
  320. goto out;
  321. }
  322. memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
  323. ie_len += token_len;
  324. break;
  325. }
  326. left_len -= token_len;
  327. parsed_len += token_len;
  328. }
  329. /* parse only WPA vendor IE from tail, WMM IE is configured by
  330. * bss_config command
  331. */
  332. vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
  333. WLAN_OUI_TYPE_MICROSOFT_WPA,
  334. info->tail, info->tail_len);
  335. if (vendorhdr) {
  336. token_len = vendorhdr->len + sizeof(struct ieee_types_header);
  337. if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
  338. err = -EINVAL;
  339. goto out;
  340. }
  341. memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
  342. ie_len += token_len;
  343. }
  344. if (!ie_len)
  345. goto out;
  346. gen_ie->ie_index = cpu_to_le16(gen_idx);
  347. gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
  348. MGMT_MASK_PROBE_RESP |
  349. MGMT_MASK_ASSOC_RESP);
  350. gen_ie->ie_length = cpu_to_le16(ie_len);
  351. if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
  352. NULL, NULL)) {
  353. err = -EINVAL;
  354. goto out;
  355. }
  356. priv->gen_idx = gen_idx;
  357. out:
  358. kfree(gen_ie);
  359. return err;
  360. }
  361. /* This function parses different IEs-head & tail IEs, beacon IEs,
  362. * probe response IEs, association response IEs from cfg80211_ap_settings
  363. * function and sets these IE to FW.
  364. */
  365. int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
  366. struct cfg80211_beacon_data *info)
  367. {
  368. int ret;
  369. ret = mwifiex_uap_parse_tail_ies(priv, info);
  370. if (ret)
  371. return ret;
  372. return mwifiex_set_mgmt_beacon_data_ies(priv, info);
  373. }
  374. /* This function removes management IE set */
  375. int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
  376. {
  377. struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
  378. struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
  379. int ret = 0;
  380. if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) {
  381. gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL);
  382. if (!gen_ie)
  383. return -ENOMEM;
  384. gen_ie->ie_index = cpu_to_le16(priv->gen_idx);
  385. gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
  386. gen_ie->ie_length = 0;
  387. if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx,
  388. NULL, &priv->proberesp_idx,
  389. NULL, &priv->assocresp_idx)) {
  390. ret = -1;
  391. goto done;
  392. }
  393. priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
  394. }
  395. if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
  396. beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
  397. if (!beacon_ie) {
  398. ret = -ENOMEM;
  399. goto done;
  400. }
  401. beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
  402. beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
  403. beacon_ie->ie_length = 0;
  404. }
  405. if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
  406. pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
  407. if (!pr_ie) {
  408. ret = -ENOMEM;
  409. goto done;
  410. }
  411. pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
  412. pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
  413. pr_ie->ie_length = 0;
  414. }
  415. if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
  416. ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
  417. if (!ar_ie) {
  418. ret = -ENOMEM;
  419. goto done;
  420. }
  421. ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
  422. ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
  423. ar_ie->ie_length = 0;
  424. }
  425. if (beacon_ie || pr_ie || ar_ie)
  426. ret = mwifiex_update_uap_custom_ie(priv,
  427. beacon_ie, &priv->beacon_idx,
  428. pr_ie, &priv->proberesp_idx,
  429. ar_ie, &priv->assocresp_idx);
  430. done:
  431. kfree(gen_ie);
  432. kfree(beacon_ie);
  433. kfree(pr_ie);
  434. kfree(ar_ie);
  435. return ret;
  436. }