12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- 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 (
- PNET_NETWORK_ENTRY Network,
- PNETWORK_ADDRESS LocalAddress,
- 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:
- Network - Supplies a pointer to the network entry to which the address
- belongs.
- LocalAddress - Supplies a pointer to the local address to test against.
- 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,
- Network,
- LocalAddress,
- &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,
- Network,
- LocalAddress,
- &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,
- PNET_NETWORK_ENTRY Network,
- PNETWORK_ADDRESS Address,
- 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.
- Network - Supplies an optional pointer to the network entry to which the
- address belongs.
- Address - Supplies the address to search for.
- 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.
- --*/
- {
- NET_ADDRESS_TYPE AddressType;
- 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;
- //
- // If the network is known, classify the address type using this link
- // address entry. It is necessary to classify the address for each link
- // address entry in case it is the subnet broadcast address.
- //
- if ((Network != NULL) &&
- (Network->Interface.GetAddressType != NULL)) {
- AddressType = Network->Interface.GetAddressType(Link,
- CurrentAddress,
- Address);
- //
- // If the address type is unknown, then it definitely cannot be
- // satisfied by this link address entry.
- //
- if (AddressType == NetAddressUnknown) {
- continue;
- }
- //
- // Otherwise, assume it is a unicast address, meaning it must exactly
- // match the link address entry's local address.
- //
- } else {
- AddressType = NetAddressUnicast;
- }
- //
- // Only a search for an any address can match a non-configured link
- // address entry.
- //
- if ((CurrentAddress->Configured == FALSE) &&
- (AddressType != NetAddressAny)) {
- continue;
- }
- //
- // The domain and port must always match.
- //
- if ((CurrentAddress->Address.Domain != Address->Domain) ||
- (CurrentAddress->Address.Port != Address->Port)) {
- continue;
- }
- //
- // The any and broadcast addresses only need the domain and port to
- // match.
- //
- if ((AddressType == NetAddressAny) ||
- (AddressType == NetAddressBroadcast)) {
- *AddressEntry = CurrentAddress;
- Status = STATUS_SUCCESS;
- break;
- }
- ASSERT(AddressType == NetAddressUnicast);
- //
- // A unicast address must match the link address entry's local address.
- //
- ComparisonResult = NetpCompareNetworkAddresses(
- &(CurrentAddress->Address),
- Address);
- if (ComparisonResult == ComparisonResultSame) {
- *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;
- }
- 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->Link != NULL) &&
- (BindingType == SocketFullyBound) &&
- ((Socket->Link != LocalInformation->Link) ||
- (Socket->LinkAddress != LocalInformation->LinkAddress))) {
- Status = STATUS_INVALID_PARAMETER;
- goto BindSocketEnd;
- }
- //
- // Determine the local address and link. Use the ones in the socket if
- // available. They should be set for sockets that are fully or locally
- // bound, with exception for sockets locally bound to a global broadcast
- // address.
- //
- Link = Socket->Link;
- LocalAddress = &(Socket->LocalAddress);
- if (Link == NULL) {
- ASSERT(LocalInformation != NULL);
- Link = LocalInformation->Link;
- LocalAddress = &(LocalInformation->LocalAddress);
- //
- // If the socket was previously bound, use the local port that was
- // already assigned.
- //
- if (Socket->BindingType != SocketBindingInvalid) {
- 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 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.
- // Don't release the reference taken when the socket was first put on the
- // tree. Pass it on to the new tree or keep it for the reinsert.
- //
- SkipValidation = FALSE;
- 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;
- }
- //
- // 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 set.
- //
- if (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);
- }
- }
- //
- // If the socket wasn't already in a tree, increment the reference count on
- // the socket so that it cannot disappear while being in the tree.
- //
- if (Socket->BindingType == SocketBindingInvalid) {
- IoSocketAddReference(&(Socket->KernelSocket));
- }
- //
- // Welcome this new friend into the bound sockets tree.
- //
- RtlRedBlackTreeInsert(&(Protocol->SocketTree[BindingType]),
- &(Socket->U.TreeEntry));
- Socket->BindingType = BindingType;
- 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
- KSTATUS
- NetFindSocket (
- PNET_RECEIVE_CONTEXT ReceiveContext,
- PNET_SOCKET *Socket
- )
- /*++
- Routine Description:
- This routine attempts to find a socket on the receiving end of the given
- context based on matching the addresses and protocol. 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. If this routine returns
- that more processing is required, then subsequent calls should pass the
- previously found socket back to the routine and the search will pick up
- where it left off.
- Arguments:
- ReceiveContext - Supplies a pointer to the receive context used to find
- the socket. This contains the remote address, local address, protocol,
- and network to match on.
- Socket - Supplies a pointer that receives a pointer to the found socket on
- output. On input, it can optionally contain a pointer to the socket
- from which the search for a new socket should start.
- Return Value:
- STATUS_SUCCESS if a socket was found.
- STATUS_MORE_PROCESSING_REQUIRED if a socket was found, but more sockets
- may match the given address tuple.
- Error status code otherwise.
- --*/
- {
- NET_ADDRESS_TYPE AddressType;
- NET_SOCKET_BINDING_TYPE BindingType;
- BOOL FindMultiple;
- PRED_BLACK_TREE_NODE FoundNode;
- PNET_SOCKET FoundSocket;
- PNET_SOCKET LastSocket;
- PNETWORK_ADDRESS LocalAddress;
- PNET_NETWORK_ENTRY Network;
- PRED_BLACK_TREE_NODE NextNode;
- PNET_SOCKET NextSocket;
- PRED_BLACK_TREE_NODE PreviousNode;
- PNET_SOCKET PreviousSocket;
- PNET_PROTOCOL_ENTRY Protocol;
- PNETWORK_ADDRESS RemoteAddress;
- COMPARISON_RESULT Result;
- NET_SOCKET SearchEntry;
- KSTATUS Status;
- PRED_BLACK_TREE Tree;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- FoundSocket = NULL;
- LocalAddress = ReceiveContext->Destination;
- RemoteAddress = ReceiveContext->Source;
- Network = ReceiveContext->Network;
- Protocol = ReceiveContext->Protocol;
- PreviousSocket = *Socket;
- *Socket = NULL;
- //
- // If broadcast addresses are allowed for this protocol (the default), then
- // test to see if the destination address is a broadcast address. This test
- // is not necessary if a previous socket is supplied; assume that a
- // previous invocation determined that multiple sockets needed to be found
- // for this address tuple.
- //
- FindMultiple = FALSE;
- if ((Protocol->Flags & NET_PROTOCOL_FLAG_UNICAST_ONLY) == 0) {
- if (PreviousSocket != NULL) {
- FindMultiple = TRUE;
- } else if (Network->Interface.GetAddressType != NULL) {
- AddressType = Network->Interface.GetAddressType(
- ReceiveContext->Link,
- NULL,
- LocalAddress);
- if (AddressType == NetAddressBroadcast) {
- FindMultiple = TRUE;
- }
- }
- }
- //
- // 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. This cannot be done if multiple sockets
- // need to be found as it would start the search iteration in the wrong
- // location.
- //
- KeAcquireSharedExclusiveLockShared(Protocol->SocketLock);
- if (FindMultiple == FALSE) {
- LastSocket = Protocol->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));
- //
- // If only one socket needs to be found check each binding 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).
- //
- if (FindMultiple == FALSE) {
- Tree = &(Protocol->SocketTree[SocketFullyBound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- Tree = &(Protocol->SocketTree[SocketLocallyBound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- Tree = &(Protocol->SocketTree[SocketUnbound]);
- FoundNode = RtlRedBlackTreeSearch(Tree, &(SearchEntry.U.TreeEntry));
- if (FoundNode != NULL) {
- goto FindSocketEnd;
- }
- //
- // Otherwise go about finding the lowest socket in the unbound tree that
- // matches the criteria. Return it. The caller should call again and this
- // will pick up where it left off, iterating through that first tree. When
- // that tree is exhausted of matches, it will move to the next tree. This
- // could greatly benefit from a hash table. RTL is yet to include a hash
- // table library as the problem of how to grow hash tables is yet to be
- // investigated.
- //
- } else {
- BindingType = SocketUnbound;
- if (PreviousSocket != NULL) {
- BindingType = PreviousSocket->BindingType;
- }
- FoundNode = NULL;
- while (BindingType < SocketBindingTypeCount) {
- Tree = &(Protocol->SocketTree[BindingType]);
- BindingType += 1;
- //
- // Pick up where the last search left off if a previous socket was
- // provided.
- //
- if (PreviousSocket != NULL) {
- PreviousNode = &(PreviousSocket->U.TreeEntry);
- while (TRUE) {
- NextNode = RtlRedBlackTreeGetNextNode(Tree,
- FALSE,
- PreviousNode);
- if (NextNode == NULL) {
- break;
- }
- NextSocket = RED_BLACK_TREE_VALUE(NextNode,
- NET_SOCKET,
- U.TreeEntry);
- if ((NextSocket->Flags & NET_SOCKET_FLAG_ACTIVE) == 0) {
- PreviousNode = NextNode;
- continue;
- }
- break;
- }
- if (NextNode != NULL) {
- Result = Tree->CompareFunction(Tree,
- NextNode,
- &(SearchEntry.U.TreeEntry));
- if (Result == ComparisonResultSame) {
- FoundNode = NextNode;
- goto FindSocketEnd;
- }
- }
- //
- // There are no more matching sockets in this tree. Skip to the
- // next tree.
- //
- PreviousSocket = NULL;
- continue;
- //
- // Otherwise find the first matching, active socket in the new tree.
- //
- } else {
- NextNode = RtlRedBlackTreeSearch(Tree,
- &(SearchEntry.U.TreeEntry));
- if (NextNode == NULL) {
- continue;
- }
- //
- // A match was found. Find the lowest match in the tree. When
- // the loop exits, it will be the previous node touched.
- //
- do {
- PreviousNode = NextNode;
- NextNode = RtlRedBlackTreeGetNextNode(Tree,
- TRUE,
- PreviousNode);
- if (NextNode == NULL) {
- break;
- }
- Result = Tree->CompareFunction(Tree,
- NextNode,
- &(SearchEntry.U.TreeEntry));
- } while (Result == ComparisonResultSame);
- //
- // Now move forward finding the first active socket that
- // matches.
- //
- NextNode = PreviousNode;
- do {
- NextSocket = RED_BLACK_TREE_VALUE(NextNode,
- NET_SOCKET,
- U.TreeEntry);
- if ((NextSocket->Flags & NET_SOCKET_FLAG_ACTIVE) != 0) {
- FoundNode = NextNode;
- goto FindSocketEnd;
- }
- NextNode = RtlRedBlackTreeGetNextNode(Tree,
- FALSE,
- NextNode);
- if (NextNode == NULL) {
- break;
- }
- Result = Tree->CompareFunction(Tree,
- NextNode,
- &(SearchEntry.U.TreeEntry));
- } while (Result == ComparisonResultSame);
- //
- // If no active sockets were found, move to the next tree.
- //
- continue;
- }
- }
- }
- FindSocketEnd:
- if (FoundNode != NULL) {
- FoundSocket = RED_BLACK_TREE_VALUE(FoundNode, NET_SOCKET, U.TreeEntry);
- }
- Status = STATUS_NOT_FOUND;
- 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 != Protocol->LastSocket);
- FoundSocket = NULL;
- //
- // Otherwise, increment the reference count so the socket cannot
- // disappear once the lock is released.
- //
- } else {
- IoSocketAddReference(&(FoundSocket->KernelSocket));
- if (FindMultiple != FALSE) {
- Status = STATUS_MORE_PROCESSING_REQUIRED;
- } else {
- if (FoundSocket->BindingType == SocketFullyBound) {
- Protocol->LastSocket = FoundSocket;
- }
- Status = STATUS_SUCCESS;
- }
- }
- }
- KeReleaseSharedExclusiveLockShared(Protocol->SocketLock);
- *Socket = FoundSocket;
- return Status;
- }
- 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 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);
- //
- // 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);
- //
- // 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);
- LinkAddressEntry->Configured = OriginalConfiguredState;
- }
- }
- //
- // Now that the information has potentially been set, get the new
- // information.
- //
- 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:
- KeReleaseQueuedLock(Link->QueuedLock);
- return Status;
- }
- NET_API
- VOID
- NetRawSocketsProcessReceivedData (
- PNET_RECEIVE_CONTEXT ReceiveContext,
- 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:
- ReceiveContext - Supplies a pointer to the receive context that stores the
- link, network entry, source address, destination address, and the
- packet that was received.
- 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(ReceiveContext->Source->Port == 0);
- ASSERT(ReceiveContext->Destination->Port == 0);
- ASSERT(ReceiveContext->Source->Domain ==
- ReceiveContext->Destination->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 !=
- ReceiveContext->Destination->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] !=
- ReceiveContext->Destination->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] !=
- ReceiveContext->Source->Address[PartIndex]) {
- Match = FALSE;
- break;
- }
- }
- if (Match == FALSE) {
- continue;
- }
- }
- //
- // This raw socket is lucky. It gets to look at the packet.
- //
- RawProtocol->Interface.ProcessReceivedSocketData(Socket,
- ReceiveContext);
- }
- 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);
- IoSocketAddReference(&(Socket->KernelSocket));
- }
- Socket->BindingType = BindingType;
- 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;
- }
|