:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / net / tcpip / 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 #include <tcpip.h>
11 #include <udp.h>
12 #include <routines.h>
13 #include <transmit.h>
14 #include <datagram.h>
15 #include <checksum.h>
16 #include <address.h>
17 #include <pool.h>
18
19
20 BOOLEAN UDPInitialized = FALSE;
21
22
23 NTSTATUS AddUDPHeaderIPv4(
24   PDATAGRAM_SEND_REQUEST SendRequest,
25   PIP_ADDRESS LocalAddress,
26   USHORT LocalPort,
27   PIP_PACKET IPPacket)
28 /*
29  * FUNCTION: Adds an IPv4 and UDP header to an IP packet
30  * ARGUMENTS:
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
35  * RETURNS:
36  *     Status of operation
37  */
38 {
39   PIPv4_HEADER IPHeader;
40   PUDP_HEADER UDPHeader;
41   PVOID Header;
42         ULONG BufferSize;
43   NDIS_STATUS NdisStatus;
44   PNDIS_BUFFER HeaderBuffer;
45
46         BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER);
47   Header     = ExAllocatePool(NonPagedPool, BufferSize);
48   if (!Header) {
49     TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));
50     return STATUS_INSUFFICIENT_RESOURCES;
51   }
52
53   TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n", BufferSize, Header));
54
55   /* Allocate NDIS buffer for maximum Link level, IP and UDP header */
56   NdisAllocateBuffer(&NdisStatus,
57                      &HeaderBuffer,
58                      GlobalBufferPool,
59                      Header,
60                      BufferSize);
61   if (NdisStatus != NDIS_STATUS_SUCCESS) {
62     TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus));
63     ExFreePool(Header);
64     return STATUS_INSUFFICIENT_RESOURCES;
65   }
66
67   /* Chain header at front of NDIS packet */
68   NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer);
69   
70   IPPacket->Header     = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize);
71   IPPacket->HeaderSize = 20;
72
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 */
78   IPHeader->Tos = 0;
79   /* Length of header and data */
80   IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
81   /* Identification */
82   IPHeader->Id = 0;
83   /* One fragment at offset 0 */
84   IPHeader->FlagsFragOfs = 0;
85   /* Time-to-Live is 128 */
86   IPHeader->Ttl = 128;
87   /* User Datagram Protocol */
88   IPHeader->Protocol = IPPROTO_UDP;
89   /* Checksum is 0 (for later calculation of this) */
90   IPHeader->Checksum = 0;
91   /* Source address */
92   IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
93   /* Destination address. FIXME: IPv4 only */
94   IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address;
95
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);
105
106   return STATUS_SUCCESS;
107 }
108
109
110 NTSTATUS BuildUDPPacket(
111   PVOID Context,
112   PIP_ADDRESS LocalAddress,
113   USHORT LocalPort,
114   PIP_PACKET *IPPacket)
115 /*
116  * FUNCTION: Builds an UDP packet
117  * ARGUMENTS:
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
122  * RETURNS:
123  *     Status of operation
124  */
125 {
126   NTSTATUS Status;
127   PIP_PACKET Packet;
128   NDIS_STATUS NdisStatus;
129   PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
130
131   TI_DbgPrint(MAX_TRACE, ("Called.\n"));
132
133   /* Prepare packet */
134
135   /* FIXME: Assumes IPv4 */
136   Packet = IPCreatePacket(IP_ADDRESS_V4);
137   if (!Packet)
138     return STATUS_INSUFFICIENT_RESOURCES;
139
140   Packet->TotalSize = sizeof(IPv4_HEADER) +
141                       sizeof(UDP_HEADER)  +
142                       SendRequest->BufferSize;
143
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;
150   }
151
152   switch (SendRequest->RemoteAddress->Type) {
153   case IP_ADDRESS_V4:
154     Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet);
155     break;
156   case IP_ADDRESS_V6:
157     /* FIXME: Support IPv6 */
158     TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));
159   default:
160     Status = STATUS_UNSUCCESSFUL;
161     break;
162   }
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);
167     return Status;
168   }
169
170   /* Chain data after header */
171   NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer);
172
173   DISPLAY_IP_PACKET(Packet);
174
175   *IPPacket = Packet;
176
177   return STATUS_SUCCESS;
178 }
179
180
181 NTSTATUS UDPSendDatagram(
182   PTDI_REQUEST Request,
183   PTDI_CONNECTION_INFORMATION ConnInfo,
184   PNDIS_BUFFER Buffer,
185   ULONG DataSize)
186 /*
187  * FUNCTION: Sends an UDP datagram to a remote address
188  * ARGUMENTS:
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
193  * RETURNS:
194  *     Status of operation
195  */
196 {
197   return DGSendDatagram(Request,
198                         ConnInfo,
199                         Buffer,
200                         DataSize,
201                         BuildUDPPacket);
202 }
203
204
205 NTSTATUS UDPReceiveDatagram(
206     PTDI_REQUEST Request,
207     PTDI_CONNECTION_INFORMATION ConnInfo,
208     PNDIS_BUFFER Buffer,
209     ULONG ReceiveLength,
210     ULONG ReceiveFlags,
211     PTDI_CONNECTION_INFORMATION ReturnInfo,
212     PULONG BytesReceived)
213 /*
214  * FUNCTION: Attempts to receive an UDP datagram from a remote address
215  * ARGUMENTS:
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
223  * RETURNS:
224  *     Status of operation
225  * NOTES:
226  *     This is the high level interface for receiving UDP datagrams
227  */
228 {
229   return DGReceiveDatagram(Request,
230                            ConnInfo,
231                            Buffer,
232                            ReceiveLength,
233                            ReceiveFlags,
234                            ReturnInfo,
235                            BytesReceived);
236 }
237
238
239 VOID UDPReceive(
240    PNET_TABLE_ENTRY NTE,
241    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;
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     break;
267
268   /* IPv6 packet */
269   case IP_ADDRESS_V6:
270     TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));
271
272     /* FIXME: IPv6 is not supported */
273     return;
274
275   default:
276     return;
277   }
278
279   UDPHeader = (PUDP_HEADER)IPPacket->Data;
280
281   /* FIXME: Calculate and validate UDP checksum */
282
283   /* Sanity checks */
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"));
288     return;
289   }
290
291   DataSize = i - sizeof(UDP_HEADER);
292
293   /* Go to UDP data area */
294   (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER);
295
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 */
300
301   AddrFile = AddrSearchFirst(DstAddress,
302                              UDPHeader->DestPort,
303                              IPPROTO_UDP,
304                              &SearchContext);
305   if (AddrFile) {
306     do {
307       DGDeliverData(AddrFile,
308                     DstAddress,
309                     IPPacket,
310                     DataSize);
311     } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
312   } else {
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)));
317
318     /* FIXME: Send ICMP reply */
319   }
320   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
321 }
322
323
324 NTSTATUS UDPStartup(
325   VOID)
326 /*
327  * FUNCTION: Initializes the UDP subsystem
328  * RETURNS:
329  *     Status of operation
330  */
331 {
332   RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
333
334   /* Register this protocol with IP layer */
335   IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
336
337   UDPInitialized = TRUE;
338
339   return STATUS_SUCCESS;
340 }
341
342
343 NTSTATUS UDPShutdown(
344   VOID)
345 /*
346  * FUNCTION: Shuts down the UDP subsystem
347  * RETURNS:
348  *     Status of operation
349  */
350 {
351   if (!UDPInitialized)
352       return STATUS_SUCCESS;
353
354   /* Deregister this protocol with IP layer */
355   IPRegisterProtocol(IPPROTO_UDP, NULL);
356
357   return STATUS_SUCCESS;
358 }
359
360 /* EOF */