1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        transport/datagram/datagram.c
5  * PURPOSE:     Routines for sending and receiving datagrams
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 
11 #include "precomp.h"
12 
DGRemoveIRP(PADDRESS_FILE AddrFile,PIRP Irp)13 BOOLEAN DGRemoveIRP(
14     PADDRESS_FILE AddrFile,
15     PIRP Irp)
16 {
17     PLIST_ENTRY ListEntry;
18     PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
19     BOOLEAN Found = FALSE;
20 
21     TI_DbgPrint(MAX_TRACE, ("Called (Cancel IRP %08x for file %08x).\n",
22                             Irp, AddrFile));
23 
24     LockObject(AddrFile);
25 
26     for( ListEntry = AddrFile->ReceiveQueue.Flink;
27          ListEntry != &AddrFile->ReceiveQueue;
28          ListEntry = ListEntry->Flink )
29     {
30         ReceiveRequest = CONTAINING_RECORD
31             (ListEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
32 
33         TI_DbgPrint(MAX_TRACE, ("Request: %08x?\n", ReceiveRequest));
34 
35         if (ReceiveRequest->Irp == Irp)
36         {
37             RemoveEntryList(&ReceiveRequest->ListEntry);
38             ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG);
39             Found = TRUE;
40             break;
41         }
42     }
43 
44     UnlockObject(AddrFile);
45 
46     TI_DbgPrint(MAX_TRACE, ("Done.\n"));
47 
48     return Found;
49 }
50 
51 VOID
DGDeliverData(PADDRESS_FILE AddrFile,PIP_ADDRESS SrcAddress,PIP_ADDRESS DstAddress,USHORT SrcPort,USHORT DstPort,PIP_PACKET IPPacket,UINT DataSize)52 DGDeliverData(
53     PADDRESS_FILE AddrFile,
54     PIP_ADDRESS SrcAddress,
55     PIP_ADDRESS DstAddress,
56     USHORT SrcPort,
57     USHORT DstPort,
58     PIP_PACKET IPPacket,
59     UINT DataSize)
60 /*
61  * FUNCTION: Delivers datagram data to a user
62  * ARGUMENTS:
63  *     AddrFile = Address file to deliver data to
64  *     Address  = Remote address the packet came from
65  *     IPPacket = Pointer to IP packet to deliver
66  *     DataSize = Number of bytes in data area
67  *                (incl. IP header for raw IP file objects)
68  * NOTES:
69  *     If there is a receive request, then we copy the data to the
70  *     buffer supplied by the user and complete the receive request.
71  *     If no suitable receive request exists, then we call the event
72  *     handler if it exists, otherwise we drop the packet.
73  */
74 {
75     LONG AddressLength;
76     PVOID SourceAddress;
77     ULONG BytesTaken;
78     NTSTATUS Status;
79     PVOID DataBuffer;
80 
81     TI_DbgPrint(MIN_TRACE, ("Called.\n"));
82 
83     LockObject(AddrFile);
84 
85     if (AddrFile->Protocol == IPPROTO_UDP)
86     {
87         DataBuffer = IPPacket->Data;
88     }
89     else if (AddrFile->HeaderIncl)
90     {
91         DataBuffer = IPPacket->Header;
92     }
93     else
94     {
95         DataBuffer = IPPacket->Data;
96         DataSize -= IPPacket->HeaderSize;
97     }
98 
99     if (!IsListEmpty(&AddrFile->ReceiveQueue))
100     {
101         PLIST_ENTRY CurrentEntry;
102         PDATAGRAM_RECEIVE_REQUEST Current = NULL;
103         PTA_IP_ADDRESS RTAIPAddress;
104 
105         TI_DbgPrint(MAX_TRACE, ("There is a receive request.\n"));
106 
107         /* Search receive request list to find a match */
108         CurrentEntry = AddrFile->ReceiveQueue.Flink;
109         while (CurrentEntry != &AddrFile->ReceiveQueue)
110         {
111             Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
112             CurrentEntry = CurrentEntry->Flink;
113             if (DstPort == AddrFile->Port &&
114                (AddrIsEqual(DstAddress, &AddrFile->Address) ||
115                 AddrIsUnspecified(&AddrFile->Address) ||
116                 AddrIsUnspecified(DstAddress)))
117             {
118 
119                 /* Remove the request from the queue */
120                 RemoveEntryList(&Current->ListEntry);
121 
122                 TI_DbgPrint(MAX_TRACE, ("Suitable receive request found.\n"));
123 
124                 TI_DbgPrint(MAX_TRACE,
125                            ("Target Buffer: %x, Source Buffer: %x, Size %d\n",
126                             Current->Buffer, DataBuffer, DataSize));
127 
128                 /* Copy the data into buffer provided by the user */
129                 RtlCopyMemory(Current->Buffer,
130                      DataBuffer,
131                      MIN(Current->BufferSize, DataSize));
132 
133                 RTAIPAddress = (PTA_IP_ADDRESS)Current->ReturnInfo->RemoteAddress;
134                 RTAIPAddress->TAAddressCount = 1;
135                 RTAIPAddress->Address->AddressType = TDI_ADDRESS_TYPE_IP;
136                 RTAIPAddress->Address->AddressLength = TDI_ADDRESS_LENGTH_IP;
137                 RTAIPAddress->Address->Address->sin_port = SrcPort;
138                 RTAIPAddress->Address->Address->in_addr = SrcAddress->Address.IPv4Address;
139                 RtlZeroMemory(RTAIPAddress->Address->Address->sin_zero, 8);
140 
141                 TI_DbgPrint(MAX_TRACE, ("(A: %08x) Addr %08x Port %04x\n",
142                             RTAIPAddress,
143                             SrcAddress->Address.IPv4Address, SrcPort));
144 
145                 ReferenceObject(AddrFile);
146                 UnlockObject(AddrFile);
147 
148                 /* Complete the receive request */
149                 if (Current->BufferSize < DataSize)
150                     Current->Complete(Current->Context, STATUS_BUFFER_OVERFLOW, Current->BufferSize);
151                 else
152                     Current->Complete(Current->Context, STATUS_SUCCESS, DataSize);
153 
154                 LockObject(AddrFile);
155                 DereferenceObject(AddrFile);
156             }
157         }
158 
159         UnlockObject(AddrFile);
160     }
161     else if (AddrFile->RegisteredReceiveDatagramHandler)
162     {
163         PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler = AddrFile->ReceiveDatagramHandler;
164         PVOID HandlerContext = AddrFile->ReceiveDatagramHandlerContext;
165         PVOID OptionsData = NULL;
166         INT32 OptionsSize = 0;
167 
168         TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
169 
170         if (SrcAddress->Type == IP_ADDRESS_V4)
171         {
172             AddressLength = sizeof(IPv4_RAW_ADDRESS);
173             SourceAddress = &SrcAddress->Address.IPv4Address;
174             OptionsSize = IPPacket->HeaderSize - sizeof(IPv4_HEADER);
175             if (OptionsSize > 0)
176             {
177                 OptionsData = (PUCHAR)IPPacket->Header + sizeof(IPv4_HEADER);
178             }
179         }
180         else /* (Address->Type == IP_ADDRESS_V6) */
181         {
182             AddressLength = sizeof(IPv6_RAW_ADDRESS);
183             SourceAddress = SrcAddress->Address.IPv6Address;
184         }
185 
186         ReferenceObject(AddrFile);
187         UnlockObject(AddrFile);
188 
189         TI_DbgPrint(MIN_TRACE, ("OptionsSize %d DataSize: %u\n", OptionsSize, DataSize));
190 
191         Status = (*ReceiveHandler)(HandlerContext,
192             AddressLength,
193             SourceAddress,
194             OptionsSize,
195             OptionsData,
196             TDI_RECEIVE_ENTIRE_MESSAGE,
197             DataSize,
198             DataSize,
199             &BytesTaken,
200             DataBuffer,
201             NULL);
202 
203         if (STATUS_SUCCESS != Status)
204             TI_DbgPrint(MAX_TRACE, ("receive handler signaled failure with Status 0x%x\n", Status));
205 
206         DereferenceObject(AddrFile);
207     }
208     else
209     {
210         UnlockObject(AddrFile);
211         TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
212     }
213 
214     TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
215 }
216 
DGReceiveComplete(PVOID Context,NTSTATUS Status,ULONG Count)217 VOID DGReceiveComplete(PVOID Context, NTSTATUS Status, ULONG Count) {
218     PDATAGRAM_RECEIVE_REQUEST ReceiveRequest =
219 	(PDATAGRAM_RECEIVE_REQUEST)Context;
220     TI_DbgPrint(MAX_TRACE,("Called (%08x:%08x)\n", Status, Count));
221     ReceiveRequest->UserComplete( ReceiveRequest->UserContext, Status, Count );
222     ExFreePoolWithTag( ReceiveRequest, DATAGRAM_RECV_TAG );
223     TI_DbgPrint(MAX_TRACE,("Done\n"));
224 }
225 
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)226 NTSTATUS DGReceiveDatagram(
227     PADDRESS_FILE AddrFile,
228     PTDI_CONNECTION_INFORMATION ConnInfo,
229     PCHAR BufferData,
230     ULONG ReceiveLength,
231     ULONG ReceiveFlags,
232     PTDI_CONNECTION_INFORMATION ReturnInfo,
233     PULONG BytesReceived,
234     PDATAGRAM_COMPLETION_ROUTINE Complete,
235     PVOID Context,
236     PIRP Irp)
237 /*
238  * FUNCTION: Attempts to receive an DG datagram from a remote address
239  * ARGUMENTS:
240  *     Request       = Pointer to TDI request
241  *     ConnInfo      = Pointer to connection information
242  *     Buffer        = Pointer to NDIS buffer chain to store received data
243  *     ReceiveLength = Maximum size to use of buffer, 0 if all can be used
244  *     ReceiveFlags  = Receive flags (None, Normal, Peek)
245  *     ReturnInfo    = Pointer to structure for return information
246  *     BytesReceive  = Pointer to structure for number of bytes received
247  * RETURNS:
248  *     Status of operation
249  * NOTES:
250  *     This is the high level interface for receiving DG datagrams
251  */
252 {
253     NTSTATUS Status;
254     PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
255 
256     TI_DbgPrint(MAX_TRACE, ("Called.\n"));
257 
258     LockObject(AddrFile);
259 
260     ReceiveRequest = ExAllocatePoolWithTag(NonPagedPool, sizeof(DATAGRAM_RECEIVE_REQUEST),
261                                            DATAGRAM_RECV_TAG);
262     if (ReceiveRequest)
263     {
264 	/* Initialize a receive request */
265 
266 	/* Extract the remote address filter from the request (if any) */
267 	if ((ConnInfo->RemoteAddressLength != 0) &&
268 	    (ConnInfo->RemoteAddress))
269         {
270 	    Status = AddrGetAddress(ConnInfo->RemoteAddress,
271 				    &ReceiveRequest->RemoteAddress,
272 				    &ReceiveRequest->RemotePort);
273 	    if (!NT_SUCCESS(Status))
274             {
275 		ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG);
276 	        UnlockObject(AddrFile);
277 		return Status;
278             }
279 	}
280 	else
281         {
282 	    ReceiveRequest->RemotePort = 0;
283 	    AddrInitIPv4(&ReceiveRequest->RemoteAddress, 0);
284         }
285 
286 	IoMarkIrpPending(Irp);
287 
288 	ReceiveRequest->ReturnInfo = ReturnInfo;
289 	ReceiveRequest->Buffer = BufferData;
290 	ReceiveRequest->BufferSize = ReceiveLength;
291 	ReceiveRequest->UserComplete = Complete;
292 	ReceiveRequest->UserContext = Context;
293 	ReceiveRequest->Complete =
294 		(PDATAGRAM_COMPLETION_ROUTINE)DGReceiveComplete;
295 	ReceiveRequest->Context = ReceiveRequest;
296         ReceiveRequest->AddressFile = AddrFile;
297         ReceiveRequest->Irp = Irp;
298 
299 	/* Queue receive request */
300 	InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);
301 
302 	TI_DbgPrint(MAX_TRACE, ("Leaving (pending %08x).\n", ReceiveRequest));
303 
304 	UnlockObject(AddrFile);
305 
306 	return STATUS_PENDING;
307     }
308     else
309     {
310 	UnlockObject(AddrFile);
311         Status = STATUS_INSUFFICIENT_RESOURCES;
312     }
313 
314     TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));
315 
316     return Status;
317 }
318