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