1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850 |
- /*++
- 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,
- BOOL LockHeld
- );
- 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
- 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;
- }
- 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;
- }
- 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.
- --*/
- {
- PNET80211_LINK Net80211Link;
- Net80211Link = (PNET80211_LINK)Dpc->UserData;
- 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: %d\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, LockHeld);
- }
- //
- // 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, LockHeld);
- }
- //
- // 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.
- // Protect against leaving and joining an already active BSS, but still
- // reauthenticate with the active BSS as the scan was issued for some
- // reason (e.g. maybe the connection is half-baked and the user isn't
- // seeing an IP address).
- //
- if (Link->ActiveBss != FoundEntry) {
- 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: %d\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,
- BOOL LockHeld
- )
- /*++
- 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.
- LockHeld - Supplies a boolean indicating whether or not the link's lock is
- already held.
- Return Value:
- None.
- --*/
- {
- PNET80211_BSS BssState;
- PVOID DeviceContext;
- KSTATUS Status;
- if (LockHeld == FALSE) {
- 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: %d\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:
- if (LockHeld == FALSE) {
- 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
- 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;
- }
|