reactos/sdk/lib/drivers/ip/transport/datagram/datagram.c
2020-04-07 05:32:40 +03:00

321 lines
10 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/datagram/datagram.c
* PURPOSE: Routines for sending and receiving datagrams
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISIONS:
* CSH 01/08-2000 Created
*/
#include "precomp.h"
BOOLEAN DGRemoveIRP(
PADDRESS_FILE AddrFile,
PIRP Irp)
{
PLIST_ENTRY ListEntry;
PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
KIRQL OldIrql;
BOOLEAN Found = FALSE;
TI_DbgPrint(MAX_TRACE, ("Called (Cancel IRP %08x for file %08x).\n",
Irp, AddrFile));
LockObject(AddrFile, &OldIrql);
for( ListEntry = AddrFile->ReceiveQueue.Flink;
ListEntry != &AddrFile->ReceiveQueue;
ListEntry = ListEntry->Flink )
{
ReceiveRequest = CONTAINING_RECORD
(ListEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
TI_DbgPrint(MAX_TRACE, ("Request: %08x?\n", ReceiveRequest));
if (ReceiveRequest->Irp == Irp)
{
RemoveEntryList(&ReceiveRequest->ListEntry);
ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG);
Found = TRUE;
break;
}
}
UnlockObject(AddrFile, OldIrql);
TI_DbgPrint(MAX_TRACE, ("Done.\n"));
return Found;
}
VOID
DGDeliverData(
PADDRESS_FILE AddrFile,
PIP_ADDRESS SrcAddress,
PIP_ADDRESS DstAddress,
USHORT SrcPort,
USHORT DstPort,
PIP_PACKET IPPacket,
UINT DataSize)
/*
* FUNCTION: Delivers datagram data to a user
* ARGUMENTS:
* AddrFile = Address file to deliver data to
* Address = Remote address the packet came from
* IPPacket = Pointer to IP packet to deliver
* DataSize = Number of bytes in data area
* (incl. IP header for raw IP file objects)
* NOTES:
* If there is a receive request, then we copy the data to the
* buffer supplied by the user and complete the receive request.
* If no suitable receive request exists, then we call the event
* handler if it exists, otherwise we drop the packet.
*/
{
KIRQL OldIrql;
LONG AddressLength;
PVOID SourceAddress;
ULONG BytesTaken;
NTSTATUS Status;
PVOID DataBuffer;
TI_DbgPrint(MIN_TRACE, ("Called.\n"));
LockObject(AddrFile, &OldIrql);
if (AddrFile->Protocol == IPPROTO_UDP)
{
DataBuffer = IPPacket->Data;
}
else if (AddrFile->HeaderIncl)
{
DataBuffer = IPPacket->Header;
}
else
{
DataBuffer = IPPacket->Data;
DataSize -= IPPacket->HeaderSize;
}
if (!IsListEmpty(&AddrFile->ReceiveQueue))
{
PLIST_ENTRY CurrentEntry;
PDATAGRAM_RECEIVE_REQUEST Current = NULL;
PTA_IP_ADDRESS RTAIPAddress;
TI_DbgPrint(MAX_TRACE, ("There is a receive request.\n"));
/* Search receive request list to find a match */
CurrentEntry = AddrFile->ReceiveQueue.Flink;
while (CurrentEntry != &AddrFile->ReceiveQueue)
{
Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
CurrentEntry = CurrentEntry->Flink;
if (DstPort == AddrFile->Port &&
(AddrIsEqual(DstAddress, &AddrFile->Address) ||
AddrIsUnspecified(&AddrFile->Address) ||
AddrIsUnspecified(DstAddress)))
{
/* Remove the request from the queue */
RemoveEntryList(&Current->ListEntry);
TI_DbgPrint(MAX_TRACE, ("Suitable receive request found.\n"));
TI_DbgPrint(MAX_TRACE,
("Target Buffer: %x, Source Buffer: %x, Size %d\n",
Current->Buffer, DataBuffer, DataSize));
/* Copy the data into buffer provided by the user */
RtlCopyMemory(Current->Buffer,
DataBuffer,
MIN(Current->BufferSize, DataSize));
RTAIPAddress = (PTA_IP_ADDRESS)Current->ReturnInfo->RemoteAddress;
RTAIPAddress->TAAddressCount = 1;
RTAIPAddress->Address->AddressType = TDI_ADDRESS_TYPE_IP;
RTAIPAddress->Address->AddressLength = TDI_ADDRESS_LENGTH_IP;
RTAIPAddress->Address->Address->sin_port = SrcPort;
RTAIPAddress->Address->Address->in_addr = SrcAddress->Address.IPv4Address;
RtlZeroMemory(RTAIPAddress->Address->Address->sin_zero, 8);
TI_DbgPrint(MAX_TRACE, ("(A: %08x) Addr %08x Port %04x\n",
RTAIPAddress,
SrcAddress->Address.IPv4Address, SrcPort));
ReferenceObject(AddrFile);
UnlockObject(AddrFile, OldIrql);
/* Complete the receive request */
if (Current->BufferSize < DataSize)
Current->Complete(Current->Context, STATUS_BUFFER_OVERFLOW, Current->BufferSize);
else
Current->Complete(Current->Context, STATUS_SUCCESS, DataSize);
LockObject(AddrFile, &OldIrql);
DereferenceObject(AddrFile);
}
}
UnlockObject(AddrFile, OldIrql);
}
else if (AddrFile->RegisteredReceiveDatagramHandler)
{
PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler = AddrFile->ReceiveDatagramHandler;
PVOID HandlerContext = AddrFile->ReceiveDatagramHandlerContext;
PVOID OptionsData = NULL;
INT32 OptionsSize = 0;
TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
if (SrcAddress->Type == IP_ADDRESS_V4)
{
AddressLength = sizeof(IPv4_RAW_ADDRESS);
SourceAddress = &SrcAddress->Address.IPv4Address;
OptionsSize = IPPacket->HeaderSize - sizeof(IPv4_HEADER);
if (OptionsSize > 0)
{
OptionsData = (PUCHAR)IPPacket->Header + sizeof(IPv4_HEADER);
}
}
else /* (Address->Type == IP_ADDRESS_V6) */
{
AddressLength = sizeof(IPv6_RAW_ADDRESS);
SourceAddress = SrcAddress->Address.IPv6Address;
}
ReferenceObject(AddrFile);
UnlockObject(AddrFile, OldIrql);
TI_DbgPrint(MIN_TRACE, ("OptionsSize %d DataSize: %u\n", OptionsSize, DataSize));
Status = (*ReceiveHandler)(HandlerContext,
AddressLength,
SourceAddress,
OptionsSize,
OptionsData,
TDI_RECEIVE_ENTIRE_MESSAGE,
DataSize,
DataSize,
&BytesTaken,
DataBuffer,
NULL);
if (STATUS_SUCCESS != Status)
TI_DbgPrint(MAX_TRACE, ("receive handler signaled failure with Status 0x%x\n", Status));
DereferenceObject(AddrFile);
}
else
{
UnlockObject(AddrFile, OldIrql);
TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
}
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
}
VOID DGReceiveComplete(PVOID Context, NTSTATUS Status, ULONG Count) {
PDATAGRAM_RECEIVE_REQUEST ReceiveRequest =
(PDATAGRAM_RECEIVE_REQUEST)Context;
TI_DbgPrint(MAX_TRACE,("Called (%08x:%08x)\n", Status, Count));
ReceiveRequest->UserComplete( ReceiveRequest->UserContext, Status, Count );
ExFreePoolWithTag( ReceiveRequest, DATAGRAM_RECV_TAG );
TI_DbgPrint(MAX_TRACE,("Done\n"));
}
NTSTATUS DGReceiveDatagram(
PADDRESS_FILE AddrFile,
PTDI_CONNECTION_INFORMATION ConnInfo,
PCHAR BufferData,
ULONG ReceiveLength,
ULONG ReceiveFlags,
PTDI_CONNECTION_INFORMATION ReturnInfo,
PULONG BytesReceived,
PDATAGRAM_COMPLETION_ROUTINE Complete,
PVOID Context,
PIRP Irp)
/*
* FUNCTION: Attempts to receive an DG datagram from a remote address
* ARGUMENTS:
* Request = Pointer to TDI request
* ConnInfo = Pointer to connection information
* Buffer = Pointer to NDIS buffer chain to store received data
* ReceiveLength = Maximum size to use of buffer, 0 if all can be used
* ReceiveFlags = Receive flags (None, Normal, Peek)
* ReturnInfo = Pointer to structure for return information
* BytesReceive = Pointer to structure for number of bytes received
* RETURNS:
* Status of operation
* NOTES:
* This is the high level interface for receiving DG datagrams
*/
{
NTSTATUS Status;
PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
KIRQL OldIrql;
TI_DbgPrint(MAX_TRACE, ("Called.\n"));
LockObject(AddrFile, &OldIrql);
ReceiveRequest = ExAllocatePoolWithTag(NonPagedPool, sizeof(DATAGRAM_RECEIVE_REQUEST),
DATAGRAM_RECV_TAG);
if (ReceiveRequest)
{
/* Initialize a receive request */
/* Extract the remote address filter from the request (if any) */
if ((ConnInfo->RemoteAddressLength != 0) &&
(ConnInfo->RemoteAddress))
{
Status = AddrGetAddress(ConnInfo->RemoteAddress,
&ReceiveRequest->RemoteAddress,
&ReceiveRequest->RemotePort);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG);
UnlockObject(AddrFile, OldIrql);
return Status;
}
}
else
{
ReceiveRequest->RemotePort = 0;
AddrInitIPv4(&ReceiveRequest->RemoteAddress, 0);
}
IoMarkIrpPending(Irp);
ReceiveRequest->ReturnInfo = ReturnInfo;
ReceiveRequest->Buffer = BufferData;
ReceiveRequest->BufferSize = ReceiveLength;
ReceiveRequest->UserComplete = Complete;
ReceiveRequest->UserContext = Context;
ReceiveRequest->Complete =
(PDATAGRAM_COMPLETION_ROUTINE)DGReceiveComplete;
ReceiveRequest->Context = ReceiveRequest;
ReceiveRequest->AddressFile = AddrFile;
ReceiveRequest->Irp = Irp;
/* Queue receive request */
InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);
TI_DbgPrint(MAX_TRACE, ("Leaving (pending %08x).\n", ReceiveRequest));
UnlockObject(AddrFile, OldIrql);
return STATUS_PENDING;
}
else
{
UnlockObject(AddrFile, OldIrql);
Status = STATUS_INSUFFICIENT_RESOURCES;
}
TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));
return Status;
}