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
13 BOOLEAN UDPInitialized
= FALSE
;
16 NTSTATUS
AddUDPHeaderIPv4(
17 PIP_ADDRESS RemoteAddress
,
19 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 /* Port values are already big-endian values */
51 UDPHeader
->SourcePort
= LocalPort
;
52 UDPHeader
->DestPort
= RemotePort
;
53 UDPHeader
->Checksum
= 0;
54 /* Length of UDP header and data */
55 UDPHeader
->Length
= WH2N(DataLength
+ sizeof(UDP_HEADER
));
57 TI_DbgPrint(MID_TRACE
, ("Copying data (hdr %x data %x (%d))\n",
58 IPPacket
->Header
, IPPacket
->Data
,
59 (PCHAR
)IPPacket
->Data
- (PCHAR
)IPPacket
->Header
));
61 RtlCopyMemory(IPPacket
->Data
, Data
, DataLength
);
63 UDPHeader
->Checksum
= UDPv4ChecksumCalculate((PIPv4_HEADER
)IPPacket
->Header
,
65 DataLength
+ sizeof(UDP_HEADER
));
66 UDPHeader
->Checksum
= WH2N(UDPHeader
->Checksum
);
68 TI_DbgPrint(MID_TRACE
, ("Packet: %d ip %d udp %d payload\n",
69 (PCHAR
)UDPHeader
- (PCHAR
)IPPacket
->Header
,
70 (PCHAR
)IPPacket
->Data
- (PCHAR
)UDPHeader
,
73 return STATUS_SUCCESS
;
77 NTSTATUS
BuildUDPPacket(
79 PIP_ADDRESS RemoteAddress
,
81 PIP_ADDRESS LocalAddress
,
86 * FUNCTION: Builds an UDP packet
88 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
89 * LocalAddress = Pointer to our local address
90 * LocalPort = The port we send this datagram from
91 * IPPacket = Address of pointer to IP packet
98 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
100 /* FIXME: Assumes IPv4 */
101 IPInitializePacket(Packet
, IP_ADDRESS_V4
);
103 Packet
->TotalSize
= sizeof(IPv4_HEADER
) + sizeof(UDP_HEADER
) + DataLen
;
106 Status
= AllocatePacketWithBuffer( &Packet
->NdisPacket
,
110 if( !NT_SUCCESS(Status
) ) return Status
;
112 TI_DbgPrint(MID_TRACE
, ("Allocated packet: %x\n", Packet
->NdisPacket
));
113 TI_DbgPrint(MID_TRACE
, ("Local Addr : %s\n", A2S(LocalAddress
)));
114 TI_DbgPrint(MID_TRACE
, ("Remote Addr: %s\n", A2S(RemoteAddress
)));
116 switch (RemoteAddress
->Type
) {
118 Status
= AddUDPHeaderIPv4(RemoteAddress
, RemotePort
,
119 LocalAddress
, LocalPort
, Packet
, DataBuffer
, DataLen
);
122 /* FIXME: Support IPv6 */
123 TI_DbgPrint(MIN_TRACE
, ("IPv6 UDP datagrams are not supported.\n"));
125 Status
= STATUS_UNSUCCESSFUL
;
128 if (!NT_SUCCESS(Status
)) {
129 TI_DbgPrint(MIN_TRACE
, ("Cannot add UDP header. Status = (0x%X)\n",
131 FreeNdisPacket(Packet
->NdisPacket
);
135 TI_DbgPrint(MID_TRACE
, ("Displaying packet\n"));
137 DISPLAY_IP_PACKET(Packet
);
139 TI_DbgPrint(MID_TRACE
, ("Leaving\n"));
141 return STATUS_SUCCESS
;
144 VOID UDPSendPacketComplete
145 ( PVOID Context
, PNDIS_PACKET Packet
, NDIS_STATUS Status
) {
146 FreeNdisPacket( Packet
);
149 NTSTATUS
UDPSendDatagram(
150 PADDRESS_FILE AddrFile
,
151 PTDI_CONNECTION_INFORMATION ConnInfo
,
156 * FUNCTION: Sends an UDP datagram to a remote address
158 * Request = Pointer to TDI request
159 * ConnInfo = Pointer to connection information
160 * Buffer = Pointer to NDIS buffer with data
161 * DataSize = Size in bytes of data to be sent
163 * Status of operation
167 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
168 IP_ADDRESS RemoteAddress
;
169 IP_ADDRESS LocalAddress
;
172 PNEIGHBOR_CACHE_ENTRY NCE
;
174 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
175 AddrFile
, ConnInfo
, BufferData
, DataSize
));
176 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
178 switch( RemoteAddressTa
->Address
[0].AddressType
) {
179 case TDI_ADDRESS_TYPE_IP
:
180 RemoteAddress
.Type
= IP_ADDRESS_V4
;
181 RemoteAddress
.Address
.IPv4Address
=
182 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
183 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
187 return STATUS_UNSUCCESSFUL
;
190 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
))) {
191 return STATUS_NETWORK_UNREACHABLE
;
194 LocalAddress
= AddrFile
->Address
;
195 if (AddrIsUnspecified(&LocalAddress
))
197 /* If the local address is unspecified (0),
198 * then use the unicast address of the
199 * interface we're sending over
201 LocalAddress
= NCE
->Interface
->Unicast
;
204 Status
= BuildUDPPacket( &Packet
,
212 if( !NT_SUCCESS(Status
) )
215 if (!NT_SUCCESS(Status
= IPSendDatagram( &Packet
, NCE
, UDPSendPacketComplete
, NULL
)))
217 FreeNdisPacket(Packet
.NdisPacket
);
221 return STATUS_SUCCESS
;
225 VOID
UDPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
227 * FUNCTION: Receives and queues a UDP datagram
229 * NTE = Pointer to net table entry which the packet was received on
230 * IPPacket = Pointer to an IP packet that was received
232 * This is the low level interface for receiving UDP datagrams. It strips
233 * the UDP header from a packet and delivers the data to anyone that wants it
236 AF_SEARCH SearchContext
;
237 PIPv4_HEADER IPv4Header
;
238 PADDRESS_FILE AddrFile
;
239 PUDP_HEADER UDPHeader
;
240 PIP_ADDRESS DstAddress
, SrcAddress
;
243 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
245 switch (IPPacket
->Type
) {
248 IPv4Header
= IPPacket
->Header
;
249 DstAddress
= &IPPacket
->DstAddr
;
250 SrcAddress
= &IPPacket
->SrcAddr
;
255 TI_DbgPrint(MIN_TRACE
, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket
->TotalSize
));
257 /* FIXME: IPv6 is not supported */
264 UDPHeader
= (PUDP_HEADER
)IPPacket
->Data
;
266 /* Calculate and validate UDP checksum */
267 i
= UDPv4ChecksumCalculate(IPv4Header
,
269 WH2N(UDPHeader
->Length
));
270 if (i
!= DH2N(0x0000FFFF) && UDPHeader
->Checksum
!= 0)
272 TI_DbgPrint(MIN_TRACE
, ("Bad checksum on packet received.\n"));
277 i
= WH2N(UDPHeader
->Length
);
278 if ((i
< sizeof(UDP_HEADER
)) || (i
> IPPacket
->TotalSize
- IPPacket
->Position
)) {
279 /* Incorrect or damaged packet received, discard it */
280 TI_DbgPrint(MIN_TRACE
, ("Incorrect or damaged UDP packet received.\n"));
284 DataSize
= i
- sizeof(UDP_HEADER
);
286 /* Go to UDP data area */
287 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)IPPacket
->Data
+ sizeof(UDP_HEADER
));
289 /* Locate a receive request on destination address file object
290 and deliver the packet if one is found. If there is no receive
291 request on the address file object, call the associated receive
292 handler. If no receive handler is registered, drop the packet */
294 AddrFile
= AddrSearchFirst(DstAddress
,
300 DGDeliverData(AddrFile
,
303 UDPHeader
->SourcePort
,
307 } while ((AddrFile
= AddrSearchNext(&SearchContext
)) != NULL
);
309 /* There are no open address files that will take this datagram */
310 /* FIXME: IPv4 only */
311 TI_DbgPrint(MID_TRACE
, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
312 DN2H(DstAddress
->Address
.IPv4Address
)));
314 /* FIXME: Send ICMP reply */
316 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
323 * FUNCTION: Initializes the UDP subsystem
325 * Status of operation
331 RtlZeroMemory(&UDPStats
, sizeof(UDP_STATISTICS
));
334 Status
= PortsStartup( &UDPPorts
, 1, UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
336 if( !NT_SUCCESS(Status
) ) return Status
;
338 /* Register this protocol with IP layer */
339 IPRegisterProtocol(IPPROTO_UDP
, UDPReceive
);
341 UDPInitialized
= TRUE
;
343 return STATUS_SUCCESS
;
347 NTSTATUS
UDPShutdown(
350 * FUNCTION: Shuts down the UDP subsystem
352 * Status of operation
356 return STATUS_SUCCESS
;
358 PortsShutdown( &UDPPorts
);
360 /* Deregister this protocol with IP layer */
361 IPRegisterProtocol(IPPROTO_UDP
, NULL
);
363 UDPInitialized
= FALSE
;
365 return STATUS_SUCCESS
;
368 UINT
UDPAllocatePort( UINT HintPort
) {
370 if( AllocatePort( &UDPPorts
, HintPort
) ) return HintPort
;
371 else return (UINT
)-1;
372 } else return AllocatePortFromRange
373 ( &UDPPorts
, UDP_STARTING_PORT
,
374 UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
377 VOID
UDPFreePort( UINT Port
) {
378 DeallocatePort( &UDPPorts
, Port
);