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