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)
8 * CSH 01/08-2000 Created
14 PADDRESS_FILE AddrFile
,
17 PLIST_ENTRY ListEntry
;
18 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
20 BOOLEAN Found
= FALSE
;
22 TI_DbgPrint(MAX_TRACE
, ("Called (Cancel IRP %08x for file %08x).\n",
25 LockObject(AddrFile
, &OldIrql
);
27 for( ListEntry
= AddrFile
->ReceiveQueue
.Flink
;
28 ListEntry
!= &AddrFile
->ReceiveQueue
;
29 ListEntry
= ListEntry
->Flink
)
31 ReceiveRequest
= CONTAINING_RECORD
32 (ListEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
34 TI_DbgPrint(MAX_TRACE
, ("Request: %08x?\n", ReceiveRequest
));
36 if (ReceiveRequest
->Irp
== Irp
)
38 RemoveEntryList(&ReceiveRequest
->ListEntry
);
39 ExFreePoolWithTag(ReceiveRequest
, DATAGRAM_RECV_TAG
);
45 UnlockObject(AddrFile
, OldIrql
);
47 TI_DbgPrint(MAX_TRACE
, ("Done.\n"));
53 PADDRESS_FILE AddrFile
,
54 PIP_ADDRESS SrcAddress
,
55 PIP_ADDRESS DstAddress
,
61 * FUNCTION: Delivers datagram data to a user
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)
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.
76 PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler
;
84 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
86 LockObject(AddrFile
, &OldIrql
);
88 if (AddrFile
->Protocol
== IPPROTO_UDP
)
90 DataBuffer
= IPPacket
->Data
;
94 if (AddrFile
->HeaderIncl
)
95 DataBuffer
= IPPacket
->Header
;
98 DataBuffer
= IPPacket
->Data
;
99 DataSize
-= IPPacket
->HeaderSize
;
103 if (!IsListEmpty(&AddrFile
->ReceiveQueue
))
105 PLIST_ENTRY CurrentEntry
;
106 PDATAGRAM_RECEIVE_REQUEST Current
= NULL
;
107 PTA_IP_ADDRESS RTAIPAddress
;
109 TI_DbgPrint(MAX_TRACE
, ("There is a receive request.\n"));
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
))) {
121 /* Remove the request from the queue */
122 RemoveEntryList(&Current
->ListEntry
);
124 TI_DbgPrint(MAX_TRACE
, ("Suitable receive request found.\n"));
126 TI_DbgPrint(MAX_TRACE
,
127 ("Target Buffer: %x, Source Buffer: %x, Size %d\n",
128 Current
->Buffer
, DataBuffer
, DataSize
));
130 /* Copy the data into buffer provided by the user */
131 RtlCopyMemory( Current
->Buffer
,
133 MIN(Current
->BufferSize
, DataSize
) );
135 RTAIPAddress
= (PTA_IP_ADDRESS
)Current
->ReturnInfo
->RemoteAddress
;
136 RTAIPAddress
->TAAddressCount
= 1;
137 RTAIPAddress
->Address
->AddressType
= TDI_ADDRESS_TYPE_IP
;
138 RTAIPAddress
->Address
->AddressLength
= TDI_ADDRESS_LENGTH_IP
;
139 RTAIPAddress
->Address
->Address
->sin_port
= SrcPort
;
140 RTAIPAddress
->Address
->Address
->in_addr
= SrcAddress
->Address
.IPv4Address
;
141 RtlZeroMemory(RTAIPAddress
->Address
->Address
->sin_zero
, 8);
143 TI_DbgPrint(MAX_TRACE
, ("(A: %08x) Addr %08x Port %04x\n",
145 SrcAddress
->Address
.IPv4Address
, SrcPort
));
147 ReferenceObject(AddrFile
);
148 UnlockObject(AddrFile
, OldIrql
);
150 /* Complete the receive request */
151 if (Current
->BufferSize
< DataSize
)
152 Current
->Complete(Current
->Context
, STATUS_BUFFER_OVERFLOW
, Current
->BufferSize
);
154 Current
->Complete(Current
->Context
, STATUS_SUCCESS
, DataSize
);
156 LockObject(AddrFile
, &OldIrql
);
157 DereferenceObject(AddrFile
);
161 UnlockObject(AddrFile
, OldIrql
);
163 else if (AddrFile
->RegisteredReceiveDatagramHandler
)
165 TI_DbgPrint(MAX_TRACE
, ("Calling receive event handler.\n"));
167 ReceiveHandler
= AddrFile
->ReceiveDatagramHandler
;
168 HandlerContext
= AddrFile
->ReceiveDatagramHandlerContext
;
170 if (SrcAddress
->Type
== IP_ADDRESS_V4
)
172 AddressLength
= sizeof(IPv4_RAW_ADDRESS
);
173 SourceAddress
= &SrcAddress
->Address
.IPv4Address
;
175 else /* (Address->Type == IP_ADDRESS_V6) */
177 AddressLength
= sizeof(IPv6_RAW_ADDRESS
);
178 SourceAddress
= SrcAddress
->Address
.IPv6Address
;
181 ReferenceObject(AddrFile
);
182 UnlockObject(AddrFile
, OldIrql
);
184 Status
= (*ReceiveHandler
)(HandlerContext
,
189 TDI_RECEIVE_ENTIRE_MESSAGE
,
196 if (STATUS_SUCCESS
!= Status
)
197 TI_DbgPrint(MAX_TRACE
, ("receive handler signaled failure with Status 0x%x\n", Status
));
199 DereferenceObject(AddrFile
);
203 UnlockObject(AddrFile
, OldIrql
);
204 TI_DbgPrint(MAX_TRACE
, ("Discarding datagram.\n"));
207 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
211 VOID
DGReceiveComplete(PVOID Context
, NTSTATUS Status
, ULONG Count
) {
212 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
=
213 (PDATAGRAM_RECEIVE_REQUEST
)Context
;
214 TI_DbgPrint(MAX_TRACE
,("Called (%08x:%08x)\n", Status
, Count
));
215 ReceiveRequest
->UserComplete( ReceiveRequest
->UserContext
, Status
, Count
);
216 ExFreePoolWithTag( ReceiveRequest
, DATAGRAM_RECV_TAG
);
217 TI_DbgPrint(MAX_TRACE
,("Done\n"));
220 NTSTATUS
DGReceiveDatagram(
221 PADDRESS_FILE AddrFile
,
222 PTDI_CONNECTION_INFORMATION ConnInfo
,
226 PTDI_CONNECTION_INFORMATION ReturnInfo
,
227 PULONG BytesReceived
,
228 PDATAGRAM_COMPLETION_ROUTINE Complete
,
232 * FUNCTION: Attempts to receive an DG datagram from a remote address
234 * Request = Pointer to TDI request
235 * ConnInfo = Pointer to connection information
236 * Buffer = Pointer to NDIS buffer chain to store received data
237 * ReceiveLength = Maximum size to use of buffer, 0 if all can be used
238 * ReceiveFlags = Receive flags (None, Normal, Peek)
239 * ReturnInfo = Pointer to structure for return information
240 * BytesReceive = Pointer to structure for number of bytes received
242 * Status of operation
244 * This is the high level interface for receiving DG datagrams
248 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
251 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
253 LockObject(AddrFile
, &OldIrql
);
255 ReceiveRequest
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DATAGRAM_RECEIVE_REQUEST
),
259 /* Initialize a receive request */
261 /* Extract the remote address filter from the request (if any) */
262 if ((ConnInfo
->RemoteAddressLength
!= 0) &&
263 (ConnInfo
->RemoteAddress
))
265 Status
= AddrGetAddress(ConnInfo
->RemoteAddress
,
266 &ReceiveRequest
->RemoteAddress
,
267 &ReceiveRequest
->RemotePort
);
268 if (!NT_SUCCESS(Status
))
270 ExFreePoolWithTag(ReceiveRequest
, DATAGRAM_RECV_TAG
);
271 UnlockObject(AddrFile
, OldIrql
);
277 ReceiveRequest
->RemotePort
= 0;
278 AddrInitIPv4(&ReceiveRequest
->RemoteAddress
, 0);
281 IoMarkIrpPending(Irp
);
283 ReceiveRequest
->ReturnInfo
= ReturnInfo
;
284 ReceiveRequest
->Buffer
= BufferData
;
285 ReceiveRequest
->BufferSize
= ReceiveLength
;
286 ReceiveRequest
->UserComplete
= Complete
;
287 ReceiveRequest
->UserContext
= Context
;
288 ReceiveRequest
->Complete
=
289 (PDATAGRAM_COMPLETION_ROUTINE
)DGReceiveComplete
;
290 ReceiveRequest
->Context
= ReceiveRequest
;
291 ReceiveRequest
->AddressFile
= AddrFile
;
292 ReceiveRequest
->Irp
= Irp
;
294 /* Queue receive request */
295 InsertTailList(&AddrFile
->ReceiveQueue
, &ReceiveRequest
->ListEntry
);
297 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending %08x).\n", ReceiveRequest
));
299 UnlockObject(AddrFile
, OldIrql
);
301 return STATUS_PENDING
;
305 UnlockObject(AddrFile
, OldIrql
);
306 Status
= STATUS_INSUFFICIENT_RESOURCES
;
309 TI_DbgPrint(MAX_TRACE
, ("Leaving with errors (0x%X).\n", Status
));