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.

621 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. httptdi.cxx
  5. Abstract:
  6. This module implements the TDI/MUX/SSL component that is common between
  7. ultdi and uctdi
  8. Author:
  9. Rajesh Sundaram (rajeshsu)
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text( PAGE, UxInitializeTdi )
  15. #pragma alloc_text( PAGE, UxTerminateTdi )
  16. #pragma alloc_text( PAGE, UxOpenTdiAddressObject )
  17. #pragma alloc_text( PAGE, UxOpenTdiConnectionObject )
  18. #pragma alloc_text( PAGE, UxpOpenTdiObjectHelper )
  19. #pragma alloc_text( PAGE, UxSetEventHandler )
  20. #endif
  21. #if 0
  22. NOT PAGEABLE - UxCreateDisconnectIrp
  23. NOT PAGEABLE - UxInitializeDisconnectIrp
  24. #endif
  25. //
  26. // Timeout for disconnects. This cannot be a stack-based local,
  27. // so we make it a global.
  28. //
  29. BOOLEAN g_UxTdiInitialized;
  30. UNICODE_STRING g_TransportDeviceName; // global transport device name
  31. LARGE_INTEGER g_TdiDisconnectTimeout;
  32. /***************************************************************************++
  33. Routine Description:
  34. Performs global initialization of this module.
  35. Return Value:
  36. NTSTATUS - Completion status.
  37. --***************************************************************************/
  38. NTSTATUS
  39. UxInitializeTdi(
  40. VOID
  41. )
  42. {
  43. //
  44. // Sanity check.
  45. //
  46. PAGED_CODE();
  47. ASSERT( !g_UxTdiInitialized );
  48. RtlInitUnicodeString(
  49. &g_TransportDeviceName,
  50. TCP_DEVICE_NAME // CODEWORK : Make this configurable ?
  51. );
  52. g_TdiDisconnectTimeout = RtlConvertLongToLargeInteger( -1 );
  53. g_UxTdiInitialized = TRUE;
  54. return STATUS_SUCCESS;
  55. }
  56. /***************************************************************************++
  57. Routine Description:
  58. Performs global termination of this module.
  59. --***************************************************************************/
  60. VOID
  61. UxTerminateTdi(
  62. VOID
  63. )
  64. {
  65. //
  66. // Sanity check.
  67. //
  68. PAGED_CODE();
  69. if (g_UxTdiInitialized)
  70. {
  71. }
  72. } // UxTerminateTdi
  73. /***************************************************************************++
  74. Routine Description:
  75. Opens a TDI address object.
  76. Arguments:
  77. pTransportDeviceName - Supplies the device name of the TDI transport
  78. to open.
  79. pLocalAddress - Supplies the local address to bind to.
  80. LocalAddressLength - Supplies the length of pLocalAddress.
  81. pTdiObject - Receives the file handle, referenced FILE_OBJECT
  82. pointer, and corresponding DEVICE_OBJECT pointer.
  83. Return Value:
  84. NTSTATUS - Completion status.
  85. --***************************************************************************/
  86. NTSTATUS
  87. UxOpenTdiAddressObject(
  88. IN PTRANSPORT_ADDRESS pLocalAddress,
  89. IN ULONG LocalAddressLength,
  90. OUT PUX_TDI_OBJECT pTdiObject
  91. )
  92. {
  93. NTSTATUS status;
  94. PFILE_FULL_EA_INFORMATION pEaInfo;
  95. ULONG eaLength;
  96. UCHAR eaBuffer[MAX_ADDRESS_EA_BUFFER_LENGTH];
  97. //
  98. // Sanity check.
  99. //
  100. PAGED_CODE();
  101. eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  102. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  103. LocalAddressLength;
  104. ASSERT( eaLength <= sizeof(eaBuffer) );
  105. ASSERT( LocalAddressLength == sizeof(TA_IP_ADDRESS) );
  106. ASSERT( pLocalAddress->TAAddressCount == 1 );
  107. ASSERT( pLocalAddress->Address[0].AddressLength == sizeof(TDI_ADDRESS_IP) );
  108. ASSERT( pLocalAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP );
  109. //
  110. // Initialize the EA buffer. See UxpOpenTdiObjectHelper() for the
  111. // gory details.
  112. //
  113. pEaInfo = (PFILE_FULL_EA_INFORMATION)eaBuffer;
  114. pEaInfo->NextEntryOffset = 0;
  115. pEaInfo->Flags = 0;
  116. pEaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  117. pEaInfo->EaValueLength = (USHORT)LocalAddressLength;
  118. RtlMoveMemory(
  119. pEaInfo->EaName,
  120. TdiTransportAddress,
  121. pEaInfo->EaNameLength + 1
  122. );
  123. RtlMoveMemory(
  124. &pEaInfo->EaName[pEaInfo->EaNameLength + 1],
  125. pLocalAddress,
  126. LocalAddressLength
  127. );
  128. //
  129. // Let the helper do the dirty work.
  130. //
  131. status = UxpOpenTdiObjectHelper(
  132. &g_TransportDeviceName,
  133. eaBuffer,
  134. eaLength,
  135. pTdiObject
  136. );
  137. return status;
  138. } // UxpOpenTdiAddressObject
  139. /***************************************************************************++
  140. Routine Description:
  141. Opens a TDI connection object.
  142. Arguments:
  143. pTransportDeviceName - Supplies the device name of the TDI transport
  144. to open.
  145. pConnectionContext - Supplies the context to associate with the
  146. new connection.
  147. pTdiObject - Receives the file handle, referenced FILE_OBJECT
  148. pointer, and corresponding DEVICE_OBJECT pointer.
  149. Return Value:
  150. NTSTATUS - Completion status.
  151. --***************************************************************************/
  152. NTSTATUS
  153. UxOpenTdiConnectionObject(
  154. IN CONNECTION_CONTEXT pConnectionContext,
  155. OUT PUX_TDI_OBJECT pTdiObject
  156. )
  157. {
  158. NTSTATUS status;
  159. PFILE_FULL_EA_INFORMATION pEaInfo;
  160. ULONG eaLength;
  161. UCHAR eaBuffer[MAX_CONNECTION_EA_BUFFER_LENGTH];
  162. //
  163. // Sanity check.
  164. //
  165. PAGED_CODE();
  166. eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  167. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  168. sizeof(pConnectionContext);
  169. ASSERT( eaLength <= sizeof(eaBuffer) );
  170. ASSERT( pConnectionContext != NULL );
  171. //
  172. // Initialize the EA buffer. See UxpOpenTdiObjectHelper() for the
  173. // gory details.
  174. //
  175. pEaInfo = (PFILE_FULL_EA_INFORMATION)eaBuffer;
  176. pEaInfo->NextEntryOffset = 0;
  177. pEaInfo->Flags = 0;
  178. pEaInfo->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  179. pEaInfo->EaValueLength = (USHORT)sizeof(CONNECTION_CONTEXT);
  180. RtlMoveMemory(
  181. pEaInfo->EaName,
  182. TdiConnectionContext,
  183. pEaInfo->EaNameLength + 1
  184. );
  185. RtlMoveMemory(
  186. &pEaInfo->EaName[pEaInfo->EaNameLength + 1],
  187. &pConnectionContext,
  188. sizeof(pConnectionContext)
  189. );
  190. //
  191. // Let the helper do the dirty work.
  192. //
  193. status = UxpOpenTdiObjectHelper(
  194. &g_TransportDeviceName,
  195. eaBuffer,
  196. eaLength,
  197. pTdiObject
  198. );
  199. if (NT_SUCCESS(status))
  200. {
  201. //
  202. // Enable/disable Nagle's Algorithm as appropriate.
  203. //
  204. status = UlpSetNagling( pTdiObject, g_UlEnableNagling );
  205. if (!NT_SUCCESS(status))
  206. {
  207. UxCloseTdiObject( pTdiObject );
  208. }
  209. }
  210. return status;
  211. } // UxpOpenTdiConnectionObject
  212. /***************************************************************************++
  213. Routine Description:
  214. Helper routine for UxpOpenTdiAddressObject and
  215. UxpOpenTdiConnectionObject.
  216. Arguments:
  217. pTransportDeviceName - Supplies the device name of the TDI transport
  218. to open.
  219. pEaBuffer - Supplies a pointer to the EA to use when opening
  220. the object. This buffer consists of a FILE_FULL_EA_INFORMATION
  221. structure, followed by the EA Name, followed by the EA Value.
  222. The EA Name and Value are use as follows:
  223. Address Object:
  224. Ea Name = TdiTransportAddress ("TransportAddress")
  225. Ea Value = The local TRANSPORT_ADDRESS to bind to
  226. Connection Object:
  227. Ea Name = TdiConnectionContext ("ConnectionContext")
  228. Ea Value = The connection context (basically a PVOID)
  229. EaLength - Supplies the length of pEaBuffer.
  230. pTdiObject - Receives the file handle, referenced FILE_OBJECT
  231. pointer, and corresponding DEVICE_OBJECT pointer.
  232. Return Value:
  233. NTSTATUS - Completion status.
  234. --***************************************************************************/
  235. NTSTATUS
  236. UxpOpenTdiObjectHelper(
  237. IN PUNICODE_STRING pTransportDeviceName,
  238. IN PVOID pEaBuffer,
  239. IN ULONG EaLength,
  240. OUT PUX_TDI_OBJECT pTdiObject
  241. )
  242. {
  243. NTSTATUS status;
  244. IO_STATUS_BLOCK ioStatusBlock;
  245. OBJECT_ATTRIBUTES objectAttributes;
  246. //
  247. // Sanity check.
  248. //
  249. PAGED_CODE();
  250. //
  251. // Open the TDI object.
  252. //
  253. InitializeObjectAttributes(
  254. &objectAttributes, // ObjectAttributes
  255. pTransportDeviceName, // ObjectName
  256. OBJ_CASE_INSENSITIVE | // Attributes
  257. UL_KERNEL_HANDLE,
  258. NULL, // RootHandle
  259. NULL // SecurityDescriptor
  260. );
  261. UlAttachToSystemProcess();
  262. status = IoCreateFile(
  263. &pTdiObject->Handle, // FileHandle
  264. GENERIC_READ | // DesiredAccess
  265. GENERIC_WRITE |
  266. SYNCHRONIZE,
  267. &objectAttributes, // ObjectAttributes
  268. &ioStatusBlock, // IoStatusBlock
  269. NULL, // AllocationSize
  270. 0, // FileAttributes
  271. 0, // ShareAccess
  272. 0, // Disposition
  273. 0, // CreateOptions
  274. pEaBuffer, // EaBuffer
  275. EaLength, // EaLength
  276. CreateFileTypeNone, // CreateFileType
  277. NULL, // ExtraCreateParameters
  278. IO_NO_PARAMETER_CHECKING // Options
  279. );
  280. if (NT_SUCCESS(status))
  281. {
  282. //
  283. // Now that we have an open handle to the transport,
  284. // reference it so we can get the file & device object
  285. // pointers.
  286. //
  287. status = ObReferenceObjectByHandle(
  288. pTdiObject->Handle, // Handle
  289. 0, // DesiredAccess
  290. *IoFileObjectType, // ObjectType
  291. KernelMode, // AccessMode
  292. (PVOID *)&pTdiObject->pFileObject, // Object
  293. NULL // HandleInformation
  294. );
  295. if (NT_SUCCESS(status))
  296. {
  297. //
  298. // Chase down the appropriate device object for the file
  299. // object.
  300. //
  301. pTdiObject->pDeviceObject =
  302. IoGetRelatedDeviceObject( pTdiObject->pFileObject );
  303. UlDetachFromSystemProcess();
  304. return status;
  305. }
  306. //
  307. // The ObReferenceObjectByHandle() failed, so close the handle
  308. // we managed to open & fail the call.
  309. //
  310. ZwClose( pTdiObject->Handle );
  311. }
  312. UlDetachFromSystemProcess();
  313. RtlZeroMemory(
  314. pTdiObject,
  315. sizeof(*pTdiObject)
  316. );
  317. return status;
  318. } // UxpOpenTdiObjectHelper
  319. /***************************************************************************++
  320. Routine Description:
  321. Establishes a TDI event handler for the specified endpoint.
  322. Arguments:
  323. pEndpoint - Supplies the endpoint for which to set the event handler.
  324. EventType - Supplies the type of event to set. This should be one
  325. of the TDI_EVENT_* values.
  326. pEventHandler - Supplies a pointer to the indication handler function
  327. to be invoked for the specified event type.
  328. Return Value:
  329. NTSTATUS - Completion status.
  330. --***************************************************************************/
  331. NTSTATUS
  332. UxSetEventHandler(
  333. IN PUX_TDI_OBJECT pUlTdiObject,
  334. IN ULONG EventType,
  335. IN PVOID pEventHandler,
  336. IN PVOID pEventContext
  337. )
  338. {
  339. NTSTATUS status;
  340. TDI_REQUEST_KERNEL_SET_EVENT eventParams;
  341. //
  342. // Sanity check.
  343. //
  344. PAGED_CODE();
  345. //
  346. // Build the parameter block.
  347. //
  348. eventParams.EventType = EventType;
  349. eventParams.EventHandler = pEventHandler;
  350. eventParams.EventContext = pEventContext;
  351. //
  352. // Make the call.
  353. //
  354. status = UlIssueDeviceControl(
  355. pUlTdiObject, // pTdiObject
  356. &eventParams, // pIrpParameters
  357. sizeof(eventParams), // IrpParamtersLength
  358. NULL, // pMdlBuffer
  359. 0, // MdlBufferLength
  360. TDI_SET_EVENT_HANDLER // MinorFunction
  361. );
  362. return status;
  363. } // UxSetEventHandler
  364. /***************************************************************************++
  365. Routine Description:
  366. Allocates & initializes a new disconnect IRP.
  367. Arguments:
  368. pConnection - Supplies the UC_CONNECTION to be disconnected.
  369. Flags - Supplies the TDI_DISCONNECT_* flags for the IRP.
  370. pCompletionRoutine - Supplies the completion routine for the IRP.
  371. pCompletionContext - Supplies an uninterpreted context for the
  372. completion routine.
  373. Return Value:
  374. PIRP - Pointer to the IRP if successful, NULL otherwise.
  375. --***************************************************************************/
  376. PIRP
  377. UxCreateDisconnectIrp(
  378. IN PUX_TDI_OBJECT pTdiObject,
  379. IN ULONG_PTR Flags,
  380. IN PIO_COMPLETION_ROUTINE pCompletionRoutine,
  381. IN PVOID pCompletionContext
  382. )
  383. {
  384. PIRP pIrp;
  385. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  386. //
  387. // Allocate an IRP for the disconnect.
  388. //
  389. pIrp = UlAllocateIrp(
  390. pTdiObject->pDeviceObject->StackSize, // StackSize
  391. FALSE // ChargeQuota
  392. );
  393. if (pIrp != NULL)
  394. {
  395. UxInitializeDisconnectIrp(
  396. pIrp,
  397. pTdiObject,
  398. Flags,
  399. pCompletionRoutine,
  400. pCompletionContext
  401. );
  402. }
  403. return pIrp;
  404. } // UxCreateDisconnectIrp
  405. /***************************************************************************++
  406. Routine Description:
  407. Initializes a disconnect IRP.
  408. Arguments:
  409. pIrp - Supplies the disconnect IRP.
  410. pConnection - Supplies the UC_CONNECTION to be disconnected.
  411. Flags - Supplies the TDI_DISCONNECT_* flags for the IRP.
  412. pCompletionRoutine - Supplies the completion routine for the IRP.
  413. pCompletionContext - Supplies an uninterpreted context for the
  414. completion routine.
  415. Return Value:
  416. None
  417. --***************************************************************************/
  418. VOID
  419. UxInitializeDisconnectIrp(
  420. IN PIRP pIrp,
  421. IN PUX_TDI_OBJECT pTdiObject,
  422. IN ULONG_PTR Flags,
  423. IN PIO_COMPLETION_ROUTINE pCompletionRoutine,
  424. IN PVOID pCompletionContext
  425. )
  426. {
  427. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  428. ASSERT( pIrp != NULL );
  429. //
  430. // Initialize the IRP. Note that IRPs are always zero-initialized
  431. // when allocated. Therefore, we don't need to explicitly set
  432. // the zeroed fields.
  433. //
  434. pIrp->RequestorMode = KernelMode;
  435. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  436. pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  437. TdiBuildDisconnect(
  438. pIrp, // Irp
  439. pTdiObject->pDeviceObject, // DeviceObject
  440. pTdiObject->pFileObject, // FileObject
  441. pCompletionRoutine, // CompletionRoutine
  442. pCompletionContext, // CompletionContext
  443. &g_TdiDisconnectTimeout, // Timeout
  444. Flags, // Flags
  445. NULL, // RequestConnectionInfo
  446. NULL // ReturnConnectionInfo
  447. );
  448. } // UxInitializeDisconnectIrp