Leaked source code of windows server 2003
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.

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