2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/udp/udp.c
5 * PURPOSE: User Datagram Protocol routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
14 BOOLEAN UDPInitialized
= FALSE
;
17 NTSTATUS
AddUDPHeaderIPv4(
18 PIP_ADDRESS RemoteAddress
,
20 PIP_ADDRESS LocalAddress
,
25 * FUNCTION: Adds an IPv4 and UDP header to an IP packet
27 * SendRequest = Pointer to send request
28 * LocalAddress = Pointer to our local address
29 * LocalPort = The port we send this datagram from
30 * IPPacket = Pointer to IP packet
35 PUDP_HEADER UDPHeader
;
37 TI_DbgPrint(MID_TRACE
, ("Packet: %x NdisPacket %x\n",
38 IPPacket
, IPPacket
->NdisPacket
));
41 ( RemoteAddress
, RemotePort
,
42 LocalAddress
, LocalPort
,
43 IPPacket
, DataLength
, IPPROTO_UDP
,
44 sizeof(UDP_HEADER
), (PVOID
*)&UDPHeader
);
46 /* Build UDP header */
47 UDPHeader
= (PUDP_HEADER
)(IPPacket
->Data
- sizeof(UDP_HEADER
));
48 /* Port values are already big-endian values */
49 UDPHeader
->SourcePort
= LocalPort
;
50 UDPHeader
->DestPort
= RemotePort
;
51 /* FIXME: Calculate UDP checksum and put it in UDP header */
52 UDPHeader
->Checksum
= 0;
53 /* Length of UDP header and data */
54 UDPHeader
->Length
= WH2N(DataLength
+ sizeof(UDP_HEADER
));
56 IPPacket
->Data
= ((PCHAR
)UDPHeader
) + sizeof(UDP_HEADER
);
58 TI_DbgPrint(MID_TRACE
, ("Packet: %d ip %d udp %d payload\n",
59 (PCHAR
)UDPHeader
- (PCHAR
)IPPacket
->Header
,
60 (PCHAR
)IPPacket
->Data
- (PCHAR
)UDPHeader
,
63 return STATUS_SUCCESS
;
67 NTSTATUS
BuildUDPPacket(
69 PIP_ADDRESS RemoteAddress
,
71 PIP_ADDRESS LocalAddress
,
76 * FUNCTION: Builds an UDP packet
78 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
79 * LocalAddress = Pointer to our local address
80 * LocalPort = The port we send this datagram from
81 * IPPacket = Address of pointer to IP packet
88 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
90 /* FIXME: Assumes IPv4 */
91 IPInitializePacket(Packet
, IP_ADDRESS_V4
);
93 return STATUS_INSUFFICIENT_RESOURCES
;
95 Packet
->TotalSize
= sizeof(IPv4_HEADER
) + sizeof(UDP_HEADER
) + DataLen
;
98 Status
= AllocatePacketWithBuffer( &Packet
->NdisPacket
,
100 Packet
->TotalSize
+ MaxLLHeaderSize
);
102 if( !NT_SUCCESS(Status
) ) return Status
;
104 TI_DbgPrint(MID_TRACE
, ("Allocated packet: %x\n", Packet
->NdisPacket
));
105 TI_DbgPrint(MID_TRACE
, ("Local Addr : %s\n", A2S(LocalAddress
)));
106 TI_DbgPrint(MID_TRACE
, ("Remote Addr: %s\n", A2S(RemoteAddress
)));
108 switch (RemoteAddress
->Type
) {
110 Status
= AddUDPHeaderIPv4(RemoteAddress
, RemotePort
,
111 LocalAddress
, LocalPort
, Packet
, DataLen
);
114 /* FIXME: Support IPv6 */
115 TI_DbgPrint(MIN_TRACE
, ("IPv6 UDP datagrams are not supported.\n"));
117 Status
= STATUS_UNSUCCESSFUL
;
120 if (!NT_SUCCESS(Status
)) {
121 TI_DbgPrint(MIN_TRACE
, ("Cannot add UDP header. Status = (0x%X)\n",
123 FreeNdisPacket(Packet
->NdisPacket
);
127 TI_DbgPrint(MID_TRACE
, ("Copying data (hdr %x data %x (%d))\n",
128 Packet
->Header
, Packet
->Data
,
129 (PCHAR
)Packet
->Data
- (PCHAR
)Packet
->Header
));
131 RtlCopyMemory( Packet
->Data
, DataBuffer
, DataLen
);
133 TI_DbgPrint(MID_TRACE
, ("Displaying packet\n"));
135 DISPLAY_IP_PACKET(Packet
);
137 TI_DbgPrint(MID_TRACE
, ("Leaving\n"));
139 return STATUS_SUCCESS
;
142 VOID UDPSendPacketComplete
143 ( PVOID Context
, PNDIS_PACKET Packet
, NDIS_STATUS Status
) {
144 FreeNdisPacket( Packet
);
147 NTSTATUS
UDPSendDatagram(
148 PADDRESS_FILE AddrFile
,
149 PTDI_CONNECTION_INFORMATION ConnInfo
,
154 * FUNCTION: Sends an UDP datagram to a remote address
156 * Request = Pointer to TDI request
157 * ConnInfo = Pointer to connection information
158 * Buffer = Pointer to NDIS buffer with data
159 * DataSize = Size in bytes of data to be sent
161 * Status of operation
165 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
166 IP_ADDRESS RemoteAddress
;
169 PNEIGHBOR_CACHE_ENTRY NCE
;
171 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
172 AddrFile
, ConnInfo
, BufferData
, DataSize
));
173 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
175 switch( RemoteAddressTa
->Address
[0].AddressType
) {
176 case TDI_ADDRESS_TYPE_IP
:
177 RemoteAddress
.Type
= IP_ADDRESS_V4
;
178 RemoteAddress
.Address
.IPv4Address
=
179 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
180 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
184 return STATUS_UNSUCCESSFUL
;
187 Status
= BuildUDPPacket( &Packet
,
195 if( !NT_SUCCESS(Status
) )
198 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
)))
199 return STATUS_UNSUCCESSFUL
;
201 IPSendDatagram( &Packet
, NCE
, UDPSendPacketComplete
, NULL
);
203 return STATUS_SUCCESS
;
206 VOID
UDPReceiveComplete(PVOID Context
, NTSTATUS Status
, ULONG Count
) {
207 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
=
208 (PDATAGRAM_RECEIVE_REQUEST
)Context
;
209 TI_DbgPrint(MAX_TRACE
,("Called\n"));
210 ReceiveRequest
->UserComplete( ReceiveRequest
->UserContext
, Status
, Count
);
211 exFreePool( ReceiveRequest
);
212 TI_DbgPrint(MAX_TRACE
,("Done\n"));
215 NTSTATUS
UDPReceiveDatagram(
216 PADDRESS_FILE AddrFile
,
217 PTDI_CONNECTION_INFORMATION ConnInfo
,
221 PTDI_CONNECTION_INFORMATION ReturnInfo
,
222 PULONG BytesReceived
,
223 PDATAGRAM_COMPLETION_ROUTINE Complete
,
226 * FUNCTION: Attempts to receive an UDP datagram from a remote address
228 * Request = Pointer to TDI request
229 * ConnInfo = Pointer to connection information
230 * Buffer = Pointer to NDIS buffer chain to store received data
231 * ReceiveLength = Maximum size to use of buffer, 0 if all can be used
232 * ReceiveFlags = Receive flags (None, Normal, Peek)
233 * ReturnInfo = Pointer to structure for return information
234 * BytesReceive = Pointer to structure for number of bytes received
236 * Status of operation
238 * This is the high level interface for receiving UDP datagrams
243 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
245 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
247 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
249 if (AF_IS_VALID(AddrFile
))
251 ReceiveRequest
= exAllocatePool(NonPagedPool
, sizeof(DATAGRAM_RECEIVE_REQUEST
));
254 /* Initialize a receive request */
256 /* Extract the remote address filter from the request (if any) */
257 if ((ConnInfo
->RemoteAddressLength
!= 0) &&
258 (ConnInfo
->RemoteAddress
))
260 Status
= AddrGetAddress(ConnInfo
->RemoteAddress
,
261 &ReceiveRequest
->RemoteAddress
,
262 &ReceiveRequest
->RemotePort
);
263 if (!NT_SUCCESS(Status
))
265 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
266 exFreePool(ReceiveRequest
);
272 ReceiveRequest
->RemotePort
= 0;
274 ReceiveRequest
->ReturnInfo
= ReturnInfo
;
275 ReceiveRequest
->Buffer
= BufferData
;
276 ReceiveRequest
->BufferSize
= ReceiveLength
;
277 ReceiveRequest
->UserComplete
= Complete
;
278 ReceiveRequest
->UserContext
= Context
;
279 ReceiveRequest
->Complete
=
280 (PDATAGRAM_COMPLETION_ROUTINE
)UDPReceiveComplete
;
281 ReceiveRequest
->Context
= ReceiveRequest
;
283 /* Queue receive request */
284 InsertTailList(&AddrFile
->ReceiveQueue
, &ReceiveRequest
->ListEntry
);
285 AF_SET_PENDING(AddrFile
, AFF_RECEIVE
);
287 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
289 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending).\n"));
291 return STATUS_PENDING
;
295 Status
= STATUS_INSUFFICIENT_RESOURCES
;
300 Status
= STATUS_INVALID_ADDRESS
;
303 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
305 TI_DbgPrint(MAX_TRACE
, ("Leaving with errors (0x%X).\n", Status
));
311 VOID
UDPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
313 * FUNCTION: Receives and queues a UDP datagram
315 * NTE = Pointer to net table entry which the packet was received on
316 * IPPacket = Pointer to an IP packet that was received
318 * This is the low level interface for receiving UDP datagrams. It strips
319 * the UDP header from a packet and delivers the data to anyone that wants it
322 AF_SEARCH SearchContext
;
323 PIPv4_HEADER IPv4Header
;
324 PADDRESS_FILE AddrFile
;
325 PUDP_HEADER UDPHeader
;
326 PIP_ADDRESS DstAddress
, SrcAddress
;
329 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
331 switch (IPPacket
->Type
) {
334 IPv4Header
= IPPacket
->Header
;
335 DstAddress
= &IPPacket
->DstAddr
;
336 SrcAddress
= &IPPacket
->SrcAddr
;
341 TI_DbgPrint(MIN_TRACE
, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket
->TotalSize
));
343 /* FIXME: IPv6 is not supported */
350 UDPHeader
= (PUDP_HEADER
)IPPacket
->Data
;
352 /* FIXME: Calculate and validate UDP checksum */
355 i
= WH2N(UDPHeader
->Length
);
356 if ((i
< sizeof(UDP_HEADER
)) || (i
> IPPacket
->TotalSize
- IPPacket
->Position
)) {
357 /* Incorrect or damaged packet received, discard it */
358 TI_DbgPrint(MIN_TRACE
, ("Incorrect or damaged UDP packet received.\n"));
362 DataSize
= i
- sizeof(UDP_HEADER
);
364 /* Go to UDP data area */
365 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)IPPacket
->Data
+ sizeof(UDP_HEADER
));
367 /* Locate a receive request on destination address file object
368 and deliver the packet if one is found. If there is no receive
369 request on the address file object, call the associated receive
370 handler. If no receive handler is registered, drop the packet */
372 AddrFile
= AddrSearchFirst(DstAddress
,
378 DGDeliverData(AddrFile
,
381 UDPHeader
->SourcePort
,
385 } while ((AddrFile
= AddrSearchNext(&SearchContext
)) != NULL
);
387 /* There are no open address files that will take this datagram */
388 /* FIXME: IPv4 only */
389 TI_DbgPrint(MID_TRACE
, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
390 DN2H(DstAddress
->Address
.IPv4Address
)));
392 /* FIXME: Send ICMP reply */
394 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
401 * FUNCTION: Initializes the UDP subsystem
403 * Status of operation
407 RtlZeroMemory(&UDPStats
, sizeof(UDP_STATISTICS
));
410 PortsStartup( &UDPPorts
, 1, 0xfffe );
412 /* Register this protocol with IP layer */
413 IPRegisterProtocol(IPPROTO_UDP
, UDPReceive
);
415 UDPInitialized
= TRUE
;
417 return STATUS_SUCCESS
;
421 NTSTATUS
UDPShutdown(
424 * FUNCTION: Shuts down the UDP subsystem
426 * Status of operation
430 return STATUS_SUCCESS
;
432 PortsShutdown( &UDPPorts
);
434 /* Deregister this protocol with IP layer */
435 IPRegisterProtocol(IPPROTO_UDP
, NULL
);
437 return STATUS_SUCCESS
;
440 UINT
UDPAllocatePort( UINT HintPort
) {
442 if( AllocatePort( &UDPPorts
, HintPort
) ) return HintPort
;
443 else return (UINT
)-1;
444 } else return AllocatePortFromRange
445 ( &UDPPorts
, UDP_STARTING_PORT
,
446 UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
449 VOID
UDPFreePort( UINT Port
) {
450 DeallocatePort( &UDPPorts
, Port
);