53c9403f982ee6362b0791cbb93aedef5f9d96e5
[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 = sizeof(IPv4_HEADER) + ExtraLength;
41
42 GetDataPtr( IPPacket->NdisPacket,
43 0,
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 = (USHORT)Random();
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
111 Packet->TotalSize = sizeof(IPv4_HEADER) + DataLen;
112
113 /* Prepare packet */
114 Status = AllocatePacketWithBuffer( &Packet->NdisPacket,
115 NULL,
116 Packet->TotalSize );
117
118 if( !NT_SUCCESS(Status) ) return Status;
119
120 TI_DbgPrint(MID_TRACE, ("Allocated packet: %x\n", Packet->NdisPacket));
121 TI_DbgPrint(MID_TRACE, ("Local Addr : %s\n", A2S(LocalAddress)));
122 TI_DbgPrint(MID_TRACE, ("Remote Addr: %s\n", A2S(RemoteAddress)));
123
124 switch (RemoteAddress->Type) {
125 case IP_ADDRESS_V4:
126 Status = AddGenericHeaderIPv4
127 (RemoteAddress, RemotePort,
128 LocalAddress, LocalPort, Packet, DataLen,
129 IPPROTO_RAW,
130 0, (PVOID *)&Payload );
131 break;
132 case IP_ADDRESS_V6:
133 /* FIXME: Support IPv6 */
134 Status = STATUS_UNSUCCESSFUL;
135 TI_DbgPrint(MIN_TRACE, ("IPv6 RawIp datagrams are not supported.\n"));
136 break;
137
138 default:
139 Status = STATUS_UNSUCCESSFUL;
140 TI_DbgPrint(MIN_TRACE, ("Bad Address Type %d\n", RemoteAddress->Type));
141 break;
142 }
143
144 if( !NT_SUCCESS(Status) ) {
145 TI_DbgPrint(MIN_TRACE, ("Cannot add header. Status = (0x%X)\n",
146 Status));
147 FreeNdisPacket(Packet->NdisPacket);
148 return Status;
149 }
150
151 TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
152 Packet->Header, Packet->Data,
153 (PCHAR)Packet->Data - (PCHAR)Packet->Header));
154
155 RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
156
157 Packet->Flags |= IP_PACKET_FLAG_RAW;
158
159 TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
160
161 DISPLAY_IP_PACKET(Packet);
162
163 TI_DbgPrint(MID_TRACE, ("Leaving\n"));
164
165 return STATUS_SUCCESS;
166 }
167
168 VOID RawIpSendPacketComplete
169 ( PVOID Context, PNDIS_PACKET Packet, NDIS_STATUS Status ) {
170 FreeNdisPacket( Packet );
171 }
172
173 NTSTATUS RawIPSendDatagram(
174 PADDRESS_FILE AddrFile,
175 PTDI_CONNECTION_INFORMATION ConnInfo,
176 PCHAR BufferData,
177 ULONG DataSize,
178 PULONG DataUsed )
179 /*
180 * FUNCTION: Sends an RawIp datagram to a remote address
181 * ARGUMENTS:
182 * Request = Pointer to TDI request
183 * ConnInfo = Pointer to connection information
184 * Buffer = Pointer to NDIS buffer with data
185 * DataSize = Size in bytes of data to be sent
186 * RETURNS:
187 * Status of operation
188 */
189 {
190 IP_PACKET Packet;
191 PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
192 IP_ADDRESS RemoteAddress, LocalAddress;
193 USHORT RemotePort;
194 NTSTATUS Status;
195 PNEIGHBOR_CACHE_ENTRY NCE;
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 return STATUS_UNSUCCESSFUL;
211 }
212
213 TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
214
215 if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
216 return STATUS_NETWORK_UNREACHABLE;
217
218 LocalAddress = AddrFile->Address;
219 if (AddrIsUnspecified(&LocalAddress))
220 {
221 /* If the local address is unspecified (0),
222 * then use the unicast address of the
223 * interface we're sending over
224 */
225 LocalAddress = NCE->Interface->Unicast;
226 }
227
228 Status = BuildRawIpPacket( &Packet,
229 &RemoteAddress,
230 RemotePort,
231 &LocalAddress,
232 AddrFile->Port,
233 BufferData,
234 DataSize );
235
236 if( !NT_SUCCESS(Status) )
237 return Status;
238
239 TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
240
241 if (!NT_SUCCESS(Status = IPSendDatagram( &Packet, NCE, RawIpSendPacketComplete, NULL )))
242 {
243 FreeNdisPacket(Packet.NdisPacket);
244 return Status;
245 }
246
247 TI_DbgPrint(MID_TRACE,("Leaving\n"));
248
249 return STATUS_SUCCESS;
250 }
251
252
253 VOID RawIpReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
254 /*
255 * FUNCTION: Receives and queues a RawIp datagram
256 * ARGUMENTS:
257 * NTE = Pointer to net table entry which the packet was received on
258 * IPPacket = Pointer to an IP packet that was received
259 * NOTES:
260 * This is the low level interface for receiving RawIp datagrams. It strips
261 * the RawIp header from a packet and delivers the data to anyone that wants it
262 */
263 {
264 AF_SEARCH SearchContext;
265 PIPv4_HEADER IPv4Header;
266 PADDRESS_FILE AddrFile;
267 PIP_ADDRESS DstAddress, SrcAddress;
268 UINT DataSize;
269
270 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
271
272 switch (IPPacket->Type) {
273 /* IPv4 packet */
274 case IP_ADDRESS_V4:
275 IPv4Header = IPPacket->Header;
276 DstAddress = &IPPacket->DstAddr;
277 SrcAddress = &IPPacket->SrcAddr;
278 DataSize = IPPacket->TotalSize;
279 break;
280
281 /* IPv6 packet */
282 case IP_ADDRESS_V6:
283 TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 datagram (%i bytes).\n", IPPacket->TotalSize));
284
285 /* FIXME: IPv6 is not supported */
286 return;
287
288 default:
289 return;
290 }
291
292 /* Locate a receive request on destination address file object
293 and deliver the packet if one is found. If there is no receive
294 request on the address file object, call the associated receive
295 handler. If no receive handler is registered, drop the packet */
296
297 AddrFile = AddrSearchFirst(DstAddress,
298 0,
299 IPv4Header->Protocol,
300 &SearchContext);
301 if (AddrFile) {
302 do {
303 DGDeliverData(AddrFile,
304 SrcAddress,
305 DstAddress,
306 0,
307 0,
308 IPPacket,
309 DataSize);
310 } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
311 } else {
312 /* There are no open address files that will take this datagram */
313 /* FIXME: IPv4 only */
314 TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 raw datagram to address (0x%X).\n",
315 DN2H(DstAddress->Address.IPv4Address)));
316
317 /* FIXME: Send ICMP reply */
318 }
319 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
320 }
321
322
323 NTSTATUS RawIPStartup(VOID)
324 /*
325 * FUNCTION: Initializes the UDP subsystem
326 * RETURNS:
327 * Status of operation
328 */
329 {
330 #ifdef __NTDRIVER__
331 RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
332 #endif
333
334 /* Register this protocol with IP layer */
335 IPRegisterProtocol(IPPROTO_RAW, RawIpReceive);
336
337 return STATUS_SUCCESS;
338 }
339
340
341 NTSTATUS RawIPShutdown(VOID)
342 /*
343 * FUNCTION: Shuts down the UDP subsystem
344 * RETURNS:
345 * Status of operation
346 */
347 {
348 /* Deregister this protocol with IP layer */
349 IPRegisterProtocol(IPPROTO_RAW, NULL);
350
351 return STATUS_SUCCESS;
352 }
353
354 /* EOF */