wl_android.c 325 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098
  1. /*
  2. * Linux cfg80211 driver - Android related functions
  3. *
  4. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  5. *
  6. * Copyright (C) 1999-2020, Broadcom Corporation
  7. *
  8. * Unless you and Broadcom execute a separate written software license
  9. * agreement governing use of this software, this software is licensed to you
  10. * under the terms of the GNU General Public License version 2 (the "GPL"),
  11. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  12. * following added to such license:
  13. *
  14. * As a special exception, the copyright holders of this software give you
  15. * permission to link this software with independent modules, and to copy and
  16. * distribute the resulting executable under terms of your choice, provided that
  17. * you also meet, for each linked independent module, the terms and conditions of
  18. * the license of that module. An independent module is a module which is not
  19. * derived from this software. The special exception does not apply to any
  20. * modifications of the software.
  21. *
  22. * Notwithstanding the above, under no circumstances may you combine this
  23. * software in any way with any other Broadcom software provided under a license
  24. * other than the GPL, without Broadcom's express prior written consent.
  25. *
  26. *
  27. * <<Broadcom-WL-IPTag/Open:>>
  28. *
  29. * $Id: wl_android.c 814826 2019-04-15 05:25:59Z $
  30. */
  31. #include <linux/module.h>
  32. #include <linux/netdevice.h>
  33. #include <net/netlink.h>
  34. #include <wl_android.h>
  35. #include <wldev_common.h>
  36. #include <wlioctl.h>
  37. #include <wlioctl_utils.h>
  38. #include <bcmutils.h>
  39. #include <bcmstdlib_s.h>
  40. #include <linux_osl.h>
  41. #include <dhd_dbg.h>
  42. #include <dngl_stats.h>
  43. #include <dhd.h>
  44. #include <bcmip.h>
  45. #ifdef PNO_SUPPORT
  46. #include <dhd_pno.h>
  47. #endif // endif
  48. #ifdef BCMSDIO
  49. #include <bcmsdbus.h>
  50. #endif // endif
  51. #ifdef WL_CFG80211
  52. #include <wl_cfg80211.h>
  53. #include <wl_cfgscan.h>
  54. #endif // endif
  55. #ifdef WL_NAN
  56. #include <wl_cfgnan.h>
  57. #endif /* WL_NAN */
  58. #ifdef DHDTCPACK_SUPPRESS
  59. #include <dhd_ip.h>
  60. #endif /* DHDTCPACK_SUPPRESS */
  61. #include <bcmwifi_rspec.h>
  62. #include <dhd_linux.h>
  63. #include <bcmiov.h>
  64. #ifdef DHD_PKT_LOGGING
  65. #include <dhd_pktlog.h>
  66. #endif /* DHD_PKT_LOGGING */
  67. #ifdef WL_BCNRECV
  68. #include <wl_cfgvendor.h>
  69. #include <brcm_nl80211.h>
  70. #endif /* WL_BCNRECV */
  71. #ifdef WL_MBO
  72. #include <mbo.h>
  73. #endif /* WL_MBO */
  74. #ifdef DHD_BANDSTEER
  75. #include <dhd_bandsteer.h>
  76. #endif /* DHD_BANDSTEER */
  77. #ifdef WL_STATIC_IF
  78. #define WL_BSSIDX_MAX 16
  79. #endif /* WL_STATIC_IF */
  80. /*
  81. * Android private command strings, PLEASE define new private commands here
  82. * so they can be updated easily in the future (if needed)
  83. */
  84. #define CMD_START "START"
  85. #define CMD_STOP "STOP"
  86. #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
  87. #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
  88. #define CMD_RSSI "RSSI"
  89. #define CMD_LINKSPEED "LINKSPEED"
  90. #define CMD_RXFILTER_START "RXFILTER-START"
  91. #define CMD_RXFILTER_STOP "RXFILTER-STOP"
  92. #define CMD_RXFILTER_ADD "RXFILTER-ADD"
  93. #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
  94. #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
  95. #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
  96. #define CMD_BTCOEXMODE "BTCOEXMODE"
  97. #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
  98. #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
  99. #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
  100. #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
  101. #define CMD_DISDTIM_IN_SUSPEND "DISABLE_DTIM_IN_SUSPEND"
  102. #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
  103. #define CMD_SETFWPATH "SETFWPATH"
  104. #define CMD_SETBAND "SETBAND"
  105. #define CMD_GETBAND "GETBAND"
  106. #define CMD_COUNTRY "COUNTRY"
  107. #define CMD_P2P_SET_NOA "P2P_SET_NOA"
  108. #if !defined WL_ENABLE_P2P_IF
  109. #define CMD_P2P_GET_NOA "P2P_GET_NOA"
  110. #endif /* WL_ENABLE_P2P_IF */
  111. #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
  112. #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
  113. #define CMD_P2P_SET_PS "P2P_SET_PS"
  114. #define CMD_P2P_ECSA "P2P_ECSA"
  115. #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
  116. #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
  117. #define CMD_SETROAMMODE "SETROAMMODE"
  118. #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
  119. #define CMD_MIRACAST "MIRACAST"
  120. #ifdef WL_NAN
  121. #define CMD_NAN "NAN_"
  122. #endif /* WL_NAN */
  123. #define CMD_COUNTRY_DELIMITER "/"
  124. #if defined(WL_SUPPORT_AUTO_CHANNEL)
  125. #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
  126. #endif /* WL_SUPPORT_AUTO_CHANNEL */
  127. #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
  128. #define CMD_CHANSPEC "CHANSPEC"
  129. #define CMD_DATARATE "DATARATE"
  130. #define CMD_ASSOC_CLIENTS "ASSOCLIST"
  131. #define CMD_SET_CSA "SETCSA"
  132. #define CMD_RSDB_MODE "RSDB_MODE"
  133. #ifdef WL_SUPPORT_AUTO_CHANNEL
  134. #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
  135. #endif /* WL_SUPPORT_AUTO_CHANNEL */
  136. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  137. /* Hostapd private command */
  138. #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
  139. #define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC"
  140. #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
  141. #ifdef SUPPORT_SET_LPC
  142. #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
  143. #endif /* SUPPORT_SET_LPC */
  144. #ifdef SUPPORT_TRIGGER_HANG_EVENT
  145. #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
  146. #endif /* SUPPORT_TRIGGER_HANG_EVENT */
  147. #ifdef SUPPORT_LTECX
  148. #define CMD_LTECX_SET "LTECOEX"
  149. #endif /* SUPPORT_LTECX */
  150. #ifdef TEST_TX_POWER_CONTROL
  151. #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
  152. #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
  153. #endif /* TEST_TX_POWER_CONTROL */
  154. #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
  155. #ifdef SUPPORT_SET_TID
  156. #define CMD_SET_TID "SET_TID"
  157. #define CMD_GET_TID "GET_TID"
  158. #endif /* SUPPORT_SET_TID */
  159. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  160. #define CMD_KEEP_ALIVE "KEEPALIVE"
  161. #ifdef SUPPORT_HIDDEN_AP
  162. #define CMD_SET_HAPD_MAX_NUM_STA "MAX_NUM_STA"
  163. #define CMD_SET_HAPD_SSID "HAPD_SSID"
  164. #define CMD_SET_HAPD_HIDE_SSID "HIDE_SSID"
  165. #endif /* SUPPORT_HIDDEN_AP */
  166. #ifdef PNO_SUPPORT
  167. #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
  168. #define CMD_PNOSETUP_SET "PNOSETUP "
  169. #define CMD_PNOENABLE_SET "PNOFORCE"
  170. #define CMD_PNODEBUG_SET "PNODEBUG"
  171. #define CMD_WLS_BATCHING "WLS_BATCHING"
  172. #endif /* PNO_SUPPORT */
  173. #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
  174. #define CMD_ADDIE "ADD_IE"
  175. #define CMD_DELIE "DEL_IE"
  176. #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
  177. #ifdef ROAM_API
  178. #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
  179. #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
  180. #define CMD_ROAMDELTA_SET "SETROAMDELTA"
  181. #define CMD_ROAMDELTA_GET "GETROAMDELTA"
  182. #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
  183. #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
  184. #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
  185. #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
  186. #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
  187. #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
  188. #endif /* ROAM_API */
  189. #if defined(SUPPORT_RANDOM_MAC_SCAN)
  190. #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
  191. #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
  192. #endif /* SUPPORT_RANDOM_MAC_SCAN */
  193. #ifdef WES_SUPPORT
  194. #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
  195. #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
  196. #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
  197. #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
  198. #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
  199. #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
  200. #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
  201. #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
  202. #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
  203. #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
  204. #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
  205. #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
  206. #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
  207. #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
  208. #define CMD_GETSCANNPROBES "GETSCANNPROBES"
  209. #define CMD_SETSCANNPROBES "SETSCANNPROBES"
  210. #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
  211. #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
  212. #define CMD_SETJOINPREFER "SETJOINPREFER"
  213. #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
  214. #define CMD_REASSOC "REASSOC"
  215. #define CMD_GETWESMODE "GETWESMODE"
  216. #define CMD_SETWESMODE "SETWESMODE"
  217. #define CMD_GETOKCMODE "GETOKCMODE"
  218. #define CMD_SETOKCMODE "SETOKCMODE"
  219. #define CMD_OKC_SET_PMK "SET_PMK"
  220. #define CMD_OKC_ENABLE "OKC_ENABLE"
  221. typedef struct android_wifi_reassoc_params {
  222. unsigned char bssid[18];
  223. int channel;
  224. } android_wifi_reassoc_params_t;
  225. #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
  226. #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
  227. typedef struct android_wifi_af_params {
  228. unsigned char bssid[18];
  229. int channel;
  230. int dwell_time;
  231. int len;
  232. unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
  233. } android_wifi_af_params_t;
  234. #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
  235. #endif /* WES_SUPPORT */
  236. #ifdef SUPPORT_AMPDU_MPDU_CMD
  237. #define CMD_AMPDU_MPDU "AMPDU_MPDU"
  238. #endif /* SUPPORT_AMPDU_MPDU_CMD */
  239. #define CMD_CHANGE_RL "CHANGE_RL"
  240. #define CMD_RESTORE_RL "RESTORE_RL"
  241. #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
  242. #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
  243. #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
  244. #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
  245. #define CMD_SET_RMC_LEADER "SETRMCLEADER"
  246. #define CMD_SET_RMC_EVENT "SETRMCEVENT"
  247. #define CMD_SET_SCSCAN "SETSINGLEANT"
  248. #define CMD_GET_SCSCAN "GETSINGLEANT"
  249. #ifdef WLTDLS
  250. #define CMD_TDLS_RESET "TDLS_RESET"
  251. #endif /* WLTDLS */
  252. #ifdef CONFIG_SILENT_ROAM
  253. #define CMD_SROAM_TURN_ON "SROAMTURNON"
  254. #define CMD_SROAM_SET_INFO "SROAMSETINFO"
  255. #define CMD_SROAM_GET_INFO "SROAMGETINFO"
  256. #endif /* CONFIG_SILENT_ROAM */
  257. #define CMD_SET_DISCONNECT_IES "SET_DISCONNECT_IES"
  258. #ifdef FCC_PWR_LIMIT_2G
  259. #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
  260. #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
  261. /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
  262. #define CUSTOMER_HW4_ENABLE 0
  263. #define CUSTOMER_HW4_DISABLE -1
  264. #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
  265. #endif /* FCC_PWR_LIMIT_2G */
  266. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  267. #ifdef WLFBT
  268. #define CMD_GET_FTKEY "GET_FTKEY"
  269. #endif // endif
  270. #ifdef WLAIBSS
  271. #define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT"
  272. #define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO"
  273. #define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL"
  274. #define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE"
  275. #define CMD_SETIBSSAMPDU "SETIBSSAMPDU"
  276. #define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE"
  277. #endif /* WLAIBSS */
  278. #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
  279. #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
  280. #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
  281. #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
  282. #if defined(DHD_ENABLE_BIGDATA_LOGGING)
  283. #define CMD_GET_BSS_INFO "GETBSSINFO"
  284. #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
  285. #endif /* DHD_ENABLE_BIGDATA_LOGGING */
  286. #define CMD_GET_STA_INFO "GETSTAINFO"
  287. /* related with CMD_GET_LINK_STATUS */
  288. #define WL_ANDROID_LINK_VHT 0x01
  289. #define WL_ANDROID_LINK_MIMO 0x02
  290. #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
  291. #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
  292. #ifdef P2PRESP_WFDIE_SRC
  293. #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
  294. #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
  295. #endif /* P2PRESP_WFDIE_SRC */
  296. #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
  297. #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
  298. #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
  299. #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
  300. #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
  301. #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
  302. #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
  303. #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
  304. #define CMD_WBTEXT_ESTM_ENABLE "WBTEXT_ESTM_ENABLE"
  305. #ifdef WBTEXT
  306. #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
  307. #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
  308. #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
  309. #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
  310. #define DEFAULT_WBTEXT_PROFILE_A_V2 "a -70 -75 70 10 -75 -128 0 10"
  311. #define DEFAULT_WBTEXT_PROFILE_B_V2 "b -60 -75 70 10 -75 -128 0 10"
  312. #define DEFAULT_WBTEXT_PROFILE_A_V3 "a -70 -75 70 10 -75 -128 0 10"
  313. #define DEFAULT_WBTEXT_PROFILE_B_V3 "b -60 -75 70 10 -75 -128 0 10"
  314. #define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
  315. #define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
  316. #define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
  317. #define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
  318. #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A "ESTM_DL a 70"
  319. #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B "ESTM_DL b 70"
  320. #ifdef WBTEXT_SCORE_V2
  321. #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
  322. 60 70 60 70 80 20 80 128 20"
  323. #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
  324. 60 70 60 70 80 20 80 128 20"
  325. #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 80 20 \
  326. 80 100 20"
  327. #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 70 20 \
  328. 70 100 20"
  329. #else
  330. #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
  331. 60 65 70 65 70 50 70 128 20"
  332. #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
  333. 60 65 70 65 70 50 70 128 20"
  334. #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
  335. 50 60 70 60 80 50 80 100 20"
  336. #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
  337. 25 40 70 40 70 50 70 100 20"
  338. #endif /* WBTEXT_SCORE_V2 */
  339. #endif /* WBTEXT */
  340. #define BUFSZ 8
  341. #define BUFSZN BUFSZ + 1
  342. #define _S(x) #x
  343. #define S(x) _S(x)
  344. #define MAXBANDS 2 /**< Maximum #of bands */
  345. #define BAND_2G_INDEX 0
  346. #define BAND_5G_INDEX 0
  347. typedef union {
  348. wl_roam_prof_band_v1_t v1;
  349. wl_roam_prof_band_v2_t v2;
  350. wl_roam_prof_band_v3_t v3;
  351. } wl_roamprof_band_t;
  352. #ifdef WLWFDS
  353. #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
  354. #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
  355. #endif /* WLWFDS */
  356. #ifdef SET_RPS_CPUS
  357. #define CMD_RPSMODE "RPSMODE"
  358. #endif /* SET_RPS_CPUS */
  359. #ifdef BT_WIFI_HANDOVER
  360. #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
  361. #endif /* BT_WIFI_HANDOVER */
  362. #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
  363. #ifdef SUPPORT_RSSI_SUM_REPORT
  364. #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
  365. #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
  366. #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
  367. #endif /* SUPPORT_RSSI_SUM_REPORT */
  368. #define CMD_GET_SNR "GET_SNR"
  369. #ifdef SUPPORT_AP_HIGHER_BEACONRATE
  370. #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
  371. #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
  372. #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
  373. #ifdef SUPPORT_AP_RADIO_PWRSAVE
  374. #define CMD_SET_AP_RPS "SET_AP_RPS"
  375. #define CMD_GET_AP_RPS "GET_AP_RPS"
  376. #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
  377. #endif /* SUPPORT_AP_RADIO_PWRSAVE */
  378. #ifdef DHD_BANDSTEER
  379. #define CMD_BANDSTEER "BANDSTEER"
  380. #define CMD_BANDSTEER_TRIGGER "TRIGGER_BANDSTEER"
  381. #endif /* DHD_BANDSTEER */
  382. /* miracast related definition */
  383. #define MIRACAST_MODE_OFF 0
  384. #define MIRACAST_MODE_SOURCE 1
  385. #define MIRACAST_MODE_SINK 2
  386. #define CMD_CHANNEL_WIDTH "CHANNEL_WIDTH"
  387. #ifdef CONNECTION_STATISTICS
  388. #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
  389. struct connection_stats {
  390. u32 txframe;
  391. u32 txbyte;
  392. u32 txerror;
  393. u32 rxframe;
  394. u32 rxbyte;
  395. u32 txfail;
  396. u32 txretry;
  397. u32 txretrie;
  398. u32 txrts;
  399. u32 txnocts;
  400. u32 txexptime;
  401. u32 txrate;
  402. u8 chan_idle;
  403. };
  404. #endif /* CONNECTION_STATISTICS */
  405. #ifdef SUPPORT_LQCM
  406. #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
  407. #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
  408. #endif // endif
  409. static LIST_HEAD(miracast_resume_list);
  410. static u8 miracast_cur_mode;
  411. #ifdef DHD_LOG_DUMP
  412. #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
  413. #define SUBCMD_UNWANTED "UNWANTED"
  414. #define SUBCMD_DISCONNECTED "DISCONNECTED"
  415. void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
  416. #endif /* DHD_LOG_DUMP */
  417. #ifdef DHD_STATUS_LOGGING
  418. #define CMD_DUMP_STATUS_LOG "DUMP_STAT_LOG"
  419. #define CMD_QUERY_STATUS_LOG "QUERY_STAT_LOG"
  420. #endif /* DHD_STATUS_LOGGING */
  421. #ifdef DHD_HANG_SEND_UP_TEST
  422. #define CMD_MAKE_HANG "MAKE_HANG"
  423. #endif /* CMD_DHD_HANG_SEND_UP_TEST */
  424. #ifdef DHD_DEBUG_UART
  425. extern bool dhd_debug_uart_is_running(struct net_device *dev);
  426. #endif /* DHD_DEBUG_UART */
  427. struct io_cfg {
  428. s8 *iovar;
  429. s32 param;
  430. u32 ioctl;
  431. void *arg;
  432. u32 len;
  433. struct list_head list;
  434. };
  435. typedef enum {
  436. HEAD_SAR_BACKOFF_DISABLE = -1,
  437. HEAD_SAR_BACKOFF_ENABLE = 0,
  438. GRIP_SAR_BACKOFF_DISABLE,
  439. GRIP_SAR_BACKOFF_ENABLE,
  440. NR_mmWave_SAR_BACKOFF_DISABLE,
  441. NR_mmWave_SAR_BACKOFF_ENABLE,
  442. NR_Sub6_SAR_BACKOFF_DISABLE,
  443. NR_Sub6_SAR_BACKOFF_ENABLE,
  444. SAR_BACKOFF_DISABLE_ALL
  445. } sar_modes;
  446. #if defined(BCMFW_ROAM_ENABLE)
  447. #define CMD_SET_ROAMPREF "SET_ROAMPREF"
  448. #define MAX_NUM_SUITES 10
  449. #define WIDTH_AKM_SUITE 8
  450. #define JOIN_PREF_RSSI_LEN 0x02
  451. #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
  452. #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
  453. #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
  454. #define JOIN_PREF_MAX_WPA_TUPLES 16
  455. #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
  456. (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
  457. #endif /* BCMFW_ROAM_ENABLE */
  458. #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
  459. #ifdef WL_NATOE
  460. #define CMD_NATOE "NATOE"
  461. #define NATOE_MAX_PORT_NUM 65535
  462. /* natoe command info structure */
  463. typedef struct wl_natoe_cmd_info {
  464. uint8 *command; /* pointer to the actual command */
  465. uint16 tot_len; /* total length of the command */
  466. uint16 bytes_written; /* Bytes written for get response */
  467. } wl_natoe_cmd_info_t;
  468. typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
  469. typedef int (natoe_cmd_handler_t)(struct net_device *dev,
  470. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  471. struct wl_natoe_sub_cmd {
  472. char *name;
  473. uint8 version; /* cmd version */
  474. uint16 id; /* id for the dongle f/w switch/case */
  475. uint16 type; /* base type of argument */
  476. natoe_cmd_handler_t *handler; /* cmd handler */
  477. };
  478. #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
  479. static int wl_android_process_natoe_cmd(struct net_device *dev,
  480. char *command, int total_len);
  481. static int wl_android_natoe_subcmd_enable(struct net_device *dev,
  482. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  483. static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
  484. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  485. static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
  486. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  487. static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
  488. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  489. static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
  490. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
  491. static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
  492. /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
  493. {"enable", 0x01, WL_NATOE_CMD_ENABLE,
  494. IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
  495. },
  496. {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
  497. IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
  498. },
  499. {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
  500. IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
  501. },
  502. {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
  503. IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
  504. },
  505. {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
  506. IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
  507. },
  508. {NULL, 0, 0, 0, NULL}
  509. };
  510. #endif /* WL_NATOE */
  511. #ifdef SET_PCIE_IRQ_CPU_CORE
  512. #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
  513. #endif /* SET_PCIE_IRQ_CPU_CORE */
  514. #ifdef WLADPS_PRIVATE_CMD
  515. #define CMD_SET_ADPS "SET_ADPS"
  516. #define CMD_GET_ADPS "GET_ADPS"
  517. #endif /* WLADPS_PRIVATE_CMD */
  518. #ifdef DHD_PKT_LOGGING
  519. #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
  520. #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
  521. #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
  522. #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
  523. #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
  524. #define CMD_PKTLOG_FILTER_DEL "PKTLOG_FILTER_DEL"
  525. #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
  526. #define CMD_PKTLOG_START "PKTLOG_START"
  527. #define CMD_PKTLOG_STOP "PKTLOG_STOP"
  528. #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
  529. #define CMD_PKTLOG_MINMIZE_ENABLE "PKTLOG_MINMIZE_ENABLE"
  530. #define CMD_PKTLOG_MINMIZE_DISABLE "PKTLOG_MINMIZE_DISABLE"
  531. #define CMD_PKTLOG_CHANGE_SIZE "PKTLOG_CHANGE_SIZE"
  532. #endif /* DHD_PKT_LOGGING */
  533. #ifdef DHD_EVENT_LOG_FILTER
  534. #define CMD_EWP_FILTER "EWP_FILTER"
  535. #endif /* DHD_EVENT_LOG_FILTER */
  536. #ifdef WL_BCNRECV
  537. #define CMD_BEACON_RECV "BEACON_RECV"
  538. #endif /* WL_BCNRECV */
  539. #ifdef WL_CAC_TS
  540. #define CMD_CAC_TSPEC "CAC_TSPEC"
  541. #endif /* WL_CAC_TS */
  542. #ifdef WL_CHAN_UTIL
  543. #define CMD_GET_CHAN_UTIL "GET_CU"
  544. #endif /* WL_CHAN_UTIL */
  545. /* drv command info structure */
  546. typedef struct wl_drv_cmd_info {
  547. uint8 *command; /* pointer to the actual command */
  548. uint16 tot_len; /* total length of the command */
  549. uint16 bytes_written; /* Bytes written for get response */
  550. } wl_drv_cmd_info_t;
  551. typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
  552. typedef int (drv_cmd_handler_t)(struct net_device *dev,
  553. const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
  554. struct wl_drv_sub_cmd {
  555. char *name;
  556. uint8 version; /* cmd version */
  557. uint16 id; /* id for the dongle f/w switch/case */
  558. uint16 type; /* base type of argument */
  559. drv_cmd_handler_t *handler; /* cmd handler */
  560. };
  561. #ifdef WL_MBO
  562. #define CMD_MBO "MBO"
  563. enum {
  564. WL_MBO_CMD_NON_CHAN_PREF = 1,
  565. WL_MBO_CMD_CELL_DATA_CAP = 2
  566. };
  567. #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
  568. static int wl_android_process_mbo_cmd(struct net_device *dev,
  569. char *command, int total_len);
  570. static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
  571. const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
  572. static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
  573. const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
  574. static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
  575. {"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
  576. IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
  577. },
  578. {"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
  579. IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
  580. },
  581. {NULL, 0, 0, 0, NULL}
  582. };
  583. #endif /* WL_MBO */
  584. #ifdef WL_GENL
  585. static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
  586. static int wl_genl_init(void);
  587. static int wl_genl_deinit(void);
  588. extern struct net init_net;
  589. /* attribute policy: defines which attribute has which type (e.g int, char * etc)
  590. * possible values defined in net/netlink.h
  591. */
  592. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
  593. static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
  594. [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
  595. [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
  596. };
  597. #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) */
  598. #define WL_GENL_VER 1
  599. /* family definition */
  600. static struct genl_family wl_genl_family = {
  601. #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
  602. .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
  603. #endif // endif
  604. .hdrsize = 0,
  605. .name = "bcm-genl", /* Netlink I/F for Android */
  606. .version = WL_GENL_VER, /* Version Number */
  607. .maxattr = BCM_GENL_ATTR_MAX,
  608. };
  609. /* commands: mapping between the command enumeration and the actual function */
  610. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
  611. struct genl_ops wl_genl_ops[] = {
  612. {
  613. .cmd = BCM_GENL_CMD_MSG,
  614. .flags = 0,
  615. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
  616. .policy = wl_genl_policy,
  617. #else
  618. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  619. #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) */
  620. .doit = wl_genl_handle_msg,
  621. .dumpit = NULL,
  622. },
  623. };
  624. #else
  625. struct genl_ops wl_genl_ops = {
  626. .cmd = BCM_GENL_CMD_MSG,
  627. .flags = 0,
  628. .policy = wl_genl_policy,
  629. .doit = wl_genl_handle_msg,
  630. .dumpit = NULL,
  631. };
  632. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
  633. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
  634. static struct genl_multicast_group wl_genl_mcast[] = {
  635. { .name = "bcm-genl-mcast", },
  636. };
  637. #else
  638. static struct genl_multicast_group wl_genl_mcast = {
  639. .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
  640. .name = "bcm-genl-mcast",
  641. };
  642. #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
  643. #endif /* WL_GENL */
  644. #ifdef SUPPORT_LQCM
  645. #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
  646. #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
  647. #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
  648. #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
  649. #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
  650. #endif /* SUPPORT_LQCM */
  651. #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
  652. #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS 7
  653. static int priv_cmd_errors = 0;
  654. #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
  655. /**
  656. * Extern function declarations (TODO: move them to dhd_linux.h)
  657. */
  658. int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
  659. int dhd_dev_init_ioctl(struct net_device *dev);
  660. #ifdef WL_CFG80211
  661. int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
  662. int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
  663. #ifdef WES_SUPPORT
  664. int wl_cfg80211_set_wes_mode(int mode);
  665. int wl_cfg80211_get_wes_mode(void);
  666. #endif /* WES_SUPPORT */
  667. #else
  668. int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
  669. { return 0; }
  670. int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
  671. { return 0; }
  672. int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
  673. { return 0; }
  674. int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
  675. { return 0; }
  676. int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
  677. { return 0; }
  678. int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
  679. { return 0; }
  680. #endif /* WK_CFG80211 */
  681. #ifdef WBTEXT
  682. static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
  683. static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
  684. char *command, int total_len);
  685. static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
  686. char *command, int total_len);
  687. static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
  688. char *command, int total_len);
  689. static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
  690. uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
  691. #endif /* WBTEXT */
  692. #ifdef WES_SUPPORT
  693. /* wl_roam.c */
  694. extern int get_roamscan_mode(struct net_device *dev, int *mode);
  695. extern int set_roamscan_mode(struct net_device *dev, int mode);
  696. extern int get_roamscan_channel_list(struct net_device *dev,
  697. unsigned char channels[], int n_channels);
  698. extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n,
  699. unsigned char channels[], int ioctl_ver);
  700. #endif /* WES_SUPPORT */
  701. #ifdef ROAM_CHANNEL_CACHE
  702. extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
  703. #endif /* ROAM_CHANNEL_CACHE */
  704. #ifdef ENABLE_4335BT_WAR
  705. extern int bcm_bt_lock(int cookie);
  706. extern void bcm_bt_unlock(int cookie);
  707. static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
  708. #endif /* ENABLE_4335BT_WAR */
  709. extern bool ap_fw_loaded;
  710. extern char iface_name[IFNAMSIZ];
  711. #ifdef DHD_PM_CONTROL_FROM_FILE
  712. extern bool g_pm_control;
  713. #endif /* DHD_PM_CONTROL_FROM_FILE */
  714. /* private command support for restoring roam/scan parameters */
  715. #ifdef SUPPORT_RESTORE_SCAN_PARAMS
  716. #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
  717. typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
  718. typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
  719. enum {
  720. RESTORE_TYPE_UNSPECIFIED = 0,
  721. RESTORE_TYPE_PRIV_CMD = 1,
  722. RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
  723. };
  724. typedef struct android_restore_scan_params {
  725. char command[64];
  726. int parameter;
  727. int cmd_type;
  728. union {
  729. PRIV_CMD_HANDLER cmd_handler;
  730. PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
  731. };
  732. } android_restore_scan_params_t;
  733. /* function prototypes of private command handler */
  734. static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
  735. int wl_android_set_roam_delta(struct net_device *dev, char* command);
  736. int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
  737. int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command, int total_len);
  738. int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
  739. int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
  740. int wl_android_set_scan_home_time(struct net_device *dev, char *command);
  741. int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
  742. int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
  743. static int wl_android_set_band(struct net_device *dev, char *command);
  744. int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
  745. int wl_android_set_wes_mode(struct net_device *dev, char *command);
  746. int wl_android_set_okc_mode(struct net_device *dev, char *command);
  747. /* default values */
  748. #ifdef ROAM_API
  749. #define DEFAULT_ROAM_TIRGGER -75
  750. #define DEFAULT_ROAM_DELTA 10
  751. #define DEFAULT_ROAMSCANPERIOD 10
  752. #define DEFAULT_FULLROAMSCANPERIOD_SET 120
  753. #endif /* ROAM_API */
  754. #ifdef WES_SUPPORT
  755. #define DEFAULT_ROAMSCANCONTROL 0
  756. #define DEFAULT_SCANCHANNELTIME 40
  757. #ifdef BCM4361_CHIP
  758. #define DEFAULT_SCANHOMETIME 60
  759. #else
  760. #define DEFAULT_SCANHOMETIME 45
  761. #endif /* BCM4361_CHIP */
  762. #define DEFAULT_SCANHOMEAWAYTIME 100
  763. #define DEFAULT_SCANPROBES 2
  764. #define DEFAULT_DFSSCANMODE 1
  765. #define DEFAULT_WESMODE 0
  766. #define DEFAULT_OKCMODE 1
  767. #endif /* WES_SUPPORT */
  768. #define DEFAULT_BAND 0
  769. #ifdef WBTEXT
  770. #define DEFAULT_WBTEXT_ENABLE 1
  771. #endif /* WBTEXT */
  772. /* restoring parameter list, please don't change order */
  773. static android_restore_scan_params_t restore_params[] =
  774. {
  775. /* wbtext need to be disabled while updating roam/scan parameters */
  776. #ifdef WBTEXT
  777. { CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
  778. .cmd_handler_w_len = wl_android_wbtext},
  779. #endif /* WBTEXT */
  780. #ifdef ROAM_API
  781. { CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
  782. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
  783. { CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
  784. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
  785. { CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
  786. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
  787. { CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
  788. RESTORE_TYPE_PRIV_CMD_WITH_LEN,
  789. .cmd_handler_w_len = wl_android_set_full_roam_scan_period},
  790. #endif /* ROAM_API */
  791. #ifdef WES_SUPPORT
  792. { CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
  793. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
  794. { CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
  795. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
  796. { CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
  797. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
  798. { CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
  799. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
  800. { CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
  801. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
  802. { CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
  803. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
  804. { CMD_SETWESMODE, DEFAULT_WESMODE,
  805. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
  806. { CMD_SETOKCMODE, DEFAULT_OKCMODE,
  807. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_okc_mode},
  808. #endif /* WES_SUPPORT */
  809. { CMD_SETBAND, DEFAULT_BAND,
  810. RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
  811. #ifdef WBTEXT
  812. { CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
  813. RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
  814. #endif /* WBTEXT */
  815. { "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
  816. };
  817. #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
  818. /**
  819. * Local (static) functions and variables
  820. */
  821. /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
  822. * time (only) in dhd_open, subsequential wifi on will be handled by
  823. * wl_android_wifi_on
  824. */
  825. static int g_wifi_on = TRUE;
  826. /**
  827. * Local (static) function definitions
  828. */
  829. static int
  830. wl_android_set_channel_width(struct net_device *dev, char *command, int total_len)
  831. {
  832. u32 channel_width = 0;
  833. struct wireless_dev *wdev = dev->ieee80211_ptr;
  834. struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
  835. command = (command + strlen(CMD_CHANNEL_WIDTH));
  836. command++;
  837. channel_width = bcm_atoi(command);
  838. if (channel_width == 80)
  839. wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_80);
  840. else if (channel_width == 40)
  841. wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_40);
  842. else if (channel_width == 20)
  843. wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_20);
  844. else
  845. return 0;
  846. DHD_INFO(("%s : channel width = %d\n", __FUNCTION__, channel_width));
  847. return 0;
  848. }
  849. #ifdef DHD_BANDSTEER
  850. static int
  851. wl_android_set_bandsteer(struct net_device *dev, char *command, int total_len)
  852. {
  853. char *iftype;
  854. char *token1, *context1 = NULL;
  855. int val;
  856. int ret = 0;
  857. struct wireless_dev *__wdev = (struct wireless_dev *)(dev)->ieee80211_ptr;
  858. struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(__wdev->wiphy);
  859. command = (command + strlen(CMD_BANDSTEER));
  860. command++;
  861. token1 = command;
  862. iftype = bcmstrtok(&token1, " ", context1);
  863. val = bcm_atoi(token1);
  864. if (val < 0 || val > 1) {
  865. DHD_ERROR(("%s : invalid val\n", __FUNCTION__));
  866. return -1;
  867. }
  868. if (!strncmp(iftype, "p2p", 3)) {
  869. cfg->ap_bs = 0;
  870. cfg->p2p_bs = 1;
  871. if (val) {
  872. ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
  873. if (ret == BCME_ERROR) {
  874. DHD_ERROR(("%s: Failed to enable %s bandsteer\n", __FUNCTION__,
  875. cfg->ap_bs ? "ap":"p2p"));
  876. return ret;
  877. } else {
  878. DHD_ERROR(("%s: Successfully enabled %s bandsteer\n", __FUNCTION__,
  879. cfg->ap_bs ? "ap":"p2p"));
  880. }
  881. } else {
  882. ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
  883. if (ret == BCME_ERROR) {
  884. DHD_ERROR(("%s: Failed to disable %s bandsteer\n", __FUNCTION__,
  885. cfg->ap_bs ? "ap":"p2p"));
  886. return ret;
  887. } else {
  888. DHD_ERROR(("%s: Successfully disabled %s bandsteer\n", __FUNCTION__,
  889. cfg->ap_bs ? "ap":"p2p"));
  890. }
  891. }
  892. } else if (!strncmp(iftype, "ap", 2)) {
  893. cfg->ap_bs = 1;
  894. cfg->p2p_bs = 0;
  895. if (val) {
  896. ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
  897. if (ret == BCME_ERROR) {
  898. DHD_ERROR(("%s: Failed to enable %s bandsteer\n", __FUNCTION__,
  899. cfg->ap_bs ? "ap":"p2p"));
  900. return ret;
  901. } else {
  902. DHD_ERROR(("%s: Successfully enabled %s bandsteer\n", __FUNCTION__,
  903. cfg->ap_bs ? "ap":"p2p"));
  904. }
  905. } else {
  906. ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
  907. if (ret == BCME_ERROR) {
  908. DHD_ERROR(("%s: Failed to disable %s bandsteer\n", __FUNCTION__,
  909. cfg->ap_bs ? "ap":"p2p"));
  910. return ret;
  911. } else {
  912. DHD_ERROR(("%s: Successfully disabled %s bandsteer\n", __FUNCTION__,
  913. cfg->ap_bs ? "ap":"p2p"));
  914. }
  915. }
  916. } else if (!strncmp(iftype, "1", 1)) {
  917. cfg->ap_bs = 1;
  918. cfg->p2p_bs = 1;
  919. ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
  920. if (ret == BCME_ERROR) {
  921. DHD_ERROR(("%s: Failed to enable bandsteer\n", __FUNCTION__));
  922. return ret;
  923. } else {
  924. DHD_ERROR(("%s: Successfully enabled bandsteer\n", __FUNCTION__));
  925. }
  926. } else if (!strncmp(iftype, "0", 1)) {
  927. cfg->ap_bs = 1;
  928. cfg->p2p_bs = 1;
  929. ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
  930. if (ret == BCME_ERROR) {
  931. DHD_ERROR(("%s: Failed to diable bandsteer\n", __FUNCTION__));
  932. return ret;
  933. } else {
  934. DHD_ERROR(("%s: Successfully disabled bandsteer\n", __FUNCTION__));
  935. }
  936. } else {
  937. DHD_ERROR(("%s: Invalid bandsteer iftype\n", __FUNCTION__));
  938. return -1;
  939. }
  940. return ret;
  941. }
  942. #endif /* DHD_BANDSTEER */
  943. #ifdef WLWFDS
  944. static int wl_android_set_wfds_hash(
  945. struct net_device *dev, char *command, bool enable)
  946. {
  947. int error = 0;
  948. wl_p2p_wfds_hash_t *wfds_hash = NULL;
  949. char *smbuf = NULL;
  950. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  951. smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
  952. if (smbuf == NULL) {
  953. DHD_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
  954. WLC_IOCTL_MAXLEN));
  955. return -ENOMEM;
  956. }
  957. if (enable) {
  958. wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
  959. error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
  960. sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
  961. }
  962. else {
  963. wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
  964. error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
  965. sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
  966. }
  967. if (error) {
  968. DHD_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
  969. }
  970. if (smbuf) {
  971. MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
  972. }
  973. return error;
  974. }
  975. #endif /* WLWFDS */
  976. static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
  977. {
  978. int link_speed;
  979. int bytes_written;
  980. int error;
  981. error = wldev_get_link_speed(net, &link_speed);
  982. if (error) {
  983. DHD_ERROR(("Get linkspeed failed \n"));
  984. return -1;
  985. }
  986. /* Convert Kbps to Android Mbps */
  987. link_speed = link_speed / 1000;
  988. bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
  989. DHD_INFO(("wl_android_get_link_speed: command result is %s\n", command));
  990. return bytes_written;
  991. }
  992. static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
  993. {
  994. wlc_ssid_t ssid = {0, {0}};
  995. int bytes_written = 0;
  996. int error = 0;
  997. scb_val_t scbval;
  998. char *delim = NULL;
  999. struct net_device *target_ndev = net;
  1000. #ifdef WL_VIRTUAL_APSTA
  1001. char *pos = NULL;
  1002. struct bcm_cfg80211 *cfg;
  1003. #endif /* WL_VIRTUAL_APSTA */
  1004. delim = strchr(command, ' ');
  1005. /* For Ap mode rssi command would be
  1006. * driver rssi <sta_mac_addr>
  1007. * for STA/GC mode
  1008. * driver rssi
  1009. */
  1010. if (delim) {
  1011. /* Ap/GO mode
  1012. * driver rssi <sta_mac_addr>
  1013. */
  1014. DHD_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
  1015. /* skip space from delim after finding char */
  1016. delim++;
  1017. if (!(bcm_ether_atoe((delim), &scbval.ea))) {
  1018. DHD_ERROR(("wl_android_get_rssi: address err\n"));
  1019. return -1;
  1020. }
  1021. scbval.val = htod32(0);
  1022. DHD_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
  1023. #ifdef WL_VIRTUAL_APSTA
  1024. /* RSDB AP may have another virtual interface
  1025. * In this case, format of private command is as following,
  1026. * DRIVER rssi <sta_mac_addr> <AP interface name>
  1027. */
  1028. /* Current position is start of MAC address string */
  1029. pos = delim;
  1030. delim = strchr(pos, ' ');
  1031. if (delim) {
  1032. /* skip space from delim after finding char */
  1033. delim++;
  1034. if (strnlen(delim, IFNAMSIZ)) {
  1035. cfg = wl_get_cfg(net);
  1036. target_ndev = wl_get_ap_netdev(cfg, delim);
  1037. if (target_ndev == NULL)
  1038. target_ndev = net;
  1039. }
  1040. }
  1041. #endif /* WL_VIRTUAL_APSTA */
  1042. }
  1043. else {
  1044. /* STA/GC mode */
  1045. bzero(&scbval, sizeof(scb_val_t));
  1046. }
  1047. error = wldev_get_rssi(target_ndev, &scbval);
  1048. if (error)
  1049. return -1;
  1050. error = wldev_get_ssid(target_ndev, &ssid);
  1051. if (error)
  1052. return -1;
  1053. if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
  1054. DHD_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
  1055. } else if (total_len <= ssid.SSID_len) {
  1056. return -ENOMEM;
  1057. } else {
  1058. memcpy(command, ssid.SSID, ssid.SSID_len);
  1059. bytes_written = ssid.SSID_len;
  1060. }
  1061. if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
  1062. return -ENOMEM;
  1063. bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
  1064. " rssi %d", scbval.val);
  1065. command[bytes_written] = '\0';
  1066. DHD_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
  1067. return bytes_written;
  1068. }
  1069. static int wl_android_set_suspendopt(struct net_device *dev, char *command)
  1070. {
  1071. int suspend_flag;
  1072. int ret_now;
  1073. int ret = 0;
  1074. suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
  1075. if (suspend_flag != 0) {
  1076. suspend_flag = 1;
  1077. }
  1078. ret_now = net_os_set_suspend_disable(dev, suspend_flag);
  1079. if (ret_now != suspend_flag) {
  1080. if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
  1081. DHD_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
  1082. ret_now, suspend_flag));
  1083. } else {
  1084. DHD_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
  1085. }
  1086. }
  1087. return ret;
  1088. }
  1089. static int wl_android_set_suspendmode(struct net_device *dev, char *command)
  1090. {
  1091. int ret = 0;
  1092. #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
  1093. int suspend_flag;
  1094. suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
  1095. if (suspend_flag != 0)
  1096. suspend_flag = 1;
  1097. if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
  1098. DHD_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
  1099. else
  1100. DHD_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
  1101. #endif // endif
  1102. return ret;
  1103. }
  1104. int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
  1105. {
  1106. uint8 mode[5];
  1107. int error = 0;
  1108. int bytes_written = 0;
  1109. error = wldev_get_mode(dev, mode, sizeof(mode));
  1110. if (error)
  1111. return -1;
  1112. DHD_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
  1113. bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
  1114. DHD_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
  1115. return bytes_written;
  1116. }
  1117. extern chanspec_t
  1118. wl_chspec_driver_to_host(chanspec_t chanspec);
  1119. int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
  1120. {
  1121. int error = 0;
  1122. int bytes_written = 0;
  1123. int chsp = {0};
  1124. uint16 band = 0;
  1125. uint16 bw = 0;
  1126. uint16 channel = 0;
  1127. u32 sb = 0;
  1128. chanspec_t chanspec;
  1129. /* command is
  1130. * driver chanspec
  1131. */
  1132. error = wldev_iovar_getint(dev, "chanspec", &chsp);
  1133. if (error)
  1134. return -1;
  1135. chanspec = wl_chspec_driver_to_host(chsp);
  1136. DHD_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
  1137. channel = chanspec & WL_CHANSPEC_CHAN_MASK;
  1138. band = chanspec & WL_CHANSPEC_BAND_MASK;
  1139. bw = chanspec & WL_CHANSPEC_BW_MASK;
  1140. DHD_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
  1141. channel, band, bw));
  1142. if (bw == WL_CHANSPEC_BW_80)
  1143. bw = WL_CH_BANDWIDTH_80MHZ;
  1144. else if (bw == WL_CHANSPEC_BW_40)
  1145. bw = WL_CH_BANDWIDTH_40MHZ;
  1146. else if (bw == WL_CHANSPEC_BW_20)
  1147. bw = WL_CH_BANDWIDTH_20MHZ;
  1148. else
  1149. bw = WL_CH_BANDWIDTH_20MHZ;
  1150. if (bw == WL_CH_BANDWIDTH_40MHZ) {
  1151. if (CHSPEC_SB_UPPER(chanspec)) {
  1152. channel += CH_10MHZ_APART;
  1153. } else {
  1154. channel -= CH_10MHZ_APART;
  1155. }
  1156. }
  1157. else if (bw == WL_CH_BANDWIDTH_80MHZ) {
  1158. sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
  1159. if (sb == WL_CHANSPEC_CTL_SB_LL) {
  1160. channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
  1161. } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
  1162. channel -= CH_10MHZ_APART;
  1163. } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
  1164. channel += CH_10MHZ_APART;
  1165. } else {
  1166. /* WL_CHANSPEC_CTL_SB_UU */
  1167. channel += (CH_10MHZ_APART + CH_20MHZ_APART);
  1168. }
  1169. }
  1170. bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
  1171. channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw);
  1172. DHD_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
  1173. return bytes_written;
  1174. }
  1175. /* returns whether rsdb supported or not */
  1176. int wl_android_get_rsdb_mode(struct net_device *dev, char *command, int total_len)
  1177. {
  1178. int bytes_written = 0;
  1179. dhd_pub_t *dhd = wl_cfg80211_get_dhdp(dev);
  1180. int rsdb_mode = 0;
  1181. if(FW_SUPPORTED(dhd, rsdb)) {
  1182. rsdb_mode = 1;
  1183. }
  1184. DHD_INFO(("wl_android_get_rsdb_mode: rsdb_mode:%d\n", rsdb_mode));
  1185. bytes_written = snprintf(command, total_len, "%d", rsdb_mode);
  1186. return bytes_written;
  1187. }
  1188. /* returns current datarate datarate returned from firmware are in 500kbps */
  1189. int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
  1190. {
  1191. int error = 0;
  1192. int datarate = 0;
  1193. int bytes_written = 0;
  1194. error = wldev_get_datarate(dev, &datarate);
  1195. if (error)
  1196. return -1;
  1197. DHD_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
  1198. bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
  1199. return bytes_written;
  1200. }
  1201. int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
  1202. {
  1203. int error = 0;
  1204. int bytes_written = 0;
  1205. uint i;
  1206. int len = 0;
  1207. char mac_buf[MAX_NUM_OF_ASSOCLIST *
  1208. sizeof(struct ether_addr) + sizeof(uint)] = {0};
  1209. struct maclist *assoc_maclist = (struct maclist *)mac_buf;
  1210. DHD_TRACE(("wl_android_get_assoclist: ENTER\n"));
  1211. assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
  1212. error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
  1213. if (error)
  1214. return -1;
  1215. assoc_maclist->count = dtoh32(assoc_maclist->count);
  1216. bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
  1217. CMD_ASSOC_CLIENTS, assoc_maclist->count);
  1218. for (i = 0; i < assoc_maclist->count; i++) {
  1219. len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
  1220. MAC2STRDBG(assoc_maclist->ea[i].octet));
  1221. /* A return value of '(total_len - bytes_written)' or more means that the
  1222. * output was truncated
  1223. */
  1224. if ((len > 0) && (len < (total_len - bytes_written))) {
  1225. bytes_written += len;
  1226. } else {
  1227. DHD_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
  1228. " bytes_written %d\n",
  1229. total_len, bytes_written));
  1230. bytes_written = -1;
  1231. break;
  1232. }
  1233. }
  1234. return bytes_written;
  1235. }
  1236. extern chanspec_t
  1237. wl_chspec_host_to_driver(chanspec_t chanspec);
  1238. static int wl_android_set_csa(struct net_device *dev, char *command)
  1239. {
  1240. int error = 0;
  1241. char smbuf[WLC_IOCTL_SMLEN];
  1242. wl_chan_switch_t csa_arg;
  1243. u32 chnsp = 0;
  1244. int err = 0;
  1245. char str[3];
  1246. DHD_INFO(("wl_android_set_csa: command:%s\n", command));
  1247. /*
  1248. * SETCSA driver command provides support for AP/AGO to switch its channel
  1249. * as well as connected STAs channel. This command will send CSA frame and
  1250. * based on this connected STA will switch to channel which we will pass in
  1251. * CSA frame.
  1252. * Usage:
  1253. * > IFNAME=<group_iface_name> DRIVER SETCSA mode count channel frame_type
  1254. * > IFNAME=<group_iface_name> DRIVER SETCSA 0 10 1 u
  1255. * If no frame type is specified, frame_type=0 (Broadcast frame type)
  1256. */
  1257. command = (command + strlen(CMD_SET_CSA));
  1258. /* Order is mode, count channel */
  1259. if (!*++command) {
  1260. DHD_ERROR(("wl_android_set_csa:error missing arguments\n"));
  1261. return -1;
  1262. }
  1263. csa_arg.mode = bcm_atoi(command);
  1264. if (csa_arg.mode != 0 && csa_arg.mode != 1) {
  1265. DHD_ERROR(("Invalid mode\n"));
  1266. return -1;
  1267. }
  1268. if (!*++command) {
  1269. DHD_ERROR(("wl_android_set_csa: error missing count\n"));
  1270. return -1;
  1271. }
  1272. command++;
  1273. csa_arg.count = bcm_atoi(command);
  1274. csa_arg.reg = 0;
  1275. csa_arg.chspec = 0;
  1276. command++;
  1277. if (*command != ' ') {
  1278. command++;
  1279. }
  1280. if (!*++command) {
  1281. DHD_ERROR(("wl_android_set_csa: error missing channel\n"));
  1282. return -1;
  1283. }
  1284. str[0] = *command;
  1285. command++;
  1286. if (*command != ' ') {
  1287. str[1] = *command;
  1288. command++;
  1289. str[2] = '\0';
  1290. } else {
  1291. str[1] = '\0';
  1292. }
  1293. chnsp = wf_chspec_aton(str);
  1294. if (chnsp == 0) {
  1295. DHD_ERROR(("wl_android_set_csa:chsp is not correct\n"));
  1296. return -1;
  1297. }
  1298. chnsp = wl_chspec_host_to_driver(chnsp);
  1299. csa_arg.chspec = chnsp;
  1300. /* csa action frame type */
  1301. if (*++command) {
  1302. if (strcmp(command, "u") == 0) {
  1303. csa_arg.frame_type = CSA_UNICAST_ACTION_FRAME;
  1304. } else {
  1305. DHD_ERROR(("%s:error: invalid frame type: %s\n",
  1306. __FUNCTION__, command));
  1307. return -1;
  1308. }
  1309. } else {
  1310. csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
  1311. }
  1312. if (chnsp & WL_CHANSPEC_BAND_5G) {
  1313. u32 chanspec = chnsp;
  1314. err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
  1315. if (!err) {
  1316. if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
  1317. DHD_ERROR(("Channel is radar sensitive\n"));
  1318. return -1;
  1319. }
  1320. if (chanspec == 0) {
  1321. DHD_ERROR(("Invalid hw channel\n"));
  1322. return -1;
  1323. }
  1324. } else {
  1325. DHD_ERROR(("does not support per_chan_info\n"));
  1326. return -1;
  1327. }
  1328. DHD_INFO(("non radar sensitivity\n"));
  1329. }
  1330. error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
  1331. smbuf, sizeof(smbuf), NULL);
  1332. if (error) {
  1333. DHD_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
  1334. return -1;
  1335. }
  1336. return 0;
  1337. }
  1338. static int
  1339. wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
  1340. {
  1341. int ret = 0;
  1342. int dtim;
  1343. dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
  1344. if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
  1345. DHD_ERROR(("%s: failed, invalid dtim %d\n",
  1346. __FUNCTION__, dtim));
  1347. return BCME_ERROR;
  1348. }
  1349. if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
  1350. DHD_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
  1351. __FUNCTION__, dtim));
  1352. } else {
  1353. DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
  1354. }
  1355. return ret;
  1356. }
  1357. static int
  1358. wl_android_set_max_dtim(struct net_device *dev, char *command)
  1359. {
  1360. int ret = 0;
  1361. int dtim_flag;
  1362. dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
  1363. if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
  1364. DHD_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
  1365. (dtim_flag ? "Enable" : "Disable")));
  1366. } else {
  1367. DHD_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
  1368. }
  1369. return ret;
  1370. }
  1371. #ifdef DISABLE_DTIM_IN_SUSPEND
  1372. static int
  1373. wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
  1374. {
  1375. int ret = 0;
  1376. int dtim_flag;
  1377. dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
  1378. if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
  1379. DHD_TRACE(("wl_android_set_disable_dtim_in_suspend: "
  1380. "use Disable bcn_li_dtim in suspend %s\n",
  1381. (dtim_flag ? "Enable" : "Disable")));
  1382. } else {
  1383. DHD_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
  1384. }
  1385. return ret;
  1386. }
  1387. #endif /* DISABLE_DTIM_IN_SUSPEND */
  1388. static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
  1389. {
  1390. uint band;
  1391. int bytes_written;
  1392. int error;
  1393. error = wldev_get_band(dev, &band);
  1394. if (error)
  1395. return -1;
  1396. bytes_written = snprintf(command, total_len, "Band %d", band);
  1397. return bytes_written;
  1398. }
  1399. static int
  1400. wl_android_set_band(struct net_device *dev, char *command)
  1401. {
  1402. int error = 0;
  1403. uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
  1404. #ifdef WL_HOST_BAND_MGMT
  1405. int ret = 0;
  1406. if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
  1407. if (ret == BCME_UNSUPPORTED) {
  1408. /* If roam_var is unsupported, fallback to the original method */
  1409. WL_ERR(("WL_HOST_BAND_MGMT defined, "
  1410. "but roam_band iovar unsupported in the firmware\n"));
  1411. } else {
  1412. error = -1;
  1413. }
  1414. }
  1415. if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
  1416. /* Apply if roam_band iovar is not supported or band setting is AUTO */
  1417. error = wldev_set_band(dev, band);
  1418. }
  1419. #else
  1420. error = wl_cfg80211_set_if_band(dev, band);
  1421. #endif /* WL_HOST_BAND_MGMT */
  1422. #ifdef ROAM_CHANNEL_CACHE
  1423. wl_update_roamscan_cache_by_band(dev, band);
  1424. #endif /* ROAM_CHANNEL_CACHE */
  1425. return error;
  1426. }
  1427. static int wl_android_add_vendor_ie(struct net_device *dev, char *command, int total_len)
  1428. {
  1429. char ie_buf[VNDR_IE_MAX_LEN];
  1430. char *ioctl_buf = NULL;
  1431. char hex[] = "XX";
  1432. char *pcmd = NULL;
  1433. int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
  1434. vndr_ie_setbuf_t *vndr_ie = NULL;
  1435. s32 iecount;
  1436. uint32 pktflag;
  1437. u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  1438. s32 err = BCME_OK;
  1439. /*
  1440. * ADD_IE driver command provides support for addition of vendor elements
  1441. * to different management frames via wpa_cli
  1442. * Usage:
  1443. * Create softap/AGO
  1444. * wpa_cli> IFNAME=<group_iface_name> DRIVER ADD_IE <flag> <OUI> <DATA>
  1445. * Here Flag is 802.11 Mgmt packet flags values
  1446. * Beacon: 0
  1447. * Probe Rsp: 1
  1448. * Assoc Rsp: 2
  1449. * Auth Rsp: 4
  1450. * Probe Req: 8
  1451. * Assoc Req: 16
  1452. * E.g
  1453. * wpa_cli> IFNAME=bcm0 DRIVER ADD_IE 1 998877 1122334455667788
  1454. */
  1455. pcmd = command + strlen(CMD_ADDIE) + 1;
  1456. pktflag = simple_strtoul(pcmd, &pcmd, 16);
  1457. pcmd = pcmd + 1;
  1458. for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
  1459. hex[0] = *pcmd++;
  1460. hex[1] = *pcmd++;
  1461. ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
  1462. }
  1463. pcmd++;
  1464. while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
  1465. hex[0] = *pcmd++;
  1466. hex[1] = *pcmd++;
  1467. ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
  1468. datalen++;
  1469. }
  1470. tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
  1471. if (tot_len > VNDR_IE_MAX_LEN) {
  1472. WL_ERR(("Invalid IE total length %d\n", tot_len));
  1473. return -ENOMEM;
  1474. }
  1475. vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
  1476. if (!vndr_ie) {
  1477. WL_ERR(("IE memory alloc failed\n"));
  1478. return -ENOMEM;
  1479. }
  1480. /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
  1481. strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
  1482. vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
  1483. /* Set the IE count - the buffer contains only 1 IE */
  1484. iecount = htod32(1);
  1485. memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
  1486. /* Set packet flag to indicate the appropriate frame will contain this IE */
  1487. pktflag = htod32(1<<pktflag);
  1488. memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
  1489. sizeof(u32));
  1490. /* Set the IE ID */
  1491. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
  1492. /* Set the OUI */
  1493. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
  1494. DOT11_OUI_LEN);
  1495. /* Set the Data */
  1496. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
  1497. &ie_buf[DOT11_OUI_LEN], datalen);
  1498. ielen = DOT11_OUI_LEN + datalen;
  1499. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
  1500. ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
  1501. if (!ioctl_buf) {
  1502. WL_ERR(("ioctl memory alloc failed\n"));
  1503. if (vndr_ie) {
  1504. kfree(vndr_ie);
  1505. }
  1506. return -ENOMEM;
  1507. }
  1508. memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
  1509. err = wldev_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
  1510. WLC_IOCTL_MEDLEN, NULL);
  1511. if (err != BCME_OK) {
  1512. err = -EINVAL;
  1513. }
  1514. if (vndr_ie) {
  1515. kfree(vndr_ie);
  1516. }
  1517. if (ioctl_buf) {
  1518. kfree(ioctl_buf);
  1519. }
  1520. return err;
  1521. }
  1522. static int wl_android_del_vendor_ie(struct net_device *dev, char *command, int total_len)
  1523. {
  1524. char ie_buf[VNDR_IE_MAX_LEN];
  1525. char *ioctl_buf = NULL;
  1526. char hex[] = "XX";
  1527. char *pcmd = NULL;
  1528. int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
  1529. vndr_ie_setbuf_t *vndr_ie = NULL;
  1530. s32 iecount;
  1531. uint32 pktflag;
  1532. u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  1533. s32 err = BCME_OK;
  1534. /*
  1535. * DEL_IE driver command provides support for deletoon of vendor elements
  1536. * from different management frames via wpa_cli
  1537. * Usage:
  1538. * Create softap/AGO
  1539. * wpa_cli> IFNAME=<group_iface_name> DRIVER DEL_IE <flag> <OUI> <DATA>
  1540. * Here Flag is 802.11 Mgmt packet flags values
  1541. * Beacon: 1
  1542. * Probe Rsp: 2
  1543. * Assoc Rsp: 4
  1544. * Auth Rsp: 8
  1545. * Probe Req: 16
  1546. * Assoc Req: 32
  1547. * E.g
  1548. * wpa_cli> IFNAME=bcm0 DRIVER DEL_IE 1 998877 1122334455667788
  1549. */
  1550. pcmd = command + strlen(CMD_DELIE) + 1;
  1551. pktflag = simple_strtoul(pcmd, &pcmd, 16);
  1552. pcmd = pcmd + 1;
  1553. for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
  1554. hex[0] = *pcmd++;
  1555. hex[1] = *pcmd++;
  1556. ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
  1557. }
  1558. pcmd++;
  1559. while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
  1560. hex[0] = *pcmd++;
  1561. hex[1] = *pcmd++;
  1562. ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
  1563. datalen++;
  1564. }
  1565. tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
  1566. if (tot_len > VNDR_IE_MAX_LEN) {
  1567. WL_ERR(("Invalid IE total length %d\n", tot_len));
  1568. return -ENOMEM;
  1569. }
  1570. vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
  1571. if (!vndr_ie) {
  1572. WL_ERR(("IE memory alloc failed\n"));
  1573. return -ENOMEM;
  1574. }
  1575. /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
  1576. strncpy(vndr_ie->cmd, "del", VNDR_IE_CMD_LEN - 1);
  1577. vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
  1578. /* Set the IE count - the buffer contains only 1 IE */
  1579. iecount = htod32(1);
  1580. memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
  1581. /* Set packet flag to indicate the appropriate frame will contain this IE */
  1582. pktflag = htod32(1<<(pktflag-1));
  1583. memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
  1584. sizeof(u32));
  1585. /* Set the IE ID */
  1586. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
  1587. /* Set the OUI */
  1588. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
  1589. DOT11_OUI_LEN);
  1590. /* Set the Data */
  1591. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
  1592. &ie_buf[DOT11_OUI_LEN], datalen);
  1593. ielen = DOT11_OUI_LEN + datalen;
  1594. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
  1595. ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
  1596. if (!ioctl_buf) {
  1597. WL_ERR(("ioctl memory alloc failed\n"));
  1598. if (vndr_ie) {
  1599. kfree(vndr_ie);
  1600. }
  1601. return -ENOMEM;
  1602. }
  1603. memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
  1604. err = wldev_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
  1605. WLC_IOCTL_MEDLEN, NULL);
  1606. if (err != BCME_OK) {
  1607. err = -EINVAL;
  1608. }
  1609. if (vndr_ie) {
  1610. kfree(vndr_ie);
  1611. }
  1612. if (ioctl_buf) {
  1613. kfree(ioctl_buf);
  1614. }
  1615. return err;
  1616. }
  1617. #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
  1618. #ifdef ROAM_API
  1619. static bool wl_android_check_wbtext(struct net_device *dev)
  1620. {
  1621. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  1622. return dhdp->wbtext_support;
  1623. }
  1624. static int wl_android_set_roam_trigger(
  1625. struct net_device *dev, char* command)
  1626. {
  1627. int roam_trigger[2] = {0, 0};
  1628. int error;
  1629. #ifdef WBTEXT
  1630. if (wl_android_check_wbtext(dev)) {
  1631. WL_ERR(("blocked to set roam trigger. try with setting roam profile\n"));
  1632. return BCME_ERROR;
  1633. }
  1634. #endif /* WBTEXT */
  1635. sscanf(command, "%*s %10d", &roam_trigger[0]);
  1636. if (roam_trigger[0] >= 0) {
  1637. WL_ERR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
  1638. return BCME_ERROR;
  1639. }
  1640. roam_trigger[1] = WLC_BAND_ALL;
  1641. error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
  1642. sizeof(roam_trigger));
  1643. if (error != BCME_OK) {
  1644. WL_ERR(("failed to set roam trigger (%d)\n", error));
  1645. return BCME_ERROR;
  1646. }
  1647. return BCME_OK;
  1648. }
  1649. static int wl_android_get_roam_trigger(
  1650. struct net_device *dev, char *command, int total_len)
  1651. {
  1652. int bytes_written, error;
  1653. int roam_trigger[2] = {0, 0};
  1654. uint16 band = 0;
  1655. int chsp = {0};
  1656. chanspec_t chanspec;
  1657. #ifdef WBTEXT
  1658. int i;
  1659. wl_roamprof_band_t rp;
  1660. uint8 roam_prof_ver = 0, roam_prof_size = 0;
  1661. #endif /* WBTEXT */
  1662. error = wldev_iovar_getint(dev, "chanspec", &chsp);
  1663. if (error != BCME_OK) {
  1664. WL_ERR(("failed to get chanspec (%d)\n", error));
  1665. return BCME_ERROR;
  1666. }
  1667. chanspec = wl_chspec_driver_to_host(chsp);
  1668. band = chanspec & WL_CHANSPEC_BAND_MASK;
  1669. if (band == WL_CHANSPEC_BAND_5G)
  1670. band = WLC_BAND_5G;
  1671. else
  1672. band = WLC_BAND_2G;
  1673. if (wl_android_check_wbtext(dev)) {
  1674. #ifdef WBTEXT
  1675. memset_s(&rp, sizeof(rp), 0, sizeof(rp));
  1676. if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
  1677. &roam_prof_size))) {
  1678. WL_ERR(("Getting roam_profile failed with err=%d \n", error));
  1679. return -EINVAL;
  1680. }
  1681. switch (roam_prof_ver) {
  1682. case WL_ROAM_PROF_VER_1:
  1683. {
  1684. for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
  1685. if (rp.v2.roam_prof[i].channel_usage == 0) {
  1686. roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
  1687. break;
  1688. }
  1689. }
  1690. }
  1691. break;
  1692. case WL_ROAM_PROF_VER_2:
  1693. {
  1694. for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
  1695. if (rp.v3.roam_prof[i].channel_usage == 0) {
  1696. roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
  1697. break;
  1698. }
  1699. }
  1700. }
  1701. break;
  1702. default:
  1703. WL_ERR(("bad version = %d \n", roam_prof_ver));
  1704. return BCME_VERSION;
  1705. }
  1706. #endif /* WBTEXT */
  1707. if (roam_trigger[0] == 0) {
  1708. WL_ERR(("roam trigger was not set properly\n"));
  1709. return BCME_ERROR;
  1710. }
  1711. } else {
  1712. roam_trigger[1] = band;
  1713. error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
  1714. sizeof(roam_trigger));
  1715. if (error != BCME_OK) {
  1716. WL_ERR(("failed to get roam trigger (%d)\n", error));
  1717. return BCME_ERROR;
  1718. }
  1719. }
  1720. bytes_written = snprintf(command, total_len, "%s %d",
  1721. CMD_ROAMTRIGGER_GET, roam_trigger[0]);
  1722. return bytes_written;
  1723. }
  1724. int wl_android_set_roam_delta(
  1725. struct net_device *dev, char* command)
  1726. {
  1727. int roam_delta[2];
  1728. sscanf(command, "%*s %10d", &roam_delta[0]);
  1729. roam_delta[1] = WLC_BAND_ALL;
  1730. return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
  1731. sizeof(roam_delta));
  1732. }
  1733. static int wl_android_get_roam_delta(
  1734. struct net_device *dev, char *command, int total_len)
  1735. {
  1736. int bytes_written;
  1737. int roam_delta[2] = {0, 0};
  1738. roam_delta[1] = WLC_BAND_2G;
  1739. if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
  1740. sizeof(roam_delta))) {
  1741. roam_delta[1] = WLC_BAND_5G;
  1742. if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
  1743. sizeof(roam_delta)))
  1744. return -1;
  1745. }
  1746. bytes_written = snprintf(command, total_len, "%s %d",
  1747. CMD_ROAMDELTA_GET, roam_delta[0]);
  1748. return bytes_written;
  1749. }
  1750. int wl_android_set_roam_scan_period(
  1751. struct net_device *dev, char* command)
  1752. {
  1753. int roam_scan_period = 0;
  1754. sscanf(command, "%*s %10d", &roam_scan_period);
  1755. return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
  1756. sizeof(roam_scan_period));
  1757. }
  1758. static int wl_android_get_roam_scan_period(
  1759. struct net_device *dev, char *command, int total_len)
  1760. {
  1761. int bytes_written;
  1762. int roam_scan_period = 0;
  1763. if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
  1764. sizeof(roam_scan_period)))
  1765. return -1;
  1766. bytes_written = snprintf(command, total_len, "%s %d",
  1767. CMD_ROAMSCANPERIOD_GET, roam_scan_period);
  1768. return bytes_written;
  1769. }
  1770. int wl_android_set_full_roam_scan_period(
  1771. struct net_device *dev, char* command, int total_len)
  1772. {
  1773. int error = 0;
  1774. int full_roam_scan_period = 0;
  1775. char smbuf[WLC_IOCTL_SMLEN];
  1776. sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
  1777. WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
  1778. error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
  1779. sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
  1780. if (error) {
  1781. DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error));
  1782. }
  1783. return error;
  1784. }
  1785. static int wl_android_get_full_roam_scan_period(
  1786. struct net_device *dev, char *command, int total_len)
  1787. {
  1788. int error;
  1789. int bytes_written;
  1790. int full_roam_scan_period = 0;
  1791. error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
  1792. if (error) {
  1793. DHD_ERROR(("%s: get full roam scan period failed code %d\n",
  1794. __func__, error));
  1795. return -1;
  1796. } else {
  1797. DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
  1798. }
  1799. bytes_written = snprintf(command, total_len, "%s %d",
  1800. CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
  1801. return bytes_written;
  1802. }
  1803. int wl_android_set_country_rev(
  1804. struct net_device *dev, char* command)
  1805. {
  1806. int error = 0;
  1807. wl_country_t cspec = {{0}, 0, {0} };
  1808. char country_code[WLC_CNTRY_BUF_SZ];
  1809. char smbuf[WLC_IOCTL_SMLEN];
  1810. int rev = 0;
  1811. /*
  1812. * SETCOUNTRYREV driver command provides support setting the country.
  1813. * e.g US, DE, JP etc via supplicant. Once set, band and channels
  1814. * too automatically gets updated based on the country.
  1815. * Usage:
  1816. * > IFNAME=wlan0 DRIVER SETCOUNTRYREV JP
  1817. * OK
  1818. */
  1819. bzero(country_code, sizeof(country_code));
  1820. sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
  1821. WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
  1822. memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
  1823. memcpy(cspec.ccode, country_code, sizeof(country_code));
  1824. cspec.rev = rev;
  1825. error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
  1826. sizeof(cspec), smbuf, sizeof(smbuf), NULL);
  1827. if (error) {
  1828. DHD_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
  1829. cspec.ccode, cspec.rev, error));
  1830. } else {
  1831. dhd_bus_country_set(dev, &cspec, true);
  1832. DHD_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
  1833. cspec.ccode, cspec.rev));
  1834. }
  1835. return error;
  1836. }
  1837. static int wl_android_get_country_rev(
  1838. struct net_device *dev, char *command, int total_len)
  1839. {
  1840. int error;
  1841. int bytes_written;
  1842. char smbuf[WLC_IOCTL_SMLEN];
  1843. wl_country_t cspec;
  1844. /*
  1845. * GETCOUNTRYREV driver command provides support getting the country.
  1846. * e.g US, DE, JP etc via supplicant.
  1847. * Usage:
  1848. * > IFNAME=wlan0 DRIVER GETCOUNTRYREV
  1849. * GETCOUNTRYREV JP 0
  1850. */
  1851. error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
  1852. sizeof(smbuf), NULL);
  1853. if (error) {
  1854. DHD_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
  1855. error));
  1856. return -1;
  1857. } else {
  1858. memcpy(&cspec, smbuf, sizeof(cspec));
  1859. DHD_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
  1860. cspec.ccode[0], cspec.ccode[1], cspec.rev));
  1861. }
  1862. bytes_written = snprintf(command, total_len, "%s %c%c %d",
  1863. CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
  1864. return bytes_written;
  1865. }
  1866. #endif /* ROAM_API */
  1867. #ifdef WES_SUPPORT
  1868. int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
  1869. {
  1870. int error = 0;
  1871. int bytes_written = 0;
  1872. int mode = 0;
  1873. error = get_roamscan_mode(dev, &mode);
  1874. if (error) {
  1875. DHD_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
  1876. " error = %d\n", error));
  1877. return -1;
  1878. }
  1879. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
  1880. return bytes_written;
  1881. }
  1882. int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
  1883. {
  1884. int error = 0;
  1885. int mode = 0;
  1886. if (sscanf(command, "%*s %d", &mode) != 1) {
  1887. DHD_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
  1888. return -1;
  1889. }
  1890. error = set_roamscan_mode(dev, mode);
  1891. if (error) {
  1892. DHD_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
  1893. " error = %d\n",
  1894. mode, error));
  1895. return -1;
  1896. }
  1897. return 0;
  1898. }
  1899. int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len)
  1900. {
  1901. int bytes_written = 0;
  1902. unsigned char channels[MAX_ROAM_CHANNEL] = {0};
  1903. int channel_cnt = 0;
  1904. int i = 0;
  1905. int buf_avail, len;
  1906. channel_cnt = get_roamscan_channel_list(dev, channels, MAX_ROAM_CHANNEL);
  1907. bytes_written = snprintf(command, total_len, "%s %d",
  1908. CMD_GETROAMSCANCHANNELS, channel_cnt);
  1909. buf_avail = total_len - bytes_written;
  1910. for (i = 0; i < channel_cnt; i++) {
  1911. /* A return value of 'buf_avail' or more means that the output was truncated */
  1912. len = snprintf(command + bytes_written, buf_avail, " %d", channels[i]);
  1913. if (len >= buf_avail) {
  1914. WL_ERR(("wl_android_get_roam_scan_channels: Insufficient memory,"
  1915. " %d bytes\n",
  1916. total_len));
  1917. bytes_written = -1;
  1918. break;
  1919. }
  1920. /* 'buf_avail' decremented by number of bytes written */
  1921. buf_avail -= len;
  1922. bytes_written += len;
  1923. }
  1924. WL_INFORM(("wl_android_get_roam_scan_channels: %s\n", command));
  1925. return bytes_written;
  1926. }
  1927. int wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
  1928. {
  1929. int error = 0;
  1930. unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
  1931. int get_ioctl_version = wl_cfg80211_get_ioctl_version();
  1932. error = set_roamscan_channel_list(dev, p[0], &p[1], get_ioctl_version);
  1933. if (error) {
  1934. DHD_ERROR(("wl_android_set_roam_scan_channels: Failed to set Scan Channels %d,"
  1935. " error = %d\n",
  1936. p[0], error));
  1937. return -1;
  1938. }
  1939. return 0;
  1940. }
  1941. int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
  1942. {
  1943. int error = 0;
  1944. int bytes_written = 0;
  1945. int time = 0;
  1946. error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
  1947. if (error) {
  1948. DHD_ERROR(("wl_android_get_scan_channel_time: Failed to get Scan Channel Time,"
  1949. " error = %d\n",
  1950. error));
  1951. return -1;
  1952. }
  1953. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
  1954. return bytes_written;
  1955. }
  1956. int wl_android_set_scan_channel_time(struct net_device *dev, char *command)
  1957. {
  1958. int error = 0;
  1959. int time = 0;
  1960. if (sscanf(command, "%*s %d", &time) != 1) {
  1961. DHD_ERROR(("wl_android_set_scan_channel_time: Failed to get Parameter\n"));
  1962. return -1;
  1963. }
  1964. #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
  1965. wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
  1966. error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
  1967. #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
  1968. if (error) {
  1969. DHD_ERROR(("wl_android_set_scan_channel_time: Failed to set Scan Channel Time %d,"
  1970. " error = %d\n",
  1971. time, error));
  1972. return -1;
  1973. }
  1974. return 0;
  1975. }
  1976. int
  1977. wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
  1978. {
  1979. int error = 0;
  1980. int bytes_written = 0;
  1981. int time = 0;
  1982. error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
  1983. if (error) {
  1984. DHD_ERROR(("wl_android_get_scan_unassoc_time: Failed to get Scan Unassoc"
  1985. " Time, error = %d\n",
  1986. error));
  1987. return -1;
  1988. }
  1989. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
  1990. return bytes_written;
  1991. }
  1992. int
  1993. wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
  1994. {
  1995. int error = 0;
  1996. int time = 0;
  1997. if (sscanf(command, "%*s %d", &time) != 1) {
  1998. DHD_ERROR(("wl_android_set_scan_unassoc_time: Failed to get Parameter\n"));
  1999. return -1;
  2000. }
  2001. #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
  2002. wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
  2003. error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
  2004. #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
  2005. if (error) {
  2006. DHD_ERROR(("wl_android_set_scan_unassoc_time: Failed to set Scan Unassoc Time %d,"
  2007. " error = %d\n",
  2008. time, error));
  2009. return -1;
  2010. }
  2011. return 0;
  2012. }
  2013. int
  2014. wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
  2015. {
  2016. int error = 0;
  2017. int bytes_written = 0;
  2018. int time = 0;
  2019. error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
  2020. if (error) {
  2021. DHD_ERROR(("wl_android_get_scan_passive_time: Failed to get Scan Passive Time,"
  2022. " error = %d\n",
  2023. error));
  2024. return -1;
  2025. }
  2026. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
  2027. return bytes_written;
  2028. }
  2029. int
  2030. wl_android_set_scan_passive_time(struct net_device *dev, char *command)
  2031. {
  2032. int error = 0;
  2033. int time = 0;
  2034. if (sscanf(command, "%*s %d", &time) != 1) {
  2035. DHD_ERROR(("wl_android_set_scan_passive_time: Failed to get Parameter\n"));
  2036. return -1;
  2037. }
  2038. #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
  2039. wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
  2040. error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
  2041. #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
  2042. if (error) {
  2043. DHD_ERROR(("wl_android_set_scan_passive_time: Failed to set Scan Passive Time %d,"
  2044. " error = %d\n",
  2045. time, error));
  2046. return -1;
  2047. }
  2048. return 0;
  2049. }
  2050. int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
  2051. {
  2052. int error = 0;
  2053. int bytes_written = 0;
  2054. int time = 0;
  2055. error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
  2056. if (error) {
  2057. DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
  2058. return -1;
  2059. }
  2060. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
  2061. return bytes_written;
  2062. }
  2063. int wl_android_set_scan_home_time(struct net_device *dev, char *command)
  2064. {
  2065. int error = 0;
  2066. int time = 0;
  2067. if (sscanf(command, "%*s %d", &time) != 1) {
  2068. DHD_ERROR(("wl_android_set_scan_home_time: Failed to get Parameter\n"));
  2069. return -1;
  2070. }
  2071. #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
  2072. wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
  2073. error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
  2074. #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
  2075. if (error) {
  2076. DHD_ERROR(("wl_android_set_scan_home_time: Failed to set Scan Home Time %d,"
  2077. " error = %d\n",
  2078. time, error));
  2079. return -1;
  2080. }
  2081. return 0;
  2082. }
  2083. int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
  2084. {
  2085. int error = 0;
  2086. int bytes_written = 0;
  2087. int time = 0;
  2088. error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
  2089. if (error) {
  2090. DHD_ERROR(("wl_android_get_scan_home_away_time: Failed to get Scan Home Away Time,"
  2091. " error = %d\n",
  2092. error));
  2093. return -1;
  2094. }
  2095. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
  2096. return bytes_written;
  2097. }
  2098. int wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
  2099. {
  2100. int error = 0;
  2101. int time = 0;
  2102. if (sscanf(command, "%*s %d", &time) != 1) {
  2103. DHD_ERROR(("wl_android_set_scan_home_away_time: Failed to get Parameter\n"));
  2104. return -1;
  2105. }
  2106. #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
  2107. wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
  2108. error = wldev_iovar_setint(dev, "scan_home_away_time", time);
  2109. #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
  2110. if (error) {
  2111. DHD_ERROR(("wl_android_set_scan_home_away_time: Failed to set Scan Home Away"
  2112. " Time %d, error = %d\n",
  2113. time, error));
  2114. return -1;
  2115. }
  2116. return 0;
  2117. }
  2118. int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
  2119. {
  2120. int error = 0;
  2121. int bytes_written = 0;
  2122. int num = 0;
  2123. error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
  2124. if (error) {
  2125. DHD_ERROR(("wl_android_get_scan_nprobes: Failed to get Scan NProbes,"
  2126. " error = %d\n", error));
  2127. return -1;
  2128. }
  2129. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
  2130. return bytes_written;
  2131. }
  2132. int wl_android_set_scan_nprobes(struct net_device *dev, char *command)
  2133. {
  2134. int error = 0;
  2135. int num = 0;
  2136. if (sscanf(command, "%*s %d", &num) != 1) {
  2137. DHD_ERROR(("wl_android_set_scan_nprobes: Failed to get Parameter\n"));
  2138. return -1;
  2139. }
  2140. error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
  2141. if (error) {
  2142. DHD_ERROR(("wl_android_set_scan_nprobes: Failed to set Scan NProbes %d,"
  2143. " error = %d\n",
  2144. num, error));
  2145. return -1;
  2146. }
  2147. return 0;
  2148. }
  2149. int wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
  2150. {
  2151. int error = 0;
  2152. int bytes_written = 0;
  2153. int mode = 0;
  2154. int scan_passive_time = 0;
  2155. error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
  2156. if (error) {
  2157. DHD_ERROR(("wl_android_get_scan_dfs_channel_mode: Failed to get Passive Time,"
  2158. " error = %d\n", error));
  2159. return -1;
  2160. }
  2161. if (scan_passive_time == 0) {
  2162. mode = 0;
  2163. } else {
  2164. mode = 1;
  2165. }
  2166. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
  2167. return bytes_written;
  2168. }
  2169. int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
  2170. {
  2171. int error = 0;
  2172. int mode = 0;
  2173. int scan_passive_time = 0;
  2174. if (sscanf(command, "%*s %d", &mode) != 1) {
  2175. DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to get Parameter\n"));
  2176. return -1;
  2177. }
  2178. if (mode == 1) {
  2179. scan_passive_time = DHD_SCAN_PASSIVE_TIME;
  2180. } else if (mode == 0) {
  2181. scan_passive_time = 0;
  2182. } else {
  2183. DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to set Scan DFS"
  2184. " channel mode %d, error = %d\n",
  2185. mode, error));
  2186. return -1;
  2187. }
  2188. error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
  2189. if (error) {
  2190. DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to set Scan"
  2191. " Passive Time %d, error = %d\n",
  2192. scan_passive_time, error));
  2193. return -1;
  2194. }
  2195. return 0;
  2196. }
  2197. #define JOINPREFFER_BUF_SIZE 12
  2198. static int
  2199. wl_android_set_join_prefer(struct net_device *dev, char *command)
  2200. {
  2201. int error = BCME_OK;
  2202. char smbuf[WLC_IOCTL_SMLEN];
  2203. uint8 buf[JOINPREFFER_BUF_SIZE];
  2204. char *pcmd;
  2205. int total_len_left;
  2206. int i;
  2207. char hex[] = "XX";
  2208. #ifdef WBTEXT
  2209. char commandp[WLC_IOCTL_SMLEN];
  2210. char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
  2211. #endif /* WBTEXT */
  2212. pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
  2213. total_len_left = strlen(pcmd);
  2214. bzero(buf, sizeof(buf));
  2215. if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
  2216. DHD_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
  2217. return BCME_ERROR;
  2218. }
  2219. /* Store the MSB first, as required by join_pref */
  2220. for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
  2221. hex[0] = *pcmd++;
  2222. hex[1] = *pcmd++;
  2223. buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
  2224. }
  2225. #ifdef WBTEXT
  2226. /* No coexistance between 11kv and join pref */
  2227. if (wl_android_check_wbtext(dev)) {
  2228. bzero(commandp, sizeof(commandp));
  2229. if (memcmp(buf, clear, sizeof(buf)) == 0) {
  2230. snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
  2231. } else {
  2232. snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
  2233. }
  2234. if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
  2235. DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
  2236. return error;
  2237. }
  2238. }
  2239. #endif /* WBTEXT */
  2240. prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
  2241. error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
  2242. smbuf, sizeof(smbuf), NULL);
  2243. if (error) {
  2244. DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
  2245. }
  2246. return error;
  2247. }
  2248. int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
  2249. {
  2250. int error = -1;
  2251. android_wifi_af_params_t *params = NULL;
  2252. wl_action_frame_t *action_frame = NULL;
  2253. wl_af_params_t *af_params = NULL;
  2254. char *smbuf = NULL;
  2255. struct ether_addr tmp_bssid;
  2256. int tmp_channel = 0;
  2257. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  2258. if (total_len <
  2259. (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
  2260. DHD_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
  2261. goto send_action_frame_out;
  2262. }
  2263. params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
  2264. if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
  2265. DHD_ERROR(("wl_android_send_action_frame: Requested action frame len"
  2266. " was out of range(%d)\n",
  2267. params->len));
  2268. goto send_action_frame_out;
  2269. }
  2270. smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
  2271. if (smbuf == NULL) {
  2272. DHD_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
  2273. WLC_IOCTL_MAXLEN));
  2274. goto send_action_frame_out;
  2275. }
  2276. af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
  2277. if (af_params == NULL) {
  2278. DHD_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
  2279. goto send_action_frame_out;
  2280. }
  2281. bzero(&tmp_bssid, ETHER_ADDR_LEN);
  2282. if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
  2283. bzero(&tmp_bssid, ETHER_ADDR_LEN);
  2284. error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
  2285. if (error) {
  2286. bzero(&tmp_bssid, ETHER_ADDR_LEN);
  2287. DHD_ERROR(("wl_android_send_action_frame: failed to get bssid,"
  2288. " error=%d\n", error));
  2289. goto send_action_frame_out;
  2290. }
  2291. }
  2292. if (params->channel < 0) {
  2293. struct channel_info ci;
  2294. bzero(&ci, sizeof(ci));
  2295. error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
  2296. if (error) {
  2297. DHD_ERROR(("wl_android_send_action_frame: failed to get channel,"
  2298. " error=%d\n", error));
  2299. goto send_action_frame_out;
  2300. }
  2301. tmp_channel = ci.hw_channel;
  2302. }
  2303. else {
  2304. tmp_channel = params->channel;
  2305. }
  2306. af_params->channel = tmp_channel;
  2307. af_params->dwell_time = params->dwell_time;
  2308. memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
  2309. action_frame = &af_params->action_frame;
  2310. action_frame->packetId = 0;
  2311. memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
  2312. action_frame->len = (uint16)params->len;
  2313. memcpy(action_frame->data, params->data, action_frame->len);
  2314. error = wldev_iovar_setbuf(dev, "actframe", af_params,
  2315. sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
  2316. if (error) {
  2317. DHD_ERROR(("wl_android_send_action_frame: failed to set action frame,"
  2318. " error=%d\n", error));
  2319. }
  2320. send_action_frame_out:
  2321. if (af_params) {
  2322. MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
  2323. }
  2324. if (smbuf) {
  2325. MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
  2326. }
  2327. if (error)
  2328. return -1;
  2329. else
  2330. return 0;
  2331. }
  2332. int wl_android_reassoc(struct net_device *dev, char *command, int total_len)
  2333. {
  2334. int error = 0;
  2335. android_wifi_reassoc_params_t *params = NULL;
  2336. uint band;
  2337. chanspec_t channel;
  2338. u32 params_size;
  2339. wl_reassoc_params_t reassoc_params;
  2340. if (total_len <
  2341. (strlen(CMD_REASSOC) + 1 + sizeof(android_wifi_reassoc_params_t))) {
  2342. DHD_ERROR(("wl_android_reassoc: Invalid parameters \n"));
  2343. return -1;
  2344. }
  2345. params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1);
  2346. bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
  2347. if (bcm_ether_atoe((const char *)params->bssid,
  2348. (struct ether_addr *)&reassoc_params.bssid) == 0) {
  2349. DHD_ERROR(("wl_android_reassoc: Invalid bssid \n"));
  2350. return -1;
  2351. }
  2352. if (params->channel < 0) {
  2353. DHD_ERROR(("wl_android_reassoc: Invalid Channel \n"));
  2354. return -1;
  2355. }
  2356. reassoc_params.chanspec_num = 1;
  2357. channel = params->channel;
  2358. #ifdef D11AC_IOTYPES
  2359. if (wl_cfg80211_get_ioctl_version() == 1) {
  2360. band = ((channel <= CH_MAX_2G_CHANNEL) ?
  2361. WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G);
  2362. reassoc_params.chanspec_list[0] = channel |
  2363. band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
  2364. }
  2365. else {
  2366. band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
  2367. reassoc_params.chanspec_list[0] = channel | band | WL_CHANSPEC_BW_20;
  2368. }
  2369. #else
  2370. band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
  2371. reassoc_params.chanspec_list[0] = channel |
  2372. band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
  2373. #endif /* D11AC_IOTYPES */
  2374. params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
  2375. error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
  2376. if (error) {
  2377. DHD_ERROR(("wl_android_reassoc: failed to reassoc, error=%d\n", error));
  2378. return -1;
  2379. }
  2380. return 0;
  2381. }
  2382. int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
  2383. {
  2384. int bytes_written = 0;
  2385. int mode = 0;
  2386. mode = wl_cfg80211_get_wes_mode();
  2387. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
  2388. return bytes_written;
  2389. }
  2390. int wl_android_set_wes_mode(struct net_device *dev, char *command)
  2391. {
  2392. int error = 0;
  2393. int mode = 0;
  2394. #ifdef WBTEXT
  2395. char commandp[WLC_IOCTL_SMLEN];
  2396. #endif /* WBTEXT */
  2397. if (sscanf(command, "%*s %d", &mode) != 1) {
  2398. DHD_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
  2399. return -1;
  2400. }
  2401. error = wl_cfg80211_set_wes_mode(mode);
  2402. if (error) {
  2403. DHD_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
  2404. mode, error));
  2405. return -1;
  2406. }
  2407. #ifdef WBTEXT
  2408. /* No coexistance between 11kv and FMC */
  2409. if (wl_android_check_wbtext(dev)) {
  2410. bzero(commandp, sizeof(commandp));
  2411. if (!mode) {
  2412. snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
  2413. } else {
  2414. snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
  2415. }
  2416. if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
  2417. DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
  2418. return error;
  2419. }
  2420. }
  2421. #endif /* WBTEXT */
  2422. return 0;
  2423. }
  2424. int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len)
  2425. {
  2426. int error = 0;
  2427. int bytes_written = 0;
  2428. int mode = 0;
  2429. error = wldev_iovar_getint(dev, "okc_enable", &mode);
  2430. if (error) {
  2431. DHD_ERROR(("wl_android_get_okc_mode: Failed to get OKC Mode, error = %d\n", error));
  2432. return -1;
  2433. }
  2434. bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode);
  2435. return bytes_written;
  2436. }
  2437. int wl_android_set_okc_mode(struct net_device *dev, char *command)
  2438. {
  2439. int error = 0;
  2440. int mode = 0;
  2441. if (sscanf(command, "%*s %d", &mode) != 1) {
  2442. DHD_ERROR(("wl_android_set_okc_mode: Failed to get Parameter\n"));
  2443. return -1;
  2444. }
  2445. error = wldev_iovar_setint(dev, "okc_enable", mode);
  2446. if (error) {
  2447. DHD_ERROR(("wl_android_set_okc_mode: Failed to set OKC Mode %d, error = %d\n",
  2448. mode, error));
  2449. return -1;
  2450. }
  2451. return error;
  2452. }
  2453. static int
  2454. wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
  2455. {
  2456. uchar pmk[33];
  2457. int error = 0;
  2458. char smbuf[WLC_IOCTL_SMLEN];
  2459. dhd_pub_t *dhdp;
  2460. #ifdef OKC_DEBUG
  2461. int i = 0;
  2462. #endif // endif
  2463. if (total_len < (strlen("SET_PMK ") + 32)) {
  2464. DHD_ERROR(("wl_android_set_pmk: Invalid argument\n"));
  2465. return -1;
  2466. }
  2467. dhdp = wl_cfg80211_get_dhdp(dev);
  2468. if (!dhdp) {
  2469. DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
  2470. return -1;
  2471. }
  2472. bzero(pmk, sizeof(pmk));
  2473. DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
  2474. memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
  2475. error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
  2476. if (error) {
  2477. DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
  2478. }
  2479. #ifdef OKC_DEBUG
  2480. DHD_ERROR(("PMK is "));
  2481. for (i = 0; i < 32; i++)
  2482. DHD_ERROR(("%02X ", pmk[i]));
  2483. DHD_ERROR(("\n"));
  2484. #endif // endif
  2485. return error;
  2486. }
  2487. static int
  2488. wl_android_okc_enable(struct net_device *dev, char *command)
  2489. {
  2490. int error = 0;
  2491. char okc_enable = 0;
  2492. okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
  2493. error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
  2494. if (error) {
  2495. DHD_ERROR(("Failed to %s OKC, error = %d\n",
  2496. okc_enable ? "enable" : "disable", error));
  2497. }
  2498. return error;
  2499. }
  2500. #endif /* WES_SUPPORT */
  2501. #ifdef SUPPORT_RESTORE_SCAN_PARAMS
  2502. static int
  2503. wl_android_restore_scan_params(struct net_device *dev, char *command, int total_len)
  2504. {
  2505. int error = 0;
  2506. uint error_cnt = 0;
  2507. int cnt = 0;
  2508. char restore_command[WLC_IOCTL_SMLEN];
  2509. while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
  2510. sprintf(restore_command, "%s %d", restore_params[cnt].command,
  2511. restore_params[cnt].parameter);
  2512. if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
  2513. error = restore_params[cnt].cmd_handler(dev, restore_command);
  2514. } else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
  2515. error = restore_params[cnt].cmd_handler_w_len(dev,
  2516. restore_command, total_len);
  2517. } else {
  2518. DHD_ERROR(("Unknown restore command handler\n"));
  2519. error = -1;
  2520. }
  2521. if (error) {
  2522. DHD_ERROR(("Failed to restore scan parameters %s, error : %d\n",
  2523. restore_command, error));
  2524. error_cnt++;
  2525. }
  2526. cnt++;
  2527. }
  2528. if (error_cnt > 0) {
  2529. DHD_ERROR(("Got %d error(s) while restoring scan parameters\n",
  2530. error_cnt));
  2531. error = -1;
  2532. }
  2533. return error;
  2534. }
  2535. #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
  2536. #ifdef WLTDLS
  2537. int wl_android_tdls_reset(struct net_device *dev)
  2538. {
  2539. int ret = 0;
  2540. ret = dhd_tdls_enable(dev, false, false, NULL);
  2541. if (ret < 0) {
  2542. DHD_ERROR(("Disable tdls failed. %d\n", ret));
  2543. return ret;
  2544. }
  2545. ret = dhd_tdls_enable(dev, true, true, NULL);
  2546. if (ret < 0) {
  2547. DHD_ERROR(("enable tdls failed. %d\n", ret));
  2548. return ret;
  2549. }
  2550. return 0;
  2551. }
  2552. #endif /* WLTDLS */
  2553. #ifdef CONFIG_SILENT_ROAM
  2554. int
  2555. wl_android_sroam_turn_on(struct net_device *dev, const char* turn)
  2556. {
  2557. int ret = BCME_OK, sroam_mode;
  2558. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  2559. sroam_mode = bcm_atoi(turn);
  2560. dhdp->sroam_turn_on = sroam_mode;
  2561. DHD_INFO(("%s Silent mode %s\n", __FUNCTION__,
  2562. sroam_mode ? "enable" : "disable"));
  2563. if (!sroam_mode) {
  2564. ret = dhd_sroam_set_mon(dhdp, FALSE);
  2565. if (ret) {
  2566. DHD_ERROR(("%s Failed to Set sroam %d\n",
  2567. __FUNCTION__, ret));
  2568. }
  2569. }
  2570. return ret;
  2571. }
  2572. int
  2573. wl_android_sroam_set_info(struct net_device *dev, char *data,
  2574. char *command, int total_len)
  2575. {
  2576. int ret = BCME_OK;
  2577. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  2578. size_t slen = strlen(data);
  2579. u8 ioctl_buf[WLC_IOCTL_SMLEN];
  2580. wlc_sroam_t *psroam;
  2581. wlc_sroam_info_t *sroam;
  2582. uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
  2583. data[slen] = '\0';
  2584. psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
  2585. if (!psroam) {
  2586. WL_ERR(("%s Fail to malloc buffer\n", __FUNCTION__));
  2587. ret = BCME_NOMEM;
  2588. goto done;
  2589. }
  2590. psroam->ver = WLC_SILENT_ROAM_CUR_VER;
  2591. psroam->len = sizeof(*sroam);
  2592. sroam = (wlc_sroam_info_t *)psroam->data;
  2593. sroam->sroam_on = FALSE;
  2594. if (*data && *data != '\0') {
  2595. sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
  2596. WL_DBG(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
  2597. data++;
  2598. }
  2599. if (*data && *data != '\0') {
  2600. sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
  2601. WL_DBG(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
  2602. data++;
  2603. }
  2604. if (*data && *data != '\0') {
  2605. sroam->sroam_score_delta = simple_strtol(data, &data, 10);
  2606. WL_DBG(("3.Score Delta %d\n", sroam->sroam_score_delta));
  2607. data++;
  2608. }
  2609. if (*data && *data != '\0') {
  2610. sroam->sroam_period_time = simple_strtol(data, &data, 10);
  2611. WL_DBG(("4.Sroam period %d\n", sroam->sroam_period_time));
  2612. data++;
  2613. }
  2614. if (*data && *data != '\0') {
  2615. sroam->sroam_band = simple_strtol(data, &data, 10);
  2616. WL_DBG(("5.Sroam Band %d\n", sroam->sroam_band));
  2617. data++;
  2618. }
  2619. if (*data && *data != '\0') {
  2620. sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
  2621. WL_DBG(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
  2622. data++;
  2623. }
  2624. if (*data != '\0') {
  2625. ret = BCME_BADARG;
  2626. goto done;
  2627. }
  2628. ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
  2629. sizeof(ioctl_buf), NULL);
  2630. if (ret) {
  2631. WL_ERR(("Failed to set silent roam info(%d)\n", ret));
  2632. goto done;
  2633. }
  2634. done:
  2635. if (psroam) {
  2636. MFREE(dhdp->osh, psroam, sroamlen);
  2637. }
  2638. return ret;
  2639. }
  2640. int
  2641. wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
  2642. {
  2643. int ret = BCME_OK;
  2644. int bytes_written = 0;
  2645. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  2646. wlc_sroam_t *psroam;
  2647. wlc_sroam_info_t *sroam;
  2648. uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
  2649. psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
  2650. if (!psroam) {
  2651. WL_ERR(("%s Fail to malloc buffer\n", __FUNCTION__));
  2652. ret = BCME_NOMEM;
  2653. goto done;
  2654. }
  2655. ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
  2656. if (ret) {
  2657. WL_ERR(("Failed to get silent roam info(%d)\n", ret));
  2658. goto done;
  2659. }
  2660. if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
  2661. ret = BCME_VERSION;
  2662. WL_ERR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
  2663. psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
  2664. goto done;
  2665. }
  2666. sroam = (wlc_sroam_info_t *)psroam->data;
  2667. bytes_written = snprintf(command, total_len,
  2668. "%s %d %d %d %d %d %d %d\n",
  2669. CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
  2670. sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
  2671. sroam->sroam_inact_cnt);
  2672. ret = bytes_written;
  2673. WL_DBG(("%s", command));
  2674. done:
  2675. if (psroam) {
  2676. MFREE(dhdp->osh, psroam, sroamlen);
  2677. }
  2678. return ret;
  2679. }
  2680. #endif /* CONFIG_SILENT_ROAM */
  2681. static int
  2682. get_int_bytes(uchar *oui_str, uchar *oui, int len)
  2683. {
  2684. int idx;
  2685. uchar val;
  2686. uchar *src, *dest;
  2687. char hexstr[3];
  2688. if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
  2689. return BCME_BADARG;
  2690. }
  2691. src = oui_str;
  2692. dest = oui;
  2693. for (idx = 0; idx < len; idx++) {
  2694. if (*src == '\0') {
  2695. *dest = '\0';
  2696. break;
  2697. }
  2698. hexstr[0] = src[0];
  2699. hexstr[1] = src[1];
  2700. hexstr[2] = '\0';
  2701. val = (uchar)bcm_strtoul(hexstr, NULL, 16);
  2702. if (val == (uchar)-1) {
  2703. return BCME_ERROR;
  2704. }
  2705. *dest++ = val;
  2706. src += 2;
  2707. }
  2708. return BCME_OK;
  2709. }
  2710. #define TAG_BYTE 0
  2711. static int
  2712. wl_android_set_disconnect_ies(struct net_device *dev, char *command)
  2713. {
  2714. int cmd_prefix_len = 0;
  2715. char ie_len = 0;
  2716. int hex_ie_len = 0;
  2717. int total_len = 0;
  2718. int max_len = 0;
  2719. int cmd_len = 0;
  2720. uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
  2721. s32 bssidx = 0;
  2722. struct bcm_cfg80211 *cfg = NULL;
  2723. s32 ret = 0;
  2724. cfg = wl_get_cfg(dev);
  2725. cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
  2726. cmd_len = strlen(command);
  2727. /*
  2728. * <CMD> + <IES in HEX format>
  2729. * IES in hex format has to be in following format
  2730. * First byte = Tag, Second Byte = len and rest of
  2731. * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
  2732. * tag = dd, len =04. Total IEs len = len + 2
  2733. */
  2734. WL_DBG(("cmd recv = %s\n", command));
  2735. max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
  2736. /* Validate IEs len */
  2737. get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
  2738. WL_INFORM_MEM(("ie_len = %d \n", ie_len));
  2739. if (ie_len <= 0 || ie_len > max_len) {
  2740. ret = BCME_BADLEN;
  2741. return ret;
  2742. }
  2743. /* Total len in hex is sum of double binary len, tag and len byte */
  2744. hex_ie_len = (ie_len * 2) + 4;
  2745. total_len = cmd_prefix_len + hex_ie_len;
  2746. if (command[total_len] != '\0' || (cmd_len != total_len)) {
  2747. WL_ERR(("command recv not matching with len, command = %s"
  2748. "total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
  2749. ret = BCME_BADARG;
  2750. return ret;
  2751. }
  2752. if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
  2753. WL_ERR(("Find index failed\n"));
  2754. ret = -EINVAL;
  2755. return ret;
  2756. }
  2757. /* Tag and len bytes are also part of total len of ies in binary */
  2758. ie_len = ie_len + 2;
  2759. /* Convert IEs in binary */
  2760. get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
  2761. if (disassoc_ie[TAG_BYTE] != 0xdd) {
  2762. WL_ERR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
  2763. ret = BCME_UNSUPPORTED;
  2764. return ret;
  2765. }
  2766. ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
  2767. ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
  2768. return ret;
  2769. }
  2770. #ifdef FCC_PWR_LIMIT_2G
  2771. int
  2772. wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
  2773. {
  2774. int error = 0;
  2775. int enable = 0;
  2776. sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
  2777. if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
  2778. DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
  2779. return BCME_ERROR;
  2780. }
  2781. CUSTOMER_HW4_EN_CONVERT(enable);
  2782. DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
  2783. error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
  2784. if (error) {
  2785. DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
  2786. " set returned (%d)\n", error));
  2787. return BCME_ERROR;
  2788. }
  2789. return error;
  2790. }
  2791. int
  2792. wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
  2793. {
  2794. int error = 0;
  2795. int enable = 0;
  2796. int bytes_written = 0;
  2797. error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
  2798. if (error) {
  2799. DHD_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
  2800. " error (%d)\n", error));
  2801. return BCME_ERROR;
  2802. }
  2803. DHD_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
  2804. bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
  2805. return bytes_written;
  2806. }
  2807. #endif /* FCC_PWR_LIMIT_2G */
  2808. s32
  2809. wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
  2810. {
  2811. int bytes_written = -1, ret = 0;
  2812. char *pcmd = command;
  2813. char *str;
  2814. sta_info_v4_t *sta = NULL;
  2815. const wl_cnt_wlc_t* wlc_cnt = NULL;
  2816. struct ether_addr mac;
  2817. char *iovar_buf;
  2818. /* Client information */
  2819. uint16 cap = 0;
  2820. uint32 rxrtry = 0;
  2821. uint32 rxmulti = 0;
  2822. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  2823. #ifdef BIGDATA_SOFTAP
  2824. void *data = NULL;
  2825. int get_bigdata_softap = FALSE;
  2826. wl_ap_sta_data_t *sta_data = NULL;
  2827. struct bcm_cfg80211 *bcm_cfg = wl_get_cfg(dev);
  2828. #endif /* BIGDATA_SOFTAP */
  2829. WL_DBG(("%s\n", command));
  2830. iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
  2831. if (iovar_buf == NULL) {
  2832. DHD_ERROR(("wl_cfg80211_get_sta_info: failed to allocated memory %d bytes\n",
  2833. WLC_IOCTL_MAXLEN));
  2834. goto error;
  2835. }
  2836. str = bcmstrtok(&pcmd, " ", NULL);
  2837. if (str) {
  2838. str = bcmstrtok(&pcmd, " ", NULL);
  2839. /* If GETSTAINFO subcmd name is not provided, return error */
  2840. if (str == NULL) {
  2841. WL_ERR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
  2842. goto error;
  2843. }
  2844. bzero(&mac, ETHER_ADDR_LEN);
  2845. if ((bcm_ether_atoe((str), &mac))) {
  2846. /* get the sta info */
  2847. ret = wldev_iovar_getbuf(dev, "sta_info",
  2848. (struct ether_addr *)mac.octet,
  2849. ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
  2850. #ifdef BIGDATA_SOFTAP
  2851. get_bigdata_softap = TRUE;
  2852. #endif /* BIGDATA_SOFTAP */
  2853. if (ret < 0) {
  2854. WL_ERR(("Get sta_info ERR %d\n", ret));
  2855. #ifndef BIGDATA_SOFTAP
  2856. goto error;
  2857. #else
  2858. goto get_bigdata;
  2859. #endif /* BIGDATA_SOFTAP */
  2860. }
  2861. sta = (sta_info_v4_t *)iovar_buf;
  2862. if (dtoh16(sta->ver) != WL_STA_VER_4) {
  2863. WL_ERR(("sta_info struct version mismatch, "
  2864. "host ver : %d, fw ver : %d\n", WL_STA_VER_4,
  2865. dtoh16(sta->ver)));
  2866. goto error;
  2867. }
  2868. cap = dtoh16(sta->cap);
  2869. rxrtry = dtoh32(sta->rx_pkts_retried);
  2870. rxmulti = dtoh32(sta->rx_mcast_pkts);
  2871. } else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) {
  2872. /* get counters info */
  2873. ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
  2874. iovar_buf, WLC_IOCTL_MAXLEN, NULL);
  2875. if (unlikely(ret)) {
  2876. WL_ERR(("counters error (%d) - size = %zu\n",
  2877. ret, sizeof(wl_cnt_wlc_t)));
  2878. goto error;
  2879. }
  2880. ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
  2881. if (ret != BCME_OK) {
  2882. WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret));
  2883. goto error;
  2884. }
  2885. if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
  2886. WL_ERR(("wlc_cnt NULL!\n"));
  2887. goto error;
  2888. }
  2889. rxrtry = dtoh32(wlc_cnt->rxrtry);
  2890. rxmulti = dtoh32(wlc_cnt->rxmulti);
  2891. } else {
  2892. WL_ERR(("Get address fail\n"));
  2893. goto error;
  2894. }
  2895. } else {
  2896. WL_ERR(("Command ERR\n"));
  2897. goto error;
  2898. }
  2899. #ifdef BIGDATA_SOFTAP
  2900. get_bigdata:
  2901. if (get_bigdata_softap) {
  2902. WL_ERR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
  2903. if (wl_get_ap_stadata(bcm_cfg, &mac, &data) == BCME_OK) {
  2904. sta_data = (wl_ap_sta_data_t *)data;
  2905. bytes_written = snprintf(command, total_len,
  2906. "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
  2907. "CAP=%04x "MACOUI" %d %s %d %d %d %d %d %d\n",
  2908. CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap,
  2909. MACOUI2STR((char*)&sta_data->mac),
  2910. sta_data->channel,
  2911. wf_chspec_to_bw_str(sta_data->chanspec),
  2912. sta_data->rssi, sta_data->rate,
  2913. sta_data->mode_80211, sta_data->nss, sta_data->mimo,
  2914. sta_data->reason_code);
  2915. WL_ERR_KERN(("command %s\n", command));
  2916. goto error;
  2917. }
  2918. }
  2919. #endif /* BIGDATA_SOFTAP */
  2920. bytes_written = snprintf(command, total_len,
  2921. "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n",
  2922. CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap);
  2923. WL_DBG(("%s", command));
  2924. error:
  2925. if (iovar_buf) {
  2926. MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
  2927. }
  2928. return bytes_written;
  2929. }
  2930. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  2931. #ifdef WBTEXT
  2932. static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
  2933. {
  2934. int error = BCME_OK, argc = 0;
  2935. int data, bytes_written;
  2936. int roam_trigger[2];
  2937. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  2938. argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
  2939. if (!argc) {
  2940. error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
  2941. if (error) {
  2942. DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
  2943. error));
  2944. return error;
  2945. }
  2946. bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
  2947. (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
  2948. "ENABLED" : "DISABLED");
  2949. return bytes_written;
  2950. } else {
  2951. if (data) {
  2952. data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
  2953. }
  2954. if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
  2955. DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
  2956. error));
  2957. return error;
  2958. }
  2959. if (data) {
  2960. /* reset roam_prof when wbtext is on */
  2961. if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
  2962. return error;
  2963. }
  2964. dhdp->wbtext_support = TRUE;
  2965. } else {
  2966. /* reset legacy roam trigger when wbtext is off */
  2967. roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
  2968. roam_trigger[1] = WLC_BAND_ALL;
  2969. if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
  2970. sizeof(roam_trigger))) != BCME_OK) {
  2971. DHD_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
  2972. error));
  2973. return error;
  2974. }
  2975. dhdp->wbtext_support = FALSE;
  2976. }
  2977. }
  2978. return error;
  2979. }
  2980. static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
  2981. char *command, int total_len)
  2982. {
  2983. int error = BCME_OK, argc = 0;
  2984. int data, bytes_written;
  2985. argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
  2986. if (!argc) {
  2987. error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
  2988. if (error) {
  2989. WL_ERR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
  2990. return error;
  2991. }
  2992. bytes_written = snprintf(command, total_len, "%d\n", data);
  2993. return bytes_written;
  2994. } else {
  2995. if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
  2996. data)) != BCME_OK) {
  2997. WL_ERR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
  2998. return error;
  2999. }
  3000. }
  3001. return error;
  3002. }
  3003. static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
  3004. char *command, int total_len)
  3005. {
  3006. int error = BCME_OK, argc = 0;
  3007. int data = 0, bytes_written;
  3008. argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
  3009. if (!argc) {
  3010. error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
  3011. if (error) {
  3012. WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
  3013. return error;
  3014. }
  3015. bytes_written = snprintf(command, total_len, "%d\n", data);
  3016. return bytes_written;
  3017. } else {
  3018. if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
  3019. data)) != BCME_OK) {
  3020. WL_ERR(("Failed to set wnm_btmdelta (%d)\n", error));
  3021. return error;
  3022. }
  3023. }
  3024. return error;
  3025. }
  3026. static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
  3027. char *command, int total_len)
  3028. {
  3029. int error = BCME_OK;
  3030. int data = 0, bytes_written = 0;
  3031. int wnmmask = 0;
  3032. char *pcmd = command;
  3033. bcmstrtok(&pcmd, " ", NULL);
  3034. error = wldev_iovar_getint(dev, "wnm", &wnmmask);
  3035. if (error) {
  3036. WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
  3037. return error;
  3038. }
  3039. WL_DBG(("wnmmask %x\n", wnmmask));
  3040. if (*pcmd == WL_IOCTL_ACTION_GET) {
  3041. bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
  3042. (wnmmask & WL_WNM_ESTM) ? 1:0);
  3043. return bytes_written;
  3044. } else {
  3045. data = bcm_atoi(pcmd);
  3046. if (data == 0) {
  3047. wnmmask &= ~WL_WNM_ESTM;
  3048. } else {
  3049. wnmmask |= WL_WNM_ESTM;
  3050. }
  3051. WL_DBG(("wnmmask %x\n", wnmmask));
  3052. if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
  3053. WL_ERR(("Failed to set wnm mask (%d)\n", error));
  3054. return error;
  3055. }
  3056. }
  3057. return error;
  3058. }
  3059. #endif /* WBTEXT */
  3060. #ifdef PNO_SUPPORT
  3061. #define PNO_PARAM_SIZE 50
  3062. #define VALUE_SIZE 50
  3063. #define LIMIT_STR_FMT ("%50s %50s")
  3064. static int
  3065. wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
  3066. {
  3067. int err = BCME_OK;
  3068. uint i, tokens, len_remain;
  3069. char *pos, *pos2, *token, *token2, *delim;
  3070. char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
  3071. struct dhd_pno_batch_params batch_params;
  3072. DHD_PNO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
  3073. len_remain = total_len;
  3074. if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
  3075. pos = command + strlen(CMD_WLS_BATCHING) + 1;
  3076. len_remain -= strlen(CMD_WLS_BATCHING) + 1;
  3077. } else {
  3078. WL_ERR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
  3079. err = BCME_ERROR;
  3080. goto exit;
  3081. }
  3082. bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
  3083. if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
  3084. if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
  3085. pos += strlen(PNO_BATCHING_SET) + 1;
  3086. } else {
  3087. WL_ERR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
  3088. PNO_BATCHING_SET, total_len));
  3089. err = BCME_ERROR;
  3090. goto exit;
  3091. }
  3092. while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
  3093. bzero(param, sizeof(param));
  3094. bzero(value, sizeof(value));
  3095. if (token == NULL || !*token)
  3096. break;
  3097. if (*token == '\0')
  3098. continue;
  3099. delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
  3100. if (delim != NULL)
  3101. *delim = ' ';
  3102. tokens = sscanf(token, LIMIT_STR_FMT, param, value);
  3103. if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
  3104. batch_params.scan_fr = simple_strtol(value, NULL, 0);
  3105. DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
  3106. } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
  3107. batch_params.bestn = simple_strtol(value, NULL, 0);
  3108. DHD_PNO(("bestn : %d\n", batch_params.bestn));
  3109. } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
  3110. batch_params.mscan = simple_strtol(value, NULL, 0);
  3111. DHD_PNO(("mscan : %d\n", batch_params.mscan));
  3112. } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
  3113. i = 0;
  3114. pos2 = value;
  3115. tokens = sscanf(value, "<%s>", value);
  3116. if (tokens != 1) {
  3117. err = BCME_ERROR;
  3118. DHD_ERROR(("wls_parse_batching_cmd: invalid format"
  3119. " for channel"
  3120. " <> params\n"));
  3121. goto exit;
  3122. }
  3123. while ((token2 = strsep(&pos2,
  3124. PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
  3125. if (token2 == NULL || !*token2)
  3126. break;
  3127. if (*token2 == '\0')
  3128. continue;
  3129. if (*token2 == 'A' || *token2 == 'B') {
  3130. batch_params.band = (*token2 == 'A')?
  3131. WLC_BAND_5G : WLC_BAND_2G;
  3132. DHD_PNO(("band : %s\n",
  3133. (*token2 == 'A')? "A" : "B"));
  3134. } else {
  3135. if ((batch_params.nchan >= WL_NUMCHANNELS) ||
  3136. (i >= WL_NUMCHANNELS)) {
  3137. DHD_ERROR(("Too many nchan %d\n",
  3138. batch_params.nchan));
  3139. err = BCME_BUFTOOSHORT;
  3140. goto exit;
  3141. }
  3142. batch_params.chan_list[i++] =
  3143. simple_strtol(token2, NULL, 0);
  3144. batch_params.nchan++;
  3145. DHD_PNO(("channel :%d\n",
  3146. batch_params.chan_list[i-1]));
  3147. }
  3148. }
  3149. } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
  3150. batch_params.rtt = simple_strtol(value, NULL, 0);
  3151. DHD_PNO(("rtt : %d\n", batch_params.rtt));
  3152. } else {
  3153. DHD_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
  3154. err = BCME_ERROR;
  3155. goto exit;
  3156. }
  3157. }
  3158. err = dhd_dev_pno_set_for_batch(dev, &batch_params);
  3159. if (err < 0) {
  3160. DHD_ERROR(("failed to configure batch scan\n"));
  3161. } else {
  3162. bzero(command, total_len);
  3163. err = snprintf(command, total_len, "%d", err);
  3164. }
  3165. } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
  3166. err = dhd_dev_pno_get_for_batch(dev, command, total_len);
  3167. if (err < 0) {
  3168. DHD_ERROR(("failed to getting batching results\n"));
  3169. } else {
  3170. err = strlen(command);
  3171. }
  3172. } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
  3173. err = dhd_dev_pno_stop_for_batch(dev);
  3174. if (err < 0) {
  3175. DHD_ERROR(("failed to stop batching scan\n"));
  3176. } else {
  3177. bzero(command, total_len);
  3178. err = snprintf(command, total_len, "OK");
  3179. }
  3180. } else {
  3181. DHD_ERROR(("wls_parse_batching_cmd : unknown command\n"));
  3182. err = BCME_ERROR;
  3183. goto exit;
  3184. }
  3185. exit:
  3186. return err;
  3187. }
  3188. #ifndef WL_SCHED_SCAN
  3189. static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
  3190. {
  3191. wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
  3192. int res = -1;
  3193. int nssid = 0;
  3194. cmd_tlv_t *cmd_tlv_temp;
  3195. char *str_ptr;
  3196. int tlv_size_left;
  3197. int pno_time = 0;
  3198. int pno_repeat = 0;
  3199. int pno_freq_expo_max = 0;
  3200. #ifdef PNO_SET_DEBUG
  3201. int i;
  3202. char pno_in_example[] = {
  3203. 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
  3204. 'S', '1', '2', '0',
  3205. 'S',
  3206. 0x05,
  3207. 'd', 'l', 'i', 'n', 'k',
  3208. 'S',
  3209. 0x04,
  3210. 'G', 'O', 'O', 'G',
  3211. 'T',
  3212. '0', 'B',
  3213. 'R',
  3214. '2',
  3215. 'M',
  3216. '2',
  3217. 0x00
  3218. };
  3219. #endif /* PNO_SET_DEBUG */
  3220. DHD_PNO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
  3221. if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
  3222. DHD_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
  3223. goto exit_proc;
  3224. }
  3225. #ifdef PNO_SET_DEBUG
  3226. memcpy(command, pno_in_example, sizeof(pno_in_example));
  3227. total_len = sizeof(pno_in_example);
  3228. #endif // endif
  3229. str_ptr = command + strlen(CMD_PNOSETUP_SET);
  3230. tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
  3231. cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
  3232. bzero(ssids_local, sizeof(ssids_local));
  3233. if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
  3234. (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
  3235. (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
  3236. str_ptr += sizeof(cmd_tlv_t);
  3237. tlv_size_left -= sizeof(cmd_tlv_t);
  3238. if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
  3239. MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
  3240. DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
  3241. goto exit_proc;
  3242. } else {
  3243. if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
  3244. DHD_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
  3245. " field size %d\n",
  3246. tlv_size_left));
  3247. goto exit_proc;
  3248. }
  3249. str_ptr++;
  3250. pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
  3251. DHD_PNO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
  3252. if (str_ptr[0] != 0) {
  3253. if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
  3254. DHD_ERROR(("wl_android_set_pno_setup: pno repeat:"
  3255. " corrupted field\n"));
  3256. goto exit_proc;
  3257. }
  3258. str_ptr++;
  3259. pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
  3260. DHD_PNO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
  3261. pno_repeat));
  3262. if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
  3263. DHD_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
  3264. " corrupted field size\n"));
  3265. goto exit_proc;
  3266. }
  3267. str_ptr++;
  3268. pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
  3269. DHD_PNO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
  3270. pno_freq_expo_max));
  3271. }
  3272. }
  3273. } else {
  3274. DHD_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
  3275. goto exit_proc;
  3276. }
  3277. res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
  3278. pno_freq_expo_max, NULL, 0);
  3279. exit_proc:
  3280. return res;
  3281. }
  3282. #endif /* !WL_SCHED_SCAN */
  3283. #endif /* PNO_SUPPORT */
  3284. static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
  3285. {
  3286. int ret;
  3287. struct ether_addr p2pdev_addr;
  3288. #define MAC_ADDR_STR_LEN 18
  3289. if (total_len < MAC_ADDR_STR_LEN) {
  3290. DHD_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
  3291. total_len));
  3292. return -1;
  3293. }
  3294. ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
  3295. if (ret) {
  3296. DHD_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
  3297. return -1;
  3298. }
  3299. return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
  3300. }
  3301. int
  3302. wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
  3303. {
  3304. int i, j, match;
  3305. int ret = 0;
  3306. char mac_buf[MAX_NUM_OF_ASSOCLIST *
  3307. sizeof(struct ether_addr) + sizeof(uint)] = {0};
  3308. struct maclist *assoc_maclist = (struct maclist *)mac_buf;
  3309. /* set filtering mode */
  3310. if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
  3311. DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
  3312. return ret;
  3313. }
  3314. if (macmode != MACLIST_MODE_DISABLED) {
  3315. /* set the MAC filter list */
  3316. if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
  3317. sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
  3318. DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
  3319. return ret;
  3320. }
  3321. /* get the current list of associated STAs */
  3322. assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
  3323. if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
  3324. sizeof(mac_buf))) != 0) {
  3325. DHD_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
  3326. ret));
  3327. return ret;
  3328. }
  3329. /* do we have any STA associated? */
  3330. if (assoc_maclist->count) {
  3331. /* iterate each associated STA */
  3332. for (i = 0; i < assoc_maclist->count; i++) {
  3333. match = 0;
  3334. /* compare with each entry */
  3335. for (j = 0; j < maclist->count; j++) {
  3336. DHD_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
  3337. "list = "MACDBG "\n",
  3338. MAC2STRDBG(assoc_maclist->ea[i].octet),
  3339. MAC2STRDBG(maclist->ea[j].octet)));
  3340. if (memcmp(assoc_maclist->ea[i].octet,
  3341. maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
  3342. match = 1;
  3343. break;
  3344. }
  3345. }
  3346. /* do conditional deauth */
  3347. /* "if not in the allow list" or "if in the deny list" */
  3348. if ((macmode == MACLIST_MODE_ALLOW && !match) ||
  3349. (macmode == MACLIST_MODE_DENY && match)) {
  3350. scb_val_t scbval;
  3351. scbval.val = htod32(1);
  3352. memcpy(&scbval.ea, &assoc_maclist->ea[i],
  3353. ETHER_ADDR_LEN);
  3354. if ((ret = wldev_ioctl_set(dev,
  3355. WLC_SCB_DEAUTHENTICATE_FOR_REASON,
  3356. &scbval, sizeof(scb_val_t))) != 0)
  3357. DHD_ERROR(("wl_android_set_ap_mac_list:"
  3358. " WLC_SCB_DEAUTHENTICATE"
  3359. " error=%d\n",
  3360. ret));
  3361. }
  3362. }
  3363. }
  3364. }
  3365. return ret;
  3366. }
  3367. /*
  3368. * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
  3369. *
  3370. */
  3371. static int
  3372. wl_android_set_mac_address_filter(struct net_device *dev, char* str)
  3373. {
  3374. int i;
  3375. int ret = 0;
  3376. int macnum = 0;
  3377. int macmode = MACLIST_MODE_DISABLED;
  3378. struct maclist *list;
  3379. char eabuf[ETHER_ADDR_STR_LEN];
  3380. const char *token;
  3381. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  3382. /* string should look like below (macmode/macnum/maclist) */
  3383. /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
  3384. /* get the MAC filter mode */
  3385. token = strsep((char**)&str, " ");
  3386. if (!token) {
  3387. return -1;
  3388. }
  3389. macmode = bcm_atoi(token);
  3390. if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
  3391. DHD_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
  3392. return -1;
  3393. }
  3394. token = strsep((char**)&str, " ");
  3395. if (!token) {
  3396. return -1;
  3397. }
  3398. macnum = bcm_atoi(token);
  3399. if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
  3400. DHD_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
  3401. " address entries %d\n",
  3402. macnum));
  3403. return -1;
  3404. }
  3405. /* allocate memory for the MAC list */
  3406. list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
  3407. sizeof(struct ether_addr) * macnum);
  3408. if (!list) {
  3409. DHD_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
  3410. return -1;
  3411. }
  3412. /* prepare the MAC list */
  3413. list->count = htod32(macnum);
  3414. bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
  3415. for (i = 0; i < list->count; i++) {
  3416. token = strsep((char**)&str, " ");
  3417. if (token == NULL) {
  3418. DHD_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
  3419. ret = -EINVAL;
  3420. goto exit;
  3421. }
  3422. strlcpy(eabuf, token, sizeof(eabuf));
  3423. if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
  3424. DHD_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
  3425. " addr=%s\n",
  3426. i, eabuf));
  3427. list->count = i;
  3428. break;
  3429. }
  3430. DHD_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
  3431. i, list->count, eabuf));
  3432. }
  3433. if (i == 0)
  3434. goto exit;
  3435. /* set the list */
  3436. if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
  3437. DHD_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
  3438. ret));
  3439. exit:
  3440. MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
  3441. return ret;
  3442. }
  3443. /**
  3444. * Global function definitions (declared in wl_android.h)
  3445. */
  3446. int wl_android_wifi_on(struct net_device *dev)
  3447. {
  3448. int ret = 0;
  3449. int retry = POWERUP_MAX_RETRY;
  3450. DHD_ERROR(("wl_android_wifi_on in\n"));
  3451. if (!dev) {
  3452. DHD_ERROR(("wl_android_wifi_on: dev is null\n"));
  3453. return -EINVAL;
  3454. }
  3455. dhd_net_if_lock(dev);
  3456. if (!g_wifi_on) {
  3457. do {
  3458. dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
  3459. #ifdef BCMSDIO
  3460. ret = dhd_net_bus_resume(dev, 0);
  3461. #endif /* BCMSDIO */
  3462. #ifdef BCMPCIE
  3463. ret = dhd_net_bus_devreset(dev, FALSE);
  3464. #endif /* BCMPCIE */
  3465. if (ret == 0) {
  3466. break;
  3467. }
  3468. DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
  3469. retry));
  3470. #ifdef BCMPCIE
  3471. dhd_net_bus_devreset(dev, TRUE);
  3472. #endif /* BCMPCIE */
  3473. dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
  3474. } while (retry-- > 0);
  3475. if (ret != 0) {
  3476. DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
  3477. #ifdef BCM_DETECT_TURN_ON_FAILURE
  3478. BUG_ON(1);
  3479. #endif /* BCM_DETECT_TURN_ON_FAILURE */
  3480. goto exit;
  3481. }
  3482. #ifdef BCMSDIO
  3483. ret = dhd_net_bus_devreset(dev, FALSE);
  3484. dhd_net_bus_resume(dev, 1);
  3485. #endif /* BCMSDIO */
  3486. #ifndef BCMPCIE
  3487. if (!ret) {
  3488. if (dhd_dev_init_ioctl(dev) < 0) {
  3489. ret = -EFAULT;
  3490. }
  3491. }
  3492. #endif /* !BCMPCIE */
  3493. g_wifi_on = TRUE;
  3494. }
  3495. exit:
  3496. dhd_net_if_unlock(dev);
  3497. return ret;
  3498. }
  3499. int wl_android_wifi_off(struct net_device *dev, bool on_failure)
  3500. {
  3501. int ret = 0;
  3502. DHD_ERROR(("wl_android_wifi_off in\n"));
  3503. if (!dev) {
  3504. DHD_TRACE(("wl_android_wifi_off: dev is null\n"));
  3505. return -EINVAL;
  3506. }
  3507. #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
  3508. ret = dhd_debug_uart_is_running(dev);
  3509. if (ret) {
  3510. DHD_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
  3511. return -EBUSY;
  3512. }
  3513. #endif /* BCMPCIE && DHD_DEBUG_UART */
  3514. dhd_net_if_lock(dev);
  3515. if (g_wifi_on || on_failure) {
  3516. #if defined(BCMSDIO) || defined(BCMPCIE)
  3517. ret = dhd_net_bus_devreset(dev, TRUE);
  3518. #ifdef BCMSDIO
  3519. dhd_net_bus_suspend(dev);
  3520. #endif /* BCMSDIO */
  3521. #endif /* BCMSDIO || BCMPCIE */
  3522. dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
  3523. g_wifi_on = FALSE;
  3524. }
  3525. dhd_net_if_unlock(dev);
  3526. return ret;
  3527. }
  3528. static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
  3529. {
  3530. if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
  3531. return -1;
  3532. return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
  3533. }
  3534. #ifdef CONNECTION_STATISTICS
  3535. static int
  3536. wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
  3537. {
  3538. int err;
  3539. wl_chanim_stats_t *list;
  3540. /* Parameter _and_ returned buffer of chanim_stats. */
  3541. wl_chanim_stats_t param;
  3542. u8 result[WLC_IOCTL_SMLEN];
  3543. chanim_stats_t *stats;
  3544. bzero(&param, sizeof(param));
  3545. param.buflen = htod32(sizeof(wl_chanim_stats_t));
  3546. param.count = htod32(WL_CHANIM_COUNT_ONE);
  3547. if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
  3548. (char*)result, sizeof(result), 0)) < 0) {
  3549. WL_ERR(("Failed to get chanim results %d \n", err));
  3550. return err;
  3551. }
  3552. list = (wl_chanim_stats_t*)result;
  3553. list->buflen = dtoh32(list->buflen);
  3554. list->version = dtoh32(list->version);
  3555. list->count = dtoh32(list->count);
  3556. if (list->buflen == 0) {
  3557. list->version = 0;
  3558. list->count = 0;
  3559. } else if (list->version != WL_CHANIM_STATS_VERSION) {
  3560. WL_ERR(("Sorry, firmware has wl_chanim_stats version %d "
  3561. "but driver supports only version %d.\n",
  3562. list->version, WL_CHANIM_STATS_VERSION));
  3563. list->buflen = 0;
  3564. list->count = 0;
  3565. }
  3566. stats = list->stats;
  3567. stats->glitchcnt = dtoh32(stats->glitchcnt);
  3568. stats->badplcp = dtoh32(stats->badplcp);
  3569. stats->chanspec = dtoh16(stats->chanspec);
  3570. stats->timestamp = dtoh32(stats->timestamp);
  3571. stats->chan_idle = dtoh32(stats->chan_idle);
  3572. WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
  3573. stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
  3574. stats->timestamp));
  3575. *chan_idle = stats->chan_idle;
  3576. return (err);
  3577. }
  3578. static int
  3579. wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
  3580. {
  3581. static char iovar_buf[WLC_IOCTL_MAXLEN];
  3582. const wl_cnt_wlc_t* wlc_cnt = NULL;
  3583. #ifndef DISABLE_IF_COUNTERS
  3584. wl_if_stats_t* if_stats = NULL;
  3585. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  3586. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  3587. #endif /* DISABLE_IF_COUNTERS */
  3588. int link_speed = 0;
  3589. struct connection_stats *output;
  3590. unsigned int bufsize = 0;
  3591. int bytes_written = -1;
  3592. int ret = 0;
  3593. WL_INFORM(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
  3594. if (total_len <= 0) {
  3595. WL_ERR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
  3596. goto error;
  3597. }
  3598. bufsize = total_len;
  3599. if (bufsize < sizeof(struct connection_stats)) {
  3600. WL_ERR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
  3601. " requires=%zu\n",
  3602. bufsize,
  3603. sizeof(struct connection_stats)));
  3604. goto error;
  3605. }
  3606. output = (struct connection_stats *)command;
  3607. #ifndef DISABLE_IF_COUNTERS
  3608. if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
  3609. if (if_stats == NULL) {
  3610. WL_ERR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
  3611. goto error;
  3612. }
  3613. bzero(if_stats, sizeof(*if_stats));
  3614. if (FW_SUPPORTED(dhdp, ifst)) {
  3615. ret = wl_cfg80211_ifstats_counters(dev, if_stats);
  3616. } else
  3617. {
  3618. ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
  3619. (char *)if_stats, sizeof(*if_stats), NULL);
  3620. }
  3621. ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
  3622. (char *)if_stats, sizeof(*if_stats), NULL);
  3623. if (ret) {
  3624. WL_ERR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
  3625. ret));
  3626. /* In case if_stats IOVAR is not supported, get information from counters. */
  3627. #endif /* DISABLE_IF_COUNTERS */
  3628. ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
  3629. iovar_buf, WLC_IOCTL_MAXLEN, NULL);
  3630. if (unlikely(ret)) {
  3631. WL_ERR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
  3632. goto error;
  3633. }
  3634. ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
  3635. if (ret != BCME_OK) {
  3636. WL_ERR(("wl_android_get_connection_stats:"
  3637. " wl_cntbuf_to_xtlv_format ERR %d\n",
  3638. ret));
  3639. goto error;
  3640. }
  3641. if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
  3642. WL_ERR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
  3643. goto error;
  3644. }
  3645. output->txframe = dtoh32(wlc_cnt->txframe);
  3646. output->txbyte = dtoh32(wlc_cnt->txbyte);
  3647. output->txerror = dtoh32(wlc_cnt->txerror);
  3648. output->rxframe = dtoh32(wlc_cnt->rxframe);
  3649. output->rxbyte = dtoh32(wlc_cnt->rxbyte);
  3650. output->txfail = dtoh32(wlc_cnt->txfail);
  3651. output->txretry = dtoh32(wlc_cnt->txretry);
  3652. output->txretrie = dtoh32(wlc_cnt->txretrie);
  3653. output->txrts = dtoh32(wlc_cnt->txrts);
  3654. output->txnocts = dtoh32(wlc_cnt->txnocts);
  3655. output->txexptime = dtoh32(wlc_cnt->txexptime);
  3656. #ifndef DISABLE_IF_COUNTERS
  3657. } else {
  3658. /* Populate from if_stats. */
  3659. if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
  3660. WL_ERR(("wl_android_get_connection_stats: incorrect version of"
  3661. " wl_if_stats_t,"
  3662. " expected=%u got=%u\n",
  3663. WL_IF_STATS_T_VERSION, if_stats->version));
  3664. goto error;
  3665. }
  3666. output->txframe = (uint32)dtoh64(if_stats->txframe);
  3667. output->txbyte = (uint32)dtoh64(if_stats->txbyte);
  3668. output->txerror = (uint32)dtoh64(if_stats->txerror);
  3669. output->rxframe = (uint32)dtoh64(if_stats->rxframe);
  3670. output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
  3671. output->txfail = (uint32)dtoh64(if_stats->txfail);
  3672. output->txretry = (uint32)dtoh64(if_stats->txretry);
  3673. output->txretrie = (uint32)dtoh64(if_stats->txretrie);
  3674. if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
  3675. output->txexptime = (uint32)dtoh64(if_stats->txexptime);
  3676. output->txrts = (uint32)dtoh64(if_stats->txrts);
  3677. output->txnocts = (uint32)dtoh64(if_stats->txnocts);
  3678. } else {
  3679. output->txexptime = 0;
  3680. output->txrts = 0;
  3681. output->txnocts = 0;
  3682. }
  3683. }
  3684. #endif /* DISABLE_IF_COUNTERS */
  3685. /* link_speed is in kbps */
  3686. ret = wldev_get_link_speed(dev, &link_speed);
  3687. if (ret || link_speed < 0) {
  3688. WL_ERR(("wl_android_get_connection_stats: wldev_get_link_speed()"
  3689. " failed, ret=%d, speed=%d\n",
  3690. ret, link_speed));
  3691. goto error;
  3692. }
  3693. output->txrate = link_speed;
  3694. /* Channel idle ratio. */
  3695. if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
  3696. output->chan_idle = 0;
  3697. };
  3698. bytes_written = sizeof(struct connection_stats);
  3699. error:
  3700. #ifndef DISABLE_IF_COUNTERS
  3701. if (if_stats) {
  3702. MFREE(cfg->osh, if_stats, sizeof(*if_stats));
  3703. }
  3704. #endif /* DISABLE_IF_COUNTERS */
  3705. return bytes_written;
  3706. }
  3707. #endif /* CONNECTION_STATISTICS */
  3708. #ifdef WL_NATOE
  3709. static int
  3710. wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
  3711. {
  3712. int ret = BCME_ERROR;
  3713. char *pcmd = command;
  3714. char *str = NULL;
  3715. wl_natoe_cmd_info_t cmd_info;
  3716. const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
  3717. /* skip to cmd name after "natoe" */
  3718. str = bcmstrtok(&pcmd, " ", NULL);
  3719. /* If natoe subcmd name is not provided, return error */
  3720. if (*pcmd == '\0') {
  3721. WL_ERR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
  3722. ret = -EINVAL;
  3723. return ret;
  3724. }
  3725. /* get the natoe command name to str */
  3726. str = bcmstrtok(&pcmd, " ", NULL);
  3727. while (natoe_cmd->name != NULL) {
  3728. if (strcmp(natoe_cmd->name, str) == 0) {
  3729. /* dispacth cmd to appropriate handler */
  3730. if (natoe_cmd->handler) {
  3731. cmd_info.command = command;
  3732. cmd_info.tot_len = total_len;
  3733. ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
  3734. }
  3735. return ret;
  3736. }
  3737. natoe_cmd++;
  3738. }
  3739. return ret;
  3740. }
  3741. static int
  3742. wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
  3743. {
  3744. int res = BCME_OK;
  3745. wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
  3746. uint8 *command = cmd_info->command;
  3747. uint16 total_len = cmd_info->tot_len;
  3748. uint16 bytes_written = 0;
  3749. UNUSED_PARAMETER(len);
  3750. switch (type) {
  3751. case WL_NATOE_XTLV_ENABLE:
  3752. {
  3753. bytes_written = snprintf(command, total_len, "natoe: %s\n",
  3754. *data?"enabled":"disabled");
  3755. cmd_info->bytes_written = bytes_written;
  3756. break;
  3757. }
  3758. case WL_NATOE_XTLV_CONFIG_IPS:
  3759. {
  3760. wl_natoe_config_ips_t *config_ips;
  3761. uint8 buf[16];
  3762. config_ips = (wl_natoe_config_ips_t *)data;
  3763. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
  3764. bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
  3765. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
  3766. bytes_written += snprintf(command + bytes_written, total_len,
  3767. "sta netmask: %s\n", buf);
  3768. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
  3769. bytes_written += snprintf(command + bytes_written, total_len,
  3770. "sta router ip: %s\n", buf);
  3771. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
  3772. bytes_written += snprintf(command + bytes_written, total_len,
  3773. "sta dns ip: %s\n", buf);
  3774. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
  3775. bytes_written += snprintf(command + bytes_written, total_len,
  3776. "ap ip: %s\n", buf);
  3777. bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
  3778. bytes_written += snprintf(command + bytes_written, total_len,
  3779. "ap netmask: %s\n", buf);
  3780. cmd_info->bytes_written = bytes_written;
  3781. break;
  3782. }
  3783. case WL_NATOE_XTLV_CONFIG_PORTS:
  3784. {
  3785. wl_natoe_ports_config_t *ports_config;
  3786. ports_config = (wl_natoe_ports_config_t *)data;
  3787. bytes_written = snprintf(command, total_len, "starting port num: %d\n",
  3788. dtoh16(ports_config->start_port_num));
  3789. bytes_written += snprintf(command + bytes_written, total_len,
  3790. "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
  3791. cmd_info->bytes_written = bytes_written;
  3792. break;
  3793. }
  3794. case WL_NATOE_XTLV_DBG_STATS:
  3795. {
  3796. char *stats_dump = (char *)data;
  3797. bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
  3798. cmd_info->bytes_written = bytes_written;
  3799. break;
  3800. }
  3801. case WL_NATOE_XTLV_TBL_CNT:
  3802. {
  3803. bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
  3804. dtoh32(*(uint32 *)data));
  3805. cmd_info->bytes_written = bytes_written;
  3806. break;
  3807. }
  3808. default:
  3809. /* ignore */
  3810. break;
  3811. }
  3812. return res;
  3813. }
  3814. /*
  3815. * --- common for all natoe get commands ----
  3816. */
  3817. static int
  3818. wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
  3819. uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
  3820. {
  3821. /* for gets we only need to pass ioc header */
  3822. wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
  3823. int res;
  3824. /* send getbuf natoe iovar */
  3825. res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
  3826. buflen, NULL);
  3827. /* check the response buff */
  3828. if ((res == BCME_OK)) {
  3829. /* scans ioctl tlvbuf f& invokes the cbfn for processing */
  3830. res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
  3831. BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
  3832. if (res == BCME_OK) {
  3833. res = cmd_info->bytes_written;
  3834. }
  3835. }
  3836. else
  3837. {
  3838. DHD_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
  3839. res = BCME_ERROR;
  3840. }
  3841. return res;
  3842. }
  3843. static int
  3844. wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
  3845. char *command, wl_natoe_cmd_info_t *cmd_info)
  3846. {
  3847. int ret = BCME_OK;
  3848. wl_natoe_ioc_t *natoe_ioc;
  3849. char *pcmd = command;
  3850. uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
  3851. uint16 buflen = WL_NATOE_IOC_BUFSZ;
  3852. bcm_xtlv_t *pxtlv = NULL;
  3853. char *ioctl_buf = NULL;
  3854. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  3855. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  3856. if (!ioctl_buf) {
  3857. WL_ERR(("ioctl memory alloc failed\n"));
  3858. return -ENOMEM;
  3859. }
  3860. /* alloc mem for ioctl headr + tlv data */
  3861. natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
  3862. if (!natoe_ioc) {
  3863. WL_ERR(("ioctl header memory alloc failed\n"));
  3864. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  3865. return -ENOMEM;
  3866. }
  3867. /* make up natoe cmd ioctl header */
  3868. natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
  3869. natoe_ioc->id = htod16(cmd->id);
  3870. natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
  3871. pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
  3872. if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
  3873. iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
  3874. ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
  3875. WLC_IOCTL_MEDLEN, cmd_info);
  3876. if (ret != BCME_OK) {
  3877. WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
  3878. ret = -EINVAL;
  3879. }
  3880. } else { /* set */
  3881. uint8 val = bcm_atoi(pcmd);
  3882. /* buflen is max tlv data we can write, it will be decremented as we pack */
  3883. /* save buflen at start */
  3884. uint16 buflen_at_start = buflen;
  3885. /* we'll adjust final ioc size at the end */
  3886. ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
  3887. sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
  3888. if (ret != BCME_OK) {
  3889. ret = -EINVAL;
  3890. goto exit;
  3891. }
  3892. /* adjust iocsz to the end of last data record */
  3893. natoe_ioc->len = (buflen_at_start - buflen);
  3894. iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
  3895. ret = wldev_iovar_setbuf(dev, "natoe",
  3896. natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
  3897. if (ret != BCME_OK) {
  3898. WL_ERR(("Fail to set iovar %d\n", ret));
  3899. ret = -EINVAL;
  3900. }
  3901. }
  3902. exit:
  3903. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  3904. MFREE(cfg->osh, natoe_ioc, iocsz);
  3905. return ret;
  3906. }
  3907. static int
  3908. wl_android_natoe_subcmd_config_ips(struct net_device *dev,
  3909. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
  3910. {
  3911. int ret = BCME_OK;
  3912. wl_natoe_config_ips_t config_ips;
  3913. wl_natoe_ioc_t *natoe_ioc;
  3914. char *pcmd = command;
  3915. char *str;
  3916. uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
  3917. uint16 buflen = WL_NATOE_IOC_BUFSZ;
  3918. bcm_xtlv_t *pxtlv = NULL;
  3919. char *ioctl_buf = NULL;
  3920. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  3921. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  3922. if (!ioctl_buf) {
  3923. WL_ERR(("ioctl memory alloc failed\n"));
  3924. return -ENOMEM;
  3925. }
  3926. /* alloc mem for ioctl headr + tlv data */
  3927. natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
  3928. if (!natoe_ioc) {
  3929. WL_ERR(("ioctl header memory alloc failed\n"));
  3930. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  3931. return -ENOMEM;
  3932. }
  3933. /* make up natoe cmd ioctl header */
  3934. natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
  3935. natoe_ioc->id = htod16(cmd->id);
  3936. natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
  3937. pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
  3938. if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
  3939. iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
  3940. ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
  3941. WLC_IOCTL_MEDLEN, cmd_info);
  3942. if (ret != BCME_OK) {
  3943. WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
  3944. ret = -EINVAL;
  3945. }
  3946. } else { /* set */
  3947. /* buflen is max tlv data we can write, it will be decremented as we pack */
  3948. /* save buflen at start */
  3949. uint16 buflen_at_start = buflen;
  3950. bzero(&config_ips, sizeof(config_ips));
  3951. str = bcmstrtok(&pcmd, " ", NULL);
  3952. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
  3953. WL_ERR(("Invalid STA IP addr %s\n", str));
  3954. ret = -EINVAL;
  3955. goto exit;
  3956. }
  3957. str = bcmstrtok(&pcmd, " ", NULL);
  3958. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
  3959. WL_ERR(("Invalid STA netmask %s\n", str));
  3960. ret = -EINVAL;
  3961. goto exit;
  3962. }
  3963. str = bcmstrtok(&pcmd, " ", NULL);
  3964. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
  3965. WL_ERR(("Invalid STA router IP addr %s\n", str));
  3966. ret = -EINVAL;
  3967. goto exit;
  3968. }
  3969. str = bcmstrtok(&pcmd, " ", NULL);
  3970. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
  3971. WL_ERR(("Invalid STA DNS IP addr %s\n", str));
  3972. ret = -EINVAL;
  3973. goto exit;
  3974. }
  3975. str = bcmstrtok(&pcmd, " ", NULL);
  3976. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
  3977. WL_ERR(("Invalid AP IP addr %s\n", str));
  3978. ret = -EINVAL;
  3979. goto exit;
  3980. }
  3981. str = bcmstrtok(&pcmd, " ", NULL);
  3982. if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
  3983. WL_ERR(("Invalid AP netmask %s\n", str));
  3984. ret = -EINVAL;
  3985. goto exit;
  3986. }
  3987. ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
  3988. &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
  3989. &config_ips, BCM_XTLV_OPTION_ALIGN32);
  3990. if (ret != BCME_OK) {
  3991. ret = -EINVAL;
  3992. goto exit;
  3993. }
  3994. /* adjust iocsz to the end of last data record */
  3995. natoe_ioc->len = (buflen_at_start - buflen);
  3996. iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
  3997. ret = wldev_iovar_setbuf(dev, "natoe",
  3998. natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
  3999. if (ret != BCME_OK) {
  4000. WL_ERR(("Fail to set iovar %d\n", ret));
  4001. ret = -EINVAL;
  4002. }
  4003. }
  4004. exit:
  4005. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  4006. MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
  4007. return ret;
  4008. }
  4009. static int
  4010. wl_android_natoe_subcmd_config_ports(struct net_device *dev,
  4011. const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
  4012. {
  4013. int ret = BCME_OK;
  4014. wl_natoe_ports_config_t ports_config;
  4015. wl_natoe_ioc_t *natoe_ioc;
  4016. char *pcmd = command;
  4017. char *str;
  4018. uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
  4019. uint16 buflen = WL_NATOE_IOC_BUFSZ;
  4020. bcm_xtlv_t *pxtlv = NULL;
  4021. char *ioctl_buf = NULL;
  4022. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4023. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  4024. if (!ioctl_buf) {
  4025. WL_ERR(("ioctl memory alloc failed\n"));
  4026. return -ENOMEM;
  4027. }
  4028. /* alloc mem for ioctl headr + tlv data */
  4029. natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
  4030. if (!natoe_ioc) {
  4031. WL_ERR(("ioctl header memory alloc failed\n"));
  4032. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  4033. return -ENOMEM;
  4034. }
  4035. /* make up natoe cmd ioctl header */
  4036. natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
  4037. natoe_ioc->id = htod16(cmd->id);
  4038. natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
  4039. pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
  4040. if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
  4041. iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
  4042. ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
  4043. WLC_IOCTL_MEDLEN, cmd_info);
  4044. if (ret != BCME_OK) {
  4045. WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
  4046. ret = -EINVAL;
  4047. }
  4048. } else { /* set */
  4049. /* buflen is max tlv data we can write, it will be decremented as we pack */
  4050. /* save buflen at start */
  4051. uint16 buflen_at_start = buflen;
  4052. bzero(&ports_config, sizeof(ports_config));
  4053. str = bcmstrtok(&pcmd, " ", NULL);
  4054. if (!str) {
  4055. WL_ERR(("Invalid port string %s\n", str));
  4056. ret = -EINVAL;
  4057. goto exit;
  4058. }
  4059. ports_config.start_port_num = htod16(bcm_atoi(str));
  4060. str = bcmstrtok(&pcmd, " ", NULL);
  4061. if (!str) {
  4062. WL_ERR(("Invalid port string %s\n", str));
  4063. ret = -EINVAL;
  4064. goto exit;
  4065. }
  4066. ports_config.no_of_ports = htod16(bcm_atoi(str));
  4067. if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
  4068. NATOE_MAX_PORT_NUM) {
  4069. WL_ERR(("Invalid port configuration\n"));
  4070. ret = -EINVAL;
  4071. goto exit;
  4072. }
  4073. ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
  4074. &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
  4075. &ports_config, BCM_XTLV_OPTION_ALIGN32);
  4076. if (ret != BCME_OK) {
  4077. ret = -EINVAL;
  4078. goto exit;
  4079. }
  4080. /* adjust iocsz to the end of last data record */
  4081. natoe_ioc->len = (buflen_at_start - buflen);
  4082. iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
  4083. ret = wldev_iovar_setbuf(dev, "natoe",
  4084. natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
  4085. if (ret != BCME_OK) {
  4086. WL_ERR(("Fail to set iovar %d\n", ret));
  4087. ret = -EINVAL;
  4088. }
  4089. }
  4090. exit:
  4091. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  4092. MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
  4093. return ret;
  4094. }
  4095. static int
  4096. wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
  4097. char *command, wl_natoe_cmd_info_t *cmd_info)
  4098. {
  4099. int ret = BCME_OK;
  4100. wl_natoe_ioc_t *natoe_ioc;
  4101. char *pcmd = command;
  4102. uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  4103. uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
  4104. uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
  4105. bcm_xtlv_t *pxtlv = NULL;
  4106. char *ioctl_buf = NULL;
  4107. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4108. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
  4109. if (!ioctl_buf) {
  4110. WL_ERR(("ioctl memory alloc failed\n"));
  4111. return -ENOMEM;
  4112. }
  4113. /* alloc mem for ioctl headr + tlv data */
  4114. natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
  4115. if (!natoe_ioc) {
  4116. WL_ERR(("ioctl header memory alloc failed\n"));
  4117. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
  4118. return -ENOMEM;
  4119. }
  4120. /* make up natoe cmd ioctl header */
  4121. natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
  4122. natoe_ioc->id = htod16(cmd->id);
  4123. natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
  4124. pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
  4125. if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
  4126. iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
  4127. ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
  4128. WLC_IOCTL_MAXLEN, cmd_info);
  4129. if (ret != BCME_OK) {
  4130. WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
  4131. ret = -EINVAL;
  4132. }
  4133. } else { /* set */
  4134. uint8 val = bcm_atoi(pcmd);
  4135. /* buflen is max tlv data we can write, it will be decremented as we pack */
  4136. /* save buflen at start */
  4137. uint16 buflen_at_start = buflen;
  4138. /* we'll adjust final ioc size at the end */
  4139. ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
  4140. sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
  4141. if (ret != BCME_OK) {
  4142. ret = -EINVAL;
  4143. goto exit;
  4144. }
  4145. /* adjust iocsz to the end of last data record */
  4146. natoe_ioc->len = (buflen_at_start - buflen);
  4147. iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
  4148. ret = wldev_iovar_setbuf(dev, "natoe",
  4149. natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
  4150. if (ret != BCME_OK) {
  4151. WL_ERR(("Fail to set iovar %d\n", ret));
  4152. ret = -EINVAL;
  4153. }
  4154. }
  4155. exit:
  4156. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
  4157. MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
  4158. return ret;
  4159. }
  4160. static int
  4161. wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
  4162. char *command, wl_natoe_cmd_info_t *cmd_info)
  4163. {
  4164. int ret = BCME_OK;
  4165. wl_natoe_ioc_t *natoe_ioc;
  4166. char *pcmd = command;
  4167. uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  4168. uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
  4169. uint16 buflen = WL_NATOE_IOC_BUFSZ;
  4170. bcm_xtlv_t *pxtlv = NULL;
  4171. char *ioctl_buf = NULL;
  4172. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4173. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  4174. if (!ioctl_buf) {
  4175. WL_ERR(("ioctl memory alloc failed\n"));
  4176. return -ENOMEM;
  4177. }
  4178. /* alloc mem for ioctl headr + tlv data */
  4179. natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
  4180. if (!natoe_ioc) {
  4181. WL_ERR(("ioctl header memory alloc failed\n"));
  4182. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  4183. return -ENOMEM;
  4184. }
  4185. /* make up natoe cmd ioctl header */
  4186. natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
  4187. natoe_ioc->id = htod16(cmd->id);
  4188. natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
  4189. pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
  4190. if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
  4191. iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
  4192. ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
  4193. WLC_IOCTL_MEDLEN, cmd_info);
  4194. if (ret != BCME_OK) {
  4195. WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
  4196. ret = -EINVAL;
  4197. }
  4198. } else { /* set */
  4199. uint32 val = bcm_atoi(pcmd);
  4200. /* buflen is max tlv data we can write, it will be decremented as we pack */
  4201. /* save buflen at start */
  4202. uint16 buflen_at_start = buflen;
  4203. /* we'll adjust final ioc size at the end */
  4204. ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
  4205. sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
  4206. if (ret != BCME_OK) {
  4207. ret = -EINVAL;
  4208. goto exit;
  4209. }
  4210. /* adjust iocsz to the end of last data record */
  4211. natoe_ioc->len = (buflen_at_start - buflen);
  4212. iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
  4213. ret = wldev_iovar_setbuf(dev, "natoe",
  4214. natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
  4215. if (ret != BCME_OK) {
  4216. WL_ERR(("Fail to set iovar %d\n", ret));
  4217. ret = -EINVAL;
  4218. }
  4219. }
  4220. exit:
  4221. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  4222. MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
  4223. return ret;
  4224. }
  4225. #endif /* WL_NATOE */
  4226. #ifdef WL_MBO
  4227. static int
  4228. wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
  4229. {
  4230. int ret = BCME_ERROR;
  4231. char *pcmd = command;
  4232. char *str = NULL;
  4233. wl_drv_cmd_info_t cmd_info;
  4234. const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
  4235. /* skip to cmd name after "mbo" */
  4236. str = bcmstrtok(&pcmd, " ", NULL);
  4237. /* If mbo subcmd name is not provided, return error */
  4238. if (*pcmd == '\0') {
  4239. WL_ERR(("mbo subcmd not provided %s\n", __FUNCTION__));
  4240. ret = -EINVAL;
  4241. return ret;
  4242. }
  4243. /* get the mbo command name to str */
  4244. str = bcmstrtok(&pcmd, " ", NULL);
  4245. while (mbo_cmd->name != NULL) {
  4246. if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
  4247. /* dispatch cmd to appropriate handler */
  4248. if (mbo_cmd->handler) {
  4249. cmd_info.command = command;
  4250. cmd_info.tot_len = total_len;
  4251. ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
  4252. }
  4253. return ret;
  4254. }
  4255. mbo_cmd++;
  4256. }
  4257. return ret;
  4258. }
  4259. static int
  4260. wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
  4261. uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
  4262. {
  4263. int ret = BCME_OK;
  4264. uint8 *pxtlv = NULL;
  4265. uint16 iovlen = 0;
  4266. uint16 buflen = 0, buflen_start = 0;
  4267. memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
  4268. iov_buf->version = WL_MBO_IOV_VERSION;
  4269. iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
  4270. buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
  4271. pxtlv = (uint8 *)&iov_buf->data[0];
  4272. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
  4273. sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
  4274. if (ret != BCME_OK) {
  4275. return ret;
  4276. }
  4277. iov_buf->len = buflen_start - buflen;
  4278. iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
  4279. ret = wldev_iovar_setbuf(dev, "mbo",
  4280. iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
  4281. if (ret != BCME_OK) {
  4282. WL_ERR(("Fail to sent wnm notif %d\n", ret));
  4283. }
  4284. return ret;
  4285. }
  4286. static int
  4287. wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
  4288. {
  4289. wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
  4290. uint8 *command = cmd_info->command;
  4291. uint16 total_len = cmd_info->tot_len;
  4292. uint16 bytes_written = 0;
  4293. UNUSED_PARAMETER(len);
  4294. /* TODO: validate data value */
  4295. if (data == NULL) {
  4296. WL_ERR(("%s: Bad argument !!\n", __FUNCTION__));
  4297. return -EINVAL;
  4298. }
  4299. switch (type) {
  4300. case WL_MBO_XTLV_CELL_DATA_CAP:
  4301. {
  4302. bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
  4303. cmd_info->bytes_written = bytes_written;
  4304. }
  4305. break;
  4306. default:
  4307. WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
  4308. }
  4309. return BCME_OK;
  4310. }
  4311. static int
  4312. wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
  4313. char *command, wl_drv_cmd_info_t *cmd_info)
  4314. {
  4315. int ret = BCME_OK;
  4316. uint8 *pxtlv = NULL;
  4317. uint16 buflen = 0, buflen_start = 0;
  4318. uint16 iovlen = 0;
  4319. char *pcmd = command;
  4320. bcm_iov_buf_t *iov_buf = NULL;
  4321. bcm_iov_buf_t *p_resp = NULL;
  4322. uint8 *iov_resp = NULL;
  4323. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4324. uint16 version;
  4325. /* first get the configured value */
  4326. iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  4327. if (iov_buf == NULL) {
  4328. ret = -ENOMEM;
  4329. WL_ERR(("iov buf memory alloc exited\n"));
  4330. goto exit;
  4331. }
  4332. iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
  4333. if (iov_resp == NULL) {
  4334. ret = -ENOMEM;
  4335. WL_ERR(("iov resp memory alloc exited\n"));
  4336. goto exit;
  4337. }
  4338. /* fill header */
  4339. iov_buf->version = WL_MBO_IOV_VERSION;
  4340. iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
  4341. ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
  4342. WLC_IOCTL_MAXLEN,
  4343. NULL);
  4344. if (ret != BCME_OK) {
  4345. goto exit;
  4346. }
  4347. p_resp = (bcm_iov_buf_t *)iov_resp;
  4348. /* get */
  4349. if (*pcmd == WL_IOCTL_ACTION_GET) {
  4350. /* Check for version */
  4351. version = dtoh16(*(uint16 *)iov_resp);
  4352. if (version != WL_MBO_IOV_VERSION) {
  4353. ret = -EINVAL;
  4354. }
  4355. if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
  4356. ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
  4357. p_resp->len, BCM_XTLV_OPTION_ALIGN32,
  4358. wl_android_mbo_resp_parse_cbfn);
  4359. if (ret == BCME_OK) {
  4360. ret = cmd_info->bytes_written;
  4361. }
  4362. } else {
  4363. ret = -EINVAL;
  4364. WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
  4365. goto exit;
  4366. }
  4367. } else {
  4368. uint8 cell_cap = bcm_atoi(pcmd);
  4369. const uint8* old_cell_cap = NULL;
  4370. uint16 len = 0;
  4371. old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
  4372. WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
  4373. if (old_cell_cap && *old_cell_cap == cell_cap) {
  4374. WL_ERR(("No change is cellular data capability\n"));
  4375. /* No change in value */
  4376. goto exit;
  4377. }
  4378. buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
  4379. if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
  4380. cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
  4381. WL_ERR(("wrong value %u\n", cell_cap));
  4382. ret = -EINVAL;
  4383. goto exit;
  4384. }
  4385. pxtlv = (uint8 *)&iov_buf->data[0];
  4386. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
  4387. sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
  4388. if (ret != BCME_OK) {
  4389. goto exit;
  4390. }
  4391. iov_buf->len = buflen_start - buflen;
  4392. iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
  4393. ret = wldev_iovar_setbuf(dev, "mbo",
  4394. iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
  4395. if (ret != BCME_OK) {
  4396. WL_ERR(("Fail to set iovar %d\n", ret));
  4397. ret = -EINVAL;
  4398. goto exit;
  4399. }
  4400. /* Skip for CUSTOMER_HW4 - WNM notification
  4401. * for cellular data capability is handled by host
  4402. */
  4403. /* send a WNM notification request to associated AP */
  4404. if (wl_get_drv_status(cfg, CONNECTED, dev)) {
  4405. WL_INFORM(("Sending WNM Notif\n"));
  4406. ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
  4407. iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
  4408. if (ret != BCME_OK) {
  4409. WL_ERR(("Fail to send WNM notification %d\n", ret));
  4410. ret = -EINVAL;
  4411. }
  4412. }
  4413. }
  4414. exit:
  4415. if (iov_buf) {
  4416. MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
  4417. }
  4418. if (iov_resp) {
  4419. MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
  4420. }
  4421. return ret;
  4422. }
  4423. static int
  4424. wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
  4425. {
  4426. wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
  4427. uint8 *command = cmd_info->command + cmd_info->bytes_written;
  4428. uint16 total_len = cmd_info->tot_len;
  4429. uint16 bytes_written = 0;
  4430. WL_DBG(("Total bytes written at begining %u\n", cmd_info->bytes_written));
  4431. UNUSED_PARAMETER(len);
  4432. if (data == NULL) {
  4433. WL_ERR(("%s: Bad argument !!\n", __FUNCTION__));
  4434. return -EINVAL;
  4435. }
  4436. switch (type) {
  4437. case WL_MBO_XTLV_OPCLASS:
  4438. {
  4439. bytes_written = snprintf(command, total_len, "%u:", *data);
  4440. WL_ERR(("wr %u %u\n", bytes_written, *data));
  4441. command += bytes_written;
  4442. cmd_info->bytes_written += bytes_written;
  4443. }
  4444. break;
  4445. case WL_MBO_XTLV_CHAN:
  4446. {
  4447. bytes_written = snprintf(command, total_len, "%u:", *data);
  4448. WL_ERR(("wr %u\n", bytes_written));
  4449. command += bytes_written;
  4450. cmd_info->bytes_written += bytes_written;
  4451. }
  4452. break;
  4453. case WL_MBO_XTLV_PREFERENCE:
  4454. {
  4455. bytes_written = snprintf(command, total_len, "%u:", *data);
  4456. WL_ERR(("wr %u\n", bytes_written));
  4457. command += bytes_written;
  4458. cmd_info->bytes_written += bytes_written;
  4459. }
  4460. break;
  4461. case WL_MBO_XTLV_REASON_CODE:
  4462. {
  4463. bytes_written = snprintf(command, total_len, "%u ", *data);
  4464. WL_ERR(("wr %u\n", bytes_written));
  4465. command += bytes_written;
  4466. cmd_info->bytes_written += bytes_written;
  4467. }
  4468. break;
  4469. default:
  4470. WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
  4471. }
  4472. WL_DBG(("Total bytes written %u\n", cmd_info->bytes_written));
  4473. return BCME_OK;
  4474. }
  4475. static int
  4476. wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
  4477. const wl_drv_sub_cmd_t *cmd, char *command,
  4478. wl_drv_cmd_info_t *cmd_info)
  4479. {
  4480. int ret = BCME_OK;
  4481. uint8 *pxtlv = NULL;
  4482. uint16 buflen = 0, buflen_start = 0;
  4483. uint16 iovlen = 0;
  4484. char *pcmd = command;
  4485. bcm_iov_buf_t *iov_buf = NULL;
  4486. bcm_iov_buf_t *p_resp = NULL;
  4487. uint8 *iov_resp = NULL;
  4488. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4489. uint16 version;
  4490. WL_ERR(("%s:%d\n", __FUNCTION__, __LINE__));
  4491. iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  4492. if (iov_buf == NULL) {
  4493. ret = -ENOMEM;
  4494. WL_ERR(("iov buf memory alloc exited\n"));
  4495. goto exit;
  4496. }
  4497. iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
  4498. if (iov_resp == NULL) {
  4499. ret = -ENOMEM;
  4500. WL_ERR(("iov resp memory alloc exited\n"));
  4501. goto exit;
  4502. }
  4503. /* get */
  4504. if (*pcmd == WL_IOCTL_ACTION_GET) {
  4505. /* fill header */
  4506. iov_buf->version = WL_MBO_IOV_VERSION;
  4507. iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
  4508. ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
  4509. WLC_IOCTL_MAXLEN, NULL);
  4510. if (ret != BCME_OK) {
  4511. goto exit;
  4512. }
  4513. p_resp = (bcm_iov_buf_t *)iov_resp;
  4514. /* Check for version */
  4515. version = dtoh16(*(uint16 *)iov_resp);
  4516. if (version != WL_MBO_IOV_VERSION) {
  4517. WL_ERR(("Version mismatch. returned ver %u expected %u\n",
  4518. version, WL_MBO_IOV_VERSION));
  4519. ret = -EINVAL;
  4520. }
  4521. if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
  4522. ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
  4523. p_resp->len, BCM_XTLV_OPTION_ALIGN32,
  4524. wl_android_mbo_non_pref_chan_parse_cbfn);
  4525. if (ret == BCME_OK) {
  4526. ret = cmd_info->bytes_written;
  4527. }
  4528. } else {
  4529. ret = -EINVAL;
  4530. WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
  4531. goto exit;
  4532. }
  4533. } else {
  4534. char *str = pcmd;
  4535. uint opcl = 0, ch = 0, pref = 0, rc = 0;
  4536. str = bcmstrtok(&pcmd, " ", NULL);
  4537. if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
  4538. /* delete all configurations */
  4539. iov_buf->version = WL_MBO_IOV_VERSION;
  4540. iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
  4541. iov_buf->len = 0;
  4542. iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
  4543. ret = wldev_iovar_setbuf(dev, "mbo",
  4544. iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
  4545. if (ret != BCME_OK) {
  4546. WL_ERR(("Fail to set iovar %d\n", ret));
  4547. ret = -EINVAL;
  4548. goto exit;
  4549. }
  4550. } else {
  4551. WL_ERR(("Unknown command %s\n", str));
  4552. goto exit;
  4553. }
  4554. /* parse non pref channel list */
  4555. if (strnicmp(str, "set", 3) == 0) {
  4556. uint8 cnt = 0;
  4557. str = bcmstrtok(&pcmd, " ", NULL);
  4558. while (str != NULL) {
  4559. ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
  4560. WL_ERR(("buflen %u op %u, ch %u, pref %u rc %u\n",
  4561. buflen, opcl, ch, pref, rc));
  4562. if (ret != 4) {
  4563. WL_ERR(("Not all parameter presents\n"));
  4564. ret = -EINVAL;
  4565. }
  4566. /* TODO: add a validation check here */
  4567. memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
  4568. buflen = buflen_start = WLC_IOCTL_MEDLEN;
  4569. pxtlv = (uint8 *)&iov_buf->data[0];
  4570. /* opclass */
  4571. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
  4572. sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
  4573. if (ret != BCME_OK) {
  4574. goto exit;
  4575. }
  4576. /* channel */
  4577. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
  4578. sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
  4579. if (ret != BCME_OK) {
  4580. goto exit;
  4581. }
  4582. /* preference */
  4583. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
  4584. sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
  4585. if (ret != BCME_OK) {
  4586. goto exit;
  4587. }
  4588. /* reason */
  4589. ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
  4590. sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
  4591. if (ret != BCME_OK) {
  4592. goto exit;
  4593. }
  4594. WL_ERR(("len %u\n", (buflen_start - buflen)));
  4595. /* Now set the new non pref channels */
  4596. iov_buf->version = WL_MBO_IOV_VERSION;
  4597. iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
  4598. iov_buf->len = buflen_start - buflen;
  4599. iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
  4600. ret = wldev_iovar_setbuf(dev, "mbo",
  4601. iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
  4602. if (ret != BCME_OK) {
  4603. WL_ERR(("Fail to set iovar %d\n", ret));
  4604. ret = -EINVAL;
  4605. goto exit;
  4606. }
  4607. cnt++;
  4608. if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
  4609. break;
  4610. }
  4611. WL_ERR(("%d cnt %u\n", __LINE__, cnt));
  4612. str = bcmstrtok(&pcmd, " ", NULL);
  4613. }
  4614. }
  4615. /* send a WNM notification request to associated AP */
  4616. if (wl_get_drv_status(cfg, CONNECTED, dev)) {
  4617. WL_INFORM(("Sending WNM Notif\n"));
  4618. ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
  4619. iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
  4620. if (ret != BCME_OK) {
  4621. WL_ERR(("Fail to send WNM notification %d\n", ret));
  4622. ret = -EINVAL;
  4623. }
  4624. }
  4625. }
  4626. exit:
  4627. if (iov_buf) {
  4628. MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
  4629. }
  4630. if (iov_resp) {
  4631. MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
  4632. }
  4633. return ret;
  4634. }
  4635. #endif /* WL_MBO */
  4636. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  4637. #ifdef SUPPORT_AMPDU_MPDU_CMD
  4638. /* CMD_AMPDU_MPDU */
  4639. static int
  4640. wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
  4641. {
  4642. int err = 0;
  4643. int ampdu_mpdu;
  4644. ampdu_mpdu = bcm_atoi(string_num);
  4645. if (ampdu_mpdu > 32) {
  4646. DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
  4647. return -1;
  4648. }
  4649. DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
  4650. err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
  4651. if (err < 0) {
  4652. DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
  4653. return -1;
  4654. }
  4655. return 0;
  4656. }
  4657. #endif /* SUPPORT_AMPDU_MPDU_CMD */
  4658. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  4659. #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
  4660. extern int wl_cfg80211_send_msg_to_ril(void);
  4661. extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
  4662. extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
  4663. extern int g_mhs_chan_for_cpcoex;
  4664. #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
  4665. #if defined(WL_SUPPORT_AUTO_CHANNEL)
  4666. /* SoftAP feature */
  4667. #define APCS_BAND_2G_LEGACY1 20
  4668. #define APCS_BAND_2G_LEGACY2 0
  4669. #define APCS_BAND_AUTO "band=auto"
  4670. #define APCS_BAND_2G "band=2g"
  4671. #define APCS_BAND_5G "band=5g"
  4672. #define APCS_MAX_2G_CHANNELS 11
  4673. #define APCS_MAX_RETRY 10
  4674. #define APCS_DEFAULT_2G_CH 1
  4675. #define APCS_DEFAULT_5G_CH 149
  4676. static int
  4677. wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
  4678. char* command, int total_len)
  4679. {
  4680. int channel = 0;
  4681. int chosen = 0;
  4682. int retry = 0;
  4683. int ret = 0;
  4684. int spect = 0;
  4685. u8 *reqbuf = NULL;
  4686. uint32 band = WLC_BAND_2G;
  4687. uint32 buf_size;
  4688. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  4689. if (cmd_str) {
  4690. WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
  4691. if (strncmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
  4692. band = WLC_BAND_AUTO;
  4693. } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
  4694. band = WLC_BAND_5G;
  4695. } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
  4696. band = WLC_BAND_2G;
  4697. } else {
  4698. /*
  4699. * For backward compatibility: Some platforms used to issue argument 20 or 0
  4700. * to enforce the 2G channel selection
  4701. */
  4702. channel = bcm_atoi(cmd_str);
  4703. if ((channel == APCS_BAND_2G_LEGACY1) ||
  4704. (channel == APCS_BAND_2G_LEGACY2)) {
  4705. band = WLC_BAND_2G;
  4706. } else {
  4707. WL_ERR(("Invalid argument\n"));
  4708. return -EINVAL;
  4709. }
  4710. }
  4711. } else {
  4712. /* If no argument is provided, default to 2G */
  4713. WL_ERR(("No argument given default to 2.4G scan\n"));
  4714. band = WLC_BAND_2G;
  4715. }
  4716. WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
  4717. #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
  4718. wl_cfg80211_register_dev_ril_bridge_event_notifier();
  4719. if (band == WLC_BAND_2G) {
  4720. wl_cfg80211_send_msg_to_ril();
  4721. if (g_mhs_chan_for_cpcoex) {
  4722. channel = g_mhs_chan_for_cpcoex;
  4723. g_mhs_chan_for_cpcoex = 0;
  4724. goto done2;
  4725. }
  4726. }
  4727. wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
  4728. #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
  4729. /* If STA is connected, return is STA channel, else ACS can be issued,
  4730. * set spect to 0 and proceed with ACS
  4731. */
  4732. channel = wl_cfg80211_get_sta_channel(cfg);
  4733. if (channel) {
  4734. channel = (channel <= CH_MAX_2G_CHANNEL) ?
  4735. channel : APCS_DEFAULT_2G_CH;
  4736. goto done2;
  4737. }
  4738. ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
  4739. if (ret) {
  4740. WL_ERR(("ACS: error getting the spect, ret=%d\n", ret));
  4741. goto done;
  4742. }
  4743. if (spect > 0) {
  4744. ret = wl_cfg80211_set_spect(dev, 0);
  4745. if (ret < 0) {
  4746. WL_ERR(("ACS: error while setting spect, ret=%d\n", ret));
  4747. goto done;
  4748. }
  4749. }
  4750. reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
  4751. if (reqbuf == NULL) {
  4752. WL_ERR(("failed to allocate chanspec buffer\n"));
  4753. return -ENOMEM;
  4754. }
  4755. if (band == WLC_BAND_AUTO) {
  4756. WL_DBG(("ACS full channel scan \n"));
  4757. reqbuf[0] = htod32(0);
  4758. } else if (band == WLC_BAND_5G) {
  4759. WL_DBG(("ACS 5G band scan \n"));
  4760. if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
  4761. WL_ERR(("ACS 5g chanspec retreival failed! \n"));
  4762. goto done;
  4763. }
  4764. } else if (band == WLC_BAND_2G) {
  4765. /*
  4766. * If channel argument is not provided/ argument 20 is provided,
  4767. * Restrict channel to 2GHz, 20MHz BW, No SB
  4768. */
  4769. WL_DBG(("ACS 2G band scan \n"));
  4770. if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
  4771. WL_ERR(("ACS 2g chanspec retreival failed! \n"));
  4772. goto done;
  4773. }
  4774. } else {
  4775. WL_ERR(("ACS: No band chosen\n"));
  4776. goto done2;
  4777. }
  4778. buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
  4779. ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
  4780. buf_size);
  4781. if (ret < 0) {
  4782. WL_ERR(("can't start auto channel scan, err = %d\n", ret));
  4783. channel = 0;
  4784. goto done;
  4785. }
  4786. /* Wait for auto channel selection, max 3000 ms */
  4787. if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
  4788. OSL_SLEEP(500);
  4789. } else {
  4790. /*
  4791. * Full channel scan at the minimum takes 1.2secs
  4792. * even with parallel scan. max wait time: 3500ms
  4793. */
  4794. OSL_SLEEP(1000);
  4795. }
  4796. retry = APCS_MAX_RETRY;
  4797. while (retry--) {
  4798. ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
  4799. sizeof(chosen));
  4800. if (ret < 0) {
  4801. chosen = 0;
  4802. } else {
  4803. chosen = dtoh32(chosen);
  4804. }
  4805. if (chosen) {
  4806. int chosen_band;
  4807. int apcs_band;
  4808. #ifdef D11AC_IOTYPES
  4809. if (wl_cfg80211_get_ioctl_version() == 1) {
  4810. channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
  4811. } else {
  4812. channel = CHSPEC_CHANNEL((chanspec_t)chosen);
  4813. }
  4814. #else
  4815. channel = CHSPEC_CHANNEL((chanspec_t)chosen);
  4816. #endif /* D11AC_IOTYPES */
  4817. apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
  4818. chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
  4819. if (apcs_band == chosen_band) {
  4820. WL_ERR(("selected channel = %d\n", channel));
  4821. break;
  4822. }
  4823. }
  4824. WL_DBG(("%d tried, ret = %d, chosen = 0x%x\n",
  4825. (APCS_MAX_RETRY - retry), ret, chosen));
  4826. OSL_SLEEP(250);
  4827. }
  4828. done:
  4829. if ((retry == 0) || (ret < 0)) {
  4830. /* On failure, fallback to a default channel */
  4831. if (band == WLC_BAND_5G) {
  4832. channel = APCS_DEFAULT_5G_CH;
  4833. } else {
  4834. channel = APCS_DEFAULT_2G_CH;
  4835. }
  4836. WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel));
  4837. }
  4838. done2:
  4839. if (spect > 0) {
  4840. if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
  4841. WL_ERR(("ACS: error while setting spect\n"));
  4842. }
  4843. }
  4844. if (reqbuf) {
  4845. MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
  4846. }
  4847. if (channel) {
  4848. ret = snprintf(command, total_len, "%d", channel);
  4849. WL_INFORM(("command result is %s \n", command));
  4850. }
  4851. return ret;
  4852. }
  4853. #endif /* WL_SUPPORT_AUTO_CHANNEL */
  4854. #ifdef SUPPORT_HIDDEN_AP
  4855. static int
  4856. wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
  4857. {
  4858. int err = BCME_ERROR;
  4859. int max_assoc;
  4860. max_assoc = bcm_atoi(string_num);
  4861. DHD_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
  4862. err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
  4863. if (err < 0) {
  4864. WL_ERR(("failed to set maxassoc, error:%d\n", err));
  4865. }
  4866. return err;
  4867. }
  4868. static int
  4869. wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
  4870. {
  4871. wlc_ssid_t ssid;
  4872. s32 ret;
  4873. ssid.SSID_len = strlen(hapd_ssid);
  4874. if (ssid.SSID_len == 0) {
  4875. WL_ERR(("wl_android_set_ssids : No SSID\n"));
  4876. return -1;
  4877. }
  4878. if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
  4879. ssid.SSID_len = DOT11_MAX_SSID_LEN;
  4880. WL_ERR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
  4881. }
  4882. bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
  4883. DHD_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
  4884. ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
  4885. if (ret < 0) {
  4886. WL_ERR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
  4887. }
  4888. return 1;
  4889. }
  4890. static int
  4891. wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
  4892. {
  4893. int hide_ssid;
  4894. int enable = 0;
  4895. int err = BCME_ERROR;
  4896. hide_ssid = bcm_atoi(string_num);
  4897. DHD_INFO(("wl_android_set_hide_ssid: HIDE_SSID = %d\n", hide_ssid));
  4898. if (hide_ssid) {
  4899. enable = 1;
  4900. }
  4901. err = wldev_iovar_setint(dev, "closednet", enable);
  4902. if (err < 0) {
  4903. WL_ERR(("failed to set closednet, error:%d\n", err));
  4904. }
  4905. return err;
  4906. }
  4907. #endif /* SUPPORT_HIDDEN_AP */
  4908. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  4909. #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
  4910. static int
  4911. wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
  4912. {
  4913. scb_val_t scbval;
  4914. int error = 0;
  4915. DHD_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
  4916. /* Unspecified reason */
  4917. scbval.val = htod32(1);
  4918. if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
  4919. DHD_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
  4920. return -1;
  4921. }
  4922. DHD_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
  4923. MAC2STRDBG(scbval.ea.octet), scbval.val));
  4924. error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
  4925. sizeof(scb_val_t));
  4926. if (error) {
  4927. DHD_ERROR(("Fail to DEAUTH station, error = %d\n", error));
  4928. }
  4929. return 1;
  4930. }
  4931. #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
  4932. #ifdef SUPPORT_SET_LPC
  4933. static int
  4934. wl_android_set_lpc(struct net_device *dev, const char* string_num)
  4935. {
  4936. int lpc_enabled, ret;
  4937. s32 val = 1;
  4938. lpc_enabled = bcm_atoi(string_num);
  4939. DHD_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
  4940. ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
  4941. if (ret < 0)
  4942. DHD_ERROR(("WLC_DOWN error %d\n", ret));
  4943. wldev_iovar_setint(dev, "lpc", lpc_enabled);
  4944. ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
  4945. if (ret < 0)
  4946. DHD_ERROR(("WLC_UP error %d\n", ret));
  4947. return 1;
  4948. }
  4949. #endif /* SUPPORT_SET_LPC */
  4950. static int
  4951. wl_android_ch_res_rl(struct net_device *dev, bool change)
  4952. {
  4953. int error = 0;
  4954. s32 srl = 7;
  4955. s32 lrl = 4;
  4956. printk("wl_android_ch_res_rl: enter\n");
  4957. if (change) {
  4958. srl = 4;
  4959. lrl = 2;
  4960. }
  4961. BCM_REFERENCE(lrl);
  4962. error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
  4963. if (error) {
  4964. DHD_ERROR(("Failed to set SRL, error = %d\n", error));
  4965. }
  4966. #ifndef CUSTOM_LONG_RETRY_LIMIT
  4967. error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
  4968. if (error) {
  4969. DHD_ERROR(("Failed to set LRL, error = %d\n", error));
  4970. }
  4971. #endif /* CUSTOM_LONG_RETRY_LIMIT */
  4972. return error;
  4973. }
  4974. #ifdef SUPPORT_LTECX
  4975. #define DEFAULT_WLANRX_PROT 1
  4976. #define DEFAULT_LTERX_PROT 0
  4977. #define DEFAULT_LTETX_ADV 1200
  4978. static int
  4979. wl_android_set_ltecx(struct net_device *dev, const char* string_num)
  4980. {
  4981. uint16 chan_bitmap;
  4982. int ret;
  4983. chan_bitmap = bcm_strtoul(string_num, NULL, 16);
  4984. DHD_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
  4985. if (chan_bitmap) {
  4986. ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
  4987. if (ret < 0) {
  4988. DHD_ERROR(("mws_coex_bitmap error %d\n", ret));
  4989. }
  4990. ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
  4991. if (ret < 0) {
  4992. DHD_ERROR(("mws_wlanrx_prot error %d\n", ret));
  4993. }
  4994. ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
  4995. if (ret < 0) {
  4996. DHD_ERROR(("mws_lterx_prot error %d\n", ret));
  4997. }
  4998. ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
  4999. if (ret < 0) {
  5000. DHD_ERROR(("mws_ltetx_adv error %d\n", ret));
  5001. }
  5002. } else {
  5003. ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
  5004. if (ret < 0) {
  5005. if (ret == BCME_UNSUPPORTED) {
  5006. DHD_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
  5007. } else {
  5008. DHD_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
  5009. }
  5010. }
  5011. }
  5012. return 1;
  5013. }
  5014. #endif /* SUPPORT_LTECX */
  5015. #ifdef WL_RELMCAST
  5016. static int
  5017. wl_android_rmc_enable(struct net_device *net, int rmc_enable)
  5018. {
  5019. int err;
  5020. err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
  5021. if (err != BCME_OK) {
  5022. DHD_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
  5023. }
  5024. return err;
  5025. }
  5026. static int
  5027. wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
  5028. {
  5029. int error = BCME_OK;
  5030. char smbuf[WLC_IOCTL_SMLEN];
  5031. wl_rmc_entry_t rmc_entry;
  5032. DHD_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
  5033. bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
  5034. if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
  5035. if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
  5036. DHD_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
  5037. bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
  5038. } else {
  5039. DHD_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
  5040. return BCME_ERROR;
  5041. }
  5042. }
  5043. error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
  5044. smbuf, sizeof(smbuf), NULL);
  5045. if (error != BCME_OK) {
  5046. DHD_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
  5047. error));
  5048. }
  5049. return error;
  5050. }
  5051. static int wl_android_set_rmc_event(struct net_device *dev, char *command)
  5052. {
  5053. int err = 0;
  5054. int pid = 0;
  5055. if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
  5056. WL_ERR(("Failed to get Parameter from : %s\n", command));
  5057. return -1;
  5058. }
  5059. /* set pid, and if the event was happened, let's send a notification through netlink */
  5060. wl_cfg80211_set_rmc_pid(dev, pid);
  5061. WL_DBG(("RMC pid=%d\n", pid));
  5062. return err;
  5063. }
  5064. #endif /* WL_RELMCAST */
  5065. int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
  5066. {
  5067. int error = 0;
  5068. int bytes_written = 0;
  5069. int mode = 0;
  5070. error = wldev_iovar_getint(dev, "scan_ps", &mode);
  5071. if (error) {
  5072. DHD_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
  5073. " error = %d\n",
  5074. error));
  5075. return -1;
  5076. }
  5077. bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
  5078. return bytes_written;
  5079. }
  5080. int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
  5081. {
  5082. int error = 0;
  5083. int mode = 0;
  5084. if (sscanf(command, "%*s %d", &mode) != 1) {
  5085. DHD_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
  5086. return -1;
  5087. }
  5088. error = wldev_iovar_setint(dev, "scan_ps", mode);
  5089. if (error) {
  5090. DHD_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
  5091. mode, error));
  5092. return -1;
  5093. }
  5094. return error;
  5095. }
  5096. #ifdef TEST_TX_POWER_CONTROL
  5097. static int
  5098. wl_android_set_tx_power(struct net_device *dev, const char* string_num)
  5099. {
  5100. int err = 0;
  5101. s32 dbm;
  5102. enum nl80211_tx_power_setting type;
  5103. dbm = bcm_atoi(string_num);
  5104. if (dbm < -1) {
  5105. DHD_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
  5106. return -EINVAL;
  5107. }
  5108. if (dbm == -1)
  5109. type = NL80211_TX_POWER_AUTOMATIC;
  5110. else
  5111. type = NL80211_TX_POWER_FIXED;
  5112. err = wl_set_tx_power(dev, type, dbm);
  5113. if (unlikely(err)) {
  5114. DHD_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
  5115. return err;
  5116. }
  5117. return 1;
  5118. }
  5119. static int
  5120. wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
  5121. {
  5122. int err;
  5123. int bytes_written;
  5124. s32 dbm = 0;
  5125. err = wl_get_tx_power(dev, &dbm);
  5126. if (unlikely(err)) {
  5127. DHD_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
  5128. return err;
  5129. }
  5130. bytes_written = snprintf(command, total_len, "%s %d",
  5131. CMD_TEST_GET_TX_POWER, dbm);
  5132. DHD_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
  5133. return bytes_written;
  5134. }
  5135. #endif /* TEST_TX_POWER_CONTROL */
  5136. static int
  5137. wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
  5138. {
  5139. int err = BCME_ERROR;
  5140. int setval = 0;
  5141. s32 mode = bcm_atoi(string_num);
  5142. s32 mode_bit = 0;
  5143. int enab = 0;
  5144. /* As Samsung specific and their requirement,
  5145. * the mode set as the following form.
  5146. * -1 : HEAD SAR disabled
  5147. * 0 : HEAD SAR enabled
  5148. * 1 : GRIP SAR disabled
  5149. * 2 : GRIP SAR enabled
  5150. * 3 : NR mmWave SAR disabled
  5151. * 4 : NR mmWave SAR enabled
  5152. * 5 : NR Sub6 SAR disabled
  5153. * 6 : NR Sub6 SAR enabled
  5154. * 7 : SAR BACKOFF disabled all
  5155. * The 'SAR BACKOFF disabled all' index should be the end of the mode.
  5156. */
  5157. if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
  5158. DHD_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
  5159. err = BCME_RANGE;
  5160. goto error;
  5161. }
  5162. mode_bit = mode + 1;
  5163. enab = mode_bit % 2;
  5164. mode_bit = mode_bit / 2;
  5165. err = wldev_iovar_getint(dev, "sar_enable", &setval);
  5166. if (unlikely(err)) {
  5167. DHD_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
  5168. goto error;
  5169. }
  5170. if (mode == SAR_BACKOFF_DISABLE_ALL) {
  5171. DHD_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
  5172. setval = 0;
  5173. } else {
  5174. DHD_ERROR(("%s: SAR limit control mode %d enab %d\n",
  5175. __FUNCTION__, mode_bit, enab));
  5176. if (enab) {
  5177. setval |= (1 << mode_bit);
  5178. } else {
  5179. setval &= ~(1 << mode_bit);
  5180. }
  5181. }
  5182. err = wldev_iovar_setint(dev, "sar_enable", setval);
  5183. if (unlikely(err)) {
  5184. DHD_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
  5185. goto error;
  5186. }
  5187. error:
  5188. return err;
  5189. }
  5190. #ifdef SUPPORT_SET_TID
  5191. static int
  5192. wl_android_set_tid(struct net_device *dev, char* command)
  5193. {
  5194. int err = BCME_ERROR;
  5195. char *pos = command;
  5196. char *token = NULL;
  5197. uint8 mode = 0;
  5198. uint32 uid = 0;
  5199. uint8 prio = 0;
  5200. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  5201. if (!dhdp) {
  5202. WL_ERR(("dhd is NULL\n"));
  5203. return err;
  5204. }
  5205. WL_DBG(("%s: command[%s]\n", __FUNCTION__, command));
  5206. /* drop command */
  5207. token = bcmstrtok(&pos, " ", NULL);
  5208. token = bcmstrtok(&pos, " ", NULL);
  5209. if (!token) {
  5210. WL_ERR(("Invalid arguments\n"));
  5211. return err;
  5212. }
  5213. mode = bcm_atoi(token);
  5214. if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
  5215. WL_ERR(("Invalid arguments, mode %d\n", mode));
  5216. return err;
  5217. }
  5218. if (mode) {
  5219. token = bcmstrtok(&pos, " ", NULL);
  5220. if (!token) {
  5221. WL_ERR(("Invalid arguments for target uid\n"));
  5222. return err;
  5223. }
  5224. uid = bcm_atoi(token);
  5225. token = bcmstrtok(&pos, " ", NULL);
  5226. if (!token) {
  5227. WL_ERR(("Invalid arguments for target tid\n"));
  5228. return err;
  5229. }
  5230. prio = bcm_atoi(token);
  5231. if (prio >= 0 && prio <= MAXPRIO) {
  5232. dhdp->tid_mode = mode;
  5233. dhdp->target_uid = uid;
  5234. dhdp->target_tid = prio;
  5235. } else {
  5236. WL_ERR(("Invalid arguments, prio %d\n", prio));
  5237. return err;
  5238. }
  5239. } else {
  5240. dhdp->tid_mode = SET_TID_OFF;
  5241. dhdp->target_uid = 0;
  5242. dhdp->target_tid = 0;
  5243. }
  5244. WL_DBG(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
  5245. dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
  5246. err = BCME_OK;
  5247. return err;
  5248. }
  5249. static int
  5250. wl_android_get_tid(struct net_device *dev, char* command, int total_len)
  5251. {
  5252. int bytes_written = BCME_ERROR;
  5253. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  5254. if (!dhdp) {
  5255. WL_ERR(("dhd is NULL\n"));
  5256. return bytes_written;
  5257. }
  5258. bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
  5259. dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
  5260. WL_DBG(("%s: command results %s\n", __FUNCTION__, command));
  5261. return bytes_written;
  5262. }
  5263. #endif /* SUPPORT_SET_TID */
  5264. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  5265. int wl_android_set_roam_mode(struct net_device *dev, char *command)
  5266. {
  5267. int error = 0;
  5268. int mode = 0;
  5269. if (sscanf(command, "%*s %d", &mode) != 1) {
  5270. DHD_ERROR(("wl_android_set_roam_mode: Failed to get Parameter\n"));
  5271. return -1;
  5272. }
  5273. error = wldev_iovar_setint(dev, "roam_off", mode);
  5274. if (error) {
  5275. DHD_ERROR(("wl_android_set_roam_mode: Failed to set roaming Mode %d, error = %d\n",
  5276. mode, error));
  5277. return -1;
  5278. }
  5279. else
  5280. DHD_ERROR(("wl_android_set_roam_mode: succeeded to set roaming Mode %d,"
  5281. " error = %d\n",
  5282. mode, error));
  5283. return 0;
  5284. }
  5285. int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
  5286. {
  5287. char ie_buf[VNDR_IE_MAX_LEN];
  5288. char *ioctl_buf = NULL;
  5289. char hex[] = "XX";
  5290. char *pcmd = NULL;
  5291. int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
  5292. vndr_ie_setbuf_t *vndr_ie = NULL;
  5293. s32 iecount;
  5294. uint32 pktflag;
  5295. s32 err = BCME_OK, bssidx;
  5296. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  5297. /* Check the VSIE (Vendor Specific IE) which was added.
  5298. * If exist then send IOVAR to delete it
  5299. */
  5300. if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
  5301. return -EINVAL;
  5302. }
  5303. if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
  5304. WL_ERR(("error. total_len:%d\n", total_len));
  5305. return -EINVAL;
  5306. }
  5307. pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
  5308. for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
  5309. if (*pcmd == '\0') {
  5310. WL_ERR(("error while parsing OUI.\n"));
  5311. return -EINVAL;
  5312. }
  5313. hex[0] = *pcmd++;
  5314. hex[1] = *pcmd++;
  5315. ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
  5316. }
  5317. pcmd++;
  5318. while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
  5319. hex[0] = *pcmd++;
  5320. hex[1] = *pcmd++;
  5321. ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
  5322. datalen++;
  5323. }
  5324. if (datalen <= 0) {
  5325. WL_ERR(("error. vndr ie len:%d\n", datalen));
  5326. return -EINVAL;
  5327. }
  5328. tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
  5329. vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
  5330. if (!vndr_ie) {
  5331. WL_ERR(("IE memory alloc failed\n"));
  5332. return -ENOMEM;
  5333. }
  5334. /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
  5335. strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
  5336. /* Set the IE count - the buffer contains only 1 IE */
  5337. iecount = htod32(1);
  5338. memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
  5339. /* Set packet flag to indicate that BEACON's will contain this IE */
  5340. pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
  5341. memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
  5342. sizeof(u32));
  5343. /* Set the IE ID */
  5344. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
  5345. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
  5346. DOT11_OUI_LEN);
  5347. memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
  5348. &ie_buf[DOT11_OUI_LEN], datalen);
  5349. ielen = DOT11_OUI_LEN + datalen;
  5350. vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
  5351. ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
  5352. if (!ioctl_buf) {
  5353. WL_ERR(("ioctl memory alloc failed\n"));
  5354. if (vndr_ie) {
  5355. MFREE(cfg->osh, vndr_ie, tot_len);
  5356. }
  5357. return -ENOMEM;
  5358. }
  5359. bzero(ioctl_buf, WLC_IOCTL_MEDLEN); /* init the buffer */
  5360. if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
  5361. WL_ERR(("Find index failed\n"));
  5362. err = BCME_ERROR;
  5363. goto end;
  5364. }
  5365. err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
  5366. WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
  5367. end:
  5368. if (err != BCME_OK) {
  5369. err = -EINVAL;
  5370. if (vndr_ie) {
  5371. MFREE(cfg->osh, vndr_ie, tot_len);
  5372. }
  5373. }
  5374. else {
  5375. /* do NOT free 'vndr_ie' for the next process */
  5376. wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
  5377. }
  5378. if (ioctl_buf) {
  5379. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  5380. }
  5381. return err;
  5382. }
  5383. #if defined(BCMFW_ROAM_ENABLE)
  5384. static int
  5385. wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
  5386. {
  5387. int error = 0;
  5388. char smbuf[WLC_IOCTL_SMLEN];
  5389. uint8 buf[MAX_BUF_SIZE];
  5390. uint8 *pref = buf;
  5391. char *pcmd;
  5392. int num_ucipher_suites = 0;
  5393. int num_akm_suites = 0;
  5394. wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
  5395. wpa_suite_t akm_suites[MAX_NUM_SUITES];
  5396. int num_tuples = 0;
  5397. int total_bytes = 0;
  5398. int total_len_left;
  5399. int i, j;
  5400. char hex[] = "XX";
  5401. pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
  5402. total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
  5403. num_akm_suites = simple_strtoul(pcmd, NULL, 16);
  5404. if (num_akm_suites > MAX_NUM_SUITES) {
  5405. DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites));
  5406. return -1;
  5407. }
  5408. /* Increment for number of AKM suites field + space */
  5409. pcmd += 3;
  5410. total_len_left -= 3;
  5411. /* check to make sure pcmd does not overrun */
  5412. if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
  5413. return -1;
  5414. bzero(buf, sizeof(buf));
  5415. bzero(akm_suites, sizeof(akm_suites));
  5416. bzero(ucipher_suites, sizeof(ucipher_suites));
  5417. /* Save the AKM suites passed in the command */
  5418. for (i = 0; i < num_akm_suites; i++) {
  5419. /* Store the MSB first, as required by join_pref */
  5420. for (j = 0; j < 4; j++) {
  5421. hex[0] = *pcmd++;
  5422. hex[1] = *pcmd++;
  5423. buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
  5424. }
  5425. memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
  5426. }
  5427. total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
  5428. num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
  5429. /* Increment for number of cipher suites field + space */
  5430. pcmd += 3;
  5431. total_len_left -= 3;
  5432. if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
  5433. return -1;
  5434. /* Save the cipher suites passed in the command */
  5435. for (i = 0; i < num_ucipher_suites; i++) {
  5436. /* Store the MSB first, as required by join_pref */
  5437. for (j = 0; j < 4; j++) {
  5438. hex[0] = *pcmd++;
  5439. hex[1] = *pcmd++;
  5440. buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
  5441. }
  5442. memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
  5443. }
  5444. /* Join preference for RSSI
  5445. * Type : 1 byte (0x01)
  5446. * Length : 1 byte (0x02)
  5447. * Value : 2 bytes (reserved)
  5448. */
  5449. *pref++ = WL_JOIN_PREF_RSSI;
  5450. *pref++ = JOIN_PREF_RSSI_LEN;
  5451. *pref++ = 0;
  5452. *pref++ = 0;
  5453. /* Join preference for WPA
  5454. * Type : 1 byte (0x02)
  5455. * Length : 1 byte (not used)
  5456. * Value : (variable length)
  5457. * reserved: 1 byte
  5458. * count : 1 byte (no of tuples)
  5459. * Tuple1 : 12 bytes
  5460. * akm[4]
  5461. * ucipher[4]
  5462. * mcipher[4]
  5463. * Tuple2 : 12 bytes
  5464. * Tuplen : 12 bytes
  5465. */
  5466. num_tuples = num_akm_suites * num_ucipher_suites;
  5467. if (num_tuples != 0) {
  5468. if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
  5469. *pref++ = WL_JOIN_PREF_WPA;
  5470. *pref++ = 0;
  5471. *pref++ = 0;
  5472. *pref++ = (uint8)num_tuples;
  5473. total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
  5474. (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
  5475. } else {
  5476. DHD_ERROR(("wl_android_set_roampref: Too many wpa configs"
  5477. " for join_pref \n"));
  5478. return -1;
  5479. }
  5480. } else {
  5481. /* No WPA config, configure only RSSI preference */
  5482. total_bytes = JOIN_PREF_RSSI_SIZE;
  5483. }
  5484. /* akm-ucipher-mcipher tuples in the format required for join_pref */
  5485. for (i = 0; i < num_ucipher_suites; i++) {
  5486. for (j = 0; j < num_akm_suites; j++) {
  5487. memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
  5488. pref += WPA_SUITE_LEN;
  5489. memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
  5490. pref += WPA_SUITE_LEN;
  5491. /* Set to 0 to match any available multicast cipher */
  5492. bzero(pref, WPA_SUITE_LEN);
  5493. pref += WPA_SUITE_LEN;
  5494. }
  5495. }
  5496. prhex("join pref", (uint8 *)buf, total_bytes);
  5497. error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
  5498. if (error) {
  5499. DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
  5500. }
  5501. return error;
  5502. }
  5503. #endif /* defined(BCMFW_ROAM_ENABLE */
  5504. static int
  5505. wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
  5506. {
  5507. struct io_cfg *resume_cfg;
  5508. s32 ret;
  5509. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  5510. resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
  5511. if (!resume_cfg)
  5512. return -ENOMEM;
  5513. if (config->iovar) {
  5514. ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
  5515. if (ret) {
  5516. DHD_ERROR(("wl_android_iolist_add: Failed to get current %s value\n",
  5517. config->iovar));
  5518. goto error;
  5519. }
  5520. ret = wldev_iovar_setint(dev, config->iovar, config->param);
  5521. if (ret) {
  5522. DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n",
  5523. config->iovar, config->param));
  5524. goto error;
  5525. }
  5526. resume_cfg->iovar = config->iovar;
  5527. } else {
  5528. resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
  5529. if (!resume_cfg->arg) {
  5530. ret = -ENOMEM;
  5531. goto error;
  5532. }
  5533. ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
  5534. if (ret) {
  5535. DHD_ERROR(("wl_android_iolist_add: Failed to get ioctl %d\n",
  5536. config->ioctl));
  5537. goto error;
  5538. }
  5539. ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
  5540. if (ret) {
  5541. DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n",
  5542. config->iovar, config->param));
  5543. goto error;
  5544. }
  5545. if (config->ioctl + 1 == WLC_SET_PM)
  5546. wl_cfg80211_update_power_mode(dev);
  5547. resume_cfg->ioctl = config->ioctl;
  5548. resume_cfg->len = config->len;
  5549. }
  5550. list_add(&resume_cfg->list, head);
  5551. return 0;
  5552. error:
  5553. MFREE(cfg->osh, resume_cfg->arg, config->len);
  5554. MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
  5555. return ret;
  5556. }
  5557. static void
  5558. wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
  5559. {
  5560. struct io_cfg *config;
  5561. struct list_head *cur, *q;
  5562. s32 ret = 0;
  5563. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  5564. GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
  5565. list_for_each_safe(cur, q, head) {
  5566. config = list_entry(cur, struct io_cfg, list);
  5567. GCC_DIAGNOSTIC_POP();
  5568. if (config->iovar) {
  5569. if (!ret)
  5570. ret = wldev_iovar_setint(dev, config->iovar,
  5571. config->param);
  5572. } else {
  5573. if (!ret)
  5574. ret = wldev_ioctl_set(dev, config->ioctl + 1,
  5575. config->arg, config->len);
  5576. if (config->ioctl + 1 == WLC_SET_PM)
  5577. wl_cfg80211_update_power_mode(dev);
  5578. MFREE(cfg->osh, config->arg, config->len);
  5579. }
  5580. list_del(cur);
  5581. MFREE(cfg->osh, config, sizeof(struct io_cfg));
  5582. }
  5583. }
  5584. static int
  5585. wl_android_set_miracast(struct net_device *dev, char *command)
  5586. {
  5587. int mode, val = 0;
  5588. int ret = 0;
  5589. struct io_cfg config;
  5590. if (sscanf(command, "%*s %d", &mode) != 1) {
  5591. DHD_ERROR(("wl_android_set_miracasts: Failed to get Parameter\n"));
  5592. return -1;
  5593. }
  5594. DHD_INFO(("wl_android_set_miracast: enter miracast mode %d\n", mode));
  5595. if (miracast_cur_mode == mode) {
  5596. return 0;
  5597. }
  5598. wl_android_iolist_resume(dev, &miracast_resume_list);
  5599. miracast_cur_mode = MIRACAST_MODE_OFF;
  5600. bzero((void *)&config, sizeof(config));
  5601. switch (mode) {
  5602. case MIRACAST_MODE_SOURCE:
  5603. #ifdef MIRACAST_MCHAN_ALGO
  5604. /* setting mchan_algo to platform specific value */
  5605. config.iovar = "mchan_algo";
  5606. ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
  5607. if (!ret && val > 100) {
  5608. config.param = 0;
  5609. DHD_ERROR(("wl_android_set_miracast: Connected station's beacon interval: "
  5610. "%d and set mchan_algo to %d \n",
  5611. val, config.param));
  5612. } else {
  5613. config.param = MIRACAST_MCHAN_ALGO;
  5614. }
  5615. ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
  5616. if (ret) {
  5617. goto resume;
  5618. }
  5619. #endif /* MIRACAST_MCHAN_ALGO */
  5620. #ifdef MIRACAST_MCHAN_BW
  5621. /* setting mchan_bw to platform specific value */
  5622. config.iovar = "mchan_bw";
  5623. config.param = MIRACAST_MCHAN_BW;
  5624. ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
  5625. if (ret) {
  5626. goto resume;
  5627. }
  5628. #endif /* MIRACAST_MCHAN_BW */
  5629. #ifdef MIRACAST_AMPDU_SIZE
  5630. /* setting apmdu to platform specific value */
  5631. config.iovar = "ampdu_mpdu";
  5632. config.param = MIRACAST_AMPDU_SIZE;
  5633. ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
  5634. if (ret) {
  5635. goto resume;
  5636. }
  5637. #endif /* MIRACAST_AMPDU_SIZE */
  5638. /* Source mode shares most configurations with sink mode.
  5639. * Fall through here to avoid code duplication
  5640. */
  5641. /* fall through */
  5642. case MIRACAST_MODE_SINK:
  5643. /* disable internal roaming */
  5644. config.iovar = "roam_off";
  5645. config.param = 1;
  5646. config.arg = NULL;
  5647. config.len = 0;
  5648. ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
  5649. if (ret) {
  5650. goto resume;
  5651. }
  5652. /* tunr off pm */
  5653. ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
  5654. if (ret) {
  5655. goto resume;
  5656. }
  5657. if (val != PM_OFF) {
  5658. val = PM_OFF;
  5659. config.iovar = NULL;
  5660. config.ioctl = WLC_GET_PM;
  5661. config.arg = &val;
  5662. config.len = sizeof(int);
  5663. ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
  5664. if (ret) {
  5665. goto resume;
  5666. }
  5667. }
  5668. break;
  5669. case MIRACAST_MODE_OFF:
  5670. default:
  5671. break;
  5672. }
  5673. miracast_cur_mode = mode;
  5674. return 0;
  5675. resume:
  5676. DHD_ERROR(("wl_android_set_miracast: turnoff miracast mode because of err%d\n", ret));
  5677. wl_android_iolist_resume(dev, &miracast_resume_list);
  5678. return ret;
  5679. }
  5680. #define NETLINK_OXYGEN 30
  5681. #define AIBSS_BEACON_TIMEOUT 10
  5682. static struct sock *nl_sk = NULL;
  5683. static void wl_netlink_recv(struct sk_buff *skb)
  5684. {
  5685. WL_ERR(("netlink_recv called\n"));
  5686. }
  5687. static int wl_netlink_init(void)
  5688. {
  5689. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
  5690. struct netlink_kernel_cfg cfg = {
  5691. .input = wl_netlink_recv,
  5692. };
  5693. #endif // endif
  5694. if (nl_sk != NULL) {
  5695. WL_ERR(("nl_sk already exist\n"));
  5696. return BCME_ERROR;
  5697. }
  5698. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
  5699. nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
  5700. 0, wl_netlink_recv, NULL, THIS_MODULE);
  5701. #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
  5702. nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
  5703. #else
  5704. nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
  5705. #endif // endif
  5706. if (nl_sk == NULL) {
  5707. WL_ERR(("nl_sk is not ready\n"));
  5708. return BCME_ERROR;
  5709. }
  5710. return BCME_OK;
  5711. }
  5712. static void wl_netlink_deinit(void)
  5713. {
  5714. if (nl_sk) {
  5715. netlink_kernel_release(nl_sk);
  5716. nl_sk = NULL;
  5717. }
  5718. }
  5719. s32
  5720. wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
  5721. {
  5722. struct sk_buff *skb = NULL;
  5723. struct nlmsghdr *nlh = NULL;
  5724. int ret = -1;
  5725. if (nl_sk == NULL) {
  5726. WL_ERR(("nl_sk was not initialized\n"));
  5727. goto nlmsg_failure;
  5728. }
  5729. skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
  5730. if (skb == NULL) {
  5731. WL_ERR(("failed to allocate memory\n"));
  5732. goto nlmsg_failure;
  5733. }
  5734. nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
  5735. if (nlh == NULL) {
  5736. WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
  5737. skb_tailroom(skb), nlmsg_total_size(size)));
  5738. dev_kfree_skb(skb);
  5739. goto nlmsg_failure;
  5740. }
  5741. memcpy(nlmsg_data(nlh), data, size);
  5742. nlh->nlmsg_seq = seq;
  5743. nlh->nlmsg_type = type;
  5744. /* netlink_unicast() takes ownership of the skb and frees it itself. */
  5745. ret = netlink_unicast(nl_sk, skb, pid, 0);
  5746. WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
  5747. nlmsg_failure:
  5748. return ret;
  5749. }
  5750. #ifdef WLAIBSS
  5751. static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
  5752. {
  5753. int err = 0;
  5754. int retry = 0;
  5755. int pid = 0;
  5756. aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
  5757. char smbuf[WLC_IOCTL_SMLEN];
  5758. if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
  5759. WL_ERR(("Failed to get Parameter from : %s\n", command));
  5760. return -1;
  5761. }
  5762. /* set pid, and if the event was happened, let's send a notification through netlink */
  5763. wl_cfg80211_set_txfail_pid(dev, pid);
  5764. #ifdef WL_RELMCAST
  5765. /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
  5766. wl_cfg80211_set_rmc_pid(dev, pid);
  5767. #endif /* WL_RELMCAST */
  5768. /* If retry value is 0, it disables the functionality for TX Fail. */
  5769. if (retry > 0) {
  5770. txfail_config.max_tx_retry = retry;
  5771. txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */
  5772. }
  5773. txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
  5774. txfail_config.len = sizeof(txfail_config);
  5775. err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
  5776. sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
  5777. WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
  5778. return ((err == 0)?total_len:err);
  5779. }
  5780. static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
  5781. int total_len, bool bAll)
  5782. {
  5783. int error;
  5784. int bytes_written = 0;
  5785. void *buf = NULL;
  5786. bss_peer_list_info_t peer_list_info;
  5787. bss_peer_info_t *peer_info;
  5788. int i;
  5789. bool found = false;
  5790. struct ether_addr mac_ea;
  5791. char *str = command;
  5792. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  5793. WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false"));
  5794. if (!bAll) {
  5795. if (bcmstrtok(&str, " ", NULL) == NULL) {
  5796. WL_ERR(("invalid command\n"));
  5797. return -1;
  5798. }
  5799. if (!str || !bcm_ether_atoe(str, &mac_ea)) {
  5800. WL_ERR(("invalid MAC address\n"));
  5801. return -1;
  5802. }
  5803. }
  5804. if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
  5805. WL_ERR(("kmalloc failed\n"));
  5806. return -1;
  5807. }
  5808. error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
  5809. if (unlikely(error)) {
  5810. WL_ERR(("could not get ibss peer info (%d)\n", error));
  5811. MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
  5812. return -1;
  5813. }
  5814. memcpy(&peer_list_info, buf, sizeof(peer_list_info));
  5815. peer_list_info.version = htod16(peer_list_info.version);
  5816. peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
  5817. peer_list_info.count = htod32(peer_list_info.count);
  5818. WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
  5819. peer_list_info.bss_peer_info_len, peer_list_info.count));
  5820. if (peer_list_info.count > 0) {
  5821. if (bAll)
  5822. bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
  5823. peer_list_info.count);
  5824. peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
  5825. for (i = 0; i < peer_list_info.count; i++) {
  5826. WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
  5827. peer_info->tx_rate, peer_info->rx_rate));
  5828. if (!bAll &&
  5829. memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
  5830. found = true;
  5831. }
  5832. if (bAll || found) {
  5833. bytes_written += snprintf(&command[bytes_written],
  5834. total_len - bytes_written,
  5835. MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
  5836. peer_info->tx_rate/1000, peer_info->rssi);
  5837. if (bytes_written >= total_len) {
  5838. WL_ERR(("wl_android_get_ibss_peer_info: Insufficient"
  5839. " memory, %d bytes\n",
  5840. total_len));
  5841. bytes_written = -1;
  5842. break;
  5843. }
  5844. }
  5845. if (found)
  5846. break;
  5847. peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
  5848. }
  5849. }
  5850. else {
  5851. WL_ERR(("could not get ibss peer info : no item\n"));
  5852. }
  5853. WL_DBG(("command(%u):%s\n", total_len, command));
  5854. WL_DBG(("bytes_written:%d\n", bytes_written));
  5855. MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
  5856. return bytes_written;
  5857. }
  5858. int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
  5859. {
  5860. char *pcmd = command;
  5861. char *str = NULL;
  5862. ibss_route_tbl_t *route_tbl = NULL;
  5863. char *ioctl_buf = NULL;
  5864. s32 err = BCME_OK;
  5865. uint32 route_tbl_len;
  5866. uint32 entries;
  5867. char *endptr;
  5868. uint32 i = 0;
  5869. struct ipv4_addr dipaddr;
  5870. struct ether_addr ea;
  5871. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  5872. route_tbl_len = sizeof(ibss_route_tbl_t) +
  5873. (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
  5874. route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
  5875. if (!route_tbl) {
  5876. WL_ERR(("Route TBL alloc failed\n"));
  5877. return -ENOMEM;
  5878. }
  5879. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  5880. if (!ioctl_buf) {
  5881. WL_ERR(("ioctl memory alloc failed\n"));
  5882. if (route_tbl) {
  5883. MFREE(cfg->osh, route_tbl, route_tbl_len);
  5884. }
  5885. return -ENOMEM;
  5886. }
  5887. bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
  5888. /* drop command */
  5889. str = bcmstrtok(&pcmd, " ", NULL);
  5890. /* get count */
  5891. str = bcmstrtok(&pcmd, " ", NULL);
  5892. if (!str) {
  5893. WL_ERR(("Invalid number parameter %s\n", str));
  5894. err = -EINVAL;
  5895. goto exit;
  5896. }
  5897. entries = bcm_strtoul(str, &endptr, 0);
  5898. if (*endptr != '\0') {
  5899. WL_ERR(("Invalid number parameter %s\n", str));
  5900. err = -EINVAL;
  5901. goto exit;
  5902. }
  5903. if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
  5904. WL_ERR(("Invalid entries number %u\n", entries));
  5905. err = -EINVAL;
  5906. goto exit;
  5907. }
  5908. WL_INFORM(("Routing table count:%u\n", entries));
  5909. route_tbl->num_entry = entries;
  5910. for (i = 0; i < entries; i++) {
  5911. str = bcmstrtok(&pcmd, " ", NULL);
  5912. if (!str || !bcm_atoipv4(str, &dipaddr)) {
  5913. WL_ERR(("Invalid ip string %s\n", str));
  5914. err = -EINVAL;
  5915. goto exit;
  5916. }
  5917. str = bcmstrtok(&pcmd, " ", NULL);
  5918. if (!str || !bcm_ether_atoe(str, &ea)) {
  5919. WL_ERR(("Invalid ethernet string %s\n", str));
  5920. err = -EINVAL;
  5921. goto exit;
  5922. }
  5923. bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
  5924. bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
  5925. }
  5926. route_tbl_len = sizeof(ibss_route_tbl_t) +
  5927. ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
  5928. err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
  5929. route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
  5930. if (err != BCME_OK) {
  5931. WL_ERR(("Fail to set iovar %d\n", err));
  5932. err = -EINVAL;
  5933. }
  5934. exit:
  5935. if (route_tbl) {
  5936. MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
  5937. (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
  5938. }
  5939. if (ioctl_buf) {
  5940. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  5941. }
  5942. return err;
  5943. }
  5944. int
  5945. wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
  5946. {
  5947. char *pcmd = command;
  5948. char *str = NULL, *endptr = NULL;
  5949. struct ampdu_aggr aggr;
  5950. char smbuf[WLC_IOCTL_SMLEN];
  5951. int idx;
  5952. int err = 0;
  5953. int wme_AC2PRIO[AC_COUNT][2] = {
  5954. {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */
  5955. {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */
  5956. {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */
  5957. {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */
  5958. WL_DBG(("set ibss ampdu:%s\n", command));
  5959. bzero(&aggr, sizeof(aggr));
  5960. /* Cofigure all priorities */
  5961. aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
  5962. /* acquire parameters */
  5963. /* drop command */
  5964. str = bcmstrtok(&pcmd, " ", NULL);
  5965. for (idx = 0; idx < AC_COUNT; idx++) {
  5966. bool on;
  5967. str = bcmstrtok(&pcmd, " ", NULL);
  5968. if (!str) {
  5969. WL_ERR(("Invalid parameter : %s\n", pcmd));
  5970. return -EINVAL;
  5971. }
  5972. on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
  5973. if (*endptr != '\0') {
  5974. WL_ERR(("Invalid number format %s\n", str));
  5975. return -EINVAL;
  5976. }
  5977. if (on) {
  5978. setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
  5979. setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
  5980. }
  5981. }
  5982. err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
  5983. sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
  5984. return ((err == 0) ? total_len : err);
  5985. }
  5986. int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
  5987. {
  5988. char *pcmd = command;
  5989. char *str = NULL;
  5990. int txchain, rxchain;
  5991. int err = 0;
  5992. WL_DBG(("set ibss antenna:%s\n", command));
  5993. /* acquire parameters */
  5994. /* drop command */
  5995. str = bcmstrtok(&pcmd, " ", NULL);
  5996. /* TX chain */
  5997. str = bcmstrtok(&pcmd, " ", NULL);
  5998. if (!str) {
  5999. WL_ERR(("Invalid parameter : %s\n", pcmd));
  6000. return -EINVAL;
  6001. }
  6002. txchain = bcm_atoi(str);
  6003. /* RX chain */
  6004. str = bcmstrtok(&pcmd, " ", NULL);
  6005. if (!str) {
  6006. WL_ERR(("Invalid parameter : %s\n", pcmd));
  6007. return -EINVAL;
  6008. }
  6009. rxchain = bcm_atoi(str);
  6010. err = wldev_iovar_setint(dev, "txchain", txchain);
  6011. if (err != 0)
  6012. return err;
  6013. err = wldev_iovar_setint(dev, "rxchain", rxchain);
  6014. return ((err == 0)?total_len:err);
  6015. }
  6016. #endif /* WLAIBSS */
  6017. int wl_keep_alive_set(struct net_device *dev, char* extra)
  6018. {
  6019. wl_mkeep_alive_pkt_t mkeep_alive_pkt;
  6020. int ret;
  6021. uint period_msec = 0;
  6022. char *buf;
  6023. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  6024. if (extra == NULL) {
  6025. DHD_ERROR(("wl_keep_alive_set: extra is NULL\n"));
  6026. return -1;
  6027. }
  6028. if (sscanf(extra, "%d", &period_msec) != 1) {
  6029. DHD_ERROR(("wl_keep_alive_set: sscanf error. check period_msec value\n"));
  6030. return -EINVAL;
  6031. }
  6032. DHD_ERROR(("wl_keep_alive_set: period_msec is %d\n", period_msec));
  6033. bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
  6034. mkeep_alive_pkt.period_msec = period_msec;
  6035. mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
  6036. mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
  6037. /* Setup keep alive zero for null packet generation */
  6038. mkeep_alive_pkt.keep_alive_id = 0;
  6039. mkeep_alive_pkt.len_bytes = 0;
  6040. buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_SMLEN);
  6041. if (!buf) {
  6042. DHD_ERROR(("wl_keep_alive_set: buffer alloc failed\n"));
  6043. return BCME_NOMEM;
  6044. }
  6045. ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
  6046. WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
  6047. if (ret < 0)
  6048. DHD_ERROR(("wl_keep_alive_set:keep_alive set failed:%d\n", ret));
  6049. else
  6050. DHD_TRACE(("wl_keep_alive_set: keep_alive set ok\n"));
  6051. MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN);
  6052. return ret;
  6053. }
  6054. #ifdef P2PRESP_WFDIE_SRC
  6055. static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
  6056. {
  6057. int error = 0;
  6058. int bytes_written = 0;
  6059. int only_resp_wfdsrc = 0;
  6060. error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
  6061. if (error) {
  6062. DHD_ERROR(("wl_android_get_wfdie_resp: Failed to get the mode"
  6063. " for only_resp_wfdsrc, error = %d\n",
  6064. error));
  6065. return -1;
  6066. }
  6067. bytes_written = snprintf(command, total_len, "%s %d",
  6068. CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
  6069. return bytes_written;
  6070. }
  6071. static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
  6072. {
  6073. int error = 0;
  6074. error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
  6075. if (error) {
  6076. DHD_ERROR(("wl_android_set_wfdie_resp: Failed to set only_resp_wfdsrc %d,"
  6077. " error = %d\n",
  6078. only_resp_wfdsrc, error));
  6079. return -1;
  6080. }
  6081. return 0;
  6082. }
  6083. #endif /* P2PRESP_WFDIE_SRC */
  6084. #ifdef BT_WIFI_HANDOVER
  6085. static int
  6086. wl_tbow_teardown(struct net_device *dev)
  6087. {
  6088. int err = BCME_OK;
  6089. char buf[WLC_IOCTL_SMLEN];
  6090. tbow_setup_netinfo_t netinfo;
  6091. bzero(&netinfo, sizeof(netinfo));
  6092. netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
  6093. err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
  6094. sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
  6095. if (err < 0) {
  6096. WL_ERR(("tbow_doho iovar error %d\n", err));
  6097. return err;
  6098. }
  6099. return err;
  6100. }
  6101. #endif /* BT_WIFI_HANOVER */
  6102. #ifdef SET_RPS_CPUS
  6103. static int
  6104. wl_android_set_rps_cpus(struct net_device *dev, char *command)
  6105. {
  6106. int error, enable;
  6107. enable = command[strlen(CMD_RPSMODE) + 1] - '0';
  6108. error = dhd_rps_cpus_enable(dev, enable);
  6109. #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211)
  6110. if (!error) {
  6111. void *dhdp = wl_cfg80211_get_dhdp(net);
  6112. if (enable) {
  6113. DHD_TRACE(("wl_android_set_rps_cpus: set ack suppress."
  6114. " TCPACK_SUP_HOLD.\n"));
  6115. dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
  6116. } else {
  6117. DHD_TRACE(("wl_android_set_rps_cpus: clear ack suppress.\n"));
  6118. dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
  6119. }
  6120. }
  6121. #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
  6122. return error;
  6123. }
  6124. #endif /* SET_RPS_CPUS */
  6125. static int wl_android_get_link_status(struct net_device *dev, char *command,
  6126. int total_len)
  6127. {
  6128. int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
  6129. uint32 rspec;
  6130. uint encode, txexp;
  6131. wl_bss_info_t *bi;
  6132. int datalen;
  6133. char buf[sizeof(uint32) + sizeof(wl_bss_info_t)];
  6134. datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
  6135. bzero(buf, datalen);
  6136. /* get BSS information */
  6137. *(u32 *) buf = htod32(datalen);
  6138. error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
  6139. if (unlikely(error)) {
  6140. WL_ERR(("Could not get bss info %d\n", error));
  6141. return -1;
  6142. }
  6143. bi = (wl_bss_info_t*) (buf + sizeof(uint32));
  6144. for (i = 0; i < ETHER_ADDR_LEN; i++) {
  6145. if (bi->BSSID.octet[i] > 0) {
  6146. break;
  6147. }
  6148. }
  6149. if (i == ETHER_ADDR_LEN) {
  6150. WL_DBG(("No BSSID\n"));
  6151. return -1;
  6152. }
  6153. /* check VHT capability at beacon */
  6154. if (bi->vht_cap) {
  6155. if (CHSPEC_IS5G(bi->chanspec)) {
  6156. result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
  6157. }
  6158. }
  6159. /* get a rspec (radio spectrum) rate */
  6160. error = wldev_iovar_getint(dev, "nrate", &rspec);
  6161. if (unlikely(error) || rspec == 0) {
  6162. WL_ERR(("get link status error (%d)\n", error));
  6163. return -1;
  6164. }
  6165. encode = (rspec & WL_RSPEC_ENCODING_MASK);
  6166. txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
  6167. switch (encode) {
  6168. case WL_RSPEC_ENCODE_HT:
  6169. /* check Rx MCS Map for HT */
  6170. for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
  6171. int8 bitmap = 0xFF;
  6172. if (i == MAX_STREAMS_SUPPORTED-1) {
  6173. bitmap = 0x7F;
  6174. }
  6175. if (bi->basic_mcs[i] & bitmap) {
  6176. nss++;
  6177. }
  6178. }
  6179. break;
  6180. case WL_RSPEC_ENCODE_VHT:
  6181. /* check Rx MCS Map for VHT */
  6182. for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
  6183. mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
  6184. if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
  6185. nss++;
  6186. }
  6187. }
  6188. break;
  6189. }
  6190. /* check MIMO capability with nss in beacon */
  6191. if (nss > 1) {
  6192. result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
  6193. }
  6194. single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
  6195. ((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
  6196. ((encode == WL_RSPEC_ENCODE_VHT) &&
  6197. ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
  6198. if (txexp == 0) {
  6199. if ((rspec & WL_RSPEC_STBC) && single_stream) {
  6200. stf = OLD_NRATE_STF_STBC;
  6201. } else {
  6202. stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
  6203. }
  6204. } else if (txexp == 1 && single_stream) {
  6205. stf = OLD_NRATE_STF_CDD;
  6206. }
  6207. /* check 11ac (VHT) */
  6208. if (encode == WL_RSPEC_ENCODE_VHT) {
  6209. if (CHSPEC_IS5G(bi->chanspec)) {
  6210. result |= WL_ANDROID_LINK_VHT;
  6211. }
  6212. }
  6213. /* check MIMO */
  6214. if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
  6215. switch (stf) {
  6216. case OLD_NRATE_STF_SISO:
  6217. break;
  6218. case OLD_NRATE_STF_CDD:
  6219. case OLD_NRATE_STF_STBC:
  6220. result |= WL_ANDROID_LINK_MIMO;
  6221. break;
  6222. case OLD_NRATE_STF_SDM:
  6223. if (!single_stream) {
  6224. result |= WL_ANDROID_LINK_MIMO;
  6225. }
  6226. break;
  6227. }
  6228. }
  6229. WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
  6230. __FUNCTION__, result, stf, single_stream, nss));
  6231. bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
  6232. return bytes_written;
  6233. }
  6234. #ifdef P2P_LISTEN_OFFLOADING
  6235. s32
  6236. wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
  6237. {
  6238. s32 bssidx;
  6239. int ret = 0;
  6240. int p2plo_pause = 0;
  6241. dhd_pub_t *dhd = NULL;
  6242. if (!cfg || !cfg->p2p) {
  6243. WL_ERR(("Wl %p or cfg->p2p %p is null\n",
  6244. cfg, cfg ? cfg->p2p : 0));
  6245. return 0;
  6246. }
  6247. dhd = (dhd_pub_t *)(cfg->pub);
  6248. if (!dhd->up) {
  6249. WL_ERR(("bus is already down\n"));
  6250. return ret;
  6251. }
  6252. bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
  6253. ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
  6254. "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
  6255. cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
  6256. if (ret < 0) {
  6257. WL_ERR(("p2po_stop Failed :%d\n", ret));
  6258. }
  6259. return ret;
  6260. }
  6261. s32
  6262. wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
  6263. {
  6264. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  6265. s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
  6266. wl_p2plo_listen_t p2plo_listen;
  6267. int ret = -EAGAIN;
  6268. int channel = 0;
  6269. int period = 0;
  6270. int interval = 0;
  6271. int count = 0;
  6272. if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
  6273. WL_ERR(("Sending Action Frames. Try it again.\n"));
  6274. goto exit;
  6275. }
  6276. if (wl_get_drv_status_all(cfg, SCANNING)) {
  6277. WL_ERR(("Scanning already\n"));
  6278. goto exit;
  6279. }
  6280. if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
  6281. WL_ERR(("Scanning being aborted\n"));
  6282. goto exit;
  6283. }
  6284. if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
  6285. WL_ERR(("p2p listen offloading already running\n"));
  6286. goto exit;
  6287. }
  6288. /* Just in case if it is not enabled */
  6289. if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
  6290. WL_ERR(("cfgp2p_enable discovery failed"));
  6291. goto exit;
  6292. }
  6293. bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
  6294. if (len) {
  6295. sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
  6296. if ((channel == 0) || (period == 0) ||
  6297. (interval == 0) || (count == 0)) {
  6298. WL_ERR(("Wrong argument %d/%d/%d/%d \n",
  6299. channel, period, interval, count));
  6300. ret = -EAGAIN;
  6301. goto exit;
  6302. }
  6303. p2plo_listen.period = period;
  6304. p2plo_listen.interval = interval;
  6305. p2plo_listen.count = count;
  6306. WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
  6307. channel, period, interval, count));
  6308. } else {
  6309. WL_ERR(("Argument len is wrong.\n"));
  6310. ret = -EAGAIN;
  6311. goto exit;
  6312. }
  6313. if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
  6314. sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
  6315. bssidx, &cfg->ioctl_buf_sync)) < 0) {
  6316. WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
  6317. goto exit;
  6318. }
  6319. if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
  6320. sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
  6321. bssidx, &cfg->ioctl_buf_sync)) < 0) {
  6322. WL_ERR(("p2po_listen Failed :%d\n", ret));
  6323. goto exit;
  6324. }
  6325. wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
  6326. exit :
  6327. return ret;
  6328. }
  6329. s32
  6330. wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
  6331. {
  6332. struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
  6333. s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
  6334. int ret = -EAGAIN;
  6335. if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
  6336. 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
  6337. bssidx, &cfg->ioctl_buf_sync)) < 0) {
  6338. WL_ERR(("p2po_stop Failed :%d\n", ret));
  6339. goto exit;
  6340. }
  6341. exit:
  6342. return ret;
  6343. }
  6344. s32
  6345. wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
  6346. {
  6347. int ret = 0;
  6348. WL_ERR(("Entry cmd:%s arg_len:%d \n", cmd, len));
  6349. if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
  6350. ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
  6351. } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
  6352. ret = wl_cfg80211_p2plo_listen_stop(dev);
  6353. } else {
  6354. WL_ERR(("Request for Unsupported CMD:%s \n", buf));
  6355. ret = -EINVAL;
  6356. }
  6357. return ret;
  6358. }
  6359. void
  6360. wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
  6361. {
  6362. struct wireless_dev *wdev;
  6363. if (!cfg) {
  6364. return;
  6365. }
  6366. wdev = bcmcfg_to_p2p_wdev(cfg);
  6367. if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
  6368. WL_INFORM_MEM(("P2P_FIND: Discovery offload is already in progress."
  6369. "it aborted\n"));
  6370. wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
  6371. if (wdev != NULL) {
  6372. #if defined(WL_CFG80211_P2P_DEV_IF)
  6373. cfg80211_remain_on_channel_expired(wdev,
  6374. cfg->last_roc_id,
  6375. &cfg->remain_on_chan, GFP_KERNEL);
  6376. #else
  6377. cfg80211_remain_on_channel_expired(wdev,
  6378. cfg->last_roc_id,
  6379. &cfg->remain_on_chan,
  6380. cfg->remain_on_chan_type, GFP_KERNEL);
  6381. #endif /* WL_CFG80211_P2P_DEV_IF */
  6382. }
  6383. wl_cfg80211_p2plo_deinit(cfg);
  6384. }
  6385. }
  6386. #endif /* P2P_LISTEN_OFFLOADING */
  6387. #ifdef WL_MURX
  6388. int
  6389. wl_android_murx_bfe_cap(struct net_device *dev, int val)
  6390. {
  6391. int err = BCME_OK;
  6392. int iface_count = wl_cfg80211_iface_count(dev);
  6393. struct ether_addr bssid;
  6394. wl_reassoc_params_t params;
  6395. if (iface_count > 1) {
  6396. WL_ERR(("murx_bfe_cap change is not allowed when "
  6397. "there are multiple interfaces\n"));
  6398. return -EINVAL;
  6399. }
  6400. /* Now there is only single interface */
  6401. err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
  6402. if (unlikely(err)) {
  6403. WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
  6404. "error %d\n", val, err));
  6405. return err;
  6406. }
  6407. /* If successful intiate a reassoc */
  6408. bzero(&bssid, ETHER_ADDR_LEN);
  6409. if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
  6410. WL_ERR(("Failed to get bssid, error=%d\n", err));
  6411. return err;
  6412. }
  6413. bzero(&params, sizeof(wl_reassoc_params_t));
  6414. memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
  6415. if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
  6416. sizeof(wl_reassoc_params_t))) < 0) {
  6417. WL_ERR(("reassoc failed err:%d \n", err));
  6418. } else {
  6419. WL_DBG(("reassoc issued successfully\n"));
  6420. }
  6421. return err;
  6422. }
  6423. #endif /* WL_MURX */
  6424. #ifdef SUPPORT_RSSI_SUM_REPORT
  6425. int
  6426. wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
  6427. {
  6428. wl_rssi_ant_mimo_t rssi_ant_mimo;
  6429. char *ifname = NULL;
  6430. char *peer_mac = NULL;
  6431. char *mimo_cmd = "mimo";
  6432. char *pos, *token;
  6433. int err = BCME_OK;
  6434. int bytes_written = 0;
  6435. bool mimo_rssi = FALSE;
  6436. bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
  6437. /*
  6438. * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
  6439. * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
  6440. */
  6441. pos = command;
  6442. /* drop command */
  6443. token = bcmstrtok(&pos, " ", NULL);
  6444. /* get the interface name */
  6445. token = bcmstrtok(&pos, " ", NULL);
  6446. if (!token) {
  6447. WL_ERR(("Invalid arguments\n"));
  6448. return -EINVAL;
  6449. }
  6450. ifname = token;
  6451. /* Optional: Check the MIMO RSSI mode or peer MAC address */
  6452. token = bcmstrtok(&pos, " ", NULL);
  6453. if (token) {
  6454. /* Check the MIMO RSSI mode */
  6455. if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
  6456. mimo_rssi = TRUE;
  6457. } else {
  6458. peer_mac = token;
  6459. }
  6460. }
  6461. /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
  6462. token = bcmstrtok(&pos, " ", NULL);
  6463. if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
  6464. mimo_rssi = TRUE;
  6465. }
  6466. err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
  6467. if (unlikely(err)) {
  6468. WL_ERR(("Failed to get RSSI info, err=%d\n", err));
  6469. return err;
  6470. }
  6471. /* Parse the results */
  6472. WL_DBG(("ifname %s, version %d, count %d, mimo rssi %d\n",
  6473. ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
  6474. if (mimo_rssi) {
  6475. WL_DBG(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
  6476. bytes_written = snprintf(command, total_len, "%s MIMO %d",
  6477. CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
  6478. } else {
  6479. int cnt;
  6480. bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
  6481. for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
  6482. WL_DBG(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
  6483. bytes_written = snprintf(command, total_len, "%d ",
  6484. rssi_ant_mimo.rssi_ant[cnt]);
  6485. }
  6486. }
  6487. return bytes_written;
  6488. }
  6489. int
  6490. wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
  6491. {
  6492. rssilog_set_param_t set_param;
  6493. char *pos, *token;
  6494. int err = BCME_OK;
  6495. bzero(&set_param, sizeof(rssilog_set_param_t));
  6496. /*
  6497. * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
  6498. */
  6499. pos = command;
  6500. /* drop command */
  6501. token = bcmstrtok(&pos, " ", NULL);
  6502. /* enable/disable */
  6503. token = bcmstrtok(&pos, " ", NULL);
  6504. if (!token) {
  6505. WL_ERR(("Invalid arguments\n"));
  6506. return -EINVAL;
  6507. }
  6508. set_param.enable = bcm_atoi(token);
  6509. /* RSSI Threshold */
  6510. token = bcmstrtok(&pos, " ", NULL);
  6511. if (!token) {
  6512. WL_ERR(("Invalid arguments\n"));
  6513. return -EINVAL;
  6514. }
  6515. set_param.rssi_threshold = bcm_atoi(token);
  6516. /* Time Threshold */
  6517. token = bcmstrtok(&pos, " ", NULL);
  6518. if (!token) {
  6519. WL_ERR(("Invalid arguments\n"));
  6520. return -EINVAL;
  6521. }
  6522. set_param.time_threshold = bcm_atoi(token);
  6523. WL_DBG(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
  6524. set_param.rssi_threshold, set_param.time_threshold));
  6525. err = wl_set_rssi_logging(dev, (void *)&set_param);
  6526. if (unlikely(err)) {
  6527. WL_ERR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
  6528. " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
  6529. set_param.time_threshold));
  6530. }
  6531. return err;
  6532. }
  6533. int
  6534. wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
  6535. {
  6536. rssilog_get_param_t get_param;
  6537. int err = BCME_OK;
  6538. int bytes_written = 0;
  6539. err = wl_get_rssi_logging(dev, (void *)&get_param);
  6540. if (unlikely(err)) {
  6541. WL_ERR(("Failed to get RSSI logging info\n"));
  6542. return BCME_ERROR;
  6543. }
  6544. WL_DBG(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
  6545. get_param.report_count, get_param.enable, get_param.rssi_threshold,
  6546. get_param.time_threshold));
  6547. /* Parse the parameter */
  6548. if (!get_param.enable) {
  6549. WL_DBG(("RSSI LOGGING: Feature is disables\n"));
  6550. bytes_written = snprintf(command, total_len,
  6551. "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
  6552. } else if (get_param.enable &
  6553. (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
  6554. if (!get_param.report_count) {
  6555. WL_DBG(("[PASS] RSSI difference across antennas is within"
  6556. " threshold limits\n"));
  6557. bytes_written = snprintf(command, total_len, "%s PASS\n",
  6558. CMD_GET_RSSI_LOGGING);
  6559. } else {
  6560. WL_DBG(("[FAIL] RSSI difference across antennas found "
  6561. "to be greater than %3d dB\n", get_param.rssi_threshold));
  6562. WL_DBG(("[FAIL] RSSI difference check have failed for "
  6563. "%d out of %d times\n", get_param.report_count,
  6564. get_param.time_threshold));
  6565. WL_DBG(("[FAIL] RSSI difference is being monitored once "
  6566. "per second, for a %d secs window\n", get_param.time_threshold));
  6567. bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
  6568. "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
  6569. get_param.rssi_threshold, get_param.report_count,
  6570. get_param.time_threshold);
  6571. }
  6572. } else {
  6573. WL_DBG(("[BUSY] Reprot is not ready\n"));
  6574. bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
  6575. CMD_GET_RSSI_LOGGING);
  6576. }
  6577. return bytes_written;
  6578. }
  6579. #endif /* SUPPORT_RSSI_SUM_REPORT */
  6580. #ifdef SET_PCIE_IRQ_CPU_CORE
  6581. void
  6582. wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
  6583. {
  6584. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
  6585. if (!dhdp) {
  6586. WL_ERR(("dhd is NULL\n"));
  6587. return;
  6588. }
  6589. if (affinity_cmd < PCIE_IRQ_AFFINITY_OFF || affinity_cmd > PCIE_IRQ_AFFINITY_LAST) {
  6590. WL_ERR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
  6591. return;
  6592. }
  6593. dhd_set_irq_cpucore(dhdp, affinity_cmd);
  6594. }
  6595. #endif /* SET_PCIE_IRQ_CPU_CORE */
  6596. #ifdef SUPPORT_LQCM
  6597. static int
  6598. wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
  6599. {
  6600. int err = 0;
  6601. err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
  6602. if (err != BCME_OK) {
  6603. WL_ERR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
  6604. return -EIO;
  6605. }
  6606. return err;
  6607. }
  6608. static int
  6609. wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
  6610. {
  6611. int bytes_written, err = 0;
  6612. uint32 lqcm_report = 0;
  6613. uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
  6614. err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
  6615. if (err != BCME_OK) {
  6616. WL_ERR(("failed to get lqcm report, error = %d\n", err));
  6617. return -EIO;
  6618. }
  6619. lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
  6620. tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
  6621. rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
  6622. WL_DBG(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
  6623. bytes_written = snprintf(command, total_len, "%s %d",
  6624. CMD_GET_LQCM_REPORT, lqcm_report);
  6625. return bytes_written;
  6626. }
  6627. #endif /* SUPPORT_LQCM */
  6628. int
  6629. wl_android_get_snr(struct net_device *dev, char *command, int total_len)
  6630. {
  6631. int bytes_written, error = 0;
  6632. s32 snr = 0;
  6633. error = wldev_iovar_getint(dev, "snr", &snr);
  6634. if (error) {
  6635. DHD_ERROR(("wl_android_get_snr: Failed to get SNR %d, error = %d\n",
  6636. snr, error));
  6637. return -EIO;
  6638. }
  6639. bytes_written = snprintf(command, total_len, "snr %d", snr);
  6640. DHD_INFO(("wl_android_get_snr: command result is %s\n", command));
  6641. return bytes_written;
  6642. }
  6643. #ifdef SUPPORT_AP_HIGHER_BEACONRATE
  6644. int
  6645. wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
  6646. {
  6647. int rate = 0;
  6648. char *pos, *token;
  6649. char *ifname = NULL;
  6650. int err = BCME_OK;
  6651. /*
  6652. * DRIVER SET_AP_BEACONRATE <rate> <ifname>
  6653. */
  6654. pos = command;
  6655. /* drop command */
  6656. token = bcmstrtok(&pos, " ", NULL);
  6657. /* Rate */
  6658. token = bcmstrtok(&pos, " ", NULL);
  6659. if (!token)
  6660. return -EINVAL;
  6661. rate = bcm_atoi(token);
  6662. /* get the interface name */
  6663. token = bcmstrtok(&pos, " ", NULL);
  6664. if (!token)
  6665. return -EINVAL;
  6666. ifname = token;
  6667. WL_DBG(("rate %d, ifacename %s\n", rate, ifname));
  6668. err = wl_set_ap_beacon_rate(dev, rate, ifname);
  6669. if (unlikely(err)) {
  6670. WL_ERR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
  6671. }
  6672. return err;
  6673. }
  6674. int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
  6675. {
  6676. char *pos, *token;
  6677. char *ifname = NULL;
  6678. int bytes_written = 0;
  6679. /*
  6680. * DRIVER GET_AP_BASICRATE <ifname>
  6681. */
  6682. pos = command;
  6683. /* drop command */
  6684. token = bcmstrtok(&pos, " ", NULL);
  6685. /* get the interface name */
  6686. token = bcmstrtok(&pos, " ", NULL);
  6687. if (!token)
  6688. return -EINVAL;
  6689. ifname = token;
  6690. WL_DBG(("ifacename %s\n", ifname));
  6691. bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
  6692. if (bytes_written < 1) {
  6693. WL_ERR(("Failed to get ap basic rate, error = %d\n", bytes_written));
  6694. return -EPROTO;
  6695. }
  6696. return bytes_written;
  6697. }
  6698. #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
  6699. #ifdef SUPPORT_AP_RADIO_PWRSAVE
  6700. int
  6701. wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
  6702. {
  6703. char *pos, *token;
  6704. char *ifname = NULL;
  6705. int bytes_written = 0;
  6706. char name[IFNAMSIZ];
  6707. /*
  6708. * DRIVER GET_AP_RPS <ifname>
  6709. */
  6710. pos = command;
  6711. /* drop command */
  6712. token = bcmstrtok(&pos, " ", NULL);
  6713. /* get the interface name */
  6714. token = bcmstrtok(&pos, " ", NULL);
  6715. if (!token)
  6716. return -EINVAL;
  6717. ifname = token;
  6718. strlcpy(name, ifname, sizeof(name));
  6719. WL_DBG(("ifacename %s\n", name));
  6720. bytes_written = wl_get_ap_rps(dev, command, name, total_len);
  6721. if (bytes_written < 1) {
  6722. WL_ERR(("Failed to get rps, error = %d\n", bytes_written));
  6723. return -EPROTO;
  6724. }
  6725. return bytes_written;
  6726. }
  6727. int
  6728. wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
  6729. {
  6730. int enable = 0;
  6731. char *pos, *token;
  6732. char *ifname = NULL;
  6733. int err = BCME_OK;
  6734. char name[IFNAMSIZ];
  6735. /*
  6736. * DRIVER SET_AP_RPS <0/1> <ifname>
  6737. */
  6738. pos = command;
  6739. /* drop command */
  6740. token = bcmstrtok(&pos, " ", NULL);
  6741. /* Enable */
  6742. token = bcmstrtok(&pos, " ", NULL);
  6743. if (!token)
  6744. return -EINVAL;
  6745. enable = bcm_atoi(token);
  6746. /* get the interface name */
  6747. token = bcmstrtok(&pos, " ", NULL);
  6748. if (!token)
  6749. return -EINVAL;
  6750. ifname = token;
  6751. strlcpy(name, ifname, sizeof(name));
  6752. WL_DBG(("enable %d, ifacename %s\n", enable, name));
  6753. err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
  6754. if (unlikely(err)) {
  6755. WL_ERR(("Failed to set rps, enable %d, error = %d\n", enable, err));
  6756. }
  6757. return err;
  6758. }
  6759. int
  6760. wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
  6761. {
  6762. ap_rps_info_t rps;
  6763. char *pos, *token;
  6764. char *ifname = NULL;
  6765. int err = BCME_OK;
  6766. char name[IFNAMSIZ];
  6767. bzero(&rps, sizeof(rps));
  6768. /*
  6769. * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
  6770. */
  6771. pos = command;
  6772. /* drop command */
  6773. token = bcmstrtok(&pos, " ", NULL);
  6774. /* pps */
  6775. token = bcmstrtok(&pos, " ", NULL);
  6776. if (!token)
  6777. return -EINVAL;
  6778. rps.pps = bcm_atoi(token);
  6779. /* level */
  6780. token = bcmstrtok(&pos, " ", NULL);
  6781. if (!token)
  6782. return -EINVAL;
  6783. rps.level = bcm_atoi(token);
  6784. /* quiettime */
  6785. token = bcmstrtok(&pos, " ", NULL);
  6786. if (!token)
  6787. return -EINVAL;
  6788. rps.quiet_time = bcm_atoi(token);
  6789. /* sta assoc check */
  6790. token = bcmstrtok(&pos, " ", NULL);
  6791. if (!token)
  6792. return -EINVAL;
  6793. rps.sta_assoc_check = bcm_atoi(token);
  6794. /* get the interface name */
  6795. token = bcmstrtok(&pos, " ", NULL);
  6796. if (!token)
  6797. return -EINVAL;
  6798. ifname = token;
  6799. strlcpy(name, ifname, sizeof(name));
  6800. WL_DBG(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
  6801. "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
  6802. rps.sta_assoc_check, name));
  6803. err = wl_update_ap_rps_params(dev, &rps, name);
  6804. if (unlikely(err)) {
  6805. WL_ERR(("Failed to update rps, pps %d, level %d, quiettime %d, "
  6806. "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
  6807. rps.sta_assoc_check, err));
  6808. }
  6809. return err;
  6810. }
  6811. #endif /* SUPPORT_AP_RADIO_PWRSAVE */
  6812. #if defined(DHD_HANG_SEND_UP_TEST)
  6813. void
  6814. wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
  6815. {
  6816. dhd_make_hang_with_reason(dev, string_num);
  6817. }
  6818. #endif /* DHD_HANG_SEND_UP_TEST */
  6819. #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
  6820. static void
  6821. wl_android_check_priv_cmd_errors(struct net_device *dev)
  6822. {
  6823. dhd_pub_t *dhdp;
  6824. int memdump_mode;
  6825. if (!dev) {
  6826. WL_ERR(("dev is NULL\n"));
  6827. return;
  6828. }
  6829. dhdp = wl_cfg80211_get_dhdp(dev);
  6830. if (!dhdp) {
  6831. WL_ERR(("dhdp is NULL\n"));
  6832. return;
  6833. }
  6834. #ifdef DHD_FW_COREDUMP
  6835. memdump_mode = dhdp->memdump_enabled;
  6836. #else
  6837. /* Default enable if DHD doesn't support SOCRAM dump */
  6838. memdump_mode = 1;
  6839. #endif /* DHD_FW_COREDUMP */
  6840. if (report_hang_privcmd_err) {
  6841. priv_cmd_errors++;
  6842. } else {
  6843. priv_cmd_errors = 0;
  6844. }
  6845. /* Trigger HANG event only if memdump mode is enabled
  6846. * due to customer's request
  6847. */
  6848. if (memdump_mode == DUMP_MEMFILE_BUGON &&
  6849. (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
  6850. WL_ERR(("Send HANG event due to sequential private cmd errors\n"));
  6851. priv_cmd_errors = 0;
  6852. #ifdef DHD_FW_COREDUMP
  6853. /* Take a SOCRAM dump */
  6854. dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
  6855. dhd_common_socram_dump(dhdp);
  6856. #endif /* DHD_FW_COREDUMP */
  6857. /* Send the HANG event to upper layer */
  6858. dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
  6859. dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
  6860. }
  6861. }
  6862. #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
  6863. #ifdef DHD_PKT_LOGGING
  6864. static int
  6865. wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
  6866. {
  6867. int bytes_written = 0;
  6868. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6869. dhd_pktlog_filter_t *filter;
  6870. int err = BCME_OK;
  6871. if (!dhdp || !dhdp->pktlog) {
  6872. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  6873. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  6874. return -EINVAL;
  6875. }
  6876. filter = dhdp->pktlog->pktlog_filter;
  6877. err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
  6878. err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
  6879. err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
  6880. if (err == BCME_OK) {
  6881. bytes_written = snprintf(command, total_len, "OK");
  6882. DHD_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
  6883. } else {
  6884. DHD_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
  6885. return BCME_ERROR;
  6886. }
  6887. return bytes_written;
  6888. }
  6889. static int
  6890. wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
  6891. {
  6892. int bytes_written = 0;
  6893. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6894. dhd_pktlog_filter_t *filter;
  6895. int err = BCME_OK;
  6896. if (!dhdp || !dhdp->pktlog) {
  6897. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  6898. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  6899. return -EINVAL;
  6900. }
  6901. filter = dhdp->pktlog->pktlog_filter;
  6902. err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
  6903. err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
  6904. err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
  6905. if (err == BCME_OK) {
  6906. bytes_written = snprintf(command, total_len, "OK");
  6907. DHD_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
  6908. } else {
  6909. DHD_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
  6910. return BCME_ERROR;
  6911. }
  6912. return bytes_written;
  6913. }
  6914. static int
  6915. wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
  6916. {
  6917. int bytes_written = 0;
  6918. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6919. dhd_pktlog_filter_t *filter;
  6920. int err = BCME_OK;
  6921. if (!dhdp || !dhdp->pktlog) {
  6922. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  6923. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  6924. return -EINVAL;
  6925. }
  6926. filter = dhdp->pktlog->pktlog_filter;
  6927. if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
  6928. return BCME_ERROR;
  6929. }
  6930. err = dhd_pktlog_filter_pattern_enable(filter,
  6931. command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
  6932. if (err == BCME_OK) {
  6933. bytes_written = snprintf(command, total_len, "OK");
  6934. DHD_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
  6935. } else {
  6936. DHD_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
  6937. return BCME_ERROR;
  6938. }
  6939. return bytes_written;
  6940. }
  6941. static int
  6942. wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
  6943. {
  6944. int bytes_written = 0;
  6945. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6946. dhd_pktlog_filter_t *filter;
  6947. int err = BCME_OK;
  6948. if (!dhdp || !dhdp->pktlog) {
  6949. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  6950. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  6951. return -EINVAL;
  6952. }
  6953. filter = dhdp->pktlog->pktlog_filter;
  6954. if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
  6955. return BCME_ERROR;
  6956. }
  6957. err = dhd_pktlog_filter_pattern_enable(filter,
  6958. command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
  6959. if (err == BCME_OK) {
  6960. bytes_written = snprintf(command, total_len, "OK");
  6961. DHD_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
  6962. } else {
  6963. DHD_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
  6964. return BCME_ERROR;
  6965. }
  6966. return bytes_written;
  6967. }
  6968. static int
  6969. wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
  6970. {
  6971. int bytes_written = 0;
  6972. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6973. dhd_pktlog_filter_t *filter;
  6974. int err = BCME_OK;
  6975. if (!dhdp || !dhdp->pktlog) {
  6976. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  6977. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  6978. return -EINVAL;
  6979. }
  6980. filter = dhdp->pktlog->pktlog_filter;
  6981. if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
  6982. return BCME_ERROR;
  6983. }
  6984. err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
  6985. if (err == BCME_OK) {
  6986. bytes_written = snprintf(command, total_len, "OK");
  6987. DHD_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
  6988. } else {
  6989. DHD_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
  6990. return BCME_ERROR;
  6991. }
  6992. return bytes_written;
  6993. }
  6994. static int
  6995. wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
  6996. {
  6997. int bytes_written = 0;
  6998. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  6999. dhd_pktlog_filter_t *filter;
  7000. int err = BCME_OK;
  7001. if (!dhdp || !dhdp->pktlog) {
  7002. DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n",
  7003. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7004. return -EINVAL;
  7005. }
  7006. filter = dhdp->pktlog->pktlog_filter;
  7007. if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
  7008. DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
  7009. __FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
  7010. return BCME_ERROR;
  7011. }
  7012. err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
  7013. if (err == BCME_OK) {
  7014. bytes_written = snprintf(command, total_len, "OK");
  7015. DHD_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
  7016. } else {
  7017. DHD_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
  7018. return BCME_ERROR;
  7019. }
  7020. return bytes_written;
  7021. }
  7022. static int
  7023. wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
  7024. {
  7025. int bytes_written = 0;
  7026. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7027. dhd_pktlog_filter_t *filter;
  7028. int err = BCME_OK;
  7029. if (!dhdp || !dhdp->pktlog) {
  7030. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7031. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7032. return -EINVAL;
  7033. }
  7034. filter = dhdp->pktlog->pktlog_filter;
  7035. err = dhd_pktlog_filter_info(filter);
  7036. if (err == BCME_OK) {
  7037. bytes_written = snprintf(command, total_len, "OK");
  7038. DHD_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
  7039. } else {
  7040. DHD_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
  7041. return BCME_ERROR;
  7042. }
  7043. return bytes_written;
  7044. }
  7045. static int
  7046. wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
  7047. {
  7048. int bytes_written = 0;
  7049. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7050. if (!dhdp || !dhdp->pktlog) {
  7051. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7052. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7053. return -EINVAL;
  7054. }
  7055. if (!dhdp->pktlog->pktlog_ring) {
  7056. DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
  7057. __FUNCTION__, dhdp->pktlog->pktlog_ring));
  7058. return -EINVAL;
  7059. }
  7060. atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
  7061. bytes_written = snprintf(command, total_len, "OK");
  7062. DHD_ERROR(("%s: pktlog start success\n", __FUNCTION__));
  7063. return bytes_written;
  7064. }
  7065. static int
  7066. wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
  7067. {
  7068. int bytes_written = 0;
  7069. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7070. if (!dhdp || !dhdp->pktlog) {
  7071. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7072. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7073. return -EINVAL;
  7074. }
  7075. if (!dhdp->pktlog->pktlog_ring) {
  7076. DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
  7077. __FUNCTION__, dhdp->pktlog->pktlog_ring));
  7078. return -EINVAL;
  7079. }
  7080. atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
  7081. bytes_written = snprintf(command, total_len, "OK");
  7082. DHD_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
  7083. return bytes_written;
  7084. }
  7085. static int
  7086. wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
  7087. {
  7088. int bytes_written = 0;
  7089. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7090. dhd_pktlog_filter_t *filter;
  7091. uint32 id;
  7092. bool exist = FALSE;
  7093. if (!dhdp || !dhdp->pktlog) {
  7094. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7095. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7096. return -EINVAL;
  7097. }
  7098. filter = dhdp->pktlog->pktlog_filter;
  7099. if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
  7100. return BCME_ERROR;
  7101. }
  7102. exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
  7103. &id);
  7104. if (exist) {
  7105. bytes_written = snprintf(command, total_len, "TRUE");
  7106. DHD_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
  7107. } else {
  7108. bytes_written = snprintf(command, total_len, "FALSE");
  7109. DHD_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
  7110. }
  7111. return bytes_written;
  7112. }
  7113. static int
  7114. wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
  7115. {
  7116. int bytes_written = 0;
  7117. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7118. if (!dhdp || !dhdp->pktlog) {
  7119. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7120. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7121. return -EINVAL;
  7122. }
  7123. if (!dhdp->pktlog->pktlog_ring) {
  7124. DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
  7125. __FUNCTION__, dhdp->pktlog->pktlog_ring));
  7126. return -EINVAL;
  7127. }
  7128. dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
  7129. bytes_written = snprintf(command, total_len, "OK");
  7130. DHD_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
  7131. return bytes_written;
  7132. }
  7133. static int
  7134. wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
  7135. {
  7136. int bytes_written = 0;
  7137. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7138. if (!dhdp || !dhdp->pktlog) {
  7139. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7140. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7141. return -EINVAL;
  7142. }
  7143. if (!dhdp->pktlog->pktlog_ring) {
  7144. DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
  7145. __FUNCTION__, dhdp->pktlog->pktlog_ring));
  7146. return -EINVAL;
  7147. }
  7148. dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
  7149. bytes_written = snprintf(command, total_len, "OK");
  7150. DHD_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
  7151. return bytes_written;
  7152. }
  7153. static int
  7154. wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
  7155. {
  7156. int bytes_written = 0;
  7157. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7158. int err = BCME_OK;
  7159. int size;
  7160. if (!dhdp || !dhdp->pktlog) {
  7161. DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
  7162. __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
  7163. return -EINVAL;
  7164. }
  7165. if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
  7166. return BCME_ERROR;
  7167. }
  7168. size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
  7169. dhdp->pktlog->pktlog_ring =
  7170. dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
  7171. if (!dhdp->pktlog->pktlog_ring) {
  7172. err = BCME_ERROR;
  7173. }
  7174. if (err == BCME_OK) {
  7175. bytes_written = snprintf(command, total_len, "OK");
  7176. DHD_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
  7177. } else {
  7178. DHD_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
  7179. return BCME_ERROR;
  7180. }
  7181. return bytes_written;
  7182. }
  7183. #endif /* DHD_PKT_LOGGING */
  7184. #ifdef DHD_EVENT_LOG_FILTER
  7185. uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
  7186. #ifdef DHD_EWPR_VER2
  7187. uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
  7188. int index1, int index2, int index3);
  7189. #endif // endif
  7190. static int
  7191. wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
  7192. {
  7193. uint32 bytes_written = 0;
  7194. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7195. #ifdef DHD_EWPR_VER2
  7196. int index1 = 0, index2 = 0, index3 = 0;
  7197. unsigned char *index_str = (unsigned char *)(command +
  7198. strlen(CMD_EWP_FILTER) + 1);
  7199. #else
  7200. int type = 0;
  7201. #endif // endif
  7202. if (!dhdp || !command) {
  7203. DHD_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
  7204. return -EINVAL;
  7205. }
  7206. #ifdef DHD_EWPR_VER2
  7207. if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
  7208. sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
  7209. DHD_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
  7210. index1, index2, index3));
  7211. }
  7212. bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
  7213. &command[bytes_written], tot_len - bytes_written, index1, index2, index3);
  7214. #else
  7215. /* NEED TO GET TYPE if EXIST */
  7216. type = 0;
  7217. bytes_written += dhd_event_log_filter_serialize(dhdp,
  7218. &command[bytes_written], tot_len - bytes_written, type);
  7219. #endif // endif
  7220. return (int)bytes_written;
  7221. }
  7222. #endif /* DHD_EVENT_LOG_FILTER */
  7223. int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
  7224. {
  7225. #define PRIVATE_COMMAND_MAX_LEN 8192
  7226. #define PRIVATE_COMMAND_DEF_LEN 4096
  7227. int ret = 0;
  7228. char *command = NULL;
  7229. int bytes_written = 0;
  7230. android_wifi_priv_cmd priv_cmd;
  7231. int buf_size = 0;
  7232. struct bcm_cfg80211 *cfg = wl_get_cfg(net);
  7233. net_os_wake_lock(net);
  7234. if (!capable(CAP_NET_ADMIN)) {
  7235. ret = -EPERM;
  7236. goto exit;
  7237. }
  7238. if (!ifr->ifr_data) {
  7239. ret = -EINVAL;
  7240. goto exit;
  7241. }
  7242. {
  7243. if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
  7244. ret = -EFAULT;
  7245. goto exit;
  7246. }
  7247. }
  7248. if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
  7249. DHD_ERROR(("wl_android_priv_cmd: buf length invalid:%d\n",
  7250. priv_cmd.total_len));
  7251. ret = -EINVAL;
  7252. goto exit;
  7253. }
  7254. buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
  7255. command = (char *)MALLOC(cfg->osh, (buf_size + 1));
  7256. if (!command) {
  7257. DHD_ERROR(("wl_android_priv_cmd: failed to allocate memory\n"));
  7258. ret = -ENOMEM;
  7259. goto exit;
  7260. }
  7261. if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
  7262. ret = -EFAULT;
  7263. goto exit;
  7264. }
  7265. command[priv_cmd.total_len] = '\0';
  7266. DHD_ERROR(("wl_android_priv_cmd: Android private cmd \"%s\" on %s\n",
  7267. command, ifr->ifr_name));
  7268. bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
  7269. if (bytes_written >= 0) {
  7270. if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
  7271. command[0] = '\0';
  7272. }
  7273. if (bytes_written >= priv_cmd.total_len) {
  7274. DHD_ERROR(("wl_android_priv_cmd: err. bytes_written:%d >= total_len:%d,"
  7275. " buf_size:%d \n", bytes_written, priv_cmd.total_len, buf_size));
  7276. ret = BCME_BUFTOOSHORT;
  7277. goto exit;
  7278. }
  7279. bytes_written++;
  7280. priv_cmd.used_len = bytes_written;
  7281. if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
  7282. DHD_ERROR(("wl_android_priv_cmd: failed to copy data to user buffer\n"));
  7283. ret = -EFAULT;
  7284. }
  7285. }
  7286. else {
  7287. /* Propagate the error */
  7288. ret = bytes_written;
  7289. }
  7290. exit:
  7291. #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
  7292. if (ret) {
  7293. /* Avoid incrementing priv_cmd_errors in case of unsupported feature */
  7294. if (ret != BCME_UNSUPPORTED) {
  7295. wl_android_check_priv_cmd_errors(net);
  7296. }
  7297. } else {
  7298. priv_cmd_errors = 0;
  7299. }
  7300. #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
  7301. net_os_wake_unlock(net);
  7302. MFREE(cfg->osh, command, (buf_size + 1));
  7303. return ret;
  7304. }
  7305. #ifdef WLADPS_PRIVATE_CMD
  7306. static int
  7307. wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
  7308. {
  7309. int err = 0, adps_mode;
  7310. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
  7311. #ifdef DHD_PM_CONTROL_FROM_FILE
  7312. if (g_pm_control) {
  7313. return -EPERM;
  7314. }
  7315. #endif /* DHD_PM_CONTROL_FROM_FILE */
  7316. adps_mode = bcm_atoi(string_num);
  7317. WL_ERR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
  7318. if ((adps_mode < 0) && (1 < adps_mode)) {
  7319. WL_ERR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
  7320. return -EINVAL;
  7321. }
  7322. err = dhd_enable_adps(dhdp, adps_mode);
  7323. if (err != BCME_OK) {
  7324. WL_ERR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
  7325. return -EIO;
  7326. }
  7327. return err;
  7328. }
  7329. static int
  7330. wl_android_get_adps_mode(
  7331. struct net_device *dev, char *command, int total_len)
  7332. {
  7333. int bytes_written, err = 0;
  7334. uint len;
  7335. char buf[WLC_IOCTL_SMLEN];
  7336. bcm_iov_buf_t iov_buf;
  7337. bcm_iov_buf_t *ptr = NULL;
  7338. wl_adps_params_v1_t *data = NULL;
  7339. uint8 *pdata = NULL;
  7340. uint8 band, mode = 0;
  7341. bzero(&iov_buf, sizeof(iov_buf));
  7342. len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
  7343. iov_buf.version = WL_ADPS_IOV_VER;
  7344. iov_buf.len = sizeof(band);
  7345. iov_buf.id = WL_ADPS_IOV_MODE;
  7346. pdata = (uint8 *)&iov_buf.data;
  7347. for (band = 1; band <= MAX_BANDS; band++) {
  7348. pdata[0] = band;
  7349. err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
  7350. buf, WLC_IOCTL_SMLEN, NULL);
  7351. if (err != BCME_OK) {
  7352. WL_ERR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
  7353. band, err));
  7354. return -EIO;
  7355. }
  7356. ptr = (bcm_iov_buf_t *) buf;
  7357. data = (wl_adps_params_v1_t *) ptr->data;
  7358. mode = data->mode;
  7359. if (mode != OFF) {
  7360. break;
  7361. }
  7362. }
  7363. bytes_written = snprintf(command, total_len, "%s %d",
  7364. CMD_GET_ADPS, mode);
  7365. return bytes_written;
  7366. }
  7367. #endif /* WLADPS_PRIVATE_CMD */
  7368. #ifdef WL_BCNRECV
  7369. #define BCNRECV_ATTR_HDR_LEN 30
  7370. int
  7371. wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
  7372. uint status, uint reason, uint8 *data, uint data_len)
  7373. {
  7374. s32 err = BCME_OK;
  7375. struct sk_buff *skb;
  7376. gfp_t kflags;
  7377. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  7378. struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
  7379. uint len;
  7380. len = BCNRECV_ATTR_HDR_LEN + data_len;
  7381. kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  7382. skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
  7383. BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
  7384. if (!skb) {
  7385. WL_ERR(("skb alloc failed"));
  7386. return -ENOMEM;
  7387. }
  7388. if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
  7389. /* send bcn info to upper layer */
  7390. nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
  7391. } else if (attr_type == BCNRECV_ATTR_STATUS) {
  7392. nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
  7393. if (reason) {
  7394. nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
  7395. }
  7396. } else {
  7397. WL_ERR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
  7398. kfree_skb(skb);
  7399. return -EINVAL;
  7400. }
  7401. cfg80211_vendor_event(skb, kflags);
  7402. return err;
  7403. }
  7404. static int
  7405. _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
  7406. {
  7407. s32 err = BCME_OK;
  7408. /* check any scan is in progress before beacon recv scan trigger IOVAR */
  7409. if (wl_get_drv_status_all(cfg, SCANNING)) {
  7410. err = BCME_UNSUPPORTED;
  7411. WL_ERR(("Scan in progress, Aborting beacon recv start, "
  7412. "error:%d\n", err));
  7413. goto exit;
  7414. }
  7415. if (wl_get_p2p_status(cfg, SCANNING)) {
  7416. err = BCME_UNSUPPORTED;
  7417. WL_ERR(("P2P Scan in progress, Aborting beacon recv start, "
  7418. "error:%d\n", err));
  7419. goto exit;
  7420. }
  7421. if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
  7422. err = BCME_UNSUPPORTED;
  7423. WL_ERR(("P2P remain on channel, Aborting beacon recv start, "
  7424. "error:%d\n", err));
  7425. goto exit;
  7426. }
  7427. /* check STA is in connected state, Beacon recv required connected state
  7428. * else exit from beacon recv scan
  7429. */
  7430. if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
  7431. err = BCME_UNSUPPORTED;
  7432. WL_ERR(("STA is in not associated state error:%d\n", err));
  7433. goto exit;
  7434. }
  7435. #ifdef WL_NAN
  7436. /* Check NAN is enabled, if enabled exit else continue */
  7437. if (wl_cfgnan_check_state(cfg)) {
  7438. err = BCME_UNSUPPORTED;
  7439. WL_ERR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
  7440. goto exit;
  7441. }
  7442. #endif /* WL_NAN */
  7443. /* Triggering an sendup_bcn iovar */
  7444. err = wldev_iovar_setint(ndev, "sendup_bcn", 1);
  7445. if (unlikely(err)) {
  7446. WL_ERR(("sendup_bcn failed to set, error:%d\n", err));
  7447. } else {
  7448. cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
  7449. WL_INFORM_MEM(("bcnrecv started. user_trigger:%d\n", user_trigger));
  7450. if (user_trigger) {
  7451. if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS,
  7452. WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
  7453. WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
  7454. }
  7455. }
  7456. }
  7457. exit:
  7458. /*
  7459. * BCNRECV start request can be rejected from dongle
  7460. * in various conditions.
  7461. * Error code need to be overridden to BCME_UNSUPPORTED
  7462. * to avoid hang event from continous private
  7463. * command error
  7464. */
  7465. if (err) {
  7466. err = BCME_UNSUPPORTED;
  7467. }
  7468. return err;
  7469. }
  7470. int
  7471. _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
  7472. {
  7473. s32 err = BCME_OK;
  7474. u32 status;
  7475. /* Send sendup_bcn iovar for all cases except W_BCNRECV_ROAMABORT reason -
  7476. * fw generates roam abort event after aborting the bcnrecv.
  7477. */
  7478. if (reason != WL_BCNRECV_ROAMABORT) {
  7479. /* Triggering an sendup_bcn iovar */
  7480. err = wldev_iovar_setint(ndev, "sendup_bcn", 0);
  7481. if (unlikely(err)) {
  7482. WL_ERR(("sendup_bcn failed to set error:%d\n", err));
  7483. goto exit;
  7484. }
  7485. }
  7486. /* Send notification for all cases */
  7487. if (reason == WL_BCNRECV_SUSPEND) {
  7488. cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
  7489. status = WL_BCNRECV_SUSPENDED;
  7490. } else {
  7491. cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
  7492. WL_INFORM_MEM(("bcnrecv stopped\n"));
  7493. if (reason == WL_BCNRECV_USER_TRIGGER) {
  7494. status = WL_BCNRECV_STOPPED;
  7495. } else {
  7496. status = WL_BCNRECV_ABORTED;
  7497. }
  7498. }
  7499. if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS, status,
  7500. reason, NULL, 0)) != BCME_OK) {
  7501. WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
  7502. }
  7503. exit:
  7504. return err;
  7505. }
  7506. static int
  7507. wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
  7508. {
  7509. s32 err = BCME_OK;
  7510. /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
  7511. mutex_lock(&cfg->scan_sync);
  7512. mutex_lock(&cfg->bcn_sync);
  7513. err = _wl_android_bcnrecv_start(cfg, ndev, true);
  7514. mutex_unlock(&cfg->bcn_sync);
  7515. mutex_unlock(&cfg->scan_sync);
  7516. return err;
  7517. }
  7518. int
  7519. wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
  7520. {
  7521. s32 err = BCME_OK;
  7522. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  7523. mutex_lock(&cfg->bcn_sync);
  7524. if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
  7525. (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
  7526. err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
  7527. }
  7528. mutex_unlock(&cfg->bcn_sync);
  7529. return err;
  7530. }
  7531. int
  7532. wl_android_bcnrecv_suspend(struct net_device *ndev)
  7533. {
  7534. s32 ret = BCME_OK;
  7535. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  7536. mutex_lock(&cfg->bcn_sync);
  7537. if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
  7538. WL_INFORM_MEM(("bcnrecv suspend\n"));
  7539. ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
  7540. }
  7541. mutex_unlock(&cfg->bcn_sync);
  7542. return ret;
  7543. }
  7544. int
  7545. wl_android_bcnrecv_resume(struct net_device *ndev)
  7546. {
  7547. s32 ret = BCME_OK;
  7548. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  7549. /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
  7550. mutex_lock(&cfg->scan_sync);
  7551. mutex_lock(&cfg->bcn_sync);
  7552. if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
  7553. WL_INFORM_MEM(("bcnrecv resume\n"));
  7554. ret = _wl_android_bcnrecv_start(cfg, ndev, false);
  7555. }
  7556. mutex_unlock(&cfg->bcn_sync);
  7557. mutex_unlock(&cfg->scan_sync);
  7558. return ret;
  7559. }
  7560. /* Beacon recv functionality code implementation */
  7561. int
  7562. wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
  7563. {
  7564. struct bcm_cfg80211 *cfg = NULL;
  7565. uint err = BCME_OK;
  7566. if (!ndev) {
  7567. WL_ERR(("ndev is NULL\n"));
  7568. return -EINVAL;
  7569. }
  7570. cfg = wl_get_cfg(ndev);
  7571. if (!cfg) {
  7572. WL_ERR(("cfg is NULL\n"));
  7573. return -EINVAL;
  7574. }
  7575. /* sync commands from user space */
  7576. mutex_lock(&cfg->usr_sync);
  7577. if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
  7578. WL_INFORM(("BCNRECV start\n"));
  7579. err = wl_android_bcnrecv_start(cfg, ndev);
  7580. if (err != BCME_OK) {
  7581. WL_ERR(("Failed to process the start command, error:%d\n", err));
  7582. goto exit;
  7583. }
  7584. } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
  7585. WL_INFORM(("BCNRECV stop\n"));
  7586. err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
  7587. if (err != BCME_OK) {
  7588. WL_ERR(("Failed to stop the bcn recv, error:%d\n", err));
  7589. goto exit;
  7590. }
  7591. } else {
  7592. err = BCME_ERROR;
  7593. }
  7594. exit:
  7595. mutex_unlock(&cfg->usr_sync);
  7596. return err;
  7597. }
  7598. #endif /* WL_BCNRECV */
  7599. #ifdef WL_CAC_TS
  7600. /* CAC TSPEC functionality code implementation */
  7601. static void
  7602. wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
  7603. {
  7604. uint8 tspec_id;
  7605. /* Using direction as bidirectional by default */
  7606. uint8 direction = TSPEC_BI_DIRECTION;
  7607. /* Using U-APSD as the default power save mode */
  7608. uint8 user_psb = TSPEC_UAPSD_PSB;
  7609. uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
  7610. /* Map tspec_id from access category */
  7611. tspec_id = ADDTS_AC2PRIO[access_category];
  7612. /* Update the tsinfo */
  7613. tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
  7614. (tspec_id << TSPEC_TSINFO_TID_SHIFT));
  7615. tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
  7616. user_psb);
  7617. tspec_arg->tsinfo.octets[2] = 0x00;
  7618. }
  7619. static s32
  7620. wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
  7621. {
  7622. tspec_arg_t tspec_arg;
  7623. s32 err = BCME_ERROR;
  7624. u8 ts_cmd[12] = "cac_addts";
  7625. uint8 access_category;
  7626. s32 bssidx;
  7627. /* Following handling is done only for the primary interface */
  7628. memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
  7629. if (strncmp(argv, "addts", strlen("addts")) == 0) {
  7630. tspec_arg.version = TSPEC_ARG_VERSION;
  7631. tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
  7632. /* Read the params passed */
  7633. sscanf(argv, "%*s %hhu %hu %hu", &access_category,
  7634. &tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
  7635. if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
  7636. ((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
  7637. (tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
  7638. (tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
  7639. WL_ERR(("Invalid params access_category %hhu nom_msdu_size %hu"
  7640. " surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
  7641. tspec_arg.surplus_bw));
  7642. return BCME_USAGE_ERROR;
  7643. }
  7644. /* Update tsinfo */
  7645. wl_android_update_tsinfo(access_category, &tspec_arg);
  7646. /* Update other tspec parameters */
  7647. tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
  7648. tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
  7649. tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
  7650. } else if (strncmp(argv, "delts", strlen("delts")) == 0) {
  7651. snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
  7652. tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
  7653. tspec_arg.version = TSPEC_ARG_VERSION;
  7654. /* Read the params passed */
  7655. sscanf(argv, "%*s %hhu", &access_category);
  7656. if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
  7657. WL_INFORM_MEM(("Invalide param, access_category %hhu\n", access_category));
  7658. return BCME_USAGE_ERROR;
  7659. }
  7660. /* Update tsinfo */
  7661. wl_android_update_tsinfo(access_category, &tspec_arg);
  7662. }
  7663. if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
  7664. WL_ERR(("Find index failed\n"));
  7665. err = BCME_ERROR;
  7666. return err;
  7667. }
  7668. err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
  7669. cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
  7670. if (unlikely(err)) {
  7671. WL_ERR(("%s error (%d)\n", ts_cmd, err));
  7672. }
  7673. return err;
  7674. }
  7675. static s32
  7676. wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
  7677. {
  7678. struct bcm_cfg80211 *cfg = NULL;
  7679. s32 err = BCME_OK;
  7680. if (!ndev) {
  7681. WL_ERR(("ndev is NULL\n"));
  7682. return -EINVAL;
  7683. }
  7684. cfg = wl_get_cfg(ndev);
  7685. if (!cfg) {
  7686. WL_ERR(("cfg is NULL\n"));
  7687. return -EINVAL;
  7688. }
  7689. /* Request supported only for primary interface */
  7690. if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
  7691. WL_ERR(("Request on non-primary interface\n"));
  7692. return -1;
  7693. }
  7694. /* sync commands from user space */
  7695. mutex_lock(&cfg->usr_sync);
  7696. err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
  7697. mutex_unlock(&cfg->usr_sync);
  7698. return err;
  7699. }
  7700. #endif /* WL_CAC_TS */
  7701. #ifdef WL_GET_CU
  7702. /* Implementation to get channel usage from framework */
  7703. static s32
  7704. wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
  7705. {
  7706. s32 bytes_written, err = 0;
  7707. wl_bssload_t bssload;
  7708. u8 smbuf[WLC_IOCTL_SMLEN];
  7709. u8 chan_use_percentage = 0;
  7710. if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
  7711. 0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
  7712. WL_ERR(("Getting bssload report failed with err=%d \n", err));
  7713. return err;
  7714. }
  7715. (void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
  7716. /* Convert channel usage to percentage value */
  7717. chan_use_percentage = (bssload.chan_util * 100) / 255;
  7718. bytes_written = snprintf(command, total_len, "CU %hhu",
  7719. chan_use_percentage);
  7720. WL_DBG(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
  7721. return bytes_written;
  7722. }
  7723. #endif /* WL_GET_CU */
  7724. int
  7725. wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
  7726. {
  7727. int bytes_written = 0;
  7728. android_wifi_priv_cmd priv_cmd;
  7729. bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
  7730. priv_cmd.total_len = cmd_len;
  7731. if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
  7732. DHD_INFO(("wl_handle_private_cmd, Received regular START command\n"));
  7733. #ifdef SUPPORT_DEEP_SLEEP
  7734. trigger_deep_sleep = 1;
  7735. #else
  7736. #ifdef BT_OVER_SDIO
  7737. bytes_written = dhd_net_bus_get(net);
  7738. #else
  7739. bytes_written = wl_android_wifi_on(net);
  7740. #endif /* BT_OVER_SDIO */
  7741. #endif /* SUPPORT_DEEP_SLEEP */
  7742. }
  7743. else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
  7744. bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
  7745. }
  7746. if (!g_wifi_on) {
  7747. DHD_ERROR(("wl_handle_private_cmd: Ignore private cmd \"%s\" - iface is down\n",
  7748. command));
  7749. return 0;
  7750. }
  7751. if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
  7752. #ifdef SUPPORT_DEEP_SLEEP
  7753. trigger_deep_sleep = 1;
  7754. #else
  7755. #ifdef BT_OVER_SDIO
  7756. bytes_written = dhd_net_bus_put(net);
  7757. #else
  7758. bytes_written = wl_android_wifi_off(net, FALSE);
  7759. #endif /* BT_OVER_SDIO */
  7760. #endif /* SUPPORT_DEEP_SLEEP */
  7761. }
  7762. else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
  7763. wl_cfg80211_set_passive_scan(net, command);
  7764. }
  7765. else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
  7766. wl_cfg80211_set_passive_scan(net, command);
  7767. }
  7768. else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
  7769. bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
  7770. }
  7771. else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
  7772. bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
  7773. }
  7774. #ifdef PKT_FILTER_SUPPORT
  7775. else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
  7776. bytes_written = net_os_enable_packet_filter(net, 1);
  7777. }
  7778. else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
  7779. bytes_written = net_os_enable_packet_filter(net, 0);
  7780. }
  7781. else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
  7782. int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
  7783. bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
  7784. }
  7785. else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
  7786. int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
  7787. bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
  7788. }
  7789. #endif /* PKT_FILTER_SUPPORT */
  7790. else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
  7791. /* TBD: BTCOEXSCAN-START */
  7792. }
  7793. else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
  7794. /* TBD: BTCOEXSCAN-STOP */
  7795. }
  7796. else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
  7797. #ifdef WL_CFG80211
  7798. void *dhdp = wl_cfg80211_get_dhdp(net);
  7799. bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
  7800. #else
  7801. #ifdef PKT_FILTER_SUPPORT
  7802. uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
  7803. if (mode == 1)
  7804. net_os_enable_packet_filter(net, 0); /* DHCP starts */
  7805. else
  7806. net_os_enable_packet_filter(net, 1); /* DHCP ends */
  7807. #endif /* PKT_FILTER_SUPPORT */
  7808. #endif /* WL_CFG80211 */
  7809. }
  7810. else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
  7811. bytes_written = wl_android_set_suspendopt(net, command);
  7812. }
  7813. else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
  7814. bytes_written = wl_android_set_suspendmode(net, command);
  7815. }
  7816. else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
  7817. bytes_written = wl_android_set_bcn_li_dtim(net, command);
  7818. }
  7819. else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
  7820. bytes_written = wl_android_set_max_dtim(net, command);
  7821. }
  7822. #ifdef DISABLE_DTIM_IN_SUSPEND
  7823. else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
  7824. bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
  7825. }
  7826. #endif /* DISABLE_DTIM_IN_SUSPEND */
  7827. else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
  7828. bytes_written = wl_android_set_band(net, command);
  7829. }
  7830. else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
  7831. bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
  7832. }
  7833. else if (strnicmp(command, CMD_ADDIE, strlen(CMD_ADDIE)) == 0) {
  7834. bytes_written = wl_android_add_vendor_ie(net, command, priv_cmd.total_len);
  7835. }
  7836. else if (strnicmp(command, CMD_DELIE, strlen(CMD_DELIE)) == 0) {
  7837. bytes_written = wl_android_del_vendor_ie(net, command, priv_cmd.total_len);
  7838. }
  7839. #ifdef WL_CFG80211
  7840. #ifndef CUSTOMER_SET_COUNTRY
  7841. /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
  7842. else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
  7843. /*
  7844. * Usage examples:
  7845. * DRIVER COUNTRY US
  7846. * DRIVER COUNTRY US/7
  7847. */
  7848. char *country_code = command + strlen(CMD_COUNTRY) + 1;
  7849. char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
  7850. int revinfo = -1;
  7851. #if defined(DHD_BLOB_EXISTENCE_CHECK)
  7852. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
  7853. if (dhdp->is_blob) {
  7854. revinfo = 0;
  7855. } else
  7856. #endif /* DHD_BLOB_EXISTENCE_CHECK */
  7857. if ((rev_info_delim) &&
  7858. (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
  7859. strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
  7860. (rev_info_delim + 1)) {
  7861. revinfo = bcm_atoi(rev_info_delim + 1);
  7862. }
  7863. bytes_written = wl_cfg80211_set_country_code(net, country_code,
  7864. true, true, revinfo);
  7865. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  7866. #ifdef FCC_PWR_LIMIT_2G
  7867. if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
  7868. DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
  7869. } else {
  7870. DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
  7871. }
  7872. #endif /* FCC_PWR_LIMIT_2G */
  7873. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  7874. }
  7875. #endif /* CUSTOMER_SET_COUNTRY */
  7876. #endif /* WL_CFG80211 */
  7877. else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
  7878. bytes_written = wl_android_set_csa(net, command);
  7879. } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
  7880. bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
  7881. } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
  7882. bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
  7883. } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
  7884. bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
  7885. } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
  7886. bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
  7887. } else if (strnicmp(command, CMD_RSDB_MODE, strlen(CMD_RSDB_MODE)) == 0) {
  7888. bytes_written = wl_android_get_rsdb_mode(net, command, priv_cmd.total_len);
  7889. }
  7890. #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
  7891. #ifdef ROAM_API
  7892. else if (strnicmp(command, CMD_ROAMTRIGGER_SET,
  7893. strlen(CMD_ROAMTRIGGER_SET)) == 0) {
  7894. bytes_written = wl_android_set_roam_trigger(net, command);
  7895. } else if (strnicmp(command, CMD_ROAMTRIGGER_GET,
  7896. strlen(CMD_ROAMTRIGGER_GET)) == 0) {
  7897. bytes_written = wl_android_get_roam_trigger(net, command,
  7898. priv_cmd.total_len);
  7899. } else if (strnicmp(command, CMD_ROAMDELTA_SET,
  7900. strlen(CMD_ROAMDELTA_SET)) == 0) {
  7901. bytes_written = wl_android_set_roam_delta(net, command);
  7902. } else if (strnicmp(command, CMD_ROAMDELTA_GET,
  7903. strlen(CMD_ROAMDELTA_GET)) == 0) {
  7904. bytes_written = wl_android_get_roam_delta(net, command,
  7905. priv_cmd.total_len);
  7906. } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
  7907. strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
  7908. bytes_written = wl_android_set_roam_scan_period(net, command);
  7909. } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
  7910. strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
  7911. bytes_written = wl_android_get_roam_scan_period(net, command,
  7912. priv_cmd.total_len);
  7913. } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
  7914. strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
  7915. bytes_written = wl_android_set_full_roam_scan_period(net, command,
  7916. priv_cmd.total_len);
  7917. } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
  7918. strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
  7919. bytes_written = wl_android_get_full_roam_scan_period(net, command,
  7920. priv_cmd.total_len);
  7921. } else if (strnicmp(command, CMD_COUNTRYREV_SET,
  7922. strlen(CMD_COUNTRYREV_SET)) == 0) {
  7923. bytes_written = wl_android_set_country_rev(net, command);
  7924. #ifdef FCC_PWR_LIMIT_2G
  7925. if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
  7926. DHD_ERROR(("wl_handle_private_cmd: fccpwrlimit2g"
  7927. " deactivation is failed\n"));
  7928. } else {
  7929. DHD_ERROR(("wl_handle_private_cmd: fccpwrlimit2g is deactivated\n"));
  7930. }
  7931. #endif /* FCC_PWR_LIMIT_2G */
  7932. } else if (strnicmp(command, CMD_COUNTRYREV_GET,
  7933. strlen(CMD_COUNTRYREV_GET)) == 0) {
  7934. bytes_written = wl_android_get_country_rev(net, command,
  7935. priv_cmd.total_len);
  7936. }
  7937. #endif /* ROAM_API */
  7938. #ifdef WES_SUPPORT
  7939. else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
  7940. bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len);
  7941. }
  7942. else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
  7943. bytes_written = wl_android_set_roam_scan_control(net, command);
  7944. }
  7945. else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
  7946. bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len);
  7947. }
  7948. else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
  7949. bytes_written = wl_android_set_roam_scan_channels(net, command);
  7950. }
  7951. else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
  7952. bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len);
  7953. }
  7954. else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
  7955. bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len);
  7956. }
  7957. else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
  7958. bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len);
  7959. }
  7960. else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
  7961. bytes_written = wl_android_set_scan_channel_time(net, command);
  7962. }
  7963. else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
  7964. bytes_written = wl_android_get_scan_unassoc_time(net, command, priv_cmd.total_len);
  7965. }
  7966. else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
  7967. bytes_written = wl_android_set_scan_unassoc_time(net, command);
  7968. }
  7969. else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
  7970. bytes_written = wl_android_get_scan_passive_time(net, command, priv_cmd.total_len);
  7971. }
  7972. else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
  7973. bytes_written = wl_android_set_scan_passive_time(net, command);
  7974. }
  7975. else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
  7976. bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len);
  7977. }
  7978. else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
  7979. bytes_written = wl_android_set_scan_home_time(net, command);
  7980. }
  7981. else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
  7982. bytes_written = wl_android_get_scan_home_away_time(net, command,
  7983. priv_cmd.total_len);
  7984. }
  7985. else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
  7986. bytes_written = wl_android_set_scan_home_away_time(net, command);
  7987. }
  7988. else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
  7989. bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len);
  7990. }
  7991. else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
  7992. bytes_written = wl_android_set_scan_nprobes(net, command);
  7993. }
  7994. else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
  7995. bytes_written = wl_android_get_scan_dfs_channel_mode(net, command,
  7996. priv_cmd.total_len);
  7997. }
  7998. else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
  7999. bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
  8000. }
  8001. else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
  8002. bytes_written = wl_android_set_join_prefer(net, command);
  8003. }
  8004. else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
  8005. bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len);
  8006. }
  8007. else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
  8008. bytes_written = wl_android_set_wes_mode(net, command);
  8009. }
  8010. else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) {
  8011. bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len);
  8012. }
  8013. else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) {
  8014. bytes_written = wl_android_set_okc_mode(net, command);
  8015. }
  8016. else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
  8017. bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
  8018. }
  8019. else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
  8020. bytes_written = wl_android_okc_enable(net, command);
  8021. }
  8022. #endif /* WES_SUPPORT */
  8023. #ifdef SUPPORT_RESTORE_SCAN_PARAMS
  8024. else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
  8025. bytes_written = wl_android_restore_scan_params(net, command, priv_cmd.total_len);
  8026. }
  8027. #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
  8028. #ifdef WLTDLS
  8029. else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
  8030. bytes_written = wl_android_tdls_reset(net);
  8031. }
  8032. #endif /* WLTDLS */
  8033. #ifdef CONFIG_SILENT_ROAM
  8034. else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
  8035. int skip = strlen(CMD_SROAM_TURN_ON) + 1;
  8036. bytes_written = wl_android_sroam_turn_on(net, (const char*)command+skip);
  8037. }
  8038. else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
  8039. char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
  8040. bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
  8041. }
  8042. else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
  8043. bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
  8044. }
  8045. #endif /* CONFIG_SILENT_ROAM */
  8046. else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
  8047. bytes_written = wl_android_set_disconnect_ies(net, command);
  8048. }
  8049. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  8050. #ifdef PNO_SUPPORT
  8051. else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
  8052. bytes_written = dhd_dev_pno_stop_for_ssid(net);
  8053. }
  8054. #ifndef WL_SCHED_SCAN
  8055. else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
  8056. bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
  8057. }
  8058. #endif /* !WL_SCHED_SCAN */
  8059. else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
  8060. int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
  8061. bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
  8062. }
  8063. else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
  8064. bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
  8065. }
  8066. #endif /* PNO_SUPPORT */
  8067. else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
  8068. bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
  8069. }
  8070. else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
  8071. int skip = strlen(CMD_P2P_SET_NOA) + 1;
  8072. bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
  8073. priv_cmd.total_len - skip);
  8074. }
  8075. #ifdef P2P_LISTEN_OFFLOADING
  8076. else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
  8077. u8 *sub_command = strchr(command, ' ');
  8078. bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
  8079. sub_command ? strlen(sub_command) : 0);
  8080. }
  8081. #endif /* P2P_LISTEN_OFFLOADING */
  8082. #if !defined WL_ENABLE_P2P_IF
  8083. else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
  8084. bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
  8085. }
  8086. #endif /* WL_ENABLE_P2P_IF */
  8087. else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
  8088. int skip = strlen(CMD_P2P_SET_PS) + 1;
  8089. bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
  8090. priv_cmd.total_len - skip);
  8091. }
  8092. else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
  8093. int skip = strlen(CMD_P2P_ECSA) + 1;
  8094. bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
  8095. priv_cmd.total_len - skip);
  8096. }
  8097. else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
  8098. int skip = strlen(CMD_P2P_INC_BW) + 1;
  8099. bytes_written = wl_cfg80211_increase_p2p_bw(net,
  8100. command + skip, priv_cmd.total_len - skip);
  8101. }
  8102. #ifdef WL_CFG80211
  8103. else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
  8104. strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
  8105. int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
  8106. bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
  8107. priv_cmd.total_len - skip, *(command + skip - 2) - '0');
  8108. }
  8109. #ifdef WLFBT
  8110. else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
  8111. bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
  8112. }
  8113. #endif /* WLFBT */
  8114. #endif /* WL_CFG80211 */
  8115. #if defined(WL_SUPPORT_AUTO_CHANNEL)
  8116. else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
  8117. strlen(CMD_GET_BEST_CHANNELS)) == 0) {
  8118. bytes_written = wl_cfg80211_get_best_channels(net, command,
  8119. priv_cmd.total_len);
  8120. }
  8121. #endif /* WL_SUPPORT_AUTO_CHANNEL */
  8122. #if defined(WL_SUPPORT_AUTO_CHANNEL)
  8123. else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
  8124. strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
  8125. int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
  8126. bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
  8127. priv_cmd.total_len);
  8128. }
  8129. #endif /* WL_SUPPORT_AUTO_CHANNEL */
  8130. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  8131. #ifdef SUPPORT_AMPDU_MPDU_CMD
  8132. /* CMD_AMPDU_MPDU */
  8133. else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
  8134. int skip = strlen(CMD_AMPDU_MPDU) + 1;
  8135. bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
  8136. }
  8137. #endif /* SUPPORT_AMPDU_MPDU_CMD */
  8138. #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
  8139. else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
  8140. strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
  8141. int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
  8142. wl_android_sta_diassoc(net, (const char*)command+skip);
  8143. }
  8144. #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
  8145. #ifdef SUPPORT_SET_LPC
  8146. else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
  8147. strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
  8148. int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
  8149. wl_android_set_lpc(net, (const char*)command+skip);
  8150. }
  8151. #endif /* SUPPORT_SET_LPC */
  8152. #ifdef SUPPORT_TRIGGER_HANG_EVENT
  8153. else if (strnicmp(command, CMD_TEST_FORCE_HANG,
  8154. strlen(CMD_TEST_FORCE_HANG)) == 0) {
  8155. int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
  8156. net_os_send_hang_message_reason(net, (const char*)command+skip);
  8157. }
  8158. #endif /* SUPPORT_TRIGGER_HANG_EVENT */
  8159. else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
  8160. bytes_written = wl_android_ch_res_rl(net, true);
  8161. else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
  8162. bytes_written = wl_android_ch_res_rl(net, false);
  8163. #ifdef SUPPORT_LTECX
  8164. else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
  8165. int skip = strlen(CMD_LTECX_SET) + 1;
  8166. bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
  8167. }
  8168. #endif /* SUPPORT_LTECX */
  8169. #ifdef WL_RELMCAST
  8170. else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
  8171. int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
  8172. bytes_written = wl_android_rmc_enable(net, rmc_enable);
  8173. }
  8174. else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
  8175. int rmc_txrate;
  8176. sscanf(command, "%*s %10d", &rmc_txrate);
  8177. bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
  8178. }
  8179. else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
  8180. int actperiod;
  8181. sscanf(command, "%*s %10d", &actperiod);
  8182. bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
  8183. }
  8184. else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
  8185. int acktimeout;
  8186. sscanf(command, "%*s %10d", &acktimeout);
  8187. acktimeout *= 1000;
  8188. bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
  8189. }
  8190. else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
  8191. int skip = strlen(CMD_SET_RMC_LEADER) + 1;
  8192. bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
  8193. }
  8194. else if (strnicmp(command, CMD_SET_RMC_EVENT,
  8195. strlen(CMD_SET_RMC_EVENT)) == 0) {
  8196. bytes_written = wl_android_set_rmc_event(net, command);
  8197. }
  8198. #endif /* WL_RELMCAST */
  8199. else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
  8200. bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
  8201. }
  8202. else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
  8203. bytes_written = wl_android_set_singlecore_scan(net, command);
  8204. }
  8205. #ifdef TEST_TX_POWER_CONTROL
  8206. else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
  8207. strlen(CMD_TEST_SET_TX_POWER)) == 0) {
  8208. int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
  8209. wl_android_set_tx_power(net, (const char*)command+skip);
  8210. }
  8211. else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
  8212. strlen(CMD_TEST_GET_TX_POWER)) == 0) {
  8213. wl_android_get_tx_power(net, command, priv_cmd.total_len);
  8214. }
  8215. #endif /* TEST_TX_POWER_CONTROL */
  8216. else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
  8217. strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
  8218. int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
  8219. bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
  8220. }
  8221. #ifdef SUPPORT_SET_TID
  8222. else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
  8223. bytes_written = wl_android_set_tid(net, command);
  8224. }
  8225. else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
  8226. bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
  8227. }
  8228. #endif /* SUPPORT_SET_TID */
  8229. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  8230. #if defined(SUPPORT_HIDDEN_AP)
  8231. else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
  8232. strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
  8233. int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
  8234. wl_android_set_max_num_sta(net, (const char*)command+skip);
  8235. }
  8236. else if (strnicmp(command, CMD_SET_HAPD_SSID,
  8237. strlen(CMD_SET_HAPD_SSID)) == 0) {
  8238. int skip = strlen(CMD_SET_HAPD_SSID) + 3;
  8239. wl_android_set_ssid(net, (const char*)command+skip);
  8240. }
  8241. else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
  8242. strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
  8243. int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 1;
  8244. wl_android_set_hide_ssid(net, (const char*)(command+skip));
  8245. }
  8246. #endif /* SUPPORT_HIDDEN_AP */
  8247. else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
  8248. int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
  8249. wl_android_set_mac_address_filter(net, command+skip);
  8250. }
  8251. else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
  8252. bytes_written = wl_android_set_roam_mode(net, command);
  8253. #if defined(BCMFW_ROAM_ENABLE)
  8254. else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
  8255. bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
  8256. }
  8257. #endif /* BCMFW_ROAM_ENABLE */
  8258. else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
  8259. bytes_written = wl_android_set_miracast(net, command);
  8260. else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
  8261. bytes_written = wl_android_set_ibss_beacon_ouidata(net,
  8262. command, priv_cmd.total_len);
  8263. #ifdef WLAIBSS
  8264. else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
  8265. strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
  8266. bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
  8267. else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
  8268. strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
  8269. bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
  8270. TRUE);
  8271. else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
  8272. strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
  8273. bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
  8274. FALSE);
  8275. else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
  8276. strlen(CMD_SETIBSSROUTETABLE)) == 0)
  8277. bytes_written = wl_android_set_ibss_routetable(net, command);
  8278. else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
  8279. bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
  8280. else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
  8281. bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
  8282. #endif /* WLAIBSS */
  8283. else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
  8284. int skip = strlen(CMD_KEEP_ALIVE) + 1;
  8285. bytes_written = wl_keep_alive_set(net, command + skip);
  8286. }
  8287. else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
  8288. int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
  8289. bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
  8290. }
  8291. else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
  8292. char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
  8293. WL_INFORM(("Creating %s interface\n", name));
  8294. if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
  8295. name, NULL) == NULL) {
  8296. bytes_written = -ENODEV;
  8297. } else {
  8298. /* Return success */
  8299. bytes_written = 0;
  8300. }
  8301. }
  8302. else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
  8303. char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
  8304. WL_INFORM(("Deleteing %s interface\n", name));
  8305. bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
  8306. }
  8307. else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
  8308. bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
  8309. }
  8310. #ifdef P2PRESP_WFDIE_SRC
  8311. else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
  8312. strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
  8313. int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
  8314. bytes_written = wl_android_set_wfdie_resp(net, mode);
  8315. } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
  8316. strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
  8317. bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
  8318. }
  8319. #endif /* P2PRESP_WFDIE_SRC */
  8320. else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
  8321. char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
  8322. bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
  8323. }
  8324. #ifdef WBTEXT
  8325. else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
  8326. bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
  8327. }
  8328. else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
  8329. strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
  8330. char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
  8331. bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
  8332. }
  8333. else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
  8334. strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
  8335. char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  8336. bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
  8337. command, priv_cmd.total_len);
  8338. }
  8339. else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
  8340. strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
  8341. char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
  8342. bytes_written = wl_cfg80211_wbtext_table_config(net, data,
  8343. command, priv_cmd.total_len);
  8344. }
  8345. else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
  8346. strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
  8347. char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
  8348. bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
  8349. command, priv_cmd.total_len);
  8350. }
  8351. else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
  8352. strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
  8353. bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
  8354. priv_cmd.total_len);
  8355. }
  8356. else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
  8357. strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
  8358. bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
  8359. priv_cmd.total_len);
  8360. }
  8361. else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
  8362. strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
  8363. bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
  8364. priv_cmd.total_len);
  8365. }
  8366. #endif /* WBTEXT */
  8367. #ifdef SET_RPS_CPUS
  8368. else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
  8369. bytes_written = wl_android_set_rps_cpus(net, command);
  8370. }
  8371. #endif /* SET_RPS_CPUS */
  8372. #ifdef WLWFDS
  8373. else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
  8374. bytes_written = wl_android_set_wfds_hash(net, command, 1);
  8375. }
  8376. else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
  8377. bytes_written = wl_android_set_wfds_hash(net, command, 0);
  8378. }
  8379. #endif /* WLWFDS */
  8380. #ifdef BT_WIFI_HANDOVER
  8381. else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
  8382. bytes_written = wl_tbow_teardown(net);
  8383. }
  8384. #endif /* BT_WIFI_HANDOVER */
  8385. #ifdef CUSTOMER_HW4_PRIVATE_CMD
  8386. #ifdef FCC_PWR_LIMIT_2G
  8387. else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
  8388. strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
  8389. bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
  8390. }
  8391. else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
  8392. strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
  8393. bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
  8394. }
  8395. #endif /* FCC_PWR_LIMIT_2G */
  8396. else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
  8397. bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
  8398. }
  8399. #endif /* CUSTOMER_HW4_PRIVATE_CMD */
  8400. else if (strnicmp(command, CMD_MURX_BFE_CAP,
  8401. strlen(CMD_MURX_BFE_CAP)) == 0) {
  8402. #ifdef WL_MURX
  8403. uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
  8404. bytes_written = wl_android_murx_bfe_cap(net, val);
  8405. #else
  8406. return BCME_UNSUPPORTED;
  8407. #endif /* WL_MURX */
  8408. }
  8409. #ifdef SUPPORT_AP_HIGHER_BEACONRATE
  8410. else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
  8411. bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
  8412. }
  8413. else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
  8414. bytes_written = wl_android_set_ap_beaconrate(net, command);
  8415. }
  8416. #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
  8417. #ifdef SUPPORT_AP_RADIO_PWRSAVE
  8418. else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
  8419. bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
  8420. }
  8421. else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
  8422. bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
  8423. }
  8424. else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
  8425. bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
  8426. }
  8427. #endif /* SUPPORT_AP_RADIO_PWRSAVE */
  8428. #ifdef SUPPORT_RSSI_SUM_REPORT
  8429. else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
  8430. bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
  8431. }
  8432. else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
  8433. bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
  8434. }
  8435. else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
  8436. bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
  8437. }
  8438. #endif /* SUPPORT_RSSI_SUM_REPORT */
  8439. #if defined(DHD_ENABLE_BIGDATA_LOGGING)
  8440. else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
  8441. bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
  8442. }
  8443. else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
  8444. == 0) {
  8445. bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
  8446. priv_cmd.total_len);
  8447. }
  8448. #endif /* DHD_ENABLE_BIGDATA_LOGGING */
  8449. #if defined(SUPPORT_RANDOM_MAC_SCAN)
  8450. else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
  8451. bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
  8452. } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
  8453. bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
  8454. }
  8455. #endif /* SUPPORT_RANDOM_MAC_SCAN */
  8456. #ifdef DHD_BANDSTEER
  8457. else if (strnicmp(command, CMD_BANDSTEER, strlen(CMD_BANDSTEER)) == 0) {
  8458. bytes_written = wl_android_set_bandsteer(net, command, priv_cmd.total_len);
  8459. }
  8460. else if (strnicmp(command, CMD_BANDSTEER_TRIGGER, strlen(CMD_BANDSTEER_TRIGGER)) == 0) {
  8461. uint8 *p = command + strlen(CMD_BANDSTEER_TRIGGER)+1;
  8462. struct ether_addr ea;
  8463. char eabuf[ETHER_ADDR_STR_LEN];
  8464. bytes_written = 0;
  8465. bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
  8466. strncpy(eabuf, p, ETHER_ADDR_STR_LEN - 1);
  8467. if (!bcm_ether_atoe(eabuf, &ea)) {
  8468. DHD_ERROR(("BANDSTEER: ERROR while parsing macaddr cmd %s - ignored\n",
  8469. command));
  8470. return BCME_BADARG;
  8471. }
  8472. bytes_written = dhd_bandsteer_trigger_bandsteer(net, ea.octet);
  8473. }
  8474. #endif /* DHD_BANDSTEER */
  8475. #ifdef WL_NATOE
  8476. else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
  8477. bytes_written = wl_android_process_natoe_cmd(net, command,
  8478. priv_cmd.total_len);
  8479. }
  8480. #endif /* WL_NATOE */
  8481. #ifdef CONNECTION_STATISTICS
  8482. else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
  8483. strlen(CMD_GET_CONNECTION_STATS)) == 0) {
  8484. bytes_written = wl_android_get_connection_stats(net, command,
  8485. priv_cmd.total_len);
  8486. }
  8487. #endif // endif
  8488. #ifdef DHD_LOG_DUMP
  8489. else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
  8490. strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
  8491. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
  8492. /* check whether it has more command */
  8493. if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
  8494. /* compare unwanted/disconnected command */
  8495. if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
  8496. SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
  8497. dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
  8498. } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
  8499. SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
  8500. dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
  8501. } else {
  8502. dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
  8503. }
  8504. } else {
  8505. dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
  8506. }
  8507. }
  8508. #endif /* DHD_LOG_DUMP */
  8509. #ifdef DHD_STATUS_LOGGING
  8510. else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
  8511. dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
  8512. }
  8513. else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
  8514. dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
  8515. bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
  8516. }
  8517. #endif /* DHD_STATUS_LOGGING */
  8518. #ifdef SET_PCIE_IRQ_CPU_CORE
  8519. else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
  8520. int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
  8521. wl_android_set_irq_cpucore(net, affinity_cmd);
  8522. }
  8523. #endif /* SET_PCIE_IRQ_CPU_CORE */
  8524. #if defined(DHD_HANG_SEND_UP_TEST)
  8525. else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
  8526. int skip = strlen(CMD_MAKE_HANG) + 1;
  8527. wl_android_make_hang_with_reason(net, (const char*)command+skip);
  8528. }
  8529. #endif /* DHD_HANG_SEND_UP_TEST */
  8530. #ifdef SUPPORT_LQCM
  8531. else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
  8532. int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
  8533. bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
  8534. }
  8535. else if (strnicmp(command, CMD_GET_LQCM_REPORT,
  8536. strlen(CMD_GET_LQCM_REPORT)) == 0) {
  8537. bytes_written = wl_android_get_lqcm_report(net, command,
  8538. priv_cmd.total_len);
  8539. }
  8540. #endif // endif
  8541. else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
  8542. bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
  8543. }
  8544. #ifdef WLADPS_PRIVATE_CMD
  8545. else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
  8546. int skip = strlen(CMD_SET_ADPS) + 1;
  8547. bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
  8548. }
  8549. else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
  8550. bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
  8551. }
  8552. #endif /* WLADPS_PRIVATE_CMD */
  8553. #ifdef DHD_PKT_LOGGING
  8554. else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
  8555. strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
  8556. bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
  8557. }
  8558. else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
  8559. strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
  8560. bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
  8561. }
  8562. else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
  8563. strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
  8564. bytes_written =
  8565. wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
  8566. }
  8567. else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
  8568. strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
  8569. bytes_written =
  8570. wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
  8571. }
  8572. else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
  8573. bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
  8574. }
  8575. else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
  8576. bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
  8577. }
  8578. else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
  8579. bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
  8580. }
  8581. else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
  8582. bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
  8583. }
  8584. else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
  8585. bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
  8586. }
  8587. else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
  8588. bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
  8589. }
  8590. else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
  8591. strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
  8592. bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
  8593. }
  8594. else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
  8595. strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
  8596. bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
  8597. }
  8598. else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
  8599. strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
  8600. bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
  8601. }
  8602. #endif /* DHD_PKT_LOGGING */
  8603. else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
  8604. int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
  8605. bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
  8606. }
  8607. #ifdef DHD_EVENT_LOG_FILTER
  8608. else if (strnicmp(command, CMD_EWP_FILTER,
  8609. strlen(CMD_EWP_FILTER)) == 0) {
  8610. bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
  8611. }
  8612. #endif /* DHD_EVENT_LOG_FILTER */
  8613. #ifdef WL_BCNRECV
  8614. else if (strnicmp(command, CMD_BEACON_RECV,
  8615. strlen(CMD_BEACON_RECV)) == 0) {
  8616. char *data = (command + strlen(CMD_BEACON_RECV) + 1);
  8617. bytes_written = wl_android_bcnrecv_config(net,
  8618. data, priv_cmd.total_len);
  8619. }
  8620. #endif /* WL_BCNRECV */
  8621. #ifdef WL_MBO
  8622. else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
  8623. bytes_written = wl_android_process_mbo_cmd(net, command,
  8624. priv_cmd.total_len);
  8625. }
  8626. #endif /* WL_MBO */
  8627. #ifdef WL_CAC_TS
  8628. else if (strnicmp(command, CMD_CAC_TSPEC,
  8629. strlen(CMD_CAC_TSPEC)) == 0) {
  8630. char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
  8631. bytes_written = wl_android_cac_ts_config(net,
  8632. data, priv_cmd.total_len);
  8633. }
  8634. #endif /* WL_CAC_TS */
  8635. #ifdef WL_GET_CU
  8636. else if (strnicmp(command, CMD_GET_CHAN_UTIL,
  8637. strlen(CMD_GET_CHAN_UTIL)) == 0) {
  8638. bytes_written = wl_android_get_channel_util(net,
  8639. command, priv_cmd.total_len);
  8640. }
  8641. #endif /* WL_GET_CU */
  8642. else if (strnicmp(command, CMD_CHANNEL_WIDTH, strlen(CMD_CHANNEL_WIDTH)) == 0) {
  8643. bytes_written = wl_android_set_channel_width(net, command, priv_cmd.total_len);
  8644. }
  8645. else {
  8646. DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
  8647. bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
  8648. }
  8649. return bytes_written;
  8650. }
  8651. int wl_android_init(void)
  8652. {
  8653. int ret = 0;
  8654. #ifdef ENABLE_INSMOD_NO_FW_LOAD
  8655. dhd_download_fw_on_driverload = FALSE;
  8656. #endif /* ENABLE_INSMOD_NO_FW_LOAD */
  8657. if (!iface_name[0]) {
  8658. bzero(iface_name, IFNAMSIZ);
  8659. bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
  8660. }
  8661. #ifdef CUSTOMER_HW4_DEBUG
  8662. g_assert_type = 1;
  8663. #endif /* CUSTOMER_HW4_DEBUG */
  8664. #ifdef WL_GENL
  8665. wl_genl_init();
  8666. #endif // endif
  8667. wl_netlink_init();
  8668. return ret;
  8669. }
  8670. int wl_android_exit(void)
  8671. {
  8672. int ret = 0;
  8673. struct io_cfg *cur, *q;
  8674. #ifdef WL_GENL
  8675. wl_genl_deinit();
  8676. #endif /* WL_GENL */
  8677. wl_netlink_deinit();
  8678. GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
  8679. list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
  8680. GCC_DIAGNOSTIC_POP();
  8681. list_del(&cur->list);
  8682. kfree(cur);
  8683. }
  8684. return ret;
  8685. }
  8686. void wl_android_post_init(void)
  8687. {
  8688. #ifdef ENABLE_4335BT_WAR
  8689. bcm_bt_unlock(lock_cookie_wifi);
  8690. printk("wl_android_post_init: btlock released\n");
  8691. #endif /* ENABLE_4335BT_WAR */
  8692. if (!dhd_download_fw_on_driverload)
  8693. g_wifi_on = FALSE;
  8694. }
  8695. #ifdef WL_GENL
  8696. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
  8697. static int
  8698. wl_genl_register_family_with_ops_groups(struct genl_family *family,
  8699. const struct genl_ops *ops, size_t n_ops,
  8700. const struct genl_multicast_group *mcgrps,
  8701. size_t n_mcgrps)
  8702. {
  8703. family->module = THIS_MODULE;
  8704. family->ops = ops;
  8705. family->n_ops = n_ops;
  8706. family->mcgrps = mcgrps;
  8707. family->n_mcgrps = n_mcgrps;
  8708. return genl_register_family(family);
  8709. }
  8710. #endif // endif
  8711. /* Generic Netlink Initializaiton */
  8712. static int wl_genl_init(void)
  8713. {
  8714. int ret;
  8715. WL_DBG(("GEN Netlink Init\n\n"));
  8716. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
  8717. /* register new family */
  8718. ret = genl_register_family(&wl_genl_family);
  8719. if (ret != 0)
  8720. goto failure;
  8721. /* register functions (commands) of the new family */
  8722. ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
  8723. if (ret != 0) {
  8724. WL_ERR(("register ops failed: %i\n", ret));
  8725. genl_unregister_family(&wl_genl_family);
  8726. goto failure;
  8727. }
  8728. ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
  8729. #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) && \
  8730. (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)))
  8731. ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
  8732. #else
  8733. ret = wl_genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops,
  8734. ARRAY_SIZE(wl_genl_ops), wl_genl_mcast, ARRAY_SIZE(wl_genl_mcast));
  8735. #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
  8736. if (ret != 0) {
  8737. WL_ERR(("register mc_group failed: %i\n", ret));
  8738. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
  8739. genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
  8740. #endif // endif
  8741. genl_unregister_family(&wl_genl_family);
  8742. goto failure;
  8743. }
  8744. return 0;
  8745. failure:
  8746. WL_ERR(("Registering Netlink failed!!\n"));
  8747. return -1;
  8748. }
  8749. /* Generic netlink deinit */
  8750. static int wl_genl_deinit(void)
  8751. {
  8752. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
  8753. if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
  8754. WL_ERR(("Unregister wl_genl_ops failed\n"));
  8755. #endif // endif
  8756. if (genl_unregister_family(&wl_genl_family) < 0)
  8757. WL_ERR(("Unregister wl_genl_ops failed\n"));
  8758. return 0;
  8759. }
  8760. s32 wl_event_to_bcm_event(u16 event_type)
  8761. {
  8762. u16 event = -1;
  8763. switch (event_type) {
  8764. case WLC_E_SERVICE_FOUND:
  8765. event = BCM_E_SVC_FOUND;
  8766. break;
  8767. case WLC_E_P2PO_ADD_DEVICE:
  8768. event = BCM_E_DEV_FOUND;
  8769. break;
  8770. case WLC_E_P2PO_DEL_DEVICE:
  8771. event = BCM_E_DEV_LOST;
  8772. break;
  8773. /* Above events are supported from BCM Supp ver 47 Onwards */
  8774. #ifdef BT_WIFI_HANDOVER
  8775. case WLC_E_BT_WIFI_HANDOVER_REQ:
  8776. event = BCM_E_DEV_BT_WIFI_HO_REQ;
  8777. break;
  8778. #endif /* BT_WIFI_HANDOVER */
  8779. default:
  8780. WL_ERR(("Event not supported\n"));
  8781. }
  8782. return event;
  8783. }
  8784. s32
  8785. wl_genl_send_msg(
  8786. struct net_device *ndev,
  8787. u32 event_type,
  8788. const u8 *buf,
  8789. u16 len,
  8790. u8 *subhdr,
  8791. u16 subhdr_len)
  8792. {
  8793. int ret = 0;
  8794. struct sk_buff *skb;
  8795. void *msg;
  8796. u32 attr_type = 0;
  8797. bcm_event_hdr_t *hdr = NULL;
  8798. int mcast = 1; /* By default sent as mutlicast type */
  8799. int pid = 0;
  8800. u8 *ptr = NULL, *p = NULL;
  8801. u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
  8802. u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
  8803. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  8804. WL_DBG(("Enter \n"));
  8805. /* Decide between STRING event and Data event */
  8806. if (event_type == 0)
  8807. attr_type = BCM_GENL_ATTR_STRING;
  8808. else
  8809. attr_type = BCM_GENL_ATTR_MSG;
  8810. skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
  8811. if (skb == NULL) {
  8812. ret = -ENOMEM;
  8813. goto out;
  8814. }
  8815. msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
  8816. if (msg == NULL) {
  8817. ret = -ENOMEM;
  8818. goto out;
  8819. }
  8820. if (attr_type == BCM_GENL_ATTR_STRING) {
  8821. /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
  8822. * make sure it is null terminated
  8823. */
  8824. if (subhdr || subhdr_len) {
  8825. WL_ERR(("No sub hdr support for the ATTR STRING type \n"));
  8826. ret = -EINVAL;
  8827. goto out;
  8828. }
  8829. ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
  8830. if (ret != 0) {
  8831. WL_ERR(("nla_put_string failed\n"));
  8832. goto out;
  8833. }
  8834. } else {
  8835. /* ATTR_MSG */
  8836. /* Create a single buffer for all */
  8837. p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
  8838. if (!ptr) {
  8839. ret = -ENOMEM;
  8840. WL_ERR(("ENOMEM!!\n"));
  8841. goto out;
  8842. }
  8843. /* Include the bcm event header */
  8844. hdr = (bcm_event_hdr_t *)ptr;
  8845. hdr->event_type = wl_event_to_bcm_event(event_type);
  8846. hdr->len = len + subhdr_len;
  8847. ptr += sizeof(bcm_event_hdr_t);
  8848. /* Copy subhdr (if any) */
  8849. if (subhdr && subhdr_len) {
  8850. memcpy(ptr, subhdr, subhdr_len);
  8851. ptr += subhdr_len;
  8852. }
  8853. /* Copy the data */
  8854. if (buf && len) {
  8855. memcpy(ptr, buf, len);
  8856. }
  8857. ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
  8858. if (ret != 0) {
  8859. WL_ERR(("nla_put_string failed\n"));
  8860. goto out;
  8861. }
  8862. }
  8863. if (mcast) {
  8864. int err = 0;
  8865. /* finalize the message */
  8866. genlmsg_end(skb, msg);
  8867. /* NETLINK_CB(skb).dst_group = 1; */
  8868. #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
  8869. if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
  8870. #else
  8871. if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
  8872. #endif // endif
  8873. WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
  8874. attr_type, err));
  8875. else
  8876. WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n",
  8877. attr_type, tot_len));
  8878. } else {
  8879. NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
  8880. /* finalize the message */
  8881. genlmsg_end(skb, msg);
  8882. /* send the message back */
  8883. if (genlmsg_unicast(&init_net, skb, pid) < 0)
  8884. WL_ERR(("genlmsg_unicast failed\n"));
  8885. }
  8886. out:
  8887. if (p) {
  8888. MFREE(cfg->osh, p, tot_len);
  8889. }
  8890. if (ret)
  8891. nlmsg_free(skb);
  8892. return ret;
  8893. }
  8894. static s32
  8895. wl_genl_handle_msg(
  8896. struct sk_buff *skb,
  8897. struct genl_info *info)
  8898. {
  8899. struct nlattr *na;
  8900. u8 *data = NULL;
  8901. WL_DBG(("Enter \n"));
  8902. if (info == NULL) {
  8903. return -EINVAL;
  8904. }
  8905. na = info->attrs[BCM_GENL_ATTR_MSG];
  8906. if (!na) {
  8907. WL_ERR(("nlattribute NULL\n"));
  8908. return -EINVAL;
  8909. }
  8910. data = (char *)nla_data(na);
  8911. if (!data) {
  8912. WL_ERR(("Invalid data\n"));
  8913. return -EINVAL;
  8914. } else {
  8915. /* Handle the data */
  8916. #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS)
  8917. WL_DBG(("%s: Data received from pid (%d) \n", __func__,
  8918. info->snd_pid));
  8919. #else
  8920. WL_DBG(("%s: Data received from pid (%d) \n", __func__,
  8921. info->snd_portid));
  8922. #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
  8923. }
  8924. return 0;
  8925. }
  8926. #endif /* WL_GENL */
  8927. int wl_fatal_error(void * wl, int rc)
  8928. {
  8929. return FALSE;
  8930. }
  8931. #if defined(BT_OVER_SDIO)
  8932. void
  8933. wl_android_set_wifi_on_flag(bool enable)
  8934. {
  8935. g_wifi_on = enable;
  8936. }
  8937. #endif /* BT_OVER_SDIO */
  8938. #ifdef WL_STATIC_IF
  8939. struct net_device *
  8940. wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname)
  8941. {
  8942. struct net_device *ndev;
  8943. struct wireless_dev *wdev = NULL;
  8944. int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
  8945. u8 mac_addr[ETH_ALEN];
  8946. struct net_device *primary_ndev;
  8947. WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
  8948. if (!cfg) {
  8949. WL_ERR(("cfg null\n"));
  8950. return NULL;
  8951. }
  8952. /* Use primary mac with locally admin bit set */
  8953. primary_ndev = bcmcfg_to_prmry_ndev(cfg);
  8954. (void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
  8955. mac_addr[0] |= 0x02;
  8956. ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
  8957. WL_BSSIDX_MAX, NULL);
  8958. if (unlikely(!ndev)) {
  8959. WL_ERR(("Failed to allocate static_if\n"));
  8960. goto fail;
  8961. }
  8962. wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
  8963. if (unlikely(!wdev)) {
  8964. WL_ERR(("Failed to allocate wdev for static_if\n"));
  8965. goto fail;
  8966. }
  8967. wdev->wiphy = cfg->wdev->wiphy;
  8968. wdev->iftype = iftype;
  8969. ndev->ieee80211_ptr = wdev;
  8970. SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
  8971. wdev->netdev = ndev;
  8972. if (wl_cfg80211_register_if(cfg, ifidx,
  8973. ndev, TRUE) != BCME_OK) {
  8974. WL_ERR(("ndev registration failed!\n"));
  8975. goto fail;
  8976. }
  8977. cfg->static_ndev = ndev;
  8978. cfg->static_ndev_state = NDEV_STATE_OS_IF_CREATED;
  8979. wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
  8980. ifname, NDEV_STATE_OS_IF_CREATED);
  8981. WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name));
  8982. return ndev;
  8983. fail:
  8984. wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
  8985. return NULL;
  8986. }
  8987. void
  8988. wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
  8989. {
  8990. WL_INFORM_MEM(("[STATIC_IF] Enter\n"));
  8991. if (!cfg || !cfg->static_ndev) {
  8992. WL_ERR(("invalid input\n"));
  8993. return;
  8994. }
  8995. /* wdev free will happen from notifier context */
  8996. /* free_netdev(cfg->static_ndev);
  8997. */
  8998. unregister_netdev(cfg->static_ndev);
  8999. }
  9000. s32
  9001. wl_cfg80211_static_if_open(struct net_device *net)
  9002. {
  9003. struct wireless_dev *wdev = NULL;
  9004. struct bcm_cfg80211 *cfg = wl_get_cfg(net);
  9005. struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
  9006. u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
  9007. u16 wl_iftype, wl_mode;
  9008. WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
  9009. ASSERT(cfg->static_ndev == net);
  9010. if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
  9011. return BCME_ERROR;
  9012. }
  9013. if (cfg->static_ndev_state != NDEV_STATE_FW_IF_CREATED) {
  9014. wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, NULL);
  9015. if (!wdev) {
  9016. WL_ERR(("[STATIC_IF] wdev is NULL, can't proceed"));
  9017. return BCME_ERROR;
  9018. }
  9019. } else {
  9020. WL_INFORM_MEM(("Fw IF for static netdev already created\n"));
  9021. }
  9022. return BCME_OK;
  9023. }
  9024. s32
  9025. wl_cfg80211_static_if_close(struct net_device *net)
  9026. {
  9027. int ret = BCME_OK;
  9028. struct bcm_cfg80211 *cfg = wl_get_cfg(net);
  9029. struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
  9030. if (cfg->static_ndev_state == NDEV_STATE_FW_IF_CREATED) {
  9031. if (mutex_is_locked(&cfg->if_sync) == TRUE) {
  9032. ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
  9033. } else {
  9034. ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
  9035. }
  9036. if (unlikely(ret)) {
  9037. WL_ERR(("Del iface failed for static_if %d\n", ret));
  9038. }
  9039. }
  9040. return ret;
  9041. }
  9042. struct net_device *
  9043. wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
  9044. wl_if_event_info *event, u8 *addr, s32 iface_type)
  9045. {
  9046. struct net_device *new_ndev = NULL;
  9047. struct wireless_dev *wdev = NULL;
  9048. WL_INFORM_MEM(("Updating static iface after Fw IF create \n"));
  9049. new_ndev = cfg->static_ndev;
  9050. if (new_ndev) {
  9051. wdev = new_ndev->ieee80211_ptr;
  9052. ASSERT(wdev);
  9053. wdev->iftype = iface_type;
  9054. (void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
  9055. }
  9056. cfg->static_ndev_state = NDEV_STATE_FW_IF_CREATED;
  9057. wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
  9058. event->name, NDEV_STATE_FW_IF_CREATED);
  9059. return new_ndev;
  9060. }
  9061. s32
  9062. wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
  9063. {
  9064. cfg->static_ndev_state = NDEV_STATE_FW_IF_DELETED;
  9065. wl_cfg80211_update_iflist_info(cfg, ndev, WL_STATIC_IFIDX, NULL,
  9066. WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
  9067. wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
  9068. wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
  9069. return BCME_OK;
  9070. }
  9071. #endif /* WL_STATIC_IF */
  9072. #ifdef WBTEXT
  9073. static int
  9074. wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
  9075. uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
  9076. {
  9077. int err = BCME_OK;
  9078. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9079. u8 *ioctl_buf = NULL;
  9080. ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  9081. if (unlikely(!ioctl_buf)) {
  9082. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9083. err = -ENOMEM;
  9084. goto exit;
  9085. }
  9086. rp->v1.band = band;
  9087. rp->v1.len = 0;
  9088. /* Getting roam profile from fw */
  9089. if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
  9090. ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
  9091. WL_ERR(("Getting roam_profile failed with err=%d \n", err));
  9092. goto exit;
  9093. }
  9094. memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
  9095. /* roam_prof version get */
  9096. if (rp->v1.ver > WL_ROAM_PROF_VER_2) {
  9097. WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver));
  9098. err = BCME_VERSION;
  9099. goto exit;
  9100. }
  9101. switch (rp->v1.ver) {
  9102. case WL_ROAM_PROF_VER_0:
  9103. {
  9104. *roam_prof_size = sizeof(wl_roam_prof_v1_t);
  9105. *roam_prof_ver = WL_ROAM_PROF_VER_0;
  9106. }
  9107. break;
  9108. case WL_ROAM_PROF_VER_1:
  9109. {
  9110. *roam_prof_size = sizeof(wl_roam_prof_v2_t);
  9111. *roam_prof_ver = WL_ROAM_PROF_VER_1;
  9112. }
  9113. break;
  9114. case WL_ROAM_PROF_VER_2:
  9115. {
  9116. *roam_prof_size = sizeof(wl_roam_prof_v3_t);
  9117. *roam_prof_ver = WL_ROAM_PROF_VER_2;
  9118. }
  9119. break;
  9120. default:
  9121. WL_ERR(("bad version = %d \n", rp->v1.ver));
  9122. err = BCME_VERSION;
  9123. goto exit;
  9124. }
  9125. WL_DBG(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
  9126. if ((rp->v1.len % *roam_prof_size) != 0) {
  9127. WL_ERR(("bad length (=%d) in return data\n", rp->v1.len));
  9128. err = BCME_BADLEN;
  9129. }
  9130. exit:
  9131. if (ioctl_buf) {
  9132. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  9133. }
  9134. return err;
  9135. }
  9136. s32
  9137. wl_cfg80211_wbtext_set_default(struct net_device *ndev)
  9138. {
  9139. char *commandp = NULL;
  9140. s32 ret = BCME_OK;
  9141. char *data;
  9142. u8 *ioctl_buf = NULL;
  9143. wl_roamprof_band_t rp;
  9144. uint8 bandidx = 0;
  9145. int wnmmask = 0;
  9146. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9147. WL_DBG(("set wbtext to default\n"));
  9148. commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
  9149. if (unlikely(!commandp)) {
  9150. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9151. ret = -ENOMEM;
  9152. goto exit;
  9153. }
  9154. ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
  9155. if (unlikely(!ioctl_buf)) {
  9156. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9157. ret = -ENOMEM;
  9158. goto exit;
  9159. }
  9160. rp.v1.band = WLC_BAND_2G;
  9161. rp.v1.len = 0;
  9162. /* Getting roam profile from fw */
  9163. if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
  9164. ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
  9165. WL_ERR(("Getting roam_profile failed with err=%d \n", ret));
  9166. goto exit;
  9167. }
  9168. memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
  9169. for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
  9170. switch (rp.v1.ver) {
  9171. case WL_ROAM_PROF_VER_1:
  9172. {
  9173. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9174. if (bandidx == BAND_5G_INDEX) {
  9175. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9176. CMD_WBTEXT_PROFILE_CONFIG,
  9177. DEFAULT_WBTEXT_PROFILE_A_V2);
  9178. data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
  9179. } else {
  9180. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9181. CMD_WBTEXT_PROFILE_CONFIG,
  9182. DEFAULT_WBTEXT_PROFILE_B_V2);
  9183. data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
  9184. }
  9185. }
  9186. break;
  9187. case WL_ROAM_PROF_VER_2:
  9188. {
  9189. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9190. if (bandidx == BAND_5G_INDEX) {
  9191. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9192. CMD_WBTEXT_PROFILE_CONFIG,
  9193. DEFAULT_WBTEXT_PROFILE_A_V3);
  9194. data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
  9195. } else {
  9196. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9197. CMD_WBTEXT_PROFILE_CONFIG,
  9198. DEFAULT_WBTEXT_PROFILE_B_V3);
  9199. data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
  9200. }
  9201. }
  9202. break;
  9203. default:
  9204. WL_ERR(("No Support for roam prof ver = %d \n", rp.v1.ver));
  9205. ret = -EINVAL;
  9206. goto exit;
  9207. }
  9208. /* set roam profile */
  9209. ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9210. if (ret != BCME_OK) {
  9211. WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
  9212. __FUNCTION__, data, ret));
  9213. goto exit;
  9214. }
  9215. }
  9216. /* set RSSI weight */
  9217. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9218. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9219. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
  9220. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9221. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9222. if (ret != BCME_OK) {
  9223. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9224. __FUNCTION__, data, ret));
  9225. goto exit;
  9226. }
  9227. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9228. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9229. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
  9230. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9231. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9232. if (ret != BCME_OK) {
  9233. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9234. __FUNCTION__, data, ret));
  9235. goto exit;
  9236. }
  9237. /* set CU weight */
  9238. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9239. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9240. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
  9241. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9242. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9243. if (ret != BCME_OK) {
  9244. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9245. __FUNCTION__, data, ret));
  9246. goto exit;
  9247. }
  9248. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9249. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9250. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
  9251. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9252. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9253. if (ret != BCME_OK) {
  9254. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9255. __FUNCTION__, data, ret));
  9256. goto exit;
  9257. }
  9258. ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
  9259. if (ret != BCME_OK) {
  9260. WL_ERR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
  9261. goto exit;
  9262. }
  9263. /* set ESTM DL weight. */
  9264. if (wnmmask & WL_WNM_ESTM) {
  9265. WL_ERR(("Setting ESTM wt\n"));
  9266. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9267. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9268. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
  9269. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9270. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9271. if (ret != BCME_OK) {
  9272. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9273. __FUNCTION__, data, ret));
  9274. goto exit;
  9275. }
  9276. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9277. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9278. CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
  9279. data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
  9280. ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9281. if (ret != BCME_OK) {
  9282. WL_ERR(("%s: Failed to set weight config %s error = %d\n",
  9283. __FUNCTION__, data, ret));
  9284. goto exit;
  9285. }
  9286. }
  9287. /* set RSSI table */
  9288. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9289. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9290. CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
  9291. data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
  9292. ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9293. if (ret != BCME_OK) {
  9294. WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
  9295. __FUNCTION__, data, ret));
  9296. goto exit;
  9297. }
  9298. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9299. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9300. CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
  9301. data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
  9302. ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9303. if (ret != BCME_OK) {
  9304. WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
  9305. __FUNCTION__, data, ret));
  9306. goto exit;
  9307. }
  9308. /* set CU table */
  9309. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9310. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9311. CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
  9312. data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
  9313. ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9314. if (ret != BCME_OK) {
  9315. WL_ERR(("%s: Failed to set CU table %s error = %d\n",
  9316. __FUNCTION__, data, ret));
  9317. goto exit;
  9318. }
  9319. memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
  9320. snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
  9321. CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
  9322. data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
  9323. ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
  9324. if (ret != BCME_OK) {
  9325. WL_ERR(("%s: Failed to set CU table %s error = %d\n",
  9326. __FUNCTION__, data, ret));
  9327. goto exit;
  9328. }
  9329. exit:
  9330. if (commandp) {
  9331. MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
  9332. }
  9333. if (ioctl_buf) {
  9334. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
  9335. }
  9336. return ret;
  9337. }
  9338. s32
  9339. wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
  9340. {
  9341. uint i = 0;
  9342. long int rssi_lower, roam_trigger;
  9343. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9344. wl_roamprof_band_t *rp = NULL;
  9345. int err = -EINVAL, bytes_written = 0;
  9346. size_t len = strlen(data);
  9347. int rp_len = 0;
  9348. u8 *ioctl_buf = NULL;
  9349. uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
  9350. data[len] = '\0';
  9351. ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
  9352. if (unlikely(!ioctl_buf)) {
  9353. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9354. err = -ENOMEM;
  9355. goto exit;
  9356. }
  9357. rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
  9358. if (unlikely(!rp)) {
  9359. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9360. err = -ENOMEM;
  9361. goto exit;
  9362. }
  9363. if (*data && (!strncmp(data, "b", 1))) {
  9364. rp->v1.band = WLC_BAND_2G;
  9365. } else if (*data && (!strncmp(data, "a", 1))) {
  9366. rp->v1.band = WLC_BAND_5G;
  9367. } else {
  9368. err = snprintf(command, total_len, "Missing band\n");
  9369. goto exit;
  9370. }
  9371. data++;
  9372. rp->v1.len = 0;
  9373. /* Getting roam profile from fw */
  9374. if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
  9375. ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
  9376. WL_ERR(("Getting roam_profile failed with err=%d \n", err));
  9377. goto exit;
  9378. }
  9379. memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
  9380. /* roam_prof version get */
  9381. if (rp->v1.ver > WL_ROAM_PROF_VER_2) {
  9382. WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver));
  9383. err = -EINVAL;
  9384. goto exit;
  9385. }
  9386. switch (rp->v1.ver) {
  9387. case WL_ROAM_PROF_VER_0:
  9388. {
  9389. roam_prof_size = sizeof(wl_roam_prof_v1_t);
  9390. roam_prof_ver = WL_ROAM_PROF_VER_0;
  9391. }
  9392. break;
  9393. case WL_ROAM_PROF_VER_1:
  9394. {
  9395. roam_prof_size = sizeof(wl_roam_prof_v2_t);
  9396. roam_prof_ver = WL_ROAM_PROF_VER_1;
  9397. }
  9398. break;
  9399. case WL_ROAM_PROF_VER_2:
  9400. {
  9401. roam_prof_size = sizeof(wl_roam_prof_v3_t);
  9402. roam_prof_ver = WL_ROAM_PROF_VER_2;
  9403. }
  9404. break;
  9405. default:
  9406. WL_ERR(("bad version = %d \n", rp->v1.ver));
  9407. goto exit;
  9408. }
  9409. WL_DBG(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
  9410. if ((rp->v1.len % roam_prof_size) != 0) {
  9411. WL_ERR(("bad length (=%d) in return data\n", rp->v1.len));
  9412. err = -EINVAL;
  9413. goto exit;
  9414. }
  9415. for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
  9416. /* printing contents of roam profile data from fw and exits
  9417. * if code hits any of one of the below condtion. If remaining
  9418. * length of buffer is less than roam profile size or
  9419. * if there is no valid entry.
  9420. */
  9421. if (((i * roam_prof_size) > rp->v1.len)) {
  9422. break;
  9423. }
  9424. if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
  9425. fs_per = rp->v1.roam_prof[i].fullscan_period;
  9426. } else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
  9427. fs_per = rp->v2.roam_prof[i].fullscan_period;
  9428. } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
  9429. fs_per = rp->v3.roam_prof[i].fullscan_period;
  9430. }
  9431. if (fs_per == 0) {
  9432. break;
  9433. }
  9434. prof_cnt++;
  9435. }
  9436. if (!*data) {
  9437. for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
  9438. if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
  9439. bytes_written += snprintf(command+bytes_written,
  9440. total_len - bytes_written,
  9441. "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
  9442. rp->v2.roam_prof[i].roam_trigger,
  9443. rp->v2.roam_prof[i].rssi_lower,
  9444. rp->v2.roam_prof[i].channel_usage,
  9445. rp->v2.roam_prof[i].cu_avg_calc_dur);
  9446. } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
  9447. bytes_written += snprintf(command+bytes_written,
  9448. total_len - bytes_written,
  9449. "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
  9450. rp->v3.roam_prof[i].roam_trigger,
  9451. rp->v3.roam_prof[i].rssi_lower,
  9452. rp->v3.roam_prof[i].channel_usage,
  9453. rp->v3.roam_prof[i].cu_avg_calc_dur);
  9454. }
  9455. }
  9456. err = bytes_written;
  9457. goto exit;
  9458. } else {
  9459. /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
  9460. if (prof_cnt != 2) {
  9461. WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
  9462. err = -EINVAL;
  9463. goto exit;
  9464. }
  9465. /* setting roam profile to fw */
  9466. data++;
  9467. for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
  9468. roam_trigger = simple_strtol(data, &data, 10);
  9469. if (roam_trigger >= 0) {
  9470. WL_ERR(("roam trigger[%d] value must be negative\n", i));
  9471. err = -EINVAL;
  9472. goto exit;
  9473. }
  9474. data++;
  9475. rssi_lower = simple_strtol(data, &data, 10);
  9476. if (rssi_lower >= 0) {
  9477. WL_ERR(("rssi lower[%d] value must be negative\n", i));
  9478. err = -EINVAL;
  9479. goto exit;
  9480. }
  9481. if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
  9482. rp->v2.roam_prof[i].roam_trigger = roam_trigger;
  9483. rp->v2.roam_prof[i].rssi_lower = rssi_lower;
  9484. data++;
  9485. rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
  9486. data++;
  9487. rp->v2.roam_prof[i].cu_avg_calc_dur =
  9488. simple_strtol(data, &data, 10);
  9489. }
  9490. if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
  9491. rp->v3.roam_prof[i].roam_trigger = roam_trigger;
  9492. rp->v3.roam_prof[i].rssi_lower = rssi_lower;
  9493. data++;
  9494. rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
  9495. data++;
  9496. rp->v3.roam_prof[i].cu_avg_calc_dur =
  9497. simple_strtol(data, &data, 10);
  9498. }
  9499. rp_len += roam_prof_size;
  9500. if (*data == '\0') {
  9501. break;
  9502. }
  9503. data++;
  9504. }
  9505. if (i != 1) {
  9506. WL_ERR(("Only two roam_prof rows supported.\n"));
  9507. err = -EINVAL;
  9508. goto exit;
  9509. }
  9510. rp->v1.len = rp_len;
  9511. if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
  9512. sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
  9513. &cfg->ioctl_buf_sync)) < 0) {
  9514. WL_ERR(("seting roam_profile failed with err %d\n", err));
  9515. }
  9516. }
  9517. exit:
  9518. if (rp) {
  9519. MFREE(cfg->osh, rp, sizeof(*rp));
  9520. }
  9521. if (ioctl_buf) {
  9522. MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
  9523. }
  9524. return err;
  9525. }
  9526. int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
  9527. char *command, int total_len)
  9528. {
  9529. int bytes_written = 0, err = -EINVAL, argc = 0;
  9530. char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
  9531. char *endptr = NULL;
  9532. wnm_bss_select_weight_cfg_t *bwcfg;
  9533. u8 ioctl_buf[WLC_IOCTL_SMLEN];
  9534. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9535. bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
  9536. if (unlikely(!bwcfg)) {
  9537. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9538. err = -ENOMEM;
  9539. goto exit;
  9540. }
  9541. bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
  9542. bwcfg->type = 0;
  9543. bwcfg->weight = 0;
  9544. argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
  9545. if (!strcasecmp(rssi, "rssi"))
  9546. bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
  9547. else if (!strcasecmp(rssi, "cu"))
  9548. bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
  9549. else if (!strcasecmp(rssi, "estm_dl"))
  9550. bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
  9551. else {
  9552. /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
  9553. WL_ERR(("%s: Command usage error\n", __func__));
  9554. goto exit;
  9555. }
  9556. if (!strcasecmp(band, "a"))
  9557. bwcfg->band = WLC_BAND_5G;
  9558. else if (!strcasecmp(band, "b"))
  9559. bwcfg->band = WLC_BAND_2G;
  9560. else if (!strcasecmp(band, "all"))
  9561. bwcfg->band = WLC_BAND_ALL;
  9562. else {
  9563. WL_ERR(("%s: Command usage error\n", __func__));
  9564. goto exit;
  9565. }
  9566. if (argc == 2) {
  9567. /* If there is no data after band, getting wnm_bss_select_weight from fw */
  9568. if (bwcfg->band == WLC_BAND_ALL) {
  9569. WL_ERR(("band option \"all\" is for set only, not get\n"));
  9570. goto exit;
  9571. }
  9572. if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
  9573. sizeof(*bwcfg),
  9574. ioctl_buf, sizeof(ioctl_buf), NULL))) {
  9575. WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
  9576. goto exit;
  9577. }
  9578. memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
  9579. bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
  9580. (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
  9581. (bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
  9582. (bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
  9583. err = bytes_written;
  9584. goto exit;
  9585. } else {
  9586. /* if weight is non integer returns command usage error */
  9587. bwcfg->weight = simple_strtol(weight, &endptr, 0);
  9588. if (*endptr != '\0') {
  9589. WL_ERR(("%s: Command usage error", __func__));
  9590. goto exit;
  9591. }
  9592. /* setting weight for iovar wnm_bss_select_weight to fw */
  9593. if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
  9594. sizeof(*bwcfg),
  9595. ioctl_buf, sizeof(ioctl_buf), NULL))) {
  9596. WL_ERR(("setting wnm_bss_select_weight failed with err=%d\n", err));
  9597. }
  9598. }
  9599. exit:
  9600. if (bwcfg) {
  9601. MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
  9602. }
  9603. return err;
  9604. }
  9605. /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
  9606. #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
  9607. int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
  9608. char *command, int total_len)
  9609. {
  9610. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9611. int bytes_written = 0, err = -EINVAL;
  9612. char rssi[BUFSZN], band[BUFSZN];
  9613. int btcfg_len = 0, i = 0, parsed_len = 0;
  9614. wnm_bss_select_factor_cfg_t *btcfg;
  9615. size_t slen = strlen(data);
  9616. char *start_addr = NULL;
  9617. u8 ioctl_buf[WLC_IOCTL_SMLEN];
  9618. data[slen] = '\0';
  9619. btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
  9620. (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
  9621. if (unlikely(!btcfg)) {
  9622. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9623. err = -ENOMEM;
  9624. goto exit;
  9625. }
  9626. btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
  9627. btcfg->band = WLC_BAND_AUTO;
  9628. btcfg->type = 0;
  9629. btcfg->count = 0;
  9630. sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
  9631. if (!strcasecmp(rssi, "rssi")) {
  9632. btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
  9633. }
  9634. else if (!strcasecmp(rssi, "cu")) {
  9635. btcfg->type = WNM_BSS_SELECT_TYPE_CU;
  9636. }
  9637. else {
  9638. WL_ERR(("%s: Command usage error\n", __func__));
  9639. goto exit;
  9640. }
  9641. if (!strcasecmp(band, "a")) {
  9642. btcfg->band = WLC_BAND_5G;
  9643. }
  9644. else if (!strcasecmp(band, "b")) {
  9645. btcfg->band = WLC_BAND_2G;
  9646. }
  9647. else if (!strcasecmp(band, "all")) {
  9648. btcfg->band = WLC_BAND_ALL;
  9649. }
  9650. else {
  9651. WL_ERR(("%s: Command usage, Wrong band\n", __func__));
  9652. goto exit;
  9653. }
  9654. if ((slen - 1) == (strlen(rssi) + strlen(band))) {
  9655. /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
  9656. if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
  9657. sizeof(*btcfg),
  9658. ioctl_buf, sizeof(ioctl_buf), NULL))) {
  9659. WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
  9660. goto exit;
  9661. }
  9662. memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
  9663. memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
  9664. bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
  9665. "No of entries in table: %d\n", btcfg->count);
  9666. bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
  9667. "%s factor table\n",
  9668. (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
  9669. bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
  9670. "low\thigh\tfactor\n");
  9671. for (i = 0; i <= btcfg->count-1; i++) {
  9672. bytes_written += snprintf(command + bytes_written,
  9673. total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
  9674. btcfg->params[i].high, btcfg->params[i].factor);
  9675. }
  9676. err = bytes_written;
  9677. goto exit;
  9678. } else {
  9679. uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
  9680. memset_s(btcfg->params, len, 0, len);
  9681. data += (strlen(rssi) + strlen(band) + 2);
  9682. start_addr = data;
  9683. slen = slen - (strlen(rssi) + strlen(band) + 2);
  9684. for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
  9685. if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
  9686. btcfg->params[i].low = simple_strtol(data, &data, 10);
  9687. data++;
  9688. btcfg->params[i].high = simple_strtol(data, &data, 10);
  9689. data++;
  9690. btcfg->params[i].factor = simple_strtol(data, &data, 10);
  9691. btcfg->count++;
  9692. if (*data == '\0') {
  9693. break;
  9694. }
  9695. data++;
  9696. parsed_len = data - start_addr;
  9697. } else {
  9698. WL_ERR(("%s:Command usage:less no of args\n", __func__));
  9699. goto exit;
  9700. }
  9701. }
  9702. btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
  9703. if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
  9704. cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
  9705. WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
  9706. goto exit;
  9707. }
  9708. }
  9709. exit:
  9710. if (btcfg) {
  9711. MFREE(cfg->osh, btcfg,
  9712. (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
  9713. }
  9714. return err;
  9715. }
  9716. s32
  9717. wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
  9718. {
  9719. uint i = 0;
  9720. struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
  9721. int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
  9722. char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
  9723. wl_roamprof_band_t *rp = NULL;
  9724. uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
  9725. rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
  9726. if (unlikely(!rp)) {
  9727. WL_ERR(("%s: failed to allocate memory\n", __func__));
  9728. err = -ENOMEM;
  9729. goto exit;
  9730. }
  9731. argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
  9732. if (!strcasecmp(band, "a"))
  9733. band_val = WLC_BAND_5G;
  9734. else if (!strcasecmp(band, "b"))
  9735. band_val = WLC_BAND_2G;
  9736. else {
  9737. WL_ERR(("%s: Missing band\n", __func__));
  9738. goto exit;
  9739. }
  9740. if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
  9741. &roam_prof_size))) {
  9742. WL_ERR(("Getting roam_profile failed with err=%d \n", err));
  9743. err = -EINVAL;
  9744. goto exit;
  9745. }
  9746. if (argc == 2) {
  9747. /* if delta is non integer returns command usage error */
  9748. val = simple_strtol(delta, &endptr, 0);
  9749. if (*endptr != '\0') {
  9750. WL_ERR(("%s: Command usage error", __func__));
  9751. goto exit;
  9752. }
  9753. for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
  9754. /*
  9755. * Checking contents of roam profile data from fw and exits
  9756. * if code hits below condtion. If remaining length of buffer is
  9757. * less than roam profile size or if there is no valid entry.
  9758. */
  9759. if (((i * roam_prof_size) > rp->v1.len) ||
  9760. (rp->v1.roam_prof[i].fullscan_period == 0)) {
  9761. break;
  9762. }
  9763. if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
  9764. if (rp->v2.roam_prof[i].channel_usage != 0) {
  9765. rp->v2.roam_prof[i].roam_delta = val;
  9766. }
  9767. } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
  9768. if (rp->v3.roam_prof[i].channel_usage != 0) {
  9769. rp->v3.roam_prof[i].roam_delta = val;
  9770. }
  9771. }
  9772. len += roam_prof_size;
  9773. }
  9774. }
  9775. else {
  9776. if (rp->v2.roam_prof[0].channel_usage != 0) {
  9777. bytes_written = snprintf(command, total_len,
  9778. "%s Delta %d\n", (rp->v1.band == WLC_BAND_2G) ? "2G" : "5G",
  9779. rp->v2.roam_prof[0].roam_delta);
  9780. }
  9781. err = bytes_written;
  9782. goto exit;
  9783. }
  9784. rp->v1.len = len;
  9785. if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
  9786. sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
  9787. &cfg->ioctl_buf_sync)) < 0) {
  9788. WL_ERR(("seting roam_profile failed with err %d\n", err));
  9789. }
  9790. exit :
  9791. if (rp) {
  9792. MFREE(cfg->osh, rp, sizeof(*rp));
  9793. }
  9794. return err;
  9795. }
  9796. #endif /* WBTEXT */