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

2255 lines
51 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. dhcpif.c
  5. Abstract:
  6. This module contains code for the DHCP allocator's interface management.
  7. Author:
  8. Abolade Gbadegesin (aboladeg) 5-Mar-1998
  9. Revision History:
  10. Raghu Gatta (rgatta) 15-Dec-2000
  11. Added DhcpGetPrivateInterfaceAddress()
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <ipinfo.h>
  16. extern "C" {
  17. #include <iphlpstk.h>
  18. }
  19. //
  20. // LOCAL TYPE DECLARATIONS
  21. //
  22. typedef struct _DHCP_DEFER_READ_CONTEXT {
  23. ULONG Index;
  24. SOCKET Socket;
  25. ULONG DeferralCount;
  26. } DHCP_DEFER_READ_CONTEXT, *PDHCP_DEFER_READ_CONTEXT;
  27. #define DHCP_DEFER_READ_TIMEOUT (5 * 1000)
  28. //
  29. // GLOBAL DATA DEFINITIONS
  30. //
  31. LIST_ENTRY DhcpInterfaceList;
  32. CRITICAL_SECTION DhcpInterfaceLock;
  33. //
  34. // Forward declarations
  35. //
  36. VOID NTAPI
  37. DhcpDeferReadCallbackRoutine(
  38. PVOID Context,
  39. BOOLEAN TimedOut
  40. );
  41. VOID APIENTRY
  42. DhcpDeferReadWorkerRoutine(
  43. PVOID Context
  44. );
  45. ULONG
  46. DhcpActivateInterface(
  47. PDHCP_INTERFACE Interfacep
  48. )
  49. /*++
  50. Routine Description:
  51. This routine is called to activate an interface, when the interface
  52. becomes both enabled and bound.
  53. Activation involves
  54. (a) creating sockets for each binding of the interface
  55. (b) initiating datagram-reads on each created socket
  56. Arguments:
  57. Context - the index of the interface to be activated
  58. Return Value:
  59. ULONG - Win32 status code indicating success or failure.
  60. Environment:
  61. Always invoked locally, with 'Interfacep' referenced by caller and/or
  62. 'DhcpInterfaceLock' held by caller.
  63. --*/
  64. {
  65. ULONG Error;
  66. ULONG i;
  67. ULONG ScopeNetwork;
  68. ULONG ScopeMask;
  69. ULONG InterfaceCharacteristics;
  70. DHCP_INTERFACE_TYPE dhcpIfType;
  71. PROFILE("DhcpActivateInterface");
  72. //
  73. // Read the scope-network from which addresses are to be assigned
  74. //
  75. EnterCriticalSection(&DhcpGlobalInfoLock);
  76. ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
  77. ScopeMask = DhcpGlobalInfo->ScopeMask;
  78. LeaveCriticalSection(&DhcpGlobalInfoLock);
  79. //
  80. // (re)take the interface lock for the duration of the routine
  81. //
  82. EnterCriticalSection(&DhcpInterfaceLock);
  83. if (DHCP_INTERFACE_ADMIN_DISABLED(Interfacep)) {
  84. LeaveCriticalSection(&DhcpInterfaceLock);
  85. return NO_ERROR;
  86. }
  87. InterfaceCharacteristics =
  88. NatGetInterfaceCharacteristics(
  89. Interfacep->Index
  90. );
  91. if (!InterfaceCharacteristics) {
  92. ACQUIRE_LOCK(Interfacep);
  93. Interfacep->DhcpInterfaceType = DhcpInterfaceInvalid;
  94. RELEASE_LOCK(Interfacep);
  95. LeaveCriticalSection(&DhcpInterfaceLock);
  96. NhTrace(
  97. TRACE_FLAG_DHCP,
  98. "DhcpActivateInterface: ignoring non-NAT interface %d",
  99. Interfacep->Index
  100. );
  101. return NO_ERROR;
  102. }
  103. if (NAT_IFC_BOUNDARY(InterfaceCharacteristics))
  104. {
  105. if (NAT_IFC_FW(InterfaceCharacteristics))
  106. {
  107. dhcpIfType = DhcpInterfaceBoundaryFirewalled;
  108. }
  109. else
  110. {
  111. dhcpIfType = DhcpInterfaceBoundary;
  112. }
  113. }
  114. else
  115. if (NAT_IFC_FW(InterfaceCharacteristics))
  116. {
  117. dhcpIfType = DhcpInterfaceFirewalled;
  118. }
  119. else
  120. {
  121. dhcpIfType = DhcpInterfacePrivate;
  122. }
  123. //
  124. // Create datagram sockets for receiving data on each logical network;
  125. // N.B. We exclude networks other than the scope network.
  126. //
  127. Error = NO_ERROR;
  128. ACQUIRE_LOCK(Interfacep);
  129. Interfacep->DhcpInterfaceType = dhcpIfType;
  130. if (DhcpInterfacePrivate != dhcpIfType)
  131. {
  132. //
  133. // DHCP should be active only on Private interfaces
  134. //
  135. NhTrace(
  136. TRACE_FLAG_DHCP,
  137. "DhcpActivateInterface: ignoring NAT interface %d",
  138. Interfacep->Index
  139. );
  140. NhWarningLog(
  141. IP_AUTO_DHCP_LOG_NAT_INTERFACE_IGNORED,
  142. 0,
  143. "%d",
  144. Interfacep->Index
  145. );
  146. RELEASE_LOCK(Interfacep);
  147. LeaveCriticalSection(&DhcpInterfaceLock);
  148. return NO_ERROR;
  149. }
  150. for (i = 0; i < Interfacep->BindingCount; i++) {
  151. if ((Interfacep->BindingArray[i].Address & ScopeMask) !=
  152. (ScopeNetwork & ScopeMask)
  153. ) {
  154. NhErrorLog(
  155. IP_AUTO_DHCP_LOG_NON_SCOPE_ADDRESS,
  156. 0,
  157. "%I%I%I",
  158. Interfacep->BindingArray[i].Address,
  159. ScopeNetwork,
  160. ScopeMask
  161. );
  162. continue;
  163. }
  164. Error =
  165. NhCreateDatagramSocket(
  166. Interfacep->BindingArray[i].Address,
  167. DHCP_PORT_SERVER,
  168. &Interfacep->BindingArray[i].Socket
  169. );
  170. if (Error) { break; }
  171. }
  172. //
  173. // If an error occurred, roll back all work done so far and fail.
  174. //
  175. if (Error) {
  176. ULONG FailedAddress = i;
  177. for (; (LONG)i >= 0; i--) {
  178. NhDeleteDatagramSocket(
  179. Interfacep->BindingArray[i].Socket
  180. );
  181. Interfacep->BindingArray[i].Socket = INVALID_SOCKET;
  182. }
  183. NhErrorLog(
  184. IP_AUTO_DHCP_LOG_ACTIVATE_FAILED,
  185. Error,
  186. "%I",
  187. Interfacep->BindingArray[FailedAddress].Address
  188. );
  189. RELEASE_LOCK(Interfacep);
  190. LeaveCriticalSection(&DhcpInterfaceLock);
  191. return Error;
  192. }
  193. //
  194. // Initiate read-operations on each socket
  195. //
  196. for (i = 0; i < Interfacep->BindingCount; i++) {
  197. if ((Interfacep->BindingArray[i].Address & ScopeMask) !=
  198. (ScopeNetwork & ScopeMask)
  199. ) { continue; }
  200. //
  201. // Make a reference to the interface;
  202. // this reference is released in the completion routine
  203. //
  204. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { continue; }
  205. //
  206. // Initiate the read-operation
  207. //
  208. Error =
  209. NhReadDatagramSocket(
  210. &DhcpComponentReference,
  211. Interfacep->BindingArray[i].Socket,
  212. NULL,
  213. DhcpReadCompletionRoutine,
  214. Interfacep,
  215. UlongToPtr(Interfacep->BindingArray[i].Mask)
  216. );
  217. //
  218. // Drop the reference if a failure occurred
  219. //
  220. if (Error) {
  221. NhErrorLog(
  222. IP_AUTO_DHCP_LOG_RECEIVE_FAILED,
  223. Error,
  224. "%I",
  225. Interfacep->BindingArray[i].Address
  226. );
  227. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  228. //
  229. // Reissue the read-operation later
  230. //
  231. DhcpDeferReadInterface(
  232. Interfacep,
  233. Interfacep->BindingArray[i].Socket
  234. );
  235. Error = NO_ERROR;
  236. }
  237. //
  238. // Now make another reference for the client-request
  239. // with which we detect servers on the network.
  240. //
  241. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { continue; }
  242. Error =
  243. DhcpWriteClientRequestMessage(
  244. Interfacep,
  245. &Interfacep->BindingArray[i]
  246. );
  247. //
  248. // Drop the reference if a failure occurred
  249. //
  250. if (Error) { DHCP_DEREFERENCE_INTERFACE(Interfacep); Error = NO_ERROR; }
  251. }
  252. //
  253. // cache that this particular interface is a non boundary NAT interface
  254. //
  255. Interfacep->Flags |= DHCP_INTERFACE_FLAG_NAT_NONBOUNDARY;
  256. RELEASE_LOCK(Interfacep);
  257. LeaveCriticalSection(&DhcpInterfaceLock);
  258. return NO_ERROR;
  259. } // DhcpActivateInterface
  260. ULONG
  261. DhcpBindInterface(
  262. ULONG Index,
  263. PIP_ADAPTER_BINDING_INFO BindingInfo
  264. )
  265. /*++
  266. Routine Description:
  267. This routine is invoked to supply the binding for an interface.
  268. It records the binding information received, and if necessary,
  269. it activates the interface.
  270. Arguments:
  271. Index - the index of the interface to be bound
  272. BindingInfo - the binding-information for the interface
  273. Return Value:
  274. ULONG - Win32 status code.
  275. Environment:
  276. Invoked internally in the context of an IP router-manager thread.
  277. (See 'RMDHCP.C').
  278. --*/
  279. {
  280. ULONG Error = NO_ERROR;
  281. ULONG i;
  282. PDHCP_INTERFACE Interfacep;
  283. PROFILE("DhcpBindInterface");
  284. EnterCriticalSection(&DhcpInterfaceLock);
  285. //
  286. // Retrieve the interface to be bound
  287. //
  288. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  289. LeaveCriticalSection(&DhcpInterfaceLock);
  290. NhTrace(
  291. TRACE_FLAG_IF,
  292. "DhcpBindInterface: interface %d not found",
  293. Index
  294. );
  295. return ERROR_NO_SUCH_INTERFACE;
  296. }
  297. //
  298. // Make sure the interface isn't already bound
  299. //
  300. if (DHCP_INTERFACE_BOUND(Interfacep)) {
  301. LeaveCriticalSection(&DhcpInterfaceLock);
  302. NhTrace(
  303. TRACE_FLAG_IF,
  304. "DhcpBindInterface: interface %d is already bound",
  305. Index
  306. );
  307. return ERROR_ADDRESS_ALREADY_ASSOCIATED;
  308. }
  309. //
  310. // Reference the interface
  311. //
  312. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  313. LeaveCriticalSection(&DhcpInterfaceLock);
  314. NhTrace(
  315. TRACE_FLAG_IF,
  316. "DhcpBindInterface: interface %d cannot be referenced",
  317. Index
  318. );
  319. return ERROR_INTERFACE_DISABLED;
  320. }
  321. //
  322. // Update the interface's flags
  323. //
  324. Interfacep->Flags |= DHCP_INTERFACE_FLAG_BOUND;
  325. LeaveCriticalSection(&DhcpInterfaceLock);
  326. ACQUIRE_LOCK(Interfacep);
  327. //
  328. // Allocate space for the binding
  329. //
  330. if (!BindingInfo->AddressCount) {
  331. Interfacep->BindingCount = 0;
  332. Interfacep->BindingArray = NULL;
  333. }
  334. else {
  335. Interfacep->BindingArray =
  336. reinterpret_cast<PDHCP_BINDING>(
  337. NH_ALLOCATE(BindingInfo->AddressCount * sizeof(DHCP_BINDING))
  338. );
  339. if (!Interfacep->BindingArray) {
  340. RELEASE_LOCK(Interfacep);
  341. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  342. NhTrace(
  343. TRACE_FLAG_IF,
  344. "DhcpBindInterface: allocation failed for interface %d binding",
  345. Index
  346. );
  347. NhWarningLog(
  348. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  349. 0,
  350. "%d",
  351. BindingInfo->AddressCount * sizeof(DHCP_BINDING)
  352. );
  353. return ERROR_NOT_ENOUGH_MEMORY;
  354. }
  355. Interfacep->BindingCount = BindingInfo->AddressCount;
  356. }
  357. //
  358. // Copy the binding
  359. //
  360. for (i = 0; i < BindingInfo->AddressCount; i++) {
  361. Interfacep->BindingArray[i].Address = BindingInfo->Address[i].Address;
  362. Interfacep->BindingArray[i].Mask = BindingInfo->Address[i].Mask;
  363. Interfacep->BindingArray[i].Socket = INVALID_SOCKET;
  364. Interfacep->BindingArray[i].ClientSocket = INVALID_SOCKET;
  365. Interfacep->BindingArray[i].TimerPending = FALSE;
  366. }
  367. RELEASE_LOCK(Interfacep);
  368. //
  369. // Activate the interface if necessary
  370. //
  371. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  372. Error = DhcpActivateInterface(Interfacep);
  373. }
  374. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  375. return Error;
  376. } // DhcpBindInterface
  377. VOID
  378. DhcpCleanupInterface(
  379. PDHCP_INTERFACE Interfacep
  380. )
  381. /*++
  382. Routine Description:
  383. This routine is invoked when the very last reference to an interface
  384. is released, and the interface must be destroyed.
  385. Arguments:
  386. Interfacep - the interface to be destroyed
  387. Return Value:
  388. none.
  389. Environment:
  390. Invoked internally from an arbitrary context.
  391. --*/
  392. {
  393. PROFILE("DhcpCleanupInterface");
  394. if (Interfacep->BindingArray) {
  395. NH_FREE(Interfacep->BindingArray);
  396. Interfacep->BindingArray = NULL;
  397. }
  398. DeleteCriticalSection(&Interfacep->Lock);
  399. NH_FREE(Interfacep);
  400. } // DhcpCleanupInterface
  401. ULONG
  402. DhcpConfigureInterface(
  403. ULONG Index,
  404. PIP_AUTO_DHCP_INTERFACE_INFO InterfaceInfo
  405. )
  406. /*++
  407. Routine Description:
  408. This routine is called to set the configuration for an interface.
  409. Arguments:
  410. Index - the interface to be configured
  411. InterfaceInfo - the new configuration
  412. Return Value:
  413. ULONG - Win32 status code
  414. Environment:
  415. Invoked internally in the context of a IP router-manager thread.
  416. (See 'RMDHCP.C').
  417. --*/
  418. {
  419. ULONG Error;
  420. PDHCP_INTERFACE Interfacep;
  421. ULONG NewFlags;
  422. ULONG OldFlags;
  423. PROFILE("DhcpConfigureInterface");
  424. //
  425. // Retrieve the interface to be configured
  426. //
  427. EnterCriticalSection(&DhcpInterfaceLock);
  428. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  429. LeaveCriticalSection(&DhcpInterfaceLock);
  430. NhTrace(
  431. TRACE_FLAG_IF,
  432. "DhcpConfigureInterface: interface %d not found",
  433. Index
  434. );
  435. return ERROR_NO_SUCH_INTERFACE;
  436. }
  437. //
  438. // Reference the interface
  439. //
  440. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  441. LeaveCriticalSection(&DhcpInterfaceLock);
  442. NhTrace(
  443. TRACE_FLAG_IF,
  444. "DhcpConfigureInterface: interface %d cannot be referenced",
  445. Index
  446. );
  447. return ERROR_INTERFACE_DISABLED;
  448. }
  449. LeaveCriticalSection(&DhcpInterfaceLock);
  450. Error = NO_ERROR;
  451. ACQUIRE_LOCK(Interfacep);
  452. //
  453. // Compare the interface's current and new configuration
  454. //
  455. OldFlags = Interfacep->Info.Flags;
  456. NewFlags =
  457. (InterfaceInfo
  458. ? (InterfaceInfo->Flags|DHCP_INTERFACE_FLAG_CONFIGURED) : 0);
  459. Interfacep->Flags &= ~OldFlags;
  460. Interfacep->Flags |= NewFlags;
  461. if (!InterfaceInfo) {
  462. ZeroMemory(&Interfacep->Info, sizeof(IP_AUTO_DHCP_INTERFACE_INFO));
  463. //
  464. // The interface no longer has any information;
  465. // default to being enabled.
  466. //
  467. if (OldFlags & IP_AUTO_DHCP_INTERFACE_FLAG_DISABLED) {
  468. //
  469. // Activate the interface if necessary
  470. //
  471. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  472. RELEASE_LOCK(Interfacep);
  473. Error = DhcpActivateInterface(Interfacep);
  474. ACQUIRE_LOCK(Interfacep);
  475. }
  476. }
  477. }
  478. else {
  479. CopyMemory(
  480. &Interfacep->Info,
  481. InterfaceInfo,
  482. sizeof(IP_AUTO_DHCP_INTERFACE_INFO)
  483. );
  484. //
  485. // Activate or deactivate the interface if its status changed
  486. //
  487. if ((OldFlags & IP_AUTO_DHCP_INTERFACE_FLAG_DISABLED) &&
  488. !(NewFlags & IP_AUTO_DHCP_INTERFACE_FLAG_DISABLED)) {
  489. //
  490. // Activate the interface
  491. //
  492. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  493. RELEASE_LOCK(Interfacep);
  494. Error = DhcpActivateInterface(Interfacep);
  495. ACQUIRE_LOCK(Interfacep);
  496. }
  497. }
  498. else
  499. if (!(OldFlags & IP_AUTO_DHCP_INTERFACE_FLAG_DISABLED) &&
  500. (NewFlags & IP_AUTO_DHCP_INTERFACE_FLAG_DISABLED)) {
  501. //
  502. // Deactivate the interface if necessary
  503. //
  504. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  505. RELEASE_LOCK(Interfacep);
  506. DhcpDeactivateInterface(Interfacep);
  507. ACQUIRE_LOCK(Interfacep);
  508. }
  509. }
  510. }
  511. RELEASE_LOCK(Interfacep);
  512. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  513. return Error;
  514. } // DhcpConfigureInterface
  515. ULONG
  516. DhcpCreateInterface(
  517. ULONG Index,
  518. NET_INTERFACE_TYPE Type,
  519. PIP_AUTO_DHCP_INTERFACE_INFO InterfaceInfo,
  520. OUT PDHCP_INTERFACE* InterfaceCreated
  521. )
  522. /*++
  523. Routine Description:
  524. This routine is invoked by the router-manager to add a new interface
  525. to the DHCP allocator.
  526. Arguments:
  527. Index - the index of the new interface
  528. Type - the media type of the new interface
  529. InterfaceInfo - the interface's configuration
  530. Interfacep - receives the interface created
  531. Return Value:
  532. ULONG - Win32 error code
  533. Environment:
  534. Invoked internally in the context of an IP router-manager thread.
  535. (See 'RMDHCP.C').
  536. --*/
  537. {
  538. PLIST_ENTRY InsertionPoint;
  539. PDHCP_INTERFACE Interfacep;
  540. PROFILE("DhcpCreateInterface");
  541. EnterCriticalSection(&DhcpInterfaceLock);
  542. //
  543. // See if the interface already exists;
  544. // If not, this obtains the insertion point
  545. //
  546. if (DhcpLookupInterface(Index, &InsertionPoint)) {
  547. LeaveCriticalSection(&DhcpInterfaceLock);
  548. NhTrace(
  549. TRACE_FLAG_IF,
  550. "DhcpCreateInterface: duplicate index found for %d",
  551. Index
  552. );
  553. return ERROR_INTERFACE_ALREADY_EXISTS;
  554. }
  555. //
  556. // Allocate a new interface
  557. //
  558. Interfacep = reinterpret_cast<PDHCP_INTERFACE>(
  559. NH_ALLOCATE(sizeof(DHCP_INTERFACE))
  560. );
  561. if (!Interfacep) {
  562. LeaveCriticalSection(&DhcpInterfaceLock);
  563. NhTrace(
  564. TRACE_FLAG_IF, "DhcpCreateInterface: error allocating interface"
  565. );
  566. NhWarningLog(
  567. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  568. 0,
  569. "%d",
  570. sizeof(DHCP_INTERFACE)
  571. );
  572. return ERROR_NOT_ENOUGH_MEMORY;
  573. }
  574. //
  575. // Initialize the new interface
  576. //
  577. ZeroMemory(Interfacep, sizeof(*Interfacep));
  578. __try {
  579. InitializeCriticalSection(&Interfacep->Lock);
  580. }
  581. __except(EXCEPTION_EXECUTE_HANDLER) {
  582. LeaveCriticalSection(&DhcpInterfaceLock);
  583. NH_FREE(Interfacep);
  584. return GetExceptionCode();
  585. }
  586. Interfacep->Index = Index;
  587. Interfacep->Type = Type;
  588. if (InterfaceInfo) {
  589. Interfacep->Flags = InterfaceInfo->Flags|DHCP_INTERFACE_FLAG_CONFIGURED;
  590. CopyMemory(&Interfacep->Info, InterfaceInfo, sizeof(*InterfaceInfo));
  591. }
  592. Interfacep->ReferenceCount = 1;
  593. InsertTailList(InsertionPoint, &Interfacep->Link);
  594. LeaveCriticalSection(&DhcpInterfaceLock);
  595. if (InterfaceCreated) { *InterfaceCreated = Interfacep; }
  596. return NO_ERROR;
  597. } // DhcpCreateInterface
  598. VOID
  599. DhcpDeactivateInterface(
  600. PDHCP_INTERFACE Interfacep
  601. )
  602. /*++
  603. Routine Description:
  604. This routine is called to deactivate an interface.
  605. It closes all sockets on the interface's bindings (if any).
  606. Arguments:
  607. Interfacep - the interface to be deactivated
  608. Return Value:
  609. none.
  610. Environment:
  611. Always invoked locally, with 'Interfacep' referenced by caller and/or
  612. 'DhcpInterfaceLock' held by caller.
  613. --*/
  614. {
  615. ULONG i;
  616. PROFILE("DhcpDeactivateInterface");
  617. //
  618. // Stop all network I/O on the interface's logical networks
  619. //
  620. ACQUIRE_LOCK(Interfacep);
  621. for (i = 0; i < Interfacep->BindingCount; i++) {
  622. if (Interfacep->BindingArray[i].Socket != INVALID_SOCKET) {
  623. NhDeleteDatagramSocket(Interfacep->BindingArray[i].Socket);
  624. Interfacep->BindingArray[i].Socket = INVALID_SOCKET;
  625. }
  626. if (Interfacep->BindingArray[i].ClientSocket != INVALID_SOCKET) {
  627. NhDeleteDatagramSocket(Interfacep->BindingArray[i].ClientSocket);
  628. Interfacep->BindingArray[i].ClientSocket = INVALID_SOCKET;
  629. }
  630. }
  631. //
  632. // clear interface status as a non boundary NAT interface
  633. //
  634. Interfacep->Flags &= ~DHCP_INTERFACE_FLAG_NAT_NONBOUNDARY;
  635. RELEASE_LOCK(Interfacep);
  636. } // DhcpDeactivateInterface
  637. VOID NTAPI
  638. DhcpDeferReadCallbackRoutine(
  639. PVOID Context,
  640. BOOLEAN TimedOut
  641. )
  642. /*++
  643. Routine Description:
  644. This routine is invoked to re-issue a deferred read when the countdown
  645. for the deferral completes.
  646. Arguments:
  647. Context - holds information identifying the interface and socket
  648. TimedOut - indicates whether the countdown completed
  649. Return Value:
  650. none.
  651. Environment:
  652. Invoked with an outstanding reference to the component on our behalf.
  653. --*/
  654. {
  655. PDHCP_DEFER_READ_CONTEXT Contextp;
  656. ULONG Error;
  657. ULONG i;
  658. PDHCP_INTERFACE Interfacep;
  659. NTSTATUS status;
  660. PROFILE("DhcpDeferReadCallbackRoutine");
  661. Contextp = (PDHCP_DEFER_READ_CONTEXT)Context;
  662. //
  663. // Find the interface on which the read was deferred
  664. //
  665. EnterCriticalSection(&DhcpInterfaceLock);
  666. Interfacep = DhcpLookupInterface(Contextp->Index, NULL);
  667. if (!Interfacep ||
  668. !DHCP_INTERFACE_ACTIVE(Interfacep) ||
  669. !DHCP_REFERENCE_INTERFACE(Interfacep)) {
  670. LeaveCriticalSection(&DhcpInterfaceLock);
  671. NH_FREE(Contextp);
  672. DEREFERENCE_DHCP();
  673. return;
  674. }
  675. LeaveCriticalSection(&DhcpInterfaceLock);
  676. ACQUIRE_LOCK(Interfacep);
  677. //
  678. // Search for the socket on which to reissue the read
  679. //
  680. for (i = 0; i < Interfacep->BindingCount; i++) {
  681. if (Interfacep->BindingArray[i].Socket != Contextp->Socket) {continue;}
  682. //
  683. // This is the binding on which to reissue the read.
  684. // If no pending timer is recorded, assume a rebind occurred, and quit.
  685. //
  686. if (!Interfacep->BindingArray[i].TimerPending) { break; }
  687. Interfacep->BindingArray[i].TimerPending = FALSE;
  688. Error =
  689. NhReadDatagramSocket(
  690. &DhcpComponentReference,
  691. Interfacep->BindingArray[i].Socket,
  692. NULL,
  693. DhcpReadCompletionRoutine,
  694. Interfacep,
  695. UlongToPtr(Interfacep->BindingArray[i].Mask)
  696. );
  697. RELEASE_LOCK(Interfacep);
  698. if (!Error) {
  699. NH_FREE(Contextp);
  700. DEREFERENCE_DHCP();
  701. return;
  702. }
  703. //
  704. // An error occurred; we'll have to retry later.
  705. // we queue a work item which sets the timer.
  706. //
  707. NhTrace(
  708. TRACE_FLAG_DHCP,
  709. "DhcpDeferReadCallbackRoutine: error %d reading interface %d",
  710. Error,
  711. Interfacep->Index
  712. );
  713. //
  714. // Reference the component on behalf of the work-item
  715. //
  716. if (REFERENCE_DHCP()) {
  717. //
  718. // Queue a work-item, reusing the deferral context
  719. //
  720. status =
  721. RtlQueueWorkItem(
  722. DhcpDeferReadWorkerRoutine,
  723. Contextp,
  724. WT_EXECUTEINIOTHREAD
  725. );
  726. if (NT_SUCCESS(status)) {
  727. Contextp = NULL;
  728. }
  729. else {
  730. NH_FREE(Contextp);
  731. NhTrace(
  732. TRACE_FLAG_DHCP,
  733. "DhcpDeferReadCallbackRoutine: error %d deferring %d",
  734. Error,
  735. Interfacep->Index
  736. );
  737. DEREFERENCE_DHCP();
  738. }
  739. }
  740. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  741. DEREFERENCE_DHCP();
  742. return;
  743. }
  744. //
  745. // The interface was not found; never mind.
  746. //
  747. RELEASE_LOCK(Interfacep);
  748. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  749. NH_FREE(Contextp);
  750. DEREFERENCE_DHCP();
  751. } // DhcpDeferReadCallbackRoutine
  752. VOID
  753. DhcpDeferReadInterface(
  754. PDHCP_INTERFACE Interfacep,
  755. SOCKET Socket
  756. )
  757. /*++
  758. Routine Description:
  759. This routine is invoked to defer a read-request on an interface,
  760. typically if an attempt to post a read failed.
  761. Arguments:
  762. Interfacep - the interface on which to defer the request
  763. Socket - the socket on which to defer the request
  764. Return Value:
  765. none.
  766. Environment:
  767. Invoked with 'Interfacep' referenced and locked by the caller.
  768. The caller may release the reference upon return.
  769. --*/
  770. {
  771. PDHCP_DEFER_READ_CONTEXT Contextp;
  772. ULONG i;
  773. NTSTATUS status;
  774. PROFILE("DhcpDeferReadInterface");
  775. //
  776. // Find the binding for the given socket.
  777. //
  778. status = STATUS_SUCCESS;
  779. for (i = 0; i < Interfacep->BindingCount; i++) {
  780. if (Interfacep->BindingArray[i].Socket != Socket) { continue; }
  781. //
  782. // This is the binding. If there is already a timer for it,
  783. // then just return silently.
  784. //
  785. if (Interfacep->BindingArray[i].TimerPending) {
  786. status = STATUS_UNSUCCESSFUL;
  787. break;
  788. }
  789. //
  790. // Allocate a context block for the deferral.
  791. //
  792. Contextp =
  793. (PDHCP_DEFER_READ_CONTEXT)
  794. NH_ALLOCATE(sizeof(DHCP_DEFER_READ_CONTEXT));
  795. if (!Contextp) {
  796. NhTrace(
  797. TRACE_FLAG_DHCP,
  798. "DhcpDeferReadInterface: cannot allocate deferral context"
  799. );
  800. status = STATUS_NO_MEMORY;
  801. break;
  802. }
  803. Contextp->Index = Interfacep->Index;
  804. Contextp->Socket = Socket;
  805. Contextp->DeferralCount = 1;
  806. //
  807. // Install a timer to re-issue the read request
  808. //
  809. status =
  810. NhSetTimer(
  811. &DhcpComponentReference,
  812. NULL,
  813. DhcpDeferReadCallbackRoutine,
  814. Contextp,
  815. DHCP_DEFER_READ_TIMEOUT
  816. );
  817. if (NT_SUCCESS(status)) {
  818. Interfacep->BindingArray[i].TimerPending = TRUE;
  819. }
  820. else {
  821. NH_FREE(Contextp);
  822. NhTrace(
  823. TRACE_FLAG_DHCP,
  824. "DhcpDeferReadInterface: status %08x setting deferral timer",
  825. status
  826. );
  827. }
  828. break;
  829. }
  830. if (i >= Interfacep->BindingCount) { status = STATUS_UNSUCCESSFUL; }
  831. } // DhcpDeferReadInterface
  832. VOID APIENTRY
  833. DhcpDeferReadWorkerRoutine(
  834. PVOID Context
  835. )
  836. /*++
  837. Routine Description:
  838. This routine is invoked to set a timer for reissuing a deferred read.
  839. Arguments:
  840. Context - contains the context for the timer.
  841. Return Value:
  842. none.
  843. Environment:
  844. Invoked with an outstanding reference to the module made on our behalf.
  845. --*/
  846. {
  847. PDHCP_DEFER_READ_CONTEXT Contextp;
  848. ULONG i;
  849. PDHCP_INTERFACE Interfacep;
  850. NTSTATUS status;
  851. PROFILE("DhcpDeferReadWorkerRoutine");
  852. Contextp = (PDHCP_DEFER_READ_CONTEXT)Context;
  853. ++Contextp->DeferralCount;
  854. //
  855. // Find the interface on which the read was deferred
  856. //
  857. EnterCriticalSection(&DhcpInterfaceLock);
  858. Interfacep = DhcpLookupInterface(Contextp->Index, NULL);
  859. if (!Interfacep ||
  860. !DHCP_INTERFACE_ACTIVE(Interfacep) ||
  861. !DHCP_REFERENCE_INTERFACE(Interfacep)) {
  862. LeaveCriticalSection(&DhcpInterfaceLock);
  863. NH_FREE(Contextp);
  864. DEREFERENCE_DHCP();
  865. return;
  866. }
  867. LeaveCriticalSection(&DhcpInterfaceLock);
  868. ACQUIRE_LOCK(Interfacep);
  869. //
  870. // Search for the binding on which to set the timer
  871. //
  872. for (i = 0; i < Interfacep->BindingCount; i++) {
  873. if (Interfacep->BindingArray[i].Socket != Contextp->Socket) {continue;}
  874. //
  875. // This is the binding on which to reissue the read.
  876. // If a timer is already pending, assume a rebind occurred, and quit.
  877. //
  878. if (Interfacep->BindingArray[i].TimerPending) { break; }
  879. //
  880. // Install a timer to re-issue the read request,
  881. // reusing the deferral context.
  882. //
  883. status =
  884. NhSetTimer(
  885. &DhcpComponentReference,
  886. NULL,
  887. DhcpDeferReadCallbackRoutine,
  888. Contextp,
  889. DHCP_DEFER_READ_TIMEOUT
  890. );
  891. if (NT_SUCCESS(status)) {
  892. Contextp = NULL;
  893. Interfacep->BindingArray[i].TimerPending = TRUE;
  894. }
  895. else {
  896. NhTrace(
  897. TRACE_FLAG_DHCP,
  898. "DhcpDeferReadWorkerRoutine: status %08x setting timer",
  899. status
  900. );
  901. }
  902. }
  903. RELEASE_LOCK(Interfacep);
  904. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  905. if (Contextp) { NH_FREE(Contextp); }
  906. DEREFERENCE_DHCP();
  907. } // DhcpDeferReadWorkerRoutine
  908. ULONG
  909. DhcpDeleteInterface(
  910. ULONG Index
  911. )
  912. /*++
  913. Routine Description:
  914. This routine is called to delete an interface.
  915. It drops the reference count on the interface so that the last
  916. dereferencer will delete the interface, and sets the 'deleted' flag
  917. so that further references to the interface will fail.
  918. Arguments:
  919. Index - the index of the interface to be deleted
  920. Return Value:
  921. ULONG - Win32 status code.
  922. Environment:
  923. Invoked internally in the context of an IP router-manager thread.
  924. (See 'RMDHCP.C').
  925. --*/
  926. {
  927. PDHCP_INTERFACE Interfacep;
  928. PROFILE("DhcpDeleteInterface");
  929. //
  930. // Retrieve the interface to be deleted
  931. //
  932. EnterCriticalSection(&DhcpInterfaceLock);
  933. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  934. LeaveCriticalSection(&DhcpInterfaceLock);
  935. NhTrace(
  936. TRACE_FLAG_IF,
  937. "DhcpDeleteInterface: interface %d not found",
  938. Index
  939. );
  940. return ERROR_NO_SUCH_INTERFACE;
  941. }
  942. //
  943. // Make sure it isn't already deleted
  944. //
  945. if (DHCP_INTERFACE_DELETED(Interfacep)) {
  946. LeaveCriticalSection(&DhcpInterfaceLock);
  947. NhTrace(
  948. TRACE_FLAG_IF,
  949. "DhcpDeleteInterface: interface %d already deleted",
  950. Index
  951. );
  952. return ERROR_NO_SUCH_INTERFACE;
  953. }
  954. //
  955. // Deactivate the interface
  956. //
  957. DhcpDeactivateInterface(Interfacep);
  958. //
  959. // Mark the interface as deleted and take it off the interface list
  960. //
  961. Interfacep->Flags |= DHCP_INTERFACE_FLAG_DELETED;
  962. Interfacep->Flags &= ~DHCP_INTERFACE_FLAG_ENABLED;
  963. RemoveEntryList(&Interfacep->Link);
  964. //
  965. // Drop the reference count; if it is non-zero,
  966. // the deletion will complete later.
  967. //
  968. if (--Interfacep->ReferenceCount) {
  969. LeaveCriticalSection(&DhcpInterfaceLock);
  970. NhTrace(
  971. TRACE_FLAG_IF,
  972. "DhcpDeleteInterface: interface %d deletion pending",
  973. Index
  974. );
  975. return NO_ERROR;
  976. }
  977. //
  978. // The reference count is zero, so perform final cleanup
  979. //
  980. DhcpCleanupInterface(Interfacep);
  981. LeaveCriticalSection(&DhcpInterfaceLock);
  982. return NO_ERROR;
  983. } // DhcpDeleteInterface
  984. ULONG
  985. DhcpDisableInterface(
  986. ULONG Index
  987. )
  988. /*++
  989. Routine Description:
  990. This routine is called to disable I/O on an interface.
  991. If the interface is active, it is deactivated.
  992. Arguments:
  993. Index - the index of the interface to be disabled.
  994. Return Value:
  995. none.
  996. Environment:
  997. Invoked internally in the context of an IP router-manager thread.
  998. (See 'RMDHCP.C').
  999. --*/
  1000. {
  1001. PDHCP_INTERFACE Interfacep;
  1002. PROFILE("DhcpDisableInterface");
  1003. //
  1004. // Retrieve the interface to be disabled
  1005. //
  1006. EnterCriticalSection(&DhcpInterfaceLock);
  1007. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  1008. LeaveCriticalSection(&DhcpInterfaceLock);
  1009. NhTrace(
  1010. TRACE_FLAG_IF,
  1011. "DhcpDisableInterface: interface %d not found",
  1012. Index
  1013. );
  1014. return ERROR_NO_SUCH_INTERFACE;
  1015. }
  1016. //
  1017. // Make sure the interface is not already disabled
  1018. //
  1019. if (!DHCP_INTERFACE_ENABLED(Interfacep)) {
  1020. LeaveCriticalSection(&DhcpInterfaceLock);
  1021. NhTrace(
  1022. TRACE_FLAG_IF,
  1023. "DhcpDisableInterface: interface %d already disabled",
  1024. Index
  1025. );
  1026. return ERROR_INTERFACE_DISABLED;
  1027. }
  1028. //
  1029. // Reference the interface
  1030. //
  1031. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1032. LeaveCriticalSection(&DhcpInterfaceLock);
  1033. NhTrace(
  1034. TRACE_FLAG_IF,
  1035. "DhcpDisableInterface: interface %d cannot be referenced",
  1036. Index
  1037. );
  1038. return ERROR_INTERFACE_DISABLED;
  1039. }
  1040. //
  1041. // Clear the 'enabled' flag
  1042. //
  1043. Interfacep->Flags &= ~DHCP_INTERFACE_FLAG_ENABLED;
  1044. //
  1045. // Deactivate the interface, if necessary
  1046. //
  1047. if (DHCP_INTERFACE_BOUND(Interfacep)) {
  1048. DhcpDeactivateInterface(Interfacep);
  1049. }
  1050. LeaveCriticalSection(&DhcpInterfaceLock);
  1051. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1052. return NO_ERROR;
  1053. } // DhcpDisableInterface
  1054. ULONG
  1055. DhcpEnableInterface(
  1056. ULONG Index
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine is called to enable I/O on an interface.
  1061. If the interface is already bound, this enabling activates it.
  1062. Arguments:
  1063. Index - the index of the interfaec to be enabled
  1064. Return Value:
  1065. ULONG - Win32 status code.
  1066. Environment:
  1067. Invoked internally in the context of an IP router-manager thread.
  1068. (See 'RMDHCP.C').
  1069. --*/
  1070. {
  1071. ULONG Error = NO_ERROR;
  1072. PDHCP_INTERFACE Interfacep;
  1073. PROFILE("DhcpEnableInterface");
  1074. //
  1075. // Retrieve the interface to be enabled
  1076. //
  1077. EnterCriticalSection(&DhcpInterfaceLock);
  1078. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  1079. LeaveCriticalSection(&DhcpInterfaceLock);
  1080. NhTrace(
  1081. TRACE_FLAG_IF,
  1082. "DhcpEnableInterface: interface %d not found",
  1083. Index
  1084. );
  1085. return ERROR_NO_SUCH_INTERFACE;
  1086. }
  1087. //
  1088. // Make sure the interface is not already enabled
  1089. //
  1090. if (DHCP_INTERFACE_ENABLED(Interfacep)) {
  1091. LeaveCriticalSection(&DhcpInterfaceLock);
  1092. NhTrace(
  1093. TRACE_FLAG_IF,
  1094. "DhcpEnableInterface: interface %d already enabled",
  1095. Index
  1096. );
  1097. return ERROR_INTERFACE_ALREADY_EXISTS;
  1098. }
  1099. //
  1100. // Reference the interface
  1101. //
  1102. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1103. LeaveCriticalSection(&DhcpInterfaceLock);
  1104. NhTrace(
  1105. TRACE_FLAG_IF,
  1106. "DhcpEnableInterface: interface %d cannot be referenced",
  1107. Index
  1108. );
  1109. return ERROR_INTERFACE_DISABLED;
  1110. }
  1111. //
  1112. // Set the 'enabled' flag
  1113. //
  1114. Interfacep->Flags |= DHCP_INTERFACE_FLAG_ENABLED;
  1115. //
  1116. // Activate the interface, if necessary
  1117. //
  1118. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  1119. Error = DhcpActivateInterface(Interfacep);
  1120. }
  1121. LeaveCriticalSection(&DhcpInterfaceLock);
  1122. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1123. return Error;
  1124. } // DhcpEnableInterface
  1125. ULONG
  1126. DhcpInitializeInterfaceManagement(
  1127. VOID
  1128. )
  1129. /*++
  1130. Routine Description:
  1131. This routine is called to initialize the interface-management module.
  1132. Arguments:
  1133. none.
  1134. Return Value:
  1135. ULONG - Win32 status code.
  1136. Environment:
  1137. Invoked internally in the context of an IP router-manager thread.
  1138. (See 'RMDHCP.C').
  1139. --*/
  1140. {
  1141. ULONG Error = NO_ERROR;
  1142. PROFILE("DhcpInitializeInterfaceManagement");
  1143. InitializeListHead(&DhcpInterfaceList);
  1144. __try {
  1145. InitializeCriticalSection(&DhcpInterfaceLock);
  1146. }
  1147. __except(EXCEPTION_EXECUTE_HANDLER) {
  1148. NhTrace(
  1149. TRACE_FLAG_IF,
  1150. "DhcpInitializeInterfaceManagement: exception %d creating lock",
  1151. Error = GetExceptionCode()
  1152. );
  1153. }
  1154. return Error;
  1155. } // DhcpInitializeInterfaceManagement
  1156. BOOLEAN
  1157. DhcpIsLocalHardwareAddress(
  1158. PUCHAR HardwareAddress,
  1159. ULONG HardwareAddressLength
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. This routine is invoked to determine whether the given hardware address
  1164. is for a local interface.
  1165. Arguments:
  1166. HardwareAddress - the hardware address to find
  1167. HardwareAddressLength - the length of the hardware address in bytes
  1168. Return Value:
  1169. BOOLEAN - TRUE if the address is found, FALSE otherwise
  1170. --*/
  1171. {
  1172. ULONG Error;
  1173. ULONG i;
  1174. PMIB_IFTABLE Table;
  1175. //
  1176. // if the hardware address length is zero, assume external address
  1177. //
  1178. if (!HardwareAddressLength || !HardwareAddress)
  1179. {
  1180. return FALSE;
  1181. }
  1182. Error =
  1183. AllocateAndGetIfTableFromStack(
  1184. &Table, FALSE, GetProcessHeap(), 0, FALSE
  1185. );
  1186. if (Error) {
  1187. NhTrace(
  1188. TRACE_FLAG_IF,
  1189. "DhcpIsLocalHardwareAddress: GetIfTableFromStack=%d", Error
  1190. );
  1191. return FALSE;
  1192. }
  1193. for (i = 0; i < Table->dwNumEntries; i++) {
  1194. if (Table->table[i].dwPhysAddrLen == HardwareAddressLength &&
  1195. memcmp(
  1196. Table->table[i].bPhysAddr,
  1197. HardwareAddress,
  1198. HardwareAddressLength
  1199. ) == 0) {
  1200. HeapFree(GetProcessHeap(), 0, Table);
  1201. return TRUE;
  1202. }
  1203. }
  1204. HeapFree(GetProcessHeap(), 0, Table);
  1205. return FALSE;
  1206. } // DhcpIsLocalHardwareAddress
  1207. PDHCP_INTERFACE
  1208. DhcpLookupInterface(
  1209. ULONG Index,
  1210. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. This routine is called to retrieve an interface given its index.
  1215. Arguments:
  1216. Index - the index of the interface to be retrieved
  1217. InsertionPoint - if the interface is not found, optionally receives
  1218. the point where the interface would be inserted in the interface list
  1219. Return Value:
  1220. PDHCP_INTERFACE - the interface, if found; otherwise, NULL.
  1221. Environment:
  1222. Invoked internally from an arbitrary context, with 'DhcpInterfaceLock'
  1223. held by caller.
  1224. --*/
  1225. {
  1226. PDHCP_INTERFACE Interfacep;
  1227. PLIST_ENTRY Link;
  1228. PROFILE("DhcpLookupInterface");
  1229. for (Link = DhcpInterfaceList.Flink;
  1230. Link != &DhcpInterfaceList;
  1231. Link = Link->Flink
  1232. ) {
  1233. Interfacep = CONTAINING_RECORD(Link, DHCP_INTERFACE, Link);
  1234. if (Index > Interfacep->Index) { continue; }
  1235. else
  1236. if (Index < Interfacep->Index) { break; }
  1237. return Interfacep;
  1238. }
  1239. if (InsertionPoint) { *InsertionPoint = Link; }
  1240. return NULL;
  1241. } // DhcpLookupInterface
  1242. ULONG
  1243. DhcpQueryInterface(
  1244. ULONG Index,
  1245. PVOID InterfaceInfo,
  1246. PULONG InterfaceInfoSize
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. This routine is invoked to retrieve the configuration for an interface.
  1251. Arguments:
  1252. Index - the interface to be queried
  1253. InterfaceInfo - receives the retrieved information
  1254. InterfaceInfoSize - receives the (required) size of the information
  1255. Return Value:
  1256. ULONG - Win32 status code.
  1257. --*/
  1258. {
  1259. PDHCP_INTERFACE Interfacep;
  1260. PROFILE("DhcpQueryInterface");
  1261. //
  1262. // Check the caller's buffer size
  1263. //
  1264. if (!InterfaceInfoSize) { return ERROR_INVALID_PARAMETER; }
  1265. //
  1266. // Retrieve the interface to be configured
  1267. //
  1268. EnterCriticalSection(&DhcpInterfaceLock);
  1269. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  1270. LeaveCriticalSection(&DhcpInterfaceLock);
  1271. NhTrace(
  1272. TRACE_FLAG_IF,
  1273. "DhcpQueryInterface: interface %d not found",
  1274. Index
  1275. );
  1276. return ERROR_NO_SUCH_INTERFACE;
  1277. }
  1278. //
  1279. // Reference the interface
  1280. //
  1281. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1282. LeaveCriticalSection(&DhcpInterfaceLock);
  1283. NhTrace(
  1284. TRACE_FLAG_IF,
  1285. "DhcpQueryInterface: interface %d cannot be referenced",
  1286. Index
  1287. );
  1288. return ERROR_INTERFACE_DISABLED;
  1289. }
  1290. //
  1291. // See if there is any explicit config on this interface
  1292. //
  1293. if (!DHCP_INTERFACE_CONFIGURED(Interfacep)) {
  1294. LeaveCriticalSection(&DhcpInterfaceLock);
  1295. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1296. NhTrace(
  1297. TRACE_FLAG_IF,
  1298. "DhcpQueryInterface: interface %d has no configuration",
  1299. Index
  1300. );
  1301. *InterfaceInfoSize = 0;
  1302. return NO_ERROR;
  1303. }
  1304. if (*InterfaceInfoSize < sizeof(IP_AUTO_DHCP_INTERFACE_INFO)) {
  1305. LeaveCriticalSection(&DhcpInterfaceLock);
  1306. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1307. *InterfaceInfoSize = sizeof(IP_AUTO_DHCP_INTERFACE_INFO);
  1308. return ERROR_INSUFFICIENT_BUFFER;
  1309. }
  1310. if (!InterfaceInfo) {
  1311. LeaveCriticalSection(&DhcpInterfaceLock);
  1312. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1313. return ERROR_INVALID_PARAMETER;
  1314. }
  1315. //
  1316. // Copy the requested data
  1317. //
  1318. CopyMemory(
  1319. InterfaceInfo,
  1320. &Interfacep->Info,
  1321. sizeof(IP_AUTO_DHCP_INTERFACE_INFO)
  1322. );
  1323. *InterfaceInfoSize = sizeof(IP_AUTO_DHCP_INTERFACE_INFO);
  1324. LeaveCriticalSection(&DhcpInterfaceLock);
  1325. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1326. return NO_ERROR;
  1327. } // DhcpQueryInterface
  1328. VOID
  1329. DhcpReactivateEveryInterface(
  1330. VOID
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This routine is called to reactivate all activate interfaces
  1335. when a change occurs to the global DHCP configuration.
  1336. Thus if, for instance, the scope network has been changed and is now
  1337. either valid or invalid, during deactivation all sockets are closed,
  1338. and during reactivation they are or are not reopened as appropriate.
  1339. depending on the validity or invalidity of the new configuration.
  1340. Arguments:
  1341. none.
  1342. Return Value:
  1343. none.
  1344. Environment:
  1345. Invoked from a router-manager thread with no locks held.
  1346. --*/
  1347. {
  1348. PDHCP_INTERFACE Interfacep;
  1349. PLIST_ENTRY Link;
  1350. PROFILE("DhcpReactivateEveryInterface");
  1351. EnterCriticalSection(&DhcpInterfaceLock);
  1352. for (Link = DhcpInterfaceList.Flink; Link != &DhcpInterfaceList;
  1353. Link = Link->Flink) {
  1354. Interfacep = CONTAINING_RECORD(Link, DHCP_INTERFACE, Link);
  1355. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) { continue; }
  1356. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  1357. DhcpDeactivateInterface(Interfacep);
  1358. DhcpActivateInterface(Interfacep);
  1359. }
  1360. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1361. }
  1362. LeaveCriticalSection(&DhcpInterfaceLock);
  1363. } // DhcpReactivateEveryInterface
  1364. VOID
  1365. DhcpShutdownInterfaceManagement(
  1366. VOID
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. This routine is called to shutdown the interface-management module.
  1371. Arguments:
  1372. none.
  1373. Return Value:
  1374. none.
  1375. Environment:
  1376. Invoked internally in an arbitrary thread context,
  1377. after all references to all interfaces have been released.
  1378. --*/
  1379. {
  1380. PDHCP_INTERFACE Interfacep;
  1381. PLIST_ENTRY Link;
  1382. PROFILE("DhcpShutdownInterfaceManagement");
  1383. while (!IsListEmpty(&DhcpInterfaceList)) {
  1384. Link = RemoveHeadList(&DhcpInterfaceList);
  1385. Interfacep = CONTAINING_RECORD(Link, DHCP_INTERFACE, Link);
  1386. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  1387. DhcpDeactivateInterface(Interfacep);
  1388. }
  1389. DhcpCleanupInterface(Interfacep);
  1390. }
  1391. DeleteCriticalSection(&DhcpInterfaceLock);
  1392. } // DhcpShutdownInterfaceManagement
  1393. VOID
  1394. DhcpSignalNatInterface(
  1395. ULONG Index,
  1396. BOOLEAN Boundary
  1397. )
  1398. /*++
  1399. Routine Description:
  1400. This routine is invoked upon reconfiguration of a NAT interface.
  1401. Note that this routine may be invoked even when the DHCP allocator
  1402. is neither installed nor running; it operates as expected,
  1403. since the interface list and lock are always initialized.
  1404. Arguments:
  1405. Index - the reconfigured interface
  1406. Boundary - indicates whether the interface is now a boundary interface
  1407. Return Value:
  1408. none.
  1409. Environment:
  1410. Invoked from an arbitrary context.
  1411. --*/
  1412. {
  1413. PDHCP_INTERFACE Interfacep;
  1414. PROFILE("DhcpSignalNatInterface");
  1415. EnterCriticalSection(&DhcpGlobalInfoLock);
  1416. if (!DhcpGlobalInfo) {
  1417. LeaveCriticalSection(&DhcpGlobalInfoLock);
  1418. return;
  1419. }
  1420. LeaveCriticalSection(&DhcpGlobalInfoLock);
  1421. EnterCriticalSection(&DhcpInterfaceLock);
  1422. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  1423. LeaveCriticalSection(&DhcpInterfaceLock);
  1424. return;
  1425. }
  1426. DhcpDeactivateInterface(Interfacep);
  1427. if (DHCP_INTERFACE_ACTIVE(Interfacep)) {
  1428. DhcpActivateInterface(Interfacep);
  1429. }
  1430. LeaveCriticalSection(&DhcpInterfaceLock);
  1431. } // DhcpSignalNatInterface
  1432. ULONG
  1433. DhcpUnbindInterface(
  1434. ULONG Index
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. This routine is invoked to revoke the binding on an interface.
  1439. This involves deactivating the interface if it is active.
  1440. Arguments:
  1441. Index - the index of the interface to be unbound
  1442. Return Value:
  1443. none.
  1444. Environment:
  1445. Invoked internally in the context of an IP router-manager thread.
  1446. (See 'RMDHCP.C').
  1447. --*/
  1448. {
  1449. PDHCP_INTERFACE Interfacep;
  1450. PROFILE("DhcpUnbindInterface");
  1451. //
  1452. // Retrieve the interface to be unbound
  1453. //
  1454. EnterCriticalSection(&DhcpInterfaceLock);
  1455. if (!(Interfacep = DhcpLookupInterface(Index, NULL))) {
  1456. LeaveCriticalSection(&DhcpInterfaceLock);
  1457. NhTrace(
  1458. TRACE_FLAG_IF,
  1459. "DhcpUnbindInterface: interface %d not found",
  1460. Index
  1461. );
  1462. return ERROR_NO_SUCH_INTERFACE;
  1463. }
  1464. //
  1465. // Make sure the interface is not already unbound
  1466. //
  1467. if (!DHCP_INTERFACE_BOUND(Interfacep)) {
  1468. LeaveCriticalSection(&DhcpInterfaceLock);
  1469. NhTrace(
  1470. TRACE_FLAG_IF,
  1471. "DhcpUnbindInterface: interface %d already unbound",
  1472. Index
  1473. );
  1474. return ERROR_ADDRESS_NOT_ASSOCIATED;
  1475. }
  1476. //
  1477. // Reference the interface
  1478. //
  1479. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1480. LeaveCriticalSection(&DhcpInterfaceLock);
  1481. NhTrace(
  1482. TRACE_FLAG_IF,
  1483. "DhcpUnbindInterface: interface %d cannot be referenced",
  1484. Index
  1485. );
  1486. return ERROR_INTERFACE_DISABLED;
  1487. }
  1488. //
  1489. // Clear the 'bound' flag
  1490. //
  1491. Interfacep->Flags &= ~DHCP_INTERFACE_FLAG_BOUND;
  1492. //
  1493. // Deactivate the interface, if necessary
  1494. //
  1495. if (DHCP_INTERFACE_ENABLED(Interfacep)) {
  1496. DhcpDeactivateInterface(Interfacep);
  1497. }
  1498. LeaveCriticalSection(&DhcpInterfaceLock);
  1499. //
  1500. // Destroy the interface's binding
  1501. //
  1502. ACQUIRE_LOCK(Interfacep);
  1503. if (Interfacep->BindingArray)
  1504. {
  1505. NH_FREE(Interfacep->BindingArray);
  1506. Interfacep->BindingArray = NULL;
  1507. }
  1508. Interfacep->BindingCount = 0;
  1509. RELEASE_LOCK(Interfacep);
  1510. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1511. return NO_ERROR;
  1512. } // DhcpUnbindInterface
  1513. ULONG
  1514. DhcpGetPrivateInterfaceAddress(
  1515. VOID
  1516. )
  1517. /*++
  1518. Routine Description:
  1519. This routine is invoked to return the IP address on which DHCP
  1520. has been enabled (and which matches the scope net and mask).
  1521. Arguments:
  1522. none.
  1523. Return Value:
  1524. Bound IP address if an address is found (else 0).
  1525. Environment:
  1526. Invoked from an arbitrary context.
  1527. --*/
  1528. {
  1529. PROFILE("DhcpGetPrivateInterfaceAddress");
  1530. ULONG ipAddr = 0;
  1531. ULONG ulRet = NO_ERROR;
  1532. //
  1533. // Find out the interface on which we are enabled and
  1534. // return the primary IP address to which we are bound.
  1535. // (Try to match the scope to the IP address.)
  1536. //
  1537. PDHCP_INTERFACE Interfacep = NULL;
  1538. PLIST_ENTRY Link;
  1539. ULONG i;
  1540. BOOLEAN IsNatInterface;
  1541. //
  1542. // Get Scope information from DHCP Global Info
  1543. //
  1544. ULONG ScopeNetwork = 0;
  1545. ULONG ScopeMask = 0;
  1546. EnterCriticalSection(&DhcpGlobalInfoLock);
  1547. //
  1548. // Check to see if we have been initialized
  1549. //
  1550. if (!DhcpGlobalInfo)
  1551. {
  1552. LeaveCriticalSection(&DhcpGlobalInfoLock);
  1553. return ipAddr;
  1554. }
  1555. ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
  1556. ScopeMask = DhcpGlobalInfo->ScopeMask;
  1557. LeaveCriticalSection(&DhcpGlobalInfoLock);
  1558. EnterCriticalSection(&DhcpInterfaceLock);
  1559. if (ScopeNetwork && ScopeMask)
  1560. {
  1561. ULONG NetAddress = ScopeNetwork & ScopeMask;
  1562. //
  1563. // Search & Retrieve the interface to be configured
  1564. //
  1565. for (Link = DhcpInterfaceList.Flink;
  1566. Link != &DhcpInterfaceList;
  1567. Link = Link->Flink
  1568. )
  1569. {
  1570. Interfacep = CONTAINING_RECORD(Link, DHCP_INTERFACE, Link);
  1571. ACQUIRE_LOCK(Interfacep);
  1572. if (DhcpInterfacePrivate != Interfacep->DhcpInterfaceType)
  1573. {
  1574. RELEASE_LOCK(Interfacep);
  1575. continue;
  1576. }
  1577. for (i = 0; i < Interfacep->BindingCount; i++)
  1578. {
  1579. NhTrace(
  1580. TRACE_FLAG_DHCP,
  1581. "DhcpGetPrivateInterfaceAddress: IP address %s (Index %d)",
  1582. INET_NTOA(Interfacep->BindingArray[i].Address),
  1583. Interfacep->Index
  1584. );
  1585. if (NetAddress == (Interfacep->BindingArray[i].Address &
  1586. Interfacep->BindingArray[i].Mask))
  1587. {
  1588. ipAddr = Interfacep->BindingArray[i].Address;
  1589. break;
  1590. }
  1591. }
  1592. RELEASE_LOCK(Interfacep);
  1593. if (ipAddr)
  1594. {
  1595. LeaveCriticalSection(&DhcpInterfaceLock);
  1596. NhTrace(
  1597. TRACE_FLAG_DHCP,
  1598. "DhcpGetPrivateInterfaceAddress: Dhcp private interface IP address %s (Index %d)",
  1599. INET_NTOA(ipAddr),
  1600. Interfacep->Index
  1601. );
  1602. return ipAddr;
  1603. }
  1604. }
  1605. }
  1606. // default to trying interface 0
  1607. if (!(Interfacep = DhcpLookupInterface(0, NULL)))
  1608. {
  1609. LeaveCriticalSection(&DhcpInterfaceLock);
  1610. NhTrace(
  1611. TRACE_FLAG_DHCP,
  1612. "DhcpGetPrivateInterfaceAddress: interface index 0 (default) not found"
  1613. );
  1614. return 0;
  1615. }
  1616. ACQUIRE_LOCK(Interfacep);
  1617. if (DhcpInterfacePrivate != Interfacep->DhcpInterfaceType)
  1618. {
  1619. RELEASE_LOCK(Interfacep);
  1620. LeaveCriticalSection(&DhcpInterfaceLock);
  1621. return 0;
  1622. }
  1623. if (Interfacep->BindingCount)
  1624. {
  1625. //
  1626. // simply take the first address available
  1627. //
  1628. ipAddr = Interfacep->BindingArray[0].Address;
  1629. }
  1630. RELEASE_LOCK(Interfacep);
  1631. LeaveCriticalSection(&DhcpInterfaceLock);
  1632. NhTrace(
  1633. TRACE_FLAG_DHCP,
  1634. "DhcpGetPrivateInterfaceAddress: Dhcp private interface IP address %s (Index 0)",
  1635. INET_NTOA(ipAddr)
  1636. );
  1637. return ipAddr;
  1638. } // DhcpGetPrivateInterfaceAddress