- Leftover 2 from 42210
[reactos.git] / reactos / 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 PIP_ADDRESS RemoteAddress,
18 USHORT RemotePort,
19 PIP_ADDRESS LocalAddress,
20 USHORT LocalPort,
21 PIP_PACKET IPPacket,
22 UINT DataLength)
23 /*
24 * FUNCTION: Adds an IPv4 and UDP header to an IP packet
25 * ARGUMENTS:
26 * SendRequest = Pointer to send request
27 * LocalAddress = Pointer to our local address
28 * LocalPort = The port we send this datagram from
29 * IPPacket = Pointer to IP packet
30 * RETURNS:
31 * Status of operation
32 */
33 {
34 PUDP_HEADER UDPHeader;
35 NTSTATUS Status;
36
37 TI_DbgPrint(MID_TRACE, ("Packet: %x NdisPacket %x\n",
38 IPPacket, IPPacket->NdisPacket));
39
40 Status = AddGenericHeaderIPv4
41 ( RemoteAddress, RemotePort,
42 LocalAddress, LocalPort,
43 IPPacket, DataLength, IPPROTO_UDP,
44 sizeof(UDP_HEADER), (PVOID *)&UDPHeader );
45
46 if (!NT_SUCCESS(Status))
47 return Status;
48
49 /* Port values are already big-endian values */
50 UDPHeader->SourcePort = LocalPort;
51 UDPHeader->DestPort = RemotePort;
52 /* FIXME: Calculate UDP checksum and put it in UDP header */
53 UDPHeader->Checksum = 0;
54 /* Length of UDP header and data */
55 UDPHeader->Length = WH2N(DataLength + sizeof(UDP_HEADER));
56
57 TI_DbgPrint(MID_TRACE, ("Packet: %d ip %d udp %d payload\n",
58 (PCHAR)UDPHeader - (PCHAR)IPPacket->Header,
59 (PCHAR)IPPacket->Data - (PCHAR)UDPHeader,
60 DataLength));
61
62 return STATUS_SUCCESS;
63 }
64
65
66 NTSTATUS BuildUDPPacket(
67 PIP_PACKET Packet,
68 PIP_ADDRESS RemoteAddress,
69 USHORT RemotePort,
70 PIP_ADDRESS LocalAddress,
71 USHORT LocalPort,
72 PCHAR DataBuffer,
73 UINT DataLen )
74 /*
75 * FUNCTION: Builds an UDP packet
76 * ARGUMENTS:
77 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
78 * LocalAddress = Pointer to our local address
79 * LocalPort = The port we send this datagram from
80 * IPPacket = Address of pointer to IP packet
81 * RETURNS:
82 * Status of operation
83 */
84 {
85 NTSTATUS Status;
86
87 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
88
89 /* FIXME: Assumes IPv4 */
90 IPInitializePacket(Packet, IP_ADDRESS_V4);
91
92 Packet->TotalSize = sizeof(IPv4_HEADER) + sizeof(UDP_HEADER) + DataLen;
93
94 /* Prepare packet */
95 Status = AllocatePacketWithBuffer( &Packet->NdisPacket,
96 NULL,
97 Packet->TotalSize + MaxLLHeaderSize );
98
99 if( !NT_SUCCESS(Status) ) return Status;
100
101 TI_DbgPrint(MID_TRACE, ("Allocated packet: %x\n", Packet->NdisPacket));
102 TI_DbgPrint(MID_TRACE, ("Local Addr : %s\n", A2S(LocalAddress)));
103 TI_DbgPrint(MID_TRACE, ("Remote Addr: %s\n", A2S(RemoteAddress)));
104
105 switch (RemoteAddress->Type) {
106 case IP_ADDRESS_V4:
107 Status = AddUDPHeaderIPv4(RemoteAddress, RemotePort,
108 LocalAddress, LocalPort, Packet, DataLen);
109 break;
110 case IP_ADDRESS_V6:
111 /* FIXME: Support IPv6 */
112 TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));
113 default:
114 Status = STATUS_UNSUCCESSFUL;
115 break;
116 }
117 if (!NT_SUCCESS(Status)) {
118 TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n",
119 Status));
120 FreeNdisPacket(Packet->NdisPacket);
121 return Status;
122 }
123
124 TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
125 Packet->Header, Packet->Data,
126 (PCHAR)Packet->Data - (PCHAR)Packet->Header));
127
128 RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
129
130 TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
131
132 DISPLAY_IP_PACKET(Packet);
133
134 TI_DbgPrint(MID_TRACE, ("Leaving\n"));
135
136 return STATUS_SUCCESS;
137 }
138
139 VOID UDPSendPacketComplete
140 ( PVOID Context, PNDIS_PACKET Packet, NDIS_STATUS Status ) {
141 FreeNdisPacket( Packet );
142 }
143
144 NTSTATUS UDPSendDatagram(
145 PADDRESS_FILE AddrFile,
146 PTDI_CONNECTION_INFORMATION ConnInfo,
147 PCHAR BufferData,
148 ULONG DataSize,
149 PULONG DataUsed )
150 /*
151 * FUNCTION: Sends an UDP datagram to a remote address
152 * ARGUMENTS:
153 * Request = Pointer to TDI request
154 * ConnInfo = Pointer to connection information
155 * Buffer = Pointer to NDIS buffer with data
156 * DataSize = Size in bytes of data to be sent
157 * RETURNS:
158 * Status of operation
159 */
160 {
161 IP_PACKET Packet;
162 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
163 IP_ADDRESS RemoteAddress;
164 IP_ADDRESS LocalAddress;
165 USHORT RemotePort;
166 NTSTATUS Status;
167 PNEIGHBOR_CACHE_ENTRY NCE;
168
169 TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
170 AddrFile, ConnInfo, BufferData, DataSize));
171 TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa));
172
173 switch( RemoteAddressTa->Address[0].AddressType ) {
174 case TDI_ADDRESS_TYPE_IP:
175 RemoteAddress.Type = IP_ADDRESS_V4;
176 RemoteAddress.Address.IPv4Address =
177 RemoteAddressTa->Address[0].Address[0].in_addr;
178 RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port;
179 break;
180
181 default:
182 return STATUS_UNSUCCESSFUL;
183 }
184
185 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) {
186 return STATUS_NETWORK_UNREACHABLE;
187 }
188
189 LocalAddress = AddrFile->Address;
190 if (AddrIsUnspecified(&LocalAddress))
191 {
192 /* If the local address is unspecified (0),
193 * then use the unicast address of the
194 * interface we're sending over
195 */
196 LocalAddress = NCE->Interface->Unicast;
197 }
198
199 Status = BuildUDPPacket( &Packet,
200 &RemoteAddress,
201 RemotePort,
202 &LocalAddress,
203 AddrFile->Port,
204 BufferData,
205 DataSize );
206
207 if( !NT_SUCCESS(Status) )
208 return Status;
209
210 if (!NT_SUCCESS(Status = IPSendDatagram( &Packet, NCE, UDPSendPacketComplete, NULL )))
211 {
212 FreeNdisPacket(Packet.NdisPacket);
213 return Status;
214 }
215
216 return STATUS_SUCCESS;
217 }
218
219
220 VOID UDPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
221 /*
222 * FUNCTION: Receives and queues a UDP datagram
223 * ARGUMENTS:
224 * NTE = Pointer to net table entry which the packet was received on
225 * IPPacket = Pointer to an IP packet that was received
226 * NOTES:
227 * This is the low level interface for receiving UDP datagrams. It strips
228 * the UDP header from a packet and delivers the data to anyone that wants it
229 */
230 {
231 AF_SEARCH SearchContext;
232 PIPv4_HEADER IPv4Header;
233 PADDRESS_FILE AddrFile;
234 PUDP_HEADER UDPHeader;
235 PIP_ADDRESS DstAddress, SrcAddress;
236 UINT DataSize, i;
237
238 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
239
240 switch (IPPacket->Type) {
241 /* IPv4 packet */
242 case IP_ADDRESS_V4:
243 IPv4Header = IPPacket->Header;
244 DstAddress = &IPPacket->DstAddr;
245 SrcAddress = &IPPacket->SrcAddr;
246 break;
247
248 /* IPv6 packet */
249 case IP_ADDRESS_V6:
250 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));
251
252 /* FIXME: IPv6 is not supported */
253 return;
254
255 default:
256 return;
257 }
258
259 UDPHeader = (PUDP_HEADER)IPPacket->Data;
260
261 /* FIXME: Calculate and validate UDP checksum */
262
263 /* Sanity checks */
264 i = WH2N(UDPHeader->Length);
265 if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) {
266 /* Incorrect or damaged packet received, discard it */
267 TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n"));
268 return;
269 }
270
271 DataSize = i - sizeof(UDP_HEADER);
272
273 /* Go to UDP data area */
274 IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Data + sizeof(UDP_HEADER));
275
276 /* Locate a receive request on destination address file object
277 and deliver the packet if one is found. If there is no receive
278 request on the address file object, call the associated receive
279 handler. If no receive handler is registered, drop the packet */
280
281 AddrFile = AddrSearchFirst(DstAddress,
282 UDPHeader->DestPort,
283 IPPROTO_UDP,
284 &SearchContext);
285 if (AddrFile) {
286 do {
287 DGDeliverData(AddrFile,
288 SrcAddress,
289 DstAddress,
290 UDPHeader->SourcePort,
291 UDPHeader->DestPort,
292 IPPacket,
293 DataSize);
294 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
295 } else {
296 /* There are no open address files that will take this datagram */
297 /* FIXME: IPv4 only */
298 TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
299 DN2H(DstAddress->Address.IPv4Address)));
300
301 /* FIXME: Send ICMP reply */
302 }
303 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
304 }
305
306
307 NTSTATUS UDPStartup(
308 VOID)
309 /*
310 * FUNCTION: Initializes the UDP subsystem
311 * RETURNS:
312 * Status of operation
313 */
314 {
315 NTSTATUS Status;
316
317 #ifdef __NTDRIVER__
318 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
319 #endif
320
321 Status = PortsStartup( &UDPPorts, 1, UDP_STARTING_PORT + UDP_DYNAMIC_PORTS );
322
323 if( !NT_SUCCESS(Status) ) return Status;
324
325 /* Register this protocol with IP layer */
326 IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
327
328 UDPInitialized = TRUE;
329
330 return STATUS_SUCCESS;
331 }
332
333
334 NTSTATUS UDPShutdown(
335 VOID)
336 /*
337 * FUNCTION: Shuts down the UDP subsystem
338 * RETURNS:
339 * Status of operation
340 */
341 {
342 if (!UDPInitialized)
343 return STATUS_SUCCESS;
344
345 PortsShutdown( &UDPPorts );
346
347 /* Deregister this protocol with IP layer */
348 IPRegisterProtocol(IPPROTO_UDP, NULL);
349
350 UDPInitialized = FALSE;
351
352 return STATUS_SUCCESS;
353 }
354
355 UINT UDPAllocatePort( UINT HintPort ) {
356 if( HintPort ) {
357 if( AllocatePort( &UDPPorts, HintPort ) ) return HintPort;
358 else return (UINT)-1;
359 } else return AllocatePortFromRange
360 ( &UDPPorts, UDP_STARTING_PORT,
361 UDP_STARTING_PORT + UDP_DYNAMIC_PORTS );
362 }
363
364 VOID UDPFreePort( UINT Port ) {
365 DeallocatePort( &UDPPorts, Port );
366 }
367
368 /* EOF */