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 /* Give client the IP header too if it is a raw IP file object */
95 DataBuffer
= IPPacket
->Header
;
98 if (!IsListEmpty(&AddrFile
->ReceiveQueue
))
100 PLIST_ENTRY CurrentEntry
;
101 PDATAGRAM_RECEIVE_REQUEST Current
= NULL
;
102 PTA_IP_ADDRESS RTAIPAddress
;
104 TI_DbgPrint(MAX_TRACE
, ("There is a receive request.\n"));
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
))) {
116 /* Remove the request from the queue */
117 RemoveEntryList(&Current
->ListEntry
);
119 TI_DbgPrint(MAX_TRACE
, ("Suitable receive request found.\n"));
121 TI_DbgPrint(MAX_TRACE
,
122 ("Target Buffer: %x, Source Buffer: %x, Size %d\n",
123 Current
->Buffer
, DataBuffer
, DataSize
));
125 /* Copy the data into buffer provided by the user */
126 RtlCopyMemory( Current
->Buffer
,
128 MIN(Current
->BufferSize
, DataSize
) );
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
;
135 TI_DbgPrint(MAX_TRACE
, ("(A: %08x) Addr %08x Port %04x\n",
137 SrcAddress
->Address
.IPv4Address
, SrcPort
));
139 RtlCopyMemory( &RTAIPAddress
->Address
->Address
->in_addr
,
140 &SrcAddress
->Address
.IPv4Address
,
141 sizeof(SrcAddress
->Address
.IPv4Address
) );
143 ReferenceObject(AddrFile
);
144 UnlockObject(AddrFile
, OldIrql
);
146 /* Complete the receive request */
147 if (Current
->BufferSize
< DataSize
)
148 Current
->Complete(Current
->Context
, STATUS_BUFFER_OVERFLOW
, Current
->BufferSize
);
150 Current
->Complete(Current
->Context
, STATUS_SUCCESS
, DataSize
);
152 LockObject(AddrFile
, &OldIrql
);
153 DereferenceObject(AddrFile
);
157 UnlockObject(AddrFile
, OldIrql
);
159 else if (AddrFile
->RegisteredReceiveDatagramHandler
)
161 TI_DbgPrint(MAX_TRACE
, ("Calling receive event handler.\n"));
163 ReceiveHandler
= AddrFile
->ReceiveDatagramHandler
;
164 HandlerContext
= AddrFile
->ReceiveDatagramHandlerContext
;
166 if (SrcAddress
->Type
== IP_ADDRESS_V4
)
168 AddressLength
= sizeof(IPv4_RAW_ADDRESS
);
169 SourceAddress
= &SrcAddress
->Address
.IPv4Address
;
171 else /* (Address->Type == IP_ADDRESS_V6) */
173 AddressLength
= sizeof(IPv6_RAW_ADDRESS
);
174 SourceAddress
= SrcAddress
->Address
.IPv6Address
;
177 ReferenceObject(AddrFile
);
178 UnlockObject(AddrFile
, OldIrql
);
180 Status
= (*ReceiveHandler
)(HandlerContext
,
185 TDI_RECEIVE_ENTIRE_MESSAGE
,
192 DereferenceObject(AddrFile
);
196 UnlockObject(AddrFile
, OldIrql
);
197 TI_DbgPrint(MAX_TRACE
, ("Discarding datagram.\n"));
200 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
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"));
213 NTSTATUS
DGReceiveDatagram(
214 PADDRESS_FILE AddrFile
,
215 PTDI_CONNECTION_INFORMATION ConnInfo
,
219 PTDI_CONNECTION_INFORMATION ReturnInfo
,
220 PULONG BytesReceived
,
221 PDATAGRAM_COMPLETION_ROUTINE Complete
,
225 * FUNCTION: Attempts to receive an DG datagram from a remote address
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
235 * Status of operation
237 * This is the high level interface for receiving DG datagrams
241 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
244 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
246 LockObject(AddrFile
, &OldIrql
);
248 ReceiveRequest
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DATAGRAM_RECEIVE_REQUEST
),
252 /* Initialize a receive request */
254 /* Extract the remote address filter from the request (if any) */
255 if ((ConnInfo
->RemoteAddressLength
!= 0) &&
256 (ConnInfo
->RemoteAddress
))
258 Status
= AddrGetAddress(ConnInfo
->RemoteAddress
,
259 &ReceiveRequest
->RemoteAddress
,
260 &ReceiveRequest
->RemotePort
);
261 if (!NT_SUCCESS(Status
))
263 ExFreePoolWithTag(ReceiveRequest
, DATAGRAM_RECV_TAG
);
264 UnlockObject(AddrFile
, OldIrql
);
270 ReceiveRequest
->RemotePort
= 0;
271 AddrInitIPv4(&ReceiveRequest
->RemoteAddress
, 0);
274 IoMarkIrpPending(Irp
);
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
;
287 /* Queue receive request */
288 InsertTailList(&AddrFile
->ReceiveQueue
, &ReceiveRequest
->ListEntry
);
290 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending %08x).\n", ReceiveRequest
));
292 UnlockObject(AddrFile
, OldIrql
);
294 return STATUS_PENDING
;
298 UnlockObject(AddrFile
, OldIrql
);
299 Status
= STATUS_INSUFFICIENT_RESOURCES
;
302 TI_DbgPrint(MAX_TRACE
, ("Leaving with errors (0x%X).\n", Status
));