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