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