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.

1290 lines
35 KiB

  1. /*************************************************************************
  2. *
  3. * tdipx.c
  4. *
  5. * IPX transport specific routines for TDI based TD's
  6. *
  7. * Copyright 1998, Microsoft
  8. *
  9. *************************************************************************/
  10. #include <ntddk.h>
  11. #include <tdi.h>
  12. #include <isnkrnl.h>
  13. #include <ndis.h>
  14. #include <wsnwlink.h>
  15. #include <winstaw.h>
  16. #define _DEFCHARINFO_
  17. #include <icadd.h>
  18. #include <ctxdd.h>
  19. #include <icaipx.h>
  20. //#include <cxstatus.h>
  21. #include <sdapi.h>
  22. #include <td.h>
  23. #include "tdtdi.h"
  24. #include "tdipx.h"
  25. #ifdef _HYDRA_
  26. // This becomes the device name
  27. PWCHAR ModuleName = L"tdipx";
  28. #endif
  29. #define REG_IPX_Linkage \
  30. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkIpx\\Linkage"
  31. #if DBG
  32. ULONG
  33. DbgPrint(
  34. PCH Format,
  35. ...
  36. );
  37. #define DBGPRINT(x) DbgPrint x
  38. #if DBGTRACE
  39. #define TRACE0(x) DbgPrint x
  40. #define TRACE1(x) DbgPrint x
  41. #else
  42. #define TRACE0(x)
  43. #define TRACE1(x)
  44. #endif
  45. #else
  46. #define DBGPRINT(x)
  47. #define TRACE0(x)
  48. #define TRACE1(x)
  49. #endif
  50. /*=============================================================================
  51. == External Functions Defined
  52. =============================================================================*/
  53. NTSTATUS TdiDeviceOpen( PTD, PSD_OPEN );
  54. NTSTATUS TdiDeviceClose( PTD, PSD_CLOSE );
  55. NTSTATUS TdiDeviceOpenEndpoint( PTD, PVOID, ULONG );
  56. NTSTATUS TdiDeviceBuildTransportNameAndAddress( PTD, PICA_STACK_ADDRESS,
  57. PUNICODE_STRING,
  58. PTRANSPORT_ADDRESS *, PULONG );
  59. NTSTATUS TdiDeviceBuildWildcardAddress( PTD, PTRANSPORT_ADDRESS *, PULONG );
  60. NTSTATUS TdiDeviceWaitForDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT,
  61. PTRANSPORT_ADDRESS *, PULONG );
  62. NTSTATUS TdiDeviceCompleteDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT, PTRANSPORT_ADDRESS, ULONG );
  63. NTSTATUS TdiDeviceConnectionSend( PTD );
  64. NTSTATUS TdiDeviceReadComplete( PTD, PUCHAR, PULONG );
  65. NTSTATUS _OpenRegKey(PHANDLE, PWCHAR);
  66. NTSTATUS _GetRegStringValue( HANDLE,PWCHAR,PKEY_VALUE_PARTIAL_INFORMATION *,PUSHORT);
  67. NTSTATUS _GetRegDWORDValue( HANDLE, PWCHAR, PULONG );
  68. NTSTATUS _GetRegMultiSZValue(HANDLE ,PWCHAR,PUNICODE_STRING );
  69. VOID GetGUID(OUT PUNICODE_STRING, IN int);
  70. /*=============================================================================
  71. == External Functions Referenced
  72. =============================================================================*/
  73. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  74. VOID MemoryFree( PVOID );
  75. BOOLEAN IsOnIgnoreList( PTD, PLIST_ENTRY, PTRANSPORT_ADDRESS, ULONG );
  76. VOID AddToIgnoreList( PTD, PLIST_ENTRY, PTRANSPORT_ADDRESS, ULONG );
  77. VOID CleanupIgnoreList( PTD, PLIST_ENTRY );
  78. NTSTATUS InitializeWatchDog( PTD );
  79. NTSTATUS
  80. _TdiReceiveDatagram(
  81. IN PTD pTd,
  82. IN PIRP Irp OPTIONAL,
  83. IN PFILE_OBJECT FileObject,
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN PTRANSPORT_ADDRESS pRemoteAddress,
  86. IN ULONG RemoteAddressLength,
  87. IN ULONG RecvFlags,
  88. IN PVOID pBuffer,
  89. IN ULONG BufferLength,
  90. OUT PULONG ReturnBufferLength
  91. );
  92. NTSTATUS
  93. _TdiSendDatagram(
  94. IN PTD pTd,
  95. IN PIRP Irp OPTIONAL,
  96. IN PFILE_OBJECT FileObject,
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PTRANSPORT_ADDRESS pRemoteAddress,
  99. IN ULONG RemoteAddressLength,
  100. IN PVOID pBuffer,
  101. IN ULONG BufferLength
  102. );
  103. /*=============================================================================
  104. == Internal Functions Defined
  105. =============================================================================*/
  106. NTSTATUS _IpxGetTransportAddress( PTD, int, PULONG, PUCHAR );
  107. NTSTATUS _DoTdiAction( PFILE_OBJECT, ULONG, PCHAR, ULONG );
  108. NTSTATUS _IPXGetAdapterNumber( int Lana, int * AdpNum );
  109. #if DBG
  110. VOID
  111. DumpIpxAddress(
  112. PTRANSPORT_ADDRESS p,
  113. ULONG Len
  114. );
  115. #endif
  116. /*=============================================================================
  117. == Global variables
  118. =============================================================================*/
  119. /*
  120. * Define variables used by tdi common code
  121. */
  122. USHORT TdiDeviceEndpointType = TdiConnectionDatagram;
  123. USHORT TdiDeviceAddressType = TDI_ADDRESS_TYPE_IPX;
  124. ULONG TdiDeviceInBufHeader = IPX_HEADER_LENGTH;
  125. ULONG TdiDeviceMaxTransportAddressLength = sizeof(TA_IPX_ADDRESS);
  126. /*******************************************************************************
  127. *
  128. * TdiDeviceOpen
  129. *
  130. * Allocate and initialize private data structures
  131. *
  132. * ENTRY:
  133. * pTd (input)
  134. * Pointer to TD data structure
  135. * pSdOpen (input/output)
  136. * Points to the parameter structure SD_OPEN.
  137. *
  138. * EXIT:
  139. * STATUS_SUCCESS - no error
  140. *
  141. ******************************************************************************/
  142. NTSTATUS
  143. TdiDeviceOpen( PTD pTd, PSD_OPEN pSdOpen )
  144. {
  145. PTDIPX pTdIpx;
  146. NTSTATUS Status;
  147. /*
  148. * TDIPX uses multiple input buffers since the
  149. * underlying IPX driver does not do any buffering.
  150. */
  151. pTd->InBufCount = 2;
  152. /*
  153. * Allocate IPX TD data structure
  154. */
  155. Status = MemoryAllocate( sizeof(*pTdIpx), &pTdIpx );
  156. if ( !NT_SUCCESS(Status) )
  157. goto badalloc;
  158. //ASSERT( pTd->pPrivate == NULL );
  159. pTd->pPrivate = pTdIpx;
  160. /*
  161. * Initialize TDIPX data structure
  162. */
  163. RtlZeroMemory( pTdIpx, sizeof(*pTdIpx) );
  164. InitializeListHead( &pTdIpx->IgnoreList );
  165. /*
  166. * Watchdog time in registry is seconds
  167. * time = (seconds * 1000) / 2
  168. */
  169. pTdIpx->AliveTime = pSdOpen->PdConfig.Create.KeepAliveTimeout * 500;
  170. return( STATUS_SUCCESS );
  171. /*=============================================================================
  172. == Error returns
  173. =============================================================================*/
  174. /*
  175. * allocate failed
  176. */
  177. badalloc:
  178. return( Status );
  179. }
  180. /*******************************************************************************
  181. *
  182. * TdiDeviceClose
  183. *
  184. * Close transport driver
  185. *
  186. * NOTE: this must not close the current connection endpoint
  187. *
  188. * ENTRY:
  189. * pTd (input)
  190. * Pointer to TD data structure
  191. * pSdClose (input/output)
  192. * Points to the parameter structure SD_CLOSE.
  193. *
  194. * EXIT:
  195. * STATUS_SUCCESS - no error
  196. *
  197. ******************************************************************************/
  198. NTSTATUS
  199. TdiDeviceClose( PTD pTd, PSD_CLOSE pSdClose )
  200. {
  201. PTDIPX pTdIpx;
  202. /*
  203. * Get pointer to IPX structure
  204. */
  205. pTdIpx = (PTDIPX) pTd->pPrivate;
  206. /*
  207. * Free ignore list memory
  208. */
  209. CleanupIgnoreList( pTd, &pTdIpx->IgnoreList );
  210. /*
  211. * Stop and close watchdog timer
  212. */
  213. if ( pTdIpx->pAliveTimer )
  214. IcaTimerClose( pTdIpx->pAliveTimer );
  215. return( STATUS_SUCCESS );
  216. }
  217. /*******************************************************************************
  218. *
  219. * TdiDeviceOpenEndpoint
  220. *
  221. * Open an existing endpoint
  222. *
  223. * ENTRY:
  224. * pTd (input)
  225. * Pointer to TD data structure
  226. * pIcaEndpoint (input)
  227. * Pointer to ICA endpoint structure
  228. * IcaEndpointLength (input)
  229. * length of endpoint data
  230. *
  231. * EXIT:
  232. * STATUS_SUCCESS - no error
  233. *
  234. ******************************************************************************/
  235. NTSTATUS
  236. TdiDeviceOpenEndpoint(
  237. PTD pTd,
  238. PVOID pIcaEndpoint,
  239. ULONG IcaEndpointLength
  240. )
  241. {
  242. /*
  243. * For IPX, we bump the error threshold so that a single
  244. * network I/O error does not cause a disconnect.
  245. */
  246. pTd->ReadErrorThreshold = 5;
  247. pTd->WriteErrorThreshold = 5;
  248. /*
  249. * Arm watch dog
  250. */
  251. (VOID) InitializeWatchDog( pTd );
  252. return( STATUS_SUCCESS );
  253. }
  254. /*****************************************************************************
  255. *
  256. * TdiDeviceBuildTransportNameAndAddress
  257. *
  258. * Build the Transport Name and Address given an optional ICA_STACK_ADDRESS,
  259. * or the Lana value from the pTd->Params structure.
  260. *
  261. * ENTRY:
  262. *
  263. * pTd (input)
  264. * pointer to TD data structure
  265. * pLocalAddress (input)
  266. * pointer to local address to use (OPTIONAL)
  267. * pTransportName (output)
  268. * pointer to UNICODE_STRING to return transport name
  269. * NOTE: the buffer pointed to be pTransportName.Buffer must
  270. * be free'd by the caller
  271. * ppTransportAddress (output)
  272. * pointer to location to return TRANSPORT_ADDRESS structure
  273. * NOTE: the transport address buffer must be free'd by the caller
  274. * pTransportAddressLength (output)
  275. * pointer to location to return TransportAddress length
  276. *
  277. * EXIT:
  278. * STATUS_SUCCESS - Success
  279. *
  280. ****************************************************************************/
  281. NTSTATUS
  282. TdiDeviceBuildTransportNameAndAddress(
  283. PTD pTd,
  284. PICA_STACK_ADDRESS pLocalAddress,
  285. PUNICODE_STRING pTransportName,
  286. PTRANSPORT_ADDRESS *ppTransportAddress,
  287. PULONG pTransportAddressLength
  288. )
  289. {
  290. PTDI_ADDRESS_IPX pIpxAddress;
  291. int Lana;
  292. NTSTATUS Status;
  293. /*
  294. * For IPX, the transport device name is fixed,
  295. * so just allocate and initialize the transport name string here.
  296. */
  297. Status = MemoryAllocate( sizeof(DD_IPX_DEVICE_NAME), &pTransportName->Buffer );
  298. if ( !NT_SUCCESS( Status ) )
  299. goto badmalloc1;
  300. wcscpy( pTransportName->Buffer, DD_IPX_DEVICE_NAME );
  301. pTransportName->Length = sizeof(DD_IPX_DEVICE_NAME) - sizeof(UNICODE_NULL);
  302. pTransportName->MaximumLength = pTransportName->Length + sizeof(UNICODE_NULL);
  303. /*
  304. * Allocate a transport address structure
  305. */
  306. *pTransportAddressLength = sizeof(TA_IPX_ADDRESS);
  307. Status = MemoryAllocate( *pTransportAddressLength, ppTransportAddress );
  308. if ( !NT_SUCCESS( Status ) )
  309. goto badmalloc2;
  310. /*
  311. * Initialize the static part of the transport address
  312. */
  313. (*ppTransportAddress)->TAAddressCount = 1;
  314. (*ppTransportAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
  315. (*ppTransportAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  316. pIpxAddress = (PTDI_ADDRESS_IPX)(*ppTransportAddress)->Address[0].Address;
  317. pIpxAddress->Socket = htons( CITRIX_IPX_SOCKET );
  318. /*
  319. * If a local address is specified, then use it.
  320. */
  321. if ( pLocalAddress ) {
  322. /*
  323. * Skip over the address family(type) data (bytes 0&1) of the
  324. * local address struct, and copy the remainder of the address
  325. * directly to the Address field of the TransportAddress struct.
  326. */
  327. ASSERT( *(PUSHORT)pLocalAddress == TDI_ADDRESS_TYPE_IPX );
  328. RtlCopyMemory( pIpxAddress, &((PCHAR)pLocalAddress)[2], sizeof(TDI_ADDRESS_IPX) );
  329. /*
  330. * There was no local address specified.
  331. * In this case, we use the LanAdapter value from the PDPARAMS
  332. * structure to lookup the corresponding IPX address.
  333. */
  334. } else if ( (Lana = pTd->Params.Network.LanAdapter) ) {
  335. /*
  336. * Get Local Address Information
  337. */
  338. Status = _IpxGetTransportAddress( pTd, Lana,
  339. &pIpxAddress->NetworkAddress,
  340. pIpxAddress->NodeAddress );
  341. if ( !NT_SUCCESS( Status ) )
  342. goto badadapterdata;
  343. /*
  344. * No LanAdapter value was specified, so use the wildcard address (zero)
  345. */
  346. } else {
  347. pIpxAddress->NetworkAddress = 0;
  348. RtlZeroMemory( pIpxAddress->NodeAddress,
  349. sizeof(pIpxAddress->NodeAddress) );
  350. }
  351. return( STATUS_SUCCESS );
  352. /*=============================================================================
  353. == Error returns
  354. =============================================================================*/
  355. badadapterdata:
  356. MemoryFree( *ppTransportAddress );
  357. badmalloc2:
  358. MemoryFree( pTransportName->Buffer );
  359. badmalloc1:
  360. return( Status );
  361. }
  362. /*****************************************************************************
  363. *
  364. * TdiDeviceBuildWildcardAddress
  365. *
  366. * Build a wildcard Address for this protocol.
  367. *
  368. * ENTRY:
  369. *
  370. * pTd (input)
  371. * pointer to TD data structure
  372. * ppWildcardAddress (output)
  373. * pointer to location to return TRANSPORT_ADDRESS structure
  374. * NOTE: the transport address buffer must be free'd by the caller
  375. * pWildcardAddressLength (output)
  376. * pointer to location to return TransportAddress length
  377. *
  378. * EXIT:
  379. * STATUS_SUCCESS - Success
  380. *
  381. ****************************************************************************/
  382. NTSTATUS
  383. TdiDeviceBuildWildcardAddress(
  384. PTD pTd,
  385. PTRANSPORT_ADDRESS *ppWildcardAddress,
  386. PULONG pWildcardAddressLength
  387. )
  388. {
  389. PTDI_ADDRESS_IPX pIpxAddress;
  390. NTSTATUS Status;
  391. /*
  392. * Allocate a transport address structure
  393. */
  394. *pWildcardAddressLength = sizeof(TRANSPORT_ADDRESS) +
  395. sizeof(TDI_ADDRESS_IPX);
  396. Status = MemoryAllocate( *pWildcardAddressLength, ppWildcardAddress );
  397. if ( !NT_SUCCESS( Status ) )
  398. return( Status );
  399. /*
  400. * Initialize the static part of the transport address
  401. */
  402. (*ppWildcardAddress)->TAAddressCount = 1;
  403. (*ppWildcardAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
  404. (*ppWildcardAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  405. pIpxAddress = (PTDI_ADDRESS_IPX)(*ppWildcardAddress)->Address[0].Address;
  406. pIpxAddress->NetworkAddress = 0;
  407. RtlZeroMemory( pIpxAddress->NodeAddress,
  408. sizeof(pIpxAddress->NodeAddress) );
  409. pIpxAddress->Socket = 0;
  410. return( STATUS_SUCCESS );
  411. }
  412. /*****************************************************************************
  413. *
  414. * TdiDeviceWaitForDatagramConnection
  415. *
  416. * Wait for a datagram connection request, validate it,
  417. * and return the remote transport address of the connection.
  418. *
  419. * ENTRY:
  420. *
  421. * pTd (input)
  422. * pointer to TD data structure
  423. * pFileObject (input)
  424. * pointer to file object to wait for a connection on
  425. * ppRemoteAddress (output)
  426. * pointer to location to return TRANSPORT_ADDRESS structure
  427. * NOTE: the transport address buffer must be free'd by the caller
  428. * pRemoteAddressLength (output)
  429. * pointer to location to return RemoteAddress length
  430. *
  431. * EXIT:
  432. * STATUS_SUCCESS - Success
  433. *
  434. ****************************************************************************/
  435. NTSTATUS
  436. TdiDeviceWaitForDatagramConnection(
  437. PTD pTd,
  438. PFILE_OBJECT pFileObject,
  439. PDEVICE_OBJECT pDeviceObject,
  440. PTRANSPORT_ADDRESS *ppRemoteAddress,
  441. PULONG pRemoteAddressLength
  442. )
  443. {
  444. char *pReceiveBuffer;
  445. PTRANSPORT_ADDRESS pRemoteAddress;
  446. ULONG RemoteAddressLength;
  447. NTSTATUS Status;
  448. PTDIPX pTdIpx;
  449. ULONG BufferLength, ReturnLength;
  450. /*
  451. * Get pointer to IPX structure
  452. */
  453. pTdIpx = (PTDIPX) pTd->pPrivate;
  454. /*
  455. * Allocate a receive data buffer as well as
  456. * a buffer to hold the remote transport address.
  457. */
  458. BufferLength = CALL_BUFFER_SIZE;
  459. Status = MemoryAllocate( BufferLength, &pReceiveBuffer );
  460. if ( !NT_SUCCESS( Status ) ) {
  461. goto badmalloc;
  462. }
  463. RemoteAddressLength = TdiDeviceMaxTransportAddressLength;
  464. Status = MemoryAllocate( RemoteAddressLength, &pRemoteAddress );
  465. if ( !NT_SUCCESS( Status ) ) {
  466. goto badmalloc2;
  467. }
  468. /*
  469. * Initialize the receive info buffer
  470. */
  471. for ( ; ; ) {
  472. RemoteAddressLength = TdiDeviceMaxTransportAddressLength;
  473. TRACE0(("IPX: TdiWaitForDatagramConnection: Waiting for datagram request RemoteAddressLength %d\n",RemoteAddressLength));
  474. /*
  475. * Wait for data to arrive
  476. */
  477. Status = _TdiReceiveDatagram(
  478. pTd,
  479. NULL, // Irp
  480. pFileObject,
  481. pDeviceObject,
  482. (PTRANSPORT_ADDRESS)pRemoteAddress,
  483. RemoteAddressLength,
  484. TDI_RECEIVE_NORMAL, // TDI ReceiveFlags
  485. pReceiveBuffer,
  486. BufferLength,
  487. &ReturnLength
  488. );
  489. if ( !NT_SUCCESS( Status ) ) {
  490. DBGPRINT(("TdiDeviceWaitForDatagramConnection: Error 0x%x from _TdiReceiveDatagram\n",Status));
  491. goto badrecv;
  492. }
  493. TRACEBUF(( pTd->pContext, TC_TD, TT_IRAW, pReceiveBuffer, ReturnLength ));
  494. /*
  495. * See if the received buffer is the correct size
  496. */
  497. if ( ReturnLength != CALL_BUFFER_SIZE ) {
  498. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: Invalid IPX connect packet length\n" ));
  499. TRACE0(("TDIPX: Invalid IPX connect packet length 0x%x\n",ReturnLength));
  500. continue;
  501. }
  502. /*
  503. * See if it matches our expected connection string
  504. */
  505. if ( memcmp( pReceiveBuffer, CONNECTION_STRING, sizeof(CONNECTION_STRING) ) ){
  506. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: Invalid IPX connect packet data\n" ));
  507. TRACE0(("TDIPX: Invalid IPX connect packet data\n"));
  508. continue;
  509. }
  510. #if DBG
  511. TRACE0(("TdiDeviceWaitForDatagramConnection: Connect Request From Client Address:\n"));
  512. DumpIpxAddress( pRemoteAddress, RemoteAddressLength );
  513. #endif
  514. /*
  515. * Fix up the remote transport address
  516. */
  517. #ifdef notdef
  518. pRemoteAddress->TAAddressCount = 1;
  519. pRemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
  520. pRemoteAddress->Address[0].AddressLength = (USHORT)RemoteAddressLength;
  521. RemoteAddressLength += FIELD_OFFSET( TRANSPORT_ADDRESS, Address[0].Address[0] );
  522. #endif
  523. /*
  524. * Validation complete - seems to be a valid ipx connection packet
  525. */
  526. if ( IsOnIgnoreList( pTd, &pTdIpx->IgnoreList, pRemoteAddress, RemoteAddressLength ) ) {
  527. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: TdiDeviceWaitForDatagramConnection ignored dup IPX connect\n"));
  528. TRACE0(("TDIPX: TdiDeviceWaitForDatagramConnection ignored dup IPX connect\n"));
  529. continue;
  530. }
  531. break;
  532. }
  533. AddToIgnoreList( pTd, &pTdIpx->IgnoreList, pRemoteAddress, RemoteAddressLength );
  534. MemoryFree( pReceiveBuffer );
  535. *ppRemoteAddress = pRemoteAddress;
  536. *pRemoteAddressLength = RemoteAddressLength;
  537. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDIPX: TdiDeviceWaitForDatagramConnection: %u bytes, success\n",
  538. ReturnLength ));
  539. TRACE0(("TDIPX: TdiDeviceWaitForDatagramConnection: %u bytes, success\n",ReturnLength));
  540. return( STATUS_SUCCESS );
  541. /*=============================================================================
  542. == Error returns
  543. =============================================================================*/
  544. badrecv:
  545. MemoryFree( pRemoteAddress );
  546. badmalloc2:
  547. MemoryFree( pReceiveBuffer );
  548. badmalloc:
  549. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  550. "TDIPX: TdiDeviceWaitForDatagramConnection ERROR, Status=0x%x\n", Status ));
  551. TRACE0(("TDIPX: TdiDeviceWaitForDatagramConnection ERROR, Status=0x%x\n", Status));
  552. return( Status );
  553. }
  554. /*****************************************************************************
  555. *
  556. * TdiDeviceCompleteDatagramConnection
  557. *
  558. * Do any final work to complete a datagram connection.
  559. *
  560. * ENTRY:
  561. *
  562. * pTd (input)
  563. * pointer to TD data structure
  564. * pFileObject (input)
  565. * pointer to file object for this connection
  566. *
  567. * EXIT:
  568. * STATUS_SUCCESS - Success
  569. *
  570. ****************************************************************************/
  571. NTSTATUS
  572. TdiDeviceCompleteDatagramConnection(
  573. PTD pTd,
  574. PFILE_OBJECT pFileObject,
  575. PDEVICE_OBJECT pDeviceObject,
  576. PTRANSPORT_ADDRESS pRemoteAddress,
  577. ULONG RemoteAddressLength
  578. )
  579. {
  580. CHAR ptype;
  581. NTSTATUS Status;
  582. BYTE ReplyBuffer[CALL_BUFFER_SIZE];
  583. /*
  584. * Create reply packet with reply string
  585. */
  586. memset( ReplyBuffer, 0, CALL_BUFFER_SIZE );
  587. memcpy( ReplyBuffer, CONNECTION_STRING_REPLY, sizeof(CONNECTION_STRING_REPLY) );
  588. /*
  589. * Add ICA 3.0 and not sequenced to reply packet
  590. */
  591. ReplyBuffer[CALL_HOST_IPX_VERSION] = ICA_3_IPX_VERSION;
  592. ReplyBuffer[CALL_HOST_SEQUENCE_ENABLE] = 0x00;
  593. TRACEBUF(( pTd->pContext, TC_TD, TT_ORAW, ReplyBuffer, CALL_BUFFER_SIZE ));
  594. #if DBG
  595. TRACE0(("TdiDeviceCompleteDatagramConnection: Sending Connect Reply to Client Address:\n"));
  596. DumpIpxAddress( pRemoteAddress, RemoteAddressLength );
  597. #endif
  598. /*
  599. * Write data to the network
  600. */
  601. Status = _TdiSendDatagram(
  602. pTd,
  603. NULL, // Irp
  604. pFileObject,
  605. pDeviceObject,
  606. pRemoteAddress,
  607. RemoteAddressLength,
  608. ReplyBuffer,
  609. CALL_BUFFER_SIZE
  610. );
  611. ASSERT( Status == STATUS_SUCCESS );
  612. /*
  613. * Set up the default packet send type to be data
  614. */
  615. ptype = IPX_TYPE_DATA;
  616. Status = _DoTdiAction( pFileObject, MIPX_SETSENDPTYPE, &ptype, 1 );
  617. ASSERT( Status == STATUS_SUCCESS );
  618. if ( !NT_SUCCESS( Status ) )
  619. goto badtdiaction;
  620. /*
  621. * Indicate we want the IPX header included in send/receive data
  622. */
  623. Status = _DoTdiAction( pFileObject, MIPX_SENDHEADER, NULL, 0 );
  624. ASSERT( Status == STATUS_SUCCESS );
  625. if ( !NT_SUCCESS( Status ) )
  626. goto badtdiaction;
  627. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDIPX: TdiDeviceCompleteDatagramConnection: %u bytes, success\n" ,
  628. CALL_BUFFER_SIZE ));
  629. TRACE0(("TDIPX: TdiDeviceCompleteDatagramConnection: %u bytes, success\n",CALL_BUFFER_SIZE));
  630. return( STATUS_SUCCESS );
  631. /*=============================================================================
  632. == Error returns
  633. =============================================================================*/
  634. badtdiaction:
  635. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  636. "TDIPX: TdiDeviceCompleteDatagramConnection ERROR, Status=0x%x\n", Status ));
  637. TRACE0(("TDIPX: TdiDeviceCompleteDatagramConnection ERROR, Status=0x%x\n",Status));
  638. return( Status );
  639. }
  640. /*******************************************************************************
  641. *
  642. * TdiDeviceConnectionSend
  643. *
  644. * Initialize host module data structure
  645. * -- this structure gets sent to the client
  646. *
  647. *
  648. * ENTRY:
  649. * pTd (input)
  650. * Pointer to td data structure
  651. *
  652. * EXIT:
  653. * STATUS_SUCCESS - no error
  654. *
  655. ******************************************************************************/
  656. NTSTATUS
  657. TdiDeviceConnectionSend( PTD pTd )
  658. {
  659. PCLIENTMODULES pClient;
  660. /*
  661. * Get pointer to client structure
  662. */
  663. pClient = pTd->pClient;
  664. /*
  665. * Initialize Td host module structure
  666. */
  667. pClient->TdVersionL = VERSION_HOSTL_TDIPX;
  668. pClient->TdVersionH = VERSION_HOSTH_TDIPX;
  669. pClient->TdVersion = VERSION_HOSTH_TDIPX;
  670. return( STATUS_SUCCESS );
  671. }
  672. /*******************************************************************************
  673. *
  674. * TdiDeviceReadComplete
  675. *
  676. * Do any read complete processing
  677. *
  678. *
  679. * ENTRY:
  680. * pTd (input)
  681. * Pointer to td data structure
  682. * pBuffer (input)
  683. * Pointer to input buffer
  684. * pByteCount (input/output)
  685. * Pointer to location containing byte count read
  686. *
  687. * EXIT:
  688. * STATUS_SUCCESS - no error
  689. *
  690. ******************************************************************************/
  691. NTSTATUS
  692. TdiDeviceReadComplete( PTD pTd, PUCHAR pBuffer, PULONG pByteCount )
  693. {
  694. IPX_PACKET * pIpxHeader;
  695. PUCHAR pByte;
  696. NTSTATUS Status;
  697. PTDIPX pTdIpx;
  698. /*
  699. * Get pointer to IPX structure
  700. */
  701. pTdIpx = (PTDIPX) pTd->pPrivate;
  702. /*
  703. * Check for at least IPX_PACKET bytes
  704. */
  705. if ( *pByteCount < IPX_HEADER_LENGTH ) {
  706. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: recv failed, less than ipx header bytes\n" ));
  707. return( STATUS_CTX_TD_ERROR );
  708. }
  709. /*
  710. * Address ipx header
  711. */
  712. pIpxHeader = (IPX_PACKET *) pBuffer;
  713. /*
  714. * Check for control packet
  715. */
  716. if ( pIpxHeader->PacketType == IPX_TYPE_CONTROL ) {
  717. /*
  718. * Get first data byte
  719. */
  720. pByte = (PUCHAR) pBuffer + IPX_HEADER_LENGTH;
  721. /*
  722. * What type of packet
  723. */
  724. switch ( *pByte ) {
  725. /*
  726. * Keep alive response
  727. */
  728. case IPX_CTRL_PACKET_PING_RESP :
  729. pTdIpx->fClientAlive = TRUE;
  730. pTdIpx->AlivePoll = 0;
  731. pTd->pStatus->Input.Bytes++;
  732. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDIPX: Watchdog Response Control Packet\n" ));
  733. break;
  734. /*
  735. * Client disconnect packet
  736. */
  737. case IPX_CTRL_PACKET_HANGUP :
  738. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDIPX: Hangup Control Packet\n" ));
  739. pTd->pStatus->Input.Bytes++;
  740. // drop error threshold so returned error isn't ignored
  741. pTd->ReadErrorThreshold = 0;
  742. return( STATUS_IO_TIMEOUT );
  743. break;
  744. /*
  745. * Unknown packet
  746. */
  747. default :
  748. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDIPX: Unknown Control Packet, type %u\n", *pByte ));
  749. break;
  750. }
  751. /*
  752. * Indicate to caller that we ate all the data
  753. */
  754. *pByteCount = 0;
  755. return( STATUS_SUCCESS );
  756. }
  757. /*
  758. * Got a valid non-control packet
  759. */
  760. pTdIpx->fClientAlive = TRUE;
  761. pTdIpx->AlivePoll = 0;
  762. return( STATUS_SUCCESS );
  763. }
  764. /*******************************************************************************
  765. *
  766. * TransportAddress
  767. *
  768. * Get IPX transport address for a given LanAdapter number
  769. *
  770. *
  771. * ENTRY:
  772. * pTd (input)
  773. * pointer to TD data structure
  774. * Lana (input)
  775. * Lan Adapter number
  776. * pNetworkAddress (output)
  777. * pointer to location to return NetworkAddress
  778. * pNodeAddress (output)
  779. * pointer to location to return NodeAddress
  780. *
  781. *
  782. * EXIT:
  783. * STATUS_SUCCESS - no error
  784. *
  785. ******************************************************************************/
  786. NTSTATUS
  787. _IpxGetTransportAddress(
  788. PTD pTd,
  789. int Lana,
  790. PULONG pNetworkAddress,
  791. PUCHAR pNodeAddress
  792. )
  793. {
  794. OBJECT_ATTRIBUTES objectAttributes;
  795. IO_STATUS_BLOCK ioStatusBlock;
  796. UNICODE_STRING nameString;
  797. HANDLE IPXHandle;
  798. ULONG tdiBufferLength;
  799. PSTREAMS_TDI_ACTION tdiBuffer;
  800. ULONG cmd;
  801. PIPX_ADDRESS_DATA pIpxAddressData;
  802. PFILE_OBJECT pFileObject;
  803. NTSTATUS Status;
  804. int IpxAdapterNum = 0;
  805. /*
  806. * Open a Handle to the IPX driver.
  807. */
  808. RtlInitUnicodeString( &nameString, DD_IPX_DEVICE_NAME );
  809. InitializeObjectAttributes(
  810. &objectAttributes,
  811. &nameString,
  812. OBJ_CASE_INSENSITIVE,
  813. (HANDLE) NULL,
  814. (PSECURITY_DESCRIPTOR) NULL
  815. );
  816. Status = ZwCreateFile( &IPXHandle,
  817. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  818. &objectAttributes,
  819. &ioStatusBlock,
  820. NULL,
  821. FILE_ATTRIBUTE_NORMAL,
  822. FILE_SHARE_READ | FILE_SHARE_WRITE,
  823. FILE_OPEN_IF,
  824. 0,
  825. NULL,
  826. 0
  827. );
  828. if ( !NT_SUCCESS( Status ) )
  829. return( Status );
  830. /*
  831. * Allocate a TDI buffer to do the IOCTL.
  832. */
  833. tdiBufferLength = sizeof(STREAMS_TDI_ACTION) + sizeof(ULONG) +
  834. sizeof(IPX_ADDRESS_DATA);
  835. Status = MemoryAllocate( tdiBufferLength, &tdiBuffer );
  836. if ( !NT_SUCCESS( Status ) ) {
  837. ZwClose( IPXHandle );
  838. return( Status );
  839. }
  840. /*
  841. * Fill in the tdiBuffer header
  842. */
  843. RtlMoveMemory( &tdiBuffer->Header.TransportId, "MISN", 4 );
  844. // use the following since we opened a control channel above
  845. tdiBuffer->DatagramOption = NWLINK_OPTION_CONTROL;
  846. // Get IPX Adapter Num from winstation Lana ID
  847. Status = _IPXGetAdapterNumber( Lana, &IpxAdapterNum);
  848. DbgPrint("IpxAdapterNum: %d\n", IpxAdapterNum);
  849. if ( !NT_SUCCESS( Status ) ) {
  850. ZwClose( IPXHandle );
  851. return( Status );
  852. }
  853. /**
  854. Fill out the buffer, the buffer looks like this:
  855. ULONG cmd
  856. data passed.
  857. **/
  858. cmd = MIPX_GETCARDINFO;
  859. memcpy( tdiBuffer->Buffer, &cmd, sizeof(ULONG));
  860. tdiBuffer->BufferLength = sizeof(ULONG) + sizeof(IPX_ADDRESS_DATA);
  861. pIpxAddressData = (PIPX_ADDRESS_DATA)(tdiBuffer->Buffer + sizeof(ULONG));
  862. pIpxAddressData->adapternum = IpxAdapterNum ;
  863. Status = ObReferenceObjectByHandle( IPXHandle,
  864. 0,
  865. NULL,
  866. KernelMode,
  867. (PVOID *)&pFileObject,
  868. NULL
  869. );
  870. ASSERT( Status == STATUS_SUCCESS );
  871. Status = CtxDeviceIoControlFile( pFileObject,
  872. IOCTL_TDI_ACTION,
  873. NULL,
  874. 0,
  875. tdiBuffer,
  876. tdiBufferLength,
  877. FALSE,
  878. NULL,
  879. NULL,
  880. NULL
  881. );
  882. ObDereferenceObject( pFileObject );
  883. ZwClose( IPXHandle );
  884. if ( Status == STATUS_SUCCESS ) {
  885. RtlCopyMemory( pNetworkAddress, pIpxAddressData->netnum,
  886. sizeof(pIpxAddressData->netnum) );
  887. RtlCopyMemory( pNodeAddress, pIpxAddressData->nodenum,
  888. sizeof(pIpxAddressData->nodenum) );
  889. DbgPrint("pNetworkAddress: %x, pNodeAddress %s\n", *pNetworkAddress, *pNodeAddress);
  890. }
  891. MemoryFree( tdiBuffer );
  892. return( Status );
  893. }
  894. /*****************************************************************************
  895. *
  896. * _DoTdiAction
  897. *
  898. * Perform special IOCTL on IPX TDI.
  899. *
  900. * ENTRY:
  901. * Param1 (input/output)
  902. * Comments
  903. *
  904. * EXIT:
  905. * STATUS_SUCCESS - no error
  906. *
  907. ****************************************************************************/
  908. NTSTATUS
  909. _DoTdiAction(
  910. PFILE_OBJECT pFileObject,
  911. ULONG cmd,
  912. PCHAR optbuf,
  913. ULONG optlen
  914. )
  915. {
  916. ULONG tdiBufferLength;
  917. PSTREAMS_TDI_ACTION tdiBuffer;
  918. NTSTATUS Status;
  919. /*
  920. * Allocate a TDI buffer to do the IOCTL.
  921. */
  922. tdiBufferLength = sizeof(STREAMS_TDI_ACTION) + sizeof(ULONG) + optlen;
  923. Status = MemoryAllocate( tdiBufferLength, &tdiBuffer );
  924. if ( !NT_SUCCESS( Status ) )
  925. return( Status );
  926. /*
  927. * Fill in the tdiBuffer header
  928. */
  929. RtlMoveMemory( &tdiBuffer->Header.TransportId, "MISN", 4 );
  930. tdiBuffer->DatagramOption = 1; // Action is on an address on ISN
  931. /**
  932. Fill out the buffer, the buffer looks like this:
  933. ULONG cmd
  934. data passed.
  935. **/
  936. memcpy( tdiBuffer->Buffer, &cmd, sizeof(ULONG));
  937. tdiBuffer->BufferLength = sizeof(ULONG) + sizeof(CHAR);
  938. RtlMoveMemory( tdiBuffer->Buffer + sizeof(ULONG), optbuf, optlen );
  939. Status = CtxDeviceIoControlFile( pFileObject,
  940. IOCTL_TDI_ACTION,
  941. NULL,
  942. 0,
  943. tdiBuffer,
  944. tdiBufferLength,
  945. FALSE,
  946. NULL,
  947. NULL,
  948. NULL
  949. );
  950. /*
  951. * Copy return data back to optbuf if needed
  952. */
  953. if ( NT_SUCCESS( Status ) && optlen ) {
  954. RtlMoveMemory( optbuf, tdiBuffer->Buffer + sizeof(ULONG), optlen );
  955. }
  956. MemoryFree( tdiBuffer );
  957. return( Status );
  958. }
  959. #if DBG
  960. VOID
  961. DumpIpxAddress(
  962. PTRANSPORT_ADDRESS p,
  963. ULONG Len
  964. )
  965. {
  966. ULONG j;
  967. LONG i;
  968. PTDI_ADDRESS_IPX Ipx;
  969. DbgPrint("TAAddressCount %d, TotalLen %d\n",p->TAAddressCount,Len);
  970. for( i=0; i < p->TAAddressCount; i++ ) {
  971. DbgPrint("AddressLength %d, AddressType %d\n",p->Address[i].AddressLength,p->Address[i].AddressType);
  972. Ipx = (PTDI_ADDRESS_IPX)&p->Address[i].Address[0];
  973. DbgPrint("Network 0x%x Socket 0x%x\n",Ipx->NetworkAddress,Ipx->Socket);
  974. for( j=0; j < 6; j++ ) {
  975. DbgPrint("%x:",Ipx->NodeAddress[j]);
  976. }
  977. DbgPrint("\n\n");
  978. }
  979. }
  980. #endif
  981. NTSTATUS
  982. _IPXGetAdapterNumber(
  983. int Lana,
  984. int * AdpNum
  985. )
  986. /*++
  987. Routine Description:
  988. Get the IPX Lan Adapter number using the instation Lana ID index
  989. Arguments:
  990. Lana - IN the winstation Lana ID index
  991. AdpNum - OUT the IPX Lana Adapter num
  992. Return Value:
  993. return nt status
  994. --*/
  995. {
  996. NTSTATUS Status;
  997. int AdapterNum;
  998. UNICODE_STRING RouteString;
  999. UNICODE_STRING NameString;
  1000. HANDLE KeyHandle = NULL;
  1001. PWSTR RouteStr, Str;
  1002. unsigned RouteLen, Len;
  1003. /*
  1004. * Convert winstation Lana_ID to Network Adapter number
  1005. */
  1006. RtlInitUnicodeString( &RouteString , NULL );
  1007. GetGUID( &RouteString , Lana );
  1008. RouteLen = RouteString.Length;
  1009. RouteStr = RouteString.Buffer;
  1010. AdapterNum =0;
  1011. #if DBG
  1012. KdPrint( ( "TDIPX: _TcpGetTransportAddress Length = %d GUID = %ws\n" , RouteLen, RouteStr ) );
  1013. #endif
  1014. if (RouteLen < (2 * sizeof(UNICODE_NULL))) {
  1015. return( STATUS_DEVICE_DOES_NOT_EXIST );
  1016. }
  1017. RtlInitUnicodeString( &NameString, REG_IPX_Linkage );
  1018. Status = _OpenRegKey( &KeyHandle, REG_IPX_Linkage );
  1019. if ( !NT_SUCCESS( Status ) )
  1020. return Status;
  1021. NameString.Length = 0;
  1022. NameString.MaximumLength = 0;
  1023. NameString.Buffer = NULL;
  1024. Status = _GetRegMultiSZValue( KeyHandle, L"Route", &NameString );
  1025. ZwClose( KeyHandle );
  1026. if ( !NT_SUCCESS( Status ) )
  1027. return Status;
  1028. if (NameString.Length < (2 * sizeof(WCHAR))) {
  1029. return(STATUS_DEVICE_DOES_NOT_EXIST);
  1030. }
  1031. Len = NameString.Length;
  1032. Str = NameString.Buffer;
  1033. Status = STATUS_DEVICE_DOES_NOT_EXIST;
  1034. AdapterNum = 0;
  1035. for (;;) {
  1036. // Check current string to see if it's a GUID (it must start with an
  1037. // open brace after initial double-quote).
  1038. if (Str[1] == L'{') {
  1039. KdPrint( ( "TDIPX: _TcpGetTransportAddress, Str: %ws\n", &Str[1]));
  1040. if ( wcsncmp( (PWSTR) &Str[1],RouteStr, wcslen(&Str[1])-2) == 0) {
  1041. KdPrint( ( "TDIPX: _TcpGetTransportAddress, adapter number %i \n\n",AdapterNum) );
  1042. Status = STATUS_SUCCESS;
  1043. break;
  1044. }
  1045. else {
  1046. KdPrint( ( "TDIPX: _TcpGetTransportAddress, No this lana Adapter = %i\n",AdapterNum ) );// KdPrint( ( "TDIPX: _TcpGetTransportAddress, No this lana Adapter = %i\n",AdapterNum ) );
  1047. AdapterNum ++;
  1048. }
  1049. }
  1050. // Skip through current string past NULL.
  1051. while (Len >= sizeof(WCHAR)) {
  1052. Len -= sizeof(WCHAR);
  1053. if (*Str++ == UNICODE_NULL)
  1054. break;
  1055. }
  1056. // Check for index out of range.
  1057. if (Len < (2 * sizeof(UNICODE_NULL))) {
  1058. break;
  1059. }
  1060. }
  1061. if ( !NT_SUCCESS( Status ) )
  1062. return Status;
  1063. *AdpNum = AdapterNum;
  1064. return STATUS_SUCCESS;
  1065. }