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