Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3509 lines
106 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. dhcp.c
  5. Abstract:
  6. This file contains specific to NT dhcp service.
  7. Author:
  8. Madan Appiah (madana) 7-Dec-1993.
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include <optchg.h>
  15. #define GLOBAL_DATA_ALLOCATE
  16. #include "dhcpglobal.h"
  17. #include <dhcploc.h>
  18. #include <dhcppro.h>
  19. #include <lmsname.h>
  20. #include <align.h>
  21. #include <ipexport.h>
  22. #include <dnsapi.h>
  23. #include <iphlpapi.h>
  24. #include <apiimpl.h>
  25. #include <ntlsa.h>
  26. #include <ntddndis.h>
  27. #include "nlanotif.h"
  28. extern
  29. DWORD
  30. MadcapInitGlobalData(VOID);
  31. extern
  32. VOID
  33. MadcapCleanupGlobalData(VOID);
  34. BOOL DhcpGlobalServiceRunning = FALSE;
  35. HANDLE DhcpGlobalMediaSenseHandle = NULL;
  36. HANDLE DhcpLsaDnsDomChangeNotifyHandle = NULL;
  37. BOOL Initialized = FALSE;
  38. //
  39. // local protos
  40. //
  41. DWORD
  42. DhcpInitMediaSense(
  43. VOID
  44. );
  45. VOID
  46. MediaSenseDetectionLoop(
  47. VOID
  48. );
  49. DWORD
  50. ProcessAdapterBindingEvent(
  51. LPWSTR adapterName,
  52. DWORD ipInterfaceContext,
  53. IP_STATUS mediaStatus
  54. );
  55. DWORD
  56. ProcessMediaSenseEvent(
  57. LPWSTR adapterName,
  58. DWORD ipInterfaceContext,
  59. IP_STATUS mediaStatus
  60. );
  61. DWORD
  62. DhcpInitGlobalData(
  63. VOID
  64. );
  65. VOID
  66. DhcpCleanupGlobalData(
  67. VOID
  68. );
  69. CHAR DhcpGlobalHostNameBuf[sizeof(WCHAR)*(MAX_COMPUTERNAME_LENGTH+300)];
  70. WCHAR DhcpGlobalHostNameBufW[MAX_COMPUTERNAME_LENGTH+300];
  71. VOID __inline
  72. CancelRenew (
  73. PDHCP_CONTEXT DhcpContext
  74. )
  75. {
  76. if (DhcpContext->CancelEvent != WSA_INVALID_EVENT) {
  77. WSASetEvent(DhcpContext->CancelEvent);
  78. }
  79. }
  80. VOID
  81. CancelAllRenew (
  82. VOID
  83. )
  84. {
  85. PLIST_ENTRY listEntry = NULL;
  86. PDHCP_CONTEXT dhcpContext = NULL;
  87. listEntry = DhcpGlobalNICList.Flink;
  88. while ( listEntry != &DhcpGlobalNICList ) {
  89. dhcpContext = CONTAINING_RECORD( listEntry, DHCP_CONTEXT, NicListEntry );
  90. CancelRenew (dhcpContext);
  91. listEntry = listEntry->Flink;
  92. }
  93. }
  94. BOOLEAN
  95. DhcpClientDllInit (
  96. IN PVOID DllHandle,
  97. IN ULONG Reason,
  98. IN PCONTEXT Context OPTIONAL
  99. )
  100. /*++
  101. Routine Description:
  102. This is the DLL initialization routine for dhcpcsvc.dll.
  103. Arguments:
  104. Standard.
  105. Return Value:
  106. TRUE iff initialization succeeded.
  107. --*/
  108. {
  109. DWORD Error = ERROR_SUCCESS;
  110. BOOL BoolError;
  111. DWORD Length;
  112. UNREFERENCED_PARAMETER(DllHandle); // avoid compiler warnings
  113. UNREFERENCED_PARAMETER(Context); // avoid compiler warnings
  114. //
  115. // Handle attaching netlogon.dll to a new process.
  116. //
  117. if (Reason == DLL_PROCESS_ATTACH) {
  118. DhcpGlobalMessageFileHandle = DllHandle;
  119. if ( !DisableThreadLibraryCalls( DllHandle ) ) {
  120. return( FALSE );
  121. }
  122. DhcpGlobalWinSockInitialized = FALSE;
  123. Error = DhcpInitGlobalData();
  124. if( ERROR_SUCCESS != Error ) return FALSE;
  125. Error = DhcpInitializeParamChangeRequests();
  126. if( ERROR_SUCCESS != Error ) return FALSE;
  127. } else if (Reason == DLL_PROCESS_DETACH) {
  128. //
  129. // Handle detaching dhcpcsvc.dll from a process.
  130. //
  131. DhcpCleanupGlobalData();
  132. DhcpGlobalMessageFileHandle = NULL;
  133. }
  134. return( TRUE );
  135. }
  136. DWORD
  137. UpdateStatus(
  138. VOID
  139. )
  140. /*++
  141. Routine Description:
  142. This function updates the dhcp service status with the Service
  143. Controller.
  144. Arguments:
  145. None.
  146. Return Value:
  147. Return code from SetServiceStatus.
  148. --*/
  149. {
  150. DWORD Error = ERROR_SUCCESS;
  151. if ( ((SERVICE_STATUS_HANDLE)0) != DhcpGlobalServiceStatusHandle ) {
  152. DhcpGlobalServiceStatus.dwCheckPoint++;
  153. if (!SetServiceStatus(
  154. DhcpGlobalServiceStatusHandle,
  155. &DhcpGlobalServiceStatus)) {
  156. Error = GetLastError();
  157. DhcpPrint((DEBUG_ERRORS, "SetServiceStatus failed, %ld.\n", Error ));
  158. }
  159. }
  160. return(Error);
  161. }
  162. DWORD
  163. ServiceControlHandler(
  164. IN DWORD Opcode,
  165. DWORD EventType,
  166. PVOID EventData,
  167. PVOID pContext
  168. )
  169. /*++
  170. Routine Description:
  171. This is the service control handler of the dhcp service.
  172. Arguments:
  173. Opcode - Supplies a value which specifies the action for the
  174. service to perform.
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. DWORD dwStatus = NO_ERROR;
  180. switch (Opcode) {
  181. case SERVICE_CONTROL_SHUTDOWN:
  182. DhcpGlobalIsShuttingDown = TRUE;
  183. case SERVICE_CONTROL_STOP:
  184. if (DhcpGlobalServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  185. DhcpPrint(( DEBUG_MISC, "Service is stop pending.\n"));
  186. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  187. DhcpGlobalServiceStatus.dwCheckPoint = 0;
  188. //
  189. // Send the status response.
  190. //
  191. UpdateStatus();
  192. if (! SetEvent(DhcpGlobalTerminateEvent)) {
  193. //
  194. // Problem with setting event to terminate dhcp
  195. // service.
  196. //
  197. DhcpPrint(( DEBUG_ERRORS,
  198. "Error setting Terminate Event %lu\n",
  199. GetLastError() ));
  200. DhcpAssert(FALSE);
  201. }
  202. return dwStatus;
  203. }
  204. break;
  205. case SERVICE_CONTROL_PAUSE:
  206. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
  207. DhcpPrint(( DEBUG_MISC, "Service is paused.\n"));
  208. break;
  209. case SERVICE_CONTROL_CONTINUE:
  210. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  211. DhcpPrint(( DEBUG_MISC, "Service is Continued.\n"));
  212. break;
  213. case SERVICE_CONTROL_INTERROGATE:
  214. DhcpPrint(( DEBUG_MISC, "Service is interrogated.\n"));
  215. break;
  216. default:
  217. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  218. DhcpPrint(( DEBUG_MISC, "Service received unknown control.\n"));
  219. break;
  220. }
  221. //
  222. // Send the status response.
  223. //
  224. UpdateStatus();
  225. return dwStatus;
  226. }
  227. VOID
  228. ScheduleWakeUp(
  229. PDHCP_CONTEXT DhcpContext,
  230. DWORD TimeToSleep
  231. )
  232. /*++
  233. Routine Description:
  234. This functions schedules a DHCP routine to run.
  235. Arguments:
  236. Context - A pointer to a DHCP context block.
  237. TimeToSleep - The time to sleep before running the renewal function,
  238. in seconds.
  239. Return Value:
  240. The status of the operation.
  241. --*/
  242. {
  243. time_t TimeNow;
  244. BOOL BoolError;
  245. if ( TimeToSleep == INFINIT_LEASE ) {
  246. DhcpContext->RunTime = INFINIT_TIME;
  247. } else {
  248. TimeNow = time( NULL);
  249. DhcpContext->RunTime = TimeNow + TimeToSleep;
  250. if( DhcpContext->RunTime < TimeNow ) { // time wrapped around
  251. DhcpContext->RunTime = INFINIT_TIME;
  252. }
  253. }
  254. //
  255. // Append this work item to the DhcpGlobalRenewList and kick the list event.
  256. // Also, release the semaphore on this context, so that someone else can enter.
  257. //
  258. LOCK_RENEW_LIST();
  259. // RenewalListEntry could be non-empty as there could be another thread scheduled on this.
  260. // This could easily happen if:
  261. // ProcessDhcpRequestForEver spawns a thread, but API Threads grabs semaphore and
  262. // completes renewal process.. so it goes back into the RenewalList. Now Renewal thread
  263. // completes, comes here and our list entry is not empty. So do this only when
  264. // our list entry is not empty.
  265. if( IsListEmpty(&DhcpContext->RenewalListEntry ) ) {
  266. InsertTailList( &DhcpGlobalRenewList, &DhcpContext->RenewalListEntry );
  267. }
  268. UNLOCK_RENEW_LIST();
  269. BoolError = SetEvent( DhcpGlobalRecomputeTimerEvent );
  270. DhcpAssert( BoolError == TRUE );
  271. }
  272. SOCKET DhcpGlobalSocketForZeroAddress = INVALID_SOCKET;
  273. ULONG DhcpGlobalNOpensForZeroAddress = 0;
  274. CRITICAL_SECTION DhcpGlobalZeroAddressCritSect;
  275. DWORD
  276. OpenDhcpSocket(
  277. PDHCP_CONTEXT DhcpContext
  278. )
  279. {
  280. DWORD Error;
  281. PLOCAL_CONTEXT_INFO localInfo;
  282. DhcpAssert(!IS_MDHCP_CTX( DhcpContext ) ) ;
  283. localInfo = DhcpContext->LocalInformation;
  284. if ( localInfo->Socket != INVALID_SOCKET ) {
  285. return ( ERROR_SUCCESS );
  286. }
  287. if( IS_DHCP_DISABLED(DhcpContext) ) {
  288. //
  289. // For static IP addresses, always bind to IP address of context.
  290. //
  291. Error = InitializeDhcpSocket(
  292. &localInfo->Socket,
  293. DhcpContext->IpAddress,
  294. IS_APICTXT_ENABLED(DhcpContext)
  295. );
  296. goto Cleanup;
  297. }
  298. if( !IS_ADDRESS_PLUMBED(DhcpContext) || DhcpIsInitState(DhcpContext) ) {
  299. // need to bind to zero address.. try to use the global one..
  300. EnterCriticalSection(&DhcpGlobalZeroAddressCritSect);
  301. if( ++DhcpGlobalNOpensForZeroAddress == 1 ) {
  302. // open DhcpGlobalSocketForZeroAddress bound to zero address..
  303. Error = InitializeDhcpSocket(&DhcpGlobalSocketForZeroAddress,0, IS_APICTXT_ENABLED(DhcpContext));
  304. if( ERROR_SUCCESS != Error ) {
  305. --DhcpGlobalNOpensForZeroAddress;
  306. }
  307. } else {
  308. Error = ERROR_SUCCESS;
  309. }
  310. LeaveCriticalSection(&DhcpGlobalZeroAddressCritSect);
  311. if( ERROR_SUCCESS == Error )
  312. {
  313. DhcpAssert(INVALID_SOCKET != DhcpGlobalSocketForZeroAddress);
  314. if( INVALID_SOCKET == DhcpGlobalSocketForZeroAddress )
  315. {
  316. Error = ERROR_GEN_FAILURE;
  317. goto Cleanup;
  318. }
  319. localInfo->Socket = DhcpGlobalSocketForZeroAddress;
  320. }
  321. goto Cleanup;
  322. }
  323. //
  324. // create a socket for the dhcp protocol. it's important to bind the
  325. // socket to the correct ip address. There are currently three cases:
  326. //
  327. // 1. If the interface has been autoconfigured, it already has an address,
  328. // say, IP1. If the client receives a unicast offer from a dhcp server
  329. // the offer will be addressed to IP2, which is the client's new dhcp
  330. // address. If we bind the dhcp socket to IP1, the client won't be able
  331. // to receive unicast responses. So, we bind the socket to 0.0.0.0.
  332. // This will allow the socket to receive a unicast datagram addressed to
  333. // any address.
  334. //
  335. // 2. If the interface in not plumbed (i.e. doesn't have an address) bind
  336. // the socket to 0.0.0.0
  337. //
  338. // 3. If the interface has been plumbed has in *not* autoconfigured, then
  339. // bind to the current address.
  340. Error = InitializeDhcpSocket(
  341. &localInfo->Socket,
  342. ( IS_ADDRESS_PLUMBED(DhcpContext) &&
  343. !DhcpContext->IPAutoconfigurationContext.Address
  344. ) ?
  345. DhcpContext->IpAddress : (DHCP_IP_ADDRESS)(0),
  346. IS_APICTXT_ENABLED(DhcpContext)
  347. );
  348. Cleanup:
  349. if( Error != ERROR_SUCCESS )
  350. {
  351. localInfo->Socket = INVALID_SOCKET;
  352. DhcpPrint((DEBUG_ERRORS, "Socket open failed: 0x%lx\n", Error));
  353. }
  354. return(Error);
  355. }
  356. DWORD
  357. CloseDhcpSocket(
  358. PDHCP_CONTEXT DhcpContext
  359. )
  360. {
  361. DWORD Error = ERROR_SUCCESS;
  362. PLOCAL_CONTEXT_INFO localInfo;
  363. DWORD Error1;
  364. localInfo = DhcpContext->LocalInformation;
  365. if( localInfo->Socket != INVALID_SOCKET ) {
  366. if( DhcpGlobalSocketForZeroAddress == localInfo->Socket ) {
  367. EnterCriticalSection(&DhcpGlobalZeroAddressCritSect);
  368. if( 0 == --DhcpGlobalNOpensForZeroAddress ) {
  369. // last open socket..
  370. Error = closesocket( localInfo->Socket );
  371. DhcpGlobalSocketForZeroAddress = INVALID_SOCKET;
  372. }
  373. LeaveCriticalSection(&DhcpGlobalZeroAddressCritSect);
  374. } else {
  375. Error = closesocket( localInfo->Socket );
  376. }
  377. if( Error != ERROR_SUCCESS ) {
  378. DhcpPrint(( DEBUG_ERRORS, " Socket close failed, %ld\n", Error ));
  379. }
  380. localInfo->Socket = INVALID_SOCKET;
  381. //
  382. // Reset the IP stack to send DHCP broadcast to first
  383. // uninitialized stack.
  384. //
  385. if (!IS_MDHCP_CTX(DhcpContext)) {
  386. Error1 = IPResetInterface(localInfo->IpInterfaceContext);
  387. // DhcpAssert( Error1 == ERROR_SUCCESS );
  388. }
  389. }
  390. return( Error );
  391. }
  392. BEGIN_EXPORT
  393. DWORD // status
  394. UninitializeInterface( // close the scoket and unplumb the address
  395. IN OUT PDHCP_CONTEXT DhcpContext // interface to unplumb
  396. ) END_EXPORT {
  397. DWORD Error = ERROR_SUCCESS;
  398. DWORD ReturnError = ERROR_SUCCESS;
  399. PLOCAL_CONTEXT_INFO LocalInfo;
  400. if( IS_ADDRESS_UNPLUMBED(DhcpContext) ) { // if address is not plumbed
  401. DhcpPrint((DEBUG_ASSERT,"UninitializeInterface:Already unplumbed\n"));
  402. return ERROR_SUCCESS;
  403. }
  404. LocalInfo = DhcpContext->LocalInformation;
  405. ReturnError = CloseDhcpSocket( DhcpContext );
  406. /*
  407. * If the adapter is unbound, there is no point to reset the IP.
  408. * The stack may re-use the IpInterfaceContext for other adapter.
  409. * We cannot depend on the order of the event, ie, the new adapter which
  410. * re-uses a context will be indicated to us later than the adapter which
  411. * is going away.
  412. */
  413. if (!IS_MEDIA_UNBOUND(DhcpContext)) {
  414. Error = IPResetIPAddress( // remove the address we got before
  415. LocalInfo->IpInterfaceContext,
  416. DhcpContext->SubnetMask
  417. );
  418. }
  419. if( Error != ERROR_SUCCESS ) ReturnError = Error;
  420. ADDRESS_UNPLUMBED(DhcpContext);
  421. if( ReturnError != ERROR_SUCCESS ) {
  422. DhcpPrint(( DEBUG_ERRORS,"UninitializeInterface:0x%ld\n", ReturnError));
  423. }
  424. return ReturnError;
  425. }
  426. BEGIN_EXPORT
  427. DWORD // status
  428. InitializeInterface( // plumb address and open socket
  429. IN OUT PDHCP_CONTEXT DhcpContext // context to initialize
  430. ) END_EXPORT {
  431. PLOCAL_CONTEXT_INFO LocalInfo;
  432. DWORD Error;
  433. DWORD ReturnError;
  434. if( IS_ADDRESS_PLUMBED(DhcpContext) ) { // if already plumbed, nothing to do
  435. DhcpPrint((DEBUG_ASSERT, "InitializeInterface:Already plumbed\n"));
  436. return ERROR_SUCCESS;
  437. }
  438. LocalInfo = DhcpContext->LocalInformation;
  439. ADDRESS_PLUMBED(DhcpContext);
  440. Error = IPSetIPAddress( // set new ip address, mask with ip
  441. LocalInfo->IpInterfaceContext, // identify context
  442. DhcpContext->IpAddress,
  443. DhcpContext->SubnetMask
  444. );
  445. if( ERROR_SUCCESS != Error ) { // if anything fails, got to be address conflict
  446. DhcpPrint((DEBUG_TRACK, "IPSetIPAddress %ld,%ld,%ld : 0x%lx\n",
  447. LocalInfo->IpInterfaceContext,
  448. DhcpContext->IpAddress, DhcpContext->SubnetMask,
  449. Error
  450. ));
  451. Error = ERROR_DHCP_ADDRESS_CONFLICT;
  452. } else { // everything went fine, open the socket for future
  453. Error = OpenDhcpSocket( DhcpContext );
  454. }
  455. if( ERROR_SUCCESS != Error ) {
  456. DhcpPrint((DEBUG_ERRORS, "InitializeInterface:0x%lx\n", Error));
  457. }
  458. return Error;
  459. }
  460. HKEY
  461. DhcpRegGetAltKey(
  462. IN LPCWSTR AdapterName
  463. )
  464. /*++
  465. Routine Description:
  466. Try to open the old format registry key for the adapter.
  467. Arguments:
  468. AdapterName -- adapter device name (no \Device\.. prefix)
  469. Return Value:
  470. NULL if key could not be opened..
  471. valid HKEY otherwise.
  472. --*/
  473. {
  474. DWORD dwError = ERROR_SUCCESS;
  475. LPWSTR RegExpandedLocation = NULL;
  476. HKEY ReturnKey = NULL;
  477. if( NULL == AdapterName ) {
  478. goto error;
  479. }
  480. dwError = DhcpRegExpandString( // expand each location into full string
  481. DHCP_ADAPTER_PARAMETERS_KEY_OLD,
  482. AdapterName,
  483. &RegExpandedLocation,
  484. NULL
  485. );
  486. if(ERROR_SUCCESS != dwError || NULL == RegExpandedLocation) {
  487. goto error;
  488. }
  489. dwError = RegOpenKeyEx(
  490. HKEY_LOCAL_MACHINE,
  491. RegExpandedLocation,
  492. 0 /* Reserved */,
  493. DHCP_CLIENT_KEY_ACCESS,
  494. &ReturnKey
  495. );
  496. if( ERROR_SUCCESS != dwError ) {
  497. goto error;
  498. }
  499. error:
  500. if (RegExpandedLocation) {
  501. DhcpFreeMemory(RegExpandedLocation);
  502. }
  503. return ReturnKey;
  504. }
  505. #ifdef BOOTPERF
  506. VOID
  507. DhcpSaveQuickBootValuesToRegistry(
  508. IN PDHCP_CONTEXT DhcpContext,
  509. IN BOOL fDelete
  510. )
  511. /*++
  512. Routine Description:
  513. If quick boot is enabled for this interface as well as fDelete is
  514. not FALSE, then this routine will save the IP address, mask and
  515. lease time options to the registry. Otherwise, it would delete
  516. these optiosn from the registry.
  517. This routine also checks to see if current time has gone past the
  518. T1 time and if so, it would clear the registry values..
  519. Arguments:
  520. DhcpContext -- the context to do this for
  521. fDelete -- shoudl the values be deleted?
  522. --*/
  523. {
  524. ULONG Error;
  525. ULONG Now = (ULONG)time(NULL);
  526. ULONGLONG NtSysTime;
  527. //
  528. // Check if quick boot is enabled on the context,
  529. // if the context is dhcp enabled or not,
  530. // Check if we are past t1 time or lease expiration..
  531. //
  532. if( TRUE == fDelete ||
  533. FALSE == DhcpContext->fQuickBootEnabled ||
  534. IS_DHCP_DISABLED(DhcpContext) ||
  535. 0 == DhcpContext->IpAddress ||
  536. ( IS_ADDRESS_DHCP(DhcpContext) &&
  537. ( Now >= (ULONG)DhcpContext->T2Time ||
  538. Now >= (ULONG)DhcpContext->LeaseExpires
  539. ) ) ) {
  540. fDelete = TRUE;
  541. }
  542. //
  543. // Now we know if we are going to delete the values
  544. // or create them. If creating the values, we need to
  545. // save the lease time in NT system time format.
  546. //
  547. if( TRUE == fDelete ) {
  548. DhcpRegDeleteQuickBootValues(
  549. DhcpContext->AdapterInfoKey
  550. );
  551. } else {
  552. ULONG Diff;
  553. ULONGLONG Diff64;
  554. GetSystemTimeAsFileTime((FILETIME *)&NtSysTime);
  555. if( IS_ADDRESS_DHCP(DhcpContext) ) {
  556. Diff = ((ULONG)DhcpContext->T2Time) - Now;
  557. //DhcpAssert(Diff == DhcpContext->T2 );
  558. //
  559. // Now add the diff to the system time.
  560. // (Diff is in seconds. 10000*1000 times this is
  561. // in 100-nanoseconds like the file time)
  562. //
  563. Diff64 = ((ULONGLONG)Diff);
  564. Diff64 *= (ULONGLONG)10000;
  565. Diff64 *= (ULONGLONG)1000;
  566. NtSysTime += Diff64;
  567. } else {
  568. //
  569. // For autonet addresses, time is infinte
  570. //
  571. LARGE_INTEGER Li = {0,0};
  572. Li.HighPart = 0x7FFFFFFF;
  573. Li.LowPart = 0xFFFFFFFF;
  574. NtSysTime = *(ULONGLONG*)&Li;
  575. }
  576. //
  577. // Now save the IP address, Mask and Lease time.
  578. // We will leave default gateways alone.
  579. //
  580. DhcpRegSaveQuickBootValues(
  581. DhcpContext->AdapterInfoKey,
  582. DhcpContext->IpAddress,
  583. DhcpContext->SubnetMask,
  584. NtSysTime
  585. );
  586. }
  587. }
  588. #endif BOOTPERF
  589. BEGIN_EXPORT
  590. DWORD // win32 status
  591. DhcpSetAllRegistryParameters( // update the registry completely
  592. IN PDHCP_CONTEXT DhcpContext, // input context to save stuff
  593. IN DHCP_IP_ADDRESS ServerAddress // which server is this about?
  594. ) END_EXPORT {
  595. DWORD i;
  596. DWORD Error;
  597. DWORD LastError;
  598. HKEY AltKey;
  599. PLOCAL_CONTEXT_INFO LocalInfo;
  600. struct /* anonymous */ {
  601. LPWSTR ValueName; // where to store this in the registry?
  602. DWORD Value; // what is the value to store
  603. DWORD RegValueType; // dword or string?
  604. } DwordArray[] = {
  605. DHCP_IP_ADDRESS_STRING, DhcpContext->IpAddress, DHCP_IP_ADDRESS_STRING_TYPE,
  606. DHCP_SUBNET_MASK_STRING, DhcpContext->SubnetMask, DHCP_SUBNET_MASK_STRING_TYPE,
  607. DHCP_SERVER, ServerAddress, DHCP_SERVER_TYPE,
  608. DHCP_LEASE, DhcpContext->Lease, DHCP_LEASE_TYPE,
  609. DHCP_LEASE_OBTAINED_TIME, (DWORD) DhcpContext->LeaseObtained, DHCP_LEASE_OBTAINED_TIME_TYPE,
  610. DHCP_LEASE_T1_TIME, (DWORD) DhcpContext->T1Time, DHCP_LEASE_T1_TIME_TYPE,
  611. DHCP_LEASE_T2_TIME, (DWORD) DhcpContext->T2Time, DHCP_LEASE_T2_TIME_TYPE,
  612. DHCP_LEASE_TERMINATED_TIME, (DWORD) DhcpContext->LeaseExpires, DHCP_LEASE_TERMINATED_TIME_TYPE,
  613. //
  614. // Sentinel -- all values from below this won't get
  615. // save to fake AdapterKey (for Server Apps portability).
  616. //
  617. NULL, 0, REG_NONE,
  618. DHCP_IPAUTOCONFIGURATION_ADDRESS, DhcpContext->IPAutoconfigurationContext.Address, DHCP_IPAUTOCONFIGURATION_ADDRESS_TYPE,
  619. DHCP_IPAUTOCONFIGURATION_MASK, DhcpContext->IPAutoconfigurationContext.Mask, DHCP_IPAUTOCONFIGURATION_MASK_TYPE,
  620. DHCP_IPAUTOCONFIGURATION_SEED, DhcpContext->IPAutoconfigurationContext.Seed, DHCP_IPAUTOCONFIGURATION_SEED_TYPE,
  621. DHCP_ADDRESS_TYPE_VALUE, IS_ADDRESS_AUTO(DhcpContext)?ADDRESS_TYPE_AUTO:ADDRESS_TYPE_DHCP, DHCP_ADDRESS_TYPE_TYPE,
  622. };
  623. LocalInfo = ((PLOCAL_CONTEXT_INFO) DhcpContext->LocalInformation);
  624. LOCK_OPTIONS_LIST();
  625. Error = DhcpRegSaveOptions( // save the options info - ignore error
  626. &DhcpContext->RecdOptionsList,
  627. LocalInfo->AdapterName,
  628. DhcpContext->ClassId,
  629. DhcpContext->ClassIdLength
  630. );
  631. UNLOCK_OPTIONS_LIST();
  632. LastError = ERROR_SUCCESS;
  633. AltKey = DhcpRegGetAltKey(LocalInfo->AdapterName);
  634. for( i = 0; i < sizeof(DwordArray)/sizeof(DwordArray[0]); i ++ ) {
  635. if( REG_DWORD == DwordArray[i].RegValueType ) {
  636. Error = RegSetValueEx(
  637. DhcpContext->AdapterInfoKey,
  638. DwordArray[i].ValueName,
  639. 0 /* Reserved */,
  640. REG_DWORD,
  641. (LPBYTE)&DwordArray[i].Value,
  642. sizeof(DWORD)
  643. );
  644. if( NULL != AltKey ) {
  645. (void)RegSetValueEx(
  646. AltKey, DwordArray[i].ValueName,
  647. 0, REG_DWORD, (LPBYTE)&DwordArray[i].Value,
  648. sizeof(DWORD)
  649. );
  650. }
  651. } else if( REG_NONE == DwordArray[i].RegValueType ) {
  652. if( NULL != AltKey ) {
  653. RegCloseKey(AltKey);
  654. AltKey = NULL;
  655. }
  656. } else {
  657. Error = RegSetIpAddress(
  658. DhcpContext->AdapterInfoKey,
  659. DwordArray[i].ValueName,
  660. DwordArray[i].RegValueType,
  661. DwordArray[i].Value
  662. );
  663. if( NULL != AltKey ) {
  664. (void)RegSetIpAddress(
  665. AltKey, DwordArray[i].ValueName,
  666. DwordArray[i].RegValueType, DwordArray[i].Value
  667. );
  668. }
  669. }
  670. if( ERROR_SUCCESS != Error ) {
  671. DhcpPrint((DEBUG_ERRORS,"SetAllRegistryParams:RegSetValueEx(%ws):0x%lx\n", DwordArray[i].ValueName,Error));
  672. LastError = Error;
  673. }
  674. }
  675. if( NULL != AltKey ) {
  676. RegCloseKey(AltKey);
  677. AltKey = NULL;
  678. }
  679. #ifdef BOOTPERF
  680. DhcpSaveQuickBootValuesToRegistry(DhcpContext, FALSE);
  681. #endif BOOTPERF
  682. return LastError;
  683. }
  684. DWORD // win32 status
  685. CheckForAddressConflict( // send ARP and see if the address conflicts..
  686. IN DHCP_IP_ADDRESS Address, // address to send gratuitous ARP for..
  687. IN ULONG nRetries // how many attempts to do?
  688. )
  689. {
  690. DWORD HwAddressBufDummy[20]; // HwAddress cant be larger than50*sizeof(DWORD)
  691. ULONG HwAddressBufSize;
  692. DWORD Error;
  693. if( 0 == Address ) return NO_ERROR; // nothing to do if we are resetting address
  694. while( nRetries -- ) { // keep trying as many times are required..
  695. HwAddressBufSize = sizeof(HwAddressBufDummy);
  696. // even though src and dest addr are same below, tcpip discards the src address we give
  697. // here (it just uses it to find the interface to send on) and uses the addr of interface..
  698. Error = SendARP( // send an ARP Request
  699. Address, // destination address to ARP for
  700. Address, // dont use zero -- tcpip asserts, use same addres..
  701. HwAddressBufDummy,
  702. &HwAddressBufSize
  703. );
  704. if( ERROR_SUCCESS == Error && 0 != HwAddressBufSize ) {
  705. DhcpPrint((DEBUG_ERRORS, "Address conflict detected for RAS\n"));
  706. return ERROR_DHCP_ADDRESS_CONFLICT; // some other client has got this address!!!!
  707. } else {
  708. DhcpPrint((DEBUG_ERRORS, "RAS stuff: SendARP returned 0x%lx\n", Error));
  709. }
  710. }
  711. return ERROR_SUCCESS;
  712. }
  713. BEGIN_EXPORT
  714. DWORD // status
  715. SetDhcpConfigurationForNIC( // plumb registry, stack and notify clients
  716. IN OUT PDHCP_CONTEXT DhcpContext, // input context to do work for
  717. IN PDHCP_FULL_OPTIONS DhcpOptions, // options to plumb registry with
  718. IN DHCP_IP_ADDRESS Address, // address to plumb stack with
  719. IN DHCP_IP_ADDRESS ServerAddress, // need to plumb registry
  720. IN DWORD PrevLeaseObtainedTime,
  721. IN BOOL fNewAddress // TRUE==>plumb stack, FALSE=> dont plumb stack
  722. ) END_EXPORT {
  723. DWORD Error;
  724. DWORD BoolError;
  725. DWORD LeaseTime;
  726. DWORD_PTR LeaseObtainedTime;
  727. DWORD_PTR LeaseExpiresTime;
  728. DWORD_PTR T1Time;
  729. DWORD_PTR T2Time;
  730. DWORD SubnetMask;
  731. LIST_ENTRY ExpiredOptions;
  732. PLOCAL_CONTEXT_INFO LocalInfo;
  733. ULONG OldIp, OldMask;
  734. DWORD NotifyDnsCache(void);
  735. BOOLEAN fSomethingChanged = FALSE;
  736. LocalInfo = (PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation;
  737. #ifdef BOOTPERF
  738. OldIp = LocalInfo->OldIpAddress;
  739. OldMask = LocalInfo->OldIpMask;
  740. LocalInfo->OldIpAddress = LocalInfo->OldIpMask = 0;
  741. if( Address && fNewAddress && OldIp && Address != OldIp
  742. && IS_ADDRESS_UNPLUMBED(DhcpContext) ) {
  743. //
  744. // If the first time the address is being set, and for some reason
  745. // the address being set is NOT the address we are trying to set,
  746. // then the machine already has an IP. Bad Bad thing.
  747. // So, we just reset the old IP to avoid spurious address conflict
  748. // errors..
  749. //
  750. Error = IPResetIPAddress(
  751. LocalInfo->IpInterfaceContext, DhcpContext->SubnetMask
  752. );
  753. }
  754. #endif BOOTPERF
  755. InitializeListHead(&ExpiredOptions);
  756. DhcpGetExpiredOptions(&DhcpContext->RecdOptionsList, &ExpiredOptions);
  757. LOCK_OPTIONS_LIST();
  758. Error = DhcpDestroyOptionsList(&ExpiredOptions, &DhcpGlobalClassesList);
  759. UNLOCK_OPTIONS_LIST();
  760. DhcpAssert(ERROR_SUCCESS == Error);
  761. if( Address && (DWORD)-1 == ServerAddress ) // mark address type as auto or dhcp..
  762. ACQUIRED_AUTO_ADDRESS(DhcpContext);
  763. else ACQUIRED_DHCP_ADDRESS(DhcpContext);
  764. SubnetMask = ntohl(DhcpDefaultSubnetMask(Address));
  765. if( IS_ADDRESS_AUTO(DhcpContext) ) {
  766. LeaseTime = 0;
  767. } else {
  768. LeaseTime = htonl(DHCP_MINIMUM_LEASE);
  769. }
  770. T1Time = 0;
  771. T2Time = 0;
  772. if( DhcpOptions && DhcpOptions->SubnetMask ) SubnetMask = *(DhcpOptions->SubnetMask);
  773. if( DhcpOptions && DhcpOptions->LeaseTime) LeaseTime = *(DhcpOptions->LeaseTime);
  774. if( DhcpOptions && DhcpOptions->T1Time) T1Time = *(DhcpOptions->T1Time);
  775. if( DhcpOptions && DhcpOptions->T2Time) T2Time = *(DhcpOptions->T2Time);
  776. LeaseTime = ntohl(LeaseTime);
  777. if (PrevLeaseObtainedTime) {
  778. LeaseObtainedTime = PrevLeaseObtainedTime;
  779. } else {
  780. LeaseObtainedTime = time(NULL);
  781. }
  782. if( 0 == T1Time ) T1Time = LeaseTime/2;
  783. else {
  784. T1Time = ntohl((DWORD) T1Time);
  785. DhcpAssert(T1Time < LeaseTime);
  786. }
  787. T1Time += LeaseObtainedTime;
  788. if( T1Time < LeaseObtainedTime ) T1Time = INFINIT_TIME;
  789. if( 0 == T2Time ) T2Time = LeaseTime * 7/8;
  790. else {
  791. T2Time = ntohl((DWORD)T2Time);
  792. DhcpAssert(T2Time < DhcpContext->Lease );
  793. DhcpAssert(T2Time > T1Time - LeaseObtainedTime);
  794. }
  795. T2Time += LeaseObtainedTime;
  796. if( T2Time < LeaseObtainedTime ) T2Time = INFINIT_TIME;
  797. LeaseExpiresTime = LeaseObtainedTime + LeaseTime;
  798. if( LeaseExpiresTime < LeaseObtainedTime ) LeaseExpiresTime = INFINIT_TIME;
  799. if( IS_ADDRESS_AUTO(DhcpContext) ) {
  800. LeaseExpiresTime = INFINIT_TIME;
  801. // DhcpContext->IPAutoconfigurationContext.Address = 0;
  802. }
  803. if( IS_ADDRESS_DHCP(DhcpContext) ) {
  804. DhcpContext->DesiredIpAddress = Address? Address : DhcpContext->IpAddress;
  805. DhcpContext->SubnetMask = SubnetMask;
  806. DhcpContext->IPAutoconfigurationContext.Address = 0;
  807. }
  808. DhcpContext->IpAddress = Address;
  809. DhcpContext->Lease = LeaseTime;
  810. DhcpContext->LeaseObtained = LeaseObtainedTime;
  811. DhcpContext->T1Time = T1Time;
  812. DhcpContext->T2Time = T2Time;
  813. DhcpContext->LeaseExpires = LeaseExpiresTime;
  814. if( IS_APICTXT_ENABLED(DhcpContext) ) { // dont do anything when called thru lease api's for RAS
  815. if( IS_ADDRESS_DHCP(DhcpContext) ) { // dont do any conflict detection for dhcp addresses..
  816. return ERROR_SUCCESS;
  817. }
  818. Error = CheckForAddressConflict(Address,2);
  819. if( ERROR_SUCCESS != Error ) { // address did conflict with something
  820. DhcpPrint((DEBUG_ERRORS, "RAS AddressConflict: 0x%lx\n", Error));
  821. return Error;
  822. }
  823. return ERROR_SUCCESS;
  824. }
  825. if( DhcpIsInitState(DhcpContext) &&
  826. (Address == 0 || IS_FALLBACK_DISABLED(DhcpContext)) )
  827. { // lost address, lose options
  828. Error = DhcpClearAllOptions(DhcpContext);
  829. }
  830. /*
  831. * Check if something is changed before the registry is overwritten
  832. */
  833. if (!fNewAddress) {
  834. fSomethingChanged = DhcpRegIsOptionChanged( // Check if something is really changed
  835. &DhcpContext->RecdOptionsList,
  836. LocalInfo->AdapterName,
  837. DhcpContext->ClassId,
  838. DhcpContext->ClassIdLength
  839. );
  840. } else {
  841. fSomethingChanged = TRUE;
  842. }
  843. Error = DhcpSetAllRegistryParameters( // save all the registry parameters
  844. DhcpContext,
  845. ServerAddress
  846. );
  847. if( fNewAddress && 0 == DhcpContext->IpAddress ) {
  848. Error = DhcpSetAllStackParameters( // reset all stack parameters, and also DNS
  849. DhcpContext,
  850. DhcpOptions
  851. );
  852. }
  853. if( !fNewAddress ) { // address did not change, but ask NetBT to read from registry
  854. NetBTNotifyRegChanges(LocalInfo->AdapterName);
  855. } else { // address change -- reset the stack
  856. Error = UninitializeInterface(DhcpContext);
  857. if(ERROR_SUCCESS != Error ) return Error;
  858. if( Address ) {
  859. Error = InitializeInterface(DhcpContext);
  860. if( ERROR_SUCCESS != Error) return Error;
  861. }
  862. BoolError = PulseEvent(DhcpGlobalNewIpAddressNotifyEvent);
  863. if (FALSE == BoolError) {
  864. DhcpPrint((DEBUG_ERRORS, "PulseEvent failed: 0x%lx\n", GetLastError()));
  865. DhcpAssert(FALSE);
  866. }
  867. }
  868. if( !fNewAddress || 0 != DhcpContext->IpAddress ) {
  869. Error = DhcpSetAllStackParameters( // reset all stack parameters, and also DNS
  870. DhcpContext,
  871. DhcpOptions
  872. );
  873. }
  874. NotifyDnsCache();
  875. if (fSomethingChanged) {
  876. NLANotifyDHCPChange();
  877. }
  878. return Error;
  879. }
  880. BEGIN_EXPORT
  881. DWORD // win32 status
  882. SetAutoConfigurationForNIC( // autoconfigured address-set dummy options before calling SetDhcp..
  883. IN OUT PDHCP_CONTEXT DhcpContext, // the context to set info for
  884. IN DHCP_IP_ADDRESS Address, // autoconfigured address
  885. IN DHCP_IP_ADDRESS Mask // input mask
  886. ) END_EXPORT
  887. {
  888. DWORD Error = ERROR_SUCCESS;
  889. PDHCP_OPTIONS pOptions = NULL;
  890. if (Address != 0 && IS_FALLBACK_ENABLED(DhcpContext))
  891. {
  892. // we rely that DhcpAllocateMemory is using
  893. // calloc() hence zeroes all the structure
  894. pOptions = DhcpAllocateMemory(sizeof (DHCP_OPTIONS));
  895. if (pOptions == NULL)
  896. return ERROR_NOT_ENOUGH_MEMORY;
  897. // replace DhcpContext->RecdOptionsList w/ FbOptionsList
  898. // and filter out the fallback IpAddress & SubnetMask
  899. Error = DhcpCopyFallbackOptions(DhcpContext, &Address, &Mask);
  900. // pOptions->SubnetMask has to point to the fallback mask address
  901. // it is safe to get pOptions->SubnetMask to point to a local variable
  902. // since pOptions will not live more than Mask.
  903. pOptions->SubnetMask = &Mask;
  904. }
  905. // if no error has been hit so far go further and try to
  906. // plumb in the autonet/fallback configuration.
  907. if (Error == ERROR_SUCCESS)
  908. {
  909. DhcpContext->SubnetMask = Mask;
  910. Error = SetDhcpConfigurationForNIC(
  911. DhcpContext,
  912. pOptions,
  913. Address,
  914. (DWORD)-1,
  915. 0,
  916. TRUE
  917. );
  918. }
  919. if (pOptions != NULL)
  920. DhcpFreeMemory(pOptions);
  921. return Error;
  922. }
  923. DWORD
  924. SystemInitialize(
  925. VOID
  926. )
  927. /*++
  928. Routine Description:
  929. This function performs implementation specific initialization
  930. of DHCP.
  931. Arguments:
  932. None.
  933. Return Value:
  934. The status of the operation.
  935. --*/
  936. {
  937. DWORD Error;
  938. HKEY OptionInfoKey = NULL;
  939. DHCP_KEY_QUERY_INFO QueryInfo;
  940. DWORD OptionInfoSize;
  941. DWORD Index;
  942. #if 0
  943. PLIST_ENTRY listEntry;
  944. PDHCP_CONTEXT dhcpContext;
  945. #endif
  946. DWORD Version;
  947. //
  948. // Init Global variables.
  949. //
  950. DhcpGlobalOptionCount = 0;
  951. DhcpGlobalOptionInfo = NULL;
  952. DhcpGlobalOptionList = NULL;
  953. //
  954. // Seed the random number generator for Transaction IDs.
  955. //
  956. srand( (unsigned int) time( NULL ) );
  957. //
  958. // Register for global machine domain name changes.
  959. //
  960. DhcpLsaDnsDomChangeNotifyHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
  961. if( NULL == DhcpLsaDnsDomChangeNotifyHandle ) {
  962. Error = GetLastError();
  963. goto Cleanup;
  964. }
  965. Error = LsaRegisterPolicyChangeNotification(
  966. PolicyNotifyDnsDomainInformation,
  967. DhcpLsaDnsDomChangeNotifyHandle
  968. );
  969. Error = LsaNtStatusToWinError(Error);
  970. if( ERROR_SUCCESS != Error ) {
  971. DhcpPrint((DEBUG_INIT, "LsaRegisterPolicyChangeNotification failed %lx\n", Error));
  972. goto Cleanup;
  973. }
  974. Error = ERROR_SUCCESS;
  975. // Start DNS Thread now..
  976. if( UseMHAsyncDns ) {
  977. Error = DnsDhcpRegisterInit();
  978. // If we could not start Async Dns.. do not try to quit it.
  979. if( ERROR_SUCCESS != Error ) UseMHAsyncDns = 0;
  980. //
  981. // ignore any Dns register init errors..
  982. //
  983. Error = ERROR_SUCCESS;
  984. }
  985. Cleanup:
  986. return( Error );
  987. }
  988. DWORD
  989. DhcpInitData(
  990. VOID
  991. )
  992. /*++
  993. Routine Description:
  994. This function initializes DHCP Global data.
  995. Arguments:
  996. None.
  997. Return Value:
  998. Windows Error.
  999. --*/
  1000. {
  1001. DWORD Error;
  1002. DhcpGlobalRecomputeTimerEvent = NULL;
  1003. DhcpGlobalTerminateEvent = NULL;
  1004. DhcpGlobalClientApiPipe = NULL;
  1005. DhcpGlobalClientApiPipeEvent = NULL;
  1006. UseMHAsyncDns = DEFAULT_USEMHASYNCDNS;
  1007. DhcpGlobalNewIpAddressNotifyEvent = NULL;
  1008. InitializeListHead( &DhcpGlobalNICList );
  1009. InitializeListHead( &DhcpGlobalRenewList );
  1010. DhcpGlobalMsgPopupThreadHandle = NULL;
  1011. DhcpGlobalDisplayPopup = TRUE;
  1012. DhcpGlobalParametersKey = NULL;
  1013. DhcpGlobalTcpipParametersKey = NULL;
  1014. UseMHAsyncDns = DEFAULT_USEMHASYNCDNS;
  1015. AutonetRetriesSeconds = EASYNET_ALLOCATION_RETRY;
  1016. DhcpGlobalUseInformFlag = TRUE;
  1017. DhcpGlobalDontPingGatewayFlag = FALSE;
  1018. DhcpGlobalIsShuttingDown = FALSE;
  1019. #ifdef BOOTPERF
  1020. DhcpGlobalQuickBootEnabledFlag = TRUE;
  1021. #endif BOOTPERF
  1022. //
  1023. // init service status data.
  1024. //
  1025. DhcpGlobalServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  1026. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  1027. DhcpGlobalServiceStatus.dwControlsAccepted = (
  1028. SERVICE_ACCEPT_STOP |
  1029. SERVICE_ACCEPT_SHUTDOWN
  1030. );
  1031. DhcpGlobalServiceStatus.dwCheckPoint = 1;
  1032. DhcpGlobalServiceStatus.dwWaitHint = 25000;
  1033. // should be larger than the wait before the last retry.
  1034. DhcpGlobalServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;
  1035. DhcpGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1036. //
  1037. // Initialize dhcp to receive service requests by registering the
  1038. // control Handler.
  1039. //
  1040. DhcpGlobalServiceStatusHandle = RegisterServiceCtrlHandlerEx(
  1041. SERVICE_DHCP,
  1042. ServiceControlHandler,
  1043. NULL );
  1044. if ( DhcpGlobalServiceStatusHandle == 0 ) {
  1045. Error = GetLastError();
  1046. DhcpPrint(( DEBUG_INIT,
  1047. "RegisterServiceCtrlHandlerW failed, %ld.\n", Error ));
  1048. //return(Error);
  1049. }
  1050. //
  1051. // Tell Service Controller that we are start pending.
  1052. //
  1053. UpdateStatus();
  1054. Error = DhcpInitRegistry();
  1055. if( ERROR_SUCCESS != Error ) goto Cleanup;
  1056. // create the waitable timer.
  1057. DhcpGlobalWaitableTimerHandle = CreateWaitableTimer(
  1058. NULL,
  1059. FALSE,
  1060. NULL );
  1061. if( DhcpGlobalWaitableTimerHandle == NULL ) {
  1062. Error = GetLastError();
  1063. goto Cleanup;
  1064. }
  1065. DhcpGlobalRecomputeTimerEvent =
  1066. CreateEvent(
  1067. NULL, // no security.
  1068. FALSE, // automatic reset.
  1069. TRUE, // initial state is signaled.
  1070. NULL ); // no name.
  1071. if( DhcpGlobalRecomputeTimerEvent == NULL ) {
  1072. Error = GetLastError();
  1073. goto Cleanup;
  1074. }
  1075. DhcpGlobalTerminateEvent =
  1076. CreateEvent(
  1077. NULL, // no security.
  1078. TRUE, // manual reset
  1079. FALSE, // initial state is signaled.
  1080. NULL ); // no name.
  1081. if( DhcpGlobalTerminateEvent == NULL ) {
  1082. Error = GetLastError();
  1083. goto Cleanup;
  1084. }
  1085. //
  1086. // create a named event that notifies the ip address changes to
  1087. // external apps.
  1088. //
  1089. DhcpGlobalNewIpAddressNotifyEvent = DhcpOpenGlobalEvent();
  1090. if( DhcpGlobalNewIpAddressNotifyEvent == NULL ) {
  1091. Error = GetLastError();
  1092. goto Cleanup;
  1093. }
  1094. Error = DhcpApiInit();
  1095. if( Error != ERROR_SUCCESS ) {
  1096. goto Cleanup;
  1097. }
  1098. Error = ERROR_SUCCESS;
  1099. Cleanup:
  1100. if( Error != ERROR_SUCCESS ) {
  1101. DhcpPrint(( DEBUG_ERRORS, "DhcpInitData failed, %ld.\n", Error ));
  1102. }
  1103. return( Error );
  1104. }
  1105. BOOL
  1106. DhcpDoReleaseOnShutDown(
  1107. IN PDHCP_CONTEXT DhcpContext
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. This routine checks to see if the context has release on
  1112. shutdown enabled.
  1113. Release on shutdown is enabled if either deliberately enabled
  1114. via the registry. It is disabled if deliberately disabled
  1115. via the registry. If neither, then the vendor option is searched
  1116. for to see if the particular option is present. If present,
  1117. then the value in that is used. If not present, then this is
  1118. not considered enabled.
  1119. Return Value:
  1120. TRUE -- Release on shutdown enabled.
  1121. FALSE -- Release on shutdown disabled.
  1122. --*/
  1123. {
  1124. BOOL fFound;
  1125. DWORD Result;
  1126. if( DhcpContext->ReleaseOnShutdown != RELEASE_ON_SHUTDOWN_OBEY_DHCP_SERVER ) {
  1127. //
  1128. // The user deliberately specified the behaviour. Do as instructed.
  1129. //
  1130. return DhcpContext->ReleaseOnShutdown != RELEASE_ON_SHUTDOWN_NEVER;
  1131. }
  1132. //
  1133. // Need to do as requested by the server. In this case, need to
  1134. // look for vendor option
  1135. //
  1136. fFound = DhcpFindDwordOption(
  1137. DhcpContext,
  1138. OPTION_MSFT_VENDOR_FEATURELIST,
  1139. TRUE,
  1140. &Result
  1141. );
  1142. if( fFound ) {
  1143. //
  1144. // Found the option? then do what the server specified.
  1145. //
  1146. return (
  1147. (Result & BIT_RELEASE_ON_SHUTDOWN) == BIT_RELEASE_ON_SHUTDOWN
  1148. );
  1149. }
  1150. //
  1151. // Didn't find the option. By default, we have this turned off.
  1152. //
  1153. return FALSE;
  1154. }
  1155. VOID
  1156. DhcpCleanup(
  1157. DWORD dwErrorParam
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This function cleans up DHCP Global data before stopping the
  1162. service.
  1163. Arguments:
  1164. None.
  1165. Return Value:
  1166. Windows Error.
  1167. --*/
  1168. {
  1169. DWORD WaitStatus;
  1170. DhcpPrint(( DEBUG_MISC,
  1171. "Dhcp Client service is shutting down, %ld.\n", dwErrorParam ));
  1172. if( dwErrorParam != ERROR_SUCCESS ) {
  1173. DhcpLogEvent( NULL, EVENT_DHCP_SHUTDOWN, dwErrorParam );
  1174. }
  1175. //
  1176. // Service is shuting down, may be due to some service problem or
  1177. // the administrator is stopping the service. Inform the service.
  1178. //
  1179. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1180. DhcpGlobalServiceStatus.dwCheckPoint = 0;
  1181. UpdateStatus();
  1182. if( FALSE == DhcpGlobalWinSockInitialized ||
  1183. FALSE == Initialized ) {
  1184. goto Done;
  1185. }
  1186. DhcpGlobalServiceRunning = FALSE;
  1187. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1188. //
  1189. // Cancel all the ongoing renewal to speed up the termination of
  1190. // MediaSenseDetectionLoop thread which could be stuck in pinging
  1191. // gateway.
  1192. //
  1193. LOCK_RENEW_LIST();
  1194. CancelAllRenew();
  1195. UNLOCK_RENEW_LIST();
  1196. if( NULL != DhcpGlobalMediaSenseHandle ) {
  1197. // MediaSenseDetectionLoop can do discovers, etc. That has to die before
  1198. // any other data is killed
  1199. //
  1200. // BUG 415272: increase the wait time to 120 seconds from 3 seconds.
  1201. // 3 seconds is not enough since MediaSenseDetectionLoop is quite heavy.
  1202. // 1. It could be stucked in the pinging gateway which can takes 3 seconds.
  1203. // 2. It acquires critical sections.
  1204. // 3. It read/write registry.
  1205. //
  1206. // TBD: remove the TerminateThread since killing a thread could leave critical
  1207. // sections in locked state.
  1208. //
  1209. WaitStatus = WaitForSingleObject( DhcpGlobalMediaSenseHandle, 120 * 1000 );
  1210. if( WAIT_OBJECT_0 != WaitStatus ) {
  1211. // Should have completed by now. Since it did not, kill it!
  1212. // DhcpAssert (0);
  1213. if( TerminateThread( DhcpGlobalMediaSenseHandle, (DWORD)-1) ) {
  1214. DhcpPrint((DEBUG_ERRORS, "MediaSenseDetectionLoop killed!\n"));
  1215. } else {
  1216. DhcpPrint((DEBUG_ERRORS, "Could not kill MediaSense Loop: %ld\n", GetLastError()));
  1217. }
  1218. }
  1219. CloseHandle(DhcpGlobalMediaSenseHandle);
  1220. DhcpGlobalMediaSenseHandle = NULL;
  1221. }
  1222. if ( NULL != DhcpGlobalWaitableTimerHandle ) {
  1223. DhcpCancelWaitableTimer( DhcpGlobalWaitableTimerHandle );
  1224. CloseHandle( DhcpGlobalWaitableTimerHandle );
  1225. DhcpGlobalWaitableTimerHandle = NULL;
  1226. }
  1227. }
  1228. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1229. if( NULL != DhcpLsaDnsDomChangeNotifyHandle ) {
  1230. LsaUnregisterPolicyChangeNotification(
  1231. PolicyNotifyDnsDomainInformation,
  1232. DhcpLsaDnsDomChangeNotifyHandle
  1233. );
  1234. CloseHandle(DhcpLsaDnsDomChangeNotifyHandle);
  1235. DhcpLsaDnsDomChangeNotifyHandle = NULL;
  1236. }
  1237. }
  1238. LOCK_RENEW_LIST();
  1239. while( !IsListEmpty(&DhcpGlobalNICList) ) {
  1240. PLIST_ENTRY NextEntry;
  1241. PDHCP_CONTEXT DhcpContext;
  1242. DWORD LocalError;
  1243. int Retries;
  1244. NextEntry = RemoveHeadList(&DhcpGlobalNICList);
  1245. DhcpContext = CONTAINING_RECORD( NextEntry, DHCP_CONTEXT, NicListEntry );
  1246. InitializeListHead(&DhcpContext->NicListEntry);
  1247. RemoveEntryList( &DhcpContext->RenewalListEntry );
  1248. InitializeListHead( &DhcpContext->RenewalListEntry );
  1249. //
  1250. // Close the semaphore handle after first acquiring it
  1251. //
  1252. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1253. UNLOCK_RENEW_LIST();
  1254. //
  1255. // BUG 415272
  1256. // Busy wait for the renewal thread to terminate.
  1257. //
  1258. // It is safe to do busy waiting. Once we reach this point,
  1259. // no new renewal thread will be launched since MediaSense
  1260. // and ProcessDhcpRequestForever threads has died.
  1261. //
  1262. Retries = 120;
  1263. while ((Retries-- > 0) && (1 != *((volatile LONG*)&(DhcpContext->RefCount)))) {
  1264. CancelRenew (DhcpContext);
  1265. Sleep (1000);
  1266. }
  1267. CloseHandle(DhcpContext->RenewHandle);
  1268. DhcpContext->RenewHandle = NULL;
  1269. if (DhcpContext->CancelEvent != WSA_INVALID_EVENT) {
  1270. WSACloseEvent(DhcpContext->CancelEvent);
  1271. DhcpContext->CancelEvent = WSA_INVALID_EVENT;
  1272. }
  1273. LOCK_RENEW_LIST();
  1274. }
  1275. //
  1276. // reset the stack since dhcp is going away and we dont want IP to keep
  1277. // using an expired address if we are not brought back up
  1278. //
  1279. if ( IS_DHCP_ENABLED(DhcpContext) ) {
  1280. if( TRUE == DhcpGlobalIsShuttingDown
  1281. && !DhcpIsInitState(DhcpContext)
  1282. && DhcpDoReleaseOnShutDown(DhcpContext) ) {
  1283. //
  1284. // Shutting down. Check if Release On Shutdown is enabled
  1285. // For the adapter in question. If so, then do it.
  1286. //
  1287. LocalError = ReleaseIpAddress(DhcpContext);
  1288. if( ERROR_SUCCESS != LocalError ) {
  1289. DhcpPrint((DEBUG_ERRORS, "ReleaseAddress failed: %ld\n"));
  1290. }
  1291. }
  1292. }
  1293. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1294. if( 0 == InterlockedDecrement(&DhcpContext->RefCount) ) {
  1295. //
  1296. // Ok, we lost the context.. Just free it now..
  1297. //
  1298. DhcpDestroyContext(DhcpContext);
  1299. } else {
  1300. DhcpAssert (0);
  1301. }
  1302. }
  1303. }
  1304. UNLOCK_RENEW_LIST();
  1305. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1306. DhcpCleanupParamChangeRequests();
  1307. DhcpCleanupRegistry ();
  1308. }
  1309. if( DhcpGlobalMsgPopupThreadHandle != NULL ) {
  1310. WaitStatus = WaitForSingleObject(
  1311. DhcpGlobalMsgPopupThreadHandle,
  1312. 0 );
  1313. if ( WaitStatus == 0 ) {
  1314. //
  1315. // This shouldn't be a case, because we close this handle at
  1316. // the end of popup thread.
  1317. //
  1318. DhcpAssert( WaitStatus == 0 );
  1319. CloseHandle( DhcpGlobalMsgPopupThreadHandle );
  1320. DhcpGlobalMsgPopupThreadHandle = NULL;
  1321. } else {
  1322. DhcpPrint((DEBUG_ERRORS,
  1323. "Cannot WaitFor message popup thread: %ld\n",
  1324. WaitStatus ));
  1325. if( TerminateThread(
  1326. DhcpGlobalMsgPopupThreadHandle,
  1327. (DWORD)(-1)) == TRUE) {
  1328. DhcpPrint(( DEBUG_ERRORS, "Terminated popup Thread.\n" ));
  1329. }
  1330. else {
  1331. DhcpPrint(( DEBUG_ERRORS,
  1332. "Can't terminate popup Thread %ld.\n",
  1333. GetLastError() ));
  1334. }
  1335. }
  1336. }
  1337. if( FALSE == DhcpGlobalIsShuttingDown ) {
  1338. DhcpApiCleanup();
  1339. if( DhcpGlobalOptionInfo != NULL) {
  1340. DhcpFreeMemory( DhcpGlobalOptionInfo );
  1341. DhcpGlobalOptionInfo = NULL;
  1342. }
  1343. if( DhcpGlobalOptionList != NULL) {
  1344. DhcpFreeMemory( DhcpGlobalOptionList );
  1345. DhcpGlobalOptionList = NULL;
  1346. }
  1347. if( DhcpGlobalTerminateEvent != NULL ) {
  1348. CloseHandle( DhcpGlobalTerminateEvent );
  1349. DhcpGlobalTerminateEvent = NULL;
  1350. }
  1351. if( DhcpGlobalNewIpAddressNotifyEvent != NULL ) {
  1352. CloseHandle( DhcpGlobalNewIpAddressNotifyEvent );
  1353. DhcpGlobalNewIpAddressNotifyEvent = NULL;
  1354. }
  1355. if( DhcpGlobalRecomputeTimerEvent != NULL ) {
  1356. CloseHandle( DhcpGlobalRecomputeTimerEvent );
  1357. DhcpGlobalRecomputeTimerEvent = NULL;
  1358. }
  1359. }
  1360. if( UseMHAsyncDns && FALSE == DhcpGlobalIsShuttingDown ) {
  1361. DWORD LocalError = DnsDhcpRegisterTerm();
  1362. if(ERROR_SUCCESS != LocalError) {
  1363. DhcpPrint((DEBUG_ERRORS, "DnsDhcpRegisterTerm: %ld\n", LocalError));
  1364. }
  1365. }
  1366. Done:
  1367. #if DBG
  1368. if (NULL != DhcpGlobalDebugFile) {
  1369. CloseHandle(DhcpGlobalDebugFile);
  1370. DhcpGlobalDebugFile = NULL;
  1371. }
  1372. #endif
  1373. //
  1374. // stop winsock.
  1375. //
  1376. if( DhcpGlobalWinSockInitialized == TRUE ) {
  1377. WSACleanup();
  1378. DhcpGlobalWinSockInitialized = FALSE;
  1379. }
  1380. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
  1381. DhcpGlobalServiceStatus.dwWin32ExitCode = dwErrorParam;
  1382. DhcpGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1383. DhcpGlobalServiceStatus.dwCheckPoint = 0;
  1384. DhcpGlobalServiceStatus.dwWaitHint = 0;
  1385. UpdateStatus();
  1386. return;
  1387. }
  1388. typedef struct _DHCP_THREAD_CTXT { // params to the thread
  1389. HANDLE Handle; // semaphore handle
  1390. PDHCP_CONTEXT DhcpContext;
  1391. } DHCP_THREAD_CTXT, *PDHCP_THREAD_CTXT;
  1392. DWORD // status
  1393. DhcpRenewThread( // renew the context
  1394. IN OUT PDHCP_THREAD_CTXT ThreadCtxt // the context to run...
  1395. )
  1396. {
  1397. DWORD Error; // return value
  1398. srand((ULONG)( // set the per-thread rand seed
  1399. time(NULL) + (ULONG_PTR)ThreadCtxt
  1400. ));
  1401. DhcpAssert( NULL != ThreadCtxt && NULL != ThreadCtxt->Handle );
  1402. DhcpPrint((DEBUG_TRACE, ".. Getting RenewHandle %d ..\n",ThreadCtxt->Handle));
  1403. Error = WaitForSingleObject(ThreadCtxt->Handle, INFINITE);
  1404. if( WAIT_OBJECT_0 != Error ) { // could happen if this context just disappeared
  1405. Error = GetLastError();
  1406. DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject: %ld\n", Error));
  1407. DhcpAssert(FALSE); // not that likely is it?
  1408. if( 0 == InterlockedDecrement(&ThreadCtxt->DhcpContext->RefCount) ) {
  1409. DhcpDestroyContext(ThreadCtxt->DhcpContext);
  1410. }
  1411. } else {
  1412. Error = ERROR_SUCCESS;
  1413. DhcpPrint((DEBUG_TRACE, "[-- Acquired RenewHandle %d --\n",ThreadCtxt->Handle));
  1414. if( 1 == ThreadCtxt->DhcpContext->RefCount ) {
  1415. //
  1416. // Last reference to this context. No need to do any refresh.
  1417. //
  1418. DhcpAssert(IsListEmpty(&ThreadCtxt->DhcpContext->NicListEntry));
  1419. } else if( IS_DHCP_ENABLED(ThreadCtxt->DhcpContext)) {
  1420. //
  1421. // Perform this only on DHCP enabled interfaces.
  1422. // It is possible that the interface got converted to static
  1423. // when the thread was waiting for it.
  1424. //
  1425. Error = ThreadCtxt->DhcpContext->RenewalFunction(ThreadCtxt->DhcpContext,NULL);
  1426. }
  1427. DhcpPrint((DEBUG_TRACE, "-- Releasing RenewHandle %d --]\n",ThreadCtxt->Handle));
  1428. //
  1429. // Do this while we still hold the semaphore to synchronize the access to the registry
  1430. //
  1431. if( 0 == InterlockedDecrement(&ThreadCtxt->DhcpContext->RefCount) ) {
  1432. DhcpDestroyContext(ThreadCtxt->DhcpContext);
  1433. } else {
  1434. BOOL BoolError;
  1435. BoolError = ReleaseSemaphore(ThreadCtxt->Handle, 1, NULL);
  1436. DhcpPrint((DEBUG_TRACE, ".. Released RenewHandle %d ..\n", ThreadCtxt->Handle));
  1437. DhcpAssert( FALSE != BoolError );
  1438. }
  1439. }
  1440. DhcpFreeMemory(ThreadCtxt);
  1441. return Error;
  1442. }
  1443. DWORD // Status
  1444. DhcpCreateThreadAndRenew( // renew in a separate thread
  1445. IN OUT PDHCP_CONTEXT DhcpContext // the context to renew
  1446. )
  1447. {
  1448. DWORD Error; // return value
  1449. HANDLE RenewThread;
  1450. DWORD Unused;
  1451. BOOL BoolError;
  1452. PDHCP_THREAD_CTXT ThreadCtxt;
  1453. ThreadCtxt = DhcpAllocateMemory(sizeof(DHCP_THREAD_CTXT));
  1454. if( NULL == ThreadCtxt ) {
  1455. DhcpPrint((DEBUG_ERRORS, "DhcpCreateThreadAndRenew:Alloc:NULL\n"));
  1456. return ERROR_NOT_ENOUGH_MEMORY;
  1457. }
  1458. ThreadCtxt->Handle = DhcpContext->RenewHandle;
  1459. ThreadCtxt->DhcpContext = DhcpContext;
  1460. InterlockedIncrement(&DhcpContext->RefCount);
  1461. DhcpPrint((DEBUG_TRACE, "Creating thread in DhcpCreateThreadAndRenew\n"));
  1462. RenewThread = CreateThread( // thread that does the real renew
  1463. NULL, // no securtiy
  1464. 0, // default process stack size
  1465. (LPTHREAD_START_ROUTINE) DhcpRenewThread, // the function to start off with
  1466. (LPVOID) ThreadCtxt, // the only parameter to the function
  1467. 0, // start the other thread right away
  1468. &Unused // Dont care about thread id
  1469. );
  1470. if( NULL == RenewThread) { // create thread failed for some reason
  1471. Error = GetLastError();
  1472. DhcpPrint((DEBUG_ERRORS, "CreateThread(DhcpCreateThreadAndRenew): %ld\n", Error));
  1473. if( ERROR_NOT_ENOUGH_MEMORY != Error && ERROR_NO_SYSTEM_RESOURCES != Error ) {
  1474. // DhcpAssert(FALSE); // this assert is bothering lots of ppl
  1475. }
  1476. DhcpFreeMemory(ThreadCtxt);
  1477. if( 0 == InterlockedDecrement(&DhcpContext->RefCount) ) {
  1478. DhcpDestroyContext(DhcpContext);
  1479. }
  1480. return Error;
  1481. }
  1482. BoolError = CloseHandle(RenewThread); // Dont need the handle, close it
  1483. return ERROR_SUCCESS;
  1484. }
  1485. VOID
  1486. HandleFailedRenewals(
  1487. VOID
  1488. )
  1489. /*++
  1490. Routine Description:
  1491. This routine handles all contexts that have failed to
  1492. create a separate thread to renew... by doing the renewal
  1493. inline. Note that if several contexts have this problem,
  1494. then this may take a long time.
  1495. The algorithm used is to walk the list of all contexts,
  1496. looking for one which has failed renewal. If none found,
  1497. the routine returns. If anything found, then an inline renewal
  1498. is attempted.
  1499. --*/
  1500. {
  1501. ULONG Error, BoolError;
  1502. PDHCP_CONTEXT DhcpContext;
  1503. PLIST_ENTRY List;
  1504. while( TRUE ) {
  1505. BOOL bFound = FALSE;
  1506. //
  1507. // Find a desirable context.
  1508. //
  1509. LOCK_RENEW_LIST();
  1510. for( List = DhcpGlobalNICList.Flink;
  1511. List != &DhcpGlobalNICList;
  1512. List = List->Flink
  1513. ) {
  1514. DhcpContext = CONTAINING_RECORD(
  1515. List, DHCP_CONTEXT, NicListEntry
  1516. );
  1517. //
  1518. // if not failed renewal give up.
  1519. //
  1520. if( FALSE == DhcpContext->bFailedRenewal ) {
  1521. continue;
  1522. }
  1523. DhcpContext->bFailedRenewal = FALSE;
  1524. //
  1525. // if not DHCP enabled give up.
  1526. //
  1527. if( IS_DHCP_DISABLED(DhcpContext)) {
  1528. continue;
  1529. }
  1530. //
  1531. // If list entry is not empty, ignore
  1532. //
  1533. if( !IsListEmpty(&DhcpContext->RenewalListEntry) ) {
  1534. continue;
  1535. }
  1536. //
  1537. // Got a context, break!
  1538. //
  1539. bFound = TRUE;
  1540. InterlockedIncrement(&DhcpContext->RefCount);
  1541. break;
  1542. }
  1543. UNLOCK_RENEW_LIST();
  1544. //
  1545. // If no contexts, quit
  1546. //
  1547. if( FALSE == bFound ) return;
  1548. //
  1549. // Acquire context and perform renewal
  1550. //
  1551. Error = WaitForSingleObject(DhcpContext->RenewHandle, INFINITE);
  1552. if( WAIT_OBJECT_0 != Error ) {
  1553. Error = GetLastError();
  1554. DhcpPrint((DEBUG_ERRORS, "WaitForSingleObject: 0x%lx\n", Error));
  1555. DhcpAssert(FALSE);
  1556. } else {
  1557. Error = ERROR_SUCCESS;
  1558. if( 1 == DhcpContext->RefCount ) {
  1559. //
  1560. // Last reference to this context?
  1561. //
  1562. DhcpAssert(IsListEmpty(&DhcpContext->NicListEntry));
  1563. } else if ( IS_DHCP_ENABLED(DhcpContext) ) {
  1564. //
  1565. // Work only for DHCP enabled contexts.
  1566. //
  1567. Error = DhcpContext->RenewalFunction(DhcpContext, NULL);
  1568. }
  1569. BoolError = ReleaseSemaphore(DhcpContext->RenewHandle, 1, NULL);
  1570. DhcpAssert(FALSE != BoolError );
  1571. }
  1572. if( 0 == InterlockedDecrement(&DhcpContext->RefCount) ) {
  1573. //
  1574. // Last reference went away..
  1575. //
  1576. DhcpDestroyContext(DhcpContext);
  1577. }
  1578. }
  1579. //
  1580. // dead code.
  1581. //
  1582. DhcpAssert(FALSE);
  1583. }
  1584. DWORD // win32 status; returns only on STOP of dhcp
  1585. ProcessDhcpRequestForever( // process renewal requests and api requests
  1586. IN DWORD TimeToSleep // initial time to sleep
  1587. ) {
  1588. #define TERMINATE_EVENT 0
  1589. #define TIMER_EVENT 1
  1590. #define PIPE_EVENT 2
  1591. #define GLOBAL_DOM_CHANGE 3
  1592. #define EVENT_COUNT 4
  1593. HANDLE WaitHandle[EVENT_COUNT];
  1594. DWORD LocalTimeToSleep = TimeToSleep;
  1595. DWORD ElapseTime;
  1596. LIST_ENTRY CurrentRenewals;
  1597. DWORD ResumeTime;
  1598. DWORD Length;
  1599. BOOL bFailedRenewal;
  1600. // Wait and Process the following work items:
  1601. //
  1602. // 1. Wait for Timer recompute event for Client renewal.
  1603. // 2. DHCP Client APIs.
  1604. WaitHandle[TIMER_EVENT] = DhcpGlobalRecomputeTimerEvent;
  1605. WaitHandle[PIPE_EVENT] = DhcpGlobalClientApiPipeEvent;
  1606. WaitHandle[TERMINATE_EVENT] = DhcpGlobalTerminateEvent;
  1607. WaitHandle[GLOBAL_DOM_CHANGE] = DhcpLsaDnsDomChangeNotifyHandle;
  1608. DhcpGlobalDoRefresh = 0;
  1609. ResumeTime = 0;
  1610. bFailedRenewal = FALSE;
  1611. for(;;) {
  1612. DWORD Waiter;
  1613. DWORD SleepTimeMsec;
  1614. if( INFINITE == LocalTimeToSleep ) {
  1615. SleepTimeMsec = INFINITE;
  1616. } else {
  1617. SleepTimeMsec = LocalTimeToSleep * 1000;
  1618. if( SleepTimeMsec < LocalTimeToSleep ) {
  1619. SleepTimeMsec = INFINITE ;
  1620. }
  1621. }
  1622. // There is a flaw in the way resume is done below in that if the machine
  1623. // suspends while we are actually doing dhcp on any of the adapter, we will not get
  1624. // around in doing DhcpStartWaitableTime. One simpler way to fix this is to restart
  1625. // the waitable timer, immediately after we get out of WaitForMultipleObjects but that is
  1626. // ugly and also that we will be able to wakeup the system but will not be able to detect
  1627. // that it did happen. The best way to fix this is to run the waitable timer on a separate
  1628. // thread and just signal this loop here whenever necessary. This should be fixed after
  1629. // new client code is checked in so that merge can be
  1630. // avoided.
  1631. // -- The above problem should be fixed because a new
  1632. // thread is now created for each renewal
  1633. // Resumed = FALSE;
  1634. if (INFINITE != ResumeTime) {
  1635. DhcpStartWaitableTimer(
  1636. DhcpGlobalWaitableTimerHandle,
  1637. ResumeTime );
  1638. } else {
  1639. DhcpCancelWaitableTimer( DhcpGlobalWaitableTimerHandle );
  1640. }
  1641. //
  1642. // Need to wait to see what happened.
  1643. //
  1644. DhcpPrint((DEBUG_MISC, "ProcessDhcpRequestForever sleeping 0x%lx msec\n",
  1645. SleepTimeMsec));
  1646. Waiter = WaitForMultipleObjects(
  1647. EVENT_COUNT, // num. of handles.
  1648. WaitHandle, // handle array.
  1649. FALSE, // wait for any.
  1650. SleepTimeMsec // timeout in msecs.
  1651. );
  1652. //
  1653. // Initialize sleep value to zero so that if we need to recompute
  1654. // time to sleep after we process the event, it will be done automatically
  1655. //
  1656. LocalTimeToSleep = 0 ;
  1657. switch( Waiter ) {
  1658. case GLOBAL_DOM_CHANGE:
  1659. //
  1660. // If domain name has changed, all we got to do is set
  1661. // the global refresh flag and fall-through.
  1662. // That will fall to the wait_timeout case and then
  1663. // refresh all NICs.
  1664. //
  1665. DhcpGlobalDoRefresh = TRUE;
  1666. case TIMER_EVENT:
  1667. //
  1668. // FALL THROUGH and recompute
  1669. //
  1670. case WAIT_TIMEOUT: { // we timed out or were woken up -- recompute timers
  1671. PDHCP_CONTEXT DhcpContext;
  1672. time_t TimeNow;
  1673. PLIST_ENTRY ListEntry;
  1674. DhcpPrint((DEBUG_TRACE,"ProcessDhcpRequestForever - processing WAIT_TIMEOUT\n"));
  1675. if( bFailedRenewal ) {
  1676. HandleFailedRenewals();
  1677. bFailedRenewal = FALSE;
  1678. }
  1679. LocalTimeToSleep = ResumeTime = INFINIT_LEASE;
  1680. TimeNow = time( NULL );
  1681. LOCK_RENEW_LIST(); // with pnp, it is ok to have no adapters; sleep till we get one
  1682. // recalculate timers and do any required renewals.. ScheduleWakeup would re-schedule these renewals
  1683. for( ListEntry = DhcpGlobalNICList.Flink;
  1684. ListEntry != &DhcpGlobalNICList;
  1685. ) {
  1686. DhcpContext = CONTAINING_RECORD(ListEntry,DHCP_CONTEXT,NicListEntry );
  1687. ListEntry = ListEntry->Flink;
  1688. //
  1689. // For static adapters, we may need to refresh params ONLY if we're asked to..
  1690. // Otherwise we can ignore them..
  1691. //
  1692. if( IS_DHCP_DISABLED(DhcpContext) ) {
  1693. if( 0 == DhcpGlobalDoRefresh ) continue;
  1694. StaticRefreshParams(DhcpContext);
  1695. continue;
  1696. }
  1697. //
  1698. // If it is time to run this renewal function, remove the
  1699. // renewal context from the list. If the power just resumed on this
  1700. // system, we need to re-run all the contexts in INIT-REBOOT mode,
  1701. // coz during suspend the machine may have been moved to a different
  1702. // network.
  1703. //
  1704. if ( 0 != DhcpGlobalDoRefresh || DhcpContext->RunTime <= TimeNow ) {
  1705. RemoveEntryList( &DhcpContext->RenewalListEntry );
  1706. if( IsListEmpty( &DhcpContext->RenewalListEntry ) ) {
  1707. //
  1708. // This context is already being processed, so ignore it
  1709. //
  1710. } else {
  1711. InitializeListHead( &DhcpContext->RenewalListEntry);
  1712. if( NO_ERROR != DhcpCreateThreadAndRenew(DhcpContext)) {
  1713. DhcpContext->bFailedRenewal = TRUE;
  1714. bFailedRenewal = TRUE;
  1715. SetEvent(DhcpGlobalRecomputeTimerEvent);
  1716. }
  1717. }
  1718. } else if( INFINIT_TIME != DhcpContext->RunTime ) {
  1719. // if RunTime is INFINIT_TIME then we never want to schedule it...
  1720. ElapseTime = (DWORD)(DhcpContext->RunTime - TimeNow);
  1721. if ( LocalTimeToSleep > ElapseTime ) {
  1722. LocalTimeToSleep = ElapseTime;
  1723. //
  1724. // if this adapter is in the autonet mode, dont let
  1725. // the 5 minute retry timer wake the machine up.
  1726. //
  1727. // Also, if context not enabled for WOL, don't do this
  1728. //
  1729. if ( DhcpContext->fTimersEnabled
  1730. && IS_ADDRESS_DHCP( DhcpContext ) ) {
  1731. // shorten the resumetime by half minute so that we can process power up event
  1732. // before normal timer fires. this we can guarantee we start with INIT-REBOOT
  1733. // sequence after power up.
  1734. if (LocalTimeToSleep > 10 ) {
  1735. ResumeTime = LocalTimeToSleep - 10;
  1736. } else {
  1737. ResumeTime = 0;
  1738. }
  1739. }
  1740. }
  1741. }
  1742. }
  1743. DhcpGlobalDoRefresh = 0;
  1744. UNLOCK_RENEW_LIST();
  1745. break;
  1746. }
  1747. case PIPE_EVENT: {
  1748. BOOL BoolError;
  1749. DhcpPrint( (DEBUG_TRACE,"ProcessDhcpRequestForever - processing PIPE_EVENT\n"));
  1750. ProcessApiRequest(DhcpGlobalClientApiPipe,&DhcpGlobalClientApiOverLapBuffer );
  1751. // Disconnect from the current client, setup listen for next client;
  1752. BoolError = DisconnectNamedPipe( DhcpGlobalClientApiPipe );
  1753. DhcpAssert( BoolError );
  1754. // ensure the event handle in the overlapped structure is reset
  1755. // before we initiate putting the pipe into listening state
  1756. ResetEvent(DhcpGlobalClientApiPipeEvent);
  1757. BoolError = ConnectNamedPipe(
  1758. DhcpGlobalClientApiPipe,
  1759. &DhcpGlobalClientApiOverLapBuffer );
  1760. if( ! DhcpGlobalDoRefresh ) {
  1761. //
  1762. // Completed processing!
  1763. //
  1764. break;
  1765. }
  1766. //
  1767. // Need to do refresh DNS host name etc..
  1768. //
  1769. Length = sizeof(DhcpGlobalHostNameBufW)/sizeof(WCHAR);
  1770. DhcpGlobalHostNameW = DhcpGlobalHostNameBufW;
  1771. BoolError = GetComputerNameExW(
  1772. ComputerNameDnsHostname,
  1773. DhcpGlobalHostNameW,
  1774. &Length
  1775. );
  1776. if( FALSE == BoolError ) {
  1777. KdPrint(("DHCP:GetComputerNameExW failed %ld\n", GetLastError()));
  1778. DhcpAssert(FALSE);
  1779. break;
  1780. }
  1781. if(DhcpUnicodeToOemSize(DhcpGlobalHostNameW) >= sizeof(DhcpGlobalHostNameBuf)) {
  1782. break;
  1783. }
  1784. DhcpUnicodeToOem( DhcpGlobalHostNameW, DhcpGlobalHostNameBuf);
  1785. DhcpGlobalHostName = DhcpGlobalHostNameBuf;
  1786. //
  1787. // We need to re-visit each context to refresh. So, hack that with
  1788. // setting LocalTimeToSleep to zero
  1789. break;
  1790. }
  1791. case TERMINATE_EVENT:
  1792. return( ERROR_SUCCESS );
  1793. case WAIT_FAILED:
  1794. DhcpPrint((DEBUG_ERRORS,"WaitForMultipleObjects failed, %ld.\n", GetLastError() ));
  1795. break;
  1796. default:
  1797. DhcpPrint((DEBUG_ERRORS,"WaitForMultipleObjects received invalid handle, %ld.\n",Waiter));
  1798. break;
  1799. }
  1800. }
  1801. }
  1802. DWORD
  1803. ResetStaticInterface(
  1804. IN PDHCP_CONTEXT DhcpContext
  1805. )
  1806. {
  1807. ULONG Error;
  1808. DWORD IpInterfaceContext;
  1809. //
  1810. // Try to delete all the non-primary interfaces for the adapter..
  1811. //
  1812. Error = IPDelNonPrimaryAddresses(DhcpAdapterName(DhcpContext));
  1813. if( ERROR_SUCCESS != Error ) {
  1814. DhcpAssert(FALSE);
  1815. return Error;
  1816. }
  1817. //
  1818. // Now we have to set the primary address to zero..
  1819. //
  1820. Error = GetIpInterfaceContext(
  1821. DhcpAdapterName(DhcpContext),
  1822. 0,
  1823. &IpInterfaceContext
  1824. );
  1825. if( ERROR_SUCCESS != Error ) {
  1826. DhcpAssert(FALSE);
  1827. return Error;
  1828. }
  1829. //
  1830. // Got hte interface context.. just set address to zero for that..
  1831. //
  1832. Error = IPResetIPAddress(
  1833. IpInterfaceContext,
  1834. DhcpDefaultSubnetMask(0)
  1835. );
  1836. return Error;
  1837. }
  1838. DWORD
  1839. DhcpDestroyContextEx(
  1840. IN PDHCP_CONTEXT DhcpContext,
  1841. IN ULONG fKeepInformation
  1842. )
  1843. {
  1844. ULONG Error;
  1845. BOOL bNotifyNLA = TRUE;
  1846. DWORD NotifyDnsCache(VOID);
  1847. if (NdisWanAdapter(DhcpContext))
  1848. InterlockedDecrement(&DhcpGlobalNdisWanAdaptersCount);
  1849. DhcpAssert( IS_MDHCP_CTX( DhcpContext ) || IsListEmpty(&DhcpContext->NicListEntry) );
  1850. if(!IsListEmpty(&DhcpContext->RenewalListEntry) ) {
  1851. LOCK_RENEW_LIST();
  1852. RemoveEntryList( &DhcpContext->RenewalListEntry );
  1853. InitializeListHead( &DhcpContext->RenewalListEntry );
  1854. UNLOCK_RENEW_LIST();
  1855. }
  1856. #ifdef BOOTPERF
  1857. //
  1858. // No matter what, if the context is going away, we
  1859. // clear out the quickboot values.
  1860. //
  1861. if( NULL != DhcpContext->AdapterInfoKey ) {
  1862. DhcpRegDeleteQuickBootValues(
  1863. DhcpContext->AdapterInfoKey
  1864. );
  1865. }
  1866. #endif BOOTPERF
  1867. if (!IS_MDHCP_CTX( DhcpContext ) ) {
  1868. if( IS_DHCP_DISABLED(DhcpContext) ) {
  1869. Error = ERROR_SUCCESS;
  1870. //Error = ResetStaticInterface(DhcpContext);
  1871. } else {
  1872. if( FALSE == fKeepInformation ) {
  1873. Error = SetDhcpConfigurationForNIC(
  1874. DhcpContext,
  1875. NULL,
  1876. 0,
  1877. (DWORD)-1,
  1878. 0,
  1879. TRUE
  1880. );
  1881. // if we get here, NLA is notified through SetDhcpConfigurationForNIC
  1882. // hence avoid sending a second notification later
  1883. if (Error == ERROR_SUCCESS)
  1884. bNotifyNLA = FALSE;
  1885. Error = DhcpRegDeleteIpAddressAndOtherValues(
  1886. DhcpContext->AdapterInfoKey
  1887. );
  1888. } else {
  1889. LOCK_OPTIONS_LIST();
  1890. (void) DhcpRegClearOptDefs(DhcpAdapterName(DhcpContext));
  1891. UNLOCK_OPTIONS_LIST();
  1892. Error = UninitializeInterface(DhcpContext);
  1893. }
  1894. //DhcpAssert(ERROR_SUCCESS == Error);
  1895. }
  1896. DhcpRegisterWithDns(DhcpContext, TRUE);
  1897. NotifyDnsCache();
  1898. }
  1899. LOCK_OPTIONS_LIST();
  1900. DhcpDestroyOptionsList(&DhcpContext->SendOptionsList, &DhcpGlobalClassesList);
  1901. DhcpDestroyOptionsList(&DhcpContext->RecdOptionsList, &DhcpGlobalClassesList);
  1902. // all fallback options are not supposed to have classes, so &DhcpGlobalClassesList below
  1903. // is actually not used.
  1904. DhcpDestroyOptionsList(&DhcpContext->FbOptionsList, &DhcpGlobalClassesList);
  1905. if( DhcpContext->ClassIdLength ) { // remove any class id we might have
  1906. DhcpDelClass(&DhcpGlobalClassesList, DhcpContext->ClassId, DhcpContext->ClassIdLength);
  1907. }
  1908. UNLOCK_OPTIONS_LIST();
  1909. CloseHandle(DhcpContext->AdapterInfoKey); // close the open handles to the registry
  1910. CloseHandle(DhcpContext->RenewHandle); // and synchronization events
  1911. if (DhcpContext->CancelEvent != WSA_INVALID_EVENT) {
  1912. WSACloseEvent(DhcpContext->CancelEvent);
  1913. DhcpContext->CancelEvent = WSA_INVALID_EVENT;
  1914. }
  1915. CloseDhcpSocket( DhcpContext ); // close the socket if it's open.
  1916. DhcpFreeMemory(DhcpContext); // done!
  1917. if (bNotifyNLA)
  1918. NLANotifyDHCPChange(); // notify NLA the adapter went away
  1919. return ERROR_SUCCESS; // always return success
  1920. }
  1921. DWORD
  1922. DhcpDestroyContext(
  1923. IN PDHCP_CONTEXT DhcpContext
  1924. )
  1925. {
  1926. return DhcpDestroyContextEx(
  1927. DhcpContext,
  1928. FALSE
  1929. );
  1930. }
  1931. DWORD
  1932. DhcpCommonInit( // initialize common stuff for service as well as APIs
  1933. VOID
  1934. )
  1935. {
  1936. ULONG Length;
  1937. BOOL BoolError;
  1938. DWORD Error;
  1939. #if DBG
  1940. LPWSTR DebugFileName = NULL;
  1941. #endif
  1942. #if DBG
  1943. //
  1944. // This is very funcky.
  1945. // Initialized won't be reset to FALSE after it gets a TRUE value
  1946. // As a result, DhcpCommonInit will be called only once.
  1947. //
  1948. // DhcpGlobalDebugFlag is updated in DhcpInitRegistry each time
  1949. // the service is stoped and started.
  1950. //
  1951. DebugFileName = NULL;
  1952. Error = DhcpGetRegistryValue(
  1953. DHCP_CLIENT_PARAMETER_KEY,
  1954. DHCP_DEBUG_FILE_VALUE,
  1955. DHCP_DEBUG_FILE_VALUE_TYPE,
  1956. &DebugFileName
  1957. );
  1958. if (DebugFileName) {
  1959. if (DhcpGlobalDebugFile) {
  1960. CloseHandle(DhcpGlobalDebugFile);
  1961. }
  1962. DhcpGlobalDebugFile = CreateFileW(
  1963. DebugFileName,
  1964. GENERIC_WRITE,
  1965. FILE_SHARE_READ,
  1966. NULL,
  1967. OPEN_ALWAYS,
  1968. FILE_FLAG_SEQUENTIAL_SCAN,
  1969. NULL
  1970. );
  1971. DhcpFreeMemory(DebugFileName);
  1972. DebugFileName = NULL;
  1973. }
  1974. #endif
  1975. if( Initialized ) return ERROR_SUCCESS;
  1976. EnterCriticalSection(&DhcpGlobalApiCritSect);
  1977. if( Initialized ) {
  1978. Error = ERROR_SUCCESS ;
  1979. goto Cleanup;
  1980. }
  1981. Length = sizeof(DhcpGlobalHostNameBufW)/sizeof(WCHAR);
  1982. DhcpGlobalHostNameW = DhcpGlobalHostNameBufW;
  1983. BoolError = GetComputerNameExW(
  1984. ComputerNameDnsHostname,
  1985. DhcpGlobalHostNameW,
  1986. &Length
  1987. );
  1988. if( FALSE == BoolError ) {
  1989. Error = GetLastError();
  1990. #if DBG
  1991. KdPrint(("DHCP:GetComputerNameExW failed %ld\n", Error));
  1992. #endif
  1993. goto success;
  1994. }
  1995. DhcpUnicodeToOem(DhcpGlobalHostNameBufW, DhcpGlobalHostNameBuf);
  1996. DhcpGlobalHostName = DhcpGlobalHostNameBuf;
  1997. #if DBG
  1998. Error = DhcpGetRegistryValue(
  1999. DHCP_CLIENT_PARAMETER_KEY,
  2000. DHCP_DEBUG_FLAG_VALUE,
  2001. DHCP_DEBUG_FLAG_VALUE_TYPE,
  2002. (PVOID *)&DhcpGlobalDebugFlag
  2003. );
  2004. if( Error != ERROR_SUCCESS ) {
  2005. DhcpGlobalDebugFlag = 0;
  2006. }
  2007. if( DhcpGlobalDebugFlag & DEBUG_BREAK_POINT ) {
  2008. DbgBreakPoint();
  2009. }
  2010. #endif
  2011. success:
  2012. Error = ERROR_SUCCESS;
  2013. Initialized = TRUE;
  2014. Cleanup:
  2015. LeaveCriticalSection(&DhcpGlobalApiCritSect);
  2016. return Error;
  2017. }
  2018. VOID
  2019. ServiceMain ( // (SVC_main) this thread quits when dhcp is unloaded
  2020. IN DWORD argc, // unused
  2021. IN LPTSTR argv[] // unused
  2022. )
  2023. {
  2024. DWORD Error;
  2025. DWORD timeToSleep = 1;
  2026. UNREFERENCED_PARAMETER(argc);
  2027. UNREFERENCED_PARAMETER(argv);
  2028. if (DhcpGlobalServiceStatus.dwCurrentState != 0 && DhcpGlobalServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  2029. return;
  2030. }
  2031. Error = WSAStartup( 0x0101, &DhcpGlobalWsaData );
  2032. if( ERROR_SUCCESS != Error ) { // initialize winsock first
  2033. goto Cleanup;
  2034. }
  2035. DhcpGlobalWinSockInitialized = TRUE;
  2036. Error = DhcpCommonInit();
  2037. if( ERROR_SUCCESS != Error ) goto Cleanup;
  2038. Error = DhcpInitData();
  2039. if( ERROR_SUCCESS != Error ) goto Cleanup; // should not happen, we abort if this happens
  2040. UpdateStatus(); // send heart beat to the service controller.
  2041. Error = DhcpInitialize( &timeToSleep ); // with pnp, this does not get any addresses
  2042. if( Error != ERROR_SUCCESS ) goto Cleanup; // this should succeed without any problems
  2043. Error = DhcpInitMediaSense(); // this would handle the notifications for arrival/departure of
  2044. if( Error != ERROR_SUCCESS ) goto Cleanup;
  2045. DhcpGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  2046. UpdateStatus(); // placate the service controller -- we are running.
  2047. DhcpPrint(( DEBUG_MISC, "Service is running.\n"));
  2048. DhcpGlobalServiceRunning = TRUE;
  2049. Error = ProcessDhcpRequestForever( // this gets the address for any adapters that may come up
  2050. timeToSleep
  2051. );
  2052. Cleanup:
  2053. DhcpCleanup( Error );
  2054. return;
  2055. }
  2056. DWORD
  2057. DhcpInitMediaSense(
  2058. VOID
  2059. )
  2060. /*++
  2061. Routine Description:
  2062. This function initializes the media sense detection code.
  2063. It creates a thread which basically just waits for media
  2064. sense notifications from tcpip.
  2065. Arguments:
  2066. None.
  2067. Return Value:
  2068. Success or Failure.
  2069. --*/
  2070. {
  2071. DWORD Error = ERROR_SUCCESS;
  2072. DWORD threadId;
  2073. DhcpGlobalIPEventSeqNo = 0;
  2074. DhcpGlobalMediaSenseHandle = CreateThread(
  2075. NULL,
  2076. 0,
  2077. (LPTHREAD_START_ROUTINE)MediaSenseDetectionLoop,
  2078. NULL,
  2079. 0,
  2080. &threadId
  2081. );
  2082. if ( DhcpGlobalMediaSenseHandle == NULL ) {
  2083. Error = GetLastError();
  2084. DhcpPrint((DEBUG_INIT, "DhcpInitMediaSense: Can't create MediaThread, %ld.\n", Error));
  2085. return(Error);
  2086. }
  2087. DhcpPrint((DEBUG_INIT, "DhcpInitMediaSense succeded\n", Error));
  2088. return(Error);
  2089. }
  2090. VOID
  2091. DoInterfaceMetricChange(
  2092. IN LPWSTR AdapterName,
  2093. IN ULONG IpInterfaceContext
  2094. )
  2095. /*++
  2096. Routine Description:
  2097. This routine handles interface metric changes for the context
  2098. specified by the AdapterName or IpInterfaceContext values.
  2099. Arguments:
  2100. AdapterName -- name of adapter for which interface metric is
  2101. changing.
  2102. IpInterfaceContext -- nte_context value for interface
  2103. --*/
  2104. {
  2105. PDHCP_CONTEXT DhcpContext;
  2106. DHCP_FULL_OPTIONS DhcpOptions;
  2107. ULONG Error;
  2108. LOCK_RENEW_LIST();
  2109. do {
  2110. DhcpContext = FindDhcpContextOnNicList(
  2111. AdapterName, IpInterfaceContext
  2112. );
  2113. if( NULL == DhcpContext ) {
  2114. //
  2115. // If there is no context, we can't do much.
  2116. //
  2117. break;
  2118. }
  2119. InterlockedIncrement( &DhcpContext->RefCount );
  2120. break;
  2121. } while ( 0 );
  2122. UNLOCK_RENEW_LIST();
  2123. if( NULL == DhcpContext ) {
  2124. //
  2125. // We never found the context. Just have to return.
  2126. //
  2127. return;
  2128. }
  2129. //
  2130. // Since we found the context, we have to acquire it.
  2131. //
  2132. Error = WaitForSingleObject( DhcpContext->RenewHandle, INFINITE);
  2133. if( WAIT_OBJECT_0 == Error ) {
  2134. //
  2135. // Now set the interface gateways again.
  2136. //
  2137. RtlZeroMemory(&DhcpOptions, sizeof(DhcpOptions));
  2138. DhcpOptions.nGateways = DhcpContext->nGateways;
  2139. DhcpOptions.GatewayAddresses = DhcpContext->GatewayAddresses;
  2140. DhcpSetGateways(DhcpContext, &DhcpOptions, TRUE);
  2141. } else {
  2142. //
  2143. // Shouldn't really happen.
  2144. //
  2145. Error = GetLastError();
  2146. DhcpAssert( ERROR_SUCCESS == Error );
  2147. }
  2148. (void) ReleaseSemaphore( DhcpContext->RenewHandle, 1, NULL);
  2149. if( 0 == InterlockedDecrement( &DhcpContext->RefCount ) ) {
  2150. //
  2151. // Last reference to the context.. Destroy it.
  2152. //
  2153. DhcpDestroyContext( DhcpContext );
  2154. }
  2155. }
  2156. VOID
  2157. DoWOLCapabilityChange(
  2158. IN LPWSTR AdapterName,
  2159. IN ULONG IpInterfaceContext
  2160. )
  2161. /*++
  2162. Routine Description:
  2163. This routine handles interface metric changes for the context
  2164. specified by the AdapterName or IpInterfaceContext values.
  2165. Arguments:
  2166. AdapterName -- name of adapter for which interface metric is
  2167. changing.
  2168. IpInterfaceContext -- nte_context value for interface
  2169. --*/
  2170. {
  2171. PDHCP_CONTEXT DhcpContext;
  2172. ULONG Error;
  2173. LOCK_RENEW_LIST();
  2174. do {
  2175. DhcpContext = FindDhcpContextOnNicList(
  2176. AdapterName, IpInterfaceContext
  2177. );
  2178. if( NULL == DhcpContext ) {
  2179. //
  2180. // If there is no context, we can't do much.
  2181. //
  2182. break;
  2183. }
  2184. InterlockedIncrement( &DhcpContext->RefCount );
  2185. break;
  2186. } while ( 0 );
  2187. UNLOCK_RENEW_LIST();
  2188. if( NULL == DhcpContext ) {
  2189. //
  2190. // We never found the context. Just have to return.
  2191. //
  2192. return;
  2193. }
  2194. //
  2195. // Since we found the context, we have to acquire it.
  2196. //
  2197. Error = WaitForSingleObject( DhcpContext->RenewHandle, INFINITE);
  2198. if( WAIT_OBJECT_0 == Error ) {
  2199. //
  2200. // Now set the interface gateways again.
  2201. //
  2202. ULONG Caps;
  2203. BOOL fTimersEnabled;
  2204. Error = IPGetWOLCapability(
  2205. DhcpIpGetIfIndex(DhcpContext), &Caps
  2206. );
  2207. if( ERROR_SUCCESS != Error ) {
  2208. DhcpPrint((DEBUG_ERRORS, "Failed IPGetWOLCapability: 0x%lx\n", Error));
  2209. } else {
  2210. fTimersEnabled = ((Caps& NDIS_DEVICE_WAKE_UP_ENABLE)!= 0);
  2211. if( fTimersEnabled != DhcpContext->fTimersEnabled ) {
  2212. DhcpContext->fTimersEnabled = fTimersEnabled;
  2213. DhcpPrint((DEBUG_MISC, "WOL Capability: %ld\n", fTimersEnabled));
  2214. if( IS_DHCP_ENABLED(DhcpContext)
  2215. && !DhcpIsInitState(DhcpContext) ) {
  2216. //
  2217. // Cause processdhcpprocessdiscoverforeever to wakeup
  2218. // to take care of this timer issue..
  2219. //
  2220. SetEvent(DhcpGlobalRecomputeTimerEvent);
  2221. }
  2222. }
  2223. }
  2224. } else {
  2225. //
  2226. // Shouldn't really happen.
  2227. //
  2228. Error = GetLastError();
  2229. DhcpAssert( ERROR_SUCCESS == Error );
  2230. }
  2231. (void) ReleaseSemaphore( DhcpContext->RenewHandle, 1, NULL);
  2232. if( 0 == InterlockedDecrement( &DhcpContext->RefCount ) ) {
  2233. //
  2234. // Last reference to the context.. Destroy it.
  2235. //
  2236. DhcpDestroyContext( DhcpContext );
  2237. }
  2238. }
  2239. VOID
  2240. MediaSenseDetectionLoop(
  2241. VOID
  2242. )
  2243. /*++
  2244. Routine Description:
  2245. This function is the starting point for the main MediaSenseDetection thread.
  2246. It loops to process queued messages, and sends replies.
  2247. Arguments:
  2248. none.
  2249. Return Value:
  2250. None.
  2251. --*/
  2252. {
  2253. #define TERMINATION_EVENT 0
  2254. #define MEDIA_SENSE_EVENT 1
  2255. #undef EVENT_COUNT
  2256. #define EVENT_COUNT 2
  2257. IP_STATUS MediaStatus;
  2258. HANDLE WaitHandle[EVENT_COUNT];
  2259. HANDLE tcpHandle = NULL;
  2260. PIP_GET_IP_EVENT_RESPONSE responseBuffer;
  2261. DWORD responseBufferSize;
  2262. IO_STATUS_BLOCK ioStatusBlock;
  2263. NTSTATUS status;
  2264. DWORD Error,result;
  2265. PDHCP_CONTEXT dhcpContext;
  2266. BOOL serviceStopped = FALSE;
  2267. responseBuffer = NULL; // Bug 292526: in case that OpenDriver and CreateEvent fails.
  2268. WaitHandle[TERMINATION_EVENT] = DhcpGlobalTerminateEvent;
  2269. WaitHandle[MEDIA_SENSE_EVENT] = CreateEvent(
  2270. NULL, // no security
  2271. FALSE, // no manual reset
  2272. FALSE, // initial state not signalled
  2273. NULL // no name
  2274. );
  2275. if ( !WaitHandle[MEDIA_SENSE_EVENT] ) {
  2276. DhcpPrint( (DEBUG_ERRORS,"MediaSenseDetectionLoop: OpenDriver failed %lx\n",GetLastError()));
  2277. goto Exit;
  2278. }
  2279. Error = OpenDriver(&tcpHandle, DD_IP_DEVICE_NAME);
  2280. if (Error != ERROR_SUCCESS) {
  2281. DhcpPrint( (DEBUG_ERRORS,"MediaSenseDetectionLoop: OpenDriver failed %lx\n",Error));
  2282. goto Exit;
  2283. }
  2284. //
  2285. // Allocate large enough buffer to hold adapter name
  2286. //
  2287. responseBufferSize = sizeof(IP_GET_IP_EVENT_RESPONSE)+ ADAPTER_STRING_SIZE;
  2288. responseBuffer = DhcpAllocateMemory(responseBufferSize);
  2289. if( responseBuffer == NULL ) {
  2290. Error = ERROR_NOT_ENOUGH_MEMORY;
  2291. goto Exit;
  2292. }
  2293. do {
  2294. ZeroMemory( responseBuffer, responseBufferSize );
  2295. DhcpPrint((DEBUG_MEDIA, "-->IPGetIPEventRequest(..%d..)\n", DhcpGlobalIPEventSeqNo));
  2296. status = IPGetIPEventRequest(
  2297. tcpHandle,
  2298. WaitHandle[MEDIA_SENSE_EVENT],
  2299. DhcpGlobalIPEventSeqNo,
  2300. responseBuffer,
  2301. responseBufferSize,
  2302. &ioStatusBlock);
  2303. if ( (STATUS_PENDING != status) && (STATUS_SUCCESS != status) )
  2304. {
  2305. DhcpPrint( (DEBUG_ERRORS,"Media Sense request ioctl failed with error %lx\n",status));
  2306. Error = RtlNtStatusToDosError(status);
  2307. break;
  2308. } else {
  2309. DhcpPrint( (DEBUG_TRACE,"Media Sense request ioctl sent\n"));
  2310. //
  2311. // Note: even in case of a immediate success from IPGetIPEventRequest,
  2312. // we do waitformultipleobjects. This is to make sure that we catch terminate
  2313. // event in case where we are getting bombarded with media sense events.
  2314. //
  2315. result = WaitForMultipleObjects(
  2316. EVENT_COUNT, // num. of handles.
  2317. WaitHandle, // handle array.
  2318. FALSE, // wait for any.
  2319. ( status == STATUS_SUCCESS ? 0 : INFINITE )); // timeout in msecs
  2320. switch( result ) {
  2321. case TERMINATION_EVENT:
  2322. DhcpPrint( (DEBUG_TRACE,"MediaSenseDetectionLoop: rcvd terminate event\n"));
  2323. if ( status == STATUS_PENDING ) {
  2324. Error = IPCancelIPEventRequest(
  2325. tcpHandle,
  2326. &ioStatusBlock);
  2327. }
  2328. //
  2329. // the service is asked to stop, break the loop.
  2330. //
  2331. serviceStopped = TRUE;
  2332. break;
  2333. default:
  2334. DhcpAssert( result == WAIT_FAILED );
  2335. DhcpPrint( (DEBUG_TRACE,"WaitForMultipleObjects returned %lx\n",result));
  2336. //
  2337. // when IPGetIPEventRequest gives immediate return code,
  2338. // we may here. So we should never fall here if it returned
  2339. // STATUS_PENDING
  2340. //
  2341. if ( status == STATUS_PENDING ) {
  2342. Error = GetLastError();
  2343. DhcpPrint( (DEBUG_ERRORS,"WaitForMultipleObjects failed with error %lx\n",Error));
  2344. break;
  2345. }
  2346. //
  2347. // THERE IS NO BREAK HERE.
  2348. //
  2349. case MEDIA_SENSE_EVENT:
  2350. if ( status != STATUS_SUCCESS && status != STATUS_PENDING ) {
  2351. DhcpPrint( (DEBUG_ERRORS,"Media Sense ioctl failed with error %lx\n",status));
  2352. break;
  2353. }
  2354. DhcpPrint((DEBUG_MEDIA,"Wait-> SequenceNo=%d; MediaStatus=%d\n",
  2355. responseBuffer->SequenceNo,
  2356. responseBuffer->MediaStatus));
  2357. DhcpPrint((DEBUG_MEDIA,"DhcpGlobalIPEventSeqNo=%d\n", DhcpGlobalIPEventSeqNo));
  2358. //
  2359. // remap the adaptername buffer from kernel space to user space
  2360. //
  2361. responseBuffer->AdapterName.Buffer = (PWSTR)(
  2362. (char *)responseBuffer + sizeof(IP_GET_IP_EVENT_RESPONSE)
  2363. );
  2364. //
  2365. // nul-terminate the string for adapter name: HACKHACK!
  2366. //
  2367. {
  2368. DWORD Size = strlen("{16310E8D-F93B-42C7-B952-00F695E40ECF}");
  2369. responseBuffer->AdapterName.Buffer[Size] = L'\0';
  2370. }
  2371. if ( responseBuffer->MediaStatus == IP_INTERFACE_METRIC_CHANGE ) {
  2372. //
  2373. // Handle interface metric change requests..
  2374. //
  2375. DoInterfaceMetricChange(
  2376. responseBuffer->AdapterName.Buffer,
  2377. responseBuffer->ContextStart
  2378. );
  2379. if( responseBuffer->SequenceNo > DhcpGlobalIPEventSeqNo ) {
  2380. DhcpGlobalIPEventSeqNo = responseBuffer->SequenceNo;
  2381. } else {
  2382. DhcpAssert(FALSE);
  2383. }
  2384. break;
  2385. }
  2386. if( responseBuffer->MediaStatus == IP_INTERFACE_WOL_CAPABILITY_CHANGE ) {
  2387. //
  2388. // Handle WOL capabilities change.
  2389. //
  2390. DoWOLCapabilityChange(
  2391. responseBuffer->AdapterName.Buffer,
  2392. responseBuffer->ContextStart
  2393. );
  2394. if( responseBuffer->SequenceNo > DhcpGlobalIPEventSeqNo ) {
  2395. DhcpGlobalIPEventSeqNo = responseBuffer->SequenceNo;
  2396. } else {
  2397. DhcpAssert(FALSE);
  2398. }
  2399. break;
  2400. }
  2401. if ( responseBuffer->MediaStatus != IP_MEDIA_CONNECT &&
  2402. responseBuffer->MediaStatus != IP_BIND_ADAPTER &&
  2403. responseBuffer->MediaStatus != IP_UNBIND_ADAPTER &&
  2404. responseBuffer->MediaStatus != IP_MEDIA_DISCONNECT &&
  2405. responseBuffer->MediaStatus != IP_INTERFACE_METRIC_CHANGE
  2406. ) {
  2407. DhcpPrint( (DEBUG_ERRORS, "Media Sense ioctl received unknown event %lx"
  2408. "for %ws, context %x\n",
  2409. responseBuffer->MediaStatus,
  2410. responseBuffer->AdapterName.Buffer,
  2411. responseBuffer->ContextStart));
  2412. break;
  2413. }
  2414. Error = ProcessAdapterBindingEvent(
  2415. responseBuffer->AdapterName.Buffer,
  2416. responseBuffer->ContextStart,
  2417. responseBuffer->MediaStatus);
  2418. DhcpGlobalIPEventSeqNo = responseBuffer->SequenceNo;
  2419. break;
  2420. } // end of switch
  2421. }
  2422. } while (!serviceStopped);
  2423. Exit:
  2424. if ( WaitHandle[MEDIA_SENSE_EVENT] ) CloseHandle( WaitHandle[MEDIA_SENSE_EVENT] );
  2425. if ( responseBuffer) DhcpFreeMemory(responseBuffer);
  2426. if ( tcpHandle ) NtClose(tcpHandle);
  2427. return;
  2428. }
  2429. VOID
  2430. DhcpDeleteGlobalRegistrySettings(
  2431. VOID
  2432. )
  2433. {
  2434. DWORD dwError = 0;
  2435. dwError = DhcpDeleteRegistryOption(
  2436. NULL,
  2437. OPTION_NETBIOS_NODE_TYPE,
  2438. FALSE
  2439. );
  2440. dwError = DhcpDeleteRegistryOption(
  2441. NULL,
  2442. OPTION_NETBIOS_SCOPE_OPTION,
  2443. FALSE
  2444. );
  2445. }
  2446. VOID
  2447. DhcpDeletePerInterfaceRegistrySettings(
  2448. IN LPWSTR adapterName
  2449. )
  2450. {
  2451. DWORD dwError = 0;
  2452. dwError = DhcpDeleteRegistryOption(
  2453. adapterName,
  2454. OPTION_NETBIOS_NAME_SERVER,
  2455. FALSE
  2456. );
  2457. dwError = DhcpDeleteRegistryOption(
  2458. adapterName,
  2459. OPTION_NETBIOS_DATAGRAM_SERVER,
  2460. FALSE
  2461. );
  2462. dwError = DhcpDeleteRegistryOption(
  2463. adapterName,
  2464. OPTION_MSFT_VENDOR_NETBIOSLESS,
  2465. TRUE
  2466. );
  2467. dwError = DhcpDeleteRegistryOption(
  2468. adapterName,
  2469. OPTION_DOMAIN_NAME_SERVERS,
  2470. FALSE
  2471. );
  2472. }
  2473. DWORD
  2474. ProcessAdapterBindingEvent(
  2475. IN LPWSTR adapterName,
  2476. IN DWORD ipInterfaceContext,
  2477. IN IP_STATUS bindingStatus
  2478. )
  2479. /*++
  2480. Routine Description:
  2481. This routine handles both the media sense for a card as well as
  2482. bind-unbind notifications.
  2483. It heavily assumes the fact that this is routine is called
  2484. synchronously by a single thread (thereby, connect and disconnect
  2485. cannot happen in parallel).
  2486. bindingStatus can be any of the four values IP_BIND_ADAPTER,
  2487. IP_UNBIND_ADAPTER, IP_MEDIA_CONNECT or IP_MEDIA_DISCONNECT ---
  2488. Of these, the first and third are treated exactly the same and
  2489. so is the second and fourth.
  2490. On BIND/CONNECT, this routine creates a DHCP Context structure
  2491. initializing the RefCount to ONE on it. But if the context
  2492. already existed, then just a refresh is done on the context.
  2493. (Assuming the router isn't present at that time etc).
  2494. On UNBIND/DISCONNECT, the refcount is temporarily bumped up
  2495. until the context semaphore can be obtained -- after that, the
  2496. context refcount is bumped down twice and if that hits zero,
  2497. the context is released. If the context refcount didn't fall to
  2498. zero, then some other thread is waiting to acquire the context
  2499. and that thread would acquire and do its work and when done,
  2500. it would bump down the refcount and at that time the refount
  2501. would fall to zero.
  2502. Arguments:
  2503. adapterName -- name of adapter all this si being done on
  2504. ipInterfaceContext -- interface context # (nte_context)_
  2505. bindingStatus -- bind/unbind/connect/disconnect indication.
  2506. Return Values:
  2507. Various useless Win32 errors.
  2508. --*/
  2509. {
  2510. DWORD Error = ERROR_SUCCESS;
  2511. PDHCP_CONTEXT dhcpContext;
  2512. DhcpPrint((DEBUG_MEDIA, "ProcessAdapterBindingEvent(%d) for %ws.\n",
  2513. bindingStatus,
  2514. adapterName));
  2515. if ( bindingStatus == IP_BIND_ADAPTER ||
  2516. bindingStatus == IP_MEDIA_CONNECT ) {
  2517. //
  2518. // New adapter or adapter re-connecting.
  2519. //
  2520. LOCK_RENEW_LIST();
  2521. dhcpContext = FindDhcpContextOnNicList(
  2522. adapterName, ipInterfaceContext
  2523. );
  2524. if( NULL == dhcpContext ) {
  2525. if (IsListEmpty(&DhcpGlobalNICList)) {
  2526. //
  2527. // BUG 528718
  2528. // This is the first interface.
  2529. // Clean up the global settings.
  2530. //
  2531. DhcpDeleteGlobalRegistrySettings();
  2532. }
  2533. //
  2534. // Clean up the per-interface settings
  2535. // (If they are needed, we'll add them after the lease is renewed).
  2536. //
  2537. DhcpDeletePerInterfaceRegistrySettings(adapterName);
  2538. //
  2539. // Create new context now!
  2540. //
  2541. DhcpPrint(( DEBUG_MEDIA, "New Adapter (Event %ld)\n", bindingStatus ));
  2542. Error = DhcpAddNICtoListEx(
  2543. adapterName,
  2544. ipInterfaceContext,
  2545. &dhcpContext
  2546. );
  2547. if (Error != ERROR_SUCCESS ) {
  2548. //
  2549. // Failed to create a context? PnP hazard. Just ignore error
  2550. // and print debug info.
  2551. //
  2552. UNLOCK_RENEW_LIST();
  2553. //DhcpAssert(FALSE);
  2554. DhcpLogEvent(NULL, EVENT_COULD_NOT_INITIALISE_INTERFACE, Error);
  2555. return Error;
  2556. }
  2557. //
  2558. // Now handle new adapter. Static case first followed by DHCP case.
  2559. //
  2560. if ( IS_DHCP_DISABLED(dhcpContext) ) {
  2561. StaticRefreshParams(dhcpContext);
  2562. UNLOCK_RENEW_LIST();
  2563. return Error;
  2564. }
  2565. //
  2566. // No prior-DHCP address case (INIT state) or INIT-REBOOT state?
  2567. //
  2568. if( DhcpIsInitState(dhcpContext) ) {
  2569. dhcpContext->RenewalFunction = ReObtainInitialParameters;
  2570. } else {
  2571. dhcpContext->RenewalFunction = ReRenewParameters;
  2572. }
  2573. //
  2574. // Do this on a separate thread..
  2575. //
  2576. ScheduleWakeUp(dhcpContext, 0);
  2577. UNLOCK_RENEW_LIST();
  2578. return ERROR_SUCCESS;
  2579. }
  2580. //
  2581. // Ok we already have a context.
  2582. //
  2583. DhcpPrint((DEBUG_MEDIA, "bind/connect for an existing adapter (context %p).\n",dhcpContext));
  2584. if( IS_DHCP_DISABLED(dhcpContext) ) {
  2585. //
  2586. // For static addresses, nothing to do.
  2587. //
  2588. UNLOCK_RENEW_LIST();
  2589. return ERROR_SUCCESS;
  2590. }
  2591. //
  2592. // For DHCP enabled, we need to call ProcessMediaConnectEvent
  2593. //
  2594. InterlockedIncrement( &dhcpContext->RefCount );
  2595. UNLOCK_RENEW_LIST();
  2596. Error = LockDhcpContext(dhcpContext, TRUE);
  2597. if( WAIT_OBJECT_0 == Error ) {
  2598. LOCK_RENEW_LIST();
  2599. //
  2600. // do not remove from renewal list at all..
  2601. // schedulewakeup is what is called in processmediaconnectevent
  2602. // and that can take care of renewallist being present..
  2603. //
  2604. // RemoveEntryList( &dhcpContext->RenewalListEntry);
  2605. // InitializeListHead( &dhcpContext->RenewalListEntry );
  2606. //
  2607. Error = ProcessMediaConnectEvent(
  2608. dhcpContext,
  2609. bindingStatus
  2610. );
  2611. UNLOCK_RENEW_LIST();
  2612. DhcpPrint((DEBUG_MEDIA, "-- media: releasing RenewHandle %d --]\n", dhcpContext->RenewHandle));
  2613. UnlockDhcpContext(dhcpContext);
  2614. } else {
  2615. //
  2616. // Shouldn't really happen..
  2617. //
  2618. Error = GetLastError();
  2619. DhcpAssert( ERROR_SUCCESS == Error );
  2620. }
  2621. if( 0 == InterlockedDecrement (&dhcpContext->RefCount ) ) {
  2622. //
  2623. // Can't really be as only this current thread can
  2624. // remove refcount on unbind/unconnect..
  2625. //
  2626. DhcpAssert(FALSE);
  2627. DhcpDestroyContext(dhcpContext);
  2628. }
  2629. return Error;
  2630. }
  2631. //
  2632. // Unbind or disconnect.
  2633. //
  2634. DhcpAssert( bindingStatus == IP_UNBIND_ADAPTER ||
  2635. bindingStatus == IP_MEDIA_DISCONNECT );
  2636. DhcpPrint((DEBUG_MEDIA, "ProcessAdapterBindingEvent: rcvd"
  2637. " unbind event for %ws, ipcontext %lx\n",
  2638. adapterName, ipInterfaceContext));
  2639. LOCK_RENEW_LIST();
  2640. dhcpContext = FindDhcpContextOnNicList(
  2641. adapterName, ipInterfaceContext
  2642. );
  2643. if( NULL == dhcpContext) {
  2644. //
  2645. // Can happen... We take this opportunity to clear registry.
  2646. //
  2647. UNLOCK_RENEW_LIST();
  2648. LOCK_OPTIONS_LIST();
  2649. (void) DhcpRegClearOptDefs( adapterName );
  2650. UNLOCK_OPTIONS_LIST();
  2651. return ERROR_FILE_NOT_FOUND;
  2652. }
  2653. InterlockedIncrement( &dhcpContext->RefCount );
  2654. UNLOCK_RENEW_LIST();
  2655. Error = LockDhcpContext(dhcpContext, TRUE);
  2656. if( WAIT_OBJECT_0 == Error ) {
  2657. LOCK_RENEW_LIST();
  2658. RemoveEntryList( &dhcpContext->RenewalListEntry );
  2659. InitializeListHead( &dhcpContext->RenewalListEntry );
  2660. RemoveEntryList( &dhcpContext->NicListEntry);
  2661. InitializeListHead( &dhcpContext->NicListEntry );
  2662. UNLOCK_RENEW_LIST();
  2663. InterlockedDecrement( &dhcpContext->RefCount );
  2664. DhcpAssert( dhcpContext->RefCount );
  2665. Error = ERROR_SUCCESS;
  2666. } else {
  2667. //
  2668. // Wait can't fail really. Nevermind.
  2669. //
  2670. Error = GetLastError();
  2671. DhcpAssert(ERROR_SUCCESS == Error);
  2672. }
  2673. //
  2674. // Now decrease ref-count and if it goes to zero destroy
  2675. // context.
  2676. //
  2677. if (bindingStatus == IP_UNBIND_ADAPTER) {
  2678. /*
  2679. * Set the state properly so that UninitializeInterface won't reset the stack
  2680. * When adapter is unbound, the IpInterfaceContext may be re-used.
  2681. */
  2682. MEDIA_UNBOUND(dhcpContext);
  2683. }
  2684. if( 0 == InterlockedDecrement(&dhcpContext->RefCount ) ) {
  2685. //
  2686. // Last person to hold onto context? Destroy context.
  2687. //
  2688. DhcpAssert(ERROR_SUCCESS == Error);
  2689. DhcpDestroyContextEx(
  2690. dhcpContext,
  2691. (bindingStatus == IP_MEDIA_DISCONNECT)
  2692. );
  2693. } else {
  2694. //
  2695. // Some other thread attempting to hold onto context.
  2696. //
  2697. ULONG BoolError = UnlockDhcpContext(dhcpContext);
  2698. DhcpAssert( FALSE != BoolError );
  2699. }
  2700. return Error;
  2701. }
  2702. LPWSTR
  2703. DhcpAdapterName(
  2704. IN PDHCP_CONTEXT DhcpContext
  2705. )
  2706. {
  2707. return ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->AdapterName;
  2708. }
  2709. static
  2710. DWORD DhcpGlobalInit = 0; // did we do any global initialization at all?
  2711. extern CRITICAL_SECTION MadcapGlobalScopeListCritSect;
  2712. DWORD DhcpGlobalNumberInitedCriticalSections = 0;
  2713. PCRITICAL_SECTION DhcpGlobalCriticalSections[] = {
  2714. (&DhcpGlobalOptionsListCritSect),
  2715. (&DhcpGlobalSetInterfaceCritSect),
  2716. (&DhcpGlobalRecvFromCritSect),
  2717. (&DhcpGlobalZeroAddressCritSect),
  2718. (&DhcpGlobalApiCritSect),
  2719. (&DhcpGlobalRenewListCritSect),
  2720. (&MadcapGlobalScopeListCritSect),
  2721. (&gNLA_LPC_CS),
  2722. #if DBG
  2723. (&DhcpGlobalDebugFileCritSect),
  2724. #endif
  2725. (&DhcpGlobalPopupCritSect)
  2726. };
  2727. #define NUM_CRITICAL_SECTION (sizeof(DhcpGlobalCriticalSections)/sizeof(DhcpGlobalCriticalSections[0]))
  2728. extern REGISTER_HOST_STATUS DhcpGlobalHostStatus;
  2729. DWORD // win32 status
  2730. DhcpInitGlobalData( // initialize the dhcp module spec data (included for RAS etc)
  2731. VOID
  2732. )
  2733. {
  2734. DWORD i;
  2735. InitializeListHead(&DhcpGlobalClassesList);
  2736. InitializeListHead(&DhcpGlobalOptionDefList);
  2737. InitializeListHead(&DhcpGlobalRecvFromList);
  2738. try {
  2739. for (DhcpGlobalNumberInitedCriticalSections = 0;
  2740. DhcpGlobalNumberInitedCriticalSections < NUM_CRITICAL_SECTION;
  2741. DhcpGlobalNumberInitedCriticalSections++) {
  2742. InitializeCriticalSection(DhcpGlobalCriticalSections[DhcpGlobalNumberInitedCriticalSections]);
  2743. }
  2744. } except (EXCEPTION_EXECUTE_HANDLER) {
  2745. for (i = 0; i < DhcpGlobalNumberInitedCriticalSections; i++) {
  2746. DeleteCriticalSection(DhcpGlobalCriticalSections[i]);
  2747. }
  2748. DhcpGlobalNumberInitedCriticalSections = 0;
  2749. return ERROR_OUTOFMEMORY;
  2750. }
  2751. DhcpGlobalHostStatus.hDoneEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  2752. AutonetRetriesSeconds = EASYNET_ALLOCATION_RETRY;
  2753. DhcpGlobalClientClassInfo = DHCP_DEFAULT_CLIENT_CLASS_INFO;
  2754. DhcpGlobalDoRefresh = 0;
  2755. DhcpGlobalInit ++;
  2756. DhcpGlobalServerPort = DHCP_SERVR_PORT;
  2757. DhcpGlobalClientPort = DHCP_CLIENT_PORT;
  2758. return ERROR_SUCCESS;
  2759. }
  2760. VOID
  2761. DhcpCleanupGlobalData( // cleanup data intialized via DhcpInitGlobalData
  2762. VOID
  2763. )
  2764. {
  2765. DWORD i;
  2766. if( 0 == DhcpGlobalInit ) return;
  2767. for (i = 0; i < DhcpGlobalNumberInitedCriticalSections; i++) {
  2768. DeleteCriticalSection(DhcpGlobalCriticalSections[i]);
  2769. }
  2770. DhcpGlobalNumberInitedCriticalSections = 0;
  2771. if (ghNLA_LPC_Port != NULL)
  2772. {
  2773. CloseHandle(ghNLA_LPC_Port);
  2774. ghNLA_LPC_Port = NULL;
  2775. }
  2776. if (NULL != DhcpGlobalHostStatus.hDoneEvent) {
  2777. CloseHandle(DhcpGlobalHostStatus.hDoneEvent);
  2778. DhcpGlobalHostStatus.hDoneEvent = NULL;
  2779. }
  2780. DhcpFreeAllOptionDefs(&DhcpGlobalOptionDefList, &DhcpGlobalClassesList);
  2781. DhcpFreeAllClasses(&DhcpGlobalClassesList);
  2782. DhcpGlobalClientClassInfo = NULL;
  2783. DhcpGlobalDoRefresh = 0;
  2784. DhcpGlobalInit --;
  2785. }
  2786. DWORD
  2787. LockDhcpContext(
  2788. PDHCP_CONTEXT DhcpContext,
  2789. BOOL bCancelOngoingRequest
  2790. )
  2791. {
  2792. DWORD Error;
  2793. if (bCancelOngoingRequest) {
  2794. InterlockedIncrement(&DhcpContext->NumberOfWaitingThreads);
  2795. CancelRenew (DhcpContext);
  2796. }
  2797. Error = WaitForSingleObject(DhcpContext->RenewHandle,INFINITE);
  2798. //
  2799. // If CancelEvent is valid, reset it just in case no one waited on it.
  2800. // It is safe to do it here since we already locked the context
  2801. //
  2802. if (bCancelOngoingRequest && (0 == InterlockedDecrement(&DhcpContext->NumberOfWaitingThreads))) {
  2803. if (DhcpContext->CancelEvent != WSA_INVALID_EVENT) {
  2804. //
  2805. // There is a small chance that we reset the event
  2806. // before another thread set the event. In order to
  2807. // fully solve this problem, we need to protect the
  2808. // SetEvent/ResetEvent with a critical section. It
  2809. // doesn't worth the effort.
  2810. //
  2811. // The only harm of this problem is that that thread
  2812. // has to wait for up to 1 minutes to lock the context.
  2813. // This should be ok.
  2814. //
  2815. WSAResetEvent(DhcpContext->CancelEvent);
  2816. }
  2817. }
  2818. return Error;
  2819. }
  2820. BOOL
  2821. UnlockDhcpContext(
  2822. PDHCP_CONTEXT DhcpContext
  2823. )
  2824. {
  2825. return ReleaseSemaphore(DhcpContext->RenewHandle,1,NULL);
  2826. }
  2827. //================================================================================
  2828. // End of file
  2829. //================================================================================