123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- addr.c
- Abstract:
- This module implements generic Network layer functionality, largely
- addressing.
- Author:
- Evan Green 4-Apr-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include "netcore.h"
- #include "arp.h"
- #include "dhcp.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro determines whether or not reuse of the any address is allowed
- // between the two sockets.
- //
- #define CAN_REUSE_ANY_ADDRESS(_NewSocket, _OldSocket) \
- ((((_NewSocket)->Flags & NET_SOCKET_FLAG_REUSE_ANY_ADDRESS) != 0) && \
- (((_OldSocket)->Flags & NET_SOCKET_FLAG_REUSE_ANY_ADDRESS) != 0))
- //
- // This macro determines whether or not reuse of the exact address is allowed
- // between the two sockets.
- //
- #define CAN_REUSE_EXACT_ADDRESS(_NewSocket, _OldSocket) \
- ((((_NewSocket)->Flags & NET_SOCKET_FLAG_REUSE_EXACT_ADDRESS) != 0) && \
- (((_OldSocket)->Flags & NET_SOCKET_FLAG_REUSE_EXACT_ADDRESS) != 0))
- //
- // This macro determines whether or not reuse of the exact address in the time
- // wait state is allowed between the two sockets.
- //
- #define CAN_REUSE_TIME_WAIT(_NewSocket, _OldSocket) \
- ((((_OldSocket)->Flags & NET_SOCKET_FLAG_TIME_WAIT) != 0) && \
- (((_NewSocket)->Flags & NET_SOCKET_FLAG_REUSE_TIME_WAIT) != 0) && \
- (((_OldSocket)->Flags & NET_SOCKET_FLAG_REUSE_TIME_WAIT) != 0))
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the amount of time to wait for an address translation to come back,
- // in milliseconds.
- //
- #define ADDRESS_TRANSLATION_TIMEOUT (5 * MILLISECONDS_PER_SECOND)
- #define ADDRESS_TRANSLATION_RETRY_INTERVAL MILLISECONDS_PER_SECOND
- //
- // Define the ephemeral port range.
- //
- #define NET_EPHEMERAL_PORT_START 49152
- #define NET_EPHEMERAL_PORT_END 65536
- #define NET_EPHEMERAL_PORT_COUNT \
- (NET_EPHEMERAL_PORT_END - NET_EPHEMERAL_PORT_START)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines a translation between a network address and a
- physical one.
- Members:
- TreeEntry - Stores the red black tree information for this node.
- NetworkAddress - Stores the network address, the key for the red black
- tree node.
- PhysicalAddress - Stores the physical address that corresponds to the
- network address.
- --*/
- typedef struct _ADDRESS_TRANSLATION_ENTRY {
- RED_BLACK_TREE_NODE TreeEntry;
- NETWORK_ADDRESS NetworkAddress;
- NETWORK_ADDRESS PhysicalAddress;
- } ADDRESS_TRANSLATION_ENTRY, *PADDRESS_TRANSLATION_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- NetpDestroyLink (
- PNET_LINK Link
- );
- VOID
- NetpDeactivateSocketUnlocked (
- PNET_SOCKET Socket
- );
- VOID
- NetpDeactivateRawSocketUnlocked (
- PNET_SOCKET Socket
- );
- VOID
- NetpDetachSockets (
- PNET_LINK Link,
- PNET_LINK_ADDRESS_ENTRY LinkAddress
- );
- VOID
- NetpDetachSocket (
- PNET_SOCKET Socket
- );
- VOID
- NetpDetachRawSocket (
- PNET_SOCKET Socket
- );
- KSTATUS
- NetpBindRawSocket (
- PNET_SOCKET Socket,
- NET_SOCKET_BINDING_TYPE BindingType,
- PNET_LINK_LOCAL_ADDRESS LocalInformation,
- PNETWORK_ADDRESS RemoteAddress,
- ULONG Flags
- );
- KSTATUS
- NetpLookupAddressTranslation (
- PNET_LINK Link,
- PNETWORK_ADDRESS NetworkAddress,
- PNETWORK_ADDRESS PhysicalAddress
- );
- COMPARISON_RESULT
- NetpCompareFullyBoundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- );
- COMPARISON_RESULT
- NetpMatchFullyBoundSocket (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS LocalAddress,
- PNETWORK_ADDRESS RemoteAddress
- );
- COMPARISON_RESULT
- NetpCompareLocallyBoundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- );
- COMPARISON_RESULT
- NetpCompareUnboundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- );
- COMPARISON_RESULT
- NetpCompareAddressTranslationEntries (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- );
- BOOL
- NetpCheckLocalAddressAvailability (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS LocalAddress
- );
- VOID
- NetpGetPacketSizeInformation (
- PNET_LINK Link,
- PNET_SOCKET Socket,
- PNET_PACKET_SIZE_INFORMATION SizeInformation
- );
- VOID
- NetpDebugPrintNetworkAddress (
- PNET_NETWORK_ENTRY Network,
- PNETWORK_ADDRESS Address
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the list of raw sockets. These do not get put in the socket trees.
- //
- LIST_ENTRY NetRawSocketsList;
- PSHARED_EXCLUSIVE_LOCK NetRawSocketsLock;
- //
- // Define the list of available network links (things that can actually send
- // packets). Any party accessing this list must have acquired the link list
- // lock. The lock can only be acquired at low level.
- //
- LIST_ENTRY NetLinkList;
- PSHARED_EXCLUSIVE_LOCK NetLinkListLock;
- UUID NetNetworkDeviceInformationUuid = NETWORK_DEVICE_INFORMATION_UUID;
- //
- // ------------------------------------------------------------------ Functions
- //
- NET_API
- KSTATUS
- NetAddLink (
- PNET_LINK_PROPERTIES Properties,
- PNET_LINK *NewLink
- )
- /*++
- Routine Description:
- This routine adds a new network link based on the given properties. The
- link must be ready to send and receive traffic and have a valid physical
- layer address supplied in the properties.
- Arguments:
- Properties - Supplies a pointer describing the properties and interface of
- the link. This memory will not be referenced after the function returns,
- so this may be a stack allocated structure.
- NewLink - Supplies a pointer where a pointer to the new link will be
- returned on success.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated for the
- structure.
- --*/
- {
- PNET_DATA_LINK_ENTRY CurrentDataLink;
- PLIST_ENTRY CurrentEntry;
- PNET_NETWORK_ENTRY CurrentNetwork;
- PNET_DATA_LINK_ENTRY FoundDataLink;
- PLIST_ENTRY LastEntry;
- PNET_LINK Link;
- BOOL LockHeld;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- LastEntry = NULL;
- Link = NULL;
- LockHeld = FALSE;
- Status = STATUS_SUCCESS;
- if (Properties->Version < NET_LINK_PROPERTIES_VERSION) {
- Status = STATUS_VERSION_MISMATCH;
- goto AddLinkEnd;
- }
- if (Properties->TransmitAlignment == 0) {
- Properties->TransmitAlignment = 1;
- }
- if ((!POWER_OF_2(Properties->TransmitAlignment)) ||
- (Properties->PhysicalAddress.Domain == NetDomainInvalid) ||
- (Properties->MaxPhysicalAddress == 0) ||
- (Properties->Interface.Send == NULL) ||
- (Properties->Interface.GetSetInformation == NULL)) {
- Status = STATUS_INVALID_PARAMETER;
- goto AddLinkEnd;
- }
- Link = MmAllocatePagedPool(sizeof(NET_LINK), NET_CORE_ALLOCATION_TAG);
- if (Link == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddLinkEnd;
- }
- RtlZeroMemory(Link, sizeof(NET_LINK));
- Link->ReferenceCount = 1;
- RtlCopyMemory(&(Link->Properties), Properties, sizeof(NET_LINK_PROPERTIES));
- Link->QueuedLock = KeCreateQueuedLock();
- if (Link->QueuedLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddLinkEnd;
- }
- INITIALIZE_LIST_HEAD(&(Link->LinkAddressList));
- Link->AddressTranslationEvent = KeCreateEvent(NULL);
- if (Link->AddressTranslationEvent == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddLinkEnd;
- }
- KeSignalEvent(Link->AddressTranslationEvent, SignalOptionUnsignal);
- RtlRedBlackTreeInitialize(&(Link->AddressTranslationTree),
- 0,
- NetpCompareAddressTranslationEntries);
- //
- // Find the appropriate data link layer and initialize it for this link.
- //
- FoundDataLink = NULL;
- KeAcquireSharedExclusiveLockShared(NetPluginListLock);
- LockHeld = TRUE;
- CurrentEntry = NetDataLinkList.Next;
- while (CurrentEntry != &NetDataLinkList) {
- CurrentDataLink = LIST_VALUE(CurrentEntry,
- NET_DATA_LINK_ENTRY,
- ListEntry);
- if (CurrentDataLink->Domain == Properties->DataLinkType) {
- FoundDataLink = CurrentDataLink;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (FoundDataLink == NULL) {
- Status = STATUS_NOT_SUPPORTED;
- goto AddLinkEnd;
- }
- Status = FoundDataLink->Interface.InitializeLink(Link);
- if (!KSUCCESS(Status)) {
- goto AddLinkEnd;
- }
- Link->DataLinkEntry = FoundDataLink;
- //
- // Let the network layers have their shot at initializing state for this
- // link.
- //
- CurrentEntry = NetNetworkList.Next;
- while (CurrentEntry != &NetNetworkList) {
- CurrentNetwork = LIST_VALUE(CurrentEntry, NET_NETWORK_ENTRY, ListEntry);
- Status = CurrentNetwork->Interface.InitializeLink(Link);
- if (!KSUCCESS(Status)) {
- goto AddLinkEnd;
- }
- CurrentEntry = CurrentEntry->Next;
- LastEntry = CurrentEntry;
- }
- KeReleaseSharedExclusiveLockShared(NetPluginListLock);
- LockHeld = FALSE;
- //
- // All network devices respond to the network device information requests.
- //
- Status = IoRegisterDeviceInformation(Link->Properties.Device,
- &NetNetworkDeviceInformationUuid,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto AddLinkEnd;
- }
- //
- // With success a sure thing, take a reference on the OS device that
- // registered the link with netcore. Its device context and driver need to
- // remain available as long as netcore can access the device link interface.
- //
- IoDeviceAddReference(Link->Properties.Device);
- //
- // Add the link to the global list. It is all ready to send and receive
- // data.
- //
- KeAcquireSharedExclusiveLockExclusive(NetLinkListLock);
- ASSERT(Link->ListEntry.Next == NULL);
- INSERT_BEFORE(&(Link->ListEntry), &NetLinkList);
- KeReleaseSharedExclusiveLockExclusive(NetLinkListLock);
- Status = STATUS_SUCCESS;
- AddLinkEnd:
- if (!KSUCCESS(Status)) {
- if (Link != NULL) {
- IoRegisterDeviceInformation(Link->Properties.Device,
- &NetNetworkDeviceInformationUuid,
- FALSE);
- //
- // If some network layer entries have initialized already, call
- // them back to cancel.
- //
- if (LastEntry != NULL) {
- if (LockHeld == FALSE) {
- KeAcquireSharedExclusiveLockShared(NetPluginListLock);
- LockHeld = TRUE;
- }
- CurrentEntry = NetNetworkList.Next;
- while (CurrentEntry != LastEntry) {
- CurrentNetwork = LIST_VALUE(CurrentEntry,
- NET_NETWORK_ENTRY,
- ListEntry);
- CurrentNetwork->Interface.DestroyLink(Link);
- CurrentEntry = CurrentEntry->Next;
- }
- }
- if (LockHeld != FALSE) {
- KeReleaseSharedExclusiveLockShared(NetPluginListLock);
- LockHeld = FALSE;
- }
- if (Link->DataLinkEntry != NULL) {
- Link->DataLinkEntry->Interface.DestroyLink(Link);
- }
- if (Link->QueuedLock != NULL) {
- KeDestroyQueuedLock(Link->QueuedLock);
- }
- if (Link->AddressTranslationEvent != NULL) {
- KeDestroyEvent(Link->AddressTranslationEvent);
- }
- MmFreePagedPool(Link);
- Link = NULL;
- }
- }
- ASSERT(LockHeld == FALSE);
- *NewLink = Link;
- return Status;
- }
- NET_API
- VOID
- NetLinkAddReference (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine increases the reference count on a network link.
- Arguments:
- Link - Supplies a pointer to the network link whose reference count
- should be incremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Link->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) & (OldReferenceCount < 0x20000000));
- return;
- }
- NET_API
- VOID
- NetLinkReleaseReference (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine decreases the reference count of a network link, and destroys
- the link if the reference count drops to zero.
- Arguments:
- Link - Supplies a pointer to the network link whose reference count
- should be decremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Link->ReferenceCount), -1);
- ASSERT(OldReferenceCount != 0);
- if (OldReferenceCount == 1) {
- NetpDestroyLink(Link);
- }
- return;
- }
- NET_API
- VOID
- NetSetLinkState (
- PNET_LINK Link,
- BOOL LinkUp,
- ULONGLONG LinkSpeed
- )
- /*++
- Routine Description:
- This routine sets the link state of the given link. The physical device
- layer is responsible for synchronizing link state changes.
- Arguments:
- Link - Supplies a pointer to the link whose state is changing.
- LinkUp - Supplies a boolean indicating whether the link is active (TRUE) or
- disconnected (FALSE).
- LinkSpeed - Supplies the speed of the link, in bits per second.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- NET_DOMAIN_TYPE Domain;
- PNET_LINK_ADDRESS_ENTRY LinkAddress;
- BOOL OriginalLinkUp;
- KSTATUS Status;
- PADDRESS_TRANSLATION_ENTRY Translation;
- PRED_BLACK_TREE Tree;
- PRED_BLACK_TREE_NODE TreeNode;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(Link != NULL);
- //
- // Link state is synchronized under the global link list lock.
- //
- KeAcquireSharedExclusiveLockExclusive(NetLinkListLock);
- OriginalLinkUp = Link->LinkUp;
- Link->LinkUp = LinkUp;
- Link->LinkSpeed = LinkSpeed;
- RtlDebugPrint("NET: ");
- NetDebugPrintAddress(&(Link->Properties.PhysicalAddress));
- if (LinkUp != FALSE) {
- RtlDebugPrint(" up, Speed %I64d mbps\n", LinkSpeed / 1000000ULL);
- } else {
- RtlDebugPrint(" down\n");
- }
- KeReleaseSharedExclusiveLockExclusive(NetLinkListLock);
- //
- // If the link state was not changed, then take no action.
- //
- if (LinkUp == OriginalLinkUp) {
- return;
- }
- //
- // If the link is now up, then use DHCP to get an address. It is assumed
- // that the link will not go down before handing off to DHCP.
- //
- if (LinkUp != FALSE) {
- ASSERT(Link->LinkUp != FALSE);
- ASSERT(LIST_EMPTY(&(Link->LinkAddressList)) == FALSE);
- //
- // If the link had previously gone down then the address translation
- // event was left signalled.
- //
- KeSignalEvent(Link->AddressTranslationEvent, SignalOptionUnsignal);
- //
- // Request an address for the first link.
- //
- LinkAddress = LIST_VALUE(Link->LinkAddressList.Next,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- Status = NetpDhcpBeginAssignment(Link, LinkAddress);
- if (!KSUCCESS(Status)) {
- //
- // TODO: Handle failed DHCP.
- //
- ASSERT(FALSE);
- }
- //
- // The link has gone down. Sockets can no longer take references on the
- // link via bind until it goes back up. It is assumed that the link will
- // not go back up while in the middle of this process to take it down.
- //
- } else {
- ASSERT(Link->LinkUp == FALSE);
- //
- // Clean up the address translation tree. If the link reconnects after
- // moving to a new network, some of the address translations may be
- // incorrect.
- //
- Tree = &(Link->AddressTranslationTree);
- KeAcquireQueuedLock(Link->QueuedLock);
- while (TRUE) {
- TreeNode = RtlRedBlackTreeGetLowestNode(Tree);
- if (TreeNode == NULL) {
- break;
- }
- RtlRedBlackTreeRemove(Tree, TreeNode);
- Translation = RED_BLACK_TREE_VALUE(TreeNode,
- ADDRESS_TRANSLATION_ENTRY,
- TreeEntry);
- MmFreePagedPool(Translation);
- }
- KeReleaseQueuedLock(Link->QueuedLock);
- //
- // Now that the address translation tree is empty, signal anyone
- // waiting for address translations on this event once and for all.
- //
- KeSignalEvent(Link->AddressTranslationEvent, SignalOptionSignalAll);
- //
- // Notify every fully bound, locally bound, and raw socket using this
- // link that the link has gone down. Sockets may be waiting on data or
- // in the middle of sending data.
- //
- NetpDetachSockets(Link, NULL);
- //
- // Now that the sockets are out of the way, go through and gut the
- // non-static link address entries.
- //
- KeAcquireQueuedLock(Link->QueuedLock);
- CurrentEntry = Link->LinkAddressList.Next;
- while (CurrentEntry != &(Link->LinkAddressList)) {
- LinkAddress = LIST_VALUE(CurrentEntry,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (LinkAddress->Configured == FALSE) {
- continue;
- }
- //
- // If the link address was configured via DHCP, then release the IP
- // address.
- //
- if (LinkAddress->StaticAddress == FALSE) {
- //
- // Zero out the network address, except the network type which
- // is needed to reconfigure the link. The rest of the state can
- // be left stale.
- //
- Domain = LinkAddress->Address.Domain;
- RtlZeroMemory(&(LinkAddress->Address), sizeof(NETWORK_ADDRESS));
- LinkAddress->Address.Domain = Domain;
- //
- // Notify DHCP that the link and link address combination is
- // now invalid. It may have saved state.
- //
- NetpDhcpCancelLease(Link, LinkAddress);
- }
- LinkAddress->Configured = FALSE;
- }
- KeReleaseQueuedLock(Link->QueuedLock);
- }
- return;
- }
- NET_API
- VOID
- NetGetLinkState (
- PNET_LINK Link,
- PBOOL LinkUp,
- PULONGLONG LinkSpeed
- )
- /*++
- Routine Description:
- This routine gets the link state of the given link.
- Arguments:
- Link - Supplies a pointer to the link whose state is being retrieved.
- LinkUp - Supplies a pointer that receives a boolean indicating whether the
- link is active (TRUE) or disconnected (FALSE). This parameter is
- optional.
- LinkSpeed - Supplies a pointer that receives the speed of the link, in bits
- per second. This parameter is optional.
- Return Value:
- None.
- --*/
- {
- ASSERT(Link != NULL);
- if (LinkUp != NULL) {
- *LinkUp = Link->LinkUp;
- }
- if (LinkSpeed != NULL) {
- *LinkSpeed = Link->LinkSpeed;
- }
- return;
- }
- NET_API
- KSTATUS
- NetGetSetLinkDeviceInformation (
- PNET_LINK Link,
- PUUID Uuid,
- PVOID Data,
- PUINTN DataSize,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets device information for a link.
- Arguments:
- Link - Supplies a pointer to the link whose device information is being
- retrieved or set.
- Uuid - Supplies a pointer to the information identifier.
- Data - Supplies a pointer to the data buffer.
- DataSize - Supplies a pointer that on input contains the size of the data
- buffer in bytes. On output, returns the needed size of the data buffer,
- even if the supplied buffer was nonexistant or too small.
- Set - Supplies a boolean indicating whether to get the information (FALSE)
- or set the information (TRUE).
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_BUFFER_TOO_SMALL if the supplied buffer was too small.
- STATUS_NOT_HANDLED if the given UUID was not recognized.
- --*/
- {
- KSTATUS Status;
- Status = STATUS_NOT_HANDLED;
- if (RtlAreUuidsEqual(Uuid, &NetNetworkDeviceInformationUuid) != FALSE) {
- if (*DataSize < sizeof(NETWORK_DEVICE_INFORMATION)) {
- *DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
- goto GetSetLinkDeviceInformationEnd;
- }
- *DataSize = sizeof(NETWORK_DEVICE_INFORMATION);
- Status = NetGetSetNetworkDeviceInformation(Link, NULL, Data, Set);
- goto GetSetLinkDeviceInformationEnd;
- }
- GetSetLinkDeviceInformationEnd:
- return Status;
- }
- NET_API
- VOID
- NetRemoveLink (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine removes a link from the networking core after its device has
- been removed. This should not be used if the media has simply been removed.
- In that case, setting the link state to 'down' is suffiient. There may
- still be outstanding references on the link, so the networking core will
- call the device back to notify it when the link is destroyed.
- Arguments:
- Link - Supplies a pointer to the link to remove.
- Return Value:
- None.
- --*/
- {
- //
- // The device has been removed, the link should no longer respond to
- // information requests.
- //
- IoRegisterDeviceInformation(Link->Properties.Device,
- &NetNetworkDeviceInformationUuid,
- FALSE);
- //
- // If the link is still up, then send out the notice that is is actually
- // down.
- //
- if (Link->LinkUp != FALSE) {
- NetSetLinkState(Link, FALSE, 0);
- }
- //
- // Remove the link from the net link list. Disconnecting the link by
- // setting its state to down should have already stopped sockets from
- // taking new references on the link.
- //
- if (Link->ListEntry.Next != NULL) {
- KeAcquireSharedExclusiveLockExclusive(NetLinkListLock);
- LIST_REMOVE(&(Link->ListEntry));
- Link->ListEntry.Next = NULL;
- KeReleaseSharedExclusiveLockExclusive(NetLinkListLock);
- }
- //
- // Dereference the link. The final clean-up will be triggered once the last
- // reference is released.
- //
- NetLinkReleaseReference(Link);
- return;
- }
- NET_API
- KSTATUS
- NetFindLinkForLocalAddress (
- PNETWORK_ADDRESS LocalAddress,
- BOOL AnyAddress,
- PNET_LINK Link,
- PNET_LINK_LOCAL_ADDRESS LinkResult
- )
- /*++
- Routine Description:
- This routine searches for a link and the associated address entry that
- matches the given local address. If a link is supplied as a hint, then the
- given link must be able to service the given address for this routine to
- succeed.
- Arguments:
- LocalAddress - Supplies a pointer to the local address to test against.
- AnyAddress - Supplies a boolean indicating whether or not the local address
- is the network's any address.
- Link - Supplies an optional pointer to a link that the local address must
- be from.
- LinkResult - Supplies a pointer that receives the found link, link address
- entry, and local address.
- Return Value:
- STATUS_SUCCESS if a link was found and bound with the socket.
- STATUS_INVALID_ADDRESS if no link was found to own that address.
- STATUS_NO_NETWORK_CONNECTION if no networks are available.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PNET_LINK CurrentLink;
- PNET_LINK_ADDRESS_ENTRY LinkAddress;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Status = STATUS_INVALID_ADDRESS;
- KeAcquireSharedExclusiveLockShared(NetLinkListLock);
- if (LIST_EMPTY(&NetLinkList)) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto FindLinkForLocalAddress;
- }
- //
- // If there's a specific link being bound to, then just try to find the
- // address entry within that link.
- //
- if (Link != NULL) {
- if (Link->LinkUp == FALSE) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto FindLinkForLocalAddress;
- }
- Status = NetFindEntryForAddress(Link,
- LocalAddress,
- AnyAddress,
- &LinkAddress);
- //
- // There is no specific link, so scan through them all.
- //
- } else {
- CurrentEntry = NetLinkList.Next;
- while (CurrentEntry != &NetLinkList) {
- CurrentLink = LIST_VALUE(CurrentEntry, NET_LINK, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Don't bother if the link is down.
- //
- if (CurrentLink->LinkUp == FALSE) {
- continue;
- }
- Status = NetFindEntryForAddress(CurrentLink,
- LocalAddress,
- AnyAddress,
- &LinkAddress);
- if (KSUCCESS(Status)) {
- Link = CurrentLink;
- break;
- }
- }
- }
- //
- // If a link address entry was found, then fill out the link information.
- //
- if (KSUCCESS(Status)) {
- NetLinkAddReference(Link);
- LinkResult->Link = Link;
- LinkResult->LinkAddress = LinkAddress;
- RtlCopyMemory(&(LinkResult->LocalAddress),
- LocalAddress,
- sizeof(NETWORK_ADDRESS));
- }
- FindLinkForLocalAddress:
- KeReleaseSharedExclusiveLockShared(NetLinkListLock);
- return Status;
- }
- NET_API
- KSTATUS
- NetFindLinkForRemoteAddress (
- PNETWORK_ADDRESS RemoteAddress,
- PNET_LINK_LOCAL_ADDRESS LinkResult
- )
- /*++
- Routine Description:
- This routine searches for a link and associated address entry that can
- reach the given remote address.
- Arguments:
- RemoteAddress - Supplies a pointer to the address to test against.
- LinkResult - Supplies a pointer that receives the link information,
- including the link, link address entry, and associated local address.
- Return Value:
- STATUS_SUCCESS if a link was found and bound with the socket.
- STATUS_NO_NETWORK_CONNECTION if no networks are available.
- --*/
- {
- PNET_LINK CurrentLink;
- PNET_LINK_ADDRESS_ENTRY CurrentLinkAddressEntry;
- PLIST_ENTRY CurrentLinkEntry;
- PNET_LINK_ADDRESS_ENTRY FoundAddress;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- KeAcquireSharedExclusiveLockShared(NetLinkListLock);
- if (LIST_EMPTY(&NetLinkList)) {
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto FindLinkForDestinationAddressEnd;
- }
- Status = STATUS_NO_NETWORK_CONNECTION;
- FoundAddress = NULL;
- CurrentLinkEntry = NetLinkList.Next;
- while (CurrentLinkEntry != &NetLinkList) {
- CurrentLink = LIST_VALUE(CurrentLinkEntry, NET_LINK, ListEntry);
- CurrentLinkEntry = CurrentLinkEntry->Next;
- //
- // Don't bother if the link is down.
- //
- if (CurrentLink->LinkUp == FALSE) {
- continue;
- }
- //
- // TODO: Properly determine the route for this destination, rather
- // than just connecting through the first working network link and first
- // address inside it. Make sure to not use the routing tables if
- // SOCKET_IO_DONT_ROUTE is set at time of send/receive.
- //
- KeAcquireQueuedLock(CurrentLink->QueuedLock);
- ASSERT(!LIST_EMPTY(&(CurrentLink->LinkAddressList)));
- CurrentLinkAddressEntry = LIST_VALUE(CurrentLink->LinkAddressList.Next,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- if (CurrentLinkAddressEntry->Configured != FALSE) {
- FoundAddress = CurrentLinkAddressEntry;
- RtlCopyMemory(&(LinkResult->LocalAddress),
- &(FoundAddress->Address),
- sizeof(NETWORK_ADDRESS));
- ASSERT(LinkResult->LocalAddress.Port == 0);
- }
- KeReleaseQueuedLock(CurrentLink->QueuedLock);
- //
- // If a suitable link address was not found, continue on to the next
- // link.
- //
- if (FoundAddress == NULL) {
- continue;
- }
- //
- // Fill out the link information. The local address was copied above
- // under the lock in order to prevent a torn read.
- //
- NetLinkAddReference(CurrentLink);
- LinkResult->Link = CurrentLink;
- LinkResult->LinkAddress = FoundAddress;
- Status = STATUS_SUCCESS;
- break;
- }
- FindLinkForDestinationAddressEnd:
- KeReleaseSharedExclusiveLockShared(NetLinkListLock);
- return Status;
- }
- NET_API
- KSTATUS
- NetLookupLinkByDevice (
- PDEVICE Device,
- PNET_LINK *Link
- )
- /*++
- Routine Description:
- This routine looks for a link that belongs to the given device. If a link
- is found, a reference will be added. It is the callers responsibility to
- release this reference.
- Arguments:
- Device - Supplies a pointer to the device for which the link is being
- searched.
- Link - Supplies a pointer that receives a pointer to the link, if found.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PNET_LINK CurrentLink;
- KSTATUS Status;
- if (LIST_EMPTY(&NetLinkList) != FALSE) {
- return STATUS_NOT_FOUND;
- }
- Status = STATUS_NOT_FOUND;
- KeAcquireSharedExclusiveLockShared(NetLinkListLock);
- CurrentEntry = NetLinkList.Next;
- while (CurrentEntry != &NetLinkList) {
- CurrentLink = LIST_VALUE(CurrentEntry, NET_LINK, ListEntry);
- if (CurrentLink->Properties.Device == Device) {
- NetLinkAddReference(CurrentLink);
- *Link = CurrentLink;
- Status = STATUS_SUCCESS;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- KeReleaseSharedExclusiveLockShared(NetLinkListLock);
- return Status;
- }
- NET_API
- KSTATUS
- NetCreateLinkAddressEntry (
- PNET_LINK Link,
- PNETWORK_ADDRESS Address,
- PNETWORK_ADDRESS Subnet,
- PNETWORK_ADDRESS DefaultGateway,
- BOOL StaticAddress,
- PNET_LINK_ADDRESS_ENTRY *NewLinkAddress
- )
- /*++
- Routine Description:
- This routine initializes a new network link address entry.
- Arguments:
- Link - Supplies a pointer to the physical link that has the new network
- address.
- Address - Supplies an optional pointer to the address to assign to the link
- address entry.
- Subnet - Supplies an optional pointer to the subnet mask to assign to the
- link address entry.
- DefaultGateway - Supplies an optional pointer to the default gateway
- address to assign to the link address entry.
- StaticAddress - Supplies a boolean indicating if the provided information
- is a static configuration of the link address entry. This parameter is
- only used when the Address, Subnet, and DefaultGateway parameters are
- supplied.
- NewLinkAddress - Supplies a pointer where a pointer to the new link address
- will be returned. The new link address will also be inserted onto the
- link.
- Return Value:
- Status code.
- --*/
- {
- PNET_LINK_ADDRESS_ENTRY LinkAddress;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- LinkAddress = MmAllocatePagedPool(sizeof(NET_LINK_ADDRESS_ENTRY),
- NET_CORE_ALLOCATION_TAG);
- if (LinkAddress == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateLinkAddressEnd;
- }
- //
- // Copy in the initial addressing parameters if supplied.
- //
- RtlZeroMemory(LinkAddress, sizeof(NET_LINK_ADDRESS_ENTRY));
- if (Address != NULL) {
- RtlCopyMemory(&(LinkAddress->Address),
- Address,
- sizeof(NETWORK_ADDRESS));
- }
- if (Subnet != NULL) {
- RtlCopyMemory(&(LinkAddress->Subnet), Subnet, sizeof(NETWORK_ADDRESS));
- }
- if (DefaultGateway != NULL) {
- RtlCopyMemory(&(LinkAddress->DefaultGateway),
- DefaultGateway,
- sizeof(NETWORK_ADDRESS));
- }
- //
- // Start the link address off with the built-in physical address.
- //
- RtlCopyMemory(&(LinkAddress->PhysicalAddress),
- &(Link->Properties.PhysicalAddress),
- sizeof(NETWORK_ADDRESS));
- //
- // If an address, subnet, and default gateway were supplied, then this link
- // address entry is as good as configured.
- //
- ASSERT(LinkAddress->Configured == FALSE);
- if ((Address != NULL) && (Subnet != NULL) && (DefaultGateway != NULL)) {
- LinkAddress->StaticAddress = StaticAddress;
- LinkAddress->Configured = TRUE;
- }
- //
- // Everything's good to go, add the address to the link's list.
- //
- KeAcquireQueuedLock(Link->QueuedLock);
- INSERT_AFTER(&(LinkAddress->ListEntry), &(Link->LinkAddressList));
- KeReleaseQueuedLock(Link->QueuedLock);
- Status = STATUS_SUCCESS;
- CreateLinkAddressEnd:
- if (!KSUCCESS(Status)) {
- if (LinkAddress != NULL) {
- MmFreePagedPool(LinkAddress);
- LinkAddress = NULL;
- }
- }
- *NewLinkAddress = LinkAddress;
- return Status;
- }
- NET_API
- VOID
- NetDestroyLinkAddressEntry (
- PNET_LINK Link,
- PNET_LINK_ADDRESS_ENTRY LinkAddress
- )
- /*++
- Routine Description:
- This routine removes and destroys a link address.
- Arguments:
- Link - Supplies a pointer to the physical link that has the network address.
- LinkAddress - Supplies a pointer to the link address to remove and destroy.
- Return Value:
- None.
- --*/
- {
- ASSERT(KeGetRunLevel() == RunLevelLow);
- KeAcquireQueuedLock(Link->QueuedLock);
- LIST_REMOVE(&(LinkAddress->ListEntry));
- KeReleaseQueuedLock(Link->QueuedLock);
- MmFreePagedPool(LinkAddress);
- return;
- }
- NET_API
- KSTATUS
- NetTranslateNetworkAddress (
- PNETWORK_ADDRESS NetworkAddress,
- PNET_LINK Link,
- PNET_LINK_ADDRESS_ENTRY LinkAddress,
- PNETWORK_ADDRESS PhysicalAddress
- )
- /*++
- Routine Description:
- This routine translates a network level address to a physical address.
- Arguments:
- NetworkAddress - Supplies a pointer to the network address to translate.
- Link - Supplies a pointer to the link to use.
- LinkAddress - Supplies a pointer to the link address entry to use for this
- request.
- PhysicalAddress - Supplies a pointer where the corresponding physical
- address for this network address will be returned.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG EndTime;
- KSTATUS Status;
- ULONGLONG TimeDelta;
- EndTime = 0;
- //
- // Loop trying to get the address, and waiting for an answer.
- //
- while (TRUE) {
- Status = NetpLookupAddressTranslation(Link,
- NetworkAddress,
- PhysicalAddress);
- if (KSUCCESS(Status)) {
- break;
- }
- //
- // If the lookup failed once, but this is the first time, set an end
- // time to give up.
- //
- if (EndTime == 0) {
- TimeDelta = ADDRESS_TRANSLATION_TIMEOUT *
- MICROSECONDS_PER_MILLISECOND;
- EndTime = KeGetRecentTimeCounter() +
- KeConvertMicrosecondsToTimeTicks(TimeDelta);
- Status = NetpArpSendRequest(Link, LinkAddress, NetworkAddress);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // If this loop has already been around at least once, look for a
- // timeout event.
- //
- } else if (KeGetRecentTimeCounter() >= EndTime) {
- Status = STATUS_TIMEOUT;
- break;
- }
- //
- // Wait for some new address translation to come in.
- //
- Status = KeWaitForEvent(Link->AddressTranslationEvent,
- FALSE,
- ADDRESS_TRANSLATION_RETRY_INTERVAL);
- //
- // On timeouts, re-send the ARP request.
- //
- if (Status == STATUS_TIMEOUT) {
- Status = NetpArpSendRequest(Link, LinkAddress, NetworkAddress);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- }
- //
- // On all other failures to wait for the event, break.
- //
- if (!KSUCCESS(Status)) {
- break;
- }
- }
- return Status;
- }
- NET_API
- KSTATUS
- NetAddNetworkAddressTranslation (
- PNET_LINK Link,
- PNETWORK_ADDRESS NetworkAddress,
- PNETWORK_ADDRESS PhysicalAddress
- )
- /*++
- Routine Description:
- This routine adds a mapping between a network address and its associated
- physical address.
- Arguments:
- Link - Supplies a pointer to the link receiving the mapping.
- NetworkAddress - Supplies a pointer to the network address whose physical
- mapping is known.
- PhysicalAddress - Supplies a pointer to the physical address corresponding
- to the network address.
- Return Value:
- Status code.
- --*/
- {
- PADDRESS_TRANSLATION_ENTRY FoundEntry;
- PRED_BLACK_TREE_NODE FoundNode;
- BOOL LockHeld;
- PADDRESS_TRANSLATION_ENTRY NewEntry;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- LockHeld = FALSE;
- //
- // Create the new address translation entry.
- //
- NewEntry = MmAllocatePagedPool(sizeof(ADDRESS_TRANSLATION_ENTRY),
- NET_CORE_ALLOCATION_TAG);
- if (NewEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddNetworkAddressTranslationEnd;
- }
- RtlCopyMemory(&(NewEntry->NetworkAddress),
- NetworkAddress,
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(NewEntry->PhysicalAddress),
- PhysicalAddress,
- sizeof(NETWORK_ADDRESS));
- Status = STATUS_SUCCESS;
- KeAcquireQueuedLock(Link->QueuedLock);
- LockHeld = TRUE;
- FoundNode = RtlRedBlackTreeSearch(&(Link->AddressTranslationTree),
- &(NewEntry->TreeEntry));
- //
- // If a node is found, update it.
- //
- if (FoundNode != NULL) {
- FoundEntry = RED_BLACK_TREE_VALUE(FoundNode,
- ADDRESS_TRANSLATION_ENTRY,
- TreeEntry);
- RtlCopyMemory(&(FoundEntry->NetworkAddress),
- NetworkAddress,
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(FoundEntry->PhysicalAddress),
- PhysicalAddress,
- sizeof(NETWORK_ADDRESS));
- //
- // No pre-existing entry exists for this network address, add the new
- // entry. Null out the local to indicate the entry was added.
- //
- } else {
- RtlRedBlackTreeInsert(&(Link->AddressTranslationTree),
- &(NewEntry->TreeEntry));
- KeSignalEvent(Link->AddressTranslationEvent, SignalOptionPulse);
- NewEntry = NULL;
- }
- AddNetworkAddressTranslationEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Link->QueuedLock);
- }
- if (NewEntry != NULL) {
- MmFreePagedPool(NewEntry);
- }
- return Status;
- }
- NET_API
- KSTATUS
- NetFindEntryForAddress (
- PNET_LINK Link,
- PNETWORK_ADDRESS Address,
- BOOL AnyAddress,
- PNET_LINK_ADDRESS_ENTRY *AddressEntry
- )
- /*++
- Routine Description:
- This routine searches for a link address entry within the given link
- matching the desired address.
- Arguments:
- Link - Supplies the link whose address entries should be searched.
- Address - Supplies the address to search for.
- AnyAddress - Supplies a boolean indicating whether or not the given address
- is the owning network's any address.
- AddressEntry - Supplies a pointer where the address entry will be returned
- on success.
- Return Value:
- STATUS_SUCCESS if a link was found and bound with the socket.
- STATUS_INVALID_ADDRESS if no link was found to own that address.
- --*/
- {
- COMPARISON_RESULT ComparisonResult;
- PNET_LINK_ADDRESS_ENTRY CurrentAddress;
- PLIST_ENTRY CurrentAddressEntry;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Status = STATUS_INVALID_ADDRESS;
- *AddressEntry = NULL;
- //
- // Loop over all the addresses owned by this link.
- //
- KeAcquireQueuedLock(Link->QueuedLock);
- CurrentAddressEntry = Link->LinkAddressList.Next;
- while (CurrentAddressEntry != &(Link->LinkAddressList)) {
- CurrentAddress = LIST_VALUE(CurrentAddressEntry,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- CurrentAddressEntry = CurrentAddressEntry->Next;
- //
- // Only a search for an any address can match a non-configured link
- // address entry.
- //
- if ((CurrentAddress->Configured == FALSE) && (AnyAddress == FALSE)) {
- continue;
- }
- //
- // Compare the full addresses unless the any address was supplied. In
- // that case, only the port and network need to match.
- //
- if (AnyAddress == FALSE) {
- ComparisonResult = NetpCompareNetworkAddresses(
- &(CurrentAddress->Address),
- Address);
- if (ComparisonResult == ComparisonResultSame) {
- *AddressEntry = CurrentAddress;
- Status = STATUS_SUCCESS;
- break;
- }
- } else if ((CurrentAddress->Address.Port == Address->Port) &&
- (CurrentAddress->Address.Domain == Address->Domain)) {
- *AddressEntry = CurrentAddress;
- Status = STATUS_SUCCESS;
- break;
- }
- }
- KeReleaseQueuedLock(Link->QueuedLock);
- return Status;
- }
- NET_API
- KSTATUS
- NetActivateSocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine activates a socket, making it eligible to receive data.
- Arguments:
- Socket - Supplies a pointer to the initialized socket to activate.
- Return Value:
- Status code.
- --*/
- {
- if (Socket->BindingType == SocketBindingInvalid) {
- return STATUS_NOT_CONFIGURED;
- }
- //
- // Activate the socket and move on.
- //
- RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_ACTIVE);
- return STATUS_SUCCESS;
- }
- NET_API
- VOID
- NetDeactivateSocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine removes a socket from the socket tree it's on, removing it
- from eligibility to receive packets. If the socket is removed from the
- tree then a reference will be released.
- Arguments:
- Socket - Supplies a pointer to the initialized socket to remove from the
- socket tree.
- Return Value:
- None.
- --*/
- {
- if (((Socket->Flags & NET_SOCKET_FLAG_ACTIVE) == 0) &&
- (Socket->BindingType == SocketBindingInvalid)) {
- return;
- }
- if (Socket->KernelSocket.Type == NetSocketRaw) {
- KeAcquireSharedExclusiveLockExclusive(NetRawSocketsLock);
- NetpDeactivateRawSocketUnlocked(Socket);
- KeReleaseSharedExclusiveLockExclusive(NetRawSocketsLock);
- } else {
- KeAcquireSharedExclusiveLockExclusive(Socket->Protocol->SocketLock);
- NetpDeactivateSocketUnlocked(Socket);
- KeReleaseSharedExclusiveLockExclusive(Socket->Protocol->SocketLock);
- }
- return;
- }
- NET_API
- KSTATUS
- NetBindSocket (
- PNET_SOCKET Socket,
- NET_SOCKET_BINDING_TYPE BindingType,
- PNET_LINK_LOCAL_ADDRESS LocalInformation,
- PNETWORK_ADDRESS RemoteAddress,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine officially binds a socket to a local address, local port,
- remote address and remote port tuple by adding it to the appropriate socket
- tree. It can also re-bind a socket in the case where it has already been
- bound to a different tree. Raw sockets are handled specially as ports do
- not make sense for raw sockets; they are put in a list that contains all
- raw sockets.
- Arguments:
- Socket - Supplies a pointer to the initialized socket to bind.
- BindingType - Supplies the type of binding for the socket.
- LocalInformation - Supplies an optional pointer to the information for the
- local link or address to which the socket shall be bound. Use this for
- unbound sockets, leaving the link and link address NULL.
- RemoteAddress - Supplies an optional pointer to a remote address to use
- when fully binding the socket.
- Flags - Supplies a bitmask of binding flags. See NET_SOCKET_BINDING_FLAG_*
- for definitions.
- Return Value:
- Status code.
- --*/
- {
- ULONG AttemptIndex;
- BOOL Available;
- ULONG CurrentPort;
- PRED_BLACK_TREE_NODE ExistingNode;
- PNET_SOCKET ExistingSocket;
- PNET_LINK Link;
- PNETWORK_ADDRESS LocalAddress;
- NET_LINK_LOCAL_ADDRESS LocalInformationBuffer;
- BOOL LockHeld;
- ULONG OldFlags;
- ULONG OriginalPort;
- PNET_PROTOCOL_ENTRY Protocol;
- BOOL Reinsert;
- NET_SOCKET SearchSocket;
- BOOL SkipValidation;
- KSTATUS Status;
- PRED_BLACK_TREE Tree;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT((LocalInformation != NULL) || (RemoteAddress != NULL));
- ASSERT((BindingType == SocketFullyBound) || (LocalInformation != NULL));
- ASSERT((BindingType != SocketFullyBound) || (RemoteAddress != NULL));
- LockHeld = FALSE;
- Protocol = Socket->Protocol;
- Reinsert = FALSE;
- //
- // If the socket is to be fully bound, then a remote address must have been
- // supplied. Make sure local information is present as well via an implicit
- // local binding.
- //
- if ((BindingType == SocketFullyBound) && (LocalInformation == NULL)) {
- OriginalPort = RemoteAddress->Port;
- RemoteAddress->Port = 0;
- Status = NetFindLinkForRemoteAddress(RemoteAddress,
- &LocalInformationBuffer);
- RemoteAddress->Port = OriginalPort;
- if (!KSUCCESS(Status)) {
- goto BindSocketEnd;
- }
- LocalInformation = &LocalInformationBuffer;
- }
- //
- // Raw sockets are treated a bit differently. Handle that separately.
- //
- if (Socket->KernelSocket.Type == NetSocketRaw) {
- Status = NetpBindRawSocket(Socket,
- BindingType,
- LocalInformation,
- RemoteAddress,
- Flags);
- goto BindSocketEnd;
- }
- SkipValidation = FALSE;
- KeAcquireSharedExclusiveLockExclusive(Protocol->SocketLock);
- LockHeld = TRUE;
- //
- // A socket is not allowed to become "less bound".
- //
- if ((Socket->BindingType != SocketBindingInvalid) &&
- (Socket->BindingType > BindingType)) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindSocketEnd;
- }
- //
- // A socket is not allowed to rebind unless it is to the fully bound state.
- //
- if ((Socket->BindingType != SocketFullyBound) &&
- (Socket->BindingType == BindingType)) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindSocketEnd;
- }
- //
- // Either the existing local port or the future local port better be zero
- // if they do not match.
- //
- if ((Socket->LocalAddress.Port != LocalInformation->LocalAddress.Port) &&
- (Socket->LocalAddress.Port != 0) &&
- (LocalInformation->LocalAddress.Port != 0)) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindSocketEnd;
- }
- //
- // If the socket is locally bound and destined to be fully bound, then the
- // link and link address entry better match. The supplied link was chosen
- // specifically as a link that can reach the remote address.
- //
- if (((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound)) &&
- (BindingType == SocketFullyBound) &&
- ((Socket->Link != LocalInformation->Link) ||
- (Socket->LinkAddress != LocalInformation->LinkAddress))) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindSocketEnd;
- }
- //
- // If the socket is already in a tree, temporarily remove it. It will
- // either get moved to the new tree or be restored, untouched, on error.
- //
- if (Socket->BindingType != SocketBindingInvalid) {
- RtlRedBlackTreeRemove(&(Protocol->SocketTree[Socket->BindingType]),
- &(Socket->U.TreeEntry));
- SkipValidation = TRUE;
- Reinsert = TRUE;
- //
- // If the socket is the forked copy of some listening socket, skip
- // validation. This socket is allowed to share the same local address and
- // port.
- //
- } else if ((Socket->Flags & NET_SOCKET_FLAG_FORKED_LISTENER) != 0) {
- ASSERT(LocalInformation != NULL);
- ASSERT(BindingType == SocketLocallyBound);
- ASSERT(LocalInformation->LocalAddress.Port != 0);
- SkipValidation = TRUE;
- }
- //
- // Determine the local address and link. They're in the socket if the
- // socket was already locally bound. Otherwise they're in the local
- // information.
- //
- if ((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound)) {
- ASSERT(Socket->Link != NULL);
- Link = Socket->Link;
- LocalAddress = &(Socket->LocalAddress);
- } else {
- ASSERT(LocalInformation != NULL);
- ASSERT(Socket->Link == NULL);
- Link = LocalInformation->Link;
- LocalAddress = &(LocalInformation->LocalAddress);
- //
- // If the socket used to be unbound, then the local address gets the
- // unbound port.
- //
- if (Socket->BindingType == SocketUnbound) {
- LocalAddress->Port = Socket->LocalAddress.Port;
- }
- }
- //
- // Debug print the socket binding.
- //
- if (NetGlobalDebug != FALSE) {
- switch (BindingType) {
- case SocketUnbound:
- RtlDebugPrint("Net: Binding unbound socket %x.\n", Socket);
- break;
- case SocketLocallyBound:
- RtlDebugPrint("Net: Binding locally bound socket %x: ", Socket);
- NetpDebugPrintNetworkAddress(Socket->Network, LocalAddress);
- RtlDebugPrint("\n");
- break;
- case SocketFullyBound:
- RtlDebugPrint("Net: Binding fully bound socket %x, Local ", Socket);
- NetpDebugPrintNetworkAddress(Socket->Network, LocalAddress);
- RtlDebugPrint(", Remote ");
- NetpDebugPrintNetworkAddress(Socket->Network, RemoteAddress);
- RtlDebugPrint(".\n");
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- }
- //
- // If the socket is bound to a link and the link is down, then do not
- // insert the socket.
- //
- // N.B. Because taking a link down requires iterating over the socket
- // trees, this does not require any additional synchronization. The
- // link state is updated and then it waits on the socket lock. So,
- // either changing the link state acquired the socket lock first, in
- // which case the link state is already set to 'down' and this should
- // fail. Or this routine acquired the lock first and if it notices the
- // link is down, great. If it doesn't, then the socket will get put in
- // the tree and the process of taking the link down will clean it up.
- // Of course the link could come back up after this check, but that's
- // OK. It's up to the caller to try again.
- //
- if ((Link != NULL) && (Link->LinkUp == FALSE)) {
- NetpDetachSocket(Socket);
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto BindSocketEnd;
- }
- //
- // If no local port number is assigned, attempt to assign one from the
- // ephemeral port range. This will result in a unique tuple, even for fully
- // bound sockets. Some networks allow use of port zero, so skip this if
- // indicated by the binding flags.
- //
- if ((LocalAddress->Port == 0) &&
- ((Flags & NET_SOCKET_BINDING_FLAG_NO_PORT_ASSIGNMENT) == 0)) {
- ASSERT(SkipValidation == FALSE);
- CurrentPort = HlQueryTimeCounter() % NET_EPHEMERAL_PORT_COUNT;
- //
- // Find an ephemeral port for this connection.
- //
- Status = STATUS_RESOURCE_IN_USE;
- for (AttemptIndex = 0;
- AttemptIndex < NET_EPHEMERAL_PORT_COUNT;
- AttemptIndex += 1) {
- LocalAddress->Port = CurrentPort + NET_EPHEMERAL_PORT_START;
- //
- // If the ephemeral port is already being used by a socket, then
- // try again.
- //
- Available = NetpCheckLocalAddressAvailability(Socket, LocalAddress);
- if (Available != FALSE) {
- if (NetGlobalDebug != FALSE) {
- RtlDebugPrint("Net: Using ephemeral port %d.\n",
- LocalAddress->Port);
- }
- Status = STATUS_SUCCESS;
- break;
- }
- CurrentPort += 1;
- if (CurrentPort >= NET_EPHEMERAL_PORT_COUNT) {
- CurrentPort = 0;
- }
- }
- if (!KSUCCESS(Status)) {
- if (NetGlobalDebug != FALSE) {
- RtlDebugPrint("Net: Rejecting binding for socket %x because "
- "ephemeral ports exhausted.\n",
- Socket);
- goto BindSocketEnd;
- }
- }
- //
- // Do checks for the case where the port was already defined. If the socket
- // was previously in the tree, then the local address is OK. Just make sure
- // that if this is to be a fully bound socket, that the 5-tuple is unique.
- // The exception is if the existing fully bound socket is in the time wait
- // state; deactivate such a socket.
- //
- } else {
- if (SkipValidation == FALSE) {
- Available = NetpCheckLocalAddressAvailability(Socket, LocalAddress);
- if (Available == FALSE) {
- Status = STATUS_ADDRESS_IN_USE;
- goto BindSocketEnd;
- }
- }
- if (BindingType == SocketFullyBound) {
- SearchSocket.Protocol = Socket->Protocol;
- RtlCopyMemory(&(SearchSocket.LocalAddress),
- LocalAddress,
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(SearchSocket.RemoteAddress),
- RemoteAddress,
- sizeof(NETWORK_ADDRESS));
- Tree = &(Protocol->SocketTree[SocketFullyBound]);
- ExistingNode = RtlRedBlackTreeSearch(Tree,
- &(SearchSocket.U.TreeEntry));
- if (ExistingNode != NULL) {
- ExistingSocket = RED_BLACK_TREE_VALUE(ExistingNode,
- NET_SOCKET,
- U.TreeEntry);
- if ((ExistingSocket->Flags & NET_SOCKET_FLAG_TIME_WAIT) != 0) {
- NetpDeactivateSocketUnlocked(ExistingSocket);
- } else {
- if (NetGlobalDebug != FALSE) {
- RtlDebugPrint("Net: Rejected binding of socket %x "
- "because of existing socket %x.\n",
- Socket,
- ExistingSocket);
- }
- Status = STATUS_ADDRESS_IN_USE;
- goto BindSocketEnd;
- }
- }
- }
- }
- //
- // This socket is good to go to use the remote address.
- //
- if (RemoteAddress != NULL) {
- ASSERT(BindingType == SocketFullyBound);
- RtlCopyMemory(&(Socket->RemoteAddress),
- RemoteAddress,
- sizeof(NETWORK_ADDRESS));
- }
- //
- // Set the local information in the socket if it isn't already locally
- // bound.
- //
- if ((Socket->BindingType != SocketLocallyBound) &&
- (Socket->BindingType != SocketFullyBound)) {
- ASSERT(Socket->Link == NULL);
- ASSERT(LocalInformation != NULL);
- if (LocalInformation->Link != NULL) {
- ASSERT(LocalInformation->LinkAddress != NULL);
- NetLinkAddReference(LocalInformation->Link);
- Socket->Link = LocalInformation->Link;
- Socket->LinkAddress = LocalInformation->LinkAddress;
- //
- // Now is the time to update the socket's max packet size,
- // header size, and footer size based on the link.
- //
- NetpGetPacketSizeInformation(Socket->Link,
- Socket,
- &(Socket->PacketSizeInformation));
- }
- RtlCopyMemory(&(Socket->LocalAddress),
- LocalAddress,
- sizeof(NETWORK_ADDRESS));
- }
- //
- // Mark the socket as active if requested. If this is moving to the fully
- // bound state from another state, record whether or not it was previously
- // active.
- //
- if ((Flags & NET_SOCKET_BINDING_FLAG_ACTIVATE) != 0) {
- OldFlags = RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_ACTIVE);
- if ((BindingType == SocketFullyBound) &&
- (Socket->BindingType != SocketFullyBound) &&
- ((OldFlags & NET_SOCKET_FLAG_ACTIVE) != 0)) {
- RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_PREVIOUSLY_ACTIVE);
- }
- }
- //
- // Welcome this new friend into the bound sockets tree.
- //
- RtlRedBlackTreeInsert(&(Protocol->SocketTree[BindingType]),
- &(Socket->U.TreeEntry));
- Socket->BindingType = BindingType;
- //
- // Increment the reference count on the socket so that it cannot disappear
- // while being on the tree.
- //
- IoSocketAddReference(&(Socket->KernelSocket));
- Status = STATUS_SUCCESS;
- BindSocketEnd:
- if (!KSUCCESS(Status)) {
- if (Reinsert != FALSE) {
- ASSERT(Socket->BindingType != SocketBindingInvalid);
- Tree = &(Protocol->SocketTree[Socket->BindingType]);
- RtlRedBlackTreeInsert(Tree, &(Socket->U.TreeEntry));
- }
- }
- if (LockHeld != FALSE) {
- KeReleaseSharedExclusiveLockExclusive(Protocol->SocketLock);
- }
- if ((LocalInformation == &LocalInformationBuffer) &&
- (LocalInformationBuffer.Link != NULL)) {
- NetLinkReleaseReference(LocalInformationBuffer.Link);
- }
- return Status;
- }
- NET_API
- KSTATUS
- NetDisconnectSocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine disconnects a socket from the fully bound state, rolling it
- back to the locally bound state.
- Arguments:
- Socket - Supplies a pointer to the socket to disconnect.
- Return Value:
- Status code.
- --*/
- {
- PNET_PROTOCOL_ENTRY Protocol;
- KSTATUS Status;
- //
- // Disconnect only makes sense on fully bound sockets.
- //
- if (Socket->BindingType != SocketFullyBound) {
- return STATUS_INVALID_PARAMETER;
- }
- //
- // Handle raw sockets separately.
- //
- Protocol = Socket->Protocol;
- if (Socket->KernelSocket.Type == NetSocketRaw) {
- KeAcquireSharedExclusiveLockExclusive(NetRawSocketsLock);
- if (Socket->BindingType != SocketFullyBound) {
- Status = STATUS_INVALID_PARAMETER;
- goto DisconnectSocketEnd;
- }
- //
- // The disconnect just wipes out the remote address. The socket may
- // have been implicitly bound on the connect. So be it. It stays
- // locally bound.
- //
- RtlZeroMemory(&(Socket->RemoteAddress), sizeof(NETWORK_ADDRESS));
- //
- // If the socket was previously inactive before becoming fully bound,
- // return it to the inactivate state.
- //
- if ((Socket->Flags & NET_SOCKET_FLAG_PREVIOUSLY_ACTIVE) == 0) {
- RtlAtomicAnd32(&(Socket->Flags), ~NET_SOCKET_FLAG_ACTIVE);
- }
- Socket->BindingType = SocketLocallyBound;
- } else {
- KeAcquireSharedExclusiveLockExclusive(Protocol->SocketLock);
- if (Socket->BindingType != SocketFullyBound) {
- Status = STATUS_INVALID_PARAMETER;
- goto DisconnectSocketEnd;
- }
- //
- // The disconnect just wipes out the remote address. The socket may
- // have been implicitly bound on the connect. So be it. It stays
- // locally bound.
- //
- RtlZeroMemory(&(Socket->RemoteAddress), sizeof(NETWORK_ADDRESS));
- //
- // If the socket was previously inactive before becoming fully bound,
- // return it to the inactive state and clear it from the last found
- // cache of one.
- //
- if ((Socket->Flags & NET_SOCKET_FLAG_PREVIOUSLY_ACTIVE) == 0) {
- RtlAtomicAnd32(&(Socket->Flags), ~NET_SOCKET_FLAG_ACTIVE);
- if (Socket == Protocol->LastSocket) {
- Protocol->LastSocket = NULL;
- }
- }
- //
- // Remove the socket from the fully bound tree and put it in the
- // locally bound tree. As the socket remains in the tree, the reference
- // on the link does not need to be updated.
- //
- RtlRedBlackTreeRemove(&(Protocol->SocketTree[SocketFullyBound]),
- &(Socket->U.TreeEntry));
- RtlRedBlackTreeInsert(&(Protocol->SocketTree[SocketLocallyBound]),
- &(Socket->U.TreeEntry));
- Socket->BindingType = SocketLocallyBound;
- }
- DisconnectSocketEnd:
- if (Socket->KernelSocket.Type == NetSocketRaw) {
- KeReleaseSharedExclusiveLockExclusive(NetRawSocketsLock);
- } else {
- KeReleaseSharedExclusiveLockExclusive(Protocol->SocketLock);
- }
- return Status;
- }
- NET_API
- KSTATUS
- NetInitializeSocketLinkOverride (
- PNET_SOCKET Socket,
- PNET_LINK_LOCAL_ADDRESS LinkInformation,
- PNET_SOCKET_LINK_OVERRIDE LinkOverride
- )
- /*++
- Routine Description:
- This routine initializes the given socket link override structure with the
- appropriate mix of socket and link information. The routine will fail if it
- determines that the socket is already bound to a link.
- Arguments:
- Socket - Supplies a pointer to a network socket.
- LinkInformation - Supplies a pointer to link local address information.
- LinkOverride - Supplies a pointer to a socket link override structure that
- will be filled in by this routine.
- Return Value:
- STATUS_SUCCESS if the link override was successfully filled in.
- STATUS_CONNECTION_EXISTS if the socket is already bound to a link.
- --*/
- {
- if (Socket->Link != NULL) {
- return STATUS_CONNECTION_EXISTS;
- }
- //
- // The socket is not yet associated with a link. Since the unbound header
- // size, footer size, and max packet size are saved in the socket, there is
- // no need to protect this under a socket lock.
- //
- NetpGetPacketSizeInformation(LinkInformation->Link,
- Socket,
- &(LinkOverride->PacketSizeInformation));
- RtlCopyMemory(&(LinkOverride->LinkInformation),
- LinkInformation,
- sizeof(NET_LINK_LOCAL_ADDRESS));
- NetLinkAddReference(LinkOverride->LinkInformation.Link);
- return STATUS_SUCCESS;
- }
- NET_API
- PNET_SOCKET
- NetFindSocket (
- PNET_PROTOCOL_ENTRY ProtocolEntry,
- PNETWORK_ADDRESS LocalAddress,
- PNETWORK_ADDRESS RemoteAddress
- )
- /*++
- Routine Description:
- This routine attempts to find an active socket that matches the given
- parameters. If the socket is found and returned, the reference count will
- be increased on it. It is the caller's responsiblity to release that
- reference.
- Arguments:
- ProtocolEntry - Supplies the protocol the socket must be on.
- LocalAddress - Supplies a pointer to the local address of the socket.
- RemoteAddress - Supplies a pointer to the remote address of the socket.
- Return Value:
- Returns a pointer to a socket matching the given parameters, with an
- increased reference count.
- NULL if no socket matches.
- --*/
- {
- PRED_BLACK_TREE_NODE FoundNode;
- PNET_SOCKET FoundSocket;
- PNET_SOCKET LastSocket;
- COMPARISON_RESULT Result;
- NET_SOCKET SearchEntry;
- PRED_BLACK_TREE Tree;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- FoundSocket = NULL;
- //
- // Check to see if the given remote and local addresses match the last
- // fully bound socket found. This speeds up the search process when there
- // isn't a whole lot of activity.
- //
- KeAcquireSharedExclusiveLockShared(ProtocolEntry->SocketLock);
- LastSocket = ProtocolEntry->LastSocket;
- if (LastSocket != NULL) {
- ASSERT(LastSocket->BindingType == SocketFullyBound);
- Result = NetpMatchFullyBoundSocket(LastSocket,
- LocalAddress,
- RemoteAddress);
- if (Result == ComparisonResultSame) {
- FoundNode = NULL;
- FoundSocket = LastSocket;
- goto FindSocketEnd;
- }
- }
- //
- // Fill out a fake socket entry for search purposes.
- //
- RtlCopyMemory(&(SearchEntry.LocalAddress),
- LocalAddress,
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(SearchEntry.RemoteAddress),
- RemoteAddress,
- sizeof(NETWORK_ADDRESS));
- //
- // Loop through each tree looking for a match, starting with the most
- // specified parameters (local and remote address), and working towards the
- // most generic parameters (local port only).
- //
- Tree = &(ProtocolEntry->SocketTree[SocketFullyBound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- Tree = &(ProtocolEntry->SocketTree[SocketLocallyBound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- Tree = &(ProtocolEntry->SocketTree[SocketUnbound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- FindSocketEnd:
- if (FoundNode != NULL) {
- FoundSocket = RED_BLACK_TREE_VALUE(FoundNode, NET_SOCKET, U.TreeEntry);
- }
- if (FoundSocket != NULL) {
- //
- // If the socket is not active, act as if it were never seen. The
- // cached socket should never be found as inactive. Deactivating the
- // cached socket clears the cache.
- //
- if ((FoundSocket->Flags & NET_SOCKET_FLAG_ACTIVE) == 0) {
- ASSERT(FoundSocket != ProtocolEntry->LastSocket);
- FoundSocket = NULL;
- //
- // Otherwise, increment the reference count so the socket cannot
- // disappear once the lock is released.
- //
- } else {
- IoSocketAddReference(&(FoundSocket->KernelSocket));
- if (FoundSocket->BindingType == SocketFullyBound) {
- ProtocolEntry->LastSocket = FoundSocket;
- }
- }
- }
- KeReleaseSharedExclusiveLockShared(ProtocolEntry->SocketLock);
- return FoundSocket;
- }
- NET_API
- KSTATUS
- NetGetSetNetworkDeviceInformation (
- PNET_LINK Link,
- PNET_LINK_ADDRESS_ENTRY LinkAddressEntry,
- PNETWORK_DEVICE_INFORMATION Information,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets the network device information for a particular
- link.
- Arguments:
- Link - Supplies a pointer to the link to work with.
- LinkAddressEntry - Supplies an optional pointer to the specific address
- entry to set. If NULL, a link address entry matching the network type
- contained in the information will be found.
- Information - Supplies a pointer that either receives the device
- information, or contains the new information to set. For set operations,
- the information buffer will contain the current settings on return.
- Set - Supplies a boolean indicating if the information should be set or
- returned.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- ULONG DnsServerIndex;
- NET_DOMAIN_TYPE Domain;
- BOOL LockHeld;
- BOOL OriginalConfiguredState;
- BOOL SameAddress;
- BOOL StaticAddress;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- if (Information->Version < NETWORK_DEVICE_INFORMATION_VERSION) {
- return STATUS_INVALID_PARAMETER;
- }
- //
- // Currently only IPv4 is supported.
- //
- Domain = Information->Domain;
- if (Domain != NetDomainIp4) {
- return STATUS_INVALID_CONFIGURATION;
- }
- KeAcquireQueuedLock(Link->QueuedLock);
- LockHeld = TRUE;
- //
- // If the caller passed in a link address entry, ensure it corresponds to
- // the network type they are working with.
- //
- if (LinkAddressEntry != NULL) {
- if (Information->Domain != LinkAddressEntry->Address.Domain) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetSetNetworkDeviceInformationEnd;
- }
- //
- // Find a link address entry for this network type.
- //
- } else {
- CurrentEntry = Link->LinkAddressList.Next;
- while (CurrentEntry != &(Link->LinkAddressList)) {
- LinkAddressEntry = LIST_VALUE(CurrentEntry,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- if (LinkAddressEntry->Address.Domain == Information->Domain) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &(Link->LinkAddressList)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetSetNetworkDeviceInformationEnd;
- }
- }
- if (Set != FALSE) {
- StaticAddress = TRUE;
- SameAddress = FALSE;
- //
- // If the caller is setting up the link, copy the parameters in.
- //
- if ((Information->Flags & NETWORK_DEVICE_FLAG_CONFIGURED) != 0) {
- if ((Information->Address.Domain != Domain) ||
- (Information->Subnet.Domain != Domain) ||
- (Information->Gateway.Domain != Domain) ||
- ((Information->ConfigurationMethod !=
- NetworkAddressConfigurationStatic) &&
- (Information->ConfigurationMethod !=
- NetworkAddressConfigurationDhcp))) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetSetNetworkDeviceInformationEnd;
- }
- if (Information->DnsServerCount > NETWORK_DEVICE_MAX_DNS_SERVERS) {
- Information->DnsServerCount = NETWORK_DEVICE_MAX_DNS_SERVERS;
- }
- for (DnsServerIndex = 0;
- DnsServerIndex < Information->DnsServerCount;
- DnsServerIndex += 1) {
- if (Information->DnsServers[DnsServerIndex].Domain != Domain) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetSetNetworkDeviceInformationEnd;
- }
- }
- SameAddress = RtlCompareMemory(&(LinkAddressEntry->Address),
- &(Information->Address),
- sizeof(NETWORK_ADDRESS));
- if (SameAddress == FALSE) {
- RtlCopyMemory(&(LinkAddressEntry->Address),
- &(Information->Address),
- sizeof(NETWORK_ADDRESS));
- }
- LinkAddressEntry->Address.Port = 0;
- RtlCopyMemory(&(LinkAddressEntry->Subnet),
- &(Information->Subnet),
- sizeof(NETWORK_ADDRESS));
- LinkAddressEntry->Subnet.Port = 0;
- RtlCopyMemory(&(LinkAddressEntry->DefaultGateway),
- &(Information->Gateway),
- sizeof(NETWORK_ADDRESS));
- LinkAddressEntry->DefaultGateway.Port = 0;
- for (DnsServerIndex = 0;
- DnsServerIndex < Information->DnsServerCount;
- DnsServerIndex += 1) {
- RtlCopyMemory(&(LinkAddressEntry->DnsServer[DnsServerIndex]),
- &(Information->DnsServers[DnsServerIndex]),
- sizeof(NETWORK_ADDRESS));
- }
- LinkAddressEntry->DnsServerCount = Information->DnsServerCount;
- LinkAddressEntry->StaticAddress = TRUE;
- if (Information->ConfigurationMethod ==
- NetworkAddressConfigurationDhcp) {
- LinkAddressEntry->StaticAddress = FALSE;
- RtlCopyMemory(&(LinkAddressEntry->LeaseServerAddress),
- &(Information->LeaseServerAddress),
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(LinkAddressEntry->LeaseStartTime),
- &(Information->LeaseStartTime),
- sizeof(SYSTEM_TIME));
- RtlCopyMemory(&(LinkAddressEntry->LeaseEndTime),
- &(Information->LeaseEndTime),
- sizeof(SYSTEM_TIME));
- }
- LinkAddressEntry->Configured = TRUE;
- //
- // Unconfigure the link and bring it down.
- //
- } else {
- //
- // If the link address is not static, then zero the address,
- // leaving the network type.
- //
- StaticAddress = TRUE;
- if (LinkAddressEntry->StaticAddress == FALSE) {
- Domain = LinkAddressEntry->Address.Domain;
- RtlZeroMemory(&(LinkAddressEntry->Address),
- sizeof(NETWORK_ADDRESS));
- LinkAddressEntry->Address.Domain = Domain;
- StaticAddress = FALSE;
- }
- LinkAddressEntry->Configured = FALSE;
- }
- //
- // If the address is changing or going down, invalidate all sockets
- // using the address. Make sure that the link address entry is not
- // marked as configured, otherwise new sockets could show up while the
- // link's queued lock is relesaed.
- //
- if (SameAddress == FALSE) {
- OriginalConfiguredState = LinkAddressEntry->Configured;
- LinkAddressEntry->Configured = FALSE;
- KeReleaseQueuedLock(Link->QueuedLock);
- LockHeld = FALSE;
- //
- // Notify DHCP that the link and link address combination is now
- // invalid. It may have saved state.
- //
- if (((Information->Flags & NETWORK_DEVICE_FLAG_CONFIGURED) == 0) &&
- (StaticAddress == FALSE)) {
- NetpDhcpCancelLease(Link, LinkAddressEntry);
- }
- //
- // Notify every fully bound, locally bound, and raw socket using
- // this link and link address pair that the link address is being
- // disabled. Sockets may be waiting on data or in the middle of
- // sending data.
- //
- NetpDetachSockets(Link, LinkAddressEntry);
- KeAcquireQueuedLock(Link->QueuedLock);
- LockHeld = TRUE;
- LinkAddressEntry->Configured = OriginalConfiguredState;
- }
- }
- //
- // Now that the information has potentially been set, get the new
- // information.
- //
- if (LockHeld == FALSE) {
- KeAcquireQueuedLock(Link->QueuedLock);
- LockHeld = TRUE;
- }
- Information->Flags = 0;
- RtlCopyMemory(&(Information->PhysicalAddress),
- &(LinkAddressEntry->PhysicalAddress),
- sizeof(NETWORK_ADDRESS));
- if (Link->LinkUp != FALSE) {
- Information->Flags |= NETWORK_DEVICE_FLAG_MEDIA_CONNECTED;
- }
- if (LinkAddressEntry->Configured == FALSE) {
- Information->ConfigurationMethod = NetworkAddressConfigurationNone;
- Status = STATUS_SUCCESS;
- goto GetSetNetworkDeviceInformationEnd;
- }
- Information->Flags |= NETWORK_DEVICE_FLAG_CONFIGURED;
- Information->ConfigurationMethod = NetworkAddressConfigurationDhcp;
- if (LinkAddressEntry->StaticAddress != FALSE) {
- Information->ConfigurationMethod = NetworkAddressConfigurationStatic;
- }
- RtlCopyMemory(&(Information->Address),
- &(LinkAddressEntry->Address),
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(Information->Subnet),
- &(LinkAddressEntry->Subnet),
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(Information->Gateway),
- &(LinkAddressEntry->DefaultGateway),
- sizeof(NETWORK_ADDRESS));
- Information->DnsServerCount = LinkAddressEntry->DnsServerCount;
- for (DnsServerIndex = 0;
- DnsServerIndex < Information->DnsServerCount;
- DnsServerIndex += 1) {
- RtlCopyMemory(&(Information->DnsServers[DnsServerIndex]),
- &(LinkAddressEntry->DnsServer[DnsServerIndex]),
- sizeof(NETWORK_ADDRESS));
- }
- if (LinkAddressEntry->StaticAddress == FALSE) {
- RtlCopyMemory(&(Information->LeaseServerAddress),
- &(LinkAddressEntry->LeaseServerAddress),
- sizeof(NETWORK_ADDRESS));
- RtlCopyMemory(&(Information->LeaseStartTime),
- &(LinkAddressEntry->LeaseStartTime),
- sizeof(SYSTEM_TIME));
- RtlCopyMemory(&(Information->LeaseEndTime),
- &(LinkAddressEntry->LeaseEndTime),
- sizeof(SYSTEM_TIME));
- }
- Status = STATUS_SUCCESS;
- GetSetNetworkDeviceInformationEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Link->QueuedLock);
- }
- return Status;
- }
- NET_API
- VOID
- NetRawSocketsProcessReceivedData (
- PNET_LINK Link,
- PNET_PACKET_BUFFER Packet,
- PNETWORK_ADDRESS SourceAddress,
- PNETWORK_ADDRESS DestinationAddress,
- ULONG NetworkProtocol
- )
- /*++
- Routine Description:
- This routine processes a received packet and sends it to any raw sockets
- that should be receiving it based on the protocol, source address, and
- destination address.
- Arguments:
- Link - Supplies a pointer to the link that received the packet.
- Packet - Supplies a pointer to the network packet. It is only guaranteed to
- include network layer headers, not physical layer headers.
- SourceAddress - Supplies a pointer to the source (remote) address of the
- packet.
- DestinationAddress - Supplies a pointer to the destination (local) address
- of the packet.
- NetworkProtocol - Supplies the network protocol of the packet.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- BOOL Match;
- ULONG PartIndex;
- PNET_PROTOCOL_ENTRY RawProtocol;
- PNET_SOCKET Socket;
- ASSERT(SourceAddress->Port == 0);
- ASSERT(DestinationAddress->Port == 0);
- ASSERT(SourceAddress->Domain == DestinationAddress->Domain);
- //
- // Exit immediately if the raw socket list is empty.
- //
- if (LIST_EMPTY(&NetRawSocketsList) != FALSE) {
- return;
- }
- //
- // Lookup the protocol used for raw sockets.
- //
- RawProtocol = NetGetProtocolEntry(SOCKET_INTERNET_PROTOCOL_RAW);
- if (RawProtocol == NULL) {
- return;
- }
- //
- // Iterate over the raw sockets list. If any socket should be receiving the
- // packet, allow it to process the data.
- //
- KeAcquireSharedExclusiveLockShared(NetRawSocketsLock);
- CurrentEntry = NetRawSocketsList.Next;
- while (CurrentEntry != &NetRawSocketsList) {
- Socket = LIST_VALUE(CurrentEntry, NET_SOCKET, U.ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ASSERT(Socket->Protocol == RawProtocol);
- //
- // The networks must match, first and foremost. Otherwise the protocol
- // might not make sense.
- //
- if (Socket->KernelSocket.Domain != DestinationAddress->Domain) {
- continue;
- }
- //
- // The protocol must match. There are no wildcard protocols to receive
- // all packets.
- //
- if (Socket->KernelSocket.Protocol != NetworkProtocol) {
- continue;
- }
- //
- // If the socket is locally bound, then the local address must match
- // the destination address.
- //
- if ((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound)) {
- ASSERT(Socket->LocalAddress.Port == 0);
- Match = TRUE;
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (Socket->LocalAddress.Address[PartIndex] !=
- DestinationAddress->Address[PartIndex]) {
- Match = FALSE;
- break;
- }
- }
- if (Match == FALSE) {
- continue;
- }
- }
- //
- // If the socket is fully bound, then the remote address must match the
- // source address.
- //
- if (Socket->BindingType == SocketFullyBound) {
- ASSERT(Socket->RemoteAddress.Port == 0);
- Match = TRUE;
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (Socket->RemoteAddress.Address[PartIndex] !=
- SourceAddress->Address[PartIndex]) {
- Match = FALSE;
- break;
- }
- }
- if (Match == FALSE) {
- continue;
- }
- }
- //
- // This raw socket is lucky. It gets to look at the packet.
- //
- RawProtocol->Interface.ProcessReceivedSocketData(Link,
- Socket,
- Packet,
- SourceAddress,
- DestinationAddress);
- }
- KeReleaseSharedExclusiveLockShared(NetRawSocketsLock);
- return;
- }
- NET_API
- COMPARISON_RESULT
- NetCompareNetworkAddresses (
- PNETWORK_ADDRESS FirstAddress,
- PNETWORK_ADDRESS SecondAddress
- )
- /*++
- Routine Description:
- This routine compares two network addresses.
- Arguments:
- FirstAddress - Supplies a pointer to the left side of the comparison.
- SecondAddress - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- return NetpCompareNetworkAddresses(FirstAddress, SecondAddress);
- }
- KSTATUS
- NetpInitializeNetworkLayer (
- VOID
- )
- /*++
- Routine Description:
- This routine initialize support for generic Network layer functionality.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- NetLinkListLock = KeCreateSharedExclusiveLock();
- if (NetLinkListLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeNetworkLayerEnd;
- }
- NetRawSocketsLock = KeCreateSharedExclusiveLock();
- if (NetRawSocketsLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeNetworkLayerEnd;
- }
- INITIALIZE_LIST_HEAD(&NetRawSocketsList);
- INITIALIZE_LIST_HEAD(&NetLinkList);
- Status = STATUS_SUCCESS;
- InitializeNetworkLayerEnd:
- if (!KSUCCESS(Status)) {
- if (NetLinkListLock != NULL) {
- KeDestroySharedExclusiveLock(NetLinkListLock);
- NetLinkListLock = NULL;
- }
- if (NetRawSocketsLock != NULL) {
- KeDestroySharedExclusiveLock(NetRawSocketsLock);
- NetRawSocketsLock = NULL;
- }
- }
- return Status;
- }
- COMPARISON_RESULT
- NetpCompareNetworkAddresses (
- PNETWORK_ADDRESS FirstAddress,
- PNETWORK_ADDRESS SecondAddress
- )
- /*++
- Routine Description:
- This routine compares two network addresses.
- Arguments:
- FirstAddress - Supplies a pointer to the left side of the comparison.
- SecondAddress - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- ULONG PartIndex;
- if (FirstAddress == SecondAddress) {
- return ComparisonResultSame;
- }
- //
- // Very likely the ports will disagree, so check those first.
- //
- if (FirstAddress->Port < SecondAddress->Port) {
- return ComparisonResultAscending;
- } else if (FirstAddress->Port > SecondAddress->Port) {
- return ComparisonResultDescending;
- }
- //
- // Compare the networks before the addresses. This is necessary because
- // binding requires a search for addresses of the same protocol and network
- // that use the same port. Sorting by network before address makes this
- // easier.
- //
- if (FirstAddress->Domain < SecondAddress->Domain) {
- return ComparisonResultAscending;
- } else if (FirstAddress->Domain > SecondAddress->Domain) {
- return ComparisonResultDescending;
- }
- //
- // Check the address itself.
- //
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (FirstAddress->Address[PartIndex] <
- SecondAddress->Address[PartIndex]) {
- return ComparisonResultAscending;
- } else if (FirstAddress->Address[PartIndex] >
- SecondAddress->Address[PartIndex]) {
- return ComparisonResultDescending;
- }
- //
- // The parts here are equal, move on to the next part.
- //
- }
- //
- // Well, nothing's not different, so they must be the same.
- //
- return ComparisonResultSame;
- }
- COMPARISON_RESULT
- NetpCompareFullyBoundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- )
- /*++
- Routine Description:
- This routine compares two fully bound sockets, where both the local and
- remote addresses are fixed.
- Arguments:
- Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
- FirstNode - Supplies a pointer to the left side of the comparison.
- SecondNode - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- PNET_SOCKET FirstSocket;
- COMPARISON_RESULT Result;
- PNET_SOCKET SecondSocket;
- FirstSocket = RED_BLACK_TREE_VALUE(FirstNode, NET_SOCKET, U.TreeEntry);
- SecondSocket = RED_BLACK_TREE_VALUE(SecondNode, NET_SOCKET, U.TreeEntry);
- Result = NetpMatchFullyBoundSocket(FirstSocket,
- &(SecondSocket->LocalAddress),
- &(SecondSocket->RemoteAddress));
- return Result;
- }
- COMPARISON_RESULT
- NetpCompareLocallyBoundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- )
- /*++
- Routine Description:
- This routine compares two locally bound sockets, where the local address
- and port are fixed.
- Arguments:
- Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
- FirstNode - Supplies a pointer to the left side of the comparison.
- SecondNode - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- PNET_SOCKET FirstSocket;
- COMPARISON_RESULT Result;
- PNET_SOCKET SecondSocket;
- FirstSocket = RED_BLACK_TREE_VALUE(FirstNode, NET_SOCKET, U.TreeEntry);
- SecondSocket = RED_BLACK_TREE_VALUE(SecondNode, NET_SOCKET, U.TreeEntry);
- Result = NetpCompareNetworkAddresses(&(FirstSocket->LocalAddress),
- &(SecondSocket->LocalAddress));
- return Result;
- }
- COMPARISON_RESULT
- NetpCompareUnboundSockets (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- )
- /*++
- Routine Description:
- This routine compares two unbound sockets, meaning only the local port
- number is known.
- Arguments:
- Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
- FirstNode - Supplies a pointer to the left side of the comparison.
- SecondNode - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- PNETWORK_ADDRESS FirstLocalAddress;
- PNET_SOCKET FirstSocket;
- PNETWORK_ADDRESS SecondLocalAddress;
- PNET_SOCKET SecondSocket;
- FirstSocket = RED_BLACK_TREE_VALUE(FirstNode, NET_SOCKET, U.TreeEntry);
- SecondSocket = RED_BLACK_TREE_VALUE(SecondNode, NET_SOCKET, U.TreeEntry);
- //
- // Compare the local port numbers.
- //
- FirstLocalAddress = &(FirstSocket->LocalAddress);
- SecondLocalAddress = &(SecondSocket->LocalAddress);
- if (FirstLocalAddress->Port < SecondLocalAddress->Port) {
- return ComparisonResultAscending;
- } else if (FirstLocalAddress->Port > SecondLocalAddress->Port) {
- return ComparisonResultDescending;
- }
- //
- // Compare the networks.
- //
- if (FirstLocalAddress->Domain < SecondLocalAddress->Domain) {
- return ComparisonResultAscending;
- } else if (FirstLocalAddress->Domain > SecondLocalAddress->Domain) {
- return ComparisonResultDescending;
- }
- return ComparisonResultSame;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- NetpDestroyLink (
- PNET_LINK Link
- )
- /*++
- Routine Description:
- This routine destroys the state for the given link.
- Arguments:
- Link - Supplies a pointer to the link that needs to be destroyed.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PNET_NETWORK_ENTRY CurrentNetwork;
- PNET_LINK_ADDRESS_ENTRY LinkAddressEntry;
- ASSERT(Link->ReferenceCount == 0);
- ASSERT(Link->ListEntry.Next == NULL);
- //
- // Destroy all the link address entries. Don't bother to lock the list as
- // all the references are gone.
- //
- while (LIST_EMPTY(&(Link->LinkAddressList)) == FALSE) {
- LinkAddressEntry = LIST_VALUE(Link->LinkAddressList.Next,
- NET_LINK_ADDRESS_ENTRY,
- ListEntry);
- LIST_REMOVE(&(LinkAddressEntry->ListEntry));
- MmFreePagedPool(LinkAddressEntry);
- }
- KeDestroyEvent(Link->AddressTranslationEvent);
- KeAcquireSharedExclusiveLockShared(NetPluginListLock);
- CurrentEntry = NetNetworkList.Next;
- while (CurrentEntry != &NetNetworkList) {
- CurrentNetwork = LIST_VALUE(CurrentEntry, NET_NETWORK_ENTRY, ListEntry);
- CurrentNetwork->Interface.DestroyLink(Link);
- CurrentEntry = CurrentEntry->Next;
- }
- KeReleaseSharedExclusiveLockShared(NetPluginListLock);
- Link->DataLinkEntry->Interface.DestroyLink(Link);
- Link->Properties.Interface.DestroyLink(Link->Properties.DeviceContext);
- IoDeviceReleaseReference(Link->Properties.Device);
- MmFreePagedPool(Link);
- return;
- }
- VOID
- NetpDeactivateSocketUnlocked (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine deactivates and unbinds a socket, preventing the socket from
- receiving incoming packets. It assumes that the net socket tree lock is
- already held. It does not, however, disassociate a socket from its local
- or remote address. Those are still valid properties of the socket, while
- its on its way out.
- Arguments:
- Socket - Supplies a pointer to the initialized socket to remove from the
- socket tree.
- Return Value:
- None.
- --*/
- {
- PNET_PROTOCOL_ENTRY Protocol;
- PRED_BLACK_TREE Tree;
- Protocol = Socket->Protocol;
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(Protocol->SocketLock) != FALSE);
- ASSERT(Socket->BindingType < SocketBindingTypeCount);
- if (((Socket->Flags & NET_SOCKET_FLAG_ACTIVE) == 0) &&
- (Socket->BindingType == SocketBindingInvalid)) {
- ASSERT(Socket != Protocol->LastSocket);
- return;
- }
- RtlAtomicAnd32(&(Socket->Flags), ~NET_SOCKET_FLAG_ACTIVE);
- Tree = &(Protocol->SocketTree[Socket->BindingType]);
- if (NetGlobalDebug != FALSE) {
- RtlDebugPrint("Net: Deactivating socket %x\n", Socket);
- }
- //
- // Remove this old friend from the tree.
- //
- RtlRedBlackTreeRemove(Tree, &(Socket->U.TreeEntry));
- Socket->BindingType = SocketBindingInvalid;
- //
- // If it was in the socket "cache", then remove it.
- //
- if (Socket == Protocol->LastSocket) {
- Protocol->LastSocket = NULL;
- }
- //
- // Release that reference that was added when the socket was added to the
- // tree. This should not be the last reference on the kernel socket.
- //
- ASSERT(Socket->KernelSocket.ReferenceCount > 1);
- IoSocketReleaseReference(&(Socket->KernelSocket));
- return;
- }
- VOID
- NetpDeactivateRawSocketUnlocked (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine deactivates and unbinds a raw socket, preventing the socket
- from receiving incoming packets. It assumes that the raw socket lock is
- already held. It does not, however, disassociate a socket from its local or
- remote address. Those are still valid properties of the socket, while its
- on its way out.
- Arguments:
- Socket - Supplies a pointer to the initialized raw socket to remove from
- the raw socket list.
- Return Value:
- None.
- --*/
- {
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(NetRawSocketsLock) != FALSE);
- ASSERT(Socket->KernelSocket.Type == NetSocketRaw);
- if (((Socket->Flags & NET_SOCKET_FLAG_ACTIVE) == 0) &&
- (Socket->BindingType == SocketBindingInvalid)) {
- return;
- }
- RtlAtomicAnd32(&(Socket->Flags), ~NET_SOCKET_FLAG_ACTIVE);
- if (NetGlobalDebug != FALSE) {
- RtlDebugPrint("Net: Deactivating raw socket %x\n", Socket);
- }
- //
- // Remove this old friend from the list.
- //
- LIST_REMOVE(&(Socket->U.ListEntry));
- Socket->BindingType = SocketBindingInvalid;
- //
- // Release that reference that was added when the socket was added to the
- // tree. This should not be the last reference on the kernel socket.
- //
- ASSERT(Socket->KernelSocket.ReferenceCount > 1);
- IoSocketReleaseReference(&(Socket->KernelSocket));
- return;
- }
- VOID
- NetpDetachSockets (
- PNET_LINK Link,
- PNET_LINK_ADDRESS_ENTRY LinkAddress
- )
- /*++
- Routine Description:
- This routine detaches all of the sockets associated with the given link
- and optional link address.
- Arguments:
- Link - Supplies a pointer to the network link whose sockets are to be
- detached.
- LinkAddress - Supplies a pointer to an optional link address entry. If
- supplied then only the link's sockets bound to the given link address
- will be detached.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PRED_BLACK_TREE_NODE Node;
- PNET_PROTOCOL_ENTRY Protocol;
- PNET_SOCKET Socket;
- PRED_BLACK_TREE Tree;
- //
- // The fully and locally bound socket trees must be pruned for each
- // protocol.
- //
- KeAcquireSharedExclusiveLockShared(NetPluginListLock);
- CurrentEntry = NetProtocolList.Next;
- while (CurrentEntry != &NetProtocolList) {
- Protocol = LIST_VALUE(CurrentEntry, NET_PROTOCOL_ENTRY, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- KeAcquireSharedExclusiveLockExclusive(Protocol->SocketLock);
- Tree = &(Protocol->SocketTree[SocketFullyBound]);
- Node = RtlRedBlackTreeGetNextNode(Tree, FALSE, NULL);
- while (Node != NULL) {
- Socket = RED_BLACK_TREE_VALUE(Node, NET_SOCKET, U.TreeEntry);
- Node = RtlRedBlackTreeGetNextNode(Tree, FALSE, Node);
- if ((Socket->Link != Link) ||
- ((LinkAddress != NULL) &&
- (Socket->LinkAddress != LinkAddress))) {
- continue;
- }
- NetpDetachSocket(Socket);
- }
- //
- // Do the same for locally bound sockets using this link.
- //
- Tree = &(Protocol->SocketTree[SocketLocallyBound]);
- Node = RtlRedBlackTreeGetNextNode(Tree, FALSE, NULL);
- while (Node != NULL) {
- Socket = RED_BLACK_TREE_VALUE(Node, NET_SOCKET, U.TreeEntry);
- Node = RtlRedBlackTreeGetNextNode(Tree, FALSE, Node);
- if ((Socket->Link != Link) ||
- ((LinkAddress != NULL) &&
- (Socket->LinkAddress != LinkAddress))) {
- continue;
- }
- NetpDetachSocket(Socket);
- }
- KeReleaseSharedExclusiveLockExclusive(Protocol->SocketLock);
- }
- KeReleaseSharedExclusiveLockShared(NetPluginListLock);
- //
- // Detach all the raw sockets that were using this link.
- //
- KeAcquireSharedExclusiveLockExclusive(NetRawSocketsLock);
- CurrentEntry = NetRawSocketsList.Next;
- while (CurrentEntry != &NetRawSocketsList) {
- Socket = LIST_VALUE(CurrentEntry, NET_SOCKET, U.ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Socket->Link != Link) ||
- ((LinkAddress != NULL) && (Socket->LinkAddress != LinkAddress))) {
- continue;
- }
- NetpDetachRawSocket(Socket);
- }
- KeReleaseSharedExclusiveLockExclusive(NetRawSocketsLock);
- return;
- }
- VOID
- NetpDetachSocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine detaches a socket from all activity as a result of its link
- going down. It assumes the socket lock is held.
- Arguments:
- Socket - Supplies a pointer to the network socket that is to be unbound
- from its link.
- Return Value:
- None.
- --*/
- {
- ASSERT((Socket->Link->LinkUp == FALSE) ||
- (Socket->LinkAddress->Configured == FALSE));
- ASSERT((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound));
- NetpDeactivateSocketUnlocked(Socket);
- NET_SOCKET_SET_LAST_ERROR(Socket, STATUS_NO_NETWORK_CONNECTION);
- IoSetIoObjectState(Socket->KernelSocket.IoState,
- POLL_EVENT_DISCONNECTED,
- TRUE);
- return;
- }
- VOID
- NetpDetachRawSocket (
- PNET_SOCKET Socket
- )
- /*++
- Routine Description:
- This routine detaches a raw socket from all activity as a result of its
- link going down. It assumes the raw socket lock is held.
- Arguments:
- Socket - Supplies a pointer to the network socket that is to be unbound
- from its link.
- Return Value:
- None.
- --*/
- {
- ASSERT((Socket->Link->LinkUp == FALSE) ||
- (Socket->LinkAddress->Configured == FALSE));
- ASSERT((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound));
- NetpDeactivateRawSocketUnlocked(Socket);
- NET_SOCKET_SET_LAST_ERROR(Socket, STATUS_NO_NETWORK_CONNECTION);
- IoSetIoObjectState(Socket->KernelSocket.IoState,
- POLL_EVENT_DISCONNECTED,
- TRUE);
- return;
- }
- KSTATUS
- NetpBindRawSocket (
- PNET_SOCKET Socket,
- NET_SOCKET_BINDING_TYPE BindingType,
- PNET_LINK_LOCAL_ADDRESS LocalInformation,
- PNETWORK_ADDRESS RemoteAddress,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine officially binds a raw socket to a local address and/or remote
- address. It can also re-bind a socket in the case where it has already been
- bound to a different address.
- Arguments:
- Socket - Supplies a pointer to the initialized socket to bind.
- BindingType - Supplies the type of binding for the socket.
- LocalInformation - Supplies a pointer to the information for the local link
- or address to which the socket shall be bound. Use this for unbound
- sockets, leaving the link and link address NULL.
- RemoteAddress - Supplies an optional pointer to a remote address to use
- when fully binding the socket.
- Flags - Supplies a bitmask of binding flags. See NET_SOCKET_BINDING_FLAG_*
- for definitions.
- Return Value:
- Status code.
- --*/
- {
- ULONG OldFlags;
- KSTATUS Status;
- ASSERT(Socket->KernelSocket.Type == NetSocketRaw);
- ASSERT(LocalInformation != NULL);
- //
- // This routine is simple. It updates the local and/or remote address for
- // the socket.
- //
- KeAcquireSharedExclusiveLockExclusive(NetRawSocketsLock);
- //
- // If the socket is locally bound and destined to be fully bound, then the
- // link and link address entry better match. The supplied link was chosen
- // specifically as a link that can reach the remote address.
- //
- if (((Socket->BindingType == SocketLocallyBound) ||
- (Socket->BindingType == SocketFullyBound)) &&
- (BindingType == SocketFullyBound) &&
- ((Socket->Link != LocalInformation->Link) ||
- (Socket->LinkAddress != LocalInformation->LinkAddress))) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindRawSocketEnd;
- }
- //
- // Debug print the socket binding.
- //
- if (NetGlobalDebug != FALSE) {
- switch (BindingType) {
- case SocketUnbound:
- RtlDebugPrint("Net: Binding unbound raw socket %x.\n", Socket);
- break;
- case SocketLocallyBound:
- RtlDebugPrint("Net: Binding locally bound raw socket %x: ", Socket);
- NetDebugPrintAddress(&(LocalInformation->LocalAddress));
- RtlDebugPrint("\n");
- break;
- case SocketFullyBound:
- RtlDebugPrint("Net: Binding fully bound raw socket %x, Local ",
- Socket);
- NetDebugPrintAddress(&(LocalInformation->LocalAddress));
- RtlDebugPrint(", Remote ");
- NetDebugPrintAddress(RemoteAddress);
- RtlDebugPrint(".\n");
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- }
- //
- // If the socket is bound to a link and the link is down, then do not
- // insert the socket.
- //
- // N.B. Because taking a link down requires iterating over the raw socket
- // list, this does not require any additional synchronization. The
- // link state is updated and then it waits on the raw socket lock. So,
- // either changing the link state acquired the raw socket lock first,
- // in which case the link state is already set to 'down' and this
- // should fail. Or this routine acquired the raw socket lock first and
- // if it notices the link is down, great. If it doesn't, then the
- // socket will get put in the list and the process of taking the link
- // down will clean it up. Of course the link could come back up after
- // this check, but that's OK. It's up to the caller to try again.
- //
- if ((LocalInformation->Link != NULL) &&
- (LocalInformation->Link->LinkUp == FALSE)) {
- NetpDetachRawSocket(Socket);
- Status = STATUS_NO_NETWORK_CONNECTION;
- goto BindRawSocketEnd;
- }
- //
- // This socket is good to go to use the remote address.
- //
- if (RemoteAddress != NULL) {
- ASSERT(BindingType == SocketFullyBound);
- RtlCopyMemory(&(Socket->RemoteAddress),
- RemoteAddress,
- sizeof(NETWORK_ADDRESS));
- }
- //
- // Clear out any old link information.
- //
- if (Socket->Link != NULL) {
- NetLinkReleaseReference(Socket->Link);
- Socket->Link = NULL;
- Socket->LinkAddress = NULL;
- RtlCopyMemory(&(Socket->PacketSizeInformation),
- &(Socket->UnboundPacketSizeInformation),
- sizeof(NET_PACKET_SIZE_INFORMATION));
- }
- //
- // Set the link information in the socket.
- //
- if (LocalInformation->Link != NULL) {
- ASSERT(LocalInformation->LinkAddress != NULL);
- NetLinkAddReference(LocalInformation->Link);
- Socket->Link = LocalInformation->Link;
- Socket->LinkAddress = LocalInformation->LinkAddress;
- //
- // Now is the time to update the socket's max packet size,
- // header size, and footer size based on the link.
- //
- NetpGetPacketSizeInformation(Socket->Link,
- Socket,
- &(Socket->PacketSizeInformation));
- }
- RtlCopyMemory(&(Socket->LocalAddress),
- &(LocalInformation->LocalAddress),
- sizeof(NETWORK_ADDRESS));
- //
- // Mark the socket as active if requested. If this is moving to the fully
- // bound state from another state, record whether or not it was previously
- // active.
- //
- if ((Flags & NET_SOCKET_BINDING_FLAG_ACTIVATE) != 0) {
- OldFlags = RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_ACTIVE);
- if ((BindingType == SocketFullyBound) &&
- (Socket->BindingType != SocketFullyBound) &&
- ((OldFlags & NET_SOCKET_FLAG_ACTIVE) != 0)) {
- RtlAtomicOr32(&(Socket->Flags), NET_SOCKET_FLAG_PREVIOUSLY_ACTIVE);
- }
- }
- //
- // Insert the socket into the list of raw sockets, unless it's already in
- // the list.
- //
- if (Socket->BindingType == SocketBindingInvalid) {
- INSERT_BEFORE(&(Socket->U.ListEntry), &NetRawSocketsList);
- }
- Socket->BindingType = BindingType;
- //
- // Increment the reference count on the socket so that it cannot disappear
- // while being in the list.
- //
- IoSocketAddReference(&(Socket->KernelSocket));
- Status = STATUS_SUCCESS;
- BindRawSocketEnd:
- KeReleaseSharedExclusiveLockExclusive(NetRawSocketsLock);
- return Status;
- }
- KSTATUS
- NetpLookupAddressTranslation (
- PNET_LINK Link,
- PNETWORK_ADDRESS NetworkAddress,
- PNETWORK_ADDRESS PhysicalAddress
- )
- /*++
- Routine Description:
- This routine performs a lookup from network address to physical address
- using the link address translation tree.
- Arguments:
- Link - Supplies a pointer to the link that supposedly owns the network
- address.
- NetworkAddress - Supplies the network address to look up.
- PhysicalAddress - Supplies a pointer where the corresponding physical
- address for this network address will be returned on success.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_NOT_FOUND if no corresponding entry could be found.
- --*/
- {
- PADDRESS_TRANSLATION_ENTRY FoundEntry;
- PRED_BLACK_TREE_NODE FoundNode;
- ADDRESS_TRANSLATION_ENTRY SearchEntry;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- RtlCopyMemory(&(SearchEntry.NetworkAddress),
- NetworkAddress,
- sizeof(NETWORK_ADDRESS));
- SearchEntry.NetworkAddress.Port = 0;
- Status = STATUS_NOT_FOUND;
- KeAcquireQueuedLock(Link->QueuedLock);
- FoundNode = RtlRedBlackTreeSearch(&(Link->AddressTranslationTree),
- &(SearchEntry.TreeEntry));
- //
- // If a node is found, copy the translation into the result while the lock
- // is still held to avoid racing with someone destroying this node.
- //
- if (FoundNode != NULL) {
- FoundEntry = RED_BLACK_TREE_VALUE(FoundNode,
- ADDRESS_TRANSLATION_ENTRY,
- TreeEntry);
- RtlCopyMemory(PhysicalAddress,
- &(FoundEntry->PhysicalAddress),
- sizeof(NETWORK_ADDRESS));
- Status = STATUS_SUCCESS;
- }
- KeReleaseQueuedLock(Link->QueuedLock);
- return Status;
- }
- COMPARISON_RESULT
- NetpMatchFullyBoundSocket (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS LocalAddress,
- PNETWORK_ADDRESS RemoteAddress
- )
- /*++
- Routine Description:
- This routine compares a socket to a local address and remote address to
- determine if the socket matches the provided information in a fully bound
- way.
- Arguments:
- Socket - Supplies a pointer to a socket to match against the given data.
- LocalAddress - Supplies a pointer to a local network address.
- RemoteAddress - Supplies a pointer to a remote network address.
- Return Value:
- Same if the socket has the same values as the data.
- Ascending if the socket's values are less than the data's.
- Descending if the socket's values are greater than the data's.
- --*/
- {
- ULONG PartIndex;
- COMPARISON_RESULT Result;
- //
- // Compare the local port and local network first. This is required because
- // binding needs to look for fully-bound sockets already using the same
- // local port. This allows bind to iterate over a sub-tree that contains
- // only matching local ports.
- //
- if (Socket->LocalAddress.Port < LocalAddress->Port) {
- return ComparisonResultAscending;
- } else if (Socket->LocalAddress.Port > LocalAddress->Port) {
- return ComparisonResultDescending;
- }
- if (Socket->LocalAddress.Domain < LocalAddress->Domain) {
- return ComparisonResultAscending;
- } else if (Socket->LocalAddress.Domain > LocalAddress->Domain) {
- return ComparisonResultDescending;
- }
- //
- // The nodes are really only the same if the local and remote addresses are
- // the same. The remote address is the more likely to be different, so try
- // that one first.
- //
- Result = NetpCompareNetworkAddresses(&(Socket->RemoteAddress),
- RemoteAddress);
- if (Result != ComparisonResultSame) {
- return Result;
- }
- //
- // Ugh, their remote addresses are the same, check the local addresses.
- //
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (Socket->LocalAddress.Address[PartIndex] <
- LocalAddress->Address[PartIndex]) {
- return ComparisonResultAscending;
- } else if (Socket->LocalAddress.Address[PartIndex] >
- LocalAddress->Address[PartIndex]) {
- return ComparisonResultDescending;
- }
- //
- // The parts here are equal, move on to the next part.
- //
- }
- return ComparisonResultSame;
- }
- COMPARISON_RESULT
- NetpCompareAddressTranslationEntries (
- PRED_BLACK_TREE Tree,
- PRED_BLACK_TREE_NODE FirstNode,
- PRED_BLACK_TREE_NODE SecondNode
- )
- /*++
- Routine Description:
- This routine compares two Red-Black tree nodes, in this case two
- network address translation entries.
- Arguments:
- Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
- FirstNode - Supplies a pointer to the left side of the comparison.
- SecondNode - Supplies a pointer to the second side of the comparison.
- Return Value:
- Same if the two nodes have the same value.
- Ascending if the first node is less than the second node.
- Descending if the second node is less than the first node.
- --*/
- {
- PADDRESS_TRANSLATION_ENTRY FirstEntry;
- COMPARISON_RESULT Result;
- PADDRESS_TRANSLATION_ENTRY SecondEntry;
- FirstEntry = RED_BLACK_TREE_VALUE(FirstNode,
- ADDRESS_TRANSLATION_ENTRY,
- TreeEntry);
- SecondEntry = RED_BLACK_TREE_VALUE(SecondNode,
- ADDRESS_TRANSLATION_ENTRY,
- TreeEntry);
- Result = NetpCompareNetworkAddresses(&(FirstEntry->NetworkAddress),
- &(SecondEntry->NetworkAddress));
- return Result;
- }
- BOOL
- NetpCheckLocalAddressAvailability (
- PNET_SOCKET Socket,
- PNETWORK_ADDRESS LocalAddress
- )
- /*++
- Routine Description:
- This routine determines whether or not the given local address can be used
- by the given socket. It takes into account address and port reusability as
- indicated by the socket's flags. It assumes that the socket lock is held.
- Arguments:
- Socket - Supplies a pointer to the socket whose local address is to be
- validated.
- LocalAddress - Supplies a pointer to a local network address to validate.
- Return Value:
- Returns TRUE if the given local address is OK for the socket to use or
- FALSE otherwise.
- --*/
- {
- BOOL AddressesMatch;
- BOOL AvailableAddress;
- BOOL DeactivateSocket;
- BOOL Descending;
- PRED_BLACK_TREE_NODE FirstFound;
- BOOL FirstFoundMatched;
- PRED_BLACK_TREE_NODE FoundNode;
- PNET_SOCKET FoundSocket;
- ULONG PartIndex;
- PNET_PROTOCOL_ENTRY Protocol;
- NET_SOCKET SearchSocket;
- PRED_BLACK_TREE Tree;
- BOOL UnspecifiedAddress;
- Protocol = Socket->Protocol;
- FoundSocket = NULL;
- ASSERT(KeIsSharedExclusiveLockHeldExclusive(Protocol->SocketLock) != FALSE);
- //
- // Remember if the supplied socket is for the unspecified address.
- //
- UnspecifiedAddress = TRUE;
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (LocalAddress->Address[PartIndex] != 0) {
- UnspecifiedAddress = FALSE;
- break;
- }
- }
- //
- // Create a search entry that does not have a remote address.
- //
- RtlCopyMemory(&(SearchSocket.LocalAddress),
- LocalAddress,
- sizeof(NETWORK_ADDRESS));
- RtlZeroMemory(&(SearchSocket.RemoteAddress), sizeof(NETWORK_ADDRESS));
- //
- // Assume this is going to be a resounding success.
- //
- AvailableAddress = TRUE;
- //
- // Search the tree of fully bound sockets for any using this local address
- // and port combination. Because the search entry's remote address is zero,
- // this should never match exactly, and just return the lowest entry in the
- // tree that matches on network and local port. The compare routine looks
- // at remote address before local address, so this may end up doing a bit
- // of iterating to get through all the necessary entries.
- //
- DeactivateSocket = FALSE;
- Tree = &(Protocol->SocketTree[SocketFullyBound]);
- FoundNode = RtlRedBlackTreeSearchClosest(Tree,
- &(SearchSocket.U.TreeEntry),
- TRUE);
- while (FoundNode != NULL) {
- FoundSocket = RED_BLACK_TREE_VALUE(FoundNode, NET_SOCKET, U.TreeEntry);
- if (FoundSocket->LocalAddress.Port != LocalAddress->Port) {
- break;
- }
- if (FoundSocket->LocalAddress.Domain != LocalAddress->Domain) {
- break;
- }
- //
- // If the supplied socket contains the unspecified address, do not
- // compare it with the found address. It should never match. But if
- // both sockets do not allow address reuse with the any address, then
- // do not allow the any address to use the port.
- //
- if (UnspecifiedAddress != FALSE) {
- if (CAN_REUSE_ANY_ADDRESS(Socket, FoundSocket) == FALSE) {
- AvailableAddress = FALSE;
- break;
- }
- //
- // Otherwise test to see if the addresses match.
- //
- } else {
- AddressesMatch = TRUE;
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (FoundSocket->LocalAddress.Address[PartIndex] !=
- LocalAddress->Address[PartIndex]) {
- AddressesMatch = FALSE;
- break;
- }
- }
- //
- // If the addresses match, then the new socket is only allowed to
- // use the address if either both sockets allow exact address reuse
- // or both sockets allow time wait state address reuse and the
- // found socket is in the time wait state. Deactivate any sockets
- // found in the time wait state if the address is going to be
- // reused.
- //
- if (AddressesMatch != FALSE) {
- if ((CAN_REUSE_EXACT_ADDRESS(Socket, FoundSocket) == FALSE) &&
- (CAN_REUSE_TIME_WAIT(Socket, FoundSocket) == FALSE)) {
- AvailableAddress = FALSE;
- break;
- }
- if ((FoundSocket->Flags & NET_SOCKET_FLAG_TIME_WAIT) != 0) {
- DeactivateSocket = TRUE;
- }
- }
- }
- //
- // So far, so good. Try the next node.
- //
- FoundNode = RtlRedBlackTreeGetNextNode(Tree, FALSE, FoundNode);
- //
- // If the last socket needed deactivating, do it now that the iteration
- // has moved on. Removing a node does not break iteration.
- //
- if (DeactivateSocket != FALSE) {
- NetpDeactivateSocketUnlocked(FoundSocket);
- DeactivateSocket = FALSE;
- }
- }
- //
- // Exit now if it has already been determined that the address is not valid
- // for use.
- //
- if (AvailableAddress == FALSE) {
- goto CheckLocalAddressAvailabilityEnd;
- }
- //
- // Search the tree of locally bound sockets for any using this local
- // address and port combination. If the search socket is using the
- // unspecified address, then this will not match. It should return the
- // lowest entry in the tree that shares the same port and network. If the
- // search socket is using a complete local address, then this may need to
- // search in both directions on the tree if the first node matches.
- //
- Tree = &(Protocol->SocketTree[SocketLocallyBound]);
- FirstFound = RtlRedBlackTreeSearchClosest(Tree,
- &(SearchSocket.U.TreeEntry),
- TRUE);
- Descending = FALSE;
- FoundNode = FirstFound;
- FirstFoundMatched = FALSE;
- while (FoundNode != NULL) {
- while (FoundNode != NULL) {
- FoundSocket = RED_BLACK_TREE_VALUE(FoundNode,
- NET_SOCKET,
- U.TreeEntry);
- if (FoundSocket->LocalAddress.Port != LocalAddress->Port) {
- break;
- }
- if (FoundSocket->LocalAddress.Domain != LocalAddress->Domain) {
- break;
- }
- //
- // Locally bound sockets should not be in the time wait state.
- //
- ASSERT((FoundSocket->Flags & NET_SOCKET_FLAG_TIME_WAIT) == 0);
- //
- // If the supplied socket contains the unspecified address, do not
- // compare it with the found address. It should never match. But if
- // both sockets do not allow any address reuse, then do not allow
- // the unspecified address to use the port.
- //
- if (UnspecifiedAddress != FALSE) {
- if (CAN_REUSE_ANY_ADDRESS(Socket, FoundSocket) == FALSE) {
- AvailableAddress = FALSE;
- break;
- }
- //
- // Otherwise test to see if the addresses match.
- //
- } else {
- AddressesMatch = TRUE;
- for (PartIndex = 0;
- PartIndex < MAX_NETWORK_ADDRESS_SIZE / sizeof(UINTN);
- PartIndex += 1) {
- if (FoundSocket->LocalAddress.Address[PartIndex] !=
- LocalAddress->Address[PartIndex]) {
- AddressesMatch = FALSE;
- break;
- }
- }
- //
- // If the local addresses do not match, then this has gone
- // beyond the range of any matches.
- //
- if (AddressesMatch == FALSE) {
- break;
- }
- //
- // Record if this was the first found and it matched.
- //
- if (FoundNode == FirstFound) {
- FirstFoundMatched = TRUE;
- }
- //
- // If the addresses match, then the new socket is only allowed
- // to use the address if both sockets allow exact address reuse.
- //
- if (CAN_REUSE_EXACT_ADDRESS(Socket, FoundSocket) == FALSE) {
- AvailableAddress = FALSE;
- break;
- }
- }
- //
- // So far, so good. Try the next node.
- //
- FoundNode = RtlRedBlackTreeGetNextNode(Tree, Descending, FoundNode);
- }
- //
- // Exit now if it has already been determined that the address is not
- // valid for use.
- //
- if (AvailableAddress == FALSE) {
- goto CheckLocalAddressAvailabilityEnd;
- }
- //
- // If the first found was not a match, then the tree does not need to
- // be searched in the descending direction.
- //
- if (FirstFoundMatched == FALSE) {
- break;
- }
- ASSERT(UnspecifiedAddress == FALSE);
- //
- // Switch the search direction once and start over from the node before
- // the first found.
- //
- if (Descending != FALSE) {
- break;
- }
- Descending = TRUE;
- FoundNode = RtlRedBlackTreeGetNextNode(Tree, Descending, FirstFound);
- }
- //
- // Search the tree of unbound sockets for any using this local port. This
- // has to deal with the same situation as the locally bound search because
- // the closest may match with other matches entries both above and below in
- // the tree.
- //
- Tree = &(Protocol->SocketTree[SocketUnbound]);
- FirstFound = RtlRedBlackTreeSearchClosest(Tree,
- &(SearchSocket.U.TreeEntry),
- TRUE);
- Descending = FALSE;
- FoundNode = FirstFound;
- FirstFoundMatched = FALSE;
- while (FoundNode != NULL) {
- while (FoundNode != NULL) {
- FoundSocket = RED_BLACK_TREE_VALUE(FoundNode,
- NET_SOCKET,
- U.TreeEntry);
- if (FoundSocket->LocalAddress.Port != LocalAddress->Port) {
- break;
- }
- if (FoundSocket->LocalAddress.Domain != LocalAddress->Domain) {
- break;
- }
- //
- // If the first found got this far, then it's a match.
- //
- if (FoundNode == FirstFound) {
- FirstFoundMatched = TRUE;
- }
- //
- // An unbound socket should not be in the time-wait state.
- //
- ASSERT((FoundSocket->Flags & NET_SOCKET_FLAG_TIME_WAIT) == 0);
- //
- // If the supplied socket has an unspecified address, then the
- // addresses match as well. The only way for the new socket to use
- // the address is if reusing the exact address is allowed on both
- // sockets.
- //
- if (UnspecifiedAddress != FALSE) {
- if (CAN_REUSE_EXACT_ADDRESS(Socket, FoundSocket) == FALSE) {
- AvailableAddress = FALSE;
- break;
- }
- //
- // Otherwise, the addresses are different. Reuse of the port is
- // only allowed if reusing the any address is allowed on both
- // sockets.
- //
- } else {
- if (CAN_REUSE_ANY_ADDRESS(Socket, FoundSocket) == FALSE) {
- AvailableAddress = FALSE;
- break;
- }
- }
- //
- // So far, so good. Try the next node.
- //
- FoundNode = RtlRedBlackTreeGetNextNode(Tree, Descending, FoundNode);
- }
- //
- // Exit now if it has already been determined that the address is not
- // valid for use.
- //
- if (AvailableAddress == FALSE) {
- goto CheckLocalAddressAvailabilityEnd;
- }
- //
- // If the first found was not a match, then the tree does not need to
- // be searched in the descending direction.
- //
- if (FirstFoundMatched == FALSE) {
- break;
- }
- //
- // Switch the search direction once and start over from the node before
- // the first found.
- //
- if (Descending != FALSE) {
- break;
- }
- Descending = TRUE;
- FoundNode = RtlRedBlackTreeGetNextNode(Tree, Descending, FirstFound);
- }
- CheckLocalAddressAvailabilityEnd:
- if (AvailableAddress == FALSE) {
- if (NetGlobalDebug != FALSE) {
- ASSERT(FoundSocket != NULL);
- RtlDebugPrint("Net: Rejected address availability of socket %x "
- "because of existing socket %x.\n",
- Socket,
- FoundSocket);
- }
- }
- return AvailableAddress;
- }
- VOID
- NetpGetPacketSizeInformation (
- PNET_LINK Link,
- PNET_SOCKET Socket,
- PNET_PACKET_SIZE_INFORMATION SizeInformation
- )
- /*++
- Routine Description:
- This routine calculates the packet size information given an link and a
- socket. It uses the unbound packet size information from the socket in
- order to calculate the resulting size information.
- Arguments:
- Link - Supplies a pointer to a network link.
- Socket - Supplies a pointer to a network socket.
- SizeInformation - Supplies a pointer to a packet size information structure
- that receives the calculated max packet, header, and footer size to
- use for sending packets from the given socket out over the given
- network link.
- Return Value:
- None.
- --*/
- {
- PNET_DATA_LINK_ENTRY DataLinkEntry;
- NET_PACKET_SIZE_INFORMATION DataLinkInformation;
- ULONG FooterSize;
- ULONG HeaderSize;
- ULONG MaxPacketSize;
- ULONG MinPacketSize;
- //
- // Add the data link layer's header and footer sizes to the socket's
- // unbound max packet size. If this is greater than the allowed maximum
- // packet size for the data link layer, then truncate it.
- //
- DataLinkEntry = Link->DataLinkEntry;
- DataLinkEntry->Interface.GetPacketSizeInformation(Link->DataLinkContext,
- &DataLinkInformation,
- 0);
- MaxPacketSize = DataLinkInformation.HeaderSize +
- Socket->UnboundPacketSizeInformation.MaxPacketSize +
- DataLinkInformation.FooterSize;
- if (MaxPacketSize > DataLinkInformation.MaxPacketSize) {
- MaxPacketSize = DataLinkInformation.MaxPacketSize;
- }
- //
- // Add the data link layer's header and footer sizes to the socket's
- // unbound minimum packet size. The maximum of the minimum packet size is
- // what wins here.
- //
- MinPacketSize = DataLinkInformation.HeaderSize +
- Socket->UnboundPacketSizeInformation.MinPacketSize +
- DataLinkInformation.FooterSize;
- if (MinPacketSize < DataLinkInformation.MinPacketSize) {
- MinPacketSize = DataLinkInformation.MinPacketSize;
- }
- //
- // Repeat for the device link layer, truncating the allowed maximum packet
- // size if necessary.
- //
- MaxPacketSize = Link->Properties.PacketSizeInformation.HeaderSize +
- MaxPacketSize +
- Link->Properties.PacketSizeInformation.FooterSize;
- if (MaxPacketSize > Link->Properties.PacketSizeInformation.MaxPacketSize) {
- MaxPacketSize = Link->Properties.PacketSizeInformation.MaxPacketSize;
- }
- //
- // Repeat for the device link layer, increasing the the minimum packet
- // size if necessary.
- //
- MinPacketSize = Link->Properties.PacketSizeInformation.HeaderSize +
- MinPacketSize +
- Link->Properties.PacketSizeInformation.FooterSize;
- if (MinPacketSize < Link->Properties.PacketSizeInformation.MinPacketSize) {
- MinPacketSize = Link->Properties.PacketSizeInformation.MinPacketSize;
- }
- SizeInformation->MaxPacketSize = MaxPacketSize;
- SizeInformation->MinPacketSize = MinPacketSize;
- //
- // The headers and footers of all layers are included in the final tally.
- //
- HeaderSize = Socket->UnboundPacketSizeInformation.HeaderSize +
- DataLinkInformation.HeaderSize +
- Link->Properties.PacketSizeInformation.HeaderSize;
- SizeInformation->HeaderSize = HeaderSize;
- FooterSize = Socket->UnboundPacketSizeInformation.FooterSize +
- DataLinkInformation.FooterSize +
- Link->Properties.PacketSizeInformation.FooterSize;
- SizeInformation->FooterSize = FooterSize;
- return;
- }
- VOID
- NetpDebugPrintNetworkAddress (
- PNET_NETWORK_ENTRY Network,
- PNETWORK_ADDRESS Address
- )
- /*++
- Routine Description:
- This routine prints the given address to the debug console. It must belong
- to the given network.
- Arguments:
- Network - Supplies a pointer to the network to which the address belongs.
- Address - Supplies a pointer to the address to print.
- Return Value:
- None.
- --*/
- {
- ULONG Length;
- CHAR StringBuffer[NET_PRINT_ADDRESS_STRING_LENGTH];
- ASSERT(Network->Domain == Address->Domain);
- StringBuffer[0] = '\0';
- Length = Network->Interface.PrintAddress(Address,
- StringBuffer,
- NET_PRINT_ADDRESS_STRING_LENGTH);
- ASSERT(Length <= NET_PRINT_ADDRESS_STRING_LENGTH);
- StringBuffer[NET_PRINT_ADDRESS_STRING_LENGTH - 1] = '\0';
- RtlDebugPrint("%s", StringBuffer);
- return;
- }
|