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