More work on winsock stack (ping is now working)
[reactos.git] / reactos / drivers / net / tcpip / transport / datagram / datagram.c
index ac9d48e..d779b6f 100644 (file)
@@ -227,6 +227,130 @@ VOID DGSend(
 }
 
 
+VOID DGDeliverData(
+    PADDRESS_FILE AddrFile,
+    PIP_ADDRESS Address,
+    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;
+    PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler;
+    PVOID HandlerContext;
+    LONG AddressLength;
+    PVOID SourceAddress;
+    ULONG BytesTaken;
+    NTSTATUS Status;
+    PVOID DataBuffer;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    if (AddrFile->Protocol == IPPROTO_UDP) {
+        DataBuffer = IPPacket->Data;
+    } else {
+        /* Give client the IP header too if it is a raw IP file object */
+        DataBuffer = IPPacket->Header;
+    }
+
+    if (!IsListEmpty(&AddrFile->ReceiveQueue)) {
+        PLIST_ENTRY CurrentEntry;
+        PDATAGRAM_RECEIVE_REQUEST Current;
+        BOOLEAN Found;
+
+        TI_DbgPrint(MAX_TRACE, ("There is a receive request.\n"));
+
+        /* Search receive request list to find a match */
+        Found = FALSE;
+        CurrentEntry = AddrFile->ReceiveQueue.Flink;
+        while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {
+            Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+            if (!Current->RemoteAddress)
+                Found = TRUE;
+            else if (AddrIsEqual(Address, Current->RemoteAddress))
+                Found = TRUE;
+
+            if (Found) {
+                /* FIXME: Maybe we should check if the buffer of this
+                   receive request is large enough and if not, search
+                   for another */
+
+                /* Remove the request from the queue */
+                RemoveEntryList(&Current->ListEntry);
+                AddrFile->RefCount--;
+                break;
+            }
+            CurrentEntry = CurrentEntry->Flink;
+        }
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        if (Found) {
+            TI_DbgPrint(MAX_TRACE, ("Suitable receive request found.\n"));
+
+            /* Copy the data into buffer provided by the user */
+            CopyBufferToBufferChain(Current->Buffer,
+                                    0,
+                                    DataBuffer,
+                                    DataSize);
+
+            /* Complete the receive request */
+            (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize);
+
+            /* Finally free the receive request */
+            if (Current->RemoteAddress)
+                PoolFreeBuffer(Current->RemoteAddress);
+            PoolFreeBuffer(Current);
+        }
+    } else if (AddrFile->RegisteredReceiveDatagramHandler) {
+        TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
+
+        ReceiveHandler = AddrFile->ReceiveDatagramHandler;
+        HandlerContext = AddrFile->ReceiveDatagramHandlerContext;
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        if (Address->Type == IP_ADDRESS_V4) {
+            AddressLength = sizeof(IPv4_RAW_ADDRESS);
+            SourceAddress = &Address->Address.IPv4Address;
+        } else /* (Address->Type == IP_ADDRESS_V6) */ {
+            AddressLength = sizeof(IPv6_RAW_ADDRESS);
+            SourceAddress = Address->Address.IPv6Address;
+        }
+
+        Status = (*ReceiveHandler)(HandlerContext,
+                                   AddressLength,
+                                   SourceAddress,
+                                   0,
+                                   NULL,
+                                   TDI_RECEIVE_ENTIRE_MESSAGE,
+                                   DataSize,
+                                   DataSize,
+                                   &BytesTaken,
+                                   DataBuffer,
+                                   NULL);
+    } else {
+      TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
 VOID DGCancelSendRequest(
     PADDRESS_FILE AddrFile,
     PVOID Context)