Source code of Windows XP (NT5)
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.

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