Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1284 lines
35 KiB

  1. /****************************************************************************/
  2. // tdtcp.c
  3. //
  4. // TDI based TCP transport specific routines.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <ntddk.h>
  9. #include <tdi.h>
  10. #include <ntddtcp.h>
  11. #include <tdiinfo.h>
  12. #include <tdistat.h>
  13. #include <ipinfo.h>
  14. #include <winstaw.h>
  15. #define _DEFCHARINFO_
  16. #include <icadd.h>
  17. #include <ctxdd.h>
  18. #include <sdapi.h>
  19. #include <td.h>
  20. #include "tdtdi.h"
  21. #include "tdtcp.h"
  22. #ifdef _HYDRA_
  23. // This becomes the device name
  24. PWCHAR ModuleName = L"tdtcp";
  25. #endif
  26. #define REGISTRY_SERVICES \
  27. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
  28. #define REGISTRY_TCP_LINKAGE \
  29. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Linkage"
  30. #define REGISTRY_TCP_INTERFACES \
  31. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
  32. // \nt\private\inc\tcpinfo.h
  33. #define TCP_SOCKET_NODELAY 1
  34. #define TL_INSTANCE 0
  35. #if DBG
  36. ULONG
  37. DbgPrint(
  38. PCH Format,
  39. ...
  40. );
  41. #define DBGPRINT(x) DbgPrint x
  42. #if DBGTRACE
  43. #define TRACE0(x) DbgPrint x
  44. #define TRACE1(x) DbgPrint x
  45. #else
  46. #define TRACE0(x)
  47. #define TRACE1(x)
  48. #endif
  49. #else
  50. #define DBGPRINT(x)
  51. #define TRACE0(x)
  52. #define TRACE1(x)
  53. #endif
  54. /*=============================================================================
  55. == External Functions Defined
  56. =============================================================================*/
  57. // These are called by TDICOM
  58. NTSTATUS TdiDeviceOpen( PTD, PSD_OPEN );
  59. NTSTATUS TdiDeviceClose( PTD, PSD_CLOSE );
  60. NTSTATUS TdiDeviceOpenEndpoint( PTD, PVOID, ULONG );
  61. NTSTATUS TdiDeviceBuildTransportNameAndAddress( PTD, PICA_STACK_ADDRESS,
  62. PUNICODE_STRING,
  63. PTRANSPORT_ADDRESS *, PULONG );
  64. NTSTATUS TdiDeviceBuildWildcardAddress( PTD, PTRANSPORT_ADDRESS *, PULONG );
  65. NTSTATUS TdiDeviceWaitForDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT,
  66. PTRANSPORT_ADDRESS *, PULONG );
  67. NTSTATUS TdiDeviceCompleteDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT, PTRANSPORT_ADDRESS, ULONG );
  68. NTSTATUS TdiDeviceConnectionSend( PTD );
  69. NTSTATUS TdiDeviceReadComplete( PTD, PUCHAR, PULONG );
  70. /*=============================================================================
  71. == External Functions Referenced
  72. =============================================================================*/
  73. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  74. VOID MemoryFree( PVOID );
  75. /*=============================================================================
  76. == Internal Functions Defined
  77. =============================================================================*/
  78. NTSTATUS _TcpGetTransportAddress( PTD, int, PULONG );
  79. VOID
  80. _UnicodeToAnsi(
  81. CHAR * pAnsiString,
  82. ULONG lAnsiMax,
  83. WCHAR * pUnicodeString
  84. );
  85. unsigned long
  86. _inet_addr(
  87. IN const char *cp
  88. );
  89. NTSTATUS
  90. _TcpSetNagle(
  91. IN PFILE_OBJECT pFileObject,
  92. IN PDEVICE_OBJECT DeviceObject,
  93. IN BOOLEAN Flag
  94. );
  95. NTSTATUS
  96. _TdiTcpSetInformation (
  97. IN PFILE_OBJECT FileObject,
  98. IN PDEVICE_OBJECT DeviceObject,
  99. IN ULONG Entity,
  100. IN ULONG Class,
  101. IN ULONG Type,
  102. IN ULONG Id,
  103. IN PVOID Value,
  104. IN ULONG ValueLength,
  105. IN BOOLEAN WaitForCompletion
  106. );
  107. NTSTATUS
  108. _OpenRegKey(
  109. PHANDLE HandlePtr,
  110. PWCHAR KeyName
  111. );
  112. NTSTATUS
  113. _GetRegDWORDValue(
  114. HANDLE KeyHandle,
  115. PWCHAR ValueName,
  116. PULONG ValueData
  117. );
  118. NTSTATUS
  119. _GetRegStringValue(
  120. HANDLE KeyHandle,
  121. PWCHAR ValueName,
  122. PKEY_VALUE_PARTIAL_INFORMATION *ValueData,
  123. PUSHORT ValueSize
  124. );
  125. NTSTATUS
  126. _GetRegMultiSZValue(
  127. HANDLE KeyHandle,
  128. PWCHAR ValueName,
  129. PUNICODE_STRING ValueData
  130. );
  131. NTSTATUS
  132. _GetRegSZValue(
  133. HANDLE KeyHandle,
  134. PWCHAR ValueName,
  135. PUNICODE_STRING ValueData,
  136. PULONG ValueType
  137. );
  138. PWCHAR
  139. _EnumRegMultiSz(
  140. PWCHAR MszString,
  141. ULONG MszStringLength,
  142. ULONG StringIndex
  143. );
  144. VOID
  145. GetGUID(
  146. OUT PUNICODE_STRING szGuid ,
  147. IN int Lana
  148. );
  149. /*=============================================================================
  150. == Global variables
  151. =============================================================================*/
  152. USHORT TdiDeviceEndpointType = TdiConnectionStream; // tdicom\tdtdi.h
  153. USHORT TdiDeviceAddressType = TDI_ADDRESS_TYPE_IP; // TDI address type
  154. USHORT TdiDeviceInBufHeader = 0; // For packet oriented protocols
  155. /*******************************************************************************
  156. *
  157. * TdiDeviceOpen
  158. *
  159. * Allocate and initialize private data structures
  160. *
  161. * ENTRY:
  162. * pTd (input)
  163. * Pointer to TD data structure
  164. * pSdOpen (input/output)
  165. * Points to the parameter structure SD_OPEN.
  166. *
  167. * EXIT:
  168. * STATUS_SUCCESS - no error
  169. *
  170. ******************************************************************************/
  171. NTSTATUS
  172. TdiDeviceOpen( PTD pTd, PSD_OPEN pSdOpen )
  173. {
  174. return( STATUS_SUCCESS );
  175. }
  176. /*******************************************************************************
  177. *
  178. * TdiDeviceClose
  179. *
  180. * Close transport driver
  181. *
  182. * NOTE: this must not close the current connection endpoint
  183. *
  184. * ENTRY:
  185. * pTd (input)
  186. * Pointer to TD data structure
  187. * pSdClose (input/output)
  188. * Points to the parameter structure SD_CLOSE.
  189. *
  190. * EXIT:
  191. * STATUS_SUCCESS - no error
  192. *
  193. ******************************************************************************/
  194. NTSTATUS
  195. TdiDeviceClose( PTD pTd, PSD_CLOSE pSdClose )
  196. {
  197. return( STATUS_SUCCESS );
  198. }
  199. /*******************************************************************************
  200. *
  201. * TdiDeviceOpenEndpoint
  202. *
  203. * Open an existing endpoint
  204. *
  205. * ENTRY:
  206. * pTd (input)
  207. * Pointer to TD data structure
  208. * pIcaEndpoint (input)
  209. * Pointer to ICA endpoint structure
  210. * IcaEndpointLength (input)
  211. * length of endpoint data
  212. *
  213. * EXIT:
  214. * STATUS_SUCCESS - no error
  215. *
  216. ******************************************************************************/
  217. NTSTATUS
  218. TdiDeviceOpenEndpoint(
  219. PTD pTd,
  220. PVOID pIcaEndpoint,
  221. ULONG IcaEndpointLength
  222. )
  223. {
  224. PTDTDI pTdTdi;
  225. NTSTATUS Status;
  226. BOOLEAN Flag;
  227. pTdTdi = (PTDTDI) pTd->pAfd;
  228. /*
  229. * JohnR: Adaptive TCP flow control. 03/02/97
  230. *
  231. * If the OutBufDelay is 0, there is no OutBuf timer,
  232. * and no Nagles. This setting is for the most response time
  233. * sensitive networks with the side effect of sending smaller
  234. * segments.
  235. *
  236. * If the OutBufDelay is greater than 1, the standard CITRIX
  237. * ICA timer is used to determine at the WD level when to
  238. * send a segment. No nagling is enabled since the extra
  239. * delay would not be benefitial.
  240. *
  241. * The new OutBufDelay == 1, means that the WD will treat the
  242. * OutBufDelay as if it were 0, but the TCP code will enable
  243. * the "Nagle" algorithum. This algorithum will send data
  244. * immediately if no un-acknowledged segments are outstanding,
  245. * OR if half of the send window is filled. If not, data is
  246. * stored locally until either a segment acknowledge comes in,
  247. * or more data is sent causing half the send window to fill.
  248. * This has the advantage of dynamically sizing our "outbuf timer"
  249. * to be the round trip time of the network, and not some
  250. * arbritrary fixed value.
  251. */
  252. if( pTdTdi->OutBufDelay == 1 ) {
  253. /*
  254. * OutBufDelay == 1 means NAGLE only.
  255. */
  256. Flag = TRUE;
  257. }
  258. else {
  259. /*
  260. * Turn off nagling for any OutBufDelay timer value, or 0
  261. */
  262. Flag = FALSE;
  263. }
  264. Status = _TcpSetNagle(
  265. pTd->pFileObject,
  266. pTd->pDeviceObject,
  267. Flag
  268. );
  269. DBGPRINT(("TdiDeviceOpenEndpoint: SetNagle 0x%x Result 0x%x\n",Flag,Status));
  270. return( STATUS_SUCCESS );
  271. }
  272. /*****************************************************************************
  273. *
  274. * TdiDeviceBuildTransportNameAndAddress
  275. *
  276. * Build the Transport Name and Address given an optional ICA_STACK_ADDRESS,
  277. * or the Lana value from the pTd->Params structure.
  278. *
  279. * ENTRY:
  280. *
  281. * pTd (input)
  282. * pointer to TD data structure
  283. * pLocalAddress (input)
  284. * pointer to local address to use (OPTIONAL)
  285. * pTransportName (output)
  286. * pointer to UNICODE_STRING to return transport name
  287. * NOTE: the buffer pointed to be pTransportName.Buffer must
  288. * be free'd by the caller
  289. * ppTransportAddress (output)
  290. * pointer to location to return TRANSPORT_ADDRESS structure
  291. * NOTE: the transport address buffer must be free'd by the caller
  292. * pTransportAddressLength (output)
  293. * pointer to location to return TransportAddress length
  294. *
  295. * EXIT:
  296. * STATUS_SUCCESS - Success
  297. *
  298. ****************************************************************************/
  299. NTSTATUS
  300. TdiDeviceBuildTransportNameAndAddress(
  301. PTD pTd,
  302. PICA_STACK_ADDRESS pLocalAddress,
  303. PUNICODE_STRING pTransportName,
  304. PTRANSPORT_ADDRESS *ppTransportAddress,
  305. PULONG pTransportAddressLength
  306. )
  307. {
  308. PTDI_ADDRESS_IP pIpAddress;
  309. int Lana;
  310. NTSTATUS Status;
  311. /*
  312. * For TCP, the transport device name is fixed,
  313. * so just allocate and initialize the transport name string here.
  314. */
  315. Status = MemoryAllocate( sizeof(DD_TCP_DEVICE_NAME), &pTransportName->Buffer );
  316. if ( !NT_SUCCESS( Status ) )
  317. goto badmalloc1;
  318. wcscpy( pTransportName->Buffer, DD_TCP_DEVICE_NAME );
  319. pTransportName->Length = sizeof(DD_TCP_DEVICE_NAME) - sizeof(UNICODE_NULL);
  320. pTransportName->MaximumLength = pTransportName->Length + sizeof(UNICODE_NULL);
  321. /*
  322. * Allocate a transport address structure
  323. */
  324. *pTransportAddressLength = sizeof(TRANSPORT_ADDRESS) +
  325. sizeof(TDI_ADDRESS_IP);
  326. Status = MemoryAllocate( *pTransportAddressLength, ppTransportAddress );
  327. if ( !NT_SUCCESS( Status ) )
  328. goto badmalloc2;
  329. /*
  330. * Initialize the static part of the transport address
  331. */
  332. (*ppTransportAddress)->TAAddressCount = 1;
  333. (*ppTransportAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  334. (*ppTransportAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  335. pIpAddress = (PTDI_ADDRESS_IP)(*ppTransportAddress)->Address[0].Address;
  336. pIpAddress->sin_port = htons( (USHORT)pTd->PortNumber );
  337. RtlZeroMemory( pIpAddress->sin_zero, sizeof(pIpAddress->sin_zero) );
  338. /*
  339. * If a local address is specified, then use it.
  340. */
  341. if ( pLocalAddress ) {
  342. /*
  343. * Skip over the address family(type) data (bytes 0&1) of the
  344. * local address struct, and copy the remainder of the address
  345. * directly to the Address field of the TransportAddress struct.
  346. */
  347. ASSERT( *(PUSHORT)pLocalAddress == TDI_ADDRESS_TYPE_IP );
  348. RtlCopyMemory( pIpAddress, &((PCHAR)pLocalAddress)[2], sizeof(TDI_ADDRESS_IP) );
  349. /*
  350. * There was no local address specified.
  351. * In this case, we use the LanAdapter value from the PDPARAMS
  352. * structure to lookup the corresponding IP address.
  353. */
  354. } else if ( (Lana = pTd->Params.Network.LanAdapter) ) {
  355. ULONG in_addr;
  356. /*
  357. * Get Local Address Information
  358. */
  359. Status = _TcpGetTransportAddress( pTd, Lana, &in_addr );
  360. if ( !NT_SUCCESS( Status ) )
  361. goto badadapterdata;
  362. pIpAddress->in_addr = in_addr;
  363. /*
  364. * No LanAdapter value was specified, so use the wildcard address (zero)
  365. */
  366. } else {
  367. pIpAddress->in_addr = 0;
  368. }
  369. return( STATUS_SUCCESS );
  370. /*=============================================================================
  371. == Error returns
  372. =============================================================================*/
  373. badadapterdata:
  374. MemoryFree( *ppTransportAddress );
  375. badmalloc2:
  376. MemoryFree( pTransportName->Buffer );
  377. badmalloc1:
  378. return( Status );
  379. }
  380. /*****************************************************************************
  381. *
  382. * TdiDeviceBuildWildcardAddress
  383. *
  384. * Build a wildcard Address for this protocol.
  385. *
  386. * ENTRY:
  387. *
  388. * pTd (input)
  389. * pointer to TD data structure
  390. * ppWildcardAddress (output)
  391. * pointer to location to return TRANSPORT_ADDRESS structure
  392. * NOTE: the transport address buffer must be free'd by the caller
  393. * pWildcardAddressLength (output)
  394. * pointer to location to return TransportAddress length
  395. *
  396. * EXIT:
  397. * STATUS_SUCCESS - Success
  398. *
  399. ****************************************************************************/
  400. NTSTATUS
  401. TdiDeviceBuildWildcardAddress(
  402. PTD pTd,
  403. PTRANSPORT_ADDRESS *ppWildcardAddress,
  404. PULONG pWildcardAddressLength
  405. )
  406. {
  407. PTDI_ADDRESS_IP pIpAddress;
  408. NTSTATUS Status;
  409. /*
  410. * Allocate a transport address structure
  411. */
  412. *pWildcardAddressLength = sizeof(TRANSPORT_ADDRESS) +
  413. sizeof(TDI_ADDRESS_IP);
  414. Status = MemoryAllocate( *pWildcardAddressLength, ppWildcardAddress );
  415. if ( !NT_SUCCESS( Status ) )
  416. return( Status );
  417. /*
  418. * Initialize the static part of the transport address
  419. */
  420. (*ppWildcardAddress)->TAAddressCount = 1;
  421. (*ppWildcardAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  422. (*ppWildcardAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  423. pIpAddress = (PTDI_ADDRESS_IP)(*ppWildcardAddress)->Address[0].Address;
  424. pIpAddress->sin_port = 0;
  425. pIpAddress->in_addr = 0;
  426. RtlZeroMemory( pIpAddress->sin_zero, sizeof(pIpAddress->sin_zero) );
  427. return( STATUS_SUCCESS );
  428. }
  429. /*****************************************************************************
  430. *
  431. * TdiDeviceWaitForDatagramConnection
  432. *
  433. * Wait for a datagram connection request, validate it,
  434. * and return the remote transport address of the connection.
  435. *
  436. * ENTRY:
  437. *
  438. * pTd (input)
  439. * pointer to TD data structure
  440. * pFileObject (input)
  441. * pointer to file object to wait for a connection on
  442. * ppRemoteAddress (output)
  443. * pointer to location to return TRANSPORT_ADDRESS structure
  444. * NOTE: the transport address buffer must be free'd by the caller
  445. * pRemoteAddressLength (output)
  446. * pointer to location to return RemoteAddress length
  447. *
  448. * EXIT:
  449. * STATUS_SUCCESS - Success
  450. *
  451. ****************************************************************************/
  452. NTSTATUS
  453. TdiDeviceWaitForDatagramConnection(
  454. PTD pTd,
  455. PFILE_OBJECT pFileObject,
  456. PDEVICE_OBJECT pDeviceObject,
  457. PTRANSPORT_ADDRESS *ppRemoteAddress,
  458. PULONG pRemoteAddressLength
  459. )
  460. {
  461. return( STATUS_NOT_SUPPORTED );
  462. }
  463. /*****************************************************************************
  464. *
  465. * TdiDeviceCompleteDatagramConnection
  466. *
  467. * Do any final work to complete a datagram connection.
  468. *
  469. * ENTRY:
  470. *
  471. * pTd (input)
  472. * pointer to TD data structure
  473. * pFileObject (input)
  474. * pointer to file object for this connection
  475. *
  476. * EXIT:
  477. * STATUS_SUCCESS - Success
  478. *
  479. ****************************************************************************/
  480. NTSTATUS
  481. TdiDeviceCompleteDatagramConnection(
  482. PTD pTd,
  483. PFILE_OBJECT pFileObject,
  484. PDEVICE_OBJECT pDeviceObject,
  485. PTRANSPORT_ADDRESS pRemoteAddress,
  486. ULONG RemoteAddressLength
  487. )
  488. {
  489. return( STATUS_NOT_SUPPORTED );
  490. }
  491. /*******************************************************************************
  492. *
  493. * TdiDeviceConnectionSend
  494. *
  495. * Initialize host module data structure
  496. * -- this structure gets sent to the client
  497. *
  498. *
  499. * ENTRY:
  500. * pTd (input)
  501. * Pointer to td data structure
  502. *
  503. * EXIT:
  504. * STATUS_SUCCESS - no error
  505. *
  506. ******************************************************************************/
  507. NTSTATUS
  508. TdiDeviceConnectionSend( PTD pTd )
  509. {
  510. PCLIENTMODULES pClient;
  511. /*
  512. * Get pointer to client structure
  513. */
  514. pClient = pTd->pClient;
  515. /*
  516. * Initialize Td host module structure
  517. */
  518. pClient->TdVersionL = VERSION_HOSTL_TDTCP;
  519. pClient->TdVersionH = VERSION_HOSTH_TDTCP;
  520. pClient->TdVersion = VERSION_HOSTH_TDTCP;
  521. return( STATUS_SUCCESS );
  522. }
  523. /*******************************************************************************
  524. *
  525. * TdiDeviceReadComplete
  526. *
  527. * Do any read complete processing
  528. *
  529. *
  530. * ENTRY:
  531. * pTd (input)
  532. * Pointer to td data structure
  533. * pBuffer (input)
  534. * Pointer to input buffer
  535. * pByteCount (input/output)
  536. * Pointer to location containing byte count read
  537. *
  538. * EXIT:
  539. * STATUS_SUCCESS - no error
  540. *
  541. ******************************************************************************/
  542. NTSTATUS
  543. TdiDeviceReadComplete( PTD pTd, PUCHAR pBuffer, PULONG pByteCount )
  544. {
  545. return( STATUS_SUCCESS );
  546. }
  547. /*******************************************************************************
  548. *
  549. * _TcpGetTransportAddress
  550. *
  551. * Get TCP transport address for a given LanAdapter number
  552. *
  553. *
  554. * ENTRY:
  555. * pTd (input)
  556. * pointer to TD data structure
  557. * Lana (input)
  558. * Lan Adapter number, 1-based based on the tscc.msc UI ordering.
  559. * pIpAddr (output)
  560. * address to return IP address
  561. *
  562. * EXIT:
  563. * STATUS_SUCCESS - no error
  564. *
  565. ******************************************************************************/
  566. #if 0 // replacement below
  567. NTSTATUS _TcpGetTransportAddress(PTD pTd, int Lana, PULONG pIpAddr)
  568. {
  569. HANDLE KeyHandle;
  570. UNICODE_STRING RouteString;
  571. PWCHAR pInterfaceGuid;
  572. NTSTATUS Status;
  573. unsigned Len;
  574. PWCHAR Str;
  575. /*
  576. * Open the Tcp Linkage key
  577. */
  578. Status = _OpenRegKey( &KeyHandle, REGISTRY_TCP_LINKAGE );
  579. if ( !NT_SUCCESS( Status ) )
  580. goto badopen;
  581. /*
  582. * Alloc and read in the linkage route multi-string.
  583. *
  584. * This is of the form (including the double quotes):
  585. * "{<guid>}"\0"{<guid>}"\0"NdisWanIp"\0\0
  586. *
  587. * Each of the GUIDs is a link to the adapter interface keys
  588. * stored at HKLM\System\CCS\Services\tcpip\Parameters\Interfaces,
  589. * inside of which is the IP address information.
  590. */
  591. RouteString.Length = 0;
  592. RouteString.MaximumLength = 0;
  593. RouteString.Buffer = NULL;
  594. Status = _GetRegMultiSZValue( KeyHandle, L"Route", &RouteString );
  595. ZwClose( KeyHandle );
  596. if ( !NT_SUCCESS( Status ) )
  597. goto badvalue;
  598. /*
  599. * Find the interface GUID that corresponds to the specified UI LANA
  600. * index. The LANA index corresponds to the registry ordering of the
  601. * interfaces, skipping the PPP interface(s). From the way the
  602. * registry looks PPP interfaces do not have GUIDs specified in
  603. * the Linkage key, so we skip the non-GUID entries.
  604. */
  605. if (RouteString.Length < (2 * sizeof(WCHAR))) {
  606. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  607. goto PostAllocRouteString;
  608. }
  609. Len = RouteString.Length;
  610. Str = RouteString.Buffer;
  611. for (;;) {
  612. // Check current string to see if it's a GUID (it must start with an
  613. // open brace after initial double-quote).
  614. if (Str[1] == L'{') {
  615. // Have we found it?
  616. if (Lana == 1)
  617. break;
  618. Lana--;
  619. }
  620. // Skip through current string past NULL.
  621. while (Len >= sizeof(WCHAR)) {
  622. Len -= sizeof(WCHAR);
  623. if (*Str++ == UNICODE_NULL)
  624. break;
  625. }
  626. // Check for index out of range.
  627. if (Len < (2 * sizeof(UNICODE_NULL))) {
  628. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  629. goto PostAllocRouteString;
  630. }
  631. }
  632. if (Len >= (2 * sizeof(UNICODE_NULL))) {
  633. ULONG DhcpEnabled;
  634. UNICODE_STRING IpAddrString;
  635. UNICODE_STRING KeyString;
  636. WCHAR KeyName[256];
  637. char AnsiBuf[256];
  638. // Skip the initial double quote, and change the ending quote to a
  639. // NULL.
  640. Str++;
  641. pInterfaceGuid = Str;
  642. while (*Str != L'\"')
  643. Str++;
  644. *Str = L'\0';
  645. /*
  646. * Use the GUID to look up the interface IP info.
  647. */
  648. // We open HKLM\System\CCS\Services\tcpip\Parameters\Interfaces\<GUID>
  649. // to get to the DHCP and IP address information.
  650. KeyString.Length = 0;
  651. KeyString.MaximumLength = sizeof(KeyName);
  652. KeyString.Buffer = KeyName;
  653. RtlAppendUnicodeToString(&KeyString, REGISTRY_TCP_INTERFACES);
  654. RtlAppendUnicodeToString(&KeyString, pInterfaceGuid);
  655. Status = _OpenRegKey(&KeyHandle, KeyName);
  656. if (!NT_SUCCESS(Status))
  657. goto PostAllocRouteString;
  658. // Query the "EnableDHCP" value.
  659. Status = _GetRegDWORDValue(KeyHandle, L"EnableDHCP", &DhcpEnabled);
  660. if (!NT_SUCCESS(Status)) {
  661. ZwClose(KeyHandle);
  662. goto PostAllocRouteString;
  663. }
  664. IpAddrString.Length = 0;
  665. IpAddrString.MaximumLength = 0;
  666. IpAddrString.Buffer = NULL;
  667. if (DhcpEnabled) {
  668. ULONG ValueType;
  669. // If DHCP is enabled for this device, then we query the current
  670. // IP address from the "DhcpIPAddress" value.
  671. Status = _GetRegSZValue(KeyHandle, L"DhcpIPAddress",
  672. &IpAddrString, &ValueType);
  673. }
  674. else {
  675. // DHCP is not enabled for this device, so we query the
  676. // IP address from the "IPAddress" value.
  677. Status = _GetRegMultiSZValue(KeyHandle, L"IPAddress",
  678. &IpAddrString);
  679. }
  680. ZwClose(KeyHandle);
  681. if (!NT_SUCCESS(Status))
  682. goto PostAllocRouteString;
  683. // Convert IP address from Unicode to ansi to a ULONG.
  684. _UnicodeToAnsi(AnsiBuf, sizeof(AnsiBuf) - 1, IpAddrString.Buffer);
  685. *pIpAddr = _inet_addr(AnsiBuf);
  686. MemoryFree(IpAddrString.Buffer);
  687. }
  688. else {
  689. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  690. goto PostAllocRouteString;
  691. }
  692. PostAllocRouteString:
  693. MemoryFree(RouteString.Buffer);
  694. badvalue:
  695. badopen:
  696. return Status;
  697. }
  698. #endif
  699. /*******************************************************************************
  700. *
  701. * _TcpGetTransportAddress(2)
  702. *
  703. * Get TCP transport address for a given LanAdapter number
  704. *
  705. *
  706. * ENTRY:
  707. * pTd (input)
  708. * pointer to TD data structure
  709. * Lana (input)
  710. * Lan Adapter number, 1-based based on the tscc.msc UI ordering.
  711. * pIpAddr (output)
  712. * address to return IP address
  713. *
  714. * EXIT:
  715. * STATUS_SUCCESS - no error
  716. *
  717. ******************************************************************************/
  718. NTSTATUS _TcpGetTransportAddress(PTD pTd, int Lana, PULONG pIpAddr)
  719. {
  720. HANDLE KeyHandle;
  721. UNICODE_STRING RouteString;
  722. PWCHAR pInterfaceGuid;
  723. NTSTATUS Status;
  724. unsigned Len;
  725. PWCHAR Str;
  726. RtlInitUnicodeString( &RouteString , NULL );
  727. GetGUID( &RouteString , Lana );
  728. Len = RouteString.Length;
  729. Str = RouteString.Buffer;
  730. KdPrint( ( "TDTCP: _TcpGetTransportAddress Length = %d GUID = %ws\n" , Len , Str ) );
  731. if( Str == NULL )
  732. {
  733. return STATUS_DEVICE_DOES_NOT_EXIST;
  734. }
  735. if (Len >= (2 * sizeof(UNICODE_NULL))) {
  736. ULONG DhcpEnabled;
  737. UNICODE_STRING IpAddrString;
  738. UNICODE_STRING KeyString;
  739. WCHAR KeyName[256];
  740. char AnsiBuf[256];
  741. pInterfaceGuid = Str;
  742. // Skip the initial double quote, and change the ending quote to a
  743. // NULL.
  744. /*
  745. Str++;
  746. pInterfaceGuid = Str;
  747. while (*Str != L'\"')
  748. Str++;
  749. *Str = L'\0';
  750. */
  751. /*
  752. * Use the GUID to look up the interface IP info.
  753. */
  754. // We open HKLM\System\CCS\Services\tcpip\Parameters\Interfaces\<GUID>
  755. // to get to the DHCP and IP address information.
  756. KeyString.Length = 0;
  757. KeyString.MaximumLength = sizeof(KeyName);
  758. KeyString.Buffer = KeyName;
  759. RtlAppendUnicodeToString(&KeyString, REGISTRY_TCP_INTERFACES);
  760. RtlAppendUnicodeToString(&KeyString, pInterfaceGuid);
  761. Status = _OpenRegKey(&KeyHandle, KeyName);
  762. if (!NT_SUCCESS(Status))
  763. goto PostAllocRouteString;
  764. // Query the "EnableDHCP" value.
  765. Status = _GetRegDWORDValue(KeyHandle, L"EnableDHCP", &DhcpEnabled);
  766. if (!NT_SUCCESS(Status)) {
  767. ZwClose(KeyHandle);
  768. goto PostAllocRouteString;
  769. }
  770. IpAddrString.Length = 0;
  771. IpAddrString.MaximumLength = 0;
  772. IpAddrString.Buffer = NULL;
  773. if (DhcpEnabled) {
  774. ULONG ValueType;
  775. // If DHCP is enabled for this device, then we query the current
  776. // IP address from the "DhcpIPAddress" value.
  777. Status = _GetRegSZValue(KeyHandle, L"DhcpIPAddress",
  778. &IpAddrString, &ValueType);
  779. }
  780. else {
  781. // DHCP is not enabled for this device, so we query the
  782. // IP address from the "IPAddress" value.
  783. Status = _GetRegMultiSZValue(KeyHandle, L"IPAddress",
  784. &IpAddrString);
  785. }
  786. ZwClose(KeyHandle);
  787. if (!NT_SUCCESS(Status))
  788. goto PostAllocRouteString;
  789. // Convert IP address from Unicode to ansi to a ULONG.
  790. _UnicodeToAnsi(AnsiBuf, sizeof(AnsiBuf) - 1, IpAddrString.Buffer);
  791. *pIpAddr = _inet_addr(AnsiBuf);
  792. MemoryFree(IpAddrString.Buffer);
  793. }
  794. else {
  795. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  796. goto PostAllocRouteString;
  797. }
  798. PostAllocRouteString:
  799. if( RouteString.Buffer != NULL )
  800. {
  801. MemoryFree(RouteString.Buffer);
  802. }
  803. return Status;
  804. }
  805. /*******************************************************************************
  806. *
  807. * _UnicodeToAnsi
  808. *
  809. * convert a UNICODE (WCHAR) string into an ANSI (CHAR) string
  810. *
  811. * ENTRY:
  812. *
  813. * pAnsiString (output)
  814. * buffer to place ANSI string into
  815. * lAnsiMax (input)
  816. * maximum number of characters to write into pAnsiString
  817. * pUnicodeString (input)
  818. * UNICODE string to convert
  819. *
  820. * EXIT:
  821. * nothing (VOID)
  822. *
  823. ******************************************************************************/
  824. VOID
  825. _UnicodeToAnsi(
  826. CHAR * pAnsiString,
  827. ULONG lAnsiMax,
  828. WCHAR * pUnicodeString )
  829. {
  830. ULONG ByteCount;
  831. NTSTATUS
  832. RtlUnicodeToMultiByteN(
  833. OUT PCH MultiByteString,
  834. IN ULONG MaxBytesInMultiByteString,
  835. OUT PULONG BytesInMultiByteString OPTIONAL,
  836. IN PWCH UnicodeString,
  837. IN ULONG BytesInUnicodeString);
  838. RtlUnicodeToMultiByteN( pAnsiString, lAnsiMax, &ByteCount,
  839. pUnicodeString,
  840. ((wcslen(pUnicodeString) + 1) << 1) );
  841. }
  842. /*
  843. * Internet address interpretation routine.
  844. * All the network library routines call this
  845. * routine to interpret entries in the data bases
  846. * which are expected to be an address.
  847. * The value returned is in network order.
  848. */
  849. unsigned long
  850. _inet_addr(
  851. IN const char *cp
  852. )
  853. /*++
  854. Routine Description:
  855. This function interprets the character string specified by the cp
  856. parameter. This string represents a numeric Internet address
  857. expressed in the Internet standard ".'' notation. The value
  858. returned is a number suitable for use as an Internet address. All
  859. Internet addresses are returned in network order (bytes ordered from
  860. left to right).
  861. Internet Addresses
  862. Values specified using the "." notation take one of the following
  863. forms:
  864. a.b.c.d a.b.c a.b a
  865. When four parts are specified, each is interpreted as a byte of data
  866. and assigned, from left to right, to the four bytes of an Internet
  867. address. Note that when an Internet address is viewed as a 32-bit
  868. integer quantity on the Intel architecture, the bytes referred to
  869. above appear as "d.c.b.a''. That is, the bytes on an Intel
  870. processor are ordered from right to left.
  871. Note: The following notations are only used by Berkeley, and nowhere
  872. else on the Internet. In the interests of compatibility with their
  873. software, they are supported as specified.
  874. When a three part address is specified, the last part is interpreted
  875. as a 16-bit quantity and placed in the right most two bytes of the
  876. network address. This makes the three part address format
  877. convenient for specifying Class B network addresses as
  878. "128.net.host''.
  879. When a two part address is specified, the last part is interpreted
  880. as a 24-bit quantity and placed in the right most three bytes of the
  881. network address. This makes the two part address format convenient
  882. for specifying Class A network addresses as "net.host''.
  883. When only one part is given, the value is stored directly in the
  884. network address without any byte rearrangement.
  885. Arguments:
  886. cp - A character string representing a number expressed in the
  887. Internet standard "." notation.
  888. Return Value:
  889. If no error occurs, inet_addr() returns an in_addr structure
  890. containing a suitable binary representation of the Internet address
  891. given. Otherwise, it returns the value INADDR_NONE.
  892. --*/
  893. {
  894. register unsigned long val, base, n;
  895. register char c;
  896. unsigned long parts[4], *pp = parts;
  897. #define INADDR_NONE 0xffffffff
  898. #define htonl(x) ((((x) >> 24) & 0x000000FFL) | \
  899. (((x) >> 8) & 0x0000FF00L) | \
  900. (((x) << 8) & 0x00FF0000L) | \
  901. (((x) << 24) & 0xFF000000L))
  902. again:
  903. /*
  904. * Collect number up to ``.''.
  905. * Values are specified as for C:
  906. * 0x=hex, 0=octal, other=decimal.
  907. */
  908. val = 0; base = 10;
  909. if (*cp == '0') {
  910. base = 8, cp++;
  911. if (*cp == 'x' || *cp == 'X')
  912. base = 16, cp++;
  913. }
  914. while (c = *cp) {
  915. if (isdigit(c)) {
  916. val = (val * base) + (c - '0');
  917. cp++;
  918. continue;
  919. }
  920. if (base == 16 && isxdigit(c)) {
  921. val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
  922. cp++;
  923. continue;
  924. }
  925. break;
  926. }
  927. if (*cp == '.') {
  928. /*
  929. * Internet format:
  930. * a.b.c.d
  931. * a.b.c (with c treated as 16-bits)
  932. * a.b (with b treated as 24 bits)
  933. */
  934. /* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
  935. if (pp >= parts + 3) {
  936. return ((unsigned long) -1);
  937. }
  938. *pp++ = val, cp++;
  939. goto again;
  940. }
  941. /*
  942. * Check for trailing characters.
  943. */
  944. if (*cp && !isspace(*cp)) {
  945. return (INADDR_NONE);
  946. }
  947. *pp++ = val;
  948. /*
  949. * Concoct the address according to
  950. * the number of parts specified.
  951. */
  952. n = (unsigned long)(pp - parts);
  953. switch ((int) n) {
  954. case 1: /* a -- 32 bits */
  955. val = parts[0];
  956. break;
  957. case 2: /* a.b -- 8.24 bits */
  958. if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
  959. return(INADDR_NONE);
  960. }
  961. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  962. break;
  963. case 3: /* a.b.c -- 8.8.16 bits */
  964. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  965. (parts[2] > 0xffff)) {
  966. return(INADDR_NONE);
  967. }
  968. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  969. (parts[2] & 0xffff);
  970. break;
  971. case 4: /* a.b.c.d -- 8.8.8.8 bits */
  972. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  973. (parts[2] > 0xff) || (parts[3] > 0xff)) {
  974. return(INADDR_NONE);
  975. }
  976. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  977. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  978. break;
  979. default:
  980. return (INADDR_NONE);
  981. }
  982. val = htonl(val);
  983. return (val);
  984. }
  985. /*****************************************************************************
  986. *
  987. * _TcpSetNagle
  988. *
  989. * This function turns on, or off the NAGLE algorithum.
  990. *
  991. * ENTRY:
  992. * Param1 (input/output)
  993. * Comments
  994. *
  995. * EXIT:
  996. * STATUS_SUCCESS - no error
  997. *
  998. ****************************************************************************/
  999. NTSTATUS
  1000. _TcpSetNagle(
  1001. IN PFILE_OBJECT pFileObject,
  1002. IN PDEVICE_OBJECT DeviceObject,
  1003. IN BOOLEAN Flag
  1004. )
  1005. {
  1006. NTSTATUS Status;
  1007. ULONG Value;
  1008. if( Flag ) {
  1009. Value = FALSE;
  1010. }
  1011. else {
  1012. Value = TRUE;
  1013. }
  1014. Status = _TdiTcpSetInformation(
  1015. pFileObject,
  1016. DeviceObject,
  1017. CO_TL_ENTITY,
  1018. INFO_CLASS_PROTOCOL,
  1019. INFO_TYPE_CONNECTION,
  1020. TCP_SOCKET_NODELAY,
  1021. &Value,
  1022. sizeof(Value),
  1023. TRUE
  1024. );
  1025. DBGPRINT(("_TcpSetNagle: Flag 0x%x, Result 0x%x\n",Flag,Status));
  1026. return( Status );
  1027. }
  1028. NTSTATUS
  1029. _TdiTcpSetInformation (
  1030. IN PFILE_OBJECT pFileObject,
  1031. IN PDEVICE_OBJECT DeviceObject,
  1032. IN ULONG Entity,
  1033. IN ULONG Class,
  1034. IN ULONG Type,
  1035. IN ULONG Id,
  1036. IN PVOID Value,
  1037. IN ULONG ValueLength,
  1038. IN BOOLEAN WaitForCompletion)
  1039. /*++
  1040. NOTE: This is a modified routine from WSHTCPIP.C
  1041. Routine Description:
  1042. Performs a TDI action to the TCP/IP driver. A TDI action translates
  1043. into a streams T_OPTMGMT_REQ.
  1044. Arguments:
  1045. TdiConnectionObjectHandle - a TDI connection object on which to perform
  1046. the TDI action.
  1047. Entity - value to put in the tei_entity field of the TDIObjectID
  1048. structure.
  1049. Class - value to put in the toi_class field of the TDIObjectID
  1050. structure.
  1051. Type - value to put in the toi_type field of the TDIObjectID
  1052. structure.
  1053. Id - value to put in the toi_id field of the TDIObjectID structure.
  1054. Value - a pointer to a buffer to set as the information.
  1055. ValueLength - the length of the buffer.
  1056. Return Value:
  1057. NTSTATUS code
  1058. --*/
  1059. {
  1060. NTSTATUS status;
  1061. PTCP_REQUEST_SET_INFORMATION_EX pSetInfoEx;
  1062. PIO_STATUS_BLOCK pIOSB;
  1063. // Allocate space to hold the TDI set information buffers and the IO
  1064. // status block. Note the IOSB is a required field for the lower
  1065. // layers despite the OPTIONAL label in CtxDeviceIoControlFile.
  1066. status = MemoryAllocate(sizeof(*pSetInfoEx) + ValueLength +
  1067. sizeof(IO_STATUS_BLOCK), &pIOSB);
  1068. if (status == STATUS_SUCCESS) {
  1069. // The SetInfoEx is after the I/O status block in this alloc.
  1070. pSetInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)(pIOSB + 1);
  1071. // Initialize the TDI information buffers.
  1072. pSetInfoEx->ID.toi_entity.tei_entity = Entity;
  1073. pSetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  1074. pSetInfoEx->ID.toi_class = Class;
  1075. pSetInfoEx->ID.toi_type = Type;
  1076. pSetInfoEx->ID.toi_id = Id;
  1077. RtlCopyMemory(pSetInfoEx->Buffer, Value, ValueLength);
  1078. pSetInfoEx->BufferSize = ValueLength;
  1079. // Make the actual TDI action call. The Streams TDI mapper will
  1080. // translate this into a TPI option management request for us and
  1081. // give it to TCP/IP.
  1082. status = CtxDeviceIoControlFile(pFileObject,
  1083. IOCTL_TCP_SET_INFORMATION_EX, pSetInfoEx,
  1084. sizeof(*pSetInfoEx) + ValueLength, NULL, 0, FALSE, NULL,
  1085. pIOSB, NULL);
  1086. MemoryFree(pIOSB);
  1087. }
  1088. #if DBG
  1089. if (!NT_SUCCESS(status)) {
  1090. DBGPRINT(("_TdiTcpSetInformation: Error 0x%x\n",status));
  1091. }
  1092. #endif
  1093. return status;
  1094. }