utils_mlo.c 202 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527
  1. /*
  2. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /*
  18. * DOC: contains MLO manager util api's
  19. */
  20. #include <wlan_cmn.h>
  21. #include <wlan_mlo_mgr_sta.h>
  22. #include <wlan_cm_public_struct.h>
  23. #include <wlan_mlo_mgr_main.h>
  24. #include <wlan_cm_api.h>
  25. #include "wlan_scan_api.h"
  26. #include "qdf_types.h"
  27. #include "utils_mlo.h"
  28. #include "wlan_mlo_mgr_cmn.h"
  29. #include "wlan_utility.h"
  30. #ifdef WLAN_FEATURE_11BE_MLO
  31. static uint8_t *util_find_eid(uint8_t eid, uint8_t *frame, qdf_size_t len)
  32. {
  33. if (!frame)
  34. return NULL;
  35. while (len >= MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
  36. if (frame[ID_POS] == eid)
  37. return frame;
  38. len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
  39. frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
  40. }
  41. return NULL;
  42. }
  43. static
  44. uint8_t *util_find_extn_eid(uint8_t eid, uint8_t extn_eid,
  45. uint8_t *frame, qdf_size_t len)
  46. {
  47. if (!frame)
  48. return NULL;
  49. while (len > MIN_IE_LEN && len >= frame[TAG_LEN_POS] + MIN_IE_LEN) {
  50. if ((frame[ID_POS] == eid) &&
  51. (frame[ELEM_ID_EXTN_POS] == extn_eid))
  52. return frame;
  53. len -= frame[TAG_LEN_POS] + MIN_IE_LEN;
  54. frame += frame[TAG_LEN_POS] + MIN_IE_LEN;
  55. }
  56. return NULL;
  57. }
  58. static QDF_STATUS
  59. util_parse_multi_link_ctrl(uint8_t *mlieseqpayload,
  60. qdf_size_t mlieseqpayloadlen,
  61. uint8_t **link_info,
  62. qdf_size_t *link_info_len)
  63. {
  64. qdf_size_t parsed_payload_len;
  65. uint16_t mlcontrol;
  66. uint16_t presence_bm;
  67. uint16_t cinfo_len = 0;
  68. uint16_t exp_cinfo_len = 0;
  69. /* This helper returns the location(s) and length(s) of (sub)field(s)
  70. * inferable after parsing the Multi Link element Control field. These
  71. * location(s) and length(s) is/are in reference to the payload section
  72. * of the Multi Link element (after defragmentation, if applicable).
  73. * Here, the payload is the point after the element ID extension of the
  74. * Multi Link element, and includes the payloads of all subsequent
  75. * fragments (if any) but not the headers of those fragments.
  76. *
  77. * Currently, the helper returns the location and length of the Link
  78. * Info field in the Multi Link element sequence. Other (sub)field(s)
  79. * can be added later as required.
  80. */
  81. if (!mlieseqpayload) {
  82. mlo_err("ML seq payload pointer is NULL");
  83. return QDF_STATUS_E_NULL_VALUE;
  84. }
  85. if (!mlieseqpayloadlen) {
  86. mlo_err("ML seq payload len is 0");
  87. return QDF_STATUS_E_INVAL;
  88. }
  89. if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
  90. mlo_err_rl("ML seq payload len %zu < ML Control size %u",
  91. mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
  92. return QDF_STATUS_E_PROTO;
  93. }
  94. parsed_payload_len = 0;
  95. qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE);
  96. mlcontrol = qdf_le16_to_cpu(mlcontrol);
  97. parsed_payload_len += WLAN_ML_CTRL_SIZE;
  98. presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  99. WLAN_ML_CTRL_PBM_BITS);
  100. if (mlieseqpayloadlen <
  101. (parsed_payload_len + WLAN_ML_BV_CINFO_LENGTH_SIZE)) {
  102. mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.",
  103. mlieseqpayloadlen,
  104. WLAN_ML_BV_CINFO_LENGTH_SIZE,
  105. parsed_payload_len);
  106. return QDF_STATUS_E_PROTO;
  107. }
  108. cinfo_len = *(mlieseqpayload + parsed_payload_len);
  109. parsed_payload_len += WLAN_ML_BV_CINFO_LENGTH_SIZE;
  110. if (mlieseqpayloadlen <
  111. (parsed_payload_len + QDF_MAC_ADDR_SIZE)) {
  112. mlo_err_rl("ML seq payload len %zu insufficient for MAC address size %u after parsed payload len %zu.",
  113. mlieseqpayloadlen,
  114. QDF_MAC_ADDR_SIZE,
  115. parsed_payload_len);
  116. return QDF_STATUS_E_PROTO;
  117. }
  118. parsed_payload_len += QDF_MAC_ADDR_SIZE;
  119. /* Check if Link ID info is present */
  120. if (presence_bm & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  121. if (mlieseqpayloadlen <
  122. (parsed_payload_len +
  123. WLAN_ML_BV_CINFO_LINKIDINFO_SIZE)) {
  124. mlo_err_rl("ML seq payload len %zu insufficient for Link ID info size %u after parsed payload len %zu.",
  125. mlieseqpayloadlen,
  126. WLAN_ML_BV_CINFO_LINKIDINFO_SIZE,
  127. parsed_payload_len);
  128. return QDF_STATUS_E_PROTO;
  129. }
  130. parsed_payload_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  131. }
  132. /* Check if BSS parameter change count is present */
  133. if (presence_bm & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
  134. if (mlieseqpayloadlen <
  135. (parsed_payload_len +
  136. WLAN_ML_BSSPARAMCHNGCNT_SIZE)) {
  137. mlo_err_rl("ML seq payload len %zu insufficient for BSS parameter change count size %u after parsed payload len %zu.",
  138. mlieseqpayloadlen,
  139. WLAN_ML_BSSPARAMCHNGCNT_SIZE,
  140. parsed_payload_len);
  141. return QDF_STATUS_E_PROTO;
  142. }
  143. parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  144. }
  145. /* Check if Medium Sync Delay Info is present */
  146. if (presence_bm & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
  147. if (mlieseqpayloadlen <
  148. (parsed_payload_len +
  149. WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE)) {
  150. mlo_err_rl("ML seq payload len %zu insufficient for Medium Sync Delay Info size %u after parsed payload len %zu.",
  151. mlieseqpayloadlen,
  152. WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE,
  153. parsed_payload_len);
  154. return QDF_STATUS_E_PROTO;
  155. }
  156. parsed_payload_len += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
  157. }
  158. /* Check if EML cap is present */
  159. if (presence_bm & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
  160. if (mlieseqpayloadlen <
  161. (parsed_payload_len +
  162. WLAN_ML_BV_CINFO_EMLCAP_SIZE)) {
  163. mlo_err_rl("ML seq payload len %zu insufficient for EML cap size %u after parsed payload len %zu.",
  164. mlieseqpayloadlen,
  165. WLAN_ML_BV_CINFO_EMLCAP_SIZE,
  166. parsed_payload_len);
  167. return QDF_STATUS_E_PROTO;
  168. }
  169. parsed_payload_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
  170. }
  171. /* Check if MLD cap is present */
  172. if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) {
  173. if (mlieseqpayloadlen <
  174. (parsed_payload_len +
  175. WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE)) {
  176. mlo_err_rl("ML seq payload len %zu insufficient for MLD cap size %u after parsed payload len %zu.",
  177. mlieseqpayloadlen,
  178. WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE,
  179. parsed_payload_len);
  180. return QDF_STATUS_E_PROTO;
  181. }
  182. parsed_payload_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
  183. }
  184. /* Check if MLD ID is present */
  185. if (presence_bm & WLAN_ML_BV_CTRL_PBM_MLDID_P) {
  186. if (mlieseqpayloadlen <
  187. (parsed_payload_len +
  188. WLAN_ML_BV_CINFO_MLDID_SIZE)) {
  189. mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.",
  190. mlieseqpayloadlen,
  191. WLAN_ML_BV_CINFO_MLDID_SIZE,
  192. parsed_payload_len);
  193. return QDF_STATUS_E_PROTO;
  194. }
  195. parsed_payload_len += WLAN_ML_BV_CINFO_MLDID_SIZE;
  196. }
  197. /* Check if Ext MLD CAP OP is present */
  198. if (presence_bm & WLAN_ML_BV_CTRL_PBM_EXT_MLDCAPANDOP_P) {
  199. if (mlieseqpayloadlen <
  200. (parsed_payload_len +
  201. WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE)) {
  202. mlo_err_rl("ML seq payload len %zu insufficient for Ext MLD CAP OP size %u after parsed payload len %zu.",
  203. mlieseqpayloadlen,
  204. WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE,
  205. parsed_payload_len);
  206. return QDF_STATUS_E_PROTO;
  207. }
  208. parsed_payload_len += WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE;
  209. }
  210. exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE;
  211. if (cinfo_len >= exp_cinfo_len) {
  212. /* If common info length received is greater,
  213. * skip through the additional bytes
  214. */
  215. parsed_payload_len += (cinfo_len - exp_cinfo_len);
  216. mlo_debug("ML seq common info len %u, parsed payload length %zu, expected common info len %u",
  217. cinfo_len, parsed_payload_len, exp_cinfo_len);
  218. } else {
  219. /* If cinfo_len < exp_cinfo_len return error */
  220. mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u",
  221. cinfo_len, exp_cinfo_len);
  222. return QDF_STATUS_E_PROTO;
  223. }
  224. if (link_info_len) {
  225. *link_info_len = mlieseqpayloadlen - parsed_payload_len;
  226. mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
  227. *link_info_len, parsed_payload_len);
  228. }
  229. if (mlieseqpayloadlen == parsed_payload_len) {
  230. if (link_info)
  231. *link_info = NULL;
  232. return QDF_STATUS_SUCCESS;
  233. }
  234. if (link_info)
  235. *link_info = mlieseqpayload + parsed_payload_len;
  236. return QDF_STATUS_SUCCESS;
  237. }
  238. static QDF_STATUS
  239. util_parse_prv_multi_link_ctrl(uint8_t *mlieseqpayload,
  240. qdf_size_t mlieseqpayloadlen,
  241. uint8_t **link_info,
  242. qdf_size_t *link_info_len)
  243. {
  244. qdf_size_t parsed_payload_len;
  245. uint16_t mlcontrol;
  246. uint16_t presence_bm;
  247. uint16_t cinfo_len = 0;
  248. uint16_t exp_cinfo_len = 0;
  249. /* This helper returns the location(s) and length(s) of (sub)field(s)
  250. * inferable after parsing the Multi Link element Control field. These
  251. * location(s) and length(s) is/are in reference to the payload section
  252. * of the Multi Link element (after defragmentation, if applicable).
  253. * Here, the payload is the point after the element ID extension of the
  254. * Multi Link element, and includes the payloads of all subsequent
  255. * fragments (if any) but not the headers of those fragments.
  256. *
  257. * Currently, the helper returns the location and length of the Link
  258. * Info field in the Multi Link element sequence. Other (sub)field(s)
  259. * can be added later as required.
  260. */
  261. if (!mlieseqpayload) {
  262. mlo_err("ML seq payload pointer is NULL");
  263. return QDF_STATUS_E_NULL_VALUE;
  264. }
  265. if (!mlieseqpayloadlen) {
  266. mlo_err("ML seq payload len is 0");
  267. return QDF_STATUS_E_INVAL;
  268. }
  269. if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
  270. mlo_err_rl("ML seq payload len %zu < ML Control size %u",
  271. mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
  272. return QDF_STATUS_E_PROTO;
  273. }
  274. parsed_payload_len = 0;
  275. qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE);
  276. mlcontrol = qdf_le16_to_cpu(mlcontrol);
  277. parsed_payload_len += WLAN_ML_CTRL_SIZE;
  278. presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  279. WLAN_ML_CTRL_PBM_BITS);
  280. if (mlieseqpayloadlen <
  281. (parsed_payload_len + WLAN_ML_PRV_CINFO_LENGTH_SIZE)) {
  282. mlo_err_rl("ML seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.",
  283. mlieseqpayloadlen,
  284. WLAN_ML_PRV_CINFO_LENGTH_SIZE,
  285. parsed_payload_len);
  286. return QDF_STATUS_E_PROTO;
  287. }
  288. cinfo_len = *(mlieseqpayload + parsed_payload_len);
  289. parsed_payload_len += WLAN_ML_PRV_CINFO_LENGTH_SIZE;
  290. /* Check if MLD ID is present */
  291. if (presence_bm & WLAN_ML_PRV_CTRL_PBM_MLDID_P) {
  292. if (mlieseqpayloadlen <
  293. (parsed_payload_len +
  294. WLAN_ML_PRV_CINFO_MLDID_SIZE)) {
  295. mlo_err_rl("ML seq payload len %zu insufficient for MLD ID size %u after parsed payload len %zu.",
  296. mlieseqpayloadlen,
  297. WLAN_ML_PRV_CINFO_MLDID_SIZE,
  298. parsed_payload_len);
  299. return QDF_STATUS_E_PROTO;
  300. }
  301. parsed_payload_len += WLAN_ML_PRV_CINFO_MLDID_SIZE;
  302. }
  303. exp_cinfo_len = parsed_payload_len - WLAN_ML_CTRL_SIZE;
  304. if (cinfo_len != exp_cinfo_len) {
  305. mlo_err_rl("ML seq common info len %u doesn't match with expected common info len %u",
  306. cinfo_len, exp_cinfo_len);
  307. return QDF_STATUS_E_PROTO;
  308. }
  309. if (link_info_len) {
  310. *link_info_len = mlieseqpayloadlen - parsed_payload_len;
  311. mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
  312. *link_info_len, parsed_payload_len);
  313. }
  314. if (mlieseqpayloadlen == parsed_payload_len) {
  315. mlo_debug("No Link Info field present");
  316. if (link_info)
  317. *link_info = NULL;
  318. return QDF_STATUS_SUCCESS;
  319. }
  320. if (link_info)
  321. *link_info = mlieseqpayload + parsed_payload_len;
  322. return QDF_STATUS_SUCCESS;
  323. }
  324. static QDF_STATUS
  325. util_parse_bvmlie_perstaprofile_stactrl(uint8_t *subelempayload,
  326. qdf_size_t subelempayloadlen,
  327. uint8_t *linkid,
  328. uint16_t *beaconinterval,
  329. bool *is_beaconinterval_valid,
  330. uint64_t *tsfoffset,
  331. bool *is_tsfoffset_valid,
  332. bool *is_complete_profile,
  333. bool *is_macaddr_valid,
  334. struct qdf_mac_addr *macaddr,
  335. bool is_staprof_reqd,
  336. uint8_t **staprof,
  337. qdf_size_t *staprof_len,
  338. struct mlo_nstr_info *nstr_info,
  339. bool *is_nstrlp_present)
  340. {
  341. qdf_size_t parsed_payload_len = 0;
  342. uint16_t stacontrol;
  343. uint8_t completeprofile;
  344. uint8_t nstrlppresent;
  345. enum wlan_ml_bv_linfo_perstaprof_stactrl_nstrbmsz nstrbmsz;
  346. qdf_size_t nstrlpoffset = 0;
  347. uint8_t link_id;
  348. /* This helper returns the location(s) and where required, the length(s)
  349. * of (sub)field(s) inferable after parsing the STA Control field in the
  350. * per-STA profile subelement. These location(s) and length(s) is/are in
  351. * reference to the payload section of the per-STA profile subelement
  352. * (after defragmentation, if applicable). Here, the payload is the
  353. * point after the subelement length in the subelement, and includes the
  354. * payloads of all subsequent fragments (if any) but not the headers of
  355. * those fragments.
  356. *
  357. * Currently, the helper returns the link ID, MAC address, and STA
  358. * profile. More (sub)fields can be added when required.
  359. */
  360. if (!subelempayload) {
  361. mlo_err("Pointer to subelement payload is NULL");
  362. return QDF_STATUS_E_NULL_VALUE;
  363. }
  364. if (!subelempayloadlen) {
  365. mlo_err("Length of subelement payload is zero");
  366. return QDF_STATUS_E_INVAL;
  367. }
  368. if (subelempayloadlen < WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE) {
  369. mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
  370. subelempayloadlen,
  371. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE);
  372. return QDF_STATUS_E_PROTO;
  373. }
  374. parsed_payload_len = 0;
  375. qdf_mem_copy(&stacontrol,
  376. subelempayload,
  377. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE);
  378. stacontrol = le16toh(stacontrol);
  379. parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE;
  380. link_id = QDF_GET_BITS(stacontrol,
  381. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
  382. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
  383. if (linkid)
  384. *linkid = link_id;
  385. /* Check if this a complete profile */
  386. completeprofile = QDF_GET_BITS(stacontrol,
  387. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
  388. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
  389. if (completeprofile && is_complete_profile)
  390. *is_complete_profile = true;
  391. /* Check STA Info Length */
  392. if (subelempayloadlen <
  393. parsed_payload_len + WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) {
  394. 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.",
  395. subelempayloadlen,
  396. WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE,
  397. parsed_payload_len);
  398. return QDF_STATUS_E_PROTO;
  399. }
  400. parsed_payload_len += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE;
  401. if (is_macaddr_valid)
  402. *is_macaddr_valid = false;
  403. /* Check STA MAC address present bit */
  404. if (QDF_GET_BITS(stacontrol,
  405. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX,
  406. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS)) {
  407. if (subelempayloadlen <
  408. (parsed_payload_len + QDF_MAC_ADDR_SIZE)) {
  409. 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.",
  410. subelempayloadlen,
  411. QDF_MAC_ADDR_SIZE,
  412. parsed_payload_len);
  413. return QDF_STATUS_E_PROTO;
  414. }
  415. if (macaddr) {
  416. qdf_mem_copy(macaddr->bytes,
  417. subelempayload + parsed_payload_len,
  418. QDF_MAC_ADDR_SIZE);
  419. mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT,
  420. QDF_MAC_ADDR_REF(macaddr->bytes));
  421. if (is_macaddr_valid)
  422. *is_macaddr_valid = true;
  423. }
  424. parsed_payload_len += QDF_MAC_ADDR_SIZE;
  425. }
  426. /* Check Beacon Interval present bit */
  427. if (QDF_GET_BITS(stacontrol,
  428. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX,
  429. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS)) {
  430. if (subelempayloadlen <
  431. (parsed_payload_len +
  432. WLAN_BEACONINTERVAL_LEN)) {
  433. 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.",
  434. subelempayloadlen,
  435. WLAN_BEACONINTERVAL_LEN,
  436. parsed_payload_len);
  437. return QDF_STATUS_E_PROTO;
  438. }
  439. if (beaconinterval) {
  440. qdf_mem_copy(beaconinterval,
  441. subelempayload + parsed_payload_len,
  442. WLAN_BEACONINTERVAL_LEN);
  443. *beaconinterval = qdf_le16_to_cpu(*beaconinterval);
  444. if (is_beaconinterval_valid)
  445. *is_beaconinterval_valid = true;
  446. }
  447. parsed_payload_len += WLAN_BEACONINTERVAL_LEN;
  448. }
  449. /* Check TSF Offset present bit */
  450. if (QDF_GET_BITS(stacontrol,
  451. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_IDX,
  452. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_TSFOFFSETP_BITS)) {
  453. if (!completeprofile) {
  454. mlo_err_rl("TSF offset is expected only for complete profiles");
  455. return QDF_STATUS_E_PROTO;
  456. }
  457. if (subelempayloadlen <
  458. (parsed_payload_len +
  459. WLAN_ML_TSF_OFFSET_SIZE)) {
  460. 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.",
  461. subelempayloadlen,
  462. WLAN_ML_TSF_OFFSET_SIZE,
  463. parsed_payload_len);
  464. return QDF_STATUS_E_PROTO;
  465. }
  466. if (tsfoffset) {
  467. qdf_mem_copy(tsfoffset,
  468. subelempayload + parsed_payload_len,
  469. WLAN_TIMESTAMP_LEN);
  470. *tsfoffset = qdf_le64_to_cpu(*tsfoffset);
  471. if (is_tsfoffset_valid)
  472. *is_tsfoffset_valid = true;
  473. }
  474. parsed_payload_len += WLAN_ML_TSF_OFFSET_SIZE;
  475. }
  476. /* Check DTIM Info present bit */
  477. if (QDF_GET_BITS(stacontrol,
  478. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX,
  479. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS)) {
  480. if (subelempayloadlen <
  481. (parsed_payload_len +
  482. sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo))) {
  483. 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.",
  484. subelempayloadlen,
  485. sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo),
  486. parsed_payload_len);
  487. return QDF_STATUS_E_PROTO;
  488. }
  489. parsed_payload_len +=
  490. sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo);
  491. }
  492. /* Check NTSR Link pair present bit */
  493. nstrlppresent =
  494. QDF_GET_BITS(stacontrol,
  495. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX,
  496. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS);
  497. if (completeprofile && nstrlppresent) {
  498. nstrlpoffset = parsed_payload_len;
  499. /* Check NTSR Bitmap Size bit */
  500. nstrbmsz =
  501. QDF_GET_BITS(stacontrol,
  502. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX,
  503. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS);
  504. if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) {
  505. if (subelempayloadlen <
  506. (parsed_payload_len + 1)) {
  507. 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.",
  508. subelempayloadlen,
  509. parsed_payload_len);
  510. return QDF_STATUS_E_PROTO;
  511. }
  512. parsed_payload_len += 1;
  513. } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) {
  514. if (subelempayloadlen <
  515. (parsed_payload_len + 2)) {
  516. 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.",
  517. subelempayloadlen,
  518. parsed_payload_len);
  519. return QDF_STATUS_E_PROTO;
  520. }
  521. parsed_payload_len += 2;
  522. } else {
  523. /* Though an invalid value cannot occur if only 1 bit is
  524. * used, we check for it in a generic manner in case the
  525. * number of bits is increased in the future.
  526. */
  527. mlo_err_rl("Invalid NSTR Bitmap size %u", nstrbmsz);
  528. return QDF_STATUS_E_PROTO;
  529. }
  530. if (nstr_info) {
  531. nstr_info->nstr_lp_present = nstrlppresent;
  532. nstr_info->nstr_bmp_size = nstrbmsz;
  533. *is_nstrlp_present = true;
  534. nstr_info->link_id = link_id;
  535. if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_1_OCTET) {
  536. nstr_info->nstr_lp_bitmap =
  537. *(uint8_t *)(subelempayload + nstrlpoffset);
  538. } else if (nstrbmsz == WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_2_OCTETS) {
  539. nstr_info->nstr_lp_bitmap =
  540. qdf_le16_to_cpu(*(uint16_t *)(subelempayload + nstrlpoffset));
  541. }
  542. }
  543. }
  544. /* Check BSS Parameters Change Count Present bit */
  545. if (QDF_GET_BITS(stacontrol,
  546. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_IDX,
  547. WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BSSPARAMCHNGCNTP_BITS)) {
  548. if (subelempayloadlen <
  549. (parsed_payload_len +
  550. WLAN_ML_BSSPARAMCHNGCNT_SIZE)) {
  551. 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.",
  552. subelempayloadlen,
  553. WLAN_ML_BSSPARAMCHNGCNT_SIZE,
  554. parsed_payload_len);
  555. return QDF_STATUS_E_PROTO;
  556. }
  557. parsed_payload_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  558. }
  559. /* Note: Some implementation versions of hostapd/wpa_supplicant may
  560. * provide a per-STA profile without STA profile. Let the caller
  561. * indicate whether a STA profile is required to be found. This may be
  562. * revisited as upstreaming progresses.
  563. */
  564. if (!is_staprof_reqd)
  565. return QDF_STATUS_SUCCESS;
  566. if (subelempayloadlen == parsed_payload_len) {
  567. mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.",
  568. subelempayloadlen,
  569. parsed_payload_len);
  570. return QDF_STATUS_E_PROTO;
  571. }
  572. if (staprof_len)
  573. *staprof_len = subelempayloadlen - parsed_payload_len;
  574. if (staprof)
  575. *staprof = subelempayload + parsed_payload_len;
  576. return QDF_STATUS_SUCCESS;
  577. }
  578. static QDF_STATUS
  579. util_parse_prvmlie_perstaprofile_stactrl(uint8_t *subelempayload,
  580. qdf_size_t subelempayloadlen,
  581. uint8_t *linkid,
  582. bool is_staprof_reqd,
  583. uint8_t **staprof,
  584. qdf_size_t *staprof_len)
  585. {
  586. qdf_size_t parsed_payload_len = 0;
  587. uint16_t stacontrol;
  588. uint8_t completeprofile;
  589. /* This helper returns the location(s) and where required, the length(s)
  590. * of (sub)field(s) inferable after parsing the STA Control field in the
  591. * per-STA profile subelement. These location(s) and length(s) is/are in
  592. * reference to the payload section of the per-STA profile subelement
  593. * (after defragmentation, if applicable). Here, the payload is the
  594. * point after the subelement length in the subelement, and includes the
  595. * payloads of all subsequent fragments (if any) but not the headers of
  596. * those fragments.
  597. *
  598. * Currently, the helper returns the link ID, MAC address, and STA
  599. * profile. More (sub)fields can be added when required.
  600. */
  601. if (!subelempayload) {
  602. mlo_err("Pointer to subelement payload is NULL");
  603. return QDF_STATUS_E_NULL_VALUE;
  604. }
  605. if (!subelempayloadlen) {
  606. mlo_err("Length of subelement payload is zero");
  607. return QDF_STATUS_E_INVAL;
  608. }
  609. if (subelempayloadlen < WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE) {
  610. mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
  611. subelempayloadlen,
  612. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE);
  613. return QDF_STATUS_E_PROTO;
  614. }
  615. parsed_payload_len = 0;
  616. qdf_mem_copy(&stacontrol,
  617. subelempayload,
  618. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE);
  619. stacontrol = qdf_le16_to_cpu(stacontrol);
  620. parsed_payload_len += WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_SIZE;
  621. if (linkid) {
  622. *linkid = QDF_GET_BITS(stacontrol,
  623. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
  624. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
  625. }
  626. /* Check if this a complete profile */
  627. completeprofile = QDF_GET_BITS(stacontrol,
  628. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
  629. WLAN_ML_PRV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
  630. /* Note: Some implementation versions of hostapd/wpa_supplicant may
  631. * provide a per-STA profile without STA profile. Let the caller
  632. * indicate whether a STA profile is required to be found. This may be
  633. * revisited as upstreaming progresses.
  634. */
  635. if (!is_staprof_reqd)
  636. return QDF_STATUS_SUCCESS;
  637. if (subelempayloadlen == parsed_payload_len) {
  638. mlo_err_rl("Subelement payload length %zu == parsed payload length %zu. Unable to get STA profile.",
  639. subelempayloadlen,
  640. parsed_payload_len);
  641. return QDF_STATUS_E_PROTO;
  642. }
  643. if (staprof_len)
  644. *staprof_len = subelempayloadlen - parsed_payload_len;
  645. if (staprof)
  646. *staprof = subelempayload + parsed_payload_len;
  647. return QDF_STATUS_SUCCESS;
  648. }
  649. static
  650. uint8_t *util_get_successorfrag(uint8_t *currie, uint8_t *frame, qdf_size_t len)
  651. {
  652. uint8_t *nextie;
  653. if (!currie || !frame || !len)
  654. return NULL;
  655. if ((currie + MIN_IE_LEN) > (frame + len))
  656. return NULL;
  657. /* Check whether there is sufficient space in the frame for the current
  658. * IE, plus at least another MIN_IE_LEN bytes for the IE header of a
  659. * fragment (if present) that would come just after the current IE.
  660. */
  661. if ((currie + MIN_IE_LEN + currie[TAG_LEN_POS] + MIN_IE_LEN) >
  662. (frame + len))
  663. return NULL;
  664. nextie = currie + currie[TAG_LEN_POS] + MIN_IE_LEN;
  665. /* Check whether there is sufficient space in the frame for the next IE
  666. */
  667. if ((nextie + MIN_IE_LEN + nextie[TAG_LEN_POS]) > (frame + len))
  668. return NULL;
  669. if (nextie[ID_POS] != WLAN_ELEMID_FRAGMENT)
  670. return NULL;
  671. return nextie;
  672. }
  673. static
  674. QDF_STATUS util_parse_partner_info_from_linkinfo(uint8_t *linkinfo,
  675. qdf_size_t linkinfo_len,
  676. struct mlo_partner_info *partner_info)
  677. {
  678. uint8_t linkid;
  679. struct qdf_mac_addr macaddr;
  680. struct mlo_nstr_info nstr_info = {0};
  681. bool is_macaddr_valid;
  682. uint8_t *linkinfo_currpos;
  683. qdf_size_t linkinfo_remlen;
  684. bool is_subelemfragseq;
  685. uint8_t subelemid;
  686. qdf_size_t subelemseqtotallen;
  687. qdf_size_t subelemseqpayloadlen;
  688. qdf_size_t defragpayload_len;
  689. QDF_STATUS ret;
  690. bool is_nstrlp_present = false;
  691. /* This helper function parses partner info from the per-STA profiles
  692. * present (if any) in the Link Info field in the payload of a Multi
  693. * Link element (after defragmentation if required). The caller should
  694. * pass a copy of the payload so that inline defragmentation of
  695. * subelements can be carried out if required. The subelement
  696. * defragmentation (if applicable) in this Control Path helper is
  697. * required for maintainability, accuracy and eliminating current and
  698. * future per-field-access multi-level fragment boundary checks and
  699. * adjustments, given the complex format of Multi Link elements. It is
  700. * also most likely to be required mainly at the client side.
  701. */
  702. if (!linkinfo) {
  703. mlo_err("linkinfo is NULL");
  704. return QDF_STATUS_E_NULL_VALUE;
  705. }
  706. if (!linkinfo_len) {
  707. mlo_err("linkinfo_len is zero");
  708. return QDF_STATUS_E_NULL_VALUE;
  709. }
  710. if (!partner_info) {
  711. mlo_err("ML partner info is NULL");
  712. return QDF_STATUS_E_NULL_VALUE;
  713. }
  714. partner_info->num_partner_links = 0;
  715. linkinfo_currpos = linkinfo;
  716. linkinfo_remlen = linkinfo_len;
  717. while (linkinfo_remlen) {
  718. if (linkinfo_remlen < sizeof(struct subelem_header)) {
  719. mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
  720. linkinfo_remlen,
  721. sizeof(struct subelem_header));
  722. return QDF_STATUS_E_PROTO;
  723. }
  724. subelemid = linkinfo_currpos[ID_POS];
  725. is_subelemfragseq = false;
  726. subelemseqtotallen = 0;
  727. subelemseqpayloadlen = 0;
  728. ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  729. linkinfo_currpos,
  730. linkinfo_remlen,
  731. &is_subelemfragseq,
  732. &subelemseqtotallen,
  733. &subelemseqpayloadlen);
  734. if (QDF_IS_STATUS_ERROR(ret))
  735. return ret;
  736. if (is_subelemfragseq) {
  737. if (!subelemseqpayloadlen) {
  738. mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
  739. return QDF_STATUS_E_FAILURE;
  740. }
  741. mlo_debug("Subelement fragment sequence found with payload len %zu",
  742. subelemseqpayloadlen);
  743. ret = wlan_defrag_subelem_fragseq(true,
  744. WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  745. linkinfo_currpos,
  746. linkinfo_remlen,
  747. NULL,
  748. 0,
  749. &defragpayload_len);
  750. if (QDF_IS_STATUS_ERROR(ret))
  751. return ret;
  752. if (defragpayload_len != subelemseqpayloadlen) {
  753. mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
  754. defragpayload_len,
  755. subelemseqpayloadlen);
  756. return QDF_STATUS_E_FAILURE;
  757. }
  758. /* Adjust linkinfo_remlen to reflect removal of all
  759. * subelement headers except the header of the lead
  760. * subelement.
  761. */
  762. linkinfo_remlen -= (subelemseqtotallen -
  763. subelemseqpayloadlen -
  764. sizeof(struct subelem_header));
  765. } else {
  766. if (linkinfo_remlen <
  767. (sizeof(struct subelem_header) +
  768. linkinfo_currpos[TAG_LEN_POS])) {
  769. mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
  770. linkinfo_remlen,
  771. sizeof(struct subelem_header) +
  772. linkinfo_currpos[TAG_LEN_POS]);
  773. return QDF_STATUS_E_PROTO;
  774. }
  775. subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
  776. }
  777. if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
  778. is_macaddr_valid = false;
  779. ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos +
  780. sizeof(struct subelem_header),
  781. subelemseqpayloadlen,
  782. &linkid,
  783. NULL,
  784. NULL,
  785. NULL,
  786. NULL,
  787. NULL,
  788. &is_macaddr_valid,
  789. &macaddr,
  790. false,
  791. NULL,
  792. NULL,
  793. &nstr_info,
  794. &is_nstrlp_present);
  795. if (QDF_IS_STATUS_ERROR(ret)) {
  796. return ret;
  797. }
  798. if (is_nstrlp_present) {
  799. if (partner_info->num_nstr_info_links >=
  800. QDF_ARRAY_SIZE(partner_info->nstr_info)) {
  801. mlo_err_rl("Insufficient size %zu of array for nstr link info",
  802. QDF_ARRAY_SIZE(partner_info->nstr_info));
  803. return QDF_STATUS_E_NOMEM;
  804. }
  805. qdf_mem_copy(&partner_info->nstr_info[partner_info->num_nstr_info_links],
  806. &nstr_info, sizeof(nstr_info));
  807. partner_info->num_nstr_info_links++;
  808. is_nstrlp_present = false;
  809. }
  810. if (is_macaddr_valid) {
  811. if (partner_info->num_partner_links >=
  812. QDF_ARRAY_SIZE(partner_info->partner_link_info)) {
  813. mlo_err_rl("Insufficient size %zu of array for partner link info",
  814. QDF_ARRAY_SIZE(partner_info->partner_link_info));
  815. return QDF_STATUS_E_NOMEM;
  816. }
  817. partner_info->partner_link_info[partner_info->num_partner_links].link_id =
  818. linkid;
  819. qdf_mem_copy(&partner_info->partner_link_info[partner_info->num_partner_links].link_addr,
  820. &macaddr,
  821. sizeof(partner_info->partner_link_info[partner_info->num_partner_links].link_addr));
  822. partner_info->num_partner_links++;
  823. } else {
  824. mlo_warn_rl("MAC address not found in STA Info field of per-STA profile with link ID %u",
  825. linkid);
  826. }
  827. }
  828. linkinfo_remlen -= (sizeof(struct subelem_header) +
  829. subelemseqpayloadlen);
  830. linkinfo_currpos += (sizeof(struct subelem_header) +
  831. subelemseqpayloadlen);
  832. }
  833. mlo_debug("Number of ML partner links found=%u",
  834. partner_info->num_partner_links);
  835. return QDF_STATUS_SUCCESS;
  836. }
  837. static QDF_STATUS
  838. util_parse_probereq_info_from_linkinfo(uint8_t *linkinfo,
  839. qdf_size_t linkinfo_len,
  840. struct mlo_probereq_info *probereq_info)
  841. {
  842. uint8_t linkid;
  843. uint8_t *linkinfo_currpos;
  844. qdf_size_t linkinfo_remlen;
  845. bool is_subelemfragseq;
  846. uint8_t subelemid;
  847. qdf_size_t subelemseqtotallen;
  848. qdf_size_t subelemseqpayloadlen;
  849. qdf_size_t defragpayload_len;
  850. QDF_STATUS ret;
  851. /* This helper function parses probe request info from the per-STA prof
  852. * present (if any) in the Link Info field in the payload of a Multi
  853. * Link element (after defragmentation if required). The caller should
  854. * pass a copy of the payload so that inline defragmentation of
  855. * subelements can be carried out if required. The subelement
  856. * defragmentation (if applicable) in this Control Path helper is
  857. * required for maintainability, accuracy and eliminating current and
  858. * future per-field-access multi-level fragment boundary checks and
  859. * adjustments, given the complex format of Multi Link elements. It is
  860. * also most likely to be required mainly at the client side.
  861. */
  862. if (!linkinfo) {
  863. mlo_err("linkinfo is NULL");
  864. return QDF_STATUS_E_NULL_VALUE;
  865. }
  866. if (!linkinfo_len) {
  867. mlo_err("linkinfo_len is zero");
  868. return QDF_STATUS_E_NULL_VALUE;
  869. }
  870. if (!probereq_info) {
  871. mlo_err("ML probe req info is NULL");
  872. return QDF_STATUS_E_NULL_VALUE;
  873. }
  874. probereq_info->num_links = 0;
  875. linkinfo_currpos = linkinfo;
  876. linkinfo_remlen = linkinfo_len;
  877. while (linkinfo_remlen) {
  878. if (linkinfo_remlen < sizeof(struct subelem_header)) {
  879. mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
  880. linkinfo_remlen,
  881. sizeof(struct subelem_header));
  882. return QDF_STATUS_E_PROTO;
  883. }
  884. subelemid = linkinfo_currpos[ID_POS];
  885. is_subelemfragseq = false;
  886. subelemseqtotallen = 0;
  887. subelemseqpayloadlen = 0;
  888. ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  889. linkinfo_currpos,
  890. linkinfo_remlen,
  891. &is_subelemfragseq,
  892. &subelemseqtotallen,
  893. &subelemseqpayloadlen);
  894. if (QDF_IS_STATUS_ERROR(ret))
  895. return ret;
  896. if (is_subelemfragseq) {
  897. if (!subelemseqpayloadlen) {
  898. mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
  899. return QDF_STATUS_E_FAILURE;
  900. }
  901. mlo_debug("Subelement fragment sequence found with payload len %zu",
  902. subelemseqpayloadlen);
  903. ret = wlan_defrag_subelem_fragseq(true,
  904. WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  905. linkinfo_currpos,
  906. linkinfo_remlen,
  907. NULL,
  908. 0,
  909. &defragpayload_len);
  910. if (QDF_IS_STATUS_ERROR(ret))
  911. return ret;
  912. if (defragpayload_len != subelemseqpayloadlen) {
  913. mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
  914. defragpayload_len,
  915. subelemseqpayloadlen);
  916. return QDF_STATUS_E_FAILURE;
  917. }
  918. /* Adjust linkinfo_remlen to reflect removal of all
  919. * subelement headers except the header of the lead
  920. * subelement.
  921. */
  922. linkinfo_remlen -= (subelemseqtotallen -
  923. subelemseqpayloadlen -
  924. sizeof(struct subelem_header));
  925. } else {
  926. if (linkinfo_remlen <
  927. (sizeof(struct subelem_header) +
  928. linkinfo_currpos[TAG_LEN_POS])) {
  929. mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
  930. linkinfo_remlen,
  931. sizeof(struct subelem_header) +
  932. linkinfo_currpos[TAG_LEN_POS]);
  933. return QDF_STATUS_E_PROTO;
  934. }
  935. subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
  936. }
  937. if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
  938. ret = util_parse_prvmlie_perstaprofile_stactrl(linkinfo_currpos +
  939. sizeof(struct subelem_header),
  940. subelemseqpayloadlen,
  941. &linkid,
  942. false,
  943. NULL,
  944. NULL);
  945. if (QDF_IS_STATUS_ERROR(ret))
  946. return ret;
  947. if (probereq_info->num_links >=
  948. QDF_ARRAY_SIZE(probereq_info->link_id)) {
  949. mlo_err_rl("Insufficient size %zu of array for probe req link id",
  950. QDF_ARRAY_SIZE(probereq_info->link_id));
  951. return QDF_STATUS_E_NOMEM;
  952. }
  953. probereq_info->link_id[probereq_info->num_links] = linkid;
  954. probereq_info->num_links++;
  955. mlo_debug("LINK ID requested is = %u", linkid);
  956. }
  957. linkinfo_remlen -= (sizeof(struct subelem_header) +
  958. subelemseqpayloadlen);
  959. linkinfo_currpos += (sizeof(struct subelem_header) +
  960. subelemseqpayloadlen);
  961. }
  962. mlo_debug("Number of ML probe request links found=%u",
  963. probereq_info->num_links);
  964. return QDF_STATUS_SUCCESS;
  965. }
  966. static
  967. QDF_STATUS util_get_noninheritlists(uint8_t *buff, qdf_size_t buff_len,
  968. uint8_t **ninherit_elemlist,
  969. qdf_size_t *ninherit_elemlist_len,
  970. uint8_t **ninherit_elemextlist,
  971. qdf_size_t *ninherit_elemextlist_len)
  972. {
  973. uint8_t *ninherit_ie;
  974. qdf_size_t unparsed_len;
  975. /* Note: This functionality provided by this helper may be combined with
  976. * other, older non-inheritance parsing helper functionality and exposed
  977. * as a common API as part of future efforts once the older
  978. * functionality can be made generic.
  979. */
  980. if (!buff) {
  981. mlo_err("Pointer to buffer for IEs is NULL");
  982. return QDF_STATUS_E_NULL_VALUE;
  983. }
  984. if (!buff_len) {
  985. mlo_err("IE buffer length is zero");
  986. return QDF_STATUS_E_INVAL;
  987. }
  988. if (!ninherit_elemlist) {
  989. mlo_err("Pointer to Non-Inheritance element ID list array is NULL");
  990. return QDF_STATUS_E_NULL_VALUE;
  991. }
  992. if (!ninherit_elemlist_len) {
  993. mlo_err("Pointer to Non-Inheritance element ID list array length is NULL");
  994. return QDF_STATUS_E_NULL_VALUE;
  995. }
  996. if (!ninherit_elemextlist) {
  997. mlo_err("Pointer to Non-Inheritance element ID extension list array is NULL");
  998. return QDF_STATUS_E_NULL_VALUE;
  999. }
  1000. if (!ninherit_elemextlist_len) {
  1001. mlo_err("Pointer to Non-Inheritance element ID extension list array length is NULL");
  1002. return QDF_STATUS_E_NULL_VALUE;
  1003. }
  1004. ninherit_ie = NULL;
  1005. *ninherit_elemlist_len = 0;
  1006. *ninherit_elemlist = NULL;
  1007. *ninherit_elemextlist_len = 0;
  1008. *ninherit_elemextlist = NULL;
  1009. ninherit_ie =
  1010. (uint8_t *)util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
  1011. WLAN_EXTN_ELEMID_NONINHERITANCE,
  1012. buff,
  1013. buff_len);
  1014. if (ninherit_ie) {
  1015. if ((ninherit_ie + TAG_LEN_POS) > (buff + buff_len - 1)) {
  1016. mlo_err_rl("Position of length field of Non-Inheritance element would exceed IE buffer boundary");
  1017. return QDF_STATUS_E_PROTO;
  1018. }
  1019. if ((ninherit_ie + ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) >
  1020. (buff + buff_len)) {
  1021. mlo_err_rl("Non-Inheritance element with total length %u would exceed IE buffer boundary",
  1022. ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN);
  1023. return QDF_STATUS_E_PROTO;
  1024. }
  1025. if ((ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN) <
  1026. MIN_NONINHERITANCEELEM_LEN) {
  1027. mlo_err_rl("Non-Inheritance element size %u is smaller than the minimum required %u",
  1028. ninherit_ie[TAG_LEN_POS] + MIN_IE_LEN,
  1029. MIN_NONINHERITANCEELEM_LEN);
  1030. return QDF_STATUS_E_PROTO;
  1031. }
  1032. /* Track the number of unparsed octets, excluding the IE header.
  1033. */
  1034. unparsed_len = ninherit_ie[TAG_LEN_POS];
  1035. /* Mark the element ID extension as parsed */
  1036. unparsed_len--;
  1037. *ninherit_elemlist_len = ninherit_ie[ELEM_ID_LIST_LEN_POS];
  1038. unparsed_len--;
  1039. /* While checking if the Non-Inheritance element ID list length
  1040. * exceeds the remaining unparsed IE space, we factor in one
  1041. * octet for the element extension ID list length and subtract
  1042. * this from the unparsed IE space.
  1043. */
  1044. if (*ninherit_elemlist_len > (unparsed_len - 1)) {
  1045. 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",
  1046. *ninherit_elemlist_len, unparsed_len - 1);
  1047. return QDF_STATUS_E_PROTO;
  1048. }
  1049. if (*ninherit_elemlist_len != 0) {
  1050. *ninherit_elemlist = ninherit_ie + ELEM_ID_LIST_POS;
  1051. unparsed_len -= *ninherit_elemlist_len;
  1052. }
  1053. *ninherit_elemextlist_len =
  1054. ninherit_ie[ELEM_ID_LIST_LEN_POS + *ninherit_elemlist_len + 1];
  1055. unparsed_len--;
  1056. if (*ninherit_elemextlist_len > unparsed_len) {
  1057. mlo_err_rl("Non-Inheritance element ID extension list length %zu exceeds remaining unparsed IE space %zu",
  1058. *ninherit_elemextlist_len, unparsed_len);
  1059. return QDF_STATUS_E_PROTO;
  1060. }
  1061. if (*ninherit_elemextlist_len != 0) {
  1062. *ninherit_elemextlist = ninherit_ie +
  1063. ELEM_ID_LIST_LEN_POS + (*ninherit_elemlist_len)
  1064. + 2;
  1065. unparsed_len -= *ninherit_elemextlist_len;
  1066. }
  1067. if (unparsed_len > 0) {
  1068. mlo_err_rl("Unparsed length is %zu, expected 0",
  1069. unparsed_len);
  1070. return QDF_STATUS_E_PROTO;
  1071. }
  1072. }
  1073. /* If Non-Inheritance element is not found, we still return success,
  1074. * with the list lengths kept at zero.
  1075. */
  1076. mlo_debug("Non-Inheritance element ID list array length=%zu",
  1077. *ninherit_elemlist_len);
  1078. mlo_debug("Non-Inheritance element ID extension list array length=%zu",
  1079. *ninherit_elemextlist_len);
  1080. return QDF_STATUS_SUCCESS;
  1081. }
  1082. static
  1083. QDF_STATUS util_eval_ie_in_noninheritlist(uint8_t *ie, qdf_size_t total_ie_len,
  1084. uint8_t *ninherit_elemlist,
  1085. qdf_size_t ninherit_elemlist_len,
  1086. uint8_t *ninherit_elemextlist,
  1087. qdf_size_t ninherit_elemextlist_len,
  1088. bool *is_in_noninheritlist)
  1089. {
  1090. int i;
  1091. /* Evaluate whether the given IE is in the given Non-Inheritance element
  1092. * ID list or Non-Inheritance element ID extension list, and update the
  1093. * result into is_in_noninheritlist. If any list is empty, then the IE
  1094. * is considered to not be present in that list. Both lists can be
  1095. * empty.
  1096. *
  1097. * If QDF_STATUS_SUCCESS is returned, it means that the evaluation is
  1098. * successful, and that is_in_noninheritlist contains a valid value
  1099. * (which could be true or false). If a QDF_STATUS error value is
  1100. * returned, the value in is_in_noninheritlist is invalid and the caller
  1101. * should ignore it.
  1102. */
  1103. /* Note: The functionality provided by this helper may be combined with
  1104. * other, older non-inheritance parsing helper functionality and exposed
  1105. * as a common API as part of future efforts once the older
  1106. * functionality can be made generic.
  1107. */
  1108. /* Except for is_in_noninheritlist and ie, other pointer arguments are
  1109. * permitted to be NULL if they are inapplicable. If they are
  1110. * applicable, they will be checked to ensure they are not NULL.
  1111. */
  1112. if (!is_in_noninheritlist) {
  1113. mlo_err("NULL pointer to flag that indicates if element is in a Non-Inheritance list");
  1114. return QDF_STATUS_E_NULL_VALUE;
  1115. }
  1116. /* If ninherit_elemlist_len and ninherit_elemextlist_len are both zero
  1117. * as checked soon in this function, we won't be accessing the IE.
  1118. * However, we still check right-away if the pointer to the IE is
  1119. * non-NULL and whether the total IE length is sane enough to access the
  1120. * element ID and if applicable, the element ID extension, since it
  1121. * doesn't make sense to set the flag in is_in_noninheritlist for a NULL
  1122. * IE pointer or an IE whose total length is not sane enough to
  1123. * distinguish the identity of the IE.
  1124. */
  1125. if (!ie) {
  1126. mlo_err("NULL pointer to IE");
  1127. return QDF_STATUS_E_NULL_VALUE;
  1128. }
  1129. if (total_ie_len < (ID_POS + 1)) {
  1130. mlo_err("Total IE length %zu is smaller than minimum required to access element ID %u",
  1131. total_ie_len, ID_POS + 1);
  1132. return QDF_STATUS_E_INVAL;
  1133. }
  1134. if ((ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1135. (total_ie_len < (IDEXT_POS + 1))) {
  1136. mlo_err("Total IE length %zu is smaller than minimum required to access element ID extension %u",
  1137. total_ie_len, IDEXT_POS + 1);
  1138. return QDF_STATUS_E_INVAL;
  1139. }
  1140. *is_in_noninheritlist = false;
  1141. /* If both the Non-Inheritance element list and Non-Inheritance element
  1142. * ID extension list are empty, then return success since we can
  1143. * conclude immediately that the given element does not occur in any
  1144. * Non-Inheritance list. The is_in_noninheritlist remains set to false
  1145. * as required.
  1146. */
  1147. if (!ninherit_elemlist_len && !ninherit_elemextlist_len)
  1148. return QDF_STATUS_SUCCESS;
  1149. if (ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
  1150. if (!ninherit_elemlist_len)
  1151. return QDF_STATUS_SUCCESS;
  1152. if (!ninherit_elemlist) {
  1153. mlo_err("NULL pointer to Non-Inheritance element ID list though length of element ID list is %zu",
  1154. ninherit_elemlist_len);
  1155. return QDF_STATUS_E_NULL_VALUE;
  1156. }
  1157. for (i = 0; i < ninherit_elemlist_len; i++) {
  1158. if (ie[ID_POS] == ninherit_elemlist[i]) {
  1159. *is_in_noninheritlist = true;
  1160. return QDF_STATUS_SUCCESS;
  1161. }
  1162. }
  1163. } else {
  1164. if (!ninherit_elemextlist_len)
  1165. return QDF_STATUS_SUCCESS;
  1166. if (!ninherit_elemextlist) {
  1167. mlo_err("NULL pointer to Non-Inheritance element ID extension list though length of element ID extension list is %zu",
  1168. ninherit_elemextlist_len);
  1169. return QDF_STATUS_E_NULL_VALUE;
  1170. }
  1171. for (i = 0; i < ninherit_elemextlist_len; i++) {
  1172. if (ie[IDEXT_POS] == ninherit_elemextlist[i]) {
  1173. *is_in_noninheritlist = true;
  1174. return QDF_STATUS_SUCCESS;
  1175. }
  1176. }
  1177. }
  1178. return QDF_STATUS_SUCCESS;
  1179. }
  1180. #if defined (SAP_MULTI_LINK_EMULATION)
  1181. static inline
  1182. QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie,
  1183. const uint8_t *frame_iesection,
  1184. const qdf_size_t frame_iesection_len)
  1185. {
  1186. return QDF_STATUS_SUCCESS;
  1187. }
  1188. #else
  1189. static inline
  1190. QDF_STATUS util_validate_reportingsta_ie(const uint8_t *reportingsta_ie,
  1191. const uint8_t *frame_iesection,
  1192. const qdf_size_t frame_iesection_len)
  1193. {
  1194. qdf_size_t reportingsta_ie_size;
  1195. if (!reportingsta_ie) {
  1196. mlo_err("Pointer to reporting STA IE is NULL");
  1197. return QDF_STATUS_E_NULL_VALUE;
  1198. }
  1199. if (!frame_iesection) {
  1200. mlo_err("Pointer to start of IE section in reporting frame is NULL");
  1201. return QDF_STATUS_E_NULL_VALUE;
  1202. }
  1203. if (!frame_iesection_len) {
  1204. mlo_err("Length of IE section in reporting frame is zero");
  1205. return QDF_STATUS_E_INVAL;
  1206. }
  1207. if ((reportingsta_ie + ID_POS) > (frame_iesection +
  1208. frame_iesection_len - 1)) {
  1209. mlo_err_rl("Position of element ID field of element for reporting STA would exceed frame IE section boundary");
  1210. return QDF_STATUS_E_PROTO;
  1211. }
  1212. if ((reportingsta_ie + TAG_LEN_POS) > (frame_iesection +
  1213. frame_iesection_len - 1)) {
  1214. mlo_err_rl("Position of length field of element with element ID %u for reporting STA would exceed frame IE section boundary",
  1215. reportingsta_ie[ID_POS]);
  1216. return QDF_STATUS_E_PROTO;
  1217. }
  1218. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1219. ((reportingsta_ie + IDEXT_POS) > (frame_iesection +
  1220. frame_iesection_len - 1))) {
  1221. mlo_err_rl("Position of element ID extension field of element would exceed frame IE section boundary");
  1222. return QDF_STATUS_E_PROTO;
  1223. }
  1224. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
  1225. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1226. (reportingsta_ie_size < (IDEXT_POS + 1))) {
  1227. mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access element ID extension %u",
  1228. reportingsta_ie_size, IDEXT_POS + 1);
  1229. return QDF_STATUS_E_PROTO;
  1230. }
  1231. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
  1232. (reportingsta_ie_size < (PAYLOAD_START_POS + OUI_LEN))) {
  1233. mlo_err_rl("Total length %zu of element for reporting STA is smaller than minimum required to access vendor EID %u",
  1234. reportingsta_ie_size, PAYLOAD_START_POS + OUI_LEN);
  1235. return QDF_STATUS_E_PROTO;
  1236. }
  1237. if ((reportingsta_ie + reportingsta_ie_size) >
  1238. (frame_iesection + frame_iesection_len)) {
  1239. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1240. 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",
  1241. reportingsta_ie_size,
  1242. reportingsta_ie[ID_POS],
  1243. reportingsta_ie[IDEXT_POS]);
  1244. } else {
  1245. mlo_err_rl("Total size %zu octets of element with element ID %u for reporting STA would exceed frame IE section boundary",
  1246. reportingsta_ie_size,
  1247. reportingsta_ie[ID_POS]);
  1248. }
  1249. return QDF_STATUS_E_PROTO;
  1250. }
  1251. return QDF_STATUS_SUCCESS;
  1252. }
  1253. #endif
  1254. static inline
  1255. QDF_STATUS util_validate_sta_prof_ie(const uint8_t *sta_prof_ie,
  1256. const uint8_t *sta_prof_iesection,
  1257. const qdf_size_t sta_prof_iesection_len)
  1258. {
  1259. qdf_size_t sta_prof_ie_size;
  1260. if (!sta_prof_ie) {
  1261. mlo_err("Pointer to STA profile IE is NULL");
  1262. return QDF_STATUS_E_NULL_VALUE;
  1263. }
  1264. if (!sta_prof_iesection) {
  1265. mlo_err("Pointer to start of IE section in STA profile is NULL");
  1266. return QDF_STATUS_E_NULL_VALUE;
  1267. }
  1268. if (!sta_prof_iesection_len) {
  1269. mlo_err("Length of IE section in STA profile is zero");
  1270. return QDF_STATUS_E_INVAL;
  1271. }
  1272. if ((sta_prof_ie + ID_POS) > (sta_prof_iesection +
  1273. sta_prof_iesection_len - 1)) {
  1274. mlo_err_rl("Position of element ID field of STA profile element would exceed STA profile IE section boundary");
  1275. return QDF_STATUS_E_PROTO;
  1276. }
  1277. if ((sta_prof_ie + TAG_LEN_POS) > (sta_prof_iesection +
  1278. sta_prof_iesection_len - 1)) {
  1279. mlo_err_rl("Position of length field of element with element ID %u in STA profile would exceed STA profile IE section boundary",
  1280. sta_prof_ie[ID_POS]);
  1281. return QDF_STATUS_E_PROTO;
  1282. }
  1283. if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1284. ((sta_prof_ie + IDEXT_POS) > (sta_prof_iesection +
  1285. sta_prof_iesection_len - 1))) {
  1286. mlo_err_rl("Position of element ID extension field of element would exceed STA profile IE section boundary");
  1287. return QDF_STATUS_E_PROTO;
  1288. }
  1289. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
  1290. if ((sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  1291. (sta_prof_ie_size < (IDEXT_POS + 1))) {
  1292. mlo_err_rl("Total length %zu of STA profile element is smaller than minimum required to access element ID extension %u",
  1293. sta_prof_ie_size, IDEXT_POS + 1);
  1294. return QDF_STATUS_E_PROTO;
  1295. }
  1296. if ((sta_prof_ie + sta_prof_ie_size) >
  1297. (sta_prof_iesection + sta_prof_iesection_len)) {
  1298. if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  1299. 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",
  1300. sta_prof_ie_size,
  1301. sta_prof_ie[ID_POS],
  1302. sta_prof_ie[IDEXT_POS]);
  1303. } else {
  1304. mlo_err_rl("Total size %zu octets of element with element ID %u in STA profile would exceed STA profile IE section boundary",
  1305. sta_prof_ie_size,
  1306. sta_prof_ie[ID_POS]);
  1307. }
  1308. return QDF_STATUS_E_PROTO;
  1309. }
  1310. return QDF_STATUS_SUCCESS;
  1311. }
  1312. #ifdef CONN_MGR_ADV_FEATURE
  1313. /**
  1314. * util_add_mlie_for_prb_rsp_gen - Add the basic variant Multi-Link element
  1315. * when generating link specific probe response.
  1316. * @reportingsta_ie: Pointer to the reportingsta ie
  1317. * @reportingsta_ie_len: Length for reporting sta ie
  1318. * @plink_frame_currpos: Pointer to Link frame current pos
  1319. * @plink_frame_currlen: Current length of link frame.
  1320. * @link_frame_maxsize: Maximum size of the frame to be generated
  1321. * @linkid: Link Id value
  1322. *
  1323. * Add the basic variant Multi-Link element when
  1324. * generating link specific probe response.
  1325. *
  1326. * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving
  1327. * the reason for error in the case of failure
  1328. */
  1329. static QDF_STATUS
  1330. util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie,
  1331. qdf_size_t reportingsta_ie_len,
  1332. uint8_t **plink_frame_currpos,
  1333. qdf_size_t *plink_frame_currlen,
  1334. qdf_size_t link_frame_maxsize,
  1335. uint8_t linkid)
  1336. {
  1337. uint8_t mlie_len = 0;
  1338. uint8_t common_info_len = 0;
  1339. struct wlan_ie_multilink ml_ie_ff;
  1340. uint16_t mlcontrol;
  1341. uint16_t presencebm;
  1342. uint8_t *mlie_frame = NULL;
  1343. uint8_t link_id_offset = sizeof(struct wlan_ie_multilink) +
  1344. QDF_MAC_ADDR_SIZE +
  1345. WLAN_ML_BV_CINFO_LENGTH_SIZE;
  1346. uint8_t *link_frame_currpos = *plink_frame_currpos;
  1347. qdf_size_t link_frame_currlen = *plink_frame_currlen;
  1348. QDF_STATUS status = QDF_STATUS_SUCCESS;
  1349. status = util_get_mlie_common_info_len((uint8_t *)reportingsta_ie,
  1350. reportingsta_ie_len,
  1351. &common_info_len);
  1352. if (QDF_IS_STATUS_ERROR(status) ||
  1353. common_info_len > reportingsta_ie_len ||
  1354. (reportingsta_ie_len - common_info_len <
  1355. sizeof(struct wlan_ie_multilink))) {
  1356. mlo_err("Failed to parse common info, mlie len %d common info len %d",
  1357. reportingsta_ie_len, common_info_len);
  1358. return status;
  1359. }
  1360. /* common info len + bvmlie fixed fields */
  1361. mlie_len = common_info_len + sizeof(struct wlan_ie_multilink);
  1362. mlo_debug_rl("mlie_len %d, common_info_len %d, link_id_offset %d",
  1363. mlie_len,
  1364. common_info_len,
  1365. link_id_offset);
  1366. /*
  1367. * Validate the buffer available before copying ML IE.
  1368. * Incase if mlie_len is modified at later place, move this validation
  1369. * there to make sure no buffer overflow happens.
  1370. */
  1371. if ((link_frame_maxsize - link_frame_currlen) < mlie_len) {
  1372. mlo_err("Insufficient space in link specific frame for ML IE. Required: %u octets, available: %zu octets",
  1373. mlie_len, (link_frame_maxsize - link_frame_currlen));
  1374. return QDF_STATUS_E_NOMEM;
  1375. }
  1376. mlie_frame = qdf_mem_malloc(mlie_len);
  1377. if (!mlie_frame)
  1378. return QDF_STATUS_E_NOMEM;
  1379. /* Copy ml ie fixed fields */
  1380. qdf_mem_copy(&ml_ie_ff,
  1381. reportingsta_ie,
  1382. sizeof(struct wlan_ie_multilink));
  1383. ml_ie_ff.elem_len = mlie_len - sizeof(struct ie_header);
  1384. mlcontrol = qdf_le16_to_cpu(ml_ie_ff.mlcontrol);
  1385. presencebm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  1386. WLAN_ML_CTRL_PBM_BITS);
  1387. qdf_set_bit(WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P,
  1388. (unsigned long *)&presencebm);
  1389. QDF_SET_BITS(ml_ie_ff.mlcontrol,
  1390. WLAN_ML_CTRL_PBM_IDX,
  1391. WLAN_ML_CTRL_PBM_BITS,
  1392. presencebm);
  1393. qdf_mem_copy(mlie_frame,
  1394. &ml_ie_ff,
  1395. sizeof(struct wlan_ie_multilink));
  1396. qdf_mem_copy(mlie_frame + sizeof(struct wlan_ie_multilink),
  1397. reportingsta_ie + sizeof(struct wlan_ie_multilink),
  1398. mlie_len - sizeof(struct wlan_ie_multilink));
  1399. if (linkid == 0xFF || mlie_len <= link_id_offset) {
  1400. qdf_mem_free(mlie_frame);
  1401. mlo_err("Failed to process link id, link_id %d", linkid);
  1402. return QDF_STATUS_E_INVAL;
  1403. }
  1404. mlie_frame[link_id_offset] = (mlie_frame[link_id_offset] & ~0x0f) |
  1405. (linkid & 0x0f);
  1406. qdf_mem_copy(link_frame_currpos,
  1407. mlie_frame,
  1408. mlie_len);
  1409. mlo_debug("Add mlie for link id %d", linkid);
  1410. QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
  1411. mlie_frame, mlie_len);
  1412. link_frame_currpos += mlie_len;
  1413. link_frame_currlen += mlie_len;
  1414. *plink_frame_currpos = link_frame_currpos;
  1415. *plink_frame_currlen = link_frame_currlen;
  1416. qdf_mem_free(mlie_frame);
  1417. return QDF_STATUS_SUCCESS;
  1418. }
  1419. #else
  1420. static QDF_STATUS
  1421. util_add_mlie_for_prb_rsp_gen(const uint8_t *reportingsta_ie,
  1422. qdf_size_t reportingsta_ie_len,
  1423. uint8_t **plink_frame_currpos,
  1424. qdf_size_t *plink_frame_currlen,
  1425. qdf_size_t link_frame_maxsize,
  1426. uint8_t linkid)
  1427. {
  1428. return QDF_STATUS_SUCCESS;
  1429. }
  1430. #endif
  1431. /**
  1432. * util_find_bvmlie_persta_prof_for_linkid() - get per sta profile per link id
  1433. * @req_link_id: link id
  1434. * @linkinfo: the pointer of link info
  1435. * @linkinfo_len: the length of link info
  1436. * @persta_prof_frame: the pointer to store the address of sta profile
  1437. * @persta_prof_len: the sta profile length
  1438. *
  1439. * This helper function parses partner info from the per-STA profiles
  1440. * present (if any) in the Link Info field in the payload of a Multi
  1441. * Link element (after defragmentation if required). The caller should
  1442. * pass a copy of the payload so that inline defragmentation of
  1443. * subelements can be carried out if required. The subelement
  1444. * defragmentation (if applicable) in this Control Path helper is
  1445. * required for maintainability, accuracy and eliminating current and
  1446. * future per-field-access multi-level fragment boundary checks and
  1447. * adjustments, given the complex format of Multi Link elements. It is
  1448. * also most likely to be required mainly at the client side.
  1449. *
  1450. * Return: QDF_STATUS
  1451. */
  1452. static QDF_STATUS
  1453. util_find_bvmlie_persta_prof_for_linkid(uint8_t req_link_id,
  1454. uint8_t *linkinfo,
  1455. qdf_size_t linkinfo_len,
  1456. uint8_t **persta_prof_frame,
  1457. qdf_size_t *persta_prof_len)
  1458. {
  1459. uint8_t linkid;
  1460. struct qdf_mac_addr macaddr;
  1461. bool is_macaddr_valid;
  1462. uint8_t *linkinfo_currpos;
  1463. qdf_size_t linkinfo_remlen;
  1464. bool is_subelemfragseq;
  1465. uint8_t subelemid;
  1466. qdf_size_t subelemseqtotallen;
  1467. qdf_size_t subelemseqpayloadlen;
  1468. qdf_size_t defragpayload_len;
  1469. QDF_STATUS ret;
  1470. if (!linkinfo) {
  1471. mlo_err("linkinfo is NULL");
  1472. return QDF_STATUS_E_NULL_VALUE;
  1473. }
  1474. if (!linkinfo_len) {
  1475. mlo_err("linkinfo_len is zero");
  1476. return QDF_STATUS_E_NULL_VALUE;
  1477. }
  1478. if (!persta_prof_frame) {
  1479. mlo_err("Pointer to per-STA prof frame is NULL");
  1480. return QDF_STATUS_E_NULL_VALUE;
  1481. }
  1482. if (!persta_prof_len) {
  1483. mlo_err("Length to per-STA prof frame is 0");
  1484. return QDF_STATUS_E_NULL_VALUE;
  1485. }
  1486. linkinfo_currpos = linkinfo;
  1487. linkinfo_remlen = linkinfo_len;
  1488. while (linkinfo_remlen) {
  1489. if (linkinfo_remlen < sizeof(struct subelem_header)) {
  1490. mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
  1491. linkinfo_remlen,
  1492. sizeof(struct subelem_header));
  1493. return QDF_STATUS_E_PROTO;
  1494. }
  1495. subelemid = linkinfo_currpos[ID_POS];
  1496. is_subelemfragseq = false;
  1497. subelemseqtotallen = 0;
  1498. subelemseqpayloadlen = 0;
  1499. ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  1500. linkinfo_currpos,
  1501. linkinfo_remlen,
  1502. &is_subelemfragseq,
  1503. &subelemseqtotallen,
  1504. &subelemseqpayloadlen);
  1505. if (QDF_IS_STATUS_ERROR(ret))
  1506. return ret;
  1507. if (is_subelemfragseq) {
  1508. if (!subelemseqpayloadlen) {
  1509. mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
  1510. return QDF_STATUS_E_FAILURE;
  1511. }
  1512. mlo_debug("Subelement fragment sequence found with payload len %zu",
  1513. subelemseqpayloadlen);
  1514. ret = wlan_defrag_subelem_fragseq(true,
  1515. WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  1516. linkinfo_currpos,
  1517. linkinfo_remlen,
  1518. NULL,
  1519. 0,
  1520. &defragpayload_len);
  1521. if (QDF_IS_STATUS_ERROR(ret))
  1522. return ret;
  1523. if (defragpayload_len != subelemseqpayloadlen) {
  1524. mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
  1525. defragpayload_len,
  1526. subelemseqpayloadlen);
  1527. return QDF_STATUS_E_FAILURE;
  1528. }
  1529. /* Adjust linkinfo_remlen to reflect removal of all
  1530. * subelement headers except the header of the lead
  1531. * subelement.
  1532. */
  1533. linkinfo_remlen -= (subelemseqtotallen -
  1534. subelemseqpayloadlen -
  1535. sizeof(struct subelem_header));
  1536. } else {
  1537. if (linkinfo_remlen <
  1538. (sizeof(struct subelem_header) +
  1539. linkinfo_currpos[TAG_LEN_POS])) {
  1540. mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
  1541. linkinfo_remlen,
  1542. sizeof(struct subelem_header) +
  1543. linkinfo_currpos[TAG_LEN_POS]);
  1544. return QDF_STATUS_E_PROTO;
  1545. }
  1546. subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
  1547. }
  1548. if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
  1549. is_macaddr_valid = false;
  1550. ret = util_parse_bvmlie_perstaprofile_stactrl(linkinfo_currpos +
  1551. sizeof(struct subelem_header),
  1552. subelemseqpayloadlen,
  1553. &linkid,
  1554. NULL,
  1555. NULL,
  1556. NULL,
  1557. NULL,
  1558. NULL,
  1559. &is_macaddr_valid,
  1560. &macaddr,
  1561. false,
  1562. NULL,
  1563. NULL,
  1564. NULL,
  1565. NULL);
  1566. if (QDF_IS_STATUS_ERROR(ret))
  1567. return ret;
  1568. if (req_link_id == linkid) {
  1569. mlo_debug("Found requested per-STA prof for linkid %u, len %zu",
  1570. linkid, subelemseqpayloadlen);
  1571. *persta_prof_frame = linkinfo_currpos;
  1572. *persta_prof_len = subelemseqpayloadlen;
  1573. return QDF_STATUS_SUCCESS;
  1574. }
  1575. }
  1576. linkinfo_remlen -= (sizeof(struct subelem_header) +
  1577. subelemseqpayloadlen);
  1578. linkinfo_currpos += (sizeof(struct subelem_header) +
  1579. subelemseqpayloadlen);
  1580. }
  1581. return QDF_STATUS_E_PROTO;
  1582. }
  1583. static
  1584. QDF_STATUS util_gen_link_prb_rsp_from_assoc_rsp_cmn(uint8_t *frame,
  1585. qdf_size_t frame_len,
  1586. uint8_t orig_subtype,
  1587. uint8_t gen_subtype,
  1588. uint8_t req_link_id,
  1589. struct qdf_mac_addr link_addr,
  1590. uint8_t *link_frame,
  1591. qdf_size_t link_frame_maxsize,
  1592. qdf_size_t *link_frame_len,
  1593. uint8_t *bcn_prb_ptr,
  1594. qdf_size_t bcn_prb_len)
  1595. {
  1596. /* Pointer to Multi-Link element/Multi-Link element fragment sequence */
  1597. uint8_t *mlieseq;
  1598. /* Total length of Multi-Link element sequence (including fragments if
  1599. * any)
  1600. */
  1601. qdf_size_t mlieseqlen;
  1602. /* Variant (i.e. type) of the Multi-Link element */
  1603. enum wlan_ml_variant variant;
  1604. /* Length of the payload of the Multi-Link element (inclusive of
  1605. * fragment payloads if any) without IE headers and element ID extension
  1606. */
  1607. qdf_size_t mlieseqpayloadlen;
  1608. /* Pointer to copy of the payload of the Multi-Link element (inclusive
  1609. * of fragment payloads if any) without IE headers and element ID
  1610. * extension
  1611. */
  1612. uint8_t *mlieseqpayload_copy;
  1613. /* Pointer to start of Link Info within the copy of the payload of the
  1614. * Multi-Link element
  1615. */
  1616. uint8_t *link_info;
  1617. /* Length of the Link Info */
  1618. qdf_size_t link_info_len;
  1619. /* Pointer to the IE section that occurs after the fixed fields in the
  1620. * original frame for the reporting STA.
  1621. */
  1622. uint8_t *frame_iesection;
  1623. /* Offset to the start of the IE section in the original frame for the
  1624. * reporting STA.
  1625. */
  1626. qdf_size_t frame_iesection_offset;
  1627. /* Total length of the IE section in the original frame for the
  1628. * reporting STA.
  1629. */
  1630. qdf_size_t frame_iesection_len;
  1631. /* Pointer to the IEEE802.11 frame header in the link specific frame
  1632. * being generated for the reported STA.
  1633. */
  1634. struct wlan_frame_hdr *link_frame_hdr;
  1635. /* Current position in the link specific frame being generated for the
  1636. * reported STA.
  1637. */
  1638. uint8_t *link_frame_currpos;
  1639. /* Current length of the link specific frame being generated for the
  1640. * reported STA.
  1641. */
  1642. qdf_size_t link_frame_currlen;
  1643. /* Pointer to IE for reporting STA */
  1644. const uint8_t *reportingsta_ie;
  1645. /* Total size of IE for reporting STA, inclusive of the element header
  1646. */
  1647. qdf_size_t reportingsta_ie_size;
  1648. /* Pointer to current position in STA profile */
  1649. uint8_t *sta_prof_currpos;
  1650. /* Remaining length of STA profile */
  1651. qdf_size_t sta_prof_remlen;
  1652. /* Pointer to start of IE section in STA profile that occurs after fixed
  1653. * fields.
  1654. */
  1655. uint8_t *sta_prof_iesection;
  1656. /* Total length of IE section in STA profile */
  1657. qdf_size_t sta_prof_iesection_len;
  1658. /* Pointer to current position being processed in IE section in STA
  1659. * profile.
  1660. */
  1661. uint8_t *sta_prof_iesection_currpos;
  1662. /* Remaining length of IE section in STA profile */
  1663. qdf_size_t sta_prof_iesection_remlen;
  1664. /* Pointer to IE in STA profile, that occurs within IE section */
  1665. uint8_t *sta_prof_ie;
  1666. /* Total size of IE in STA profile, inclusive of the element header */
  1667. qdf_size_t sta_prof_ie_size;
  1668. /* Pointer to element ID list in Non-Inheritance IE */
  1669. uint8_t *ninherit_elemlist;
  1670. /* Length of element ID list in Non-Inheritance IE */
  1671. qdf_size_t ninherit_elemlist_len;
  1672. /* Pointer to element ID extension list in Non-Inheritance IE */
  1673. uint8_t *ninherit_elemextlist;
  1674. /* Length of element ID extension list in Non-Inheritance IE */
  1675. qdf_size_t ninherit_elemextlist_len;
  1676. /* Whether a given IE is in a non-inheritance list */
  1677. bool is_in_noninheritlist;
  1678. /* Whether MAC address of reported STA is valid */
  1679. bool is_reportedmacaddr_valid;
  1680. /* MAC address of reported STA */
  1681. struct qdf_mac_addr reportedmacaddr;
  1682. /* Pointer to per-STA profile */
  1683. uint8_t *persta_prof;
  1684. /* Length of the containing buffer which starts with the per-STA profile
  1685. */
  1686. qdf_size_t persta_prof_bufflen;
  1687. /* Other variables for temporary purposes */
  1688. /* Variable into which API for determining fragment information will
  1689. * indicate whether the element is the start of a fragment sequence or
  1690. * not.
  1691. */
  1692. bool is_elemfragseq;
  1693. /* De-fragmented payload length returned by API for element
  1694. * defragmentation.
  1695. */
  1696. qdf_size_t defragpayload_len;
  1697. /* Pointer to Beacon interval in STA info field */
  1698. uint16_t beaconinterval;
  1699. /* Whether Beacon interval value valid */
  1700. bool is_beaconinterval_valid;
  1701. /* TSF offset of the reproted AP */
  1702. uint64_t tsfoffset;
  1703. /* TSF offset value valid */
  1704. bool is_tsfoffset_valid;
  1705. /* If Complete Profile or not*/
  1706. bool is_completeprofile;
  1707. qdf_size_t tmplen;
  1708. QDF_STATUS ret;
  1709. uint8_t ie_idx, linkid = 0xFF;
  1710. /* List of IEs to add from @bcn_prb_ptr */
  1711. uint8_t missing_ie_list[] = {WLAN_ELEMID_SSID, WLAN_ELEMID_RSN};
  1712. /* No.of IEs in @missing_ie_list array */
  1713. uint8_t missing_ie_len = sizeof(missing_ie_list);
  1714. /* List of Extn IEs to add from @bcn_prb_ptr */
  1715. uint8_t *missing_ext_ie_list = NULL;
  1716. /* No.of IEs in @missing_ext_ie_list array */
  1717. uint8_t missing_ext_ie_len = 0x0;
  1718. uint8_t *bcn_prb_ies_ptr, *secondary_ie;
  1719. qdf_size_t bcn_prb_ies_len;
  1720. if (!frame) {
  1721. mlo_err("Pointer to original frame is NULL");
  1722. return QDF_STATUS_E_NULL_VALUE;
  1723. }
  1724. if (!frame_len) {
  1725. mlo_err("Length of original frame is zero");
  1726. return QDF_STATUS_E_INVAL;
  1727. }
  1728. if (!link_frame) {
  1729. mlo_err("Pointer to secondary link specific frame is NULL");
  1730. return QDF_STATUS_E_NULL_VALUE;
  1731. }
  1732. if (!link_frame_maxsize) {
  1733. mlo_err("Maximum size of secondary link specific frame is zero");
  1734. return QDF_STATUS_E_INVAL;
  1735. }
  1736. if (!link_frame_len) {
  1737. mlo_err("Pointer to populated length of secondary link specific frame is NULL");
  1738. return QDF_STATUS_E_NULL_VALUE;
  1739. }
  1740. frame_iesection_offset = 0;
  1741. /* This is a (re)association response */
  1742. frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET;
  1743. if (frame_len < frame_iesection_offset) {
  1744. /* The caller is supposed to have confirmed that this is a valid
  1745. * frame containing a Multi-Link element. Hence we treat this as
  1746. * a case of invalid argument being passed to us.
  1747. */
  1748. mlo_err("Frame length %zu is smaller than the IE section offset %zu for orig_subtype %u",
  1749. frame_len, frame_iesection_offset, orig_subtype);
  1750. return QDF_STATUS_E_INVAL;
  1751. }
  1752. frame_iesection_len = frame_len - frame_iesection_offset;
  1753. if (frame_iesection_len == 0) {
  1754. /* The caller is supposed to have confirmed that this is a valid
  1755. * frame containing a Multi-Link element. Hence we treat this as
  1756. * a case of invalid argument being passed to us.
  1757. */
  1758. mlo_err("No space left in frame for IE section");
  1759. return QDF_STATUS_E_INVAL;
  1760. }
  1761. frame_iesection = frame + frame_iesection_offset;
  1762. bcn_prb_ies_ptr = bcn_prb_ptr + WLAN_PROBE_RESP_IES_OFFSET;
  1763. bcn_prb_ies_len = bcn_prb_len - WLAN_PROBE_RESP_IES_OFFSET;
  1764. mlieseq = NULL;
  1765. mlieseqlen = 0;
  1766. ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq,
  1767. &mlieseqlen);
  1768. if (QDF_IS_STATUS_ERROR(ret))
  1769. return ret;
  1770. if (!mlieseq) {
  1771. /* The caller is supposed to have confirmed that a Multi-Link
  1772. * element is present in the frame. Hence we treat this as a
  1773. * case of invalid argument being passed to us.
  1774. */
  1775. mlo_err("Invalid original frame since no Multi-Link element found");
  1776. return QDF_STATUS_E_INVAL;
  1777. }
  1778. /* Sanity check the Multi-Link element sequence length */
  1779. if (!mlieseqlen) {
  1780. mlo_err("Length of Multi-Link element sequence is zero. Investigate.");
  1781. return QDF_STATUS_E_FAILURE;
  1782. }
  1783. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  1784. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  1785. mlieseqlen, sizeof(struct wlan_ie_multilink));
  1786. return QDF_STATUS_E_PROTO;
  1787. }
  1788. ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant);
  1789. if (QDF_IS_STATUS_ERROR(ret))
  1790. return ret;
  1791. if (variant != WLAN_ML_VARIANT_BASIC) {
  1792. mlo_err_rl("Unexpected variant %u of Multi-Link element.",
  1793. variant);
  1794. return QDF_STATUS_E_PROTO;
  1795. }
  1796. mlieseqpayloadlen = 0;
  1797. tmplen = 0;
  1798. is_elemfragseq = false;
  1799. ret = wlan_get_elem_fragseq_info(mlieseq,
  1800. mlieseqlen,
  1801. &is_elemfragseq,
  1802. &tmplen,
  1803. &mlieseqpayloadlen);
  1804. if (QDF_IS_STATUS_ERROR(ret))
  1805. return ret;
  1806. if (is_elemfragseq) {
  1807. if (tmplen != mlieseqlen) {
  1808. 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",
  1809. tmplen, mlieseqlen);
  1810. return QDF_STATUS_E_FAILURE;
  1811. }
  1812. if (!mlieseqpayloadlen) {
  1813. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  1814. return QDF_STATUS_E_FAILURE;
  1815. }
  1816. mlo_debug("ML IE fragment sequence found with payload len %zu",
  1817. mlieseqpayloadlen);
  1818. } else {
  1819. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  1820. 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",
  1821. mlieseqlen,
  1822. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  1823. return QDF_STATUS_E_FAILURE;
  1824. }
  1825. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  1826. }
  1827. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  1828. if (!mlieseqpayload_copy) {
  1829. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  1830. return QDF_STATUS_E_NOMEM;
  1831. }
  1832. if (is_elemfragseq) {
  1833. ret = wlan_defrag_elem_fragseq(false,
  1834. mlieseq,
  1835. mlieseqlen,
  1836. mlieseqpayload_copy,
  1837. mlieseqpayloadlen,
  1838. &defragpayload_len);
  1839. if (QDF_IS_STATUS_ERROR(ret))
  1840. goto mem_free;
  1841. if (defragpayload_len != mlieseqpayloadlen) {
  1842. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  1843. defragpayload_len, mlieseqpayloadlen);
  1844. ret = QDF_STATUS_E_FAILURE;
  1845. goto mem_free;
  1846. }
  1847. } else {
  1848. qdf_mem_copy(mlieseqpayload_copy,
  1849. mlieseq + sizeof(struct ie_header) + 1,
  1850. mlieseqpayloadlen);
  1851. }
  1852. link_info = NULL;
  1853. link_info_len = 0;
  1854. ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
  1855. mlieseqpayloadlen,
  1856. &link_info,
  1857. &link_info_len);
  1858. if (QDF_IS_STATUS_ERROR(ret))
  1859. goto mem_free;
  1860. /* As per the standard, the sender must include Link Info for
  1861. * association request/response. Throw an error if we are unable to
  1862. * obtain this.
  1863. */
  1864. if (!link_info) {
  1865. mlo_err_rl("Unable to successfully obtain Link Info");
  1866. ret = QDF_STATUS_E_PROTO;
  1867. goto mem_free;
  1868. }
  1869. /* Note: We may have a future change to skip subelements which are not
  1870. * Per-STA Profile, handle more than two links in MLO, handle cases
  1871. * where we unexpectedly find more Per-STA Profiles than expected, etc.
  1872. */
  1873. persta_prof = NULL;
  1874. persta_prof_bufflen = 0;
  1875. ret = util_find_bvmlie_persta_prof_for_linkid(req_link_id,
  1876. link_info,
  1877. link_info_len,
  1878. &persta_prof,
  1879. &persta_prof_bufflen);
  1880. if (QDF_IS_STATUS_ERROR(ret)) {
  1881. mlo_err_rl("Per STA profile not found for link id %d",
  1882. req_link_id);
  1883. goto mem_free;
  1884. }
  1885. sta_prof_remlen = 0;
  1886. sta_prof_currpos = NULL;
  1887. is_reportedmacaddr_valid = false;
  1888. is_beaconinterval_valid = false;
  1889. is_completeprofile = false;
  1890. is_tsfoffset_valid = false;
  1891. /* Parse per-STA profile */
  1892. ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof +
  1893. sizeof(struct subelem_header),
  1894. persta_prof_bufflen,
  1895. &linkid,
  1896. &beaconinterval,
  1897. &is_beaconinterval_valid,
  1898. &tsfoffset,
  1899. &is_tsfoffset_valid,
  1900. &is_completeprofile,
  1901. &is_reportedmacaddr_valid,
  1902. &reportedmacaddr,
  1903. true,
  1904. &sta_prof_currpos,
  1905. &sta_prof_remlen,
  1906. NULL,
  1907. NULL);
  1908. if (QDF_IS_STATUS_ERROR(ret))
  1909. goto mem_free;
  1910. if (!is_completeprofile) {
  1911. mlo_err("Complete profile information is not present in per-STA profile");
  1912. ret = QDF_STATUS_E_NOSUPPORT;
  1913. goto mem_free;
  1914. }
  1915. /* We double check for a NULL STA Profile, though the helper function
  1916. * above would have taken care of this. We need to get a non-NULL STA
  1917. * profile, because we need to get at least the expected fixed fields,
  1918. * even if there is an (improbable) total inheritance.
  1919. */
  1920. if (!sta_prof_currpos) {
  1921. mlo_err_rl("STA profile is NULL");
  1922. ret = QDF_STATUS_E_PROTO;
  1923. goto mem_free;
  1924. }
  1925. /* As per the standard, the sender sets the MAC address in the per-STA
  1926. * profile in association request/response. Without this, we cannot
  1927. * generate the link specific frame.
  1928. */
  1929. if (!is_reportedmacaddr_valid) {
  1930. mlo_err_rl("Unable to get MAC address from per-STA profile");
  1931. ret = QDF_STATUS_E_PROTO;
  1932. goto mem_free;
  1933. }
  1934. link_frame_currpos = link_frame;
  1935. *link_frame_len = 0;
  1936. link_frame_currlen = 0;
  1937. if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) {
  1938. mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets",
  1939. WLAN_MAC_HDR_LEN_3A, link_frame_maxsize);
  1940. ret = QDF_STATUS_E_NOMEM;
  1941. goto mem_free;
  1942. }
  1943. link_frame_currpos += WLAN_MAC_HDR_LEN_3A;
  1944. link_frame_currlen += WLAN_MAC_HDR_LEN_3A;
  1945. /* This is a (re)association response */
  1946. mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame");
  1947. if (sta_prof_remlen < (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
  1948. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u",
  1949. sta_prof_remlen,
  1950. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN);
  1951. ret = QDF_STATUS_E_PROTO;
  1952. goto mem_free;
  1953. }
  1954. /* TODO: */
  1955. qdf_mem_copy(link_frame_currpos, bcn_prb_ptr, WLAN_TIMESTAMP_LEN);
  1956. link_frame_currpos += WLAN_TIMESTAMP_LEN;
  1957. link_frame_currlen += WLAN_TIMESTAMP_LEN;
  1958. if (is_beaconinterval_valid) {
  1959. qdf_mem_copy(link_frame_currpos, &beaconinterval,
  1960. WLAN_BEACONINTERVAL_LEN);
  1961. } else {
  1962. /* Use the BI from input frame if per-STA doesn't have valid
  1963. * BI
  1964. */
  1965. qdf_mem_copy(link_frame_currpos,
  1966. bcn_prb_ptr + WLAN_TIMESTAMP_LEN,
  1967. WLAN_BEACONINTERVAL_LEN);
  1968. }
  1969. link_frame_currpos += WLAN_BEACONINTERVAL_LEN;
  1970. link_frame_currlen += WLAN_BEACONINTERVAL_LEN;
  1971. /* Capability information and Status Code are specific to the
  1972. * link. Copy these from the STA profile.
  1973. */
  1974. if ((link_frame_maxsize - link_frame_currlen) <
  1975. WLAN_CAPABILITYINFO_LEN) {
  1976. mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets",
  1977. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN,
  1978. (link_frame_maxsize - link_frame_currlen));
  1979. ret = QDF_STATUS_E_NOMEM;
  1980. goto mem_free;
  1981. }
  1982. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  1983. WLAN_CAPABILITYINFO_LEN);
  1984. link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
  1985. link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
  1986. mlo_debug("Added Capability Info (%u octets) to link specific frame",
  1987. WLAN_CAPABILITYINFO_LEN);
  1988. sta_prof_currpos += WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN;
  1989. sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN;
  1990. sta_prof_iesection = sta_prof_currpos;
  1991. sta_prof_iesection_len = sta_prof_remlen;
  1992. /* Populate non-inheritance lists if applicable */
  1993. ninherit_elemlist_len = 0;
  1994. ninherit_elemlist = NULL;
  1995. ninherit_elemextlist_len = 0;
  1996. ninherit_elemextlist = NULL;
  1997. ret = util_get_noninheritlists(sta_prof_iesection,
  1998. sta_prof_iesection_len,
  1999. &ninherit_elemlist,
  2000. &ninherit_elemlist_len,
  2001. &ninherit_elemextlist,
  2002. &ninherit_elemextlist_len);
  2003. if (QDF_IS_STATUS_ERROR(ret))
  2004. goto mem_free;
  2005. /* Go through IEs of the reporting STA, and those in STA profile, merge
  2006. * them into link_frame (except for elements in the Non-Inheritance
  2007. * list).
  2008. *
  2009. * Note: Currently, only 2-link MLO is supported here. We may have a
  2010. * future change to expand to more links.
  2011. */
  2012. reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection,
  2013. frame_iesection_len);
  2014. /* This is a (re)association response. Sanity check that the
  2015. * SSID element is present neither for the reporting STA nor in
  2016. * the STA profile.
  2017. */
  2018. if (reportingsta_ie) {
  2019. mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present.");
  2020. ret = QDF_STATUS_E_PROTO;
  2021. goto mem_free;
  2022. }
  2023. sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID,
  2024. sta_prof_iesection,
  2025. sta_prof_iesection_len);
  2026. if (sta_prof_ie) {
  2027. mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present.");
  2028. ret = QDF_STATUS_E_PROTO;
  2029. goto mem_free;
  2030. }
  2031. reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection;
  2032. ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection,
  2033. frame_iesection_len);
  2034. if (QDF_IS_STATUS_ERROR(ret))
  2035. goto mem_free;
  2036. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2037. while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection)
  2038. <= frame_iesection_len) {
  2039. if (reportingsta_ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
  2040. for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
  2041. if (missing_ie_list[ie_idx] ==
  2042. reportingsta_ie[ID_POS]) {
  2043. missing_ie_list[ie_idx] =
  2044. WLAN_ELEMID_EXTN_ELEM;
  2045. }
  2046. }
  2047. } else {
  2048. for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
  2049. if (missing_ext_ie_list[ie_idx] ==
  2050. reportingsta_ie[IDEXT_POS]) {
  2051. missing_ext_ie_list[ie_idx] =
  2052. WLAN_ELEMID_EXTN_ELEM;
  2053. }
  2054. }
  2055. }
  2056. /* Skip Multi-Link element */
  2057. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  2058. (reportingsta_ie[IDEXT_POS] ==
  2059. WLAN_EXTN_ELEMID_MULTI_LINK)) {
  2060. if (((reportingsta_ie + reportingsta_ie_size) -
  2061. frame_iesection) == frame_iesection_len)
  2062. break;
  2063. /* Add BV ML IE for link specific probe response */
  2064. ret = util_add_mlie_for_prb_rsp_gen(
  2065. reportingsta_ie,
  2066. reportingsta_ie[TAG_LEN_POS],
  2067. &link_frame_currpos,
  2068. &link_frame_currlen,
  2069. link_frame_maxsize,
  2070. linkid);
  2071. if (QDF_IS_STATUS_ERROR(ret))
  2072. goto mem_free;
  2073. reportingsta_ie += reportingsta_ie_size;
  2074. ret = util_validate_reportingsta_ie(reportingsta_ie,
  2075. frame_iesection,
  2076. frame_iesection_len);
  2077. if (QDF_IS_STATUS_ERROR(ret))
  2078. goto mem_free;
  2079. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  2080. MIN_IE_LEN;
  2081. continue;
  2082. }
  2083. sta_prof_ie = NULL;
  2084. sta_prof_ie_size = 0;
  2085. if (sta_prof_iesection_len) {
  2086. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  2087. sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS],
  2088. reportingsta_ie[IDEXT_POS],
  2089. sta_prof_iesection,
  2090. sta_prof_iesection_len);
  2091. } else {
  2092. sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS],
  2093. sta_prof_iesection,
  2094. sta_prof_iesection_len);
  2095. }
  2096. }
  2097. if (!sta_prof_ie) {
  2098. /* IE is present for reporting STA, but not in STA
  2099. * profile.
  2100. */
  2101. is_in_noninheritlist = false;
  2102. ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie,
  2103. reportingsta_ie_size,
  2104. ninherit_elemlist,
  2105. ninherit_elemlist_len,
  2106. ninherit_elemextlist,
  2107. ninherit_elemextlist_len,
  2108. &is_in_noninheritlist);
  2109. if (QDF_IS_STATUS_ERROR(ret))
  2110. goto mem_free;
  2111. if (!is_in_noninheritlist) {
  2112. if ((link_frame_currpos +
  2113. reportingsta_ie_size) <=
  2114. (link_frame + link_frame_maxsize)) {
  2115. qdf_mem_copy(link_frame_currpos,
  2116. reportingsta_ie,
  2117. reportingsta_ie_size);
  2118. link_frame_currpos +=
  2119. reportingsta_ie_size;
  2120. link_frame_currlen +=
  2121. reportingsta_ie_size;
  2122. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  2123. mlo_etrace_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",
  2124. reportingsta_ie[ID_POS],
  2125. reportingsta_ie[IDEXT_POS],
  2126. reportingsta_ie_size);
  2127. } else {
  2128. mlo_etrace_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",
  2129. reportingsta_ie[ID_POS],
  2130. reportingsta_ie_size);
  2131. }
  2132. } else {
  2133. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  2134. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  2135. reportingsta_ie[ID_POS],
  2136. reportingsta_ie[IDEXT_POS],
  2137. reportingsta_ie_size,
  2138. link_frame_maxsize -
  2139. link_frame_currlen);
  2140. } else {
  2141. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  2142. reportingsta_ie[ID_POS],
  2143. reportingsta_ie_size,
  2144. link_frame_maxsize -
  2145. link_frame_currlen);
  2146. }
  2147. ret = QDF_STATUS_E_NOMEM;
  2148. goto mem_free;
  2149. }
  2150. } else {
  2151. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  2152. mlo_etrace_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.",
  2153. reportingsta_ie[ID_POS],
  2154. reportingsta_ie[IDEXT_POS],
  2155. reportingsta_ie_size);
  2156. } else {
  2157. mlo_etrace_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.",
  2158. reportingsta_ie[ID_POS],
  2159. reportingsta_ie_size);
  2160. }
  2161. }
  2162. } else {
  2163. /* IE is present for reporting STA and also in STA
  2164. * profile, copy from STA profile and flag the IE in STA
  2165. * profile as copied (by setting EID field to 0). The
  2166. * SSID element (with EID 0) is processed first to
  2167. * enable this. For vendor IE, compare OUI + type +
  2168. * subType to determine if they are the same IE.
  2169. */
  2170. /* Note: This may be revisited in a future change, to
  2171. * adhere to provisions in the standard for multiple
  2172. * occurrences of a given element ID/extension element
  2173. * ID.
  2174. */
  2175. ret = util_validate_sta_prof_ie(sta_prof_ie,
  2176. sta_prof_iesection,
  2177. sta_prof_iesection_len);
  2178. if (QDF_IS_STATUS_ERROR(ret))
  2179. goto mem_free;
  2180. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] +
  2181. MIN_IE_LEN;
  2182. sta_prof_iesection_remlen =
  2183. sta_prof_iesection_len -
  2184. (sta_prof_ie - sta_prof_iesection);
  2185. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
  2186. (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) {
  2187. /* If Vendor IE also presents in STA profile,
  2188. * then ignore the Vendor IE which is for
  2189. * reporting STA. It only needs to copy Vendor
  2190. * IE from STA profile to link specific frame.
  2191. * The copy happens when going through the
  2192. * remaining IEs.
  2193. */
  2194. ;
  2195. } else {
  2196. /* Copy IE from STA profile into link specific
  2197. * frame.
  2198. */
  2199. if ((link_frame_currpos + sta_prof_ie_size) <=
  2200. (link_frame + link_frame_maxsize)) {
  2201. qdf_mem_copy(link_frame_currpos,
  2202. sta_prof_ie,
  2203. sta_prof_ie_size);
  2204. link_frame_currpos += sta_prof_ie_size;
  2205. link_frame_currlen +=
  2206. sta_prof_ie_size;
  2207. if (reportingsta_ie[ID_POS] ==
  2208. WLAN_ELEMID_EXTN_ELEM) {
  2209. mlo_etrace_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",
  2210. sta_prof_ie[ID_POS],
  2211. sta_prof_ie[IDEXT_POS],
  2212. sta_prof_ie_size);
  2213. } else {
  2214. mlo_etrace_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",
  2215. sta_prof_ie[ID_POS],
  2216. sta_prof_ie_size);
  2217. }
  2218. sta_prof_ie[0] = 0;
  2219. } else {
  2220. if (sta_prof_ie[ID_POS] ==
  2221. WLAN_ELEMID_EXTN_ELEM) {
  2222. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  2223. sta_prof_ie[ID_POS],
  2224. sta_prof_ie[IDEXT_POS],
  2225. sta_prof_ie_size,
  2226. link_frame_maxsize -
  2227. link_frame_currlen);
  2228. } else {
  2229. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  2230. sta_prof_ie[ID_POS],
  2231. sta_prof_ie_size,
  2232. link_frame_maxsize -
  2233. link_frame_currlen);
  2234. }
  2235. ret = QDF_STATUS_E_NOMEM;
  2236. goto mem_free;
  2237. }
  2238. }
  2239. }
  2240. if (((reportingsta_ie + reportingsta_ie_size) -
  2241. frame_iesection) == frame_iesection_len)
  2242. break;
  2243. reportingsta_ie += reportingsta_ie_size;
  2244. ret = util_validate_reportingsta_ie(reportingsta_ie,
  2245. frame_iesection,
  2246. frame_iesection_len);
  2247. if (QDF_IS_STATUS_ERROR(ret))
  2248. goto mem_free;
  2249. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  2250. MIN_IE_LEN;
  2251. }
  2252. /* Go through the remaining unprocessed IEs in STA profile and copy them
  2253. * to the link specific frame. The processed ones are marked with 0 in
  2254. * the first octet. The first octet corresponds to the element ID. In
  2255. * the case of (re)association request, the element with actual ID
  2256. * WLAN_ELEMID_SSID(0) has already been copied to the link specific
  2257. * frame. In the case of (re)association response, it has been verified
  2258. * that the element with actual ID WLAN_ELEMID_SSID(0) is present
  2259. * neither for the reporting STA nor in the STA profile.
  2260. */
  2261. sta_prof_iesection_currpos = sta_prof_iesection;
  2262. sta_prof_iesection_remlen = sta_prof_iesection_len;
  2263. while (sta_prof_iesection_remlen > 0) {
  2264. sta_prof_ie = sta_prof_iesection_currpos;
  2265. ret = util_validate_sta_prof_ie(sta_prof_ie,
  2266. sta_prof_iesection_currpos,
  2267. sta_prof_iesection_remlen);
  2268. if (QDF_IS_STATUS_ERROR(ret))
  2269. goto mem_free;
  2270. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2271. if (!sta_prof_ie[0] || (sta_prof_ie[0] == 0xff && sta_prof_ie[1] > 0 && sta_prof_ie[2] == 0x38)) {
  2272. /* Skip this, since it has already been processed
  2273. * or it is non inheritance IE which is not required
  2274. */
  2275. sta_prof_iesection_currpos += sta_prof_ie_size;
  2276. sta_prof_iesection_remlen -= sta_prof_ie_size;
  2277. continue;
  2278. }
  2279. /* Copy IE from STA profile into link specific frame. */
  2280. if ((link_frame_currpos + sta_prof_ie_size) <=
  2281. (link_frame + link_frame_maxsize)) {
  2282. if (sta_prof_ie[ID_POS] != WLAN_ELEMID_EXTN_ELEM) {
  2283. for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
  2284. if (missing_ie_list[ie_idx] ==
  2285. sta_prof_ie[ID_POS]) {
  2286. missing_ie_list[ie_idx] =
  2287. WLAN_ELEMID_EXTN_ELEM;
  2288. }
  2289. }
  2290. } else {
  2291. for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
  2292. if (missing_ext_ie_list[ie_idx] ==
  2293. sta_prof_ie[IDEXT_POS]) {
  2294. missing_ext_ie_list[ie_idx] =
  2295. WLAN_ELEMID_EXTN_ELEM;
  2296. }
  2297. }
  2298. }
  2299. qdf_mem_copy(link_frame_currpos,
  2300. sta_prof_ie,
  2301. sta_prof_ie_size);
  2302. link_frame_currpos += sta_prof_ie_size;
  2303. link_frame_currlen +=
  2304. sta_prof_ie_size;
  2305. if (reportingsta_ie[ID_POS] ==
  2306. WLAN_ELEMID_EXTN_ELEM) {
  2307. mlo_etrace_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",
  2308. sta_prof_ie[ID_POS],
  2309. sta_prof_ie[IDEXT_POS],
  2310. sta_prof_ie_size);
  2311. } else {
  2312. mlo_etrace_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
  2313. sta_prof_ie[ID_POS],
  2314. sta_prof_ie_size);
  2315. }
  2316. sta_prof_ie[0] = 0;
  2317. } else {
  2318. if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  2319. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  2320. sta_prof_ie[ID_POS],
  2321. sta_prof_ie[IDEXT_POS],
  2322. sta_prof_ie_size,
  2323. link_frame_maxsize -
  2324. link_frame_currlen);
  2325. } else {
  2326. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  2327. sta_prof_ie[ID_POS],
  2328. sta_prof_ie_size,
  2329. link_frame_maxsize -
  2330. link_frame_currlen);
  2331. }
  2332. ret = QDF_STATUS_E_NOMEM;
  2333. goto mem_free;
  2334. }
  2335. sta_prof_iesection_currpos += sta_prof_ie_size;
  2336. sta_prof_iesection_remlen -= sta_prof_ie_size;
  2337. }
  2338. /* Copy missing IEs from probe resp of original link */
  2339. for (ie_idx = 0; ie_idx < missing_ie_len; ie_idx++) {
  2340. if (missing_ie_list[ie_idx] == WLAN_ELEMID_EXTN_ELEM)
  2341. continue;
  2342. secondary_ie = util_find_eid(missing_ie_list[ie_idx],
  2343. bcn_prb_ies_ptr, bcn_prb_ies_len);
  2344. if (!secondary_ie) {
  2345. mlo_etrace_err_rl("IE %u not found in secondary probe resp buffer",
  2346. missing_ie_list[ie_idx]);
  2347. continue;
  2348. }
  2349. if ((link_frame_currpos + secondary_ie[TAG_LEN_POS]) >
  2350. (link_frame + link_frame_maxsize)) {
  2351. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  2352. secondary_ie[ID_POS],
  2353. secondary_ie[TAG_LEN_POS],
  2354. link_frame_maxsize -
  2355. link_frame_currlen);
  2356. continue;
  2357. }
  2358. qdf_mem_copy(link_frame_currpos, secondary_ie,
  2359. secondary_ie[TAG_LEN_POS] + MIN_IE_LEN);
  2360. link_frame_currpos += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2361. link_frame_currlen += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2362. }
  2363. /* Copy missing extn IEs from probe resp of original link */
  2364. for (ie_idx = 0; ie_idx < missing_ext_ie_len; ie_idx++) {
  2365. if (missing_ext_ie_list[ie_idx] == WLAN_ELEMID_EXTN_ELEM)
  2366. continue;
  2367. secondary_ie = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
  2368. missing_ext_ie_list[ie_idx],
  2369. bcn_prb_ies_ptr,
  2370. bcn_prb_ies_len);
  2371. if (!secondary_ie) {
  2372. mlo_etrace_err_rl("Extn IE %u not found in secondary probe resp buffer",
  2373. missing_iext_ie_list[ie_idx]);
  2374. continue;
  2375. }
  2376. if ((link_frame_currpos + secondary_ie[TAG_LEN_POS]) >
  2377. (link_frame + link_frame_maxsize)) {
  2378. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with extn element ID : %u. Required: %zu octets, available: %zu octets",
  2379. secondary_ie[IDEXT_POS],
  2380. secondary_ie[TAG_LEN_POS],
  2381. link_frame_maxsize -
  2382. link_frame_currlen);
  2383. continue;
  2384. }
  2385. qdf_mem_copy(link_frame_currpos, secondary_ie,
  2386. secondary_ie[TAG_LEN_POS] + MIN_IE_LEN);
  2387. link_frame_currpos += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2388. link_frame_currlen += secondary_ie[TAG_LEN_POS] + MIN_IE_LEN;
  2389. }
  2390. /* Copy the link MAC addr */
  2391. link_frame_hdr = (struct wlan_frame_hdr *)link_frame;
  2392. qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
  2393. QDF_MAC_ADDR_SIZE);
  2394. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  2395. QDF_MAC_ADDR_SIZE);
  2396. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr, QDF_MAC_ADDR_SIZE);
  2397. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0;
  2398. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1;
  2399. mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:"
  2400. QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT,
  2401. gen_subtype,
  2402. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3),
  2403. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2),
  2404. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1));
  2405. /* Seq num not used so not populated */
  2406. *link_frame_len = link_frame_currlen;
  2407. qdf_err("Generated ML Probe from assoc resp");
  2408. qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
  2409. link_frame, link_frame_currlen);
  2410. ret = QDF_STATUS_SUCCESS;
  2411. mem_free:
  2412. qdf_mem_free(mlieseqpayload_copy);
  2413. return ret;
  2414. }
  2415. static
  2416. QDF_STATUS util_gen_link_reqrsp_cmn(uint8_t *frame, qdf_size_t frame_len,
  2417. uint8_t subtype,
  2418. uint8_t req_link_id,
  2419. struct qdf_mac_addr link_addr,
  2420. uint8_t *link_frame,
  2421. qdf_size_t link_frame_maxsize,
  2422. qdf_size_t *link_frame_len)
  2423. {
  2424. /* Please see documentation for util_gen_link_assoc_req() and
  2425. * util_gen_link_assoc_resp() for information on the inputs to and
  2426. * output from this helper, since those APIs are essentially wrappers
  2427. * over this helper.
  2428. */
  2429. /* Pointer to Multi-Link element/Multi-Link element fragment sequence */
  2430. uint8_t *mlieseq;
  2431. /* Total length of Multi-Link element sequence (including fragments if
  2432. * any)
  2433. */
  2434. qdf_size_t mlieseqlen;
  2435. /* Variant (i.e. type) of the Multi-Link element */
  2436. enum wlan_ml_variant variant;
  2437. /* Length of the payload of the Multi-Link element (inclusive of
  2438. * fragment payloads if any) without IE headers and element ID extension
  2439. */
  2440. qdf_size_t mlieseqpayloadlen;
  2441. /* Pointer to copy of the payload of the Multi-Link element (inclusive
  2442. * of fragment payloads if any) without IE headers and element ID
  2443. * extension
  2444. */
  2445. uint8_t *mlieseqpayload_copy;
  2446. /* Pointer to start of Link Info within the copy of the payload of the
  2447. * Multi-Link element
  2448. */
  2449. uint8_t *link_info;
  2450. /* Length of the Link Info */
  2451. qdf_size_t link_info_len;
  2452. /* Pointer to the IE section that occurs after the fixed fields in the
  2453. * original frame for the reporting STA.
  2454. */
  2455. uint8_t *frame_iesection;
  2456. /* Offset to the start of the IE section in the original frame for the
  2457. * reporting STA.
  2458. */
  2459. qdf_size_t frame_iesection_offset;
  2460. /* Total length of the IE section in the original frame for the
  2461. * reporting STA.
  2462. */
  2463. qdf_size_t frame_iesection_len;
  2464. /* Pointer to the IEEE802.11 frame header in the link specific frame
  2465. * being generated for the reported STA.
  2466. */
  2467. struct wlan_frame_hdr *link_frame_hdr;
  2468. /* Current position in the link specific frame being generated for the
  2469. * reported STA.
  2470. */
  2471. uint8_t *link_frame_currpos;
  2472. /* Current length of the link specific frame being generated for the
  2473. * reported STA.
  2474. */
  2475. qdf_size_t link_frame_currlen;
  2476. /* Pointer to IE for reporting STA */
  2477. const uint8_t *reportingsta_ie;
  2478. /* Total size of IE for reporting STA, inclusive of the element header
  2479. */
  2480. qdf_size_t reportingsta_ie_size;
  2481. /* Pointer to current position in STA profile */
  2482. uint8_t *sta_prof_currpos;
  2483. /* Remaining length of STA profile */
  2484. qdf_size_t sta_prof_remlen;
  2485. /* Pointer to start of IE section in STA profile that occurs after fixed
  2486. * fields.
  2487. */
  2488. uint8_t *sta_prof_iesection;
  2489. /* Total length of IE section in STA profile */
  2490. qdf_size_t sta_prof_iesection_len;
  2491. /* Pointer to current position being processed in IE section in STA
  2492. * profile.
  2493. */
  2494. uint8_t *sta_prof_iesection_currpos;
  2495. /* Remaining length of IE section in STA profile */
  2496. qdf_size_t sta_prof_iesection_remlen;
  2497. /* Pointer to IE in STA profile, that occurs within IE section */
  2498. uint8_t *sta_prof_ie;
  2499. /* Total size of IE in STA profile, inclusive of the element header */
  2500. qdf_size_t sta_prof_ie_size;
  2501. /* Pointer to element ID list in Non-Inheritance IE */
  2502. uint8_t *ninherit_elemlist;
  2503. /* Length of element ID list in Non-Inheritance IE */
  2504. qdf_size_t ninherit_elemlist_len;
  2505. /* Pointer to element ID extension list in Non-Inheritance IE */
  2506. uint8_t *ninherit_elemextlist;
  2507. /* Length of element ID extension list in Non-Inheritance IE */
  2508. qdf_size_t ninherit_elemextlist_len;
  2509. /* Whether a given IE is in a non-inheritance list */
  2510. bool is_in_noninheritlist;
  2511. /* Whether MAC address of reported STA is valid */
  2512. bool is_reportedmacaddr_valid;
  2513. /* MAC address of reported STA */
  2514. struct qdf_mac_addr reportedmacaddr;
  2515. /* Pointer to per-STA profile */
  2516. uint8_t *persta_prof;
  2517. /* Length of the containing buffer which starts with the per-STA profile
  2518. */
  2519. qdf_size_t persta_prof_bufflen;
  2520. /* Other variables for temporary purposes */
  2521. /* Variable into which API for determining fragment information will
  2522. * indicate whether the element is the start of a fragment sequence or
  2523. * not.
  2524. */
  2525. bool is_elemfragseq;
  2526. /* De-fragmented payload length returned by API for element
  2527. * defragmentation.
  2528. */
  2529. qdf_size_t defragpayload_len;
  2530. /* Pointer to Beacon interval in STA info field */
  2531. uint16_t beaconinterval;
  2532. /* Whether Beacon interval value valid */
  2533. bool is_beaconinterval_valid;
  2534. /* TSF timer of the reporting AP */
  2535. uint64_t tsf;
  2536. /* TSF offset of the reproted AP */
  2537. uint64_t tsfoffset;
  2538. /* TSF offset value valid */
  2539. bool is_tsfoffset_valid;
  2540. /* If Complete Profile or not*/
  2541. bool is_completeprofile;
  2542. qdf_size_t tmplen;
  2543. QDF_STATUS ret;
  2544. uint8_t linkid = 0xFF;
  2545. if (!frame) {
  2546. mlo_err("Pointer to original frame is NULL");
  2547. return QDF_STATUS_E_NULL_VALUE;
  2548. }
  2549. if (!frame_len) {
  2550. mlo_err("Length of original frame is zero");
  2551. return QDF_STATUS_E_INVAL;
  2552. }
  2553. if ((subtype != WLAN_FC0_STYPE_ASSOC_REQ) &&
  2554. (subtype != WLAN_FC0_STYPE_REASSOC_REQ) &&
  2555. (subtype != WLAN_FC0_STYPE_ASSOC_RESP) &&
  2556. (subtype != WLAN_FC0_STYPE_REASSOC_RESP) &&
  2557. (subtype != WLAN_FC0_STYPE_PROBE_RESP)) {
  2558. mlo_err("802.11 frame subtype %u is invalid", subtype);
  2559. return QDF_STATUS_E_INVAL;
  2560. }
  2561. if (!link_frame) {
  2562. mlo_err("Pointer to secondary link specific frame is NULL");
  2563. return QDF_STATUS_E_NULL_VALUE;
  2564. }
  2565. if (!link_frame_maxsize) {
  2566. mlo_err("Maximum size of secondary link specific frame is zero");
  2567. return QDF_STATUS_E_INVAL;
  2568. }
  2569. if (!link_frame_len) {
  2570. mlo_err("Pointer to populated length of secondary link specific frame is NULL");
  2571. return QDF_STATUS_E_NULL_VALUE;
  2572. }
  2573. frame_iesection_offset = 0;
  2574. if (subtype == WLAN_FC0_STYPE_ASSOC_REQ) {
  2575. frame_iesection_offset = WLAN_ASSOC_REQ_IES_OFFSET;
  2576. } else if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
  2577. frame_iesection_offset = WLAN_REASSOC_REQ_IES_OFFSET;
  2578. } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
  2579. frame_iesection_offset = WLAN_PROBE_RESP_IES_OFFSET;
  2580. if (frame_len < WLAN_TIMESTAMP_LEN) {
  2581. mlo_err("Frame length %zu is smaller than required timestamp length",
  2582. frame_len);
  2583. return QDF_STATUS_E_INVAL;
  2584. }
  2585. qdf_mem_copy(&tsf, frame, WLAN_TIMESTAMP_LEN);
  2586. tsf = qdf_le64_to_cpu(tsf);
  2587. } else {
  2588. /* This is a (re)association response */
  2589. frame_iesection_offset = WLAN_ASSOC_RSP_IES_OFFSET;
  2590. }
  2591. if (frame_len < frame_iesection_offset) {
  2592. /* The caller is supposed to have confirmed that this is a valid
  2593. * frame containing a Multi-Link element. Hence we treat this as
  2594. * a case of invalid argument being passed to us.
  2595. */
  2596. mlo_err("Frame length %zu is smaller than the IE section offset %zu for subtype %u",
  2597. frame_len, frame_iesection_offset, subtype);
  2598. return QDF_STATUS_E_INVAL;
  2599. }
  2600. frame_iesection_len = frame_len - frame_iesection_offset;
  2601. if (frame_iesection_len == 0) {
  2602. /* The caller is supposed to have confirmed that this is a valid
  2603. * frame containing a Multi-Link element. Hence we treat this as
  2604. * a case of invalid argument being passed to us.
  2605. */
  2606. mlo_err("No space left in frame for IE section");
  2607. return QDF_STATUS_E_INVAL;
  2608. }
  2609. frame_iesection = frame + frame_iesection_offset;
  2610. mlieseq = NULL;
  2611. mlieseqlen = 0;
  2612. ret = util_find_mlie(frame_iesection, frame_iesection_len, &mlieseq,
  2613. &mlieseqlen);
  2614. if (QDF_IS_STATUS_ERROR(ret))
  2615. return ret;
  2616. if (!mlieseq) {
  2617. /* The caller is supposed to have confirmed that a Multi-Link
  2618. * element is present in the frame. Hence we treat this as a
  2619. * case of invalid argument being passed to us.
  2620. */
  2621. mlo_err("Invalid original frame since no Multi-Link element found");
  2622. return QDF_STATUS_E_INVAL;
  2623. }
  2624. /* Sanity check the Multi-Link element sequence length */
  2625. if (!mlieseqlen) {
  2626. mlo_err("Length of Multi-Link element sequence is zero. Investigate.");
  2627. return QDF_STATUS_E_FAILURE;
  2628. }
  2629. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  2630. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  2631. mlieseqlen, sizeof(struct wlan_ie_multilink));
  2632. return QDF_STATUS_E_PROTO;
  2633. }
  2634. ret = util_get_mlie_variant(mlieseq, mlieseqlen, (int *)&variant);
  2635. if (QDF_IS_STATUS_ERROR(ret))
  2636. return ret;
  2637. if (variant != WLAN_ML_VARIANT_BASIC) {
  2638. mlo_err_rl("Unexpected variant %u of Multi-Link element.",
  2639. variant);
  2640. return QDF_STATUS_E_PROTO;
  2641. }
  2642. mlieseqpayloadlen = 0;
  2643. tmplen = 0;
  2644. is_elemfragseq = false;
  2645. ret = wlan_get_elem_fragseq_info(mlieseq,
  2646. mlieseqlen,
  2647. &is_elemfragseq,
  2648. &tmplen,
  2649. &mlieseqpayloadlen);
  2650. if (QDF_IS_STATUS_ERROR(ret))
  2651. return ret;
  2652. if (is_elemfragseq) {
  2653. if (tmplen != mlieseqlen) {
  2654. 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",
  2655. tmplen, mlieseqlen);
  2656. return QDF_STATUS_E_FAILURE;
  2657. }
  2658. if (!mlieseqpayloadlen) {
  2659. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  2660. return QDF_STATUS_E_FAILURE;
  2661. }
  2662. mlo_debug("ML IE fragment sequence found with payload len %zu",
  2663. mlieseqpayloadlen);
  2664. } else {
  2665. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  2666. 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",
  2667. mlieseqlen,
  2668. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  2669. return QDF_STATUS_E_FAILURE;
  2670. }
  2671. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  2672. }
  2673. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  2674. if (!mlieseqpayload_copy) {
  2675. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  2676. ret = QDF_STATUS_E_NOMEM;
  2677. goto mem_free;
  2678. }
  2679. if (is_elemfragseq) {
  2680. ret = wlan_defrag_elem_fragseq(false,
  2681. mlieseq,
  2682. mlieseqlen,
  2683. mlieseqpayload_copy,
  2684. mlieseqpayloadlen,
  2685. &defragpayload_len);
  2686. if (QDF_IS_STATUS_ERROR(ret))
  2687. goto mem_free;
  2688. if (defragpayload_len != mlieseqpayloadlen) {
  2689. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  2690. defragpayload_len, mlieseqpayloadlen);
  2691. ret = QDF_STATUS_E_FAILURE;
  2692. goto mem_free;
  2693. }
  2694. } else {
  2695. qdf_mem_copy(mlieseqpayload_copy,
  2696. mlieseq + sizeof(struct ie_header) + 1,
  2697. mlieseqpayloadlen);
  2698. }
  2699. link_info = NULL;
  2700. link_info_len = 0;
  2701. ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
  2702. mlieseqpayloadlen,
  2703. &link_info,
  2704. &link_info_len);
  2705. if (QDF_IS_STATUS_ERROR(ret))
  2706. goto mem_free;
  2707. /* As per the standard, the sender must include Link Info for
  2708. * association request/response. Throw an error if we are unable to
  2709. * obtain this.
  2710. */
  2711. if (!link_info) {
  2712. mlo_err_rl("Unable to successfully obtain Link Info");
  2713. ret = QDF_STATUS_E_PROTO;
  2714. goto mem_free;
  2715. }
  2716. /* Note: We may have a future change to skip subelements which are not
  2717. * Per-STA Profile, handle more than two links in MLO, handle cases
  2718. * where we unexpectedly find more Per-STA Profiles than expected, etc.
  2719. */
  2720. persta_prof = NULL;
  2721. persta_prof_bufflen = 0;
  2722. ret = util_find_bvmlie_persta_prof_for_linkid(req_link_id,
  2723. link_info,
  2724. link_info_len,
  2725. &persta_prof,
  2726. &persta_prof_bufflen);
  2727. if (QDF_IS_STATUS_ERROR(ret)) {
  2728. mlo_err_rl("Per STA profile not found for link id %d",
  2729. req_link_id);
  2730. goto mem_free;
  2731. }
  2732. sta_prof_remlen = 0;
  2733. sta_prof_currpos = NULL;
  2734. is_reportedmacaddr_valid = false;
  2735. is_beaconinterval_valid = false;
  2736. is_completeprofile = false;
  2737. is_tsfoffset_valid = false;
  2738. /* Parse per-STA profile */
  2739. ret = util_parse_bvmlie_perstaprofile_stactrl(persta_prof +
  2740. sizeof(struct subelem_header),
  2741. persta_prof_bufflen,
  2742. &linkid,
  2743. &beaconinterval,
  2744. &is_beaconinterval_valid,
  2745. &tsfoffset,
  2746. &is_tsfoffset_valid,
  2747. &is_completeprofile,
  2748. &is_reportedmacaddr_valid,
  2749. &reportedmacaddr,
  2750. true,
  2751. &sta_prof_currpos,
  2752. &sta_prof_remlen,
  2753. NULL,
  2754. NULL);
  2755. if (QDF_IS_STATUS_ERROR(ret))
  2756. goto mem_free;
  2757. if (subtype == WLAN_FC0_STYPE_PROBE_RESP && !is_completeprofile) {
  2758. mlo_err("Complete profile information is not present in per-STA profile of probe response frame");
  2759. ret = QDF_STATUS_E_NOSUPPORT;
  2760. goto mem_free;
  2761. }
  2762. /* We double check for a NULL STA Profile, though the helper function
  2763. * above would have taken care of this. We need to get a non-NULL STA
  2764. * profile, because we need to get at least the expected fixed fields,
  2765. * even if there is an (improbable) total inheritance.
  2766. */
  2767. if (!sta_prof_currpos) {
  2768. mlo_err_rl("STA profile is NULL");
  2769. ret = QDF_STATUS_E_PROTO;
  2770. goto mem_free;
  2771. }
  2772. /* As per the standard, the sender sets the MAC address in the per-STA
  2773. * profile in association request/response. Without this, we cannot
  2774. * generate the link specific frame.
  2775. */
  2776. if (!is_reportedmacaddr_valid) {
  2777. mlo_err_rl("Unable to get MAC address from per-STA profile");
  2778. ret = QDF_STATUS_E_PROTO;
  2779. goto mem_free;
  2780. }
  2781. link_frame_currpos = link_frame;
  2782. *link_frame_len = 0;
  2783. link_frame_currlen = 0;
  2784. if (link_frame_maxsize < WLAN_MAC_HDR_LEN_3A) {
  2785. mlo_err("Insufficient space in link specific frame for 802.11 header. Required: %u octets, available: %zu octets",
  2786. WLAN_MAC_HDR_LEN_3A, link_frame_maxsize);
  2787. ret = QDF_STATUS_E_NOMEM;
  2788. goto mem_free;
  2789. }
  2790. link_frame_currpos += WLAN_MAC_HDR_LEN_3A;
  2791. link_frame_currlen += WLAN_MAC_HDR_LEN_3A;
  2792. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  2793. (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
  2794. mlo_debug("Populating fixed fields for (re)assoc req in link specific frame");
  2795. if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) {
  2796. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u",
  2797. sta_prof_remlen,
  2798. WLAN_CAPABILITYINFO_LEN);
  2799. ret = QDF_STATUS_E_PROTO;
  2800. goto mem_free;
  2801. }
  2802. /* Capability information is specific to the link. Copy this
  2803. * from the STA profile.
  2804. */
  2805. if ((link_frame_maxsize - link_frame_currlen) <
  2806. WLAN_CAPABILITYINFO_LEN) {
  2807. mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets",
  2808. WLAN_CAPABILITYINFO_LEN,
  2809. (link_frame_maxsize - link_frame_currlen));
  2810. ret = QDF_STATUS_E_NOMEM;
  2811. goto mem_free;
  2812. }
  2813. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  2814. WLAN_CAPABILITYINFO_LEN);
  2815. link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
  2816. link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
  2817. sta_prof_currpos += WLAN_CAPABILITYINFO_LEN;
  2818. sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN;
  2819. /* Listen Interval is common between all links. Copy this from
  2820. * the reporting section of the frame.
  2821. */
  2822. if ((link_frame_maxsize - link_frame_currlen) <
  2823. WLAN_LISTENINTERVAL_LEN) {
  2824. mlo_err("Insufficient space in link specific frame for Listen Interval field. Required: %u octets, available: %zu octets",
  2825. WLAN_LISTENINTERVAL_LEN,
  2826. (link_frame_maxsize - link_frame_currlen));
  2827. ret = QDF_STATUS_E_NOMEM;
  2828. goto mem_free;
  2829. }
  2830. qdf_mem_copy(link_frame_currpos,
  2831. frame + WLAN_CAPABILITYINFO_LEN,
  2832. WLAN_LISTENINTERVAL_LEN);
  2833. link_frame_currpos += WLAN_LISTENINTERVAL_LEN;
  2834. link_frame_currlen += WLAN_LISTENINTERVAL_LEN;
  2835. if (subtype == WLAN_FC0_STYPE_REASSOC_REQ) {
  2836. /* Current AP address is common between all links. Copy
  2837. * this from the reporting section of the frame.
  2838. */
  2839. if ((link_frame_maxsize - link_frame_currlen) <
  2840. QDF_MAC_ADDR_SIZE) {
  2841. mlo_err("Insufficient space in link specific frame for current AP address. Required: %u octets, available: %zu octets",
  2842. QDF_MAC_ADDR_SIZE,
  2843. (link_frame_maxsize -
  2844. link_frame_currlen));
  2845. ret = QDF_STATUS_E_NOMEM;
  2846. goto mem_free;
  2847. }
  2848. qdf_mem_copy(link_frame_currpos,
  2849. frame + WLAN_CAPABILITYINFO_LEN +
  2850. WLAN_LISTENINTERVAL_LEN,
  2851. QDF_MAC_ADDR_SIZE);
  2852. link_frame_currpos += QDF_MAC_ADDR_SIZE;
  2853. link_frame_currlen += QDF_MAC_ADDR_SIZE;
  2854. mlo_debug("Reassoc req: Added Current AP address field (%u octets) to link specific frame",
  2855. QDF_MAC_ADDR_SIZE);
  2856. }
  2857. } else if (subtype == WLAN_FC0_STYPE_ASSOC_RESP ||
  2858. subtype == WLAN_FC0_STYPE_REASSOC_RESP) {
  2859. /* This is a (re)association response */
  2860. mlo_debug("Populating fixed fields for (re)assoc resp in link specific frame");
  2861. if (sta_prof_remlen <
  2862. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
  2863. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info + length of Status Code %u",
  2864. sta_prof_remlen,
  2865. WLAN_CAPABILITYINFO_LEN +
  2866. WLAN_STATUSCODE_LEN);
  2867. ret = QDF_STATUS_E_PROTO;
  2868. goto mem_free;
  2869. }
  2870. /* Capability information and Status Code are specific to the
  2871. * link. Copy these from the STA profile.
  2872. */
  2873. if ((link_frame_maxsize - link_frame_currlen) <
  2874. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN)) {
  2875. mlo_err("Insufficient space in link specific frame for Capability Info and Status Code fields. Required: %u octets, available: %zu octets",
  2876. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN,
  2877. (link_frame_maxsize - link_frame_currlen));
  2878. ret = QDF_STATUS_E_NOMEM;
  2879. goto mem_free;
  2880. }
  2881. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  2882. (WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN));
  2883. link_frame_currpos += (WLAN_CAPABILITYINFO_LEN +
  2884. WLAN_STATUSCODE_LEN);
  2885. link_frame_currlen += (WLAN_CAPABILITYINFO_LEN +
  2886. WLAN_STATUSCODE_LEN);
  2887. mlo_debug("Added Capability Info and Status Code fields (%u octets) to link specific frame",
  2888. WLAN_CAPABILITYINFO_LEN + WLAN_STATUSCODE_LEN);
  2889. sta_prof_currpos += (WLAN_CAPABILITYINFO_LEN +
  2890. WLAN_STATUSCODE_LEN);
  2891. sta_prof_remlen -= (WLAN_CAPABILITYINFO_LEN +
  2892. WLAN_STATUSCODE_LEN);
  2893. /* AID is common between all links. Copy this from the original
  2894. * frame.
  2895. */
  2896. if ((link_frame_maxsize - link_frame_currlen) < WLAN_AID_LEN) {
  2897. mlo_err("Insufficient space in link specific frame for AID field. Required: %u octets, available: %zu octets",
  2898. WLAN_AID_LEN,
  2899. (link_frame_maxsize - link_frame_currlen));
  2900. ret = QDF_STATUS_E_NOMEM;
  2901. goto mem_free;
  2902. }
  2903. qdf_mem_copy(link_frame_currpos,
  2904. frame + WLAN_CAPABILITYINFO_LEN +
  2905. WLAN_STATUSCODE_LEN,
  2906. WLAN_AID_LEN);
  2907. link_frame_currpos += WLAN_AID_LEN;
  2908. link_frame_currlen += WLAN_AID_LEN;
  2909. mlo_debug("Added AID field (%u octets) to link specific frame",
  2910. WLAN_AID_LEN);
  2911. } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
  2912. /* This is a probe response */
  2913. mlo_debug("Populating fixed fields for probe response in link specific frame");
  2914. if ((link_frame_maxsize - link_frame_currlen) <
  2915. WLAN_TIMESTAMP_LEN) {
  2916. mlo_err("Insufficient space in link specific frame for Timestamp Info field. Required: %u octets, available: %zu octets",
  2917. WLAN_TIMESTAMP_LEN,
  2918. (link_frame_maxsize - link_frame_currlen));
  2919. ret = QDF_STATUS_E_NOMEM;
  2920. goto mem_free;
  2921. }
  2922. /* Per spec 11be_D2.1.1, the TSF Offset subfield of the STA Info
  2923. * field indicates the offset (Toffset)between the TSF timer of
  2924. * the reported AP (TA) and the TSF timer of the reporting
  2925. * AP (TB) and is encoded as a 2s complement signed integer
  2926. * with units of 2 µs. Toffset is calculated as
  2927. * Toffset= Floor((TA – TB)/2).
  2928. */
  2929. if (is_tsfoffset_valid)
  2930. tsf += tsfoffset * 2;
  2931. qdf_mem_copy(link_frame_currpos, &tsf, WLAN_TIMESTAMP_LEN);
  2932. link_frame_currpos += WLAN_TIMESTAMP_LEN;
  2933. link_frame_currlen += WLAN_TIMESTAMP_LEN;
  2934. if (!is_beaconinterval_valid) {
  2935. mlo_err_rl("Beacon interval information not present in STA info field of per-STA profile");
  2936. ret = QDF_STATUS_E_PROTO;
  2937. goto mem_free;
  2938. }
  2939. /* Beacon Interval information copy this from
  2940. * the STA info field.
  2941. */
  2942. if ((link_frame_maxsize - link_frame_currlen) <
  2943. WLAN_BEACONINTERVAL_LEN) {
  2944. mlo_err("Insufficient space in link specific frame for Beacon Interval Info field. Required: %u octets, available: %zu octets",
  2945. WLAN_BEACONINTERVAL_LEN,
  2946. (link_frame_maxsize - link_frame_currlen));
  2947. ret = QDF_STATUS_E_NOMEM;
  2948. goto mem_free;
  2949. }
  2950. qdf_mem_copy(link_frame_currpos, &beaconinterval,
  2951. WLAN_BEACONINTERVAL_LEN);
  2952. link_frame_currpos += WLAN_BEACONINTERVAL_LEN;
  2953. link_frame_currlen += WLAN_BEACONINTERVAL_LEN;
  2954. if (sta_prof_remlen < WLAN_CAPABILITYINFO_LEN) {
  2955. mlo_err_rl("Remaining length of STA profile %zu octets is less than length of Capability Info %u",
  2956. sta_prof_remlen,
  2957. WLAN_CAPABILITYINFO_LEN);
  2958. ret = QDF_STATUS_E_PROTO;
  2959. goto mem_free;
  2960. }
  2961. /* Capability information is specific to the link. Copy this
  2962. * from the STA profile.
  2963. */
  2964. if ((link_frame_maxsize - link_frame_currlen) <
  2965. WLAN_CAPABILITYINFO_LEN) {
  2966. mlo_err("Insufficient space in link specific frame for Capability Info field. Required: %u octets, available: %zu octets",
  2967. WLAN_CAPABILITYINFO_LEN,
  2968. (link_frame_maxsize - link_frame_currlen));
  2969. ret = QDF_STATUS_E_NOMEM;
  2970. goto mem_free;
  2971. }
  2972. qdf_mem_copy(link_frame_currpos, sta_prof_currpos,
  2973. WLAN_CAPABILITYINFO_LEN);
  2974. link_frame_currpos += WLAN_CAPABILITYINFO_LEN;
  2975. link_frame_currlen += WLAN_CAPABILITYINFO_LEN;
  2976. sta_prof_currpos += WLAN_CAPABILITYINFO_LEN;
  2977. sta_prof_remlen -= WLAN_CAPABILITYINFO_LEN;
  2978. }
  2979. sta_prof_iesection = sta_prof_currpos;
  2980. sta_prof_iesection_len = sta_prof_remlen;
  2981. /* Populate non-inheritance lists if applicable */
  2982. ninherit_elemlist_len = 0;
  2983. ninherit_elemlist = NULL;
  2984. ninherit_elemextlist_len = 0;
  2985. ninherit_elemextlist = NULL;
  2986. ret = util_get_noninheritlists(sta_prof_iesection,
  2987. sta_prof_iesection_len,
  2988. &ninherit_elemlist,
  2989. &ninherit_elemlist_len,
  2990. &ninherit_elemextlist,
  2991. &ninherit_elemextlist_len);
  2992. if (QDF_IS_STATUS_ERROR(ret))
  2993. goto mem_free;
  2994. /* Go through IEs of the reporting STA, and those in STA profile, merge
  2995. * them into link_frame (except for elements in the Non-Inheritance
  2996. * list).
  2997. *
  2998. * Note: Currently, only 2-link MLO is supported here. We may have a
  2999. * future change to expand to more links.
  3000. */
  3001. reportingsta_ie = util_find_eid(WLAN_ELEMID_SSID, frame_iesection,
  3002. frame_iesection_len);
  3003. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  3004. (subtype == WLAN_FC0_STYPE_REASSOC_REQ) ||
  3005. (subtype == WLAN_FC0_STYPE_PROBE_RESP)) {
  3006. /* Sanity check that the SSID element is present for the
  3007. * reporting STA. There is no stipulation in the standard for
  3008. * the STA profile in this regard, so we do not check the STA
  3009. * profile for the SSID element.
  3010. */
  3011. if (!reportingsta_ie) {
  3012. mlo_err_rl("SSID element not found in reporting STA of the frame.");
  3013. ret = QDF_STATUS_E_PROTO;
  3014. goto mem_free;
  3015. }
  3016. } else {
  3017. /* This is a (re)association response. Sanity check that the
  3018. * SSID element is present neither for the reporting STA nor in
  3019. * the STA profile.
  3020. */
  3021. if (reportingsta_ie) {
  3022. mlo_err_rl("SSID element found for reporting STA for (re)association response. It should not be present.");
  3023. ret = QDF_STATUS_E_PROTO;
  3024. goto mem_free;
  3025. }
  3026. sta_prof_ie = util_find_eid(WLAN_ELEMID_SSID,
  3027. sta_prof_iesection,
  3028. sta_prof_iesection_len);
  3029. if (sta_prof_ie) {
  3030. mlo_err_rl("SSID element found in STA profile for (re)association response. It should not be present.");
  3031. ret = QDF_STATUS_E_PROTO;
  3032. goto mem_free;
  3033. }
  3034. }
  3035. reportingsta_ie = reportingsta_ie ? reportingsta_ie : frame_iesection;
  3036. ret = util_validate_reportingsta_ie(reportingsta_ie, frame_iesection,
  3037. frame_iesection_len);
  3038. if (QDF_IS_STATUS_ERROR(ret))
  3039. goto mem_free;
  3040. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] + MIN_IE_LEN;
  3041. while (((reportingsta_ie + reportingsta_ie_size) - frame_iesection)
  3042. <= frame_iesection_len) {
  3043. /* Skip Multi-Link element */
  3044. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) &&
  3045. (reportingsta_ie[IDEXT_POS] ==
  3046. WLAN_EXTN_ELEMID_MULTI_LINK)) {
  3047. if (((reportingsta_ie + reportingsta_ie_size) -
  3048. frame_iesection) == frame_iesection_len)
  3049. break;
  3050. /* Add BV ML IE for link specific probe response */
  3051. if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
  3052. ret = util_add_mlie_for_prb_rsp_gen(
  3053. reportingsta_ie,
  3054. reportingsta_ie[TAG_LEN_POS],
  3055. &link_frame_currpos,
  3056. &link_frame_currlen,
  3057. link_frame_maxsize,
  3058. linkid);
  3059. if (QDF_IS_STATUS_ERROR(ret))
  3060. goto mem_free;
  3061. }
  3062. reportingsta_ie += reportingsta_ie_size;
  3063. ret = util_validate_reportingsta_ie(reportingsta_ie,
  3064. frame_iesection,
  3065. frame_iesection_len);
  3066. if (QDF_IS_STATUS_ERROR(ret))
  3067. goto mem_free;
  3068. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  3069. MIN_IE_LEN;
  3070. continue;
  3071. }
  3072. sta_prof_ie = NULL;
  3073. sta_prof_ie_size = 0;
  3074. if (sta_prof_iesection_len) {
  3075. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  3076. sta_prof_ie = (uint8_t *)util_find_extn_eid(reportingsta_ie[ID_POS],
  3077. reportingsta_ie[IDEXT_POS],
  3078. sta_prof_iesection,
  3079. sta_prof_iesection_len);
  3080. } else {
  3081. sta_prof_ie = (uint8_t *)util_find_eid(reportingsta_ie[ID_POS],
  3082. sta_prof_iesection,
  3083. sta_prof_iesection_len);
  3084. }
  3085. }
  3086. if (!sta_prof_ie) {
  3087. /* IE is present for reporting STA, but not in STA
  3088. * profile.
  3089. */
  3090. is_in_noninheritlist = false;
  3091. ret = util_eval_ie_in_noninheritlist((uint8_t *)reportingsta_ie,
  3092. reportingsta_ie_size,
  3093. ninherit_elemlist,
  3094. ninherit_elemlist_len,
  3095. ninherit_elemextlist,
  3096. ninherit_elemextlist_len,
  3097. &is_in_noninheritlist);
  3098. if (QDF_IS_STATUS_ERROR(ret))
  3099. goto mem_free;
  3100. if (!is_in_noninheritlist) {
  3101. if ((link_frame_currpos +
  3102. reportingsta_ie_size) <=
  3103. (link_frame + link_frame_maxsize)) {
  3104. qdf_mem_copy(link_frame_currpos,
  3105. reportingsta_ie,
  3106. reportingsta_ie_size);
  3107. link_frame_currpos +=
  3108. reportingsta_ie_size;
  3109. link_frame_currlen +=
  3110. reportingsta_ie_size;
  3111. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  3112. mlo_etrace_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",
  3113. reportingsta_ie[ID_POS],
  3114. reportingsta_ie[IDEXT_POS],
  3115. reportingsta_ie_size);
  3116. } else {
  3117. mlo_etrace_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",
  3118. reportingsta_ie[ID_POS],
  3119. reportingsta_ie_size);
  3120. }
  3121. } else {
  3122. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  3123. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  3124. reportingsta_ie[ID_POS],
  3125. reportingsta_ie[IDEXT_POS],
  3126. reportingsta_ie_size,
  3127. link_frame_maxsize -
  3128. link_frame_currlen);
  3129. } else {
  3130. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  3131. reportingsta_ie[ID_POS],
  3132. reportingsta_ie_size,
  3133. link_frame_maxsize -
  3134. link_frame_currlen);
  3135. }
  3136. ret = QDF_STATUS_E_NOMEM;
  3137. goto mem_free;
  3138. }
  3139. } else {
  3140. if (reportingsta_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  3141. mlo_etrace_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.",
  3142. reportingsta_ie[ID_POS],
  3143. reportingsta_ie[IDEXT_POS],
  3144. reportingsta_ie_size);
  3145. } else {
  3146. mlo_etrace_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.",
  3147. reportingsta_ie[ID_POS],
  3148. reportingsta_ie_size);
  3149. }
  3150. }
  3151. } else {
  3152. /* IE is present for reporting STA and also in STA
  3153. * profile, copy from STA profile and flag the IE in STA
  3154. * profile as copied (by setting EID field to 0). The
  3155. * SSID element (with EID 0) is processed first to
  3156. * enable this. For vendor IE, compare OUI + type +
  3157. * subType to determine if they are the same IE.
  3158. */
  3159. /* Note: This may be revisited in a future change, to
  3160. * adhere to provisions in the standard for multiple
  3161. * occurrences of a given element ID/extension element
  3162. * ID.
  3163. */
  3164. ret = util_validate_sta_prof_ie(sta_prof_ie,
  3165. sta_prof_iesection,
  3166. sta_prof_iesection_len);
  3167. if (QDF_IS_STATUS_ERROR(ret))
  3168. goto mem_free;
  3169. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] +
  3170. MIN_IE_LEN;
  3171. sta_prof_iesection_remlen =
  3172. sta_prof_iesection_len -
  3173. (sta_prof_ie - sta_prof_iesection);
  3174. if ((reportingsta_ie[ID_POS] == WLAN_ELEMID_VENDOR) &&
  3175. (sta_prof_iesection_remlen >= MIN_VENDOR_TAG_LEN)) {
  3176. /* If Vendor IE also presents in STA profile,
  3177. * then ignore the Vendor IE which is for
  3178. * reporting STA. It only needs to copy Vendor
  3179. * IE from STA profile to link specific frame.
  3180. * The copy happens when going through the
  3181. * remaining IEs.
  3182. */
  3183. ;
  3184. } else {
  3185. /* Copy IE from STA profile into link specific
  3186. * frame.
  3187. */
  3188. if ((link_frame_currpos + sta_prof_ie_size) <=
  3189. (link_frame + link_frame_maxsize)) {
  3190. qdf_mem_copy(link_frame_currpos,
  3191. sta_prof_ie,
  3192. sta_prof_ie_size);
  3193. link_frame_currpos += sta_prof_ie_size;
  3194. link_frame_currlen +=
  3195. sta_prof_ie_size;
  3196. if (reportingsta_ie[ID_POS] ==
  3197. WLAN_ELEMID_EXTN_ELEM) {
  3198. mlo_etrace_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",
  3199. sta_prof_ie[ID_POS],
  3200. sta_prof_ie[IDEXT_POS],
  3201. sta_prof_ie_size);
  3202. } else {
  3203. mlo_etrace_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",
  3204. sta_prof_ie[ID_POS],
  3205. sta_prof_ie_size);
  3206. }
  3207. sta_prof_ie[0] = 0;
  3208. } else {
  3209. if (sta_prof_ie[ID_POS] ==
  3210. WLAN_ELEMID_EXTN_ELEM) {
  3211. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  3212. sta_prof_ie[ID_POS],
  3213. sta_prof_ie[IDEXT_POS],
  3214. sta_prof_ie_size,
  3215. link_frame_maxsize -
  3216. link_frame_currlen);
  3217. } else {
  3218. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  3219. sta_prof_ie[ID_POS],
  3220. sta_prof_ie_size,
  3221. link_frame_maxsize -
  3222. link_frame_currlen);
  3223. }
  3224. ret = QDF_STATUS_E_NOMEM;
  3225. goto mem_free;
  3226. }
  3227. }
  3228. }
  3229. if (((reportingsta_ie + reportingsta_ie_size) -
  3230. frame_iesection) == frame_iesection_len)
  3231. break;
  3232. reportingsta_ie += reportingsta_ie_size;
  3233. ret = util_validate_reportingsta_ie(reportingsta_ie,
  3234. frame_iesection,
  3235. frame_iesection_len);
  3236. if (QDF_IS_STATUS_ERROR(ret))
  3237. goto mem_free;
  3238. reportingsta_ie_size = reportingsta_ie[TAG_LEN_POS] +
  3239. MIN_IE_LEN;
  3240. }
  3241. /* Go through the remaining unprocessed IEs in STA profile and copy them
  3242. * to the link specific frame. The processed ones are marked with 0 in
  3243. * the first octet. The first octet corresponds to the element ID. In
  3244. * the case of (re)association request, the element with actual ID
  3245. * WLAN_ELEMID_SSID(0) has already been copied to the link specific
  3246. * frame. In the case of (re)association response, it has been verified
  3247. * that the element with actual ID WLAN_ELEMID_SSID(0) is present
  3248. * neither for the reporting STA nor in the STA profile.
  3249. */
  3250. sta_prof_iesection_currpos = sta_prof_iesection;
  3251. sta_prof_iesection_remlen = sta_prof_iesection_len;
  3252. while (sta_prof_iesection_remlen > 0) {
  3253. sta_prof_ie = sta_prof_iesection_currpos;
  3254. ret = util_validate_sta_prof_ie(sta_prof_ie,
  3255. sta_prof_iesection_currpos,
  3256. sta_prof_iesection_remlen);
  3257. if (QDF_IS_STATUS_ERROR(ret))
  3258. goto mem_free;
  3259. sta_prof_ie_size = sta_prof_ie[TAG_LEN_POS] + MIN_IE_LEN;
  3260. if (!sta_prof_ie[0]) {
  3261. /* Skip this, since it has already been processed */
  3262. sta_prof_iesection_currpos += sta_prof_ie_size;
  3263. sta_prof_iesection_remlen -= sta_prof_ie_size;
  3264. continue;
  3265. }
  3266. /* Copy IE from STA profile into link specific frame. */
  3267. if ((link_frame_currpos + sta_prof_ie_size) <=
  3268. (link_frame + link_frame_maxsize)) {
  3269. qdf_mem_copy(link_frame_currpos,
  3270. sta_prof_ie,
  3271. sta_prof_ie_size);
  3272. link_frame_currpos += sta_prof_ie_size;
  3273. link_frame_currlen +=
  3274. sta_prof_ie_size;
  3275. if (reportingsta_ie[ID_POS] ==
  3276. WLAN_ELEMID_EXTN_ELEM) {
  3277. mlo_etrace_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",
  3278. sta_prof_ie[ID_POS],
  3279. sta_prof_ie[IDEXT_POS],
  3280. sta_prof_ie_size);
  3281. } else {
  3282. mlo_etrace_debug("IE with element ID : %u (%zu octets) is present only in STA profile. Copied IE from STA profile to link specific frame",
  3283. sta_prof_ie[ID_POS],
  3284. sta_prof_ie_size);
  3285. }
  3286. sta_prof_ie[0] = 0;
  3287. } else {
  3288. if (sta_prof_ie[ID_POS] == WLAN_ELEMID_EXTN_ELEM) {
  3289. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u extension element ID : %u. Required: %zu octets, available: %zu octets",
  3290. sta_prof_ie[ID_POS],
  3291. sta_prof_ie[IDEXT_POS],
  3292. sta_prof_ie_size,
  3293. link_frame_maxsize -
  3294. link_frame_currlen);
  3295. } else {
  3296. mlo_etrace_err_rl("Insufficient space in link specific frame for IE with element ID : %u. Required: %zu octets, available: %zu octets",
  3297. sta_prof_ie[ID_POS],
  3298. sta_prof_ie_size,
  3299. link_frame_maxsize -
  3300. link_frame_currlen);
  3301. }
  3302. ret = QDF_STATUS_E_NOMEM;
  3303. goto mem_free;
  3304. }
  3305. sta_prof_iesection_currpos += sta_prof_ie_size;
  3306. sta_prof_iesection_remlen -= sta_prof_ie_size;
  3307. }
  3308. /* Copy the link MAC addr */
  3309. link_frame_hdr = (struct wlan_frame_hdr *)link_frame;
  3310. if ((subtype == WLAN_FC0_STYPE_ASSOC_REQ) ||
  3311. (subtype == WLAN_FC0_STYPE_REASSOC_REQ)) {
  3312. qdf_mem_copy(link_frame_hdr->i_addr3, &link_addr,
  3313. QDF_MAC_ADDR_SIZE);
  3314. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  3315. QDF_MAC_ADDR_SIZE);
  3316. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
  3317. QDF_MAC_ADDR_SIZE);
  3318. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_REQ_FC0;
  3319. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_REQ_FC1;
  3320. } else if (subtype == WLAN_FC0_STYPE_PROBE_RESP) {
  3321. qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
  3322. QDF_MAC_ADDR_SIZE);
  3323. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  3324. QDF_MAC_ADDR_SIZE);
  3325. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
  3326. QDF_MAC_ADDR_SIZE);
  3327. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_PROBE_RESP_FC0;
  3328. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_PROBE_RESP_FC1;
  3329. } else {
  3330. /* This is a (re)association response */
  3331. qdf_mem_copy(link_frame_hdr->i_addr3, reportedmacaddr.bytes,
  3332. QDF_MAC_ADDR_SIZE);
  3333. qdf_mem_copy(link_frame_hdr->i_addr2, reportedmacaddr.bytes,
  3334. QDF_MAC_ADDR_SIZE);
  3335. qdf_mem_copy(link_frame_hdr->i_addr1, &link_addr,
  3336. QDF_MAC_ADDR_SIZE);
  3337. link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0;
  3338. link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1;
  3339. }
  3340. mlo_debug("subtype:%u addr3:" QDF_MAC_ADDR_FMT " addr2:"
  3341. QDF_MAC_ADDR_FMT " addr1:" QDF_MAC_ADDR_FMT,
  3342. subtype,
  3343. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr3),
  3344. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr2),
  3345. QDF_MAC_ADDR_REF(link_frame_hdr->i_addr1));
  3346. /* Seq num not used so not populated */
  3347. *link_frame_len = link_frame_currlen;
  3348. ret = QDF_STATUS_SUCCESS;
  3349. mem_free:
  3350. qdf_mem_free(mlieseqpayload_copy);
  3351. return ret;
  3352. }
  3353. QDF_STATUS
  3354. util_gen_link_assoc_req(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
  3355. uint8_t link_id,
  3356. struct qdf_mac_addr link_addr,
  3357. uint8_t *link_frame,
  3358. qdf_size_t link_frame_maxsize,
  3359. qdf_size_t *link_frame_len)
  3360. {
  3361. return util_gen_link_reqrsp_cmn(frame, frame_len,
  3362. (isreassoc ? WLAN_FC0_STYPE_REASSOC_REQ :
  3363. WLAN_FC0_STYPE_ASSOC_REQ),
  3364. link_id, link_addr, link_frame,
  3365. link_frame_maxsize, link_frame_len);
  3366. }
  3367. QDF_STATUS
  3368. util_gen_link_probe_rsp_from_assoc_rsp(uint8_t *frame, qdf_size_t frame_len,
  3369. uint8_t link_id, struct qdf_mac_addr link_addr,
  3370. uint8_t *link_frame, qdf_size_t link_frame_maxsize,
  3371. qdf_size_t *link_frame_len,
  3372. uint8_t *bcn_prb_ptr,
  3373. qdf_size_t bcn_prb_len)
  3374. {
  3375. return util_gen_link_prb_rsp_from_assoc_rsp_cmn(frame, frame_len,
  3376. WLAN_FC0_STYPE_ASSOC_RESP,
  3377. WLAN_FC0_STYPE_PROBE_RESP,
  3378. link_id, link_addr,
  3379. link_frame,
  3380. link_frame_maxsize,
  3381. link_frame_len,
  3382. bcn_prb_ptr,
  3383. bcn_prb_len);
  3384. }
  3385. QDF_STATUS
  3386. util_gen_link_assoc_rsp(uint8_t *frame, qdf_size_t frame_len, bool isreassoc,
  3387. uint8_t link_id,
  3388. struct qdf_mac_addr link_addr,
  3389. uint8_t *link_frame,
  3390. qdf_size_t link_frame_maxsize,
  3391. qdf_size_t *link_frame_len)
  3392. {
  3393. return util_gen_link_reqrsp_cmn(frame, frame_len,
  3394. (isreassoc ? WLAN_FC0_STYPE_REASSOC_RESP :
  3395. WLAN_FC0_STYPE_ASSOC_RESP),
  3396. link_id, link_addr, link_frame,
  3397. link_frame_maxsize, link_frame_len);
  3398. }
  3399. QDF_STATUS
  3400. util_gen_link_probe_rsp(uint8_t *frame, qdf_size_t frame_len,
  3401. uint8_t link_id,
  3402. struct qdf_mac_addr link_addr,
  3403. uint8_t *link_frame,
  3404. qdf_size_t link_frame_maxsize,
  3405. qdf_size_t *link_frame_len)
  3406. {
  3407. return util_gen_link_reqrsp_cmn(frame, frame_len,
  3408. WLAN_FC0_STYPE_PROBE_RESP, link_id,
  3409. link_addr, link_frame, link_frame_maxsize,
  3410. link_frame_len);
  3411. }
  3412. QDF_STATUS
  3413. util_find_mlie(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
  3414. qdf_size_t *mlieseqlen)
  3415. {
  3416. uint8_t *bufboundary;
  3417. uint8_t *ieseq;
  3418. qdf_size_t ieseqlen;
  3419. uint8_t *currie;
  3420. uint8_t *successorfrag;
  3421. if (!buf || !buflen || !mlieseq || !mlieseqlen)
  3422. return QDF_STATUS_E_NULL_VALUE;
  3423. *mlieseq = NULL;
  3424. *mlieseqlen = 0;
  3425. /* Find Multi-Link element. In case a fragment sequence is present,
  3426. * this element will be the leading fragment.
  3427. */
  3428. ieseq = util_find_extn_eid(WLAN_ELEMID_EXTN_ELEM,
  3429. WLAN_EXTN_ELEMID_MULTI_LINK, buf,
  3430. buflen);
  3431. /* Even if the element is not found, we have successfully examined the
  3432. * buffer. The caller will be provided a NULL value for the starting of
  3433. * the Multi-Link element. Hence, we return success.
  3434. */
  3435. if (!ieseq)
  3436. return QDF_STATUS_SUCCESS;
  3437. bufboundary = buf + buflen;
  3438. if ((ieseq + MIN_IE_LEN) > bufboundary)
  3439. return QDF_STATUS_E_INVAL;
  3440. ieseqlen = MIN_IE_LEN + ieseq[TAG_LEN_POS];
  3441. if (ieseqlen < sizeof(struct wlan_ie_multilink))
  3442. return QDF_STATUS_E_PROTO;
  3443. if ((ieseq + ieseqlen) > bufboundary)
  3444. return QDF_STATUS_E_INVAL;
  3445. /* In the next sequence of checks, if there is no space in the buffer
  3446. * for another element after the Multi-Link element/element fragment
  3447. * sequence, it could indicate an issue since non-MLO EHT elements
  3448. * would be expected to follow the Multi-Link element/element fragment
  3449. * sequence. However, this is outside of the purview of this function,
  3450. * hence we ignore it.
  3451. */
  3452. currie = ieseq;
  3453. successorfrag = util_get_successorfrag(currie, buf, buflen);
  3454. /* Fragmentation definitions as of IEEE802.11be D1.0 and
  3455. * IEEE802.11REVme D0.2 are applied. Only the case where Multi-Link
  3456. * element is present in a buffer from the core frame is considered.
  3457. * Future changes to fragmentation, cases where the Multi-Link element
  3458. * is present in a subelement, etc. to be reflected here if applicable
  3459. * as and when the rules evolve.
  3460. */
  3461. while (successorfrag) {
  3462. /* We should not be seeing a successor fragment if the length
  3463. * of the current IE is lesser than the max.
  3464. */
  3465. if (currie[TAG_LEN_POS] != WLAN_MAX_IE_LEN)
  3466. return QDF_STATUS_E_PROTO;
  3467. if (successorfrag[TAG_LEN_POS] == 0)
  3468. return QDF_STATUS_E_PROTO;
  3469. ieseqlen += (MIN_IE_LEN + successorfrag[TAG_LEN_POS]);
  3470. currie = successorfrag;
  3471. successorfrag = util_get_successorfrag(currie, buf, buflen);
  3472. }
  3473. *mlieseq = ieseq;
  3474. *mlieseqlen = ieseqlen;
  3475. return QDF_STATUS_SUCCESS;
  3476. }
  3477. static inline QDF_STATUS
  3478. util_validate_bv_mlie_min_seq_len(qdf_size_t mlieseqlen)
  3479. {
  3480. qdf_size_t parsed_len = sizeof(struct wlan_ie_multilink);
  3481. if (mlieseqlen < parsed_len + WLAN_ML_BV_CINFO_LENGTH_SIZE) {
  3482. mlo_err_rl("ML seq payload of len %zu doesn't accommodate the mandatory BV ML IE Common info len field",
  3483. mlieseqlen);
  3484. return QDF_STATUS_E_PROTO;
  3485. }
  3486. parsed_len += WLAN_ML_BV_CINFO_LENGTH_SIZE;
  3487. if (mlieseqlen < parsed_len + QDF_MAC_ADDR_SIZE) {
  3488. mlo_err_rl("ML seq payload of len %zu doesn't accommodate the mandatory MLD addr",
  3489. mlieseqlen);
  3490. return QDF_STATUS_E_PROTO;
  3491. }
  3492. return QDF_STATUS_SUCCESS;
  3493. }
  3494. QDF_STATUS
  3495. util_find_mlie_by_variant(uint8_t *buf, qdf_size_t buflen, uint8_t **mlieseq,
  3496. qdf_size_t *mlieseqlen, int variant)
  3497. {
  3498. uint8_t *ieseq;
  3499. qdf_size_t ieseqlen;
  3500. QDF_STATUS status;
  3501. int ml_variant;
  3502. qdf_size_t buf_parsed_len;
  3503. if (!buf || !buflen || !mlieseq || !mlieseqlen)
  3504. return QDF_STATUS_E_NULL_VALUE;
  3505. if (variant >= WLAN_ML_VARIANT_INVALIDSTART)
  3506. return QDF_STATUS_E_PROTO;
  3507. ieseq = NULL;
  3508. ieseqlen = 0;
  3509. *mlieseq = NULL;
  3510. *mlieseqlen = 0;
  3511. buf_parsed_len = 0;
  3512. while (buflen > buf_parsed_len) {
  3513. status = util_find_mlie(buf + buf_parsed_len,
  3514. buflen - buf_parsed_len,
  3515. &ieseq, &ieseqlen);
  3516. if (QDF_IS_STATUS_ERROR(status))
  3517. return status;
  3518. /* Even if the element is not found, we have successfully
  3519. * examined the buffer. The caller will be provided a NULL value
  3520. * for the starting of the Multi-Link element. Hence, we return
  3521. * success.
  3522. */
  3523. if (!ieseq)
  3524. return QDF_STATUS_SUCCESS;
  3525. status = util_get_mlie_variant(ieseq, ieseqlen,
  3526. &ml_variant);
  3527. if (QDF_IS_STATUS_ERROR(status)) {
  3528. mlo_err("Unable to get Multi-link element variant");
  3529. return status;
  3530. }
  3531. if (ml_variant == variant) {
  3532. *mlieseq = ieseq;
  3533. *mlieseqlen = ieseqlen;
  3534. return QDF_STATUS_SUCCESS;
  3535. }
  3536. buf_parsed_len = ieseq + ieseqlen - buf;
  3537. }
  3538. return QDF_STATUS_E_INVAL;
  3539. }
  3540. QDF_STATUS
  3541. util_get_mlie_common_info_len(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3542. uint8_t *commoninfo_len)
  3543. {
  3544. struct wlan_ie_multilink *mlie_fixed;
  3545. enum wlan_ml_variant variant;
  3546. uint16_t mlcontrol;
  3547. if (!mlieseq || !mlieseqlen || !commoninfo_len)
  3548. return QDF_STATUS_E_NULL_VALUE;
  3549. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3550. return QDF_STATUS_E_INVAL;
  3551. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3552. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  3553. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  3554. return QDF_STATUS_E_INVAL;
  3555. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3556. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3557. WLAN_ML_CTRL_TYPE_BITS);
  3558. if (variant != WLAN_ML_VARIANT_BASIC)
  3559. return QDF_STATUS_E_INVAL;
  3560. /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink).
  3561. * Check if there is sufficient space in the buffer for the Common Info
  3562. * Length and MLD MAC address.
  3563. */
  3564. if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE +
  3565. QDF_MAC_ADDR_SIZE) > mlieseqlen)
  3566. return QDF_STATUS_E_PROTO;
  3567. *commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3568. return QDF_STATUS_SUCCESS;
  3569. }
  3570. QDF_STATUS
  3571. util_get_bvmlie_bssparamchangecnt(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3572. bool *bssparamchangecntfound,
  3573. uint8_t *bssparamchangecnt)
  3574. {
  3575. struct wlan_ie_multilink *mlie_fixed;
  3576. enum wlan_ml_variant variant;
  3577. uint16_t mlcontrol;
  3578. uint16_t presencebitmap;
  3579. uint8_t *commoninfo;
  3580. uint8_t commoninfolen;
  3581. qdf_size_t mldcap_offset;
  3582. if (!mlieseq || !mlieseqlen || !bssparamchangecntfound ||
  3583. !bssparamchangecnt)
  3584. return QDF_STATUS_E_NULL_VALUE;
  3585. *bssparamchangecntfound = false;
  3586. *bssparamchangecnt = 0;
  3587. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3588. return QDF_STATUS_E_INVAL;
  3589. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3590. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  3591. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  3592. return QDF_STATUS_E_INVAL;
  3593. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3594. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3595. WLAN_ML_CTRL_TYPE_BITS);
  3596. if (variant != WLAN_ML_VARIANT_BASIC)
  3597. return QDF_STATUS_E_NOSUPPORT;
  3598. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3599. WLAN_ML_CTRL_PBM_BITS);
  3600. if (QDF_IS_STATUS_ERROR(util_validate_bv_mlie_min_seq_len(mlieseqlen)))
  3601. return QDF_STATUS_E_INVAL;
  3602. commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
  3603. commoninfolen = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3604. mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE;
  3605. mldcap_offset += QDF_MAC_ADDR_SIZE;
  3606. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  3607. mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3608. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
  3609. mlieseqlen)
  3610. return QDF_STATUS_E_PROTO;
  3611. }
  3612. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
  3613. if (commoninfolen < (mldcap_offset +
  3614. WLAN_ML_BSSPARAMCHNGCNT_SIZE))
  3615. return QDF_STATUS_E_PROTO;
  3616. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset +
  3617. WLAN_ML_BSSPARAMCHNGCNT_SIZE) >
  3618. mlieseqlen)
  3619. return QDF_STATUS_E_PROTO;
  3620. *bssparamchangecntfound = true;
  3621. *bssparamchangecnt = *(commoninfo + mldcap_offset);
  3622. }
  3623. return QDF_STATUS_SUCCESS;
  3624. }
  3625. QDF_STATUS
  3626. util_get_mlie_variant(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3627. int *variant)
  3628. {
  3629. struct wlan_ie_multilink *mlie_fixed;
  3630. enum wlan_ml_variant var;
  3631. uint16_t mlcontrol;
  3632. if (!mlieseq || !mlieseqlen || !variant)
  3633. return QDF_STATUS_E_NULL_VALUE;
  3634. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3635. return QDF_STATUS_E_INVAL;
  3636. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3637. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  3638. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  3639. return QDF_STATUS_E_INVAL;
  3640. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  3641. var = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3642. WLAN_ML_CTRL_TYPE_BITS);
  3643. if (var >= WLAN_ML_VARIANT_INVALIDSTART)
  3644. return QDF_STATUS_E_PROTO;
  3645. *variant = var;
  3646. return QDF_STATUS_SUCCESS;
  3647. }
  3648. QDF_STATUS
  3649. util_get_bvmlie_eml_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3650. bool *eml_cap_found,
  3651. uint16_t *eml_cap)
  3652. {
  3653. struct wlan_ie_multilink *mlie_fixed;
  3654. enum wlan_ml_variant variant;
  3655. uint16_t mlcontrol;
  3656. uint8_t eml_cap_offset;
  3657. uint8_t commoninfo_len;
  3658. uint16_t presencebitmap;
  3659. if (!mlieseq || !mlieseqlen || !eml_cap_found || !eml_cap)
  3660. return QDF_STATUS_E_NULL_VALUE;
  3661. *eml_cap = 0;
  3662. *eml_cap_found = false;
  3663. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3664. return QDF_STATUS_E_INVAL;
  3665. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3666. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  3667. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  3668. return QDF_STATUS_E_INVAL;
  3669. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3670. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3671. WLAN_ML_CTRL_TYPE_BITS);
  3672. if (variant != WLAN_ML_VARIANT_BASIC)
  3673. return QDF_STATUS_E_INVAL;
  3674. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3675. WLAN_ML_CTRL_PBM_BITS);
  3676. /* eml_cap_offset stores the offset of EML Capabilities within
  3677. * Common Info
  3678. */
  3679. eml_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE;
  3680. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
  3681. eml_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3682. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
  3683. eml_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  3684. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P)
  3685. eml_cap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
  3686. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
  3687. /* Common Info starts at
  3688. * mlieseq + sizeof(struct wlan_ie_multilink).
  3689. * Check if there is sufficient space in the buffer for
  3690. * the Common Info Length.
  3691. */
  3692. if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
  3693. WLAN_ML_BV_CINFO_LENGTH_SIZE))
  3694. return QDF_STATUS_E_PROTO;
  3695. /* Check if the value indicated in the Common Info Length
  3696. * subfield is sufficient to access the EML capabilities.
  3697. */
  3698. commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3699. if (commoninfo_len < (eml_cap_offset +
  3700. WLAN_ML_BV_CINFO_EMLCAP_SIZE))
  3701. return QDF_STATUS_E_PROTO;
  3702. /* Common Info starts at mlieseq + sizeof(struct
  3703. * wlan_ie_multilink). Check if there is sufficient space in
  3704. * Common Info for the EML capability.
  3705. */
  3706. if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
  3707. eml_cap_offset +
  3708. WLAN_ML_BV_CINFO_EMLCAP_SIZE))
  3709. return QDF_STATUS_E_PROTO;
  3710. *eml_cap_found = true;
  3711. *eml_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq +
  3712. sizeof(struct wlan_ie_multilink) +
  3713. eml_cap_offset));
  3714. }
  3715. return QDF_STATUS_SUCCESS;
  3716. }
  3717. QDF_STATUS
  3718. util_get_bvmlie_msd_cap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3719. bool *msd_cap_found,
  3720. uint16_t *msd_cap)
  3721. {
  3722. struct wlan_ie_multilink *mlie_fixed;
  3723. enum wlan_ml_variant variant;
  3724. uint16_t mlcontrol;
  3725. uint8_t msd_cap_offset;
  3726. uint8_t commoninfo_len;
  3727. uint16_t presencebitmap;
  3728. if (!mlieseq || !mlieseqlen || !msd_cap_found || !msd_cap)
  3729. return QDF_STATUS_E_NULL_VALUE;
  3730. *msd_cap = 0;
  3731. *msd_cap_found = false;
  3732. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3733. return QDF_STATUS_E_INVAL;
  3734. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3735. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  3736. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  3737. return QDF_STATUS_E_INVAL;
  3738. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3739. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3740. WLAN_ML_CTRL_TYPE_BITS);
  3741. if (variant != WLAN_ML_VARIANT_BASIC)
  3742. return QDF_STATUS_E_INVAL;
  3743. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3744. WLAN_ML_CTRL_PBM_BITS);
  3745. /* msd_cap_offset stores the offset of MSD capabilities within
  3746. * Common Info
  3747. */
  3748. msd_cap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE;
  3749. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P)
  3750. msd_cap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3751. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P)
  3752. msd_cap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  3753. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
  3754. /* Common Info starts at
  3755. * mlieseq + sizeof(struct wlan_ie_multilink).
  3756. * Check if there is sufficient space in the buffer for
  3757. * the Common Info Length.
  3758. */
  3759. if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
  3760. WLAN_ML_BV_CINFO_LENGTH_SIZE))
  3761. return QDF_STATUS_E_PROTO;
  3762. /* Check if the value indicated in the Common Info Length
  3763. * subfield is sufficient to access the MSD capabilities.
  3764. */
  3765. commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3766. if (commoninfo_len < (msd_cap_offset +
  3767. WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE))
  3768. return QDF_STATUS_E_PROTO;
  3769. /* Common Info starts at mlieseq + sizeof(struct
  3770. * wlan_ie_multilink). Check if there is sufficient space in
  3771. * Common Info for the MSD capability.
  3772. */
  3773. if (mlieseqlen < (sizeof(struct wlan_ie_multilink) +
  3774. msd_cap_offset +
  3775. WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE))
  3776. return QDF_STATUS_E_PROTO;
  3777. *msd_cap_found = true;
  3778. *msd_cap = qdf_le16_to_cpu(*(uint16_t *)(mlieseq +
  3779. sizeof(struct wlan_ie_multilink) +
  3780. msd_cap_offset));
  3781. } else {
  3782. mlo_debug("MSD caps not found in assoc rsp");
  3783. }
  3784. return QDF_STATUS_SUCCESS;
  3785. }
  3786. QDF_STATUS
  3787. util_get_bvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3788. struct qdf_mac_addr *mldmacaddr)
  3789. {
  3790. struct wlan_ie_multilink *mlie_fixed;
  3791. enum wlan_ml_variant variant;
  3792. uint16_t mlcontrol;
  3793. uint8_t commoninfo_len;
  3794. if (!mlieseq || !mlieseqlen || !mldmacaddr)
  3795. return QDF_STATUS_E_NULL_VALUE;
  3796. qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr));
  3797. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3798. return QDF_STATUS_E_INVAL;
  3799. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3800. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  3801. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  3802. return QDF_STATUS_E_INVAL;
  3803. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3804. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3805. WLAN_ML_CTRL_TYPE_BITS);
  3806. if (variant != WLAN_ML_VARIANT_BASIC)
  3807. return QDF_STATUS_E_INVAL;
  3808. /* Common Info starts at mlieseq + sizeof(struct wlan_ie_multilink).
  3809. * Check if there is sufficient space in the buffer for the Common Info
  3810. * Length and MLD MAC address.
  3811. */
  3812. if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_BV_CINFO_LENGTH_SIZE +
  3813. QDF_MAC_ADDR_SIZE) > mlieseqlen)
  3814. return QDF_STATUS_E_PROTO;
  3815. /* Check if the value indicated in the Common Info Length subfield is
  3816. * sufficient to access the MLD MAC address.
  3817. */
  3818. commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3819. if (commoninfo_len < (WLAN_ML_BV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE))
  3820. return QDF_STATUS_E_PROTO;
  3821. qdf_mem_copy(mldmacaddr->bytes,
  3822. mlieseq + sizeof(struct wlan_ie_multilink) +
  3823. WLAN_ML_BV_CINFO_LENGTH_SIZE,
  3824. QDF_MAC_ADDR_SIZE);
  3825. return QDF_STATUS_SUCCESS;
  3826. }
  3827. QDF_STATUS
  3828. util_get_bvmlie_primary_linkid(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3829. bool *linkidfound, uint8_t *linkid)
  3830. {
  3831. struct wlan_ie_multilink *mlie_fixed;
  3832. enum wlan_ml_variant variant;
  3833. uint16_t mlcontrol;
  3834. uint16_t presencebitmap;
  3835. uint8_t *commoninfo;
  3836. qdf_size_t commoninfolen;
  3837. uint8_t *linkidinfo;
  3838. if (!mlieseq || !mlieseqlen || !linkidfound || !linkid)
  3839. return QDF_STATUS_E_NULL_VALUE;
  3840. *linkidfound = false;
  3841. *linkid = 0;
  3842. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3843. return QDF_STATUS_E_INVAL;
  3844. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3845. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  3846. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK))
  3847. return QDF_STATUS_E_INVAL;
  3848. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  3849. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3850. WLAN_ML_CTRL_TYPE_BITS);
  3851. if (variant != WLAN_ML_VARIANT_BASIC)
  3852. return QDF_STATUS_E_INVAL;
  3853. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3854. WLAN_ML_CTRL_PBM_BITS);
  3855. commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
  3856. commoninfolen = 0;
  3857. commoninfolen += WLAN_ML_BV_CINFO_LENGTH_SIZE;
  3858. if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
  3859. mlieseqlen)
  3860. return QDF_STATUS_E_PROTO;
  3861. commoninfolen += QDF_MAC_ADDR_SIZE;
  3862. if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
  3863. mlieseqlen)
  3864. return QDF_STATUS_E_PROTO;
  3865. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  3866. linkidinfo = commoninfo + commoninfolen;
  3867. commoninfolen += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3868. if ((sizeof(struct wlan_ie_multilink) + commoninfolen) >
  3869. mlieseqlen)
  3870. return QDF_STATUS_E_PROTO;
  3871. *linkidfound = true;
  3872. *linkid = QDF_GET_BITS(linkidinfo[0],
  3873. WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX,
  3874. WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS);
  3875. }
  3876. return QDF_STATUS_SUCCESS;
  3877. }
  3878. QDF_STATUS
  3879. util_get_bvmlie_mldcap(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  3880. bool *mldcapfound, uint16_t *mldcap)
  3881. {
  3882. struct wlan_ie_multilink *mlie_fixed;
  3883. enum wlan_ml_variant variant;
  3884. uint16_t mlcontrol;
  3885. uint16_t presencebitmap;
  3886. uint8_t *commoninfo;
  3887. uint8_t commoninfo_len;
  3888. qdf_size_t mldcap_offset;
  3889. if (!mlieseq || !mlieseqlen || !mldcapfound || !mldcap)
  3890. return QDF_STATUS_E_NULL_VALUE;
  3891. *mldcapfound = false;
  3892. *mldcap = 0;
  3893. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  3894. return QDF_STATUS_E_INVAL;
  3895. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  3896. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  3897. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  3898. return QDF_STATUS_E_INVAL;
  3899. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3900. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3901. WLAN_ML_CTRL_TYPE_BITS);
  3902. if (variant != WLAN_ML_VARIANT_BASIC)
  3903. return QDF_STATUS_E_NOSUPPORT;
  3904. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3905. WLAN_ML_CTRL_PBM_BITS);
  3906. if (QDF_IS_STATUS_ERROR(util_validate_bv_mlie_min_seq_len(mlieseqlen)))
  3907. return QDF_STATUS_E_INVAL;
  3908. commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
  3909. commoninfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  3910. /* mldcap_offset stores the offset of MLD Capabilities within
  3911. * Common Info
  3912. */
  3913. mldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE;
  3914. mldcap_offset += QDF_MAC_ADDR_SIZE;
  3915. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  3916. mldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3917. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
  3918. mlieseqlen)
  3919. return QDF_STATUS_E_PROTO;
  3920. }
  3921. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
  3922. mldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  3923. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
  3924. mlieseqlen)
  3925. return QDF_STATUS_E_PROTO;
  3926. }
  3927. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
  3928. mldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
  3929. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
  3930. mlieseqlen)
  3931. return QDF_STATUS_E_PROTO;
  3932. }
  3933. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
  3934. mldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
  3935. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset) >
  3936. mlieseqlen)
  3937. return QDF_STATUS_E_PROTO;
  3938. }
  3939. if (presencebitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) {
  3940. /* Check if the value indicated in the Common Info Length
  3941. * subfield is sufficient to access the MLD capabilities.
  3942. */
  3943. if (commoninfo_len < (mldcap_offset +
  3944. WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE))
  3945. return QDF_STATUS_E_PROTO;
  3946. if ((sizeof(struct wlan_ie_multilink) + mldcap_offset +
  3947. WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE) >
  3948. mlieseqlen)
  3949. return QDF_STATUS_E_PROTO;
  3950. *mldcap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo + mldcap_offset)));
  3951. *mldcapfound = true;
  3952. }
  3953. return QDF_STATUS_SUCCESS;
  3954. }
  3955. QDF_STATUS
  3956. util_get_bvmlie_ext_mld_cap_op_info(uint8_t *mlie_seq,
  3957. qdf_size_t mlie_seqlen,
  3958. bool *ext_mld_cap_found,
  3959. uint16_t *ext_mld_cap)
  3960. {
  3961. struct wlan_ie_multilink *mlie_fixed;
  3962. uint16_t mlcontrol;
  3963. enum wlan_ml_variant variant;
  3964. uint16_t presence_bitmap;
  3965. uint8_t *commoninfo;
  3966. uint8_t commoninfo_len;
  3967. qdf_size_t extmldcap_offset;
  3968. if (!mlie_seq || !mlie_seqlen || !ext_mld_cap_found || !ext_mld_cap)
  3969. return QDF_STATUS_E_NULL_VALUE;
  3970. *ext_mld_cap_found = false;
  3971. *ext_mld_cap = 0;
  3972. if (mlie_seqlen < sizeof(struct wlan_ie_multilink))
  3973. return QDF_STATUS_E_INVAL;
  3974. mlie_fixed = (struct wlan_ie_multilink *)mlie_seq;
  3975. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  3976. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  3977. return QDF_STATUS_E_INVAL;
  3978. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  3979. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  3980. WLAN_ML_CTRL_TYPE_BITS);
  3981. if (variant != WLAN_ML_VARIANT_BASIC)
  3982. return QDF_STATUS_E_NOSUPPORT;
  3983. presence_bitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  3984. WLAN_ML_CTRL_PBM_BITS);
  3985. commoninfo = mlie_seq + sizeof(struct wlan_ie_multilink);
  3986. commoninfo_len = *(mlie_seq + sizeof(struct wlan_ie_multilink));
  3987. /* extmldcap_offset stores the offset of Ext MLD Capabilities and
  3988. * operations within the Common Info
  3989. */
  3990. extmldcap_offset = WLAN_ML_BV_CINFO_LENGTH_SIZE;
  3991. extmldcap_offset += QDF_MAC_ADDR_SIZE;
  3992. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P) {
  3993. extmldcap_offset += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE;
  3994. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  3995. mlie_seqlen)
  3996. return QDF_STATUS_E_PROTO;
  3997. }
  3998. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P) {
  3999. extmldcap_offset += WLAN_ML_BSSPARAMCHNGCNT_SIZE;
  4000. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  4001. mlie_seqlen)
  4002. return QDF_STATUS_E_PROTO;
  4003. }
  4004. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P) {
  4005. extmldcap_offset += WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_SIZE;
  4006. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  4007. mlie_seqlen)
  4008. return QDF_STATUS_E_PROTO;
  4009. }
  4010. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_EMLCAP_P) {
  4011. extmldcap_offset += WLAN_ML_BV_CINFO_EMLCAP_SIZE;
  4012. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  4013. mlie_seqlen)
  4014. return QDF_STATUS_E_PROTO;
  4015. }
  4016. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P) {
  4017. extmldcap_offset += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE;
  4018. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  4019. mlie_seqlen)
  4020. return QDF_STATUS_E_PROTO;
  4021. }
  4022. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_MLDID_P) {
  4023. extmldcap_offset += WLAN_ML_BV_CINFO_MLDID_SIZE;
  4024. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset) >
  4025. mlie_seqlen)
  4026. return QDF_STATUS_E_PROTO;
  4027. }
  4028. if (presence_bitmap & WLAN_ML_BV_CTRL_PBM_EXT_MLDCAPANDOP_P) {
  4029. /* Check if the value indicated in the Common Info Length
  4030. * subfield is sufficient to access the Ext MLD capabilities.
  4031. */
  4032. if (commoninfo_len < (extmldcap_offset +
  4033. WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE))
  4034. return QDF_STATUS_E_PROTO;
  4035. if ((sizeof(struct wlan_ie_multilink) + extmldcap_offset +
  4036. WLAN_ML_BV_CINFO_EXT_MLDCAPANDOP_SIZE) >
  4037. mlie_seqlen)
  4038. return QDF_STATUS_E_PROTO;
  4039. *ext_mld_cap = qdf_le16_to_cpu(*((uint16_t *)(commoninfo +
  4040. extmldcap_offset)));
  4041. *ext_mld_cap_found = true;
  4042. }
  4043. return QDF_STATUS_SUCCESS;
  4044. }
  4045. QDF_STATUS
  4046. util_get_bvmlie_persta_partner_info(uint8_t *mlieseq,
  4047. qdf_size_t mlieseqlen,
  4048. struct mlo_partner_info *partner_info)
  4049. {
  4050. struct wlan_ie_multilink *mlie_fixed;
  4051. uint16_t mlcontrol;
  4052. enum wlan_ml_variant variant;
  4053. uint8_t *linkinfo;
  4054. qdf_size_t linkinfo_len;
  4055. struct mlo_partner_info pinfo = {0};
  4056. qdf_size_t mlieseqpayloadlen;
  4057. uint8_t *mlieseqpayload_copy;
  4058. bool is_elemfragseq;
  4059. qdf_size_t defragpayload_len;
  4060. qdf_size_t tmplen;
  4061. QDF_STATUS ret;
  4062. if (!mlieseq) {
  4063. mlo_err("Pointer to Multi-Link element sequence is NULL");
  4064. return QDF_STATUS_E_NULL_VALUE;
  4065. }
  4066. if (!mlieseqlen) {
  4067. mlo_err("Length of Multi-Link element sequence is zero");
  4068. return QDF_STATUS_E_INVAL;
  4069. }
  4070. if (!partner_info) {
  4071. mlo_err("partner_info is NULL");
  4072. return QDF_STATUS_E_NULL_VALUE;
  4073. }
  4074. partner_info->num_partner_links = 0;
  4075. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  4076. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  4077. mlieseqlen, sizeof(struct wlan_ie_multilink));
  4078. return QDF_STATUS_E_INVAL;
  4079. }
  4080. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  4081. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  4082. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) {
  4083. mlo_err("The element is not a Multi-Link element");
  4084. return QDF_STATUS_E_INVAL;
  4085. }
  4086. mlcontrol = le16toh(mlie_fixed->mlcontrol);
  4087. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  4088. WLAN_ML_CTRL_TYPE_BITS);
  4089. if (variant != WLAN_ML_VARIANT_BASIC) {
  4090. mlo_err("The variant value %u does not correspond to Basic Variant value %u",
  4091. variant, WLAN_ML_VARIANT_BASIC);
  4092. return QDF_STATUS_E_INVAL;
  4093. }
  4094. mlieseqpayloadlen = 0;
  4095. tmplen = 0;
  4096. is_elemfragseq = false;
  4097. ret = wlan_get_elem_fragseq_info(mlieseq,
  4098. mlieseqlen,
  4099. &is_elemfragseq,
  4100. &tmplen,
  4101. &mlieseqpayloadlen);
  4102. if (QDF_IS_STATUS_ERROR(ret))
  4103. return ret;
  4104. if (is_elemfragseq) {
  4105. if (tmplen != mlieseqlen) {
  4106. 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",
  4107. tmplen, mlieseqlen);
  4108. return QDF_STATUS_E_INVAL;
  4109. }
  4110. if (!mlieseqpayloadlen) {
  4111. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  4112. return QDF_STATUS_E_FAILURE;
  4113. }
  4114. mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
  4115. mlieseqpayloadlen);
  4116. } else {
  4117. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  4118. 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",
  4119. mlieseqlen,
  4120. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  4121. return QDF_STATUS_E_FAILURE;
  4122. }
  4123. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  4124. }
  4125. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  4126. if (!mlieseqpayload_copy) {
  4127. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  4128. return QDF_STATUS_E_NOMEM;
  4129. }
  4130. if (is_elemfragseq) {
  4131. ret = wlan_defrag_elem_fragseq(false,
  4132. mlieseq,
  4133. mlieseqlen,
  4134. mlieseqpayload_copy,
  4135. mlieseqpayloadlen,
  4136. &defragpayload_len);
  4137. if (QDF_IS_STATUS_ERROR(ret)) {
  4138. qdf_mem_free(mlieseqpayload_copy);
  4139. return ret;
  4140. }
  4141. if (defragpayload_len != mlieseqpayloadlen) {
  4142. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  4143. defragpayload_len, mlieseqpayloadlen);
  4144. qdf_mem_free(mlieseqpayload_copy);
  4145. return QDF_STATUS_E_FAILURE;
  4146. }
  4147. } else {
  4148. qdf_mem_copy(mlieseqpayload_copy,
  4149. mlieseq + sizeof(struct ie_header) + 1,
  4150. mlieseqpayloadlen);
  4151. }
  4152. linkinfo = NULL;
  4153. linkinfo_len = 0;
  4154. ret = util_parse_multi_link_ctrl(mlieseqpayload_copy,
  4155. mlieseqpayloadlen,
  4156. &linkinfo,
  4157. &linkinfo_len);
  4158. if (QDF_IS_STATUS_ERROR(ret)) {
  4159. qdf_mem_free(mlieseqpayload_copy);
  4160. return ret;
  4161. }
  4162. /*
  4163. * If Probe Request variant Multi-Link element in the Multi-Link probe
  4164. * request does not include any per-STA profile, then all APs affiliated
  4165. * with the same AP MLD as the AP identified in the Addr 1 or Addr 3
  4166. * field or AP MLD ID of the Multi-Link probe request are requested
  4167. * APs return success here
  4168. */
  4169. if (!linkinfo) {
  4170. qdf_mem_free(mlieseqpayload_copy);
  4171. return QDF_STATUS_SUCCESS;
  4172. }
  4173. ret = util_parse_partner_info_from_linkinfo(linkinfo,
  4174. linkinfo_len,
  4175. &pinfo);
  4176. if (QDF_IS_STATUS_ERROR(ret)) {
  4177. qdf_mem_free(mlieseqpayload_copy);
  4178. return ret;
  4179. }
  4180. qdf_mem_copy(partner_info, &pinfo, sizeof(*partner_info));
  4181. qdf_mem_free(mlieseqpayload_copy);
  4182. return QDF_STATUS_SUCCESS;
  4183. }
  4184. QDF_STATUS
  4185. util_get_prvmlie_persta_link_id(uint8_t *mlieseq,
  4186. qdf_size_t mlieseqlen,
  4187. struct mlo_probereq_info *probereq_info)
  4188. {
  4189. struct wlan_ie_multilink *mlie_fixed;
  4190. uint16_t mlcontrol;
  4191. enum wlan_ml_variant variant;
  4192. uint8_t *linkinfo;
  4193. qdf_size_t linkinfo_len;
  4194. qdf_size_t mlieseqpayloadlen;
  4195. uint8_t *mlieseqpayload_copy;
  4196. bool is_elemfragseq;
  4197. qdf_size_t defragpayload_len;
  4198. qdf_size_t tmplen;
  4199. QDF_STATUS ret;
  4200. if (!mlieseq) {
  4201. mlo_err("Pointer to Multi-Link element sequence is NULL");
  4202. return QDF_STATUS_E_NULL_VALUE;
  4203. }
  4204. if (!mlieseqlen) {
  4205. mlo_err("Length of Multi-Link element sequence is zero");
  4206. return QDF_STATUS_E_INVAL;
  4207. }
  4208. if (!probereq_info) {
  4209. mlo_err("probe request_info is NULL");
  4210. return QDF_STATUS_E_NULL_VALUE;
  4211. }
  4212. probereq_info->num_links = 0;
  4213. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  4214. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  4215. mlieseqlen, sizeof(struct wlan_ie_multilink));
  4216. return QDF_STATUS_E_INVAL;
  4217. }
  4218. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  4219. if ((mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM) ||
  4220. (mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)) {
  4221. mlo_err("The element is not a Multi-Link element");
  4222. return QDF_STATUS_E_INVAL;
  4223. }
  4224. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  4225. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  4226. WLAN_ML_CTRL_TYPE_BITS);
  4227. if (variant != WLAN_ML_VARIANT_PROBEREQ) {
  4228. mlo_err("The variant value %u does not correspond to Probe Request Variant value %u",
  4229. variant, WLAN_ML_VARIANT_PROBEREQ);
  4230. return QDF_STATUS_E_INVAL;
  4231. }
  4232. mlieseqpayloadlen = 0;
  4233. tmplen = 0;
  4234. is_elemfragseq = false;
  4235. ret = wlan_get_elem_fragseq_info(mlieseq,
  4236. mlieseqlen,
  4237. &is_elemfragseq,
  4238. &tmplen,
  4239. &mlieseqpayloadlen);
  4240. if (QDF_IS_STATUS_ERROR(ret))
  4241. return ret;
  4242. if (is_elemfragseq) {
  4243. if (tmplen != mlieseqlen) {
  4244. 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",
  4245. tmplen, mlieseqlen);
  4246. return QDF_STATUS_E_INVAL;
  4247. }
  4248. if (!mlieseqpayloadlen) {
  4249. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  4250. return QDF_STATUS_E_FAILURE;
  4251. }
  4252. mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
  4253. mlieseqpayloadlen);
  4254. } else {
  4255. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  4256. 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",
  4257. mlieseqlen,
  4258. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  4259. return QDF_STATUS_E_FAILURE;
  4260. }
  4261. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  4262. }
  4263. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  4264. if (!mlieseqpayload_copy) {
  4265. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  4266. return QDF_STATUS_E_NOMEM;
  4267. }
  4268. if (is_elemfragseq) {
  4269. ret = wlan_defrag_elem_fragseq(false,
  4270. mlieseq,
  4271. mlieseqlen,
  4272. mlieseqpayload_copy,
  4273. mlieseqpayloadlen,
  4274. &defragpayload_len);
  4275. if (QDF_IS_STATUS_ERROR(ret)) {
  4276. qdf_mem_free(mlieseqpayload_copy);
  4277. return ret;
  4278. }
  4279. if (defragpayload_len != mlieseqpayloadlen) {
  4280. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  4281. defragpayload_len, mlieseqpayloadlen);
  4282. qdf_mem_free(mlieseqpayload_copy);
  4283. return QDF_STATUS_E_FAILURE;
  4284. }
  4285. } else {
  4286. qdf_mem_copy(mlieseqpayload_copy,
  4287. mlieseq + sizeof(struct ie_header) + 1,
  4288. mlieseqpayloadlen);
  4289. }
  4290. linkinfo = NULL;
  4291. linkinfo_len = 0;
  4292. ret = util_parse_prv_multi_link_ctrl(mlieseqpayload_copy,
  4293. mlieseqpayloadlen,
  4294. &linkinfo,
  4295. &linkinfo_len);
  4296. if (QDF_IS_STATUS_ERROR(ret)) {
  4297. qdf_mem_free(mlieseqpayload_copy);
  4298. return ret;
  4299. }
  4300. /* In case Link Info is absent, the number of links will remain
  4301. * zero.
  4302. */
  4303. if (!linkinfo) {
  4304. mlo_debug("No link info present");
  4305. qdf_mem_free(mlieseqpayload_copy);
  4306. return QDF_STATUS_SUCCESS;
  4307. }
  4308. ret = util_parse_probereq_info_from_linkinfo(linkinfo,
  4309. linkinfo_len,
  4310. probereq_info);
  4311. if (QDF_IS_STATUS_ERROR(ret)) {
  4312. qdf_mem_free(mlieseqpayload_copy);
  4313. return ret;
  4314. }
  4315. qdf_mem_free(mlieseqpayload_copy);
  4316. return QDF_STATUS_SUCCESS;
  4317. }
  4318. QDF_STATUS
  4319. util_get_prvmlie_mldid(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  4320. bool *mldidfound, uint8_t *mldid)
  4321. {
  4322. struct wlan_ie_multilink *mlie_fixed;
  4323. enum wlan_ml_variant variant;
  4324. uint16_t mlcontrol;
  4325. uint16_t presencebitmap;
  4326. uint8_t *commoninfo;
  4327. qdf_size_t commoninfolen;
  4328. if (!mlieseq || !mlieseqlen || !mldidfound || !mldid)
  4329. return QDF_STATUS_E_NULL_VALUE;
  4330. *mldidfound = false;
  4331. *mldid = 0;
  4332. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  4333. return QDF_STATUS_E_INVAL;
  4334. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  4335. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  4336. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  4337. return QDF_STATUS_E_INVAL;
  4338. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  4339. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  4340. WLAN_ML_CTRL_TYPE_BITS);
  4341. if (variant != WLAN_ML_VARIANT_PROBEREQ)
  4342. return QDF_STATUS_E_NOSUPPORT;
  4343. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  4344. WLAN_ML_CTRL_PBM_BITS);
  4345. commoninfo = mlieseq + sizeof(struct wlan_ie_multilink);
  4346. commoninfolen = WLAN_ML_PRV_CINFO_LENGTH_SIZE;
  4347. if (presencebitmap & WLAN_ML_PRV_CTRL_PBM_MLDID_P) {
  4348. if ((sizeof(struct wlan_ie_multilink) + commoninfolen +
  4349. WLAN_ML_PRV_CINFO_MLDID_SIZE) >
  4350. mlieseqlen)
  4351. return QDF_STATUS_E_PROTO;
  4352. *mldid = *((uint8_t *)(commoninfo + commoninfolen));
  4353. commoninfolen += WLAN_ML_PRV_CINFO_MLDID_SIZE;
  4354. *mldidfound = true;
  4355. }
  4356. return QDF_STATUS_SUCCESS;
  4357. }
  4358. QDF_STATUS util_get_rvmlie_mldmacaddr(uint8_t *mlieseq, qdf_size_t mlieseqlen,
  4359. struct qdf_mac_addr *mldmacaddr,
  4360. bool *is_mldmacaddr_found)
  4361. {
  4362. struct wlan_ie_multilink *mlie_fixed;
  4363. enum wlan_ml_variant variant;
  4364. uint16_t mlcontrol;
  4365. uint16_t presencebitmap;
  4366. qdf_size_t rv_cinfo_len;
  4367. if (!mlieseq || !mlieseqlen || !mldmacaddr || !is_mldmacaddr_found)
  4368. return QDF_STATUS_E_NULL_VALUE;
  4369. *is_mldmacaddr_found = false;
  4370. qdf_mem_zero(mldmacaddr, sizeof(*mldmacaddr));
  4371. if (mlieseqlen < sizeof(struct wlan_ie_multilink))
  4372. return QDF_STATUS_E_INVAL;
  4373. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  4374. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  4375. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK)
  4376. return QDF_STATUS_E_INVAL;
  4377. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  4378. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  4379. WLAN_ML_CTRL_TYPE_BITS);
  4380. if (variant != WLAN_ML_VARIANT_RECONFIG)
  4381. return QDF_STATUS_E_INVAL;
  4382. /* ML Reconfig Common Info Length field present */
  4383. if ((sizeof(struct wlan_ie_multilink) + WLAN_ML_RV_CINFO_LENGTH_SIZE) >
  4384. mlieseqlen)
  4385. return QDF_STATUS_E_PROTO;
  4386. rv_cinfo_len = *(mlieseq + sizeof(struct wlan_ie_multilink));
  4387. presencebitmap = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  4388. WLAN_ML_CTRL_PBM_BITS);
  4389. /* Check if MLD mac address is present */
  4390. if (presencebitmap & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) {
  4391. /* Check if the value indicated in the Common Info Length
  4392. * subfield is sufficient to access the MLD MAC address.
  4393. */
  4394. if (rv_cinfo_len < (WLAN_ML_RV_CINFO_LENGTH_SIZE +
  4395. QDF_MAC_ADDR_SIZE))
  4396. return QDF_STATUS_E_PROTO;
  4397. if ((sizeof(struct wlan_ie_multilink) +
  4398. WLAN_ML_RV_CINFO_LENGTH_SIZE + QDF_MAC_ADDR_SIZE) >
  4399. mlieseqlen)
  4400. return QDF_STATUS_E_PROTO;
  4401. qdf_mem_copy(mldmacaddr->bytes,
  4402. mlieseq + sizeof(struct wlan_ie_multilink) +
  4403. WLAN_ML_RV_CINFO_LENGTH_SIZE,
  4404. QDF_MAC_ADDR_SIZE);
  4405. *is_mldmacaddr_found = true;
  4406. }
  4407. return QDF_STATUS_SUCCESS;
  4408. }
  4409. static QDF_STATUS
  4410. util_parse_rv_multi_link_ctrl(uint8_t *mlieseqpayload,
  4411. qdf_size_t mlieseqpayloadlen,
  4412. uint8_t **link_info,
  4413. qdf_size_t *link_info_len)
  4414. {
  4415. qdf_size_t parsed_payload_len, rv_cinfo_len;
  4416. uint16_t mlcontrol;
  4417. uint16_t presence_bm;
  4418. /* This helper returns the location(s) and length(s) of (sub)field(s)
  4419. * inferable after parsing the Multi Link element Control field. These
  4420. * location(s) and length(s) is/are in reference to the payload section
  4421. * of the Multi Link element (after defragmentation, if applicable).
  4422. * Here, the payload is the point after the element ID extension of the
  4423. * Multi Link element, and includes the payloads of all subsequent
  4424. * fragments (if any) but not the headers of those fragments.
  4425. *
  4426. * Currently, the helper returns the location and length of the Link
  4427. * Info field in the Multi Link element sequence. Other (sub)field(s)
  4428. * can be added later as required.
  4429. */
  4430. if (!mlieseqpayload) {
  4431. mlo_err("ML seq payload pointer is NULL");
  4432. return QDF_STATUS_E_NULL_VALUE;
  4433. }
  4434. if (!mlieseqpayloadlen) {
  4435. mlo_err("ML seq payload len is 0");
  4436. return QDF_STATUS_E_INVAL;
  4437. }
  4438. if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
  4439. mlo_err_rl("ML seq payload len %zu < ML Control size %u",
  4440. mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
  4441. return QDF_STATUS_E_PROTO;
  4442. }
  4443. parsed_payload_len = 0;
  4444. qdf_mem_copy(&mlcontrol, mlieseqpayload, WLAN_ML_CTRL_SIZE);
  4445. mlcontrol = qdf_le16_to_cpu(mlcontrol);
  4446. parsed_payload_len += WLAN_ML_CTRL_SIZE;
  4447. if (mlieseqpayloadlen <
  4448. (parsed_payload_len + WLAN_ML_RV_CINFO_LENGTH_SIZE)) {
  4449. mlo_err_rl("ML rv seq payload len %zu insufficient for common info length size %u after parsed payload len %zu.",
  4450. mlieseqpayloadlen,
  4451. WLAN_ML_RV_CINFO_LENGTH_SIZE,
  4452. parsed_payload_len);
  4453. return QDF_STATUS_E_PROTO;
  4454. }
  4455. rv_cinfo_len = *(mlieseqpayload + parsed_payload_len);
  4456. parsed_payload_len += WLAN_ML_RV_CINFO_LENGTH_SIZE;
  4457. presence_bm = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_PBM_IDX,
  4458. WLAN_ML_CTRL_PBM_BITS);
  4459. /* Check if MLD MAC address is present */
  4460. if (presence_bm & WLAN_ML_RV_CTRL_PBM_MLDMACADDR_P) {
  4461. /* Check if the value indicated in the Common Info Length
  4462. * subfield is sufficient to access the MLD MAC address.
  4463. * Note: In D3.0, MLD MAC address will not be present
  4464. * in ML Reconfig IE. But for code completeness, we
  4465. * should have below code to sanity check.
  4466. */
  4467. if (rv_cinfo_len < (WLAN_ML_RV_CINFO_LENGTH_SIZE +
  4468. QDF_MAC_ADDR_SIZE)) {
  4469. mlo_err_rl("ML rv Common Info Length %zu insufficient to access MLD MAC addr size %u.",
  4470. rv_cinfo_len,
  4471. QDF_MAC_ADDR_SIZE);
  4472. return QDF_STATUS_E_PROTO;
  4473. }
  4474. if (mlieseqpayloadlen <
  4475. (parsed_payload_len +
  4476. QDF_MAC_ADDR_SIZE)) {
  4477. mlo_err_rl("ML seq payload len %zu insufficient for MLD MAC size %u after parsed payload len %zu.",
  4478. mlieseqpayloadlen,
  4479. QDF_MAC_ADDR_SIZE,
  4480. parsed_payload_len);
  4481. return QDF_STATUS_E_PROTO;
  4482. }
  4483. parsed_payload_len += QDF_MAC_ADDR_SIZE;
  4484. }
  4485. /* At present, we only handle MAC address field in common info field.
  4486. * To be compatible with future spec updating, if new items are added
  4487. * to common info, below log will highlight the spec change.
  4488. */
  4489. if (rv_cinfo_len != (parsed_payload_len - WLAN_ML_CTRL_SIZE))
  4490. mlo_debug_rl("ML rv seq common info len %zu doesn't match with expected common info len %zu",
  4491. rv_cinfo_len,
  4492. parsed_payload_len - WLAN_ML_CTRL_SIZE);
  4493. if (mlieseqpayloadlen < (WLAN_ML_CTRL_SIZE + rv_cinfo_len)) {
  4494. mlo_err_rl("ML seq payload len %zu insufficient for rv link info after parsed mutli-link control %u and indicated Common Info length %zu",
  4495. mlieseqpayloadlen,
  4496. WLAN_ML_CTRL_SIZE,
  4497. rv_cinfo_len);
  4498. return QDF_STATUS_E_PROTO;
  4499. }
  4500. /* Update parsed_payload_len to reflect the actual bytes in common info
  4501. * field to be compatible with future spec updating.
  4502. */
  4503. parsed_payload_len = WLAN_ML_CTRL_SIZE + rv_cinfo_len;
  4504. if (link_info_len) {
  4505. *link_info_len = mlieseqpayloadlen - parsed_payload_len;
  4506. mlo_debug("link_info_len:%zu, parsed_payload_len:%zu, rv_cinfo_len %zu ",
  4507. *link_info_len, parsed_payload_len, rv_cinfo_len);
  4508. }
  4509. if (mlieseqpayloadlen == parsed_payload_len) {
  4510. mlo_debug("No Link Info field present");
  4511. if (link_info)
  4512. *link_info = NULL;
  4513. return QDF_STATUS_SUCCESS;
  4514. }
  4515. if (link_info)
  4516. *link_info = mlieseqpayload + parsed_payload_len;
  4517. return QDF_STATUS_SUCCESS;
  4518. }
  4519. static QDF_STATUS
  4520. util_parse_rvmlie_perstaprofile_stactrl(uint8_t *subelempayload,
  4521. qdf_size_t subelempayloadlen,
  4522. uint8_t *linkid,
  4523. bool *is_macaddr_valid,
  4524. struct qdf_mac_addr *macaddr,
  4525. bool *is_ap_removal_timer_valid,
  4526. uint16_t *ap_removal_timer)
  4527. {
  4528. qdf_size_t parsed_payload_len = 0, sta_info_len;
  4529. qdf_size_t parsed_sta_info_len;
  4530. uint16_t stacontrol;
  4531. uint8_t completeprofile;
  4532. /* This helper returns the location(s) and where required, the length(s)
  4533. * of (sub)field(s) inferable after parsing the STA Control field in the
  4534. * per-STA profile subelement. These location(s) and length(s) is/are in
  4535. * reference to the payload section of the per-STA profile subelement
  4536. * (after defragmentation, if applicable). Here, the payload is the
  4537. * point after the subelement length in the subelement, and includes the
  4538. * payloads of all subsequent fragments (if any) but not the headers of
  4539. * those fragments.
  4540. *
  4541. * Currently, the helper returns the link ID, MAC address, AP removal
  4542. * timer and STA profile. More (sub)fields can be added when required.
  4543. */
  4544. if (!subelempayload) {
  4545. mlo_err("Pointer to subelement payload is NULL");
  4546. return QDF_STATUS_E_NULL_VALUE;
  4547. }
  4548. if (!subelempayloadlen) {
  4549. mlo_err("Length of subelement payload is zero");
  4550. return QDF_STATUS_E_INVAL;
  4551. }
  4552. if (subelempayloadlen < WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE) {
  4553. mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
  4554. subelempayloadlen,
  4555. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE);
  4556. return QDF_STATUS_E_PROTO;
  4557. }
  4558. parsed_payload_len = 0;
  4559. qdf_mem_copy(&stacontrol,
  4560. subelempayload,
  4561. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE);
  4562. stacontrol = qdf_le16_to_cpu(stacontrol);
  4563. parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE;
  4564. if (linkid)
  4565. *linkid = QDF_GET_BITS(stacontrol,
  4566. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
  4567. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
  4568. /* Check if this a complete profile */
  4569. completeprofile = QDF_GET_BITS(stacontrol,
  4570. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX,
  4571. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS);
  4572. if (is_macaddr_valid)
  4573. *is_macaddr_valid = false;
  4574. if (subelempayloadlen < parsed_payload_len +
  4575. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE) {
  4576. mlo_err_rl("Length of subelement payload %zu octets not sufficient for sta info length of size %u octets after parsed payload length of %zu octets.",
  4577. subelempayloadlen, WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE,
  4578. parsed_payload_len);
  4579. return QDF_STATUS_E_PROTO;
  4580. }
  4581. sta_info_len = *(subelempayload + parsed_payload_len);
  4582. parsed_payload_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE;
  4583. parsed_sta_info_len = WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE;
  4584. /* Check STA MAC address present bit */
  4585. if (QDF_GET_BITS(stacontrol,
  4586. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_STAMACADDRP_IDX,
  4587. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_STAMACADDRP_BITS)) {
  4588. if (sta_info_len < (parsed_sta_info_len + QDF_MAC_ADDR_SIZE)) {
  4589. mlo_err_rl("Length of sta info len %zu octets not sufficient to contain MAC address of size %u octets after parsed sta info length of %zu octets.",
  4590. sta_info_len, QDF_MAC_ADDR_SIZE,
  4591. parsed_sta_info_len);
  4592. return QDF_STATUS_E_PROTO;
  4593. }
  4594. if (subelempayloadlen <
  4595. (parsed_payload_len + QDF_MAC_ADDR_SIZE)) {
  4596. 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.",
  4597. subelempayloadlen, QDF_MAC_ADDR_SIZE,
  4598. parsed_payload_len);
  4599. return QDF_STATUS_E_PROTO;
  4600. }
  4601. if (macaddr) {
  4602. qdf_mem_copy(macaddr->bytes,
  4603. subelempayload + parsed_payload_len,
  4604. QDF_MAC_ADDR_SIZE);
  4605. mlo_nofl_debug("Copied MAC address: " QDF_MAC_ADDR_FMT,
  4606. QDF_MAC_ADDR_REF(macaddr->bytes));
  4607. if (is_macaddr_valid)
  4608. *is_macaddr_valid = true;
  4609. }
  4610. parsed_payload_len += QDF_MAC_ADDR_SIZE;
  4611. parsed_sta_info_len += QDF_MAC_ADDR_SIZE;
  4612. }
  4613. /* Check AP Removal timer present bit */
  4614. if (QDF_GET_BITS(stacontrol,
  4615. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_APREMOVALTIMERP_IDX,
  4616. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_APREMOVALTIMERP_BITS)) {
  4617. if (sta_info_len <
  4618. (parsed_sta_info_len +
  4619. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE)) {
  4620. mlo_err_rl("Length of sta info len %zu octets not sufficient to contain AP removal timer of size %u octets after parsed sta info length of %zu octets.",
  4621. sta_info_len, WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE,
  4622. parsed_sta_info_len);
  4623. return QDF_STATUS_E_PROTO;
  4624. }
  4625. if (subelempayloadlen <
  4626. (parsed_payload_len +
  4627. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE)) {
  4628. mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain AP removal timer of size %u octets after parsed payload length of %zu octets.",
  4629. subelempayloadlen,
  4630. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE,
  4631. parsed_payload_len);
  4632. return QDF_STATUS_E_PROTO;
  4633. }
  4634. if (ap_removal_timer) {
  4635. qdf_mem_copy(ap_removal_timer,
  4636. subelempayload + parsed_payload_len,
  4637. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE);
  4638. if (is_ap_removal_timer_valid)
  4639. *is_ap_removal_timer_valid = true;
  4640. }
  4641. parsed_payload_len +=
  4642. WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE;
  4643. parsed_sta_info_len += WLAN_ML_RV_LINFO_PERSTAPROF_STAINFO_APREMOVALTIMER_SIZE;
  4644. }
  4645. /* At present, we only handle link MAC address field and ap removal
  4646. * timer tbtt field parsing. To be compatible with future spec
  4647. * updating, if new items are added to sta info, below log will
  4648. * highlight the spec change.
  4649. */
  4650. if (sta_info_len != (parsed_payload_len -
  4651. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE))
  4652. mlo_debug_rl("Length of sta info len %zu octets not match parsed payload length of %zu octets.",
  4653. sta_info_len,
  4654. parsed_payload_len -
  4655. WLAN_ML_RV_LINFO_PERSTAPROF_STACTRL_SIZE);
  4656. return QDF_STATUS_SUCCESS;
  4657. }
  4658. static QDF_STATUS
  4659. util_parse_rv_info_from_linkinfo(uint8_t *linkinfo,
  4660. qdf_size_t linkinfo_len,
  4661. struct ml_rv_info *reconfig_info)
  4662. {
  4663. uint8_t linkid;
  4664. uint8_t *linkinfo_currpos;
  4665. qdf_size_t linkinfo_remlen;
  4666. bool is_subelemfragseq;
  4667. uint8_t subelemid;
  4668. qdf_size_t subelemseqtotallen;
  4669. qdf_size_t subelemseqpayloadlen;
  4670. qdf_size_t defragpayload_len;
  4671. QDF_STATUS ret;
  4672. struct qdf_mac_addr mac_addr;
  4673. bool is_macaddr_valid;
  4674. bool is_ap_removal_timer_valid;
  4675. uint16_t ap_removal_timer;
  4676. /* This helper function parses probe request info from the per-STA prof
  4677. * present (if any) in the Link Info field in the payload of a Multi
  4678. * Link element (after defragmentation if required). The caller should
  4679. * pass a copy of the payload so that inline defragmentation of
  4680. * subelements can be carried out if required. The subelement
  4681. * defragmentation (if applicable) in this Control Path helper is
  4682. * required for maintainability, accuracy and eliminating current and
  4683. * future per-field-access multi-level fragment boundary checks and
  4684. * adjustments, given the complex format of Multi Link elements. It is
  4685. * also most likely to be required mainly at the client side.
  4686. * Fragmentation is currently unlikely to be required for subelements
  4687. * in Reconfiguration variant Multi-Link elements, but it should be
  4688. * handled in order to be future ready.
  4689. */
  4690. if (!linkinfo) {
  4691. mlo_err("linkinfo is NULL");
  4692. return QDF_STATUS_E_NULL_VALUE;
  4693. }
  4694. if (!linkinfo_len) {
  4695. mlo_err("linkinfo_len is zero");
  4696. return QDF_STATUS_E_NULL_VALUE;
  4697. }
  4698. if (!reconfig_info) {
  4699. mlo_err("ML reconfig info is NULL");
  4700. return QDF_STATUS_E_NULL_VALUE;
  4701. }
  4702. reconfig_info->num_links = 0;
  4703. linkinfo_currpos = linkinfo;
  4704. linkinfo_remlen = linkinfo_len;
  4705. while (linkinfo_remlen) {
  4706. if (linkinfo_remlen < sizeof(struct subelem_header)) {
  4707. mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
  4708. linkinfo_remlen,
  4709. sizeof(struct subelem_header));
  4710. return QDF_STATUS_E_PROTO;
  4711. }
  4712. subelemid = linkinfo_currpos[ID_POS];
  4713. is_subelemfragseq = false;
  4714. subelemseqtotallen = 0;
  4715. subelemseqpayloadlen = 0;
  4716. ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  4717. linkinfo_currpos,
  4718. linkinfo_remlen,
  4719. &is_subelemfragseq,
  4720. &subelemseqtotallen,
  4721. &subelemseqpayloadlen);
  4722. if (QDF_IS_STATUS_ERROR(ret))
  4723. return ret;
  4724. if (qdf_unlikely(is_subelemfragseq)) {
  4725. if (!subelemseqpayloadlen) {
  4726. mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
  4727. return QDF_STATUS_E_FAILURE;
  4728. }
  4729. mlo_debug("Subelement fragment sequence found with payload len %zu",
  4730. subelemseqpayloadlen);
  4731. ret = wlan_defrag_subelem_fragseq(true,
  4732. WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  4733. linkinfo_currpos,
  4734. linkinfo_remlen,
  4735. NULL,
  4736. 0,
  4737. &defragpayload_len);
  4738. if (QDF_IS_STATUS_ERROR(ret))
  4739. return ret;
  4740. if (defragpayload_len != subelemseqpayloadlen) {
  4741. mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
  4742. defragpayload_len,
  4743. subelemseqpayloadlen);
  4744. return QDF_STATUS_E_FAILURE;
  4745. }
  4746. /* Adjust linkinfo_remlen to reflect removal of all
  4747. * subelement headers except the header of the lead
  4748. * subelement.
  4749. */
  4750. linkinfo_remlen -= (subelemseqtotallen -
  4751. subelemseqpayloadlen -
  4752. sizeof(struct subelem_header));
  4753. } else {
  4754. if (linkinfo_remlen <
  4755. (sizeof(struct subelem_header) +
  4756. linkinfo_currpos[TAG_LEN_POS])) {
  4757. mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
  4758. linkinfo_remlen,
  4759. sizeof(struct subelem_header) +
  4760. linkinfo_currpos[TAG_LEN_POS]);
  4761. return QDF_STATUS_E_PROTO;
  4762. }
  4763. subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
  4764. }
  4765. if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
  4766. struct ml_rv_partner_link_info *link_info;
  4767. is_macaddr_valid = false;
  4768. is_ap_removal_timer_valid = false;
  4769. ret = util_parse_rvmlie_perstaprofile_stactrl(linkinfo_currpos +
  4770. sizeof(struct subelem_header),
  4771. subelemseqpayloadlen,
  4772. &linkid,
  4773. &is_macaddr_valid,
  4774. &mac_addr,
  4775. &is_ap_removal_timer_valid,
  4776. &ap_removal_timer);
  4777. if (QDF_IS_STATUS_ERROR(ret))
  4778. return ret;
  4779. if (reconfig_info->num_links >=
  4780. WLAN_UMAC_MLO_MAX_VDEVS) {
  4781. mlo_err("num_link %d invalid",
  4782. reconfig_info->num_links);
  4783. return QDF_STATUS_E_INVAL;
  4784. }
  4785. link_info =
  4786. &reconfig_info->link_info[reconfig_info->num_links];
  4787. link_info->link_id = linkid;
  4788. link_info->is_ap_removal_timer_p = is_ap_removal_timer_valid;
  4789. if (is_macaddr_valid)
  4790. qdf_copy_macaddr(&link_info->link_mac_addr,
  4791. &mac_addr);
  4792. if (is_ap_removal_timer_valid)
  4793. link_info->ap_removal_timer = ap_removal_timer;
  4794. else
  4795. mlo_warn_rl("AP removal timer not found in STA Info field of per-STA profile with link ID %u",
  4796. linkid);
  4797. mlo_debug("Per-STA Profile Link ID: %u AP removal timer present: %d AP removal timer: %u",
  4798. link_info->link_id,
  4799. link_info->is_ap_removal_timer_p,
  4800. link_info->ap_removal_timer);
  4801. reconfig_info->num_links++;
  4802. }
  4803. linkinfo_remlen -= (sizeof(struct subelem_header) +
  4804. subelemseqpayloadlen);
  4805. linkinfo_currpos += (sizeof(struct subelem_header) +
  4806. subelemseqpayloadlen);
  4807. }
  4808. mlo_debug("Number of ML probe request links found=%u",
  4809. reconfig_info->num_links);
  4810. return QDF_STATUS_SUCCESS;
  4811. }
  4812. QDF_STATUS util_get_rvmlie_persta_link_info(uint8_t *mlieseq,
  4813. qdf_size_t mlieseqlen,
  4814. struct ml_rv_info *reconfig_info)
  4815. {
  4816. struct wlan_ie_multilink *mlie_fixed;
  4817. uint16_t mlcontrol;
  4818. enum wlan_ml_variant variant;
  4819. uint8_t *linkinfo;
  4820. qdf_size_t linkinfo_len;
  4821. struct ml_rv_info rinfo = {0};
  4822. qdf_size_t mlieseqpayloadlen;
  4823. uint8_t *mlieseqpayload_copy;
  4824. bool is_elemfragseq;
  4825. qdf_size_t defragpayload_len;
  4826. qdf_size_t tmplen;
  4827. QDF_STATUS ret;
  4828. if (!mlieseq) {
  4829. mlo_err("Pointer to Multi-Link element sequence is NULL");
  4830. return QDF_STATUS_E_NULL_VALUE;
  4831. }
  4832. if (!mlieseqlen) {
  4833. mlo_err("Length of Multi-Link element sequence is zero");
  4834. return QDF_STATUS_E_INVAL;
  4835. }
  4836. if (!reconfig_info) {
  4837. mlo_err("reconfig_info is NULL");
  4838. return QDF_STATUS_E_NULL_VALUE;
  4839. }
  4840. reconfig_info->num_links = 0;
  4841. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  4842. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  4843. mlieseqlen, sizeof(struct wlan_ie_multilink));
  4844. return QDF_STATUS_E_INVAL;
  4845. }
  4846. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  4847. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  4848. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) {
  4849. mlo_err("The element is not a Multi-Link element");
  4850. return QDF_STATUS_E_INVAL;
  4851. }
  4852. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  4853. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  4854. WLAN_ML_CTRL_TYPE_BITS);
  4855. if (variant != WLAN_ML_VARIANT_RECONFIG) {
  4856. mlo_err("The variant value %u does not correspond to Reconfig Variant value %u",
  4857. variant, WLAN_ML_VARIANT_RECONFIG);
  4858. return QDF_STATUS_E_INVAL;
  4859. }
  4860. mlieseqpayloadlen = 0;
  4861. tmplen = 0;
  4862. is_elemfragseq = false;
  4863. ret = wlan_get_elem_fragseq_info(mlieseq,
  4864. mlieseqlen,
  4865. &is_elemfragseq,
  4866. &tmplen,
  4867. &mlieseqpayloadlen);
  4868. if (QDF_IS_STATUS_ERROR(ret))
  4869. return ret;
  4870. if (qdf_unlikely(is_elemfragseq)) {
  4871. if (tmplen != mlieseqlen) {
  4872. 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",
  4873. tmplen, mlieseqlen);
  4874. return QDF_STATUS_E_INVAL;
  4875. }
  4876. if (!mlieseqpayloadlen) {
  4877. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  4878. return QDF_STATUS_E_FAILURE;
  4879. }
  4880. mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
  4881. mlieseqpayloadlen);
  4882. } else {
  4883. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  4884. 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",
  4885. mlieseqlen,
  4886. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  4887. return QDF_STATUS_E_FAILURE;
  4888. }
  4889. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  4890. }
  4891. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  4892. if (!mlieseqpayload_copy) {
  4893. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  4894. return QDF_STATUS_E_NOMEM;
  4895. }
  4896. if (qdf_unlikely(is_elemfragseq)) {
  4897. ret = wlan_defrag_elem_fragseq(false,
  4898. mlieseq,
  4899. mlieseqlen,
  4900. mlieseqpayload_copy,
  4901. mlieseqpayloadlen,
  4902. &defragpayload_len);
  4903. if (QDF_IS_STATUS_ERROR(ret)) {
  4904. qdf_mem_free(mlieseqpayload_copy);
  4905. return ret;
  4906. }
  4907. if (defragpayload_len != mlieseqpayloadlen) {
  4908. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  4909. defragpayload_len, mlieseqpayloadlen);
  4910. qdf_mem_free(mlieseqpayload_copy);
  4911. return QDF_STATUS_E_FAILURE;
  4912. }
  4913. } else {
  4914. qdf_mem_copy(mlieseqpayload_copy,
  4915. mlieseq + sizeof(struct ie_header) + 1,
  4916. mlieseqpayloadlen);
  4917. }
  4918. linkinfo = NULL;
  4919. linkinfo_len = 0;
  4920. ret = util_parse_rv_multi_link_ctrl(mlieseqpayload_copy,
  4921. mlieseqpayloadlen,
  4922. &linkinfo,
  4923. &linkinfo_len);
  4924. if (QDF_IS_STATUS_ERROR(ret)) {
  4925. qdf_mem_free(mlieseqpayload_copy);
  4926. return ret;
  4927. }
  4928. /* In case Link Info is absent, the number of links will remain
  4929. * zero.
  4930. */
  4931. if (!linkinfo) {
  4932. qdf_mem_free(mlieseqpayload_copy);
  4933. return QDF_STATUS_SUCCESS;
  4934. }
  4935. ret = util_parse_rv_info_from_linkinfo(linkinfo, linkinfo_len, &rinfo);
  4936. if (QDF_IS_STATUS_ERROR(ret)) {
  4937. qdf_mem_free(mlieseqpayload_copy);
  4938. return ret;
  4939. }
  4940. qdf_mem_copy(reconfig_info, &rinfo, sizeof(*reconfig_info));
  4941. qdf_mem_free(mlieseqpayload_copy);
  4942. return QDF_STATUS_SUCCESS;
  4943. }
  4944. static QDF_STATUS
  4945. util_parse_pa_multi_link_ctrl(uint8_t *mlieseqpayload,
  4946. qdf_size_t mlieseqpayloadlen,
  4947. uint8_t **link_info,
  4948. qdf_size_t *link_info_len)
  4949. {
  4950. qdf_size_t parsed_payload_len;
  4951. /* This helper returns the location(s) and length(s) of (sub)field(s)
  4952. * inferable after parsing the Multi Link element Control field. These
  4953. * location(s) and length(s) is/are in reference to the payload section
  4954. * of the Multi Link element (after defragmentation, if applicable).
  4955. * Here, the payload is the point after the element ID extension of the
  4956. * Multi Link element, and includes the payloads of all subsequent
  4957. * fragments (if any) but not the headers of those fragments.
  4958. *
  4959. * Currently, the helper returns the location and length of the Link
  4960. * Info field in the Multi Link element sequence. Other (sub)field(s)
  4961. * can be added later as required.
  4962. */
  4963. if (!mlieseqpayload) {
  4964. mlo_err("ML seq payload pointer is NULL");
  4965. return QDF_STATUS_E_NULL_VALUE;
  4966. }
  4967. if (!mlieseqpayloadlen) {
  4968. mlo_err("ML seq payload len is 0");
  4969. return QDF_STATUS_E_INVAL;
  4970. }
  4971. if (mlieseqpayloadlen < WLAN_ML_CTRL_SIZE) {
  4972. mlo_err_rl("ML seq payload len %zu < ML Control size %u",
  4973. mlieseqpayloadlen, WLAN_ML_CTRL_SIZE);
  4974. return QDF_STATUS_E_PROTO;
  4975. }
  4976. parsed_payload_len = 0;
  4977. parsed_payload_len += WLAN_ML_CTRL_SIZE;
  4978. if (mlieseqpayloadlen <
  4979. (parsed_payload_len +
  4980. WLAN_ML_PAV_CINFO_LENGTH_MAX)) {
  4981. mlo_err_rl("ML seq payload len %zu insufficient for MLD cmn size %u after parsed payload len %zu.",
  4982. mlieseqpayloadlen,
  4983. WLAN_ML_PAV_CINFO_LENGTH_MAX,
  4984. parsed_payload_len);
  4985. return QDF_STATUS_E_PROTO;
  4986. }
  4987. parsed_payload_len += QDF_MAC_ADDR_SIZE + WLAN_ML_PAV_CINFO_LENGTH_SIZE;
  4988. if (link_info_len) {
  4989. *link_info_len = mlieseqpayloadlen - parsed_payload_len;
  4990. mlo_debug("link_info_len:%zu, parsed_payload_len:%zu",
  4991. *link_info_len, parsed_payload_len);
  4992. }
  4993. if (mlieseqpayloadlen == parsed_payload_len) {
  4994. mlo_debug("No Link Info field present");
  4995. if (link_info)
  4996. *link_info = NULL;
  4997. return QDF_STATUS_SUCCESS;
  4998. }
  4999. if (link_info)
  5000. *link_info = mlieseqpayload + parsed_payload_len;
  5001. return QDF_STATUS_SUCCESS;
  5002. }
  5003. static QDF_STATUS
  5004. util_parse_pamlie_perstaprofile_stactrl(uint8_t *subelempayload,
  5005. qdf_size_t subelempayloadlen,
  5006. struct ml_pa_partner_link_info *pa_link_info)
  5007. {
  5008. qdf_size_t parsed_payload_len = 0;
  5009. uint16_t stacontrol;
  5010. struct ie_header *ie;
  5011. struct extn_ie_header *extn_ie;
  5012. /* This helper returns the location(s) and where required, the length(s)
  5013. * of (sub)field(s) inferable after parsing the STA Control field in the
  5014. * per-STA profile subelement. These location(s) and length(s) is/are in
  5015. * reference to the payload section of the per-STA profile subelement
  5016. * (after defragmentation, if applicable). Here, the payload is the
  5017. * point after the subelement length in the subelement, and includes the
  5018. * payloads of all subsequent fragments (if any) but not the headers of
  5019. * those fragments.
  5020. *
  5021. * Currently, the helper returns the priority access link information
  5022. * for all parner links.
  5023. */
  5024. if (!subelempayload) {
  5025. mlo_err("Pointer to subelement payload is NULL");
  5026. return QDF_STATUS_E_NULL_VALUE;
  5027. }
  5028. if (!subelempayloadlen) {
  5029. mlo_err("Length of subelement payload is zero");
  5030. return QDF_STATUS_E_INVAL;
  5031. }
  5032. if (subelempayloadlen < WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE) {
  5033. mlo_err_rl("Subelement payload length %zu octets is smaller than STA control field of per-STA profile subelement %u octets",
  5034. subelempayloadlen,
  5035. WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE);
  5036. return QDF_STATUS_E_PROTO;
  5037. }
  5038. parsed_payload_len = 0;
  5039. qdf_mem_copy(&stacontrol,
  5040. subelempayload,
  5041. WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE);
  5042. stacontrol = qdf_le16_to_cpu(stacontrol);
  5043. parsed_payload_len += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE;
  5044. subelempayload += WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_SIZE;
  5045. pa_link_info->link_id =
  5046. QDF_GET_BITS(stacontrol,
  5047. WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX,
  5048. WLAN_ML_PAV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS);
  5049. pa_link_info->edca_ie_present = false;
  5050. pa_link_info->ven_wme_ie_present = false;
  5051. pa_link_info->muedca_ie_present = false;
  5052. do {
  5053. if (subelempayloadlen <
  5054. (parsed_payload_len +
  5055. sizeof(struct ie_header))) {
  5056. mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain min ie length %zu after parsed payload length of %zu octets",
  5057. subelempayloadlen,
  5058. sizeof(struct ie_header),
  5059. parsed_payload_len);
  5060. return QDF_STATUS_E_PROTO;
  5061. }
  5062. ie = (struct ie_header *)subelempayload;
  5063. if (subelempayloadlen <
  5064. (parsed_payload_len +
  5065. (sizeof(struct ie_header) + ie->ie_len))) {
  5066. mlo_err_rl("Length of subelement payload %zu octets not sufficient to contain ie length %zu after parsed payload length of %zu octets",
  5067. subelempayloadlen,
  5068. sizeof(struct ie_header) + ie->ie_len,
  5069. parsed_payload_len);
  5070. return QDF_STATUS_E_PROTO;
  5071. }
  5072. switch (ie->ie_id) {
  5073. case WLAN_ELEMID_EDCAPARMS:
  5074. if (pa_link_info->ven_wme_ie_present) {
  5075. /* WME parameters already present
  5076. * use that one instead of EDCA */
  5077. break;
  5078. }
  5079. if (ie->ie_len == (sizeof(struct edca_ie) -
  5080. sizeof(struct ie_header))) {
  5081. pa_link_info->edca_ie_present = true;
  5082. qdf_mem_copy(&pa_link_info->edca,
  5083. subelempayload,
  5084. sizeof(struct edca_ie));
  5085. } else {
  5086. epcs_debug("Invalid edca length %d in PAV IE",
  5087. ie->ie_len);
  5088. }
  5089. break;
  5090. case WLAN_ELEMID_VENDOR:
  5091. if (is_wme_param((uint8_t *)ie) &&
  5092. (ie->ie_len == WLAN_VENDOR_WME_IE_LEN)) {
  5093. pa_link_info->ven_wme_ie_present = true;
  5094. qdf_mem_copy(&pa_link_info->ven_wme_ie_bytes,
  5095. subelempayload,
  5096. sizeof(WLAN_VENDOR_WME_IE_LEN +
  5097. sizeof(struct ie_header)));
  5098. pa_link_info->edca_ie_present = false;
  5099. } else {
  5100. epcs_debug("Unrelated Venfor IE reecived ie_id %d ie_len %d",
  5101. ie->ie_id,
  5102. ie->ie_len);
  5103. }
  5104. break;
  5105. case WLAN_ELEMID_EXTN_ELEM:
  5106. extn_ie = (struct extn_ie_header *)ie;
  5107. switch (extn_ie->ie_extn_id) {
  5108. case WLAN_EXTN_ELEMID_MUEDCA:
  5109. if (extn_ie->ie_len == WLAN_MAX_MUEDCA_IE_LEN) {
  5110. pa_link_info->muedca_ie_present = true;
  5111. qdf_mem_copy(&pa_link_info->muedca,
  5112. subelempayload,
  5113. sizeof(struct muedca_ie));
  5114. } else {
  5115. epcs_debug("Invalid muedca length %d in PAV IE",
  5116. ie->ie_len);
  5117. }
  5118. break;
  5119. default:
  5120. epcs_debug("Unrelated Extn IE reecived ie_id %d ie_len %d extid %d IN PAV IE",
  5121. ie->ie_id,
  5122. ie->ie_len,
  5123. extn_ie->ie_extn_id);
  5124. break;
  5125. }
  5126. break;
  5127. default:
  5128. epcs_debug("Unrelated IE reecived ie_id %d ie_len %d in PAV IE",
  5129. ie->ie_id,
  5130. ie->ie_len);
  5131. break;
  5132. }
  5133. subelempayload += ie->ie_len + sizeof(struct ie_header);
  5134. parsed_payload_len += ie->ie_len + sizeof(struct ie_header);
  5135. } while (parsed_payload_len < subelempayloadlen);
  5136. if (parsed_payload_len != subelempayloadlen)
  5137. epcs_debug("Error in processing per sta profile of PA ML IE %zu %zu",
  5138. parsed_payload_len,
  5139. subelempayloadlen);
  5140. epcs_debug("Link id %d presence of edca %d muedca %d wme %d",
  5141. pa_link_info->link_id,
  5142. pa_link_info->edca_ie_present,
  5143. pa_link_info->muedca_ie_present,
  5144. pa_link_info->ven_wme_ie_present);
  5145. return QDF_STATUS_SUCCESS;
  5146. }
  5147. static QDF_STATUS
  5148. util_parse_pa_info_from_linkinfo(uint8_t *linkinfo,
  5149. qdf_size_t linkinfo_len,
  5150. struct ml_pa_info *pa_info)
  5151. {
  5152. uint8_t *linkinfo_currpos;
  5153. qdf_size_t linkinfo_remlen;
  5154. bool is_subelemfragseq;
  5155. uint8_t subelemid;
  5156. qdf_size_t subelemseqtotallen;
  5157. qdf_size_t subelemseqpayloadlen;
  5158. qdf_size_t defragpayload_len;
  5159. QDF_STATUS ret;
  5160. /* This helper function parses priority access info from the per-STA
  5161. * prof present (if any) in the Link Info field in the payload of a
  5162. * Multi Link element (after defragmentation if required). The caller
  5163. * should pass a copy of the payload so that inline defragmentation of
  5164. * subelements can be carried out if required. The subelement
  5165. * defragmentation (if applicable) in this Control Path helper is
  5166. * required for maintainability, accuracy and eliminating current and
  5167. * future per-field-access multi-level fragment boundary checks and
  5168. * adjustments, given the complex format of Multi Link elements. It is
  5169. * also most likely to be required mainly at the client side.
  5170. * Fragmentation is currently unlikely to be required for subelements
  5171. * in Reconfiguration variant Multi-Link elements, but it should be
  5172. * handled in order to be future ready.
  5173. */
  5174. if (!linkinfo) {
  5175. mlo_err("linkinfo is NULL");
  5176. return QDF_STATUS_E_NULL_VALUE;
  5177. }
  5178. if (!linkinfo_len) {
  5179. mlo_err("linkinfo_len is zero");
  5180. return QDF_STATUS_E_NULL_VALUE;
  5181. }
  5182. if (!pa_info) {
  5183. mlo_err("ML pa info is NULL");
  5184. return QDF_STATUS_E_NULL_VALUE;
  5185. }
  5186. pa_info->num_links = 0;
  5187. linkinfo_currpos = linkinfo;
  5188. linkinfo_remlen = linkinfo_len;
  5189. while (linkinfo_remlen) {
  5190. if (linkinfo_remlen < sizeof(struct subelem_header)) {
  5191. mlo_err_rl("Remaining length in link info %zu octets is smaller than subelement header length %zu octets",
  5192. linkinfo_remlen,
  5193. sizeof(struct subelem_header));
  5194. return QDF_STATUS_E_PROTO;
  5195. }
  5196. subelemid = linkinfo_currpos[ID_POS];
  5197. is_subelemfragseq = false;
  5198. subelemseqtotallen = 0;
  5199. subelemseqpayloadlen = 0;
  5200. ret = wlan_get_subelem_fragseq_info(WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  5201. linkinfo_currpos,
  5202. linkinfo_remlen,
  5203. &is_subelemfragseq,
  5204. &subelemseqtotallen,
  5205. &subelemseqpayloadlen);
  5206. if (QDF_IS_STATUS_ERROR(ret))
  5207. return ret;
  5208. if (qdf_unlikely(is_subelemfragseq)) {
  5209. if (!subelemseqpayloadlen) {
  5210. mlo_err_rl("Subelement fragment sequence payload is reported as 0, investigate");
  5211. return QDF_STATUS_E_FAILURE;
  5212. }
  5213. mlo_debug("Subelement fragment sequence found with payload len %zu",
  5214. subelemseqpayloadlen);
  5215. ret = wlan_defrag_subelem_fragseq(true,
  5216. WLAN_ML_LINFO_SUBELEMID_FRAGMENT,
  5217. linkinfo_currpos,
  5218. linkinfo_remlen,
  5219. NULL,
  5220. 0,
  5221. &defragpayload_len);
  5222. if (QDF_IS_STATUS_ERROR(ret))
  5223. return ret;
  5224. if (defragpayload_len != subelemseqpayloadlen) {
  5225. mlo_err_rl("Length of defragmented payload %zu octets is not equal to length of subelement fragment sequence payload %zu octets",
  5226. defragpayload_len,
  5227. subelemseqpayloadlen);
  5228. return QDF_STATUS_E_FAILURE;
  5229. }
  5230. /* Adjust linkinfo_remlen to reflect removal of all
  5231. * subelement headers except the header of the lead
  5232. * subelement.
  5233. */
  5234. linkinfo_remlen -= (subelemseqtotallen -
  5235. subelemseqpayloadlen -
  5236. sizeof(struct subelem_header));
  5237. } else {
  5238. if (linkinfo_remlen <
  5239. (sizeof(struct subelem_header) +
  5240. linkinfo_currpos[TAG_LEN_POS])) {
  5241. mlo_err_rl("Remaining length in link info %zu octets is smaller than total size of current subelement %zu octets",
  5242. linkinfo_remlen,
  5243. sizeof(struct subelem_header) +
  5244. linkinfo_currpos[TAG_LEN_POS]);
  5245. return QDF_STATUS_E_PROTO;
  5246. }
  5247. subelemseqpayloadlen = linkinfo_currpos[TAG_LEN_POS];
  5248. }
  5249. if (subelemid == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) {
  5250. struct ml_pa_partner_link_info *link_info =
  5251. &pa_info->link_info[pa_info->num_links];
  5252. ret = util_parse_pamlie_perstaprofile_stactrl(linkinfo_currpos +
  5253. sizeof(struct subelem_header),
  5254. subelemseqpayloadlen,
  5255. link_info);
  5256. if (QDF_IS_STATUS_ERROR(ret))
  5257. return ret;
  5258. }
  5259. pa_info->num_links++;
  5260. linkinfo_remlen -= (sizeof(struct subelem_header) +
  5261. subelemseqpayloadlen);
  5262. linkinfo_currpos += (sizeof(struct subelem_header) +
  5263. subelemseqpayloadlen);
  5264. }
  5265. mlo_debug("Number of ML probe request links found=%u",
  5266. pa_info->num_links);
  5267. return QDF_STATUS_SUCCESS;
  5268. }
  5269. QDF_STATUS
  5270. util_get_pav_mlie_link_info(uint8_t *mlieseq,
  5271. qdf_size_t mlieseqlen,
  5272. struct ml_pa_info *pa_info)
  5273. {
  5274. struct wlan_ie_multilink *mlie_fixed;
  5275. uint16_t mlcontrol;
  5276. enum wlan_ml_variant variant;
  5277. uint8_t *linkinfo;
  5278. qdf_size_t linkinfo_len;
  5279. struct ml_pa_info painfo = {0};
  5280. qdf_size_t mlieseqpayloadlen;
  5281. uint8_t *mlieseqpayload_copy;
  5282. bool is_elemfragseq;
  5283. qdf_size_t defragpayload_len;
  5284. qdf_size_t tmplen;
  5285. QDF_STATUS ret;
  5286. if (!mlieseq) {
  5287. mlo_err("Pointer to Multi-Link element sequence is NULL");
  5288. return QDF_STATUS_E_NULL_VALUE;
  5289. }
  5290. if (!mlieseqlen) {
  5291. mlo_err("Length of Multi-Link element sequence is zero");
  5292. return QDF_STATUS_E_INVAL;
  5293. }
  5294. if (!pa_info) {
  5295. mlo_err("pa_info is NULL");
  5296. return QDF_STATUS_E_NULL_VALUE;
  5297. }
  5298. pa_info->num_links = 0;
  5299. if (mlieseqlen < sizeof(struct wlan_ie_multilink)) {
  5300. mlo_err_rl("Multi-Link element sequence length %zu octets is smaller than required for the fixed portion of Multi-Link element (%zu octets)",
  5301. mlieseqlen, sizeof(struct wlan_ie_multilink));
  5302. return QDF_STATUS_E_INVAL;
  5303. }
  5304. mlie_fixed = (struct wlan_ie_multilink *)mlieseq;
  5305. if (mlie_fixed->elem_id != WLAN_ELEMID_EXTN_ELEM ||
  5306. mlie_fixed->elem_id_ext != WLAN_EXTN_ELEMID_MULTI_LINK) {
  5307. mlo_err("The element is not a Multi-Link element");
  5308. return QDF_STATUS_E_INVAL;
  5309. }
  5310. mlcontrol = qdf_le16_to_cpu(mlie_fixed->mlcontrol);
  5311. variant = QDF_GET_BITS(mlcontrol, WLAN_ML_CTRL_TYPE_IDX,
  5312. WLAN_ML_CTRL_TYPE_BITS);
  5313. if (variant != WLAN_ML_VARIANT_PRIORITYACCESS) {
  5314. mlo_err("The variant value %u does not correspond to priority access Variant value %u",
  5315. variant, WLAN_ML_VARIANT_PRIORITYACCESS);
  5316. return QDF_STATUS_E_INVAL;
  5317. }
  5318. mlieseqpayloadlen = 0;
  5319. tmplen = 0;
  5320. is_elemfragseq = false;
  5321. ret = wlan_get_elem_fragseq_info(mlieseq,
  5322. mlieseqlen,
  5323. &is_elemfragseq,
  5324. &tmplen,
  5325. &mlieseqpayloadlen);
  5326. if (QDF_IS_STATUS_ERROR(ret))
  5327. return ret;
  5328. if (qdf_unlikely(is_elemfragseq)) {
  5329. if (tmplen != mlieseqlen) {
  5330. 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",
  5331. tmplen, mlieseqlen);
  5332. return QDF_STATUS_E_INVAL;
  5333. }
  5334. if (!mlieseqpayloadlen) {
  5335. mlo_err_rl("Multi-Link element fragment sequence payload is reported as 0, investigate");
  5336. return QDF_STATUS_E_FAILURE;
  5337. }
  5338. mlo_debug("Multi-Link element fragment sequence found with payload len %zu",
  5339. mlieseqpayloadlen);
  5340. } else {
  5341. if (mlieseqlen > (sizeof(struct ie_header) + WLAN_MAX_IE_LEN)) {
  5342. 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",
  5343. mlieseqlen,
  5344. sizeof(struct ie_header) + WLAN_MAX_IE_LEN);
  5345. return QDF_STATUS_E_FAILURE;
  5346. }
  5347. mlieseqpayloadlen = mlieseqlen - (sizeof(struct ie_header) + 1);
  5348. }
  5349. mlieseqpayload_copy = qdf_mem_malloc(mlieseqpayloadlen);
  5350. if (!mlieseqpayload_copy) {
  5351. mlo_err_rl("Could not allocate memory for Multi-Link element payload copy");
  5352. return QDF_STATUS_E_NOMEM;
  5353. }
  5354. if (qdf_unlikely(is_elemfragseq)) {
  5355. ret = wlan_defrag_elem_fragseq(false,
  5356. mlieseq,
  5357. mlieseqlen,
  5358. mlieseqpayload_copy,
  5359. mlieseqpayloadlen,
  5360. &defragpayload_len);
  5361. if (QDF_IS_STATUS_ERROR(ret)) {
  5362. qdf_mem_free(mlieseqpayload_copy);
  5363. return ret;
  5364. }
  5365. if (defragpayload_len != mlieseqpayloadlen) {
  5366. mlo_err_rl("Length of de-fragmented payload %zu octets is not equal to length of Multi-Link element fragment sequence payload %zu octets",
  5367. defragpayload_len, mlieseqpayloadlen);
  5368. qdf_mem_free(mlieseqpayload_copy);
  5369. return QDF_STATUS_E_FAILURE;
  5370. }
  5371. } else {
  5372. qdf_mem_copy(mlieseqpayload_copy,
  5373. mlieseq + sizeof(struct ie_header) + 1,
  5374. mlieseqpayloadlen);
  5375. }
  5376. linkinfo = NULL;
  5377. linkinfo_len = 0;
  5378. ret = util_parse_pa_multi_link_ctrl(mlieseqpayload_copy,
  5379. mlieseqpayloadlen,
  5380. &linkinfo,
  5381. &linkinfo_len);
  5382. if (QDF_IS_STATUS_ERROR(ret)) {
  5383. qdf_mem_free(mlieseqpayload_copy);
  5384. return ret;
  5385. }
  5386. /* In case Link Info is absent, the number of links will remain
  5387. * zero.
  5388. */
  5389. if (!linkinfo) {
  5390. qdf_mem_free(mlieseqpayload_copy);
  5391. return QDF_STATUS_SUCCESS;
  5392. }
  5393. mlo_debug("Dumping hex of link info after parsing Multi-Link element control");
  5394. QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLO, QDF_TRACE_LEVEL_ERROR,
  5395. linkinfo, linkinfo_len);
  5396. ret = util_parse_pa_info_from_linkinfo(linkinfo, linkinfo_len, &painfo);
  5397. if (QDF_IS_STATUS_ERROR(ret)) {
  5398. qdf_mem_free(mlieseqpayload_copy);
  5399. return ret;
  5400. }
  5401. qdf_mem_copy(pa_info, &painfo, sizeof(painfo));
  5402. qdf_mem_free(mlieseqpayload_copy);
  5403. return QDF_STATUS_SUCCESS;
  5404. }
  5405. #endif
  5406. #ifdef WLAN_FEATURE_11BE
  5407. QDF_STATUS util_add_bw_ind(struct wlan_ie_bw_ind *bw_ind, uint8_t ccfs0,
  5408. uint8_t ccfs1, enum phy_ch_width ch_width,
  5409. uint16_t puncture_bitmap, int *bw_ind_len)
  5410. {
  5411. uint8_t bw_ind_width;
  5412. if (!bw_ind) {
  5413. mlo_err("Pointer to bandwidth indiaction element is NULL");
  5414. return QDF_STATUS_E_NULL_VALUE;
  5415. }
  5416. if (!bw_ind_len) {
  5417. mlo_err("Length of bandwidth indaication element is Zero");
  5418. return QDF_STATUS_E_INVAL;
  5419. }
  5420. switch (ch_width) {
  5421. case CH_WIDTH_20MHZ:
  5422. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_20;
  5423. break;
  5424. case CH_WIDTH_40MHZ:
  5425. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_40;
  5426. break;
  5427. case CH_WIDTH_80MHZ:
  5428. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_80;
  5429. break;
  5430. case CH_WIDTH_160MHZ:
  5431. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_160;
  5432. break;
  5433. case CH_WIDTH_320MHZ:
  5434. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_320;
  5435. break;
  5436. default:
  5437. bw_ind_width = IEEE80211_11BEOP_CHWIDTH_20;
  5438. }
  5439. bw_ind->elem_id = WLAN_ELEMID_EXTN_ELEM;
  5440. *bw_ind_len = WLAN_BW_IND_IE_MAX_LEN;
  5441. bw_ind->elem_len = WLAN_BW_IND_IE_MAX_LEN - WLAN_IE_HDR_LEN;
  5442. bw_ind->elem_id_extn = WLAN_EXTN_ELEMID_BW_IND;
  5443. bw_ind->ccfs0 = ccfs0;
  5444. bw_ind->ccfs1 = ccfs1;
  5445. QDF_SET_BITS(bw_ind->control, BW_IND_CHAN_WIDTH_IDX,
  5446. BW_IND_CHAN_WIDTH_BITS, bw_ind_width);
  5447. if (puncture_bitmap) {
  5448. bw_ind->disabled_sub_chan_bitmap[0] =
  5449. QDF_GET_BITS(puncture_bitmap, 0, 8);
  5450. bw_ind->disabled_sub_chan_bitmap[1] =
  5451. QDF_GET_BITS(puncture_bitmap, 8, 8);
  5452. QDF_SET_BITS(bw_ind->bw_ind_param,
  5453. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX,
  5454. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS, 1);
  5455. } else {
  5456. QDF_SET_BITS(bw_ind->bw_ind_param,
  5457. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX,
  5458. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS, 0);
  5459. bw_ind->elem_len -=
  5460. QDF_ARRAY_SIZE(bw_ind->disabled_sub_chan_bitmap);
  5461. *bw_ind_len -=
  5462. QDF_ARRAY_SIZE(bw_ind->disabled_sub_chan_bitmap);
  5463. }
  5464. return QDF_STATUS_SUCCESS;
  5465. }
  5466. QDF_STATUS util_parse_bw_ind(struct wlan_ie_bw_ind *bw_ind, uint8_t *ccfs0,
  5467. uint8_t *ccfs1, enum phy_ch_width *ch_width,
  5468. uint16_t *puncture_bitmap)
  5469. {
  5470. uint8_t bw_ind_width;
  5471. if (!bw_ind) {
  5472. mlo_err("Pointer to bandwidth indiaction element is NULL");
  5473. return QDF_STATUS_E_NULL_VALUE;
  5474. }
  5475. *ccfs0 = bw_ind->ccfs0;
  5476. *ccfs1 = bw_ind->ccfs1;
  5477. bw_ind_width = QDF_GET_BITS(bw_ind->control, BW_IND_CHAN_WIDTH_IDX,
  5478. BW_IND_CHAN_WIDTH_BITS);
  5479. switch (bw_ind_width) {
  5480. case IEEE80211_11BEOP_CHWIDTH_20:
  5481. *ch_width = CH_WIDTH_20MHZ;
  5482. break;
  5483. case IEEE80211_11BEOP_CHWIDTH_40:
  5484. *ch_width = CH_WIDTH_40MHZ;
  5485. break;
  5486. case IEEE80211_11BEOP_CHWIDTH_80:
  5487. *ch_width = CH_WIDTH_80MHZ;
  5488. break;
  5489. case IEEE80211_11BEOP_CHWIDTH_160:
  5490. *ch_width = CH_WIDTH_160MHZ;
  5491. break;
  5492. case IEEE80211_11BEOP_CHWIDTH_320:
  5493. *ch_width = CH_WIDTH_320MHZ;
  5494. break;
  5495. default:
  5496. *ch_width = CH_WIDTH_20MHZ;
  5497. }
  5498. if (QDF_GET_BITS(bw_ind->bw_ind_param,
  5499. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX,
  5500. BW_IND_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS)) {
  5501. QDF_SET_BITS(*puncture_bitmap, 0, 8,
  5502. bw_ind->disabled_sub_chan_bitmap[0]);
  5503. QDF_SET_BITS(*puncture_bitmap, 8, 8,
  5504. bw_ind->disabled_sub_chan_bitmap[1]);
  5505. } else {
  5506. *puncture_bitmap = 0;
  5507. }
  5508. return QDF_STATUS_SUCCESS;
  5509. }
  5510. #endif