12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436 |
- /*
- * Broadcom Dongle Host Driver (DHD)
- * Prefered Network Offload and Wi-Fi Location Service(WLS) code.
- *
- * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
- *
- * Copyright (C) 1999-2020, Broadcom Corporation
- *
- * Unless you and Broadcom execute a separate written software license
- * agreement governing use of this software, this software is licensed to you
- * under the terms of the GNU General Public License version 2 (the "GPL"),
- * available at http://www.broadcom.com/licenses/GPLv2.php, with the
- * following added to such license:
- *
- * As a special exception, the copyright holders of this software give you
- * permission to link this software with independent modules, and to copy and
- * distribute the resulting executable under terms of your choice, provided that
- * you also meet, for each linked independent module, the terms and conditions of
- * the license of that module. An independent module is a module which is not
- * derived from this software. The special exception does not apply to any
- * modifications of the software.
- *
- * Notwithstanding the above, under no circumstances may you combine this
- * software in any way with any other Broadcom software provided under a license
- * other than the GPL, without Broadcom's express prior written consent.
- *
- *
- * <<Broadcom-WL-IPTag/Open:>>
- *
- * $Id: dhd_pno.c 812762 2019-04-02 09:36:26Z $
- */
- #if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT)
- #error "GSCAN needs PNO to be enabled!"
- #endif // endif
- #ifdef PNO_SUPPORT
- #include <typedefs.h>
- #include <osl.h>
- #include <epivers.h>
- #include <bcmutils.h>
- #include <bcmendian.h>
- #ifdef OEM_ANDROID
- #include <linuxver.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/sort.h>
- #endif // endif
- #include <dngl_stats.h>
- #include <wlioctl.h>
- #include <bcmevent.h>
- #include <dhd.h>
- #include <dhd_linux.h>
- #include <dhd_pno.h>
- #include <dhd_dbg.h>
- #ifdef GSCAN_SUPPORT
- #include <linux/gcd.h>
- #endif /* GSCAN_SUPPORT */
- #ifdef WL_CFG80211
- #include <wl_cfg80211.h>
- #endif /* WL_CFG80211 */
- #ifdef __BIG_ENDIAN
- #include <bcmendian.h>
- #define htod32(i) (bcmswap32(i))
- #define htod16(i) (bcmswap16(i))
- #define dtoh32(i) (bcmswap32(i))
- #define dtoh16(i) (bcmswap16(i))
- #define htodchanspec(i) htod16(i)
- #define dtohchanspec(i) dtoh16(i)
- #else
- #define htod32(i) (i)
- #define htod16(i) (i)
- #define dtoh32(i) (i)
- #define dtoh16(i) (i)
- #define htodchanspec(i) (i)
- #define dtohchanspec(i) (i)
- #endif /* IL_BIGENDINA */
- #ifdef OEM_ANDROID
- #define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state)
- #define PNO_BESTNET_LEN WLC_IOCTL_MEDLEN
- #define PNO_ON 1
- #define PNO_OFF 0
- #define CHANNEL_2G_MIN 1
- #define CHANNEL_2G_MAX 14
- #define CHANNEL_5G_MIN 34
- #define CHANNEL_5G_MAX 165
- #define IS_2G_CHANNEL(ch) ((ch >= CHANNEL_2G_MIN) && \
- (ch <= CHANNEL_2G_MAX))
- #define IS_5G_CHANNEL(ch) ((ch >= CHANNEL_5G_MIN) && \
- (ch <= CHANNEL_5G_MAX))
- #define MAX_NODE_CNT 5
- #define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE)
- #define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \
- - (uint32)(timestamp2/1000)))
- #define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \
- - (uint32)(timestamp2)))
- #define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
- (ts).tv_nsec / NSEC_PER_USEC)
- #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====")
- #define TIME_MIN_DIFF 5
- #define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t))
- #define EVENT_MAX_NETCNT_V1 \
- ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v1_t)) \
- / sizeof(wl_pfn_net_info_v1_t) + 1)
- #define EVENT_MAX_NETCNT_V2 \
- ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v2_t)) \
- / sizeof(wl_pfn_net_info_v2_t) + 1)
- #ifdef GSCAN_SUPPORT
- static int _dhd_pno_flush_ssid(dhd_pub_t *dhd);
- static wl_pfn_gscan_ch_bucket_cfg_t *
- dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state,
- uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw);
- #endif /* GSCAN_SUPPORT */
- static int dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat,
- int pno_freq_expo_max, uint16 *channel_list, int nchan);
- static inline bool
- is_dfs(dhd_pub_t *dhd, uint16 channel)
- {
- u32 ch;
- s32 err;
- u8 buf[32];
- ch = wl_ch_host_to_driver(channel);
- err = dhd_iovar(dhd, 0, "per_chan_info", (char *)&ch,
- sizeof(u32), buf, sizeof(buf), FALSE);
- if (unlikely(err)) {
- DHD_ERROR(("get per chan info failed:%d\n", err));
- return FALSE;
- }
- /* Check the channel flags returned by fw */
- if (*((u32 *)buf) & WL_CHAN_PASSIVE) {
- return TRUE;
- }
- return FALSE;
- }
- int
- dhd_pno_clean(dhd_pub_t *dhd)
- {
- int pfn = 0;
- int err;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- /* Disable PNO */
- err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn(error : %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- _pno_state->pno_status = DHD_PNO_DISABLED;
- err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n",
- __FUNCTION__, err));
- }
- exit:
- return err;
- }
- bool
- dhd_is_pno_supported(dhd_pub_t *dhd)
- {
- dhd_pno_status_info_t *_pno_state;
- if (!dhd || !dhd->pno_state) {
- DHD_ERROR(("NULL POINTER : %s\n",
- __FUNCTION__));
- return FALSE;
- }
- _pno_state = PNO_GET_PNOSTATE(dhd);
- return WLS_SUPPORTED(_pno_state);
- }
- bool
- dhd_is_legacy_pno_enabled(dhd_pub_t *dhd)
- {
- dhd_pno_status_info_t *_pno_state;
- if (!dhd || !dhd->pno_state) {
- DHD_ERROR(("NULL POINTER : %s\n",
- __FUNCTION__));
- return FALSE;
- }
- _pno_state = PNO_GET_PNOSTATE(dhd);
- return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0);
- }
- #ifdef GSCAN_SUPPORT
- static uint64
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
- convert_fw_rel_time_to_systime(struct timespec64 *ts, uint32 fw_ts_ms)
- #else
- convert_fw_rel_time_to_systime(struct timespec *ts, uint32 fw_ts_ms)
- #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
- {
- return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000));
- }
- static void
- dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params,
- dhd_epno_results_t *res, uint32 idx)
- {
- dhd_pno_ssid_t *iter, *next;
- int i;
- /* If idx doesn't make sense */
- if (idx >= gscan_params->epno_cfg.num_epno_ssid) {
- DHD_ERROR(("No match, idx %d num_ssid %d\n", idx,
- gscan_params->epno_cfg.num_epno_ssid));
- goto exit;
- }
- if (gscan_params->epno_cfg.num_epno_ssid > 0) {
- i = 0;
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &gscan_params->epno_cfg.epno_ssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- if (i++ == idx) {
- memcpy(res->ssid, iter->SSID, iter->SSID_len);
- res->ssid_len = iter->SSID_len;
- return;
- }
- }
- }
- exit:
- /* If we are here then there was no match */
- res->ssid[0] = '\0';
- res->ssid_len = 0;
- return;
- }
- /* Translate HAL flag bitmask to BRCM FW flag bitmask */
- void
- dhd_pno_translate_epno_fw_flags(uint32 *flags)
- {
- uint32 in_flags, fw_flags = 0;
- in_flags = *flags;
- if (in_flags & DHD_EPNO_A_BAND_TRIG) {
- fw_flags |= WL_PFN_SSID_A_BAND_TRIG;
- }
- if (in_flags & DHD_EPNO_BG_BAND_TRIG) {
- fw_flags |= WL_PFN_SSID_BG_BAND_TRIG;
- }
- if (!(in_flags & DHD_EPNO_STRICT_MATCH) &&
- !(in_flags & DHD_EPNO_HIDDEN_SSID)) {
- fw_flags |= WL_PFN_SSID_IMPRECISE_MATCH;
- }
- if (in_flags & DHD_EPNO_SAME_NETWORK) {
- fw_flags |= WL_PFN_SSID_SAME_NETWORK;
- }
- /* Add any hard coded flags needed */
- fw_flags |= WL_PFN_SUPPRESS_AGING_MASK;
- *flags = fw_flags;
- return;
- }
- /* Translate HAL auth bitmask to BRCM FW bitmask */
- void
- dhd_pno_set_epno_auth_flag(uint32 *wpa_auth)
- {
- switch (*wpa_auth) {
- case DHD_PNO_AUTH_CODE_OPEN:
- *wpa_auth = WPA_AUTH_DISABLED;
- break;
- case DHD_PNO_AUTH_CODE_PSK:
- *wpa_auth = (WPA_AUTH_PSK | WPA2_AUTH_PSK);
- break;
- case DHD_PNO_AUTH_CODE_EAPOL:
- *wpa_auth = ~WPA_AUTH_NONE;
- break;
- default:
- DHD_ERROR(("%s: Unknown auth %d", __FUNCTION__, *wpa_auth));
- *wpa_auth = WPA_AUTH_PFN_ANY;
- break;
- }
- return;
- }
- /* Cleanup all results */
- static void
- dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd)
- {
- struct dhd_pno_gscan_params *gscan_params;
- dhd_pno_status_info_t *_pno_state;
- gscan_results_cache_t *iter;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan;
- iter = gscan_params->gscan_batch_cache;
- /* Mark everything as consumed */
- while (iter) {
- iter->tot_consumed = iter->tot_count;
- iter = iter->next;
- }
- dhd_gscan_batch_cache_cleanup(dhd);
- return;
- }
- static int
- _dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size)
- {
- int err = BCME_OK;
- NULL_CHECK(dhd, "dhd is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__));
- goto exit;
- }
- exit:
- return err;
- }
- static int
- _dhd_pno_flush_ssid(dhd_pub_t *dhd)
- {
- int err;
- wl_pfn_t pfn_elem;
- memset(&pfn_elem, 0, sizeof(wl_pfn_t));
- pfn_elem.flags = htod32(WL_PFN_FLUSH_ALL_SSIDS);
- err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_elem, sizeof(wl_pfn_t), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
- }
- return err;
- }
- static bool
- is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params)
- {
- smp_rmb();
- return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE);
- }
- #endif /* GSCAN_SUPPORT */
- static int
- _dhd_pno_suspend(dhd_pub_t *dhd)
- {
- int err;
- int suspend = 1;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err));
- goto exit;
- }
- _pno_state->pno_status = DHD_PNO_SUSPEND;
- exit:
- return err;
- }
- static int
- _dhd_pno_enable(dhd_pub_t *dhd, int enable)
- {
- int err = BCME_OK;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (enable & 0xfffe) {
- DHD_ERROR(("%s invalid value\n", __FUNCTION__));
- err = BCME_BADARG;
- goto exit;
- }
- if (!dhd_support_sta_mode(dhd)) {
- DHD_ERROR(("PNO is not allowed for non-STA mode"));
- err = BCME_BADOPTION;
- goto exit;
- }
- if (enable) {
- if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
- dhd_is_associated(dhd, 0, NULL)) {
- DHD_ERROR(("%s Legacy PNO mode cannot be enabled "
- "in assoc mode , ignore it\n", __FUNCTION__));
- err = BCME_BADOPTION;
- goto exit;
- }
- }
- /* Enable/Disable PNO */
- err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err));
- goto exit;
- }
- _pno_state->pno_status = (enable)?
- DHD_PNO_ENABLED : DHD_PNO_DISABLED;
- if (!enable)
- _pno_state->pno_mode = DHD_PNO_NONE_MODE;
- DHD_PNO(("%s set pno as %s\n",
- __FUNCTION__, enable ? "Enable" : "Disable"));
- exit:
- return err;
- }
- static int
- _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode)
- {
- int err = BCME_OK;
- wl_pfn_param_t pfn_param;
- dhd_pno_params_t *_params;
- dhd_pno_status_info_t *_pno_state;
- bool combined_scan = FALSE;
- DHD_PNO(("%s enter\n", __FUNCTION__));
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- memset(&pfn_param, 0, sizeof(pfn_param));
- /* set pfn parameters */
- pfn_param.version = htod32(PFN_VERSION);
- pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) |
- (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT));
- if (mode == DHD_PNO_LEGACY_MODE) {
- /* check and set extra pno params */
- if ((pno_params->params_legacy.pno_repeat != 0) ||
- (pno_params->params_legacy.pno_freq_expo_max != 0)) {
- pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
- pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat);
- pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max);
- }
- /* set up pno scan fr */
- if (pno_params->params_legacy.scan_fr != 0)
- pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr);
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n"));
- mode |= DHD_PNO_BATCH_MODE;
- combined_scan = TRUE;
- } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
- DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n"));
- mode |= DHD_PNO_HOTLIST_MODE;
- combined_scan = TRUE;
- }
- #ifdef GSCAN_SUPPORT
- else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n"));
- mode |= DHD_PNO_GSCAN_MODE;
- }
- #endif /* GSCAN_SUPPORT */
- }
- if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) {
- /* Scan frequency of 30 sec */
- pfn_param.scan_freq = htod32(30);
- /* slow adapt scan is off by default */
- pfn_param.slow_freq = htod32(0);
- /* RSSI margin of 30 dBm */
- pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM);
- /* Network timeout 60 sec */
- pfn_param.lost_network_timeout = htod32(60);
- /* best n = 2 by default */
- pfn_param.bestn = DEFAULT_BESTN;
- /* mscan m=0 by default, so not record best networks by default */
- pfn_param.mscan = DEFAULT_MSCAN;
- /* default repeat = 10 */
- pfn_param.repeat = DEFAULT_REPEAT;
- /* by default, maximum scan interval = 2^2
- * scan_freq when adaptive scan is turned on
- */
- pfn_param.exp = DEFAULT_EXP;
- if (mode == DHD_PNO_BATCH_MODE) {
- /* In case of BATCH SCAN */
- if (pno_params->params_batch.bestn)
- pfn_param.bestn = pno_params->params_batch.bestn;
- if (pno_params->params_batch.scan_fr)
- pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr);
- if (pno_params->params_batch.mscan)
- pfn_param.mscan = pno_params->params_batch.mscan;
- /* enable broadcast scan */
- pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT);
- } else if (mode == DHD_PNO_HOTLIST_MODE) {
- /* In case of HOTLIST SCAN */
- if (pno_params->params_hotlist.scan_fr)
- pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr);
- pfn_param.bestn = 0;
- pfn_param.repeat = 0;
- /* enable broadcast scan */
- pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT);
- }
- if (combined_scan) {
- /* Disable Adaptive Scan */
- pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT));
- pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT);
- pfn_param.repeat = 0;
- pfn_param.exp = 0;
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- /* In case of Legacy PNO + BATCH SCAN */
- _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]);
- if (_params->params_batch.bestn)
- pfn_param.bestn = _params->params_batch.bestn;
- if (_params->params_batch.scan_fr)
- pfn_param.scan_freq = htod32(_params->params_batch.scan_fr);
- if (_params->params_batch.mscan)
- pfn_param.mscan = _params->params_batch.mscan;
- } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
- /* In case of Legacy PNO + HOTLIST SCAN */
- _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
- if (_params->params_hotlist.scan_fr)
- pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr);
- pfn_param.bestn = 0;
- pfn_param.repeat = 0;
- }
- }
- }
- #ifdef GSCAN_SUPPORT
- if (mode & DHD_PNO_GSCAN_MODE) {
- uint32 lost_network_timeout;
- pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr);
- if (pno_params->params_gscan.mscan) {
- pfn_param.bestn = pno_params->params_gscan.bestn;
- pfn_param.mscan = pno_params->params_gscan.mscan;
- pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT);
- }
- /* RSSI margin of 30 dBm */
- pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM);
- pfn_param.repeat = 0;
- pfn_param.exp = 0;
- pfn_param.slow_freq = 0;
- pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- dhd_pno_params_t *params;
- params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
- pfn_param.scan_freq = gcd(pno_params->params_gscan.scan_fr,
- params->params_legacy.scan_fr);
- if ((params->params_legacy.pno_repeat != 0) ||
- (params->params_legacy.pno_freq_expo_max != 0)) {
- pfn_param.repeat = (uchar) (params->params_legacy.pno_repeat);
- pfn_param.exp = (uchar) (params->params_legacy.pno_freq_expo_max);
- }
- }
- lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq *
- pfn_param.scan_freq *
- pno_params->params_gscan.lost_ap_window);
- if (lost_network_timeout) {
- pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout,
- GSCAN_MIN_BSSID_TIMEOUT));
- } else {
- pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT);
- }
- } else
- #endif /* GSCAN_SUPPORT */
- {
- if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) ||
- pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) {
- DHD_ERROR(("%s pno freq(%d sec) is not valid \n",
- __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
- err = BCME_BADARG;
- goto exit;
- }
- }
- err = dhd_set_rand_mac_oui(dhd);
- /* Ignore if chip doesnt support the feature */
- if (err < 0 && err != BCME_UNSUPPORTED) {
- DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err));
- goto exit;
- }
- #ifdef GSCAN_SUPPORT
- if (mode == DHD_PNO_BATCH_MODE ||
- ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) {
- #else
- if (mode == DHD_PNO_BATCH_MODE) {
- #endif /* GSCAN_SUPPORT */
- int _tmp = pfn_param.bestn;
- /* set bestn to calculate the max mscan which firmware supports */
- err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__));
- goto exit;
- }
- /* get max mscan which the firmware supports */
- err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__));
- goto exit;
- }
- pfn_param.mscan = MIN(pfn_param.mscan, _tmp);
- DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn,
- pfn_param.mscan));
- }
- err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err));
- goto exit;
- }
- /* need to return mscan if this is for batch scan instead of err */
- err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err;
- exit:
- return err;
- }
- static int
- _dhd_pno_add_ssid(dhd_pub_t *dhd, struct list_head* ssid_list, int nssid)
- {
- int err = BCME_OK;
- int i = 0, mem_needed;
- wl_pfn_t *pfn_elem_buf;
- struct dhd_pno_ssid *iter, *next;
- NULL_CHECK(dhd, "dhd is NULL", err);
- if (!nssid) {
- NULL_CHECK(ssid_list, "ssid list is NULL", err);
- return BCME_ERROR;
- }
- mem_needed = (sizeof(wl_pfn_t) * nssid);
- pfn_elem_buf = (wl_pfn_t *) MALLOCZ(dhd->osh, mem_needed);
- if (!pfn_elem_buf) {
- DHD_ERROR(("%s: Can't malloc %d bytes!\n", __FUNCTION__, mem_needed));
- return BCME_NOMEM;
- }
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next, ssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- pfn_elem_buf[i].infra = htod32(1);
- pfn_elem_buf[i].auth = htod32(DOT11_OPEN_SYSTEM);
- pfn_elem_buf[i].wpa_auth = htod32(iter->wpa_auth);
- pfn_elem_buf[i].flags = htod32(iter->flags);
- if (iter->hidden)
- pfn_elem_buf[i].flags |= htod32(ENABLE << WL_PFN_HIDDEN_BIT);
- /* If a single RSSI threshold is defined, use that */
- #ifdef PNO_MIN_RSSI_TRIGGER
- pfn_elem_buf[i].flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT);
- #else
- pfn_elem_buf[i].flags |= ((iter->rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT);
- #endif /* PNO_MIN_RSSI_TRIGGER */
- memcpy((char *)pfn_elem_buf[i].ssid.SSID, iter->SSID,
- iter->SSID_len);
- pfn_elem_buf[i].ssid.SSID_len = iter->SSID_len;
- DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n",
- iter->SSID, iter->SSID_len, iter->hidden,
- iter->flags, iter->rssi_thresh));
- if (++i >= nssid) {
- /* shouldn't happen */
- break;
- }
- }
- err = dhd_iovar(dhd, 0, "pfn_add", (char *)pfn_elem_buf, mem_needed, NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
- }
- MFREE(dhd->osh, pfn_elem_buf, mem_needed);
- return err;
- }
- /* qsort compare function */
- static int
- _dhd_pno_cmpfunc(const void *a, const void *b)
- {
- return (*(const uint16*)a - *(const uint16*)b);
- }
- static int
- _dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan,
- uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2)
- {
- int err = BCME_OK;
- int i = 0, j = 0, k = 0;
- uint16 tmp;
- NULL_CHECK(d_chan_list, "d_chan_list is NULL", err);
- NULL_CHECK(nchan, "nchan is NULL", err);
- NULL_CHECK(chan_list1, "chan_list1 is NULL", err);
- NULL_CHECK(chan_list2, "chan_list2 is NULL", err);
- /* chan_list1 and chan_list2 should be sorted at first */
- while (i < nchan1 && j < nchan2) {
- tmp = chan_list1[i] < chan_list2[j]?
- chan_list1[i++] : chan_list2[j++];
- for (; i < nchan1 && chan_list1[i] == tmp; i++);
- for (; j < nchan2 && chan_list2[j] == tmp; j++);
- d_chan_list[k++] = tmp;
- }
- while (i < nchan1) {
- tmp = chan_list1[i++];
- for (; i < nchan1 && chan_list1[i] == tmp; i++);
- d_chan_list[k++] = tmp;
- }
- while (j < nchan2) {
- tmp = chan_list2[j++];
- for (; j < nchan2 && chan_list2[j] == tmp; j++);
- d_chan_list[k++] = tmp;
- }
- *nchan = k;
- return err;
- }
- static int
- _dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list,
- int *nchan, uint8 band, bool skip_dfs)
- {
- int err = BCME_OK;
- int i, j;
- uint32 chan_buf[WL_NUMCHANNELS + 1];
- wl_uint32_list_t *list;
- NULL_CHECK(dhd, "dhd is NULL", err);
- if (*nchan) {
- NULL_CHECK(d_chan_list, "d_chan_list is NULL", err);
- }
- memset(&chan_buf, 0, sizeof(chan_buf));
- list = (wl_uint32_list_t *) (void *)chan_buf;
- list->count = htod32(WL_NUMCHANNELS);
- err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0);
- if (err < 0) {
- DHD_ERROR(("failed to get channel list (err: %d)\n", err));
- return err;
- }
- for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) {
- if (IS_2G_CHANNEL(dtoh32(list->element[i]))) {
- if (!(band & WLC_BAND_2G)) {
- /* Skip, if not 2g */
- continue;
- }
- /* fall through to include the channel */
- } else if (IS_5G_CHANNEL(dtoh32(list->element[i]))) {
- bool dfs_channel = is_dfs(dhd, dtoh32(list->element[i]));
- if ((skip_dfs && dfs_channel) ||
- (!(band & WLC_BAND_5G) && !dfs_channel)) {
- /* Skip the channel if:
- * the DFS bit is NOT set & the channel is a dfs channel
- * the band 5G is not set & the channel is a non DFS 5G channel
- */
- continue;
- }
- /* fall through to include the channel */
- } else {
- /* Not in range. Bad channel */
- DHD_ERROR(("Not in range. bad channel\n"));
- *nchan = 0;
- return BCME_BADCHAN;
- }
- /* Include the channel */
- d_chan_list[j++] = (uint16) dtoh32(list->element[i]);
- }
- *nchan = j;
- return err;
- }
- static int
- _dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch,
- char *buf, int nbufsize)
- {
- int err = BCME_OK;
- int bytes_written = 0, nreadsize = 0;
- int t_delta = 0;
- int nleftsize = nbufsize;
- uint8 cnt = 0;
- char *bp = buf;
- char eabuf[ETHER_ADDR_STR_LEN];
- #ifdef PNO_DEBUG
- char *_base_bp;
- char msg[150];
- #endif // endif
- dhd_pno_bestnet_entry_t *iter, *next;
- dhd_pno_scan_results_t *siter, *snext;
- dhd_pno_best_header_t *phead, *pprev;
- NULL_CHECK(params_batch, "params_batch is NULL", err);
- if (nbufsize > 0)
- NULL_CHECK(buf, "buf is NULL", err);
- /* initialize the buffer */
- memset(buf, 0, nbufsize);
- DHD_PNO(("%s enter \n", __FUNCTION__));
- /* # of scans */
- if (!params_batch->get_batch.batch_started) {
- bp += nreadsize = snprintf(bp, nleftsize, "scancount=%d\n",
- params_batch->get_batch.expired_tot_scan_cnt);
- nleftsize -= nreadsize;
- params_batch->get_batch.batch_started = TRUE;
- }
- DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt));
- /* preestimate scan count until which scan result this report is going to end */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(siter, snext,
- ¶ms_batch->get_batch.expired_scan_results_list, list) {
- GCC_DIAGNOSTIC_POP();
- phead = siter->bestnetheader;
- while (phead != NULL) {
- /* if left_size is less than bestheader total size , stop this */
- if (nleftsize <=
- (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD))
- goto exit;
- /* increase scan count */
- cnt++;
- /* # best of each scan */
- DHD_PNO(("\n<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt));
- /* attribute of the scan */
- if (phead->reason & PNO_STATUS_ABORT_MASK) {
- bp += nreadsize = snprintf(bp, nleftsize, "trunc\n");
- nleftsize -= nreadsize;
- }
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &phead->entry_list, list) {
- GCC_DIAGNOSTIC_POP();
- t_delta = jiffies_to_msecs(jiffies - iter->recorded_time);
- #ifdef PNO_DEBUG
- _base_bp = bp;
- memset(msg, 0, sizeof(msg));
- #endif // endif
- /* BSSID info */
- bp += nreadsize = snprintf(bp, nleftsize, "bssid=%s\n",
- bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf));
- nleftsize -= nreadsize;
- /* SSID */
- bp += nreadsize = snprintf(bp, nleftsize, "ssid=%s\n", iter->SSID);
- nleftsize -= nreadsize;
- /* channel */
- bp += nreadsize = snprintf(bp, nleftsize, "freq=%d\n",
- wf_channel2mhz(iter->channel,
- iter->channel <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- nleftsize -= nreadsize;
- /* RSSI */
- bp += nreadsize = snprintf(bp, nleftsize, "level=%d\n", iter->RSSI);
- nleftsize -= nreadsize;
- /* add the time consumed in Driver to the timestamp of firmware */
- iter->timestamp += t_delta;
- bp += nreadsize = snprintf(bp, nleftsize,
- "age=%d\n", iter->timestamp);
- nleftsize -= nreadsize;
- /* RTT0 */
- bp += nreadsize = snprintf(bp, nleftsize, "dist=%d\n",
- (iter->rtt0 == 0)? -1 : iter->rtt0);
- nleftsize -= nreadsize;
- /* RTT1 */
- bp += nreadsize = snprintf(bp, nleftsize, "distSd=%d\n",
- (iter->rtt0 == 0)? -1 : iter->rtt1);
- nleftsize -= nreadsize;
- bp += nreadsize = snprintf(bp, nleftsize, "%s", AP_END_MARKER);
- nleftsize -= nreadsize;
- list_del(&iter->list);
- MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE);
- #ifdef PNO_DEBUG
- memcpy(msg, _base_bp, bp - _base_bp);
- DHD_PNO(("Entry : \n%s", msg));
- #endif // endif
- }
- bp += nreadsize = snprintf(bp, nleftsize, "%s", SCAN_END_MARKER);
- DHD_PNO(("%s", SCAN_END_MARKER));
- nleftsize -= nreadsize;
- pprev = phead;
- /* reset the header */
- siter->bestnetheader = phead = phead->next;
- MFREE(dhd->osh, pprev, BEST_HEADER_SIZE);
- siter->cnt_header--;
- }
- if (phead == NULL) {
- /* we store all entry in this scan , so it is ok to delete */
- list_del(&siter->list);
- MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE);
- }
- }
- exit:
- if (cnt < params_batch->get_batch.expired_tot_scan_cnt) {
- DHD_ERROR(("Buffer size is small to save all batch entry,"
- " cnt : %d (remained_scan_cnt): %d\n",
- cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt));
- }
- params_batch->get_batch.expired_tot_scan_cnt -= cnt;
- /* set FALSE only if the link list is empty after returning the data */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) {
- GCC_DIAGNOSTIC_POP();
- params_batch->get_batch.batch_started = FALSE;
- bp += snprintf(bp, nleftsize, "%s", RESULTS_END_MARKER);
- DHD_PNO(("%s", RESULTS_END_MARKER));
- DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__));
- }
- /* return used memory in buffer */
- bytes_written = (int32)(bp - buf);
- return bytes_written;
- }
- static int
- _dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last)
- {
- int err = BCME_OK;
- int removed_scan_cnt = 0;
- dhd_pno_scan_results_t *siter, *snext;
- dhd_pno_best_header_t *phead, *pprev;
- dhd_pno_bestnet_entry_t *iter, *next;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(head, "head is NULL", err);
- NULL_CHECK(head->next, "head->next is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(siter, snext,
- head, list) {
- if (only_last) {
- /* in case that we need to delete only last one */
- if (!list_is_last(&siter->list, head)) {
- /* skip if the one is not last */
- continue;
- }
- }
- /* delete all data belong if the one is last */
- phead = siter->bestnetheader;
- while (phead != NULL) {
- removed_scan_cnt++;
- list_for_each_entry_safe(iter, next,
- &phead->entry_list, list) {
- list_del(&iter->list);
- MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE);
- }
- pprev = phead;
- phead = phead->next;
- MFREE(dhd->osh, pprev, BEST_HEADER_SIZE);
- }
- if (phead == NULL) {
- /* it is ok to delete top node */
- list_del(&siter->list);
- MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE);
- }
- }
- GCC_DIAGNOSTIC_POP();
- return removed_scan_cnt;
- }
- static int
- _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan)
- {
- int err = BCME_OK;
- int i = 0;
- wl_pfn_cfg_t pfncfg_param;
- NULL_CHECK(dhd, "dhd is NULL", err);
- if (nchan) {
- NULL_CHECK(channel_list, "nchan is NULL", err);
- }
- if (nchan > WL_NUMCHANNELS) {
- return BCME_RANGE;
- }
- DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan));
- memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t));
- /* Setup default values */
- pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET);
- pfncfg_param.channel_num = htod32(0);
- for (i = 0; i < nchan; i++)
- pfncfg_param.channel_list[i] = channel_list[i];
- pfncfg_param.channel_num = htod32(nchan);
- err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0,
- TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__));
- goto exit;
- }
- exit:
- return err;
- }
- static int
- _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode)
- {
- int err = BCME_OK;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- mutex_lock(&_pno_state->pno_mutex);
- switch (mode) {
- case DHD_PNO_LEGACY_MODE: {
- struct dhd_pno_ssid *iter, *next;
- if (params->params_legacy.nssid > 0) {
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- ¶ms->params_legacy.ssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_del(&iter->list);
- MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid));
- }
- }
- params->params_legacy.nssid = 0;
- params->params_legacy.scan_fr = 0;
- params->params_legacy.pno_freq_expo_max = 0;
- params->params_legacy.pno_repeat = 0;
- params->params_legacy.nchan = 0;
- memset(params->params_legacy.chan_list, 0,
- sizeof(params->params_legacy.chan_list));
- break;
- }
- case DHD_PNO_BATCH_MODE: {
- params->params_batch.scan_fr = 0;
- params->params_batch.mscan = 0;
- params->params_batch.nchan = 0;
- params->params_batch.rtt = 0;
- params->params_batch.bestn = 0;
- params->params_batch.nchan = 0;
- params->params_batch.band = WLC_BAND_AUTO;
- memset(params->params_batch.chan_list, 0,
- sizeof(params->params_batch.chan_list));
- params->params_batch.get_batch.batch_started = FALSE;
- params->params_batch.get_batch.buf = NULL;
- params->params_batch.get_batch.bufsize = 0;
- params->params_batch.get_batch.reason = 0;
- _dhd_pno_clear_all_batch_results(dhd,
- ¶ms->params_batch.get_batch.scan_results_list, FALSE);
- _dhd_pno_clear_all_batch_results(dhd,
- ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE);
- params->params_batch.get_batch.tot_scan_cnt = 0;
- params->params_batch.get_batch.expired_tot_scan_cnt = 0;
- params->params_batch.get_batch.top_node_cnt = 0;
- INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list);
- INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list);
- break;
- }
- case DHD_PNO_HOTLIST_MODE: {
- struct dhd_pno_bssid *iter, *next;
- if (params->params_hotlist.nbssid > 0) {
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- ¶ms->params_hotlist.bssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_del(&iter->list);
- MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid));
- }
- }
- params->params_hotlist.scan_fr = 0;
- params->params_hotlist.nbssid = 0;
- params->params_hotlist.nchan = 0;
- params->params_batch.band = WLC_BAND_AUTO;
- memset(params->params_hotlist.chan_list, 0,
- sizeof(params->params_hotlist.chan_list));
- break;
- }
- default:
- DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode));
- break;
- }
- mutex_unlock(&_pno_state->pno_mutex);
- return err;
- }
- static int
- _dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid)
- {
- int err = BCME_OK;
- NULL_CHECK(dhd, "dhd is NULL", err);
- if (nbssid) {
- NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err);
- }
- err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid,
- sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__));
- goto exit;
- }
- exit:
- return err;
- }
- int
- dhd_pno_stop_for_ssid(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- uint32 mode = 0, cnt = 0;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params = NULL;
- wl_pfn_bssid_t *p_pfn_bssid = NULL, *tmp_bssid;
- NULL_CHECK(dhd, "dev is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) {
- DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__));
- goto exit;
- }
- DHD_PNO(("%s enter\n", __FUNCTION__));
- /* If pno mode is PNO_LEGACY_MODE clear the pno values and unset the DHD_PNO_LEGACY_MODE */
- _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
- _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
- #ifdef GSCAN_SUPPORT
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- struct dhd_pno_gscan_params *gscan_params;
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- gscan_params = &_params->params_gscan;
- if (gscan_params->mscan) {
- /* retrieve the batching data from firmware into host */
- err = dhd_wait_batch_results_complete(dhd);
- if (err != BCME_OK)
- goto exit;
- }
- /* save current pno_mode before calling dhd_pno_clean */
- mutex_lock(&_pno_state->pno_mutex);
- mode = _pno_state->pno_mode;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- mutex_unlock(&_pno_state->pno_mutex);
- goto exit;
- }
- /* restore previous pno_mode */
- _pno_state->pno_mode = mode;
- mutex_unlock(&_pno_state->pno_mutex);
- /* Restart gscan */
- err = dhd_pno_initiate_gscan_request(dhd, 1, 0);
- goto exit;
- }
- #endif /* GSCAN_SUPPORT */
- /* restart Batch mode if the batch mode is on */
- if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) {
- /* retrieve the batching data from firmware into host */
- dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE);
- /* save current pno_mode before calling dhd_pno_clean */
- mode = _pno_state->pno_mode;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- err = BCME_ERROR;
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- /* restore previous pno_mode */
- _pno_state->pno_mode = mode;
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]);
- /* restart BATCH SCAN */
- err = dhd_pno_set_for_batch(dhd, &_params->params_batch);
- if (err < 0) {
- _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
- DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
- /* restart HOTLIST SCAN */
- struct dhd_pno_bssid *iter, *next;
- _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
- p_pfn_bssid = MALLOCZ(dhd->osh, sizeof(wl_pfn_bssid_t) *
- _params->params_hotlist.nbssid);
- if (p_pfn_bssid == NULL) {
- DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
- " (count: %d)",
- __FUNCTION__, _params->params_hotlist.nbssid));
- err = BCME_ERROR;
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- goto exit;
- }
- /* convert dhd_pno_bssid to wl_pfn_bssid */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- cnt = 0;
- tmp_bssid = p_pfn_bssid;
- list_for_each_entry_safe(iter, next,
- &_params->params_hotlist.bssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- memcpy(&tmp_bssid->macaddr,
- &iter->macaddr, ETHER_ADDR_LEN);
- tmp_bssid->flags = iter->flags;
- if (cnt < _params->params_hotlist.nbssid) {
- tmp_bssid++;
- cnt++;
- } else {
- DHD_ERROR(("%s: Allocated insufficient memory\n",
- __FUNCTION__));
- break;
- }
- }
- err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist);
- if (err < 0) {
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- } else {
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- exit:
- if (p_pfn_bssid) {
- MFREE(dhd->osh, p_pfn_bssid, sizeof(wl_pfn_bssid_t) *
- _params->params_hotlist.nbssid);
- }
- return err;
- }
- int
- dhd_pno_enable(dhd_pub_t *dhd, int enable)
- {
- int err = BCME_OK;
- NULL_CHECK(dhd, "dhd is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- return (_dhd_pno_enable(dhd, enable));
- }
- static int
- dhd_pno_add_to_ssid_list(dhd_pub_t *dhd, struct list_head *ptr, wlc_ssid_ext_t *ssid_list,
- int nssid, int *num_ssid_added)
- {
- int ret = BCME_OK;
- int i;
- struct dhd_pno_ssid *_pno_ssid;
- for (i = 0; i < nssid; i++) {
- if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s : Invalid SSID length %d\n",
- __FUNCTION__, ssid_list[i].SSID_len));
- ret = BCME_ERROR;
- goto exit;
- }
- /* Check for broadcast ssid */
- if (!ssid_list[i].SSID_len) {
- DHD_ERROR(("%d: Broadcast SSID is illegal for PNO setting\n", i));
- ret = BCME_ERROR;
- goto exit;
- }
- _pno_ssid = (struct dhd_pno_ssid *)MALLOCZ(dhd->osh,
- sizeof(struct dhd_pno_ssid));
- if (_pno_ssid == NULL) {
- DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n",
- __FUNCTION__));
- ret = BCME_ERROR;
- goto exit;
- }
- _pno_ssid->SSID_len = ssid_list[i].SSID_len;
- _pno_ssid->hidden = ssid_list[i].hidden;
- _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh;
- _pno_ssid->flags = ssid_list[i].flags;
- _pno_ssid->wpa_auth = WPA_AUTH_PFN_ANY;
- memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len);
- list_add_tail(&_pno_ssid->list, ptr);
- }
- exit:
- *num_ssid_added = i;
- return ret;
- }
- int
- dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid,
- uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
- {
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- struct dhd_pno_legacy_params *params_legacy;
- int err = BCME_OK;
- if (!dhd || !dhd->pno_state) {
- DHD_ERROR(("%s: PNO Not enabled/Not ready\n", __FUNCTION__));
- return BCME_NOTREADY;
- }
- if (!dhd_support_sta_mode(dhd)) {
- return BCME_BADOPTION;
- }
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
- params_legacy = &(_params->params_legacy);
- err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n",
- __FUNCTION__, err));
- return err;
- }
- INIT_LIST_HEAD(¶ms_legacy->ssid_list);
- if (dhd_pno_add_to_ssid_list(dhd, ¶ms_legacy->ssid_list, ssid_list,
- nssid, ¶ms_legacy->nssid) < 0) {
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
- return BCME_ERROR;
- }
- DHD_PNO(("%s enter : nssid %d, scan_fr :%d, pno_repeat :%d,"
- "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__,
- params_legacy->nssid, scan_fr, pno_repeat, pno_freq_expo_max, nchan));
- return dhd_pno_set_legacy_pno(dhd, scan_fr, pno_repeat,
- pno_freq_expo_max, channel_list, nchan);
- }
- static int
- dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat,
- int pno_freq_expo_max, uint16 *channel_list, int nchan)
- {
- dhd_pno_params_t *_params;
- dhd_pno_params_t *_params2;
- dhd_pno_status_info_t *_pno_state;
- uint16 _chan_list[WL_NUMCHANNELS];
- int32 tot_nchan = 0;
- int err = BCME_OK;
- int i, nssid;
- int mode = 0;
- struct list_head *ssid_list;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
- /* If GSCAN is also ON will handle this down below */
- #ifdef GSCAN_SUPPORT
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE &&
- !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) {
- #else
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- #endif /* GSCAN_SUPPORT */
- DHD_ERROR(("%s : Legacy PNO mode was already started, "
- "will disable previous one to start new one\n", __FUNCTION__));
- err = dhd_pno_stop_for_ssid(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n",
- __FUNCTION__, err));
- return err;
- }
- }
- _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE;
- memset(_chan_list, 0, sizeof(_chan_list));
- tot_nchan = MIN(nchan, WL_NUMCHANNELS);
- if (tot_nchan > 0 && channel_list) {
- for (i = 0; i < tot_nchan; i++)
- _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i];
- }
- #ifdef GSCAN_SUPPORT
- else {
- tot_nchan = WL_NUMCHANNELS;
- err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan,
- (WLC_BAND_2G | WLC_BAND_5G), FALSE);
- if (err < 0) {
- tot_nchan = 0;
- DHD_PNO(("Could not get channel list for PNO SSID\n"));
- } else {
- for (i = 0; i < tot_nchan; i++)
- _params->params_legacy.chan_list[i] = _chan_list[i];
- }
- }
- #endif /* GSCAN_SUPPORT */
- if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) {
- DHD_PNO(("BATCH SCAN is on progress in firmware\n"));
- /* retrieve the batching data from firmware into host */
- dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE);
- /* store current pno_mode before disabling pno */
- mode = _pno_state->pno_mode;
- err = _dhd_pno_enable(dhd, PNO_OFF);
- if (err < 0) {
- DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__));
- goto exit;
- }
- /* restore the previous mode */
- _pno_state->pno_mode = mode;
- /* use superset of channel list between two mode */
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]);
- if (_params2->params_batch.nchan > 0 && tot_nchan > 0) {
- err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
- &_params2->params_batch.chan_list[0],
- _params2->params_batch.nchan,
- &channel_list[0], tot_nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to merge channel list"
- " between legacy and batch\n",
- __FUNCTION__));
- goto exit;
- }
- } else {
- DHD_PNO(("superset channel will use"
- " all channels in firmware\n"));
- }
- } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
- _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
- if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) {
- err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
- &_params2->params_hotlist.chan_list[0],
- _params2->params_hotlist.nchan,
- &channel_list[0], tot_nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to merge channel list"
- " between legacy and hotlist\n",
- __FUNCTION__));
- goto exit;
- }
- }
- }
- }
- _params->params_legacy.scan_fr = scan_fr;
- _params->params_legacy.pno_repeat = pno_repeat;
- _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max;
- _params->params_legacy.nchan = tot_nchan;
- ssid_list = &_params->params_legacy.ssid_list;
- nssid = _params->params_legacy.nssid;
- #ifdef GSCAN_SUPPORT
- /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- struct dhd_pno_gscan_params *gscan_params;
- gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan;
- /* ePNO and Legacy PNO do not co-exist */
- if (gscan_params->epno_cfg.num_epno_ssid) {
- DHD_PNO(("ePNO and Legacy PNO do not co-exist\n"));
- err = BCME_EPERM;
- goto exit;
- }
- DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n"));
- err = dhd_pno_initiate_gscan_request(dhd, 1, 0);
- goto exit;
- }
- #endif /* GSCAN_SUPPORT */
- if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) {
- DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err));
- goto exit;
- }
- if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) {
- DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid));
- goto exit;
- }
- if (tot_nchan > 0) {
- if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- if (_pno_state->pno_status == DHD_PNO_DISABLED) {
- if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0)
- DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__));
- }
- exit:
- if (err < 0) {
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
- }
- /* clear mode in case of error */
- if (err < 0) {
- int ret = dhd_pno_clean(dhd);
- if (ret < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, ret));
- } else {
- _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
- }
- }
- return err;
- }
- int
- dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params)
- {
- int err = BCME_OK;
- uint16 _chan_list[WL_NUMCHANNELS];
- int rem_nchan = 0, tot_nchan = 0;
- int mode = 0, mscan = 0;
- dhd_pno_params_t *_params;
- dhd_pno_params_t *_params2;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- NULL_CHECK(batch_params, "batch_params is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS];
- if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
- _pno_state->pno_mode |= DHD_PNO_BATCH_MODE;
- err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n",
- __FUNCTION__));
- goto exit;
- }
- } else {
- /* batch mode is already started */
- return -EBUSY;
- }
- _params->params_batch.scan_fr = batch_params->scan_fr;
- _params->params_batch.bestn = batch_params->bestn;
- _params->params_batch.mscan = (batch_params->mscan)?
- batch_params->mscan : DEFAULT_BATCH_MSCAN;
- _params->params_batch.nchan = batch_params->nchan;
- memcpy(_params->params_batch.chan_list, batch_params->chan_list,
- sizeof(_params->params_batch.chan_list));
- memset(_chan_list, 0, sizeof(_chan_list));
- rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan;
- if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) {
- /* get a valid channel list based on band B or A */
- err = _dhd_pno_get_channels(dhd,
- &_params->params_batch.chan_list[batch_params->nchan],
- &rem_nchan, batch_params->band, FALSE);
- if (err < 0) {
- DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n",
- __FUNCTION__, batch_params->band));
- goto exit;
- }
- /* now we need to update nchan because rem_chan has valid channel count */
- _params->params_batch.nchan += rem_nchan;
- /* need to sort channel list */
- sort(_params->params_batch.chan_list, _params->params_batch.nchan,
- sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL);
- }
- #ifdef PNO_DEBUG
- {
- DHD_PNO(("Channel list : "));
- for (i = 0; i < _params->params_batch.nchan; i++) {
- DHD_PNO(("%d ", _params->params_batch.chan_list[i]));
- }
- DHD_PNO(("\n"));
- }
- #endif // endif
- if (_params->params_batch.nchan) {
- /* copy the channel list into local array */
- memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list));
- tot_nchan = _params->params_batch.nchan;
- }
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- DHD_PNO(("PNO SSID is on progress in firmware\n"));
- /* store current pno_mode before disabling pno */
- mode = _pno_state->pno_mode;
- err = _dhd_pno_enable(dhd, PNO_OFF);
- if (err < 0) {
- DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__));
- goto exit;
- }
- /* restore the previous mode */
- _pno_state->pno_mode = mode;
- /* Use the superset for channelist between two mode */
- _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
- if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) {
- err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
- &_params2->params_legacy.chan_list[0],
- _params2->params_legacy.nchan,
- &_params->params_batch.chan_list[0], _params->params_batch.nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to merge channel list"
- " between legacy and batch\n",
- __FUNCTION__));
- goto exit;
- }
- } else {
- DHD_PNO(("superset channel will use all channels in firmware\n"));
- }
- if ((err = _dhd_pno_add_ssid(dhd, &_params2->params_legacy.ssid_list,
- _params2->params_legacy.nssid)) < 0) {
- DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
- goto exit;
- }
- }
- if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- } else {
- /* we need to return mscan */
- mscan = err;
- }
- if (tot_nchan > 0) {
- if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- if (_pno_state->pno_status == DHD_PNO_DISABLED) {
- if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0)
- DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__));
- }
- exit:
- /* clear mode in case of error */
- if (err < 0)
- _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
- else {
- /* return #max scan firmware can do */
- err = mscan;
- }
- return err;
- }
- #ifdef GSCAN_SUPPORT
- static int
- dhd_set_epno_params(dhd_pub_t *dhd, wl_ssid_ext_params_t *params, bool set)
- {
- wl_pfn_ssid_cfg_t cfg;
- int err;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- memset(&cfg, 0, sizeof(wl_pfn_ssid_cfg_t));
- cfg.version = WL_PFN_SSID_CFG_VERSION;
- /* If asked to clear params (set == FALSE) just set the CLEAR bit */
- if (!set)
- cfg.flags |= WL_PFN_SSID_CFG_CLEAR;
- else if (params)
- memcpy(&cfg.params, params, sizeof(wl_ssid_ext_params_t));
- err = dhd_iovar(dhd, 0, "pfn_ssid_cfg", (char *)&cfg,
- sizeof(wl_pfn_ssid_cfg_t), NULL, 0, TRUE);
- if (err != BCME_OK) {
- DHD_ERROR(("%s : Failed to execute pfn_ssid_cfg %d\n", __FUNCTION__, err));
- }
- return err;
- }
- int
- dhd_pno_flush_fw_epno(dhd_pub_t *dhd)
- {
- int err;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- err = dhd_set_epno_params(dhd, NULL, FALSE);
- if (err < 0) {
- DHD_ERROR(("failed to set ePNO params %d\n", err));
- return err;
- }
- err = _dhd_pno_flush_ssid(dhd);
- return err;
- }
- int
- dhd_pno_set_epno(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- dhd_pno_params_t *params;
- dhd_pno_status_info_t *_pno_state;
- struct dhd_pno_gscan_params *gscan_params;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- gscan_params = ¶ms->params_gscan;
- if (gscan_params->epno_cfg.num_epno_ssid) {
- DHD_PNO(("num_epno_ssid %d\n", gscan_params->epno_cfg.num_epno_ssid));
- if ((err = _dhd_pno_add_ssid(dhd, &gscan_params->epno_cfg.epno_ssid_list,
- gscan_params->epno_cfg.num_epno_ssid)) < 0) {
- DHD_ERROR(("failed to add ssid list (err %d) to firmware\n", err));
- return err;
- }
- err = dhd_set_epno_params(dhd, &gscan_params->epno_cfg.params, TRUE);
- if (err < 0) {
- DHD_ERROR(("failed to set ePNO params %d\n", err));
- }
- }
- return err;
- }
- static void
- dhd_pno_reset_cfg_gscan(dhd_pub_t *dhd, dhd_pno_params_t *_params,
- dhd_pno_status_info_t *_pno_state, uint8 flags)
- {
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (flags & GSCAN_FLUSH_SCAN_CFG) {
- _params->params_gscan.bestn = 0;
- _params->params_gscan.mscan = 0;
- _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
- _params->params_gscan.scan_fr = 0;
- _params->params_gscan.send_all_results_flag = 0;
- memset(_params->params_gscan.channel_bucket, 0,
- _params->params_gscan.nchannel_buckets *
- sizeof(struct dhd_pno_gscan_channel_bucket));
- _params->params_gscan.nchannel_buckets = 0;
- DHD_PNO(("Flush Scan config\n"));
- }
- if (flags & GSCAN_FLUSH_HOTLIST_CFG) {
- struct dhd_pno_bssid *iter, *next;
- if (_params->params_gscan.nbssid_hotlist > 0) {
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &_params->params_gscan.hotlist_bssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_del(&iter->list);
- MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid));
- }
- }
- _params->params_gscan.nbssid_hotlist = 0;
- DHD_PNO(("Flush Hotlist Config\n"));
- }
- if (flags & GSCAN_FLUSH_EPNO_CFG) {
- dhd_pno_ssid_t *iter, *next;
- dhd_epno_ssid_cfg_t *epno_cfg = &_params->params_gscan.epno_cfg;
- if (epno_cfg->num_epno_ssid > 0) {
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &epno_cfg->epno_ssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_del(&iter->list);
- MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid));
- }
- epno_cfg->num_epno_ssid = 0;
- }
- memset(&epno_cfg->params, 0, sizeof(wl_ssid_ext_params_t));
- DHD_PNO(("Flushed ePNO Config\n"));
- }
- return;
- }
- int
- dhd_pno_lock_batch_results(dhd_pub_t *dhd)
- {
- dhd_pno_status_info_t *_pno_state;
- int err = BCME_OK;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- mutex_lock(&_pno_state->pno_mutex);
- return err;
- }
- void
- dhd_pno_unlock_batch_results(dhd_pub_t *dhd)
- {
- dhd_pno_status_info_t *_pno_state;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- mutex_unlock(&_pno_state->pno_mutex);
- return;
- }
- int
- dhd_wait_batch_results_complete(dhd_pub_t *dhd)
- {
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- int err = BCME_OK;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- /* Has the workqueue finished its job already?? */
- if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) {
- DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__));
- wait_event_interruptible_timeout(_pno_state->batch_get_wait,
- is_batch_retrieval_complete(&_params->params_gscan),
- msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT));
- } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */
- gscan_results_cache_t *iter;
- uint16 num_results = 0;
- mutex_lock(&_pno_state->pno_mutex);
- iter = _params->params_gscan.gscan_batch_cache;
- while (iter) {
- num_results += iter->tot_count - iter->tot_consumed;
- iter = iter->next;
- }
- mutex_unlock(&_pno_state->pno_mutex);
- /* All results consumed/No results cached??
- * Get fresh results from FW
- */
- if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) {
- DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__));
- err = dhd_retreive_batch_scan_results(dhd);
- if (err == BCME_OK) {
- wait_event_interruptible_timeout(_pno_state->batch_get_wait,
- is_batch_retrieval_complete(&_params->params_gscan),
- msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT));
- }
- }
- }
- DHD_PNO(("%s: Wait complete\n", __FUNCTION__));
- return err;
- }
- int
- dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
- void *buf, bool flush)
- {
- int err = BCME_OK;
- dhd_pno_params_t *_params;
- int i;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- mutex_lock(&_pno_state->pno_mutex);
- switch (type) {
- case DHD_PNO_BATCH_SCAN_CFG_ID:
- {
- gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf;
- _params->params_gscan.bestn = ptr->bestn;
- _params->params_gscan.mscan = ptr->mscan;
- _params->params_gscan.buffer_threshold = ptr->buffer_threshold;
- }
- break;
- case DHD_PNO_GEOFENCE_SCAN_CFG_ID:
- {
- gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf;
- struct dhd_pno_bssid *_pno_bssid;
- struct bssid_t *bssid_ptr;
- int8 flags;
- if (flush) {
- dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state,
- GSCAN_FLUSH_HOTLIST_CFG);
- }
- if (!ptr->nbssid) {
- break;
- }
- if (!_params->params_gscan.nbssid_hotlist) {
- INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list);
- }
- if ((_params->params_gscan.nbssid_hotlist +
- ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
- DHD_ERROR(("Excessive number of hotlist APs programmed %d\n",
- (_params->params_gscan.nbssid_hotlist +
- ptr->nbssid)));
- err = BCME_RANGE;
- goto exit;
- }
- for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) {
- _pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh,
- sizeof(struct dhd_pno_bssid));
- if (!_pno_bssid) {
- DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes",
- sizeof(struct dhd_pno_bssid)));
- err = BCME_NOMEM;
- goto exit;
- }
- memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, ETHER_ADDR_LEN);
- flags = (int8) bssid_ptr->rssi_reporting_threshold;
- _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT;
- list_add_tail(&_pno_bssid->list,
- &_params->params_gscan.hotlist_bssid_list);
- }
- _params->params_gscan.nbssid_hotlist += ptr->nbssid;
- _params->params_gscan.lost_ap_window = ptr->lost_ap_window;
- }
- break;
- case DHD_PNO_SCAN_CFG_ID:
- {
- int k;
- uint16 band;
- gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf;
- struct dhd_pno_gscan_channel_bucket *ch_bucket;
- if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) {
- _params->params_gscan.nchannel_buckets = ptr->nchannel_buckets;
- memcpy(_params->params_gscan.channel_bucket, ptr->channel_bucket,
- _params->params_gscan.nchannel_buckets *
- sizeof(struct dhd_pno_gscan_channel_bucket));
- ch_bucket = _params->params_gscan.channel_bucket;
- for (i = 0; i < ptr->nchannel_buckets; i++) {
- band = ch_bucket[i].band;
- for (k = 0; k < ptr->channel_bucket[i].num_channels; k++) {
- ch_bucket[i].chan_list[k] =
- wf_mhz2channel(ptr->channel_bucket[i].chan_list[k],
- 0);
- }
- ch_bucket[i].band = 0;
- /* HAL and DHD use different bits for 2.4G and
- * 5G in bitmap. Hence translating it here...
- */
- if (band & GSCAN_BG_BAND_MASK) {
- ch_bucket[i].band |= WLC_BAND_2G;
- }
- if (band & GSCAN_A_BAND_MASK) {
- ch_bucket[i].band |= WLC_BAND_5G;
- }
- if (band & GSCAN_DFS_MASK) {
- ch_bucket[i].band |= GSCAN_DFS_MASK;
- }
- DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band,
- ch_bucket[i].report_flag));
- }
- for (i = 0; i < ptr->nchannel_buckets; i++) {
- ch_bucket[i].bucket_freq_multiple =
- ch_bucket[i].bucket_freq_multiple/ptr->scan_fr;
- ch_bucket[i].bucket_max_multiple =
- ch_bucket[i].bucket_max_multiple/ptr->scan_fr;
- DHD_PNO(("mult %d max_mult %d\n",
- ch_bucket[i].bucket_freq_multiple,
- ch_bucket[i].bucket_max_multiple));
- }
- _params->params_gscan.scan_fr = ptr->scan_fr;
- DHD_PNO(("num_buckets %d scan_fr %d\n", ptr->nchannel_buckets,
- _params->params_gscan.scan_fr));
- } else {
- err = BCME_BADARG;
- }
- }
- break;
- case DHD_PNO_EPNO_CFG_ID:
- if (flush) {
- dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state,
- GSCAN_FLUSH_EPNO_CFG);
- }
- break;
- case DHD_PNO_EPNO_PARAMS_ID:
- if (flush) {
- memset(&_params->params_gscan.epno_cfg.params, 0,
- sizeof(wl_ssid_ext_params_t));
- }
- if (buf) {
- memcpy(&_params->params_gscan.epno_cfg.params, buf,
- sizeof(wl_ssid_ext_params_t));
- }
- break;
- default:
- err = BCME_BADARG;
- DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
- break;
- }
- exit:
- mutex_unlock(&_pno_state->pno_mutex);
- return err;
- }
- static bool
- validate_gscan_params(struct dhd_pno_gscan_params *gscan_params)
- {
- unsigned int i, k;
- if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) {
- DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n",
- __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets));
- return false;
- }
- for (i = 0; i < gscan_params->nchannel_buckets; i++) {
- if (!gscan_params->channel_bucket[i].band) {
- for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) {
- if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) {
- DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__,
- gscan_params->channel_bucket[i].chan_list[k]));
- return false;
- }
- }
- }
- }
- return true;
- }
- static int
- dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params)
- {
- int err = BCME_OK;
- int mode, i = 0;
- uint16 _chan_list[WL_NUMCHANNELS];
- int tot_nchan = 0;
- int num_buckets_to_fw, tot_num_buckets, gscan_param_size = 0;
- dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
- wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL;
- wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL;
- wl_pfn_bssid_t *p_pfn_bssid = NULL;
- dhd_pno_params_t *_params;
- bool fw_flushed = FALSE;
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- NULL_CHECK(gscan_params, "gscan_params is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- if (!validate_gscan_params(gscan_params)) {
- DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__));
- err = BCME_BADARG;
- goto exit;
- }
- if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state,
- _chan_list, &tot_num_buckets, &num_buckets_to_fw))) {
- goto exit;
- }
- mutex_lock(&_pno_state->pno_mutex);
- /* Clear any pre-existing results in our cache
- * not consumed by framework
- */
- dhd_gscan_clear_all_batch_results(dhd);
- if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) {
- /* store current pno_mode before disabling pno */
- mode = _pno_state->pno_mode;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__));
- mutex_unlock(&_pno_state->pno_mutex);
- goto exit;
- }
- fw_flushed = TRUE;
- /* restore the previous mode */
- _pno_state->pno_mode = mode;
- }
- _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE;
- mutex_unlock(&_pno_state->pno_mutex);
- if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
- !gscan_params->epno_cfg.num_epno_ssid) {
- struct dhd_pno_legacy_params *params_legacy;
- params_legacy =
- &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
- if ((err = _dhd_pno_add_ssid(dhd, ¶ms_legacy->ssid_list,
- params_legacy->nssid)) < 0) {
- DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err));
- goto exit;
- }
- }
- if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) {
- DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err));
- goto exit;
- }
- gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) +
- (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t);
- pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size);
- if (!pfn_gscan_cfg_t) {
- DHD_ERROR(("%s: failed to malloc memory of size %d\n",
- __FUNCTION__, gscan_param_size));
- err = BCME_NOMEM;
- goto exit;
- }
- pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION;
- if (gscan_params->mscan)
- pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold;
- else
- pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET;
- pfn_gscan_cfg_t->flags =
- (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK);
- pfn_gscan_cfg_t->flags |= GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK;
- pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw;
- pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD;
- for (i = 0; i < num_buckets_to_fw; i++) {
- pfn_gscan_cfg_t->channel_bucket[i].bucket_end_index =
- ch_bucket[i].bucket_end_index;
- pfn_gscan_cfg_t->channel_bucket[i].bucket_freq_multiple =
- ch_bucket[i].bucket_freq_multiple;
- pfn_gscan_cfg_t->channel_bucket[i].max_freq_multiple =
- ch_bucket[i].max_freq_multiple;
- pfn_gscan_cfg_t->channel_bucket[i].repeat =
- ch_bucket[i].repeat;
- pfn_gscan_cfg_t->channel_bucket[i].flag =
- ch_bucket[i].flag;
- }
- tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1;
- DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan,
- tot_num_buckets, num_buckets_to_fw));
- if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- /* Reprogram ePNO cfg from dhd cache if FW has been flushed */
- if (fw_flushed) {
- dhd_pno_set_epno(dhd);
- }
- if (gscan_params->nbssid_hotlist) {
- struct dhd_pno_bssid *iter, *next;
- wl_pfn_bssid_t *ptr;
- p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh,
- sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist);
- if (p_pfn_bssid == NULL) {
- DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
- " (count: %d)",
- __FUNCTION__, _params->params_hotlist.nbssid));
- err = BCME_NOMEM;
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- goto exit;
- }
- ptr = p_pfn_bssid;
- /* convert dhd_pno_bssid to wl_pfn_bssid */
- DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist));
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &gscan_params->hotlist_bssid_list, list) {
- char buffer_hotlist[64];
- GCC_DIAGNOSTIC_POP();
- memcpy(&ptr->macaddr,
- &iter->macaddr, ETHER_ADDR_LEN);
- BCM_REFERENCE(buffer_hotlist);
- DHD_PNO(("%s\n", bcm_ether_ntoa(&ptr->macaddr, buffer_hotlist)));
- ptr->flags = iter->flags;
- ptr++;
- }
- err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) {
- DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err));
- }
- exit:
- /* clear mode in case of error */
- if (err < 0) {
- int ret = dhd_pno_clean(dhd);
- if (ret < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, ret));
- } else {
- _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE;
- }
- }
- MFREE(dhd->osh, p_pfn_bssid,
- sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist);
- if (pfn_gscan_cfg_t) {
- MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size);
- }
- if (ch_bucket) {
- MFREE(dhd->osh, ch_bucket,
- (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t)));
- }
- return err;
- }
- static wl_pfn_gscan_ch_bucket_cfg_t *
- dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd,
- dhd_pno_status_info_t *_pno_state,
- uint16 *chan_list,
- uint32 *num_buckets,
- uint32 *num_buckets_to_fw)
- {
- int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt;
- uint16 *ptr = chan_list, max;
- wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket;
- dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- bool is_pno_legacy_running;
- dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket;
- /* ePNO and Legacy PNO do not co-exist */
- is_pno_legacy_running = ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
- !_params->params_gscan.epno_cfg.num_epno_ssid);
- if (is_pno_legacy_running)
- *num_buckets = _params->params_gscan.nchannel_buckets + 1;
- else
- *num_buckets = _params->params_gscan.nchannel_buckets;
- *num_buckets_to_fw = 0;
- ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh,
- ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t)));
- if (!ch_bucket) {
- DHD_ERROR(("%s: failed to malloc memory of size %zd\n",
- __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t)));
- *num_buckets_to_fw = *num_buckets = 0;
- return NULL;
- }
- max = gscan_buckets[0].bucket_freq_multiple;
- num_channels = 0;
- /* nchan is the remaining space left in chan_list buffer
- * So any overflow list of channels is ignored
- */
- for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) {
- if (!gscan_buckets[i].band) {
- ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan);
- num_channels += ch_cnt;
- memcpy(ptr, gscan_buckets[i].chan_list,
- ch_cnt * sizeof(uint16));
- ptr = ptr + ch_cnt;
- } else {
- /* get a valid channel list based on band B or A */
- err = _dhd_pno_get_channels(dhd, ptr,
- &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK),
- !(gscan_buckets[i].band & GSCAN_DFS_MASK));
- if (err < 0) {
- DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n",
- __FUNCTION__, gscan_buckets[i].band));
- MFREE(dhd->osh, ch_bucket,
- ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t)));
- *num_buckets_to_fw = *num_buckets = 0;
- return NULL;
- }
- num_channels += nchan;
- ptr = ptr + nchan;
- }
- ch_bucket[i].bucket_end_index = num_channels - 1;
- ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple;
- ch_bucket[i].repeat = gscan_buckets[i].repeat;
- ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple;
- ch_bucket[i].flag = gscan_buckets[i].report_flag;
- /* HAL and FW interpretations are opposite for this bit */
- ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH;
- if (max < gscan_buckets[i].bucket_freq_multiple)
- max = gscan_buckets[i].bucket_freq_multiple;
- nchan = WL_NUMCHANNELS - num_channels;
- *num_buckets_to_fw = *num_buckets_to_fw + 1;
- DHD_PNO(("end_idx %d freq_mult - %d\n",
- ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple));
- }
- _params->params_gscan.max_ch_bucket_freq = max;
- /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket
- * Get GCF of Legacy PNO and Gscan scanfreq
- */
- if (is_pno_legacy_running) {
- dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
- uint16 *legacy_chan_list = _params1->params_legacy.chan_list;
- uint16 common_freq;
- uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets;
- /* If no space is left then only gscan buckets will be sent to FW */
- if (nchan) {
- common_freq = gcd(_params->params_gscan.scan_fr,
- _params1->params_legacy.scan_fr);
- max = gscan_buckets[0].bucket_freq_multiple;
- /* GSCAN buckets */
- for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) {
- ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr;
- ch_bucket[i].bucket_freq_multiple /= common_freq;
- if (max < gscan_buckets[i].bucket_freq_multiple)
- max = gscan_buckets[i].bucket_freq_multiple;
- }
- /* Legacy PNO bucket */
- ch_bucket[legacy_bucket_idx].bucket_freq_multiple =
- _params1->params_legacy.scan_fr;
- ch_bucket[legacy_bucket_idx].bucket_freq_multiple /=
- common_freq;
- _params->params_gscan.max_ch_bucket_freq = MAX(max,
- ch_bucket[legacy_bucket_idx].bucket_freq_multiple);
- ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR;
- /* Now add channels to the legacy scan bucket */
- for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) {
- ptr[i] = legacy_chan_list[i];
- num_channels++;
- }
- ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1;
- *num_buckets_to_fw = *num_buckets_to_fw + 1;
- DHD_PNO(("end_idx %d freq_mult - %d\n",
- ch_bucket[legacy_bucket_idx].bucket_end_index,
- ch_bucket[legacy_bucket_idx].bucket_freq_multiple));
- }
- }
- return ch_bucket;
- }
- static int
- dhd_pno_stop_for_gscan(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- int mode;
- dhd_pno_status_info_t *_pno_state;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n",
- __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) {
- DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__));
- goto exit;
- }
- if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) {
- /* retrieve the batching data from firmware into host */
- err = dhd_wait_batch_results_complete(dhd);
- if (err != BCME_OK)
- goto exit;
- }
- mutex_lock(&_pno_state->pno_mutex);
- mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- mutex_unlock(&_pno_state->pno_mutex);
- return err;
- }
- _pno_state->pno_mode = mode;
- mutex_unlock(&_pno_state->pno_mutex);
- /* Reprogram Legacy PNO if it was running */
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- struct dhd_pno_legacy_params *params_legacy;
- uint16 chan_list[WL_NUMCHANNELS];
- params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
- _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
- DHD_PNO(("Restarting Legacy PNO SSID scan...\n"));
- memcpy(chan_list, params_legacy->chan_list,
- (params_legacy->nchan * sizeof(uint16)));
- err = dhd_pno_set_legacy_pno(dhd, params_legacy->scan_fr,
- params_legacy->pno_repeat, params_legacy->pno_freq_expo_max,
- chan_list, params_legacy->nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- exit:
- return err;
- }
- int
- dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush)
- {
- int err = BCME_OK;
- dhd_pno_params_t *params;
- dhd_pno_status_info_t *_pno_state;
- struct dhd_pno_gscan_params *gscan_params;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush));
- params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- gscan_params = ¶ms->params_gscan;
- if (run) {
- err = dhd_pno_set_for_gscan(dhd, gscan_params);
- } else {
- if (flush) {
- mutex_lock(&_pno_state->pno_mutex);
- dhd_pno_reset_cfg_gscan(dhd, params, _pno_state, GSCAN_FLUSH_ALL_CFG);
- mutex_unlock(&_pno_state->pno_mutex);
- }
- /* Need to stop all gscan */
- err = dhd_pno_stop_for_gscan(dhd);
- }
- return err;
- }
- int
- dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag)
- {
- int err = BCME_OK;
- dhd_pno_params_t *params;
- dhd_pno_status_info_t *_pno_state;
- struct dhd_pno_gscan_params *gscan_params;
- uint8 old_flag;
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- gscan_params = ¶ms->params_gscan;
- mutex_lock(&_pno_state->pno_mutex);
- old_flag = gscan_params->send_all_results_flag;
- gscan_params->send_all_results_flag = (uint8) real_time_flag;
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- if (old_flag != gscan_params->send_all_results_flag) {
- wl_pfn_gscan_cfg_t gscan_cfg;
- gscan_cfg.version = WL_GSCAN_CFG_VERSION;
- gscan_cfg.flags = (gscan_params->send_all_results_flag &
- GSCAN_SEND_ALL_RESULTS_MASK);
- gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK;
- if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg,
- sizeof(wl_pfn_gscan_cfg_t))) < 0) {
- DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit_mutex_unlock;
- }
- } else {
- DHD_PNO(("No change in flag - %d\n", old_flag));
- }
- } else {
- DHD_PNO(("Gscan not started\n"));
- }
- exit_mutex_unlock:
- mutex_unlock(&_pno_state->pno_mutex);
- exit:
- return err;
- }
- /* Cleanup any consumed results
- * Return TRUE if all results consumed else FALSE
- */
- int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd)
- {
- int ret = 0;
- dhd_pno_params_t *params;
- struct dhd_pno_gscan_params *gscan_params;
- dhd_pno_status_info_t *_pno_state;
- gscan_results_cache_t *iter, *tmp;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- gscan_params = ¶ms->params_gscan;
- iter = gscan_params->gscan_batch_cache;
- while (iter) {
- if (iter->tot_consumed == iter->tot_count) {
- tmp = iter->next;
- MFREE(dhd->osh, iter,
- ((iter->tot_count - 1) * sizeof(wifi_gscan_result_t))
- + sizeof(gscan_results_cache_t));
- iter = tmp;
- } else
- break;
- }
- gscan_params->gscan_batch_cache = iter;
- ret = (iter == NULL);
- return ret;
- }
- static int
- _dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- uint32 timestamp = 0, ts = 0, i, j, timediff;
- dhd_pno_params_t *params;
- dhd_pno_status_info_t *_pno_state;
- wl_pfn_lnet_info_v1_t *plnetinfo;
- wl_pfn_lnet_info_v2_t *plnetinfo_v2;
- struct dhd_pno_gscan_params *gscan_params;
- wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL;
- wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL;
- gscan_results_cache_t *iter, *tail;
- wifi_gscan_result_t *result;
- uint8 *nAPs_per_scan = NULL;
- uint8 num_scans_in_cur_iter;
- uint16 count;
- uint16 fwcount;
- uint16 fwstatus = PFN_INCOMPLETE;
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
- struct timespec64 tm_spec;
- #else
- struct timespec tm_spec;
- #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
- /* Static asserts in _dhd_pno_get_for_batch() below guarantee the v1 and v2
- * net_info and subnet_info structures are compatible in size and SSID offset,
- * allowing v1 to be safely used in the code below except for lscanresults
- * fields themselves (status, count, offset to netinfo).
- */
- NULL_CHECK(dhd, "dhd is NULL\n", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) {
- DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__));
- goto exit;
- }
- gscan_params = ¶ms->params_gscan;
- nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan);
- if (!nAPs_per_scan) {
- DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__,
- gscan_params->mscan));
- err = BCME_NOMEM;
- goto exit;
- }
- plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
- if (!plbestnet_v1) {
- DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__,
- (int)PNO_BESTNET_LEN));
- err = BCME_NOMEM;
- goto exit;
- }
- plbestnet_v2 = (wl_pfn_lscanresults_v2_t *)plbestnet_v1;
- mutex_lock(&_pno_state->pno_mutex);
- dhd_gscan_clear_all_batch_results(dhd);
- if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) {
- DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__));
- goto exit_mutex_unlock;
- }
- timediff = gscan_params->scan_fr * 1000;
- timediff = timediff >> 1;
- /* Ok, now lets start getting results from the FW */
- tail = gscan_params->gscan_batch_cache;
- do {
- err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN,
- FALSE);
- if (err < 0) {
- DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n",
- __FUNCTION__, err));
- goto exit_mutex_unlock;
- }
- get_monotonic_boottime(&tm_spec);
- if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) {
- fwstatus = plbestnet_v1->status;
- fwcount = plbestnet_v1->count;
- plnetinfo = &plbestnet_v1->netinfo[0];
- DHD_PNO(("ver %d, status : %d, count %d\n",
- plbestnet_v1->version, fwstatus, fwcount));
- if (fwcount == 0) {
- DHD_PNO(("No more batch results\n"));
- goto exit_mutex_unlock;
- }
- if (fwcount > BESTN_MAX) {
- DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
- __FUNCTION__, fwcount, (int)BESTN_MAX));
- /* Process only BESTN_MAX number of results per batch */
- fwcount = BESTN_MAX;
- }
- num_scans_in_cur_iter = 0;
- timestamp = plnetinfo->timestamp;
- /* find out how many scans' results did we get in
- * this batch of FW results
- */
- for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo++) {
- /* Unlikely to happen, but just in case the results from
- * FW doesnt make sense..... Assume its part of one single scan
- */
- if (num_scans_in_cur_iter >= gscan_params->mscan) {
- num_scans_in_cur_iter = 0;
- count = fwcount;
- break;
- }
- if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) {
- nAPs_per_scan[num_scans_in_cur_iter] = count;
- count = 0;
- num_scans_in_cur_iter++;
- }
- timestamp = plnetinfo->timestamp;
- }
- if (num_scans_in_cur_iter < gscan_params->mscan) {
- nAPs_per_scan[num_scans_in_cur_iter] = count;
- num_scans_in_cur_iter++;
- }
- DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter));
- /* reset plnetinfo to the first item for the next loop */
- plnetinfo -= i;
- for (i = 0; i < num_scans_in_cur_iter; i++) {
- iter = (gscan_results_cache_t *)
- MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) *
- sizeof(wifi_gscan_result_t)) +
- sizeof(gscan_results_cache_t));
- if (!iter) {
- DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n",
- __FUNCTION__, gscan_params->mscan));
- err = BCME_NOMEM;
- goto exit_mutex_unlock;
- }
- /* Need this check because the new set of results from FW
- * maybe a continuation of previous sets' scan results
- */
- if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) {
- iter->scan_id = ++gscan_params->scan_id;
- } else {
- iter->scan_id = gscan_params->scan_id;
- }
- DHD_PNO(("scan_id %d tot_count %d \n",
- gscan_params->scan_id, nAPs_per_scan[i]));
- iter->tot_count = nAPs_per_scan[i];
- iter->tot_consumed = 0;
- iter->flag = 0;
- if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
- DHD_PNO(("This scan is aborted\n"));
- iter->flag = (ENABLE << PNO_STATUS_ABORT);
- } else if (gscan_params->reason) {
- iter->flag = (ENABLE << gscan_params->reason);
- }
- if (!tail) {
- gscan_params->gscan_batch_cache = iter;
- } else {
- tail->next = iter;
- }
- tail = iter;
- iter->next = NULL;
- for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) {
- result = &iter->results[j];
- result->channel =
- wf_channel2mhz(plnetinfo->pfnsubnet.channel,
- (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- result->rssi = (int32) plnetinfo->RSSI;
- result->beacon_period = 0;
- result->capability = 0;
- result->rtt = (uint64) plnetinfo->rtt0;
- result->rtt_sd = (uint64) plnetinfo->rtt1;
- result->ts = convert_fw_rel_time_to_systime(&tm_spec,
- plnetinfo->timestamp);
- ts = plnetinfo->timestamp;
- if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s: Invalid SSID length %d\n",
- __FUNCTION__,
- plnetinfo->pfnsubnet.SSID_len));
- plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
- }
- memcpy(result->ssid, plnetinfo->pfnsubnet.SSID,
- plnetinfo->pfnsubnet.SSID_len);
- result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0';
- memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- DHD_PNO(("\tSSID : "));
- DHD_PNO(("\n"));
- DHD_PNO(("\tBSSID: "MACDBG"\n",
- MAC2STRDBG(result->macaddr.octet)));
- DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
- plnetinfo->pfnsubnet.channel,
- plnetinfo->RSSI, plnetinfo->timestamp));
- DHD_PNO(("\tRTT0 : %d, RTT1: %d\n",
- plnetinfo->rtt0, plnetinfo->rtt1));
- }
- }
- } else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) {
- fwstatus = plbestnet_v2->status;
- fwcount = plbestnet_v2->count;
- plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0];
- DHD_PNO(("ver %d, status : %d, count %d\n",
- plbestnet_v2->version, fwstatus, fwcount));
- if (fwcount == 0) {
- DHD_PNO(("No more batch results\n"));
- goto exit_mutex_unlock;
- }
- if (fwcount > BESTN_MAX) {
- DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
- __FUNCTION__, fwcount, (int)BESTN_MAX));
- /* Process only BESTN_MAX number of results per batch */
- fwcount = BESTN_MAX;
- }
- num_scans_in_cur_iter = 0;
- timestamp = plnetinfo_v2->timestamp;
- /* find out how many scans' results did we get
- * in this batch of FW results
- */
- for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo_v2++) {
- /* Unlikely to happen, but just in case the results from
- * FW doesnt make sense..... Assume its part of one single scan
- */
- if (num_scans_in_cur_iter >= gscan_params->mscan) {
- num_scans_in_cur_iter = 0;
- count = fwcount;
- break;
- }
- if (TIME_DIFF_MS(timestamp, plnetinfo_v2->timestamp) > timediff) {
- nAPs_per_scan[num_scans_in_cur_iter] = count;
- count = 0;
- num_scans_in_cur_iter++;
- }
- timestamp = plnetinfo_v2->timestamp;
- }
- if (num_scans_in_cur_iter < gscan_params->mscan) {
- nAPs_per_scan[num_scans_in_cur_iter] = count;
- num_scans_in_cur_iter++;
- }
- DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter));
- /* reset plnetinfo to the first item for the next loop */
- plnetinfo_v2 -= i;
- for (i = 0; i < num_scans_in_cur_iter; i++) {
- iter = (gscan_results_cache_t *)
- MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) *
- sizeof(wifi_gscan_result_t)) +
- sizeof(gscan_results_cache_t));
- if (!iter) {
- DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n",
- __FUNCTION__, gscan_params->mscan));
- err = BCME_NOMEM;
- goto exit_mutex_unlock;
- }
- /* Need this check because the new set of results from FW
- * maybe a continuation of previous sets' scan results
- */
- if (TIME_DIFF_MS(ts, plnetinfo_v2->timestamp) > timediff) {
- iter->scan_id = ++gscan_params->scan_id;
- } else {
- iter->scan_id = gscan_params->scan_id;
- }
- DHD_PNO(("scan_id %d tot_count %d ch_bucket %x\n",
- gscan_params->scan_id, nAPs_per_scan[i],
- plbestnet_v2->scan_ch_buckets[i]));
- iter->tot_count = nAPs_per_scan[i];
- iter->scan_ch_bucket = plbestnet_v2->scan_ch_buckets[i];
- iter->tot_consumed = 0;
- iter->flag = 0;
- if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) {
- DHD_PNO(("This scan is aborted\n"));
- iter->flag = (ENABLE << PNO_STATUS_ABORT);
- } else if (gscan_params->reason) {
- iter->flag = (ENABLE << gscan_params->reason);
- }
- if (!tail) {
- gscan_params->gscan_batch_cache = iter;
- } else {
- tail->next = iter;
- }
- tail = iter;
- iter->next = NULL;
- for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo_v2++) {
- result = &iter->results[j];
- result->channel =
- wf_channel2mhz(plnetinfo_v2->pfnsubnet.channel,
- (plnetinfo_v2->pfnsubnet.channel <=
- CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- result->rssi = (int32) plnetinfo_v2->RSSI;
- /* Info not available & not expected */
- result->beacon_period = 0;
- result->capability = 0;
- result->rtt = (uint64) plnetinfo_v2->rtt0;
- result->rtt_sd = (uint64) plnetinfo_v2->rtt1;
- result->ts = convert_fw_rel_time_to_systime(&tm_spec,
- plnetinfo_v2->timestamp);
- ts = plnetinfo_v2->timestamp;
- if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s: Invalid SSID length %d\n",
- __FUNCTION__,
- plnetinfo_v2->pfnsubnet.SSID_len));
- plnetinfo_v2->pfnsubnet.SSID_len =
- DOT11_MAX_SSID_LEN;
- }
- memcpy(result->ssid, plnetinfo_v2->pfnsubnet.u.SSID,
- plnetinfo_v2->pfnsubnet.SSID_len);
- result->ssid[plnetinfo_v2->pfnsubnet.SSID_len] = '\0';
- memcpy(&result->macaddr, &plnetinfo_v2->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- DHD_PNO(("\tSSID : "));
- DHD_PNO(("\n"));
- DHD_PNO(("\tBSSID: "MACDBG"\n",
- MAC2STRDBG(result->macaddr.octet)));
- DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
- plnetinfo_v2->pfnsubnet.channel,
- plnetinfo_v2->RSSI, plnetinfo_v2->timestamp));
- DHD_PNO(("\tRTT0 : %d, RTT1: %d\n",
- plnetinfo_v2->rtt0, plnetinfo_v2->rtt1));
- }
- }
- } else {
- err = BCME_VERSION;
- DHD_ERROR(("bestnet fw version %d not supported\n",
- plbestnet_v1->version));
- goto exit_mutex_unlock;
- }
- } while (fwstatus == PFN_INCOMPLETE);
- exit_mutex_unlock:
- mutex_unlock(&_pno_state->pno_mutex);
- exit:
- params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE;
- smp_wmb();
- wake_up_interruptible(&_pno_state->batch_get_wait);
- if (nAPs_per_scan) {
- MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan * sizeof(uint8));
- }
- if (plbestnet_v1) {
- MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN);
- }
- DHD_PNO(("Batch retrieval done!\n"));
- return err;
- }
- #endif /* GSCAN_SUPPORT */
- #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
- static void *
- dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len)
- {
- gscan_results_cache_t *iter, *results;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- uint16 num_scan_ids = 0, num_results = 0;
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- iter = results = _params->params_gscan.gscan_batch_cache;
- while (iter) {
- num_results += iter->tot_count - iter->tot_consumed;
- num_scan_ids++;
- iter = iter->next;
- }
- *len = ((num_results << 16) | (num_scan_ids));
- return results;
- }
- void *
- dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
- void *info, uint32 *len)
- {
- void *ret = NULL;
- dhd_pno_gscan_capabilities_t *ptr;
- dhd_pno_ssid_t *ssid_elem;
- dhd_pno_params_t *_params;
- dhd_epno_ssid_cfg_t *epno_cfg;
- dhd_pno_status_info_t *_pno_state;
- if (!dhd || !dhd->pno_state) {
- DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__));
- return NULL;
- }
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- if (!len) {
- DHD_ERROR(("%s: len is NULL\n", __FUNCTION__));
- return NULL;
- }
- switch (type) {
- case DHD_PNO_GET_CAPABILITIES:
- ptr = (dhd_pno_gscan_capabilities_t *)
- MALLOCZ(dhd->osh, sizeof(dhd_pno_gscan_capabilities_t));
- if (!ptr)
- break;
- /* Hardcoding these values for now, need to get
- * these values from FW, will change in a later check-in
- */
- ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE;
- ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS;
- ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN;
- ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX;
- ptr->max_scan_reporting_threshold = 100;
- ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS;
- ptr->max_hotlist_ssids = 0;
- ptr->max_significant_wifi_change_aps = 0;
- ptr->max_bssid_history_entries = 0;
- ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM;
- ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID;
- ptr->max_white_list_ssid = MAX_WHITELIST_SSID;
- ret = (void *)ptr;
- *len = sizeof(dhd_pno_gscan_capabilities_t);
- break;
- case DHD_PNO_GET_BATCH_RESULTS:
- ret = dhd_get_gscan_batch_results(dhd, len);
- break;
- case DHD_PNO_GET_CHANNEL_LIST:
- if (info) {
- uint16 ch_list[WL_NUMCHANNELS];
- uint32 *p, mem_needed, i;
- int32 err, nchan = WL_NUMCHANNELS;
- uint32 *gscan_band = (uint32 *) info;
- uint8 band = 0;
- /* No band specified?, nothing to do */
- if ((*gscan_band & GSCAN_BAND_MASK) == 0) {
- DHD_PNO(("No band specified\n"));
- *len = 0;
- break;
- }
- /* HAL and DHD use different bits for 2.4G and
- * 5G in bitmap. Hence translating it here...
- */
- if (*gscan_band & GSCAN_BG_BAND_MASK) {
- band |= WLC_BAND_2G;
- }
- if (*gscan_band & GSCAN_A_BAND_MASK) {
- band |= WLC_BAND_5G;
- }
- err = _dhd_pno_get_channels(dhd, ch_list, &nchan,
- (band & GSCAN_ABG_BAND_MASK),
- !(*gscan_band & GSCAN_DFS_MASK));
- if (err < 0) {
- DHD_ERROR(("%s: failed to get valid channel list\n",
- __FUNCTION__));
- *len = 0;
- } else {
- mem_needed = sizeof(uint32) * nchan;
- p = (uint32 *)MALLOC(dhd->osh, mem_needed);
- if (!p) {
- DHD_ERROR(("%s: Unable to malloc %d bytes\n",
- __FUNCTION__, mem_needed));
- break;
- }
- for (i = 0; i < nchan; i++) {
- p[i] = wf_channel2mhz(ch_list[i],
- (ch_list[i] <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- }
- ret = p;
- *len = mem_needed;
- }
- } else {
- *len = 0;
- DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__));
- }
- break;
- case DHD_PNO_GET_NEW_EPNO_SSID_ELEM:
- epno_cfg = &_params->params_gscan.epno_cfg;
- if (epno_cfg->num_epno_ssid >=
- MAX_EPNO_SSID_NUM) {
- DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n",
- epno_cfg->num_epno_ssid));
- return NULL;
- }
- if (!epno_cfg->num_epno_ssid) {
- INIT_LIST_HEAD(&epno_cfg->epno_ssid_list);
- }
- ssid_elem = MALLOCZ(dhd->osh, sizeof(dhd_pno_ssid_t));
- if (!ssid_elem) {
- DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes",
- sizeof(dhd_pno_ssid_t)));
- return NULL;
- }
- epno_cfg->num_epno_ssid++;
- list_add_tail(&ssid_elem->list, &epno_cfg->epno_ssid_list);
- ret = ssid_elem;
- break;
- default:
- DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
- break;
- }
- return ret;
- }
- #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
- static int
- _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason)
- {
- int err = BCME_OK;
- int i, j;
- uint32 timestamp = 0;
- dhd_pno_params_t *_params = NULL;
- dhd_pno_status_info_t *_pno_state = NULL;
- wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL;
- wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL;
- wl_pfn_lnet_info_v1_t *plnetinfo;
- wl_pfn_lnet_info_v2_t *plnetinfo_v2;
- dhd_pno_bestnet_entry_t *pbestnet_entry;
- dhd_pno_best_header_t *pbestnetheader = NULL;
- dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext;
- bool allocate_header = FALSE;
- uint16 fwstatus = PFN_INCOMPLETE;
- uint16 fwcount;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- /* The static asserts below guarantee the v1 and v2 net_info and subnet_info
- * structures are compatible in size and SSID offset, allowing v1 to be safely
- * used in the code below except for lscanresults fields themselves
- * (status, count, offset to netinfo).
- */
- STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t));
- STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t));
- STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t));
- STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) ==
- OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID));
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit_no_unlock;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit_no_unlock;
- }
- if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
- DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__));
- goto exit_no_unlock;
- }
- mutex_lock(&_pno_state->pno_mutex);
- _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS];
- if (buf && bufsize) {
- if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) {
- /* need to check whether we have cashed data or not */
- DHD_PNO(("%s: have cashed batching data in Driver\n",
- __FUNCTION__));
- /* convert to results format */
- goto convert_format;
- } else {
- /* this is a first try to get batching results */
- if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) {
- /* move the scan_results_list to expired_scan_results_lists */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(siter, snext,
- &_params->params_batch.get_batch.scan_results_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_move_tail(&siter->list,
- &_params->params_batch.get_batch.expired_scan_results_list);
- }
- _params->params_batch.get_batch.top_node_cnt = 0;
- _params->params_batch.get_batch.expired_tot_scan_cnt =
- _params->params_batch.get_batch.tot_scan_cnt;
- _params->params_batch.get_batch.tot_scan_cnt = 0;
- goto convert_format;
- }
- }
- }
- /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */
- pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE);
- if (pscan_results == NULL) {
- err = BCME_NOMEM;
- DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n"));
- goto exit;
- }
- pscan_results->bestnetheader = NULL;
- pscan_results->cnt_header = 0;
- /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */
- if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) {
- list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list);
- _params->params_batch.get_batch.top_node_cnt++;
- } else {
- int _removed_scan_cnt;
- /* remove oldest one and add new one */
- DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__));
- _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd,
- &_params->params_batch.get_batch.scan_results_list, TRUE);
- _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt;
- list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list);
- }
- plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
- NULL_CHECK(plbestnet_v1, "failed to allocate buffer for bestnet", err);
- plbestnet_v2 = (wl_pfn_lscanresults_v2_t*)plbestnet_v1;
- DHD_PNO(("%s enter\n", __FUNCTION__));
- do {
- err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN,
- FALSE);
- if (err < 0) {
- if (err == BCME_EPERM) {
- DHD_ERROR(("we cannot get the batching data "
- "during scanning in firmware, try again\n,"));
- msleep(500);
- continue;
- } else {
- DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) {
- fwstatus = plbestnet_v1->status;
- fwcount = plbestnet_v1->count;
- plnetinfo = &plbestnet_v1->netinfo[0];
- if (fwcount == 0) {
- DHD_PNO(("No more batch results\n"));
- goto exit;
- }
- if (fwcount > BESTN_MAX) {
- DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
- __FUNCTION__, fwcount, (int)BESTN_MAX));
- /* Process only BESTN_MAX number of results per batch */
- fwcount = BESTN_MAX;
- }
- for (i = 0; i < fwcount; i++) {
- pbestnet_entry = (dhd_pno_bestnet_entry_t *)
- MALLOC(dhd->osh, BESTNET_ENTRY_SIZE);
- if (pbestnet_entry == NULL) {
- err = BCME_NOMEM;
- DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n"));
- goto exit;
- }
- memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE);
- /* record the current time */
- pbestnet_entry->recorded_time = jiffies;
- /* create header for the first entry */
- allocate_header = (i == 0)? TRUE : FALSE;
- /* check whether the new generation is started or not */
- if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp)
- > TIME_MIN_DIFF))
- allocate_header = TRUE;
- timestamp = plnetinfo->timestamp;
- if (allocate_header) {
- pbestnetheader = (dhd_pno_best_header_t *)
- MALLOC(dhd->osh, BEST_HEADER_SIZE);
- if (pbestnetheader == NULL) {
- err = BCME_NOMEM;
- if (pbestnet_entry)
- MFREE(dhd->osh, pbestnet_entry,
- BESTNET_ENTRY_SIZE);
- DHD_ERROR(("failed to allocate"
- " dhd_pno_bestnet_entry\n"));
- goto exit;
- }
- /* increase total cnt of bestnet header */
- pscan_results->cnt_header++;
- /* need to record the reason to call dhd_pno_get_for_bach */
- if (reason)
- pbestnetheader->reason = (ENABLE << reason);
- memset(pbestnetheader, 0, BEST_HEADER_SIZE);
- /* initialize the head of linked list */
- INIT_LIST_HEAD(&(pbestnetheader->entry_list));
- /* link the pbestnet heaer into existed list */
- if (pscan_results->bestnetheader == NULL)
- /* In case of header */
- pscan_results->bestnetheader = pbestnetheader;
- else {
- dhd_pno_best_header_t *head =
- pscan_results->bestnetheader;
- pscan_results->bestnetheader = pbestnetheader;
- pbestnetheader->next = head;
- }
- }
- pbestnet_entry->channel = plnetinfo->pfnsubnet.channel;
- pbestnet_entry->RSSI = plnetinfo->RSSI;
- if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) {
- /* if RSSI is positive value, we assume that
- * this scan is aborted by other scan
- */
- DHD_PNO(("This scan is aborted\n"));
- pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT);
- }
- pbestnet_entry->rtt0 = plnetinfo->rtt0;
- pbestnet_entry->rtt1 = plnetinfo->rtt1;
- pbestnet_entry->timestamp = plnetinfo->timestamp;
- if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s: Invalid SSID length"
- " %d: trimming it to max\n",
- __FUNCTION__, plnetinfo->pfnsubnet.SSID_len));
- plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
- }
- pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len;
- memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID,
- pbestnet_entry->SSID_len);
- memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- /* add the element into list */
- list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list);
- /* increase best entry count */
- pbestnetheader->tot_cnt++;
- pbestnetheader->tot_size += BESTNET_ENTRY_SIZE;
- DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1));
- DHD_PNO(("\tSSID : "));
- for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++)
- DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j]));
- DHD_PNO(("\n"));
- DHD_PNO(("\tBSSID: "MACDBG"\n",
- MAC2STRDBG(plnetinfo->pfnsubnet.BSSID.octet)));
- DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
- plnetinfo->pfnsubnet.channel,
- plnetinfo->RSSI, plnetinfo->timestamp));
- DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0,
- plnetinfo->rtt1));
- plnetinfo++;
- }
- } else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) {
- fwstatus = plbestnet_v2->status;
- fwcount = plbestnet_v2->count;
- plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0];
- if (fwcount == 0) {
- DHD_PNO(("No more batch results\n"));
- goto exit;
- }
- if (fwcount > BESTN_MAX) {
- DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n",
- __FUNCTION__, fwcount, (int)BESTN_MAX));
- /* Process only BESTN_MAX number of results per batch */
- fwcount = BESTN_MAX;
- }
- DHD_PNO(("ver %d, status : %d, count %d\n",
- plbestnet_v2->version, fwstatus, fwcount));
- for (i = 0; i < fwcount; i++) {
- pbestnet_entry = (dhd_pno_bestnet_entry_t *)
- MALLOC(dhd->osh, BESTNET_ENTRY_SIZE);
- if (pbestnet_entry == NULL) {
- err = BCME_NOMEM;
- DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n"));
- goto exit;
- }
- memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE);
- /* record the current time */
- pbestnet_entry->recorded_time = jiffies;
- /* create header for the first entry */
- allocate_header = (i == 0)? TRUE : FALSE;
- /* check whether the new generation is started or not */
- if (timestamp && (TIME_DIFF(timestamp, plnetinfo_v2->timestamp)
- > TIME_MIN_DIFF))
- allocate_header = TRUE;
- timestamp = plnetinfo_v2->timestamp;
- if (allocate_header) {
- pbestnetheader = (dhd_pno_best_header_t *)
- MALLOC(dhd->osh, BEST_HEADER_SIZE);
- if (pbestnetheader == NULL) {
- err = BCME_NOMEM;
- if (pbestnet_entry)
- MFREE(dhd->osh, pbestnet_entry,
- BESTNET_ENTRY_SIZE);
- DHD_ERROR(("failed to allocate"
- " dhd_pno_bestnet_entry\n"));
- goto exit;
- }
- /* increase total cnt of bestnet header */
- pscan_results->cnt_header++;
- /* need to record the reason to call dhd_pno_get_for_bach */
- if (reason)
- pbestnetheader->reason = (ENABLE << reason);
- memset(pbestnetheader, 0, BEST_HEADER_SIZE);
- /* initialize the head of linked list */
- INIT_LIST_HEAD(&(pbestnetheader->entry_list));
- /* link the pbestnet heaer into existed list */
- if (pscan_results->bestnetheader == NULL)
- /* In case of header */
- pscan_results->bestnetheader = pbestnetheader;
- else {
- dhd_pno_best_header_t *head =
- pscan_results->bestnetheader;
- pscan_results->bestnetheader = pbestnetheader;
- pbestnetheader->next = head;
- }
- }
- /* fills the best network info */
- pbestnet_entry->channel = plnetinfo_v2->pfnsubnet.channel;
- pbestnet_entry->RSSI = plnetinfo_v2->RSSI;
- if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) {
- /* if RSSI is positive value, we assume that
- * this scan is aborted by other scan
- */
- DHD_PNO(("This scan is aborted\n"));
- pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT);
- }
- pbestnet_entry->rtt0 = plnetinfo_v2->rtt0;
- pbestnet_entry->rtt1 = plnetinfo_v2->rtt1;
- pbestnet_entry->timestamp = plnetinfo_v2->timestamp;
- if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s: Invalid SSID length"
- " %d: trimming it to max\n",
- __FUNCTION__, plnetinfo_v2->pfnsubnet.SSID_len));
- plnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
- }
- pbestnet_entry->SSID_len = plnetinfo_v2->pfnsubnet.SSID_len;
- memcpy(pbestnet_entry->SSID, plnetinfo_v2->pfnsubnet.u.SSID,
- pbestnet_entry->SSID_len);
- memcpy(&pbestnet_entry->BSSID, &plnetinfo_v2->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- /* add the element into list */
- list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list);
- /* increase best entry count */
- pbestnetheader->tot_cnt++;
- pbestnetheader->tot_size += BESTNET_ENTRY_SIZE;
- DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1));
- DHD_PNO(("\tSSID : "));
- for (j = 0; j < plnetinfo_v2->pfnsubnet.SSID_len; j++)
- DHD_PNO(("%c", plnetinfo_v2->pfnsubnet.u.SSID[j]));
- DHD_PNO(("\n"));
- DHD_PNO(("\tBSSID: "MACDBG"\n",
- MAC2STRDBG(plnetinfo_v2->pfnsubnet.BSSID.octet)));
- DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n",
- plnetinfo_v2->pfnsubnet.channel,
- plnetinfo_v2->RSSI, plnetinfo_v2->timestamp));
- DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo_v2->rtt0,
- plnetinfo_v2->rtt1));
- plnetinfo_v2++;
- }
- } else {
- err = BCME_VERSION;
- DHD_ERROR(("bestnet fw version %d not supported\n",
- plbestnet_v1->version));
- goto exit;
- }
- } while (fwstatus != PFN_COMPLETE);
- if (pscan_results->cnt_header == 0) {
- /* In case that we didn't get any data from the firmware
- * Remove the current scan_result list from get_bach.scan_results_list.
- */
- DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n"));
- list_del(&pscan_results->list);
- MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE);
- _params->params_batch.get_batch.top_node_cnt--;
- } else {
- /* increase total scan count using current scan count */
- _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header;
- }
- if (buf && bufsize) {
- /* This is a first try to get batching results */
- if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) {
- /* move the scan_results_list to expired_scan_results_lists */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(siter, snext,
- &_params->params_batch.get_batch.scan_results_list, list) {
- GCC_DIAGNOSTIC_POP();
- list_move_tail(&siter->list,
- &_params->params_batch.get_batch.expired_scan_results_list);
- }
- /* reset gloval values after moving to expired list */
- _params->params_batch.get_batch.top_node_cnt = 0;
- _params->params_batch.get_batch.expired_tot_scan_cnt =
- _params->params_batch.get_batch.tot_scan_cnt;
- _params->params_batch.get_batch.tot_scan_cnt = 0;
- }
- convert_format:
- err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize);
- if (err < 0) {
- DHD_ERROR(("failed to convert the data into upper layer format\n"));
- goto exit;
- }
- }
- exit:
- if (plbestnet_v1)
- MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN);
- if (_params) {
- _params->params_batch.get_batch.buf = NULL;
- _params->params_batch.get_batch.bufsize = 0;
- _params->params_batch.get_batch.bytes_written = err;
- }
- mutex_unlock(&_pno_state->pno_mutex);
- exit_no_unlock:
- if (waitqueue_active(&_pno_state->get_batch_done.wait))
- complete(&_pno_state->get_batch_done);
- return err;
- }
- static void
- _dhd_pno_get_batch_handler(struct work_struct *work)
- {
- dhd_pno_status_info_t *_pno_state;
- dhd_pub_t *dhd;
- struct dhd_pno_batch_params *params_batch;
- DHD_PNO(("%s enter\n", __FUNCTION__));
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- _pno_state = container_of(work, struct dhd_pno_status_info, work);
- GCC_DIAGNOSTIC_POP();
- dhd = _pno_state->dhd;
- if (dhd == NULL) {
- DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
- return;
- }
- #ifdef GSCAN_SUPPORT
- _dhd_pno_get_gscan_batch_from_fw(dhd);
- #endif /* GSCAN_SUPPORT */
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
- _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf,
- params_batch->get_batch.bufsize, params_batch->get_batch.reason);
- }
- }
- int
- dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason)
- {
- int err = BCME_OK;
- char *pbuf = buf;
- dhd_pno_status_info_t *_pno_state;
- struct dhd_pno_batch_params *params_batch;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
- #ifdef GSCAN_SUPPORT
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- struct dhd_pno_gscan_params *gscan_params;
- gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan;
- gscan_params->reason = reason;
- err = dhd_retreive_batch_scan_results(dhd);
- if (err == BCME_OK) {
- wait_event_interruptible_timeout(_pno_state->batch_get_wait,
- is_batch_retrieval_complete(gscan_params),
- msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT));
- }
- } else
- #endif // endif
- {
- if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
- DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__));
- memset(pbuf, 0, bufsize);
- pbuf += snprintf(pbuf, bufsize, "scancount=%d\n", 0);
- snprintf(pbuf, bufsize, "%s", RESULTS_END_MARKER);
- err = strlen(buf);
- goto exit;
- }
- params_batch->get_batch.buf = buf;
- params_batch->get_batch.bufsize = bufsize;
- params_batch->get_batch.reason = reason;
- params_batch->get_batch.bytes_written = 0;
- schedule_work(&_pno_state->work);
- wait_for_completion(&_pno_state->get_batch_done);
- }
- #ifdef GSCAN_SUPPORT
- if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE))
- #endif // endif
- err = params_batch->get_batch.bytes_written;
- exit:
- return err;
- }
- int
- dhd_pno_stop_for_batch(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- int mode = 0;
- int i = 0;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- wl_pfn_bssid_t *p_pfn_bssid = NULL;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n",
- __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- #ifdef GSCAN_SUPPORT
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- DHD_PNO(("Gscan is ongoing, nothing to stop here\n"));
- return err;
- }
- #endif // endif
- if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
- DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__));
- goto exit;
- }
- _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
- if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) {
- mode = _pno_state->pno_mode;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- _pno_state->pno_mode = mode;
- /* restart Legacy PNO if the Legacy PNO is on */
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- struct dhd_pno_legacy_params *_params_legacy;
- _params_legacy =
- &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
- err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr,
- _params_legacy->pno_repeat,
- _params_legacy->pno_freq_expo_max,
- _params_legacy->chan_list, _params_legacy->nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) {
- struct dhd_pno_bssid *iter, *next;
- _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]);
- p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh,
- sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid);
- if (p_pfn_bssid == NULL) {
- DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array"
- " (count: %d)",
- __FUNCTION__, _params->params_hotlist.nbssid));
- err = BCME_ERROR;
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- goto exit;
- }
- i = 0;
- /* convert dhd_pno_bssid to wl_pfn_bssid */
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- list_for_each_entry_safe(iter, next,
- &_params->params_hotlist.bssid_list, list) {
- GCC_DIAGNOSTIC_POP();
- memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN);
- p_pfn_bssid[i].flags = iter->flags;
- i++;
- }
- err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist);
- if (err < 0) {
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- } else {
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- exit:
- _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS];
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE);
- MFREE(dhd->osh, p_pfn_bssid,
- sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid);
- return err;
- }
- int
- dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid,
- struct dhd_pno_hotlist_params *hotlist_params)
- {
- int err = BCME_OK;
- int i;
- uint16 _chan_list[WL_NUMCHANNELS];
- int rem_nchan = 0;
- int tot_nchan = 0;
- int mode = 0;
- dhd_pno_params_t *_params;
- dhd_pno_params_t *_params2;
- struct dhd_pno_bssid *_pno_bssid;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- NULL_CHECK(hotlist_params, "hotlist_params is NULL", err);
- NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- if (!dhd_support_sta_mode(dhd)) {
- err = BCME_BADOPTION;
- goto exit;
- }
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS];
- if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) {
- _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE;
- err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n",
- __FUNCTION__));
- goto exit;
- }
- }
- _params->params_batch.nchan = hotlist_params->nchan;
- _params->params_batch.scan_fr = hotlist_params->scan_fr;
- if (hotlist_params->nchan)
- memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list,
- sizeof(_params->params_hotlist.chan_list));
- memset(_chan_list, 0, sizeof(_chan_list));
- rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan;
- if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) {
- /* get a valid channel list based on band B or A */
- err = _dhd_pno_get_channels(dhd,
- &_params->params_hotlist.chan_list[hotlist_params->nchan],
- &rem_nchan, hotlist_params->band, FALSE);
- if (err < 0) {
- DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n",
- __FUNCTION__, hotlist_params->band));
- goto exit;
- }
- /* now we need to update nchan because rem_chan has valid channel count */
- _params->params_hotlist.nchan += rem_nchan;
- /* need to sort channel list */
- sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan,
- sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL);
- }
- #ifdef PNO_DEBUG
- {
- int i;
- DHD_PNO(("Channel list : "));
- for (i = 0; i < _params->params_batch.nchan; i++) {
- DHD_PNO(("%d ", _params->params_batch.chan_list[i]));
- }
- DHD_PNO(("\n"));
- }
- #endif // endif
- if (_params->params_hotlist.nchan) {
- /* copy the channel list into local array */
- memcpy(_chan_list, _params->params_hotlist.chan_list,
- sizeof(_chan_list));
- tot_nchan = _params->params_hotlist.nchan;
- }
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- DHD_PNO(("PNO SSID is on progress in firmware\n"));
- /* store current pno_mode before disabling pno */
- mode = _pno_state->pno_mode;
- err = _dhd_pno_enable(dhd, PNO_OFF);
- if (err < 0) {
- DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__));
- goto exit;
- }
- /* restore the previous mode */
- _pno_state->pno_mode = mode;
- /* Use the superset for channelist between two mode */
- _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
- if (_params2->params_legacy.nchan > 0 &&
- _params->params_hotlist.nchan > 0) {
- err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
- &_params2->params_legacy.chan_list[0],
- _params2->params_legacy.nchan,
- &_params->params_hotlist.chan_list[0],
- _params->params_hotlist.nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to merge channel list"
- "between legacy and hotlist\n",
- __FUNCTION__));
- goto exit;
- }
- }
- }
- INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list));
- err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- if (tot_nchan > 0) {
- if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) {
- DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- for (i = 0; i < hotlist_params->nbssid; i++) {
- _pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh,
- sizeof(struct dhd_pno_bssid));
- NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err);
- memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN);
- _pno_bssid->flags = p_pfn_bssid[i].flags;
- list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list);
- }
- _params->params_hotlist.nbssid = hotlist_params->nbssid;
- if (_pno_state->pno_status == DHD_PNO_DISABLED) {
- if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0)
- DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__));
- }
- exit:
- /* clear mode in case of error */
- if (err < 0)
- _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE;
- return err;
- }
- int
- dhd_pno_stop_for_hotlist(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- uint32 mode = 0;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n",
- __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) {
- DHD_ERROR(("%s : Hotlist MODE is not enabled\n",
- __FUNCTION__));
- goto exit;
- }
- _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
- if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) {
- /* retrieve the batching data from firmware into host */
- dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE);
- /* save current pno_mode before calling dhd_pno_clean */
- mode = _pno_state->pno_mode;
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- /* restore previos pno mode */
- _pno_state->pno_mode = mode;
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- /* restart Legacy PNO Scan */
- struct dhd_pno_legacy_params *_params_legacy;
- _params_legacy =
- &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
- err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr,
- _params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max,
- _params_legacy->chan_list, _params_legacy->nchan);
- if (err < 0) {
- DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- /* restart Batching Scan */
- _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]);
- /* restart BATCH SCAN */
- err = dhd_pno_set_for_batch(dhd, &_params->params_batch);
- if (err < 0) {
- _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE;
- DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- } else {
- err = dhd_pno_clean(dhd);
- if (err < 0) {
- DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n",
- __FUNCTION__, err));
- goto exit;
- }
- }
- exit:
- return err;
- }
- #ifdef GSCAN_SUPPORT
- int
- dhd_retreive_batch_scan_results(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- struct dhd_pno_batch_params *params_batch;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
- if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) {
- DHD_PNO(("Retreive batch results\n"));
- params_batch->get_batch.buf = NULL;
- params_batch->get_batch.bufsize = 0;
- params_batch->get_batch.reason = PNO_STATUS_EVENT;
- _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS;
- smp_wmb();
- schedule_work(&_pno_state->work);
- } else {
- DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval"
- "already in progress, will skip\n", __FUNCTION__));
- err = BCME_ERROR;
- }
- return err;
- }
- void
- dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type)
- {
- dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
- struct dhd_pno_gscan_params *gscan_params;
- gscan_results_cache_t *iter, *tmp;
- if (!_pno_state) {
- return;
- }
- gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
- if (type == HOTLIST_FOUND) {
- iter = gscan_params->gscan_hotlist_found;
- gscan_params->gscan_hotlist_found = NULL;
- } else {
- iter = gscan_params->gscan_hotlist_lost;
- gscan_params->gscan_hotlist_lost = NULL;
- }
- while (iter) {
- tmp = iter->next;
- MFREE(dhd->osh, iter,
- ((iter->tot_count - 1) * sizeof(wifi_gscan_result_t))
- + sizeof(gscan_results_cache_t));
- iter = tmp;
- }
- return;
- }
- void *
- dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size)
- {
- wl_bss_info_t *bi = NULL;
- wl_gscan_result_t *gscan_result;
- wifi_gscan_full_result_t *result = NULL;
- u32 bi_length = 0;
- uint8 channel;
- uint32 mem_needed;
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
- struct timespec64 ts;
- #else
- struct timespec ts;
- #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
- u32 bi_ie_length = 0;
- u32 bi_ie_offset = 0;
- *size = 0;
- GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
- gscan_result = (wl_gscan_result_t *)data;
- GCC_DIAGNOSTIC_POP();
- if (!gscan_result) {
- DHD_ERROR(("Invalid gscan result (NULL pointer)\n"));
- goto exit;
- }
- if ((len < sizeof(*gscan_result)) ||
- (len < dtoh32(gscan_result->buflen)) ||
- (dtoh32(gscan_result->buflen) >
- (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) {
- DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__,
- dtoh32(gscan_result->buflen)));
- goto exit;
- }
- bi = &gscan_result->bss_info[0].info;
- bi_length = dtoh32(bi->length);
- if (bi_length != (dtoh32(gscan_result->buflen) -
- WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) {
- DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length));
- goto exit;
- }
- bi_ie_offset = dtoh32(bi->ie_offset);
- bi_ie_length = dtoh32(bi->ie_length);
- if ((bi_ie_offset + bi_ie_length) > bi_length) {
- DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n",
- __FUNCTION__, bi_ie_length, bi_ie_offset));
- goto exit;
- }
- if (bi->SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len));
- goto exit;
- }
- mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi->ie_length;
- result = (wifi_gscan_full_result_t *)MALLOC(dhd->osh, mem_needed);
- if (!result) {
- DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n",
- __FUNCTION__, mem_needed));
- goto exit;
- }
- result->scan_ch_bucket = gscan_result->scan_ch_bucket;
- memcpy(result->fixed.ssid, bi->SSID, bi->SSID_len);
- result->fixed.ssid[bi->SSID_len] = '\0';
- channel = wf_chspec_ctlchan(bi->chanspec);
- result->fixed.channel = wf_channel2mhz(channel,
- (channel <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- result->fixed.rssi = (int32) bi->RSSI;
- result->fixed.rtt = 0;
- result->fixed.rtt_sd = 0;
- get_monotonic_boottime(&ts);
- result->fixed.ts = (uint64) TIMESPEC_TO_US(ts);
- result->fixed.beacon_period = dtoh16(bi->beacon_period);
- result->fixed.capability = dtoh16(bi->capability);
- result->ie_length = bi_ie_length;
- memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN);
- memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length);
- *size = mem_needed;
- exit:
- return result;
- }
- void *
- dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size)
- {
- dhd_epno_results_t *results = NULL;
- dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
- struct dhd_pno_gscan_params *gscan_params;
- uint32 count, mem_needed = 0, i;
- uint8 ssid[DOT11_MAX_SSID_LEN + 1];
- struct ether_addr *bssid;
- *size = 0;
- if (!_pno_state)
- return NULL;
- gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
- if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) {
- wl_pfn_scanresults_v1_t *pfn_result = (wl_pfn_scanresults_v1_t *)data;
- wl_pfn_scanresults_v2_t *pfn_result_v2 = (wl_pfn_scanresults_v2_t *)data;
- wl_pfn_net_info_v1_t *net;
- wl_pfn_net_info_v2_t *net_v2;
- if (pfn_result->version == PFN_SCANRESULT_VERSION_V1) {
- if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V1)) {
- DHD_ERROR(("%s event %d: wrong pfn v1 results count %d\n",
- __FUNCTION__, event, pfn_result->count));
- return NULL;
- }
- count = pfn_result->count;
- mem_needed = sizeof(dhd_epno_results_t) * count;
- results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed);
- if (!results) {
- DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
- mem_needed));
- return NULL;
- }
- for (i = 0; i < count; i++) {
- net = &pfn_result->netinfo[i];
- results[i].rssi = net->RSSI;
- results[i].channel = wf_channel2mhz(net->pfnsubnet.channel,
- (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- results[i].flags = (event == WLC_E_PFN_NET_FOUND) ?
- WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST;
- results[i].ssid_len = min(net->pfnsubnet.SSID_len,
- (uint8)DOT11_MAX_SSID_LEN);
- bssid = &results[i].bssid;
- memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN);
- if (!net->pfnsubnet.SSID_len) {
- DHD_ERROR(("%s: Gscan results indexing is not"
- " supported in version 1 \n", __FUNCTION__));
- MFREE(dhd->osh, results, mem_needed);
- return NULL;
- } else {
- memcpy(results[i].ssid, net->pfnsubnet.SSID,
- results[i].ssid_len);
- }
- memcpy(ssid, results[i].ssid, results[i].ssid_len);
- ssid[results[i].ssid_len] = '\0';
- DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n",
- ssid, MAC2STRDBG(bssid->octet), results[i].channel,
- results[i].rssi, results[i].flags));
- }
- } else if (pfn_result_v2->version == PFN_SCANRESULT_VERSION_V2) {
- if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V2)) {
- DHD_ERROR(("%s event %d: wrong pfn v2 results count %d\n",
- __FUNCTION__, event, pfn_result->count));
- return NULL;
- }
- count = pfn_result_v2->count;
- mem_needed = sizeof(dhd_epno_results_t) * count;
- results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed);
- if (!results) {
- DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__,
- mem_needed));
- return NULL;
- }
- for (i = 0; i < count; i++) {
- net_v2 = &pfn_result_v2->netinfo[i];
- results[i].rssi = net_v2->RSSI;
- results[i].channel = wf_channel2mhz(net_v2->pfnsubnet.channel,
- (net_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- results[i].flags = (event == WLC_E_PFN_NET_FOUND) ?
- WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST;
- results[i].ssid_len = min(net_v2->pfnsubnet.SSID_len,
- (uint8)DOT11_MAX_SSID_LEN);
- bssid = &results[i].bssid;
- memcpy(bssid, &net_v2->pfnsubnet.BSSID, ETHER_ADDR_LEN);
- if (!net_v2->pfnsubnet.SSID_len) {
- dhd_pno_idx_to_ssid(gscan_params, &results[i],
- net_v2->pfnsubnet.u.index);
- } else {
- memcpy(results[i].ssid, net_v2->pfnsubnet.u.SSID,
- results[i].ssid_len);
- }
- memcpy(ssid, results[i].ssid, results[i].ssid_len);
- ssid[results[i].ssid_len] = '\0';
- DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n",
- ssid, MAC2STRDBG(bssid->octet), results[i].channel,
- results[i].rssi, results[i].flags));
- }
- } else {
- DHD_ERROR(("%s event %d: Incorrect version %d , not supported\n",
- __FUNCTION__, event, pfn_result->version));
- return NULL;
- }
- }
- *size = mem_needed;
- return results;
- }
- void *
- dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data,
- int *send_evt_bytes, hotlist_type_t type, u32 *buf_len)
- {
- void *ptr = NULL;
- dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
- struct dhd_pno_gscan_params *gscan_params;
- wl_pfn_scanresults_v1_t *results_v1 = (wl_pfn_scanresults_v1_t *)event_data;
- wl_pfn_scanresults_v2_t *results_v2 = (wl_pfn_scanresults_v2_t *)event_data;
- wifi_gscan_result_t *hotlist_found_array;
- wl_pfn_net_info_v1_t *pnetinfo;
- wl_pfn_net_info_v2_t *pnetinfo_v2;
- gscan_results_cache_t *gscan_hotlist_cache;
- u32 malloc_size = 0, i, total = 0;
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
- struct timespec64 tm_spec;
- #else
- struct timespec tm_spec;
- #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */
- uint16 fwstatus;
- uint16 fwcount;
- /* Static asserts in _dhd_pno_get_for_batch() above guarantee the v1 and v2
- * net_info and subnet_info structures are compatible in size and SSID offset,
- * allowing v1 to be safely used in the code below except for lscanresults
- * fields themselves (status, count, offset to netinfo).
- */
- *buf_len = 0;
- if (results_v1->version == PFN_SCANRESULTS_VERSION_V1) {
- fwstatus = results_v1->status;
- fwcount = results_v1->count;
- pnetinfo = &results_v1->netinfo[0];
- gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
- if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V1)) {
- DHD_ERROR(("%s: wrong v1 fwcount:%d\n", __FUNCTION__, fwcount));
- *send_evt_bytes = 0;
- return ptr;
- }
- get_monotonic_boottime(&tm_spec);
- malloc_size = sizeof(gscan_results_cache_t) +
- ((fwcount - 1) * sizeof(wifi_gscan_result_t));
- gscan_hotlist_cache = (gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size);
- if (!gscan_hotlist_cache) {
- DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size));
- *send_evt_bytes = 0;
- return ptr;
- }
- *buf_len = malloc_size;
- if (type == HOTLIST_FOUND) {
- gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
- gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
- DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount));
- } else {
- gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost;
- gscan_params->gscan_hotlist_lost = gscan_hotlist_cache;
- DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount));
- }
- gscan_hotlist_cache->tot_count = fwcount;
- gscan_hotlist_cache->tot_consumed = 0;
- for (i = 0; i < fwcount; i++, pnetinfo++) {
- hotlist_found_array = &gscan_hotlist_cache->results[i];
- memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t));
- hotlist_found_array->channel = wf_channel2mhz(pnetinfo->pfnsubnet.channel,
- (pnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- hotlist_found_array->rssi = (int32) pnetinfo->RSSI;
- hotlist_found_array->ts =
- convert_fw_rel_time_to_systime(&tm_spec,
- (pnetinfo->timestamp * 1000));
- if (pnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("Invalid SSID length %d: trimming it to max\n",
- pnetinfo->pfnsubnet.SSID_len));
- pnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
- }
- memcpy(hotlist_found_array->ssid, pnetinfo->pfnsubnet.SSID,
- pnetinfo->pfnsubnet.SSID_len);
- hotlist_found_array->ssid[pnetinfo->pfnsubnet.SSID_len] = '\0';
- memcpy(&hotlist_found_array->macaddr, &pnetinfo->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- DHD_PNO(("\t%s "MACDBG" rssi %d\n",
- hotlist_found_array->ssid,
- MAC2STRDBG(hotlist_found_array->macaddr.octet),
- hotlist_found_array->rssi));
- }
- } else if (results_v2->version == PFN_SCANRESULTS_VERSION_V2) {
- fwstatus = results_v2->status;
- fwcount = results_v2->count;
- pnetinfo_v2 = (wl_pfn_net_info_v2_t*)&results_v2->netinfo[0];
- gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
- if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V2)) {
- DHD_ERROR(("%s: wrong v2 fwcount:%d\n", __FUNCTION__, fwcount));
- *send_evt_bytes = 0;
- return ptr;
- }
- get_monotonic_boottime(&tm_spec);
- malloc_size = sizeof(gscan_results_cache_t) +
- ((fwcount - 1) * sizeof(wifi_gscan_result_t));
- gscan_hotlist_cache =
- (gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size);
- if (!gscan_hotlist_cache) {
- DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size));
- *send_evt_bytes = 0;
- return ptr;
- }
- *buf_len = malloc_size;
- if (type == HOTLIST_FOUND) {
- gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
- gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
- DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount));
- } else {
- gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost;
- gscan_params->gscan_hotlist_lost = gscan_hotlist_cache;
- DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount));
- }
- gscan_hotlist_cache->tot_count = fwcount;
- gscan_hotlist_cache->tot_consumed = 0;
- gscan_hotlist_cache->scan_ch_bucket = results_v2->scan_ch_bucket;
- for (i = 0; i < fwcount; i++, pnetinfo_v2++) {
- hotlist_found_array = &gscan_hotlist_cache->results[i];
- memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t));
- hotlist_found_array->channel =
- wf_channel2mhz(pnetinfo_v2->pfnsubnet.channel,
- (pnetinfo_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
- hotlist_found_array->rssi = (int32) pnetinfo_v2->RSSI;
- hotlist_found_array->ts =
- convert_fw_rel_time_to_systime(&tm_spec,
- (pnetinfo_v2->timestamp * 1000));
- if (pnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) {
- DHD_ERROR(("Invalid SSID length %d: trimming it to max\n",
- pnetinfo_v2->pfnsubnet.SSID_len));
- pnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN;
- }
- memcpy(hotlist_found_array->ssid, pnetinfo_v2->pfnsubnet.u.SSID,
- pnetinfo_v2->pfnsubnet.SSID_len);
- hotlist_found_array->ssid[pnetinfo_v2->pfnsubnet.SSID_len] = '\0';
- memcpy(&hotlist_found_array->macaddr, &pnetinfo_v2->pfnsubnet.BSSID,
- ETHER_ADDR_LEN);
- DHD_PNO(("\t%s "MACDBG" rssi %d\n",
- hotlist_found_array->ssid,
- MAC2STRDBG(hotlist_found_array->macaddr.octet),
- hotlist_found_array->rssi));
- }
- } else {
- DHD_ERROR(("%s: event version %d not supported\n",
- __FUNCTION__, results_v1->version));
- *send_evt_bytes = 0;
- return ptr;
- }
- if (fwstatus == PFN_COMPLETE) {
- ptr = (void *) gscan_hotlist_cache;
- while (gscan_hotlist_cache) {
- total += gscan_hotlist_cache->tot_count;
- gscan_hotlist_cache = gscan_hotlist_cache->next;
- }
- *send_evt_bytes = total * sizeof(wifi_gscan_result_t);
- }
- return ptr;
- }
- #endif /* GSCAN_SUPPORT */
- int
- dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
- {
- int err = BCME_OK;
- uint event_type;
- dhd_pno_status_info_t *_pno_state;
- NULL_CHECK(dhd, "dhd is NULL", err);
- NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
- _pno_state = PNO_GET_PNOSTATE(dhd);
- if (!WLS_SUPPORTED(_pno_state)) {
- DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__));
- err = BCME_UNSUPPORTED;
- goto exit;
- }
- event_type = ntoh32(event->event_type);
- DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type));
- switch (event_type) {
- case WLC_E_PFN_BSSID_NET_FOUND:
- case WLC_E_PFN_BSSID_NET_LOST:
- /* TODO : need to implement event logic using generic netlink */
- break;
- case WLC_E_PFN_BEST_BATCHING:
- #ifndef GSCAN_SUPPORT
- {
- struct dhd_pno_batch_params *params_batch;
- params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
- if (!waitqueue_active(&_pno_state->get_batch_done.wait)) {
- DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__));
- params_batch->get_batch.buf = NULL;
- params_batch->get_batch.bufsize = 0;
- params_batch->get_batch.reason = PNO_STATUS_EVENT;
- schedule_work(&_pno_state->work);
- } else
- DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING"
- "will skip this event\n", __FUNCTION__));
- break;
- }
- #else
- break;
- #endif /* !GSCAN_SUPPORT */
- default:
- DHD_ERROR(("unknown event : %d\n", event_type));
- }
- exit:
- return err;
- }
- int dhd_pno_init(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- dhd_pno_status_info_t *_pno_state;
- char *buf = NULL;
- NULL_CHECK(dhd, "dhd is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- UNUSED_PARAMETER(_dhd_pno_suspend);
- if (dhd->pno_state)
- goto exit;
- dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t));
- NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err);
- memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t));
- /* need to check whether current firmware support batching and hotlist scan */
- _pno_state = PNO_GET_PNOSTATE(dhd);
- _pno_state->wls_supported = TRUE;
- _pno_state->dhd = dhd;
- mutex_init(&_pno_state->pno_mutex);
- INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler);
- init_completion(&_pno_state->get_batch_done);
- #ifdef GSCAN_SUPPORT
- init_waitqueue_head(&_pno_state->batch_get_wait);
- #endif /* GSCAN_SUPPORT */
- buf = MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
- if (!buf) {
- DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__));
- return BCME_NOMEM;
- }
- err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN,
- FALSE);
- if (err == BCME_UNSUPPORTED) {
- _pno_state->wls_supported = FALSE;
- DHD_INFO(("Current firmware doesn't support"
- " Android Location Service\n"));
- } else {
- DHD_ERROR(("%s: Support Android Location Service\n",
- __FUNCTION__));
- }
- exit:
- MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
- return err;
- }
- int dhd_pno_deinit(dhd_pub_t *dhd)
- {
- int err = BCME_OK;
- dhd_pno_status_info_t *_pno_state;
- dhd_pno_params_t *_params;
- NULL_CHECK(dhd, "dhd is NULL", err);
- DHD_PNO(("%s enter\n", __FUNCTION__));
- _pno_state = PNO_GET_PNOSTATE(dhd);
- NULL_CHECK(_pno_state, "pno_state is NULL", err);
- /* may need to free legacy ssid_list */
- if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
- _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE);
- }
- #ifdef GSCAN_SUPPORT
- if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
- _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
- mutex_lock(&_pno_state->pno_mutex);
- dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state, GSCAN_FLUSH_ALL_CFG);
- mutex_unlock(&_pno_state->pno_mutex);
- }
- #endif /* GSCAN_SUPPORT */
- if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) {
- _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS];
- /* clear resource if the BATCH MODE is on */
- _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE);
- }
- cancel_work_sync(&_pno_state->work);
- MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t));
- dhd->pno_state = NULL;
- return err;
- }
- #endif /* OEM_ANDROID */
- #endif /* PNO_SUPPORT */
|