Put sound into multimedia and rename it to audio because it is "MoreCorrect©"
[reactos.git] / reactos / lib / drivers / ip / transport / rawip / rawip.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/rawip/rawip.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 NTSTATUS AddGenericHeaderIPv4(
14 PIP_ADDRESS RemoteAddress,
15 USHORT RemotePort,
16 PIP_ADDRESS LocalAddress,
17 USHORT LocalPort,
18 PIP_PACKET IPPacket,
19 UINT DataLength,
20 UINT Protocol,
21 UINT ExtraLength,
22 PVOID *NextHeader )
23 /*
24 * FUNCTION: Adds an IPv4 and RawIp 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 PIPv4_HEADER IPHeader;
35 ULONG BufferSize;
36
37 TI_DbgPrint(MID_TRACE, ("Packet: %x NdisPacket %x\n",
38 IPPacket, IPPacket->NdisPacket));
39
40 BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + ExtraLength;
41
42 GetDataPtr( IPPacket->NdisPacket,
43 MaxLLHeaderSize,
44 (PCHAR *)&IPPacket->Header,
45 &IPPacket->ContigSize );
46
47 IPPacket->HeaderSize = 20;
48
49 TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n",
50 BufferSize, IPPacket->Header));
51 TI_DbgPrint(MAX_TRACE, ("Packet total length %d\n", IPPacket->TotalSize));
52
53 /* Build IPv4 header */
54 IPHeader = (PIPv4_HEADER)IPPacket->Header;
55 /* Version = 4, Length = 5 DWORDs */
56 IPHeader->VerIHL = 0x45;
57 /* Normal Type-of-Service */
58 IPHeader->Tos = 0;
59 /* Length of header and data */
60 IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
61 /* Identification */
62 IPHeader->Id = 0;
63 /* One fragment at offset 0 */
64 IPHeader->FlagsFragOfs = 0;
65 /* Time-to-Live is 128 */
66 IPHeader->Ttl = 128;
67 /* User Datagram Protocol */
68 IPHeader->Protocol = Protocol;
69 /* Checksum is 0 (for later calculation of this) */
70 IPHeader->Checksum = 0;
71 /* Source address */
72 IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
73 /* Destination address. FIXME: IPv4 only */
74 IPHeader->DstAddr = RemoteAddress->Address.IPv4Address;
75
76 /* Build RawIp header */
77 *NextHeader = (((PCHAR)IPHeader) + sizeof(IPv4_HEADER));
78 IPPacket->Data = ((PCHAR)*NextHeader) + ExtraLength;
79
80 return STATUS_SUCCESS;
81 }
82
83
84 NTSTATUS BuildRawIpPacket(
85 PIP_PACKET Packet,
86 PIP_ADDRESS RemoteAddress,
87 USHORT RemotePort,
88 PIP_ADDRESS LocalAddress,
89 USHORT LocalPort,
90 PCHAR DataBuffer,
91 UINT DataLen )
92 /*
93 * FUNCTION: Builds an RawIp packet
94 * ARGUMENTS:
95 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
96 * LocalAddress = Pointer to our local address
97 * LocalPort = The port we send this datagram from
98 * IPPacket = Address of pointer to IP packet
99 * RETURNS:
100 * Status of operation
101 */
102 {
103 NTSTATUS Status;
104 PCHAR Payload;
105
106 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
107
108 /* FIXME: Assumes IPv4 */
109 IPInitializePacket(Packet, IP_ADDRESS_V4);
110 if (!Packet)
111 return STATUS_INSUFFICIENT_RESOURCES;
112
113 Packet->TotalSize = sizeof(IPv4_HEADER) + DataLen;
114
115 /* Prepare packet */
116 Status = AllocatePacketWithBuffer( &Packet->NdisPacket,
117 NULL,
118 Packet->TotalSize + MaxLLHeaderSize );
119
120 if( !NT_SUCCESS(Status) ) return Status;
121
122 TI_DbgPrint(MID_TRACE, ("Allocated packet: %x\n", Packet->NdisPacket));
123 TI_DbgPrint(MID_TRACE, ("Local Addr : %s\n", A2S(LocalAddress)));
124 TI_DbgPrint(MID_TRACE, ("Remote Addr: %s\n", A2S(RemoteAddress)));
125
126 switch (RemoteAddress->Type) {
127 case IP_ADDRESS_V4:
128 Status = AddGenericHeaderIPv4
129 (RemoteAddress, RemotePort,
130 LocalAddress, LocalPort, Packet, DataLen,
131 IPPROTO_ICMP, /* XXX Figure out a better way to do this */
132 0, (PVOID *)&Payload );
133 break;
134 case IP_ADDRESS_V6:
135 /* FIXME: Support IPv6 */
136 Status = STATUS_UNSUCCESSFUL;
137 TI_DbgPrint(MIN_TRACE, ("IPv6 RawIp datagrams are not supported.\n"));
138 break;
139
140 default:
141 Status = STATUS_UNSUCCESSFUL;
142 TI_DbgPrint(MIN_TRACE, ("Bad Address Type %d\n", RemoteAddress->Type));
143 break;
144 }
145
146 TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
147 Packet->Header, Packet->Data,
148 (PCHAR)Packet->Data - (PCHAR)Packet->Header));
149
150 RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
151
152 TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
153
154 DISPLAY_IP_PACKET(Packet);
155
156 TI_DbgPrint(MID_TRACE, ("Leaving\n"));
157
158 return STATUS_SUCCESS;
159 }
160
161 VOID RawIpSendPacketComplete
162 ( PVOID Context, PNDIS_PACKET Packet, NDIS_STATUS Status ) {
163 FreeNdisPacket( Packet );
164 }
165
166 NTSTATUS RawIPSendDatagram(
167 PADDRESS_FILE AddrFile,
168 PTDI_CONNECTION_INFORMATION ConnInfo,
169 PCHAR BufferData,
170 ULONG DataSize,
171 PULONG DataUsed )
172 /*
173 * FUNCTION: Sends an RawIp datagram to a remote address
174 * ARGUMENTS:
175 * Request = Pointer to TDI request
176 * ConnInfo = Pointer to connection information
177 * Buffer = Pointer to NDIS buffer with data
178 * DataSize = Size in bytes of data to be sent
179 * RETURNS:
180 * Status of operation
181 */
182 {
183 IP_PACKET Packet;
184 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
185 IP_ADDRESS RemoteAddress;
186 USHORT RemotePort;
187 NTSTATUS Status;
188 PNEIGHBOR_CACHE_ENTRY NCE;
189
190 TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
191 AddrFile, ConnInfo, BufferData, DataSize));
192 TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa));
193
194 switch( RemoteAddressTa->Address[0].AddressType ) {
195 case TDI_ADDRESS_TYPE_IP:
196 RemoteAddress.Type = IP_ADDRESS_V4;
197 RemoteAddress.Address.IPv4Address =
198 RemoteAddressTa->Address[0].Address[0].in_addr;
199 RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port;
200 break;
201
202 default:
203 return STATUS_UNSUCCESSFUL;
204 }
205
206 Status = BuildRawIpPacket( &Packet,
207 &RemoteAddress,
208 RemotePort,
209 &AddrFile->Address,
210 AddrFile->Port,
211 BufferData,
212 DataSize );
213
214 if( !NT_SUCCESS(Status) )
215 return Status;
216
217 TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
218
219 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
220 return STATUS_UNSUCCESSFUL;
221
222 TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
223
224 IPSendDatagram( &Packet, NCE, RawIpSendPacketComplete, NULL );
225
226 TI_DbgPrint(MID_TRACE,("Leaving\n"));
227
228 return STATUS_SUCCESS;
229 }
230
231 VOID RawIpReceiveComplete(PVOID Context, NTSTATUS Status, ULONG Count) {
232 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest =
233 (PDATAGRAM_RECEIVE_REQUEST)Context;
234 TI_DbgPrint(MAX_TRACE,("Called\n"));
235 ReceiveRequest->UserComplete( ReceiveRequest->UserContext, Status, Count );
236 exFreePool( ReceiveRequest );
237 TI_DbgPrint(MAX_TRACE,("Done\n"));
238 }
239
240 NTSTATUS RawIPReceiveDatagram(
241 PADDRESS_FILE AddrFile,
242 PTDI_CONNECTION_INFORMATION ConnInfo,
243 PCHAR BufferData,
244 ULONG ReceiveLength,
245 ULONG ReceiveFlags,
246 PTDI_CONNECTION_INFORMATION ReturnInfo,
247 PULONG BytesReceived,
248 PDATAGRAM_COMPLETION_ROUTINE Complete,
249 PVOID Context)
250 /*
251 * FUNCTION: Attempts to receive an RawIp datagram from a remote address
252 * ARGUMENTS:
253 * Request = Pointer to TDI request
254 * ConnInfo = Pointer to connection information
255 * Buffer = Pointer to NDIS buffer chain to store received data
256 * ReceiveLength = Maximum size to use of buffer, 0 if all can be used
257 * ReceiveFlags = Receive flags (None, Normal, Peek)
258 * ReturnInfo = Pointer to structure for return information
259 * BytesReceive = Pointer to structure for number of bytes received
260 * RETURNS:
261 * Status of operation
262 * NOTES:
263 * This is the high level interface for receiving RawIp datagrams
264 */
265 {
266 KIRQL OldIrql;
267 NTSTATUS Status;
268 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
269
270 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
271
272 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
273
274 if (AF_IS_VALID(AddrFile))
275 {
276 ReceiveRequest = exAllocatePool(NonPagedPool, sizeof(DATAGRAM_RECEIVE_REQUEST));
277 if (ReceiveRequest)
278 {
279 /* Initialize a receive request */
280
281 /* Extract the remote address filter from the request (if any) */
282 if ((ConnInfo->RemoteAddressLength != 0) &&
283 (ConnInfo->RemoteAddress))
284 {
285 Status = AddrGetAddress(ConnInfo->RemoteAddress,
286 &ReceiveRequest->RemoteAddress,
287 &ReceiveRequest->RemotePort);
288 if (!NT_SUCCESS(Status))
289 {
290 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
291 exFreePool(ReceiveRequest);
292 return Status;
293 }
294 }
295 else
296 {
297 ReceiveRequest->RemotePort = 0;
298 }
299 ReceiveRequest->ReturnInfo = ReturnInfo;
300 ReceiveRequest->Buffer = BufferData;
301 ReceiveRequest->BufferSize = ReceiveLength;
302 ReceiveRequest->UserComplete = Complete;
303 ReceiveRequest->UserContext = Context;
304 ReceiveRequest->Complete =
305 (PDATAGRAM_COMPLETION_ROUTINE)RawIpReceiveComplete;
306 ReceiveRequest->Context = ReceiveRequest;
307
308 /* Queue receive request */
309 InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);
310 AF_SET_PENDING(AddrFile, AFF_RECEIVE);
311
312 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
313
314 TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
315
316 return STATUS_PENDING;
317 }
318 else
319 {
320 Status = STATUS_INSUFFICIENT_RESOURCES;
321 }
322 }
323 else
324 {
325 Status = STATUS_INVALID_ADDRESS;
326 }
327
328 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
329
330 TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));
331
332 return Status;
333 }
334
335
336 VOID RawIpReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
337 /*
338 * FUNCTION: Receives and queues a RawIp datagram
339 * ARGUMENTS:
340 * NTE = Pointer to net table entry which the packet was received on
341 * IPPacket = Pointer to an IP packet that was received
342 * NOTES:
343 * This is the low level interface for receiving RawIp datagrams. It strips
344 * the RawIp header from a packet and delivers the data to anyone that wants it
345 */
346 {
347 AF_SEARCH SearchContext;
348 PIPv4_HEADER IPv4Header;
349 PADDRESS_FILE AddrFile;
350 PIP_ADDRESS DstAddress, SrcAddress;
351 UINT DataSize;
352
353 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
354
355 switch (IPPacket->Type) {
356 /* IPv4 packet */
357 case IP_ADDRESS_V4:
358 IPv4Header = IPPacket->Header;
359 DstAddress = &IPPacket->DstAddr;
360 SrcAddress = &IPPacket->SrcAddr;
361 DataSize = IPPacket->TotalSize;
362 break;
363
364 /* IPv6 packet */
365 case IP_ADDRESS_V6:
366 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 datagram (%i bytes).\n", IPPacket->TotalSize));
367
368 /* FIXME: IPv6 is not supported */
369 return;
370
371 default:
372 return;
373 }
374
375 /* Locate a receive request on destination address file object
376 and deliver the packet if one is found. If there is no receive
377 request on the address file object, call the associated receive
378 handler. If no receive handler is registered, drop the packet */
379
380 AddrFile = AddrSearchFirst(DstAddress,
381 0,
382 IPv4Header->Protocol,
383 &SearchContext);
384 if (AddrFile) {
385 do {
386 DGDeliverData(AddrFile,
387 SrcAddress,
388 DstAddress,
389 0,
390 0,
391 IPPacket,
392 DataSize);
393 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
394 } else {
395 /* There are no open address files that will take this datagram */
396 /* FIXME: IPv4 only */
397 TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 raw datagram to address (0x%X).\n",
398 DN2H(DstAddress->Address.IPv4Address)));
399
400 /* FIXME: Send ICMP reply */
401 }
402 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
403 }
404
405
406 NTSTATUS RawIPStartup(VOID)
407 /*
408 * FUNCTION: Initializes the UDP subsystem
409 * RETURNS:
410 * Status of operation
411 */
412 {
413 #ifdef __NTDRIVER__
414 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
415 #endif
416
417 /* Register this protocol with IP layer */
418 IPRegisterProtocol(IPPROTO_ICMP, RawIpReceive);
419
420 return STATUS_SUCCESS;
421 }
422
423
424 NTSTATUS RawIPShutdown(VOID)
425 /*
426 * FUNCTION: Shuts down the UDP subsystem
427 * RETURNS:
428 * Status of operation
429 */
430 {
431 /* Deregister this protocol with IP layer */
432 IPRegisterProtocol(IPPROTO_ICMP, NULL);
433
434 return STATUS_SUCCESS;
435 }
436
437 /* EOF */