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
;
38 TI_DbgPrint(MID_TRACE
, ("Packet: %x NdisPacket %x\n",
39 IPPacket
, IPPacket
->NdisPacket
));
41 Status
= AddGenericHeaderIPv4
42 ( RemoteAddress
, RemotePort
,
43 LocalAddress
, LocalPort
,
44 IPPacket
, DataLength
, IPPROTO_UDP
,
45 sizeof(UDP_HEADER
), (PVOID
*)&UDPHeader
);
47 if (!NT_SUCCESS(Status
))
50 /* Build UDP header */
51 UDPHeader
= (PUDP_HEADER
)((ULONG_PTR
)IPPacket
->Data
- sizeof(UDP_HEADER
));
52 /* Port values are already big-endian values */
53 UDPHeader
->SourcePort
= LocalPort
;
54 UDPHeader
->DestPort
= RemotePort
;
55 /* FIXME: Calculate UDP checksum and put it in UDP header */
56 UDPHeader
->Checksum
= 0;
57 /* Length of UDP header and data */
58 UDPHeader
->Length
= WH2N(DataLength
+ sizeof(UDP_HEADER
));
60 IPPacket
->Data
= ((PCHAR
)UDPHeader
) + sizeof(UDP_HEADER
);
62 TI_DbgPrint(MID_TRACE
, ("Packet: %d ip %d udp %d payload\n",
63 (PCHAR
)UDPHeader
- (PCHAR
)IPPacket
->Header
,
64 (PCHAR
)IPPacket
->Data
- (PCHAR
)UDPHeader
,
67 return STATUS_SUCCESS
;
71 NTSTATUS
BuildUDPPacket(
73 PIP_ADDRESS RemoteAddress
,
75 PIP_ADDRESS LocalAddress
,
80 * FUNCTION: Builds an UDP packet
82 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
83 * LocalAddress = Pointer to our local address
84 * LocalPort = The port we send this datagram from
85 * IPPacket = Address of pointer to IP packet
92 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
94 /* FIXME: Assumes IPv4 */
95 IPInitializePacket(Packet
, IP_ADDRESS_V4
);
97 return STATUS_INSUFFICIENT_RESOURCES
;
99 Packet
->TotalSize
= sizeof(IPv4_HEADER
) + sizeof(UDP_HEADER
) + DataLen
;
102 Status
= AllocatePacketWithBuffer( &Packet
->NdisPacket
,
104 Packet
->TotalSize
+ MaxLLHeaderSize
);
106 if( !NT_SUCCESS(Status
) ) return Status
;
108 TI_DbgPrint(MID_TRACE
, ("Allocated packet: %x\n", Packet
->NdisPacket
));
109 TI_DbgPrint(MID_TRACE
, ("Local Addr : %s\n", A2S(LocalAddress
)));
110 TI_DbgPrint(MID_TRACE
, ("Remote Addr: %s\n", A2S(RemoteAddress
)));
112 switch (RemoteAddress
->Type
) {
114 Status
= AddUDPHeaderIPv4(RemoteAddress
, RemotePort
,
115 LocalAddress
, LocalPort
, Packet
, DataLen
);
118 /* FIXME: Support IPv6 */
119 TI_DbgPrint(MIN_TRACE
, ("IPv6 UDP datagrams are not supported.\n"));
121 Status
= STATUS_UNSUCCESSFUL
;
124 if (!NT_SUCCESS(Status
)) {
125 TI_DbgPrint(MIN_TRACE
, ("Cannot add UDP header. Status = (0x%X)\n",
127 FreeNdisPacket(Packet
->NdisPacket
);
131 TI_DbgPrint(MID_TRACE
, ("Copying data (hdr %x data %x (%d))\n",
132 Packet
->Header
, Packet
->Data
,
133 (PCHAR
)Packet
->Data
- (PCHAR
)Packet
->Header
));
135 RtlCopyMemory( Packet
->Data
, DataBuffer
, DataLen
);
137 TI_DbgPrint(MID_TRACE
, ("Displaying packet\n"));
139 DISPLAY_IP_PACKET(Packet
);
141 TI_DbgPrint(MID_TRACE
, ("Leaving\n"));
143 return STATUS_SUCCESS
;
146 VOID UDPSendPacketComplete
147 ( PVOID Context
, PNDIS_PACKET Packet
, NDIS_STATUS Status
) {
148 FreeNdisPacket( Packet
);
151 NTSTATUS
UDPSendDatagram(
152 PADDRESS_FILE AddrFile
,
153 PTDI_CONNECTION_INFORMATION ConnInfo
,
158 * FUNCTION: Sends an UDP datagram to a remote address
160 * Request = Pointer to TDI request
161 * ConnInfo = Pointer to connection information
162 * Buffer = Pointer to NDIS buffer with data
163 * DataSize = Size in bytes of data to be sent
165 * Status of operation
169 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
170 IP_ADDRESS RemoteAddress
;
173 PNEIGHBOR_CACHE_ENTRY NCE
;
175 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
176 AddrFile
, ConnInfo
, BufferData
, DataSize
));
177 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
179 switch( RemoteAddressTa
->Address
[0].AddressType
) {
180 case TDI_ADDRESS_TYPE_IP
:
181 RemoteAddress
.Type
= IP_ADDRESS_V4
;
182 RemoteAddress
.Address
.IPv4Address
=
183 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
184 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
188 return STATUS_UNSUCCESSFUL
;
191 Status
= BuildUDPPacket( &Packet
,
199 if( !NT_SUCCESS(Status
) )
202 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
))) {
203 FreeNdisPacket(Packet
.NdisPacket
);
204 return STATUS_UNSUCCESSFUL
;
207 IPSendDatagram( &Packet
, NCE
, UDPSendPacketComplete
, NULL
);
209 return STATUS_SUCCESS
;
213 VOID
UDPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
215 * FUNCTION: Receives and queues a UDP datagram
217 * NTE = Pointer to net table entry which the packet was received on
218 * IPPacket = Pointer to an IP packet that was received
220 * This is the low level interface for receiving UDP datagrams. It strips
221 * the UDP header from a packet and delivers the data to anyone that wants it
224 AF_SEARCH SearchContext
;
225 PIPv4_HEADER IPv4Header
;
226 PADDRESS_FILE AddrFile
;
227 PUDP_HEADER UDPHeader
;
228 PIP_ADDRESS DstAddress
, SrcAddress
;
231 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
233 switch (IPPacket
->Type
) {
236 IPv4Header
= IPPacket
->Header
;
237 DstAddress
= &IPPacket
->DstAddr
;
238 SrcAddress
= &IPPacket
->SrcAddr
;
243 TI_DbgPrint(MIN_TRACE
, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket
->TotalSize
));
245 /* FIXME: IPv6 is not supported */
252 UDPHeader
= (PUDP_HEADER
)IPPacket
->Data
;
254 /* FIXME: Calculate and validate UDP checksum */
257 i
= WH2N(UDPHeader
->Length
);
258 if ((i
< sizeof(UDP_HEADER
)) || (i
> IPPacket
->TotalSize
- IPPacket
->Position
)) {
259 /* Incorrect or damaged packet received, discard it */
260 TI_DbgPrint(MIN_TRACE
, ("Incorrect or damaged UDP packet received.\n"));
264 DataSize
= i
- sizeof(UDP_HEADER
);
266 /* Go to UDP data area */
267 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)IPPacket
->Data
+ sizeof(UDP_HEADER
));
269 /* Locate a receive request on destination address file object
270 and deliver the packet if one is found. If there is no receive
271 request on the address file object, call the associated receive
272 handler. If no receive handler is registered, drop the packet */
274 AddrFile
= AddrSearchFirst(DstAddress
,
280 DGDeliverData(AddrFile
,
283 UDPHeader
->SourcePort
,
287 } while ((AddrFile
= AddrSearchNext(&SearchContext
)) != NULL
);
289 /* There are no open address files that will take this datagram */
290 /* FIXME: IPv4 only */
291 TI_DbgPrint(MID_TRACE
, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
292 DN2H(DstAddress
->Address
.IPv4Address
)));
294 /* FIXME: Send ICMP reply */
296 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
303 * FUNCTION: Initializes the UDP subsystem
305 * Status of operation
309 RtlZeroMemory(&UDPStats
, sizeof(UDP_STATISTICS
));
314 Status
= PortsStartup( &UDPPorts
, 1, UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
316 if( !NT_SUCCESS(Status
) ) return Status
;
318 /* Register this protocol with IP layer */
319 IPRegisterProtocol(IPPROTO_UDP
, UDPReceive
);
321 UDPInitialized
= TRUE
;
323 return STATUS_SUCCESS
;
327 NTSTATUS
UDPShutdown(
330 * FUNCTION: Shuts down the UDP subsystem
332 * Status of operation
336 return STATUS_SUCCESS
;
338 PortsShutdown( &UDPPorts
);
340 /* Deregister this protocol with IP layer */
341 IPRegisterProtocol(IPPROTO_UDP
, NULL
);
343 UDPInitialized
= FALSE
;
345 return STATUS_SUCCESS
;
348 UINT
UDPAllocatePort( UINT HintPort
) {
350 if( AllocatePort( &UDPPorts
, HintPort
) ) return HintPort
;
351 else return (UINT
)-1;
352 } else return AllocatePortFromRange
353 ( &UDPPorts
, UDP_STARTING_PORT
,
354 UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
357 VOID
UDPFreePort( UINT Port
) {
358 DeallocatePort( &UDPPorts
, Port
);