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 PADDRESS_FILE AddrFile
,
18 PIP_ADDRESS RemoteAddress
,
20 PIP_ADDRESS LocalAddress
,
26 * FUNCTION: Adds an IPv4 and UDP header to an IP packet
28 * SendRequest = Pointer to send request
29 * LocalAddress = Pointer to our local address
30 * LocalPort = The port we send this datagram from
31 * IPPacket = Pointer to IP packet
36 PUDP_HEADER UDPHeader
;
39 TI_DbgPrint(MID_TRACE
, ("Packet: %x NdisPacket %x\n",
40 IPPacket
, IPPacket
->NdisPacket
));
42 Status
= AddGenericHeaderIPv4
43 ( AddrFile
, RemoteAddress
, RemotePort
,
44 LocalAddress
, LocalPort
,
45 IPPacket
, DataLength
, IPPROTO_UDP
,
46 sizeof(UDP_HEADER
), (PVOID
*)&UDPHeader
);
48 if (!NT_SUCCESS(Status
))
51 /* Port values are already big-endian values */
52 UDPHeader
->SourcePort
= LocalPort
;
53 UDPHeader
->DestPort
= RemotePort
;
54 UDPHeader
->Checksum
= 0;
55 /* Length of UDP header and data */
56 UDPHeader
->Length
= WH2N(DataLength
+ sizeof(UDP_HEADER
));
58 TI_DbgPrint(MID_TRACE
, ("Copying data (hdr %x data %x (%d))\n",
59 IPPacket
->Header
, IPPacket
->Data
,
60 (PCHAR
)IPPacket
->Data
- (PCHAR
)IPPacket
->Header
));
62 RtlCopyMemory(IPPacket
->Data
, Data
, DataLength
);
64 UDPHeader
->Checksum
= UDPv4ChecksumCalculate((PIPv4_HEADER
)IPPacket
->Header
,
66 DataLength
+ sizeof(UDP_HEADER
));
67 UDPHeader
->Checksum
= WH2N(UDPHeader
->Checksum
);
69 TI_DbgPrint(MID_TRACE
, ("Packet: %d ip %d udp %d payload\n",
70 (PCHAR
)UDPHeader
- (PCHAR
)IPPacket
->Header
,
71 (PCHAR
)IPPacket
->Data
- (PCHAR
)UDPHeader
,
74 return STATUS_SUCCESS
;
78 NTSTATUS
BuildUDPPacket(
79 PADDRESS_FILE AddrFile
,
81 PIP_ADDRESS RemoteAddress
,
83 PIP_ADDRESS LocalAddress
,
88 * FUNCTION: Builds an UDP packet
90 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
91 * LocalAddress = Pointer to our local address
92 * LocalPort = The port we send this datagram from
93 * IPPacket = Address of pointer to IP packet
100 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
102 /* FIXME: Assumes IPv4 */
103 IPInitializePacket(Packet
, IP_ADDRESS_V4
);
105 Packet
->TotalSize
= sizeof(IPv4_HEADER
) + sizeof(UDP_HEADER
) + DataLen
;
108 Status
= AllocatePacketWithBuffer(&Packet
->NdisPacket
,
112 if( !NT_SUCCESS(Status
) )
114 Packet
->Free(Packet
);
118 TI_DbgPrint(MID_TRACE
, ("Allocated packet: %x\n", Packet
->NdisPacket
));
119 TI_DbgPrint(MID_TRACE
, ("Local Addr : %s\n", A2S(LocalAddress
)));
120 TI_DbgPrint(MID_TRACE
, ("Remote Addr: %s\n", A2S(RemoteAddress
)));
122 switch (RemoteAddress
->Type
) {
124 Status
= AddUDPHeaderIPv4(AddrFile
, RemoteAddress
, RemotePort
,
125 LocalAddress
, LocalPort
, Packet
, DataBuffer
, DataLen
);
128 /* FIXME: Support IPv6 */
129 TI_DbgPrint(MIN_TRACE
, ("IPv6 UDP datagrams are not supported.\n"));
131 Status
= STATUS_UNSUCCESSFUL
;
134 if (!NT_SUCCESS(Status
)) {
135 TI_DbgPrint(MIN_TRACE
, ("Cannot add UDP header. Status = (0x%X)\n",
137 Packet
->Free(Packet
);
141 TI_DbgPrint(MID_TRACE
, ("Displaying packet\n"));
143 DISPLAY_IP_PACKET(Packet
);
145 TI_DbgPrint(MID_TRACE
, ("Leaving\n"));
147 return STATUS_SUCCESS
;
150 NTSTATUS
UDPSendDatagram(
151 PADDRESS_FILE AddrFile
,
152 PTDI_CONNECTION_INFORMATION ConnInfo
,
157 * FUNCTION: Sends an UDP datagram to a remote address
159 * Request = Pointer to TDI request
160 * ConnInfo = Pointer to connection information
161 * Buffer = Pointer to NDIS buffer with data
162 * DataSize = Size in bytes of data to be sent
164 * Status of operation
168 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
169 IP_ADDRESS RemoteAddress
;
170 IP_ADDRESS LocalAddress
;
173 PNEIGHBOR_CACHE_ENTRY NCE
;
176 LockObject(AddrFile
, &OldIrql
);
178 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
179 AddrFile
, ConnInfo
, BufferData
, DataSize
));
180 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
182 switch( RemoteAddressTa
->Address
[0].AddressType
) {
183 case TDI_ADDRESS_TYPE_IP
:
184 RemoteAddress
.Type
= IP_ADDRESS_V4
;
185 RemoteAddress
.Address
.IPv4Address
=
186 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
187 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
191 UnlockObject(AddrFile
, OldIrql
);
192 return STATUS_UNSUCCESSFUL
;
195 LocalAddress
= AddrFile
->Address
;
196 if (AddrIsUnspecified(&LocalAddress
))
198 /* If the local address is unspecified (0),
199 * then use the unicast address of the
200 * interface we're sending over
202 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
))) {
203 UnlockObject(AddrFile
, OldIrql
);
204 return STATUS_NETWORK_UNREACHABLE
;
207 LocalAddress
= NCE
->Interface
->Unicast
;
211 if(!(NCE
= NBLocateNeighbor( &LocalAddress
, NULL
))) {
212 UnlockObject(AddrFile
, OldIrql
);
213 return STATUS_INVALID_PARAMETER
;
217 Status
= BuildUDPPacket( AddrFile
,
226 UnlockObject(AddrFile
, OldIrql
);
228 if( !NT_SUCCESS(Status
) )
231 Status
= IPSendDatagram(&Packet
, NCE
);
232 if (!NT_SUCCESS(Status
))
235 *DataUsed
= DataSize
;
237 return STATUS_SUCCESS
;
241 VOID
UDPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
243 * FUNCTION: Receives and queues a UDP datagram
245 * NTE = Pointer to net table entry which the packet was received on
246 * IPPacket = Pointer to an IP packet that was received
248 * This is the low level interface for receiving UDP datagrams. It strips
249 * the UDP header from a packet and delivers the data to anyone that wants it
252 AF_SEARCH SearchContext
;
253 PIPv4_HEADER IPv4Header
;
254 PADDRESS_FILE AddrFile
;
255 PUDP_HEADER UDPHeader
;
256 PIP_ADDRESS DstAddress
, SrcAddress
;
259 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
261 switch (IPPacket
->Type
) {
264 IPv4Header
= IPPacket
->Header
;
265 DstAddress
= &IPPacket
->DstAddr
;
266 SrcAddress
= &IPPacket
->SrcAddr
;
271 TI_DbgPrint(MIN_TRACE
, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket
->TotalSize
));
273 /* FIXME: IPv6 is not supported */
280 UDPHeader
= (PUDP_HEADER
)IPPacket
->Data
;
282 /* Calculate and validate UDP checksum */
283 i
= UDPv4ChecksumCalculate(IPv4Header
,
285 WH2N(UDPHeader
->Length
));
286 if (i
!= DH2N(0x0000FFFF) && UDPHeader
->Checksum
!= 0)
288 TI_DbgPrint(MIN_TRACE
, ("Bad checksum on packet received.\n"));
293 i
= WH2N(UDPHeader
->Length
);
294 if ((i
< sizeof(UDP_HEADER
)) || (i
> IPPacket
->TotalSize
- IPPacket
->Position
)) {
295 /* Incorrect or damaged packet received, discard it */
296 TI_DbgPrint(MIN_TRACE
, ("Incorrect or damaged UDP packet received.\n"));
300 DataSize
= i
- sizeof(UDP_HEADER
);
302 /* Go to UDP data area */
303 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)IPPacket
->Data
+ sizeof(UDP_HEADER
));
305 /* Locate a receive request on destination address file object
306 and deliver the packet if one is found. If there is no receive
307 request on the address file object, call the associated receive
308 handler. If no receive handler is registered, drop the packet */
310 AddrFile
= AddrSearchFirst(DstAddress
,
316 DGDeliverData(AddrFile
,
319 UDPHeader
->SourcePort
,
323 } while ((AddrFile
= AddrSearchNext(&SearchContext
)) != NULL
);
325 /* There are no open address files that will take this datagram */
326 /* FIXME: IPv4 only */
327 TI_DbgPrint(MID_TRACE
, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
328 DN2H(DstAddress
->Address
.IPv4Address
)));
330 /* FIXME: Send ICMP reply */
332 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
339 * FUNCTION: Initializes the UDP subsystem
341 * Status of operation
347 RtlZeroMemory(&UDPStats
, sizeof(UDP_STATISTICS
));
350 Status
= PortsStartup( &UDPPorts
, 1, UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
352 if( !NT_SUCCESS(Status
) ) return Status
;
354 /* Register this protocol with IP layer */
355 IPRegisterProtocol(IPPROTO_UDP
, UDPReceive
);
357 UDPInitialized
= TRUE
;
359 return STATUS_SUCCESS
;
363 NTSTATUS
UDPShutdown(
366 * FUNCTION: Shuts down the UDP subsystem
368 * Status of operation
372 return STATUS_SUCCESS
;
374 PortsShutdown( &UDPPorts
);
376 /* Deregister this protocol with IP layer */
377 IPRegisterProtocol(IPPROTO_UDP
, NULL
);
379 UDPInitialized
= FALSE
;
381 return STATUS_SUCCESS
;
384 UINT
UDPAllocatePort( UINT HintPort
) {
386 if( AllocatePort( &UDPPorts
, HintPort
) ) return HintPort
;
387 else return (UINT
)-1;
388 } else return AllocatePortFromRange
389 ( &UDPPorts
, UDP_STARTING_PORT
,
390 UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
393 VOID
UDPFreePort( UINT Port
) {
394 DeallocatePort( &UDPPorts
, Port
);