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

3709 lines
108 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. //
  715. // Doing our own NdisHandlePnPRequest per Alid's suggestion
  716. //
  717. #include <ntddndis.h>
  718. #include <ndisprv.h>
  719. #define UNICODE_STRING_SIZE(x) \
  720. ((((x) == NULL) ? 0 : (x)->Length) + sizeof(WCHAR))
  721. VOID
  722. DhcpNdispUnicodeStringToVar(
  723. IN PVOID Base,
  724. IN PUNICODE_STRING String,
  725. IN OUT PNDIS_VAR_DATA_DESC NdisVar
  726. )
  727. /*++
  728. Routine Description:
  729. This function copies the contents of a UNICODE_STRING to an
  730. NDIS_VAR_DATA structure. NdisVar->Offset is treated as an input parameter
  731. and represents the offset into Base that the string characters should be
  732. copied to.
  733. Arguments:
  734. Base - Specifies the base address of the IOCTL buffer.
  735. String - Supplies a pointer to the UNICODE_STRING that should be copied.
  736. NdisVar - Supplies a pointer to the target NDIS_VAR_DATA_DESC. Its Offset
  737. field is taken as input, and its Length and MaximumLength fields
  738. are treated as output.
  739. Return Value:
  740. None.
  741. --*/
  742. {
  743. PWCHAR destination;
  744. //
  745. // NdisVar->Offset is assumed to be filled in and is treated
  746. // as an input parameter.
  747. //
  748. destination = (PWCHAR)(((PCHAR)Base) + NdisVar->Offset);
  749. //
  750. // Copy over the UNICODE_STRING, if any, and set NdisVar->Length
  751. //
  752. if ((String != NULL) && (String->Length > 0)) {
  753. NdisVar->Length = String->Length;
  754. memcpy(destination, String->Buffer, NdisVar->Length );
  755. } else {
  756. NdisVar->Length = 0;
  757. }
  758. //
  759. // Null-terminate, fill in MaxiumLength and we're done.
  760. //
  761. *(destination + NdisVar->Length / sizeof(WCHAR)) = L'\0';
  762. NdisVar->MaximumLength = NdisVar->Length + sizeof(WCHAR);
  763. }
  764. UINT
  765. DhcpNdisHandlePnPEvent(
  766. IN UINT Layer,
  767. IN UINT Operation,
  768. IN PUNICODE_STRING LowerComponent OPTIONAL,
  769. IN PUNICODE_STRING UpperComponent OPTIONAL,
  770. IN PUNICODE_STRING BindList OPTIONAL,
  771. IN PVOID ReConfigBuffer OPTIONAL,
  772. IN UINT ReConfigBufferSize OPTIONAL
  773. )
  774. {
  775. PNDIS_PNP_OPERATION Op;
  776. NDIS_PNP_OPERATION tempOp;
  777. HANDLE hDevice;
  778. BOOL fResult = FALSE;
  779. UINT cb, Size;
  780. DWORD Error;
  781. ULONG padding;
  782. do
  783. {
  784. //
  785. // Validate Layer & Operation
  786. //
  787. if (((Layer != NDIS) && (Layer != TDI)) ||
  788. ((Operation != BIND) && (Operation != UNBIND) && (Operation != RECONFIGURE) &&
  789. (Operation != UNLOAD) && (Operation != REMOVE_DEVICE) &&
  790. (Operation != ADD_IGNORE_BINDING) &&
  791. (Operation != DEL_IGNORE_BINDING) &&
  792. (Operation != BIND_LIST)))
  793. {
  794. Error = ERROR_INVALID_PARAMETER;
  795. break;
  796. }
  797. //
  798. // Allocate and initialize memory for the block to be passed down. The buffer
  799. // will look like this:
  800. //
  801. //
  802. // +=================================+
  803. // | NDIS_PNP_OPERATION |
  804. // | ReConfigBufferOff | ----+
  805. // +--- | LowerComponent.Offset | |
  806. // | | UpperComponent.Offset | --+ |
  807. // +-|--- | BindList.Offset | | |
  808. // | +--> +---------------------------------+ | |
  809. // | | LowerComponentStringBuffer | | |
  810. // | +---------------------------------+ <-+ |
  811. // | | UpperComponentStringBuffer | |
  812. // +----> +---------------------------------+ |
  813. // | BindListStringBuffer | |
  814. // +---------------------------------+ |
  815. // | Padding to ensure ULONG_PTR | |
  816. // | alignment of ReConfigBuffer | |
  817. // +---------------------------------+ <---+
  818. // | ReConfigBuffer |
  819. // +=================================+
  820. //
  821. // tempOp is a temporary structure into which we will store offsets as
  822. // they are calculated. This temporary structure will be moved to
  823. // the head of the real buffer once its size is known and it is
  824. // allocated.
  825. //
  826. Size = sizeof(NDIS_PNP_OPERATION);
  827. tempOp.LowerComponent.Offset = Size;
  828. Size += UNICODE_STRING_SIZE(LowerComponent);
  829. tempOp.UpperComponent.Offset = Size;
  830. Size += UNICODE_STRING_SIZE(UpperComponent);
  831. tempOp.BindList.Offset = Size;
  832. Size += UNICODE_STRING_SIZE(BindList);
  833. padding = (sizeof(ULONG_PTR) - (Size & (sizeof(ULONG_PTR) - 1))) &
  834. (sizeof(ULONG_PTR) - 1);
  835. Size += padding;
  836. tempOp.ReConfigBufferOff = Size;
  837. Size += ReConfigBufferSize + 1;
  838. Op = (PNDIS_PNP_OPERATION)LocalAlloc(LPTR, Size);
  839. if (Op == NULL)
  840. {
  841. Error = ERROR_NOT_ENOUGH_MEMORY;
  842. break;
  843. }
  844. //
  845. // We have a buffer of the necessary size. Copy in the partially-
  846. // filled in tempOp, then fill in the remaining fields and copy the
  847. // data into the buffer.
  848. //
  849. *Op = tempOp;
  850. Op->Layer = Layer;
  851. Op->Operation = Operation;
  852. //
  853. // Copy over the three unicode strings
  854. //
  855. DhcpNdispUnicodeStringToVar( Op, LowerComponent, &Op->LowerComponent );
  856. DhcpNdispUnicodeStringToVar( Op, UpperComponent, &Op->UpperComponent );
  857. DhcpNdispUnicodeStringToVar( Op, BindList, &Op->BindList );
  858. //
  859. // Finally, copy over the ReConfigBuffer
  860. //
  861. Op->ReConfigBufferSize = ReConfigBufferSize;
  862. if (ReConfigBufferSize > 0)
  863. {
  864. memcpy((PUCHAR)Op + Op->ReConfigBufferOff,
  865. ReConfigBuffer,
  866. ReConfigBufferSize);
  867. }
  868. *((PUCHAR)Op + Op->ReConfigBufferOff + ReConfigBufferSize) = 0;
  869. hDevice = CreateFile(L"\\\\.\\NDIS",
  870. 0,
  871. 0, // sharing mode - not significant
  872. NULL, // security attributes
  873. OPEN_EXISTING,
  874. 0, // file attributes and flags
  875. NULL); // handle to template file
  876. if (hDevice != INVALID_HANDLE_VALUE)
  877. {
  878. fResult = DeviceIoControl(hDevice,
  879. IOCTL_NDIS_DO_PNP_OPERATION,
  880. Op, // input buffer
  881. Size, // input buffer size
  882. NULL, // output buffer
  883. 0, // output buffer size
  884. &cb, // bytes returned
  885. NULL); // OVERLAPPED structure
  886. Error = GetLastError();
  887. CloseHandle(hDevice);
  888. }
  889. else
  890. {
  891. Error = GetLastError();
  892. }
  893. LocalFree(Op);
  894. } while (FALSE);
  895. SetLastError(Error);
  896. return(fResult);
  897. }
  898. ULONG
  899. TcpIpNotifyRouterDiscoveryOption(
  900. IN LPCWSTR AdapterName,
  901. IN BOOL fOptionPresent,
  902. IN DWORD OptionValue
  903. )
  904. {
  905. ULONG Error;
  906. ULONG RetVal;
  907. WCHAR TcpipAdapter[300+sizeof(DHCP_ADAPTERS_DEVICE_STRING)];
  908. UNICODE_STRING UpperLayer, LowerLayer, BindString;
  909. IP_PNP_RECONFIG_REQUEST Request;
  910. Error = NO_ERROR;
  911. if (wcslen(AdapterName) > 150) {
  912. ASSERT(0);
  913. Error = ERROR_INVALID_DATA;
  914. return Error;
  915. }
  916. RtlZeroMemory(&Request, sizeof(Request));
  917. Request.version = IP_PNP_RECONFIG_VERSION;
  918. Request.Flags |= IP_PNP_FLAG_DHCP_PERFORM_ROUTER_DISCOVERY;
  919. if( fOptionPresent ) {
  920. Request.DhcpPerformRouterDiscovery = (BOOLEAN)OptionValue;
  921. }
  922. wcscpy(TcpipAdapter, DHCP_ADAPTERS_DEVICE_STRING);
  923. wcscat(TcpipAdapter, AdapterName);
  924. RtlInitUnicodeString(&BindString, NULL); // no bind string
  925. RtlInitUnicodeString(&UpperLayer, TEXT("Tcpip"));
  926. RtlInitUnicodeString(&LowerLayer, TcpipAdapter);
  927. RetVal = DhcpNdisHandlePnPEvent(
  928. NDIS, // uiLayer
  929. RECONFIGURE, // Operation
  930. &LowerLayer,
  931. &UpperLayer,
  932. &BindString,
  933. &Request,
  934. sizeof(Request)
  935. );
  936. if( 0 == RetVal) Error = GetLastError();
  937. if( ERROR_SUCCESS != Error) {
  938. DhcpPrint((DEBUG_ERRORS, "TcpipNotifyRegChanges:0x%ld\n", Error));
  939. }
  940. return Error;
  941. }
  942. DWORD // win32 status
  943. NetBTNotifyRegChanges( // Notify NetBT of some parameter changes
  944. IN LPWSTR AdapterName // the adapter that needs this change notification
  945. )
  946. {
  947. DWORD Error;
  948. DWORD RetVal;
  949. WCHAR NetBTBindAdapter[300+sizeof( DHCP_TCPIP_DEVICE_STRING )];
  950. UNICODE_STRING UpperLayer;
  951. UNICODE_STRING LowerLayer;
  952. UNICODE_STRING BindString;
  953. if (wcslen(AdapterName) > 150) {
  954. return ERROR_INVALID_DATA;
  955. }
  956. Error = ERROR_SUCCESS;
  957. wcscpy(NetBTBindAdapter, DHCP_TCPIP_DEVICE_STRING);
  958. wcscat(NetBTBindAdapter, AdapterName); // \\Device\\Tcpip_{AdapterGuid} is what NetBT expects.
  959. RtlInitUnicodeString(&BindString, NULL); // no bind string
  960. RtlInitUnicodeString(&UpperLayer, TEXT("NetBT"));
  961. RtlInitUnicodeString(&LowerLayer, NetBTBindAdapter);
  962. RetVal = DhcpNdisHandlePnPEvent(
  963. TDI, // uiLayer
  964. RECONFIGURE, // Operation
  965. &LowerLayer,
  966. &UpperLayer,
  967. &BindString,
  968. NULL,
  969. 0
  970. );
  971. if( 0 != RetVal) Error = GetLastError();
  972. if( ERROR_SUCCESS != Error) {
  973. DhcpPrint((DEBUG_ERRORS, "NetBTNotifyRegChanges:0x%ld\n", Error));
  974. }
  975. return Error;
  976. }
  977. NTSTATUS
  978. FindHardwareAddr(
  979. HANDLE TCPHandle,
  980. TDIEntityID *EList,
  981. DWORD cEntities,
  982. IPAddrEntry *pIAE,
  983. LPBYTE HardwareAddressType,
  984. LPBYTE *HardwareAddress,
  985. LPDWORD HardwareAddressLength,
  986. DWORD *pIpInterfaceInstance,
  987. #ifdef BOOTPERF
  988. BOOL *pfInterfaceDown,
  989. #endif BOOTPERF
  990. BOOL *pfFound
  991. )
  992. /*++
  993. Routine Description:
  994. This function browses the TDI entries list and finds out the
  995. hardware address for the specified address entry.
  996. Arguments:
  997. TCPHandle - handle TCP driver.
  998. EList - list of TDI entries.
  999. cEntities - number of entries in the above list.
  1000. pIAE - IP entry for which we need HW address.
  1001. HardwareAddressType - hardware address type.
  1002. HardwareAddress - pointer to location where the HW address buffer
  1003. pointer is returned.
  1004. HardwareAddressLength - length of the HW address returned.
  1005. pIpInterfaceInstance - pointer to interface instance for the matching entry
  1006. pfFound - pointer to BOOL location which is set to TRUE if we found
  1007. the HW address otherwise set to FALSE.
  1008. Return Value:
  1009. Windows Error Code.
  1010. --*/
  1011. {
  1012. DWORD i;
  1013. BYTE Context[CONTEXT_SIZE];
  1014. TDIObjectID ID;
  1015. NTSTATUS Status;
  1016. DWORD Size;
  1017. *pfFound = FALSE;
  1018. ID.toi_entity.tei_entity = IF_MIB;
  1019. ID.toi_type = INFO_TYPE_PROVIDER;
  1020. for ( i = 0; i < cEntities; i++ ) {
  1021. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx, type %lx, instance %lx\n",
  1022. i, EList[i].tei_entity, EList[i].tei_instance));
  1023. if (EList[i].tei_entity == IF_ENTITY) {
  1024. IFEntry IFE;
  1025. DWORD IFType;
  1026. //
  1027. // Check and make sure the interface supports MIB-2
  1028. //
  1029. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1030. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1031. ID.toi_class = INFO_CLASS_GENERIC;
  1032. ID.toi_id = ENTITY_TYPE_ID;
  1033. Size = sizeof( IFType );
  1034. IFType = 0;
  1035. RtlZeroMemory(Context, CONTEXT_SIZE);
  1036. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: querying IF_ENTITY %lx\n",i));
  1037. Status = TCPQueryInformationEx(
  1038. TCPHandle,
  1039. &ID,
  1040. &IFType,
  1041. &Size,
  1042. Context);
  1043. if (Status != TDI_SUCCESS) {
  1044. continue;
  1045. }
  1046. if ( IFType != IF_MIB ) {
  1047. DhcpPrint((DEBUG_TCP_INFO, "FindHardwareAddress: entity %lx does not support MIB\n",i));
  1048. continue;
  1049. }
  1050. //
  1051. // We've found an interface, get its index and see if it
  1052. // matches the IP Address entry
  1053. //
  1054. ID.toi_class = INFO_CLASS_PROTOCOL;
  1055. ID.toi_id = IF_MIB_STATS_ID;
  1056. Size = sizeof(IFEntry);
  1057. RtlZeroMemory(Context, CONTEXT_SIZE);
  1058. RtlZeroMemory(&IFE, Size);
  1059. Status = TCPQueryInformationEx(
  1060. TCPHandle,
  1061. &ID,
  1062. &IFE,
  1063. &Size,
  1064. Context);
  1065. if ( Status != TDI_SUCCESS &&
  1066. Status != TDI_BUFFER_OVERFLOW ) {
  1067. goto Cleanup;
  1068. }
  1069. DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has if_index %lx.\n", &IFE, IFE.if_index ));
  1070. if ( IFE.if_index == pIAE->iae_index ) {
  1071. LPBYTE Address;
  1072. DhcpPrint(( DEBUG_TCP_INFO, "FindHardwareAddress: IFEntry %lx has our if_index %lx\n",
  1073. &IFE, pIAE->iae_index ));
  1074. //
  1075. // Allocate Memory.
  1076. //
  1077. Address = DhcpAllocateMemory( IFE.if_physaddrlen );
  1078. if( Address == NULL ) {
  1079. Status = STATUS_NO_MEMORY;
  1080. goto Cleanup;
  1081. }
  1082. RtlCopyMemory(
  1083. Address,
  1084. IFE.if_physaddr,
  1085. IFE.if_physaddrlen );
  1086. switch( IFE.if_type ) {
  1087. case IF_TYPE_ETHERNET_CSMACD:
  1088. *HardwareAddressType = HARDWARE_TYPE_10MB_EITHERNET;
  1089. break;
  1090. case IF_TYPE_ISO88025_TOKENRING:
  1091. case IF_TYPE_FDDI:
  1092. *HardwareAddressType = HARDWARE_TYPE_IEEE_802;
  1093. break;
  1094. case IF_TYPE_OTHER:
  1095. *HardwareAddressType = HARDWARE_ARCNET;
  1096. break;
  1097. case IF_TYPE_PPP:
  1098. *HardwareAddressType = HARDWARE_PPP;
  1099. break;
  1100. case IF_TYPE_IEEE1394:
  1101. *HardwareAddressType = HARDWARE_1394;
  1102. break;
  1103. default:
  1104. DhcpPrint(( DEBUG_ERRORS, "Invalid HW Type, %ld.\n", IFE.if_type ));
  1105. *HardwareAddressType = HARDWARE_ARCNET;
  1106. break;
  1107. }
  1108. *HardwareAddress = Address;
  1109. *HardwareAddressLength = IFE.if_physaddrlen;
  1110. *pIpInterfaceInstance = ID.toi_entity.tei_instance;
  1111. DhcpPrint( (DEBUG_MISC,
  1112. "tei_instance = %d\n", *pIpInterfaceInstance ));
  1113. *pfFound = TRUE;
  1114. #ifdef BOOTPERF
  1115. if( pfInterfaceDown ) {
  1116. *pfInterfaceDown = (IFE.if_adminstatus != IF_STATUS_UP);
  1117. }
  1118. #endif BOOTPERF
  1119. Status = TDI_SUCCESS;
  1120. goto Cleanup;
  1121. }
  1122. }
  1123. }
  1124. //
  1125. // we couldn't find a corresponding entry. But it may be available
  1126. // in another tanel.
  1127. //
  1128. Status = STATUS_SUCCESS;
  1129. Cleanup:
  1130. if (Status != TDI_SUCCESS) {
  1131. DhcpPrint(( DEBUG_ERRORS, "FindHardwareAddr failed, %lx.\n", Status ));
  1132. }
  1133. return TDI_SUCCESS;
  1134. }
  1135. #ifdef BOOTPERF
  1136. DWORD
  1137. DhcpQueryHWInfoEx(
  1138. DWORD IpInterfaceContext,
  1139. DWORD *pIpInterfaceInstance,
  1140. DWORD *pOldIpAddress OPTIONAL,
  1141. DWORD *pOldMask OPTIONAL,
  1142. BOOL *pfInterfaceDown OPTIONAL,
  1143. LPBYTE HardwareAddressType,
  1144. LPBYTE *HardwareAddress,
  1145. LPDWORD HardwareAddressLength
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. This function queries and browses through the TDI list to find out
  1150. the specified IpTable entry and then determines the HW address that
  1151. corresponds to this entry.
  1152. Arguments:
  1153. IpInterfaceContext - Context value of the Ip Table Entry.
  1154. pIpInterfaceInstance - pointer to the interface instance ID that corresponds
  1155. to matching IpTable entry
  1156. pOldIpAddress - the old IP address that used to exist.
  1157. pOldMask - the old IP mask for this entry.
  1158. pfInterfaceDown -- location of BOOL that tells if the interface is DOWN or UP
  1159. HardwareAddressType - hardware address type.
  1160. HardwareAddress - pointer to location where the HW address buffer
  1161. pointer is returned.
  1162. HardwareAddressLength - length of the HW address returned.
  1163. Return Value:
  1164. Windows Error Code.
  1165. --*/
  1166. {
  1167. DWORD Error;
  1168. NTSTATUS Status;
  1169. DWORD i, j;
  1170. BYTE Context[CONTEXT_SIZE];
  1171. TDIEntityID *EList = NULL;
  1172. TDIObjectID ID;
  1173. DWORD Size;
  1174. DWORD NumReturned;
  1175. BOOL fFound;
  1176. IPAddrEntry * pIAE = NULL;
  1177. IPAddrEntry *pIAEMatch = NULL;
  1178. HANDLE TCPHandle = NULL;
  1179. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  1180. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1181. if (Error != ERROR_SUCCESS) {
  1182. return( Error );
  1183. }
  1184. //
  1185. // The first thing to do is get the list of available entities, and make
  1186. // sure that there are some interface entities present.
  1187. //
  1188. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  1189. ID.toi_entity.tei_instance = 0;
  1190. ID.toi_class = INFO_CLASS_GENERIC;
  1191. ID.toi_type = INFO_TYPE_PROVIDER;
  1192. ID.toi_id = ENTITY_LIST_ID;
  1193. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  1194. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  1195. if (EList == NULL) {
  1196. Status = STATUS_INSUFFICIENT_RESOURCES;
  1197. goto Cleanup;
  1198. }
  1199. RtlZeroMemory(EList, Size);
  1200. RtlZeroMemory(Context, CONTEXT_SIZE);
  1201. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  1202. if (Status != TDI_SUCCESS) {
  1203. goto Cleanup;
  1204. }
  1205. NumReturned = Size/sizeof(TDIEntityID);
  1206. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  1207. for (i = 0; i < NumReturned; i++) {
  1208. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  1209. i, EList[i].tei_entity, EList[i].tei_instance));
  1210. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  1211. IPSNMPInfo IPStats;
  1212. DWORD NLType;
  1213. //
  1214. // Does this entity support IP?
  1215. //
  1216. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1217. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1218. ID.toi_class = INFO_CLASS_GENERIC;
  1219. ID.toi_type = INFO_TYPE_PROVIDER;
  1220. ID.toi_id = ENTITY_TYPE_ID;
  1221. Size = sizeof( NLType );
  1222. NLType = 0;
  1223. RtlZeroMemory(Context, CONTEXT_SIZE);
  1224. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  1225. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  1226. if (Status != TDI_SUCCESS) {
  1227. goto Cleanup;
  1228. }
  1229. if ( NLType != CL_NL_IP ) {
  1230. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  1231. continue;
  1232. }
  1233. //
  1234. // We've got an IP driver so get it's address table
  1235. //
  1236. ID.toi_class = INFO_CLASS_PROTOCOL;
  1237. ID.toi_id = IP_MIB_STATS_ID;
  1238. Size = sizeof(IPStats);
  1239. RtlZeroMemory( &IPStats, Size);
  1240. RtlZeroMemory(Context, CONTEXT_SIZE);
  1241. Status = TCPQueryInformationEx(
  1242. TCPHandle,
  1243. &ID,
  1244. &IPStats,
  1245. &Size,
  1246. Context);
  1247. if (Status != TDI_SUCCESS) {
  1248. goto Cleanup;
  1249. }
  1250. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  1251. if ( IPStats.ipsi_numaddr == 0 ) {
  1252. continue;
  1253. }
  1254. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  1255. while (1) {
  1256. DWORD OldSize;
  1257. pIAE = DhcpAllocateMemory(Size);
  1258. if ( pIAE == NULL ) {
  1259. Status = STATUS_NO_MEMORY;
  1260. goto Cleanup;
  1261. }
  1262. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1263. RtlZeroMemory(Context, CONTEXT_SIZE);
  1264. OldSize = Size;
  1265. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  1266. if (Status == TDI_BUFFER_OVERFLOW) {
  1267. Size = OldSize * 2;
  1268. DhcpFreeMemory(pIAE);
  1269. pIAE = NULL;
  1270. continue;
  1271. }
  1272. if (Status != TDI_SUCCESS) {
  1273. goto Cleanup;
  1274. }
  1275. if (Status == TDI_SUCCESS) {
  1276. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  1277. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  1278. break;
  1279. }
  1280. }
  1281. //
  1282. // We have the IP address table for this IP driver.
  1283. // Find the hardware address corresponds to the given
  1284. // IpInterfaceContext.
  1285. //
  1286. // Loop through the IP table entries and findout the
  1287. // matching entry.
  1288. //
  1289. pIAEMatch = NULL;
  1290. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  1291. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  1292. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  1293. if( pIAE[j].iae_context == IpInterfaceContext ) {
  1294. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  1295. &pIAE[j], IpInterfaceContext ));
  1296. pIAEMatch = &pIAE[j];
  1297. break;
  1298. }
  1299. }
  1300. if( pIAEMatch == NULL ) {
  1301. //
  1302. // freeup the loop memory.
  1303. //
  1304. DhcpFreeMemory( pIAE );
  1305. pIAE = NULL;
  1306. continue;
  1307. }
  1308. //
  1309. // NOTE : There may be more than one IpTable in the TDI
  1310. // list. We need additional information to select the
  1311. // IpTable we want. For now, we assume only one table
  1312. // is supported, so pick the first and only table from the
  1313. // list.
  1314. //
  1315. // If the old ip address is requested, return it.
  1316. //
  1317. if( pOldIpAddress ) *pOldIpAddress = pIAE->iae_addr;
  1318. if( pOldMask ) *pOldMask = pIAE->iae_mask;
  1319. Status = FindHardwareAddr(
  1320. TCPHandle,
  1321. EList,
  1322. NumReturned,
  1323. pIAEMatch,
  1324. HardwareAddressType,
  1325. HardwareAddress,
  1326. HardwareAddressLength,
  1327. pIpInterfaceInstance,
  1328. pfInterfaceDown,
  1329. &fFound
  1330. );
  1331. if (Status != TDI_SUCCESS) {
  1332. goto Cleanup;
  1333. }
  1334. if ( fFound ) {
  1335. Status = TDI_SUCCESS;
  1336. goto Cleanup;
  1337. }
  1338. //
  1339. // freeup the loop memory.
  1340. //
  1341. DhcpFreeMemory( pIAE );
  1342. pIAE = NULL;
  1343. } // if IP
  1344. } // entity traversal
  1345. Status = STATUS_UNSUCCESSFUL;
  1346. Cleanup:
  1347. if( pIAE != NULL ) {
  1348. DhcpFreeMemory( pIAE );
  1349. }
  1350. if( TCPHandle != NULL ) {
  1351. NtClose( TCPHandle );
  1352. }
  1353. if (Status != TDI_SUCCESS) {
  1354. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  1355. }
  1356. if (NULL != EList) {
  1357. DhcpFreeMemory(EList);
  1358. }
  1359. return( RtlNtStatusToDosError( Status ) );
  1360. }
  1361. DWORD
  1362. DhcpQueryHWInfo(
  1363. DWORD IpInterfaceContext,
  1364. DWORD *pIpInterfaceInstance,
  1365. LPBYTE HardwareAddressType,
  1366. LPBYTE *HardwareAddress,
  1367. LPDWORD HardwareAddressLength
  1368. )
  1369. /*++
  1370. Routine Description:
  1371. See DhcpQueryHWInfo
  1372. --*/
  1373. {
  1374. return DhcpQueryHWInfoEx(
  1375. IpInterfaceContext,
  1376. pIpInterfaceInstance,
  1377. NULL, NULL, NULL,
  1378. HardwareAddressType,
  1379. HardwareAddress,
  1380. HardwareAddressLength
  1381. );
  1382. }
  1383. #else BOOTPERF
  1384. DWORD
  1385. DhcpQueryHWInfo(
  1386. DWORD IpInterfaceContext,
  1387. DWORD *pIpInterfaceInstance,
  1388. LPBYTE HardwareAddressType,
  1389. LPBYTE *HardwareAddress,
  1390. LPDWORD HardwareAddressLength
  1391. )
  1392. /*++
  1393. Routine Description:
  1394. This function queries and browses through the TDI list to find out
  1395. the specified IpTable entry and then determines the HW address that
  1396. corresponds to this entry.
  1397. Arguments:
  1398. IpInterfaceContext - Context value of the Ip Table Entry.
  1399. pIpInterfaceInstance - pointer to the interface instance ID that corresponds
  1400. to matching IpTable entry
  1401. HardwareAddressType - hardware address type.
  1402. HardwareAddress - pointer to location where the HW address buffer
  1403. pointer is returned.
  1404. HardwareAddressLength - length of the HW address returned.
  1405. Return Value:
  1406. Windows Error Code.
  1407. --*/
  1408. {
  1409. DWORD Error;
  1410. NTSTATUS Status;
  1411. DWORD i, j;
  1412. BYTE Context[CONTEXT_SIZE];
  1413. TDIEntityID *EList = NULL;
  1414. TDIObjectID ID;
  1415. DWORD Size;
  1416. DWORD NumReturned;
  1417. BOOL fFound;
  1418. IPAddrEntry * pIAE = NULL;
  1419. IPAddrEntry *pIAEMatch = NULL;
  1420. HANDLE TCPHandle = NULL;
  1421. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  1422. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1423. if (Error != ERROR_SUCCESS) {
  1424. return( Error );
  1425. }
  1426. //
  1427. // The first thing to do is get the list of available entities, and make
  1428. // sure that there are some interface entities present.
  1429. //
  1430. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  1431. ID.toi_entity.tei_instance = 0;
  1432. ID.toi_class = INFO_CLASS_GENERIC;
  1433. ID.toi_type = INFO_TYPE_PROVIDER;
  1434. ID.toi_id = ENTITY_LIST_ID;
  1435. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  1436. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  1437. if (EList == NULL) {
  1438. Status = STATUS_INSUFFICIENT_RESOURCES;
  1439. goto Cleanup;
  1440. }
  1441. RtlZeroMemory(EList, Size);
  1442. RtlZeroMemory(Context, CONTEXT_SIZE);
  1443. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  1444. if (Status != TDI_SUCCESS) {
  1445. goto Cleanup;
  1446. }
  1447. NumReturned = Size/sizeof(TDIEntityID);
  1448. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  1449. for (i = 0; i < NumReturned; i++) {
  1450. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  1451. i, EList[i].tei_entity, EList[i].tei_instance));
  1452. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  1453. IPSNMPInfo IPStats;
  1454. DWORD NLType;
  1455. //
  1456. // Does this entity support IP?
  1457. //
  1458. ID.toi_entity.tei_entity = EList[i].tei_entity;
  1459. ID.toi_entity.tei_instance = EList[i].tei_instance;
  1460. ID.toi_class = INFO_CLASS_GENERIC;
  1461. ID.toi_type = INFO_TYPE_PROVIDER;
  1462. ID.toi_id = ENTITY_TYPE_ID;
  1463. Size = sizeof( NLType );
  1464. NLType = 0;
  1465. RtlZeroMemory(Context, CONTEXT_SIZE);
  1466. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  1467. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  1468. if (Status != TDI_SUCCESS) {
  1469. goto Cleanup;
  1470. }
  1471. if ( NLType != CL_NL_IP ) {
  1472. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  1473. continue;
  1474. }
  1475. //
  1476. // We've got an IP driver so get it's address table
  1477. //
  1478. ID.toi_class = INFO_CLASS_PROTOCOL;
  1479. ID.toi_id = IP_MIB_STATS_ID;
  1480. Size = sizeof(IPStats);
  1481. RtlZeroMemory( &IPStats, Size);
  1482. RtlZeroMemory(Context, CONTEXT_SIZE);
  1483. Status = TCPQueryInformationEx(
  1484. TCPHandle,
  1485. &ID,
  1486. &IPStats,
  1487. &Size,
  1488. Context);
  1489. if (Status != TDI_SUCCESS) {
  1490. goto Cleanup;
  1491. }
  1492. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  1493. if ( IPStats.ipsi_numaddr == 0 ) {
  1494. continue;
  1495. }
  1496. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  1497. while (1) {
  1498. DWORD OldSize;
  1499. pIAE = DhcpAllocateMemory(Size);
  1500. if ( pIAE == NULL ) {
  1501. Status = STATUS_NO_MEMORY;
  1502. goto Cleanup;
  1503. }
  1504. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1505. RtlZeroMemory(Context, CONTEXT_SIZE);
  1506. OldSize = Size;
  1507. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  1508. if (Status == TDI_BUFFER_OVERFLOW) {
  1509. Size = OldSize * 2;
  1510. DhcpFreeMemory(pIAE);
  1511. pIAE = NULL;
  1512. continue;
  1513. }
  1514. if (Status != TDI_SUCCESS) {
  1515. goto Cleanup;
  1516. }
  1517. if (Status == TDI_SUCCESS) {
  1518. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  1519. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  1520. break;
  1521. }
  1522. }
  1523. //
  1524. // We have the IP address table for this IP driver.
  1525. // Find the hardware address corresponds to the given
  1526. // IpInterfaceContext.
  1527. //
  1528. // Loop through the IP table entries and findout the
  1529. // matching entry.
  1530. //
  1531. pIAEMatch = NULL;
  1532. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  1533. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  1534. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  1535. if( pIAE[j].iae_context == IpInterfaceContext ) {
  1536. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  1537. &pIAE[j], IpInterfaceContext ));
  1538. pIAEMatch = &pIAE[j];
  1539. break;
  1540. }
  1541. }
  1542. if( pIAEMatch == NULL ) {
  1543. //
  1544. // freeup the loop memory.
  1545. //
  1546. DhcpFreeMemory( pIAE );
  1547. pIAE = NULL;
  1548. continue;
  1549. }
  1550. //
  1551. // NOTE : There may be more than one IpTable in the TDI
  1552. // list. We need additional information to select the
  1553. // IpTable we want. For now, we assume only one table
  1554. // is supported, so pick the first and only table from the
  1555. // list.
  1556. Status = FindHardwareAddr(
  1557. TCPHandle,
  1558. EList,
  1559. NumReturned,
  1560. pIAEMatch,
  1561. HardwareAddressType,
  1562. HardwareAddress,
  1563. HardwareAddressLength,
  1564. pIpInterfaceInstance,
  1565. &fFound );
  1566. if (Status != TDI_SUCCESS) {
  1567. goto Cleanup;
  1568. }
  1569. if ( fFound ) {
  1570. Status = TDI_SUCCESS;
  1571. goto Cleanup;
  1572. }
  1573. //
  1574. // freeup the loop memory.
  1575. //
  1576. DhcpFreeMemory( pIAE );
  1577. pIAE = NULL;
  1578. } // if IP
  1579. } // entity traversal
  1580. Status = STATUS_UNSUCCESSFUL;
  1581. Cleanup:
  1582. if( pIAE != NULL ) {
  1583. DhcpFreeMemory( pIAE );
  1584. }
  1585. if( TCPHandle != NULL ) {
  1586. NtClose( TCPHandle );
  1587. }
  1588. if (Status != TDI_SUCCESS) {
  1589. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  1590. }
  1591. if (NULL != EList) {
  1592. DhcpFreeMemory(EList);
  1593. }
  1594. return( RtlNtStatusToDosError( Status ) );
  1595. }
  1596. #endif BOOTPERF
  1597. #if DBG
  1598. #define print(X) DhcpPrint((DEBUG_TRACE, "%20s\t", inet_ntoa(*(struct in_addr *)&X)))
  1599. #define printx(X) DhcpPrint((DEBUG_TRACE, "%05x\t", X))
  1600. DWORD
  1601. PrintDefaultGateways( VOID ) {
  1602. DWORD Error;
  1603. NTSTATUS Status;
  1604. HANDLE TCPHandle = NULL;
  1605. BYTE Context[CONTEXT_SIZE];
  1606. TDIObjectID ID;
  1607. DWORD Size;
  1608. IPSNMPInfo IPStats;
  1609. IPAddrEntry *AddrTable = NULL;
  1610. DWORD NumReturned;
  1611. DWORD Type;
  1612. DWORD i;
  1613. DWORD MatchIndex;
  1614. IPRouteEntry RouteEntry;
  1615. IPRouteEntry *RtTable;
  1616. DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
  1617. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1618. if (Error != ERROR_SUCCESS) {
  1619. return( Error );
  1620. }
  1621. //
  1622. // Get the NetAddr info, to find an interface index for the gateway.
  1623. //
  1624. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1625. ID.toi_entity.tei_instance = 0;
  1626. ID.toi_class = INFO_CLASS_PROTOCOL;
  1627. ID.toi_type = INFO_TYPE_PROVIDER;
  1628. ID.toi_id = IP_MIB_STATS_ID;
  1629. Size = sizeof(IPStats);
  1630. RtlZeroMemory(&IPStats, Size);
  1631. RtlZeroMemory(Context, CONTEXT_SIZE);
  1632. Status = TCPQueryInformationEx(
  1633. TCPHandle,
  1634. &ID,
  1635. &IPStats,
  1636. &Size,
  1637. Context);
  1638. if (Status != TDI_SUCCESS) {
  1639. goto Cleanup;
  1640. }
  1641. // hack: RouteTable in IP is about 32 in size... and IP seems tob
  1642. // be writing the whole bunch always!
  1643. if(IPStats.ipsi_numroutes <= 32)
  1644. IPStats.ipsi_numroutes = 32;
  1645. Size = IPStats.ipsi_numroutes * sizeof(IPRouteEntry);
  1646. RtTable = DhcpAllocateMemory(Size);
  1647. if (RtTable == NULL) {
  1648. Status = STATUS_NO_MEMORY;
  1649. goto Cleanup;
  1650. }
  1651. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1652. RtlZeroMemory(Context, CONTEXT_SIZE);
  1653. Status = TCPQueryInformationEx(
  1654. TCPHandle,
  1655. &ID,
  1656. RtTable,
  1657. &Size,
  1658. Context);
  1659. if (Status != TDI_SUCCESS) {
  1660. goto Cleanup;
  1661. }
  1662. NumReturned = Size/sizeof(IPAddrEntry);
  1663. DhcpPrint((DEBUG_TRACE, "IP returned %ld routes\n", NumReturned));
  1664. // The following is almost always true... IP returns the whole array.. valid or not!
  1665. // DhcpAssert( NumReturned == IPStats.ipsi_numroutes );
  1666. if( NumReturned > IPStats.ipsi_numroutes)
  1667. NumReturned = IPStats.ipsi_numroutes;
  1668. //
  1669. // We've got the address table. Loop through it. If we find an exact
  1670. // match for the gateway, then we're adding or deleting a direct route
  1671. // and we're done. Otherwise try to find a match on the subnet mask,
  1672. // and remember the first one we find.
  1673. //
  1674. DhcpPrint((DEBUG_TRACE,"Dest mask nexthop index metric1 type proto\n"));
  1675. for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
  1676. print(RtTable[i].ire_dest);
  1677. print(RtTable[i].ire_mask);
  1678. print(RtTable[i].ire_nexthop);
  1679. printx(RtTable[i].ire_index);
  1680. printx(RtTable[i].ire_metric1);
  1681. printx(RtTable[i].ire_type);
  1682. printx(RtTable[i].ire_proto);
  1683. DhcpPrint((DEBUG_TRACE, "\n"));
  1684. }
  1685. DhcpPrint((DEBUG_TRACE, "--------------------------------------------------------\n"));
  1686. Status = TDI_SUCCESS;
  1687. Cleanup:
  1688. if( AddrTable != NULL ) {
  1689. DhcpFreeMemory( AddrTable );
  1690. }
  1691. if( TCPHandle != NULL ) {
  1692. NtClose( TCPHandle );
  1693. }
  1694. if( (Status != TDI_SUCCESS) &&
  1695. (Status != STATUS_UNSUCCESSFUL) ) { // HACK.
  1696. DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
  1697. }
  1698. return( RtlNtStatusToDosError( Status ) );
  1699. }
  1700. #endif
  1701. DWORD
  1702. SetDefaultGateway(
  1703. DWORD Command,
  1704. DHCP_IP_ADDRESS GatewayAddress,
  1705. DWORD Metric
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. This function adds/deletes a default gateway entry from the router table.
  1710. Arguments:
  1711. Command : Either DEFAULT_GATEWAY_ADD/DEFAULT_GATEWAY_DELETE.
  1712. GatewayAddress : Address of the default gateway.
  1713. Return Value:
  1714. Windows Error Code.
  1715. --*/
  1716. {
  1717. DWORD Error;
  1718. NTSTATUS Status;
  1719. HANDLE TCPHandle = NULL;
  1720. BYTE Context[CONTEXT_SIZE];
  1721. TDIObjectID ID;
  1722. DWORD Size;
  1723. IPSNMPInfo IPStats;
  1724. IPAddrEntry *AddrTable = NULL;
  1725. DWORD NumReturned;
  1726. DWORD Type;
  1727. DWORD i;
  1728. DWORD MatchIndex;
  1729. IPRouteEntry RouteEntry;
  1730. DHCP_IP_ADDRESS NetworkOrderGatewayAddress;
  1731. NetworkOrderGatewayAddress = htonl( GatewayAddress );
  1732. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  1733. if (Error != ERROR_SUCCESS) {
  1734. return( Error );
  1735. }
  1736. //
  1737. // Get the NetAddr info, to find an interface index for the gateway.
  1738. //
  1739. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1740. ID.toi_entity.tei_instance = 0;
  1741. ID.toi_class = INFO_CLASS_PROTOCOL;
  1742. ID.toi_type = INFO_TYPE_PROVIDER;
  1743. ID.toi_id = IP_MIB_STATS_ID;
  1744. Size = sizeof(IPStats);
  1745. RtlZeroMemory(&IPStats, Size);
  1746. RtlZeroMemory(Context, CONTEXT_SIZE);
  1747. Status = TCPQueryInformationEx(
  1748. TCPHandle,
  1749. &ID,
  1750. &IPStats,
  1751. &Size,
  1752. Context
  1753. );
  1754. if (Status != TDI_SUCCESS) {
  1755. goto Cleanup;
  1756. }
  1757. Size = IPStats.ipsi_numaddr * sizeof(IPAddrEntry);
  1758. AddrTable = DhcpAllocateMemory(Size);
  1759. if (AddrTable == NULL) {
  1760. Status = STATUS_NO_MEMORY;
  1761. goto Cleanup;
  1762. }
  1763. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1764. RtlZeroMemory(Context, CONTEXT_SIZE);
  1765. Status = TCPQueryInformationEx(
  1766. TCPHandle,
  1767. &ID,
  1768. AddrTable,
  1769. &Size,
  1770. Context
  1771. );
  1772. if (Status != TDI_SUCCESS) {
  1773. goto Cleanup;
  1774. }
  1775. NumReturned = Size/sizeof(IPAddrEntry);
  1776. DhcpAssert( NumReturned == IPStats.ipsi_numaddr );
  1777. //
  1778. // We've got the address table. Loop through it. If we find an exact
  1779. // match for the gateway, then we're adding or deleting a direct route
  1780. // and we're done. Otherwise try to find a match on the subnet mask,
  1781. // and remember the first one we find.
  1782. //
  1783. Type = IRE_TYPE_INDIRECT;
  1784. for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
  1785. if( AddrTable[i].iae_addr == NetworkOrderGatewayAddress ) {
  1786. //
  1787. // Found an exact match.
  1788. //
  1789. MatchIndex = i;
  1790. Type = IRE_TYPE_DIRECT;
  1791. break;
  1792. }
  1793. //
  1794. // The next hop is on the same subnet as this address. If
  1795. // we haven't already found a match, remember this one.
  1796. //
  1797. if ( (MatchIndex == 0xffff) &&
  1798. (AddrTable[i].iae_addr != 0) &&
  1799. (AddrTable[i].iae_mask != 0) &&
  1800. ((AddrTable[i].iae_addr & AddrTable[i].iae_mask) ==
  1801. (NetworkOrderGatewayAddress & AddrTable[i].iae_mask)) ) {
  1802. MatchIndex = i;
  1803. }
  1804. }
  1805. //
  1806. // We've looked at all of the entries. See if we found a match.
  1807. //
  1808. if (MatchIndex == 0xffff) {
  1809. //
  1810. // Didn't find a match.
  1811. //
  1812. Status = STATUS_UNSUCCESSFUL;
  1813. goto Cleanup;
  1814. }
  1815. //
  1816. // We've found a match. Fill in the route entry, and call the
  1817. // Set API.
  1818. //
  1819. RouteEntry.ire_dest = DEFAULT_DEST;
  1820. RouteEntry.ire_index = AddrTable[MatchIndex].iae_index;
  1821. RouteEntry.ire_metric1 = Metric;
  1822. RouteEntry.ire_metric2 = (DWORD)(-1);
  1823. RouteEntry.ire_metric3 = (DWORD)(-1);
  1824. RouteEntry.ire_metric4 = (DWORD)(-1);
  1825. RouteEntry.ire_nexthop = NetworkOrderGatewayAddress;
  1826. RouteEntry.ire_type =
  1827. (Command == DEFAULT_GATEWAY_DELETE ? IRE_TYPE_INVALID : Type);
  1828. RouteEntry.ire_proto = IRE_PROTO_NETMGMT;
  1829. RouteEntry.ire_age = 0;
  1830. RouteEntry.ire_mask = DEFAULT_DEST_MASK;
  1831. RouteEntry.ire_metric5 = (DWORD)(-1);
  1832. RouteEntry.ire_context = 0;
  1833. Size = sizeof(RouteEntry);
  1834. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1835. Status = TCPSetInformationEx(
  1836. TCPHandle,
  1837. &ID,
  1838. &RouteEntry,
  1839. Size );
  1840. if ( Status != TDI_SUCCESS &&
  1841. Status != TDI_BUFFER_OVERFLOW ) {
  1842. goto Cleanup;
  1843. }
  1844. Status = TDI_SUCCESS;
  1845. Cleanup:
  1846. if( AddrTable != NULL ) {
  1847. DhcpFreeMemory( AddrTable );
  1848. }
  1849. if( TCPHandle != NULL ) {
  1850. NtClose( TCPHandle );
  1851. }
  1852. if( (Status != TDI_SUCCESS) &&
  1853. (Status != STATUS_UNSUCCESSFUL) ) { // HACK.
  1854. DhcpPrint(( DEBUG_ERRORS, "SetDefaultGateway failed, %lx.\n", Status ));
  1855. }
  1856. return( RtlNtStatusToDosError( Status ) );
  1857. }
  1858. DWORD
  1859. GetIpInterfaceContext(
  1860. LPWSTR AdapterName,
  1861. DWORD IpIndex,
  1862. LPDWORD IpInterfaceContext
  1863. )
  1864. /*++
  1865. Routine Description:
  1866. This function returns the IpInterfaceContext for the specified
  1867. IpAddress and devicename.
  1868. Arguments:
  1869. AdapterName - name of the device.
  1870. IpIndex - index of the IpAddress for this device.
  1871. IpInterfaceContext - pointer to a location where the
  1872. interface context is returned.
  1873. Return Value:
  1874. Windows Error Code.
  1875. --*/
  1876. {
  1877. DWORD Error;
  1878. LPWSTR RegKey = NULL;
  1879. HKEY KeyHandle = NULL;
  1880. LPWSTR nteContextList = NULL;
  1881. PCHAR oemNextContext = NULL;
  1882. LPWSTR nextContext;
  1883. DWORD i;
  1884. *IpInterfaceContext = INVALID_INTERFACE_CONTEXT;
  1885. //
  1886. // Open device parameter.
  1887. //
  1888. RegKey = DhcpAllocateMemory(
  1889. (wcslen(DHCP_SERVICES_KEY) +
  1890. wcslen(REGISTRY_CONNECT_STRING) +
  1891. wcslen(AdapterName) +
  1892. wcslen(DHCP_ADAPTER_PARAMETERS_KEY) + 1) *
  1893. sizeof(WCHAR) ); // termination char.
  1894. if( RegKey == NULL ) {
  1895. Error = ERROR_NOT_ENOUGH_MEMORY;
  1896. goto Cleanup;
  1897. }
  1898. wcscpy( RegKey, DHCP_SERVICES_KEY );
  1899. wcscat( RegKey, DHCP_ADAPTER_PARAMETERS_KEY );
  1900. wcscat( RegKey, REGISTRY_CONNECT_STRING );
  1901. wcscat( RegKey, AdapterName );
  1902. //
  1903. // open this key.
  1904. //
  1905. Error = RegOpenKeyEx(
  1906. HKEY_LOCAL_MACHINE,
  1907. RegKey,
  1908. 0, // Reserved field
  1909. DHCP_CLIENT_KEY_ACCESS,
  1910. &KeyHandle
  1911. );
  1912. if( Error != ERROR_SUCCESS ) {
  1913. goto Cleanup;
  1914. }
  1915. Error = GetRegistryString(
  1916. KeyHandle,
  1917. DHCP_NTE_CONTEXT_LIST,
  1918. &nteContextList,
  1919. NULL
  1920. );
  1921. if( nteContextList == NULL ) {
  1922. Error = ERROR_BAD_FORMAT;
  1923. DhcpPrint((DEBUG_ERRORS, "NteContextList empty\n"));
  1924. goto Cleanup;
  1925. }
  1926. if ( ERROR_SUCCESS != Error )
  1927. {
  1928. DhcpPrint( (DEBUG_ERRORS,
  1929. "GetIpInterfaceContext: Could not read nteContextList %lx\n",
  1930. Error));
  1931. goto Cleanup;
  1932. }
  1933. for( nextContext = nteContextList, i = 0;
  1934. *nextContext != L'\0' && i < IpIndex;
  1935. i++, nextContext += (wcslen(nextContext) + 1) );
  1936. if ( *nextContext != L'\0' && i == IpIndex ) {
  1937. ULONG ival;
  1938. oemNextContext = DhcpUnicodeToOem(nextContext, NULL);
  1939. if ( NULL == oemNextContext ) {
  1940. Error = ERROR_BAD_FORMAT;
  1941. } else {
  1942. ival = strtoul(oemNextContext, NULL, 0);
  1943. if ( ival == ULONG_MAX || ival == 0) {
  1944. Error = ERROR_BAD_FORMAT;
  1945. } else {
  1946. *IpInterfaceContext = ival;
  1947. }
  1948. }
  1949. }
  1950. Cleanup:
  1951. if( RegKey != NULL ) {
  1952. DhcpFreeMemory( RegKey );
  1953. }
  1954. if( KeyHandle != NULL ) {
  1955. RegCloseKey( KeyHandle );
  1956. }
  1957. if ( nteContextList != NULL ) {
  1958. DhcpFreeMemory( nteContextList );
  1959. }
  1960. if ( oemNextContext != NULL ) {
  1961. DhcpFreeMemory( oemNextContext );
  1962. }
  1963. return( Error );
  1964. }
  1965. HANDLE
  1966. APIENTRY
  1967. DhcpOpenGlobalEvent(
  1968. void
  1969. )
  1970. /*++
  1971. Routine Description:
  1972. This functions creates global event that signals the the ipaddress
  1973. changes to other waiting processes. The security dacl is set to NULL
  1974. that makes anyone to open and read/set this event.
  1975. Arguments:
  1976. None.
  1977. Return Value:
  1978. Handle value of the global event. If the handle is NULL,
  1979. GetLastError() function will return Windows error code.
  1980. --*/
  1981. {
  1982. DWORD Error = NO_ERROR, Status, Length;
  1983. BOOL BoolError;
  1984. HANDLE EventHandle = NULL;
  1985. SECURITY_ATTRIBUTES SecurityAttributes;
  1986. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_WORLD_SID_AUTHORITY;
  1987. PACL Acl = NULL;
  1988. PSID WorldSID = NULL;
  1989. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  1990. //
  1991. // If event can be opened, chose that, don't attempt create
  1992. //
  1993. EventHandle = OpenEvent(
  1994. EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE,
  1995. DHCP_NEW_IPADDRESS_EVENT_NAME
  1996. );
  1997. if( NULL != EventHandle ) return EventHandle;
  1998. //
  1999. // Set DACL also.. first create basic SIDs
  2000. //
  2001. BoolError = AllocateAndInitializeSid(
  2002. &Authority, 1, SECURITY_WORLD_RID,
  2003. 0, 0, 0, 0, 0, 0, 0,
  2004. &WorldSID
  2005. );
  2006. if( BoolError == FALSE ) {
  2007. return NULL;
  2008. }
  2009. Length = ( (ULONG)sizeof(ACL) + (ULONG)sizeof(ACCESS_ALLOWED_ACE)
  2010. + GetLengthSid( WorldSID ) + 16 );
  2011. Acl = DhcpAllocateMemory( Length );
  2012. if( NULL == Acl ) {
  2013. Error = ERROR_NOT_ENOUGH_MEMORY;
  2014. goto Cleanup;
  2015. }
  2016. BoolError = InitializeAcl( Acl, Length, ACL_REVISION2 );
  2017. if( FALSE == BoolError ) {
  2018. Error = GetLastError();
  2019. goto Cleanup;
  2020. }
  2021. BoolError = AddAccessAllowedAce(
  2022. Acl, ACL_REVISION2,
  2023. EVENT_MODIFY_STATE | SYNCHRONIZE,
  2024. WorldSID
  2025. );
  2026. if( FALSE == BoolError ) {
  2027. Error = GetLastError();
  2028. goto Cleanup;
  2029. }
  2030. SecurityDescriptor = DhcpAllocateMemory(
  2031. SECURITY_DESCRIPTOR_MIN_LENGTH
  2032. );
  2033. if( NULL == SecurityDescriptor ) {
  2034. Error = ERROR_NOT_ENOUGH_MEMORY;
  2035. goto Cleanup;
  2036. }
  2037. BoolError = InitializeSecurityDescriptor(
  2038. SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION
  2039. );
  2040. if( BoolError == FALSE ) {
  2041. Error = GetLastError();
  2042. goto Cleanup;
  2043. }
  2044. BoolError = SetSecurityDescriptorDacl(
  2045. SecurityDescriptor, TRUE, Acl, FALSE
  2046. );
  2047. if( BoolError == FALSE ) {
  2048. Error = GetLastError();
  2049. goto Cleanup;
  2050. }
  2051. SecurityAttributes.nLength = sizeof( SecurityAttributes );
  2052. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  2053. SecurityAttributes.bInheritHandle = FALSE;
  2054. EventHandle = CreateEvent(
  2055. &SecurityAttributes,
  2056. // everyone all access security.
  2057. TRUE, // MANUAL reset.
  2058. FALSE, // initial state is signaled.
  2059. DHCP_NEW_IPADDRESS_EVENT_NAME
  2060. );
  2061. if( NULL == EventHandle ) {
  2062. Error = GetLastError();
  2063. } else {
  2064. Error = NO_ERROR;
  2065. }
  2066. Cleanup:
  2067. if( SecurityDescriptor ) {
  2068. DhcpFreeMemory( SecurityDescriptor );
  2069. }
  2070. if( Acl ) {
  2071. DhcpFreeMemory( Acl );
  2072. }
  2073. if( WorldSID ) {
  2074. FreeSid( WorldSID );
  2075. }
  2076. if( NO_ERROR != Error ) {
  2077. SetLastError( Error );
  2078. }
  2079. return( EventHandle );
  2080. }
  2081. BOOL
  2082. NdisWanAdapter( // Is this an NdisWan adapter?
  2083. IN PDHCP_CONTEXT DhcpContext
  2084. )
  2085. {
  2086. return DhcpContext->HardwareAddressType == HARDWARE_PPP;
  2087. }
  2088. DWORD INLINE // win32 status
  2089. DhcpEnableDynamicConfigEx( // convert from static to dhcp and start DHCP client if reqd
  2090. IN LPWSTR AdapterName
  2091. )
  2092. {
  2093. DWORD Error;
  2094. // ask the dhcp client to takeup this adapter also
  2095. Error = DhcpEnableDynamicConfig(AdapterName);
  2096. // now there are a couple possibilities:
  2097. // - the above call succeeded
  2098. // - DHCP service is not started or just got terminated
  2099. // - DHCP service failed to process the request with some error
  2100. // in the first case just go on straight to exit and return success
  2101. // in the second case we attempt to start the DHCP service if it is not already started
  2102. // in the last case we just bail out with the specific error
  2103. if( Error == ERROR_FILE_NOT_FOUND || Error == ERROR_BROKEN_PIPE )
  2104. {
  2105. SC_HANDLE SCHandle;
  2106. SC_HANDLE ServiceHandle;
  2107. SERVICE_STATUS svcStatus;
  2108. // attempt now to start the DHCP service.
  2109. // first thing to do is to open SCM
  2110. SCHandle = OpenSCManager(
  2111. NULL,
  2112. NULL,
  2113. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS
  2114. );
  2115. if( SCHandle == NULL )
  2116. return GetLastError(); // shouldn't happen normally
  2117. // attempt to open the DHCP service
  2118. ServiceHandle = OpenService(
  2119. SCHandle,
  2120. SERVICE_DHCP,
  2121. SERVICE_QUERY_STATUS | SERVICE_START
  2122. );
  2123. if (ServiceHandle != NULL)
  2124. {
  2125. // check the status of the service
  2126. if (!QueryServiceStatus(ServiceHandle, &svcStatus) ||
  2127. svcStatus.dwCurrentState != SERVICE_RUNNING)
  2128. {
  2129. // is it worthy to attempt to start the service if QueryServiceStatus failed?
  2130. Error = StartService(ServiceHandle, 0, NULL) ? ERROR_SUCCESS : GetLastError();
  2131. }
  2132. CloseServiceHandle(ServiceHandle);
  2133. }
  2134. else
  2135. Error = GetLastError();
  2136. CloseServiceHandle(SCHandle);
  2137. }
  2138. return Error;
  2139. }
  2140. DWORD // win32 status
  2141. DhcpNotifyConfigChangeNotifications( // notify whoever needed of param changes
  2142. VOID
  2143. )
  2144. {
  2145. HANDLE NotifyEvent;
  2146. DWORD Error;
  2147. BOOL BoolError;
  2148. NotifyEvent = DhcpOpenGlobalEvent();
  2149. if( NULL == NotifyEvent ) {
  2150. Error = GetLastError();
  2151. DhcpPrint((DEBUG_ERRORS, "DhcpOpenGlobalEvent:0x%lx\n", Error));
  2152. return Error;
  2153. }
  2154. BoolError = PulseEvent(NotifyEvent);
  2155. if( BoolError ) Error = ERROR_SUCCESS;
  2156. else Error = GetLastError();
  2157. CloseHandle(NotifyEvent);
  2158. if( ERROR_SUCCESS != Error ) {
  2159. DhcpPrint((DEBUG_ERRORS, "PulseEvent(NotifyEvent): 0x%lx\n", Error));
  2160. }
  2161. return Error;
  2162. }
  2163. DWORD // win32 status
  2164. APIENTRY
  2165. DhcpNotifyConfigChangeEx( // handle address changes, param changes etc.
  2166. IN LPWSTR ServerName, // name of server where this will be executed
  2167. IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
  2168. IN BOOL IsNewIpAddress,// is address new/ or address is same?
  2169. IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
  2170. IN DWORD IpAddress, // the ip address that is being set
  2171. IN DWORD SubnetMask, // corresponding subnet mask
  2172. IN SERVICE_ENABLE DhcpServiceEnabled,
  2173. IN ULONG Flags
  2174. )
  2175. {
  2176. DWORD Error;
  2177. DWORD IpInterfaceContext;
  2178. DWORD DefaultSubnetMask;
  2179. DhcpPrint(( DEBUG_MISC, "DhcpNotifyConfigChange: Adapter %ws, IsNewIp %s, IpAddr %lx, IpIndex %x, ServiceFlag %d\n",
  2180. AdapterName, IsNewIpAddress ? "TRUE" : "FALSE", IpAddress, IpIndex, DhcpServiceEnabled ));
  2181. // param checks
  2182. if( NULL == AdapterName ) return ERROR_INVALID_PARAMETER;
  2183. if( DhcpEnable == DhcpServiceEnabled ) { // converting from static to dhcp enabled address
  2184. if( FALSE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2185. if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
  2186. if( IpAddress || SubnetMask ) return ERROR_INVALID_PARAMETER;
  2187. } else if( DhcpDisable == DhcpServiceEnabled){// converting from dhcp to static address
  2188. if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2189. if( 0 != IpIndex ) return ERROR_INVALID_PARAMETER;
  2190. if( 0 == IpAddress || 0 == SubnetMask ) return ERROR_INVALID_PARAMETER;
  2191. } else {
  2192. if( IgnoreFlag != DhcpServiceEnabled ) return ERROR_INVALID_PARAMETER;
  2193. // if( TRUE != IsNewIpAddress ) return ERROR_INVALID_PARAMETER;
  2194. if( 0xFFFF == IpIndex ) {
  2195. if( 0 == SubnetMask || 0 == IpAddress ) return ERROR_INVALID_PARAMETER;
  2196. }
  2197. }
  2198. if( IgnoreFlag == DhcpServiceEnabled && FALSE == IsNewIpAddress ) {
  2199. ULONG LocalError;
  2200. // just some parameters changed -- currently, this could only be DNS domain name or server list change
  2201. // or may be static gateway list change or static route change
  2202. Error = DhcpStaticRefreshParams(AdapterName);
  2203. if( ERROR_SUCCESS != Error ) {
  2204. DhcpPrint((DEBUG_ERRORS, "DhcpNotifyConfigChange:DhcpStaticRefreshParams:0x%lx\n", Error));
  2205. }
  2206. LocalError = NetBTNotifyRegChanges(AdapterName);
  2207. if( ERROR_SUCCESS != LocalError ) {
  2208. DhcpPrint((
  2209. DEBUG_ERRORS, "NetbtNotify(%ws): 0x%lx\n",
  2210. AdapterName, LocalError
  2211. ));
  2212. }
  2213. return Error;
  2214. }
  2215. if( DhcpEnable == DhcpServiceEnabled ) { // convert from static to dhcp
  2216. Error = IPDelNonPrimaryAddresses( // remove all but the first static address
  2217. AdapterName
  2218. );
  2219. if( ERROR_SUCCESS != Error ) return Error;
  2220. Error = DhcpEnableDynamicConfigEx( // convert this to dhcp, maybe starting dhcp in the process
  2221. AdapterName
  2222. );
  2223. return Error; // notifications already done by service when we dhcp enable it..
  2224. } else if( DhcpDisable == DhcpServiceEnabled ) {
  2225. Error = DhcpDisableDynamicConfig( AdapterName );
  2226. if( Error != ERROR_SUCCESS ) return Error;
  2227. }
  2228. // NetBt device name stuff removed, see any version pre- Oct 10, 1997
  2229. DhcpAssert(TRUE == IsNewIpAddress); // ip address changed in some way
  2230. DhcpAssert(DhcpEnable != DhcpServiceEnabled); // static->dhcp already handled before
  2231. DefaultSubnetMask = DhcpDefaultSubnetMask(0);
  2232. if( INVALID_INTERFACE_CONTEXT == IpIndex ) { // adding a new ip address
  2233. DhcpAssert( IpAddress && SubnetMask); // cannot be zero, these
  2234. Error = IPAddIPAddress( // add the reqd ip address
  2235. AdapterName,
  2236. IpAddress,
  2237. SubnetMask
  2238. );
  2239. if( ERROR_SUCCESS != Error ) return Error;
  2240. } else { // either delete or modify -- first find ipinterfacecontext
  2241. Error = GetIpInterfaceContext( // get the interface context value for this
  2242. AdapterName,
  2243. IpIndex,
  2244. &IpInterfaceContext
  2245. );
  2246. if( ERROR_SUCCESS != Error ) {
  2247. DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: 0x%lx\n", Error));
  2248. return Error;
  2249. }
  2250. if( IpInterfaceContext == INVALID_INTERFACE_CONTEXT) {
  2251. DhcpPrint((DEBUG_ERRORS, "GetIpInterfaceContext: returned ifctxt=INVALID_INTERFACE_CONTEXT\n"));
  2252. return ERROR_INVALID_DRIVE;
  2253. }
  2254. if ( IpAddress != 0 ) { // if address is non-zero, we are changing address
  2255. if (Flags & NOTIFY_FLG_RESET_IPADDR)
  2256. {
  2257. Error = IPResetIPAddress( // first reset the interface to zero address
  2258. IpInterfaceContext,
  2259. DefaultSubnetMask
  2260. );
  2261. if( ERROR_SUCCESS != Error ) return Error;
  2262. }
  2263. Error = IPSetIPAddress( // then set the required address
  2264. IpInterfaceContext,
  2265. IpAddress,
  2266. SubnetMask
  2267. );
  2268. if( ERROR_SUCCESS != Error ) return Error;
  2269. Error = SetOverRideDefaultGateway( AdapterName );
  2270. } else { // we are deleting addresses
  2271. // we need to treat the 0th index separately from others.
  2272. // IPDelIPAddress actually destroys the NTE from IP. But
  2273. // we never blow away 0th index NTE. Just reset the ipaddr on it.
  2274. if ( IpIndex == 0 ) {
  2275. Error = IPResetIPAddress( // just set this address to zero, dont blow interface away
  2276. IpInterfaceContext,DefaultSubnetMask
  2277. );
  2278. } else { // in this case, blow this interface altogether
  2279. Error = IPDelIPAddress( IpInterfaceContext );
  2280. }
  2281. if( ERROR_SUCCESS != Error ) return Error;
  2282. }
  2283. }
  2284. Error = DhcpNotifyConfigChangeNotifications();// notify clients, pulse the global event
  2285. if( ERROR_SUCCESS != Error ) return Error;
  2286. // refresh the parameters for static addresses
  2287. Error = DhcpStaticRefreshParamsInternal(
  2288. AdapterName, (Flags & NOTIFY_FLG_DO_DNS) ? TRUE : FALSE
  2289. );
  2290. if( ERROR_SUCCESS != Error ) { // ignore this error anyways
  2291. DhcpPrint((DEBUG_ERRORS, "DhcpStaticRefreshParams(%ws):0x%lx\n", AdapterName,Error));
  2292. }
  2293. return ERROR_SUCCESS;
  2294. }
  2295. //================================================================================
  2296. // This function (API) notifies the TCP/IP configuration changes to
  2297. // appropriate services. These changes will be in effect as soon as
  2298. // possible.
  2299. //
  2300. // If the IP Address is modified, the services are reset to ZERO IP
  2301. // address (to cleanup the current IP address) and then set to new
  2302. // address.
  2303. //
  2304. // IpIndex - if the specified device is configured with multiple IP
  2305. // addresses, specify index of address that is modified (0 - first
  2306. // IpAddress, 1 - second IpAddres, so on) Pass 0xFFFF if adding an
  2307. // additional address. The order of IP address is determined by the
  2308. // order in the registry MULTI_SZ value "IPAddress" for the static
  2309. // addresses. For dhcp enabled ip address, only ipindex 0 is valid.
  2310. //
  2311. // Everytime when an address is added, removed or modified, the
  2312. // order in the registry may change. It is caller's responsibility
  2313. // to check the current order, and hence the index, before calling
  2314. // this api.
  2315. //
  2316. // DhcpServiceEnabled -
  2317. // IgnoreFlag - indicates Ignore this flag. IgnoreFlag
  2318. // DhcpEnable - indicates DHCP is enabled for this adapter.
  2319. // DhcpDisable - indicates DHCP is diabled for this adapter.
  2320. //
  2321. //Invarient:
  2322. //
  2323. // (1) DHCP enabled IPAddr and Static addr can exists only mutually exclusively.
  2324. // (2) An interface cannot have more than 1 dhcp enabled ip address. However it
  2325. // can have many static addresses.
  2326. //
  2327. //Usage:
  2328. //
  2329. // Case 1: Changing from dhcp enabled ipaddress to static address(es)
  2330. // - Firstly, change the first dhcp enabled ipaddress to static address.
  2331. // arguments {SN, AN, TRUE, 0, I1, S1, DhcpDisable}
  2332. // - Seconfly, add the remaining static address(es)
  2333. // arguments (SN, AN, TRUE, 0xFFFF, I2, S2, DhcpIgnore)
  2334. // arguments (SN, AN, TRUE, 0xFFFF, I3, S3, IgnoreFlag) and so on.
  2335. //
  2336. // Case 2: Changing from static address(es) to dhcp enabled ipaddress
  2337. // - Change the first static address to dhcp enabled. The api will delete
  2338. // the remaining static address(es).
  2339. // arguments (SN, AN, FALSE, 0, 0, 0, DhcpEnable)
  2340. //
  2341. // Case 3: Adding, removing or changing static addresses.
  2342. // - Adding:
  2343. // arguments (SN, AN, TRUE, 0xFFFF, I, S, DhcpIgnore)
  2344. // - Removing, say address # 2 i.e ipindex = 1
  2345. // arguments (SN, AN, TRUE, 1, 0, 0, DhcpIgnore)
  2346. // - Changing, say address # 2 i.e ipindex = 1
  2347. // arguments (SN, AN, TRUE, 1, I, S, DhcpIgnore)
  2348. //
  2349. //================================================================================
  2350. DWORD // win32 status
  2351. APIENTRY
  2352. DhcpNotifyConfigChange( // handle address changes, param changes etc.
  2353. IN LPWSTR ServerName, // name of server where this will be executed
  2354. IN LPWSTR AdapterName, // which adapter is going to be reconfigured?
  2355. IN BOOL IsNewIpAddress,// is address new/ or address is same?
  2356. IN DWORD IpIndex, // index of addr for this adapter -- 0 ==> first interface...
  2357. IN DWORD IpAddress, // the ip address that is being set
  2358. IN DWORD SubnetMask, // corresponding subnet mask
  2359. IN SERVICE_ENABLE DhcpServiceEnabled
  2360. )
  2361. {
  2362. return DhcpNotifyConfigChangeEx(
  2363. ServerName, AdapterName, IsNewIpAddress,
  2364. IpIndex, IpAddress, SubnetMask, DhcpServiceEnabled,
  2365. NOTIFY_FLG_DO_DNS | NOTIFY_FLG_RESET_IPADDR
  2366. );
  2367. }
  2368. DWORD BringUpInterface( PVOID pvLocalInformation )
  2369. {
  2370. LOCAL_CONTEXT_INFO *pContext;
  2371. TCP_REQUEST_SET_INFORMATION_EX *pTcpRequest;
  2372. TDIObjectID *pObjectID;
  2373. IFEntry *pIFEntry;
  2374. int cbTcpRequest;
  2375. HANDLE hDriver = NULL;
  2376. DWORD dwResult;
  2377. NTSTATUS NtStatus;
  2378. IO_STATUS_BLOCK IoStatusBlock;
  2379. DhcpPrint( ( DEBUG_MISC, "Entering BringUpInterface\n" ));
  2380. dwResult = OpenDriver( &hDriver, DD_TCP_DEVICE_NAME );
  2381. if ( ERROR_SUCCESS != dwResult )
  2382. {
  2383. DhcpPrint( ( DEBUG_ERRORS,
  2384. "BringUpInterface: Unable to open TCP driver.\n" ) );
  2385. return dwResult;
  2386. }
  2387. pContext = (LOCAL_CONTEXT_INFO *) pvLocalInformation;
  2388. //
  2389. // compute the input buffer size and allocate
  2390. //
  2391. cbTcpRequest = sizeof( TCP_REQUEST_SET_INFORMATION_EX )
  2392. + sizeof( IFEntry ) -1;
  2393. //
  2394. // initialize the request
  2395. //
  2396. pTcpRequest = DhcpAllocateMemory( cbTcpRequest );
  2397. if ( !pTcpRequest )
  2398. {
  2399. NtClose( hDriver );
  2400. DhcpPrint( ( DEBUG_ERRORS,
  2401. "BringUpInterface: Insufficient memory\n" ));
  2402. return ERROR_NOT_ENOUGH_MEMORY;
  2403. }
  2404. pTcpRequest->BufferSize = cbTcpRequest - sizeof(TCP_REQUEST_SET_INFORMATION_EX);
  2405. pObjectID = &pTcpRequest->ID;
  2406. pIFEntry = (IFEntry *) &pTcpRequest->Buffer[0];
  2407. pObjectID->toi_entity.tei_entity = IF_ENTITY;
  2408. pObjectID->toi_entity.tei_instance = pContext->IpInterfaceInstance;
  2409. pObjectID->toi_class = INFO_CLASS_PROTOCOL;
  2410. pObjectID->toi_type = INFO_TYPE_PROVIDER;
  2411. pObjectID->toi_id = IF_MIB_STATS_ID;
  2412. pIFEntry->if_adminstatus = IF_STATUS_UP;
  2413. NtStatus = NtDeviceIoControlFile(
  2414. hDriver, NULL, NULL, NULL, &IoStatusBlock,
  2415. IOCTL_TCP_SET_INFORMATION_EX,
  2416. pTcpRequest, cbTcpRequest,
  2417. NULL, 0
  2418. );
  2419. if ( STATUS_PENDING == NtStatus )
  2420. {
  2421. if ( STATUS_SUCCESS == NtWaitForSingleObject( hDriver, TRUE, NULL ) )
  2422. NtStatus = IoStatusBlock.Status;
  2423. #ifdef DBG
  2424. if ( STATUS_SUCCESS != NtStatus )
  2425. DhcpPrint( ( DEBUG_ERRORS,
  2426. "BringUpInterface: failed to bring up adapter\n" ));
  2427. #endif
  2428. } else if ( STATUS_SUCCESS == NtStatus ) {
  2429. NtStatus = IoStatusBlock.Status;
  2430. }
  2431. //
  2432. // Clean up
  2433. //
  2434. if ( hDriver )
  2435. NtClose( hDriver );
  2436. if ( pTcpRequest )
  2437. DhcpFreeMemory( pTcpRequest );
  2438. DhcpPrint( ( DEBUG_MISC,
  2439. "Leaving BringUpInterface\n" ) );
  2440. return RtlNtStatusToDosError( NtStatus );
  2441. }
  2442. #if defined(_PNP_POWER_)
  2443. DWORD
  2444. IPGetIPEventRequest(
  2445. HANDLE handle,
  2446. HANDLE event,
  2447. UINT seqNo,
  2448. PIP_GET_IP_EVENT_RESPONSE responseBuffer,
  2449. DWORD responseBufferSize,
  2450. PIO_STATUS_BLOCK ioStatusBlock
  2451. )
  2452. /*++
  2453. Routine Description:
  2454. This rountine sends the ioctl to get media sense notification from
  2455. IP.
  2456. Arguments:
  2457. handle - handle to tcpip driver.
  2458. event - the event we need to do wait on.
  2459. seqNo - seqNo of the last event received.
  2460. responseBuffer - pointer to the buffer where event info will be stored.
  2461. ioStatusBlock - status of the operation, if not pending.
  2462. Return Value:
  2463. NT Error Code.
  2464. --*/
  2465. {
  2466. NTSTATUS status;
  2467. DWORD Error;
  2468. IP_GET_IP_EVENT_REQUEST requestBuffer;
  2469. requestBuffer.SequenceNo = seqNo;
  2470. RtlZeroMemory( responseBuffer, sizeof(IP_GET_IP_EVENT_RESPONSE));
  2471. responseBuffer->ContextStart = 0xFFFF;
  2472. status = NtDeviceIoControlFile(
  2473. handle, // Driver handle
  2474. event, // Event
  2475. NULL, // APC Routine
  2476. NULL, // APC context
  2477. ioStatusBlock, // Status block
  2478. IOCTL_IP_GET_IP_EVENT, // Control code
  2479. &requestBuffer, // Input buffer
  2480. sizeof(IP_GET_IP_EVENT_REQUEST), // Input buffer size
  2481. responseBuffer, // Output buffer
  2482. responseBufferSize // Output buffer size
  2483. );
  2484. if ( status == STATUS_SUCCESS ) {
  2485. status = ioStatusBlock->Status;
  2486. }
  2487. return status;
  2488. }
  2489. DWORD
  2490. IPCancelIPEventRequest(
  2491. HANDLE handle,
  2492. PIO_STATUS_BLOCK ioStatusBlock
  2493. )
  2494. /*++
  2495. Routine Description:
  2496. This rountine cancels the ioctl that was sent to get media sense
  2497. notification from IP.
  2498. Arguments:
  2499. handle - handle to the ip driver.
  2500. Return Value:
  2501. NT Error Code.
  2502. --*/
  2503. {
  2504. NTSTATUS status;
  2505. DWORD Error;
  2506. status = NtCancelIoFile(
  2507. handle, // Driver handle
  2508. ioStatusBlock); // Status block
  2509. DhcpPrint( (DEBUG_TRACE,"IPCancelIPEventRequest: status %lx\n",status));
  2510. DhcpAssert( status == STATUS_SUCCESS );
  2511. return RtlNtStatusToDosError( status );
  2512. }
  2513. #endif _PNP_POWER_
  2514. #define IPSTRING(x) (inet_ntoa(*(struct in_addr*)&(x)))
  2515. DWORD // return interface index or -1
  2516. DhcpIpGetIfIndex( // get the IF index for this adapter
  2517. IN PDHCP_CONTEXT DhcpContext // context of adapter to get IfIndex for
  2518. ) {
  2519. return ((PLOCAL_CONTEXT_INFO)DhcpContext->LocalInformation)->IfIndex;
  2520. }
  2521. DWORD
  2522. QueryIfIndex(
  2523. IN ULONG IpInterfaceContext,
  2524. IN ULONG IpInterfaceInstance
  2525. )
  2526. {
  2527. DWORD Error;
  2528. DWORD Index;
  2529. DWORD Size;
  2530. DWORD NumReturned;
  2531. DWORD i;
  2532. BYTE Context[CONTEXT_SIZE];
  2533. HANDLE TcpHandle;
  2534. NTSTATUS Status;
  2535. TDIObjectID ID;
  2536. IFEntry IFE;
  2537. Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
  2538. if( ERROR_SUCCESS != Error ) {
  2539. DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:OpenDriver(DD_TCP):0x%lx\n", Error));
  2540. return (DWORD)-1;
  2541. }
  2542. ID.toi_entity.tei_entity = IF_ENTITY;
  2543. ID.toi_entity.tei_instance = IpInterfaceInstance;
  2544. ID.toi_class = INFO_CLASS_PROTOCOL;
  2545. ID.toi_type = INFO_TYPE_PROVIDER;
  2546. ID.toi_id = IF_MIB_STATS_ID;
  2547. Size = sizeof(IFE);
  2548. RtlZeroMemory(&IFE, sizeof(IFE));
  2549. RtlZeroMemory(Context, CONTEXT_SIZE);
  2550. Index = -1;
  2551. Status = TCPQueryInformationEx(
  2552. TcpHandle,
  2553. &ID,
  2554. &IFE,
  2555. &Size,
  2556. Context
  2557. );
  2558. if( TDI_SUCCESS != Status && TDI_BUFFER_OVERFLOW != Status ) {
  2559. goto Cleanup;
  2560. }
  2561. Index = IFE.if_index;
  2562. DhcpPrint((DEBUG_STACK, "IfIndex(0x%lx,0x%lx):0x%lx\n",
  2563. IpInterfaceContext, IpInterfaceInstance, Index
  2564. ));
  2565. Cleanup:
  2566. if( TcpHandle ) NtClose(TcpHandle);
  2567. if( TDI_SUCCESS != Status ) {
  2568. DhcpPrint((DEBUG_ERRORS, "DhcpIpGetIfIndex:TCPQueryInformationEx:%ld\n", Status));
  2569. }
  2570. DhcpPrint((DEBUG_TCP_INFO, "DhcpIpGetIfIndex:0x%lx\n", Index));
  2571. return Index;
  2572. }
  2573. DWORD // win32 status
  2574. DhcpSetRoute( // set a route with the stack
  2575. IN DWORD Dest, // network order destination
  2576. IN DWORD DestMask, // network order destination mask
  2577. IN DWORD IfIndex, // interface index to route
  2578. IN DWORD NextHop, // next hop n/w order address
  2579. IN DWORD Metric, // metric
  2580. IN BOOL IsLocal, // is this a local address? (IRE_DIRECT)
  2581. IN BOOL IsDelete // is this route being deleted?
  2582. )
  2583. {
  2584. DWORD Error;
  2585. NTSTATUS Status;
  2586. HANDLE TcpHandle;
  2587. IPRouteEntry RTE;
  2588. TDIObjectID ID;
  2589. if( 0xFFFFFFFF == IfIndex ) { // invalid If Index
  2590. return ERROR_INVALID_PARAMETER;
  2591. }
  2592. Error = OpenDriver(&TcpHandle, DD_TCP_DEVICE_NAME);
  2593. if( ERROR_SUCCESS != Error ) { // should not really fail
  2594. DhcpPrint((DEBUG_ERRORS, "OpenDriver(TCP_DEVICE):%ld\n", Error));
  2595. return Error;
  2596. }
  2597. memset(&RTE, 0, sizeof(RTE));
  2598. memset(&ID, 0, sizeof(ID));
  2599. RTE.ire_dest = Dest;
  2600. RTE.ire_index = IfIndex;
  2601. RTE.ire_metric1 = Metric;
  2602. RTE.ire_metric2 = (DWORD)(-1);
  2603. RTE.ire_metric3 = (DWORD)(-1);
  2604. RTE.ire_metric4 = (DWORD)(-1);
  2605. RTE.ire_metric5 = (DWORD)(-1);
  2606. RTE.ire_nexthop = NextHop;
  2607. RTE.ire_type = (IsDelete?IRE_TYPE_INVALID:(IsLocal?IRE_TYPE_DIRECT:IRE_TYPE_INDIRECT));
  2608. RTE.ire_proto = IRE_PROTO_NETMGMT;
  2609. RTE.ire_age = 0;
  2610. RTE.ire_mask = DestMask;
  2611. RTE.ire_context = 0;
  2612. ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  2613. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2614. ID.toi_entity.tei_instance = 0;
  2615. ID.toi_class = INFO_CLASS_PROTOCOL;
  2616. ID.toi_type = INFO_TYPE_PROVIDER;
  2617. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Dest: %s\n", IPSTRING(Dest)));
  2618. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w IfIndex:0x%lx\n", IfIndex));
  2619. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w NextHop:%s\n", IPSTRING(NextHop)));
  2620. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w Type:0x%lx\n", RTE.ire_type));
  2621. DhcpPrint((DEBUG_TCP_INFO, "DhcpSetRoute:n/w DestMask:%s\n", IPSTRING(DestMask)));
  2622. Status = TCPSetInformationEx(
  2623. TcpHandle,
  2624. &ID,
  2625. &RTE,
  2626. sizeof(RTE)
  2627. );
  2628. if( TDI_BUFFER_OVERFLOW == Status ) Status = TDI_SUCCESS;
  2629. NtClose(TcpHandle);
  2630. if( TDI_SUCCESS != Status ) {
  2631. DhcpPrint((DEBUG_ERRORS, "DhcpSetRoute: 0x%lx\n", Status));
  2632. }
  2633. return RtlNtStatusToDosError(Status);
  2634. }
  2635. DWORD
  2636. GetAdapterFlag(
  2637. HANDLE TCPHandle,
  2638. DHCP_IP_ADDRESS ipaddr
  2639. )
  2640. {
  2641. BYTE Buffer[256];
  2642. DWORD AdapterFlag;
  2643. NTSTATUS Status;
  2644. DWORD Size;
  2645. TDIObjectID ID;
  2646. BYTE Context[CONTEXT_SIZE];
  2647. /*
  2648. * Read in adapter flag, which could be
  2649. * 1. Point to Point
  2650. * 2. Point to MultiPoint
  2651. * 3. Unidirectional
  2652. * 4. Non of the above
  2653. */
  2654. DhcpAssert(CONTEXT_SIZE >= sizeof(ipaddr));
  2655. RtlCopyMemory(Context, &ipaddr, CONTEXT_SIZE);
  2656. ID.toi_entity.tei_entity = CL_NL_ENTITY;
  2657. ID.toi_entity.tei_instance = 0;
  2658. ID.toi_class = INFO_CLASS_PROTOCOL;
  2659. ID.toi_type = INFO_TYPE_PROVIDER;
  2660. ID.toi_id = IP_INTFC_INFO_ID;
  2661. Size = sizeof(Buffer);
  2662. Status = TCPQueryInformationEx(TCPHandle, &ID, Buffer, &Size, Context);
  2663. if (Status != TDI_SUCCESS) {
  2664. AdapterFlag = 0;
  2665. DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s Status=%lx\n",
  2666. inet_ntoa(*(struct in_addr*)&ipaddr), Status));
  2667. } else {
  2668. AdapterFlag = ((IPInterfaceInfo*)Buffer)->iii_flags;
  2669. DhcpPrint(( DEBUG_TCP_INFO, "QueryInterfaceType: IpAddress=%s AdapterFlag=%lx\n",
  2670. inet_ntoa(*(struct in_addr*)&ipaddr), AdapterFlag));
  2671. }
  2672. return AdapterFlag;
  2673. }
  2674. BOOL
  2675. IsUnidirectionalAdapter(
  2676. DWORD IpInterfaceContext
  2677. )
  2678. /*++
  2679. Routine Description:
  2680. This function queries and browses through the TDI list to find out
  2681. the specified IpTable entry and then determines if it is a unidirectional
  2682. adapter.
  2683. It almost identical to DhcpQueryHWInfo
  2684. Arguments:
  2685. IpInterfaceContext - Context value of the Ip Table Entry.
  2686. Return Value:
  2687. Windows Error Code.
  2688. --*/
  2689. {
  2690. DWORD Error;
  2691. NTSTATUS Status;
  2692. DWORD i, j;
  2693. BYTE Context[CONTEXT_SIZE];
  2694. TDIEntityID *EList = NULL;
  2695. TDIObjectID ID;
  2696. DWORD Size;
  2697. DWORD NumReturned;
  2698. BOOL fFound;
  2699. IPAddrEntry * pIAE = NULL;
  2700. IPAddrEntry *pIAEMatch = NULL;
  2701. HANDLE TCPHandle = NULL;
  2702. DWORD AdapterFlag = 0;
  2703. BYTE HardwareAddressType = 0;
  2704. LPBYTE HardwareAddress = NULL;
  2705. DWORD HardwareAddressLength = 0;
  2706. DWORD pIpInterfaceInstance = 0;
  2707. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying for interface context %lx\n", IpInterfaceContext));
  2708. Error = OpenDriver(&TCPHandle, DD_TCP_DEVICE_NAME);
  2709. if (Error != ERROR_SUCCESS) {
  2710. return( Error );
  2711. }
  2712. //
  2713. // The first thing to do is get the list of available entities, and make
  2714. // sure that there are some interface entities present.
  2715. //
  2716. ID.toi_entity.tei_entity = GENERIC_ENTITY;
  2717. ID.toi_entity.tei_instance = 0;
  2718. ID.toi_class = INFO_CLASS_GENERIC;
  2719. ID.toi_type = INFO_TYPE_PROVIDER;
  2720. ID.toi_id = ENTITY_LIST_ID;
  2721. Size = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  2722. EList = (TDIEntityID*)DhcpAllocateMemory(Size);
  2723. if (EList == NULL) {
  2724. Status = STATUS_INSUFFICIENT_RESOURCES;
  2725. goto Cleanup;
  2726. }
  2727. RtlZeroMemory(EList, Size);
  2728. RtlZeroMemory(Context, CONTEXT_SIZE);
  2729. Status = TCPQueryInformationEx(TCPHandle, &ID, EList, &Size, Context);
  2730. if (Status != TDI_SUCCESS) {
  2731. goto Cleanup;
  2732. }
  2733. NumReturned = Size/sizeof(TDIEntityID);
  2734. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: No of total entities %lx\n", NumReturned));
  2735. for (i = 0; i < NumReturned; i++) {
  2736. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, type %lx, instance %lx\n",
  2737. i, EList[i].tei_entity, EList[i].tei_instance));
  2738. if ( EList[i].tei_entity == CL_NL_ENTITY ) {
  2739. IPSNMPInfo IPStats;
  2740. DWORD NLType;
  2741. //
  2742. // Does this entity support IP?
  2743. //
  2744. ID.toi_entity.tei_entity = EList[i].tei_entity;
  2745. ID.toi_entity.tei_instance = EList[i].tei_instance;
  2746. ID.toi_class = INFO_CLASS_GENERIC;
  2747. ID.toi_type = INFO_TYPE_PROVIDER;
  2748. ID.toi_id = ENTITY_TYPE_ID;
  2749. Size = sizeof( NLType );
  2750. NLType = 0;
  2751. RtlZeroMemory(Context, CONTEXT_SIZE);
  2752. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: querying CL_NL_ENTITY %lx\n",i));
  2753. Status = TCPQueryInformationEx(TCPHandle, &ID, &NLType, &Size, Context);
  2754. if (Status != TDI_SUCCESS) {
  2755. goto Cleanup;
  2756. }
  2757. if ( NLType != CL_NL_IP ) {
  2758. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx does not support IP\n",i));
  2759. continue;
  2760. }
  2761. //
  2762. // We've got an IP driver so get it's address table
  2763. //
  2764. ID.toi_class = INFO_CLASS_PROTOCOL;
  2765. ID.toi_id = IP_MIB_STATS_ID;
  2766. Size = sizeof(IPStats);
  2767. RtlZeroMemory( &IPStats, Size);
  2768. RtlZeroMemory(Context, CONTEXT_SIZE);
  2769. Status = TCPQueryInformationEx(
  2770. TCPHandle,
  2771. &ID,
  2772. &IPStats,
  2773. &Size,
  2774. Context);
  2775. if (Status != TDI_SUCCESS) {
  2776. goto Cleanup;
  2777. }
  2778. DhcpPrint((DEBUG_TCP_INFO, "DhcpQueryHWInfo: entity %lx, numaddr %lx\n",i, IPStats.ipsi_numaddr));
  2779. if ( IPStats.ipsi_numaddr == 0 ) {
  2780. continue;
  2781. }
  2782. Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr;
  2783. while (1) {
  2784. DWORD OldSize;
  2785. pIAE = DhcpAllocateMemory(Size);
  2786. if ( pIAE == NULL ) {
  2787. Status = STATUS_NO_MEMORY;
  2788. goto Cleanup;
  2789. }
  2790. ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  2791. RtlZeroMemory(Context, CONTEXT_SIZE);
  2792. OldSize = Size;
  2793. Status = TCPQueryInformationEx(TCPHandle, &ID, pIAE, &Size, Context);
  2794. if (Status == TDI_BUFFER_OVERFLOW) {
  2795. Size = OldSize * 2;
  2796. DhcpFreeMemory(pIAE);
  2797. pIAE = NULL;
  2798. continue;
  2799. }
  2800. if (Status != TDI_SUCCESS) {
  2801. goto Cleanup;
  2802. }
  2803. if (Status == TDI_SUCCESS) {
  2804. IPStats.ipsi_numaddr = Size/sizeof(IPAddrEntry);
  2805. DhcpAssert((Size % sizeof(IPAddrEntry)) == 0);
  2806. break;
  2807. }
  2808. }
  2809. //
  2810. // We have the IP address table for this IP driver.
  2811. // Find the hardware address corresponds to the given
  2812. // IpInterfaceContext.
  2813. //
  2814. // Loop through the IP table entries and findout the
  2815. // matching entry.
  2816. //
  2817. pIAEMatch = NULL;
  2818. for( j = 0; j < IPStats.ipsi_numaddr ; j++) {
  2819. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has iae_index %lx iae_context %lx\n",
  2820. &pIAE[j], pIAE[j].iae_index, pIAE[j].iae_context ));
  2821. if( pIAE[j].iae_context == IpInterfaceContext ) {
  2822. DhcpPrint(( DEBUG_TCP_INFO, "QueryHWInfo: IPAddrEntry %lx has our interface context %lx\n",
  2823. &pIAE[j], IpInterfaceContext ));
  2824. pIAEMatch = &pIAE[j];
  2825. break;
  2826. }
  2827. }
  2828. if( pIAEMatch == NULL ) {
  2829. //
  2830. // freeup the loop memory.
  2831. //
  2832. DhcpFreeMemory( pIAE );
  2833. pIAE = NULL;
  2834. continue;
  2835. }
  2836. //
  2837. // NOTE : There may be more than one IpTable in the TDI
  2838. // list. We need additional information to select the
  2839. // IpTable we want. For now, we assume only one table
  2840. // is supported, so pick the first and only table from the
  2841. // list.
  2842. Status = FindHardwareAddr(
  2843. TCPHandle,
  2844. EList,
  2845. NumReturned,
  2846. pIAEMatch,
  2847. &HardwareAddressType,
  2848. &HardwareAddress,
  2849. &HardwareAddressLength,
  2850. &pIpInterfaceInstance,
  2851. &fFound );
  2852. if (Status != TDI_SUCCESS) {
  2853. goto Cleanup;
  2854. }
  2855. if ( fFound ) {
  2856. Status = TDI_SUCCESS;
  2857. AdapterFlag = GetAdapterFlag(TCPHandle, pIAEMatch->iae_addr);
  2858. goto Cleanup;
  2859. }
  2860. //
  2861. // freeup the loop memory.
  2862. //
  2863. DhcpFreeMemory( pIAE );
  2864. pIAE = NULL;
  2865. } // if IP
  2866. } // entity traversal
  2867. Status = STATUS_UNSUCCESSFUL;
  2868. Cleanup:
  2869. if( pIAE != NULL ) {
  2870. DhcpFreeMemory( pIAE );
  2871. }
  2872. if( TCPHandle != NULL ) {
  2873. NtClose( TCPHandle );
  2874. }
  2875. if (Status != TDI_SUCCESS) {
  2876. DhcpPrint(( DEBUG_ERRORS, "QueryHWInfo failed, %lx.\n", Status ));
  2877. }
  2878. if( HardwareAddress ) DhcpFreeMemory(HardwareAddress);
  2879. if (NULL != EList) {
  2880. DhcpFreeMemory(EList);
  2881. }
  2882. return (AdapterFlag & IP_INTFC_FLAG_UNIDIRECTIONAL);
  2883. }