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
) ) return Status
;
114 TI_DbgPrint(MID_TRACE
, ("Allocated packet: %x\n", Packet
->NdisPacket
));
115 TI_DbgPrint(MID_TRACE
, ("Local Addr : %s\n", A2S(LocalAddress
)));
116 TI_DbgPrint(MID_TRACE
, ("Remote Addr: %s\n", A2S(RemoteAddress
)));
118 switch (RemoteAddress
->Type
) {
120 Status
= AddUDPHeaderIPv4(AddrFile
, RemoteAddress
, RemotePort
,
121 LocalAddress
, LocalPort
, Packet
, DataBuffer
, DataLen
);
124 /* FIXME: Support IPv6 */
125 TI_DbgPrint(MIN_TRACE
, ("IPv6 UDP datagrams are not supported.\n"));
127 Status
= STATUS_UNSUCCESSFUL
;
130 if (!NT_SUCCESS(Status
)) {
131 TI_DbgPrint(MIN_TRACE
, ("Cannot add UDP header. Status = (0x%X)\n",
133 FreeNdisPacket(Packet
->NdisPacket
);
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
;
171 IP_ADDRESS LocalAddress
;
174 PNEIGHBOR_CACHE_ENTRY NCE
;
177 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
179 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
180 AddrFile
, ConnInfo
, BufferData
, DataSize
));
181 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
183 switch( RemoteAddressTa
->Address
[0].AddressType
) {
184 case TDI_ADDRESS_TYPE_IP
:
185 RemoteAddress
.Type
= IP_ADDRESS_V4
;
186 RemoteAddress
.Address
.IPv4Address
=
187 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
188 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
192 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
193 return STATUS_UNSUCCESSFUL
;
196 LocalAddress
= AddrFile
->Address
;
197 if (AddrIsUnspecified(&LocalAddress
))
199 /* If the local address is unspecified (0),
200 * then use the unicast address of the
201 * interface we're sending over
203 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
))) {
204 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
205 return STATUS_NETWORK_UNREACHABLE
;
208 LocalAddress
= NCE
->Interface
->Unicast
;
212 if(!(NCE
= NBLocateNeighbor( &LocalAddress
))) {
213 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
214 return STATUS_INVALID_PARAMETER
;
218 Status
= BuildUDPPacket( AddrFile
,
227 if( !NT_SUCCESS(Status
) )
229 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
233 if (!NT_SUCCESS(Status
= IPSendDatagram( &Packet
, NCE
, UDPSendPacketComplete
, NULL
)))
235 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
236 FreeNdisPacket(Packet
.NdisPacket
);
240 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
242 return STATUS_SUCCESS
;
246 VOID
UDPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
248 * FUNCTION: Receives and queues a UDP datagram
250 * NTE = Pointer to net table entry which the packet was received on
251 * IPPacket = Pointer to an IP packet that was received
253 * This is the low level interface for receiving UDP datagrams. It strips
254 * the UDP header from a packet and delivers the data to anyone that wants it
257 AF_SEARCH SearchContext
;
258 PIPv4_HEADER IPv4Header
;
259 PADDRESS_FILE AddrFile
;
260 PUDP_HEADER UDPHeader
;
261 PIP_ADDRESS DstAddress
, SrcAddress
;
264 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
266 switch (IPPacket
->Type
) {
269 IPv4Header
= IPPacket
->Header
;
270 DstAddress
= &IPPacket
->DstAddr
;
271 SrcAddress
= &IPPacket
->SrcAddr
;
276 TI_DbgPrint(MIN_TRACE
, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket
->TotalSize
));
278 /* FIXME: IPv6 is not supported */
285 UDPHeader
= (PUDP_HEADER
)IPPacket
->Data
;
287 /* Calculate and validate UDP checksum */
288 i
= UDPv4ChecksumCalculate(IPv4Header
,
290 WH2N(UDPHeader
->Length
));
291 if (i
!= DH2N(0x0000FFFF) && UDPHeader
->Checksum
!= 0)
293 TI_DbgPrint(MIN_TRACE
, ("Bad checksum on packet received.\n"));
298 i
= WH2N(UDPHeader
->Length
);
299 if ((i
< sizeof(UDP_HEADER
)) || (i
> IPPacket
->TotalSize
- IPPacket
->Position
)) {
300 /* Incorrect or damaged packet received, discard it */
301 TI_DbgPrint(MIN_TRACE
, ("Incorrect or damaged UDP packet received.\n"));
305 DataSize
= i
- sizeof(UDP_HEADER
);
307 /* Go to UDP data area */
308 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)IPPacket
->Data
+ sizeof(UDP_HEADER
));
310 /* Locate a receive request on destination address file object
311 and deliver the packet if one is found. If there is no receive
312 request on the address file object, call the associated receive
313 handler. If no receive handler is registered, drop the packet */
315 AddrFile
= AddrSearchFirst(DstAddress
,
321 DGDeliverData(AddrFile
,
324 UDPHeader
->SourcePort
,
328 } while ((AddrFile
= AddrSearchNext(&SearchContext
)) != NULL
);
330 /* There are no open address files that will take this datagram */
331 /* FIXME: IPv4 only */
332 TI_DbgPrint(MID_TRACE
, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
333 DN2H(DstAddress
->Address
.IPv4Address
)));
335 /* FIXME: Send ICMP reply */
337 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
344 * FUNCTION: Initializes the UDP subsystem
346 * Status of operation
352 RtlZeroMemory(&UDPStats
, sizeof(UDP_STATISTICS
));
355 Status
= PortsStartup( &UDPPorts
, 1, UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
357 if( !NT_SUCCESS(Status
) ) return Status
;
359 /* Register this protocol with IP layer */
360 IPRegisterProtocol(IPPROTO_UDP
, UDPReceive
);
362 UDPInitialized
= TRUE
;
364 return STATUS_SUCCESS
;
368 NTSTATUS
UDPShutdown(
371 * FUNCTION: Shuts down the UDP subsystem
373 * Status of operation
377 return STATUS_SUCCESS
;
379 PortsShutdown( &UDPPorts
);
381 /* Deregister this protocol with IP layer */
382 IPRegisterProtocol(IPPROTO_UDP
, NULL
);
384 UDPInitialized
= FALSE
;
386 return STATUS_SUCCESS
;
389 UINT
UDPAllocatePort( UINT HintPort
) {
391 if( AllocatePort( &UDPPorts
, HintPort
) ) return HintPort
;
392 else return (UINT
)-1;
393 } else return AllocatePortFromRange
394 ( &UDPPorts
, UDP_STARTING_PORT
,
395 UDP_STARTING_PORT
+ UDP_DYNAMIC_PORTS
);
398 VOID
UDPFreePort( UINT Port
) {
399 DeallocatePort( &UDPPorts
, Port
);