123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- mgmt.c
- Abstract:
- This module implements management frame handling functionality for the
- 802.11 core wireless networking library.
- Author:
- Chris Steven 19-Oct-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "net80211.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define default values for the local station's RSN capabilities.
- //
- #define NET80211_DEFAULT_RSN_ELEMENT_LENGTH \
- (sizeof(NET80211_DEFAULT_RSN_INFORMATION) - (2 * sizeof(UCHAR)))
- #define NET80211_DEFAULT_RSN_CAPABILITIES 0
- #define NET80211_DEFAULT_RSN_PAIRWISE_CIPHER_SUITE_COUNT 1
- #define NET80211_DEFAULT_RSN_AKM_SUITE_COUNT 1
- //
- // Define the default RSN group cipher suite. This is
- // NET80211_CIPHER_SUITE_CCMP in network byte order.
- //
- #define NET80211_DEFAULT_RSN_GROUP_CIPHER_SUITE 0x04AC0F00
- //
- // Define the default RSN pairwise cipher suite. This is
- // NET80211_CIPHER_SUITE_CCMP in network byte order.
- //
- #define NET80211_DEFAULT_RSN_PAIRWISE_CIPHER_SUITE 0x04AC0F00
- //
- // Define the default RSN AKM cipher suite. This is NET80211_AKM_SUITE_PSK in
- // network byte order.
- //
- #define NET80211_DEFAULT_RSN_AKM_SUITE 0x02AC0F00
- //
- // Define the time to wait for a state management frame.
- //
- #define NET80211_STATE_TIMEOUT (2 * MICROSECONDS_PER_SECOND)
- //
- // Define the time to wait for advanced authentication.
- //
- #define NET80211_AUTHENTICATION_TIMEOUT (5 * MICROSECONDS_PER_SECOND)
- //
- // Define the timeout until a BSS entry has expired in microseconds.
- //
- #define NET80211_BSS_ENTRY_TIMEOUT (10 * MICROSECONDS_PER_SECOND)
- //
- // Define the pad to subtract from the beacon interval during a background
- // scan in order to determine the amount of time to dwell on a channel without
- // missing a beacon from the active BSS.
- //
- #define NET80211_BEACON_INTERVAL_PAD (10 * MICROSECONDS_PER_MILLISECOND)
- //
- // Define the default amount of time to wait between scanning channels when
- // performing a background scan.
- //
- #define NET80211_BACKGROUND_SCAN_CHANNEL_DELAY \
- (200 * MICROSECONDS_PER_MILLISECOND)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines the set of information gathered from a probe
- response management frame or a beacon management frame.
- Members:
- Bssid - Stores a pointer to the BSSID, which is always
- NET80211_ADDRESS_SIZE bytes long.
- BeaconInterval - Stores the interval between beacons sent by an AP.
- Capabilities - Stores the 802.11 capabilities of the AP. See
- NET80211_CAPABILITY_FLAG_* for definitions.
- Timestamp - Stores the timestamp from the AP.
- Elements - Stores a pointer to the information elements.
- ElementsSize - Stores the size of the information elements, in bytes.
- Channel - Stores a pointer to the channel element, that indicates the
- channel on which the AP is operating.
- Ssid - Stores a pointer to the SSID element from the AP.
- Rates - Stores a pointer to the supported rates element.
- ExtendedRates - Stores a pointer to the extended supported rates element.
- Rsn - Stores the optional RSN element broadcasted by the AP.
- --*/
- typedef struct _NET80211_PROBE_RESPONSE {
- PUCHAR Bssid;
- USHORT BeaconInterval;
- USHORT Capabilities;
- ULONGLONG Timestamp;
- PVOID Elements;
- ULONG ElementsSize;
- PVOID Channel;
- PVOID Ssid;
- PVOID Rates;
- PVOID ExtendedRates;
- PVOID Rsn;
- } NET80211_PROBE_RESPONSE, *PNET80211_PROBE_RESPONSE;
- /*++
- Structure Description:
- This structure defines the frame body used for open system authentication.
- For other types of authentication, other fields may be required.
- Members:
- AlgorithmNumber - Stores the algorithm in use for the authentication
- process.
- TransactionSequenceNumber - Stores the sequence number of the
- authentication transaction process.
- StatusCode - Stores the states of the authentication process.
- --*/
- typedef struct _NET80211_AUTHENTICATION_OPEN_BODY {
- USHORT AlgorithmNumber;
- USHORT TransactionSequenceNumber;
- USHORT StatusCode;
- } PACKED NET80211_AUTHENTICATION_OPEN_BODY, *PNET80211_AUTHENTICATION_OPEN_BODY;
- /*++
- Structure Description:
- This structure defines the default RSN information used by the 802.11
- networking library.
- Members:
- ElementId - Stores the RSN element ID. This should be NET80211_ELEMENT_RSN.
- ElementLength - Stores the length of the RSN information, not including the
- first two bytes.
- RsnVersion - Stores the RSN information version.
- GroupCipherSuite - Stores the group cipher suite.
- PairwiseCipherSuiteCount - Stores the number of pairwise cipher suites that
- follow this field. There should only be 1.
- PairwiseCipherSuite - Stores the only supported pairwise cipher suite.
- AkmSuiteCount - Stores the number of AKM cipher suites that follow this
- field. There should be only 1.
- AkmSuite - Stores the only supported AKM cipher suite.
- RsnCapabilites - Stores the RSN capapbilites for the node.
- --*/
- typedef struct _NET80211_DEFAULT_RSN_INFORMATION {
- UCHAR ElementId;
- UCHAR ElementLength;
- USHORT RsnVersion;
- ULONG GroupCipherSuite;
- USHORT PairwiseCipherSuiteCount;
- ULONG PairwiseCipherSuite;
- USHORT AkmSuiteCount;
- ULONG AkmSuite;
- USHORT RsnCapabilities;
- } PACKED NET80211_DEFAULT_RSN_INFORMATION, *PNET80211_DEFAULT_RSN_INFORMATION;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- Net80211pSetStateUnlocked (
- PNET80211_LINK Link,
- NET80211_STATE State
- );
- VOID
- Net80211pScanThread (
- PVOID Parameter
- );
- VOID
- Net80211pStartProbing (
- PNET80211_LINK Link
- );
- VOID
- Net80211pStopProbing (
- PNET80211_LINK Link
- );
- KSTATUS
- Net80211pPrepareForReconnect (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY *Bss
- );
- VOID
- Net80211pJoinBss (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- );
- VOID
- Net80211pLeaveBss (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss,
- BOOL SendNotification,
- ULONG Subtype,
- USHORT Reason
- );
- KSTATUS
- Net80211pSendProbeRequest (
- PNET80211_LINK Link,
- PNET80211_SCAN_STATE Scan
- );
- VOID
- Net80211pProcessProbeResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- );
- KSTATUS
- Net80211pSendAuthenticationRequest (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- );
- VOID
- Net80211pProcessAuthenticationResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- );
- KSTATUS
- Net80211pSendAssociationRequest (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- );
- VOID
- Net80211pProcessAssociationResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- );
- KSTATUS
- Net80211pSendManagementFrame (
- PNET80211_LINK Link,
- PUCHAR DestinationAddress,
- PUCHAR Bssid,
- ULONG FrameSubtype,
- PVOID FrameBody,
- ULONG FrameBodySize
- );
- KSTATUS
- Net80211pQueueStateTransitionTimer (
- PNET80211_LINK Link,
- ULONGLONG Timeout
- );
- VOID
- Net80211pCancelStateTransitionTimer (
- PNET80211_LINK Link
- );
- KSTATUS
- Net80211pValidateRates (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- );
- KSTATUS
- Net80211pParseRsnElement (
- PUCHAR Rsn,
- PNET80211_ENCRYPTION Encryption
- );
- VOID
- Net80211pUpdateBssCache (
- PNET80211_LINK Link,
- PNET80211_PROBE_RESPONSE Response
- );
- VOID
- Net80211pTrimBssCache (
- PNET80211_LINK Link
- );
- PNET80211_BSS_ENTRY
- Net80211pCopyBssEntry (
- PNET80211_BSS_ENTRY Bss
- );
- PNET80211_BSS_ENTRY
- Net80211pCreateBssEntry (
- PUCHAR Bssid
- );
- VOID
- Net80211pDestroyBssEntry (
- PNET80211_BSS_ENTRY BssEntry
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the default RSN information to send out for association requests.
- //
- NET80211_DEFAULT_RSN_INFORMATION Net80211DefaultRsnInformation = {
- NET80211_ELEMENT_RSN,
- NET80211_DEFAULT_RSN_ELEMENT_LENGTH,
- NET80211_RSN_VERSION,
- NET80211_DEFAULT_RSN_GROUP_CIPHER_SUITE,
- NET80211_DEFAULT_RSN_PAIRWISE_CIPHER_SUITE_COUNT,
- NET80211_DEFAULT_RSN_PAIRWISE_CIPHER_SUITE,
- NET80211_DEFAULT_RSN_AKM_SUITE_COUNT,
- NET80211_DEFAULT_RSN_AKM_SUITE,
- NET80211_DEFAULT_RSN_CAPABILITIES
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- Net80211pProcessManagementFrame (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- )
- /*++
- Routine Description:
- This routine processes 802.11 management frames.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which the frame arrived.
- Packet - Supplies a pointer to the network packet.
- Return Value:
- None.
- --*/
- {
- ULONG FrameSubtype;
- PNET80211_MANAGEMENT_FRAME_HEADER Header;
- Header = Packet->Buffer + Packet->DataOffset;
- FrameSubtype = NET80211_GET_FRAME_SUBTYPE(Header);
- switch (FrameSubtype) {
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_PROBE_RESPONSE:
- Net80211pProcessProbeResponse(Link, Packet);
- break;
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_AUTHENTICATION:
- Net80211pProcessAuthenticationResponse(Link, Packet);
- break;
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_ASSOCIATION_RESPONSE:
- Net80211pProcessAssociationResponse(Link, Packet);
- break;
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_DISASSOCIATION:
- if ((Link->State != Net80211StateAssociated) &&
- (Link->State != Net80211StateEncrypted)) {
- break;
- }
- Net80211pSetState(Link, Net80211StateAssociating);
- break;
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_DEAUTHENTICATION:
- if ((Link->State != Net80211StateAssociating) &&
- (Link->State != Net80211StateReassociating) &&
- (Link->State != Net80211StateAssociated) &&
- (Link->State != Net80211StateEncrypted)) {
- break;
- }
- Net80211pSetState(Link, Net80211StateAuthenticating);
- break;
- //
- // Ignore packets that are not yet handled.
- //
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_REASSOCIATION_RESPONSE:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_BEACON:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_TIMING_ADVERTISEMENT:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_ATIM:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_ACTION:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_ACTION_NO_ACK:
- break;
- //
- // Toss out these request packets until AP mode is supported.
- //
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_PROBE_REQUEST:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_REASSOCIATION_REQUEST:
- case NET80211_MANAGEMENT_FRAME_SUBTYPE_ASSOCIATION_REQUEST:
- default:
- break;
- }
- return;
- }
- KSTATUS
- Net80211pStartScan (
- PNET80211_LINK Link,
- PNET80211_SCAN_STATE Parameters
- )
- /*++
- Routine Description:
- This routine starts a scan for one or more BSSs within range of this
- station.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which to perform the scan.
- Parameters - Supplies a pointer to a scan state used to initialize the
- scan. This memory will not be referenced after the function returns,
- so this may be a stack allocated structure.
- Return Value:
- Status code.
- --*/
- {
- PNET80211_SCAN_STATE ScanState;
- KSTATUS Status;
- ASSERT(Parameters->SsidLength <= NET80211_MAX_SSID_LENGTH);
- ASSERT(Parameters->PassphraseLength <= NET80211_MAX_PASSPHRASE_LENGTH);
- ScanState = MmAllocatePagedPool(sizeof(NET80211_SCAN_STATE),
- NET80211_ALLOCATION_TAG);
- if (ScanState == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto StartScanEnd;
- }
- RtlCopyMemory(ScanState, Parameters, sizeof(NET80211_SCAN_STATE));
- Net80211LinkAddReference(Link);
- ScanState->Link = Link;
- //
- // Kick off a thread to complete the scan.
- //
- Status = PsCreateKernelThread(Net80211pScanThread,
- ScanState,
- "Net80211ScanThread");
- if (!KSUCCESS(Status)) {
- goto StartScanEnd;
- }
- StartScanEnd:
- if (!KSUCCESS(Status)) {
- if (ScanState != NULL) {
- Net80211pSetState(Link, Net80211StateInitialized);
- Net80211LinkReleaseReference(ScanState->Link);
- MmFreePagedPool(ScanState);
- }
- }
- return Status;
- }
- VOID
- Net80211pSetState (
- PNET80211_LINK Link,
- NET80211_STATE State
- )
- /*++
- Routine Description:
- This routine sets the given link's 802.11 state by alerting the driver of
- the state change and then performing any necessary actions based on the
- state transition.
- Arguments:
- Link - Supplies a pointer to the 802.11 link whose state is being updated.
- State - Supplies the state to which the link is transitioning.
- Return Value:
- None.
- --*/
- {
- KeAcquireQueuedLock(Link->Lock);
- Net80211pSetStateUnlocked(Link, State);
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- PNET80211_BSS_ENTRY
- Net80211pGetBss (
- PNET80211_LINK Link
- )
- /*++
- Routine Description:
- This routine gets the link's active BSS entry and hands back a pointer with
- a reference to the caller.
- Arguments:
- Link - Supplies a pointer to the 802.11 link whose active BSS is to be
- returned.
- Return Value:
- Returns a pointer to the active BSS.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- Bss = NULL;
- if (Link->ActiveBss != NULL) {
- KeAcquireQueuedLock(Link->Lock);
- Bss = Link->ActiveBss;
- if (Bss != NULL) {
- Net80211pBssEntryAddReference(Bss);
- }
- KeReleaseQueuedLock(Link->Lock);
- }
- return Bss;
- }
- VOID
- Net80211pBssEntryAddReference (
- PNET80211_BSS_ENTRY BssEntry
- )
- /*++
- Routine Description:
- This routine increments the reference count of the given BSS entry.
- Arguments:
- BssEntry - Supplies a pointer to the BSS entry whose reference count is to
- be incremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(BssEntry->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- return;
- }
- VOID
- Net80211pBssEntryReleaseReference (
- PNET80211_BSS_ENTRY BssEntry
- )
- /*++
- Routine Description:
- This routine decrements the reference count of the given BSS entry,
- destroying the entry if there are no more references.
- Arguments:
- BssEntry - Supplies a pointer to the BSS entry whose reference count is to
- be decremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(BssEntry->ReferenceCount), -1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- Net80211pDestroyBssEntry(BssEntry);
- }
- return;
- }
- VOID
- Net80211pStateTimeoutDpcRoutine (
- PDPC Dpc
- )
- /*++
- Routine Description:
- This routine implements the 802.11 state transition timeout DPC that gets
- called after a remote node does not respond to a management frame.
- Arguments:
- Dpc - Supplies a pointer to the DPC that is running.
- Return Value:
- None.
- --*/
- {
- PNET_LINK Link;
- PNET80211_LINK Net80211Link;
- Link = (PNET_LINK)Dpc->UserData;
- Net80211Link = Link->DataLinkContext;
- KeQueueWorkItem(Net80211Link->TimeoutWorkItem);
- return;
- }
- VOID
- Net80211pStateTimeoutWorker (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine performs the low level work when an 802.11 state transition
- times out due to a remote node not responding.
- Arguments:
- Parameter - Supplies a pointer to the nework link whose 802.11 state
- transition has timed out.
- Return Value:
- None.
- --*/
- {
- PNET80211_LINK Link;
- Link = (PNET80211_LINK)Parameter;
- //
- // If a packet did not arrive to advance the state and cancel the timer,
- // then this really is a timeout. Set the state back to initialized.
- //
- KeAcquireQueuedLock(Link->Lock);
- if ((Link->Flags & NET80211_LINK_FLAG_TIMER_QUEUED) != 0) {
- Link->Flags &= ~NET80211_LINK_FLAG_TIMER_QUEUED;
- Net80211pSetStateUnlocked(Link, Net80211StateInitialized);
- }
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- PNET80211_BSS_ENTRY
- Net80211pLookupBssEntry (
- PNET80211_LINK Link,
- PUCHAR Bssid
- )
- /*++
- Routine Description:
- This routine searches the link for a known BSS entry with the given BSSID.
- It does not take a reference on the BSS entry and assumes that the link's
- lock is already held.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which to search.
- Bssid - Supplies a pointer to the BSSID for the desired BSS entry.
- Return Value:
- Returns a pointer to the matching BSS entry on success, or NULL on failure.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- PLIST_ENTRY CurrentEntry;
- BOOL Match;
- PNET80211_BSS_ENTRY MatchedBss;
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- MatchedBss = NULL;
- CurrentEntry = Link->BssList.Next;
- while (CurrentEntry != &(Link->BssList)) {
- Bss = LIST_VALUE(CurrentEntry, NET80211_BSS_ENTRY, ListEntry);
- Match = RtlCompareMemory(Bssid,
- Bss->State.Bssid,
- NET80211_ADDRESS_SIZE);
- if (Match != FALSE) {
- MatchedBss = Bss;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- return MatchedBss;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- Net80211pSetStateUnlocked (
- PNET80211_LINK Link,
- NET80211_STATE State
- )
- /*++
- Routine Description:
- This routine sets the given link's 802.11 state by alerting the driver of
- the state change and then performing any necessary actions based on the
- state transition. This routine assumes that the 802.11 link's lock is held.
- Arguments:
- Link - Supplies a pointer to the link whose state is being updated.
- State - Supplies the state to which the link is transitioning.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- PNET80211_BSS BssState;
- PVOID DeviceContext;
- ULONGLONG LinkSpeed;
- BOOL Notify;
- NET80211_STATE OldState;
- USHORT Reason;
- BOOL SetLinkUp;
- KSTATUS Status;
- ULONG Subtype;
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- Bss = Link->ActiveBss;
- OldState = Link->State;
- //
- // State transitions are not allowed from the probing state. Save the
- // transition so it can be replayed later after the link moves out of the
- // probing state.
- //
- if (OldState == Net80211StateProbing) {
- Link->ProbeNextState = State;
- goto SetStateUnlockedEnd;
- }
- //
- // Notify the driver about the state transition first, allowing it to
- // prepare for the type of packets to be sent and received in the new state.
- //
- BssState = NULL;
- if (Bss != NULL) {
- BssState = &(Bss->State);
- }
- DeviceContext = Link->Properties.DeviceContext;
- Status = Link->Properties.Interface.SetState(DeviceContext,
- State,
- BssState);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("802.11: Failed to set state %d: 0x%08x\n",
- State,
- Status);
- goto SetStateUnlockedEnd;
- }
- //
- // Officially update the state.
- //
- Link->State = State;
- //
- // Make sure the state transition timer is canceled.
- //
- Net80211pCancelStateTransitionTimer(Link);
- //
- // Perform the necessary steps according to the state transition.
- //
- SetLinkUp = FALSE;
- switch (State) {
- case Net80211StateAuthenticating:
- switch (OldState) {
- case Net80211StateAssociated:
- case Net80211StateEncrypted:
- Status = Net80211pPrepareForReconnect(Link, &Bss);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- //
- // Fall through to send the authentication request.
- //
- case Net80211StateAssociating:
- case Net80211StateReassociating:
- case Net80211StateInitialized:
- Status = Net80211pSendAuthenticationRequest(Link, Bss);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- Status = Net80211pQueueStateTransitionTimer(Link,
- NET80211_STATE_TIMEOUT);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- break;
- default:
- break;
- }
- break;
- case Net80211StateAssociating:
- switch (OldState) {
- case Net80211StateAssociated:
- case Net80211StateEncrypted:
- Status = Net80211pPrepareForReconnect(Link, &Bss);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- //
- // Fall through to send the association request.
- //
- case Net80211StateAuthenticating:
- //
- // Send out an association request and set the timeout.
- //
- Status = Net80211pSendAssociationRequest(Link, Bss);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- Status = Net80211pQueueStateTransitionTimer(Link,
- NET80211_STATE_TIMEOUT);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- break;
- default:
- break;
- }
- break;
- //
- // In the associated state, if no advanced encryption is involved, the link
- // is ready to start transmitting and receiving data.
- //
- case Net80211StateAssociated:
- ASSERT(Bss != NULL);
- if ((Bss->Encryption.Pairwise == NetworkEncryptionNone) ||
- (Bss->Encryption.Pairwise == NetworkEncryptionWep)) {
- SetLinkUp = TRUE;
- } else {
- //
- // Initialize the encryption authentication process so that it is
- // ready to receive key exchange packets.
- //
- Status = Net80211pInitializeEncryption(Link, Bss);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- Status = Net80211pQueueStateTransitionTimer(
- Link,
- NET80211_AUTHENTICATION_TIMEOUT);
- if (!KSUCCESS(Status)) {
- goto SetStateUnlockedEnd;
- }
- }
- break;
- //
- // If advanced encryption was involved, then the link is not ready until
- // the encrypted state is reached.
- //
- case Net80211StateEncrypted:
- ASSERT((Bss->Encryption.Pairwise == NetworkEncryptionWpaPsk) ||
- (Bss->Encryption.Pairwise == NetworkEncryptionWpa2Psk));
- Net80211pDestroyEncryption(Bss);
- SetLinkUp = TRUE;
- break;
- case Net80211StateInitialized:
- case Net80211StateUninitialized:
- switch (OldState) {
- case Net80211StateAssociated:
- case Net80211StateEncrypted:
- Notify = TRUE;
- Subtype = NET80211_MANAGEMENT_FRAME_SUBTYPE_DISASSOCIATION;
- Reason = NET80211_REASON_CODE_DISASSOCIATION_LEAVING;
- break;
- case Net80211StateAssociating:
- Notify = TRUE;
- Subtype = NET80211_MANAGEMENT_FRAME_SUBTYPE_DEAUTHENTICATION;
- Reason = NET80211_REASON_CODE_DEAUTHENTICATION_LEAVING;
- break;
- default:
- Notify = FALSE;
- Subtype = 0;
- Reason = 0;
- break;
- }
- if (Bss != NULL) {
- Net80211pDestroyEncryption(Bss);
- Net80211pLeaveBss(Link, Bss, Notify, Subtype, Reason);
- NetSetLinkState(Link->NetworkLink, FALSE, 0);
- }
- break;
- default:
- break;
- }
- //
- // If requested, fire up the link and get traffic going in the upper layers.
- //
- if (SetLinkUp != FALSE) {
- Net80211pResumeDataFrames(Link);
- LinkSpeed = Bss->State.MaxRate * NET80211_RATE_UNIT;
- NetSetLinkState(Link->NetworkLink, TRUE, LinkSpeed);
- }
- SetStateUnlockedEnd:
- return;
- }
- VOID
- Net80211pScanThread (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the entry point for the scan thread.
- Arguments:
- Parameter - Supplies a pointer supplied by the creator of the thread. In
- this can it is a pointer to an 802.11 scan state structure.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS_ENTRY ActiveBss;
- PNET80211_BSS_ENTRY BssEntry;
- PLIST_ENTRY CurrentEntry;
- PNET80211_BSS_ENTRY FoundEntry;
- PNET80211_LINK Link;
- BOOL LockHeld;
- BOOL Match;
- LONG MaxRssi;
- PNET80211_SCAN_STATE Scan;
- ULONGLONG ScanDelay;
- ULONG SsidLength;
- KSTATUS Status;
- LockHeld = FALSE;
- Scan = (PNET80211_SCAN_STATE)Parameter;
- Link = Scan->Link;
- //
- // Acquire the link's scan lock to prevent multiple scans from happening
- // simultaneously. This protects the hardware from being set to different
- // channels and protects against a network being joined during a scan.
- //
- KeAcquireQueuedLock(Link->ScanLock);
- //
- // Before pulling in new BSS entries, clean out the old ones.
- //
- Net80211pTrimBssCache(Link);
- //
- // If there is an active BSS, then this is a background scan.
- //
- ActiveBss = Net80211pGetBss(Link);
- if (ActiveBss != NULL) {
- Scan->Flags |= NET80211_SCAN_FLAG_BACKGROUND;
- }
- //
- // If this is a foreground scan, just set the state to probing and start
- // running through the channels.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BACKGROUND) == 0) {
- Net80211pStartProbing(Link);
- ScanDelay = NET80211_DEFAULT_SCAN_DWELL_TIME;
- } else {
- ScanDelay = ActiveBss->State.BeaconInterval * NET80211_TIME_UNIT;
- if (ScanDelay > NET80211_BEACON_INTERVAL_PAD) {
- ScanDelay -= NET80211_BEACON_INTERVAL_PAD;
- }
- }
- //
- // Always start scanning on channel 1.
- //
- Scan->Channel = 1;
- //
- // Search for BSS entries on all channels.
- //
- FoundEntry = NULL;
- while (Scan->Channel < Link->Properties.MaxChannel) {
- //
- // If this a background scan, temporarily set the state to probing to
- // alert that hardware that it's in scan mode.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BACKGROUND) != 0) {
- Net80211pStartProbing(Link);
- }
- //
- // Set the channel to send the packet over.
- //
- Status = Net80211pSetChannel(Link, Scan->Channel);
- if (!KSUCCESS(Status)) {
- goto ScanThreadEnd;
- }
- //
- // Send a probe request over the link, this will look in the
- // current scan state and set the correct channel and BSSID
- // (broadcast or a specific ID).
- //
- Status = Net80211pSendProbeRequest(Link, Scan);
- if (!KSUCCESS(Status)) {
- goto ScanThreadEnd;
- }
- //
- // Give the responses a chance before moving to the next channel.
- //
- KeDelayExecution(FALSE, FALSE, ScanDelay);
- //
- // If this a background scan, set the state back to what it was and
- // continue sending packets for a period.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BACKGROUND) != 0) {
- if (ActiveBss != NULL) {
- Status = Net80211pSetChannel(Link, ActiveBss->State.Channel);
- if (!KSUCCESS(Status)) {
- goto ScanThreadEnd;
- }
- }
- Net80211pStopProbing(Link);
- }
- //
- // Now that the channel has been probed, search to see if the
- // targeted BSS is in range. This should only be done if a specific
- // BSSID is being probed.
- //
- if (((Scan->Flags & NET80211_SCAN_FLAG_BROADCAST) == 0) &&
- ((Scan->Flags & NET80211_SCAN_FLAG_JOIN) != 0)) {
- KeAcquireQueuedLock(Link->Lock);
- LockHeld = TRUE;
- FoundEntry = Net80211pLookupBssEntry(Link, Scan->Bssid);
- if (FoundEntry != NULL) {
- Status = Net80211pValidateRates(Link, FoundEntry);
- if (!KSUCCESS(Status)) {
- goto ScanThreadEnd;
- }
- break;
- }
- KeReleaseQueuedLock(Link->Lock);
- LockHeld = FALSE;
- }
- Scan->Channel += 1;
- //
- // When performing background scans, wait a bit before moving to the
- // next channel to allow normal traffic to progress.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BACKGROUND) != 0) {
- KeDelayExecution(FALSE,
- FALSE,
- NET80211_BACKGROUND_SCAN_CHANNEL_DELAY);
- }
- }
- //
- // Stop probing if this is not a background scan.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BACKGROUND) == 0) {
- Net80211pStopProbing(Link);
- }
- //
- // If the scan completed and a join is required, then search for the
- // BSS with the most signal strength.
- //
- if (((Scan->Flags & NET80211_SCAN_FLAG_BROADCAST) != 0) &&
- ((Scan->Flags & NET80211_SCAN_FLAG_JOIN) != 0)) {
- ASSERT(Scan->SsidLength != 0);
- ASSERT(FoundEntry == NULL);
- MaxRssi = MIN_LONG;
- KeAcquireQueuedLock(Link->Lock);
- LockHeld = TRUE;
- CurrentEntry = Link->BssList.Next;
- while (CurrentEntry != &(Link->BssList)) {
- BssEntry = LIST_VALUE(CurrentEntry,
- NET80211_BSS_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- SsidLength = NET80211_GET_ELEMENT_LENGTH(BssEntry->Ssid);
- if (SsidLength != Scan->SsidLength) {
- continue;
- }
- Match = RtlCompareMemory(NET80211_GET_ELEMENT_DATA(BssEntry->Ssid),
- Scan->Ssid,
- Scan->SsidLength);
- if (Match == FALSE) {
- continue;
- }
- //
- // Validate that the BSS and station agree on a basic rate set.
- // Also determine the mode at which it would connect.
- //
- Status = Net80211pValidateRates(Link, BssEntry);
- if (!KSUCCESS(Status)) {
- continue;
- }
- if (BssEntry->State.Rssi >= MaxRssi) {
- MaxRssi = BssEntry->State.Rssi;
- FoundEntry = BssEntry;
- }
- }
- if (FoundEntry == NULL) {
- KeReleaseQueuedLock(Link->Lock);
- LockHeld = FALSE;
- }
- }
- //
- // If an entry was found, join that BSS and start the authentication
- // process.
- //
- if (FoundEntry != NULL) {
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- if (FoundEntry->Encryption.Pairwise != NetworkEncryptionNone) {
- if (Scan->PassphraseLength == 0) {
- Status = STATUS_ACCESS_DENIED;
- goto ScanThreadEnd;
- }
- if (FoundEntry->Encryption.Pairwise != NetworkEncryptionWpa2Psk) {
- Status = STATUS_NOT_SUPPORTED;
- goto ScanThreadEnd;
- }
- RtlCopyMemory(FoundEntry->Passphrase,
- Scan->Passphrase,
- Scan->PassphraseLength);
- FoundEntry->PassphraseLength = Scan->PassphraseLength;
- }
- //
- // Leave the active BSS by setting the state back to initialized.
- //
- Net80211pSetStateUnlocked(Link, Net80211StateInitialized);
- Net80211pJoinBss(Link, FoundEntry);
- Net80211pSetChannel(Link, FoundEntry->State.Channel);
- Net80211pSetStateUnlocked(Link, Net80211StateAuthenticating);
- Status = STATUS_SUCCESS;
- } else if ((Scan->Flags & NET80211_SCAN_FLAG_JOIN) != 0) {
- Status = STATUS_UNSUCCESSFUL;
- } else {
- Status = STATUS_SUCCESS;
- }
- ScanThreadEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Link->Lock);
- }
- KeReleaseQueuedLock(Link->ScanLock);
- if (!KSUCCESS(Status)) {
- Net80211pSetState(Link, Net80211StateInitialized);
- }
- if (Scan->CompletionRoutine != NULL) {
- Scan->CompletionRoutine(Link, Status);
- }
- if (ActiveBss != NULL) {
- Net80211pBssEntryReleaseReference(ActiveBss);
- }
- Net80211LinkReleaseReference(Link);
- MmFreePagedPool(Scan);
- return;
- }
- VOID
- Net80211pStartProbing (
- PNET80211_LINK Link
- )
- /*++
- Routine Description:
- This routine prepares the given link for a network probe by pausing data
- frames and saving the current state.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that is about to start probing
- for networks.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS BssState;
- PVOID DeviceContext;
- KSTATUS Status;
- KeAcquireQueuedLock(Link->Lock);
- ASSERT(Link->State != Net80211StateProbing);
- ASSERT(Link->ProbePreviousState == Net80211StateInvalid);
- ASSERT(Link->ProbeNextState == Net80211StateInvalid);
- //
- // Set the next state to invalid.
- //
- Link->ProbeNextState = Net80211StateInvalid;
- //
- // When entering the probe state, immediately pause data packet
- // transmission. This must be done before the hardware is notified of the
- // switch.
- //
- Net80211pPauseDataFrames(Link);
- //
- // Notify the hardware about the transition to probing.
- //
- BssState = NULL;
- if (Link->ActiveBss != NULL) {
- BssState = &(Link->ActiveBss->State);
- }
- DeviceContext = Link->Properties.DeviceContext;
- Status = Link->Properties.Interface.SetState(DeviceContext,
- Net80211StateProbing,
- BssState);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("802.11: Failed to set state %d: 0x%08x\n",
- Net80211StateProbing,
- Status);
- goto StartProbingEnd;
- }
- //
- // Save the current state and transition to the probing state.
- //
- Link->ProbePreviousState = Link->State;
- Link->State = Net80211StateProbing;
- StartProbingEnd:
- if (!KSUCCESS(Status)) {
- Net80211pResumeDataFrames(Link);
- }
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- VOID
- Net80211pStopProbing (
- PNET80211_LINK Link
- )
- /*++
- Routine Description:
- This routine takes the given link for out of the probing state, restoring
- the previous state. Keep in mind that an attempt to transition the state
- may have occurred while the link was probing. This routine will replay that
- transition after reverting the previous state.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that is exiting the probing
- state.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS BssState;
- PVOID DeviceContext;
- KSTATUS Status;
- KeAcquireQueuedLock(Link->Lock);
- ASSERT(Link->State == Net80211StateProbing);
- //
- // Restore the initial state, notify the hardware of the transition and
- // resume the data frames.
- //
- BssState = NULL;
- if (Link->ActiveBss != NULL) {
- BssState = &(Link->ActiveBss->State);
- }
- DeviceContext = Link->Properties.DeviceContext;
- Status = Link->Properties.Interface.SetState(DeviceContext,
- Link->ProbePreviousState,
- BssState);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("802.11: Failed to set state %d: 0x%08x\n",
- Link->ProbePreviousState,
- Status);
- goto StopProbingEnd;
- }
- Link->State = Link->ProbePreviousState;
- Net80211pResumeDataFrames(Link);
- //
- // If the transition state is not invalid, then the link tried to move to
- // a new state while the probe was active. Replay that transition now that
- // the original state is restored.
- //
- if (Link->ProbeNextState != Net80211StateInvalid) {
- Net80211pSetStateUnlocked(Link, Link->ProbeNextState);
- }
- Link->ProbePreviousState = Net80211StateInvalid;
- Link->ProbeNextState = Net80211StateInvalid;
- StopProbingEnd:
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- KSTATUS
- Net80211pPrepareForReconnect (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY *Bss
- )
- /*++
- Routine Description:
- This routine prepares the network link for reconnecting to the given BSS.
- This includes pausing all outgoing data traffic and creating a copy of the
- BSS entry to use for the new association.
- Arguments:
- Link - Supplies a pointer to the 802.11 link to be connected to the BSS.
- Bss - Supplies a pointer to a BSS on entry on input that is being left and
- on output, receives a pointer to the copied BSS entry to join.
- Return Value:
- Status code.
- --*/
- {
- PNET80211_BSS_ENTRY BssCopy;
- PNET80211_BSS_ENTRY BssOriginal;
- KSTATUS Status;
- BssOriginal = *Bss;
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- ASSERT(BssOriginal = Link->ActiveBss);
- //
- // Copy the BSS so a fresh state is used for the reconnection. Old
- // encryption keys must be reacquired.
- //
- BssCopy = Net80211pCopyBssEntry(BssOriginal);
- if (BssCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto PrepareForReconnectEnd;
- }
- //
- // Pause all data frames while the link is attempting to reconnect to the
- // BSS.
- //
- Net80211pPauseDataFrames(Link);
- //
- // Leave the original BSS and join the copy.
- //
- Net80211pLeaveBss(Link, BssOriginal, FALSE, 0, 0);
- Net80211pJoinBss(Link, BssCopy);
- INSERT_BEFORE(&(BssCopy->ListEntry), &(Link->BssList));
- *Bss = BssCopy;
- Status = STATUS_SUCCESS;
- PrepareForReconnectEnd:
- return Status;
- }
- VOID
- Net80211pJoinBss (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- )
- /*++
- Routine Description:
- This routine joins the given network link to the BSS.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that is joining the BSS.
- Bss - Supplies a pointer to the BSS to join.
- Return Value:
- None.
- --*/
- {
- ASSERT(Link->ActiveBss == NULL);
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- Link->ActiveBss = Bss;
- Net80211pBssEntryAddReference(Bss);
- return;
- }
- VOID
- Net80211pLeaveBss (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss,
- BOOL SendNotification,
- ULONG Subtype,
- USHORT Reason
- )
- /*++
- Routine Description:
- This routine disconnects the network link from the given BSS. With this
- disconnection, any encryption keys are now invalid. To safely move said
- keys out of the system, this routine removes the BSS from the global list
- and releases the reference taken by the list. The BSS entry should be
- destroyed shortly.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that is leaving the BSS.
- Bss - Supplies a pointer to the BSS to leave.
- SendNotification - Supplies a boolean indicating whether or not this
- station should notify the BSS that it is leaving.
- Subtype - Supplies the notification type in the form of a management frame
- subtype. It should either be disassociation or deauthentication.
- Reason - Supplies the reason for leaving. See NET80211_REASON_CODE_* for
- definitions.
- Return Value:
- None.
- --*/
- {
- ASSERT(Link->ActiveBss == Bss);
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- if (SendNotification != FALSE) {
- Net80211pSendManagementFrame(Link,
- Bss->State.Bssid,
- Bss->State.Bssid,
- Subtype,
- &Reason,
- sizeof(USHORT));
- }
- Link->ActiveBss = NULL;
- //
- // Remove the BSS from the global list, destroy the reference taken on join
- // and the list's reference. This really just needs to destroy the keys,
- // but while the BSS is on the list and reference are outstanding, the keys
- // may be in use. The best thing to do is destroy the BSS entry.
- //
- LIST_REMOVE(&(Bss->ListEntry));
- Net80211pBssEntryReleaseReference(Bss);
- Net80211pBssEntryReleaseReference(Bss);
- return;
- }
- KSTATUS
- Net80211pSendProbeRequest (
- PNET80211_LINK Link,
- PNET80211_SCAN_STATE Scan
- )
- /*++
- Routine Description:
- This routine sends an 802.11 management probe request frame based on the
- given scan state.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which to send the probe
- request.
- Scan - Supplies a pointer to the scan state that is requesting the probe.
- Return Value:
- Status code.
- --*/
- {
- PUCHAR Bssid;
- PUCHAR DestinationAddress;
- PUCHAR FrameBody;
- ULONG FrameBodySize;
- ULONG FrameSubtype;
- PUCHAR InformationByte;
- PNET80211_RATE_INFORMATION Rates;
- KSTATUS Status;
- FrameBody = NULL;
- //
- // The probe request packed always includes the SSID, supported rates and
- // channel (DSSS).
- //
- ASSERT(Scan->SsidLength <= NET80211_MAX_SSID_LENGTH);
- FrameBodySize = 0;
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE;
- FrameBodySize += Scan->SsidLength;
- //
- // Get the supported rates size.
- //
- Rates = Link->Properties.SupportedRates;
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE;
- if (Rates->Count > NET80211_MAX_SUPPORTED_RATES) {
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE;
- }
- FrameBodySize += Rates->Count;
- //
- // Get the DSSS (channel) size.
- //
- FrameBodySize += NET80211_DSSS_SIZE;
- //
- // Allocate a buffer to hold the probe request frame body.
- //
- FrameBody = MmAllocatePagedPool(FrameBodySize, NET80211_ALLOCATION_TAG);
- if (FrameBody == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SendProbeRequestEnd;
- }
- //
- // Fill out the frame body. There is a strict order here, so do not
- // rearrange the information elements.
- //
- InformationByte = FrameBody;
- *InformationByte = NET80211_ELEMENT_SSID;
- InformationByte += 1;
- *InformationByte = Scan->SsidLength;
- InformationByte += 1;
- if (Scan->SsidLength != 0) {
- RtlCopyMemory(InformationByte, Scan->Ssid, Scan->SsidLength);
- InformationByte += Scan->SsidLength;
- }
- *InformationByte = NET80211_ELEMENT_SUPPORTED_RATES;
- InformationByte += 1;
- if (Rates->Count <= NET80211_MAX_SUPPORTED_RATES) {
- *InformationByte = Rates->Count;
- InformationByte += 1;
- RtlCopyMemory(InformationByte, Rates->Rate, Rates->Count);
- InformationByte += Rates->Count;
- } else {
- *InformationByte = NET80211_MAX_SUPPORTED_RATES;
- InformationByte += 1;
- RtlCopyMemory(InformationByte,
- Rates->Rate,
- NET80211_MAX_SUPPORTED_RATES);
- InformationByte += NET80211_MAX_SUPPORTED_RATES;
- *InformationByte = NET80211_ELEMENT_EXTENDED_SUPPORTED_RATES;
- InformationByte += 1;
- *InformationByte = Rates->Count - NET80211_MAX_SUPPORTED_RATES;
- InformationByte += 1;
- RtlCopyMemory(InformationByte,
- &(Rates->Rate[NET80211_MAX_SUPPORTED_RATES]),
- Rates->Count - NET80211_MAX_SUPPORTED_RATES);
- InformationByte += Rates->Count - NET80211_MAX_SUPPORTED_RATES;
- }
- *InformationByte = NET80211_ELEMENT_DSSS;
- InformationByte += 1;
- *InformationByte = 1;
- InformationByte += 1;
- *InformationByte = (UCHAR)Scan->Channel;
- InformationByte += 1;
- ASSERT(FrameBodySize == (InformationByte - FrameBody));
- //
- // Send the management frame down to the lower layers.
- //
- if ((Scan->Flags & NET80211_SCAN_FLAG_BROADCAST) != 0) {
- Bssid = NULL;
- DestinationAddress = NULL;
- } else {
- Bssid = Scan->Bssid;
- DestinationAddress = Scan->Bssid;
- }
- FrameSubtype = NET80211_MANAGEMENT_FRAME_SUBTYPE_PROBE_REQUEST;
- Status = Net80211pSendManagementFrame(Link,
- DestinationAddress,
- Bssid,
- FrameSubtype,
- FrameBody,
- FrameBodySize);
- if (!KSUCCESS(Status)) {
- goto SendProbeRequestEnd;
- }
- SendProbeRequestEnd:
- if (FrameBody != NULL) {
- MmFreePagedPool(FrameBody);
- }
- return Status;
- }
- VOID
- Net80211pProcessProbeResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- )
- /*++
- Routine Description:
- This routine processes an 802.11 management probe response frame. It stores
- the information for the transmitting BSS in the BSS cache.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that received the probe
- response.
- Packet - Supplies a pointer to the packet to process.
- Return Value:
- None.
- --*/
- {
- UCHAR ElementId;
- ULONG ElementLength;
- ULONG ExpectedFrameSize;
- PUCHAR FrameBody;
- ULONG FrameSize;
- PNET80211_MANAGEMENT_FRAME_HEADER Header;
- ULONG Offset;
- NET80211_PROBE_RESPONSE Response;
- ULONG Subtype;
- if (Link->State != Net80211StateProbing) {
- goto ProcessProbeResponseEnd;
- }
- Header = Packet->Buffer + Packet->DataOffset;
- Subtype = NET80211_GET_FRAME_SUBTYPE(Header);
- RtlZeroMemory(&Response, sizeof(NET80211_PROBE_RESPONSE));
- ASSERT((Subtype == NET80211_MANAGEMENT_FRAME_SUBTYPE_BEACON) ||
- (Subtype == NET80211_MANAGEMENT_FRAME_SUBTYPE_PROBE_RESPONSE));
- //
- // Parse the response. It should at least have a timestamp, beacon
- // interval, and capabilities field.
- //
- FrameBody = Packet->Buffer + Packet->DataOffset;
- FrameSize = Packet->FooterOffset - Packet->DataOffset;
- Offset = sizeof(NET80211_MANAGEMENT_FRAME_HEADER);
- ExpectedFrameSize = Offset +
- NET80211_TIMESTAMP_SIZE +
- NET80211_BEACON_INTERVAL_SIZE +
- NET80211_CAPABILITY_SIZE;
- if (ExpectedFrameSize > FrameSize) {
- goto ProcessProbeResponseEnd;
- }
- //
- // Save the timestamp.
- //
- Response.Timestamp = *((PULONGLONG)&(FrameBody[Offset]));
- Offset += NET80211_TIMESTAMP_SIZE;
- //
- // Save the beacon internval.
- //
- Response.BeaconInterval = *((PUSHORT)&(FrameBody[Offset]));
- Offset += NET80211_BEACON_INTERVAL_SIZE;
- //
- // Save the capabilities.
- //
- Response.Capabilities = *((PUSHORT)&(FrameBody[Offset]));
- Offset += NET80211_CAPABILITY_SIZE;
- //
- // Collect the information elements.
- //
- Response.Elements = FrameBody + Offset;
- Response.ElementsSize = FrameSize - Offset;
- while (Offset < FrameSize) {
- if ((Offset + NET80211_ELEMENT_HEADER_SIZE) > FrameSize) {
- goto ProcessProbeResponseEnd;
- }
- ElementId = FrameBody[Offset + NET80211_ELEMENT_ID_OFFSET];
- ElementLength = FrameBody[Offset + NET80211_ELEMENT_LENGTH_OFFSET];
- ExpectedFrameSize = Offset +
- NET80211_ELEMENT_HEADER_SIZE +
- ElementLength;
- if (ExpectedFrameSize > FrameSize) {
- goto ProcessProbeResponseEnd;
- }
- switch (ElementId) {
- case NET80211_ELEMENT_SSID:
- Response.Ssid = FrameBody + Offset;
- break;
- case NET80211_ELEMENT_DSSS:
- if (ElementLength == 0) {
- goto ProcessProbeResponseEnd;
- }
- Response.Channel = FrameBody + Offset;
- break;
- case NET80211_ELEMENT_RSN:
- Response.Rsn = FrameBody + Offset;
- break;
- case NET80211_ELEMENT_SUPPORTED_RATES:
- if (ElementLength == 0) {
- goto ProcessProbeResponseEnd;
- }
- Response.Rates = FrameBody + Offset;
- break;
- case NET80211_ELEMENT_EXTENDED_SUPPORTED_RATES:
- if (ElementLength == 0) {
- goto ProcessProbeResponseEnd;
- }
- Response.ExtendedRates = FrameBody + Offset;
- break;
- default:
- break;
- }
- Offset += NET80211_ELEMENT_HEADER_SIZE + ElementLength;
- }
- //
- // Toss out the packet if not all of the expected information is present.
- //
- if ((Response.Rates == NULL) ||
- (Response.Channel == NULL) ||
- (Response.Ssid == NULL)) {
- goto ProcessProbeResponseEnd;
- }
- //
- // Filter out any beacon/probe responses that claim to be open but still
- // include encryption information. Also filter out the opposite where
- // privacy is a required capability, but no encryption information was
- // provided.
- //
- if (Response.Rsn != NULL) {
- if ((Response.Capabilities & NET80211_CAPABILITY_FLAG_PRIVACY) == 0) {
- RtlDebugPrint("802.11: Found RSN element in probe/beacon that does "
- "not require privacy.\n");
- goto ProcessProbeResponseEnd;
- }
- } else {
- if ((Response.Capabilities & NET80211_CAPABILITY_FLAG_PRIVACY) != 0) {
- RtlDebugPrint("802.11: Did not find RSN element in probe/beacon "
- "that requires privacy.\n");
- goto ProcessProbeResponseEnd;
- }
- }
- //
- // Update the BSS cache with the latest information from this beacon /
- // probe response. The SSID, encryption method, and rates are subject to
- // change for a BSSID.
- //
- Response.Bssid = Header->SourceAddress;
- Net80211pUpdateBssCache(Link, &Response);
- ProcessProbeResponseEnd:
- return;
- }
- KSTATUS
- Net80211pSendAuthenticationRequest (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- )
- /*++
- Routine Description:
- This routine sends an 802.11 management authentication frame to the AP of
- the given BSS.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which to send an
- authentication request.
- Bss - Supplies a pointer to the BSS over which to send the authentication
- frame.
- Return Value:
- Status code.
- --*/
- {
- NET80211_AUTHENTICATION_OPEN_BODY FrameBody;
- ULONG FrameBodySize;
- ULONG FrameSubtype;
- KSTATUS Status;
- //
- // Fill out the authentication body.
- //
- FrameBody.AlgorithmNumber = NET80211_AUTHENTICATION_ALGORITHM_OPEN;
- FrameBody.TransactionSequenceNumber =
- NET80211_AUTHENTICATION_REQUEST_SEQUENCE_NUMBER;
- FrameBody.StatusCode = NET80211_STATUS_CODE_SUCCESS;
- //
- // Send the authentication frame off. The destination address and BSSID
- // should match.
- //
- FrameBodySize = sizeof(NET80211_AUTHENTICATION_OPEN_BODY);
- FrameSubtype = NET80211_MANAGEMENT_FRAME_SUBTYPE_AUTHENTICATION;
- Status = Net80211pSendManagementFrame(Link,
- Bss->State.Bssid,
- Bss->State.Bssid,
- FrameSubtype,
- &FrameBody,
- FrameBodySize);
- if (!KSUCCESS(Status)) {
- goto SendAuthenticationEnd;
- }
- SendAuthenticationEnd:
- return Status;
- }
- VOID
- Net80211pProcessAuthenticationResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- )
- /*++
- Routine Description:
- This routine processes an authentication response frame. It is expected to
- be sent from the BSSID stored in the link's BSS context.
- Arguments:
- Link - Supplies a pointer to the 802.11 link on which the authentication
- packet was received.
- Packet - Supplies a pointer to the network packet containing the
- authentication frame.
- Return Value:
- None.
- --*/
- {
- PNET80211_AUTHENTICATION_OPEN_BODY Body;
- PNET80211_BSS_ENTRY Bss;
- ULONG ExpectedFrameSize;
- ULONG FrameSize;
- PNET80211_MANAGEMENT_FRAME_HEADER Header;
- BOOL Match;
- KSTATUS Status;
- Status = STATUS_SUCCESS;
- if (Link->State != Net80211StateAuthenticating) {
- return;
- }
- KeAcquireQueuedLock(Link->Lock);
- if (Link->State != Net80211StateAuthenticating) {
- goto ProcessAuthenticationResponseEnd;
- }
- ASSERT(Link->ActiveBss != NULL);
- Bss = Link->ActiveBss;
- //
- // Make sure the this frame was sent from the AP of the BSS.
- //
- Header = Packet->Buffer + Packet->DataOffset;
- Match = RtlCompareMemory(Header->SourceAddress,
- Bss->State.Bssid,
- NET80211_ADDRESS_SIZE);
- if (Match == FALSE) {
- Status = STATUS_INVALID_ADDRESS;
- goto ProcessAuthenticationResponseEnd;
- }
- //
- // Make sure it is large enough to hold the authentication body.
- //
- FrameSize = Packet->FooterOffset - Packet->DataOffset;
- ExpectedFrameSize = sizeof(NET80211_MANAGEMENT_FRAME_HEADER) +
- sizeof(NET80211_AUTHENTICATION_OPEN_BODY);
- if (FrameSize < ExpectedFrameSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ProcessAuthenticationResponseEnd;
- }
- //
- // The authentication response has a very fixed frame body.
- //
- Body = Packet->Buffer +
- Packet->DataOffset +
- sizeof(NET80211_MANAGEMENT_FRAME_HEADER);
- if (Body->AlgorithmNumber != NET80211_AUTHENTICATION_ALGORITHM_OPEN) {
- RtlDebugPrint("802.11: Unexpected algorithm type %d. Expected %d.\n",
- Body->AlgorithmNumber,
- NET80211_AUTHENTICATION_ALGORITHM_OPEN);
- Status = STATUS_NOT_SUPPORTED;
- goto ProcessAuthenticationResponseEnd;
- }
- if (Body->TransactionSequenceNumber !=
- NET80211_AUTHENTICATION_RESPONSE_SEQUENCE_NUMBER) {
- RtlDebugPrint("802.11: Unexpected authentication transaction "
- "sequence number 0x%04x. Expected 0x%04x.\n",
- Body->TransactionSequenceNumber,
- NET80211_AUTHENTICATION_RESPONSE_SEQUENCE_NUMBER);
- Status = STATUS_UNSUCCESSFUL;
- goto ProcessAuthenticationResponseEnd;
- }
- if (Body->StatusCode != NET80211_STATUS_CODE_SUCCESS) {
- RtlDebugPrint("802.11: Authentication failed with status %d\n",
- Body->StatusCode);
- Status = STATUS_UNSUCCESSFUL;
- goto ProcessAuthenticationResponseEnd;
- }
- Net80211pSetStateUnlocked(Link, Net80211StateAssociating);
- Status = STATUS_SUCCESS;
- ProcessAuthenticationResponseEnd:
- if (!KSUCCESS(Status)) {
- Net80211pSetStateUnlocked(Link, Net80211StateInitialized);
- }
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- KSTATUS
- Net80211pSendAssociationRequest (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- )
- /*++
- Routine Description:
- This routine sends an 802.11 management association request frame to the
- to the AP of the given BSS.
- Arguments:
- Link - Supplies a pointer to the 802.11 link over which to send the
- association request.
- Bss - Supplies a pointer to the BSS over which to send the association
- request.
- Return Value:
- Status code.
- --*/
- {
- PUCHAR FrameBody;
- ULONG FrameBodySize;
- ULONG FrameSubtype;
- PUCHAR InformationByte;
- PNET80211_RATE_INFORMATION Rates;
- ULONG SsidLength;
- KSTATUS Status;
- ASSERT(Bss != NULL);
- ASSERT(Bss->Ssid != NULL);
- FrameBody = NULL;
- SsidLength = NET80211_GET_ELEMENT_LENGTH(Bss->Ssid);
- //
- // Determine the size of the probe response packet, which always includes
- // the capabilities, listen interval, SSID, and supported rates.
- //
- ASSERT((SsidLength <= NET80211_MAX_SSID_LENGTH) && (SsidLength != 0));
- FrameBodySize = NET80211_CAPABILITY_SIZE + NET80211_LISTEN_INTERVAL_SIZE;
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE + SsidLength;
- //
- // Get the supported rates size, including the extended rates if necessary.
- //
- Rates = Link->Properties.SupportedRates;
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE;
- if (Rates->Count > NET80211_MAX_SUPPORTED_RATES) {
- FrameBodySize += NET80211_ELEMENT_HEADER_SIZE;
- }
- FrameBodySize += Rates->Count;
- //
- // Only include the RSN information if advanced encryption is required.
- //
- if ((Bss->Encryption.Pairwise != NetworkEncryptionNone) &&
- (Bss->Encryption.Pairwise != NetworkEncryptionWep)) {
- FrameBodySize += sizeof(NET80211_DEFAULT_RSN_INFORMATION);
- }
- //
- // Allocate a buffer to hold the assocation request frame body.
- //
- FrameBody = MmAllocatePagedPool(FrameBodySize, NET80211_ALLOCATION_TAG);
- if (FrameBody == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SendAssociationRequestEnd;
- }
- //
- // Fill out the frame body. There is a strict order here, so do not
- // rearrage the information elements.
- //
- InformationByte = FrameBody;
- *((PUSHORT)InformationByte) = Link->Properties.Capabilities |
- NET80211_CAPABILITY_FLAG_ESS;
- InformationByte += NET80211_CAPABILITY_SIZE;
- //
- // TODO: Implement a non-zero 802.11 listen interval for power save mode.
- //
- *((PUSHORT)InformationByte) = 0;
- InformationByte += NET80211_LISTEN_INTERVAL_SIZE;
- *InformationByte = NET80211_ELEMENT_SSID;
- InformationByte += 1;
- *InformationByte = SsidLength;
- InformationByte += 1;
- RtlCopyMemory(InformationByte,
- NET80211_GET_ELEMENT_DATA(Bss->Ssid),
- SsidLength);
- InformationByte += SsidLength;
- *InformationByte = NET80211_ELEMENT_SUPPORTED_RATES;
- InformationByte += 1;
- if (Rates->Count <= NET80211_MAX_SUPPORTED_RATES) {
- *InformationByte = Rates->Count;
- InformationByte += 1;
- RtlCopyMemory(InformationByte, Rates->Rate, Rates->Count);
- InformationByte += Rates->Count;
- } else {
- *InformationByte = NET80211_MAX_SUPPORTED_RATES;
- InformationByte += 1;
- RtlCopyMemory(InformationByte,
- Rates->Rate,
- NET80211_MAX_SUPPORTED_RATES);
- InformationByte += NET80211_MAX_SUPPORTED_RATES;
- *InformationByte = NET80211_ELEMENT_EXTENDED_SUPPORTED_RATES;
- InformationByte += 1;
- *InformationByte = Rates->Count - NET80211_MAX_SUPPORTED_RATES;
- InformationByte += 1;
- RtlCopyMemory(InformationByte,
- &(Rates->Rate[NET80211_MAX_SUPPORTED_RATES]),
- Rates->Count - NET80211_MAX_SUPPORTED_RATES);
- InformationByte += Rates->Count - NET80211_MAX_SUPPORTED_RATES;
- }
- //
- // Set the RSN information if advanced encryption is required.
- //
- if ((Bss->Encryption.Pairwise != NetworkEncryptionNone) &&
- (Bss->Encryption.Pairwise != NetworkEncryptionWep)) {
- RtlCopyMemory(InformationByte,
- &Net80211DefaultRsnInformation,
- sizeof(NET80211_DEFAULT_RSN_INFORMATION));
- InformationByte += sizeof(NET80211_DEFAULT_RSN_INFORMATION);
- }
- ASSERT(FrameBodySize == (InformationByte - FrameBody));
- //
- // Send the management frame down to the lower layers.
- //
- FrameSubtype = NET80211_MANAGEMENT_FRAME_SUBTYPE_ASSOCIATION_REQUEST;
- Status = Net80211pSendManagementFrame(Link,
- Bss->State.Bssid,
- Bss->State.Bssid,
- FrameSubtype,
- FrameBody,
- FrameBodySize);
- if (!KSUCCESS(Status)) {
- goto SendAssociationRequestEnd;
- }
- SendAssociationRequestEnd:
- if (FrameBody != NULL) {
- MmFreePagedPool(FrameBody);
- }
- return Status;
- }
- VOID
- Net80211pProcessAssociationResponse (
- PNET80211_LINK Link,
- PNET_PACKET_BUFFER Packet
- )
- /*++
- Routine Description:
- This routine processes an 802.11 management association response frame from
- an access point.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that received the association
- response.
- Packet - Supplies a pointer to the network packet that contains the
- association response frame.
- Return Value:
- None.
- --*/
- {
- USHORT AssociationId;
- PNET80211_BSS_ENTRY Bss;
- USHORT Capabilities;
- PUCHAR ElementBytePointer;
- UCHAR ElementId;
- ULONG ElementLength;
- ULONG ExpectedFrameSize;
- ULONG ExtendedRateCount;
- PUCHAR ExtendedRates;
- ULONG FrameSize;
- USHORT FrameStatus;
- PNET80211_MANAGEMENT_FRAME_HEADER Header;
- BOOL Match;
- ULONG Offset;
- ULONG RateCount;
- PUCHAR Rates;
- KSTATUS Status;
- ULONG TotalRateCount;
- Status = STATUS_SUCCESS;
- if (Link->State != Net80211StateAssociating) {
- return;
- }
- KeAcquireQueuedLock(Link->Lock);
- if (Link->State != Net80211StateAssociating) {
- goto ProcessAssociationResponseEnd;
- }
- ASSERT(Link->ActiveBss != NULL);
- Bss = Link->ActiveBss;
- //
- // Make sure the this frame was sent from the destination.
- //
- Header = Packet->Buffer + Packet->DataOffset;
- Match = RtlCompareMemory(Header->SourceAddress,
- Bss->State.Bssid,
- NET80211_ADDRESS_SIZE);
- if (Match == FALSE) {
- Status = STATUS_INVALID_ADDRESS;
- goto ProcessAssociationResponseEnd;
- }
- //
- // There should at least be capabilities, a status code and the AID.
- //
- FrameSize = Packet->FooterOffset - Packet->DataOffset;
- Offset = sizeof(NET80211_MANAGEMENT_FRAME_HEADER);
- ExpectedFrameSize = Offset +
- NET80211_CAPABILITY_SIZE +
- NET80211_STATUS_CODE_SIZE +
- NET80211_ASSOCIATION_ID_SIZE;
- if (FrameSize < ExpectedFrameSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ProcessAssociationResponseEnd;
- }
- ElementBytePointer = Packet->Buffer + Packet->DataOffset;
- //
- // Save the capabilities.
- //
- Capabilities = *((PUSHORT)&(ElementBytePointer[Offset]));
- Offset += NET80211_CAPABILITY_SIZE;
- //
- // Don't continue unless the association was a success.
- //
- FrameStatus = *((PUSHORT)(&(ElementBytePointer[Offset])));
- if (FrameStatus != NET80211_STATUS_CODE_SUCCESS) {
- RtlDebugPrint("802.11: Association response failed with status "
- "0x%04x.\n",
- FrameStatus);
- Status = STATUS_UNSUCCESSFUL;
- goto ProcessAssociationResponseEnd;
- }
- Offset += NET80211_STATUS_CODE_SIZE;
- //
- // Save the association ID.
- //
- AssociationId = *((PUSHORT)&(ElementBytePointer[Offset]));
- AssociationId &= NET80211_ASSOCIATION_ID_MASK;
- Offset += NET80211_ASSOCIATION_ID_SIZE;
- //
- // Now look at the supplied elements.
- //
- Rates = NULL;
- RateCount = 0;
- ExtendedRates = NULL;
- ExtendedRateCount = 0;
- while (Offset < FrameSize) {
- ElementId = ElementBytePointer[Offset];
- Offset += 1;
- if (Offset >= FrameSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ProcessAssociationResponseEnd;
- }
- ElementLength = ElementBytePointer[Offset];
- Offset += 1;
- if ((Offset + ElementLength) > FrameSize) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ProcessAssociationResponseEnd;
- }
- switch (ElementId) {
- case NET80211_ELEMENT_SUPPORTED_RATES:
- if (ElementLength == 0) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessAssociationResponseEnd;
- }
- Rates = ElementBytePointer + Offset;
- RateCount = ElementLength;
- break;
- case NET80211_ELEMENT_EXTENDED_SUPPORTED_RATES:
- if (ElementLength == 0) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessAssociationResponseEnd;
- }
- ExtendedRates = ElementBytePointer + Offset;
- ExtendedRateCount = ElementLength;
- break;
- default:
- break;
- }
- Offset += ElementLength;
- }
- //
- // If the capabilities or rates have changed from the probe response or
- // beacon, do not proceed with the association. The AP has changed since
- // the association process began. Deauthenticate instead.
- //
- if (Capabilities != Bss->State.Capabilities) {
- Status = STATUS_OPERATION_CANCELLED;
- goto ProcessAssociationResponseEnd;
- }
- TotalRateCount = RateCount + ExtendedRateCount;
- if (TotalRateCount != Bss->State.Rates.Count) {
- Status = STATUS_OPERATION_CANCELLED;
- goto ProcessAssociationResponseEnd;
- }
- //
- // Copy the current rates into the BSS entry.
- //
- RtlCopyMemory(Bss->State.Rates.Rate, Rates, RateCount);
- RtlCopyMemory(Bss->State.Rates.Rate + RateCount,
- ExtendedRates,
- ExtendedRateCount);
- Status = Net80211pValidateRates(Link, Bss);
- if (!KSUCCESS(Status)) {
- goto ProcessAssociationResponseEnd;
- }
- Bss->State.AssociationId = AssociationId;
- Net80211pSetStateUnlocked(Link, Net80211StateAssociated);
- ProcessAssociationResponseEnd:
- if (!KSUCCESS(Status)) {
- Net80211pSetStateUnlocked(Link, Net80211StateInitialized);
- }
- KeReleaseQueuedLock(Link->Lock);
- return;
- }
- KSTATUS
- Net80211pSendManagementFrame (
- PNET80211_LINK Link,
- PUCHAR DestinationAddress,
- PUCHAR Bssid,
- ULONG FrameSubtype,
- PVOID FrameBody,
- ULONG FrameBodySize
- )
- /*++
- Routine Description:
- This routine sends an 802.11 management frame with the given data and
- subtype out over the link.
- Arguments:
- Link - Supplies a pointer to the link on which to send the management frame.
- DestinationAddress - Supplies a pointer to an optional destination address
- for the management frame. Supply NULL to indicate the broadcast address.
- Bssid - Supplies a pointer to an optional BSSID for the management frame.
- Supply NULL to indicate the wildcard BSSID.
- FrameSubtype - Supplies the management frame subtype for the packet.
- FrameBody - Supplies a pointer to the body data to be sent within the frame.
- FrameBodySize - Supplies the size of the body to send in the frame.
- Return Value:
- Status code.
- --*/
- {
- PVOID DeviceContext;
- ULONG Flags;
- PNET80211_MANAGEMENT_FRAME_HEADER Header;
- PNET_PACKET_BUFFER Packet;
- NET_PACKET_LIST PacketList;
- KSTATUS Status;
- NET_INITIALIZE_PACKET_LIST(&PacketList);
- //
- // Allocate a network packet to send down to the lower layers.
- //
- Flags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
- NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS;
- Packet = NULL;
- Status = NetAllocateBuffer(sizeof(NET80211_MANAGEMENT_FRAME_HEADER),
- FrameBodySize,
- 0,
- Link->NetworkLink,
- Flags,
- &Packet);
- if (!KSUCCESS(Status)) {
- goto SendManagementFrameEnd;
- }
- //
- // Copy the data to the newly allocated network packet.
- //
- RtlCopyMemory(Packet->Buffer + Packet->DataOffset,
- FrameBody,
- FrameBodySize);
- //
- // Move the offset backwards and fill in the 802.11 management frame header.
- //
- Packet->DataOffset -= sizeof(NET80211_MANAGEMENT_FRAME_HEADER);
- Header = Packet->Buffer + Packet->DataOffset;
- Header->FrameControl = (NET80211_FRAME_CONTROL_PROTOCOL_VERSION <<
- NET80211_FRAME_CONTROL_PROTOCOL_VERSION_SHIFT) |
- (NET80211_FRAME_TYPE_MANAGEMENT <<
- NET80211_FRAME_CONTROL_TYPE_SHIFT) |
- (FrameSubtype <<
- NET80211_FRAME_CONTROL_SUBTYPE_SHIFT);
- //
- // The hardware handles the duration.
- //
- Header->Duration = 0;
- //
- // Initialize the header's addresses. If the destination or BSSID are NULL,
- // the the broadcast address is to be set.
- //
- if (DestinationAddress != NULL) {
- RtlCopyMemory(Header->DestinationAddress,
- DestinationAddress,
- NET80211_ADDRESS_SIZE);
- } else {
- RtlSetMemory(Header->DestinationAddress, 0xFF, NET80211_ADDRESS_SIZE);
- }
- //
- // The source address is always the local link's physical address (i.e. the
- // MAC address).
- //
- RtlCopyMemory(Header->SourceAddress,
- Link->Properties.PhysicalAddress.Address,
- NET80211_ADDRESS_SIZE);
- if (Bssid != NULL) {
- RtlCopyMemory(Header->Bssid, Bssid, NET80211_ADDRESS_SIZE);
- } else {
- RtlSetMemory(Header->Bssid, 0xFF, NET80211_ADDRESS_SIZE);
- }
- //
- // The header gets the next sequence number for the link. This is only 1
- // fragment, so that remains 0.
- //
- Header->SequenceControl = Net80211pGetSequenceNumber(Link);
- Header->SequenceControl <<= NET80211_SEQUENCE_CONTROL_SEQUENCE_NUMBER_SHIFT;
- //
- // Send the packet off.
- //
- NET_ADD_PACKET_TO_LIST(Packet, &PacketList);
- DeviceContext = Link->Properties.DeviceContext;
- Status = Link->Properties.Interface.Send(DeviceContext, &PacketList);
- if (!KSUCCESS(Status)) {
- goto SendManagementFrameEnd;
- }
- SendManagementFrameEnd:
- if (!KSUCCESS(Status)) {
- NetDestroyBufferList(&PacketList);
- }
- return Status;
- }
- KSTATUS
- Net80211pQueueStateTransitionTimer (
- PNET80211_LINK Link,
- ULONGLONG Timeout
- )
- /*++
- Routine Description:
- This routine queues the given network link's state transition timer.
- Arguments:
- Link - Supplies a pointer to a 802.11 link.
- Timeout - Supplies the desired timeout in microseconds.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG DueTime;
- KSTATUS Status;
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- DueTime = KeGetRecentTimeCounter();
- DueTime += KeConvertMicrosecondsToTimeTicks(Timeout);
- Status = KeQueueTimer(Link->StateTimer,
- TimerQueueSoft,
- DueTime,
- 0,
- 0,
- Link->TimeoutDpc);
- if (KSUCCESS(Status)) {
- Link->Flags |= NET80211_LINK_FLAG_TIMER_QUEUED;
- }
- return Status;
- }
- VOID
- Net80211pCancelStateTransitionTimer (
- PNET80211_LINK Link
- )
- /*++
- Routine Description:
- This routine cancels the given link's state transition timer if it is
- queued.
- Arguments:
- Link - Supplies a pointer to the 802.11 link whose state transition timer
- shall be canceled.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- ASSERT(KeIsQueuedLockHeld(Link->Lock) != FALSE);
- //
- // Cancel the timer if it is queued. Also make sure the DPC is flushed if
- // the timer just expired. The timer may be requeued at any time and a DPC
- // cannot be queued twice.
- //
- if ((Link->Flags & NET80211_LINK_FLAG_TIMER_QUEUED) != 0) {
- Status = KeCancelTimer(Link->StateTimer);
- if (!KSUCCESS(Status)) {
- KeFlushDpc(Link->TimeoutDpc);
- }
- Link->Flags &= ~NET80211_LINK_FLAG_TIMER_QUEUED;
- }
- return;
- }
- KSTATUS
- Net80211pValidateRates (
- PNET80211_LINK Link,
- PNET80211_BSS_ENTRY Bss
- )
- /*++
- Routine Description:
- This routine validates that the link and BSS share the same basic rates and
- detects the maximum mode for a future connection, storing the result in the
- BSS entry.
- Arguments:
- Link - Supplies a pointer to the 802.11 link for which to validate the BSS
- entry's rates.
- Bss - Supplies a pointer to a BSS entry.
- Return Value:
- Status code.
- --*/
- {
- ULONG BssIndex;
- UCHAR BssRate;
- PNET80211_RATE_INFORMATION BssRates;
- UCHAR BssRateValue;
- ULONGLONG LinkSpeed;
- ULONG LocalIndex;
- UCHAR LocalRate;
- PNET80211_RATE_INFORMATION LocalRates;
- UCHAR MaxRate;
- KSTATUS Status;
- BssRates = &(Bss->State.Rates);
- LocalRates = Link->Properties.SupportedRates;
- //
- // Make sure the basic rates are supported. Unfortunately, there is no
- // guarantee about the ordering of the rates. There aren't that many so do
- // not bother sorting.
- //
- MaxRate = 0;
- for (BssIndex = 0; BssIndex < BssRates->Count; BssIndex += 1) {
- BssRate = BssRates->Rate[BssIndex];
- BssRateValue = BssRate & NET80211_RATE_VALUE_MASK;
- if ((BssRate & NET80211_RATE_BASIC) != 0) {
- if (BssRateValue == NET80211_MEMBERSHIP_SELECTOR_HT_PHY) {
- continue;
- }
- } else if (BssRateValue <= MaxRate) {
- continue;
- }
- //
- // Attempt to find the rate in the local supported rates.
- //
- for (LocalIndex = 0; LocalIndex < LocalRates->Count; LocalIndex += 1) {
- LocalRate = LocalRates->Rate[LocalIndex] & NET80211_RATE_VALUE_MASK;
- if (LocalRate == BssRateValue) {
- break;
- }
- }
- //
- // If this is a basic rate and it is not supported locally, then
- // connecting to this BSS is not allowed.
- //
- if (LocalIndex == LocalRates->Count) {
- if ((BssRate & NET80211_RATE_BASIC) != 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto ValidateRatesEnd;
- }
- continue;
- }
- if (BssRateValue > MaxRate) {
- MaxRate = BssRateValue;
- }
- }
- //
- // If no rate could be agreed upon, then fail to connect to the BSS.
- //
- if (MaxRate == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto ValidateRatesEnd;
- }
- //
- // Fill in the connection mode based on the maximum supported rate.
- //
- Bss->State.MaxRate = MaxRate;
- LinkSpeed = MaxRate * NET80211_RATE_UNIT;
- if (LinkSpeed <= NET80211_MODE_B_MAX_RATE) {
- Bss->State.Mode = Net80211ModeB;
- } else if (LinkSpeed <= NET80211_MODE_G_MAX_RATE) {
- Bss->State.Mode = Net80211ModeG;
- } else {
- Status = STATUS_NOT_SUPPORTED;
- goto ValidateRatesEnd;
- }
- Status = STATUS_SUCCESS;
- ValidateRatesEnd:
- return Status;
- }
- KSTATUS
- Net80211pParseRsnElement (
- PUCHAR Rsn,
- PNET80211_ENCRYPTION Encryption
- )
- /*++
- Routine Description:
- This routine parses the RSN information element in order to detect which
- encryption methods are supported by the BSS to which it belongs.
- Arguments:
- Rsn - Supplies a pointer to the RSN element, the first byte of which must
- be the element ID.
- Encryption - Supplies a pointer to an 802.11 encryption structure that
- receives the parsed data from the RSN element.
- Return Value:
- Status code.
- --*/
- {
- NETWORK_ENCRYPTION_TYPE GroupEncryption;
- ULONG Index;
- ULONG Offset;
- NETWORK_ENCRYPTION_TYPE PairwiseEncryption;
- USHORT PmkidCount;
- BOOL PskSupported;
- ULONG RsnLength;
- KSTATUS Status;
- ULONG Suite;
- USHORT SuiteCount;
- PULONG Suites;
- USHORT Version;
- ASSERT(NET80211_GET_ELEMENT_ID(Rsn) == NET80211_ELEMENT_RSN);
- Status = STATUS_SUCCESS;
- Offset = NET80211_ELEMENT_HEADER_SIZE;
- PairwiseEncryption = NetworkEncryptionNone;
- GroupEncryption = NetworkEncryptionNone;
- RsnLength = NET80211_GET_ELEMENT_LENGTH(Rsn);
- //
- // The version field is the only non-optional field.
- //
- if ((Offset + sizeof(USHORT)) > RsnLength) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ParseRsnElementEnd;
- }
- Version = *((PUSHORT)&(Rsn[Offset]));
- Offset += sizeof(USHORT);
- if (Version != NET80211_RSN_VERSION) {
- RtlDebugPrint("802.11: Unexpected RSN version %d\n", Version);
- Status = STATUS_VERSION_MISMATCH;
- goto ParseRsnElementEnd;
- }
- //
- // Get the optional group suite.
- //
- if ((Offset + sizeof(ULONG)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- Suite = NETWORK_TO_CPU32(*((PULONG)&(Rsn[Offset])));
- Offset += sizeof(ULONG);
- switch (Suite) {
- case NET80211_CIPHER_SUITE_WEP_40:
- case NET80211_CIPHER_SUITE_WEP_104:
- GroupEncryption = NetworkEncryptionWep;
- break;
- case NET80211_CIPHER_SUITE_TKIP:
- GroupEncryption = NetworkEncryptionWpaEap;
- break;
- case NET80211_CIPHER_SUITE_CCMP:
- GroupEncryption = NetworkEncryptionWpa2Eap;
- break;
- case NET80211_CIPHER_SUITE_GROUP_NOT_ALLOWED:
- GroupEncryption = NetworkEncryptionNone;
- break;
- default:
- GroupEncryption = NetworkEncryptionInvalid;
- RtlDebugPrint("802.11: Group cipher suite not supported 0x%08x\n",
- Suite);
- break;
- }
- if (GroupEncryption == NetworkEncryptionInvalid) {
- Status = STATUS_NOT_SUPPORTED;
- goto ParseRsnElementEnd;
- }
- //
- // Gather the pairwise suites.
- //
- if ((Offset + sizeof(USHORT)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- SuiteCount = *((PUSHORT)&(Rsn[Offset]));
- Offset += sizeof(USHORT);
- if ((Offset + (SuiteCount * sizeof(ULONG))) > RsnLength) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ParseRsnElementEnd;
- }
- Suites = (PULONG)&(Rsn[Offset]);
- Offset += SuiteCount * sizeof(ULONG);
- for (Index = 0; Index < SuiteCount; Index += 1) {
- Suite = NETWORK_TO_CPU32(Suites[Index]);
- //
- // As soon as CCMP is found, prefer that. None of the others are
- // supported anyway.
- //
- if (Suite == NET80211_CIPHER_SUITE_CCMP) {
- PairwiseEncryption = NetworkEncryptionWpa2Eap;
- break;
- }
- switch (Suite) {
- case NET80211_CIPHER_SUITE_WEP_40:
- case NET80211_CIPHER_SUITE_WEP_104:
- PairwiseEncryption = NetworkEncryptionWep;
- break;
- case NET80211_CIPHER_SUITE_TKIP:
- PairwiseEncryption = NetworkEncryptionWpaEap;
- break;
- case NET80211_CIPHER_SUITE_USE_GROUP_CIPHER:
- PairwiseEncryption = GroupEncryption;
- Encryption->Flags |= NET80211_ENCRYPTION_FLAG_USE_GROUP_CIPHER;
- break;
- default:
- PairwiseEncryption = NetworkEncryptionInvalid;
- RtlDebugPrint("802.11: Pairwise cipher suite not supported "
- "0x%08x\n",
- Suite);
- break;
- }
- }
- if (PairwiseEncryption == NetworkEncryptionInvalid) {
- Status = STATUS_NOT_SUPPORTED;
- goto ParseRsnElementEnd;
- }
- //
- // Upgrade the group and pairwise encryption methods from EAP to PSK if
- // PSK is present.
- //
- if ((Offset + sizeof(USHORT)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- SuiteCount = *((PUSHORT)&(Rsn[Offset]));
- Offset += sizeof(USHORT);
- if ((Offset + (SuiteCount * sizeof(ULONG))) > RsnLength) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ParseRsnElementEnd;
- }
- Suites = (PULONG)&(Rsn[Offset]);
- Offset += SuiteCount * sizeof(ULONG);
- PskSupported = FALSE;
- for (Index = 0; Index < SuiteCount; Index += 1) {
- Suite = NETWORK_TO_CPU32(Suites[Index]);
- if ((Suite == NET80211_AKM_SUITE_PSK) ||
- (Suite == NET80211_AKM_SUITE_PSK_SHA256)) {
- PskSupported = TRUE;
- break;
- }
- }
- if (PskSupported != FALSE) {
- if (GroupEncryption == NetworkEncryptionWpaEap) {
- GroupEncryption = NetworkEncryptionWpaPsk;
- } else if (GroupEncryption == NetworkEncryptionWpa2Eap) {
- GroupEncryption = NetworkEncryptionWpa2Psk;
- }
- if (PairwiseEncryption == NetworkEncryptionWpaEap) {
- PairwiseEncryption = NetworkEncryptionWpaPsk;
- } else if (PairwiseEncryption == NetworkEncryptionWpa2Eap) {
- PairwiseEncryption = NetworkEncryptionWpa2Psk;
- }
- }
- //
- // Skip the RSN capabilities.
- //
- if ((Offset + sizeof(USHORT)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- Offset += sizeof(USHORT);
- //
- // Skip the PMKIDs.
- //
- if ((Offset + sizeof(USHORT)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- PmkidCount = *((PUSHORT)&(Rsn[Offset]));
- Offset += sizeof(USHORT);
- if ((Offset + (PmkidCount * NET80211_RSN_PMKID_LENGTH)) > RsnLength) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ParseRsnElementEnd;
- }
- Offset += PmkidCount * NET80211_RSN_PMKID_LENGTH;
- //
- // Skip the group management suite.
- //
- if ((Offset + sizeof(ULONG)) > RsnLength) {
- goto ParseRsnElementEnd;
- }
- Suite = *((PULONG)&(Rsn[Offset]));
- Offset += sizeof(ULONG);
- ParseRsnElementEnd:
- Encryption->Pairwise = PairwiseEncryption;
- Encryption->Group = GroupEncryption;
- return Status;
- }
- VOID
- Net80211pUpdateBssCache (
- PNET80211_LINK Link,
- PNET80211_PROBE_RESPONSE Response
- )
- /*++
- Routine Description:
- This routine updates the given BSS cache based on the data found in a
- beacon or probe response packet.
- Arguments:
- Link - Supplies a pointer to the 802.11 link that received the packet.
- Response - Supplies a pointer to a parsed representation of a beacon or
- probe response packet.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- ULONG Channel;
- BOOL DestroyBss;
- BOOL LinkDown;
- BOOL Match;
- PUCHAR NewRsn;
- ULONG NewRsnLength;
- ULONG NewSsidLength;
- ULONG Offset;
- PUCHAR OldRsn;
- ULONG OldRsnLength;
- ULONG OldSsidLength;
- PUCHAR RatesArray;
- KSTATUS Status;
- ULONG TotalRateCount;
- TotalRateCount = NET80211_GET_ELEMENT_LENGTH(Response->Rates);
- if (Response->ExtendedRates != NULL) {
- TotalRateCount += NET80211_GET_ELEMENT_LENGTH(Response->ExtendedRates);
- }
- //
- // First look for an existing BSS entry based on the BSSID. But if no
- // matching BSS entry is found, then create a new one and insert it into
- // the list.
- //
- KeAcquireQueuedLock(Link->Lock);
- Bss = Net80211pLookupBssEntry(Link, Response->Bssid);
- if (Bss == NULL) {
- Bss = Net80211pCreateBssEntry(Response->Bssid);
- if (Bss == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UpdateBssCacheEnd;
- }
- INSERT_BEFORE(&(Bss->ListEntry), &(Link->BssList));
- }
- //
- // Gather some locals from the response elements.
- //
- Channel = *NET80211_GET_ELEMENT_DATA(Response->Channel);
- //
- // If this is an update for the active BSS, then any changes will cause
- // the link to go down.
- //
- if (Link->ActiveBss == Bss) {
- LinkDown = FALSE;
- NewSsidLength = NET80211_GET_ELEMENT_LENGTH(Response->Ssid);
- OldSsidLength = NET80211_GET_ELEMENT_LENGTH(Bss->Ssid);
- NewRsnLength = 0;
- NewRsn = Response->Rsn;
- if (NewRsn != NULL) {
- NewRsnLength = NET80211_ELEMENT_HEADER_SIZE +
- NET80211_GET_ELEMENT_LENGTH(Response->Rsn);
- }
- OldRsnLength = 0;
- OldRsn = Bss->Encryption.ApRsn;
- if (OldRsn != NULL) {
- OldRsnLength = NET80211_ELEMENT_HEADER_SIZE +
- NET80211_GET_ELEMENT_LENGTH(Bss->Encryption.ApRsn);
- }
- ASSERT(NewSsidLength <= NET80211_MAX_SSID_LENGTH);
- if ((Bss->State.BeaconInterval != Response->BeaconInterval) ||
- (Bss->State.Capabilities != Response->Capabilities) ||
- (Bss->State.Channel != Channel) ||
- (Bss->State.Rates.Count != TotalRateCount) ||
- (OldSsidLength != NewSsidLength) ||
- (OldRsnLength != NewRsnLength)) {
- LinkDown = TRUE;
- }
- if (LinkDown == FALSE) {
- Match = RtlCompareMemory(NET80211_GET_ELEMENT_DATA(Bss->Ssid),
- NET80211_GET_ELEMENT_DATA(Response->Ssid),
- NewSsidLength);
- if (Match == FALSE) {
- LinkDown = TRUE;
- }
- }
- if (LinkDown == FALSE) {
- Match = RtlCompareMemory(OldRsn, NewRsn, NewRsnLength);
- if (Match == FALSE) {
- LinkDown = TRUE;
- }
- }
- if (LinkDown != FALSE) {
- Net80211pSetStateUnlocked(Link, Net80211StateInitialized);
- }
- }
- //
- // Update the BSS entry with the latest information from the AP.
- //
- Bss->State.BeaconInterval = Response->BeaconInterval;
- Bss->State.Capabilities = Response->Capabilities;
- Bss->State.Channel = Channel;
- Bss->State.Timestamp = Response->Timestamp;
- //
- // Allocate a new elements buffer with the newest data. This will include
- // resetting the SSID and AP's RSN pointers.
- //
- if (Response->ElementsSize != 0) {
- if (Bss->Elements != NULL) {
- MmFreePagedPool(Bss->Elements);
- Bss->ElementsSize = 0;
- }
- Bss->Ssid = NULL;
- Bss->Encryption.ApRsn = NULL;
- Bss->Elements = MmAllocatePagedPool(Response->ElementsSize,
- NET80211_ALLOCATION_TAG);
- if (Bss->Elements == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UpdateBssCacheEnd;
- }
- Bss->ElementsSize = Response->ElementsSize;
- RtlCopyMemory(Bss->Elements, Response->Elements, Bss->ElementsSize);
- Offset = Response->Ssid - Response->Elements;
- Bss->Ssid = Bss->Elements + Offset;
- if (Response->Rsn != NULL) {
- Offset = Response->Rsn - Response->Elements;
- Bss->Encryption.ApRsn = Bss->Elements + Offset;
- //
- // Parse the RSN information to determine the encryption algorithms
- // in use by the BSS.
- //
- Status = Net80211pParseRsnElement(Bss->Encryption.ApRsn,
- &(Bss->Encryption));
- if (!KSUCCESS(Status)) {
- goto UpdateBssCacheEnd;
- }
- }
- }
- //
- // Gather the rates from the response into one array.
- //
- ASSERT(TotalRateCount != 0);
- RatesArray = Bss->State.Rates.Rate;
- if (Bss->State.Rates.Count < TotalRateCount) {
- if (RatesArray != NULL) {
- MmFreePagedPool(RatesArray);
- Bss->State.Rates.Rate = NULL;
- }
- RatesArray = MmAllocatePagedPool(TotalRateCount * sizeof(UCHAR),
- NET80211_ALLOCATION_TAG);
- if (RatesArray == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto UpdateBssCacheEnd;
- }
- Bss->State.Rates.Rate = RatesArray;
- }
- Bss->State.Rates.Count = TotalRateCount;
- RtlCopyMemory(RatesArray,
- NET80211_GET_ELEMENT_DATA(Response->Rates),
- NET80211_GET_ELEMENT_LENGTH(Response->Rates));
- if (Response->ExtendedRates != NULL) {
- RtlCopyMemory(RatesArray + NET80211_GET_ELEMENT_LENGTH(Response->Rates),
- NET80211_GET_ELEMENT_DATA(Response->ExtendedRates),
- NET80211_GET_ELEMENT_LENGTH(Response->ExtendedRates));
- }
- //
- // Record that this BSS needs to encrypt/decrypt data.
- //
- if (Bss->Encryption.Pairwise != NetworkEncryptionNone) {
- Bss->Flags |= NET80211_BSS_FLAG_ENCRYPT_DATA;
- }
- //
- // For now, the station always advertises the same RSN information. Just
- // point at the global.
- //
- Bss->Encryption.StationRsn = (PUCHAR)&Net80211DefaultRsnInformation;
- Bss->LastUpdated = KeGetRecentTimeCounter();
- Status = STATUS_SUCCESS;
- UpdateBssCacheEnd:
- DestroyBss = FALSE;
- if (!KSUCCESS(Status)) {
- if (Bss != NULL) {
- LIST_REMOVE(&(Bss->ListEntry));
- DestroyBss = TRUE;
- }
- }
- KeReleaseQueuedLock(Link->Lock);
- if (DestroyBss != FALSE) {
- Net80211pBssEntryReleaseReference(Bss);
- }
- return;
- }
- VOID
- Net80211pTrimBssCache (
- PNET80211_LINK Link
- )
- /*++
- Routine Description:
- This routine removes the expired BSS entries from the given link's list.
- Arguments:
- Link - Supplies a pointer to the 802.11 link whose old BSS entries are to
- be removed.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- PLIST_ENTRY CurrentEntry;
- ULONGLONG CurrentTime;
- ULONGLONG ElapsedTime;
- LIST_ENTRY LocalList;
- ULONGLONG Timeout;
- INITIALIZE_LIST_HEAD(&LocalList);
- CurrentTime = KeGetRecentTimeCounter();
- Timeout = KeConvertMicrosecondsToTimeTicks(NET80211_BSS_ENTRY_TIMEOUT);
- //
- // Go through the list once and find all the expired entries, moving them
- // to a local list.
- //
- KeAcquireQueuedLock(Link->Lock);
- CurrentEntry = Link->BssList.Next;
- while (CurrentEntry != &(Link->BssList)) {
- Bss = LIST_VALUE(CurrentEntry, NET80211_BSS_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Don't trim the active BSS.
- //
- if (Bss == Link->ActiveBss) {
- continue;
- }
- ElapsedTime = CurrentTime - Bss->LastUpdated;
- if (ElapsedTime > Timeout) {
- LIST_REMOVE(&(Bss->ListEntry));
- INSERT_BEFORE(&(Bss->ListEntry), &LocalList);
- }
- }
- KeReleaseQueuedLock(Link->Lock);
- //
- // Run through the local list and release a reference on each.
- //
- while (LIST_EMPTY(&LocalList) == FALSE) {
- Bss = LIST_VALUE(LocalList.Next, NET80211_BSS_ENTRY, ListEntry);
- LIST_REMOVE(&(Bss->ListEntry));
- Net80211pBssEntryReleaseReference(Bss);
- }
- return;
- }
- PNET80211_BSS_ENTRY
- Net80211pCopyBssEntry (
- PNET80211_BSS_ENTRY Bss
- )
- /*++
- Routine Description:
- This routine creates a copy of the given BSS entry with the encryption keys
- removed.
- Arguments:
- Bss - Supplies a pointer to the BSS from a prior connection that the link
- is now trying to reconnect with.
- Return Value:
- Status code.
- --*/
- {
- PNET80211_BSS_ENTRY BssCopy;
- ULONG Offset;
- ULONG RatesSize;
- KSTATUS Status;
- BssCopy = NULL;
- //
- // Allocate a copy of the BSS entry, but do not copy any encryption keys as
- // those are associated with a single connection to a BSS.
- //
- BssCopy = Net80211pCreateBssEntry(Bss->State.Bssid);
- if (BssCopy == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CopyBssEntryEnd;
- }
- BssCopy->Flags = Bss->Flags;
- RtlCopyMemory(&(BssCopy->State), &(Bss->State), sizeof(NET80211_BSS));
- RtlCopyMemory(&(BssCopy->Encryption),
- &(Bss->Encryption),
- sizeof(NET80211_ENCRYPTION));
- if (Bss->ElementsSize != 0) {
- BssCopy->ElementsSize = Bss->ElementsSize;
- BssCopy->Elements = MmAllocatePagedPool(BssCopy->ElementsSize,
- NET80211_ALLOCATION_TAG);
- if (BssCopy->Elements == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CopyBssEntryEnd;
- }
- RtlCopyMemory(BssCopy->Elements, Bss->Elements, BssCopy->ElementsSize);
- Offset = Bss->Ssid - Bss->Elements;
- BssCopy->Ssid = BssCopy->Elements + Offset;
- if (Bss->Encryption.ApRsn != NULL) {
- Offset = Bss->Encryption.ApRsn - Bss->Elements;
- BssCopy->Encryption.ApRsn = BssCopy->Elements + Offset;
- }
- }
- RtlCopyMemory(BssCopy->Passphrase, Bss->Passphrase, Bss->PassphraseLength);
- BssCopy->PassphraseLength = Bss->PassphraseLength;
- BssCopy->State.Rates.Rate = NULL;
- RtlZeroMemory(BssCopy->Encryption.Keys,
- sizeof(PNET80211_KEY) * NET80211_MAX_KEY_COUNT);
- ASSERT(BssCopy->Encryption.StationRsn ==
- (PUCHAR)&Net80211DefaultRsnInformation);
- RatesSize = BssCopy->State.Rates.Count * sizeof(UCHAR);
- BssCopy->State.Rates.Rate = MmAllocatePagedPool(RatesSize,
- NET80211_ALLOCATION_TAG);
- if (BssCopy->State.Rates.Rate == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CopyBssEntryEnd;
- }
- RtlCopyMemory(BssCopy->State.Rates.Rate, Bss->State.Rates.Rate, RatesSize);
- Status = STATUS_SUCCESS;
- CopyBssEntryEnd:
- if (!KSUCCESS(Status)) {
- if (BssCopy != NULL) {
- Net80211pBssEntryReleaseReference(BssCopy);
- BssCopy = NULL;
- }
- }
- return BssCopy;
- }
- PNET80211_BSS_ENTRY
- Net80211pCreateBssEntry (
- PUCHAR Bssid
- )
- /*++
- Routine Description:
- This routine creates a BSS entry.
- Arguments:
- Bssid - Supplies a pointer to the BSSID.
- Return Value:
- Returns a pointer to the newly allocated BSS entry on success or NULL on
- failure.
- --*/
- {
- PNET80211_BSS_ENTRY Bss;
- Bss = MmAllocatePagedPool(sizeof(NET80211_BSS_ENTRY),
- NET80211_ALLOCATION_TAG);
- if (Bss == NULL) {
- goto CreateBssEntryEnd;
- }
- RtlZeroMemory(Bss, sizeof(NET80211_BSS_ENTRY));
- Bss->State.Version = NET80211_BSS_VERSION;
- Bss->ReferenceCount = 1;
- Bss->EapolHandle = INVALID_HANDLE;
- RtlCopyMemory(Bss->State.Bssid, Bssid, NET80211_ADDRESS_SIZE);
- CreateBssEntryEnd:
- return Bss;
- }
- VOID
- Net80211pDestroyBssEntry (
- PNET80211_BSS_ENTRY BssEntry
- )
- /*++
- Routine Description:
- This routine destroys the resources for the given BSS entry.
- Arguments:
- BssEntry - Supplies a pointer to the BSS entry to destroy.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- ASSERT((BssEntry->Encryption.StationRsn == NULL) ||
- (BssEntry->Encryption.StationRsn ==
- (PUCHAR)&Net80211DefaultRsnInformation));
- Net80211pDestroyEncryption(BssEntry);
- if (BssEntry->State.Rates.Rate != NULL) {
- MmFreePagedPool(BssEntry->State.Rates.Rate);
- }
- if (BssEntry->Elements != NULL) {
- MmFreePagedPool(BssEntry->Elements);
- }
- for (Index = 0; Index < NET80211_MAX_KEY_COUNT; Index += 1) {
- if (BssEntry->Encryption.Keys[Index] != NULL) {
- Net80211pDestroyKey(BssEntry->Encryption.Keys[Index]);
- }
- }
- MmFreePagedPool(BssEntry);
- return;
- }
|