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
20 BOOLEAN UDPInitialized = FALSE;
23 NTSTATUS AddUDPHeaderIPv4(
24 PDATAGRAM_SEND_REQUEST SendRequest,
25 PIP_ADDRESS LocalAddress,
29 * FUNCTION: Adds an IPv4 and UDP header to an IP packet
31 * SendRequest = Pointer to send request
32 * LocalAddress = Pointer to our local address
33 * LocalPort = The port we send this datagram from
34 * IPPacket = Pointer to IP packet
39 PIPv4_HEADER IPHeader;
40 PUDP_HEADER UDPHeader;
43 NDIS_STATUS NdisStatus;
44 PNDIS_BUFFER HeaderBuffer;
46 BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER);
47 Header = ExAllocatePool(NonPagedPool, BufferSize);
49 TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));
50 return STATUS_INSUFFICIENT_RESOURCES;
53 TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n", BufferSize, Header));
55 /* Allocate NDIS buffer for maximum Link level, IP and UDP header */
56 NdisAllocateBuffer(&NdisStatus,
61 if (NdisStatus != NDIS_STATUS_SUCCESS) {
62 TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus));
64 return STATUS_INSUFFICIENT_RESOURCES;
67 /* Chain header at front of NDIS packet */
68 NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer);
70 IPPacket->Header = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize);
71 IPPacket->HeaderSize = 20;
73 /* Build IPv4 header */
74 IPHeader = (PIPv4_HEADER)IPPacket->Header;
75 /* Version = 4, Length = 5 DWORDs */
76 IPHeader->VerIHL = 0x45;
77 /* Normal Type-of-Service */
79 /* Length of header and data */
80 IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
83 /* One fragment at offset 0 */
84 IPHeader->FlagsFragOfs = 0;
85 /* Time-to-Live is 128 */
87 /* User Datagram Protocol */
88 IPHeader->Protocol = IPPROTO_UDP;
89 /* Checksum is 0 (for later calculation of this) */
90 IPHeader->Checksum = 0;
92 IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
93 /* Destination address. FIXME: IPv4 only */
94 IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address;
96 /* Build UDP header */
97 UDPHeader = (PUDP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER));
98 /* Port values are already big-endian values */
99 UDPHeader->SourcePort = LocalPort;
100 UDPHeader->DestPort = SendRequest->RemotePort;
101 /* FIXME: Calculate UDP checksum and put it in UDP header */
102 UDPHeader->Checksum = 0;
103 /* Length of UDP header and data */
104 UDPHeader->Length = WH2N((USHORT)IPPacket->TotalSize - IPPacket->HeaderSize);
106 return STATUS_SUCCESS;
110 NTSTATUS BuildUDPPacket(
112 PIP_ADDRESS LocalAddress,
114 PIP_PACKET *IPPacket)
116 * FUNCTION: Builds an UDP packet
118 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
119 * LocalAddress = Pointer to our local address
120 * LocalPort = The port we send this datagram from
121 * IPPacket = Address of pointer to IP packet
123 * Status of operation
128 NDIS_STATUS NdisStatus;
129 PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
131 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
135 /* FIXME: Assumes IPv4 */
136 Packet = IPCreatePacket(IP_ADDRESS_V4);
138 return STATUS_INSUFFICIENT_RESOURCES;
140 Packet->TotalSize = sizeof(IPv4_HEADER) +
142 SendRequest->BufferSize;
144 /* Allocate NDIS packet */
145 NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);
146 if (NdisStatus != NDIS_STATUS_SUCCESS) {
147 TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS packet. NdisStatus = (0x%X)\n", NdisStatus));
148 (*Packet->Free)(Packet);
149 return STATUS_INSUFFICIENT_RESOURCES;
152 switch (SendRequest->RemoteAddress->Type) {
154 Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet);
157 /* FIXME: Support IPv6 */
158 TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));
160 Status = STATUS_UNSUCCESSFUL;
163 if (!NT_SUCCESS(Status)) {
164 TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", Status));
165 NdisFreePacket(Packet->NdisPacket);
166 (*Packet->Free)(Packet);
170 /* Chain data after header */
171 NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer);
173 DISPLAY_IP_PACKET(Packet);
177 return STATUS_SUCCESS;
181 NTSTATUS UDPSendDatagram(
182 PTDI_REQUEST Request,
183 PTDI_CONNECTION_INFORMATION ConnInfo,
187 * FUNCTION: Sends an UDP datagram to a remote address
189 * Request = Pointer to TDI request
190 * ConnInfo = Pointer to connection information
191 * Buffer = Pointer to NDIS buffer with data
192 * DataSize = Size in bytes of data to be sent
194 * Status of operation
197 return DGSendDatagram(Request,
205 NTSTATUS UDPReceiveDatagram(
206 PTDI_REQUEST Request,
207 PTDI_CONNECTION_INFORMATION ConnInfo,
211 PTDI_CONNECTION_INFORMATION ReturnInfo,
212 PULONG BytesReceived)
214 * FUNCTION: Attempts to receive an UDP datagram from a remote address
216 * Request = Pointer to TDI request
217 * ConnInfo = Pointer to connection information
218 * Buffer = Pointer to NDIS buffer chain to store received data
219 * ReceiveLength = Maximum size to use of buffer, 0 if all can be used
220 * ReceiveFlags = Receive flags (None, Normal, Peek)
221 * ReturnInfo = Pointer to structure for return information
222 * BytesReceive = Pointer to structure for number of bytes received
224 * Status of operation
226 * This is the high level interface for receiving UDP datagrams
229 return DGReceiveDatagram(Request,
240 PNET_TABLE_ENTRY NTE,
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;
259 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
261 switch (IPPacket->Type) {
264 IPv4Header = IPPacket->Header;
265 DstAddress = &IPPacket->DstAddr;
270 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));
272 /* FIXME: IPv6 is not supported */
279 UDPHeader = (PUDP_HEADER)IPPacket->Data;
281 /* FIXME: Calculate and validate UDP checksum */
284 i = WH2N(UDPHeader->Length);
285 if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) {
286 /* Incorrect or damaged packet received, discard it */
287 TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n"));
291 DataSize = i - sizeof(UDP_HEADER);
293 /* Go to UDP data area */
294 (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER);
296 /* Locate a receive request on destination address file object
297 and deliver the packet if one is found. If there is no receive
298 request on the address file object, call the associated receive
299 handler. If no receive handler is registered, drop the packet */
301 AddrFile = AddrSearchFirst(DstAddress,
307 DGDeliverData(AddrFile,
311 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
313 /* There are no open address files that will take this datagram */
314 /* FIXME: IPv4 only */
315 TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
316 DN2H(DstAddress->Address.IPv4Address)));
318 /* FIXME: Send ICMP reply */
320 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
327 * FUNCTION: Initializes the UDP subsystem
329 * Status of operation
332 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
334 /* Register this protocol with IP layer */
335 IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
337 UDPInitialized = TRUE;
339 return STATUS_SUCCESS;
343 NTSTATUS UDPShutdown(
346 * FUNCTION: Shuts down the UDP subsystem
348 * Status of operation
352 return STATUS_SUCCESS;
354 /* Deregister this protocol with IP layer */
355 IPRegisterProtocol(IPPROTO_UDP, NULL);
357 return STATUS_SUCCESS;