f2718b90696de75976eb8f3a2f12f03655a8b6a9
[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 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->ContigSize );
47
48 IPPacket->HeaderSize = 20;
49
50 TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n",
51 BufferSize, IPPacket->Header));
52 TI_DbgPrint(MAX_TRACE, ("Packet total length %d\n", IPPacket->TotalSize));
53
54 /* Build IPv4 header */
55 IPHeader = (PIPv4_HEADER)IPPacket->Header;
56 /* Version = 4, Length = 5 DWORDs */
57 IPHeader->VerIHL = 0x45;
58 /* Normal Type-of-Service */
59 IPHeader->Tos = 0;
60 /* Length of header and data */
61 IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
62 /* Identification */
63 IPHeader->Id = (USHORT)Random();
64 /* One fragment at offset 0 */
65 IPHeader->FlagsFragOfs = 0;
66 /* Time-to-Live */
67 IPHeader->Ttl = AddrFile->TTL;
68 /* Protocol */
69 IPHeader->Protocol = Protocol;
70 /* Checksum is 0 (for later calculation of this) */
71 IPHeader->Checksum = 0;
72 /* Source address */
73 IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
74 /* Destination address. FIXME: IPv4 only */
75 IPHeader->DstAddr = RemoteAddress->Address.IPv4Address;
76
77 /* Build RawIp header */
78 *NextHeader = (((PCHAR)IPHeader) + sizeof(IPv4_HEADER));
79 IPPacket->Data = ((PCHAR)*NextHeader) + ExtraLength;
80
81 return STATUS_SUCCESS;
82 }
83
84
85 NTSTATUS BuildRawIpPacket(
86 PADDRESS_FILE AddrFile,
87 PIP_PACKET Packet,
88 PIP_ADDRESS RemoteAddress,
89 USHORT RemotePort,
90 PIP_ADDRESS LocalAddress,
91 USHORT LocalPort,
92 PCHAR DataBuffer,
93 UINT DataLen )
94 /*
95 * FUNCTION: Builds an RawIp packet
96 * ARGUMENTS:
97 * Context = Pointer to context information (DATAGRAM_SEND_REQUEST)
98 * LocalAddress = Pointer to our local address
99 * LocalPort = The port we send this datagram from
100 * IPPacket = Address of pointer to IP packet
101 * RETURNS:
102 * Status of operation
103 */
104 {
105 NTSTATUS Status;
106 PCHAR Payload;
107
108 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
109
110 /* FIXME: Assumes IPv4 */
111 IPInitializePacket(Packet, IP_ADDRESS_V4);
112
113 Packet->TotalSize = sizeof(IPv4_HEADER) + DataLen;
114
115 /* Prepare packet */
116 Status = AllocatePacketWithBuffer( &Packet->NdisPacket,
117 NULL,
118 Packet->TotalSize );
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 (AddrFile, RemoteAddress, RemotePort,
130 LocalAddress, LocalPort, Packet, DataLen,
131 AddrFile->Protocol,
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 if( !NT_SUCCESS(Status) ) {
147 TI_DbgPrint(MIN_TRACE, ("Cannot add header. Status = (0x%X)\n",
148 Status));
149 FreeNdisPacket(Packet->NdisPacket);
150 return Status;
151 }
152
153 TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
154 Packet->Header, Packet->Data,
155 (PCHAR)Packet->Data - (PCHAR)Packet->Header));
156
157 RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
158
159 Packet->Flags |= IP_PACKET_FLAG_RAW;
160
161 TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
162
163 DISPLAY_IP_PACKET(Packet);
164
165 TI_DbgPrint(MID_TRACE, ("Leaving\n"));
166
167 return STATUS_SUCCESS;
168 }
169
170 NTSTATUS RawIPSendDatagram(
171 PADDRESS_FILE AddrFile,
172 PTDI_CONNECTION_INFORMATION ConnInfo,
173 PCHAR BufferData,
174 ULONG DataSize,
175 PULONG DataUsed )
176 /*
177 * FUNCTION: Sends an RawIp datagram to a remote address
178 * ARGUMENTS:
179 * Request = Pointer to TDI request
180 * ConnInfo = Pointer to connection information
181 * Buffer = Pointer to NDIS buffer with data
182 * DataSize = Size in bytes of data to be sent
183 * RETURNS:
184 * Status of operation
185 */
186 {
187 IP_PACKET Packet;
188 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
189 IP_ADDRESS RemoteAddress, LocalAddress;
190 USHORT RemotePort;
191 NTSTATUS Status;
192 PNEIGHBOR_CACHE_ENTRY NCE;
193 KIRQL OldIrql;
194
195 LockObject(AddrFile, &OldIrql);
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, OldIrql);
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, OldIrql);
225 return STATUS_NETWORK_UNREACHABLE;
226 }
227
228 LocalAddress = NCE->Interface->Unicast;
229 }
230 else
231 {
232 if(!(NCE = NBLocateNeighbor( &LocalAddress ))) {
233 UnlockObject(AddrFile, OldIrql);
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, OldIrql);
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 FreeNdisPacket(Packet.NdisPacket);
256 if (!NT_SUCCESS(Status))
257 return Status;
258
259 *DataUsed = DataSize;
260
261 TI_DbgPrint(MID_TRACE,("Leaving\n"));
262
263 return STATUS_SUCCESS;
264 }
265
266
267 VOID RawIpReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
268 /*
269 * FUNCTION: Receives and queues a RawIp datagram
270 * ARGUMENTS:
271 * NTE = Pointer to net table entry which the packet was received on
272 * IPPacket = Pointer to an IP packet that was received
273 * NOTES:
274 * This is the low level interface for receiving RawIp datagrams. It strips
275 * the RawIp header from a packet and delivers the data to anyone that wants it
276 */
277 {
278 AF_SEARCH SearchContext;
279 PIPv4_HEADER IPv4Header;
280 PADDRESS_FILE AddrFile;
281 PIP_ADDRESS DstAddress, SrcAddress;
282 UINT DataSize;
283
284 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
285
286 switch (IPPacket->Type) {
287 /* IPv4 packet */
288 case IP_ADDRESS_V4:
289 IPv4Header = IPPacket->Header;
290 DstAddress = &IPPacket->DstAddr;
291 SrcAddress = &IPPacket->SrcAddr;
292 DataSize = IPPacket->TotalSize;
293 break;
294
295 /* IPv6 packet */
296 case IP_ADDRESS_V6:
297 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 datagram (%i bytes).\n", IPPacket->TotalSize));
298
299 /* FIXME: IPv6 is not supported */
300 return;
301
302 default:
303 return;
304 }
305
306 /* Locate a receive request on destination address file object
307 and deliver the packet if one is found. If there is no receive
308 request on the address file object, call the associated receive
309 handler. If no receive handler is registered, drop the packet */
310
311 AddrFile = AddrSearchFirst(DstAddress,
312 0,
313 IPv4Header->Protocol,
314 &SearchContext);
315 if (AddrFile) {
316 do {
317 DGDeliverData(AddrFile,
318 SrcAddress,
319 DstAddress,
320 0,
321 0,
322 IPPacket,
323 DataSize);
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 #ifdef __NTDRIVER__
345 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
346 #endif
347
348 /* Register this protocol with IP layer */
349 IPRegisterProtocol(IPPROTO_RAW, RawIpReceive);
350
351 return STATUS_SUCCESS;
352 }
353
354
355 NTSTATUS RawIPShutdown(VOID)
356 /*
357 * FUNCTION: Shuts down the UDP subsystem
358 * RETURNS:
359 * Status of operation
360 */
361 {
362 /* Deregister this protocol with IP layer */
363 IPRegisterProtocol(IPPROTO_RAW, NULL);
364
365 return STATUS_SUCCESS;
366 }
367
368 /* EOF */