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.

1246 lines
38 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. Tdi.c
  5. Abstract:
  6. This module implements Initialization routines
  7. the PGM Transport and other routines that are specific to the
  8. NT implementation of a driver.
  9. Author:
  10. Mohammad Shabbir Alam (MAlam) 3-30-2000
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include <ntddtcp.h> // for IOCTL_TCP_SET_INFORMATION_EX
  15. #include <tcpinfo.h> // for TCPSocketOption
  16. #include <tdiinfo.h> // for TCP_REQUEST_SET_INFORMATION_EX
  17. //******************* Pageable Routine Declarations ****************
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, TdiOpenAddressHandle)
  20. #pragma alloc_text(PAGE, CloseAddressHandles)
  21. #pragma alloc_text(PAGE, PgmTdiOpenControl)
  22. #endif
  23. //******************* Pageable Routine Declarations ****************
  24. //----------------------------------------------------------------------------
  25. NTSTATUS
  26. PgmTdiCompletionRoutine(
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp,
  29. IN PVOID Context
  30. )
  31. /*++
  32. Routine Description:
  33. This routine does not complete the Irp. It is used to signal to a
  34. synchronous part of the NBT driver that it can proceed (i.e.
  35. to allow some code that is waiting on a "KeWaitForSingleObject" to
  36. proceeed.
  37. Arguments:
  38. IN DeviceObject -- unused.
  39. IN Irp -- Supplies Irp that the transport has finished processing.
  40. IN Context -- Supplies the event associated with the Irp.
  41. Return Value:
  42. The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
  43. processing Irp stack locations at this point.
  44. --*/
  45. {
  46. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmTdiCompletionRoutine",
  47. "CompletionEvent: pEvent=<%p>, pIrp=<%p>, DeviceObject=<%p>\n", Context, Irp, DeviceObject);
  48. KeSetEvent ((PKEVENT )Context, 0, FALSE);
  49. return STATUS_MORE_PROCESSING_REQUIRED;
  50. }
  51. //----------------------------------------------------------------------------
  52. NTSTATUS
  53. TdiSetEventHandler (
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PFILE_OBJECT FileObject,
  56. IN ULONG EventType,
  57. IN PVOID EventHandler,
  58. IN PVOID Context
  59. )
  60. /*++
  61. Routine Description:
  62. This routine registers an event handler with a TDI transport provider.
  63. Arguments:
  64. IN PDEVICE_OBJECT DeviceObject -- Supplies the device object of the transport provider.
  65. IN PFILE_OBJECT FileObject -- Supplies the address object's file object.
  66. IN ULONG EventType, -- Supplies the type of event.
  67. IN PVOID EventHandler -- Supplies the event handler.
  68. IN PVOID Context -- Supplies the context passed into the event handler when it runs
  69. Return Value:
  70. NTSTATUS - Final status of the set event operation
  71. --*/
  72. {
  73. NTSTATUS Status;
  74. KEVENT Event;
  75. PIRP pIrp;
  76. PAGED_CODE();
  77. if (!(pIrp = IoAllocateIrp (IoGetRelatedDeviceObject (FileObject)->StackSize, FALSE)))
  78. {
  79. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiSetEventHandler",
  80. "INSUFFICIENT_RESOURCES allocating Irp, StackSize=<%d>\n",
  81. IoGetRelatedDeviceObject (FileObject)->StackSize);
  82. return(STATUS_INSUFFICIENT_RESOURCES);
  83. }
  84. TdiBuildSetEventHandler (pIrp, DeviceObject, FileObject,
  85. NULL, NULL,
  86. EventType, EventHandler, Context);
  87. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  88. // set the address of the routine to be executed when the IRP
  89. // finishes. This routine signals the event and allows the code
  90. // below to continue (i.e. KeWaitForSingleObject)
  91. //
  92. IoSetCompletionRoutine (pIrp,
  93. (PIO_COMPLETION_ROUTINE) PgmTdiCompletionRoutine,
  94. (PVOID)&Event,
  95. TRUE, TRUE, TRUE);
  96. Status = IoCallDriver (IoGetRelatedDeviceObject (FileObject), pIrp);
  97. if (Status == STATUS_PENDING)
  98. {
  99. Status = KeWaitForSingleObject ((PVOID)&Event, // Object to wait on.
  100. Executive, // Reason for waiting
  101. KernelMode, // Processor mode
  102. FALSE, // Alertable
  103. NULL); // Timeout
  104. if (NT_SUCCESS(Status))
  105. {
  106. Status = pIrp->IoStatus.Status;
  107. }
  108. }
  109. IoFreeIrp (pIrp);
  110. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiSetEventHandler",
  111. "Status=<%d>, EventType=<%d>, Hanlder=<%x>\n", Status, EventType, EventHandler);
  112. return (Status);
  113. }
  114. //----------------------------------------------------------------------------
  115. NTSTATUS
  116. TdiErrorHandler(
  117. IN PVOID Context,
  118. IN NTSTATUS Status
  119. )
  120. /*++
  121. Routine Description:
  122. This routine is the handler for TDI errors
  123. Arguments:
  124. IN Context -- unused
  125. IN Status -- error status
  126. Return Value:
  127. NTSTATUS - Final status of the set event operation
  128. --*/
  129. {
  130. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiErrorHandler",
  131. "Status=<%x>\n", Status);
  132. return (STATUS_DATA_NOT_ACCEPTED);
  133. }
  134. //----------------------------------------------------------------------------
  135. NTSTATUS
  136. TdiOpenAddressHandle(
  137. IN tPGM_DEVICE *pPgmDevice,
  138. IN PVOID HandlerContext,
  139. IN tIPADDRESS IpAddress,
  140. IN USHORT PortNumber,
  141. OUT HANDLE *pFileHandle,
  142. OUT PFILE_OBJECT *ppFileObject,
  143. OUT PDEVICE_OBJECT *ppDeviceObject
  144. )
  145. /*++
  146. Routine Description:
  147. This routine is called to open an address handle on IP
  148. Arguments:
  149. IN pPgmDevice -- Pgm's Device object context
  150. IN HandlerContext -- pAddress object ptr to be used as context ptr (NULL if don't want to be notified)
  151. IN IpAddress -- local IpAddress on which to open address
  152. IN PortNumber -- IP protocol port
  153. OUT pFileHandle -- FileHandle if we succeeded
  154. OUT ppFileObject -- FileObject if we succeeded
  155. OUT ppDeviceObject -- IP's DeviceObject ptr if we succeeded
  156. Return Value:
  157. NTSTATUS - Final status of the Open Address operation
  158. --*/
  159. {
  160. NTSTATUS status;
  161. ULONG EaBufferSize;
  162. PFILE_FULL_EA_INFORMATION EaBuffer;
  163. PTRANSPORT_ADDRESS pTransAddressEa;
  164. PTRANSPORT_ADDRESS pTransAddr;
  165. TDI_ADDRESS_IP IpAddr;
  166. OBJECT_ATTRIBUTES AddressAttributes;
  167. IO_STATUS_BLOCK IoStatusBlock;
  168. PFILE_OBJECT pFileObject;
  169. HANDLE FileHandle;
  170. PDEVICE_OBJECT pDeviceObject;
  171. KAPC_STATE ApcState;
  172. BOOLEAN fAttached;
  173. ULONG True = TRUE;
  174. PAGED_CODE();
  175. EaBufferSize = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  176. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  177. sizeof(TRANSPORT_ADDRESS) +
  178. sizeof(TDI_ADDRESS_IP);
  179. if (!(EaBuffer = PgmAllocMem (EaBufferSize, PGM_TAG('1'))))
  180. {
  181. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  182. "[1]: INSUFFICIENT_RESOURCES allocating <%d> bytes\n", EaBufferSize);
  183. return (STATUS_INSUFFICIENT_RESOURCES);
  184. }
  185. // allocate Memory for the transport address
  186. //
  187. if (!(pTransAddr = PgmAllocMem (sizeof(TRANSPORT_ADDRESS)+sizeof(TDI_ADDRESS_IP), PGM_TAG('2'))))
  188. {
  189. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  190. "[2]: INSUFFICIENT_RESOURCES allocating <%d> bytes\n",
  191. (sizeof(TRANSPORT_ADDRESS)+sizeof(TDI_ADDRESS_IP)));
  192. PgmFreeMem (EaBuffer);
  193. return (STATUS_INSUFFICIENT_RESOURCES);
  194. }
  195. EaBuffer->NextEntryOffset = 0;
  196. EaBuffer->Flags = 0;
  197. EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  198. EaBuffer->EaValueLength = (USHORT)(sizeof(TRANSPORT_ADDRESS) -1 + sizeof(TDI_ADDRESS_IP));
  199. PgmMoveMemory (EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength+1); // "TransportAddress"
  200. // fill in the IP address and Port number
  201. //
  202. IpAddr.sin_port = htons (PortNumber); // put in network order
  203. IpAddr.in_addr = htonl (IpAddress);
  204. RtlFillMemory ((PVOID)&IpAddr.sin_zero, sizeof(IpAddr.sin_zero), 0); // zero fill the last component
  205. // copy the ip address to the end of the structure
  206. //
  207. PgmMoveMemory (pTransAddr->Address[0].Address, (CONST PVOID)&IpAddr, sizeof(IpAddr));
  208. pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  209. pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  210. pTransAddr->TAAddressCount = 1;
  211. // copy the ip address to the end of the name in the EA structure
  212. pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
  213. PgmMoveMemory ((PVOID)pTransAddressEa,
  214. (CONST PVOID)pTransAddr,
  215. sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
  216. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
  217. InitializeObjectAttributes (&AddressAttributes,
  218. &pPgmDevice->ucBindName,
  219. OBJ_CASE_INSENSITIVE,
  220. NULL,
  221. NULL);
  222. status = ZwCreateFile (&FileHandle,
  223. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  224. &AddressAttributes,
  225. &IoStatusBlock,
  226. NULL,
  227. FILE_ATTRIBUTE_NORMAL,
  228. 0,
  229. FILE_OPEN_IF,
  230. 0,
  231. (PVOID)EaBuffer,
  232. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  233. EaBuffer->EaNameLength + 1 +
  234. EaBuffer->EaValueLength);
  235. PgmFreeMem ((PVOID)pTransAddr);
  236. PgmFreeMem ((PVOID)EaBuffer);
  237. if (NT_SUCCESS (status))
  238. {
  239. status = IoStatusBlock.Status;
  240. }
  241. if (NT_SUCCESS (status))
  242. {
  243. //
  244. // Reference the FileObject to keep device ptr around!
  245. //
  246. status = ObReferenceObjectByHandle (FileHandle, (ULONG)0, 0, KernelMode, (PVOID *)&pFileObject, NULL);
  247. if (!NT_SUCCESS (status))
  248. {
  249. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  250. "FAILed to Reference FileObject: status=<%x>\n", status);
  251. ZwClose (FileHandle);
  252. }
  253. }
  254. else
  255. {
  256. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  257. "FAILed to create handle: status=<%x>, Device:\n\t%wZ\n", status, &pPgmDevice->ucBindName);
  258. }
  259. if (!NT_SUCCESS (status))
  260. {
  261. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
  262. return (status);
  263. }
  264. pDeviceObject = IoGetRelatedDeviceObject (pFileObject);
  265. //
  266. // Now set the Event handlers (only if we have the HandlerContext set)!
  267. //
  268. if (HandlerContext)
  269. {
  270. status = TdiSetEventHandler (pDeviceObject,
  271. pFileObject,
  272. TDI_EVENT_ERROR,
  273. (PVOID) TdiErrorHandler,
  274. HandlerContext);
  275. if (NT_SUCCESS (status))
  276. {
  277. // Datagram Udp Handler
  278. status = TdiSetEventHandler (pDeviceObject,
  279. pFileObject,
  280. TDI_EVENT_RECEIVE_DATAGRAM,
  281. (PVOID) TdiRcvDatagramHandler,
  282. HandlerContext);
  283. if (NT_SUCCESS (status))
  284. {
  285. status = PgmSetTcpInfo (FileHandle,
  286. AO_OPTION_IP_PKTINFO,
  287. &True,
  288. sizeof (True));
  289. if (!NT_SUCCESS (status))
  290. {
  291. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  292. "Setting AO_OPTION_IP_PKTINFO, status=<%x>\n", status);
  293. }
  294. }
  295. else
  296. {
  297. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  298. "FAILed to set TDI_EVENT_RECEIVE_DATAGRAM handler, status=<%x>\n", status);
  299. }
  300. }
  301. else
  302. {
  303. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiOpenAddressHandle",
  304. "FAILed to set TDI_EVENT_ERROR handler, status=<%x>\n", status);
  305. }
  306. }
  307. if (NT_SUCCESS(status))
  308. {
  309. *pFileHandle = FileHandle;
  310. *ppFileObject = pFileObject;
  311. *ppDeviceObject = pDeviceObject;
  312. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiOpenAddressHandle",
  313. "SUCCEEDed, FileHandle=<%x>, pFileObject=<%x>, pDeviceObject=<%x>\n",
  314. FileHandle, pFileObject, pDeviceObject);
  315. }
  316. else
  317. {
  318. //
  319. // FAILed to set Tdi handlers
  320. //
  321. ObDereferenceObject (pFileObject);
  322. ZwClose (FileHandle);
  323. }
  324. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_ADDR_HANDLE);
  325. return (status);
  326. }
  327. //----------------------------------------------------------------------------
  328. NTSTATUS
  329. CloseAddressHandles(
  330. IN HANDLE FileHandle,
  331. IN PFILE_OBJECT pFileObject
  332. )
  333. /*++
  334. Routine Description:
  335. This routine dereferences any FileObjects as necessary and closes the
  336. FileHandle that was opened earlier
  337. Arguments:
  338. IN FileHandle -- FileHandle to be closed
  339. IN pFileObject -- FileObject to be dereferenced
  340. Return Value:
  341. NTSTATUS - Final status of the CloseAddress operation
  342. --*/
  343. {
  344. NTSTATUS status1 = STATUS_SUCCESS, status2 = STATUS_SUCCESS;
  345. KAPC_STATE ApcState;
  346. BOOLEAN fAttached;
  347. PAGED_CODE();
  348. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_CLOSE_ADDRESS_HANDLES);
  349. if (pFileObject)
  350. {
  351. status2 = ObDereferenceObject ((PVOID *) pFileObject);
  352. }
  353. if (FileHandle)
  354. {
  355. status1 = ZwClose (FileHandle);
  356. }
  357. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_CLOSE_ADDRESS_HANDLES);
  358. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "CloseAddressHandles",
  359. "FileHandle=<%x> ==> status=<%x>, pFileObject=<%x> ==> status=<%x>\n",
  360. FileHandle, status2, pFileObject, status1);
  361. return (STATUS_SUCCESS);
  362. }
  363. //----------------------------------------------------------------------------
  364. NTSTATUS
  365. PgmTdiOpenControl(
  366. IN tPGM_DEVICE *pPgmDevice
  367. )
  368. /*++
  369. Routine Description:
  370. This routine opens a Control channel over Raw IP
  371. Arguments:
  372. IN pPgmDevice -- Pgm's Device object context
  373. Return Value:
  374. NTSTATUS - Final status of the operation
  375. --*/
  376. {
  377. NTSTATUS Status;
  378. OBJECT_ATTRIBUTES ObjectAttributes;
  379. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  380. IO_STATUS_BLOCK IoStatusBlock;
  381. KAPC_STATE ApcState;
  382. BOOLEAN fAttached;
  383. PAGED_CODE();
  384. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_OPEN_CONTROL_HANDLE);
  385. InitializeObjectAttributes (&ObjectAttributes,
  386. &pPgmDevice->ucBindName,
  387. 0,
  388. NULL,
  389. NULL);
  390. Status = ZwCreateFile ((PHANDLE) &pPgmDevice->hControl,
  391. GENERIC_READ | GENERIC_WRITE,
  392. &ObjectAttributes, // object attributes.
  393. &IoStatusBlock, // returned status information.
  394. NULL, // block size (unused).
  395. FILE_ATTRIBUTE_NORMAL, // file attributes.
  396. 0,
  397. FILE_CREATE,
  398. 0, // create options.
  399. (PVOID)EaBuffer, // EA buffer.
  400. 0); // Ea length
  401. if (NT_SUCCESS (Status))
  402. {
  403. Status = IoStatusBlock.Status;
  404. }
  405. if (NT_SUCCESS (Status))
  406. {
  407. //
  408. // get a reference to the file object and save it since we can't
  409. // dereference a file handle at DPC level so we do it now and keep
  410. // the ptr around for later.
  411. //
  412. Status = ObReferenceObjectByHandle (pPgmDevice->hControl,
  413. 0L,
  414. NULL,
  415. KernelMode,
  416. (PVOID *) &pPgmDevice->pControlFileObject,
  417. NULL);
  418. if (!NT_SUCCESS(Status))
  419. {
  420. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmTdiOpenControl",
  421. "ObReferenceObjectByHandle FAILed status=<%x>\n", Status);
  422. ZwClose (pPgmDevice->hControl);
  423. }
  424. }
  425. else
  426. {
  427. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmTdiOpenControl",
  428. "Failed to Open the Control file, Status=<%x>\n", Status);
  429. }
  430. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_OPEN_CONTROL_HANDLE);
  431. if (NT_SUCCESS(Status))
  432. {
  433. //
  434. // We Succeeded!
  435. //
  436. pPgmDevice->pControlDeviceObject = IoGetRelatedDeviceObject (pPgmDevice->pControlFileObject);
  437. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmTdiOpenControl",
  438. "Opened Control channel on: %wZ\n", &pPgmDevice->ucBindName);
  439. }
  440. else
  441. {
  442. // set control file object ptr to null so we know that we did not open the control point.
  443. pPgmDevice->hControl = NULL;
  444. pPgmDevice->pControlFileObject = NULL;
  445. }
  446. return (Status);
  447. }
  448. //----------------------------------------------------------------------------
  449. VOID
  450. PgmDereferenceControl(
  451. IN tCONTROL_CONTEXT *pControlContext,
  452. IN ULONG RefContext
  453. )
  454. /*++
  455. Routine Description:
  456. This routine dereferences the control channel oblect over RawIP and
  457. frees the memory if the RefCount drops to 0
  458. Arguments:
  459. IN pControlContext -- Control object context
  460. IN RefContext -- Context for which this control object was referenced earlier
  461. Return Value:
  462. NONE
  463. --*/
  464. {
  465. ASSERT (PGM_VERIFY_HANDLE (pControlContext, PGM_VERIFY_CONTROL));
  466. ASSERT (pControlContext->RefCount); // Check for too many derefs
  467. ASSERT (pControlContext->ReferenceContexts[RefContext]--);
  468. if (--pControlContext->RefCount)
  469. {
  470. return;
  471. }
  472. PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmDereferenceControl",
  473. "pControl=<%x> closed\n", pControlContext);
  474. //
  475. // Just Free the memory
  476. //
  477. PgmFreeMem (pControlContext);
  478. }
  479. //----------------------------------------------------------------------------
  480. NTSTATUS
  481. TdiSendDatagramCompletion(
  482. IN PDEVICE_OBJECT DeviceObject,
  483. IN PIRP pIrp,
  484. IN PVOID pContext
  485. )
  486. /*++
  487. Routine Description:
  488. This routine is called on completion of a DatagramSend
  489. Arguments:
  490. IN PDEVICE_OBJECT DeviceObject -- Supplies the device object of the transport provider.
  491. IN pIrp -- Request
  492. IN PVOID Context -- Supplies the context passed
  493. Return Value:
  494. NTSTATUS - Final status of the completion which will determine
  495. how the IO subsystem processes it subsequently
  496. --*/
  497. {
  498. NTSTATUS status;
  499. tTDI_SEND_CONTEXT *pTdiSendContext = (tTDI_SEND_CONTEXT *) pContext;
  500. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "PgmSendDatagramCompletion",
  501. "status=<%x>, Info=<%d>, pIrp=<%x>\n", pIrp->IoStatus.Status, pIrp->IoStatus.Information, pIrp);
  502. pTdiSendContext->pClientCompletionRoutine (pTdiSendContext->ClientCompletionContext1,
  503. pTdiSendContext->ClientCompletionContext2,
  504. pIrp->IoStatus.Status);
  505. //
  506. // Free the Memory that was allocated for this send
  507. //
  508. ExFreeToNPagedLookasideList (&PgmStaticConfig.TdiLookasideList, pTdiSendContext);
  509. IoFreeMdl (pIrp->MdlAddress);
  510. IoFreeIrp (pIrp);
  511. // return this status to stop the IO subsystem from further processing the
  512. // IRP - i.e. trying to complete it back to the initiating thread! -since
  513. // there is no initiating thread - we are the initiator
  514. return (STATUS_MORE_PROCESSING_REQUIRED);
  515. }
  516. //----------------------------------------------------------------------------
  517. NTSTATUS
  518. TdiSendDatagram(
  519. IN PFILE_OBJECT pTdiFileObject,
  520. IN PDEVICE_OBJECT pTdiDeviceObject,
  521. IN PVOID pBuffer,
  522. IN ULONG BufferLength,
  523. IN pCLIENT_COMPLETION_ROUTINE pClientCompletionRoutine,
  524. IN PVOID ClientCompletionContext1,
  525. IN PVOID ClientCompletionContext2,
  526. IN tIPADDRESS DestIpAddress,
  527. IN USHORT DestPort
  528. )
  529. /*++
  530. Routine Description:
  531. This routine sends a datagram over RawIp
  532. Arguments:
  533. IN pTdiFileObject -- IP's FileObject for this address
  534. IN pTdiDeviceObject -- DeviceObject for this address
  535. IN pBuffer -- Data buffer (Pgm packet)
  536. IN BufferLength -- length of pBuffer
  537. IN pClientCompletionRoutine -- SendCompletion to be called
  538. IN ClientCompletionContext1 -- Context1 for SendCompletion
  539. IN ClientCompletionContext2 -- Context2 for SendCompletion
  540. IN DestIpAddress -- IP address to send datagram to
  541. IN DestPort -- Port to send to
  542. Return Value:
  543. NTSTATUS - STATUS_PENDING on success, and also if SendCompletion was specified
  544. --*/
  545. {
  546. NTSTATUS status;
  547. tTDI_SEND_CONTEXT *pTdiSendContext = NULL;
  548. PIRP pIrp = NULL;
  549. PMDL pMdl = NULL;
  550. //
  551. // Allocate the SendContext, pIrp and pMdl
  552. //
  553. if ((!(pTdiSendContext = ExAllocateFromNPagedLookasideList (&PgmStaticConfig.TdiLookasideList))) ||
  554. (!(pIrp = IoAllocateIrp (pgPgmDevice->pPgmDeviceObject->StackSize, FALSE))) ||
  555. (!(pMdl = IoAllocateMdl (pBuffer, BufferLength, FALSE, FALSE, NULL))))
  556. {
  557. if (pTdiSendContext)
  558. {
  559. ExFreeToNPagedLookasideList (&PgmStaticConfig.TdiLookasideList, pTdiSendContext);
  560. }
  561. if (pIrp)
  562. {
  563. IoFreeIrp (pIrp);
  564. }
  565. PgmLog (PGM_LOG_ERROR, DBG_TDI, "TdiSendDatagram",
  566. "INSUFFICIENT_RESOURCES for TdiSendContext=<%d> bytes\n", sizeof(tTDI_SEND_CONTEXT));
  567. if (pClientCompletionRoutine)
  568. {
  569. pClientCompletionRoutine (ClientCompletionContext1,
  570. ClientCompletionContext2,
  571. STATUS_INSUFFICIENT_RESOURCES);
  572. status = STATUS_PENDING;
  573. }
  574. else
  575. {
  576. status = STATUS_INSUFFICIENT_RESOURCES;
  577. }
  578. return (status);
  579. }
  580. MmBuildMdlForNonPagedPool (pMdl);
  581. pIrp->MdlAddress = pMdl;
  582. // fill in the remote address
  583. pTdiSendContext->TransportAddress.TAAddressCount = 1;
  584. pTdiSendContext->TransportAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  585. pTdiSendContext->TransportAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  586. pTdiSendContext->TransportAddress.Address[0].Address->in_addr = htonl(DestIpAddress);
  587. pTdiSendContext->TransportAddress.Address[0].Address->sin_port = htons(DestPort);
  588. // fill in the connection information
  589. pTdiSendContext->TdiConnectionInfo.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  590. pTdiSendContext->TdiConnectionInfo.RemoteAddress = &pTdiSendContext->TransportAddress;
  591. // Fill in our completion Context information
  592. pTdiSendContext->pClientCompletionRoutine = pClientCompletionRoutine;
  593. pTdiSendContext->ClientCompletionContext1 = ClientCompletionContext1;
  594. pTdiSendContext->ClientCompletionContext2 = ClientCompletionContext2;
  595. // Complete the "send datagram" IRP initialization.
  596. //
  597. TdiBuildSendDatagram (pIrp,
  598. pTdiDeviceObject,
  599. pTdiFileObject,
  600. (PVOID) TdiSendDatagramCompletion,
  601. pTdiSendContext,
  602. pIrp->MdlAddress,
  603. BufferLength,
  604. &pTdiSendContext->TdiConnectionInfo);
  605. //
  606. // Tell the I/O manager to pass our IRP to the transport for
  607. // processing.
  608. //
  609. status = IoCallDriver (pTdiDeviceObject, pIrp);
  610. ASSERT (status == STATUS_PENDING);
  611. PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_TDI, "TdiSendDatagram",
  612. "%s Send to <%x:%x>, status=<%x>\n",
  613. (CLASSD_ADDR(DestIpAddress) ? "MCast" : "Unicast"), DestIpAddress, DestPort, status);
  614. //
  615. // IoCallDriver will always result in completion routien being called
  616. //
  617. return (STATUS_PENDING);
  618. }
  619. //----------------------------------------------------------------------------
  620. NTSTATUS
  621. PgmSetTcpInfo(
  622. IN HANDLE FileHandle,
  623. IN ULONG ToiId,
  624. IN PVOID pData,
  625. IN ULONG DataLength
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is called to set IP-specific options
  630. Arguments:
  631. IN FileHandle -- FileHandle over IP for which to set option
  632. IN ToId -- Option Id
  633. IN pData -- Option data
  634. IN DataLength -- pData length
  635. Return Value:
  636. NTSTATUS - Final status of the set option operation
  637. --*/
  638. {
  639. NTSTATUS Status, LocStatus;
  640. ULONG BufferLength;
  641. TCP_REQUEST_SET_INFORMATION_EX *pTcpInfo;
  642. IO_STATUS_BLOCK IoStatus;
  643. HANDLE event;
  644. KAPC_STATE ApcState;
  645. BOOLEAN fAttached;
  646. IoStatus.Status = STATUS_SUCCESS;
  647. BufferLength = sizeof (TCP_REQUEST_SET_INFORMATION_EX) + DataLength;
  648. if (!(pTcpInfo = (TCP_REQUEST_SET_INFORMATION_EX *) PgmAllocMem (BufferLength, PGM_TAG('2'))))
  649. {
  650. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
  651. "INSUFFICIENT_RESOURCES for pTcpInfo=<%d+%d> bytes\n",
  652. sizeof(TCP_REQUEST_SET_INFORMATION_EX), DataLength);
  653. return (STATUS_INSUFFICIENT_RESOURCES);
  654. }
  655. PgmZeroMemory (pTcpInfo, BufferLength);
  656. pTcpInfo->ID.toi_entity.tei_entity = CL_TL_ENTITY;
  657. pTcpInfo->ID.toi_entity.tei_instance= TL_INSTANCE;
  658. pTcpInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
  659. pTcpInfo->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
  660. //
  661. // Set the Configured values
  662. //
  663. pTcpInfo->ID.toi_id = ToiId;
  664. pTcpInfo->BufferSize = DataLength;
  665. PgmCopyMemory (&pTcpInfo->Buffer[0], pData, DataLength);
  666. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
  667. Status = ZwCreateEvent (&event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
  668. if (NT_SUCCESS(Status))
  669. {
  670. //
  671. // Make the actual TDI call
  672. //
  673. Status = ZwDeviceIoControlFile (FileHandle,
  674. event,
  675. NULL,
  676. NULL,
  677. &IoStatus,
  678. IOCTL_TCP_SET_INFORMATION_EX,
  679. pTcpInfo,
  680. BufferLength,
  681. NULL,
  682. 0);
  683. //
  684. // If the call pended and we were supposed to wait for completion,
  685. // then wait.
  686. //
  687. if (Status == STATUS_PENDING)
  688. {
  689. Status = NtWaitForSingleObject (event, FALSE, NULL);
  690. ASSERT (NT_SUCCESS(Status));
  691. }
  692. if (NT_SUCCESS (Status))
  693. {
  694. Status = IoStatus.Status;
  695. if (!NT_SUCCESS (Status))
  696. {
  697. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
  698. "TcpSetInfoEx request returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
  699. }
  700. }
  701. else
  702. {
  703. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
  704. "ZwDeviceIoControlFile returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
  705. }
  706. LocStatus = ZwClose (event);
  707. ASSERT (NT_SUCCESS(LocStatus));
  708. }
  709. else
  710. {
  711. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmSetTcpInfo",
  712. "ZwCreateEvent returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
  713. }
  714. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
  715. if (STATUS_SUCCESS == Status)
  716. {
  717. PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmSetTcpInfo",
  718. "ToiId=<%x>, DataLength=<%d>\n", ToiId, DataLength);
  719. }
  720. else
  721. {
  722. Status = STATUS_UNSUCCESSFUL; // Once, we received a wierd status!
  723. }
  724. PgmFreeMem (pTcpInfo);
  725. return (Status);
  726. }
  727. //----------------------------------------------------------------------------
  728. NTSTATUS
  729. PgmQueryTcpInfo(
  730. IN HANDLE FileHandle,
  731. IN ULONG ToiId,
  732. IN PVOID pDataIn,
  733. IN ULONG DataInLength,
  734. IN PVOID pDataOut,
  735. IN ULONG DataOutLength
  736. )
  737. /*++
  738. Routine Description:
  739. This routine queries IP for transport-specific information
  740. Arguments:
  741. IN FileHandle -- FileHandle over IP for which to set option
  742. IN ToId -- Option Id
  743. IN pDataIn -- Option data
  744. IN DataInLength -- pDataIn length
  745. IN pDataOut -- Buffer for output data
  746. IN DataOutLength -- pDataOut length
  747. Return Value:
  748. NTSTATUS - Final status of the Query operation
  749. --*/
  750. {
  751. NTSTATUS Status, LocStatus;
  752. TCP_REQUEST_QUERY_INFORMATION_EX QueryRequest;
  753. IO_STATUS_BLOCK IoStatus;
  754. HANDLE event;
  755. KAPC_STATE ApcState;
  756. BOOLEAN fAttached;
  757. IoStatus.Status = STATUS_SUCCESS;
  758. PgmZeroMemory (&QueryRequest, sizeof (TCP_REQUEST_QUERY_INFORMATION_EX));
  759. QueryRequest.ID.toi_entity.tei_entity = CL_NL_ENTITY;
  760. QueryRequest.ID.toi_entity.tei_instance = 0;
  761. QueryRequest.ID.toi_class = INFO_CLASS_PROTOCOL;
  762. QueryRequest.ID.toi_type = INFO_TYPE_PROVIDER;
  763. //
  764. // Set the Configured values
  765. //
  766. QueryRequest.ID.toi_id = ToiId;
  767. PgmCopyMemory (&QueryRequest.Context, pDataIn, DataInLength);
  768. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
  769. Status = ZwCreateEvent (&event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
  770. if (NT_SUCCESS(Status))
  771. {
  772. //
  773. // Make the actual TDI call
  774. //
  775. Status = ZwDeviceIoControlFile (FileHandle,
  776. event,
  777. NULL,
  778. NULL,
  779. &IoStatus,
  780. IOCTL_TCP_QUERY_INFORMATION_EX,
  781. &QueryRequest,
  782. sizeof (TCP_REQUEST_QUERY_INFORMATION_EX),
  783. pDataOut,
  784. DataOutLength);
  785. //
  786. // If the call pended and we were supposed to wait for completion,
  787. // then wait.
  788. //
  789. if (Status == STATUS_PENDING)
  790. {
  791. Status = NtWaitForSingleObject (event, FALSE, NULL);
  792. ASSERT (NT_SUCCESS(Status));
  793. }
  794. if (NT_SUCCESS (Status))
  795. {
  796. Status = IoStatus.Status;
  797. if (!NT_SUCCESS (Status))
  798. {
  799. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
  800. "TcpQueryInfoEx request returned Status = <%x>, Id=<0x%x>, DataOutLength=<%d>\n",
  801. Status, ToiId, DataOutLength);
  802. }
  803. }
  804. else
  805. {
  806. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
  807. "ZwDeviceIoControlFile returned Status = <%x>, Id=<0x%x>, DataOutLength=<%d>\n",
  808. Status, ToiId, DataOutLength);
  809. }
  810. LocStatus = ZwClose (event);
  811. ASSERT (NT_SUCCESS(LocStatus));
  812. }
  813. else
  814. {
  815. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmQueryTcpInfo",
  816. "ZwCreateEvent returned Status = <%x>, Id=<0x%x>\n", Status, ToiId);
  817. }
  818. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_SET_TCP_INFO);
  819. if (NT_SUCCESS(Status))
  820. {
  821. PgmLog (PGM_LOG_INFORM_STATUS, DBG_TDI, "PgmQueryTcpInfo",
  822. "ToiId=<%x>, DataInLength=<%d>, DataOutLength=<%d>\n",
  823. ToiId, DataInLength, DataOutLength);
  824. }
  825. else
  826. {
  827. Status = STATUS_UNSUCCESSFUL; // Once, we received a wierd status!
  828. }
  829. return (Status);
  830. }
  831. //----------------------------------------------------------------------------
  832. NTSTATUS
  833. PgmProcessIPRequest(
  834. IN ULONG IOControlCode,
  835. IN PVOID pInBuffer,
  836. IN ULONG InBufferLen,
  837. OUT PVOID *pOutBuffer,
  838. IN OUT ULONG *pOutBufferLen
  839. )
  840. /*++
  841. Routine Description:
  842. This routine performs IOCTL queries into IP
  843. Arguments:
  844. IOControlCode - Ioctl to be made into IP
  845. pInBuffer - Buffer containing data to be passed into IP
  846. InBufferLen - Length of Input Buffer data
  847. pOutBuffer - Returned information
  848. pOutBufferLen - Initial expected length of Output Buffer + final length
  849. Return Value:
  850. NTSTATUS - Final status of the operation
  851. --*/
  852. {
  853. NTSTATUS Status;
  854. HANDLE hIP;
  855. OBJECT_ATTRIBUTES ObjectAttributes;
  856. UNICODE_STRING ucDeviceName;
  857. IO_STATUS_BLOCK IoStatusBlock;
  858. ULONG OutBufferLen = 0;
  859. KAPC_STATE ApcState;
  860. BOOLEAN fAttached;
  861. HANDLE Event = NULL;
  862. UCHAR *pIPInfo = NULL;
  863. PWSTR pNameIP = L"\\Device\\IP";
  864. PAGED_CODE();
  865. ucDeviceName.Buffer = pNameIP;
  866. ucDeviceName.Length = (USHORT) (sizeof (WCHAR) * wcslen (pNameIP));
  867. ucDeviceName.MaximumLength = ucDeviceName.Length + sizeof (WCHAR);
  868. if (pOutBuffer)
  869. {
  870. ASSERT (pOutBufferLen);
  871. OutBufferLen = *pOutBufferLen; // Save the initial buffer length
  872. *pOutBuffer = NULL;
  873. *pOutBufferLen = 0; // Initialize the return parameter in case we fail below
  874. if (!OutBufferLen ||
  875. !(pIPInfo = PgmAllocMem (OutBufferLen, PGM_TAG('I'))))
  876. {
  877. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
  878. "STATUS_INSUFFICIENT_RESOURCES\n");
  879. return (STATUS_INSUFFICIENT_RESOURCES);
  880. }
  881. }
  882. InitializeObjectAttributes (&ObjectAttributes,
  883. &ucDeviceName,
  884. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  885. NULL,
  886. NULL);
  887. PgmAttachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
  888. Status = ZwCreateFile (&hIP,
  889. SYNCHRONIZE | GENERIC_READ,
  890. &ObjectAttributes,
  891. &IoStatusBlock,
  892. NULL,
  893. FILE_ATTRIBUTE_NORMAL,
  894. 0,
  895. FILE_OPEN,
  896. 0,
  897. NULL,
  898. 0);
  899. //
  900. // If we succeeded above, let us also try to create the Event handle
  901. //
  902. if ((NT_SUCCESS (Status)) &&
  903. (!NT_SUCCESS (Status = ZwCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))))
  904. {
  905. ZwClose (hIP);
  906. }
  907. if (!NT_SUCCESS (Status))
  908. {
  909. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
  910. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
  911. "status=<%x> -- ZwCreate\n", Status);
  912. if (pIPInfo)
  913. {
  914. PgmFreeMem (pIPInfo);
  915. }
  916. return (Status);
  917. }
  918. //
  919. // At this point, we have succeeded in creating the hIP and Event handles,
  920. // and possibly also the output buffer memory (pIPInfo)
  921. //
  922. do
  923. {
  924. Status = ZwDeviceIoControlFile(hIP, // g_hIPDriverHandle
  925. Event,
  926. NULL,
  927. NULL,
  928. &IoStatusBlock,
  929. IOControlCode, // Ioctl
  930. pInBuffer,
  931. InBufferLen,
  932. pIPInfo,
  933. OutBufferLen);
  934. if (Status == STATUS_PENDING)
  935. {
  936. Status = NtWaitForSingleObject (Event, FALSE, NULL);
  937. ASSERT(Status == STATUS_SUCCESS);
  938. }
  939. Status = IoStatusBlock.Status;
  940. if (Status == STATUS_BUFFER_OVERFLOW)
  941. {
  942. if (!OutBufferLen)
  943. {
  944. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
  945. "IOControlCode=<%x> => overflow when no data expected\n", IOControlCode);
  946. Status = STATUS_UNSUCCESSFUL;
  947. break;
  948. }
  949. PgmFreeMem (pIPInfo);
  950. OutBufferLen *=2;
  951. if (NULL == (pIPInfo = PgmAllocMem (OutBufferLen, PGM_TAG('I'))))
  952. {
  953. Status = STATUS_INSUFFICIENT_RESOURCES;
  954. }
  955. }
  956. else if (NT_SUCCESS(Status))
  957. {
  958. PgmLog (PGM_LOG_INFORM_PATH, DBG_TDI, "PgmProcessIPRequest",
  959. "Success, Ioctl=<%x>\n", IOControlCode);
  960. }
  961. else
  962. {
  963. PgmLog (PGM_LOG_ERROR, DBG_TDI, "PgmProcessIPRequest",
  964. "IOCTL=<%x> returned Status=<%x>\n", IOControlCode, Status);
  965. }
  966. } while (Status == STATUS_BUFFER_OVERFLOW);
  967. ZwClose (Event);
  968. ZwClose (hIP);
  969. PgmDetachFsp (&ApcState, &fAttached, REF_FSP_PROCESS_IP_REQUEST);
  970. if (NT_SUCCESS(Status))
  971. {
  972. if ((pOutBuffer) && (pOutBufferLen))
  973. {
  974. *pOutBuffer = pIPInfo;
  975. *pOutBufferLen = OutBufferLen;
  976. }
  977. else if (pIPInfo)
  978. {
  979. PgmFreeMem (pIPInfo);
  980. }
  981. }
  982. else
  983. {
  984. if (pIPInfo)
  985. {
  986. PgmFreeMem (pIPInfo);
  987. }
  988. }
  989. return (Status);
  990. }