dhcp.c 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dhcp.c
  5. Abstract:
  6. This module implements support for the Dynamic Host Configuration Protocol,
  7. or DHCP.
  8. Author:
  9. Evan Green 5-Apr-2013
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. //
  17. // Network layer drivers are supposed to be able to stand on their own (ie be
  18. // able to be implemented outside the core net library). For the builtin ones,
  19. // avoid including netcore.h, but still redefine those functions that would
  20. // otherwise generate imports.
  21. //
  22. #define NET_API __DLLEXPORT
  23. #include <minoca/kernel/driver.h>
  24. #include <minoca/net/netdrv.h>
  25. #include <minoca/net/ip4.h>
  26. //
  27. // --------------------------------------------------------------------- Macros
  28. //
  29. //
  30. // These macros get the renewal and binding times as a percentage of the total
  31. // lease time. The renewal time is at 50% of the lease and the rebinding time
  32. // is at 87.5% of the lease time.
  33. //
  34. #define DHCP_GET_DEFAULT_RENEWAL_TIME(_LeaseTime) (_LeaseTime) >> 1
  35. #define DHCP_GET_DEFAULT_REBINDING_TIME(_LeaseTime) \
  36. ((_LeaseTime) - ((_LeaseTime) >> 3))
  37. //
  38. // ---------------------------------------------------------------- Definitions
  39. //
  40. #define DHCP_ALLOCATION_TAG 0x70636844 // 'pchD'
  41. //
  42. // Define the maximum number of DNS server addresses that will be saved in this
  43. // implementation.
  44. //
  45. #define DHCP_MAX_DNS_SERVERS 4
  46. //
  47. // Define some well-known port numbers.
  48. //
  49. #define DHCP_CLIENT_PORT 68
  50. #define DHCP_SERVER_PORT 67
  51. //
  52. // Define DHCP packet field values.
  53. //
  54. #define DHCP_OPERATION_REQUEST 0x01
  55. #define DHCP_OPERATION_REPLY 0x02
  56. #define DHCP_HARDWARE_TYPE_ETHERNET 0x01
  57. #define DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH 6
  58. #define DHCP_FLAG_BROADCAST 0x01
  59. #define DHCP_MAGIC_COOKIE 0x63825363
  60. #define DHCP_OPTION_HEADER_SIZE 2
  61. #define DHCP_SCRATCH_PACKET_SIZE 4096
  62. //
  63. // Define how many times discovery should be retried.
  64. //
  65. #define DHCP_DISCOVER_RETRY_COUNT 5
  66. //
  67. // Define how long to wait for an offer and acknowledge, in milliseconds.
  68. //
  69. #define DHCP_OFFER_TIMEOUT 8000
  70. #define DHCP_ACKNOWLEDGE_TIMEOUT DHCP_OFFER_TIMEOUT
  71. //
  72. // Define DHCP option codes.
  73. //
  74. #define DHCP_OPTION_PAD 0
  75. #define DHCP_OPTION_SUBNET_MASK 1
  76. #define DHCP_OPTION_TIME_OFFSET 2
  77. #define DHCP_OPTION_ROUTER 3
  78. #define DHCP_OPTION_DOMAIN_NAME_SERVER 6
  79. #define DHCP_OPTION_HOST_NAME 12
  80. #define DHCP_OPTION_DOMAIN_NAME 15
  81. #define DHCP_OPTION_REQUESTED_IP_ADDRESS 50
  82. #define DHCP_OPTION_IP_ADDRESS_LEASE_TIME 51
  83. #define DHCP_OPTION_OPTION_OVERLOAD 52
  84. #define DHCP_OPTION_DHCP_MESSAGE_TYPE 53
  85. #define DHCP_OPTION_DHCP_SERVER 54
  86. #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55
  87. #define DHCP_OPTION_MESSAGE 56
  88. #define DHCP_OPTION_RENEWAL_TIME 58
  89. #define DHCP_OPTION_REBINDING_TIME 59
  90. #define DHCP_OPTION_TFTP_SERVER_NAME 66
  91. #define DHCP_OPTION_BOOT_FILE_NAME 67
  92. #define DHCP_OPTION_END 255
  93. //
  94. // Define DHCP message types.
  95. //
  96. #define DHCP_MESSAGE_DISCOVER 1
  97. #define DHCP_MESSAGE_OFFER 2
  98. #define DHCP_MESSAGE_REQUEST 3
  99. #define DHCP_MESSAGE_DECLINE 4
  100. #define DHCP_MESSAGE_ACKNOWLEDGE 5
  101. #define DHCP_MESSAGE_NAK 6
  102. #define DHCP_MESSAGE_RELEASE 7
  103. #define DHCP_MESSAGE_INFORM 8
  104. //
  105. // Define what goes in the discovery request.
  106. //
  107. #define DHCP_OPTION_MESSAGE_TYPE_SIZE 3
  108. #define DHCP_DISCOVER_OPTION_COUNT 2
  109. #define DHCP_DISCOVER_PARAMETER_REQUEST_COUNT 4
  110. #define DHCP_DISCOVER_OPTIONS_SIZE \
  111. (DHCP_OPTION_MESSAGE_TYPE_SIZE + \
  112. (DHCP_OPTION_HEADER_SIZE + \
  113. DHCP_DISCOVER_PARAMETER_REQUEST_COUNT) + 2)
  114. //
  115. // Define the minimum due time delta for the DHCP lease timer, in seconds.
  116. //
  117. #define DHCP_TIMER_DURATION_MINIMUM 60
  118. //
  119. // Define the debug flags for DHCP.
  120. //
  121. #define DHCP_DEBUG_FLAG_EXTEND 0x1
  122. #define DHCP_DEBUG_FLAG_OFFER 0X2
  123. //
  124. // ------------------------------------------------------ Data Type Definitions
  125. //
  126. /*++
  127. Structure Description:
  128. This structure defines the structure of a DHCP packet request or response.
  129. After this structure, zero or more options may follow.
  130. Members:
  131. OperationCode - Stores the operation code, either request or reply.
  132. HardwareType - Stores the media type, pretty much always the code for
  133. "ethernet".
  134. HardwareAddressLength - Stores the length of a hardware address, pretty
  135. much always 6 for ethernet MAC addresses.
  136. Hops - Stores 0 usually, can be optionally set by relay agents when booting
  137. via a relay agent.
  138. TransactionIdentifier - Stores a unique value used to match requests to
  139. replies.
  140. Seconds - Stores the number of seconds since the client began the
  141. renewal or request process.
  142. Flags - Stores the broadcast flag.
  143. ClientIpAddress - Stores the client's current IP address.
  144. YourIpAddress - Stores the IP address being offered by the DHCP server.
  145. ServerIpAddress - Stores the IP address of the DHCP server.
  146. GatewayIpAddress - Stores the IP address to contact for requests outside
  147. the subnet.
  148. ClientHardwareAddress - Stores the hardware address associated with this
  149. offer.
  150. ServerName - Stores an optional NULL terminated string containing the
  151. server name, used by the BOOTP protocol
  152. BootFileName - Stores an optional fully qualified path to the BOOTP boot
  153. file name.
  154. MagicCookie - Stores a constant value. Options potentially follow after this
  155. magic.
  156. --*/
  157. typedef struct _DHCP_PACKET {
  158. UCHAR OperationCode;
  159. UCHAR HardwareType;
  160. UCHAR HardwareAddressLength;
  161. UCHAR Hops;
  162. ULONG TransactionIdentifier;
  163. USHORT Seconds;
  164. USHORT Flags;
  165. ULONG ClientIpAddress;
  166. ULONG YourIpAddress;
  167. ULONG ServerIpAddress;
  168. ULONG GatewayIpAddress;
  169. UCHAR ClientHardwareAddress[16];
  170. UCHAR ServerName[64];
  171. UCHAR BootFileName[128];
  172. ULONG MagicCookie;
  173. } PACKED DHCP_PACKET, *PDHCP_PACKET;
  174. /*++
  175. Structure Description:
  176. This structure defines the required data parsed from a DHCP response.
  177. Members:
  178. MessageType - Stores the DHCP option message type of the response. See
  179. DHCP_MESSAGE_* for values.
  180. ServerIpAddress - Stores the IP address of the DHCP server.
  181. OfferedIpAddress - Stores the IP address being offered by the DHCP server.
  182. RouterIpAddress - Stores the default gateway IP address associated with the
  183. offered address.Stores the IP address of the
  184. SubnetMask - Stores the subnet mask of the local network, as given by the
  185. DHCP server.
  186. DomainNameServer - Stores an array of DNS addresses associated with the
  187. offer.
  188. DomainNameServerCount - Stores the number of valid addresses in the DNS
  189. address array.
  190. LeaseTime - Stores the lease time returned in the offer or acknowledge, in
  191. seconds.
  192. RenewalTime - Stores the time until the renewal state begins, in seconds.
  193. RebindingTime - Stores the time until the rebinding state begins, in
  194. seconds.
  195. --*/
  196. typedef struct _DHCP_REPLY {
  197. UCHAR MessageType;
  198. ULONG ServerIpAddress;
  199. ULONG OfferedIpAddress;
  200. ULONG RouterIpAddress;
  201. ULONG SubnetMask;
  202. ULONG DomainNameServer[DHCP_MAX_DNS_SERVERS];
  203. ULONG DomainNameServerCount;
  204. ULONG LeaseTime;
  205. ULONG RenewalTime;
  206. ULONG RebindingTime;
  207. } DHCP_REPLY, *PDHCP_REPLY;
  208. typedef enum _DHCP_LEASE_STATE {
  209. DhcpLeaseStateInvalid,
  210. DhcpLeaseStateInitialize,
  211. DhcpLeaseStateBound,
  212. DhcpLeaseStateRenewing,
  213. DhcpLeaseStateRebinding
  214. } DHCP_LEASE_STATE, *PDHCP_LEASE_STATE;
  215. /*++
  216. Structure Description:
  217. This structure defines the DHCP state for a leased network address.
  218. Members:
  219. ListEntry - Stores pointers to the next and previous leased address handed
  220. out by DHCP.
  221. Link - Stores a pointer to the link that owns the link address entry.
  222. LinkAddress - Stores a pointer to the link address entry to which the lease
  223. was given.
  224. Timer - Stores a pointer to the timer that will trigger work to either
  225. renew or rebind the lease.
  226. Dpc - Stores a pointer to the DPC that is to run once the lease timer
  227. expires.
  228. WorkItem - Stores a pointer to the work item that is to be queued by the
  229. DPC.
  230. LeaseTime - Stores the total time of the lease.
  231. RenewalTime - Stores the time at which the lease enters the renewal phase.
  232. RebindingTime - Stores the time at which the lease enters the rebinding
  233. phase.
  234. State - Stores the state of the lease.
  235. ReferenceCount - Stores the number of references taken on the lease.
  236. --*/
  237. typedef struct _DHCP_LEASE {
  238. LIST_ENTRY ListEntry;
  239. PNET_LINK Link;
  240. PNET_LINK_ADDRESS_ENTRY LinkAddress;
  241. PKTIMER Timer;
  242. PDPC Dpc;
  243. PWORK_ITEM WorkItem;
  244. ULONG LeaseTime;
  245. ULONG RenewalTime;
  246. ULONG RebindingTime;
  247. DHCP_LEASE_STATE State;
  248. volatile ULONG ReferenceCount;
  249. } DHCP_LEASE, *PDHCP_LEASE;
  250. /*++
  251. Structure Description:
  252. This structure defines DHCP context used throughout the assignment
  253. sequence.
  254. Members:
  255. Link - Stores a pointer to the link to work on.
  256. LinkAddress - Stores a pointer to the link address entry to assign an
  257. address for.
  258. Lease - Stores a pointer to any existing lease for the given link and link
  259. address combination.
  260. ScratchPacket - Stores a pointer to a scratch packet, used for building
  261. requests.
  262. ScratchPacketSize - Stores the total size of the scratch packet, including
  263. extra length for options.
  264. ScratchPacketIoBuffer - Stores a pointer to an I/O buffer containing the
  265. scratch packet buffer.
  266. Socket - Stores a pointer to the UDP socket connection.
  267. ExpectedTransactionId - Stores the transaction ID that is expected to come
  268. back in the response. All others get ignored.
  269. OfferClientAddress - Stores the network address that the DHCP server is
  270. offering to this machine.
  271. OfferSubnetMask - Stores the subnet mask of the local network, as given by
  272. the DHCP server.
  273. OfferServerAddress - Stores the network address of the server making the
  274. offer.
  275. OfferRouter - Stores the default gateway address associated with the offered
  276. address.
  277. OfferDnsAddress - Stores an array of DNS addresses associated with the
  278. offer.
  279. OfferDnsAddressCount - Stores the number of valid addresses in the DNS
  280. address array.
  281. LeaseTime - Stores the lease time returned in the offer or acknowledge, in
  282. seconds.
  283. RenewalTime - Stores the time until the renewal state begins, in seconds.
  284. RebindingTime - Stores the time until the rebinding state begins, in
  285. seconds.
  286. LeaseRequestTime - Stores the time at which the lease was requested.
  287. --*/
  288. typedef struct _DHCP_CONTEXT {
  289. PNET_LINK Link;
  290. PNET_LINK_ADDRESS_ENTRY LinkAddress;
  291. PDHCP_LEASE Lease;
  292. PDHCP_PACKET ScratchPacket;
  293. ULONG ScratchPacketSize;
  294. PIO_BUFFER ScratchPacketIoBuffer;
  295. PIO_HANDLE Socket;
  296. ULONG ExpectedTransactionId;
  297. NETWORK_ADDRESS OfferClientAddress;
  298. NETWORK_ADDRESS OfferSubnetMask;
  299. NETWORK_ADDRESS OfferServerAddress;
  300. NETWORK_ADDRESS OfferRouter;
  301. NETWORK_ADDRESS OfferDnsAddress[DHCP_MAX_DNS_SERVERS];
  302. ULONG OfferDnsAddressCount;
  303. ULONG LeaseTime;
  304. ULONG RenewalTime;
  305. ULONG RebindingTime;
  306. SYSTEM_TIME LeaseRequestTime;
  307. } DHCP_CONTEXT, *PDHCP_CONTEXT;
  308. //
  309. // ----------------------------------------------- Internal Function Prototypes
  310. //
  311. VOID
  312. NetpDhcpAssignmentThread (
  313. PVOID Parameter
  314. );
  315. KSTATUS
  316. NetpDhcpBeginLeaseExtension (
  317. PDHCP_LEASE Lease
  318. );
  319. VOID
  320. NetpDhcpLeaseExtensionThread (
  321. PVOID Parameter
  322. );
  323. KSTATUS
  324. NetpDhcpBeginRelease (
  325. PNET_LINK Link,
  326. PNET_LINK_ADDRESS_ENTRY LinkAddress
  327. );
  328. VOID
  329. NetpDhcpReleaseThread (
  330. PVOID Parameter
  331. );
  332. KSTATUS
  333. NetpDhcpSendDiscover (
  334. PDHCP_CONTEXT Context
  335. );
  336. KSTATUS
  337. NetpDhcpReceiveOffer (
  338. PDHCP_CONTEXT Context
  339. );
  340. KSTATUS
  341. NetpDhcpSendRequest (
  342. PDHCP_CONTEXT Context
  343. );
  344. KSTATUS
  345. NetpDhcpReceiveAcknowledge (
  346. PDHCP_CONTEXT Context
  347. );
  348. KSTATUS
  349. NetpDhcpSendRelease (
  350. PDHCP_CONTEXT Context
  351. );
  352. KSTATUS
  353. NetpDhcpReceiveReply (
  354. PDHCP_CONTEXT Context,
  355. PDHCP_REPLY Reply
  356. );
  357. PDHCP_CONTEXT
  358. NetpDhcpCreateContext (
  359. PNET_LINK Link,
  360. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  361. PDHCP_LEASE Lease
  362. );
  363. VOID
  364. NetpDhcpDestroyContext (
  365. PDHCP_CONTEXT Context
  366. );
  367. PDHCP_LEASE
  368. NetpDhcpCreateLease (
  369. VOID
  370. );
  371. VOID
  372. NetpDhcpLeaseAddReference (
  373. PDHCP_LEASE Lease
  374. );
  375. VOID
  376. NetpDhcpLeaseReleaseReference (
  377. PDHCP_LEASE Lease
  378. );
  379. PDHCP_LEASE
  380. NetpDhcpFindLease (
  381. PNET_LINK Link,
  382. PNET_LINK_ADDRESS_ENTRY LinkAddress
  383. );
  384. VOID
  385. NetpDhcpDestroyLease (
  386. PDHCP_LEASE AssignmentContext
  387. );
  388. VOID
  389. NetpDhcpQueueLeaseExtension (
  390. PDHCP_LEASE Lease
  391. );
  392. VOID
  393. NetpDhcpLeaseDpcRoutine (
  394. PDPC Dpc
  395. );
  396. VOID
  397. NetpDhcpLeaseWorkRoutine (
  398. PVOID Parameter
  399. );
  400. KSTATUS
  401. NetpDhcpCopyReplyToContext (
  402. PDHCP_CONTEXT Context,
  403. PDHCP_REPLY Reply
  404. );
  405. VOID
  406. NetpDhcpPrintContext (
  407. PDHCP_CONTEXT Context
  408. );
  409. //
  410. // -------------------------------------------------------------------- Globals
  411. //
  412. LIST_ENTRY NetDhcpLeaseListHead;
  413. KSPIN_LOCK NetDhcpLeaseListLock;
  414. //
  415. // Store a bitfield of enabled DHCP debug flags. See DHCP_DEBUG_* definitions.
  416. //
  417. ULONG NetDhcpDebugFlags = 0x0;
  418. //
  419. // Set this debug value to overried the lease renewal and rebinding times.
  420. //
  421. BOOL NetDhcpDebugOverrideRenewal = FALSE;
  422. //
  423. // Set these values to the desired renewal and rebinding times if force renewal
  424. // is set.
  425. //
  426. ULONG NetDhcpDebugRenewalTime = 0;
  427. ULONG NetDhcpDebugRebindingTime = 0;
  428. //
  429. // Set these debug values to force failures in the renewal and/or rebinding
  430. // phase.
  431. //
  432. BOOL NetDhcpDebugFailRenewal = FALSE;
  433. BOOL NetDhcpDebugFailRebinding = FALSE;
  434. //
  435. // ------------------------------------------------------------------ Functions
  436. //
  437. VOID
  438. NetpDhcpInitialize (
  439. VOID
  440. )
  441. /*++
  442. Routine Description:
  443. This routine initializes support for DHCP.
  444. Arguments:
  445. None.
  446. Return Value:
  447. None.
  448. --*/
  449. {
  450. INITIALIZE_LIST_HEAD(&NetDhcpLeaseListHead);
  451. KeInitializeSpinLock(&NetDhcpLeaseListLock);
  452. return;
  453. }
  454. KSTATUS
  455. NetpDhcpBeginAssignment (
  456. PNET_LINK Link,
  457. PNET_LINK_ADDRESS_ENTRY LinkAddress
  458. )
  459. /*++
  460. Routine Description:
  461. This routine kicks off the process of assigning a network address to this
  462. link address entry by using DHCP.
  463. Arguments:
  464. Link - Supplies a pointer to the link to send the discovery request out on.
  465. LinkAddress - Supplies a pointer to the address structure to bind to.
  466. Return Value:
  467. Status code indicating whether or not the process was successfully
  468. initiated.
  469. --*/
  470. {
  471. PDHCP_CONTEXT DhcpContext;
  472. KSTATUS Status;
  473. DhcpContext = NetpDhcpCreateContext(Link, LinkAddress, NULL);
  474. if (DhcpContext == NULL) {
  475. return STATUS_INSUFFICIENT_RESOURCES;
  476. }
  477. Status = PsCreateKernelThread(NetpDhcpAssignmentThread,
  478. DhcpContext,
  479. "DhcpAssignThread");
  480. if (!KSUCCESS(Status)) {
  481. NetpDhcpDestroyContext(DhcpContext);
  482. }
  483. return Status;
  484. }
  485. KSTATUS
  486. NetpDhcpCancelLease (
  487. PNET_LINK Link,
  488. PNET_LINK_ADDRESS_ENTRY LinkAddress
  489. )
  490. /*++
  491. Routine Description:
  492. This routine attempts to cancel a DHCP lease.
  493. Arguments:
  494. Link - Supplies a pointer to the network link to which the lease was
  495. provided.
  496. LinkAddress - Supplies a pointer to the network link address that was
  497. leased.
  498. Return Value:
  499. Status code.
  500. --*/
  501. {
  502. PDHCP_LEASE Lease;
  503. DHCP_LEASE_STATE LeaseState;
  504. BOOL LinkUp;
  505. KSTATUS Status;
  506. Status = STATUS_SUCCESS;
  507. Lease = NetpDhcpFindLease(Link, LinkAddress);
  508. if (Lease == NULL) {
  509. goto DhcpCancelLeaseEnd;
  510. }
  511. //
  512. // Remove the lease from the global list.
  513. //
  514. KeAcquireSpinLock(&NetDhcpLeaseListLock);
  515. LIST_REMOVE(&(Lease->ListEntry));
  516. Lease->ListEntry.Next = NULL;
  517. KeReleaseSpinLock(&NetDhcpLeaseListLock);
  518. //
  519. // Save the lease state. If the lease is in the initialized state then the
  520. // lease has expired (or never started).
  521. //
  522. LeaseState = Lease->State;
  523. ASSERT(LeaseState != DhcpLeaseStateInvalid);
  524. //
  525. // Release the original reference on the lease and the reference taken by
  526. // the find routine.
  527. //
  528. NetpDhcpLeaseReleaseReference(Lease);
  529. NetpDhcpLeaseReleaseReference(Lease);
  530. //
  531. // Be kind. If the link is still up, attempt to release the leased IP
  532. // address if it is in the bound, renewing, or rebinding state.
  533. //
  534. NetGetLinkState(Link, &LinkUp, NULL);
  535. if ((LinkUp != FALSE) && (LeaseState != DhcpLeaseStateInitialize)) {
  536. Status = NetpDhcpBeginRelease(Link, LinkAddress);
  537. if (!KSUCCESS(Status)) {
  538. goto DhcpCancelLeaseEnd;
  539. }
  540. }
  541. DhcpCancelLeaseEnd:
  542. return Status;
  543. }
  544. //
  545. // --------------------------------------------------------- Internal Functions
  546. //
  547. VOID
  548. NetpDhcpAssignmentThread (
  549. PVOID Parameter
  550. )
  551. /*++
  552. Routine Description:
  553. This routine attempts to assign an address to a link using DHCP.
  554. Arguments:
  555. Parameter - Supplies a pointer supplied by the creator of the thread, in
  556. this case a pointer to the DHCP context structure.
  557. Return Value:
  558. None.
  559. --*/
  560. {
  561. BOOL BroadcastEnabled;
  562. UINTN DataSize;
  563. PDHCP_CONTEXT DhcpContext;
  564. NETWORK_DEVICE_INFORMATION Information;
  565. PDHCP_LEASE Lease;
  566. BOOL LeaseAcquired;
  567. SYSTEM_TIME LeaseEndTime;
  568. IP4_ADDRESS LocalAddress;
  569. ULONG RetryCount;
  570. KSTATUS Status;
  571. PSTR Step;
  572. DhcpContext = (PDHCP_CONTEXT)Parameter;
  573. Lease = NULL;
  574. LeaseAcquired = FALSE;
  575. Step = "Init";
  576. ASSERT(DhcpContext->Lease == NULL);
  577. //
  578. // Make sure there are no left over leases for this link and link address
  579. // combination. If the DHCP assignment results in the same IP address then
  580. // an old lease will not be canceled by the networking core. If it results
  581. // in a different IP address then it will attempt to destroy the old lease,
  582. // preventing reuse of any current lease here.
  583. //
  584. Status = NetpDhcpCancelLease(DhcpContext->Link, DhcpContext->LinkAddress);
  585. if (!KSUCCESS(Status)) {
  586. goto DhcpAssignmentThreadEnd;
  587. }
  588. Lease = NetpDhcpCreateLease();
  589. if (Lease == NULL) {
  590. Status = STATUS_INSUFFICIENT_RESOURCES;
  591. goto DhcpAssignmentThreadEnd;
  592. }
  593. //
  594. // Create the scratch packet space and the socket.
  595. //
  596. DhcpContext->ScratchPacket = MmAllocatePagedPool(DHCP_SCRATCH_PACKET_SIZE,
  597. DHCP_ALLOCATION_TAG);
  598. if (DhcpContext->ScratchPacket == NULL) {
  599. Status = STATUS_INSUFFICIENT_RESOURCES;
  600. goto DhcpAssignmentThreadEnd;
  601. }
  602. DhcpContext->ScratchPacketSize = DHCP_SCRATCH_PACKET_SIZE;
  603. Status = MmCreateIoBuffer(DhcpContext->ScratchPacket,
  604. DhcpContext->ScratchPacketSize,
  605. IO_BUFFER_FLAG_KERNEL_MODE_DATA,
  606. &(DhcpContext->ScratchPacketIoBuffer));
  607. if (!KSUCCESS(Status)) {
  608. goto DhcpAssignmentThreadEnd;
  609. }
  610. Status = IoSocketCreate(NetDomainIp4,
  611. NetSocketDatagram,
  612. SOCKET_INTERNET_PROTOCOL_UDP,
  613. 0,
  614. &(DhcpContext->Socket));
  615. if (!KSUCCESS(Status)) {
  616. goto DhcpAssignmentThreadEnd;
  617. }
  618. //
  619. // Bind that socket to the known DHCP client port. The any address must be
  620. // used as the DHCP server will reply with broadcast packets and only an
  621. // unbound socket will pick those up.
  622. //
  623. RtlZeroMemory(&LocalAddress, sizeof(NETWORK_ADDRESS));
  624. LocalAddress.Domain = NetDomainIp4;
  625. LocalAddress.Port = DHCP_CLIENT_PORT;
  626. Status = IoSocketBindToAddress(TRUE,
  627. DhcpContext->Socket,
  628. DhcpContext->Link,
  629. (PNETWORK_ADDRESS)&LocalAddress,
  630. NULL,
  631. 0);
  632. if (!KSUCCESS(Status)) {
  633. goto DhcpAssignmentThreadEnd;
  634. }
  635. //
  636. // Enable broadcast messages on this socket.
  637. //
  638. BroadcastEnabled = TRUE;
  639. DataSize = sizeof(BOOL);
  640. Status = IoSocketGetSetInformation(DhcpContext->Socket,
  641. SocketInformationBasic,
  642. SocketBasicOptionBroadcastEnabled,
  643. &BroadcastEnabled,
  644. &DataSize,
  645. TRUE);
  646. if (!KSUCCESS(Status)) {
  647. goto DhcpAssignmentThreadEnd;
  648. }
  649. Lease->State = DhcpLeaseStateInitialize;
  650. NetpDhcpLeaseAddReference(Lease);
  651. DhcpContext->Lease = Lease;
  652. RetryCount = 0;
  653. while (RetryCount < DHCP_DISCOVER_RETRY_COUNT) {
  654. RetryCount += 1;
  655. //
  656. // Kick off the sequence by sending a discovery packet.
  657. //
  658. Step = "SendDiscover";
  659. Status = NetpDhcpSendDiscover(DhcpContext);
  660. if (!KSUCCESS(Status)) {
  661. continue;
  662. }
  663. //
  664. // Get the offer back from the server.
  665. //
  666. Step = "ReceiveOffer";
  667. Status = NetpDhcpReceiveOffer(DhcpContext);
  668. if (!KSUCCESS(Status)) {
  669. continue;
  670. }
  671. //
  672. // Request the address that came back.
  673. //
  674. Step = "SendRequest";
  675. Status = NetpDhcpSendRequest(DhcpContext);
  676. if (!KSUCCESS(Status)) {
  677. continue;
  678. }
  679. //
  680. // Get the acknowledge back to make sure the DHCP heard the request.
  681. //
  682. Step = "RecieveAcknowledge";
  683. Status = NetpDhcpReceiveAcknowledge(DhcpContext);
  684. if (!KSUCCESS(Status)) {
  685. continue;
  686. }
  687. break;
  688. }
  689. if (!KSUCCESS(Status)) {
  690. goto DhcpAssignmentThreadEnd;
  691. }
  692. LeaseAcquired = TRUE;
  693. //
  694. // Calculate the lease's end based on the DHCP offer.
  695. //
  696. RtlCopyMemory(&LeaseEndTime,
  697. &(DhcpContext->LeaseRequestTime),
  698. sizeof(SYSTEM_TIME));
  699. LeaseEndTime.Seconds += DhcpContext->LeaseTime;
  700. //
  701. // The address reservation is complete. Set the parameters in the link
  702. // address entry.
  703. //
  704. Step = "SetNetworkAddress";
  705. RtlZeroMemory(&Information, sizeof(NETWORK_DEVICE_INFORMATION));
  706. Information.Version = NETWORK_DEVICE_INFORMATION_VERSION;
  707. Information.Flags = NETWORK_DEVICE_FLAG_CONFIGURED;
  708. Information.Domain = NetDomainIp4;
  709. Information.ConfigurationMethod = NetworkAddressConfigurationDhcp;
  710. RtlCopyMemory(&(Information.Address),
  711. &(DhcpContext->OfferClientAddress),
  712. sizeof(NETWORK_ADDRESS));
  713. RtlCopyMemory(&(Information.Subnet),
  714. &(DhcpContext->OfferSubnetMask),
  715. sizeof(NETWORK_ADDRESS));
  716. RtlCopyMemory(&(Information.Gateway),
  717. &(DhcpContext->OfferRouter),
  718. sizeof(NETWORK_ADDRESS));
  719. RtlCopyMemory(&(Information.DnsServers),
  720. &(DhcpContext->OfferDnsAddress),
  721. sizeof(NETWORK_ADDRESS) * DhcpContext->OfferDnsAddressCount);
  722. Information.DnsServerCount = DhcpContext->OfferDnsAddressCount;
  723. RtlCopyMemory(&(Information.LeaseServerAddress),
  724. &(DhcpContext->OfferServerAddress),
  725. sizeof(NETWORK_ADDRESS));
  726. RtlCopyMemory(&(Information.LeaseStartTime),
  727. &(DhcpContext->LeaseRequestTime),
  728. sizeof(SYSTEM_TIME));
  729. RtlCopyMemory(&(Information.LeaseEndTime),
  730. &LeaseEndTime,
  731. sizeof(SYSTEM_TIME));
  732. Status = NetGetSetNetworkDeviceInformation(DhcpContext->Link,
  733. DhcpContext->LinkAddress,
  734. &Information,
  735. TRUE);
  736. if (!KSUCCESS(Status)) {
  737. goto DhcpAssignmentThreadEnd;
  738. }
  739. //
  740. // Celebrate the assignment with some debugger prints.
  741. //
  742. RtlDebugPrint("DHCP Assignment:\n");
  743. NetpDhcpPrintContext(DhcpContext);
  744. //
  745. // Finish initializing the lease, including adding it to the global list.
  746. //
  747. NetLinkAddReference(DhcpContext->Link);
  748. Lease->Link = DhcpContext->Link;
  749. Lease->LinkAddress = DhcpContext->LinkAddress;
  750. Lease->State = DhcpLeaseStateBound;
  751. Lease->LeaseTime = DhcpContext->LeaseTime;
  752. Lease->RenewalTime = DhcpContext->RenewalTime;
  753. Lease->RebindingTime = DhcpContext->RebindingTime;
  754. KeAcquireSpinLock(&NetDhcpLeaseListLock);
  755. INSERT_BEFORE(&(Lease->ListEntry), &NetDhcpLeaseListHead);
  756. KeReleaseSpinLock(&NetDhcpLeaseListLock);
  757. //
  758. // The lease is established. Set the lease timer so that a lease renewal is
  759. // attemtped at the time specified by the server.
  760. //
  761. NetpDhcpQueueLeaseExtension(Lease);
  762. DhcpAssignmentThreadEnd:
  763. if (!KSUCCESS(Status)) {
  764. RtlDebugPrint("Net: DHCP assignment failed at step '%s': %d.\n",
  765. Step,
  766. Status);
  767. //
  768. // If the routine failed after the lease was acquired, kindly release
  769. // the IP address back to the server.
  770. //
  771. if (LeaseAcquired != FALSE) {
  772. RtlZeroMemory(&Information, sizeof(NETWORK_DEVICE_INFORMATION));
  773. Information.Version = NETWORK_DEVICE_INFORMATION_VERSION;
  774. Information.Domain = NetDomainIp4;
  775. Information.ConfigurationMethod = NetworkAddressConfigurationNone;
  776. NetGetSetNetworkDeviceInformation(DhcpContext->Link,
  777. DhcpContext->LinkAddress,
  778. &Information,
  779. TRUE);
  780. NetpDhcpSendRelease(DhcpContext);
  781. }
  782. if (Lease != NULL) {
  783. NetpDhcpLeaseReleaseReference(Lease);
  784. }
  785. }
  786. NetpDhcpDestroyContext(DhcpContext);
  787. return;
  788. }
  789. KSTATUS
  790. NetpDhcpBeginLeaseExtension (
  791. PDHCP_LEASE Lease
  792. )
  793. /*++
  794. Routine Description:
  795. This routine kicks off the process of extending the given DHCP lease.
  796. Arguments:
  797. Lease - Supplies a pointer to a DHCP lease that is to be renewed.
  798. Return Value:
  799. Status code indicating whether or not the process was successfully
  800. initiated.
  801. --*/
  802. {
  803. PDHCP_CONTEXT DhcpContext;
  804. KSTATUS Status;
  805. ASSERT(Lease->Link != NULL);
  806. ASSERT(Lease->LinkAddress != NULL);
  807. ASSERT((Lease->State == DhcpLeaseStateRenewing) ||
  808. (Lease->State == DhcpLeaseStateRebinding));
  809. DhcpContext = NetpDhcpCreateContext(Lease->Link, Lease->LinkAddress, Lease);
  810. if (DhcpContext == NULL) {
  811. return STATUS_INSUFFICIENT_RESOURCES;
  812. }
  813. Status = PsCreateKernelThread(NetpDhcpLeaseExtensionThread,
  814. DhcpContext,
  815. "DhcpExtendThread");
  816. if (!KSUCCESS(Status)) {
  817. NetpDhcpDestroyContext(DhcpContext);
  818. return Status;
  819. }
  820. return STATUS_SUCCESS;
  821. }
  822. VOID
  823. NetpDhcpLeaseExtensionThread (
  824. PVOID Parameter
  825. )
  826. /*++
  827. Routine Description:
  828. This routine attempts to extend the lease on an address for a link using
  829. DHCP.
  830. Arguments:
  831. Parameter - Supplies a pointer supplied by the creator of the thread, in
  832. this case a pointer to the DHCP context structure.
  833. Return Value:
  834. None.
  835. --*/
  836. {
  837. PDHCP_CONTEXT DhcpContext;
  838. NETWORK_DEVICE_INFORMATION Information;
  839. PDHCP_LEASE Lease;
  840. SYSTEM_TIME LeaseEndTime;
  841. IP4_ADDRESS LocalAddress;
  842. BOOL LockHeld;
  843. KSTATUS Status;
  844. PSTR Step;
  845. ASSERT(KeGetRunLevel() == RunLevelLow);
  846. DhcpContext = (PDHCP_CONTEXT)Parameter;
  847. Lease = DhcpContext->Lease;
  848. LockHeld = FALSE;
  849. Step = "Init";
  850. ASSERT(Lease != NULL);
  851. ASSERT((Lease->State == DhcpLeaseStateRenewing) ||
  852. (Lease->State == DhcpLeaseStateRebinding));
  853. //
  854. // If the debug state is set to fail this phase, then skip to the end.
  855. //
  856. if (((NetDhcpDebugFailRenewal != FALSE) &&
  857. (Lease->State == DhcpLeaseStateRenewing)) ||
  858. ((NetDhcpDebugFailRebinding != FALSE) &&
  859. (Lease->State == DhcpLeaseStateRebinding))) {
  860. Step = "ForceFailure";
  861. Status = STATUS_TRY_AGAIN;
  862. goto DhcpLeaseExtensionThreadEnd;
  863. }
  864. //
  865. // Create the scratch packet space and the socket.
  866. //
  867. DhcpContext->ScratchPacket = MmAllocatePagedPool(DHCP_SCRATCH_PACKET_SIZE,
  868. DHCP_ALLOCATION_TAG);
  869. if (DhcpContext->ScratchPacket == NULL) {
  870. Status = STATUS_INSUFFICIENT_RESOURCES;
  871. goto DhcpLeaseExtensionThreadEnd;
  872. }
  873. DhcpContext->ScratchPacketSize = DHCP_SCRATCH_PACKET_SIZE;
  874. Status = MmCreateIoBuffer(DhcpContext->ScratchPacket,
  875. DhcpContext->ScratchPacketSize,
  876. IO_BUFFER_FLAG_KERNEL_MODE_DATA,
  877. &(DhcpContext->ScratchPacketIoBuffer));
  878. if (!KSUCCESS(Status)) {
  879. goto DhcpLeaseExtensionThreadEnd;
  880. }
  881. Status = IoSocketCreate(NetDomainIp4,
  882. NetSocketDatagram,
  883. SOCKET_INTERNET_PROTOCOL_UDP,
  884. 0,
  885. &(DhcpContext->Socket));
  886. if (!KSUCCESS(Status)) {
  887. goto DhcpLeaseExtensionThreadEnd;
  888. }
  889. //
  890. // Bind that socket to the known DHCP client port. Make sure the link
  891. // address is still valid before copying it.
  892. //
  893. KeAcquireQueuedLock(DhcpContext->Link->QueuedLock);
  894. LockHeld = TRUE;
  895. if (DhcpContext->LinkAddress->Configured == FALSE) {
  896. Status = STATUS_NO_NETWORK_CONNECTION;
  897. goto DhcpLeaseExtensionThreadEnd;
  898. }
  899. RtlCopyMemory(&LocalAddress,
  900. &(DhcpContext->LinkAddress->Address),
  901. sizeof(NETWORK_ADDRESS));
  902. KeReleaseQueuedLock(DhcpContext->Link->QueuedLock);
  903. LockHeld = FALSE;
  904. LocalAddress.Port = DHCP_CLIENT_PORT;
  905. Status = IoSocketBindToAddress(TRUE,
  906. DhcpContext->Socket,
  907. DhcpContext->Link,
  908. (PNETWORK_ADDRESS)&LocalAddress,
  909. NULL,
  910. 0);
  911. if (!KSUCCESS(Status)) {
  912. goto DhcpLeaseExtensionThreadEnd;
  913. }
  914. //
  915. // Request the address that came back.
  916. //
  917. Step = "SendRequest";
  918. Status = NetpDhcpSendRequest(DhcpContext);
  919. if (!KSUCCESS(Status)) {
  920. goto DhcpLeaseExtensionThreadEnd;
  921. }
  922. //
  923. // Get the acknowledge back to make sure the DHCP heard the request.
  924. //
  925. Step = "RecieveAcknowledge";
  926. Status = NetpDhcpReceiveAcknowledge(DhcpContext);
  927. if (!KSUCCESS(Status)) {
  928. goto DhcpLeaseExtensionThreadEnd;
  929. }
  930. //
  931. // Calculate the lease's end based on the DHCP offer.
  932. //
  933. RtlCopyMemory(&LeaseEndTime,
  934. &(DhcpContext->LeaseRequestTime),
  935. sizeof(SYSTEM_TIME));
  936. LeaseEndTime.Seconds += DhcpContext->LeaseTime;
  937. //
  938. // The lease extension is complete. Set the parameters in the link address
  939. // entry.
  940. //
  941. Step = "SetNetworkAddress";
  942. RtlZeroMemory(&Information, sizeof(NETWORK_DEVICE_INFORMATION));
  943. Information.Version = NETWORK_DEVICE_INFORMATION_VERSION;
  944. Information.Flags = NETWORK_DEVICE_FLAG_CONFIGURED;
  945. Information.Domain = NetDomainIp4;
  946. Information.ConfigurationMethod = NetworkAddressConfigurationDhcp;
  947. RtlCopyMemory(&(Information.Address),
  948. &(DhcpContext->OfferClientAddress),
  949. sizeof(NETWORK_ADDRESS));
  950. RtlCopyMemory(&(Information.Subnet),
  951. &(DhcpContext->OfferSubnetMask),
  952. sizeof(NETWORK_ADDRESS));
  953. RtlCopyMemory(&(Information.Gateway),
  954. &(DhcpContext->OfferRouter),
  955. sizeof(NETWORK_ADDRESS));
  956. RtlCopyMemory(&(Information.DnsServers),
  957. &(DhcpContext->OfferDnsAddress),
  958. sizeof(NETWORK_ADDRESS) * DhcpContext->OfferDnsAddressCount);
  959. Information.DnsServerCount = DhcpContext->OfferDnsAddressCount;
  960. RtlCopyMemory(&(Information.LeaseServerAddress),
  961. &(DhcpContext->OfferServerAddress),
  962. sizeof(NETWORK_ADDRESS));
  963. RtlCopyMemory(&(Information.LeaseStartTime),
  964. &(DhcpContext->LeaseRequestTime),
  965. sizeof(SYSTEM_TIME));
  966. RtlCopyMemory(&(Information.LeaseEndTime),
  967. &LeaseEndTime,
  968. sizeof(SYSTEM_TIME));
  969. Status = NetGetSetNetworkDeviceInformation(DhcpContext->Link,
  970. DhcpContext->LinkAddress,
  971. &Information,
  972. TRUE);
  973. if (!KSUCCESS(Status)) {
  974. goto DhcpLeaseExtensionThreadEnd;
  975. }
  976. //
  977. // Celebrate the extnesion with some debugger prints.
  978. //
  979. RtlDebugPrint("DHCP Extension:\n");
  980. NetpDhcpPrintContext(DhcpContext);
  981. if ((NetDhcpDebugFlags & DHCP_DEBUG_FLAG_EXTEND) != 0) {
  982. RtlDebugPrint("Net: DHCP extended lease (0x%08x) for link (0x%08x) "
  983. "from state %d.\n",
  984. Lease,
  985. Lease->Link,
  986. Lease->State);
  987. }
  988. //
  989. // Mark that the lease is now in the bound state.
  990. //
  991. Lease->State = DhcpLeaseStateBound;
  992. //
  993. // The lease has been extended. Set the lease timer so that a lease
  994. // renewal is attemtped at the time specified by the server.
  995. //
  996. NetpDhcpQueueLeaseExtension(Lease);
  997. DhcpLeaseExtensionThreadEnd:
  998. if (LockHeld != FALSE) {
  999. KeReleaseQueuedLock(DhcpContext->Link->QueuedLock);
  1000. }
  1001. if (!KSUCCESS(Status)) {
  1002. RtlDebugPrint("Net: DHCP lease extension failed at step '%s': %d.\n",
  1003. Step,
  1004. Status);
  1005. //
  1006. // No matter when the extension failed, try to queue lease extension
  1007. // again. This is OK even if this routine fails after extending the
  1008. // lease. There is no harm in prematurely asking the DHCP server for
  1009. // an extension.
  1010. //
  1011. NetpDhcpQueueLeaseExtension(Lease);
  1012. }
  1013. NetpDhcpDestroyContext(DhcpContext);
  1014. return;
  1015. }
  1016. KSTATUS
  1017. NetpDhcpBeginRelease (
  1018. PNET_LINK Link,
  1019. PNET_LINK_ADDRESS_ENTRY LinkAddress
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This routine kicks off the process of releasing the IP address previously
  1024. assigned to the given link and address via DHCP.
  1025. Arguments:
  1026. Link - Supplies a pointer to the link to send the discovery request out on.
  1027. LinkAddress - Supplies a pointer to the address structure to bind to.
  1028. Return Value:
  1029. Status code indicating whether or not the process was successfully
  1030. initiated.
  1031. --*/
  1032. {
  1033. PDHCP_CONTEXT DhcpContext;
  1034. KSTATUS Status;
  1035. DhcpContext = NetpDhcpCreateContext(Link, LinkAddress, NULL);
  1036. if (DhcpContext == NULL) {
  1037. return STATUS_INSUFFICIENT_RESOURCES;
  1038. }
  1039. Status = PsCreateKernelThread(NetpDhcpReleaseThread,
  1040. DhcpContext,
  1041. "DhcpReleaseThread");
  1042. if (!KSUCCESS(Status)) {
  1043. NetpDhcpDestroyContext(DhcpContext);
  1044. return Status;
  1045. }
  1046. return STATUS_SUCCESS;
  1047. }
  1048. VOID
  1049. NetpDhcpReleaseThread (
  1050. PVOID Parameter
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. This routine attempts to release the IP address previously assigned via
  1055. DHCP.
  1056. Arguments:
  1057. Parameter - Supplies a pointer supplied by the creator of the thread, in
  1058. this case a pointer to the DHCP context structure.
  1059. Return Value:
  1060. None.
  1061. --*/
  1062. {
  1063. PDHCP_CONTEXT DhcpContext;
  1064. IP4_ADDRESS LocalAddress;
  1065. BOOL LockHeld;
  1066. KSTATUS Status;
  1067. PSTR Step;
  1068. ASSERT(KeGetRunLevel() == RunLevelLow);
  1069. DhcpContext = (PDHCP_CONTEXT)Parameter;
  1070. LockHeld = FALSE;
  1071. Step = "Init";
  1072. //
  1073. // Create the scratch packet space and the socket.
  1074. //
  1075. DhcpContext->ScratchPacket = MmAllocatePagedPool(DHCP_SCRATCH_PACKET_SIZE,
  1076. DHCP_ALLOCATION_TAG);
  1077. if (DhcpContext->ScratchPacket == NULL) {
  1078. Status = STATUS_INSUFFICIENT_RESOURCES;
  1079. goto DhcpLeaseReleaseThreadEnd;
  1080. }
  1081. DhcpContext->ScratchPacketSize = DHCP_SCRATCH_PACKET_SIZE;
  1082. Status = MmCreateIoBuffer(DhcpContext->ScratchPacket,
  1083. DhcpContext->ScratchPacketSize,
  1084. IO_BUFFER_FLAG_KERNEL_MODE_DATA,
  1085. &(DhcpContext->ScratchPacketIoBuffer));
  1086. if (!KSUCCESS(Status)) {
  1087. goto DhcpLeaseReleaseThreadEnd;
  1088. }
  1089. Status = IoSocketCreate(NetDomainIp4,
  1090. NetSocketDatagram,
  1091. SOCKET_INTERNET_PROTOCOL_UDP,
  1092. 0,
  1093. &(DhcpContext->Socket));
  1094. if (!KSUCCESS(Status)) {
  1095. goto DhcpLeaseReleaseThreadEnd;
  1096. }
  1097. //
  1098. // Bind that socket to the known DHCP client port. Make sure the link
  1099. // address is still valid before copying it.
  1100. //
  1101. KeAcquireQueuedLock(DhcpContext->Link->QueuedLock);
  1102. LockHeld = TRUE;
  1103. if (DhcpContext->LinkAddress->Configured == FALSE) {
  1104. Status = STATUS_NO_NETWORK_CONNECTION;
  1105. goto DhcpLeaseReleaseThreadEnd;
  1106. }
  1107. RtlCopyMemory(&LocalAddress,
  1108. &(DhcpContext->LinkAddress->Address),
  1109. sizeof(NETWORK_ADDRESS));
  1110. KeReleaseQueuedLock(DhcpContext->Link->QueuedLock);
  1111. LockHeld = FALSE;
  1112. LocalAddress.Port = DHCP_CLIENT_PORT;
  1113. Status = IoSocketBindToAddress(TRUE,
  1114. DhcpContext->Socket,
  1115. DhcpContext->Link,
  1116. (PNETWORK_ADDRESS)&LocalAddress,
  1117. NULL,
  1118. 0);
  1119. if (!KSUCCESS(Status)) {
  1120. goto DhcpLeaseReleaseThreadEnd;
  1121. }
  1122. //
  1123. // Request the address that came back.
  1124. //
  1125. Step = "SendRelease";
  1126. Status = NetpDhcpSendRelease(DhcpContext);
  1127. if (!KSUCCESS(Status)) {
  1128. goto DhcpLeaseReleaseThreadEnd;
  1129. }
  1130. DhcpLeaseReleaseThreadEnd:
  1131. if (LockHeld != FALSE) {
  1132. KeReleaseQueuedLock(DhcpContext->Link->QueuedLock);
  1133. }
  1134. if (!KSUCCESS(Status)) {
  1135. RtlDebugPrint("Net: DHCP lease release failed at step '%s': %d.\n",
  1136. Step,
  1137. Status);
  1138. }
  1139. NetpDhcpDestroyContext(DhcpContext);
  1140. return;
  1141. }
  1142. KSTATUS
  1143. NetpDhcpSendDiscover (
  1144. PDHCP_CONTEXT Context
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. This routine sends the DHCP discovery request out onto the subnet.
  1149. Arguments:
  1150. Context - Supplies a pointer to the DHCP context information.
  1151. Return Value:
  1152. Status code indicating whether or not the discovery request was
  1153. successfully sent.
  1154. --*/
  1155. {
  1156. PBYTE OptionByte;
  1157. SOCKET_IO_PARAMETERS Parameters;
  1158. IP4_ADDRESS RemoteAddress;
  1159. PDHCP_PACKET Request;
  1160. KSTATUS Status;
  1161. ULONG TotalPacketSize;
  1162. Request = NULL;
  1163. //
  1164. // Initialize the DHCP discover request.
  1165. //
  1166. Request = Context->ScratchPacket;
  1167. RtlZeroMemory(Request, sizeof(DHCP_PACKET));
  1168. Request->OperationCode = DHCP_OPERATION_REQUEST;
  1169. Request->HardwareType = DHCP_HARDWARE_TYPE_ETHERNET;
  1170. Request->HardwareAddressLength = DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH;
  1171. Request->Hops = 0;
  1172. Request->TransactionIdentifier = HlQueryTimeCounter() & MAX_ULONG;
  1173. Context->ExpectedTransactionId = Request->TransactionIdentifier;
  1174. Request->Seconds = 0;
  1175. Request->Flags = 0;
  1176. Request->ClientIpAddress = 0;
  1177. RtlCopyMemory(&(Request->ClientHardwareAddress),
  1178. &(Context->LinkAddress->PhysicalAddress.Address),
  1179. DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH);
  1180. Request->MagicCookie = CPU_TO_NETWORK32(DHCP_MAGIC_COOKIE);
  1181. //
  1182. // Initialize the options, which come right after the request. The first
  1183. // option tells the server this is a discovery request. Options are always
  1184. // a tuple of (OptionType, LengthOfValue, Value).
  1185. //
  1186. OptionByte = (PBYTE)(Request + 1);
  1187. *OptionByte = DHCP_OPTION_DHCP_MESSAGE_TYPE;
  1188. OptionByte += 1;
  1189. *OptionByte = 1;
  1190. OptionByte += 1;
  1191. *OptionByte = DHCP_MESSAGE_DISCOVER;
  1192. OptionByte += 1;
  1193. //
  1194. // Add the parameter request list option. Five parameters are being
  1195. // requested with the offer.
  1196. //
  1197. *OptionByte = DHCP_OPTION_PARAMETER_REQUEST_LIST;
  1198. OptionByte += 1;
  1199. *OptionByte = 5;
  1200. OptionByte += 1;
  1201. *OptionByte = DHCP_OPTION_SUBNET_MASK;
  1202. OptionByte += 1;
  1203. *OptionByte = DHCP_OPTION_ROUTER;
  1204. OptionByte += 1;
  1205. *OptionByte = DHCP_OPTION_DOMAIN_NAME;
  1206. OptionByte += 1;
  1207. *OptionByte = DHCP_OPTION_DOMAIN_NAME_SERVER;
  1208. OptionByte += 1;
  1209. *OptionByte = DHCP_OPTION_IP_ADDRESS_LEASE_TIME;
  1210. OptionByte += 1;
  1211. //
  1212. // Add the end tag.
  1213. //
  1214. *OptionByte = DHCP_OPTION_END;
  1215. OptionByte += 1;
  1216. *OptionByte = 0;
  1217. OptionByte += 1;
  1218. TotalPacketSize = (UINTN)OptionByte - (UINTN)Request;
  1219. ASSERT(TotalPacketSize <= Context->ScratchPacketSize);
  1220. //
  1221. // Send off this request!
  1222. //
  1223. RtlZeroMemory(&RemoteAddress, sizeof(NETWORK_ADDRESS));
  1224. RemoteAddress.Domain = NetDomainIp4;
  1225. RemoteAddress.Address = IP4_BROADCAST_ADDRESS;
  1226. RemoteAddress.Port = DHCP_SERVER_PORT;
  1227. RtlZeroMemory(&Parameters, sizeof(SOCKET_IO_PARAMETERS));
  1228. Parameters.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
  1229. Parameters.NetworkAddress = &(RemoteAddress.NetworkAddress);
  1230. Parameters.Size = TotalPacketSize;
  1231. Status = IoSocketSendData(TRUE,
  1232. Context->Socket,
  1233. &Parameters,
  1234. Context->ScratchPacketIoBuffer);
  1235. if (!KSUCCESS(Status)) {
  1236. goto DhcpSendDiscoverEnd;
  1237. }
  1238. if (Parameters.Size != TotalPacketSize) {
  1239. Status = STATUS_DATA_LENGTH_MISMATCH;
  1240. goto DhcpSendDiscoverEnd;
  1241. }
  1242. Status = STATUS_SUCCESS;
  1243. DhcpSendDiscoverEnd:
  1244. return Status;
  1245. }
  1246. KSTATUS
  1247. NetpDhcpReceiveOffer (
  1248. PDHCP_CONTEXT Context
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. This routine receives the DHCP offer response, hopefully.
  1253. Arguments:
  1254. Context - Supplies a pointer to the DHCP context information.
  1255. Return Value:
  1256. Status code.
  1257. --*/
  1258. {
  1259. ULONG Attempts;
  1260. DHCP_REPLY Reply;
  1261. KSTATUS Status;
  1262. Attempts = 5;
  1263. while (Attempts != 0) {
  1264. Attempts -= 1;
  1265. //
  1266. // Atempt to receive a reply from the DHCP server. Quit if the request
  1267. // times out but try again for any other failure.
  1268. //
  1269. Status = NetpDhcpReceiveReply(Context, &Reply);
  1270. if (Status == STATUS_TIMEOUT) {
  1271. break;
  1272. }
  1273. if (!KSUCCESS(Status)) {
  1274. continue;
  1275. }
  1276. //
  1277. // Try again if an offer message was not received.
  1278. //
  1279. if (Reply.MessageType != DHCP_MESSAGE_OFFER) {
  1280. RtlDebugPrint("Skipping DHCP message as it wasn't an offer (%d), "
  1281. "instead it had a message type of %d.\n",
  1282. DHCP_MESSAGE_OFFER,
  1283. Reply.MessageType);
  1284. continue;
  1285. }
  1286. //
  1287. // Copy the reply to the context. This will make sure that all the
  1288. // required information is present in the reply.
  1289. //
  1290. Status = NetpDhcpCopyReplyToContext(Context, &Reply);
  1291. if (!KSUCCESS(Status)) {
  1292. continue;
  1293. }
  1294. //
  1295. // Print the offer to the debugger now that the context is filled in,
  1296. // if requested.
  1297. //
  1298. if ((NetDhcpDebugFlags & DHCP_DEBUG_FLAG_OFFER) != 0) {
  1299. RtlDebugPrint("Net: DHCP Offer\n");
  1300. NetpDhcpPrintContext(Context);
  1301. }
  1302. Status = STATUS_SUCCESS;
  1303. break;
  1304. }
  1305. return Status;
  1306. }
  1307. KSTATUS
  1308. NetpDhcpSendRequest (
  1309. PDHCP_CONTEXT Context
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. This routine sends the DHCP address request out onto the subnet.
  1314. Arguments:
  1315. Context - Supplies a pointer to the DHCP context information.
  1316. Renew - Supplies a boolean indicating whether or not this is a request to
  1317. renew a lease.
  1318. Return Value:
  1319. Status code indicating whether or not the discovery request was
  1320. successfully sent.
  1321. --*/
  1322. {
  1323. PIP4_ADDRESS Ip4Address;
  1324. PDHCP_LEASE Lease;
  1325. BOOL LockHeld;
  1326. PBYTE OptionByte;
  1327. SOCKET_IO_PARAMETERS Parameters;
  1328. IP4_ADDRESS RemoteAddress;
  1329. PDHCP_PACKET Request;
  1330. PIP4_ADDRESS RequestedIp4Address;
  1331. PIP4_ADDRESS ServerIp4Address;
  1332. KSTATUS Status;
  1333. ULONG TotalPacketSize;
  1334. ASSERT(KeGetRunLevel() == RunLevelLow);
  1335. ASSERT(Context->Lease != NULL);
  1336. Lease = Context->Lease;
  1337. LockHeld = FALSE;
  1338. Request = NULL;
  1339. //
  1340. // Initialize the DHCP discover request.
  1341. //
  1342. Request = Context->ScratchPacket;
  1343. RtlZeroMemory(Request, sizeof(DHCP_PACKET));
  1344. Request->OperationCode = DHCP_OPERATION_REQUEST;
  1345. Request->HardwareType = DHCP_HARDWARE_TYPE_ETHERNET;
  1346. Request->HardwareAddressLength = DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH;
  1347. Request->Hops = 0;
  1348. Request->TransactionIdentifier = Context->ExpectedTransactionId;
  1349. Request->Seconds = 0;
  1350. Request->Flags = 0;
  1351. Request->ClientIpAddress = 0;
  1352. //
  1353. // To renew or rebind a lease, the client IP address is set in the reqest
  1354. // header.
  1355. //
  1356. if ((Lease->State == DhcpLeaseStateRenewing) ||
  1357. (Lease->State == DhcpLeaseStateRebinding)) {
  1358. //
  1359. // Renew and rebind are trying to extend an already configured link
  1360. // address's IP address. Make sure that the link address is still
  1361. // configured before copying its data.
  1362. //
  1363. KeAcquireQueuedLock(Context->Link->QueuedLock);
  1364. LockHeld = TRUE;
  1365. if (Context->LinkAddress->Configured == FALSE) {
  1366. Status = STATUS_NO_NETWORK_CONNECTION;
  1367. goto DhcpSendRequestEnd;
  1368. }
  1369. Ip4Address = (PIP4_ADDRESS)&(Context->LinkAddress->Address);
  1370. ASSERT(Ip4Address->Domain == NetDomainIp4);
  1371. ASSERT(Ip4Address->Address != 0);
  1372. Request->ClientIpAddress = Ip4Address->Address;
  1373. KeReleaseQueuedLock(Context->Link->QueuedLock);
  1374. LockHeld = FALSE;
  1375. }
  1376. //
  1377. // The physical address of a link address entry does not change. There is
  1378. // no need to acquire the lock here.
  1379. //
  1380. RtlCopyMemory(&(Request->ClientHardwareAddress),
  1381. &(Context->LinkAddress->PhysicalAddress.Address),
  1382. DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH);
  1383. Request->MagicCookie = CPU_TO_NETWORK32(DHCP_MAGIC_COOKIE);
  1384. //
  1385. // Initialize the options, which come right after the request. The first
  1386. // option tells the server this is a request (for an address). Options are
  1387. // always a tuple of (OptionType, LengthOfValue, Value).
  1388. //
  1389. OptionByte = (PBYTE)(Request + 1);
  1390. *OptionByte = DHCP_OPTION_DHCP_MESSAGE_TYPE;
  1391. OptionByte += 1;
  1392. *OptionByte = 1;
  1393. OptionByte += 1;
  1394. *OptionByte = DHCP_MESSAGE_REQUEST;
  1395. OptionByte += 1;
  1396. //
  1397. // Add the parameter request list option. Five parameters are being
  1398. // requested. This must match the parameters requested during the
  1399. // discover message (if a discover message was sent before the request).
  1400. //
  1401. *OptionByte = DHCP_OPTION_PARAMETER_REQUEST_LIST;
  1402. OptionByte += 1;
  1403. *OptionByte = 5;
  1404. OptionByte += 1;
  1405. *OptionByte = DHCP_OPTION_SUBNET_MASK;
  1406. OptionByte += 1;
  1407. *OptionByte = DHCP_OPTION_ROUTER;
  1408. OptionByte += 1;
  1409. *OptionByte = DHCP_OPTION_DOMAIN_NAME;
  1410. OptionByte += 1;
  1411. *OptionByte = DHCP_OPTION_DOMAIN_NAME_SERVER;
  1412. OptionByte += 1;
  1413. *OptionByte = DHCP_OPTION_IP_ADDRESS_LEASE_TIME;
  1414. OptionByte += 1;
  1415. //
  1416. // The requested IP address and server identifier options must not be sent
  1417. // on a renew or rebind request.
  1418. //
  1419. if ((Lease->State != DhcpLeaseStateRenewing) &&
  1420. (Lease->State != DhcpLeaseStateRebinding)) {
  1421. //
  1422. // Add the requested address.
  1423. //
  1424. ASSERT(sizeof(ULONG) == 4);
  1425. RequestedIp4Address = (PIP4_ADDRESS)(&(Context->OfferClientAddress));
  1426. *OptionByte = DHCP_OPTION_REQUESTED_IP_ADDRESS;
  1427. OptionByte += 1;
  1428. *OptionByte = 4;
  1429. OptionByte += 1;
  1430. *((PULONG)OptionByte) = RequestedIp4Address->Address;
  1431. OptionByte += sizeof(ULONG);
  1432. //
  1433. // Add the server address.
  1434. //
  1435. ServerIp4Address = (PIP4_ADDRESS)(&(Context->OfferServerAddress));
  1436. *OptionByte = DHCP_OPTION_DHCP_SERVER;
  1437. OptionByte += 1;
  1438. *OptionByte = 4;
  1439. OptionByte += 1;
  1440. *((PULONG)OptionByte) = ServerIp4Address->Address;
  1441. OptionByte += sizeof(ULONG);
  1442. }
  1443. //
  1444. // Add the end tag.
  1445. //
  1446. *OptionByte = DHCP_OPTION_END;
  1447. OptionByte += 1;
  1448. *OptionByte = 0;
  1449. OptionByte += 1;
  1450. TotalPacketSize = (UINTN)OptionByte - (UINTN)Request;
  1451. ASSERT(TotalPacketSize <= Context->ScratchPacketSize);
  1452. //
  1453. // Record the time at which the request was sent. This will be considered
  1454. // the lease start time upon success.
  1455. //
  1456. KeGetSystemTime(&(Context->LeaseRequestTime));
  1457. //
  1458. // Send off this request! On renew, it is unicast to the server that
  1459. // initially offered the lease. Otherwise it's broadcast to let all the
  1460. // other DHCP servers that made offers know which one was selected.
  1461. //
  1462. RtlZeroMemory(&RemoteAddress, sizeof(NETWORK_ADDRESS));
  1463. RemoteAddress.Domain = NetDomainIp4;
  1464. if (Lease->State == DhcpLeaseStateRenewing) {
  1465. //
  1466. // Make sure that the link address is still configured before copying
  1467. // its data.
  1468. //
  1469. KeAcquireQueuedLock(Context->Link->QueuedLock);
  1470. LockHeld = TRUE;
  1471. if (Context->LinkAddress->Configured == FALSE) {
  1472. Status = STATUS_NO_NETWORK_CONNECTION;
  1473. goto DhcpSendRequestEnd;
  1474. }
  1475. Ip4Address = (PIP4_ADDRESS)&(Context->LinkAddress->LeaseServerAddress);
  1476. ASSERT(Ip4Address->Domain == NetDomainIp4);
  1477. ASSERT(Ip4Address->Address != 0);
  1478. RemoteAddress.Address = Ip4Address->Address;
  1479. KeReleaseQueuedLock(Context->Link->QueuedLock);
  1480. LockHeld = FALSE;
  1481. } else {
  1482. RemoteAddress.Address = IP4_BROADCAST_ADDRESS;
  1483. }
  1484. RemoteAddress.Port = DHCP_SERVER_PORT;
  1485. RtlZeroMemory(&Parameters, sizeof(SOCKET_IO_PARAMETERS));
  1486. Parameters.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
  1487. Parameters.NetworkAddress = &(RemoteAddress.NetworkAddress);
  1488. Parameters.Size = TotalPacketSize;
  1489. Status = IoSocketSendData(TRUE,
  1490. Context->Socket,
  1491. &Parameters,
  1492. Context->ScratchPacketIoBuffer);
  1493. if (!KSUCCESS(Status)) {
  1494. goto DhcpSendRequestEnd;
  1495. }
  1496. if (Parameters.Size != TotalPacketSize) {
  1497. Status = STATUS_DATA_LENGTH_MISMATCH;
  1498. goto DhcpSendRequestEnd;
  1499. }
  1500. Status = STATUS_SUCCESS;
  1501. DhcpSendRequestEnd:
  1502. if (LockHeld != FALSE) {
  1503. KeReleaseQueuedLock(Context->Link->QueuedLock);
  1504. }
  1505. return Status;
  1506. }
  1507. KSTATUS
  1508. NetpDhcpReceiveAcknowledge (
  1509. PDHCP_CONTEXT Context
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. This routine receives the acknowledgement from the DHCP server to the
  1514. request just made.
  1515. Arguments:
  1516. Context - Supplies a pointer to the DHCP context information.
  1517. Return Value:
  1518. Status code.
  1519. --*/
  1520. {
  1521. ULONG Attempts;
  1522. PIP4_ADDRESS ClientIp4Address;
  1523. DHCP_REPLY Reply;
  1524. PIP4_ADDRESS ServerIp4Address;
  1525. KSTATUS Status;
  1526. Attempts = 5;
  1527. while (Attempts != 0) {
  1528. Attempts -= 1;
  1529. //
  1530. // Atempt to receive a reply from the DHCP server. Quit if the request
  1531. // times out but try again for any other failure.
  1532. //
  1533. Status = NetpDhcpReceiveReply(Context, &Reply);
  1534. if (Status == STATUS_TIMEOUT) {
  1535. break;
  1536. }
  1537. if (!KSUCCESS(Status)) {
  1538. continue;
  1539. }
  1540. //
  1541. // Try again if an acknowledge message was not received.
  1542. //
  1543. if (Reply.MessageType != DHCP_MESSAGE_ACKNOWLEDGE) {
  1544. RtlDebugPrint("Skipping DHCP message as it wasn't an ACK (%d), "
  1545. "instead it had a message type of %d.\n",
  1546. DHCP_MESSAGE_ACKNOWLEDGE,
  1547. Reply.MessageType);
  1548. continue;
  1549. }
  1550. //
  1551. // If the DHCP lease is initializing, then an offer should have already
  1552. // been received and stored in the context. If the client or server
  1553. // addresses were provided in the acknowledgement, ensure they are the
  1554. // same as the original offer.
  1555. //
  1556. if (Context->Lease->State == DhcpLeaseStateInitialize) {
  1557. ServerIp4Address = (PIP4_ADDRESS)(&(Context->OfferServerAddress));
  1558. ClientIp4Address = (PIP4_ADDRESS)(&(Context->OfferClientAddress));
  1559. if (((Reply.ServerIpAddress != 0) &&
  1560. (Reply.ServerIpAddress != ServerIp4Address->Address)) ||
  1561. ((Reply.OfferedIpAddress != 0) &&
  1562. (Reply.OfferedIpAddress != ClientIp4Address->Address))) {
  1563. continue;
  1564. }
  1565. //
  1566. // If the lease time does not equal the offer's lease time, then
  1567. // recalculate the renewal and rebinding times if they were not
  1568. // supplied.
  1569. //
  1570. if ((Reply.LeaseTime != 0) &&
  1571. (Reply.LeaseTime != Context->LeaseTime)) {
  1572. if (Reply.RenewalTime == 0) {
  1573. Reply.RenewalTime = DHCP_GET_DEFAULT_RENEWAL_TIME(
  1574. Reply.LeaseTime);
  1575. }
  1576. if (Reply.RebindingTime == 0) {
  1577. Reply.RebindingTime = DHCP_GET_DEFAULT_REBINDING_TIME(
  1578. Reply.LeaseTime);
  1579. }
  1580. Context->LeaseTime = Reply.LeaseTime;
  1581. Context->RenewalTime = Reply.RenewalTime;
  1582. Context->RebindingTime = Reply.RebindingTime;
  1583. }
  1584. //
  1585. // For the renewal and rebinding states, the acknowledgement should
  1586. // contain the complete information for the renewal offer. Copy the
  1587. // whole reply to the context. If something is missing, the copy
  1588. // routine will fail.
  1589. //
  1590. } else {
  1591. ASSERT((Context->Lease->State == DhcpLeaseStateRenewing) ||
  1592. (Context->Lease->State == DhcpLeaseStateRebinding));
  1593. Status = NetpDhcpCopyReplyToContext(Context, &Reply);
  1594. if (!KSUCCESS(Status)) {
  1595. continue;
  1596. }
  1597. }
  1598. Status = STATUS_SUCCESS;
  1599. break;
  1600. }
  1601. return Status;
  1602. }
  1603. KSTATUS
  1604. NetpDhcpSendRelease (
  1605. PDHCP_CONTEXT Context
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine sends a release message to the DHCP server in order to release
  1610. the IP address that the server leased to it.
  1611. Arguments:
  1612. Context - Supplies a pointer to the DHCP context information.
  1613. Return Value:
  1614. Status code.
  1615. --*/
  1616. {
  1617. PIP4_ADDRESS Ip4Address;
  1618. PBYTE OptionByte;
  1619. SOCKET_IO_PARAMETERS Parameters;
  1620. IP4_ADDRESS RemoteAddress;
  1621. PDHCP_PACKET Request;
  1622. PIP4_ADDRESS ServerIp4Address;
  1623. KSTATUS Status;
  1624. ULONG TotalPacketSize;
  1625. Request = NULL;
  1626. //
  1627. // Initialize the DHCP release request.
  1628. //
  1629. Request = Context->ScratchPacket;
  1630. RtlZeroMemory(Request, sizeof(DHCP_PACKET));
  1631. Request->OperationCode = DHCP_OPERATION_REQUEST;
  1632. Request->HardwareType = DHCP_HARDWARE_TYPE_ETHERNET;
  1633. Request->HardwareAddressLength = DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH;
  1634. Request->Hops = 0;
  1635. Request->TransactionIdentifier = HlQueryTimeCounter() & MAX_ULONG;
  1636. Context->ExpectedTransactionId = Request->TransactionIdentifier;
  1637. Request->Seconds = 0;
  1638. Request->Flags = 0;
  1639. Ip4Address = (PIP4_ADDRESS)&(Context->OfferClientAddress);
  1640. ASSERT(Ip4Address->Domain == NetDomainIp4);
  1641. ASSERT(Ip4Address->Address != 0);
  1642. Request->ClientIpAddress = Ip4Address->Address;
  1643. RtlCopyMemory(&(Request->ClientHardwareAddress),
  1644. &(Context->LinkAddress->PhysicalAddress.Address),
  1645. DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH);
  1646. Request->MagicCookie = CPU_TO_NETWORK32(DHCP_MAGIC_COOKIE);
  1647. //
  1648. // Initialize the options, which come right after the request. The first
  1649. // option tells the server this is a release request. Options are always
  1650. // a tuple of (OptionType, LengthOfValue, Value).
  1651. //
  1652. OptionByte = (PBYTE)(Request + 1);
  1653. *OptionByte = DHCP_OPTION_DHCP_MESSAGE_TYPE;
  1654. OptionByte += 1;
  1655. *OptionByte = 1;
  1656. OptionByte += 1;
  1657. *OptionByte = DHCP_MESSAGE_RELEASE;
  1658. OptionByte += 1;
  1659. //
  1660. // Add the server address.
  1661. //
  1662. ServerIp4Address = (PIP4_ADDRESS)(&(Context->OfferServerAddress));
  1663. ASSERT(ServerIp4Address->Domain == NetDomainIp4);
  1664. ASSERT(ServerIp4Address->Address != 0);
  1665. *OptionByte = DHCP_OPTION_DHCP_SERVER;
  1666. OptionByte += 1;
  1667. *OptionByte = 4;
  1668. OptionByte += 1;
  1669. *((PULONG)OptionByte) = ServerIp4Address->Address;
  1670. OptionByte += sizeof(ULONG);
  1671. //
  1672. // Add the end tag.
  1673. //
  1674. *OptionByte = DHCP_OPTION_END;
  1675. OptionByte += 1;
  1676. *OptionByte = 0;
  1677. OptionByte += 1;
  1678. TotalPacketSize = (UINTN)OptionByte - (UINTN)Request;
  1679. ASSERT(TotalPacketSize <= Context->ScratchPacketSize);
  1680. //
  1681. // Send off this request!
  1682. //
  1683. RtlZeroMemory(&RemoteAddress, sizeof(NETWORK_ADDRESS));
  1684. RemoteAddress.Domain = NetDomainIp4;
  1685. Ip4Address = (PIP4_ADDRESS)&(Context->OfferServerAddress);
  1686. ASSERT(Ip4Address->Domain == NetDomainIp4);
  1687. ASSERT(Ip4Address->Address != 0);
  1688. RemoteAddress.Address = Ip4Address->Address;
  1689. RemoteAddress.Port = DHCP_SERVER_PORT;
  1690. RtlZeroMemory(&Parameters, sizeof(SOCKET_IO_PARAMETERS));
  1691. Parameters.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
  1692. Parameters.NetworkAddress = &(RemoteAddress.NetworkAddress);
  1693. Parameters.Size = TotalPacketSize;
  1694. Status = IoSocketSendData(TRUE,
  1695. Context->Socket,
  1696. &Parameters,
  1697. Context->ScratchPacketIoBuffer);
  1698. if (!KSUCCESS(Status)) {
  1699. goto DhcpSendDiscoverEnd;
  1700. }
  1701. if (Parameters.Size != TotalPacketSize) {
  1702. Status = STATUS_DATA_LENGTH_MISMATCH;
  1703. goto DhcpSendDiscoverEnd;
  1704. }
  1705. Status = STATUS_SUCCESS;
  1706. DhcpSendDiscoverEnd:
  1707. return Status;
  1708. }
  1709. KSTATUS
  1710. NetpDhcpReceiveReply (
  1711. PDHCP_CONTEXT Context,
  1712. PDHCP_REPLY Reply
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This routine attempts to receive a replay from the DHCP server for either
  1717. an offer or an acknowledge packet.
  1718. Arguments:
  1719. Context - Supplies a pointer to the DHCP context information.
  1720. Reply - Supplies a pointer to the DHCP reply context that is to be filled
  1721. in by this routine.
  1722. Return Value:
  1723. Status code.
  1724. --*/
  1725. {
  1726. ULONG AddressOffset;
  1727. ULONG Offset;
  1728. BYTE OptionByte;
  1729. PBYTE OptionBytePointer;
  1730. BYTE OptionLength;
  1731. ULONGLONG PacketSize;
  1732. SOCKET_IO_PARAMETERS Parameters;
  1733. ULONG RebindingTime;
  1734. PDHCP_PACKET Response;
  1735. ULONG RouterIp;
  1736. NETWORK_ADDRESS ServerAddress;
  1737. ULONG ServerIp;
  1738. KSTATUS Status;
  1739. Response = Context->ScratchPacket;
  1740. OptionBytePointer = (PUCHAR)Response;
  1741. RtlZeroMemory(&Parameters, sizeof(SOCKET_IO_PARAMETERS));
  1742. Parameters.TimeoutInMilliseconds = DHCP_ACKNOWLEDGE_TIMEOUT;
  1743. Parameters.NetworkAddress = &ServerAddress;
  1744. Parameters.Size = Context->ScratchPacketSize;
  1745. Status = IoSocketReceiveData(TRUE,
  1746. Context->Socket,
  1747. &Parameters,
  1748. Context->ScratchPacketIoBuffer);
  1749. if (Status == STATUS_TIMEOUT) {
  1750. goto DhcpReceiveReplyEnd;
  1751. }
  1752. if (!KSUCCESS(Status)) {
  1753. RtlDebugPrint("NetpDhcpReceiveReply skipping packet because receive "
  1754. "status was %d.\n",
  1755. Status);
  1756. goto DhcpReceiveReplyEnd;
  1757. }
  1758. PacketSize = Parameters.Size;
  1759. //
  1760. // Validate some basic attributes about the packet.
  1761. //
  1762. if (PacketSize < sizeof(DHCP_PACKET)) {
  1763. RtlDebugPrint("DHCP ack packet too small. Was %d bytes, should "
  1764. "have been at least %d bytes.\n",
  1765. PacketSize,
  1766. sizeof(DHCP_PACKET));
  1767. Status = STATUS_DATA_LENGTH_MISMATCH;
  1768. goto DhcpReceiveReplyEnd;
  1769. }
  1770. if (Response->OperationCode != DHCP_OPERATION_REPLY) {
  1771. Status = STATUS_UNSUCCESSFUL;
  1772. goto DhcpReceiveReplyEnd;
  1773. }
  1774. if ((Response->HardwareType != DHCP_HARDWARE_TYPE_ETHERNET) ||
  1775. (Response->HardwareAddressLength !=
  1776. DHCP_ETHERNET_HARDWARE_ADDRESS_LENGTH)) {
  1777. RtlDebugPrint("DHCP packet skipped because hardware type or "
  1778. "length didn't match standard ethernet.\n");
  1779. Status = STATUS_UNSUCCESSFUL;
  1780. goto DhcpReceiveReplyEnd;
  1781. }
  1782. if (NETWORK_TO_CPU32(Response->MagicCookie) != DHCP_MAGIC_COOKIE) {
  1783. RtlDebugPrint("DHCP packet skipped because the magic cookie was "
  1784. "wrong.\n");
  1785. Status = STATUS_UNSUCCESSFUL;
  1786. goto DhcpReceiveReplyEnd;
  1787. }
  1788. //
  1789. // Quietly skip packets not directed at this request.
  1790. //
  1791. if (Response->TransactionIdentifier != Context->ExpectedTransactionId) {
  1792. Status = STATUS_UNSUCCESSFUL;
  1793. goto DhcpReceiveReplyEnd;
  1794. }
  1795. RtlZeroMemory(Reply, sizeof(DHCP_REPLY));
  1796. Reply->ServerIpAddress = Response->ServerIpAddress;
  1797. Reply->OfferedIpAddress = Response->YourIpAddress;
  1798. //
  1799. // Parse the options.
  1800. //
  1801. Offset = sizeof(DHCP_PACKET);
  1802. while (Offset < PacketSize) {
  1803. OptionByte = OptionBytePointer[Offset];
  1804. Offset += 1;
  1805. //
  1806. // Skip padding.
  1807. //
  1808. if (OptionByte == DHCP_OPTION_PAD) {
  1809. continue;
  1810. }
  1811. //
  1812. // Stop if the end is reached.
  1813. //
  1814. if (OptionByte == DHCP_OPTION_END) {
  1815. break;
  1816. }
  1817. //
  1818. // Get the length of the option.
  1819. //
  1820. if (Offset >= PacketSize) {
  1821. break;
  1822. }
  1823. OptionLength = OptionBytePointer[Offset];
  1824. Offset += 1;
  1825. //
  1826. // Stop if the entire option value cannot be retrieved.
  1827. //
  1828. if (Offset + OptionLength > PacketSize) {
  1829. break;
  1830. }
  1831. //
  1832. // Parse the known options, starting with the message type.
  1833. //
  1834. if (OptionByte == DHCP_OPTION_DHCP_MESSAGE_TYPE) {
  1835. Reply->MessageType = OptionBytePointer[Offset];
  1836. } else if (OptionByte == DHCP_OPTION_DHCP_SERVER) {
  1837. if (OptionLength == 4) {
  1838. ServerIp = *((PULONG)(&(OptionBytePointer[Offset])));
  1839. Reply->ServerIpAddress = ServerIp;
  1840. }
  1841. } else if (OptionByte == DHCP_OPTION_SUBNET_MASK) {
  1842. if (OptionLength == 4) {
  1843. Reply->SubnetMask = *((PULONG)(&(OptionBytePointer[Offset])));
  1844. }
  1845. } else if (OptionByte == DHCP_OPTION_ROUTER) {
  1846. if (OptionLength == 4) {
  1847. RouterIp = *((PULONG)(&(OptionBytePointer[Offset])));
  1848. Reply->RouterIpAddress = RouterIp;
  1849. }
  1850. } else if (OptionByte == DHCP_OPTION_DOMAIN_NAME_SERVER) {
  1851. AddressOffset = Offset;
  1852. while (AddressOffset + 4 <= Offset + OptionLength) {
  1853. Reply->DomainNameServer[Reply->DomainNameServerCount] =
  1854. *((PULONG)(&(OptionBytePointer[AddressOffset])));
  1855. AddressOffset += 4;
  1856. Reply->DomainNameServerCount += 1;
  1857. if (Reply->DomainNameServerCount == DHCP_MAX_DNS_SERVERS) {
  1858. break;
  1859. }
  1860. }
  1861. } else if (OptionByte == DHCP_OPTION_IP_ADDRESS_LEASE_TIME) {
  1862. if (OptionLength == 4) {
  1863. Reply->LeaseTime = *((PULONG)(&(OptionBytePointer[Offset])));
  1864. Reply->LeaseTime = NETWORK_TO_CPU32(Reply->LeaseTime);
  1865. }
  1866. } else if (OptionByte == DHCP_OPTION_RENEWAL_TIME) {
  1867. if (OptionLength == 4) {
  1868. Reply->RenewalTime = *((PULONG)(&(OptionBytePointer[Offset])));
  1869. Reply->RenewalTime = NETWORK_TO_CPU32(Reply->RenewalTime);
  1870. }
  1871. } else if (OptionByte == DHCP_OPTION_REBINDING_TIME) {
  1872. if (OptionLength == 4) {
  1873. RebindingTime = *((PULONG)(&(OptionBytePointer[Offset])));
  1874. Reply->RebindingTime = NETWORK_TO_CPU32(RebindingTime);
  1875. }
  1876. }
  1877. //
  1878. // Skip over the option length.
  1879. //
  1880. Offset += OptionLength;
  1881. }
  1882. ASSERT(Status == STATUS_SUCCESS);
  1883. //
  1884. // Set the override renewal and rebinding times if enabled.
  1885. //
  1886. if (NetDhcpDebugOverrideRenewal != FALSE) {
  1887. Reply->RenewalTime = NetDhcpDebugRenewalTime;
  1888. Reply->RebindingTime = NetDhcpDebugRebindingTime;
  1889. }
  1890. DhcpReceiveReplyEnd:
  1891. return Status;
  1892. }
  1893. PDHCP_CONTEXT
  1894. NetpDhcpCreateContext (
  1895. PNET_LINK Link,
  1896. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  1897. PDHCP_LEASE Lease
  1898. )
  1899. /*++
  1900. Routine Description:
  1901. This routine creates a DHCP context.
  1902. Arguments:
  1903. Link - Supplies a pointer to the network link for the DHCP context.
  1904. LinkAddress - Supplies a pointer to the network link address for the DHCP
  1905. context.
  1906. Lease - Supplies an optional pointer to a DHCP lease to be associated with
  1907. the context.
  1908. Return Value:
  1909. Returns a pointer to the newly allocated DHCP context on success, or NULL
  1910. on failure.
  1911. --*/
  1912. {
  1913. PDHCP_CONTEXT Context;
  1914. Context = MmAllocatePagedPool(sizeof(DHCP_CONTEXT), DHCP_ALLOCATION_TAG);
  1915. if (Context == NULL) {
  1916. return NULL;
  1917. }
  1918. RtlZeroMemory(Context, sizeof(DHCP_CONTEXT));
  1919. NetLinkAddReference(Link);
  1920. Context->Link = Link;
  1921. Context->LinkAddress = LinkAddress;
  1922. if (Lease != NULL) {
  1923. NetpDhcpLeaseAddReference(Lease);
  1924. Context->Lease = Lease;
  1925. }
  1926. return Context;
  1927. }
  1928. VOID
  1929. NetpDhcpDestroyContext (
  1930. PDHCP_CONTEXT Context
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. This routine destroys the given DHCP context.
  1935. Arguments:
  1936. Context - Supplies a pointer to the DHCP context to destroy.
  1937. Return Value:
  1938. None.
  1939. --*/
  1940. {
  1941. if (Context->Socket != NULL) {
  1942. IoClose(Context->Socket);
  1943. }
  1944. if (Context->ScratchPacketIoBuffer != NULL) {
  1945. MmFreeIoBuffer(Context->ScratchPacketIoBuffer);
  1946. }
  1947. if (Context->ScratchPacket != NULL) {
  1948. MmFreePagedPool(Context->ScratchPacket);
  1949. }
  1950. ASSERT(Context->Link != NULL);
  1951. NetLinkReleaseReference(Context->Link);
  1952. if (Context->Lease != NULL) {
  1953. NetpDhcpLeaseReleaseReference(Context->Lease);
  1954. }
  1955. MmFreePagedPool(Context);
  1956. return;
  1957. }
  1958. PDHCP_LEASE
  1959. NetpDhcpCreateLease (
  1960. VOID
  1961. )
  1962. /*++
  1963. Routine Description:
  1964. This routine creates an the context for a DHCP lease.
  1965. Arguments:
  1966. None.
  1967. Return Value:
  1968. Returns a pointer to a DHCP lease context on success, or NULL on failure.
  1969. --*/
  1970. {
  1971. PDHCP_LEASE NewLease;
  1972. KSTATUS Status;
  1973. NewLease = MmAllocateNonPagedPool(sizeof(DHCP_LEASE), DHCP_ALLOCATION_TAG);
  1974. if (NewLease == NULL) {
  1975. Status = STATUS_INSUFFICIENT_RESOURCES;
  1976. goto DhcpCreateAssignmentContextEnd;
  1977. }
  1978. RtlZeroMemory(NewLease, sizeof(DHCP_LEASE));
  1979. NewLease->ReferenceCount = 1;
  1980. NewLease->Timer = KeCreateTimer(DHCP_ALLOCATION_TAG);
  1981. if (NewLease->Timer == NULL) {
  1982. Status = STATUS_INSUFFICIENT_RESOURCES;
  1983. goto DhcpCreateAssignmentContextEnd;
  1984. }
  1985. NewLease->Dpc = KeCreateDpc(NetpDhcpLeaseDpcRoutine, NewLease);
  1986. if (NewLease->Dpc == NULL) {
  1987. Status = STATUS_INSUFFICIENT_RESOURCES;
  1988. goto DhcpCreateAssignmentContextEnd;
  1989. }
  1990. NewLease->WorkItem = KeCreateWorkItem(NULL,
  1991. WorkPriorityNormal,
  1992. NetpDhcpLeaseWorkRoutine,
  1993. NewLease,
  1994. DHCP_ALLOCATION_TAG);
  1995. if (NewLease->WorkItem == NULL) {
  1996. Status = STATUS_INSUFFICIENT_RESOURCES;
  1997. goto DhcpCreateAssignmentContextEnd;
  1998. }
  1999. Status = STATUS_SUCCESS;
  2000. DhcpCreateAssignmentContextEnd:
  2001. if (!KSUCCESS(Status)) {
  2002. if (NewLease != NULL) {
  2003. NetpDhcpDestroyLease(NewLease);
  2004. NewLease = NULL;
  2005. }
  2006. }
  2007. return NewLease;
  2008. }
  2009. VOID
  2010. NetpDhcpLeaseAddReference (
  2011. PDHCP_LEASE Lease
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. This routine increases the reference count on a DHCP lease.
  2016. Arguments:
  2017. Lease - Supplies a pointer to the DHCP lease whose reference count should
  2018. be incremented.
  2019. Return Value:
  2020. None.
  2021. --*/
  2022. {
  2023. ULONG OldReferenceCount;
  2024. OldReferenceCount = RtlAtomicAdd32(&(Lease->ReferenceCount), 1);
  2025. ASSERT((OldReferenceCount != 0) & (OldReferenceCount < 0x20000000));
  2026. return;
  2027. }
  2028. VOID
  2029. NetpDhcpLeaseReleaseReference (
  2030. PDHCP_LEASE Lease
  2031. )
  2032. /*++
  2033. Routine Description:
  2034. This routine decreases the reference count of a DHCP lease, and destroys
  2035. the lease if the reference count drops to zero.
  2036. Arguments:
  2037. Lease - Supplies a pointer to the DHCP lease whose reference count should
  2038. be decremented.
  2039. Return Value:
  2040. None.
  2041. --*/
  2042. {
  2043. ULONG OldReferenceCount;
  2044. OldReferenceCount = RtlAtomicAdd32(&(Lease->ReferenceCount), -1);
  2045. ASSERT(OldReferenceCount != 0);
  2046. if (OldReferenceCount == 1) {
  2047. NetpDhcpDestroyLease(Lease);
  2048. }
  2049. return;
  2050. }
  2051. PDHCP_LEASE
  2052. NetpDhcpFindLease (
  2053. PNET_LINK Link,
  2054. PNET_LINK_ADDRESS_ENTRY LinkAddress
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. This routine attemps to find an existing lease for the given link and link
  2059. address. If a lease is found, a reference is added to the lease.
  2060. Arguments:
  2061. Link - Supplies a pointer to a network link.
  2062. LinkAddress - Supplies a pointer to a network link address.
  2063. Return Value:
  2064. Returns a pointer to the DHCP lease that exists for the given link and link
  2065. address, or NULL if no such lease exists.
  2066. --*/
  2067. {
  2068. PLIST_ENTRY CurrentEntry;
  2069. PDHCP_LEASE CurrentLease;
  2070. PDHCP_LEASE FoundLease;
  2071. FoundLease = NULL;
  2072. KeAcquireSpinLock(&NetDhcpLeaseListLock);
  2073. CurrentEntry = NetDhcpLeaseListHead.Next;
  2074. while (CurrentEntry != &(NetDhcpLeaseListHead)) {
  2075. CurrentLease = LIST_VALUE(CurrentEntry, DHCP_LEASE, ListEntry);
  2076. if ((CurrentLease->Link == Link) &&
  2077. (CurrentLease->LinkAddress == LinkAddress)) {
  2078. NetpDhcpLeaseAddReference(CurrentLease);
  2079. FoundLease = CurrentLease;
  2080. break;
  2081. }
  2082. CurrentEntry = CurrentEntry->Next;
  2083. }
  2084. KeReleaseSpinLock(&NetDhcpLeaseListLock);
  2085. return FoundLease;
  2086. }
  2087. VOID
  2088. NetpDhcpDestroyLease (
  2089. PDHCP_LEASE Lease
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. This routine destroys a DHCP lease context.
  2094. Arguments:
  2095. Lease - Supplies a pointer to a DHCP lease.
  2096. Return Value:
  2097. None.
  2098. --*/
  2099. {
  2100. ASSERT(Lease->ListEntry.Next == NULL);
  2101. if (Lease->Link != NULL) {
  2102. NetLinkReleaseReference(Lease->Link);
  2103. }
  2104. if (Lease->Timer != NULL) {
  2105. KeDestroyTimer(Lease->Timer);
  2106. }
  2107. if (Lease->Dpc != NULL) {
  2108. KeDestroyDpc(Lease->Dpc);
  2109. }
  2110. if (Lease->WorkItem != NULL) {
  2111. KeDestroyWorkItem(Lease->WorkItem);
  2112. }
  2113. MmFreeNonPagedPool(Lease);
  2114. return;
  2115. }
  2116. VOID
  2117. NetpDhcpQueueLeaseExtension (
  2118. PDHCP_LEASE Lease
  2119. )
  2120. /*++
  2121. Routine Description:
  2122. This routine queues the lease timer to attempt a lease extension. It
  2123. determines the correct duration for the timer.
  2124. Arguments:
  2125. Lease - Supplies a pointer to the lease that needs its timer queued.
  2126. Return Value:
  2127. None.
  2128. --*/
  2129. {
  2130. SYSTEM_TIME CurrentSystemTime;
  2131. ULONGLONG DueTime;
  2132. LONGLONG ElapsedLeaseTime;
  2133. ULONGLONG StateChangeTime;
  2134. KSTATUS Status;
  2135. ULONGLONG TimerDuration;
  2136. ULONGLONG TimeToStateChange;
  2137. if (Lease->State == DhcpLeaseStateBound) {
  2138. ASSERT(Lease->RenewalTime != 0);
  2139. TimerDuration = Lease->RenewalTime;
  2140. } else {
  2141. KeGetSystemTime(&CurrentSystemTime);
  2142. ElapsedLeaseTime = CurrentSystemTime.Seconds -
  2143. Lease->LinkAddress->LeaseStartTime.Seconds;
  2144. ASSERT(ElapsedLeaseTime >= 0);
  2145. //
  2146. // Determine the time of the next state change.
  2147. //
  2148. if (Lease->State == DhcpLeaseStateRenewing) {
  2149. StateChangeTime = Lease->RebindingTime;
  2150. } else {
  2151. ASSERT(Lease->State == DhcpLeaseStateRebinding);
  2152. StateChangeTime = Lease->LeaseTime;
  2153. }
  2154. //
  2155. // Set the time for half the time until the next state change. If
  2156. // that results in a timer duration that is less than the minimum,
  2157. // just schedule the timer for the next state change time.
  2158. //
  2159. TimerDuration = 0;
  2160. if (StateChangeTime > ElapsedLeaseTime) {
  2161. TimeToStateChange = StateChangeTime - ElapsedLeaseTime;
  2162. TimerDuration = TimeToStateChange >> 1;
  2163. if (TimerDuration < DHCP_TIMER_DURATION_MINIMUM) {
  2164. TimerDuration = TimeToStateChange;
  2165. }
  2166. }
  2167. }
  2168. TimerDuration *= MICROSECONDS_PER_SECOND;
  2169. TimerDuration = KeConvertMicrosecondsToTimeTicks(TimerDuration);
  2170. DueTime = HlQueryTimeCounter() + TimerDuration;
  2171. Status = KeQueueTimer(Lease->Timer,
  2172. TimerQueueSoft,
  2173. DueTime,
  2174. 0,
  2175. 0,
  2176. Lease->Dpc);
  2177. ASSERT(KSUCCESS(Status));
  2178. return;
  2179. }
  2180. VOID
  2181. NetpDhcpLeaseDpcRoutine (
  2182. PDPC Dpc
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. This routine implements the DPC routine that fires when a lease timer
  2187. expires. It queues the work item.
  2188. Arguments:
  2189. Dpc - Supplies a pointer to the DPC that is running.
  2190. Return Value:
  2191. None.
  2192. --*/
  2193. {
  2194. PDHCP_LEASE Lease;
  2195. Lease = (PDHCP_LEASE)Dpc->UserData;
  2196. KeQueueWorkItem(Lease->WorkItem);
  2197. return;
  2198. }
  2199. VOID
  2200. NetpDhcpLeaseWorkRoutine (
  2201. PVOID Parameter
  2202. )
  2203. /*++
  2204. Routine Description:
  2205. This routine implements the lease timer expiration work routine.
  2206. Arguments:
  2207. Parameter - Supplies a pointer to a lease context.
  2208. Return Value:
  2209. None.
  2210. --*/
  2211. {
  2212. SYSTEM_TIME CurrentSystemTime;
  2213. LONGLONG ElapsedLeaseTime;
  2214. PDHCP_LEASE Lease;
  2215. BOOL LinkUp;
  2216. KSTATUS Status;
  2217. Lease = (PDHCP_LEASE)Parameter;
  2218. ASSERT(Lease->ReferenceCount >= 1);
  2219. //
  2220. // If the link is down then do not continue.
  2221. //
  2222. NetGetLinkState(Lease->Link, &LinkUp, NULL);
  2223. if (LinkUp == FALSE) {
  2224. return;
  2225. }
  2226. //
  2227. // Determine the current state based on the time.
  2228. //
  2229. KeGetSystemTime(&CurrentSystemTime);
  2230. ElapsedLeaseTime = CurrentSystemTime.Seconds -
  2231. Lease->LinkAddress->LeaseStartTime.Seconds;
  2232. //
  2233. // If the elapsed time is greater than the lease time, then move back to
  2234. // the initialize phase.
  2235. //
  2236. if (ElapsedLeaseTime >= Lease->LeaseTime) {
  2237. Lease->State = DhcpLeaseStateInitialize;
  2238. //
  2239. // If the elapsed time is greater than or equal to the rebinding time,
  2240. // then the lease is in the rebinding state.
  2241. //
  2242. } else if (ElapsedLeaseTime >= Lease->RebindingTime) {
  2243. Lease->State = DhcpLeaseStateRebinding;
  2244. //
  2245. // Otherwise, even if the elapsed time is less than the renewal time, move
  2246. // the lease to the renewal state.
  2247. //
  2248. } else {
  2249. Lease->State = DhcpLeaseStateRenewing;
  2250. }
  2251. //
  2252. // If the lease is back in the initialization state, then the lease
  2253. // expired. Try to re-initialize the address. Note that the lease cannot be
  2254. // destroyed in its own work-item. The re-assignment process will handle
  2255. // destroying the lease.
  2256. //
  2257. if (Lease->State == DhcpLeaseStateInitialize) {
  2258. Status = NetpDhcpBeginAssignment(Lease->Link, Lease->LinkAddress);
  2259. if (!KSUCCESS(Status)) {
  2260. //
  2261. // TODO: Handle failed DHCP.
  2262. //
  2263. ASSERT(FALSE);
  2264. }
  2265. //
  2266. // Otherwise schedule work to try to renew (or rebind) the lease. If this
  2267. // fails, try again later.
  2268. //
  2269. } else {
  2270. Status = NetpDhcpBeginLeaseExtension(Lease);
  2271. if (!KSUCCESS(Status)) {
  2272. NetpDhcpQueueLeaseExtension(Lease);
  2273. }
  2274. }
  2275. return;
  2276. }
  2277. KSTATUS
  2278. NetpDhcpCopyReplyToContext (
  2279. PDHCP_CONTEXT Context,
  2280. PDHCP_REPLY Reply
  2281. )
  2282. /*++
  2283. Routine Description:
  2284. This routine copies the state from the given reply into the context. It
  2285. makes sure that all the necessary state is present in the reply.
  2286. Arguments:
  2287. Context - Supplies a pointer to the DHCP context information.
  2288. Reply - Supplies a pointer to the DHCP reply context that will be copied to
  2289. the DHCP context.
  2290. Return Value:
  2291. Status code.
  2292. --*/
  2293. {
  2294. ULONG AddressIndex;
  2295. PIP4_ADDRESS Ip4Address;
  2296. KSTATUS Status;
  2297. if ((Reply->ServerIpAddress == 0) ||
  2298. (Reply->OfferedIpAddress == 0) ||
  2299. (Reply->RouterIpAddress == 0) ||
  2300. (Reply->SubnetMask == 0) ||
  2301. (Reply->DomainNameServerCount == 0) ||
  2302. (Reply->LeaseTime == 0)) {
  2303. RtlDebugPrint("DHCP: A required parameter was missing from the "
  2304. "reply:\n ServerIp: 0x%x\n OfferedIpAddress: 0x%x,\n "
  2305. "Router: 0x%x\n SubnetMask: 0x%x\n "
  2306. "DomainNameServerCount: 0x%x\n LeaseTime: 0x%x\n",
  2307. Reply->ServerIpAddress,
  2308. Reply->OfferedIpAddress,
  2309. Reply->RouterIpAddress,
  2310. Reply->SubnetMask,
  2311. Reply->DomainNameServerCount,
  2312. Reply->LeaseTime);
  2313. Status = STATUS_INVALID_PARAMETER;
  2314. goto DhcpCopyReplyToContextEnd;
  2315. }
  2316. //
  2317. // Fill out the network address structures.
  2318. //
  2319. Ip4Address = (PIP4_ADDRESS)(&(Context->OfferClientAddress));
  2320. Ip4Address->Domain = NetDomainIp4;
  2321. Ip4Address->Address = Reply->OfferedIpAddress;
  2322. Ip4Address = (PIP4_ADDRESS)(&(Context->OfferSubnetMask));
  2323. Ip4Address->Domain = NetDomainIp4;
  2324. Ip4Address->Address = Reply->SubnetMask;
  2325. Ip4Address = (PIP4_ADDRESS)(&(Context->OfferServerAddress));
  2326. Ip4Address->Domain = NetDomainIp4;
  2327. Ip4Address->Address = Reply->ServerIpAddress;
  2328. Ip4Address = (PIP4_ADDRESS)(&(Context->OfferRouter));
  2329. Ip4Address->Domain = NetDomainIp4;
  2330. Ip4Address->Address = Reply->RouterIpAddress;
  2331. Context->OfferDnsAddressCount = Reply->DomainNameServerCount;
  2332. for (AddressIndex = 0;
  2333. AddressIndex < Reply->DomainNameServerCount;
  2334. AddressIndex += 1) {
  2335. Ip4Address =
  2336. (PIP4_ADDRESS)(&(Context->OfferDnsAddress[AddressIndex]));
  2337. Ip4Address->Domain = NetDomainIp4;
  2338. Ip4Address->Address = Reply->DomainNameServer[AddressIndex];
  2339. }
  2340. //
  2341. // Copy the lease time information.
  2342. //
  2343. Context->LeaseTime = Reply->LeaseTime;
  2344. if (Reply->RenewalTime == 0) {
  2345. Reply->RenewalTime = DHCP_GET_DEFAULT_RENEWAL_TIME(Reply->LeaseTime);
  2346. }
  2347. Context->RenewalTime = Reply->RenewalTime;
  2348. if (Reply->RebindingTime == 0) {
  2349. Reply->RebindingTime = DHCP_GET_DEFAULT_REBINDING_TIME(
  2350. Reply->LeaseTime);
  2351. }
  2352. Context->RebindingTime = Reply->RebindingTime;
  2353. Status = STATUS_SUCCESS;
  2354. DhcpCopyReplyToContextEnd:
  2355. return Status;
  2356. }
  2357. VOID
  2358. NetpDhcpPrintContext (
  2359. PDHCP_CONTEXT Context
  2360. )
  2361. /*++
  2362. Routine Description:
  2363. This routine prints out the IP address and lease time information for a
  2364. DHCP context.
  2365. Arguments:
  2366. Context - Supplies a pointer to the DHCP context information.
  2367. Return Value:
  2368. None.
  2369. --*/
  2370. {
  2371. RtlDebugPrint("%20s: %d.%d.%d.%d\n"
  2372. "%20s: %d.%d.%d.%d\n"
  2373. "%20s: %d.%d.%d.%d\n"
  2374. "%20s: %d.%d.%d.%d\n"
  2375. "%20s: %d hours.\n",
  2376. "Server IP",
  2377. (UCHAR)Context->OfferServerAddress.Address[0],
  2378. (UCHAR)(Context->OfferServerAddress.Address[0] >> 8),
  2379. (UCHAR)(Context->OfferServerAddress.Address[0] >> 16),
  2380. (UCHAR)(Context->OfferServerAddress.Address[0] >> 24),
  2381. "Offered IP",
  2382. (UCHAR)Context->OfferClientAddress.Address[0],
  2383. (UCHAR)(Context->OfferClientAddress.Address[0] >> 8),
  2384. (UCHAR)(Context->OfferClientAddress.Address[0] >> 16),
  2385. (UCHAR)(Context->OfferClientAddress.Address[0] >> 24),
  2386. "Router IP",
  2387. (UCHAR)Context->OfferRouter.Address[0],
  2388. (UCHAR)(Context->OfferRouter.Address[0] >> 8),
  2389. (UCHAR)(Context->OfferRouter.Address[0] >> 16),
  2390. (UCHAR)(Context->OfferRouter.Address[0] >> 24),
  2391. "DNS Server IP",
  2392. (UCHAR)Context->OfferDnsAddress[0].Address[0],
  2393. (UCHAR)(Context->OfferDnsAddress[0].Address[0] >> 8),
  2394. (UCHAR)(Context->OfferDnsAddress[0].Address[0] >> 16),
  2395. (UCHAR)(Context->OfferDnsAddress[0].Address[0] >> 24),
  2396. "Lease Time",
  2397. Context->LeaseTime / 3600);
  2398. return;
  2399. }