1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910 |
- /*
- * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * DOC: contains MLO manager util api's
- */
- #include <wlan_cmn.h>
- #include <wlan_mlo_mgr_sta.h>
- #include <wlan_cm_public_struct.h>
- #include <wlan_mlo_mgr_main.h>
- #include <wlan_cm_api.h>
- #include "wlan_scan_api.h"
- #include "qdf_types.h"
- #include "utils_mlo.h"
- #include "wlan_mlo_mgr_cmn.h"
- #include "wlan_utility.h"
- #ifdef WLAN_FEATURE_11BE_MLO
- static uint8_t *util_find_eid(uint8_t eid, uint8_t *frame, qdf_size_t len)
- {
- if (!frame)
- return NULL;
- while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
- if (frame[ID_POS] == eid)
- return frame;
- len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
- frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
- }
- return NULL;
- }
- static
- uint8_t *util_find_extn_eid(uint8_t eid, uint8_t extn_eid,
- uint8_t *frame, qdf_size_t len)
- {
- if (!frame)
- return NULL;
- while (len > MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
- if ((frame[ID_POS] == eid) &&
- (frame[ELEM_ID_EXTN_POS] == extn_eid))
- return frame;
- len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
- frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
- }
- return NULL;
- }
- static QDF_STATUS
- util_parse_multi_link_ctrl(uint8_t *mlieseqpayload,
- qdf_size_t mlieseqpayloadlen,
- uint8_t **link_info,
- qdf_size_t *link_info_len)
- {
- qdf_size_t parsed_payload_len;
- uint16_t mlcontrol;
- uint16_t presence_bm;
- uint16_t cinfo_len = 0;
- uint16_t exp_cinfo_len = 0;
- /* This helper returns the location(s) and length(s) of (sub)field(s)
- * inferable after parsing the Multi Link element Control field. These
- * location(s) and length(s) is/are in reference to the payload section
- * of the Multi Link element (after defragmentation, if applicable).
- * Here, the payload is the point after the element ID extension of the
- * Multi Link element, and includes the payloads of all subsequent
- * fragments (if any) but not the headers of those fragments.
- *
- * Currently, the helper returns the location and length of the Link
- * Info field in the Multi Link element sequence. Other (sub)field(s)
- * can be added later as required.
- */
- if (!mlieseqpayload) {
- mlo_err("ML seq payload pointer is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!mlieseqpayloadlen) {
- mlo_err("ML seq payload len is 0");
- return QDF_STATUS_E_INVAL;
- }
- if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
- mlo_err_rl("ML seq payload len %zu < ML Control size %u",
- mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len = 0;
- qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE);
- mlcontrol = qdf_le16_to_cpu(mlcontrol);
- parsed_payload_len += WLAN_ML_CTRL_SIZE;
- presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- if (mlieseqpayloadlen <
- (parsed_payload_len + WLAN_ML_BV_CINFO_LENGTH_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_LENGTH_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- cinfo_len = *(mlieseqpayload + parsed_payload_len);
- parsed_payload_len += WLAN_ML_BV_CINFO_LENGTH_SIZE;
- if (mlieseqpayloadlen <
- (parsed_payload_len + QDF_MAC_ADDR_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for MAC address size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- QDF_MAC_ADDR_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += QDF_MAC_ADDR_SIZE;
- /* Check if Link ID info is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BV_CINFO_LINKIDINFO_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for Link ID info size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_LINKIDINFO_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- }
- /* Check if BSS parameter change count is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BSSPARAMCHNGCNT_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for BSS parameter change count size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BSSPARAMCHNGCNT_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
- }
- /* Check if Medium Sync Delay Info is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for Medium Sync Delay Info size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
- }
- /* Check if EML cap is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BV_CINFO_EMLCAP_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for EML cap size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_EMLCAP_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
- }
- /* Check if MLD cap is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for MLD cap size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
- }
- /* Check if MLD ID is present */
- if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDID_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_BV_CINFO_MLDID_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_BV_CINFO_MLDID_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_CINFO_MLDID_SIZE;
- }
- exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE;
- if (cinfo_len != exp_cinfo_len) {
- mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u",
- cinfo_len, exp_cinfo_len);
- return QDF_STATUS_E_PROTO;
- }
- if (link_info_len) {
- *link_info_len = mlieseqpayloadlen - parsed_payload_len;
- mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
- *link_info_len, parsed_payload_len);
- }
- if (mlieseqpayloadlen == parsed_payload_len) {
- mlo_debug("No Link Info field present");
- if (link_info)
- *link_info = NULL;
- return QDF_STATUS_SUCCESS;
- }
- if (link_info)
- *link_info = mlieseqpayload + parsed_payload_len;
- return QDF_STATUS_SUCCESS;
- }
- static QDF_STATUS
- util_parse_prv_multi_link_ctrl(uint8_t *mlieseqpayload,
- qdf_size_t mlieseqpayloadlen,
- uint8_t **link_info,
- qdf_size_t *link_info_len)
- {
- qdf_size_t parsed_payload_len;
- uint16_t mlcontrol;
- uint16_t presence_bm;
- uint16_t cinfo_len = 0;
- uint16_t exp_cinfo_len = 0;
- /* This helper returns the location(s) and length(s) of (sub)field(s)
- * inferable after parsing the Multi Link element Control field. These
- * location(s) and length(s) is/are in reference to the payload section
- * of the Multi Link element (after defragmentation, if applicable).
- * Here, the payload is the point after the element ID extension of the
- * Multi Link element, and includes the payloads of all subsequent
- * fragments (if any) but not the headers of those fragments.
- *
- * Currently, the helper returns the location and length of the Link
- * Info field in the Multi Link element sequence. Other (sub)field(s)
- * can be added later as required.
- */
- if (!mlieseqpayload) {
- mlo_err("ML seq payload pointer is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!mlieseqpayloadlen) {
- mlo_err("ML seq payload len is 0");
- return QDF_STATUS_E_INVAL;
- }
- if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
- mlo_err_rl("ML seq payload len %zu < ML Control size %u",
- mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len = 0;
- qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE);
- mlcontrol = qdf_le16_to_cpu(mlcontrol);
- parsed_payload_len += WLAN_ML_CTRL_SIZE;
- presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- if (mlieseqpayloadlen <
- (parsed_payload_len + WLAN_ML_PRV_CINFO_LENGTH_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_PRV_CINFO_LENGTH_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- cinfo_len = *(mlieseqpayload + parsed_payload_len);
- parsed_payload_len += WLAN_ML_PRV_CINFO_LENGTH_SIZE;
- /* Check if MLD ID is present */
- if (presence_bm & WLAN_ML_PRV_CTRL_PBM_MLDID_P) {
- if (mlieseqpayloadlen <
- (parsed_payload_len +
- WLAN_ML_PRV_CINFO_MLDID_SIZE)) {
- mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.",
- mlieseqpayloadlen,
- WLAN_ML_PRV_CINFO_MLDID_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_PRV_CINFO_MLDID_SIZE;
- }
- exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE;
- if (cinfo_len != exp_cinfo_len) {
- mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u",
- cinfo_len, exp_cinfo_len);
- return QDF_STATUS_E_PROTO;
- }
- if (link_info_len) {
- *link_info_len = mlieseqpayloadlen - parsed_payload_len;
- mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
- *link_info_len, parsed_payload_len);
- }
- if (mlieseqpayloadlen == parsed_payload_len) {
- mlo_debug("No Link Info field present");
- if (link_info)
- *link_info = NULL;
- return QDF_STATUS_SUCCESS;
- }
- if (link_info)
- *link_info = mlieseqpayload + parsed_payload_len;
- return QDF_STATUS_SUCCESS;
- }
- static QDF_STATUS
- util_parse_bvmlie_perstaprofile_stactrl(uint8_t *subelempayload,
- qdf_size_t subelempayloadlen,
- uint8_t *linkid,
- uint16_t *beaconinterval,
- bool *is_beaconinterval_valid,
- uint64_t *tsfoffset,
- bool *is_tsfoffset_valid,
- bool *is_complete_profile,
- bool *is_macaddr_valid,
- struct qdf_mac_addr *macaddr,
- bool is_staprof_reqd,
- uint8_t **staprof,
- qdf_size_t *staprof_len)
- {
- qdf_size_t parsed_payload_len = 0;
- uint16_t stacontrol;
- uint8_t completeprofile;
- uint8_t nstrlppresent;
- enum wlan_ml_bv_linfo_perstaprof_stactrl_nstrbmsz nstrbmsz;
- /* This helper returns the location(s) and where required, the length(s)
- * of (sub)field(s) inferable after parsing the STA Control field in the
- * per-STA profile subelement. These location(s) and length(s) is/are in
- * reference to the payload section of the per-STA profile subelement
- * (after defragmentation, if applicable). Here, the payload is the
- * point after the subelement length in the subelement, and includes the
- * payloads of all subsequent fragments (if any) but not the headers of
- * those fragments.
- *
- * Currently, the helper returns the link ID, MAC address, and STA
- * profile. More (sub)fields can be added when required.
- */
- if (!subelempayload) {
- mlo_err("Pointer to subelement payload is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!subelempayloadlen) {
- mlo_err("Length of subelement payload is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (subelempayloadlen < WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE) {
- mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
- subelempayloadlen,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len = 0;
- qdf_mem_copy(&stacontrol,
- subelempayload,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE);
- stacontrol = le16toh(stacontrol);
- parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE;
- if (linkid) {
- *linkid = QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
- }
- /* Check if this a complete profile */
- completeprofile = QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
- if (completeprofile && is_complete_profile)
- *is_complete_profile = true;
- /* Check STA Info Length */
- if (subelempayloadlen <
- parsed_payload_len + WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain STA Info Length of size %u octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE;
- if (is_macaddr_valid)
- *is_macaddr_valid = false;
- /* Check STA MAC address present bit */
- if (QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) {
- if (subelempayloadlen <
- (parsed_payload_len + QDF_MAC_ADDR_SIZE)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain MAC address of size %u octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- QDF_MAC_ADDR_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- if (macaddr) {
- qdf_mem_copy(macaddr->bytes,
- subelempayload + parsed_payload_len,
- QDF_MAC_ADDR_SIZE);
- mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT,
- subelempayload + parsed_payload_len);
- if (is_macaddr_valid)
- *is_macaddr_valid = true;
- }
- parsed_payload_len += QDF_MAC_ADDR_SIZE;
- }
- /* Check Beacon Interval present bit */
- if (QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS)) {
- if (subelempayloadlen <
- (parsed_payload_len +
- WLAN_BEACONINTERVAL_LEN)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain Beacon Interval of size %u octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- WLAN_BEACONINTERVAL_LEN,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- if (beaconinterval) {
- qdf_mem_copy(beaconinterval,
- subelempayload + parsed_payload_len,
- WLAN_BEACONINTERVAL_LEN);
- *beaconinterval = qdf_le16_to_cpu(*beaconinterval);
- if (is_beaconinterval_valid)
- *is_beaconinterval_valid = true;
- }
- parsed_payload_len += WLAN_BEACONINTERVAL_LEN;
- }
- /* Check TSF Offset present bit */
- if (QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_BITS)) {
- if (!completeprofile) {
- mlo_err_rl("TSF offset is expected only for complete profiles");
- return QDF_STATUS_E_PROTO;
- }
- if (subelempayloadlen <
- (parsed_payload_len +
- WLAN_ML_TSF_OFFSET_SIZE)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain TSF Offset of size %u octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- WLAN_ML_TSF_OFFSET_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- if (tsfoffset) {
- qdf_mem_copy(tsfoffset,
- subelempayload + parsed_payload_len,
- WLAN_TIMESTAMP_LEN);
- *tsfoffset = qdf_le64_to_cpu(*tsfoffset);
- if (is_tsfoffset_valid)
- *is_tsfoffset_valid = true;
- }
- parsed_payload_len += WLAN_ML_TSF_OFFSET_SIZE;
- }
- /* Check DTIM Info present bit */
- if (QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS)) {
- if (subelempayloadlen <
- (parsed_payload_len +
- sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo))) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain DTIM Info of size %zu octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo),
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len +=
- sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo);
- }
- /* Check NTSR Link pair present bit */
- nstrlppresent =
- QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS);
- if (completeprofile && nstrlppresent) {
- /* Check NTSR Bitmap Size bit */
- nstrbmsz =
- QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS);
- if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) {
- if (subelempayloadlen <
- (parsed_payload_len + 1)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain NTSR Bitmap of size 1 octet after parsed payload length of %zu octets.",
- subelempayloadlen,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += 1;
- } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) {
- if (subelempayloadlen <
- (parsed_payload_len + 2)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain NTSR Bitmap of size 2 octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += 2;
- } else {
- /* Though an invalid value cannot occur if only 1 bit is
- * used, we check for it in a generic manner in case the
- * number of bits is increased in the future.
- */
- mlo_err_rl("Invalid NSTR Bitmap size %u", nstrbmsz);
- return QDF_STATUS_E_PROTO;
- }
- }
- /* Check BSS Parameters Change Count Present bit */
- if (QDF_GET_BITS(stacontrol,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_IDX,
- WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_BITS)) {
- if (subelempayloadlen <
- (parsed_payload_len +
- WLAN_ML_BSSPARAMCHNGCNT_SIZE)) {
- mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain BSS Parameters Change Count of size %u octets after parsed payload length of %zu octets.",
- subelempayloadlen,
- WLAN_ML_BSSPARAMCHNGCNT_SIZE,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
- }
- /* Note: Some implementation versions of hostapd/wpa_supplicant may
- * provide a per-STA profile without STA profile. Let the caller
- * indicate whether a STA profile is required to be found. This may be
- * revisited as upstreaming progresses.
- */
- if (!is_staprof_reqd)
- return QDF_STATUS_SUCCESS;
- if (subelempayloadlen == parsed_payload_len) {
- mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.",
- subelempayloadlen,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- if (staprof_len)
- *staprof_len = subelempayloadlen - parsed_payload_len;
- if (staprof)
- *staprof = subelempayload + parsed_payload_len;
- return QDF_STATUS_SUCCESS;
- }
- static QDF_STATUS
- util_parse_prvmlie_perstaprofile_stactrl(uint8_t *subelempayload,
- qdf_size_t subelempayloadlen,
- uint8_t *linkid,
- bool is_staprof_reqd,
- uint8_t **staprof,
- qdf_size_t *staprof_len)
- {
- qdf_size_t parsed_payload_len = 0;
- uint16_t stacontrol;
- uint8_t completeprofile;
- /* This helper returns the location(s) and where required, the length(s)
- * of (sub)field(s) inferable after parsing the STA Control field in the
- * per-STA profile subelement. These location(s) and length(s) is/are in
- * reference to the payload section of the per-STA profile subelement
- * (after defragmentation, if applicable). Here, the payload is the
- * point after the subelement length in the subelement, and includes the
- * payloads of all subsequent fragments (if any) but not the headers of
- * those fragments.
- *
- * Currently, the helper returns the link ID, MAC address, and STA
- * profile. More (sub)fields can be added when required.
- */
- if (!subelempayload) {
- mlo_err("Pointer to subelement payload is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!subelempayloadlen) {
- mlo_err("Length of subelement payload is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (subelempayloadlen < WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE) {
- mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
- subelempayloadlen,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE);
- return QDF_STATUS_E_PROTO;
- }
- parsed_payload_len = 0;
- qdf_mem_copy(&stacontrol,
- subelempayload,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE);
- stacontrol = qdf_le16_to_cpu(stacontrol);
- parsed_payload_len += WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE;
- if (linkid) {
- *linkid = QDF_GET_BITS(stacontrol,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
- }
- /* Check if this a complete profile */
- completeprofile = QDF_GET_BITS(stacontrol,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
- WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
- /* Note: Some implementation versions of hostapd/wpa_supplicant may
- * provide a per-STA profile without STA profile. Let the caller
- * indicate whether a STA profile is required to be found. This may be
- * revisited as upstreaming progresses.
- */
- if (!is_staprof_reqd)
- return QDF_STATUS_SUCCESS;
- if (subelempayloadlen == parsed_payload_len) {
- mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.",
- subelempayloadlen,
- parsed_payload_len);
- return QDF_STATUS_E_PROTO;
- }
- if (staprof_len)
- *staprof_len = subelempayloadlen - parsed_payload_len;
- if (staprof)
- *staprof = subelempayload + parsed_payload_len;
- return QDF_STATUS_SUCCESS;
- }
- static
- uint8_t *util_get_successorfrag(uint8_t *currie, uint8_t *frame, qdf_size_t len)
- {
- uint8_t *nextie;
- if (!currie || !frame || !len)
- return NULL;
- if ((currie + MIN_IE_LEN) > (frame + len))
- return NULL;
- /* Check whether there is sufficient space in the frame for the current
- * IE, plus at least another MIN_IE_LEN bytes for the IE header of a
- * fragment (if present) that would come just after the current IE.
- */
- if ((currie + MIN_IE_LEN + currie[TAG_LEN_POS] + MIN_IE_LEN) >
- (frame + len))
- return NULL;
- nextie = currie + currie[TAG_LEN_POS] + MIN_IE_LEN;
- /* Check whether there is sufficient space in the frame for the next IE
- */
- if ((nextie + MIN_IE_LEN + nextie[TAG_LEN_POS]) > (frame + len))
- return NULL;
- if (nextie[ID_POS] != WLAN_ELEMID_FRAGMENT)
- return NULL;
- return nextie;
- }
- static
- QDF_STATUS util_parse_partner_info_from_linkinfo(uint8_t *linkinfo,
- qdf_size_t linkinfo_len,
- struct mlo_partner_info *partner_info)
- {
- uint8_t linkid;
- struct qdf_mac_addr macaddr;
- bool is_macaddr_valid;
- uint8_t *linkinfo_currpos;
- qdf_size_t linkinfo_remlen;
- bool is_subelemfragseq;
- uint8_t subelemid;
- qdf_size_t subelemseqtotallen;
- qdf_size_t subelemseqpayloadlen;
- qdf_size_t defragpayload_len;
- QDF_STATUS ret;
- /* This helper function parses partner info from the per-STA profiles
- * present (if any) in the Link Info field in the payload of a Multi
- * Link element (after defragmentation if required). The caller should
- * pass a copy of the payload so that inline defragmentation of
- * subelements can be carried out if required. The subelement
- * defragmentation (if applicable) in this Control Path helper is
- * required for maintainability, accuracy and eliminating current and
- * future per-field-access multi-level fragment boundary checks and
- * adjustments, given the complex format of Multi Link elements. It is
- * also most likely to be required mainly at the client side.
- */
- if (!linkinfo) {
- mlo_err("linkinfo is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!linkinfo_len) {
- mlo_err("linkinfo_len is zero");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!partner_info) {
- mlo_err("ML partner info is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- partner_info->num_partner_links = 0;
- linkinfo_currpos = linkinfo;
- linkinfo_remlen = linkinfo_len;
- while (linkinfo_remlen) {
- if (linkinfo_remlen < sizeof(struct subelem_header)) {
- mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
- linkinfo_remlen,
- sizeof(struct subelem_header));
- return QDF_STATUS_E_PROTO;
- }
- subelemid = linkinfo_currpos[ID_POS];
- is_subelemfragseq = false;
- subelemseqtotallen = 0;
- subelemseqpayloadlen = 0;
- ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- linkinfo_currpos,
- linkinfo_remlen,
- &is_subelemfragseq,
- &subelemseqtotallen,
- &subelemseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (is_subelemfragseq) {
- if (!subelemseqpayloadlen) {
- mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Subelement fragment sequence found with payload len %zu",
- subelemseqpayloadlen);
- ret = wlan_defrag_subelem_fragseq(true,
- WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- linkinfo_currpos,
- linkinfo_remlen,
- NULL,
- 0,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (defragpayload_len != subelemseqpayloadlen) {
- mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
- defragpayload_len,
- subelemseqpayloadlen);
- return QDF_STATUS_E_FAILURE;
- }
- /* Adjust linkinfo_remlen to reflect removal of all
- * subelement headers except the header of the lead
- * subelement.
- */
- linkinfo_remlen -= (subelemseqtotallen -
- subelemseqpayloadlen -
- sizeof(struct subelem_header));
- } else {
- if (linkinfo_remlen <
- (sizeof(struct subelem_header) +
- linkinfo_currpos[TAG_LEN_POS])) {
- mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
- linkinfo_remlen,
- sizeof(struct subelem_header) +
- linkinfo_currpos[TAG_LEN_POS]);
- return QDF_STATUS_E_PROTO;
- }
- subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
- }
- if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
- is_macaddr_valid = false;
- ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos +
- sizeof(struct subelem_header),
- subelemseqpayloadlen,
- &linkid,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &is_macaddr_valid,
- &macaddr,
- false,
- NULL,
- NULL);
- if (QDF_IS_STATUS_ERROR(ret)) {
- return ret;
- }
- if (is_macaddr_valid) {
- if (partner_info->num_partner_links >=
- QDF_ARRAY_SIZE(partner_info->partner_link_info)) {
- mlo_err_rl("Insufficient size %zu of array for partner link info",
- QDF_ARRAY_SIZE(partner_info->partner_link_info));
- return QDF_STATUS_E_NOMEM;
- }
- partner_info->partner_link_info[partner_info->num_partner_links].link_id =
- linkid;
- qdf_mem_copy(&partner_info->partner_link_info[partner_info->num_partner_links].link_addr,
- &macaddr,
- sizeof(partner_info->partner_link_info[partner_info->num_partner_links].link_addr));
- partner_info->num_partner_links++;
- } else {
- mlo_warn_rl("MAC address not found in STA Info field of per-STA profile with link ID %u",
- linkid);
- }
- }
- linkinfo_remlen -= (sizeof(struct subelem_header) +
- subelemseqpayloadlen);
- linkinfo_currpos += (sizeof(struct subelem_header) +
- subelemseqpayloadlen);
- }
- mlo_debug("Number of ML partner links found=%u",
- partner_info->num_partner_links);
- return QDF_STATUS_SUCCESS;
- }
- static QDF_STATUS
- util_parse_probereq_info_from_linkinfo(uint8_t *linkinfo,
- qdf_size_t linkinfo_len,
- struct mlo_probereq_info *probereq_info)
- {
- uint8_t linkid;
- uint8_t *linkinfo_currpos;
- qdf_size_t linkinfo_remlen;
- bool is_subelemfragseq;
- uint8_t subelemid;
- qdf_size_t subelemseqtotallen;
- qdf_size_t subelemseqpayloadlen;
- qdf_size_t defragpayload_len;
- QDF_STATUS ret;
- /* This helper function parses probe request info from the per-STA prof
- * present (if any) in the Link Info field in the payload of a Multi
- * Link element (after defragmentation if required). The caller should
- * pass a copy of the payload so that inline defragmentation of
- * subelements can be carried out if required. The subelement
- * defragmentation (if applicable) in this Control Path helper is
- * required for maintainability, accuracy and eliminating current and
- * future per-field-access multi-level fragment boundary checks and
- * adjustments, given the complex format of Multi Link elements. It is
- * also most likely to be required mainly at the client side.
- */
- if (!linkinfo) {
- mlo_err("linkinfo is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!linkinfo_len) {
- mlo_err("linkinfo_len is zero");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!probereq_info) {
- mlo_err("ML probe req info is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- probereq_info->num_links = 0;
- linkinfo_currpos = linkinfo;
- linkinfo_remlen = linkinfo_len;
- while (linkinfo_remlen) {
- if (linkinfo_remlen < sizeof(struct subelem_header)) {
- mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
- linkinfo_remlen,
- sizeof(struct subelem_header));
- return QDF_STATUS_E_PROTO;
- }
- subelemid = linkinfo_currpos[ID_POS];
- is_subelemfragseq = false;
- subelemseqtotallen = 0;
- subelemseqpayloadlen = 0;
- ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- linkinfo_currpos,
- linkinfo_remlen,
- &is_subelemfragseq,
- &subelemseqtotallen,
- &subelemseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (is_subelemfragseq) {
- if (!subelemseqpayloadlen) {
- mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Subelement fragment sequence found with payload len %zu",
- subelemseqpayloadlen);
- ret = wlan_defrag_subelem_fragseq(true,
- WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- linkinfo_currpos,
- linkinfo_remlen,
- NULL,
- 0,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (defragpayload_len != subelemseqpayloadlen) {
- mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
- defragpayload_len,
- subelemseqpayloadlen);
- return QDF_STATUS_E_FAILURE;
- }
- /* Adjust linkinfo_remlen to reflect removal of all
- * subelement headers except the header of the lead
- * subelement.
- */
- linkinfo_remlen -= (subelemseqtotallen -
- subelemseqpayloadlen -
- sizeof(struct subelem_header));
- } else {
- if (linkinfo_remlen <
- (sizeof(struct subelem_header) +
- linkinfo_currpos[TAG_LEN_POS])) {
- mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
- linkinfo_remlen,
- sizeof(struct subelem_header) +
- linkinfo_currpos[TAG_LEN_POS]);
- return QDF_STATUS_E_PROTO;
- }
- subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
- }
- if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
- ret = util_parse_prvmlie_perstaprofile_stactrl(linkinfo_currpos +
- sizeof(struct subelem_header),
- subelemseqpayloadlen,
- &linkid,
- false,
- NULL,
- NULL);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (probereq_info->num_links >=
- QDF_ARRAY_SIZE(probereq_info->link_id)) {
- mlo_err_rl("Insufficient size %zu of array for probe req link id",
- QDF_ARRAY_SIZE(probereq_info->link_id));
- return QDF_STATUS_E_NOMEM;
- }
- probereq_info->link_id[probereq_info->num_links] = linkid;
- probereq_info->num_links++;
- mlo_debug("LINK ID requested is = %u", linkid);
- }
- linkinfo_remlen -= (sizeof(struct subelem_header) +
- subelemseqpayloadlen);
- linkinfo_currpos += (sizeof(struct subelem_header) +
- subelemseqpayloadlen);
- }
- mlo_debug("Number of ML probe request links found=%u",
- probereq_info->num_links);
- return QDF_STATUS_SUCCESS;
- }
- static
- QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len,
- uint8_t **ninherit_elemlist,
- qdf_size_t *ninherit_elemlist_len,
- uint8_t **ninherit_elemextlist,
- qdf_size_t *ninherit_elemextlist_len)
- {
- uint8_t *ninherit_ie;
- qdf_size_t unparsed_len;
- /* Note: This functionality provided by this helper may be combined with
- * other, older non-inheritance parsing helper functionality and exposed
- * as a common API as part of future efforts once the older
- * functionality can be made generic.
- */
- if (!buff) {
- mlo_err("Pointer to buffer for IEs is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!buff_len) {
- mlo_err("IE buffer length is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (!ninherit_elemlist) {
- mlo_err("Pointer to Non-Inheritance element ID list array is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!ninherit_elemlist_len) {
- mlo_err("Pointer to Non-Inheritance element ID list array length is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!ninherit_elemextlist) {
- mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!ninherit_elemextlist_len) {
- mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- ninherit_ie = NULL;
- *ninherit_elemlist_len = 0;
- *ninherit_elemlist = NULL;
- *ninherit_elemextlist_len = 0;
- *ninherit_elemextlist = NULL;
- ninherit_ie =
- (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
- WLAN_EXTN_ELEMID_NONINHERITANCE,
- buff,
- buff_len);
- if (ninherit_ie) {
- if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) {
- mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary");
- return QDF_STATUS_E_PROTO;
- }
- if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) >
- (buff + buff_len)) {
- mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary",
- ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN);
- return QDF_STATUS_E_PROTO;
- }
- if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) <
- MIN_NONINHERITANCEELEM_LEN) {
- mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u",
- ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN,
- MIN_NONINHERITANCEELEM_LEN);
- return QDF_STATUS_E_PROTO;
- }
- /* Track the number of unparsed octets, excluding the IE header.
- */
- unparsed_len = ninherit_ie[TAG_LEN_POS];
- /* Mark the element ID extension as parsed */
- unparsed_len--;
- *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS];
- unparsed_len--;
- /* While checking if the Non-Inheritance element ID list length
- * exceeds the remaining unparsed IE space, we factor in one
- * octet for the element extension ID list length and subtract
- * this from the unparsed IE space.
- */
- if (*ninherit_elemlist_len > (unparsed_len - 1)) {
- 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",
- *ninherit_elemlist_len, unparsed_len - 1);
- return QDF_STATUS_E_PROTO;
- }
- if (*ninherit_elemlist_len != 0) {
- *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS;
- unparsed_len -= *ninherit_elemlist_len;
- }
- *ninherit_elemextlist_len =
- ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1];
- unparsed_len--;
- if (*ninherit_elemextlist_len > unparsed_len) {
- mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu",
- *ninherit_elemextlist_len, unparsed_len);
- return QDF_STATUS_E_PROTO;
- }
- if (*ninherit_elemextlist_len != 0) {
- *ninherit_elemextlist = ninherit_ie +
- ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len)
- + 2;
- unparsed_len -= *ninherit_elemextlist_len;
- }
- if (unparsed_len > 0) {
- mlo_err_rl("Unparsed length is %zu, expected 0",
- unparsed_len);
- return QDF_STATUS_E_PROTO;
- }
- }
- /* If Non-Inheritance element is not found, we still return success,
- * with the list lengths kept at zero.
- */
- mlo_debug("Non-Inheritance element ID list array length=%zu",
- *ninherit_elemlist_len);
- mlo_debug("Non-Inheritance element ID extension list array length=%zu",
- *ninherit_elemextlist_len);
- return QDF_STATUS_SUCCESS;
- }
- static
- QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len,
- uint8_t *ninherit_elemlist,
- qdf_size_t ninherit_elemlist_len,
- uint8_t *ninherit_elemextlist,
- qdf_size_t ninherit_elemextlist_len,
- bool *is_in_noninheritlist)
- {
- int i;
- /* Evaluate whether the given IE is in the given Non-Inheritance element
- * ID list or Non-Inheritance element ID extension list, and update the
- * result into is_in_noninheritlist. If any list is empty, then the IE
- * is considered to not be present in that list. Both lists can be
- * empty.
- *
- * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is
- * successful, and that is_in_noninheritlist contains a valid value
- * (which could be true or false). If a QDF_STATUS error value is
- * returned, the value in is_in_noninheritlist is invalid and the caller
- * should ignore it.
- */
- /* Note: The functionality provided by this helper may be combined with
- * other, older non-inheritance parsing helper functionality and exposed
- * as a common API as part of future efforts once the older
- * functionality can be made generic.
- */
- /* Except for is_in_noninheritlist and ie, other pointer arguments are
- * permitted to be NULL if they are inapplicable. If they are
- * applicable, they will be checked to ensure they are not NULL.
- */
- if (!is_in_noninheritlist) {
- mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list");
- return QDF_STATUS_E_NULL_VALUE;
- }
- /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero
- * as checked soon in this function, we won't be accessing the IE.
- * However, we still check right-away if the pointer to the IE is
- * non-NULL and whether the total IE length is sane enough to access the
- * element ID and if applicable, the element ID extension, since it
- * doesn't make sense to set the flag in is_in_noninheritlist for a NULL
- * IE pointer or an IE whose total length is not sane enough to
- * distinguish the identity of the IE.
- */
- if (!ie) {
- mlo_err("NULL pointer to IE");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (total_ie_len < (ID_POS + 1)) {
- mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u",
- total_ie_len, ID_POS + 1);
- return QDF_STATUS_E_INVAL;
- }
- if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- (total_ie_len < (IDEXT_POS + 1))) {
- mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u",
- total_ie_len, IDEXT_POS + 1);
- return QDF_STATUS_E_INVAL;
- }
- *is_in_noninheritlist = false;
- /* If both the Non-Inheritance element list and Non-Inheritance element
- * ID extension list are empty, then return success since we can
- * conclude immediately that the given element does not occur in any
- * Non-Inheritance list. The is_in_noninheritlist remains set to false
- * as required.
- */
- if (!ninherit_elemlist_len && !ninherit_elemextlist_len)
- return QDF_STATUS_SUCCESS;
- if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
- if (!ninherit_elemlist_len)
- return QDF_STATUS_SUCCESS;
- if (!ninherit_elemlist) {
- mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu",
- ninherit_elemlist_len);
- return QDF_STATUS_E_NULL_VALUE;
- }
- for (i = 0; i < ninherit_elemlist_len; i++) {
- if (ie[ID_POS] == ninherit_elemlist[i]) {
- *is_in_noninheritlist = true;
- return QDF_STATUS_SUCCESS;
- }
- }
- } else {
- if (!ninherit_elemextlist_len)
- return QDF_STATUS_SUCCESS;
- if (!ninherit_elemextlist) {
- mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu",
- ninherit_elemextlist_len);
- return QDF_STATUS_E_NULL_VALUE;
- }
- for (i = 0; i < ninherit_elemextlist_len; i++) {
- if (ie[IDEXT_POS] == ninherit_elemextlist[i]) {
- *is_in_noninheritlist = true;
- return QDF_STATUS_SUCCESS;
- }
- }
- }
- return QDF_STATUS_SUCCESS;
- }
- static inline
- QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie,
- const uint8_t *frame_iesection,
- const qdf_size_t frame_iesection_len)
- {
- qdf_size_t reportingsta_ie_size;
- if (!reportingsta_ie) {
- mlo_err("Pointer to reporting STA IE is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!frame_iesection) {
- mlo_err("Pointer to start of IE section in reporting frame is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!frame_iesection_len) {
- mlo_err("Length of IE section in reporting frame is zero");
- return QDF_STATUS_E_INVAL;
- }
- if ((reportingsta_ie + ID_POS) > (frame_iesection +
- frame_iesection_len - 1)) {
- mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary");
- return QDF_STATUS_E_PROTO;
- }
- if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection +
- frame_iesection_len - 1)) {
- mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary",
- reportingsta_ie[ID_POS]);
- return QDF_STATUS_E_PROTO;
- }
- if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- ((reportingsta_ie + IDEXT_POS) > (frame_iesection +
- frame_iesection_len - 1))) {
- mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary");
- return QDF_STATUS_E_PROTO;
- }
- reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
- if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- (reportingsta_ie_size < (IDEXT_POS + 1))) {
- mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u",
- reportingsta_ie_size, IDEXT_POS + 1);
- return QDF_STATUS_E_PROTO;
- }
- if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
- (reportingsta_ie_size < (PAYLOAD_START_POS + OUI_LEN))) {
- mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access vendor EID %u",
- reportingsta_ie_size, PAYLOAD_START_POS + OUI_LEN);
- return QDF_STATUS_E_PROTO;
- }
- if ((reportingsta_ie + reportingsta_ie_size) >
- (frame_iesection + frame_iesection_len)) {
- if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- 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",
- reportingsta_ie_size,
- reportingsta_ie[ID_POS],
- reportingsta_ie[IDEXT_POS]);
- } else {
- mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary",
- reportingsta_ie_size,
- reportingsta_ie[ID_POS]);
- }
- return QDF_STATUS_E_PROTO;
- }
- return QDF_STATUS_SUCCESS;
- }
- static inline
- QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie,
- const uint8_t *sta_prof_iesection,
- const qdf_size_t sta_prof_iesection_len)
- {
- qdf_size_t sta_prof_ie_size;
- if (!sta_prof_ie) {
- mlo_err("Pointer to STA profile IE is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!sta_prof_iesection) {
- mlo_err("Pointer to start of IE section in STA profile is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!sta_prof_iesection_len) {
- mlo_err("Length of IE section in STA profile is zero");
- return QDF_STATUS_E_INVAL;
- }
- if ((sta_prof_ie + ID_POS) > (sta_prof_iesection +
- sta_prof_iesection_len - 1)) {
- mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary");
- return QDF_STATUS_E_PROTO;
- }
- if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection +
- sta_prof_iesection_len - 1)) {
- mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary",
- sta_prof_ie[ID_POS]);
- return QDF_STATUS_E_PROTO;
- }
- if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection +
- sta_prof_iesection_len - 1))) {
- mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary");
- return QDF_STATUS_E_PROTO;
- }
- sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
- if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- (sta_prof_ie_size < (IDEXT_POS + 1))) {
- mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u",
- sta_prof_ie_size, IDEXT_POS + 1);
- return QDF_STATUS_E_PROTO;
- }
- if ((sta_prof_ie + sta_prof_ie_size) >
- (sta_prof_iesection + sta_prof_iesection_len)) {
- if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- 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",
- sta_prof_ie_size,
- sta_prof_ie[ID_POS],
- sta_prof_ie[IDEXT_POS]);
- } else {
- mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary",
- sta_prof_ie_size,
- sta_prof_ie[ID_POS]);
- }
- return QDF_STATUS_E_PROTO;
- }
- return QDF_STATUS_SUCCESS;
- }
- #ifdef CONN_MGR_ADV_FEATURE
- /**
- * util_add_mlie_for_prb_rsp_gen - Add the basic variant Multi-Link element
- * when generating link specific probe response.
- * @reportingsta_ie: Pointer to the reportingsta ie
- * @reportingsta_ie_len: Length for reporting sta ie
- * @plink_frame_currpos: Pointer to Link frame current pos
- * @plink_frame_currlen: Current length of link frame.
- * @linkid: Link Id value
- *
- * Add the basic variant Multi-Link element when
- * generating link specific probe response.
- *
- * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
- * the reason for error in the case of failure
- */
- static QDF_STATUS
- util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie,
- qdf_size_t reportingsta_ie_len,
- uint8_t **plink_frame_currpos,
- qdf_size_t *plink_frame_currlen,
- uint8_t linkid)
- {
- uint8_t mlie_len = 0;
- uint8_t common_info_len = 0;
- struct wlan_ie_multilink ml_ie_ff;
- uint16_t mlcontrol;
- uint16_t presencebm;
- uint8_t *mlie_frame = NULL;
- uint8_t link_id_offset = sizeof(struct wlan_ie_multilink) +
- QDF_MAC_ADDR_SIZE +
- WLAN_ML_BV_CINFO_LENGTH_SIZE;
- uint8_t *link_frame_currpos = *plink_frame_currpos;
- qdf_size_t link_frame_currlen = *plink_frame_currlen;
- QDF_STATUS status = QDF_STATUS_SUCCESS;
- status = util_get_mlie_common_info_len((uint8_t *)reportingsta_ie,
- reportingsta_ie_len,
- &common_info_len);
- if (QDF_IS_STATUS_ERROR(status)) {
- mlo_err("Failed while parsing the common info length");
- return status;
- }
- /* common info len + bvmlie fixed fields */
- mlie_len = common_info_len + sizeof(struct wlan_ie_multilink);
- mlo_debug_rl("mlie_len %d, common_info_len %d, link_id_offset %d",
- mlie_len,
- common_info_len,
- link_id_offset);
- mlie_frame = qdf_mem_malloc(mlie_len);
- if (!mlie_frame)
- return QDF_STATUS_E_NOMEM;
- /* Copy ml ie fixed fields */
- qdf_mem_copy(&ml_ie_ff,
- reportingsta_ie,
- sizeof(struct wlan_ie_multilink));
- ml_ie_ff.elem_len = mlie_len - sizeof(struct ie_header);
- mlcontrol = qdf_le16_to_cpu(ml_ie_ff.mlcontrol);
- presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- qdf_set_bit(WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P,
- (unsigned long *)&presencebm);
- QDF_SET_BITS(ml_ie_ff.mlcontrol,
- WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS,
- presencebm);
- qdf_mem_copy(mlie_frame,
- &ml_ie_ff,
- sizeof(struct wlan_ie_multilink));
- qdf_mem_copy(mlie_frame + sizeof(struct wlan_ie_multilink),
- reportingsta_ie + sizeof(struct wlan_ie_multilink),
- mlie_len - sizeof(struct wlan_ie_multilink));
- if (linkid == 0xFF) {
- qdf_mem_free(mlie_frame);
- mlo_err("Link id is invalid");
- return QDF_STATUS_E_INVAL;
- }
- mlie_frame[link_id_offset] = (mlie_frame[link_id_offset] & ~0x0f) |
- (linkid & 0x0f);
- qdf_mem_copy(link_frame_currpos,
- mlie_frame,
- mlie_len);
- mlo_debug("Add mlie for link id %d", linkid);
- QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
- mlie_frame, mlie_len);
- link_frame_currpos += mlie_len;
- link_frame_currlen += mlie_len;
- *plink_frame_currpos = link_frame_currpos;
- *plink_frame_currlen = link_frame_currlen;
- qdf_mem_free(mlie_frame);
- return QDF_STATUS_SUCCESS;
- }
- #else
- static QDF_STATUS
- util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie,
- qdf_size_t reportingsta_ie_len,
- uint8_t **plink_frame_currpos,
- qdf_size_t *plink_frame_currlen,
- uint8_t linkid)
- {
- return QDF_STATUS_SUCCESS;
- }
- #endif
- #define MLO_LINKSPECIFIC_ASSOC_REQ_FC0 0x00
- #define MLO_LINKSPECIFIC_ASSOC_REQ_FC1 0x00
- #define MLO_LINKSPECIFIC_ASSOC_RESP_FC0 0x10
- #define MLO_LINKSPECIFIC_ASSOC_RESP_FC1 0x00
- #define MLO_LINKSPECIFIC_PROBE_RESP_FC0 0x50
- #define MLO_LINKSPECIFIC_PROBE_RESP_FC1 0x00
- static
- QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len,
- uint8_t subtype,
- struct qdf_mac_addr link_addr,
- uint8_t *link_frame,
- qdf_size_t link_frame_maxsize,
- qdf_size_t *link_frame_len)
- {
- /* Please see documentation for util_gen_link_assoc_req() and
- * util_gen_link_assoc_resp() for information on the inputs to and
- * output from this helper, since those APIs are essentially wrappers
- * over this helper.
- */
- /* Pointer to Multi-Link element/Multi-Link element fragment sequence */
- uint8_t *mlieseq;
- /* Total length of Multi-Link element sequence (including fragments if
- * any)
- */
- qdf_size_t mlieseqlen;
- /* Variant (i.e. type) of the Multi-Link element */
- enum wlan_ml_variant variant;
- /* Length of the payload of the Multi-Link element (inclusive of
- * fragment payloads if any) without IE headers and element ID extension
- */
- qdf_size_t mlieseqpayloadlen;
- /* Pointer to copy of the payload of the Multi-Link element (inclusive
- * of fragment payloads if any) without IE headers and element ID
- * extension
- */
- uint8_t *mlieseqpayload_copy;
- /* Pointer to start of Link Info within the copy of the payload of the
- * Multi-Link element
- */
- uint8_t *link_info;
- /* Length of the Link Info */
- qdf_size_t link_info_len;
- /* Pointer to the IE section that occurs after the fixed fields in the
- * original frame for the reporting STA.
- */
- uint8_t *frame_iesection;
- /* Offset to the start of the IE section in the original frame for the
- * reporting STA.
- */
- qdf_size_t frame_iesection_offset;
- /* Total length of the IE section in the original frame for the
- * reporting STA.
- */
- qdf_size_t frame_iesection_len;
- /* Pointer to the IEEE802.11 frame header in the link specific frame
- * being generated for the reported STA.
- */
- struct wlan_frame_hdr *link_frame_hdr;
- /* Current position in the link specific frame being generated for the
- * reported STA.
- */
- uint8_t *link_frame_currpos;
- /* Current length of the link specific frame being generated for the
- * reported STA.
- */
- qdf_size_t link_frame_currlen;
- /* Pointer to IE for reporting STA */
- const uint8_t *reportingsta_ie;
- /* Total size of IE for reporting STA, inclusive of the element header
- */
- qdf_size_t reportingsta_ie_size;
- /* Pointer to current position in STA profile */
- uint8_t *sta_prof_currpos;
- /* Remaining length of STA profile */
- qdf_size_t sta_prof_remlen;
- /* Pointer to start of IE section in STA profile that occurs after fixed
- * fields.
- */
- uint8_t *sta_prof_iesection;
- /* Total length of IE section in STA profile */
- qdf_size_t sta_prof_iesection_len;
- /* Pointer to current position being processed in IE section in STA
- * profile.
- */
- uint8_t *sta_prof_iesection_currpos;
- /* Remaining length of IE section in STA profile */
- qdf_size_t sta_prof_iesection_remlen;
- /* Pointer to IE in STA profile, that occurs within IE section */
- uint8_t *sta_prof_ie;
- /* Total size of IE in STA profile, inclusive of the element header */
- qdf_size_t sta_prof_ie_size;
- /* Pointer to element ID list in Non-Inheritance IE */
- uint8_t *ninherit_elemlist;
- /* Length of element ID list in Non-Inheritance IE */
- qdf_size_t ninherit_elemlist_len;
- /* Pointer to element ID extension list in Non-Inheritance IE */
- uint8_t *ninherit_elemextlist;
- /* Length of element ID extension list in Non-Inheritance IE */
- qdf_size_t ninherit_elemextlist_len;
- /* Whether a given IE is in a non-inheritance list */
- bool is_in_noninheritlist;
- /* Whether MAC address of reported STA is valid */
- bool is_reportedmacaddr_valid;
- /* MAC address of reported STA */
- struct qdf_mac_addr reportedmacaddr;
- /* Pointer to per-STA profile */
- uint8_t *persta_prof;
- /* Length of the containing buffer which starts with the per-STA profile
- */
- qdf_size_t persta_prof_bufflen;
- /* Other variables for temporary purposes */
- /* Variable into which API for determining fragment information will
- * indicate whether the element is the start of a fragment sequence or
- * not.
- */
- bool is_elemfragseq;
- /* De-fragmented payload length returned by API for element
- * defragmentation.
- */
- qdf_size_t defragpayload_len;
- /* Variable into which API for determining fragment information will
- * indicate whether the subelement is the start of a fragment sequence
- * or not.
- */
- bool is_subelemfragseq;
- /* Total length of the subelement fragment sequence, inclusive of
- * subelement header and the headers of fragments if any.
- */
- qdf_size_t subelemseqtotallen;
- /* Total length of the subelement fragment sequence payload, excluding
- * subelement header and fragment headers if any.
- */
- qdf_size_t subelemseqpayloadlen;
- /* Pointer to Beacon interval in STA info field */
- uint16_t beaconinterval;
- /* Whether Beacon interval value valid */
- bool is_beaconinterval_valid;
- /* TSF timer of the reporting AP */
- uint64_t tsf;
- /* TSF offset of the reproted AP */
- uint64_t tsfoffset;
- /* TSF offset value valid */
- bool is_tsfoffset_valid;
- /* If Complete Profile or not*/
- bool is_completeprofile;
- qdf_size_t tmplen;
- QDF_STATUS ret;
- uint8_t linkid = 0xFF;
- if (!frame) {
- mlo_err("Pointer to original frame is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!frame_len) {
- mlo_err("Length of original frame is zero");
- return QDF_STATUS_E_INVAL;
- }
- if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) &&
- (subtype != WLAN_FC0_STYPE_REASSOC_REQ) &&
- (subtype != WLAN_FC0_STYPE_ASSOC_RESP) &&
- (subtype != WLAN_FC0_STYPE_REASSOC_RESP) &&
- (subtype != WLAN_FC0_STYPE_PROBE_RESP)) {
- mlo_err("802.11 frame subtype %u is invalid", subtype);
- return QDF_STATUS_E_INVAL;
- }
- if (!link_frame) {
- mlo_err("Pointer to secondary link specific frame is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!link_frame_maxsize) {
- mlo_err("Maximum size of secondary link specific frame is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (!link_frame_len) {
- mlo_err("Pointer to populated length of secondary link specific frame is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- frame_iesection_offset = 0;
- if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) {
- frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET;
- } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
- frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET;
- } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
- frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET;
- qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN);
- tsf = qdf_le64_to_cpu(tsf);
- } else {
- /* This is a (re)association response */
- frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET;
- }
- if (frame_len < frame_iesection_offset) {
- /* The caller is supposed to have confirmed that this is a valid
- * frame containing a Multi-Link element. Hence we treat this as
- * a case of invalid argument being passed to us.
- */
- mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u",
- frame_len, frame_iesection_offset, subtype);
- return QDF_STATUS_E_INVAL;
- }
- frame_iesection_len = frame_len - frame_iesection_offset;
- if (frame_iesection_len == 0) {
- /* The caller is supposed to have confirmed that this is a valid
- * frame containing a Multi-Link element. Hence we treat this as
- * a case of invalid argument being passed to us.
- */
- mlo_err("No space left in frame for IE section");
- return QDF_STATUS_E_INVAL;
- }
- frame_iesection = frame + frame_iesection_offset;
- mlieseq = NULL;
- mlieseqlen = 0;
- ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq,
- &mlieseqlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (!mlieseq) {
- /* The caller is supposed to have confirmed that a Multi-Link
- * element is present in the frame. Hence we treat this as a
- * case of invalid argument being passed to us.
- */
- mlo_err("Invalid original frame since no Multi-Link element found");
- return QDF_STATUS_E_INVAL;
- }
- /* Sanity check the Multi-Link element sequence length */
- if (!mlieseqlen) {
- mlo_err("Length of Multi-Link element sequence is zero. Investigate.");
- return QDF_STATUS_E_FAILURE;
- }
- if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
- mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
- mlieseqlen, sizeof(struct wlan_ie_multilink));
- return QDF_STATUS_E_PROTO;
- }
- ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (variant != WLAN_ML_VARIANT_BASIC) {
- mlo_err_rl("Unexpected variant %u of Multi-Link element.",
- variant);
- return QDF_STATUS_E_PROTO;
- }
- mlieseqpayloadlen = 0;
- tmplen = 0;
- is_elemfragseq = false;
- ret = wlan_get_elem_fragseq_info(mlieseq,
- mlieseqlen,
- &is_elemfragseq,
- &tmplen,
- &mlieseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (is_elemfragseq) {
- if (tmplen != mlieseqlen) {
- mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val per Multi-Link element search: %zu octets",
- tmplen, mlieseqlen);
- return QDF_STATUS_E_FAILURE;
- }
- if (!mlieseqpayloadlen) {
- mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
- mlieseqpayloadlen);
- } else {
- if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
- mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found",
- mlieseqlen,
- sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
- return QDF_STATUS_E_FAILURE;
- }
- mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
- }
- mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
- if (!mlieseqpayload_copy) {
- mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
- return QDF_STATUS_E_NOMEM;
- }
- if (is_elemfragseq) {
- ret = wlan_defrag_elem_fragseq(false,
- mlieseq,
- mlieseqlen,
- mlieseqpayload_copy,
- mlieseqpayloadlen,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (defragpayload_len != mlieseqpayloadlen) {
- mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
- defragpayload_len, mlieseqpayloadlen);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_FAILURE;
- }
- } else {
- qdf_mem_copy(mlieseqpayload_copy,
- mlieseq + sizeof(struct ie_header) + 1,
- mlieseqpayloadlen);
- }
- link_info = NULL;
- link_info_len = 0;
- ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
- mlieseqpayloadlen,
- &link_info,
- &link_info_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- /* As per the standard, the sender must include Link Info for
- * association request/response. Throw an error if we are unable to
- * obtain this.
- */
- if (!link_info) {
- mlo_err_rl("Unable to successfully obtain Link Info");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- mlo_debug("Dumping hex of link info after parsing Multi-Link element control");
- QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_DEBUG,
- link_info, link_info_len);
- /* Note: We may have a future change to skip subelements which are not
- * Per-STA Profile, handle more than two links in MLO, handle cases
- * where we unexpectedly find more Per-STA Profiles than expected, etc.
- */
- persta_prof = link_info;
- persta_prof_bufflen = link_info_len;
- is_subelemfragseq = false;
- subelemseqtotallen = 0;
- subelemseqpayloadlen = 0;
- ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- persta_prof,
- persta_prof_bufflen,
- &is_subelemfragseq,
- &subelemseqtotallen,
- &subelemseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (is_subelemfragseq) {
- if (!subelemseqpayloadlen) {
- mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Subelement fragment sequence found with payload len %zu",
- subelemseqpayloadlen);
- ret = wlan_defrag_subelem_fragseq(true,
- WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
- persta_prof,
- persta_prof_bufflen,
- NULL,
- 0,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (defragpayload_len != subelemseqpayloadlen) {
- mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
- defragpayload_len,
- subelemseqpayloadlen);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_FAILURE;
- }
- } else {
- if (persta_prof_bufflen <
- (sizeof(struct subelem_header) +
- persta_prof[TAG_LEN_POS])) {
- mlo_err_rl("Length of buffer containing per-STA profile %zu octets is smaller than total size of current subelement %zu octets",
- persta_prof_bufflen,
- sizeof(struct subelem_header) +
- persta_prof[TAG_LEN_POS]);
- return QDF_STATUS_E_PROTO;
- }
- subelemseqpayloadlen = persta_prof[TAG_LEN_POS];
- }
- sta_prof_remlen = 0;
- sta_prof_currpos = NULL;
- is_reportedmacaddr_valid = false;
- is_beaconinterval_valid = false;
- is_completeprofile = false;
- is_tsfoffset_valid = false;
- /* Parse per-STA profile */
- ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof +
- sizeof(struct subelem_header),
- subelemseqpayloadlen,
- &linkid,
- &beaconinterval,
- &is_beaconinterval_valid,
- &tsfoffset,
- &is_tsfoffset_valid,
- &is_completeprofile,
- &is_reportedmacaddr_valid,
- &reportedmacaddr,
- true,
- &sta_prof_currpos,
- &sta_prof_remlen);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) {
- mlo_err("Complete profile information is not present in per-STA profile of probe response frame");
- return QDF_STATUS_E_NOSUPPORT;
- }
- /* We double check for a NULL STA Profile, though the helper function
- * above would have taken care of this. We need to get a non-NULL STA
- * profile, because we need to get at least the expected fixed fields,
- * even if there is an (improbable) total inheritance.
- */
- if (!sta_prof_currpos) {
- mlo_err_rl("STA profile is NULL");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- /* As per the standard, the sender sets the MAC address in the per-STA
- * profile in association request/response. Without this, we cannot
- * generate the link specific frame.
- */
- if (!is_reportedmacaddr_valid) {
- mlo_err_rl("Unable to get MAC address from per-STA profile");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- link_frame_currpos = link_frame;
- *link_frame_len = 0;
- link_frame_currlen = 0;
- if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) {
- mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets",
- WLAN_MAC_HDR_LEN_3A, link_frame_maxsize);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- link_frame_currpos += WLAN_MAC_HDR_LEN_3A;
- link_frame_currlen += WLAN_MAC_HDR_LEN_3A;
- if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
- (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
- mlo_debug("Populating fixed fields for (re)assoc req in link specific frame");
- if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) {
- mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u",
- sta_prof_remlen,
- WLAN_CAPABILITYINFO_LEN);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- /* Capability information is specific to the link. Copy this
- * from the STA profile.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- WLAN_CAPABILITYINFO_LEN) {
- mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets",
- WLAN_CAPABILITYINFO_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
- WLAN_CAPABILITYINFO_LEN);
- link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
- link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
- mlo_debug("Added Capability Info field (%u octets) to link specific frame",
- WLAN_CAPABILITYINFO_LEN);
- sta_prof_currpos += WLAN_CAPABILITYINFO_LEN;
- sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN;
- /* Listen Interval is common between all links. Copy this from
- * the reporting section of the frame.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- WLAN_LISTENINTERVAL_LEN) {
- mlo_err("Insufficient space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets",
- WLAN_LISTENINTERVAL_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos,
- frame + WLAN_CAPABILITYINFO_LEN,
- WLAN_LISTENINTERVAL_LEN);
- link_frame_currpos += WLAN_LISTENINTERVAL_LEN;
- link_frame_currlen += WLAN_LISTENINTERVAL_LEN;
- mlo_debug("Added Listen Interval field (%u octets) to link specific frame",
- WLAN_LISTENINTERVAL_LEN);
- if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
- /* Current AP address is common between all links. Copy
- * this from the reporting section of the frame.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- QDF_MAC_ADDR_SIZE) {
- mlo_err("Insufficient space in link specific frame for current AP address. Required: %u octets, available: %zu octets",
- QDF_MAC_ADDR_SIZE,
- (link_frame_maxsize -
- link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos,
- frame + WLAN_CAPABILITYINFO_LEN +
- WLAN_LISTENINTERVAL_LEN,
- QDF_MAC_ADDR_SIZE);
- link_frame_currpos += QDF_MAC_ADDR_SIZE;
- link_frame_currlen += QDF_MAC_ADDR_SIZE;
- mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame",
- QDF_MAC_ADDR_SIZE);
- }
- } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP ||
- subtype == WLAN_FC0_STYPE_REASSOC_RESP) {
- /* This is a (re)association response */
- mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame");
- if (sta_prof_remlen <
- (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
- mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u",
- sta_prof_remlen,
- WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- /* Capability information and Status Code are specific to the
- * link. Copy these from the STA profile.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
- mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets",
- WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
- (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN));
- link_frame_currpos += (WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN);
- link_frame_currlen += (WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN);
- mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame",
- WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN);
- sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN);
- sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN);
- /* AID is common between all links. Copy this from the original
- * frame.
- */
- if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) {
- mlo_err("Insufficient space in link specific frame for AID field. Required: %u octets, available: %zu octets",
- WLAN_AID_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos,
- frame + WLAN_CAPABILITYINFO_LEN +
- WLAN_STATUSCODE_LEN,
- WLAN_AID_LEN);
- link_frame_currpos += WLAN_AID_LEN;
- link_frame_currlen += WLAN_AID_LEN;
- mlo_debug("Added AID field (%u octets) to link specific frame",
- WLAN_AID_LEN);
- } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
- /* This is a probe response */
- mlo_debug("Populating fixed fields for probe response in link specific frame");
- if ((link_frame_maxsize - link_frame_currlen) <
- WLAN_TIMESTAMP_LEN) {
- mlo_err("Insufficient space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets",
- WLAN_TIMESTAMP_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info
- * field indicates the offset (Toffset)between the TSF timer of
- * the reported AP (TA) and the TSF timer of the reporting
- * AP (TB) and is encoded as a 2s complement signed integer
- * with units of 2 µs. Toffset is calculated as
- * Toffset= Floor((TA – TB)/2).
- */
- if (is_tsfoffset_valid)
- tsf += tsfoffset * 2;
- qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN);
- link_frame_currpos += WLAN_TIMESTAMP_LEN;
- link_frame_currlen += WLAN_TIMESTAMP_LEN;
- mlo_debug("Added Timestamp Info field (%u octets) to link specific frame",
- WLAN_TIMESTAMP_LEN);
- if (!is_beaconinterval_valid) {
- mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- /* Beacon Interval information copy this from
- * the STA info field.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- WLAN_BEACONINTERVAL_LEN) {
- mlo_err("Insufficient space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets",
- WLAN_BEACONINTERVAL_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos, &beaconinterval,
- WLAN_BEACONINTERVAL_LEN);
- link_frame_currpos += WLAN_BEACONINTERVAL_LEN;
- link_frame_currlen += WLAN_BEACONINTERVAL_LEN;
- mlo_debug("Added Beacon Interval Info field (%u octets) to link specific frame",
- WLAN_BEACONINTERVAL_LEN);
- if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) {
- mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u",
- sta_prof_remlen,
- WLAN_CAPABILITYINFO_LEN);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- /* Capability information is specific to the link. Copy this
- * from the STA profile.
- */
- if ((link_frame_maxsize - link_frame_currlen) <
- WLAN_CAPABILITYINFO_LEN) {
- mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets",
- WLAN_CAPABILITYINFO_LEN,
- (link_frame_maxsize - link_frame_currlen));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
- WLAN_CAPABILITYINFO_LEN);
- link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
- link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
- mlo_debug("Added Capability Info field (%u octets) to link specific frame",
- WLAN_CAPABILITYINFO_LEN);
- sta_prof_currpos += WLAN_CAPABILITYINFO_LEN;
- sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN;
- }
- sta_prof_iesection = sta_prof_currpos;
- sta_prof_iesection_len = sta_prof_remlen;
- /* Populate non-inheritance lists if applicable */
- ninherit_elemlist_len = 0;
- ninherit_elemlist = NULL;
- ninherit_elemextlist_len = 0;
- ninherit_elemextlist = NULL;
- ret = util_get_noninheritlists(sta_prof_iesection,
- sta_prof_iesection_len,
- &ninherit_elemlist,
- &ninherit_elemlist_len,
- &ninherit_elemextlist,
- &ninherit_elemextlist_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- /* Go through IEs of the reporting STA, and those in STA profile, merge
- * them into link_frame (except for elements in the Non-Inheritance
- * list).
- *
- * Note: Currently, only 2-link MLO is supported here. We may have a
- * future change to expand to more links.
- */
- reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection,
- frame_iesection_len);
- if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
- (subtype == WLAN_FC0_STYPE_REASSOC_REQ) ||
- (subtype == WLAN_FC0_STYPE_PROBE_RESP)) {
- /* Sanity check that the SSID element is present for the
- * reporting STA. There is no stipulation in the standard for
- * the STA profile in this regard, so we do not check the STA
- * profile for the SSID element.
- */
- if (!reportingsta_ie) {
- mlo_err_rl("SSID element not found in reporting STA of the frame.");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- } else {
- /* This is a (re)association response. Sanity check that the
- * SSID element is present neither for the reporting STA nor in
- * the STA profile.
- */
- if (reportingsta_ie) {
- mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present.");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID,
- sta_prof_iesection,
- sta_prof_iesection_len);
- if (sta_prof_ie) {
- mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present.");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_PROTO;
- }
- }
- reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection;
- ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection,
- frame_iesection_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
- while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection)
- <= frame_iesection_len) {
- /* Skip Multi-Link element */
- if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
- (reportingsta_ie[IDEXT_POS] ==
- WLAN_EXTN_ELEMID_MULTI_LINK)) {
- if (((reportingsta_ie + reportingsta_ie_size) -
- frame_iesection) == frame_iesection_len)
- break;
- /* Add BV ML IE for link specific probe response */
- if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
- ret = util_add_mlie_for_prb_rsp_gen(reportingsta_ie,
- reportingsta_ie[TAG_LEN_POS],
- &link_frame_currpos,
- &link_frame_currlen,
- linkid);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- }
- reportingsta_ie += reportingsta_ie_size;
- ret = util_validate_reportingsta_ie(reportingsta_ie,
- frame_iesection,
- frame_iesection_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
- MIN_IE_LEN;
- continue;
- }
- sta_prof_ie = NULL;
- sta_prof_ie_size = 0;
- if (sta_prof_iesection_len) {
- if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS],
- reportingsta_ie[IDEXT_POS],
- sta_prof_iesection,
- sta_prof_iesection_len);
- } else {
- sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS],
- sta_prof_iesection,
- sta_prof_iesection_len);
- }
- }
- if (!sta_prof_ie) {
- /* IE is present for reporting STA, but not in STA
- * profile.
- */
- is_in_noninheritlist = false;
- ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie,
- reportingsta_ie_size,
- ninherit_elemlist,
- ninherit_elemlist_len,
- ninherit_elemextlist,
- ninherit_elemextlist_len,
- &is_in_noninheritlist);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (!is_in_noninheritlist) {
- if ((link_frame_currpos +
- reportingsta_ie_size) <=
- (link_frame + link_frame_maxsize)) {
- qdf_mem_copy(link_frame_currpos,
- reportingsta_ie,
- reportingsta_ie_size);
- link_frame_currpos +=
- reportingsta_ie_size;
- link_frame_currlen +=
- reportingsta_ie_size;
- if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- 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",
- reportingsta_ie[ID_POS],
- reportingsta_ie[IDEXT_POS],
- reportingsta_ie_size);
- } else {
- 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",
- reportingsta_ie[ID_POS],
- reportingsta_ie_size);
- }
- } else {
- if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
- reportingsta_ie[ID_POS],
- reportingsta_ie[IDEXT_POS],
- reportingsta_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- } else {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
- reportingsta_ie[ID_POS],
- reportingsta_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- }
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- } else {
- if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- 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.",
- reportingsta_ie[ID_POS],
- reportingsta_ie[IDEXT_POS],
- reportingsta_ie_size);
- } else {
- 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.",
- reportingsta_ie[ID_POS],
- reportingsta_ie_size);
- }
- }
- } else {
- /* IE is present for reporting STA and also in STA
- * profile, copy from STA profile and flag the IE in STA
- * profile as copied (by setting EID field to 0). The
- * SSID element (with EID 0) is processed first to
- * enable this. For vendor IE, compare OUI + type +
- * subType to determine if they are the same IE.
- */
- /* Note: This may be revisited in a future change, to
- * adhere to provisions in the standard for multiple
- * occurrences of a given element ID/extension element
- * ID.
- */
- ret = util_validate_sta_prof_ie(sta_prof_ie,
- sta_prof_iesection,
- sta_prof_iesection_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] +
- MIN_IE_LEN;
- sta_prof_iesection_remlen =
- sta_prof_iesection_len -
- (sta_prof_ie - sta_prof_iesection);
- if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
- (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) {
- /* If Vendor IE also presents in STA profile,
- * then ignore the Vendor IE which is for
- * reporting STA. It only needs to copy Vendor
- * IE from STA profile to link specific frame.
- * The copy happens when going through the
- * remaining IEs.
- */
- ;
- } else {
- /* Copy IE from STA profile into link specific
- * frame.
- */
- if ((link_frame_currpos + sta_prof_ie_size) <=
- (link_frame + link_frame_maxsize)) {
- qdf_mem_copy(link_frame_currpos,
- sta_prof_ie,
- sta_prof_ie_size);
- link_frame_currpos += sta_prof_ie_size;
- link_frame_currlen +=
- sta_prof_ie_size;
- if (reportingsta_ie[ID_POS] ==
- WLAN_ELEMID_EXTN_ELEM) {
- 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",
- sta_prof_ie[ID_POS],
- sta_prof_ie[IDEXT_POS],
- sta_prof_ie_size);
- } else {
- 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",
- sta_prof_ie[ID_POS],
- sta_prof_ie_size);
- }
- sta_prof_ie[0] = 0;
- } else {
- if (sta_prof_ie[ID_POS] ==
- WLAN_ELEMID_EXTN_ELEM) {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
- sta_prof_ie[ID_POS],
- sta_prof_ie[IDEXT_POS],
- sta_prof_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- } else {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
- sta_prof_ie[ID_POS],
- sta_prof_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- }
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- }
- }
- if (((reportingsta_ie + reportingsta_ie_size) -
- frame_iesection) == frame_iesection_len)
- break;
- reportingsta_ie += reportingsta_ie_size;
- ret = util_validate_reportingsta_ie(reportingsta_ie,
- frame_iesection,
- frame_iesection_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
- MIN_IE_LEN;
- }
- /* Go through the remaining unprocessed IEs in STA profile and copy them
- * to the link specific frame. The processed ones are marked with 0 in
- * the first octet. The first octet corresponds to the element ID. In
- * the case of (re)association request, the element with actual ID
- * WLAN_ELEMID_SSID(0) has already been copied to the link specific
- * frame. In the case of (re)association response, it has been verified
- * that the element with actual ID WLAN_ELEMID_SSID(0) is present
- * neither for the reporting STA nor in the STA profile.
- */
- sta_prof_iesection_currpos = sta_prof_iesection;
- sta_prof_iesection_remlen = sta_prof_iesection_len;
- while (sta_prof_iesection_remlen > 0) {
- sta_prof_ie = sta_prof_iesection_currpos;
- ret = util_validate_sta_prof_ie(sta_prof_ie,
- sta_prof_iesection_currpos,
- sta_prof_iesection_remlen);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
- if (!sta_prof_ie[0]) {
- /* Skip this, since it has already been processed */
- sta_prof_iesection_currpos += sta_prof_ie_size;
- sta_prof_iesection_remlen -= sta_prof_ie_size;
- continue;
- }
- /* Copy IE from STA profile into link specific frame. */
- if ((link_frame_currpos + sta_prof_ie_size) <=
- (link_frame + link_frame_maxsize)) {
- qdf_mem_copy(link_frame_currpos,
- sta_prof_ie,
- sta_prof_ie_size);
- link_frame_currpos += sta_prof_ie_size;
- link_frame_currlen +=
- sta_prof_ie_size;
- if (reportingsta_ie[ID_POS] ==
- WLAN_ELEMID_EXTN_ELEM) {
- 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",
- sta_prof_ie[ID_POS],
- sta_prof_ie[IDEXT_POS],
- sta_prof_ie_size);
- } else {
- mlo_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
- sta_prof_ie[ID_POS],
- sta_prof_ie_size);
- }
- sta_prof_ie[0] = 0;
- } else {
- if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
- sta_prof_ie[ID_POS],
- sta_prof_ie[IDEXT_POS],
- sta_prof_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- } else {
- mlo_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
- sta_prof_ie[ID_POS],
- sta_prof_ie_size,
- link_frame_maxsize -
- link_frame_currlen);
- }
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_NOMEM;
- }
- sta_prof_iesection_currpos += sta_prof_ie_size;
- sta_prof_iesection_remlen -= sta_prof_ie_size;
- }
- /* Copy the link MAC addr */
- link_frame_hdr = (struct wlan_frame_hdr *)link_frame;
- if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
- (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
- qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
- QDF_MAC_ADDR_SIZE);
- link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0;
- link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1;
- } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
- qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
- QDF_MAC_ADDR_SIZE);
- link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0;
- link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1;
- } else {
- /* This is a (re)association response */
- qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
- QDF_MAC_ADDR_SIZE);
- qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
- QDF_MAC_ADDR_SIZE);
- link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0;
- link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1;
- }
- mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:"
- QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT,
- subtype,
- QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3),
- QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2),
- QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1));
- /* Seq num not used so not populated */
- qdf_mem_free(mlieseqpayload_copy);
- *link_frame_len = link_frame_currlen;
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
- struct qdf_mac_addr link_addr,
- uint8_t *link_frame,
- qdf_size_t link_frame_maxsize,
- qdf_size_t *link_frame_len)
- {
- return util_gen_link_reqrsp_cmn(frame, frame_len,
- (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ :
- WLAN_FC0_STYPE_ASSOC_REQ),
- link_addr, link_frame, link_frame_maxsize,
- link_frame_len);
- }
- QDF_STATUS
- util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
- struct qdf_mac_addr link_addr,
- uint8_t *link_frame,
- qdf_size_t link_frame_maxsize,
- qdf_size_t *link_frame_len)
- {
- return util_gen_link_reqrsp_cmn(frame, frame_len,
- (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP :
- WLAN_FC0_STYPE_ASSOC_RESP),
- link_addr, link_frame, link_frame_maxsize,
- link_frame_len);
- }
- QDF_STATUS
- util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len,
- struct qdf_mac_addr link_addr,
- uint8_t *link_frame,
- qdf_size_t link_frame_maxsize,
- qdf_size_t *link_frame_len)
- {
- return util_gen_link_reqrsp_cmn(frame, frame_len,
- WLAN_FC0_STYPE_PROBE_RESP,
- link_addr, link_frame, link_frame_maxsize,
- link_frame_len);
- }
- QDF_STATUS
- util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
- qdf_size_t *mlieseqlen)
- {
- uint8_t *bufboundary;
- uint8_t *ieseq;
- qdf_size_t ieseqlen;
- uint8_t *currie;
- uint8_t *successorfrag;
- if (!buf || !buflen || !mlieseq || !mlieseqlen)
- return QDF_STATUS_E_NULL_VALUE;
- *mlieseq = NULL;
- *mlieseqlen = 0;
- /* Find Multi-Link element. In case a fragment sequence is present,
- * this element will be the leading fragment.
- */
- ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
- WLAN_EXTN_ELEMID_MULTI_LINK, buf,
- buflen);
- /* Even if the element is not found, we have successfully examined the
- * buffer. The caller will be provided a NULL value for the starting of
- * the Multi-Link element. Hence, we return success.
- */
- if (!ieseq)
- return QDF_STATUS_SUCCESS;
- bufboundary = buf + buflen;
- if ((ieseq + MIN_IE_LEN) > bufboundary)
- return QDF_STATUS_E_INVAL;
- ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS];
- if (ieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_PROTO;
- if ((ieseq + ieseqlen) > bufboundary)
- return QDF_STATUS_E_INVAL;
- /* In the next sequence of checks, if there is no space in the buffer
- * for another element after the Multi-Link element/element fragment
- * sequence, it could indicate an issue since non-MLO EHT elements
- * would be expected to follow the Multi-Link element/element fragment
- * sequence. However, this is outside of the purview of this function,
- * hence we ignore it.
- */
- currie = ieseq;
- successorfrag = util_get_successorfrag(currie, buf, buflen);
- /* Fragmentation definitions as of IEEE802.11be D1.0 and
- * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link
- * element is present in a buffer from the core frame is considered.
- * Future changes to fragmentation, cases where the Multi-Link element
- * is present in a subelement, etc. to be reflected here if applicable
- * as and when the rules evolve.
- */
- while (successorfrag) {
- /* We should not be seeing a successor fragment if the length
- * of the current IE is lesser than the max.
- */
- if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN)
- return QDF_STATUS_E_PROTO;
- if (successorfrag[TAG_LEN_POS] == 0)
- return QDF_STATUS_E_PROTO;
- ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]);
- currie = successorfrag;
- successorfrag = util_get_successorfrag(currie, buf, buflen);
- }
- *mlieseq = ieseq;
- *mlieseqlen = ieseqlen;
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_find_mlie_by_variant(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
- qdf_size_t *mlieseqlen, int variant)
- {
- uint8_t *ieseq;
- qdf_size_t ieseqlen;
- QDF_STATUS status;
- int ml_variant;
- qdf_size_t buf_parsed_len;
- if (!buf || !buflen || !mlieseq || !mlieseqlen)
- return QDF_STATUS_E_NULL_VALUE;
- if (variant >= WLAN_ML_VARIANT_INVALIDSTART)
- return QDF_STATUS_E_PROTO;
- ieseq = NULL;
- ieseqlen = 0;
- *mlieseq = NULL;
- *mlieseqlen = 0;
- buf_parsed_len = 0;
- while (buflen > buf_parsed_len) {
- status = util_find_mlie(buf + buf_parsed_len,
- buflen - buf_parsed_len,
- &ieseq, &ieseqlen);
- if (QDF_IS_STATUS_ERROR(status))
- return status;
- /* Even if the element is not found, we have successfully
- * examined the buffer. The caller will be provided a NULL value
- * for the starting of the Multi-Link element. Hence, we return
- * success.
- */
- if (!ieseq)
- return QDF_STATUS_SUCCESS;
- status = util_get_mlie_variant(ieseq, ieseqlen,
- &ml_variant);
- if (QDF_IS_STATUS_ERROR(status)) {
- mlo_err("Unable to get Multi-link element variant");
- return status;
- }
- if (ml_variant == variant) {
- *mlieseq = ieseq;
- *mlieseqlen = ieseqlen;
- return QDF_STATUS_SUCCESS;
- }
- buf_parsed_len = ieseq + ieseqlen - buf;
- }
- return QDF_STATUS_E_INVAL;
- }
- QDF_STATUS
- util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- uint8_t *commoninfo_len)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- if (!mlieseq || !mlieseqlen || !commoninfo_len)
- return QDF_STATUS_E_NULL_VALUE;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
- mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_INVAL;
- /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink).
- * Check if there is sufficient space in the buffer for the Common Info
- * Length and MLD MAC address.
- */
- if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE +
- QDF_MAC_ADDR_SIZE) > mlieseqlen)
- return QDF_STATUS_E_PROTO;
- *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *bssparamchangecntfound,
- uint8_t *bssparamchangecnt)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint16_t presencebitmap;
- uint8_t *commoninfo;
- qdf_size_t commoninfolen;
- if (!mlieseq || !mlieseqlen || !bssparamchangecntfound ||
- !bssparamchangecnt)
- return QDF_STATUS_E_NULL_VALUE;
- *bssparamchangecntfound = false;
- *bssparamchangecnt = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
- mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_NOSUPPORT;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
- commoninfolen = WLAN_ML_BV_CINFO_LENGTH_SIZE;
- commoninfolen += QDF_MAC_ADDR_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
- commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- }
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
- *bssparamchangecntfound = true;
- *bssparamchangecnt = *(commoninfo + commoninfolen);
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- int *variant)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant var;
- uint16_t mlcontrol;
- if (!mlieseq || !mlieseqlen || !variant)
- return QDF_STATUS_E_NULL_VALUE;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
- return QDF_STATUS_E_INVAL;
- mlcontrol = le16toh(mlie_fixed->mlcontrol);
- var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (var >= WLAN_ML_VARIANT_INVALIDSTART)
- return QDF_STATUS_E_PROTO;
- *variant = var;
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *eml_cap_found,
- uint16_t *eml_cap)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint8_t eml_cap_offset;
- uint8_t commoninfo_len;
- uint16_t presencebitmap;
- if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap)
- return QDF_STATUS_E_NULL_VALUE;
- *eml_cap = 0;
- *eml_cap_found = false;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_INVAL;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- /* eml_cap_offset stores the offset of EML Capabilities within
- * Common Info
- */
- eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
- eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
- eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P)
- eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
- /* Common Info starts at
- * mlieseq + sizeof(struct wlan_ie_multilink).
- * Check if there is sufficient space in the buffer for
- * the Common Info Length.
- */
- if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
- WLAN_ML_BV_CINFO_LENGTH_SIZE))
- return QDF_STATUS_E_PROTO;
- /* Check if the value indicated in the Common Info Length
- * subfield is sufficient to access the EML capabilities.
- */
- commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
- if (commoninfo_len < (eml_cap_offset +
- WLAN_ML_BV_CINFO_EMLCAP_SIZE))
- return QDF_STATUS_E_PROTO;
- /* Common Info starts at mlieseq + sizeof(struct
- * wlan_ie_multilink). Check if there is sufficient space in
- * Common Info for the EML capability.
- */
- if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
- eml_cap_offset +
- WLAN_ML_BV_CINFO_EMLCAP_SIZE))
- return QDF_STATUS_E_PROTO;
- *eml_cap_found = true;
- *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq +
- sizeof(struct wlan_ie_multilink) +
- eml_cap_offset));
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *msd_cap_found,
- uint16_t *msd_cap)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint8_t msd_cap_offset;
- uint8_t commoninfo_len;
- uint16_t presencebitmap;
- if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap)
- return QDF_STATUS_E_NULL_VALUE;
- *msd_cap = 0;
- *msd_cap_found = false;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_INVAL;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- /* msd_cap_offset stores the offset of MSD capabilities within
- * Common Info
- */
- msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
- msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
- msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
- /* Common Info starts at
- * mlieseq + sizeof(struct wlan_ie_multilink).
- * Check if there is sufficient space in the buffer for
- * the Common Info Length.
- */
- if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
- WLAN_ML_BV_CINFO_LENGTH_SIZE))
- return QDF_STATUS_E_PROTO;
- /* Check if the value indicated in the Common Info Length
- * subfield is sufficient to access the MSD capabilities.
- */
- commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
- if (commoninfo_len < (msd_cap_offset +
- WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE))
- return QDF_STATUS_E_PROTO;
- /* Common Info starts at mlieseq + sizeof(struct
- * wlan_ie_multilink). Check if there is sufficient space in
- * Common Info for the MSD capability.
- */
- if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
- msd_cap_offset +
- WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE))
- return QDF_STATUS_E_PROTO;
- *msd_cap_found = true;
- *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq +
- sizeof(struct wlan_ie_multilink) +
- msd_cap_offset));
- } else {
- mlo_debug("MSD caps not found in assoc rsp");
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- struct qdf_mac_addr *mldmacaddr)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint8_t commoninfo_len;
- if (!mlieseq || !mlieseqlen || !mldmacaddr)
- return QDF_STATUS_E_NULL_VALUE;
- qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr));
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_INVAL;
- /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink).
- * Check if there is sufficient space in the buffer for the Common Info
- * Length and MLD MAC address.
- */
- if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE +
- QDF_MAC_ADDR_SIZE) > mlieseqlen)
- return QDF_STATUS_E_PROTO;
- /* Check if the value indicated in the Common Info Length subfield is
- * sufficient to access the MLD MAC address.
- */
- commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
- if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE))
- return QDF_STATUS_E_PROTO;
- qdf_mem_copy(mldmacaddr->bytes,
- mlieseq + sizeof(struct wlan_ie_multilink) +
- WLAN_ML_BV_CINFO_LENGTH_SIZE,
- QDF_MAC_ADDR_SIZE);
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *linkidfound, uint8_t *linkid)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint16_t presencebitmap;
- uint8_t *commoninfo;
- qdf_size_t commoninfolen;
- uint8_t *linkidinfo;
- if (!mlieseq || !mlieseqlen || !linkidfound || !linkid)
- return QDF_STATUS_E_NULL_VALUE;
- *linkidfound = false;
- *linkid = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
- return QDF_STATUS_E_INVAL;
- mlcontrol = le16toh(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_INVAL;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
- commoninfolen = 0;
- commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- commoninfolen += QDF_MAC_ADDR_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
- linkidinfo = commoninfo + commoninfolen;
- commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- *linkidfound = true;
- *linkid = QDF_GET_BITS(linkidinfo[0],
- WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX,
- WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS);
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *mldcapfound, uint16_t *mldcap)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint16_t presencebitmap;
- uint8_t *commoninfo;
- uint8_t commoninfo_len;
- qdf_size_t mldcap_offset;
- if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap)
- return QDF_STATUS_E_NULL_VALUE;
- *mldcapfound = false;
- *mldcap = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
- mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC)
- return QDF_STATUS_E_NOSUPPORT;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
- commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
- /* mldcap_offset stores the offset of MLD Capabilities within
- * Common Info
- */
- mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE;
- mldcap_offset += QDF_MAC_ADDR_SIZE;
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
- mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- }
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
- mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- }
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
- mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- }
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
- mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
- if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- }
- if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) {
- /* Check if the value indicated in the Common Info Length
- * subfield is sufficient to access the MLD capabilities.
- */
- if (commoninfo_len < (mldcap_offset +
- WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE))
- return QDF_STATUS_E_PROTO;
- if ((sizeof(struct wlan_ie_multilink) + mldcap_offset +
- WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset)));
- *mldcapfound = true;
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_bvmlie_persta_partner_info(uint8_t *mlieseq,
- qdf_size_t mlieseqlen,
- struct mlo_partner_info *partner_info)
- {
- struct wlan_ie_multilink *mlie_fixed;
- uint16_t mlcontrol;
- enum wlan_ml_variant variant;
- uint8_t *linkinfo;
- qdf_size_t linkinfo_len;
- struct mlo_partner_info pinfo = {0};
- qdf_size_t mlieseqpayloadlen;
- uint8_t *mlieseqpayload_copy;
- bool is_elemfragseq;
- qdf_size_t defragpayload_len;
- qdf_size_t tmplen;
- QDF_STATUS ret;
- if (!mlieseq) {
- mlo_err("Pointer to Multi-Link element sequence is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!mlieseqlen) {
- mlo_err("Length of Multi-Link element sequence is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (!partner_info) {
- mlo_err("partner_info is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- partner_info->num_partner_links = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
- mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
- mlieseqlen, sizeof(struct wlan_ie_multilink));
- return QDF_STATUS_E_INVAL;
- }
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) {
- mlo_err("The element is not a Multi-Link element");
- return QDF_STATUS_E_INVAL;
- }
- mlcontrol = le16toh(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_BASIC) {
- mlo_err("The variant value %u does not correspond to Basic Variant value %u",
- variant, WLAN_ML_VARIANT_BASIC);
- return QDF_STATUS_E_INVAL;
- }
- mlieseqpayloadlen = 0;
- tmplen = 0;
- is_elemfragseq = false;
- ret = wlan_get_elem_fragseq_info(mlieseq,
- mlieseqlen,
- &is_elemfragseq,
- &tmplen,
- &mlieseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (is_elemfragseq) {
- if (tmplen != mlieseqlen) {
- mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets",
- tmplen, mlieseqlen);
- return QDF_STATUS_E_INVAL;
- }
- if (!mlieseqpayloadlen) {
- mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
- mlieseqpayloadlen);
- } else {
- if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
- mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found",
- mlieseqlen,
- sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
- return QDF_STATUS_E_FAILURE;
- }
- mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
- }
- mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
- if (!mlieseqpayload_copy) {
- mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
- return QDF_STATUS_E_NOMEM;
- }
- if (is_elemfragseq) {
- ret = wlan_defrag_elem_fragseq(false,
- mlieseq,
- mlieseqlen,
- mlieseqpayload_copy,
- mlieseqpayloadlen,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (defragpayload_len != mlieseqpayloadlen) {
- mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
- defragpayload_len, mlieseqpayloadlen);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_FAILURE;
- }
- } else {
- qdf_mem_copy(mlieseqpayload_copy,
- mlieseq + sizeof(struct ie_header) + 1,
- mlieseqpayloadlen);
- }
- linkinfo = NULL;
- linkinfo_len = 0;
- ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
- mlieseqpayloadlen,
- &linkinfo,
- &linkinfo_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- /*
- * If Probe Request variant Multi-Link element in the Multi-Link probe
- * request does not include any per-STA profile, then all APs affiliated
- * with the same AP MLD as the AP identified in the Addr 1 or Addr 3
- * field or AP MLD ID of the Multi-Link probe request are requested
- * APs return success here
- */
- if (!linkinfo) {
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_SUCCESS;
- }
- ret = util_parse_partner_info_from_linkinfo(linkinfo,
- linkinfo_len,
- &pinfo);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info));
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_prvmlie_persta_link_id(uint8_t *mlieseq,
- qdf_size_t mlieseqlen,
- struct mlo_probereq_info *probereq_info)
- {
- struct wlan_ie_multilink *mlie_fixed;
- uint16_t mlcontrol;
- enum wlan_ml_variant variant;
- uint8_t *linkinfo;
- qdf_size_t linkinfo_len;
- qdf_size_t mlieseqpayloadlen;
- uint8_t *mlieseqpayload_copy;
- bool is_elemfragseq;
- qdf_size_t defragpayload_len;
- qdf_size_t tmplen;
- QDF_STATUS ret;
- if (!mlieseq) {
- mlo_err("Pointer to Multi-Link element sequence is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- if (!mlieseqlen) {
- mlo_err("Length of Multi-Link element sequence is zero");
- return QDF_STATUS_E_INVAL;
- }
- if (!probereq_info) {
- mlo_err("probe request_info is NULL");
- return QDF_STATUS_E_NULL_VALUE;
- }
- probereq_info->num_links = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
- mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
- mlieseqlen, sizeof(struct wlan_ie_multilink));
- return QDF_STATUS_E_INVAL;
- }
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
- (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) {
- mlo_err("The element is not a Multi-Link element");
- return QDF_STATUS_E_INVAL;
- }
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_PROBEREQ) {
- mlo_err("The variant value %u does not correspond to Probe Request Variant value %u",
- variant, WLAN_ML_VARIANT_PROBEREQ);
- return QDF_STATUS_E_INVAL;
- }
- mlieseqpayloadlen = 0;
- tmplen = 0;
- is_elemfragseq = false;
- ret = wlan_get_elem_fragseq_info(mlieseq,
- mlieseqlen,
- &is_elemfragseq,
- &tmplen,
- &mlieseqpayloadlen);
- if (QDF_IS_STATUS_ERROR(ret))
- return ret;
- if (is_elemfragseq) {
- if (tmplen != mlieseqlen) {
- mlo_err_rl("Mismatch in values of element fragment sequence total length. Val per frag info determination: %zu octets, val passed as arg: %zu octets",
- tmplen, mlieseqlen);
- return QDF_STATUS_E_INVAL;
- }
- if (!mlieseqpayloadlen) {
- mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
- return QDF_STATUS_E_FAILURE;
- }
- mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
- mlieseqpayloadlen);
- } else {
- if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
- mlo_err_rl("Expected presence of valid fragment sequence since Multi-Link element sequence length %zu octets is larger than frag threshold of %zu octets, however no valid fragment sequence found",
- mlieseqlen,
- sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
- return QDF_STATUS_E_FAILURE;
- }
- mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
- }
- mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
- if (!mlieseqpayload_copy) {
- mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
- return QDF_STATUS_E_NOMEM;
- }
- if (is_elemfragseq) {
- ret = wlan_defrag_elem_fragseq(false,
- mlieseq,
- mlieseqlen,
- mlieseqpayload_copy,
- mlieseqpayloadlen,
- &defragpayload_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- if (defragpayload_len != mlieseqpayloadlen) {
- mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
- defragpayload_len, mlieseqpayloadlen);
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_E_FAILURE;
- }
- } else {
- qdf_mem_copy(mlieseqpayload_copy,
- mlieseq + sizeof(struct ie_header) + 1,
- mlieseqpayloadlen);
- }
- linkinfo = NULL;
- linkinfo_len = 0;
- ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy,
- mlieseqpayloadlen,
- &linkinfo,
- &linkinfo_len);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- /* In case Link Info is absent, the number of links will remain
- * zero.
- */
- if (!linkinfo) {
- mlo_debug("No link info present");
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_SUCCESS;
- }
- ret = util_parse_probereq_info_from_linkinfo(linkinfo,
- linkinfo_len,
- probereq_info);
- if (QDF_IS_STATUS_ERROR(ret)) {
- qdf_mem_free(mlieseqpayload_copy);
- return ret;
- }
- qdf_mem_free(mlieseqpayload_copy);
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- bool *mldidfound, uint8_t *mldid)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint16_t presencebitmap;
- uint8_t *commoninfo;
- qdf_size_t commoninfolen;
- if (!mlieseq || !mlieseqlen || !mldidfound || !mldid)
- return QDF_STATUS_E_NULL_VALUE;
- *mldidfound = false;
- *mldid = 0;
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
- mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_PROBEREQ)
- return QDF_STATUS_E_NOSUPPORT;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
- commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE;
- if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) {
- if ((sizeof(struct wlan_ie_multilink) + commoninfolen +
- WLAN_ML_PRV_CINFO_MLDID_SIZE) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- *mldid = *((uint8_t *)(commoninfo + commoninfolen));
- commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE;
- *mldidfound = true;
- }
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS util_get_rvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen,
- struct qdf_mac_addr *mldmacaddr)
- {
- struct wlan_ie_multilink *mlie_fixed;
- enum wlan_ml_variant variant;
- uint16_t mlcontrol;
- uint16_t presencebitmap;
- if (!mlieseq || !mlieseqlen || !mldmacaddr)
- return QDF_STATUS_E_NULL_VALUE;
- qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr));
- if (mlieseqlen < sizeof(struct wlan_ie_multilink))
- return QDF_STATUS_E_INVAL;
- mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
- if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
- mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
- return QDF_STATUS_E_INVAL;
- mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
- variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
- WLAN_ML_CTRL_TYPE_BITS);
- if (variant != WLAN_ML_VARIANT_RECONFIG)
- return QDF_STATUS_E_INVAL;
- presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
- WLAN_ML_CTRL_PBM_BITS);
- /* Check if MLD mac address is present */
- if (presencebitmap & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) {
- if ((sizeof(struct wlan_ie_multilink) + QDF_MAC_ADDR_SIZE) >
- mlieseqlen)
- return QDF_STATUS_E_PROTO;
- qdf_mem_copy(mldmacaddr->bytes,
- mlieseq + sizeof(struct wlan_ie_multilink),
- QDF_MAC_ADDR_SIZE);
- }
- return QDF_STATUS_SUCCESS;
- }
- #endif
|