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.

1441 lines
35 KiB

  1. /*++
  2. Copyright (c) 1998 Micros oft Corporation
  3. Module Name:
  4. spudp.c
  5. Abstract:
  6. Routines for handling sending and receiving datagram packets to a BINL server.
  7. Author:
  8. Sean Selitrennikoff (v-seasel) 22-Jun-1998
  9. Revision History:
  10. Notes:
  11. --*/
  12. #include "spprecmp.h"
  13. #pragma hdrstop
  14. #include "spcmdcon.h"
  15. #include <tdi.h>
  16. #include <tdikrnl.h>
  17. #include <remboot.h>
  18. #include <oscpkt.h>
  19. //
  20. // Useful definitions
  21. //
  22. #define NULL_IP_ADDR 0
  23. #define htons( a ) ((((a) & 0xFF00) >> 8) |\
  24. (((a) & 0x00FF) << 8))
  25. //
  26. // Type definitions
  27. //
  28. typedef struct _SPUDP_FSCONTEXT {
  29. LIST_ENTRY Linkage;
  30. PFILE_OBJECT FileObject;
  31. LONG ReferenceCount;
  32. UCHAR CancelIrps;
  33. UCHAR Pad[3];
  34. } SPUDP_FSCONTEXT, *PSPUDP_FSCONTEXT;
  35. typedef enum {
  36. SpUdpNetworkDisconnected,
  37. SpUdpNetworkDisconnecting,
  38. SpUdpNetworkConnecting,
  39. SpUdpNetworkConnected
  40. } SPUDP_NETWORK_STATE;
  41. typedef struct _SPUDP_RECEIVE_ENTRY {
  42. LIST_ENTRY ListEntry;
  43. ULONG DataBufferLength;
  44. PVOID DataBuffer;
  45. } SPUDP_RECEIVE_ENTRY, *PSPUDP_RECEIVE_ENTRY;
  46. //
  47. // Globals
  48. //
  49. SPUDP_NETWORK_STATE SpUdpNetworkState = SpUdpNetworkDisconnected;
  50. ULONG SpUdpActiveRefCount = 0;
  51. HANDLE SpUdpDatagramHandle;
  52. PFILE_OBJECT SpUdpDatagramFileObject;
  53. PDEVICE_OBJECT SpUdpDatagramDeviceObject;
  54. KSPIN_LOCK SpUdpLock;
  55. KIRQL SpUdpOldIrql;
  56. LIST_ENTRY SpUdpReceiveList;
  57. ULONG SpUdpNumReceivePackets = 0;
  58. ULONG SpUdpSendSequenceNumber = 1;
  59. //
  60. // Function definitions
  61. //
  62. NTSTATUS
  63. SpUdpRestartDeviceControl (
  64. IN PDEVICE_OBJECT DeviceObject,
  65. IN PIRP Irp,
  66. IN PVOID Context
  67. );
  68. NTSTATUS
  69. SpUdpTdiErrorHandler(
  70. IN PVOID TdiEventContext,
  71. IN NTSTATUS Status
  72. );
  73. NTSTATUS
  74. SpUdpTdiSetEventHandler(
  75. IN PFILE_OBJECT FileObject,
  76. IN PDEVICE_OBJECT DeviceObject,
  77. IN ULONG EventType,
  78. IN PVOID EventHandler,
  79. IN PVOID EventContext
  80. );
  81. NTSTATUS
  82. SpUdpIssueDeviceControl (
  83. IN PFILE_OBJECT FileObject,
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN PVOID IrpParameters,
  86. IN ULONG IrpParametersLength,
  87. IN PVOID MdlBuffer,
  88. IN ULONG MdlBufferLength,
  89. IN UCHAR MinorFunction
  90. );
  91. NTSTATUS
  92. SpUdpTdiReceiveDatagramHandler(
  93. IN PVOID TdiEventContext,
  94. IN LONG SourceAddressLength,
  95. IN PVOID SourceAddress,
  96. IN LONG OptionsLength,
  97. IN PVOID Options,
  98. IN ULONG ReceiveDatagramFlags,
  99. IN ULONG BytesIndicated,
  100. IN ULONG BytesAvailable,
  101. OUT PULONG BytesTaken,
  102. IN PVOID Tsdu,
  103. OUT PIRP * Irp
  104. );
  105. NTSTATUS
  106. SpUdpReceivePacketHandler(
  107. IN ULONG TdiReceiveDatagramFlags,
  108. IN ULONG BytesIndicated,
  109. IN ULONG BytesAvailable,
  110. OUT PULONG BytesTaken,
  111. IN PVOID Tsdu,
  112. OUT PIRP * Irp
  113. );
  114. NTSTATUS
  115. SpUdpCompleteReceivePacket(
  116. IN PDEVICE_OBJECT DeviceObject,
  117. IN PIRP Irp,
  118. IN PVOID Context
  119. );
  120. VOID
  121. SpUdpProcessReceivePacket(
  122. IN ULONG TsduSize,
  123. IN PVOID Tsdu
  124. );
  125. NTSTATUS
  126. SpUdpSendDatagram(
  127. IN PVOID SendBuffer,
  128. IN ULONG SendBufferLength,
  129. IN ULONG RemoteHostAddress,
  130. IN USHORT RemoteHostPort
  131. );
  132. NTSTATUS
  133. SpUdpCompleteSendDatagram(
  134. IN PDEVICE_OBJECT DeviceObject,
  135. IN PIRP Irp,
  136. IN PVOID Context
  137. );
  138. VOID
  139. SpUdpDereferenceFsContext(
  140. PSPUDP_FSCONTEXT FsContext
  141. )
  142. {
  143. LONG newValue = InterlockedDecrement(&(FsContext->ReferenceCount));
  144. ASSERT(newValue >= 0);
  145. if (newValue != 0) {
  146. return;
  147. }
  148. return;
  149. } // SpUdpDereferenceFsContext
  150. NTSTATUS
  151. SpUdpMarkRequestPending(
  152. PIRP Irp,
  153. PIO_STACK_LOCATION IrpSp,
  154. PDRIVER_CANCEL CancelRoutine
  155. )
  156. /*++
  157. Notes:
  158. Called with IoCancelSpinLock held.
  159. --*/
  160. {
  161. PSPUDP_FSCONTEXT fsContext = (PSPUDP_FSCONTEXT) IrpSp->FileObject->FsContext;
  162. KIRQL oldIrql;
  163. //
  164. // Set up for cancellation
  165. //
  166. ASSERT(Irp->CancelRoutine == NULL);
  167. if (!Irp->Cancel) {
  168. IoMarkIrpPending(Irp);
  169. IoSetCancelRoutine(Irp, CancelRoutine);
  170. InterlockedIncrement(&(fsContext->ReferenceCount));
  171. return(STATUS_SUCCESS);
  172. }
  173. //
  174. // The IRP has already been cancelled.
  175. //
  176. return(STATUS_CANCELLED);
  177. } // SpUdpMarkRequestPending
  178. VOID
  179. SpUdpCompletePendingRequest(
  180. IN PIRP Irp,
  181. IN NTSTATUS Status,
  182. IN ULONG BytesReturned
  183. )
  184. /*++
  185. Routine Description:
  186. Completes a pending request.
  187. Arguments:
  188. Irp - A pointer to the IRP for this request.
  189. Status - The final status of the request.
  190. BytesReturned - Bytes sent/received information.
  191. Return Value:
  192. None.
  193. Notes:
  194. Called with IoCancelSpinLock held. Lock Irql is stored in Irp->CancelIrql.
  195. Releases IoCancelSpinLock before returning.
  196. --*/
  197. {
  198. PIO_STACK_LOCATION irpSp;
  199. PSPUDP_FSCONTEXT fsContext;
  200. irpSp = IoGetCurrentIrpStackLocation(Irp);
  201. fsContext = (PSPUDP_FSCONTEXT) irpSp->FileObject->FsContext;
  202. IoSetCancelRoutine(Irp, NULL);
  203. SpUdpDereferenceFsContext(fsContext);
  204. if (Irp->Cancel || fsContext->CancelIrps) {
  205. Status = (unsigned int) STATUS_CANCELLED;
  206. BytesReturned = 0;
  207. }
  208. IoReleaseCancelSpinLock(Irp->CancelIrql);
  209. Irp->IoStatus.Status = (NTSTATUS) Status;
  210. Irp->IoStatus.Information = BytesReturned;
  211. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  212. return;
  213. } // SpUdpCompletePendingRequest
  214. PFILE_OBJECT
  215. SpUdpBeginCancelRoutine(
  216. IN PIRP Irp
  217. )
  218. /*++
  219. Routine Description:
  220. Performs common bookkeeping for irp cancellation.
  221. Arguments:
  222. Irp - Pointer to I/O request packet
  223. Return Value:
  224. A pointer to the file object on which the irp was submitted.
  225. This value must be passed to SpUdpEndCancelRequest().
  226. Notes:
  227. Called with cancel spinlock held.
  228. --*/
  229. {
  230. PIO_STACK_LOCATION irpSp;
  231. PSPUDP_FSCONTEXT fsContext;
  232. NTSTATUS status = STATUS_SUCCESS;
  233. PFILE_OBJECT fileObject;
  234. ASSERT(Irp->Cancel);
  235. irpSp = IoGetCurrentIrpStackLocation(Irp);
  236. fileObject = irpSp->FileObject;
  237. fsContext = (PSPUDP_FSCONTEXT) fileObject->FsContext;
  238. IoSetCancelRoutine(Irp, NULL);
  239. //
  240. // Add a reference so the object can't be closed while the cancel routine
  241. // is executing.
  242. //
  243. InterlockedIncrement(&(fsContext->ReferenceCount));
  244. return(fileObject);
  245. } // SpUdpBeginCancelRoutine
  246. VOID
  247. SpUdpEndCancelRoutine(
  248. PFILE_OBJECT FileObject
  249. )
  250. /*++
  251. Routine Description:
  252. Performs common bookkeeping for irp cancellation.
  253. Arguments:
  254. Return Value:
  255. Notes:
  256. Called with cancel spinlock held.
  257. --*/
  258. {
  259. PSPUDP_FSCONTEXT fsContext = (PSPUDP_FSCONTEXT) FileObject->FsContext;
  260. //
  261. // Remove the reference placed on the endpoint by the cancel routine.
  262. //
  263. SpUdpDereferenceFsContext(fsContext);
  264. return;
  265. } // SpUdpEndCancelRoutine
  266. NTSTATUS
  267. SpUdpConnect(
  268. VOID
  269. )
  270. {
  271. NTSTATUS status;
  272. OBJECT_ATTRIBUTES objectAttributes;
  273. IO_STATUS_BLOCK iosb;
  274. PFILE_FULL_EA_INFORMATION ea = NULL;
  275. ULONG eaBufferLength;
  276. HANDLE addressHandle = NULL;
  277. PFILE_OBJECT addressFileObject = NULL;
  278. PDEVICE_OBJECT addressDeviceObject = NULL;
  279. BOOLEAN attached = FALSE;
  280. UNICODE_STRING unicodeString;
  281. TDI_REQUEST_KERNEL_QUERY_INFORMATION queryInfo;
  282. PTDI_ADDRESS_INFO addressInfo;
  283. TDI_PROVIDER_INFO providerInfo;
  284. PWCHAR TdiProviderName;
  285. ULONG TdiProviderNameLength;
  286. PTRANSPORT_ADDRESS TransportAddress;
  287. PTDI_ADDRESS_IP TdiAddressIp;
  288. TdiProviderName = L"\\Device\\Udp";
  289. TdiProviderNameLength = (wcslen(TdiProviderName) + 1) * sizeof(WCHAR);
  290. InitializeListHead(&SpUdpReceiveList);
  291. //
  292. // Allocate memory to hold the EA buffer we'll use to specify the
  293. // transport address to NtCreateFile.
  294. //
  295. eaBufferLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  296. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  297. sizeof(TA_IP_ADDRESS);
  298. ea = SpMemAlloc(eaBufferLength);
  299. if (ea == NULL) {
  300. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: memory allocation of %u bytes failed.\n", eaBufferLength));
  301. return(STATUS_INSUFFICIENT_RESOURCES);
  302. }
  303. //
  304. // Initialize the EA using the network's transport information.
  305. //
  306. ea->NextEntryOffset = 0;
  307. ea->Flags = 0;
  308. ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  309. ea->EaValueLength = (USHORT)sizeof(TA_IP_ADDRESS);
  310. RtlMoveMemory(
  311. ea->EaName,
  312. TdiTransportAddress,
  313. ea->EaNameLength + 1
  314. );
  315. TransportAddress = (PTRANSPORT_ADDRESS)(&(ea->EaName[ea->EaNameLength + 1]));
  316. TransportAddress->TAAddressCount = 1;
  317. TransportAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  318. TransportAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  319. TdiAddressIp = (PTDI_ADDRESS_IP)(&(TransportAddress->Address[0].Address[0]));
  320. TdiAddressIp->sin_port= 0; // Means that you want a port assigned
  321. TdiAddressIp->in_addr= NULL_IP_ADDR;
  322. RtlZeroMemory(TdiAddressIp->sin_zero, sizeof(TdiAddressIp->sin_zero));
  323. RtlInitUnicodeString(&unicodeString, TdiProviderName);
  324. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  325. if (SpUdpNetworkState != SpUdpNetworkDisconnected) {
  326. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  327. SpMemFree(ea);
  328. return((SpUdpNetworkState == SpUdpNetworkConnected) ? STATUS_SUCCESS : STATUS_PENDING);
  329. }
  330. ASSERT(SpUdpDatagramHandle == NULL);
  331. ASSERT(SpUdpDatagramFileObject == NULL);
  332. ASSERT(SpUdpDatagramDeviceObject == NULL);
  333. ASSERT(SpUdpActiveRefCount == 0);
  334. //
  335. // Set the initial active refcount to 2. One reference will be removed
  336. // when the network is successfully brought online. The other will be
  337. // removed when the network is to be taken offline. Also increment the
  338. // base refcount to account for the active refcount. Change to
  339. // the online pending state.
  340. //
  341. SpUdpActiveRefCount = 2;
  342. SpUdpNetworkState = SpUdpNetworkConnecting;
  343. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  344. //
  345. // Prepare for opening the address object.
  346. //
  347. InitializeObjectAttributes(
  348. &objectAttributes,
  349. &unicodeString,
  350. OBJ_CASE_INSENSITIVE, // attributes
  351. NULL,
  352. NULL
  353. );
  354. //
  355. // Perform the actual open of the address object.
  356. //
  357. status = ZwCreateFile(
  358. &addressHandle,
  359. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  360. &objectAttributes,
  361. &iosb, // returned status information.
  362. 0, // block size (unused).
  363. 0, // file attributes.
  364. 0, // not shareable
  365. FILE_CREATE, // create disposition.
  366. 0, // create options.
  367. ea,
  368. eaBufferLength
  369. );
  370. SpMemFree(ea);
  371. ea = NULL;
  372. if (status != STATUS_SUCCESS) {
  373. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to open address for UDP, status %lx.\n", status));
  374. goto error_exit;
  375. }
  376. //
  377. // Get a pointer to the file object of the address.
  378. //
  379. status = ObReferenceObjectByHandle(
  380. addressHandle,
  381. 0L, // DesiredAccess
  382. NULL,
  383. KernelMode,
  384. &addressFileObject,
  385. NULL
  386. );
  387. if (status != STATUS_SUCCESS) {
  388. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to reference address handle, status %lx.\n", status));
  389. goto error_exit;
  390. }
  391. //
  392. // Remember the device object to which we need to give requests for
  393. // this address object. We can't just use the fileObject->DeviceObject
  394. // pointer because there may be a device attached to the transport
  395. // protocol.
  396. //
  397. addressDeviceObject = IoGetRelatedDeviceObject(addressFileObject);
  398. //
  399. // Get the transport provider info
  400. //
  401. queryInfo.QueryType = TDI_QUERY_PROVIDER_INFO;
  402. queryInfo.RequestConnectionInformation = NULL;
  403. status = SpUdpIssueDeviceControl(
  404. addressFileObject,
  405. addressDeviceObject,
  406. &queryInfo,
  407. sizeof(queryInfo),
  408. &providerInfo,
  409. sizeof(providerInfo),
  410. TDI_QUERY_INFORMATION
  411. );
  412. if (!NT_SUCCESS(status)) {
  413. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Failed to get provider info, status %lx\n", status));
  414. goto error_exit;
  415. }
  416. if (!(providerInfo.ServiceFlags & TDI_SERVICE_CONNECTIONLESS_MODE)) {
  417. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Provider doesn't support datagrams!\n"));
  418. status = STATUS_UNSUCCESSFUL;
  419. goto error_exit;
  420. }
  421. //
  422. // Set up indication handlers on the address object. We are eligible
  423. // to receive indications as soon as we do this.
  424. //
  425. status = SpUdpTdiSetEventHandler(
  426. addressFileObject,
  427. addressDeviceObject,
  428. TDI_EVENT_ERROR,
  429. SpUdpTdiErrorHandler,
  430. NULL
  431. );
  432. if ( !NT_SUCCESS(status) ) {
  433. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Setting TDI_EVENT_ERROR failed: %lx\n", status));
  434. goto error_exit;
  435. }
  436. status = SpUdpTdiSetEventHandler(
  437. addressFileObject,
  438. addressDeviceObject,
  439. TDI_EVENT_RECEIVE_DATAGRAM,
  440. SpUdpTdiReceiveDatagramHandler,
  441. NULL
  442. );
  443. if ( !NT_SUCCESS(status) ) {
  444. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Setting TDI_EVENT_RECEIVE_DATAGRAM failed: %lx\n", status));
  445. goto error_exit;
  446. }
  447. //
  448. // Finish transition to online state. Note that an offline request
  449. // could have been issued in the meantime.
  450. //
  451. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  452. SpUdpDatagramHandle = addressHandle;
  453. addressHandle = NULL;
  454. SpUdpDatagramFileObject = addressFileObject;
  455. addressFileObject = NULL;
  456. SpUdpDatagramDeviceObject = addressDeviceObject;
  457. addressDeviceObject = NULL;
  458. ASSERT(SpUdpActiveRefCount == 2);
  459. SpUdpActiveRefCount--;
  460. SpUdpNetworkState = SpUdpNetworkConnected;
  461. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  462. return(STATUS_SUCCESS);
  463. error_exit:
  464. if (addressFileObject != NULL) {
  465. ObDereferenceObject(addressFileObject);
  466. }
  467. if (addressHandle != NULL) {
  468. ZwClose(addressHandle);
  469. }
  470. SpUdpDisconnect();
  471. return(status);
  472. } // SpUdpConnect
  473. NTSTATUS
  474. SpUdpDisconnect(
  475. VOID
  476. )
  477. {
  478. PLIST_ENTRY ListEntry;
  479. PSPUDP_RECEIVE_ENTRY ReceiveEntry;
  480. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  481. if (SpUdpNetworkState == SpUdpNetworkDisconnected) {
  482. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  483. return(STATUS_SUCCESS);
  484. }
  485. SpUdpNetworkState = SpUdpNetworkDisconnecting;
  486. if (SpUdpActiveRefCount != 1) {
  487. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  488. return(STATUS_PENDING);
  489. }
  490. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  491. if (SpUdpDatagramFileObject != NULL) {
  492. ObDereferenceObject(SpUdpDatagramFileObject);
  493. }
  494. if (SpUdpDatagramHandle != NULL) {
  495. ZwClose(SpUdpDatagramHandle);
  496. }
  497. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  498. SpUdpDatagramFileObject = NULL;
  499. SpUdpDatagramHandle = NULL;
  500. SpUdpDatagramDeviceObject = NULL;
  501. SpUdpActiveRefCount = 0;
  502. SpUdpNetworkState = SpUdpNetworkDisconnected;
  503. while (!IsListEmpty(&SpUdpReceiveList)) {
  504. ListEntry = RemoveHeadList(&SpUdpReceiveList);
  505. ReceiveEntry = CONTAINING_RECORD(ListEntry,
  506. SPUDP_RECEIVE_ENTRY,
  507. ListEntry
  508. );
  509. SpMemFree(ReceiveEntry->DataBuffer);
  510. SpMemFree(ReceiveEntry);
  511. }
  512. SpUdpNumReceivePackets = 0;
  513. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  514. return(STATUS_SUCCESS);
  515. } // SpUdpDisconnect
  516. NTSTATUS
  517. SpUdpIssueDeviceControl (
  518. IN PFILE_OBJECT FileObject,
  519. IN PDEVICE_OBJECT DeviceObject,
  520. IN PVOID IrpParameters,
  521. IN ULONG IrpParametersLength,
  522. IN PVOID MdlBuffer,
  523. IN ULONG MdlBufferLength,
  524. IN UCHAR MinorFunction
  525. )
  526. /*++
  527. Routine Description:
  528. Issues a device control request to a TDI provider and waits for the
  529. request to complete.
  530. Arguments:
  531. FileObject - a pointer to the file object corresponding to a TDI
  532. handle
  533. DeviceObject - a pointer to the device object corresponding to the
  534. FileObject.
  535. IrpParameters - information to write to the parameters section of the
  536. stack location of the IRP.
  537. IrpParametersLength - length of the parameter information. Cannot be
  538. greater than 16.
  539. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  540. into an MDL and placed in the MdlAddress field of the IRP.
  541. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  542. MinorFunction - the minor function code for the request.
  543. Return Value:
  544. NTSTATUS -- Indicates the status of the request.
  545. --*/
  546. {
  547. NTSTATUS status = STATUS_SUCCESS;
  548. PIRP irp;
  549. PIO_STACK_LOCATION irpSp;
  550. KEVENT event;
  551. IO_STATUS_BLOCK ioStatusBlock;
  552. PDEVICE_OBJECT deviceObject;
  553. PMDL mdl;
  554. //
  555. // Initialize the kernel event that will signal I/O completion.
  556. //
  557. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  558. //
  559. // Reference the passed in file object. This is necessary because
  560. // the IO completion routine dereferences it.
  561. //
  562. ObReferenceObject( FileObject );
  563. //
  564. // Set the file object event to a non-signaled state.
  565. //
  566. (VOID) KeResetEvent( &FileObject->Event );
  567. //
  568. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  569. // for this operation.
  570. //
  571. irp = IoAllocateIrp( (DeviceObject)->StackSize, TRUE );
  572. if ( irp == NULL ) {
  573. ObDereferenceObject( FileObject );
  574. return STATUS_INSUFFICIENT_RESOURCES;
  575. }
  576. //
  577. // Fill in the service independent parameters in the IRP.
  578. //
  579. irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
  580. irp->RequestorMode = KernelMode;
  581. irp->PendingReturned = FALSE;
  582. irp->UserIosb = &ioStatusBlock;
  583. irp->UserEvent = &event;
  584. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  585. irp->AssociatedIrp.SystemBuffer = NULL;
  586. irp->UserBuffer = NULL;
  587. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  588. irp->Tail.Overlay.OriginalFileObject = FileObject;
  589. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  590. //
  591. // If an MDL buffer was specified, get an MDL, map the buffer,
  592. // and place the MDL pointer in the IRP.
  593. //
  594. if ( MdlBuffer != NULL ) {
  595. mdl = IoAllocateMdl(
  596. MdlBuffer,
  597. MdlBufferLength,
  598. FALSE,
  599. FALSE,
  600. irp
  601. );
  602. if ( mdl == NULL ) {
  603. IoFreeIrp( irp );
  604. ObDereferenceObject( FileObject );
  605. return STATUS_INSUFFICIENT_RESOURCES;
  606. }
  607. MmBuildMdlForNonPagedPool( mdl );
  608. } else {
  609. irp->MdlAddress = NULL;
  610. }
  611. //
  612. // Put the file object pointer in the stack location.
  613. //
  614. irpSp = IoGetNextIrpStackLocation( irp );
  615. irpSp->FileObject = FileObject;
  616. irpSp->DeviceObject = DeviceObject;
  617. //
  618. // Fill in the service-dependent parameters for the request.
  619. //
  620. ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) );
  621. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  622. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  623. irpSp->MinorFunction = MinorFunction;
  624. //
  625. // Set up a completion routine which we'll use to free the MDL
  626. // allocated previously.
  627. //
  628. IoSetCompletionRoutine(
  629. irp,
  630. SpUdpRestartDeviceControl,
  631. NULL,
  632. TRUE,
  633. TRUE,
  634. TRUE
  635. );
  636. //
  637. // Queue the IRP to the thread and pass it to the driver.
  638. //
  639. IoEnqueueIrp( irp );
  640. status = IoCallDriver( DeviceObject, irp );
  641. //
  642. // If necessary, wait for the I/O to complete.
  643. //
  644. if ( status == STATUS_PENDING ) {
  645. KeWaitForSingleObject(
  646. (PVOID)&event,
  647. UserRequest,
  648. KernelMode,
  649. FALSE,
  650. NULL
  651. );
  652. }
  653. //
  654. // If the request was successfully queued, get the final I/O status.
  655. //
  656. if ( NT_SUCCESS(status) ) {
  657. status = ioStatusBlock.Status;
  658. }
  659. return status;
  660. } // SpUdpIssueDeviceControl
  661. NTSTATUS
  662. SpUdpTdiSetEventHandler(
  663. IN PFILE_OBJECT FileObject,
  664. IN PDEVICE_OBJECT DeviceObject,
  665. IN ULONG EventType,
  666. IN PVOID EventHandler,
  667. IN PVOID EventContext
  668. )
  669. /*++
  670. Routine Description:
  671. Sets up a TDI indication handler on the address object. This is done synchronously, which
  672. shouldn't usually be an issue since TDI providers can usually complete
  673. indication handler setups immediately.
  674. Arguments:
  675. FileObject - a pointer to the file object for an open connection or
  676. address object.
  677. DeviceObject - a pointer to the device object associated with the
  678. file object.
  679. EventType - the event for which the indication handler should be
  680. called.
  681. EventHandler - the routine to call when tghe specified event occurs.
  682. EventContext - context which is passed to the indication routine.
  683. Return Value:
  684. NTSTATUS -- Indicates the status of the request.
  685. --*/
  686. {
  687. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  688. NTSTATUS status;
  689. parameters.EventType = EventType;
  690. parameters.EventHandler = EventHandler;
  691. parameters.EventContext = EventContext;
  692. status = SpUdpIssueDeviceControl(
  693. FileObject,
  694. DeviceObject,
  695. &parameters,
  696. sizeof(parameters),
  697. NULL,
  698. 0,
  699. TDI_SET_EVENT_HANDLER
  700. );
  701. return(status);
  702. } // SpUdpTdiSetEventHandler
  703. NTSTATUS
  704. SpUdpTdiErrorHandler(
  705. IN PVOID TdiEventContext,
  706. IN NTSTATUS Status
  707. )
  708. {
  709. return(STATUS_SUCCESS);
  710. } // SpUdpTdiErrorHandler
  711. NTSTATUS
  712. SpUdpRestartDeviceControl (
  713. IN PDEVICE_OBJECT DeviceObject,
  714. IN PIRP Irp,
  715. IN PVOID Context
  716. )
  717. {
  718. //
  719. // If there was an MDL in the IRP, free it and reset the pointer to
  720. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  721. // in an IRP, which is why we do it here.
  722. //
  723. if ( Irp->MdlAddress != NULL ) {
  724. IoFreeMdl( Irp->MdlAddress );
  725. Irp->MdlAddress = NULL;
  726. }
  727. return STATUS_SUCCESS;
  728. } // SpUdpRestartDeviceControl
  729. NTSTATUS
  730. SpUdpTdiReceiveDatagramHandler(
  731. IN PVOID TdiEventContext,
  732. IN LONG SourceAddressLength,
  733. IN PVOID SourceAddress,
  734. IN LONG OptionsLength,
  735. IN PVOID Options,
  736. IN ULONG ReceiveDatagramFlags,
  737. IN ULONG BytesIndicated,
  738. IN ULONG BytesAvailable,
  739. OUT PULONG BytesTaken,
  740. IN PVOID Tsdu,
  741. OUT PIRP * Irp
  742. )
  743. {
  744. NTSTATUS status;
  745. SPUDP_PACKET UNALIGNED * pHeader = Tsdu;
  746. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  747. if (SpUdpNetworkState != SpUdpNetworkConnected) {
  748. return(STATUS_SUCCESS);
  749. }
  750. //
  751. // Validate the CNP header.
  752. //
  753. if (BytesIndicated > sizeof(SPUDP_PACKET)) {
  754. //
  755. // Deliver the packet to the appropriate upper layer protocol.
  756. //
  757. status = SpUdpReceivePacketHandler(
  758. ReceiveDatagramFlags,
  759. BytesIndicated,
  760. BytesAvailable,
  761. BytesTaken,
  762. Tsdu,
  763. Irp
  764. );
  765. return(status);
  766. }
  767. //
  768. // Something went wrong. Drop the packet by
  769. // indicating that we consumed it.
  770. //
  771. *BytesTaken = BytesAvailable;
  772. *Irp = NULL;
  773. return(STATUS_SUCCESS);
  774. } // SpUdpTdiReceiveDatagramHandler
  775. NTSTATUS
  776. SpUdpReceivePacketHandler(
  777. IN ULONG TdiReceiveDatagramFlags,
  778. IN ULONG BytesIndicated,
  779. IN ULONG BytesAvailable,
  780. OUT PULONG BytesTaken,
  781. IN PVOID Tsdu,
  782. OUT PIRP * Irp
  783. )
  784. {
  785. NTSTATUS status;
  786. PVOID DataBuffer;
  787. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  788. if (BytesAvailable == 0) {
  789. *Irp = NULL;
  790. return(STATUS_SUCCESS);
  791. }
  792. //
  793. // We need to fetch the rest of the packet before we
  794. // can process it.
  795. //
  796. //
  797. // Allocate a buffer to hold the data.
  798. //
  799. DataBuffer = SpMemAllocNonPagedPool(BytesAvailable);
  800. if (DataBuffer != NULL) {
  801. *Irp = IoAllocateIrp(SpUdpDatagramDeviceObject->StackSize, FALSE);
  802. if (*Irp != NULL) {
  803. PMDL mdl = IoAllocateMdl(
  804. DataBuffer,
  805. BytesAvailable,
  806. FALSE,
  807. FALSE,
  808. NULL
  809. );
  810. if (mdl != NULL) {
  811. MmBuildMdlForNonPagedPool(mdl);
  812. //
  813. // Build the irp.
  814. //
  815. (*Irp)->Flags = 0;
  816. (*Irp)->RequestorMode = KernelMode;
  817. (*Irp)->PendingReturned = FALSE;
  818. (*Irp)->UserIosb = NULL;
  819. (*Irp)->UserEvent = NULL;
  820. (*Irp)->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  821. (*Irp)->AssociatedIrp.SystemBuffer = NULL;
  822. (*Irp)->UserBuffer = NULL;
  823. (*Irp)->Tail.Overlay.Thread = 0;
  824. (*Irp)->Tail.Overlay.OriginalFileObject = SpUdpDatagramFileObject;
  825. (*Irp)->Tail.Overlay.AuxiliaryBuffer = NULL;
  826. TdiBuildReceiveDatagram(
  827. (*Irp),
  828. SpUdpDatagramDeviceObject,
  829. SpUdpDatagramFileObject,
  830. SpUdpCompleteReceivePacket,
  831. DataBuffer,
  832. mdl,
  833. BytesAvailable,
  834. NULL,
  835. NULL,
  836. 0
  837. );
  838. //
  839. // Make the next stack location current.
  840. // Normally IoCallDriver would do this, but
  841. // since we're bypassing that, we do it directly.
  842. //
  843. IoSetNextIrpStackLocation( *Irp );
  844. return(STATUS_MORE_PROCESSING_REQUIRED);
  845. }
  846. IoFreeIrp(*Irp);
  847. *Irp = NULL;
  848. }
  849. SpMemFree(DataBuffer);
  850. DataBuffer = NULL;
  851. }
  852. //
  853. // Something went wrong. Drop the packet.
  854. //
  855. *BytesTaken += BytesAvailable;
  856. return(STATUS_SUCCESS);
  857. } // SpUdpReceivePacketHandler
  858. NTSTATUS
  859. SpUdpCompleteReceivePacket(
  860. IN PDEVICE_OBJECT DeviceObject,
  861. IN PIRP Irp,
  862. IN PVOID Context
  863. )
  864. {
  865. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  866. SpUdpProcessReceivePacket(
  867. (ULONG)Irp->IoStatus.Information,
  868. Context
  869. );
  870. IoFreeMdl(Irp->MdlAddress);
  871. IoFreeIrp(Irp);
  872. }
  873. return(STATUS_MORE_PROCESSING_REQUIRED);
  874. } // SpUdpCompleteReceivePacket
  875. VOID
  876. SpUdpProcessReceivePacket(
  877. IN ULONG TsduSize,
  878. IN PVOID Tsdu
  879. )
  880. {
  881. SPUDP_PACKET UNALIGNED * header = Tsdu;
  882. PSPUDP_RECEIVE_ENTRY ReceiveEntry;
  883. ASSERT(TsduSize >= sizeof(SPUDP_PACKET));
  884. if ((RtlCompareMemory(header->Signature, SetupResponseSignature, sizeof(SetupResponseSignature)) ==
  885. sizeof(SetupResponseSignature)) &&
  886. (SpUdpNumReceivePackets < 100)) {
  887. //
  888. // Put this packet on the receive list
  889. //
  890. ReceiveEntry = SpMemAllocNonPagedPool(sizeof(SPUDP_RECEIVE_ENTRY));
  891. if (ReceiveEntry == NULL) {
  892. SpMemFree(Tsdu);
  893. return;
  894. }
  895. ReceiveEntry->DataBufferLength = TsduSize;
  896. ReceiveEntry->DataBuffer = Tsdu;
  897. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  898. InsertTailList(&SpUdpReceiveList, &(ReceiveEntry->ListEntry));
  899. SpUdpNumReceivePackets++;
  900. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  901. } else {
  902. SpMemFree(Tsdu);
  903. }
  904. return;
  905. } // SpUdpProcessReceivePacket
  906. NTSTATUS
  907. SpUdpSendDatagram(
  908. IN PVOID SendBuffer,
  909. IN ULONG SendBufferLength,
  910. IN ULONG RemoteHostAddress,
  911. IN USHORT RemoteHostPort
  912. )
  913. {
  914. NTSTATUS status = STATUS_SUCCESS;
  915. PLIST_ENTRY entry;
  916. PIRP irp;
  917. PMDL dataMdl;
  918. PTDI_CONNECTION_INFORMATION TdiSendDatagramInfo = NULL;
  919. PTRANSPORT_ADDRESS TaAddress;
  920. PTDI_ADDRESS_IP TdiAddressIp;
  921. TdiSendDatagramInfo = SpMemAllocNonPagedPool(sizeof(TDI_CONNECTION_INFORMATION) +
  922. sizeof(TA_IP_ADDRESS)
  923. );
  924. if (TdiSendDatagramInfo == NULL) {
  925. return (STATUS_INSUFFICIENT_RESOURCES);
  926. }
  927. RtlZeroMemory(TdiSendDatagramInfo,
  928. sizeof(TDI_CONNECTION_INFORMATION) +
  929. sizeof(TA_IP_ADDRESS)
  930. );
  931. dataMdl = IoAllocateMdl(
  932. SendBuffer,
  933. SendBufferLength,
  934. FALSE,
  935. FALSE,
  936. NULL
  937. );
  938. if (dataMdl == NULL) {
  939. SpMemFree(TdiSendDatagramInfo);
  940. return (STATUS_INSUFFICIENT_RESOURCES);
  941. }
  942. MmBuildMdlForNonPagedPool(dataMdl);
  943. //
  944. // Ok, we can send the packet.
  945. //
  946. irp = IoAllocateIrp(SpUdpDatagramDeviceObject->StackSize, FALSE);
  947. if (irp != NULL) {
  948. //
  949. // Reference the network so it can't disconnect while we are using it.
  950. //
  951. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  952. if (SpUdpNetworkState != SpUdpNetworkConnected) {
  953. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  954. return STATUS_SUCCESS;
  955. }
  956. SpUdpActiveRefCount++;
  957. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  958. //
  959. // Set the addressing info
  960. //
  961. TdiSendDatagramInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  962. TdiSendDatagramInfo->RemoteAddress = (PVOID)(TdiSendDatagramInfo + 1);
  963. TaAddress = (PTRANSPORT_ADDRESS)(TdiSendDatagramInfo->RemoteAddress);
  964. TaAddress->TAAddressCount = 1;
  965. TaAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  966. TaAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  967. TdiAddressIp = (PTDI_ADDRESS_IP)(&(TaAddress->Address[0].Address[0]));
  968. TdiAddressIp->in_addr = RemoteHostAddress;
  969. TdiAddressIp->sin_port= htons(RemoteHostPort);
  970. RtlZeroMemory(TdiAddressIp->sin_zero, sizeof(TdiAddressIp->sin_zero));
  971. //
  972. // Build the irp.
  973. //
  974. irp->Flags = 0;
  975. irp->RequestorMode = KernelMode;
  976. irp->PendingReturned = FALSE;
  977. irp->UserIosb = NULL;
  978. irp->UserEvent = NULL;
  979. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  980. irp->AssociatedIrp.SystemBuffer = NULL;
  981. irp->UserBuffer = NULL;
  982. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  983. irp->Tail.Overlay.OriginalFileObject = SpUdpDatagramFileObject;
  984. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  985. TdiBuildSendDatagram(
  986. irp,
  987. SpUdpDatagramDeviceObject,
  988. SpUdpDatagramFileObject,
  989. SpUdpCompleteSendDatagram,
  990. TdiSendDatagramInfo,
  991. dataMdl,
  992. SendBufferLength,
  993. TdiSendDatagramInfo
  994. );
  995. //
  996. // Now send the packet.
  997. //
  998. IoCallDriver(
  999. SpUdpDatagramDeviceObject,
  1000. irp
  1001. );
  1002. return(STATUS_PENDING);
  1003. }
  1004. IoFreeMdl(dataMdl);
  1005. SpMemFree(TdiSendDatagramInfo);
  1006. return(STATUS_INSUFFICIENT_RESOURCES);
  1007. } // SpUdpSendDatagram
  1008. NTSTATUS
  1009. SpUdpCompleteSendDatagram(
  1010. IN PDEVICE_OBJECT DeviceObject,
  1011. IN PIRP Irp,
  1012. IN PVOID Context
  1013. )
  1014. {
  1015. PMDL dataMdl;
  1016. dataMdl = Irp->MdlAddress;
  1017. Irp->MdlAddress = NULL;
  1018. //
  1019. // Remove the active reference we put on.
  1020. //
  1021. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  1022. SpUdpActiveRefCount--;
  1023. if (SpUdpNetworkState == SpUdpNetworkDisconnecting) {
  1024. SpUdpDisconnect();
  1025. }
  1026. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  1027. //
  1028. // Free the TDI address buffer
  1029. //
  1030. SpMemFree(Context);
  1031. //
  1032. // Free the Irp
  1033. //
  1034. IoFreeIrp(Irp);
  1035. //
  1036. // Free the MDL chain
  1037. //
  1038. IoFreeMdl(dataMdl);
  1039. return(STATUS_MORE_PROCESSING_REQUIRED);
  1040. } // SpUdpCompleteSendPacket
  1041. NTSTATUS
  1042. SpUdpSendAndReceiveDatagram(
  1043. IN PVOID SendBuffer,
  1044. IN ULONG SendBufferLength,
  1045. IN ULONG RemoteHostAddress,
  1046. IN USHORT RemoteHostPort,
  1047. IN SPUDP_RECEIVE_FN SpUdpReceiveFunc
  1048. )
  1049. {
  1050. LARGE_INTEGER DelayTime;
  1051. ULONG SendTries;
  1052. ULONG RcvTries;
  1053. PLIST_ENTRY ListEntry;
  1054. PSPUDP_RECEIVE_ENTRY ReceiveEntry;
  1055. NTSTATUS Status;
  1056. DelayTime.QuadPart = -10*1000*1; // 10 millisecond (wake up at next tick)
  1057. for (SendTries=0; SendTries < 15; SendTries++) {
  1058. SpUdpSendDatagram(SendBuffer,
  1059. SendBufferLength,
  1060. RemoteHostAddress,
  1061. RemoteHostPort
  1062. );
  1063. //
  1064. // Wait for 1 second for a response
  1065. //
  1066. for (RcvTries=0; RcvTries < 400; ) {
  1067. KeAcquireSpinLock(&SpUdpLock, &SpUdpOldIrql);
  1068. if (!IsListEmpty(&SpUdpReceiveList)) {
  1069. SpUdpNumReceivePackets--;
  1070. ListEntry = RemoveHeadList(&SpUdpReceiveList);
  1071. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  1072. ReceiveEntry = CONTAINING_RECORD(ListEntry,
  1073. SPUDP_RECEIVE_ENTRY,
  1074. ListEntry
  1075. );
  1076. Status = (*SpUdpReceiveFunc)(ReceiveEntry->DataBuffer, ReceiveEntry->DataBufferLength);
  1077. SpMemFree(ReceiveEntry->DataBuffer);
  1078. SpMemFree(ReceiveEntry);
  1079. if (NT_SUCCESS(Status)) {
  1080. return Status;
  1081. }
  1082. } else {
  1083. KeReleaseSpinLock(&SpUdpLock, SpUdpOldIrql);
  1084. RcvTries++;
  1085. KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
  1086. }
  1087. }
  1088. }
  1089. return STATUS_UNSUCCESSFUL;
  1090. }