utils_mlo.c 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080
  1. /*
  2. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /*
  18. * DOC: contains MLO manager util api's
  19. */
  20. #include <wlan_cmn.h>
  21. #include <wlan_mlo_mgr_sta.h>
  22. #include <wlan_cm_public_struct.h>
  23. #include <wlan_mlo_mgr_main.h>
  24. #include <wlan_cm_api.h>
  25. #include "wlan_scan_api.h"
  26. #include "qdf_types.h"
  27. #include "utils_mlo.h"
  28. #include "wlan_mlo_mgr_cmn.h"
  29. #include "wlan_utility.h"
  30. #ifdef WLAN_FEATURE_11BE_MLO
  31. static uint8_t *util_find_eid(uint8_t eid, uint8_t *frame, qdf_size_t len)
  32. {
  33. if (!frame)
  34. return NULL;
  35. while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
  36. if (frame[ID_POS] == eid)
  37. return frame;
  38. len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
  39. frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
  40. }
  41. return NULL;
  42. }
  43. static
  44. uint8_t *util_find_extn_eid(uint8_t eid, uint8_t extn_eid,
  45. uint8_t *frame, qdf_size_t len)
  46. {
  47. if (!frame)
  48. return NULL;
  49. while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
  50. if ((frame[ID_POS] == eid) &&
  51. (frame[ELEM_ID_EXTN_POS] == extn_eid))
  52. return frame;
  53. len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
  54. frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
  55. }
  56. return NULL;
  57. }
  58. static
  59. uint8_t *util_parse_multi_link_ctrl(uint8_t *element,
  60. qdf_size_t len,
  61. qdf_size_t *link_info_len)
  62. {
  63. qdf_size_t parsed_ie_len = 0;
  64. struct wlan_ie_multilink *mlie_fixed;
  65. uint16_t mlcontrol;
  66. uint16_t presencebm;
  67. if (!element) {
  68. mlo_err("Pointer to element is NULL");
  69. return NULL;
  70. }
  71. if (!len) {
  72. mlo_err("Length is zero");
  73. return NULL;
  74. }
  75. if (len < sizeof(struct wlan_ie_multilink)) {
  76. mlo_err_rl("Length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  77. len, sizeof(struct wlan_ie_multilink));
  78. return NULL;
  79. }
  80. mlie_fixed = (struct wlan_ie_multilink *)element;
  81. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  82. presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  83. WLAN_ML_CTRL_PBM_BITS);
  84. parsed_ie_len += sizeof(*mlie_fixed);
  85. /* Check if MLD MAC address is present */
  86. if (presencebm & WLAN_ML_BV_CTRL_PBM_MLDMACADDR_P)
  87. parsed_ie_len += QDF_MAC_ADDR_SIZE;
  88. /* Check if Link ID info is present */
  89. if (presencebm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
  90. parsed_ie_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  91. /* Check if BSS parameter change count is present */
  92. if (presencebm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
  93. parsed_ie_len += WLAN_ML_BV_CINFO_BSSPARAMCHNGCNT_SIZE;
  94. /* Check if Medium Sync Delay Info is present */
  95. if (presencebm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P)
  96. parsed_ie_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
  97. /* Check if EML cap is present */
  98. if (presencebm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P)
  99. parsed_ie_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
  100. /* Check if MLD cap is present */
  101. if (presencebm & WLAN_ML_BV_CTRL_PBM_MLDCAP_P)
  102. parsed_ie_len += WLAN_ML_BV_CINFO_MLDCAP_SIZE;
  103. if (link_info_len) {
  104. *link_info_len = len - parsed_ie_len;
  105. mlo_debug("link_info_len:%zu, parsed_ie_len:%zu",
  106. *link_info_len, parsed_ie_len);
  107. }
  108. return &element[parsed_ie_len];
  109. }
  110. static
  111. uint8_t *util_parse_bvmlie_perstaprofile(uint8_t *subelement,
  112. qdf_size_t len,
  113. bool is_staprof_reqd,
  114. qdf_size_t *staprof_len,
  115. uint8_t *linkid,
  116. bool *is_macaddr_valid,
  117. struct qdf_mac_addr *macaddr)
  118. {
  119. qdf_size_t subelement_len = 0;
  120. struct wlan_ml_bv_linfo_perstaprof *perstaprof_fixed;
  121. uint16_t stacontrol;
  122. uint8_t completeprofile;
  123. uint8_t nstrlppresent;
  124. enum wlan_ml_bv_linfo_perstaprof_stactrl_nstrbmsz nstrbmsz;
  125. if (!subelement) {
  126. mlo_err("Pointer to subelement is NULL");
  127. return NULL;
  128. }
  129. if (!len) {
  130. mlo_err("Length is zero");
  131. return NULL;
  132. }
  133. if (subelement[0] != WLAN_ML_BV_LINFO_SUBELEMID_PERSTAPROFILE) {
  134. mlo_err_rl("Pointer to subelement does not point to per-STA profile");
  135. return NULL;
  136. }
  137. if (len < sizeof(struct wlan_ml_bv_linfo_perstaprof)) {
  138. mlo_err_rl("len %zu octets is smaller than that required for the fixed portion of per-STA profile (%zu octets)",
  139. len, sizeof(struct wlan_ml_bv_linfo_perstaprof));
  140. return NULL;
  141. }
  142. perstaprof_fixed = (struct wlan_ml_bv_linfo_perstaprof *)subelement;
  143. subelement_len = sizeof(*perstaprof_fixed);
  144. stacontrol = le16toh(perstaprof_fixed->stacontrol);
  145. if (linkid) {
  146. *linkid = QDF_GET_BITS(stacontrol,
  147. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
  148. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
  149. }
  150. /* Check if this a complete profile */
  151. completeprofile = QDF_GET_BITS(stacontrol,
  152. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
  153. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
  154. /* We increment the measured length of the per-STA profile by checking
  155. * for the presence of individual fields. We validate this length
  156. * against the total length of the sublement only at the end, except in
  157. * cases where we are actually about to access a given field.
  158. */
  159. if (is_macaddr_valid)
  160. *is_macaddr_valid = false;
  161. /* Check STA MAC address present bit */
  162. if (QDF_GET_BITS(stacontrol,
  163. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX,
  164. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) {
  165. if (macaddr) {
  166. /* Explicityly check if the length is sufficient to hold
  167. * the STA MAC address, since we are about to attempt to
  168. * access the STA MAC address.
  169. */
  170. if (len < (subelement_len + QDF_MAC_ADDR_SIZE)) {
  171. mlo_err_rl("len %zu octets is smaller than min size of per-STA profile required to accommodate STA MAC address (%zu octets)",
  172. len,
  173. (subelement_len + QDF_MAC_ADDR_SIZE));
  174. return NULL;
  175. }
  176. qdf_mem_copy(macaddr->bytes,
  177. subelement + subelement_len,
  178. QDF_MAC_ADDR_SIZE);
  179. mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT,
  180. subelement + subelement_len);
  181. if (is_macaddr_valid)
  182. *is_macaddr_valid = true;
  183. }
  184. subelement_len += QDF_MAC_ADDR_SIZE;
  185. }
  186. /* Check Beacon Interval present bit */
  187. if (QDF_GET_BITS(stacontrol,
  188. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX,
  189. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS))
  190. subelement_len += WLAN_BEACONINTERVAL_LEN;
  191. /* Check DTIM Info present bit */
  192. if (QDF_GET_BITS(stacontrol,
  193. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX,
  194. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS))
  195. subelement_len +=
  196. sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo);
  197. /* Check NTSR Link pair present bit */
  198. nstrlppresent =
  199. QDF_GET_BITS(stacontrol,
  200. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX,
  201. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS);
  202. if (completeprofile && nstrlppresent) {
  203. /* Check NTSR Bitmap Size bit */
  204. nstrbmsz =
  205. QDF_GET_BITS(stacontrol,
  206. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX,
  207. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS);
  208. if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) {
  209. subelement_len += 1;
  210. } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) {
  211. subelement_len += 2;
  212. } else {
  213. /* Though an invalid value cannot occur if only 1 bit is
  214. * used, we check for it in a generic manner in case the
  215. * number of bits is increased in the future.
  216. */
  217. mlo_err_rl("Invalid NSTR Bitmap size %u", nstrbmsz);
  218. return NULL;
  219. }
  220. }
  221. /* Note: Some implementation versions of hostapd/wpa_supplicant may
  222. * provide a per-STA profile without STA profile. Let the caller
  223. * indicate whether a STA profile is required to be found. This may be
  224. * revisited as upstreaming progresses.
  225. */
  226. if (!is_staprof_reqd) {
  227. if (len < subelement_len) {
  228. mlo_err_rl("len %zu < subelement_len %zu",
  229. len,
  230. subelement_len);
  231. return NULL;
  232. }
  233. return &subelement[subelement_len - 1];
  234. }
  235. if (len <= subelement_len) {
  236. mlo_err_rl("len %zu <= subelement_len %zu",
  237. len,
  238. subelement_len);
  239. return NULL;
  240. }
  241. if (staprof_len)
  242. *staprof_len = len - subelement_len;
  243. return &subelement[subelement_len];
  244. }
  245. static
  246. uint8_t *util_get_successorfrag(uint8_t *currie, uint8_t *frame, qdf_size_t len)
  247. {
  248. uint8_t *nextie;
  249. if (!currie || !frame || !len)
  250. return NULL;
  251. if ((currie + MIN_IE_LEN) > (frame + len))
  252. return NULL;
  253. /* Check whether there is sufficient space in the frame for the current
  254. * IE, plus at least another MIN_IE_LEN bytes for the IE header of a
  255. * fragment (if present) that would come just after the current IE.
  256. */
  257. if ((currie + MIN_IE_LEN + currie[TAG_LEN_POS] + MIN_IE_LEN) >
  258. (frame + len))
  259. return NULL;
  260. nextie = currie + currie[TAG_LEN_POS] + MIN_IE_LEN;
  261. if (nextie[ID_POS] != WLAN_ELEMID_FRAGMENT)
  262. return NULL;
  263. return nextie;
  264. }
  265. static
  266. QDF_STATUS util_parse_partner_info_from_linkinfo(uint8_t *linkinfo,
  267. qdf_size_t linkinfo_len,
  268. struct mlo_partner_info *partner_info)
  269. {
  270. uint8_t linkid;
  271. struct qdf_mac_addr macaddr;
  272. bool is_macaddr_valid;
  273. uint8_t *currpos;
  274. qdf_size_t currlen;
  275. uint8_t *endofstainfo;
  276. if (!linkinfo) {
  277. mlo_err("linkinfo is NULL");
  278. return QDF_STATUS_E_NULL_VALUE;
  279. }
  280. if (!linkinfo_len) {
  281. mlo_err("linkinfo_len is zero");
  282. return QDF_STATUS_E_NULL_VALUE;
  283. }
  284. if (!partner_info) {
  285. mlo_err("ML partner info is NULL");
  286. return QDF_STATUS_E_NULL_VALUE;
  287. }
  288. partner_info->num_partner_links = 0;
  289. currpos = linkinfo;
  290. currlen = linkinfo_len;
  291. while (currlen) {
  292. if (currlen < MIN_IE_LEN) {
  293. mlo_err_rl("currlen %zu is smaller than minimum IE length %u",
  294. currlen, MIN_IE_LEN);
  295. return QDF_STATUS_E_PROTO;
  296. }
  297. if (currlen < (MIN_IE_LEN + currpos[TAG_LEN_POS])) {
  298. mlo_err_rl("currlen %zu is smaller than length of current IE %u",
  299. currlen, MIN_IE_LEN + currpos[TAG_LEN_POS]);
  300. return QDF_STATUS_E_PROTO;
  301. }
  302. if (currpos[ID_POS] ==
  303. WLAN_ML_BV_LINFO_SUBELEMID_PERSTAPROFILE) {
  304. is_macaddr_valid = false;
  305. /* Per-STA profile fragmentation support may be added
  306. * once support for this is introduced in the standard.
  307. */
  308. endofstainfo =
  309. util_parse_bvmlie_perstaprofile(currpos,
  310. currlen,
  311. false,
  312. NULL,
  313. &linkid,
  314. &is_macaddr_valid,
  315. &macaddr);
  316. if (!endofstainfo) {
  317. mlo_err_rl("Error in parsing per-STA profile");
  318. return QDF_STATUS_E_EMPTY;
  319. }
  320. if (is_macaddr_valid) {
  321. if (partner_info->num_partner_links >=
  322. QDF_ARRAY_SIZE(partner_info->partner_link_info)) {
  323. mlo_err_rl("Insufficient size %zu of array for partner link info",
  324. QDF_ARRAY_SIZE(partner_info->partner_link_info));
  325. return QDF_STATUS_E_NOMEM;
  326. }
  327. partner_info->partner_link_info[partner_info->num_partner_links].link_id =
  328. linkid;
  329. qdf_mem_copy(&partner_info->partner_link_info[partner_info->num_partner_links].link_addr,
  330. &macaddr,
  331. sizeof(partner_info->partner_link_info[partner_info->num_partner_links].link_addr));
  332. partner_info->num_partner_links++;
  333. } else {
  334. mlo_warn_rl("MAC address not found in STA Info field of per-STA profile with link ID %u",
  335. linkid);
  336. }
  337. }
  338. currlen -= (MIN_IE_LEN + currpos[TAG_LEN_POS]);
  339. currpos += (MIN_IE_LEN + currpos[TAG_LEN_POS]);
  340. }
  341. mlo_debug("Number of ML partner links found=%u",
  342. partner_info->num_partner_links);
  343. return QDF_STATUS_SUCCESS;
  344. }
  345. static
  346. QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len,
  347. uint8_t **ninherit_elemlist,
  348. qdf_size_t *ninherit_elemlist_len,
  349. uint8_t **ninherit_elemextlist,
  350. qdf_size_t *ninherit_elemextlist_len)
  351. {
  352. uint8_t *ninherit_ie;
  353. qdf_size_t unparsed_len;
  354. /* Note: This funtionality provided by this helper may be combined with
  355. * other, older non-inheritance parsing helper functionality and exposed
  356. * as a common API as part of future efforts once the older
  357. * functionality can be made generic.
  358. */
  359. if (!buff) {
  360. mlo_err("Pointer to buffer for IEs is NULL");
  361. return QDF_STATUS_E_NULL_VALUE;
  362. }
  363. if (!buff_len) {
  364. mlo_err("IE buffer length is zero");
  365. return QDF_STATUS_E_INVAL;
  366. }
  367. if (!ninherit_elemlist) {
  368. mlo_err("Pointer to Non-Inheritance element ID list array is NULL");
  369. return QDF_STATUS_E_NULL_VALUE;
  370. }
  371. if (!ninherit_elemlist_len) {
  372. mlo_err("Pointer to Non-Inheritance element ID list array length is NULL");
  373. return QDF_STATUS_E_NULL_VALUE;
  374. }
  375. if (!ninherit_elemextlist) {
  376. mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL");
  377. return QDF_STATUS_E_NULL_VALUE;
  378. }
  379. if (!ninherit_elemextlist_len) {
  380. mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL");
  381. return QDF_STATUS_E_NULL_VALUE;
  382. }
  383. ninherit_ie = NULL;
  384. *ninherit_elemlist_len = 0;
  385. *ninherit_elemlist = NULL;
  386. *ninherit_elemextlist_len = 0;
  387. *ninherit_elemextlist = NULL;
  388. ninherit_ie =
  389. (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
  390. WLAN_EXTN_ELEMID_NONINHERITANCE,
  391. buff,
  392. buff_len);
  393. if (ninherit_ie) {
  394. if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) {
  395. mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary");
  396. return QDF_STATUS_E_PROTO;
  397. }
  398. if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) >
  399. (buff + buff_len)) {
  400. mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary",
  401. ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN);
  402. return QDF_STATUS_E_PROTO;
  403. }
  404. if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) <
  405. MIN_NONINHERITANCEELEM_LEN) {
  406. mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u",
  407. ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN,
  408. MIN_NONINHERITANCEELEM_LEN);
  409. return QDF_STATUS_E_PROTO;
  410. }
  411. /* Track the number of unparsed octets, excluding the IE header.
  412. */
  413. unparsed_len = ninherit_ie[TAG_LEN_POS];
  414. /* Mark the element ID extension as parsed */
  415. unparsed_len--;
  416. *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS];
  417. unparsed_len--;
  418. /* While checking if the Non-Inheritance element ID list length
  419. * exceeds the remaining unparsed IE space, we factor in one
  420. * octet for the element extension ID list length and subtract
  421. * this from the unparsed IE space.
  422. */
  423. if (*ninherit_elemlist_len > (unparsed_len - 1)) {
  424. mlo_err_rl("Non-Inheritance element ID list length %zu exceeds remaining unparsed IE space, minus an octet for element extension ID list length %zu",
  425. *ninherit_elemlist_len, unparsed_len - 1);
  426. return QDF_STATUS_E_PROTO;
  427. }
  428. if (*ninherit_elemlist_len != 0) {
  429. *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS;
  430. unparsed_len -= *ninherit_elemlist_len;
  431. }
  432. *ninherit_elemextlist_len =
  433. ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1];
  434. unparsed_len--;
  435. if (*ninherit_elemextlist_len > unparsed_len) {
  436. mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu",
  437. *ninherit_elemextlist_len, unparsed_len);
  438. return QDF_STATUS_E_PROTO;
  439. }
  440. if (*ninherit_elemextlist_len != 0) {
  441. *ninherit_elemextlist = ninherit_ie +
  442. ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len)
  443. + 2;
  444. unparsed_len -= *ninherit_elemlist_len;
  445. }
  446. if (unparsed_len > 0) {
  447. mlo_err_rl("Unparsed length is %zu, expected 0",
  448. unparsed_len);
  449. return QDF_STATUS_E_PROTO;
  450. }
  451. }
  452. /* If Non-Inheritance element is not found, we still return success,
  453. * with the list lengths kept at zero.
  454. */
  455. mlo_debug("Non-Inheritance element ID list array length=%zu",
  456. *ninherit_elemlist_len);
  457. mlo_debug("Non-Inheritance element ID extension list array length=%zu",
  458. *ninherit_elemextlist_len);
  459. return QDF_STATUS_SUCCESS;
  460. }
  461. static
  462. QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len,
  463. uint8_t *ninherit_elemlist,
  464. qdf_size_t ninherit_elemlist_len,
  465. uint8_t *ninherit_elemextlist,
  466. qdf_size_t ninherit_elemextlist_len,
  467. bool *is_in_noninheritlist)
  468. {
  469. int i;
  470. /* Evaluate whether the given IE is in the given Non-Inheritance element
  471. * ID list or Non-Inheritance element ID extension list, and update the
  472. * result into is_in_noninheritlist. If any list is empty, then the IE
  473. * is considered to not be present in that list. Both lists can be
  474. * empty.
  475. *
  476. * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is
  477. * successful, and that is_in_noninheritlist contains a valid value
  478. * (which could be true or false). If a QDF_STATUS error value is
  479. * returned, the value in is_in_noninheritlist is invalid and the caller
  480. * should ignore it.
  481. */
  482. /* Note: The funtionality provided by this helper may be combined with
  483. * other, older non-inheritance parsing helper functionality and exposed
  484. * as a common API as part of future efforts once the older
  485. * functionality can be made generic.
  486. */
  487. /* Except for is_in_noninheritlist and ie, other pointer arguments are
  488. * permitted to be NULL if they are inapplicable. If they are
  489. * applicable, they will be checked to ensure they are not NULL.
  490. */
  491. if (!is_in_noninheritlist) {
  492. mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list");
  493. return QDF_STATUS_E_NULL_VALUE;
  494. }
  495. /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero
  496. * as checked soon in this function, we won't be accessing the IE.
  497. * However, we still check right-away if the pointer to the IE is
  498. * non-NULL and whether the total IE length is sane enough to access the
  499. * element ID and if applicable, the element ID extension, since it
  500. * doesn't make sense to set the flag in is_in_noninheritlist for a NULL
  501. * IE pointer or an IE whose total length is not sane enough to
  502. * distinguish the identity of the IE.
  503. */
  504. if (!ie) {
  505. mlo_err("NULL pointer to IE");
  506. return QDF_STATUS_E_NULL_VALUE;
  507. }
  508. if (total_ie_len < (ID_POS + 1)) {
  509. mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u",
  510. total_ie_len, ID_POS + 1);
  511. return QDF_STATUS_E_INVAL;
  512. }
  513. if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  514. (total_ie_len < (IDEXT_POS + 1))) {
  515. mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u",
  516. total_ie_len, IDEXT_POS + 1);
  517. return QDF_STATUS_E_INVAL;
  518. }
  519. *is_in_noninheritlist = false;
  520. /* If both the Non-Inheritance element list and Non-Inheritance element
  521. * ID extension list are empty, then return success since we can
  522. * conclude immediately that the given element does not occur in any
  523. * Non-Inheritance list. The is_in_noninheritlist remains set to false
  524. * as required.
  525. */
  526. if (!ninherit_elemlist_len && !ninherit_elemextlist_len)
  527. return QDF_STATUS_SUCCESS;
  528. if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
  529. if (!ninherit_elemlist_len)
  530. return QDF_STATUS_SUCCESS;
  531. if (!ninherit_elemlist) {
  532. mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu",
  533. ninherit_elemlist_len);
  534. return QDF_STATUS_E_NULL_VALUE;
  535. }
  536. for (i = 0; i < ninherit_elemlist_len; i++) {
  537. if (ie[ID_POS] == ninherit_elemlist[i]) {
  538. *is_in_noninheritlist = true;
  539. return QDF_STATUS_SUCCESS;
  540. }
  541. }
  542. } else {
  543. if (!ninherit_elemextlist_len)
  544. return QDF_STATUS_SUCCESS;
  545. if (!ninherit_elemextlist) {
  546. mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu",
  547. ninherit_elemextlist_len);
  548. return QDF_STATUS_E_NULL_VALUE;
  549. }
  550. for (i = 0; i < ninherit_elemextlist_len; i++) {
  551. if (ie[IDEXT_POS] == ninherit_elemextlist[i]) {
  552. *is_in_noninheritlist = true;
  553. return QDF_STATUS_SUCCESS;
  554. }
  555. }
  556. }
  557. return QDF_STATUS_SUCCESS;
  558. }
  559. static inline
  560. QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie,
  561. const uint8_t *frame_iesection,
  562. const qdf_size_t frame_iesection_len)
  563. {
  564. qdf_size_t reportingsta_ie_size;
  565. if (!reportingsta_ie) {
  566. mlo_err("Pointer to reporting STA IE is NULL");
  567. return QDF_STATUS_E_NULL_VALUE;
  568. }
  569. if (!frame_iesection) {
  570. mlo_err("Pointer to start of IE section in reporting frame is NULL");
  571. return QDF_STATUS_E_NULL_VALUE;
  572. }
  573. if (!frame_iesection_len) {
  574. mlo_err("Length of IE section in reporting frame is zero");
  575. return QDF_STATUS_E_INVAL;
  576. }
  577. if ((reportingsta_ie + ID_POS) > (frame_iesection +
  578. frame_iesection_len - 1)) {
  579. mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary");
  580. return QDF_STATUS_E_PROTO;
  581. }
  582. if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection +
  583. frame_iesection_len - 1)) {
  584. mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary",
  585. reportingsta_ie[ID_POS]);
  586. return QDF_STATUS_E_PROTO;
  587. }
  588. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  589. ((reportingsta_ie + IDEXT_POS) > (frame_iesection +
  590. frame_iesection_len - 1))) {
  591. mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary");
  592. return QDF_STATUS_E_PROTO;
  593. }
  594. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
  595. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  596. (reportingsta_ie_size < (IDEXT_POS + 1))) {
  597. mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u",
  598. reportingsta_ie_size, IDEXT_POS + 1);
  599. return QDF_STATUS_E_PROTO;
  600. }
  601. if ((reportingsta_ie + reportingsta_ie_size) >
  602. (frame_iesection + frame_iesection_len)) {
  603. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  604. mlo_err_rl("Total size %zu octets of element with element ID %u element ID extension %u for reporting STA would exceed frame IE section boundary",
  605. reportingsta_ie_size,
  606. reportingsta_ie[ID_POS],
  607. reportingsta_ie[IDEXT_POS]);
  608. } else {
  609. mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary",
  610. reportingsta_ie_size,
  611. reportingsta_ie[ID_POS]);
  612. }
  613. return QDF_STATUS_E_PROTO;
  614. }
  615. return QDF_STATUS_SUCCESS;
  616. }
  617. static inline
  618. QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie,
  619. const uint8_t *sta_prof_iesection,
  620. const qdf_size_t sta_prof_iesection_len)
  621. {
  622. qdf_size_t sta_prof_ie_size;
  623. if (!sta_prof_ie) {
  624. mlo_err("Pointer to STA profile IE is NULL");
  625. return QDF_STATUS_E_NULL_VALUE;
  626. }
  627. if (!sta_prof_iesection) {
  628. mlo_err("Pointer to start of IE section in STA profile is NULL");
  629. return QDF_STATUS_E_NULL_VALUE;
  630. }
  631. if (!sta_prof_iesection_len) {
  632. mlo_err("Length of IE section in STA profile is zero");
  633. return QDF_STATUS_E_INVAL;
  634. }
  635. if ((sta_prof_ie + ID_POS) > (sta_prof_iesection +
  636. sta_prof_iesection_len - 1)) {
  637. mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary");
  638. return QDF_STATUS_E_PROTO;
  639. }
  640. if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection +
  641. sta_prof_iesection_len - 1)) {
  642. mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary",
  643. sta_prof_ie[ID_POS]);
  644. return QDF_STATUS_E_PROTO;
  645. }
  646. if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  647. ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection +
  648. sta_prof_iesection_len - 1))) {
  649. mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary");
  650. return QDF_STATUS_E_PROTO;
  651. }
  652. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
  653. if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  654. (sta_prof_ie_size < (IDEXT_POS + 1))) {
  655. mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u",
  656. sta_prof_ie_size, IDEXT_POS + 1);
  657. return QDF_STATUS_E_PROTO;
  658. }
  659. if ((sta_prof_ie + sta_prof_ie_size) >
  660. (sta_prof_iesection + sta_prof_iesection_len)) {
  661. if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  662. mlo_err_rl("Total size %zu octets of element with element ID %u element ID extension %u in STA profile would exceed STA profile IE section boundary",
  663. sta_prof_ie_size,
  664. sta_prof_ie[ID_POS],
  665. sta_prof_ie[IDEXT_POS]);
  666. } else {
  667. mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary",
  668. sta_prof_ie_size,
  669. sta_prof_ie[ID_POS]);
  670. }
  671. return QDF_STATUS_E_PROTO;
  672. }
  673. return QDF_STATUS_SUCCESS;
  674. }
  675. #define MLO_LINKSPECIFIC_ASSOC_REQ_FC0 0x00
  676. #define MLO_LINKSPECIFIC_ASSOC_REQ_FC1 0x00
  677. #define MLO_LINKSPECIFIC_ASSOC_RESP_FC0 0x10
  678. #define MLO_LINKSPECIFIC_ASSOC_RESP_FC1 0x00
  679. static
  680. QDF_STATUS util_gen_link_assoc_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len,
  681. uint8_t subtype,
  682. struct qdf_mac_addr link_addr,
  683. uint8_t *link_frame,
  684. qdf_size_t link_frame_maxsize,
  685. qdf_size_t *link_frame_len)
  686. {
  687. /* Please see documentation for util_gen_link_assoc_req() and
  688. * util_gen_link_assoc_resp() for information on the inputs to and
  689. * output from this helper, since those APIs are essentially wrappers
  690. * over this helper.
  691. */
  692. /* Pointer to Multi-Link element */
  693. uint8_t *mlie;
  694. /* Total length of Multi-Link element sequence (including fragements if
  695. * any)
  696. */
  697. qdf_size_t mlieseqlen;
  698. /* Variant (i.e. type) of the Multi-Link element */
  699. enum wlan_ml_variant variant;
  700. /* Pointer to original copy of Multi-Link element */
  701. uint8_t *orig_mlie_copy;
  702. /* Length of the Link Info */
  703. qdf_size_t link_info_len;
  704. /* Pointer to the IE section that occurs after the fixed fields in the
  705. * original frame for the reporting STA.
  706. */
  707. uint8_t *frame_iesection;
  708. /* Offset to the start of the IE section in the original frame for the
  709. * reporting STA.
  710. */
  711. qdf_size_t frame_iesection_offset;
  712. /* Total length of the IE section in the original frame for the
  713. * reporting STA.
  714. */
  715. qdf_size_t frame_iesection_len;
  716. /* Pointer to the IEEE802.11 frame header in the link specific frame
  717. * being generated for the reported STA.
  718. */
  719. struct wlan_frame_hdr *link_frame_hdr;
  720. /* Current position in the link specific frame being generated for the
  721. * reported STA.
  722. */
  723. uint8_t *link_frame_currpos;
  724. /* Current length of the link specific frame being generated for the
  725. * reported STA.
  726. */
  727. qdf_size_t link_frame_currlen;
  728. /* Pointer to IE for reporting STA */
  729. const uint8_t *reportingsta_ie;
  730. /* Total size of IE for reporting STA, inclusive of the element header
  731. */
  732. qdf_size_t reportingsta_ie_size;
  733. /* Pointer to current position in STA profile */
  734. uint8_t *sta_prof_currpos;
  735. /* Remaining length of STA profile */
  736. qdf_size_t sta_prof_remlen;
  737. /* Pointer to start of IE section in STA profile that occurs after fixed
  738. * fields.
  739. */
  740. uint8_t *sta_prof_iesection;
  741. /* Total length of IE section in STA profile */
  742. qdf_size_t sta_prof_iesection_len;
  743. /* Pointer to current position being processed in IE section in STA
  744. * profile.
  745. */
  746. uint8_t *sta_prof_iesection_currpos;
  747. /* Remaining length of IE section in STA profile */
  748. qdf_size_t sta_prof_iesection_remlen;
  749. /* Pointer to IE in STA profile, that occurs within IE section */
  750. uint8_t *sta_prof_ie;
  751. /* Total size of IE in STA profile, inclusive of the element header */
  752. qdf_size_t sta_prof_ie_size;
  753. /* Pointer to element ID list in Non-Inheritance IE */
  754. uint8_t *ninherit_elemlist;
  755. /* Length of element ID list in Non-Inheritance IE */
  756. qdf_size_t ninherit_elemlist_len;
  757. /* Pointer to element ID extension list in Non-Inheritance IE */
  758. uint8_t *ninherit_elemextlist;
  759. /* Length of element ID extension list in Non-Inheritance IE */
  760. qdf_size_t ninherit_elemextlist_len;
  761. /* Whether a given IE is in a non-inheritance list */
  762. bool is_in_noninheritlist;
  763. /* Whether MAC address of reported STA is valid */
  764. bool is_reportedmacaddr_valid;
  765. /* MAC address of reported STA */
  766. struct qdf_mac_addr reportedmacaddr;
  767. /* Other variables for temporary purposes */
  768. uint8_t *sub_copy;
  769. QDF_STATUS ret;
  770. if (!frame) {
  771. mlo_err("Pointer to original frame is NULL");
  772. return QDF_STATUS_E_NULL_VALUE;
  773. }
  774. if (!frame_len) {
  775. mlo_err("Length of original frame is zero");
  776. return QDF_STATUS_E_INVAL;
  777. }
  778. if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) &&
  779. (subtype != WLAN_FC0_STYPE_REASSOC_REQ) &&
  780. (subtype != WLAN_FC0_STYPE_ASSOC_RESP) &&
  781. (subtype != WLAN_FC0_STYPE_REASSOC_RESP)) {
  782. mlo_err("802.11 frame subtype %u is invalid", subtype);
  783. return QDF_STATUS_E_INVAL;
  784. }
  785. if (!link_frame) {
  786. mlo_err("Pointer to secondary link specific frame is NULL");
  787. return QDF_STATUS_E_NULL_VALUE;
  788. }
  789. if (!link_frame_maxsize) {
  790. mlo_err("Maximum size of secondary link specific frame is zero");
  791. return QDF_STATUS_E_INVAL;
  792. }
  793. if (!link_frame_len) {
  794. mlo_err("Pointer to populated length of secondary link specific frame is NULL");
  795. return QDF_STATUS_E_NULL_VALUE;
  796. }
  797. frame_iesection_offset = 0;
  798. if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) {
  799. frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET;
  800. } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
  801. frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET;
  802. } else {
  803. /* This is a (re)association response */
  804. frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET;
  805. }
  806. if (frame_len < frame_iesection_offset) {
  807. /* The caller is supposed to have confirmed that this is a valid
  808. * frame containing a Multi-Link element. Hence we treat this as
  809. * a case of invalid argument being passed to us.
  810. */
  811. mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u",
  812. frame_len, frame_iesection_offset, subtype);
  813. return QDF_STATUS_E_INVAL;
  814. }
  815. frame_iesection_len = frame_len - frame_iesection_offset;
  816. if (frame_iesection_len == 0) {
  817. /* The caller is supposed to have confirmed that this is a valid
  818. * frame containing a Multi-Link element. Hence we treat this as
  819. * a case of invalid argument being passed to us.
  820. */
  821. mlo_err("No space left in frame for IE section");
  822. return QDF_STATUS_E_INVAL;
  823. }
  824. frame_iesection = frame + frame_iesection_offset;
  825. mlie = NULL;
  826. mlieseqlen = 0;
  827. ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlie,
  828. &mlieseqlen);
  829. if (QDF_IS_STATUS_ERROR(ret))
  830. return ret;
  831. if (!mlie) {
  832. /* The caller is supposed to have confirmed that a Multi-Link
  833. * element is present in the frame. Hence we treat this as a
  834. * case of invalid argument being passed to us.
  835. */
  836. mlo_err("Invalid original frame since no Multi-Link element found");
  837. return QDF_STATUS_E_INVAL;
  838. }
  839. /* Sanity check the Multi-Link element sequence length */
  840. if (!mlieseqlen) {
  841. mlo_err("Length of Multi-Link element sequence is zero. Investigate.");
  842. return QDF_STATUS_E_FAILURE;
  843. }
  844. ret = util_get_mlie_variant(mlie, mlieseqlen, (int *)&variant);
  845. if (QDF_IS_STATUS_ERROR(ret))
  846. return ret;
  847. if (variant != WLAN_ML_VARIANT_BASIC) {
  848. mlo_err_rl("Unexpected variant %u of Multi-Link element.",
  849. variant);
  850. return QDF_STATUS_E_PROTO;
  851. }
  852. /* Note: Multi-Link element fragmentation support will be added in a
  853. * later change. As of now, we temporarily return error if the
  854. * Multi-Link element sequence length is greater than the max length for
  855. * an IE.
  856. */
  857. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  858. mlo_err_rl("Element fragmentation is not yet supported for this API");
  859. return QDF_STATUS_E_NOSUPPORT;
  860. }
  861. sub_copy = qdf_mem_malloc(mlieseqlen);
  862. if (!sub_copy) {
  863. mlo_err_rl("Could not allocate memory for Multi-Link element copy");
  864. return QDF_STATUS_E_NOMEM;
  865. }
  866. orig_mlie_copy = sub_copy;
  867. qdf_mem_copy(sub_copy, mlie, mlieseqlen);
  868. sub_copy = util_parse_multi_link_ctrl(sub_copy,
  869. mlieseqlen,
  870. &link_info_len);
  871. /* As per the standard, the sender must include Link Info for
  872. * association request/response. Throw an error if we are unable to
  873. * obtain this.
  874. */
  875. if (!sub_copy) {
  876. mlo_err_rl("Unable to successfully parse Multi-Link element control and obtain Link Info");
  877. qdf_mem_free(orig_mlie_copy);
  878. return QDF_STATUS_E_PROTO;
  879. }
  880. mlo_debug("Dumping hex after parsing Multi-Link element control");
  881. QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_DEBUG,
  882. sub_copy, link_info_len);
  883. sta_prof_remlen = 0;
  884. is_reportedmacaddr_valid = false;
  885. /* Note: We may have a future change to skip subelements which are not
  886. * Per-STA Profile, handle more than two links in MLO, handle cases
  887. * where we unexpectedly find more Per-STA Profiles than expected, etc.
  888. */
  889. /* Parse per-STA profile */
  890. sta_prof_currpos =
  891. util_parse_bvmlie_perstaprofile(sub_copy,
  892. link_info_len,
  893. true,
  894. &sta_prof_remlen,
  895. NULL,
  896. &is_reportedmacaddr_valid,
  897. &reportedmacaddr);
  898. /* If we do not successfully find a STA Profile, we return an error.
  899. * This is because we need to get at least the expected fixed fields,
  900. * even if there is an (improbable) total inheritance.
  901. */
  902. if (!sta_prof_currpos) {
  903. mlo_err_rl("Unable to find STA profile");
  904. qdf_mem_free(orig_mlie_copy);
  905. return QDF_STATUS_E_PROTO;
  906. }
  907. /* As per the standard, the sender sets the MAC address in the per-STA
  908. * profile in association request/response. Without this, we cannot
  909. * generate the link specific frame.
  910. */
  911. if (!is_reportedmacaddr_valid) {
  912. mlo_err_rl("Unable to get MAC address from per-STA profile");
  913. qdf_mem_free(orig_mlie_copy);
  914. return QDF_STATUS_E_PROTO;
  915. }
  916. link_frame_currpos = link_frame;
  917. *link_frame_len = 0;
  918. link_frame_currlen = 0;
  919. if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) {
  920. mlo_err("Insufficent space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets",
  921. WLAN_MAC_HDR_LEN_3A, link_frame_maxsize);
  922. qdf_mem_free(orig_mlie_copy);
  923. return QDF_STATUS_E_NOMEM;
  924. }
  925. link_frame_currpos += WLAN_MAC_HDR_LEN_3A;
  926. link_frame_currlen += WLAN_MAC_HDR_LEN_3A;
  927. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  928. (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
  929. mlo_debug("Populating fixed fields for (re)assoc req in link specific frame");
  930. if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) {
  931. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u",
  932. sta_prof_remlen,
  933. WLAN_CAPABILITYINFO_LEN);
  934. qdf_mem_free(orig_mlie_copy);
  935. return QDF_STATUS_E_PROTO;
  936. }
  937. /* Capability information is specific to the link. Copy this
  938. * from the STA profile.
  939. */
  940. if ((link_frame_maxsize - link_frame_currlen) <
  941. WLAN_CAPABILITYINFO_LEN) {
  942. mlo_err("Insufficent space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets",
  943. WLAN_CAPABILITYINFO_LEN,
  944. (link_frame_maxsize - link_frame_currlen));
  945. qdf_mem_free(orig_mlie_copy);
  946. return QDF_STATUS_E_NOMEM;
  947. }
  948. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  949. WLAN_CAPABILITYINFO_LEN);
  950. link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
  951. link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
  952. mlo_debug("Added Capablity Info field (%u octets) to link specific frame",
  953. WLAN_CAPABILITYINFO_LEN);
  954. sta_prof_currpos += WLAN_CAPABILITYINFO_LEN;
  955. sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN;
  956. /* Listen Interval is common between all links. Copy this from
  957. * the reporting section of the frame.
  958. */
  959. if ((link_frame_maxsize - link_frame_currlen) <
  960. WLAN_LISTENINTERVAL_LEN) {
  961. mlo_err("Insufficent space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets",
  962. WLAN_LISTENINTERVAL_LEN,
  963. (link_frame_maxsize - link_frame_currlen));
  964. qdf_mem_free(orig_mlie_copy);
  965. return QDF_STATUS_E_NOMEM;
  966. }
  967. qdf_mem_copy(link_frame_currpos,
  968. frame + WLAN_CAPABILITYINFO_LEN,
  969. WLAN_LISTENINTERVAL_LEN);
  970. link_frame_currpos += WLAN_LISTENINTERVAL_LEN;
  971. link_frame_currlen += WLAN_LISTENINTERVAL_LEN;
  972. mlo_debug("Added Listen Interval field (%u octets) to link specific frame",
  973. WLAN_LISTENINTERVAL_LEN);
  974. if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
  975. /* Current AP address is common between all links. Copy
  976. * this from the reporting section of the frame.
  977. */
  978. if ((link_frame_maxsize - link_frame_currlen) <
  979. QDF_MAC_ADDR_SIZE) {
  980. mlo_err("Insufficent space in link specific frame for current AP address. Required: %u octets, available: %zu octets",
  981. QDF_MAC_ADDR_SIZE,
  982. (link_frame_maxsize -
  983. link_frame_currlen));
  984. qdf_mem_free(orig_mlie_copy);
  985. return QDF_STATUS_E_NOMEM;
  986. }
  987. qdf_mem_copy(link_frame_currpos,
  988. frame + WLAN_CAPABILITYINFO_LEN +
  989. WLAN_LISTENINTERVAL_LEN,
  990. QDF_MAC_ADDR_SIZE);
  991. link_frame_currpos += QDF_MAC_ADDR_SIZE;
  992. link_frame_currlen += QDF_MAC_ADDR_SIZE;
  993. mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame",
  994. QDF_MAC_ADDR_SIZE);
  995. }
  996. } else {
  997. /* This is a (re)association response */
  998. mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame");
  999. if (sta_prof_remlen <
  1000. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
  1001. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u",
  1002. sta_prof_remlen,
  1003. WLAN_CAPABILITYINFO_LEN +
  1004. WLAN_STATUSCODE_LEN);
  1005. qdf_mem_free(orig_mlie_copy);
  1006. return QDF_STATUS_E_PROTO;
  1007. }
  1008. /* Capability information and Status Code are specific to the
  1009. * link. Copy these from the STA profile.
  1010. */
  1011. if ((link_frame_maxsize - link_frame_currlen) <
  1012. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
  1013. mlo_err("Insufficent space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets",
  1014. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN,
  1015. (link_frame_maxsize - link_frame_currlen));
  1016. qdf_mem_free(orig_mlie_copy);
  1017. return QDF_STATUS_E_NOMEM;
  1018. }
  1019. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  1020. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN));
  1021. link_frame_currpos += (WLAN_CAPABILITYINFO_LEN +
  1022. WLAN_STATUSCODE_LEN);
  1023. link_frame_currlen += (WLAN_CAPABILITYINFO_LEN +
  1024. WLAN_STATUSCODE_LEN);
  1025. mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame",
  1026. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN);
  1027. sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN +
  1028. WLAN_STATUSCODE_LEN);
  1029. sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN +
  1030. WLAN_STATUSCODE_LEN);
  1031. /* AID is common between all links. Copy this from the original
  1032. * frame.
  1033. */
  1034. if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) {
  1035. mlo_err("Insufficent space in link specific frame for AID field. Required: %u octets, available: %zu octets",
  1036. WLAN_AID_LEN,
  1037. (link_frame_maxsize - link_frame_currlen));
  1038. qdf_mem_free(orig_mlie_copy);
  1039. return QDF_STATUS_E_NOMEM;
  1040. }
  1041. qdf_mem_copy(link_frame_currpos,
  1042. frame + WLAN_CAPABILITYINFO_LEN +
  1043. WLAN_STATUSCODE_LEN,
  1044. WLAN_AID_LEN);
  1045. link_frame_currpos += WLAN_AID_LEN;
  1046. link_frame_currlen += WLAN_AID_LEN;
  1047. mlo_debug("Added AID field (%u octets) to link specific frame",
  1048. WLAN_AID_LEN);
  1049. }
  1050. sta_prof_iesection = sta_prof_currpos;
  1051. sta_prof_iesection_len = sta_prof_remlen;
  1052. /* Populate non-inheritance lists if applicable */
  1053. ninherit_elemlist_len = 0;
  1054. ninherit_elemlist = NULL;
  1055. ninherit_elemextlist_len = 0;
  1056. ninherit_elemextlist = NULL;
  1057. ret = util_get_noninheritlists(sta_prof_iesection,
  1058. sta_prof_iesection_len,
  1059. &ninherit_elemlist,
  1060. &ninherit_elemlist_len,
  1061. &ninherit_elemextlist,
  1062. &ninherit_elemextlist_len);
  1063. if (QDF_IS_STATUS_ERROR(ret)) {
  1064. qdf_mem_free(orig_mlie_copy);
  1065. return ret;
  1066. }
  1067. /* Go through IEs of the reporting STA, and those in STA profile, merge
  1068. * them into link_frame (except for elements in the Non-Inheritance
  1069. * list).
  1070. *
  1071. * Note: Currently, only 2-link MLO is supported here. We may have a
  1072. * future change to expand to more links.
  1073. */
  1074. reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection,
  1075. frame_iesection_len);
  1076. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  1077. (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
  1078. /* Sanity check that the SSID element is present for the
  1079. * reporting STA. There is no stipulation in the standard for
  1080. * the STA profile in this regard, so we do not check the STA
  1081. * profile for the SSID element.
  1082. */
  1083. if (!reportingsta_ie) {
  1084. mlo_err_rl("SSID element not found for reporting STA for (re)association request.");
  1085. qdf_mem_free(orig_mlie_copy);
  1086. return QDF_STATUS_E_PROTO;
  1087. }
  1088. } else {
  1089. /* This is a (re)association response. Sanity check that the
  1090. * SSID element is present neither for the reporting STA nor in
  1091. * the STA profile.
  1092. */
  1093. if (reportingsta_ie) {
  1094. mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present.");
  1095. qdf_mem_free(orig_mlie_copy);
  1096. return QDF_STATUS_E_PROTO;
  1097. }
  1098. sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID,
  1099. sta_prof_iesection,
  1100. sta_prof_iesection_len);
  1101. if (sta_prof_ie) {
  1102. mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present.");
  1103. qdf_mem_free(orig_mlie_copy);
  1104. return QDF_STATUS_E_PROTO;
  1105. }
  1106. }
  1107. reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection;
  1108. ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection,
  1109. frame_iesection_len);
  1110. if (QDF_IS_STATUS_ERROR(ret)) {
  1111. qdf_mem_free(orig_mlie_copy);
  1112. return ret;
  1113. }
  1114. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
  1115. while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection)
  1116. <= frame_iesection_len) {
  1117. /* Skip Multi-Link element */
  1118. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1119. (reportingsta_ie[IDEXT_POS] ==
  1120. WLAN_EXTN_ELEMID_MULTI_LINK)) {
  1121. if (((reportingsta_ie + reportingsta_ie_size) -
  1122. frame_iesection) == frame_iesection_len)
  1123. break;
  1124. reportingsta_ie += reportingsta_ie_size;
  1125. ret = util_validate_reportingsta_ie(reportingsta_ie,
  1126. frame_iesection,
  1127. frame_iesection_len);
  1128. if (QDF_IS_STATUS_ERROR(ret)) {
  1129. qdf_mem_free(orig_mlie_copy);
  1130. return ret;
  1131. }
  1132. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  1133. MIN_IE_LEN;
  1134. continue;
  1135. }
  1136. sta_prof_ie = NULL;
  1137. sta_prof_ie_size = 0;
  1138. if (sta_prof_iesection_len) {
  1139. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1140. sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS],
  1141. reportingsta_ie[IDEXT_POS],
  1142. sta_prof_iesection,
  1143. sta_prof_iesection_len);
  1144. } else {
  1145. sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS],
  1146. sta_prof_iesection,
  1147. sta_prof_iesection_len);
  1148. }
  1149. }
  1150. if (!sta_prof_ie) {
  1151. /* IE is present for reporting STA, but not in STA
  1152. * profile.
  1153. */
  1154. is_in_noninheritlist = false;
  1155. ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie,
  1156. reportingsta_ie_size,
  1157. ninherit_elemlist,
  1158. ninherit_elemlist_len,
  1159. ninherit_elemextlist,
  1160. ninherit_elemextlist_len,
  1161. &is_in_noninheritlist);
  1162. if (QDF_IS_STATUS_ERROR(ret)) {
  1163. qdf_mem_free(orig_mlie_copy);
  1164. return ret;
  1165. }
  1166. if (!is_in_noninheritlist) {
  1167. if ((link_frame_currpos +
  1168. reportingsta_ie_size) <=
  1169. (link_frame + link_frame_maxsize)) {
  1170. qdf_mem_copy(link_frame_currpos,
  1171. reportingsta_ie,
  1172. reportingsta_ie_size);
  1173. link_frame_currpos +=
  1174. reportingsta_ie_size;
  1175. link_frame_currlen +=
  1176. reportingsta_ie_size;
  1177. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1178. mlo_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame",
  1179. reportingsta_ie[ID_POS],
  1180. reportingsta_ie[IDEXT_POS],
  1181. reportingsta_ie_size);
  1182. } else {
  1183. mlo_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. Copied IE from reporting frame to link specific frame",
  1184. reportingsta_ie[ID_POS],
  1185. reportingsta_ie_size);
  1186. }
  1187. } else {
  1188. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1189. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  1190. reportingsta_ie[ID_POS],
  1191. reportingsta_ie[IDEXT_POS],
  1192. reportingsta_ie_size,
  1193. link_frame_maxsize -
  1194. link_frame_currlen);
  1195. } else {
  1196. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  1197. reportingsta_ie[ID_POS],
  1198. reportingsta_ie_size,
  1199. link_frame_maxsize -
  1200. link_frame_currlen);
  1201. }
  1202. qdf_mem_free(orig_mlie_copy);
  1203. return QDF_STATUS_E_NOMEM;
  1204. }
  1205. } else {
  1206. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1207. mlo_debug("IE with element ID : %u extension element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.",
  1208. reportingsta_ie[ID_POS],
  1209. reportingsta_ie[IDEXT_POS],
  1210. reportingsta_ie_size);
  1211. } else {
  1212. mlo_debug("IE with element ID : %u (%zu octets) present for reporting STA but not in STA profile. However it is in Non-Inheritance list, hence ignoring.",
  1213. reportingsta_ie[ID_POS],
  1214. reportingsta_ie_size);
  1215. }
  1216. }
  1217. } else {
  1218. /* IE is present for reporting STA and also in STA
  1219. * profile, copy from STA profile and flag the IE in STA
  1220. * profile as copied (by setting EID field to 0). The
  1221. * SSID element (with EID 0) is processed first to
  1222. * enable this. For vendor IE, compare OUI + type +
  1223. * subType to determine if they are the same IE.
  1224. */
  1225. /* Note: This may be revisited in a future change, to
  1226. * adhere to provisions in the standard for multiple
  1227. * occurrences of a given element ID/extension element
  1228. * ID.
  1229. */
  1230. ret = util_validate_sta_prof_ie(sta_prof_ie,
  1231. sta_prof_iesection,
  1232. sta_prof_iesection_len);
  1233. if (QDF_IS_STATUS_ERROR(ret)) {
  1234. qdf_mem_free(orig_mlie_copy);
  1235. return ret;
  1236. }
  1237. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] +
  1238. MIN_IE_LEN;
  1239. sta_prof_iesection_remlen =
  1240. sta_prof_iesection_len -
  1241. (sta_prof_ie - sta_prof_iesection);
  1242. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
  1243. (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) {
  1244. if (!qdf_mem_cmp(reportingsta_ie +
  1245. PAYLOAD_START_POS,
  1246. sta_prof_ie +
  1247. PAYLOAD_START_POS,
  1248. OUI_LEN)) {
  1249. /* Same vendor IE, copy from STA profile
  1250. */
  1251. if ((link_frame_currpos +
  1252. sta_prof_ie_size) <=
  1253. (link_frame +
  1254. link_frame_maxsize)) {
  1255. qdf_mem_copy(link_frame_currpos,
  1256. sta_prof_ie,
  1257. sta_prof_ie_size);
  1258. link_frame_currpos +=
  1259. sta_prof_ie_size;
  1260. link_frame_currlen +=
  1261. sta_prof_ie_size;
  1262. mlo_debug("Vendor IE (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame",
  1263. sta_prof_ie_size);
  1264. sta_prof_ie[0] = 0;
  1265. } else {
  1266. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  1267. sta_prof_ie[ID_POS],
  1268. sta_prof_ie_size,
  1269. link_frame_maxsize -
  1270. link_frame_currlen);
  1271. qdf_mem_free(orig_mlie_copy);
  1272. return QDF_STATUS_E_NOMEM;
  1273. }
  1274. } else {
  1275. if ((link_frame_currpos +
  1276. reportingsta_ie_size) <=
  1277. (link_frame +
  1278. link_frame_maxsize)) {
  1279. qdf_mem_copy(link_frame_currpos,
  1280. reportingsta_ie,
  1281. reportingsta_ie_size);
  1282. link_frame_currpos +=
  1283. reportingsta_ie_size;
  1284. link_frame_currlen +=
  1285. reportingsta_ie_size;
  1286. mlo_debug("Vendor IE (%zu octets) present for reporting STA but not present in STA profile. Copied IE from reporting frame to link specific frame",
  1287. reportingsta_ie_size);
  1288. } else {
  1289. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  1290. reportingsta_ie[ID_POS],
  1291. reportingsta_ie_size,
  1292. link_frame_maxsize -
  1293. link_frame_currlen);
  1294. qdf_mem_free(orig_mlie_copy);
  1295. return QDF_STATUS_E_NOMEM;
  1296. }
  1297. }
  1298. } else {
  1299. /* Copy IE from STA profile into link specific
  1300. * frame.
  1301. */
  1302. if ((link_frame_currpos + sta_prof_ie_size) <=
  1303. (link_frame + link_frame_maxsize)) {
  1304. qdf_mem_copy(link_frame_currpos,
  1305. sta_prof_ie,
  1306. sta_prof_ie_size);
  1307. link_frame_currpos += sta_prof_ie_size;
  1308. link_frame_currlen +=
  1309. sta_prof_ie_size;
  1310. if (reportingsta_ie[ID_POS] ==
  1311. WLAN_ELEMID_EXTN_ELEM) {
  1312. mlo_debug("IE with element ID : %u extension element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame",
  1313. sta_prof_ie[ID_POS],
  1314. sta_prof_ie[IDEXT_POS],
  1315. sta_prof_ie_size);
  1316. } else {
  1317. mlo_debug("IE with element ID : %u (%zu octets) for reporting STA also present in STA profile. Copied IE from STA profile to link specific frame",
  1318. sta_prof_ie[ID_POS],
  1319. sta_prof_ie_size);
  1320. }
  1321. sta_prof_ie[0] = 0;
  1322. } else {
  1323. if (sta_prof_ie[ID_POS] ==
  1324. WLAN_ELEMID_EXTN_ELEM) {
  1325. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  1326. sta_prof_ie[ID_POS],
  1327. sta_prof_ie[IDEXT_POS],
  1328. sta_prof_ie_size,
  1329. link_frame_maxsize -
  1330. link_frame_currlen);
  1331. } else {
  1332. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  1333. sta_prof_ie[ID_POS],
  1334. sta_prof_ie_size,
  1335. link_frame_maxsize -
  1336. link_frame_currlen);
  1337. }
  1338. qdf_mem_free(orig_mlie_copy);
  1339. return QDF_STATUS_E_NOMEM;
  1340. }
  1341. }
  1342. }
  1343. if (((reportingsta_ie + reportingsta_ie_size) -
  1344. frame_iesection) == frame_iesection_len)
  1345. break;
  1346. reportingsta_ie += reportingsta_ie_size;
  1347. ret = util_validate_reportingsta_ie(reportingsta_ie,
  1348. frame_iesection,
  1349. frame_iesection_len);
  1350. if (QDF_IS_STATUS_ERROR(ret)) {
  1351. qdf_mem_free(orig_mlie_copy);
  1352. return ret;
  1353. }
  1354. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  1355. MIN_IE_LEN;
  1356. }
  1357. /* Go through the remaining unprocessed IEs in STA profile and copy them
  1358. * to the link specific frame. The processed ones are marked with 0 in
  1359. * the first octet. The first octet corresponds to the element ID. In
  1360. * the case of (re)association request, the element with actual ID
  1361. * WLAN_ELEMID_SSID(0) has already been copied to the link specific
  1362. * frame. In the case of (re)association response, it has been verified
  1363. * that the element with actual ID WLAN_ELEMID_SSID(0) is present
  1364. * neither for the reporting STA nor in the STA profile.
  1365. */
  1366. sta_prof_iesection_currpos = sta_prof_iesection;
  1367. sta_prof_iesection_remlen = sta_prof_iesection_len;
  1368. while (sta_prof_iesection_remlen > 0) {
  1369. sta_prof_ie = sta_prof_iesection_currpos;
  1370. ret = util_validate_sta_prof_ie(sta_prof_ie,
  1371. sta_prof_iesection_currpos,
  1372. sta_prof_iesection_remlen);
  1373. if (QDF_IS_STATUS_ERROR(ret)) {
  1374. qdf_mem_free(orig_mlie_copy);
  1375. return ret;
  1376. }
  1377. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
  1378. if (!sta_prof_ie[0]) {
  1379. /* Skip this, since it has already been processed */
  1380. sta_prof_iesection_currpos += sta_prof_ie_size;
  1381. sta_prof_iesection_remlen -= sta_prof_ie_size;
  1382. continue;
  1383. }
  1384. /* Copy IE from STA profile into link specific frame. */
  1385. if ((link_frame_currpos + sta_prof_ie_size) <=
  1386. (link_frame + link_frame_maxsize)) {
  1387. qdf_mem_copy(link_frame_currpos,
  1388. sta_prof_ie,
  1389. sta_prof_ie_size);
  1390. link_frame_currpos += sta_prof_ie_size;
  1391. link_frame_currlen +=
  1392. sta_prof_ie_size;
  1393. if (reportingsta_ie[ID_POS] ==
  1394. WLAN_ELEMID_EXTN_ELEM) {
  1395. mlo_debug("IE with element ID : %u extension element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
  1396. sta_prof_ie[ID_POS],
  1397. sta_prof_ie[IDEXT_POS],
  1398. sta_prof_ie_size);
  1399. } else {
  1400. mlo_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
  1401. sta_prof_ie[ID_POS],
  1402. sta_prof_ie_size);
  1403. }
  1404. sta_prof_ie[0] = 0;
  1405. } else {
  1406. if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1407. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  1408. sta_prof_ie[ID_POS],
  1409. sta_prof_ie[IDEXT_POS],
  1410. sta_prof_ie_size,
  1411. link_frame_maxsize -
  1412. link_frame_currlen);
  1413. } else {
  1414. mlo_err_rl("Insufficent space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  1415. sta_prof_ie[ID_POS],
  1416. sta_prof_ie_size,
  1417. link_frame_maxsize -
  1418. link_frame_currlen);
  1419. }
  1420. qdf_mem_free(orig_mlie_copy);
  1421. return QDF_STATUS_E_NOMEM;
  1422. }
  1423. sta_prof_iesection_currpos += sta_prof_ie_size;
  1424. sta_prof_iesection_remlen -= sta_prof_ie_size;
  1425. }
  1426. /* Copy the link MAC addr */
  1427. link_frame_hdr = (struct wlan_frame_hdr *)link_frame;
  1428. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  1429. (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
  1430. qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr,
  1431. QDF_MAC_ADDR_SIZE);
  1432. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  1433. QDF_MAC_ADDR_SIZE);
  1434. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
  1435. QDF_MAC_ADDR_SIZE);
  1436. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0;
  1437. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1;
  1438. } else {
  1439. /* This is a (re)association response */
  1440. qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
  1441. QDF_MAC_ADDR_SIZE);
  1442. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  1443. QDF_MAC_ADDR_SIZE);
  1444. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
  1445. QDF_MAC_ADDR_SIZE);
  1446. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0;
  1447. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1;
  1448. }
  1449. /* Seq num not used so not populated */
  1450. qdf_mem_free(orig_mlie_copy);
  1451. *link_frame_len = link_frame_currlen;
  1452. return QDF_STATUS_SUCCESS;
  1453. }
  1454. QDF_STATUS
  1455. util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
  1456. struct qdf_mac_addr link_addr,
  1457. uint8_t *link_frame,
  1458. qdf_size_t link_frame_maxsize,
  1459. qdf_size_t *link_frame_len)
  1460. {
  1461. return util_gen_link_assoc_reqrsp_cmn(frame, frame_len,
  1462. (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ :
  1463. WLAN_FC0_STYPE_ASSOC_REQ),
  1464. link_addr, link_frame, link_frame_maxsize,
  1465. link_frame_len);
  1466. }
  1467. QDF_STATUS
  1468. util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
  1469. struct qdf_mac_addr link_addr,
  1470. uint8_t *link_frame,
  1471. qdf_size_t link_frame_maxsize,
  1472. qdf_size_t *link_frame_len)
  1473. {
  1474. return util_gen_link_assoc_reqrsp_cmn(frame, frame_len,
  1475. (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP :
  1476. WLAN_FC0_STYPE_ASSOC_RESP),
  1477. link_addr, link_frame, link_frame_maxsize,
  1478. link_frame_len);
  1479. }
  1480. QDF_STATUS
  1481. util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
  1482. qdf_size_t *mlieseqlen)
  1483. {
  1484. uint8_t *bufboundary;
  1485. uint8_t *ieseq;
  1486. qdf_size_t ieseqlen;
  1487. uint8_t *currie;
  1488. uint8_t *successorfrag;
  1489. if (!buf || !buflen || !mlieseq || !mlieseqlen)
  1490. return QDF_STATUS_E_NULL_VALUE;
  1491. *mlieseq = NULL;
  1492. *mlieseqlen = 0;
  1493. /* Find Multi-Link element. In case a fragment sequence is present,
  1494. * this element will be the leading fragment.
  1495. */
  1496. ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
  1497. WLAN_EXTN_ELEMID_MULTI_LINK, buf,
  1498. buflen);
  1499. /* Even if the element is not found, we have successfully examined the
  1500. * buffer. The caller will be provided a NULL value for the starting of
  1501. * the Multi-Link element. Hence, we return success.
  1502. */
  1503. if (!ieseq)
  1504. return QDF_STATUS_SUCCESS;
  1505. bufboundary = buf + buflen;
  1506. if ((ieseq + MIN_IE_LEN) > bufboundary)
  1507. return QDF_STATUS_E_INVAL;
  1508. ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS];
  1509. if (ieseqlen < sizeof(struct wlan_ie_multilink))
  1510. return QDF_STATUS_E_PROTO;
  1511. if ((ieseq + ieseqlen) > bufboundary)
  1512. return QDF_STATUS_E_INVAL;
  1513. /* In the next sequence of checks, if there is no space in the buffer
  1514. * for another element after the Multi-Link element/element fragment
  1515. * sequence, it could indicate an issue since non-MLO EHT elements
  1516. * would be expected to follow the Multi-Link element/element fragment
  1517. * sequence. However, this is outside of the purview of this function,
  1518. * hence we ignore it.
  1519. */
  1520. currie = ieseq;
  1521. successorfrag = util_get_successorfrag(currie, buf, buflen);
  1522. /* Fragmentation definitions as of IEEE802.11be D1.0 and
  1523. * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link
  1524. * element is present in a buffer from the core frame is considered.
  1525. * Future changes to fragmentation, cases where the Multi-Link element
  1526. * is present in a subelement, etc. to be reflected here if applicable
  1527. * as and when the rules evolve.
  1528. */
  1529. while (successorfrag) {
  1530. /* We should not be seeing a successor fragment if the length
  1531. * of the current IE is lesser than the max.
  1532. */
  1533. if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN)
  1534. return QDF_STATUS_E_PROTO;
  1535. if (successorfrag[TAG_LEN_POS] == 0)
  1536. return QDF_STATUS_E_PROTO;
  1537. ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]);
  1538. currie = successorfrag;
  1539. successorfrag = util_get_successorfrag(currie, buf, buflen);
  1540. }
  1541. *mlieseq = ieseq;
  1542. *mlieseqlen = ieseqlen;
  1543. return QDF_STATUS_SUCCESS;
  1544. }
  1545. QDF_STATUS
  1546. util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  1547. int *variant)
  1548. {
  1549. struct wlan_ie_multilink *mlie_fixed;
  1550. enum wlan_ml_variant var;
  1551. uint16_t mlcontrol;
  1552. if (!mlieseq || !mlieseqlen || !variant)
  1553. return QDF_STATUS_E_NULL_VALUE;
  1554. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  1555. return QDF_STATUS_E_INVAL;
  1556. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  1557. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  1558. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  1559. return QDF_STATUS_E_INVAL;
  1560. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  1561. var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  1562. WLAN_ML_CTRL_TYPE_BITS);
  1563. if (var >= WLAN_ML_VARIANT_INVALIDSTART)
  1564. return QDF_STATUS_E_PROTO;
  1565. *variant = var;
  1566. return QDF_STATUS_SUCCESS;
  1567. }
  1568. QDF_STATUS
  1569. util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  1570. bool *mldmacaddrfound,
  1571. struct qdf_mac_addr *mldmacaddr)
  1572. {
  1573. struct wlan_ie_multilink *mlie_fixed;
  1574. enum wlan_ml_variant variant;
  1575. uint16_t mlcontrol;
  1576. uint16_t presencebitmap;
  1577. if (!mlieseq || !mlieseqlen || !mldmacaddrfound || !mldmacaddr)
  1578. return QDF_STATUS_E_NULL_VALUE;
  1579. *mldmacaddrfound = false;
  1580. qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr));
  1581. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  1582. return QDF_STATUS_E_INVAL;
  1583. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  1584. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  1585. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  1586. return QDF_STATUS_E_INVAL;
  1587. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  1588. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  1589. WLAN_ML_CTRL_TYPE_BITS);
  1590. if (variant != WLAN_ML_VARIANT_BASIC)
  1591. return QDF_STATUS_E_INVAL;
  1592. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  1593. WLAN_ML_CTRL_PBM_BITS);
  1594. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDMACADDR_P) {
  1595. /* Common Info starts at mlieseq + sizeof(struct
  1596. * wlan_ie_multilink). Check if there is sufficient space in
  1597. * Common Info for the MLD MAC address.
  1598. */
  1599. if ((sizeof(struct wlan_ie_multilink) + QDF_MAC_ADDR_SIZE) >
  1600. mlieseqlen)
  1601. return QDF_STATUS_E_PROTO;
  1602. *mldmacaddrfound = true;
  1603. qdf_mem_copy(mldmacaddr->bytes,
  1604. mlieseq + sizeof(struct wlan_ie_multilink),
  1605. QDF_MAC_ADDR_SIZE);
  1606. }
  1607. return QDF_STATUS_SUCCESS;
  1608. }
  1609. QDF_STATUS
  1610. util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  1611. bool *linkidfound, uint8_t *linkid)
  1612. {
  1613. struct wlan_ie_multilink *mlie_fixed;
  1614. enum wlan_ml_variant variant;
  1615. uint16_t mlcontrol;
  1616. uint16_t presencebitmap;
  1617. uint8_t *commoninfo;
  1618. qdf_size_t commoninfolen;
  1619. uint8_t *linkidinfo;
  1620. if (!mlieseq || !mlieseqlen || !linkidfound || !linkid)
  1621. return QDF_STATUS_E_NULL_VALUE;
  1622. *linkidfound = false;
  1623. *linkid = 0;
  1624. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  1625. return QDF_STATUS_E_INVAL;
  1626. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  1627. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  1628. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  1629. return QDF_STATUS_E_INVAL;
  1630. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  1631. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  1632. WLAN_ML_CTRL_TYPE_BITS);
  1633. if (variant != WLAN_ML_VARIANT_BASIC)
  1634. return QDF_STATUS_E_INVAL;
  1635. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  1636. WLAN_ML_CTRL_PBM_BITS);
  1637. commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
  1638. commoninfolen = 0;
  1639. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDMACADDR_P) {
  1640. commoninfolen += QDF_MAC_ADDR_SIZE;
  1641. if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
  1642. mlieseqlen)
  1643. return QDF_STATUS_E_PROTO;
  1644. }
  1645. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  1646. linkidinfo = commoninfo + commoninfolen;
  1647. commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  1648. if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
  1649. mlieseqlen)
  1650. return QDF_STATUS_E_PROTO;
  1651. *linkidfound = true;
  1652. *linkid = QDF_GET_BITS(linkidinfo[0],
  1653. WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX,
  1654. WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS);
  1655. }
  1656. return QDF_STATUS_SUCCESS;
  1657. }
  1658. QDF_STATUS
  1659. util_get_bvmlie_persta_partner_info(uint8_t *mlie, qdf_size_t mlielen,
  1660. struct mlo_partner_info *partner_info)
  1661. {
  1662. struct wlan_ie_multilink *mlie_fixed;
  1663. uint16_t mlcontrol;
  1664. enum wlan_ml_variant variant;
  1665. uint8_t *linkinfo;
  1666. qdf_size_t linkinfo_len;
  1667. struct mlo_partner_info pinfo = {0};
  1668. QDF_STATUS ret;
  1669. if (!mlie) {
  1670. mlo_err("mlie is NULL");
  1671. return QDF_STATUS_E_NULL_VALUE;
  1672. }
  1673. if (!mlielen) {
  1674. mlo_err("mlielen is zero");
  1675. return QDF_STATUS_E_NULL_VALUE;
  1676. }
  1677. if (!partner_info) {
  1678. mlo_err("partner_info is NULL");
  1679. return QDF_STATUS_E_NULL_VALUE;
  1680. }
  1681. partner_info->num_partner_links = 0;
  1682. if (mlielen < sizeof(struct wlan_ie_multilink)) {
  1683. mlo_err_rl("mlielen %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  1684. mlielen, sizeof(struct wlan_ie_multilink));
  1685. return QDF_STATUS_E_INVAL;
  1686. }
  1687. /* Note: Multi-Link element fragmentation support will be added in a
  1688. * later change once shared helper utilities for the same are available.
  1689. * As of now, we temporarily return error if the mlielen is greater than
  1690. * the max length for an IE.
  1691. */
  1692. if (mlielen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  1693. mlo_err_rl("Element fragmentation is not yet supported for this API");
  1694. return QDF_STATUS_E_NOSUPPORT;
  1695. }
  1696. mlie_fixed = (struct wlan_ie_multilink *)mlie;
  1697. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  1698. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) {
  1699. mlo_err("The element is not a Multi-Link element");
  1700. return QDF_STATUS_E_INVAL;
  1701. }
  1702. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  1703. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  1704. WLAN_ML_CTRL_TYPE_BITS);
  1705. if (variant != WLAN_ML_VARIANT_BASIC) {
  1706. mlo_err("The variant value %u does not correspond to Basic Variant value %u",
  1707. variant, WLAN_ML_VARIANT_BASIC);
  1708. return QDF_STATUS_E_INVAL;
  1709. }
  1710. linkinfo_len = 0;
  1711. linkinfo = util_parse_multi_link_ctrl(mlie, mlielen,
  1712. &linkinfo_len);
  1713. if (!linkinfo) {
  1714. mlo_err_rl("Error in parsing Multi-Link element control");
  1715. return QDF_STATUS_E_INVAL;
  1716. }
  1717. /* In case Link Info is absent as indicated by the Link Info length
  1718. * being 0, return success. The number of partner links will remain 0.
  1719. */
  1720. if (!linkinfo_len) {
  1721. mlo_warn_rl("Link Info is absent");
  1722. return QDF_STATUS_SUCCESS;
  1723. }
  1724. ret = util_parse_partner_info_from_linkinfo(linkinfo,
  1725. linkinfo_len,
  1726. &pinfo);
  1727. if (QDF_IS_STATUS_ERROR(ret))
  1728. return ret;
  1729. qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info));
  1730. return QDF_STATUS_SUCCESS;
  1731. }
  1732. #endif