* Sync up to trunk r55544.
[reactos.git] / lib / drivers / ip / transport / udp / udp.c
1 /*
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)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 BOOLEAN UDPInitialized = FALSE;
14 PORT_SET UDPPorts;
15
16 NTSTATUS AddUDPHeaderIPv4(
17 PADDRESS_FILE AddrFile,
18 PIP_ADDRESS RemoteAddress,
19 USHORT RemotePort,
20 PIP_ADDRESS LocalAddress,
21 USHORT LocalPort,
22 PIP_PACKET IPPacket,
23 PVOID Data,
24 UINT DataLength)
25 /*
26 * FUNCTION: Adds an IPv4 and UDP header to an IP packet
27 * ARGUMENTS:
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
32 * RETURNS:
33 * Status of operation
34 */
35 {
36 PUDP_HEADER UDPHeader;
37 NTSTATUS Status;
38
39 TI_DbgPrint(MID_TRACE, ("Packet: %x NdisPacket %x\n",
40 IPPacket, IPPacket->NdisPacket));
41
42 Status = AddGenericHeaderIPv4
43 ( AddrFile, RemoteAddress, RemotePort,
44 LocalAddress, LocalPort,
45 IPPacket, DataLength, IPPROTO_UDP,
46 sizeof(UDP_HEADER), (PVOID *)&UDPHeader );
47
48 if (!NT_SUCCESS(Status))
49 return Status;
50
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));
57
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));
61
62 RtlCopyMemory(IPPacket->Data, Data, DataLength);
63
64 UDPHeader->Checksum = UDPv4ChecksumCalculate((PIPv4_HEADER)IPPacket->Header,
65 (PUCHAR)UDPHeader,
66 DataLength + sizeof(UDP_HEADER));
67 UDPHeader->Checksum = WH2N(UDPHeader->Checksum);
68
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,
72 DataLength));
73
74 return STATUS_SUCCESS;
75 }
76
77
78 NTSTATUS BuildUDPPacket(
79 PADDRESS_FILE AddrFile,
80 PIP_PACKET Packet,
81 PIP_ADDRESS RemoteAddress,
82 USHORT RemotePort,
83 PIP_ADDRESS LocalAddress,
84 USHORT LocalPort,
85 PCHAR DataBuffer,
86 UINT DataLen )
87 /*
88 * FUNCTION: Builds an UDP packet
89 * ARGUMENTS:
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
94 * RETURNS:
95 * Status of operation
96 */
97 {
98 NTSTATUS Status;
99
100 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
101
102 /* FIXME: Assumes IPv4 */
103 IPInitializePacket(Packet, IP_ADDRESS_V4);
104
105 Packet->TotalSize = sizeof(IPv4_HEADER) + sizeof(UDP_HEADER) + DataLen;
106
107 /* Prepare packet */
108 Status = AllocatePacketWithBuffer(&Packet->NdisPacket,
109 NULL,
110 Packet->TotalSize );
111
112 if( !NT_SUCCESS(Status) )
113 {
114 Packet->Free(Packet);
115 return Status;
116 }
117
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)));
121
122 switch (RemoteAddress->Type) {
123 case IP_ADDRESS_V4:
124 Status = AddUDPHeaderIPv4(AddrFile, RemoteAddress, RemotePort,
125 LocalAddress, LocalPort, Packet, DataBuffer, DataLen);
126 break;
127 case IP_ADDRESS_V6:
128 /* FIXME: Support IPv6 */
129 TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));
130 default:
131 Status = STATUS_UNSUCCESSFUL;
132 break;
133 }
134 if (!NT_SUCCESS(Status)) {
135 TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n",
136 Status));
137 Packet->Free(Packet);
138 return Status;
139 }
140
141 TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
142
143 DISPLAY_IP_PACKET(Packet);
144
145 TI_DbgPrint(MID_TRACE, ("Leaving\n"));
146
147 return STATUS_SUCCESS;
148 }
149
150 NTSTATUS UDPSendDatagram(
151 PADDRESS_FILE AddrFile,
152 PTDI_CONNECTION_INFORMATION ConnInfo,
153 PCHAR BufferData,
154 ULONG DataSize,
155 PULONG DataUsed )
156 /*
157 * FUNCTION: Sends an UDP datagram to a remote address
158 * ARGUMENTS:
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
163 * RETURNS:
164 * Status of operation
165 */
166 {
167 IP_PACKET Packet;
168 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
169 IP_ADDRESS RemoteAddress;
170 IP_ADDRESS LocalAddress;
171 USHORT RemotePort;
172 NTSTATUS Status;
173 PNEIGHBOR_CACHE_ENTRY NCE;
174 KIRQL OldIrql;
175
176 LockObject(AddrFile, &OldIrql);
177
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));
181
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;
188 break;
189
190 default:
191 UnlockObject(AddrFile, OldIrql);
192 return STATUS_UNSUCCESSFUL;
193 }
194
195 LocalAddress = AddrFile->Address;
196 if (AddrIsUnspecified(&LocalAddress))
197 {
198 /* If the local address is unspecified (0),
199 * then use the unicast address of the
200 * interface we're sending over
201 */
202 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
203 UnlockObject(AddrFile, OldIrql);
204 return STATUS_NETWORK_UNREACHABLE;
205 }
206
207 LocalAddress = NCE->Interface->Unicast;
208 }
209 else
210 {
211 if(!(NCE = NBLocateNeighbor( &LocalAddress ))) {
212 UnlockObject(AddrFile, OldIrql);
213 return STATUS_INVALID_PARAMETER;
214 }
215 }
216
217 Status = BuildUDPPacket( AddrFile,
218 &Packet,
219 &RemoteAddress,
220 RemotePort,
221 &LocalAddress,
222 AddrFile->Port,
223 BufferData,
224 DataSize );
225
226 UnlockObject(AddrFile, OldIrql);
227
228 if( !NT_SUCCESS(Status) )
229 return Status;
230
231 Status = IPSendDatagram(&Packet, NCE);
232 if (!NT_SUCCESS(Status))
233 return Status;
234
235 *DataUsed = DataSize;
236
237 return STATUS_SUCCESS;
238 }
239
240
241 VOID UDPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
242 /*
243 * FUNCTION: Receives and queues a UDP datagram
244 * ARGUMENTS:
245 * NTE = Pointer to net table entry which the packet was received on
246 * IPPacket = Pointer to an IP packet that was received
247 * NOTES:
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
250 */
251 {
252 AF_SEARCH SearchContext;
253 PIPv4_HEADER IPv4Header;
254 PADDRESS_FILE AddrFile;
255 PUDP_HEADER UDPHeader;
256 PIP_ADDRESS DstAddress, SrcAddress;
257 UINT DataSize, i;
258
259 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
260
261 switch (IPPacket->Type) {
262 /* IPv4 packet */
263 case IP_ADDRESS_V4:
264 IPv4Header = IPPacket->Header;
265 DstAddress = &IPPacket->DstAddr;
266 SrcAddress = &IPPacket->SrcAddr;
267 break;
268
269 /* IPv6 packet */
270 case IP_ADDRESS_V6:
271 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));
272
273 /* FIXME: IPv6 is not supported */
274 return;
275
276 default:
277 return;
278 }
279
280 UDPHeader = (PUDP_HEADER)IPPacket->Data;
281
282 /* Calculate and validate UDP checksum */
283 i = UDPv4ChecksumCalculate(IPv4Header,
284 (PUCHAR)UDPHeader,
285 WH2N(UDPHeader->Length));
286 if (i != DH2N(0x0000FFFF) && UDPHeader->Checksum != 0)
287 {
288 TI_DbgPrint(MIN_TRACE, ("Bad checksum on packet received.\n"));
289 return;
290 }
291
292 /* Sanity checks */
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"));
297 return;
298 }
299
300 DataSize = i - sizeof(UDP_HEADER);
301
302 /* Go to UDP data area */
303 IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Data + sizeof(UDP_HEADER));
304
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 */
309
310 AddrFile = AddrSearchFirst(DstAddress,
311 UDPHeader->DestPort,
312 IPPROTO_UDP,
313 &SearchContext);
314 if (AddrFile) {
315 do {
316 DGDeliverData(AddrFile,
317 SrcAddress,
318 DstAddress,
319 UDPHeader->SourcePort,
320 UDPHeader->DestPort,
321 IPPacket,
322 DataSize);
323 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
324 } else {
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)));
329
330 /* FIXME: Send ICMP reply */
331 }
332 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
333 }
334
335
336 NTSTATUS UDPStartup(
337 VOID)
338 /*
339 * FUNCTION: Initializes the UDP subsystem
340 * RETURNS:
341 * Status of operation
342 */
343 {
344 NTSTATUS Status;
345
346 #ifdef __NTDRIVER__
347 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
348 #endif
349
350 Status = PortsStartup( &UDPPorts, 1, UDP_STARTING_PORT + UDP_DYNAMIC_PORTS );
351
352 if( !NT_SUCCESS(Status) ) return Status;
353
354 /* Register this protocol with IP layer */
355 IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
356
357 UDPInitialized = TRUE;
358
359 return STATUS_SUCCESS;
360 }
361
362
363 NTSTATUS UDPShutdown(
364 VOID)
365 /*
366 * FUNCTION: Shuts down the UDP subsystem
367 * RETURNS:
368 * Status of operation
369 */
370 {
371 if (!UDPInitialized)
372 return STATUS_SUCCESS;
373
374 PortsShutdown( &UDPPorts );
375
376 /* Deregister this protocol with IP layer */
377 IPRegisterProtocol(IPPROTO_UDP, NULL);
378
379 UDPInitialized = FALSE;
380
381 return STATUS_SUCCESS;
382 }
383
384 UINT UDPAllocatePort( UINT HintPort ) {
385 if( 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 );
391 }
392
393 VOID UDPFreePort( UINT Port ) {
394 DeallocatePort( &UDPPorts, Port );
395 }
396
397 /* EOF */