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.

3745 lines
104 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This file contains functions to indicate to the other system
  7. services that the IP address and other TCP/IP parameters have
  8. changed.
  9. Author:
  10. Madan Appiah (madana) 30-Nov-1993
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #include "dhcpglobal.h"
  17. #include <dhcploc.h>
  18. #include <dhcppro.h>
  19. #include <dhcpcapi.h>
  20. #include <apiappl.h> // for DhcpReRegisterDynDns ?
  21. #define NT // to include data structures for NT build.
  22. #include <nbtioctl.h>
  23. #include <ntddip.h>
  24. #include <ntddtcp.h>
  25. #include <tdiinfo.h>
  26. #include <tdistat.h>
  27. #include <ipexport.h>
  28. #include <tcpinfo.h>
  29. #include <ipinfo.h>
  30. #include <llinfo.h>
  31. #include <lmcons.h>
  32. #include <lmsname.h>
  33. #include <winsvc.h>
  34. #include <ntddbrow.h>
  35. #include <limits.h>
  36. #include <ndispnp.h>
  37. #include <secobj.h>
  38. #define DEFAULT_DEST 0
  39. #define DEFAULT_DEST_MASK 0
  40. #define DEFAULT_METRIC 1
  41. //
  42. // Following two functions (APIs) should be remove when MIKEMAS provides
  43. // entry point DLL for these API.
  44. //
  45. // Also all TDI related include files that are checked-in in this dir.
  46. // should be delfile'd when MIKEMAS checkin those files in private\inc.
  47. //
  48. NTSTATUS
  49. TCPQueryInformationEx(
  50. IN HANDLE TCPHandle,
  51. IN TDIObjectID FAR *ID,
  52. OUT void FAR *Buffer,
  53. IN OUT DWORD FAR *BufferSize,
  54. IN OUT BYTE FAR *Context
  55. )
  56. /*++
  57. Routine Description:
  58. This routine provides the interface to the TDI QueryInformationEx
  59. facility of the TCP/IP stack on NT. Someday, this facility will be
  60. part of TDI.
  61. Arguments:
  62. TCPHandle - Open handle to the TCP driver
  63. ID - The TDI Object ID to query
  64. Buffer - Data buffer to contain the query results
  65. BufferSize - Pointer to the size of the results buffer. Filled in
  66. with the amount of results data on return.
  67. Context - Context value for the query. Should be zeroed for a
  68. new query. It will be filled with context
  69. information for linked enumeration queries.
  70. Return Value:
  71. An NTSTATUS value.
  72. --*/
  73. {
  74. TCP_REQUEST_QUERY_INFORMATION_EX queryBuffer;
  75. DWORD queryBufferSize;
  76. NTSTATUS status;
  77. IO_STATUS_BLOCK ioStatusBlock;
  78. if (TCPHandle == NULL) {
  79. return(TDI_INVALID_PARAMETER);
  80. }
  81. queryBufferSize = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  82. RtlCopyMemory(
  83. &(queryBuffer.ID),
  84. ID,
  85. sizeof(TDIObjectID)
  86. );
  87. RtlCopyMemory(
  88. &(queryBuffer.Context),
  89. Context,
  90. CONTEXT_SIZE
  91. );
  92. status = NtDeviceIoControlFile(
  93. TCPHandle, // Driver handle
  94. NULL, // Event
  95. NULL, // APC Routine
  96. NULL, // APC context
  97. &ioStatusBlock, // Status block
  98. IOCTL_TCP_QUERY_INFORMATION_EX, // Control code
  99. &queryBuffer, // Input buffer
  100. queryBufferSize, // Input buffer size
  101. Buffer, // Output buffer
  102. *BufferSize // Output buffer size
  103. );
  104. if (status == STATUS_PENDING) {
  105. status = NtWaitForSingleObject(
  106. TCPHandle,
  107. TRUE,
  108. NULL
  109. );
  110. }
  111. if (status == STATUS_SUCCESS) {
  112. //
  113. // Copy the return context to the caller's context buffer
  114. //
  115. RtlCopyMemory(
  116. Context,
  117. &(queryBuffer.Context),
  118. CONTEXT_SIZE
  119. );
  120. *BufferSize = (ULONG)ioStatusBlock.Information;
  121. status = ioStatusBlock.Status;
  122. }
  123. else {
  124. if ( status != TDI_BUFFER_OVERFLOW) {
  125. DhcpPrint((DEBUG_ERRORS, "TCPQueryInformationEx returned failure %lx\n", status ));
  126. }
  127. *BufferSize = 0;
  128. }
  129. return(status);
  130. }
  131. NTSTATUS
  132. TCPSetInformationEx(
  133. IN HANDLE TCPHandle,
  134. IN TDIObjectID FAR *ID,
  135. IN void FAR *Buffer,
  136. IN DWORD FAR BufferSize
  137. )
  138. /*++
  139. Routine Description:
  140. This routine provides the interface to the TDI SetInformationEx
  141. facility of the TCP/IP stack on NT. Someday, this facility will be
  142. part of TDI.
  143. Arguments:
  144. TCPHandle - Open handle to the TCP driver
  145. ID - The TDI Object ID to set
  146. Buffer - Data buffer containing the information to be set
  147. BufferSize - The size of the set data buffer.
  148. Return Value:
  149. An NTSTATUS value.
  150. --*/
  151. {
  152. PTCP_REQUEST_SET_INFORMATION_EX setBuffer;
  153. NTSTATUS status;
  154. IO_STATUS_BLOCK ioStatusBlock;
  155. DWORD setBufferSize;
  156. if (TCPHandle == NULL) {
  157. return(TDI_INVALID_PARAMETER);
  158. }
  159. setBufferSize = FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) +
  160. BufferSize;
  161. setBuffer = LocalAlloc(LMEM_FIXED, setBufferSize);
  162. if (setBuffer == NULL) {
  163. return(TDI_NO_RESOURCES);
  164. }
  165. setBuffer->BufferSize = BufferSize;
  166. RtlCopyMemory(
  167. &(setBuffer->ID),
  168. ID,
  169. sizeof(TDIObjectID)
  170. );
  171. RtlCopyMemory(
  172. &(setBuffer->Buffer[0]),
  173. Buffer,
  174. BufferSize
  175. );
  176. status = NtDeviceIoControlFile(
  177. TCPHandle, // Driver handle
  178. NULL, // Event
  179. NULL, // APC Routine
  180. NULL, // APC context
  181. &ioStatusBlock, // Status block
  182. IOCTL_TCP_SET_INFORMATION_EX, // Control code
  183. setBuffer, // Input buffer
  184. setBufferSize, // Input buffer size
  185. NULL, // Output buffer
  186. 0 // Output buffer size
  187. );
  188. if (status == STATUS_PENDING)
  189. {
  190. status = NtWaitForSingleObject(
  191. TCPHandle,
  192. TRUE,
  193. NULL
  194. );
  195. if ( STATUS_SUCCESS == status )
  196. status = ioStatusBlock.Status;
  197. } else if ( status == STATUS_SUCCESS ) {
  198. status = ioStatusBlock.Status;
  199. }
  200. LocalFree(setBuffer);
  201. return(status);
  202. }
  203. DWORD
  204. OpenDriver(
  205. HANDLE *Handle,
  206. LPWSTR DriverName
  207. )
  208. /*++
  209. Routine Description:
  210. This function opens a specified IO drivers.
  211. Arguments:
  212. Handle - pointer to location where the opened drivers handle is
  213. returned.
  214. DriverName - name of the driver to be opened.
  215. Return Value:
  216. Windows Error Code.
  217. --*/
  218. {
  219. OBJECT_ATTRIBUTES objectAttributes;
  220. IO_STATUS_BLOCK ioStatusBlock;
  221. UNICODE_STRING nameString;
  222. NTSTATUS status;
  223. *Handle = NULL;
  224. //
  225. // Open a Handle to the IP driver.
  226. //
  227. RtlInitUnicodeString(&nameString, DriverName);
  228. InitializeObjectAttributes(
  229. &objectAttributes,
  230. &nameString,
  231. OBJ_CASE_INSENSITIVE,
  232. (HANDLE) NULL,
  233. (PSECURITY_DESCRIPTOR) NULL
  234. );
  235. status = NtCreateFile(
  236. Handle,
  237. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  238. &objectAttributes,
  239. &ioStatusBlock,
  240. NULL,
  241. FILE_ATTRIBUTE_NORMAL,
  242. FILE_SHARE_READ | FILE_SHARE_WRITE,
  243. FILE_OPEN_IF,
  244. 0,
  245. NULL,
  246. 0
  247. );
  248. return( RtlNtStatusToDosError( status ) );
  249. }
  250. DWORD
  251. IPSetIPAddress(
  252. DWORD IpInterfaceContext,
  253. DHCP_IP_ADDRESS Address,
  254. DHCP_IP_ADDRESS SubnetMask
  255. )
  256. /*++
  257. Routine Description:
  258. This rountine sets the IP Address and subnet mask of the IP stack.
  259. Arguments:
  260. IpInterfaceContext - Context value of the Ip Table Entry.
  261. Address - New IP Address.
  262. SubnetMask - New subnet mask.
  263. Return Value:
  264. Windows Error Code.
  265. --*/
  266. {
  267. HANDLE IPHandle;
  268. IP_SET_ADDRESS_REQUEST requestBuffer;
  269. IO_STATUS_BLOCK ioStatusBlock;
  270. NTSTATUS status;
  271. DWORD Error;
  272. DhcpPrint((DEBUG_TRACE, "IPSetIPAddress: settting %s address on interface context %lx\n",
  273. inet_ntoa(*(struct in_addr *)&Address), IpInterfaceContext ));
  274. Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
  275. if (Error != ERROR_SUCCESS) {
  276. return( Error );
  277. }
  278. //
  279. // Initialize the input buffer.
  280. //
  281. requestBuffer.Context = (USHORT)IpInterfaceContext;
  282. requestBuffer.Address = Address;
  283. requestBuffer.SubnetMask = SubnetMask;
  284. status = NtDeviceIoControlFile(
  285. IPHandle, // Driver handle
  286. NULL, // Event
  287. NULL, // APC Routine
  288. NULL, // APC context
  289. &ioStatusBlock, // Status block
  290. IOCTL_IP_SET_ADDRESS, // Control code
  291. &requestBuffer, // Input buffer
  292. sizeof(IP_SET_ADDRESS_REQUEST), // Input buffer size
  293. NULL, // Output buffer
  294. 0 // Output buffer size
  295. );
  296. if ( status == STATUS_UNSUCCESSFUL ) { // whoa? syscall failed? should not really happen
  297. DhcpPrint( (DEBUG_ERRORS,
  298. "IOCTL_IP_SET_ADDRESS returned immediate STATUS_UNSUCCESSFUL for %s\n",
  299. inet_ntoa(*(struct in_addr *)&Address)));
  300. } else if ( STATUS_PENDING == status ) { // ip is trying to do things..
  301. status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
  302. status = ioStatusBlock.Status;
  303. } else if ( STATUS_SUCCESS == status ) { // DeviceIoControl worked, but how does ip feel?
  304. status = ioStatusBlock.Status;
  305. }
  306. if ( STATUS_SUCCESS != status ) {
  307. DhcpPrint((DEBUG_ERRORS,
  308. "IOCTL_IP_SET_ADDRESS returned STATUS_UNSUCCESSFUL<0x%lx> for %s\n",
  309. status, inet_ntoa(*(struct in_addr *)&Address)));
  310. }
  311. NtClose( IPHandle );
  312. if( 0 == Address && STATUS_DUPLICATE_NAME == status ) {
  313. // I think this is what happens when you try to set zero if it is already zero!!!
  314. DhcpPrint((DEBUG_ERRORS, "Trying to set zero address: ADDRESS_CONFLICT??? Ignored\n"));
  315. status = STATUS_SUCCESS;
  316. }
  317. if( IP_MEDIA_DISCONNECT == status ) {
  318. //
  319. // You get this if the media is disconnected... We just ignore this for now.
  320. //
  321. DhcpPrint((DEBUG_ERRORS, "Trying to set address while media disconnected..\n"));
  322. status = STATUS_SUCCESS;
  323. }
  324. return( RtlNtStatusToDosError( status ) );
  325. }
  326. DWORD
  327. IPDelIPAddress(
  328. DWORD IpInterfaceContext
  329. )
  330. /*++
  331. Routine Description:
  332. This rountine deletes a static IP address for the supplied IpInterfaceContext
  333. Arguments:
  334. IpInterfaceContext - Context value of the Ip Table Entry.
  335. Return Value:
  336. Windows Error Code.
  337. --*/
  338. {
  339. HANDLE IPHandle;
  340. IP_DELETE_NTE_REQUEST requestBuffer;
  341. IO_STATUS_BLOCK ioStatusBlock;
  342. NTSTATUS status;
  343. DWORD Error;
  344. DhcpPrint((DEBUG_MISC, "IPDelIPAddress: deleting address with ipcontext %x \n", IpInterfaceContext));
  345. Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
  346. if (Error != ERROR_SUCCESS) {
  347. return( Error );
  348. }
  349. requestBuffer.Context = (USHORT)IpInterfaceContext;
  350. status = NtDeviceIoControlFile(
  351. IPHandle, // Driver handle
  352. NULL, // Event
  353. NULL, // APC Routine
  354. NULL, // APC context
  355. &ioStatusBlock, // Status block
  356. IOCTL_IP_DELETE_NTE, // Control code
  357. &requestBuffer, // Input buffer
  358. sizeof(requestBuffer), // Input buffer size
  359. NULL, // Output buffer
  360. 0 // Output buffer size
  361. );
  362. if ( status == STATUS_UNSUCCESSFUL )
  363. {
  364. DhcpPrint( (DEBUG_ERRORS,
  365. "IOCTL_IP_DELETE_NTE returned immediate STATUS_UNSUCCESSFUL for context %lx\n",
  366. IpInterfaceContext));
  367. }
  368. else if ( STATUS_PENDING == status )
  369. {
  370. status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
  371. status = ioStatusBlock.Status;
  372. if ( STATUS_UNSUCCESSFUL == status ){
  373. DhcpPrint( (DEBUG_ERRORS,
  374. "IOCTL_IP_DELETE_NTE returned STATUS_UNSUCCESSFUL for context %lx\n",
  375. IpInterfaceContext));
  376. }
  377. } else if ( STATUS_SUCCESS == status ) {
  378. status = ioStatusBlock.Status;
  379. }
  380. NtClose( IPHandle );
  381. return( RtlNtStatusToDosError( status ) );
  382. }
  383. DWORD
  384. IPDelNonPrimaryAddresses(
  385. LPWSTR AdapterName
  386. )
  387. /*++
  388. Routine Description:
  389. This rountine deletes all the static ip addresses but
  390. the primary one.
  391. Arguments:
  392. AdapterName - The adaptername that identifies the ip interface
  393. Return Value:
  394. Windows Error Code.
  395. --*/
  396. {
  397. DWORD Error;
  398. LPWSTR RegKey = NULL;
  399. HKEY KeyHandle = NULL;
  400. LPWSTR nteContextList = NULL;
  401. PCHAR oemNextContext = NULL;
  402. LPWSTR nextContext;
  403. DWORD i;
  404. //
  405. // Open device parameter.
  406. //
  407. RegKey = DhcpAllocateMemory(
  408. (wcslen(DHCP_SERVICES_KEY) +
  409. wcslen(REGISTRY_CONNECT_STRING) +
  410. wcslen(AdapterName) +
  411. wcslen(DHCP_ADAPTER_PARAMETERS_KEY) + 1) *
  412. sizeof(WCHAR) ); // termination char.
  413. if( RegKey == NULL ) {
  414. Error = ERROR_NOT_ENOUGH_MEMORY;
  415. goto Cleanup;
  416. }
  417. wcscpy( RegKey, DHCP_SERVICES_KEY );
  418. wcscat( RegKey, DHCP_ADAPTER_PARAMETERS_KEY );
  419. wcscat( RegKey, REGISTRY_CONNECT_STRING );
  420. wcscat( RegKey, AdapterName );
  421. //
  422. // open this key.
  423. //
  424. Error = RegOpenKeyEx(
  425. HKEY_LOCAL_MACHINE,
  426. RegKey,
  427. 0, // Reserved field
  428. DHCP_CLIENT_KEY_ACCESS,
  429. &KeyHandle
  430. );
  431. if( Error != ERROR_SUCCESS ) {
  432. goto Cleanup;
  433. }
  434. Error = GetRegistryString(
  435. KeyHandle,
  436. DHCP_NTE_CONTEXT_LIST,
  437. &nteContextList,
  438. NULL
  439. );
  440. if ( ERROR_SUCCESS != Error )
  441. {
  442. DhcpPrint( (DEBUG_ERRORS,
  443. "GetIpInterfaceContext: Could not read nteContextList %lx\n",
  444. Error));
  445. goto Cleanup;
  446. }
  447. // if the adapter is disabled, nteContextList contains nothing
  448. // more than a L'\0'. No address to be deleted in this case.
  449. if (*nteContextList != L'\0')
  450. {
  451. nextContext = nteContextList;
  452. // delete all the addresses but the first one.
  453. for( nextContext += (wcslen(nextContext) + 1), i = 1;
  454. *nextContext != L'\0';
  455. i++, nextContext += (wcslen(nextContext) + 1) ) {
  456. ULONG ival;
  457. oemNextContext = DhcpUnicodeToOem(nextContext, NULL);
  458. if ( NULL == oemNextContext ) {
  459. Error = ERROR_BAD_FORMAT;
  460. } else {
  461. ival = strtoul(oemNextContext, NULL, 0);
  462. if ( ival == ULONG_MAX || ival == 0) {
  463. Error = ERROR_BAD_FORMAT;
  464. } else {
  465. // delete this address
  466. Error = IPDelIPAddress( ival );
  467. }
  468. }
  469. }
  470. }
  471. Cleanup:
  472. if( RegKey != NULL ) {
  473. DhcpFreeMemory( RegKey );
  474. }
  475. if( KeyHandle != NULL ) {
  476. RegCloseKey( KeyHandle );
  477. }
  478. if ( nteContextList != NULL ) {
  479. DhcpFreeMemory( nteContextList );
  480. }
  481. if ( oemNextContext != NULL ) {
  482. DhcpFreeMemory( oemNextContext );
  483. }
  484. return( Error );
  485. }
  486. DWORD
  487. IPGetWOLCapability(
  488. IN ULONG IfIndex,
  489. OUT PULONG pRetVal
  490. )
  491. {
  492. HANDLE IPHandle;
  493. ULONG RetVal;
  494. IO_STATUS_BLOCK ioStatusBlock;
  495. NTSTATUS status;
  496. DWORD Error;
  497. DhcpPrint((
  498. DEBUG_MISC, "IPGetWOLCapability(0x%lx) called\n", IfIndex
  499. ));
  500. Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
  501. if (Error != ERROR_SUCCESS) {
  502. return( Error );
  503. }
  504. status = NtDeviceIoControlFile(
  505. IPHandle, // Driver handle
  506. NULL, // Event
  507. NULL, // APC Routine
  508. NULL, // APC context
  509. &ioStatusBlock, // Status block
  510. IOCTL_IP_GET_WOL_CAPABILITY, // Control code
  511. &IfIndex, // Input buffer
  512. sizeof(IfIndex), // Input buffer size
  513. pRetVal, // Output buffer
  514. sizeof(*pRetVal) // Output buffer size
  515. );
  516. if ( status == STATUS_UNSUCCESSFUL )
  517. {
  518. DhcpPrint((
  519. DEBUG_ERRORS,
  520. "IOCTL_IP_GET_WOL_CAPABILITY(0x%lx): STATUS_UNSUCCESSFUL\n", IfIndex
  521. ));
  522. }
  523. else if ( STATUS_PENDING == status )
  524. {
  525. status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
  526. status = ioStatusBlock.Status;
  527. if ( STATUS_UNSUCCESSFUL == status )
  528. DhcpPrint((
  529. DEBUG_ERRORS,
  530. "IOCTL_IP_GET_WOL_CAPABILITY(0x%lx): failed\n", IfIndex
  531. ));
  532. } else if( STATUS_SUCCESS == status ) {
  533. status = ioStatusBlock.Status;
  534. }
  535. NtClose( IPHandle );
  536. return( RtlNtStatusToDosError( status ) );
  537. }
  538. DWORD
  539. IPAddIPAddress(
  540. LPWSTR AdapterName,
  541. DHCP_IP_ADDRESS Address,
  542. DHCP_IP_ADDRESS SubnetMask
  543. )
  544. /*++
  545. Routine Description:
  546. This rountine adds an static ipaddress to the IP interface for
  547. the given adaptername.
  548. Arguments:
  549. AdapterName - The adaptername that identifies the ip interface
  550. Address - IPaddress to be added
  551. SubnetMask - SubnetMask
  552. Return Value:
  553. Windows Error Code.
  554. --*/
  555. {
  556. HANDLE IPHandle;
  557. PIP_ADD_NTE_REQUEST requestBuffer;
  558. IP_ADD_NTE_RESPONSE responseBuffer;
  559. IO_STATUS_BLOCK ioStatusBlock;
  560. NTSTATUS status;
  561. DWORD Error;
  562. DWORD requestBufferSize;
  563. DhcpPrint((DEBUG_MISC, "IPAddIPAddress: adding an address on adapter %ws\n", AdapterName));
  564. Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
  565. if (Error != ERROR_SUCCESS) {
  566. return( Error );
  567. }
  568. //
  569. // The adapter name that we pass to TCPIP should be of form
  570. // \device\TCPIP_<adaptername>
  571. //
  572. //
  573. // Initialize the input buffer.
  574. //
  575. requestBufferSize = FIELD_OFFSET(IP_ADD_NTE_REQUEST, InterfaceNameBuffer) +
  576. (wcslen(DHCP_TCPIP_DEVICE_STRING) // \Device
  577. + wcslen(AdapterName)) * sizeof(WCHAR);
  578. requestBuffer = DhcpAllocateMemory( requestBufferSize + sizeof(WCHAR));
  579. if (requestBuffer == NULL) {
  580. NtClose(IPHandle);
  581. return ERROR_NOT_ENOUGH_MEMORY;
  582. }
  583. wcscpy((PWCHAR)requestBuffer->InterfaceNameBuffer, DHCP_TCPIP_DEVICE_STRING);
  584. wcscat((PWCHAR)requestBuffer->InterfaceNameBuffer, AdapterName);
  585. RtlInitUnicodeString(&requestBuffer->InterfaceName, (PWCHAR)requestBuffer->InterfaceNameBuffer);
  586. RtlUpcaseUnicodeString( &requestBuffer->InterfaceName, &requestBuffer->InterfaceName, FALSE );
  587. requestBuffer->InterfaceContext = INVALID_INTERFACE_CONTEXT;
  588. requestBuffer->Address = Address;
  589. requestBuffer->SubnetMask = SubnetMask;
  590. status = NtDeviceIoControlFile(
  591. IPHandle, // Driver handle
  592. NULL, // Event
  593. NULL, // APC Routine
  594. NULL, // APC context
  595. &ioStatusBlock, // Status block
  596. IOCTL_IP_ADD_NTE, // Control code
  597. requestBuffer, // Input buffer
  598. requestBufferSize, // Input buffer size
  599. &responseBuffer, // Output buffer
  600. sizeof(responseBuffer) // Output buffer size
  601. );
  602. if ( status == STATUS_UNSUCCESSFUL )
  603. {
  604. DhcpPrint( (DEBUG_ERRORS,
  605. "IOCTL_IP_ADD_NTE returned immediate STATUS_UNSUCCESSFUL for %s\n",
  606. inet_ntoa(*(struct in_addr *)&Address)));
  607. }
  608. else if ( STATUS_PENDING == status )
  609. {
  610. status = NtWaitForSingleObject( IPHandle, TRUE, NULL );
  611. status = ioStatusBlock.Status;
  612. } else if (STATUS_SUCCESS == status ) {
  613. status = ioStatusBlock.Status;
  614. }
  615. DhcpPrint( (DEBUG_ERRORS,
  616. "IOCTL_IP_ADD_NTE returned 0x%lx for %s\n",
  617. status, inet_ntoa(*(struct in_addr *)&Address)));
  618. NtClose( IPHandle );
  619. DhcpFreeMemory(requestBuffer);
  620. return( RtlNtStatusToDosError( status ) );
  621. }
  622. DWORD
  623. IPSetInterface(
  624. DWORD IpInterfaceContext
  625. )
  626. /*++
  627. Routine Description:
  628. This rountine sets the IP interface for sending DHCP broadcasts.
  629. Arguments:
  630. IpInterfaceContext - Context value of the Ip Table Entry.
  631. Return Value:
  632. Windows Error Code.
  633. --*/
  634. {
  635. HANDLE IPHandle;
  636. IO_STATUS_BLOCK ioStatusBlock;
  637. NTSTATUS status;
  638. DWORD Error;
  639. Error = OpenDriver(&IPHandle, DD_IP_DEVICE_NAME);
  640. if (Error != ERROR_SUCCESS) {
  641. return( Error );
  642. }
  643. status = NtDeviceIoControlFile(
  644. IPHandle, // Driver handle
  645. NULL, // Event
  646. NULL, // APC Routine
  647. NULL, // APC context
  648. &ioStatusBlock, // Status block
  649. IOCTL_IP_SET_DHCP_INTERFACE, // Control code
  650. &IpInterfaceContext, // Input buffer
  651. sizeof(IpInterfaceContext), // Input buffer size
  652. NULL, // Output buffer
  653. 0 // Output buffer size
  654. );
  655. if (status == STATUS_PENDING)
  656. {
  657. status = NtWaitForSingleObject(
  658. IPHandle,
  659. TRUE,
  660. NULL
  661. );
  662. if ( STATUS_SUCCESS == status )
  663. status = ioStatusBlock.Status;
  664. } else if ( STATUS_SUCCESS == status ) {
  665. status = ioStatusBlock.Status;
  666. }
  667. NtClose(IPHandle);
  668. return( RtlNtStatusToDosError( status ) );
  669. }
  670. DWORD
  671. IPResetInterface(
  672. DWORD dwIpInterfaceContext
  673. )
  674. /*++
  675. Routine Description:
  676. This rountine resets the IP interface to restore normal IP
  677. interface behaviour.
  678. Arguments:
  679. VOID
  680. Return Value:
  681. Windows Error Code.
  682. --*/
  683. {
  684. DWORD Error;
  685. LOCK_INTERFACE();
  686. Error = IPSetInterface(dwIpInterfaceContext);
  687. if( ERROR_SUCCESS == Error ) {
  688. Error = IPSetInterface( 0xFFFFFFFF );
  689. }
  690. UNLOCK_INTERFACE();
  691. return Error;
  692. }
  693. DWORD
  694. IPResetIPAddress(
  695. DWORD dwInterfaceContext,
  696. DHCP_IP_ADDRESS SubnetMask
  697. )
  698. /*++
  699. Routine Description:
  700. This rountine resets the IP Address of the IP to ZERO.
  701. Arguments:
  702. IpInterfaceContext - Context value of the Ip Table Entry.
  703. SubnetMask - default subnet mask.
  704. Return Value:
  705. Windows Error Code.
  706. --*/
  707. {
  708. DWORD dwResult = IPSetIPAddress( dwInterfaceContext, 0, SubnetMask);
  709. if ( ERROR_SUCCESS != dwResult )
  710. DhcpPrint( ( DEBUG_ERRORS,
  711. "IPResetIPAddress failed: %x\n", dwResult ));
  712. return dwResult;
  713. }
  714. DWORD
  715. NetBTSetIPAddress(
  716. LPWSTR DeviceName,
  717. DHCP_IP_ADDRESS IpAddress,
  718. DHCP_IP_ADDRESS SubnetMask
  719. )
  720. /*++
  721. Routine Description:
  722. This function informs the NetBT service that the IP address and
  723. SubnetMask parameters have changed.
  724. Arguments:
  725. DeviceName : name of the device (viz. \device\Elink01) we are
  726. working on.
  727. IpAddress : New IP Address.
  728. SubnetMask : New SubnetMask.
  729. Return Value:
  730. Windows Errors.
  731. --*/
  732. {
  733. DWORD Error;
  734. NTSTATUS Status;
  735. HANDLE NetBTDeviceHandle = NULL;
  736. IO_STATUS_BLOCK IoStatusBlock;
  737. tNEW_IP_ADDRESS RequestBlock;
  738. UNICODE_STRING BrowserDeviceName;
  739. UNICODE_STRING NetbtDeviceName;
  740. OBJECT_ATTRIBUTES ObjectAttributes;
  741. HANDLE BrowserHandle = NULL;
  742. LMDR_REQUEST_PACKET RequestPacket;
  743. #if !defined(_PNP_POWER_)
  744. Error = OpenDriver( &NetBTDeviceHandle, DeviceName );
  745. if( Error != ERROR_SUCCESS ) {
  746. //
  747. // This can happen if NetBT is not bound to the adapter.
  748. // Make sure that really is the case by checking that
  749. // key for the adapter exists. If so, this means that
  750. // adapter is there but netbt isnt bound to it yet.
  751. //
  752. if ( Error == ERROR_FILE_NOT_FOUND ) {
  753. LPWSTR AdapterName = NULL;
  754. LPWSTR RegKey = NULL;
  755. HKEY KeyHandle = NULL;
  756. //
  757. // First form the adaptername (e.g Elnk31) from devicename(Device\NetBt_Elnk31
  758. //
  759. AdapterName = wcsstr( DeviceName, DHCP_NETBT_DEVICE_STRING );
  760. DhcpAssert( AdapterName );
  761. AdapterName += wcslen( DHCP_NETBT_DEVICE_STRING );
  762. //
  763. // Open device key
  764. //
  765. RegKey = DhcpAllocateMemory(
  766. (wcslen(DHCP_SERVICES_KEY) +
  767. wcslen(REGISTRY_CONNECT_STRING) +
  768. wcslen(AdapterName) + 1) *
  769. sizeof(WCHAR) ); // termination char.
  770. if( RegKey == NULL ) {
  771. Error = ERROR_NOT_ENOUGH_MEMORY;
  772. goto Cleanup;
  773. }
  774. wcscpy( RegKey, DHCP_SERVICES_KEY );
  775. wcscat( RegKey, REGISTRY_CONNECT_STRING );
  776. wcscat( RegKey, AdapterName );
  777. //
  778. // open this key.
  779. //
  780. Error = RegOpenKeyEx(
  781. HKEY_LOCAL_MACHINE,
  782. RegKey,
  783. 0, // Reserved field
  784. DHCP_CLIENT_KEY_ACCESS,
  785. &KeyHandle
  786. );
  787. DhcpFreeMemory( RegKey );
  788. if( Error != ERROR_SUCCESS ) {
  789. goto Cleanup;
  790. } else {
  791. //
  792. // The adapter key exists so return ERROR_SUCCESS
  793. //
  794. RegCloseKey( KeyHandle );
  795. }
  796. }
  797. goto Cleanup;
  798. }
  799. RequestBlock.IpAddress = IpAddress;
  800. RequestBlock.SubnetMask = SubnetMask;
  801. Status = NtDeviceIoControlFile(
  802. NetBTDeviceHandle, // Handle
  803. NULL, // Event
  804. NULL, // ApcRoutine
  805. NULL, // ApcContext
  806. &IoStatusBlock, // IoStatusBlock
  807. IOCTL_NETBT_NEW_IPADDRESS,
  808. // IoControlCode
  809. &RequestBlock, // InputBuffer
  810. sizeof(RequestBlock), // InputBufferSize
  811. NULL, // OutputBuffer
  812. 0); // OutputBufferSize
  813. if (Status == STATUS_PENDING)
  814. {
  815. Status = NtWaitForSingleObject(
  816. NetBTDeviceHandle, // Handle
  817. TRUE, // Alertable
  818. NULL); // Timeout
  819. if ( STATUS_SUCCESS == Status )
  820. Status = IoStatusBlock.Status;
  821. } else if ( STATUS_SUCCESS == Status ) {
  822. Status = IoStatusBlock.Status;
  823. }
  824. if (!NT_SUCCESS(Status)) {
  825. Error = RtlNtStatusToDosError( Status );
  826. goto Cleanup;
  827. }
  828. #endif // !_PNP_POWER_
  829. //
  830. // We also need to tell the browser that the IP address has changed.
  831. //
  832. RtlInitUnicodeString(&NetbtDeviceName, DeviceName);
  833. RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION;
  834. RequestPacket.TransportName = NetbtDeviceName;
  835. RtlInitUnicodeString(&BrowserDeviceName, DD_BROWSER_DEVICE_NAME_U);
  836. InitializeObjectAttributes(
  837. &ObjectAttributes,
  838. &BrowserDeviceName,
  839. OBJ_CASE_INSENSITIVE,
  840. NULL,
  841. NULL
  842. );
  843. Status = NtOpenFile(
  844. &BrowserHandle,
  845. SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
  846. &ObjectAttributes,
  847. &IoStatusBlock,
  848. FILE_SHARE_READ | FILE_SHARE_WRITE,
  849. FILE_SYNCHRONOUS_IO_NONALERT
  850. );
  851. if (NT_SUCCESS(Status)) {
  852. Status = IoStatusBlock.Status;
  853. }
  854. if (!NT_SUCCESS(Status)) {
  855. Error = RtlNtStatusToDosError( Status );
  856. // it is OK to have ERROR_FILE_NOT_FOUND || ERROR_PATH_NOT_FOUND
  857. if( Error == ERROR_FILE_NOT_FOUND || Error == ERROR_PATH_NOT_FOUND) {
  858. Error = ERROR_SUCCESS;
  859. }
  860. goto Cleanup;
  861. }
  862. Status = NtDeviceIoControlFile(
  863. BrowserHandle,
  864. NULL,
  865. NULL,
  866. NULL,
  867. &IoStatusBlock,
  868. IOCTL_LMDR_IP_ADDRESS_CHANGED,
  869. &RequestPacket,
  870. sizeof(RequestPacket),
  871. NULL,
  872. 0
  873. );
  874. if (!NT_SUCCESS(Status)) {
  875. Error = RtlNtStatusToDosError( Status );
  876. // it is OK to have ERROR_FILE_NOT_FOUND | ERROR_PATH_NOT_FOUND
  877. if( Error == ERROR_FILE_NOT_FOUND || ERROR_PATH_NOT_FOUND == Error ) {
  878. Error = ERROR_SUCCESS;
  879. }
  880. else {
  881. goto Cleanup;
  882. }
  883. }
  884. Error = ERROR_SUCCESS;
  885. Cleanup:
  886. if( NetBTDeviceHandle != NULL ) {
  887. if( Error != ERROR_SUCCESS ) {
  888. DhcpPrint(( DEBUG_ERRORS,
  889. "NetBT IOCTL_NETBT_NEW_IPADDRESS failed on %ws, %ld.\n", DeviceName, Error ));
  890. }
  891. NtClose( NetBTDeviceHandle );
  892. }
  893. if( BrowserHandle != NULL ) {
  894. if( Error != ERROR_SUCCESS ) {
  895. DhcpPrint(( DEBUG_ERRORS,
  896. "Browser IOCTL_LMDR_IPADDRESS_CHANGED failed on %ws, %ld.\n", BrowserDeviceName, Error ));
  897. }
  898. NtClose( BrowserHandle );
  899. }
  900. return( Error );
  901. }
  902. DWORD
  903. NetBTResetIPAddress(
  904. LPWSTR DeviceName,
  905. DHCP_IP_ADDRESS SubnetMask
  906. )
  907. /*++
  908. Routine Description:
  909. This rountine resets the IP Address of the NetBT to ZERO.
  910. Arguments:
  911. DeviceName - adapter name.
  912. SubnetMask - default subnet mask.
  913. Return Value:
  914. Windows Error Code.
  915. --*/
  916. {
  917. DWORD status;
  918. status = (DWORD) NetBTSetIPAddress(DeviceName, 0, SubnetMask);
  919. return status;
  920. }
  921. ULONG
  922. TcpIpNotifyRouterDiscoveryOption(
  923. IN LPCWSTR AdapterName,
  924. IN BOOL fOptionPresent,
  925. IN DWORD OptionValue
  926. )
  927. {
  928. ULONG Error;
  929. ULONG RetVal;
  930. WCHAR TcpipAdapter[300+sizeof(DHCP_ADAPTERS_DEVICE_STRING)];
  931. UNICODE_STRING UpperLayer, LowerLayer, BindString;
  932. IP_PNP_RECONFIG_REQUEST Request;
  933. Error = NO_ERROR;
  934. RtlZeroMemory(&Request, sizeof(Request));
  935. Request.version = IP_PNP_RECONFIG_VERSION;
  936. Request.Flags |= IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY;
  937. if( fOptionPresent ) {
  938. Request.DhcpPerformRouterDiscovery = (BOOLEAN)OptionValue;
  939. }
  940. wcscpy(TcpipAdapter, DHCP_ADAPTERS_DEVICE_STRING);
  941. wcscat(TcpipAdapter, AdapterName);
  942. RtlInitUnicodeString(&BindString, NULL); // no bind string
  943. RtlInitUnicodeString(&UpperLayer, TEXT("Tcpip"));
  944. RtlInitUnicodeString(&LowerLayer, TcpipAdapter);
  945. RetVal = NdisHandlePnPEvent(
  946. NDIS, // uiLayer
  947. RECONFIGURE, // Operation
  948. &LowerLayer,
  949. &UpperLayer,
  950. &BindString,
  951. &Request,
  952. sizeof(Request)
  953. );
  954. if( 0 == RetVal) Error = GetLastError();
  955. if( ERROR_SUCCESS != Error) {
  956. DhcpPrint((DEBUG_ERRORS, "TcpipNotifyRegChanges:0x%ld\n", Error));
  957. }
  958. return Error;
  959. }
  960. DWORD // win32 status
  961. NetBTNotifyRegChanges( // Notify NetBT of some parameter changes
  962. IN LPWSTR AdapterName // the adapter that needs this change notification
  963. )
  964. {
  965. DWORD Error;
  966. DWORD RetVal;
  967. WCHAR NetBTBindAdapter[300+sizeof( DHCP_TCPIP_DEVICE_STRING )];
  968. UNICODE_STRING UpperLayer;
  969. UNICODE_STRING LowerLayer;
  970. UNICODE_STRING BindString;
  971. Error = ERROR_SUCCESS;
  972. wcscpy(NetBTBindAdapter, DHCP_TCPIP_DEVICE_STRING);
  973. wcscat(NetBTBindAdapter, AdapterName); // \\Device\\Tcpip_{AdapterGuid} is what NetBT expects.
  974. RtlInitUnicodeString(&BindString, NULL); // no bind string
  975. RtlInitUnicodeString(&UpperLayer, TEXT("NetBT"));
  976. RtlInitUnicodeString(&LowerLayer, NetBTBindAdapter);
  977. RetVal = NdisHandlePnPEvent(
  978. TDI, // uiLayer
  979. RECONFIGURE, // Operation
  980. &LowerLayer,
  981. &UpperLayer,
  982. &BindString,
  983. NULL,
  984. 0
  985. );
  986. if( 0 != RetVal) Error = GetLastError();
  987. if( ERROR_SUCCESS != Error) {
  988. DhcpPrint((DEBUG_ERRORS, "NetBTNotifyRegChanges:0x%ld\n", Error));
  989. }
  990. return Error;
  991. }
  992. NTSTATUS
  993. FindHardwareAddr(
  994. HANDLE TCPHandle,
  995. TDIEntityID *EList,
  996. DWORD cEntities,
  997. IPAddrEntry *pIAE,
  998. LPBYTE HardwareAddressType,
  999. LPBYTE *HardwareAddress,
  1000. LPDWORD HardwareAddressLength,
  1001. DWORD *pIpInterfaceInstance,
  1002. #ifdef BOOTPERF
  1003. BOOL *pfInterfaceDown,
  1004. #endif BOOTPERF
  1005. BOOL *pfFound
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. This function browses the TDI entries list and finds out the
  1010. hardware address for the specified address entry.
  1011. Arguments:
  1012. TCPHandle - handle TCP driver.
  1013. EList - list of TDI entries.
  1014. cEntities - number of entries in the above list.
  1015. pIAE - IP entry for which we need HW address.
  1016. HardwareAddressType - hardware address type.
  1017. HardwareAddress - pointer to location where the HW address buffer
  1018. pointer is returned.
  1019. HardwareAddressLength - length of the HW address returned.
  1020. pIpInterfaceInstance - pointer to interface instance for the matching entry
  1021. pfFound - pointer to BOOL location which is set to TRUE if we found
  1022. the HW address otherwise set to FALSE.
  1023. Return Value:
  1024. Windows Error Code.
  1025. --*/
  1026. {
  1027. DWORD i;
  1028. BYTE Context[CONTEXT_SIZE];
  1029. TDIObjectID ID;
  1030. NTSTATUS Status;
  1031. DWORD Size;
  1032. *pfFound = FALSE;
  1033. ID.toi_entity.tei_entity = IF_MIB;
  1034. ID.toi_type = INFO_TYPE_PROVIDER;
  1035. for ( i = 0; i < cEntities; i++ ) {
  1036. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx, type %lx, instance %lx\n",
  1037. i, EList[i].tei_entity, EList[i].tei_instance));
  1038. if (EList[i].tei_entity == IF_ENTITY) {
  1039. IFEntry IFE;
  1040. DWORD IFType;
  1041. //
  1042. // Check and make sure the interface supports MIB-2
  1043. //
  1044. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1045. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1046. ID.toi_class = INFO_CLASS_GENERIC;
  1047. ID.toi_id = ENTITY_TYPE_ID;
  1048. Size = sizeof( IFType );
  1049. IFType = 0;
  1050. RtlZeroMemory(Context, CONTEXT_SIZE);
  1051. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: querying IF_ENTITY %lx\n",i));
  1052. Status = TCPQueryInformationEx(
  1053. TCPHandle,
  1054. &ID,
  1055. &IFType,
  1056. &Size,
  1057. Context);
  1058. if (Status != TDI_SUCCESS) {
  1059. goto Cleanup;;
  1060. }
  1061. if ( IFType != IF_MIB ) {
  1062. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx does not support MIB\n",i));
  1063. continue;
  1064. }
  1065. //
  1066. // We've found an interface, get its index and see if it
  1067. // matches the IP Address entry
  1068. //
  1069. ID.toi_class = INFO_CLASS_PROTOCOL;
  1070. ID.toi_id = IF_MIB_STATS_ID;
  1071. Size = sizeof(IFEntry);
  1072. RtlZeroMemory(Context, CONTEXT_SIZE);
  1073. RtlZeroMemory(&IFE, Size);
  1074. Status = TCPQueryInformationEx(
  1075. TCPHandle,
  1076. &ID,
  1077. &IFE,
  1078. &Size,
  1079. Context);
  1080. if ( Status != TDI_SUCCESS &&
  1081. Status != TDI_BUFFER_OVERFLOW ) {
  1082. goto Cleanup;
  1083. }
  1084. DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has if_index %lx.\n", &IFE, IFE.if_index ));
  1085. if ( IFE.if_index == pIAE->iae_index ) {
  1086. LPBYTE Address;
  1087. DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has our if_index %lx\n",
  1088. &IFE, pIAE->iae_index ));
  1089. //
  1090. // Allocate Memory.
  1091. //
  1092. Address = DhcpAllocateMemory( IFE.if_physaddrlen );
  1093. if( Address == NULL ) {
  1094. Status = STATUS_NO_MEMORY;
  1095. goto Cleanup;
  1096. }
  1097. RtlCopyMemory(
  1098. Address,
  1099. IFE.if_physaddr,
  1100. IFE.if_physaddrlen );
  1101. switch( IFE.if_type ) {
  1102. case IF_TYPE_ETHERNET_CSMACD:
  1103. *HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET;
  1104. break;
  1105. case IF_TYPE_ISO88025_TOKENRING:
  1106. case IF_TYPE_FDDI:
  1107. *HardwareAddressType = HARDWARE_TYPE_IEEE_802;
  1108. break;
  1109. case IF_TYPE_OTHER:
  1110. *HardwareAddressType = HARDWARE_ARCNET;
  1111. break;
  1112. case IF_TYPE_PPP:
  1113. *HardwareAddressType = HARDWARE_PPP;
  1114. break;
  1115. case IF_TYPE_IEEE1394:
  1116. *HardwareAddressType = HARDWARE_1394;
  1117. break;
  1118. default:
  1119. DhcpPrint(( DEBUG_ERRORS, "Invalid HW Type, %ld.\n", IFE.if_type ));
  1120. *HardwareAddressType = HARDWARE_ARCNET;
  1121. break;
  1122. }
  1123. *HardwareAddress = Address;
  1124. *HardwareAddressLength = IFE.if_physaddrlen;
  1125. *pIpInterfaceInstance = ID.toi_entity.tei_instance;
  1126. DhcpPrint( (DEBUG_MISC,
  1127. "tei_instance = %d\n", *pIpInterfaceInstance ));
  1128. *pfFound = TRUE;
  1129. #ifdef BOOTPERF
  1130. if( pfInterfaceDown ) {
  1131. *pfInterfaceDown = (IFE.if_adminstatus != IF_STATUS_UP);
  1132. }
  1133. #endif BOOTPERF
  1134. Status = TDI_SUCCESS;
  1135. goto Cleanup;
  1136. }
  1137. }
  1138. }
  1139. //
  1140. // we couldn't find a corresponding entry. But it may be available
  1141. // in another tanel.
  1142. //
  1143. Status = STATUS_SUCCESS;
  1144. Cleanup:
  1145. if (Status != TDI_SUCCESS) {
  1146. DhcpPrint(( DEBUG_ERRORS, "FindHardwareAddr failed, %lx.\n", Status ));
  1147. }
  1148. return TDI_SUCCESS;
  1149. }
  1150. #ifdef BOOTPERF
  1151. DWORD
  1152. DhcpQueryHWInfoEx(
  1153. DWORD IpInterfaceContext,
  1154. DWORD *pIpInterfaceInstance,
  1155. DWORD *pOldIpAddress OPTIONAL,
  1156. DWORD *pOldMask OPTIONAL,
  1157. BOOL *pfInterfaceDown OPTIONAL,
  1158. LPBYTE HardwareAddressType,
  1159. LPBYTE *HardwareAddress,
  1160. LPDWORD HardwareAddressLength
  1161. )
  1162. /*++
  1163. Routine Description:
  1164. This function queries and browses through the TDI list to find out
  1165. the specified IpTable entry and then determines the HW address that
  1166. corresponds to this entry.
  1167. Arguments:
  1168. IpInterfaceContext - Context value of the Ip Table Entry.
  1169. pIpInterfaceInstance - pointer to the interface instance ID that corresponds
  1170. to matching IpTable entry
  1171. pOldIpAddress - the old IP address that used to exist.
  1172. pOldMask - the old IP mask for this entry.
  1173. pfInterfaceDown -- location of BOOL that tells if the interface is DOWN or UP
  1174. HardwareAddressType - hardware address type.
  1175. HardwareAddress - pointer to location where the HW address buffer
  1176. pointer is returned.
  1177. HardwareAddressLength - length of the HW address returned.
  1178. Return Value:
  1179. Windows Error Code.
  1180. --*/
  1181. {
  1182. DWORD Error;
  1183. NTSTATUS Status;
  1184. DWORD i, j;
  1185. BYTE Context[CONTEXT_SIZE];
  1186. TDIEntityID *EList = NULL;
  1187. TDIObjectID ID;
  1188. DWORD Size;
  1189. DWORD NumReturned;
  1190. BOOL fFound;
  1191. IPAddrEntry * pIAE = NULL;
  1192. IPAddrEntry *pIAEMatch = NULL;
  1193. HANDLE TCPHandle = NULL;
  1194. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  1195. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1196. if (Error != ERROR_SUCCESS) {
  1197. return( Error );
  1198. }
  1199. //
  1200. // The first thing to do is get the list of available entities, and make
  1201. // sure that there are some interface entities present.
  1202. //
  1203. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  1204. ID.toi_entity.tei_instance = 0;
  1205. ID.toi_class = INFO_CLASS_GENERIC;
  1206. ID.toi_type = INFO_TYPE_PROVIDER;
  1207. ID.toi_id = ENTITY_LIST_ID;
  1208. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  1209. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  1210. if (EList == NULL) {
  1211. Status = STATUS_INSUFFICIENT_RESOURCES;
  1212. goto Cleanup;
  1213. }
  1214. RtlZeroMemory(EList, Size);
  1215. RtlZeroMemory(Context, CONTEXT_SIZE);
  1216. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  1217. if (Status != TDI_SUCCESS) {
  1218. goto Cleanup;
  1219. }
  1220. NumReturned = Size/sizeof(TDIEntityID);
  1221. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  1222. for (i = 0; i < NumReturned; i++) {
  1223. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  1224. i, EList[i].tei_entity, EList[i].tei_instance));
  1225. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  1226. IPSNMPInfo IPStats;
  1227. DWORD NLType;
  1228. //
  1229. // Does this entity support IP?
  1230. //
  1231. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1232. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1233. ID.toi_class = INFO_CLASS_GENERIC;
  1234. ID.toi_type = INFO_TYPE_PROVIDER;
  1235. ID.toi_id = ENTITY_TYPE_ID;
  1236. Size = sizeof( NLType );
  1237. NLType = 0;
  1238. RtlZeroMemory(Context, CONTEXT_SIZE);
  1239. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  1240. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  1241. if (Status != TDI_SUCCESS) {
  1242. goto Cleanup;
  1243. }
  1244. if ( NLType != CL_NL_IP ) {
  1245. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  1246. continue;
  1247. }
  1248. //
  1249. // We've got an IP driver so get it's address table
  1250. //
  1251. ID.toi_class = INFO_CLASS_PROTOCOL;
  1252. ID.toi_id = IP_MIB_STATS_ID;
  1253. Size = sizeof(IPStats);
  1254. RtlZeroMemory( &IPStats, Size);
  1255. RtlZeroMemory(Context, CONTEXT_SIZE);
  1256. Status = TCPQueryInformationEx(
  1257. TCPHandle,
  1258. &ID,
  1259. &IPStats,
  1260. &Size,
  1261. Context);
  1262. if (Status != TDI_SUCCESS) {
  1263. goto Cleanup;
  1264. }
  1265. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  1266. if ( IPStats.ipsi_numaddr == 0 ) {
  1267. continue;
  1268. }
  1269. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  1270. while (1) {
  1271. DWORD OldSize;
  1272. pIAE = DhcpAllocateMemory(Size);
  1273. if ( pIAE == NULL ) {
  1274. Status = STATUS_NO_MEMORY;
  1275. goto Cleanup;
  1276. }
  1277. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1278. RtlZeroMemory(Context, CONTEXT_SIZE);
  1279. OldSize = Size;
  1280. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  1281. if (Status == TDI_BUFFER_OVERFLOW) {
  1282. Size = OldSize * 2;
  1283. DhcpFreeMemory(pIAE);
  1284. pIAE = NULL;
  1285. continue;
  1286. }
  1287. if (Status != TDI_SUCCESS) {
  1288. goto Cleanup;
  1289. }
  1290. if (Status == TDI_SUCCESS) {
  1291. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  1292. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  1293. break;
  1294. }
  1295. }
  1296. //
  1297. // We have the IP address table for this IP driver.
  1298. // Find the hardware address corresponds to the given
  1299. // IpInterfaceContext.
  1300. //
  1301. // Loop through the IP table entries and findout the
  1302. // matching entry.
  1303. //
  1304. pIAEMatch = NULL;
  1305. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  1306. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  1307. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  1308. if( pIAE[j].iae_context == IpInterfaceContext ) {
  1309. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  1310. &pIAE[j], IpInterfaceContext ));
  1311. pIAEMatch = &pIAE[j];
  1312. break;
  1313. }
  1314. }
  1315. if( pIAEMatch == NULL ) {
  1316. //
  1317. // freeup the loop memory.
  1318. //
  1319. DhcpFreeMemory( pIAE );
  1320. pIAE = NULL;
  1321. continue;
  1322. }
  1323. //
  1324. // NOTE : There may be more than one IpTable in the TDI
  1325. // list. We need additional information to select the
  1326. // IpTable we want. For now, we assume only one table
  1327. // is supported, so pick the first and only table from the
  1328. // list.
  1329. //
  1330. // If the old ip address is requested, return it.
  1331. //
  1332. if( pOldIpAddress ) *pOldIpAddress = pIAE->iae_addr;
  1333. if( pOldMask ) *pOldMask = pIAE->iae_mask;
  1334. Status = FindHardwareAddr(
  1335. TCPHandle,
  1336. EList,
  1337. NumReturned,
  1338. pIAEMatch,
  1339. HardwareAddressType,
  1340. HardwareAddress,
  1341. HardwareAddressLength,
  1342. pIpInterfaceInstance,
  1343. pfInterfaceDown,
  1344. &fFound
  1345. );
  1346. if (Status != TDI_SUCCESS) {
  1347. goto Cleanup;
  1348. }
  1349. if ( fFound ) {
  1350. Status = TDI_SUCCESS;
  1351. goto Cleanup;
  1352. }
  1353. //
  1354. // freeup the loop memory.
  1355. //
  1356. DhcpFreeMemory( pIAE );
  1357. pIAE = NULL;
  1358. } // if IP
  1359. } // entity traversal
  1360. Status = STATUS_UNSUCCESSFUL;
  1361. Cleanup:
  1362. if( pIAE != NULL ) {
  1363. DhcpFreeMemory( pIAE );
  1364. }
  1365. if( TCPHandle != NULL ) {
  1366. NtClose( TCPHandle );
  1367. }
  1368. if (Status != TDI_SUCCESS) {
  1369. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  1370. }
  1371. if (NULL != EList) {
  1372. DhcpFreeMemory(EList);
  1373. }
  1374. return( RtlNtStatusToDosError( Status ) );
  1375. }
  1376. DWORD
  1377. DhcpQueryHWInfo(
  1378. DWORD IpInterfaceContext,
  1379. DWORD *pIpInterfaceInstance,
  1380. LPBYTE HardwareAddressType,
  1381. LPBYTE *HardwareAddress,
  1382. LPDWORD HardwareAddressLength
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. See DhcpQueryHWInfo
  1387. --*/
  1388. {
  1389. return DhcpQueryHWInfoEx(
  1390. IpInterfaceContext,
  1391. pIpInterfaceInstance,
  1392. NULL, NULL, NULL,
  1393. HardwareAddressType,
  1394. HardwareAddress,
  1395. HardwareAddressLength
  1396. );
  1397. }
  1398. #else BOOTPERF
  1399. DWORD
  1400. DhcpQueryHWInfo(
  1401. DWORD IpInterfaceContext,
  1402. DWORD *pIpInterfaceInstance,
  1403. LPBYTE HardwareAddressType,
  1404. LPBYTE *HardwareAddress,
  1405. LPDWORD HardwareAddressLength
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. This function queries and browses through the TDI list to find out
  1410. the specified IpTable entry and then determines the HW address that
  1411. corresponds to this entry.
  1412. Arguments:
  1413. IpInterfaceContext - Context value of the Ip Table Entry.
  1414. pIpInterfaceInstance - pointer to the interface instance ID that corresponds
  1415. to matching IpTable entry
  1416. HardwareAddressType - hardware address type.
  1417. HardwareAddress - pointer to location where the HW address buffer
  1418. pointer is returned.
  1419. HardwareAddressLength - length of the HW address returned.
  1420. Return Value:
  1421. Windows Error Code.
  1422. --*/
  1423. {
  1424. DWORD Error;
  1425. NTSTATUS Status;
  1426. DWORD i, j;
  1427. BYTE Context[CONTEXT_SIZE];
  1428. TDIEntityID *EList = NULL;
  1429. TDIObjectID ID;
  1430. DWORD Size;
  1431. DWORD NumReturned;
  1432. BOOL fFound;
  1433. IPAddrEntry * pIAE = NULL;
  1434. IPAddrEntry *pIAEMatch = NULL;
  1435. HANDLE TCPHandle = NULL;
  1436. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  1437. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1438. if (Error != ERROR_SUCCESS) {
  1439. return( Error );
  1440. }
  1441. //
  1442. // The first thing to do is get the list of available entities, and make
  1443. // sure that there are some interface entities present.
  1444. //
  1445. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  1446. ID.toi_entity.tei_instance = 0;
  1447. ID.toi_class = INFO_CLASS_GENERIC;
  1448. ID.toi_type = INFO_TYPE_PROVIDER;
  1449. ID.toi_id = ENTITY_LIST_ID;
  1450. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  1451. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  1452. if (EList == NULL) {
  1453. Status = STATUS_INSUFFICIENT_RESOURCES;
  1454. goto Cleanup;
  1455. }
  1456. RtlZeroMemory(EList, Size);
  1457. RtlZeroMemory(Context, CONTEXT_SIZE);
  1458. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  1459. if (Status != TDI_SUCCESS) {
  1460. goto Cleanup;
  1461. }
  1462. NumReturned = Size/sizeof(TDIEntityID);
  1463. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  1464. for (i = 0; i < NumReturned; i++) {
  1465. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  1466. i, EList[i].tei_entity, EList[i].tei_instance));
  1467. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  1468. IPSNMPInfo IPStats;
  1469. DWORD NLType;
  1470. //
  1471. // Does this entity support IP?
  1472. //
  1473. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1474. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1475. ID.toi_class = INFO_CLASS_GENERIC;
  1476. ID.toi_type = INFO_TYPE_PROVIDER;
  1477. ID.toi_id = ENTITY_TYPE_ID;
  1478. Size = sizeof( NLType );
  1479. NLType = 0;
  1480. RtlZeroMemory(Context, CONTEXT_SIZE);
  1481. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  1482. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  1483. if (Status != TDI_SUCCESS) {
  1484. goto Cleanup;
  1485. }
  1486. if ( NLType != CL_NL_IP ) {
  1487. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  1488. continue;
  1489. }
  1490. //
  1491. // We've got an IP driver so get it's address table
  1492. //
  1493. ID.toi_class = INFO_CLASS_PROTOCOL;
  1494. ID.toi_id = IP_MIB_STATS_ID;
  1495. Size = sizeof(IPStats);
  1496. RtlZeroMemory( &IPStats, Size);
  1497. RtlZeroMemory(Context, CONTEXT_SIZE);
  1498. Status = TCPQueryInformationEx(
  1499. TCPHandle,
  1500. &ID,
  1501. &IPStats,
  1502. &Size,
  1503. Context);
  1504. if (Status != TDI_SUCCESS) {
  1505. goto Cleanup;
  1506. }
  1507. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  1508. if ( IPStats.ipsi_numaddr == 0 ) {
  1509. continue;
  1510. }
  1511. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  1512. while (1) {
  1513. DWORD OldSize;
  1514. pIAE = DhcpAllocateMemory(Size);
  1515. if ( pIAE == NULL ) {
  1516. Status = STATUS_NO_MEMORY;
  1517. goto Cleanup;
  1518. }
  1519. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1520. RtlZeroMemory(Context, CONTEXT_SIZE);
  1521. OldSize = Size;
  1522. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  1523. if (Status == TDI_BUFFER_OVERFLOW) {
  1524. Size = OldSize * 2;
  1525. DhcpFreeMemory(pIAE);
  1526. pIAE = NULL;
  1527. continue;
  1528. }
  1529. if (Status != TDI_SUCCESS) {
  1530. goto Cleanup;
  1531. }
  1532. if (Status == TDI_SUCCESS) {
  1533. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  1534. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  1535. break;
  1536. }
  1537. }
  1538. //
  1539. // We have the IP address table for this IP driver.
  1540. // Find the hardware address corresponds to the given
  1541. // IpInterfaceContext.
  1542. //
  1543. // Loop through the IP table entries and findout the
  1544. // matching entry.
  1545. //
  1546. pIAEMatch = NULL;
  1547. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  1548. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  1549. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  1550. if( pIAE[j].iae_context == IpInterfaceContext ) {
  1551. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  1552. &pIAE[j], IpInterfaceContext ));
  1553. pIAEMatch = &pIAE[j];
  1554. break;
  1555. }
  1556. }
  1557. if( pIAEMatch == NULL ) {
  1558. //
  1559. // freeup the loop memory.
  1560. //
  1561. DhcpFreeMemory( pIAE );
  1562. pIAE = NULL;
  1563. continue;
  1564. }
  1565. //
  1566. // NOTE : There may be more than one IpTable in the TDI
  1567. // list. We need additional information to select the
  1568. // IpTable we want. For now, we assume only one table
  1569. // is supported, so pick the first and only table from the
  1570. // list.
  1571. Status = FindHardwareAddr(
  1572. TCPHandle,
  1573. EList,
  1574. NumReturned,
  1575. pIAEMatch,
  1576. HardwareAddressType,
  1577. HardwareAddress,
  1578. HardwareAddressLength,
  1579. pIpInterfaceInstance,
  1580. &fFound );
  1581. if (Status != TDI_SUCCESS) {
  1582. goto Cleanup;
  1583. }
  1584. if ( fFound ) {
  1585. Status = TDI_SUCCESS;
  1586. goto Cleanup;
  1587. }
  1588. //
  1589. // freeup the loop memory.
  1590. //
  1591. DhcpFreeMemory( pIAE );
  1592. pIAE = NULL;
  1593. } // if IP
  1594. } // entity traversal
  1595. Status = STATUS_UNSUCCESSFUL;
  1596. Cleanup:
  1597. if( pIAE != NULL ) {
  1598. DhcpFreeMemory( pIAE );
  1599. }
  1600. if( TCPHandle != NULL ) {
  1601. NtClose( TCPHandle );
  1602. }
  1603. if (Status != TDI_SUCCESS) {
  1604. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  1605. }
  1606. if (NULL != EList) {
  1607. DhcpFreeMemory(EList);
  1608. }
  1609. return( RtlNtStatusToDosError( Status ) );
  1610. }
  1611. #endif BOOTPERF
  1612. #if DBG
  1613. #define print(X) DhcpPrint((DEBUG_TRACE, "%20s\t", inet_ntoa(*(struct in_addr *)&X)))
  1614. #define printx(X) DhcpPrint((DEBUG_TRACE, "%05x\t", X))
  1615. DWORD
  1616. PrintDefaultGateways( VOID ) {
  1617. DWORD Error;
  1618. NTSTATUS Status;
  1619. HANDLE TCPHandle = NULL;
  1620. BYTE Context[CONTEXT_SIZE];
  1621. TDIObjectID ID;
  1622. DWORD Size;
  1623. IPSNMPInfo IPStats;
  1624. IPAddrEntry *AddrTable = NULL;
  1625. DWORD NumReturned;
  1626. DWORD Type;
  1627. DWORD i;
  1628. DWORD MatchIndex;
  1629. IPRouteEntry RouteEntry;
  1630. IPRouteEntry *RtTable;
  1631. DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
  1632. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1633. if (Error != ERROR_SUCCESS) {
  1634. return( Error );
  1635. }
  1636. //
  1637. // Get the NetAddr info, to find an interface index for the gateway.
  1638. //
  1639. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1640. ID.toi_entity.tei_instance = 0;
  1641. ID.toi_class = INFO_CLASS_PROTOCOL;
  1642. ID.toi_type = INFO_TYPE_PROVIDER;
  1643. ID.toi_id = IP_MIB_STATS_ID;
  1644. Size = sizeof(IPStats);
  1645. RtlZeroMemory(&IPStats, Size);
  1646. RtlZeroMemory(Context, CONTEXT_SIZE);
  1647. Status = TCPQueryInformationEx(
  1648. TCPHandle,
  1649. &ID,
  1650. &IPStats,
  1651. &Size,
  1652. Context);
  1653. if (Status != TDI_SUCCESS) {
  1654. goto Cleanup;
  1655. }
  1656. // hack: RouteTable in IP is about 32 in size... and IP seems tob
  1657. // be writing the whole bunch always!
  1658. if(IPStats.ipsi_numroutes <= 32)
  1659. IPStats.ipsi_numroutes = 32;
  1660. Size = IPStats.ipsi_numroutes * sizeof(IPRouteEntry);
  1661. RtTable = DhcpAllocateMemory(Size);
  1662. if (RtTable == NULL) {
  1663. Status = STATUS_NO_MEMORY;
  1664. goto Cleanup;
  1665. }
  1666. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1667. RtlZeroMemory(Context, CONTEXT_SIZE);
  1668. Status = TCPQueryInformationEx(
  1669. TCPHandle,
  1670. &ID,
  1671. RtTable,
  1672. &Size,
  1673. Context);
  1674. if (Status != TDI_SUCCESS) {
  1675. goto Cleanup;
  1676. }
  1677. NumReturned = Size/sizeof(IPAddrEntry);
  1678. DhcpPrint((DEBUG_TRACE, "IP returned %ld routes\n", NumReturned));
  1679. // The following is almost always true... IP returns the whole array.. valid or not!
  1680. // DhcpAssert( NumReturned == IPStats.ipsi_numroutes );
  1681. if( NumReturned > IPStats.ipsi_numroutes)
  1682. NumReturned = IPStats.ipsi_numroutes;
  1683. //
  1684. // We've got the address table. Loop through it. If we find an exact
  1685. // match for the gateway, then we're adding or deleting a direct route
  1686. // and we're done. Otherwise try to find a match on the subnet mask,
  1687. // and remember the first one we find.
  1688. //
  1689. DhcpPrint((DEBUG_TRACE,"Dest mask nexthop index metric1 type proto\n"));
  1690. for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
  1691. print(RtTable[i].ire_dest);
  1692. print(RtTable[i].ire_mask);
  1693. print(RtTable[i].ire_nexthop);
  1694. printx(RtTable[i].ire_index);
  1695. printx(RtTable[i].ire_metric1);
  1696. printx(RtTable[i].ire_type);
  1697. printx(RtTable[i].ire_proto);
  1698. DhcpPrint((DEBUG_TRACE, "\n"));
  1699. }
  1700. DhcpPrint((DEBUG_TRACE, "--------------------------------------------------------\n"));
  1701. Status = TDI_SUCCESS;
  1702. Cleanup:
  1703. if( AddrTable != NULL ) {
  1704. DhcpFreeMemory( AddrTable );
  1705. }
  1706. if( TCPHandle != NULL ) {
  1707. NtClose( TCPHandle );
  1708. }
  1709. if( (Status != TDI_SUCCESS) &&
  1710. (Status != STATUS_UNSUCCESSFUL) ) { // HACK.
  1711. DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
  1712. }
  1713. return( RtlNtStatusToDosError( Status ) );
  1714. }
  1715. #endif
  1716. DWORD
  1717. SetDefaultGateway(
  1718. DWORD Command,
  1719. DHCP_IP_ADDRESS GatewayAddress,
  1720. DWORD Metric
  1721. )
  1722. /*++
  1723. Routine Description:
  1724. This function adds/deletes a default gateway entry from the router table.
  1725. Arguments:
  1726. Command : Either DEFAULT_GATEWAY_ADD/DEFAULT_GATEWAY_DELETE.
  1727. GatewayAddress : Address of the default gateway.
  1728. Return Value:
  1729. Windows Error Code.
  1730. --*/
  1731. {
  1732. DWORD Error;
  1733. NTSTATUS Status;
  1734. HANDLE TCPHandle = NULL;
  1735. BYTE Context[CONTEXT_SIZE];
  1736. TDIObjectID ID;
  1737. DWORD Size;
  1738. IPSNMPInfo IPStats;
  1739. IPAddrEntry *AddrTable = NULL;
  1740. DWORD NumReturned;
  1741. DWORD Type;
  1742. DWORD i;
  1743. DWORD MatchIndex;
  1744. IPRouteEntry RouteEntry;
  1745. DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
  1746. NetworkOrderGatewayAddress = htonl( GatewayAddress );
  1747. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1748. if (Error != ERROR_SUCCESS) {
  1749. return( Error );
  1750. }
  1751. //
  1752. // Get the NetAddr info, to find an interface index for the gateway.
  1753. //
  1754. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1755. ID.toi_entity.tei_instance = 0;
  1756. ID.toi_class = INFO_CLASS_PROTOCOL;
  1757. ID.toi_type = INFO_TYPE_PROVIDER;
  1758. ID.toi_id = IP_MIB_STATS_ID;
  1759. Size = sizeof(IPStats);
  1760. RtlZeroMemory(&IPStats, Size);
  1761. RtlZeroMemory(Context, CONTEXT_SIZE);
  1762. Status = TCPQueryInformationEx(
  1763. TCPHandle,
  1764. &ID,
  1765. &IPStats,
  1766. &Size,
  1767. Context
  1768. );
  1769. if (Status != TDI_SUCCESS) {
  1770. goto Cleanup;
  1771. }
  1772. Size = IPStats.ipsi_numaddr * sizeof(IPAddrEntry);
  1773. AddrTable = DhcpAllocateMemory(Size);
  1774. if (AddrTable == NULL) {
  1775. Status = STATUS_NO_MEMORY;
  1776. goto Cleanup;
  1777. }
  1778. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1779. RtlZeroMemory(Context, CONTEXT_SIZE);
  1780. Status = TCPQueryInformationEx(
  1781. TCPHandle,
  1782. &ID,
  1783. AddrTable,
  1784. &Size,
  1785. Context
  1786. );
  1787. if (Status != TDI_SUCCESS) {
  1788. goto Cleanup;
  1789. }
  1790. NumReturned = Size/sizeof(IPAddrEntry);
  1791. DhcpAssert( NumReturned == IPStats.ipsi_numaddr );
  1792. //
  1793. // We've got the address table. Loop through it. If we find an exact
  1794. // match for the gateway, then we're adding or deleting a direct route
  1795. // and we're done. Otherwise try to find a match on the subnet mask,
  1796. // and remember the first one we find.
  1797. //
  1798. Type = IRE_TYPE_INDIRECT;
  1799. for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
  1800. if( AddrTable[i].iae_addr == NetworkOrderGatewayAddress ) {
  1801. //
  1802. // Found an exact match.
  1803. //
  1804. MatchIndex = i;
  1805. Type = IRE_TYPE_DIRECT;
  1806. break;
  1807. }
  1808. //
  1809. // The next hop is on the same subnet as this address. If
  1810. // we haven't already found a match, remember this one.
  1811. //
  1812. if ( (MatchIndex == 0xffff) &&
  1813. (AddrTable[i].iae_addr != 0) &&
  1814. (AddrTable[i].iae_mask != 0) &&
  1815. ((AddrTable[i].iae_addr & AddrTable[i].iae_mask) ==
  1816. (NetworkOrderGatewayAddress & AddrTable[i].iae_mask)) ) {
  1817. MatchIndex = i;
  1818. }
  1819. }
  1820. //
  1821. // We've looked at all of the entries. See if we found a match.
  1822. //
  1823. if (MatchIndex == 0xffff) {
  1824. //
  1825. // Didn't find a match.
  1826. //
  1827. Status = STATUS_UNSUCCESSFUL;
  1828. goto Cleanup;
  1829. }
  1830. //
  1831. // We've found a match. Fill in the route entry, and call the
  1832. // Set API.
  1833. //
  1834. RouteEntry.ire_dest = DEFAULT_DEST;
  1835. RouteEntry.ire_index = AddrTable[MatchIndex].iae_index;
  1836. RouteEntry.ire_metric1 = Metric;
  1837. RouteEntry.ire_metric2 = (DWORD)(-1);
  1838. RouteEntry.ire_metric3 = (DWORD)(-1);
  1839. RouteEntry.ire_metric4 = (DWORD)(-1);
  1840. RouteEntry.ire_nexthop = NetworkOrderGatewayAddress;
  1841. RouteEntry.ire_type =
  1842. (Command == DEFAULT_GATEWAY_DELETE ? IRE_TYPE_INVALID : Type);
  1843. RouteEntry.ire_proto = IRE_PROTO_NETMGMT;
  1844. RouteEntry.ire_age = 0;
  1845. RouteEntry.ire_mask = DEFAULT_DEST_MASK;
  1846. RouteEntry.ire_metric5 = (DWORD)(-1);
  1847. RouteEntry.ire_context = 0;
  1848. Size = sizeof(RouteEntry);
  1849. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1850. Status = TCPSetInformationEx(
  1851. TCPHandle,
  1852. &ID,
  1853. &RouteEntry,
  1854. Size );
  1855. if ( Status != TDI_SUCCESS &&
  1856. Status != TDI_BUFFER_OVERFLOW ) {
  1857. goto Cleanup;
  1858. }
  1859. Status = TDI_SUCCESS;
  1860. Cleanup:
  1861. if( AddrTable != NULL ) {
  1862. DhcpFreeMemory( AddrTable );
  1863. }
  1864. if( TCPHandle != NULL ) {
  1865. NtClose( TCPHandle );
  1866. }
  1867. if( (Status != TDI_SUCCESS) &&
  1868. (Status != STATUS_UNSUCCESSFUL) ) { // HACK.
  1869. DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
  1870. }
  1871. return( RtlNtStatusToDosError( Status ) );
  1872. }
  1873. DWORD
  1874. GetIpInterfaceContext(
  1875. LPWSTR AdapterName,
  1876. DWORD IpIndex,
  1877. LPDWORD IpInterfaceContext
  1878. )
  1879. /*++
  1880. Routine Description:
  1881. This function returns the IpInterfaceContext for the specified
  1882. IpAddress and devicename.
  1883. Arguments:
  1884. AdapterName - name of the device.
  1885. IpIndex - index of the IpAddress for this device.
  1886. IpInterfaceContext - pointer to a location where the
  1887. interface context is returned.
  1888. Return Value:
  1889. Windows Error Code.
  1890. --*/
  1891. {
  1892. DWORD Error;
  1893. LPWSTR RegKey = NULL;
  1894. HKEY KeyHandle = NULL;
  1895. LPWSTR nteContextList = NULL;
  1896. PCHAR oemNextContext = NULL;
  1897. LPWSTR nextContext;
  1898. DWORD i;
  1899. *IpInterfaceContext = INVALID_INTERFACE_CONTEXT;
  1900. //
  1901. // Open device parameter.
  1902. //
  1903. RegKey = DhcpAllocateMemory(
  1904. (wcslen(DHCP_SERVICES_KEY) +
  1905. wcslen(REGISTRY_CONNECT_STRING) +
  1906. wcslen(AdapterName) +
  1907. wcslen(DHCP_ADAPTER_PARAMETERS_KEY) + 1) *
  1908. sizeof(WCHAR) ); // termination char.
  1909. if( RegKey == NULL ) {
  1910. Error = ERROR_NOT_ENOUGH_MEMORY;
  1911. goto Cleanup;
  1912. }
  1913. wcscpy( RegKey, DHCP_SERVICES_KEY );
  1914. wcscat( RegKey, DHCP_ADAPTER_PARAMETERS_KEY );
  1915. wcscat( RegKey, REGISTRY_CONNECT_STRING );
  1916. wcscat( RegKey, AdapterName );
  1917. //
  1918. // open this key.
  1919. //
  1920. Error = RegOpenKeyEx(
  1921. HKEY_LOCAL_MACHINE,
  1922. RegKey,
  1923. 0, // Reserved field
  1924. DHCP_CLIENT_KEY_ACCESS,
  1925. &KeyHandle
  1926. );
  1927. if( Error != ERROR_SUCCESS ) {
  1928. goto Cleanup;
  1929. }
  1930. Error = GetRegistryString(
  1931. KeyHandle,
  1932. DHCP_NTE_CONTEXT_LIST,
  1933. &nteContextList,
  1934. NULL
  1935. );
  1936. if( nteContextList == NULL ) {
  1937. Error = ERROR_BAD_FORMAT;
  1938. DhcpPrint((DEBUG_ERRORS, "NteContextList empty\n"));
  1939. goto Cleanup;
  1940. }
  1941. if ( ERROR_SUCCESS != Error )
  1942. {
  1943. DhcpPrint( (DEBUG_ERRORS,
  1944. "GetIpInterfaceContext: Could not read nteContextList %lx\n",
  1945. Error));
  1946. goto Cleanup;
  1947. }
  1948. for( nextContext = nteContextList, i = 0;
  1949. *nextContext != L'\0' && i < IpIndex;
  1950. i++, nextContext += (wcslen(nextContext) + 1) );
  1951. if ( *nextContext != L'\0' && i == IpIndex ) {
  1952. ULONG ival;
  1953. oemNextContext = DhcpUnicodeToOem(nextContext, NULL);
  1954. if ( NULL == oemNextContext ) {
  1955. Error = ERROR_BAD_FORMAT;
  1956. } else {
  1957. ival = strtoul(oemNextContext, NULL, 0);
  1958. if ( ival == ULONG_MAX || ival == 0) {
  1959. Error = ERROR_BAD_FORMAT;
  1960. } else {
  1961. *IpInterfaceContext = ival;
  1962. }
  1963. }
  1964. }
  1965. Cleanup:
  1966. if( RegKey != NULL ) {
  1967. DhcpFreeMemory( RegKey );
  1968. }
  1969. if( KeyHandle != NULL ) {
  1970. RegCloseKey( KeyHandle );
  1971. }
  1972. if ( nteContextList != NULL ) {
  1973. DhcpFreeMemory( nteContextList );
  1974. }
  1975. if ( oemNextContext != NULL ) {
  1976. DhcpFreeMemory( oemNextContext );
  1977. }
  1978. return( Error );
  1979. }
  1980. HANDLE
  1981. APIENTRY
  1982. DhcpOpenGlobalEvent(
  1983. void
  1984. )
  1985. /*++
  1986. Routine Description:
  1987. This functions creates global event that signals the the ipaddress
  1988. changes to other waiting processes. The security dacl is set to NULL
  1989. that makes anyone to open and read/set this event.
  1990. Arguments:
  1991. None.
  1992. Return Value:
  1993. Handle value of the global event. If the handle is NULL,
  1994. GetLastError() function will return Windows error code.
  1995. --*/
  1996. {
  1997. DWORD Error = NO_ERROR, Status, Length;
  1998. BOOL BoolError;
  1999. HANDLE EventHandle = NULL;
  2000. SECURITY_ATTRIBUTES SecurityAttributes;
  2001. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_WORLD_SID_AUTHORITY;
  2002. PACL Acl = NULL;
  2003. PSID WorldSid = NULL;
  2004. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  2005. //
  2006. // If event can be opened, chose that, don't attempt create
  2007. //
  2008. EventHandle = OpenEvent(
  2009. EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE,
  2010. DHCP_NEW_IPADDRESS_EVENT_NAME
  2011. );
  2012. if( NULL != EventHandle ) return EventHandle;
  2013. //
  2014. // Set DACL also.. first create basic SIDs
  2015. //
  2016. BoolError = AllocateAndInitializeSid(
  2017. &Authority, 1, SECURITY_WORLD_RID,
  2018. 0, 0, 0, 0, 0, 0, 0,
  2019. &WorldSid
  2020. );
  2021. if( BoolError == FALSE ) {
  2022. return NULL;
  2023. }
  2024. Length = ( (ULONG)sizeof(ACL) + (ULONG)sizeof(ACCESS_ALLOWED_ACE)
  2025. + GetLengthSid( WorldSid ) + 16 );
  2026. Acl = DhcpAllocateMemory( Length );
  2027. if( NULL == Acl ) {
  2028. Error = ERROR_NOT_ENOUGH_MEMORY;
  2029. goto Cleanup;
  2030. }
  2031. BoolError = InitializeAcl( Acl, Length, ACL_REVISION2 );
  2032. if( FALSE == BoolError ) {
  2033. Error = GetLastError();
  2034. goto Cleanup;
  2035. }
  2036. BoolError = AddAccessAllowedAce(
  2037. Acl, ACL_REVISION2,
  2038. EVENT_MODIFY_STATE | SYNCHRONIZE,
  2039. WorldSid
  2040. );
  2041. if( FALSE == BoolError ) {
  2042. Error = GetLastError();
  2043. goto Cleanup;
  2044. }
  2045. SecurityDescriptor = DhcpAllocateMemory(
  2046. SECURITY_DESCRIPTOR_MIN_LENGTH
  2047. );
  2048. if( NULL == SecurityDescriptor ) {
  2049. Error = ERROR_NOT_ENOUGH_MEMORY;
  2050. goto Cleanup;
  2051. }
  2052. BoolError = InitializeSecurityDescriptor(
  2053. SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION
  2054. );
  2055. if( BoolError == FALSE ) {
  2056. Error = GetLastError();
  2057. goto Cleanup;
  2058. }
  2059. BoolError = SetSecurityDescriptorDacl(
  2060. SecurityDescriptor, TRUE, Acl, FALSE
  2061. );
  2062. if( BoolError == FALSE ) {
  2063. Error = GetLastError();
  2064. goto Cleanup;
  2065. }
  2066. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  2067. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  2068. SecurityAttributes.bInheritHandle = FALSE;
  2069. EventHandle = CreateEvent(
  2070. &SecurityAttributes,
  2071. // everyone all access security.
  2072. TRUE, // MANUAL reset.
  2073. FALSE, // initial state is signaled.
  2074. DHCP_NEW_IPADDRESS_EVENT_NAME
  2075. );
  2076. if( NULL == EventHandle ) {
  2077. Error = GetLastError();
  2078. } else {
  2079. Error = NO_ERROR;
  2080. }
  2081. Cleanup:
  2082. if( SecurityDescriptor ) {
  2083. DhcpFreeMemory( SecurityDescriptor );
  2084. }
  2085. if( Acl ) {
  2086. DhcpFreeMemory( Acl );
  2087. }
  2088. if( WorldSid ) {
  2089. FreeSid( WorldSid );
  2090. }
  2091. if( NO_ERROR != Error ) {
  2092. SetLastError( Error );
  2093. }
  2094. return( EventHandle );
  2095. }
  2096. BOOL
  2097. NdisWanAdapter( // Is this an NdisWan adapter?
  2098. IN PDHCP_CONTEXT DhcpContext
  2099. )
  2100. {
  2101. return DhcpContext->HardwareAddressType == HARDWARE_PPP;
  2102. }
  2103. DWORD INLINE // win32 status
  2104. DhcpEnableDynamicConfigEx( // convert from static to dhcp and start DHCP client if reqd
  2105. IN LPWSTR AdapterName
  2106. )
  2107. {
  2108. DWORD Error;
  2109. // ask the dhcp client to takeup this adapter also
  2110. Error = DhcpEnableDynamicConfig(AdapterName);
  2111. // now there are a couple possibilities:
  2112. // - the above call succeeded
  2113. // - DHCP service is not started or just got terminated
  2114. // - DHCP service failed to process the request with some error
  2115. // in the first case just go on straight to exit and return success
  2116. // in the second case we attempt to start the DHCP service if it is not already started
  2117. // in the last case we just bail out with the specific error
  2118. if( Error == ERROR_FILE_NOT_FOUND || Error == ERROR_BROKEN_PIPE )
  2119. {
  2120. SC_HANDLE SCHandle;
  2121. SC_HANDLE ServiceHandle;
  2122. SERVICE_STATUS svcStatus;
  2123. // attempt now to start the DHCP service.
  2124. // first thing to do is to open SCM
  2125. SCHandle = OpenSCManager(
  2126. NULL,
  2127. NULL,
  2128. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS
  2129. );
  2130. if( SCHandle == NULL )
  2131. return GetLastError(); // shouldn't happen normally
  2132. // attempt to open the DHCP service
  2133. ServiceHandle = OpenService(
  2134. SCHandle,
  2135. SERVICE_DHCP,
  2136. SERVICE_QUERY_STATUS | SERVICE_START
  2137. );
  2138. if (ServiceHandle != NULL)
  2139. {
  2140. // check the status of the service
  2141. if (!QueryServiceStatus(ServiceHandle, &svcStatus) ||
  2142. svcStatus.dwCurrentState != SERVICE_RUNNING)
  2143. {
  2144. // is it worthy to attempt to start the service if QueryServiceStatus failed?
  2145. Error = StartService(ServiceHandle, 0, NULL) ? ERROR_SUCCESS : GetLastError();
  2146. }
  2147. CloseServiceHandle(ServiceHandle);
  2148. }
  2149. else
  2150. Error = GetLastError();
  2151. CloseServiceHandle(SCHandle);
  2152. }
  2153. return Error;
  2154. }
  2155. DWORD // win32 status
  2156. DhcpNotifyConfigChangeNotifications( // notify whoever needed of param changes
  2157. VOID
  2158. )
  2159. {
  2160. HANDLE NotifyEvent;
  2161. DWORD Error;
  2162. BOOL BoolError;
  2163. NotifyEvent = DhcpOpenGlobalEvent();
  2164. if( NULL == NotifyEvent ) {
  2165. Error = GetLastError();
  2166. DhcpPrint((DEBUG_ERRORS, "DhcpOpenGlobalEvent:0x%lx\n", Error));
  2167. return Error;
  2168. }
  2169. BoolError = PulseEvent(NotifyEvent);
  2170. if( BoolError ) Error = ERROR_SUCCESS;
  2171. else Error = GetLastError();
  2172. CloseHandle(NotifyEvent);
  2173. if( ERROR_SUCCESS != Error ) {
  2174. DhcpPrint((DEBUG_ERRORS, "PulseEvent(NotifyEvent): 0x%lx\n", Error));
  2175. }
  2176. return Error;
  2177. }
  2178. DWORD // win32 status
  2179. APIENTRY
  2180. DhcpNotifyConfigChangeEx( // handle address changes, param changes etc.
  2181. IN LPWSTR ServerName, // name of server where this will be executed
  2182. IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
  2183. IN BOOL IsNewIpAddress,// is address new/ or address is same?
  2184. IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
  2185. IN DWORD IpAddress, // the ip address that is being set
  2186. IN DWORD SubnetMask, // corresponding subnet mask
  2187. IN SERVICE_ENABLE DhcpServiceEnabled,
  2188. IN ULONG Flags
  2189. )
  2190. {
  2191. DWORD Error;
  2192. DWORD IpInterfaceContext;
  2193. DWORD DefaultSubnetMask;
  2194. DhcpPrint(( DEBUG_MISC, "DhcpNotifyConfigChange: Adapter %ws, IsNewIp %s, IpAddr %lx, IpIndex %x, ServiceFlag %d\n",
  2195. AdapterName, IsNewIpAddress ? "TRUE" : "FALSE", IpAddress, IpIndex, DhcpServiceEnabled ));
  2196. // param checks
  2197. if( NULL == AdapterName ) return ERROR_INVALID_PARAMETER;
  2198. if( DhcpEnable == DhcpServiceEnabled ) { // converting from static to dhcp enabled address
  2199. if( FALSE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2200. if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
  2201. if( IpAddress || SubnetMask ) return ERROR_INVALID_PARAMETER;
  2202. } else if( DhcpDisable == DhcpServiceEnabled){// converting from dhcp to static address
  2203. if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2204. if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
  2205. if( 0 == IpAddress || 0 == SubnetMask ) return ERROR_INVALID_PARAMETER;
  2206. } else {
  2207. if( IgnoreFlag != DhcpServiceEnabled ) return ERROR_INVALID_PARAMETER;
  2208. // if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2209. if( 0xFFFF == IpIndex ) {
  2210. if( 0 == SubnetMask || 0 == IpAddress ) return ERROR_INVALID_PARAMETER;
  2211. }
  2212. }
  2213. if( IgnoreFlag == DhcpServiceEnabled && FALSE == IsNewIpAddress ) {
  2214. ULONG LocalError;
  2215. // just some parameters changed -- currently, this could only be DNS domain name or server list change
  2216. // or may be static gateway list change or static route change
  2217. Error = DhcpStaticRefreshParams(AdapterName);
  2218. if( ERROR_SUCCESS != Error ) {
  2219. DhcpPrint((DEBUG_ERRORS, "DhcpNotifyConfigChange:DhcpStaticRefreshParams:0x%lx\n", Error));
  2220. }
  2221. LocalError = NetBTNotifyRegChanges(AdapterName);
  2222. if( ERROR_SUCCESS != LocalError ) {
  2223. DhcpPrint((
  2224. DEBUG_ERRORS, "NetbtNotify(%ws): 0x%lx\n",
  2225. AdapterName, LocalError
  2226. ));
  2227. }
  2228. return Error;
  2229. }
  2230. if( DhcpEnable == DhcpServiceEnabled ) { // convert from static to dhcp
  2231. Error = IPDelNonPrimaryAddresses( // remove all but the first static address
  2232. AdapterName
  2233. );
  2234. if( ERROR_SUCCESS != Error ) return Error;
  2235. Error = DhcpEnableDynamicConfigEx( // convert this to dhcp, maybe starting dhcp in the process
  2236. AdapterName
  2237. );
  2238. return Error; // notifications already done by service when we dhcp enable it..
  2239. } else if( DhcpDisable == DhcpServiceEnabled ) {
  2240. Error = DhcpDisableDynamicConfig( AdapterName );
  2241. if( Error != ERROR_SUCCESS ) return Error;
  2242. }
  2243. // NetBt device name stuff removed, see any version pre- Oct 10, 1997
  2244. DhcpAssert(TRUE == IsNewIpAddress); // ip address changed in some way
  2245. DhcpAssert(DhcpEnable != DhcpServiceEnabled); // static->dhcp already handled before
  2246. DefaultSubnetMask = DhcpDefaultSubnetMask(0);
  2247. if( INVALID_INTERFACE_CONTEXT == IpIndex ) { // adding a new ip address
  2248. DhcpAssert( IpAddress && SubnetMask); // cannot be zero, these
  2249. Error = IPAddIPAddress( // add the reqd ip address
  2250. AdapterName,
  2251. IpAddress,
  2252. SubnetMask
  2253. );
  2254. if( ERROR_SUCCESS != Error ) return Error;
  2255. } else { // either delete or modify -- first find ipinterfacecontext
  2256. Error = GetIpInterfaceContext( // get the interface context value for this
  2257. AdapterName,
  2258. IpIndex,
  2259. &IpInterfaceContext
  2260. );
  2261. if( ERROR_SUCCESS != Error ) {
  2262. DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: 0x%lx\n", Error));
  2263. return Error;
  2264. }
  2265. if( IpInterfaceContext == INVALID_INTERFACE_CONTEXT) {
  2266. DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: returned ifctxt=INVALID_INTERFACE_CONTEXT\n"));
  2267. return ERROR_INVALID_DRIVE;
  2268. }
  2269. if ( IpAddress != 0 ) { // if address is non-zero, we are changing address
  2270. if (Flags & NOTIFY_FLG_RESET_IPADDR)
  2271. {
  2272. Error = IPResetIPAddress( // first reset the interface to zero address
  2273. IpInterfaceContext,
  2274. DefaultSubnetMask
  2275. );
  2276. if( ERROR_SUCCESS != Error ) return Error;
  2277. }
  2278. Error = IPSetIPAddress( // then set the required address
  2279. IpInterfaceContext,
  2280. IpAddress,
  2281. SubnetMask
  2282. );
  2283. if( ERROR_SUCCESS != Error ) return Error;
  2284. Error = SetOverRideDefaultGateway( AdapterName );
  2285. } else { // we are deleting addresses
  2286. // we need to treat the 0th index separately from others.
  2287. // IPDelIPAddress actually destroys the NTE from IP. But
  2288. // we never blow away 0th index NTE. Just reset the ipaddr on it.
  2289. if ( IpIndex == 0 ) {
  2290. Error = IPResetIPAddress( // just set this address to zero, dont blow interface away
  2291. IpInterfaceContext,DefaultSubnetMask
  2292. );
  2293. } else { // in this case, blow this interface altogether
  2294. Error = IPDelIPAddress( IpInterfaceContext );
  2295. }
  2296. if( ERROR_SUCCESS != Error ) return Error;
  2297. }
  2298. }
  2299. Error = DhcpNotifyConfigChangeNotifications();// notify clients, pulse the global event
  2300. if( ERROR_SUCCESS != Error ) return Error;
  2301. // refresh the parameters for static addresses
  2302. Error = DhcpStaticRefreshParamsInternal(
  2303. AdapterName, (Flags & NOTIFY_FLG_DO_DNS) ? TRUE : FALSE
  2304. );
  2305. if( ERROR_SUCCESS != Error ) { // ignore this error anyways
  2306. DhcpPrint((DEBUG_ERRORS, "DhcpStaticRefreshParams(%ws):0x%lx\n", AdapterName,Error));
  2307. }
  2308. return ERROR_SUCCESS;
  2309. }
  2310. //================================================================================
  2311. // This function (API) notifies the TCP/IP configuration changes to
  2312. // appropriate services. These changes will be in effect as soon as
  2313. // possible.
  2314. //
  2315. // If the IP Address is modified, the services are reset to ZERO IP
  2316. // address (to cleanup the current IP address) and then set to new
  2317. // address.
  2318. //
  2319. // IpIndex - if the specified device is configured with multiple IP
  2320. // addresses, specify index of address that is modified (0 - first
  2321. // IpAddress, 1 - second IpAddres, so on) Pass 0xFFFF if adding an
  2322. // additional address. The order of IP address is determined by the
  2323. // order in the registry MULTI_SZ value "IPAddress" for the static
  2324. // addresses. For dhcp enabled ip address, only ipindex 0 is valid.
  2325. //
  2326. // Everytime when an address is added, removed or modified, the
  2327. // order in the registry may change. It is caller's responsibility
  2328. // to check the current order, and hence the index, before calling
  2329. // this api.
  2330. //
  2331. // DhcpServiceEnabled -
  2332. // IgnoreFlag - indicates Ignore this flag. IgnoreFlag
  2333. // DhcpEnable - indicates DHCP is enabled for this adapter.
  2334. // DhcpDisable - indicates DHCP is diabled for this adapter.
  2335. //
  2336. //Invarient:
  2337. //
  2338. // (1) DHCP enabled IPAddr and Static addr can exists only mutually exclusively.
  2339. // (2) An interface cannot have more than 1 dhcp enabled ip address. However it
  2340. // can have many static addresses.
  2341. //
  2342. //Usage:
  2343. //
  2344. // Case 1: Changing from dhcp enabled ipaddress to static address(es)
  2345. // - Firstly, change the first dhcp enabled ipaddress to static address.
  2346. // arguments {SN, AN, TRUE, 0, I1, S1, DhcpDisable}
  2347. // - Seconfly, add the remaining static address(es)
  2348. // arguments (SN, AN, TRUE, 0xFFFF, I2, S2, DhcpIgnore)
  2349. // arguments (SN, AN, TRUE, 0xFFFF, I3, S3, IgnoreFlag) and so on.
  2350. //
  2351. // Case 2: Changing from static address(es) to dhcp enabled ipaddress
  2352. // - Change the first static address to dhcp enabled. The api will delete
  2353. // the remaining static address(es).
  2354. // arguments (SN, AN, FALSE, 0, 0, 0, DhcpEnable)
  2355. //
  2356. // Case 3: Adding, removing or changing static addresses.
  2357. // - Adding:
  2358. // arguments (SN, AN, TRUE, 0xFFFF, I, S, DhcpIgnore)
  2359. // - Removing, say address # 2 i.e ipindex = 1
  2360. // arguments (SN, AN, TRUE, 1, 0, 0, DhcpIgnore)
  2361. // - Changing, say address # 2 i.e ipindex = 1
  2362. // arguments (SN, AN, TRUE, 1, I, S, DhcpIgnore)
  2363. //
  2364. //================================================================================
  2365. DWORD // win32 status
  2366. APIENTRY
  2367. DhcpNotifyConfigChange( // handle address changes, param changes etc.
  2368. IN LPWSTR ServerName, // name of server where this will be executed
  2369. IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
  2370. IN BOOL IsNewIpAddress,// is address new/ or address is same?
  2371. IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
  2372. IN DWORD IpAddress, // the ip address that is being set
  2373. IN DWORD SubnetMask, // corresponding subnet mask
  2374. IN SERVICE_ENABLE DhcpServiceEnabled
  2375. )
  2376. {
  2377. return DhcpNotifyConfigChangeEx(
  2378. ServerName, AdapterName, IsNewIpAddress,
  2379. IpIndex, IpAddress, SubnetMask, DhcpServiceEnabled,
  2380. NOTIFY_FLG_DO_DNS | NOTIFY_FLG_RESET_IPADDR
  2381. );
  2382. }
  2383. DWORD BringUpInterface( PVOID pvLocalInformation )
  2384. {
  2385. LOCAL_CONTEXT_INFO *pContext;
  2386. TCP_REQUEST_SET_INFORMATION_EX *pTcpRequest;
  2387. TDIObjectID *pObjectID;
  2388. IFEntry *pIFEntry;
  2389. int cbTcpRequest;
  2390. HANDLE hDriver = NULL;
  2391. DWORD dwResult;
  2392. NTSTATUS NtStatus;
  2393. IO_STATUS_BLOCK IoStatusBlock;
  2394. DhcpPrint( ( DEBUG_MISC, "Entering BringUpInterface\n" ));
  2395. dwResult = OpenDriver( &hDriver, DD_TCP_DEVICE_NAME );
  2396. if ( ERROR_SUCCESS != dwResult )
  2397. {
  2398. DhcpPrint( ( DEBUG_ERRORS,
  2399. "BringUpInterface: Unable to open TCP driver.\n" ) );
  2400. return dwResult;
  2401. }
  2402. pContext = (LOCAL_CONTEXT_INFO *) pvLocalInformation;
  2403. //
  2404. // compute the input buffer size and allocate
  2405. //
  2406. cbTcpRequest = sizeof( TCP_REQUEST_SET_INFORMATION_EX )
  2407. + sizeof( IFEntry ) -1;
  2408. //
  2409. // initialize the request
  2410. //
  2411. pTcpRequest = DhcpAllocateMemory( cbTcpRequest );
  2412. if ( !pTcpRequest )
  2413. {
  2414. NtClose( hDriver );
  2415. DhcpPrint( ( DEBUG_ERRORS,
  2416. "BringUpInterface: Insufficient memory\n" ));
  2417. return ERROR_NOT_ENOUGH_MEMORY;
  2418. }
  2419. pTcpRequest->BufferSize = cbTcpRequest - sizeof(TCP_REQUEST_SET_INFORMATION_EX);
  2420. pObjectID = &pTcpRequest->ID;
  2421. pIFEntry = (IFEntry *) &pTcpRequest->Buffer[0];
  2422. pObjectID->toi_entity.tei_entity = IF_ENTITY;
  2423. pObjectID->toi_entity.tei_instance = pContext->IpInterfaceInstance;
  2424. pObjectID->toi_class = INFO_CLASS_PROTOCOL;
  2425. pObjectID->toi_type = INFO_TYPE_PROVIDER;
  2426. pObjectID->toi_id = IF_MIB_STATS_ID;
  2427. pIFEntry->if_adminstatus = IF_STATUS_UP;
  2428. NtStatus = NtDeviceIoControlFile(
  2429. hDriver, NULL, NULL, NULL, &IoStatusBlock,
  2430. IOCTL_TCP_SET_INFORMATION_EX,
  2431. pTcpRequest, cbTcpRequest,
  2432. NULL, 0
  2433. );
  2434. if ( STATUS_PENDING == NtStatus )
  2435. {
  2436. if ( STATUS_SUCCESS == NtWaitForSingleObject( hDriver, TRUE, NULL ) )
  2437. NtStatus = IoStatusBlock.Status;
  2438. #ifdef DBG
  2439. if ( STATUS_SUCCESS != NtStatus )
  2440. DhcpPrint( ( DEBUG_ERRORS,
  2441. "BringUpInterface: failed to bring up adapter\n" ));
  2442. #endif
  2443. } else if ( STATUS_SUCCESS == NtStatus ) {
  2444. NtStatus = IoStatusBlock.Status;
  2445. }
  2446. //
  2447. // Clean up
  2448. //
  2449. if ( hDriver )
  2450. NtClose( hDriver );
  2451. if ( pTcpRequest )
  2452. DhcpFreeMemory( pTcpRequest );
  2453. DhcpPrint( ( DEBUG_MISC,
  2454. "Leaving BringUpInterface\n" ) );
  2455. return RtlNtStatusToDosError( NtStatus );
  2456. }
  2457. #if defined(_PNP_POWER_)
  2458. DWORD
  2459. IPGetIPEventRequest(
  2460. HANDLE handle,
  2461. HANDLE event,
  2462. UINT seqNo,
  2463. PIP_GET_IP_EVENT_RESPONSE responseBuffer,
  2464. DWORD responseBufferSize,
  2465. PIO_STATUS_BLOCK ioStatusBlock
  2466. )
  2467. /*++
  2468. Routine Description:
  2469. This rountine sends the ioctl to get media sense notification from
  2470. IP.
  2471. Arguments:
  2472. handle - handle to tcpip driver.
  2473. event - the event we need to do wait on.
  2474. seqNo - seqNo of the last event received.
  2475. responseBuffer - pointer to the buffer where event info will be stored.
  2476. ioStatusBlock - status of the operation, if not pending.
  2477. Return Value:
  2478. NT Error Code.
  2479. --*/
  2480. {
  2481. NTSTATUS status;
  2482. DWORD Error;
  2483. IP_GET_IP_EVENT_REQUEST requestBuffer;
  2484. requestBuffer.SequenceNo = seqNo;
  2485. RtlZeroMemory( responseBuffer, sizeof(IP_GET_IP_EVENT_RESPONSE));
  2486. responseBuffer->ContextStart = 0xFFFF;
  2487. status = NtDeviceIoControlFile(
  2488. handle, // Driver handle
  2489. event, // Event
  2490. NULL, // APC Routine
  2491. NULL, // APC context
  2492. ioStatusBlock, // Status block
  2493. IOCTL_IP_GET_IP_EVENT, // Control code
  2494. &requestBuffer, // Input buffer
  2495. sizeof(IP_GET_IP_EVENT_REQUEST), // Input buffer size
  2496. responseBuffer, // Output buffer
  2497. responseBufferSize // Output buffer size
  2498. );
  2499. if ( status == STATUS_SUCCESS ) {
  2500. status = ioStatusBlock->Status;
  2501. }
  2502. return status;
  2503. }
  2504. DWORD
  2505. IPCancelIPEventRequest(
  2506. HANDLE handle,
  2507. PIO_STATUS_BLOCK ioStatusBlock
  2508. )
  2509. /*++
  2510. Routine Description:
  2511. This rountine cancels the ioctl that was sent to get media sense
  2512. notification from IP.
  2513. Arguments:
  2514. handle - handle to the ip driver.
  2515. Return Value:
  2516. NT Error Code.
  2517. --*/
  2518. {
  2519. NTSTATUS status;
  2520. DWORD Error;
  2521. status = NtCancelIoFile(
  2522. handle, // Driver handle
  2523. ioStatusBlock); // Status block
  2524. DhcpPrint( (DEBUG_TRACE,"IPCancelIPEventRequest: status %lx\n",status));
  2525. DhcpAssert( status == STATUS_SUCCESS );
  2526. return RtlNtStatusToDosError( status );
  2527. }
  2528. #endif _PNP_POWER_
  2529. #define IPSTRING(x) (inet_ntoa(*(struct in_addr*)&(x)))
  2530. DWORD // return interface index or -1
  2531. DhcpIpGetIfIndex( // get the IF index for this adapter
  2532. IN PDHCP_CONTEXT DhcpContext // context of adapter to get IfIndex for
  2533. ) {
  2534. return ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->IfIndex;
  2535. }
  2536. DWORD
  2537. QueryIfIndex(
  2538. IN ULONG IpInterfaceContext,
  2539. IN ULONG IpInterfaceInstance
  2540. )
  2541. {
  2542. DWORD Error;
  2543. DWORD Index;
  2544. DWORD Size;
  2545. DWORD NumReturned;
  2546. DWORD i;
  2547. BYTE Context[CONTEXT_SIZE];
  2548. HANDLE TcpHandle;
  2549. NTSTATUS Status;
  2550. TDIObjectID ID;
  2551. IFEntry IFE;
  2552. Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
  2553. if( ERROR_SUCCESS != Error ) {
  2554. DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:OpenDriver(DD_TCP):0x%lx\n", Error));
  2555. return (DWORD)-1;
  2556. }
  2557. ID.toi_entity.tei_entity = IF_ENTITY;
  2558. ID.toi_entity.tei_instance = IpInterfaceInstance;
  2559. ID.toi_class = INFO_CLASS_PROTOCOL;
  2560. ID.toi_type = INFO_TYPE_PROVIDER;
  2561. ID.toi_id = IF_MIB_STATS_ID;
  2562. Size = sizeof(IFE);
  2563. RtlZeroMemory(&IFE, sizeof(IFE));
  2564. RtlZeroMemory(Context, CONTEXT_SIZE);
  2565. Index = -1;
  2566. Status = TCPQueryInformationEx(
  2567. TcpHandle,
  2568. &ID,
  2569. &IFE,
  2570. &Size,
  2571. Context
  2572. );
  2573. if( TDI_SUCCESS != Status && TDI_BUFFER_OVERFLOW != Status ) {
  2574. goto Cleanup;
  2575. }
  2576. Index = IFE.if_index;
  2577. DhcpPrint((DEBUG_STACK, "IfIndex(0x%lx,0x%lx):0x%lx\n",
  2578. IpInterfaceContext, IpInterfaceInstance, Index
  2579. ));
  2580. Cleanup:
  2581. if( TcpHandle ) NtClose(TcpHandle);
  2582. if( TDI_SUCCESS != Status ) {
  2583. DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:TCPQueryInformationEx:%ld\n", Status));
  2584. }
  2585. DhcpPrint((DEBUG_TCP_INFO, "DhcpIpGetIfIndex:0x%lx\n", Index));
  2586. return Index;
  2587. }
  2588. DWORD // win32 status
  2589. DhcpSetRoute( // set a route with the stack
  2590. IN DWORD Dest, // network order destination
  2591. IN DWORD DestMask, // network order destination mask
  2592. IN DWORD IfIndex, // interface index to route
  2593. IN DWORD NextHop, // next hop n/w order address
  2594. IN DWORD Metric, // metric
  2595. IN BOOL IsLocal, // is this a local address? (IRE_DIRECT)
  2596. IN BOOL IsDelete // is this route being deleted?
  2597. )
  2598. {
  2599. DWORD Error;
  2600. NTSTATUS Status;
  2601. HANDLE TcpHandle;
  2602. IPRouteEntry RTE;
  2603. TDIObjectID ID;
  2604. if( 0xFFFFFFFF == IfIndex ) { // invalid If Index
  2605. return ERROR_INVALID_PARAMETER;
  2606. }
  2607. Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
  2608. if( ERROR_SUCCESS != Error ) { // should not really fail
  2609. DhcpPrint((DEBUG_ERRORS, "OpenDriver(TCP_DEVICE):%ld\n", Error));
  2610. return Error;
  2611. }
  2612. memset(&RTE, 0, sizeof(RTE));
  2613. memset(&ID, 0, sizeof(ID));
  2614. RTE.ire_dest = Dest;
  2615. RTE.ire_index = IfIndex;
  2616. RTE.ire_metric1 = Metric;
  2617. RTE.ire_metric2 = (DWORD)(-1);
  2618. RTE.ire_metric3 = (DWORD)(-1);
  2619. RTE.ire_metric4 = (DWORD)(-1);
  2620. RTE.ire_metric5 = (DWORD)(-1);
  2621. RTE.ire_nexthop = NextHop;
  2622. RTE.ire_type = (IsDelete?IRE_TYPE_INVALID:(IsLocal?IRE_TYPE_DIRECT:IRE_TYPE_INDIRECT));
  2623. RTE.ire_proto = IRE_PROTO_NETMGMT;
  2624. RTE.ire_age = 0;
  2625. RTE.ire_mask = DestMask;
  2626. RTE.ire_context = 0;
  2627. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  2628. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2629. ID.toi_entity.tei_instance = 0;
  2630. ID.toi_class = INFO_CLASS_PROTOCOL;
  2631. ID.toi_type = INFO_TYPE_PROVIDER;
  2632. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Dest: %s\n", IPSTRING(Dest)));
  2633. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w IfIndex:0x%lx\n", IfIndex));
  2634. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w NextHop:%s\n", IPSTRING(NextHop)));
  2635. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Type:0x%lx\n", RTE.ire_type));
  2636. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w DestMask:%s\n", IPSTRING(DestMask)));
  2637. Status = TCPSetInformationEx(
  2638. TcpHandle,
  2639. &ID,
  2640. &RTE,
  2641. sizeof(RTE)
  2642. );
  2643. if( TDI_BUFFER_OVERFLOW == Status ) Status = TDI_SUCCESS;
  2644. NtClose(TcpHandle);
  2645. if( TDI_SUCCESS != Status ) {
  2646. DhcpPrint((DEBUG_ERRORS, "DhcpSetRoute: 0x%lx\n", Status));
  2647. }
  2648. return RtlNtStatusToDosError(Status);
  2649. }
  2650. DWORD
  2651. GetAdapterFlag(
  2652. HANDLE TCPHandle,
  2653. DHCP_IP_ADDRESS ipaddr
  2654. )
  2655. {
  2656. BYTE Buffer[256];
  2657. DWORD AdapterFlag;
  2658. NTSTATUS Status;
  2659. DWORD Size;
  2660. TDIObjectID ID;
  2661. BYTE Context[CONTEXT_SIZE];
  2662. /*
  2663. * Read in adapter flag, which could be
  2664. * 1. Point to Point
  2665. * 2. Point to MultiPoint
  2666. * 3. Unidirectional
  2667. * 4. Non of the above
  2668. */
  2669. DhcpAssert(CONTEXT_SIZE >= sizeof(ipaddr));
  2670. RtlCopyMemory(Context, &ipaddr, CONTEXT_SIZE);
  2671. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2672. ID.toi_entity.tei_instance = 0;
  2673. ID.toi_class = INFO_CLASS_PROTOCOL;
  2674. ID.toi_type = INFO_TYPE_PROVIDER;
  2675. ID.toi_id = IP_INTFC_INFO_ID;
  2676. Size = sizeof(Buffer);
  2677. Status = TCPQueryInformationEx(TCPHandle, &ID, Buffer, &Size, Context);
  2678. if (Status != TDI_SUCCESS) {
  2679. AdapterFlag = 0;
  2680. DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s Status=%lx\n",
  2681. inet_ntoa(*(struct in_addr*)&ipaddr), Status));
  2682. } else {
  2683. AdapterFlag = ((IPInterfaceInfo*)Buffer)->iii_flags;
  2684. DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s AdapterFlag=%lx\n",
  2685. inet_ntoa(*(struct in_addr*)&ipaddr), AdapterFlag));
  2686. }
  2687. return AdapterFlag;
  2688. }
  2689. BOOL
  2690. IsUnidirectionalAdapter(
  2691. DWORD IpInterfaceContext
  2692. )
  2693. /*++
  2694. Routine Description:
  2695. This function queries and browses through the TDI list to find out
  2696. the specified IpTable entry and then determines if it is a unidirectional
  2697. adapter.
  2698. It almost identical to DhcpQueryHWInfo
  2699. Arguments:
  2700. IpInterfaceContext - Context value of the Ip Table Entry.
  2701. Return Value:
  2702. Windows Error Code.
  2703. --*/
  2704. {
  2705. DWORD Error;
  2706. NTSTATUS Status;
  2707. DWORD i, j;
  2708. BYTE Context[CONTEXT_SIZE];
  2709. TDIEntityID *EList = NULL;
  2710. TDIObjectID ID;
  2711. DWORD Size;
  2712. DWORD NumReturned;
  2713. BOOL fFound;
  2714. IPAddrEntry * pIAE = NULL;
  2715. IPAddrEntry *pIAEMatch = NULL;
  2716. HANDLE TCPHandle = NULL;
  2717. DWORD AdapterFlag = 0;
  2718. BYTE HardwareAddressType = 0;
  2719. LPBYTE HardwareAddress = NULL;
  2720. DWORD HardwareAddressLength = 0;
  2721. DWORD pIpInterfaceInstance = 0;
  2722. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  2723. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  2724. if (Error != ERROR_SUCCESS) {
  2725. return( Error );
  2726. }
  2727. //
  2728. // The first thing to do is get the list of available entities, and make
  2729. // sure that there are some interface entities present.
  2730. //
  2731. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  2732. ID.toi_entity.tei_instance = 0;
  2733. ID.toi_class = INFO_CLASS_GENERIC;
  2734. ID.toi_type = INFO_TYPE_PROVIDER;
  2735. ID.toi_id = ENTITY_LIST_ID;
  2736. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  2737. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  2738. if (EList == NULL) {
  2739. Status = STATUS_INSUFFICIENT_RESOURCES;
  2740. goto Cleanup;
  2741. }
  2742. RtlZeroMemory(EList, Size);
  2743. RtlZeroMemory(Context, CONTEXT_SIZE);
  2744. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  2745. if (Status != TDI_SUCCESS) {
  2746. goto Cleanup;
  2747. }
  2748. NumReturned = Size/sizeof(TDIEntityID);
  2749. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  2750. for (i = 0; i < NumReturned; i++) {
  2751. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  2752. i, EList[i].tei_entity, EList[i].tei_instance));
  2753. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  2754. IPSNMPInfo IPStats;
  2755. DWORD NLType;
  2756. //
  2757. // Does this entity support IP?
  2758. //
  2759. ID.toi_entity.tei_entity = EList[i].tei_entity;
  2760. ID.toi_entity.tei_instance = EList[i].tei_instance;
  2761. ID.toi_class = INFO_CLASS_GENERIC;
  2762. ID.toi_type = INFO_TYPE_PROVIDER;
  2763. ID.toi_id = ENTITY_TYPE_ID;
  2764. Size = sizeof( NLType );
  2765. NLType = 0;
  2766. RtlZeroMemory(Context, CONTEXT_SIZE);
  2767. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  2768. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  2769. if (Status != TDI_SUCCESS) {
  2770. goto Cleanup;
  2771. }
  2772. if ( NLType != CL_NL_IP ) {
  2773. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  2774. continue;
  2775. }
  2776. //
  2777. // We've got an IP driver so get it's address table
  2778. //
  2779. ID.toi_class = INFO_CLASS_PROTOCOL;
  2780. ID.toi_id = IP_MIB_STATS_ID;
  2781. Size = sizeof(IPStats);
  2782. RtlZeroMemory( &IPStats, Size);
  2783. RtlZeroMemory(Context, CONTEXT_SIZE);
  2784. Status = TCPQueryInformationEx(
  2785. TCPHandle,
  2786. &ID,
  2787. &IPStats,
  2788. &Size,
  2789. Context);
  2790. if (Status != TDI_SUCCESS) {
  2791. goto Cleanup;
  2792. }
  2793. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  2794. if ( IPStats.ipsi_numaddr == 0 ) {
  2795. continue;
  2796. }
  2797. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  2798. while (1) {
  2799. DWORD OldSize;
  2800. pIAE = DhcpAllocateMemory(Size);
  2801. if ( pIAE == NULL ) {
  2802. Status = STATUS_NO_MEMORY;
  2803. goto Cleanup;
  2804. }
  2805. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  2806. RtlZeroMemory(Context, CONTEXT_SIZE);
  2807. OldSize = Size;
  2808. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  2809. if (Status == TDI_BUFFER_OVERFLOW) {
  2810. Size = OldSize * 2;
  2811. DhcpFreeMemory(pIAE);
  2812. pIAE = NULL;
  2813. continue;
  2814. }
  2815. if (Status != TDI_SUCCESS) {
  2816. goto Cleanup;
  2817. }
  2818. if (Status == TDI_SUCCESS) {
  2819. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  2820. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  2821. break;
  2822. }
  2823. }
  2824. //
  2825. // We have the IP address table for this IP driver.
  2826. // Find the hardware address corresponds to the given
  2827. // IpInterfaceContext.
  2828. //
  2829. // Loop through the IP table entries and findout the
  2830. // matching entry.
  2831. //
  2832. pIAEMatch = NULL;
  2833. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  2834. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  2835. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  2836. if( pIAE[j].iae_context == IpInterfaceContext ) {
  2837. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  2838. &pIAE[j], IpInterfaceContext ));
  2839. pIAEMatch = &pIAE[j];
  2840. break;
  2841. }
  2842. }
  2843. if( pIAEMatch == NULL ) {
  2844. //
  2845. // freeup the loop memory.
  2846. //
  2847. DhcpFreeMemory( pIAE );
  2848. pIAE = NULL;
  2849. continue;
  2850. }
  2851. //
  2852. // NOTE : There may be more than one IpTable in the TDI
  2853. // list. We need additional information to select the
  2854. // IpTable we want. For now, we assume only one table
  2855. // is supported, so pick the first and only table from the
  2856. // list.
  2857. Status = FindHardwareAddr(
  2858. TCPHandle,
  2859. EList,
  2860. NumReturned,
  2861. pIAEMatch,
  2862. &HardwareAddressType,
  2863. &HardwareAddress,
  2864. &HardwareAddressLength,
  2865. &pIpInterfaceInstance,
  2866. &fFound );
  2867. if (Status != TDI_SUCCESS) {
  2868. goto Cleanup;
  2869. }
  2870. if ( fFound ) {
  2871. Status = TDI_SUCCESS;
  2872. AdapterFlag = GetAdapterFlag(TCPHandle, pIAEMatch->iae_addr);
  2873. goto Cleanup;
  2874. }
  2875. //
  2876. // freeup the loop memory.
  2877. //
  2878. DhcpFreeMemory( pIAE );
  2879. pIAE = NULL;
  2880. } // if IP
  2881. } // entity traversal
  2882. Status = STATUS_UNSUCCESSFUL;
  2883. Cleanup:
  2884. if( pIAE != NULL ) {
  2885. DhcpFreeMemory( pIAE );
  2886. }
  2887. if( TCPHandle != NULL ) {
  2888. NtClose( TCPHandle );
  2889. }
  2890. if (Status != TDI_SUCCESS) {
  2891. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  2892. }
  2893. if( HardwareAddress ) DhcpFreeMemory(HardwareAddress);
  2894. if (NULL != EList) {
  2895. DhcpFreeMemory(EList);
  2896. }
  2897. return (AdapterFlag & IP_INTFC_FLAG_UNIDIRECTIONAL);
  2898. }