[TCPIP]
[reactos.git] / reactos / lib / drivers / ip / network / ip.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: network/ip.c
5 * PURPOSE: Internet Protocol module
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 #define __LWIP_INET_H__
14 #include "lwip/netifapi.h"
15
16
17 LIST_ENTRY InterfaceListHead;
18 KSPIN_LOCK InterfaceListLock;
19 LIST_ENTRY NetTableListHead;
20 KSPIN_LOCK NetTableListLock;
21 BOOLEAN IPInitialized = FALSE;
22 BOOLEAN IpWorkItemQueued = FALSE;
23 /* Work around calling timer at Dpc level */
24
25 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
26
27 VOID
28 TCPRegisterInterface(PIP_INTERFACE IF);
29
30 VOID
31 TCPUnregisterInterface(PIP_INTERFACE IF);
32
33 VOID DontFreePacket(
34 PVOID Object)
35 /*
36 * FUNCTION: Do nothing for when the IPPacket struct is part of another
37 * ARGUMENTS:
38 * Object = Pointer to an IP packet structure
39 */
40 {
41 }
42
43 VOID FreeIF(
44 PVOID Object)
45 /*
46 * FUNCTION: Frees an interface object
47 * ARGUMENTS:
48 * Object = Pointer to an interface structure
49 */
50 {
51 ExFreePoolWithTag(Object, IP_INTERFACE_TAG);
52 }
53
54 PIP_PACKET IPInitializePacket(
55 PIP_PACKET IPPacket,
56 ULONG Type)
57 /*
58 * FUNCTION: Creates an IP packet object
59 * ARGUMENTS:
60 * Type = Type of IP packet
61 * RETURNS:
62 * Pointer to the created IP packet. NULL if there was not enough free resources.
63 */
64 {
65 /* FIXME: Is this needed? */
66 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
67
68 IPPacket->Free = DontFreePacket;
69 IPPacket->Type = Type;
70
71 return IPPacket;
72 }
73
74
75 VOID NTAPI IPTimeoutDpcFn(PKDPC Dpc,
76 PVOID DeferredContext,
77 PVOID SystemArgument1,
78 PVOID SystemArgument2)
79 /*
80 * FUNCTION: Timeout DPC
81 * ARGUMENTS:
82 * Dpc = Pointer to our DPC object
83 * DeferredContext = Pointer to context information (unused)
84 * SystemArgument1 = Unused
85 * SystemArgument2 = Unused
86 * NOTES:
87 * This routine is dispatched once in a while to do maintainance jobs
88 */
89 {
90 /* Check if datagram fragments have taken too long to assemble */
91 IPDatagramReassemblyTimeout();
92
93 /* Clean possible outdated cached neighbor addresses */
94 NBTimeout();
95 }
96
97
98 VOID IPDispatchProtocol(
99 PIP_INTERFACE Interface,
100 PIP_PACKET IPPacket)
101 /*
102 * FUNCTION: IP protocol dispatcher
103 * ARGUMENTS:
104 * NTE = Pointer to net table entry which the packet was received on
105 * IPPacket = Pointer to an IP packet that was received
106 * NOTES:
107 * This routine examines the IP header and passes the packet on to the
108 * right upper level protocol receive handler
109 */
110 {
111 UINT Protocol;
112 IP_ADDRESS SrcAddress;
113
114 switch (IPPacket->Type) {
115 case IP_ADDRESS_V4:
116 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
117 AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr);
118 break;
119 case IP_ADDRESS_V6:
120 /* FIXME: IPv6 adresses not supported */
121 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
122 return;
123 default:
124 TI_DbgPrint(MIN_TRACE, ("Unrecognized datagram discarded.\n"));
125 return;
126 }
127
128 NBResetNeighborTimeout(&SrcAddress);
129
130 if (Protocol < IP_PROTOCOL_TABLE_SIZE)
131 {
132 /* Call the appropriate protocol handler */
133 (*ProtocolTable[Protocol])(Interface, IPPacket);
134 }
135 }
136
137
138 PIP_INTERFACE IPCreateInterface(
139 PLLIP_BIND_INFO BindInfo)
140 /*
141 * FUNCTION: Creates an IP interface
142 * ARGUMENTS:
143 * BindInfo = Pointer to link layer to IP binding information
144 * RETURNS:
145 * Pointer to IP_INTERFACE structure, NULL if there was
146 * not enough free resources
147 */
148 {
149 PIP_INTERFACE IF;
150
151 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
152
153 #if DBG
154 if (BindInfo->Address) {
155 PUCHAR A = BindInfo->Address;
156 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
157 A[0], A[1], A[2], A[3], A[4], A[5]));
158 }
159 #endif
160
161 IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(IP_INTERFACE),
162 IP_INTERFACE_TAG);
163 if (!IF) {
164 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
165 return NULL;
166 }
167
168 RtlZeroMemory(IF, sizeof(IP_INTERFACE));
169
170 IF->Free = FreeIF;
171 IF->Context = BindInfo->Context;
172 IF->HeaderSize = BindInfo->HeaderSize;
173 IF->MinFrameSize = BindInfo->MinFrameSize;
174 IF->MTU = BindInfo->MTU;
175 IF->Address = BindInfo->Address;
176 IF->AddressLength = BindInfo->AddressLength;
177 IF->Transmit = BindInfo->Transmit;
178
179 IF->Unicast.Type = IP_ADDRESS_V4;
180 IF->PointToPoint.Type = IP_ADDRESS_V4;
181 IF->Netmask.Type = IP_ADDRESS_V4;
182 IF->Broadcast.Type = IP_ADDRESS_V4;
183
184 TcpipInitializeSpinLock(&IF->Lock);
185
186 IF->TCPContext = ExAllocatePool
187 ( NonPagedPool, sizeof(struct netif));
188 if (!IF->TCPContext) {
189 ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
190 return NULL;
191 }
192
193 TCPRegisterInterface(IF);
194
195 #ifdef __NTDRIVER__
196 InsertTDIInterfaceEntity( IF );
197 #endif
198
199 return IF;
200 }
201
202
203 VOID IPDestroyInterface(
204 PIP_INTERFACE IF)
205 /*
206 * FUNCTION: Destroys an IP interface
207 * ARGUMENTS:
208 * IF = Pointer to interface to destroy
209 */
210 {
211 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
212
213 #ifdef __NTDRIVER__
214 RemoveTDIInterfaceEntity( IF );
215 #endif
216
217 TCPUnregisterInterface(IF);
218
219 ExFreePool(IF->TCPContext);
220 ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
221 }
222
223 VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
224 PNEIGHBOR_CACHE_ENTRY NCE;
225 IP_ADDRESS NetworkAddress;
226
227 /* Add a permanent neighbor for this NTE */
228 NCE = NBAddNeighbor(IF, &IF->Unicast,
229 IF->Address, IF->AddressLength,
230 NUD_PERMANENT, 0);
231 if (!NCE) {
232 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
233 return;
234 }
235
236 AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask );
237
238 if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) {
239 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
240 }
241
242 /* Send a gratuitous ARP packet to update the route caches of
243 * other computers */
244 if (IF != Loopback)
245 ARPTransmit(NULL, NULL, IF);
246
247 TCPUpdateInterfaceIPInformation(IF);
248 }
249
250 BOOLEAN IPRegisterInterface(
251 PIP_INTERFACE IF)
252 /*
253 * FUNCTION: Registers an IP interface with IP layer
254 * ARGUMENTS:
255 * IF = Pointer to interface to register
256 * RETURNS;
257 * TRUE if interface was successfully registered, FALSE if not
258 */
259 {
260 KIRQL OldIrql;
261 UINT ChosenIndex = 0;
262 BOOLEAN IndexHasBeenChosen;
263 IF_LIST_ITER(Interface);
264
265 TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
266
267 TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
268
269 /* Choose an index */
270 do {
271 IndexHasBeenChosen = TRUE;
272 ForEachInterface(Interface) {
273 if( Interface->Index == ChosenIndex ) {
274 ChosenIndex++;
275 IndexHasBeenChosen = FALSE;
276 }
277 } EndFor(Interface);
278 } while( !IndexHasBeenChosen );
279
280 IF->Index = ChosenIndex;
281
282 if (!AddrIsUnspecified(&IF->Unicast))
283 {
284 IPAddInterfaceRoute(IF);
285 }
286
287 /* Add interface to the global interface list */
288 TcpipInterlockedInsertTailList(&InterfaceListHead,
289 &IF->ListEntry,
290 &InterfaceListLock);
291
292 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
293
294 return TRUE;
295 }
296
297 VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) {
298 PNEIGHBOR_CACHE_ENTRY NCE;
299 IP_ADDRESS GeneralRoute;
300
301 NCE = NBLocateNeighbor(&IF->Unicast);
302 if (NCE)
303 {
304 TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast)));
305 TI_DbgPrint(DEBUG_IP,(" Mask %s\n", A2S(&IF->Netmask)));
306
307 AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask);
308
309 RouterRemoveRoute(&GeneralRoute, &IF->Unicast);
310
311 NBRemoveNeighbor(NCE);
312 }
313 }
314
315 VOID IPUnregisterInterface(
316 PIP_INTERFACE IF)
317 /*
318 * FUNCTION: Unregisters an IP interface with IP layer
319 * ARGUMENTS:
320 * IF = Pointer to interface to unregister
321 */
322 {
323 KIRQL OldIrql3;
324
325 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
326
327 IPRemoveInterfaceRoute( IF );
328
329 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
330 RemoveEntryList(&IF->ListEntry);
331 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
332 }
333
334
335 VOID DefaultProtocolHandler(
336 PIP_INTERFACE Interface,
337 PIP_PACKET IPPacket)
338 /*
339 * FUNCTION: Default handler for Internet protocols
340 * ARGUMENTS:
341 * NTE = Pointer to net table entry which the packet was received on
342 * IPPacket = Pointer to an IP packet that was received
343 */
344 {
345 TI_DbgPrint(MID_TRACE, ("[IF %x] Packet of unknown Internet protocol "
346 "discarded.\n", Interface));
347
348 Interface->Stats.InDiscardedUnknownProto++;
349 }
350
351
352 VOID IPRegisterProtocol(
353 UINT ProtocolNumber,
354 IP_PROTOCOL_HANDLER Handler)
355 /*
356 * FUNCTION: Registers a handler for an IP protocol number
357 * ARGUMENTS:
358 * ProtocolNumber = Internet Protocol number for which to register handler
359 * Handler = Pointer to handler to be called when a packet is received
360 * NOTES:
361 * To unregister a protocol handler, call this function with Handler = NULL
362 */
363 {
364 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) {
365 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
366 return;
367 }
368
369 ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler;
370 }
371
372
373 NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
374 /*
375 * FUNCTION: Initializes the IP subsystem
376 * ARGUMENTS:
377 * RegistryPath = Our registry node for configuration parameters
378 * RETURNS:
379 * Status of operation
380 */
381 {
382 UINT i;
383
384 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
385
386 /* Initialize lookaside lists */
387 ExInitializeNPagedLookasideList(
388 &IPDRList, /* Lookaside list */
389 NULL, /* Allocate routine */
390 NULL, /* Free routine */
391 0, /* Flags */
392 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
393 DATAGRAM_REASSEMBLY_TAG, /* Tag */
394 0); /* Depth */
395
396 ExInitializeNPagedLookasideList(
397 &IPFragmentList, /* Lookaside list */
398 NULL, /* Allocate routine */
399 NULL, /* Free routine */
400 0, /* Flags */
401 sizeof(IP_FRAGMENT), /* Size of each entry */
402 DATAGRAM_FRAGMENT_TAG, /* Tag */
403 0); /* Depth */
404
405 ExInitializeNPagedLookasideList(
406 &IPHoleList, /* Lookaside list */
407 NULL, /* Allocate routine */
408 NULL, /* Free routine */
409 0, /* Flags */
410 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
411 DATAGRAM_HOLE_TAG, /* Tag */
412 0); /* Depth */
413
414 /* Start routing subsystem */
415 RouterStartup();
416
417 /* Start neighbor cache subsystem */
418 NBStartup();
419
420 /* Fill the protocol dispatch table with pointers
421 to the default protocol handler */
422 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
423 IPRegisterProtocol(i, DefaultProtocolHandler);
424
425 /* Initialize NTE list and protecting lock */
426 InitializeListHead(&NetTableListHead);
427 TcpipInitializeSpinLock(&NetTableListLock);
428
429 /* Initialize reassembly list and protecting lock */
430 InitializeListHead(&ReassemblyListHead);
431 TcpipInitializeSpinLock(&ReassemblyListLock);
432
433 IPInitialized = TRUE;
434
435 return STATUS_SUCCESS;
436 }
437
438
439 NTSTATUS IPShutdown(
440 VOID)
441 /*
442 * FUNCTION: Shuts down the IP subsystem
443 * RETURNS:
444 * Status of operation
445 */
446 {
447 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
448
449 if (!IPInitialized)
450 return STATUS_SUCCESS;
451
452 /* Shutdown neighbor cache subsystem */
453 NBShutdown();
454
455 /* Shutdown routing subsystem */
456 RouterShutdown();
457
458 IPFreeReassemblyList();
459
460 /* Destroy lookaside lists */
461 ExDeleteNPagedLookasideList(&IPHoleList);
462 ExDeleteNPagedLookasideList(&IPDRList);
463 ExDeleteNPagedLookasideList(&IPFragmentList);
464
465 IPInitialized = FALSE;
466
467 return STATUS_SUCCESS;
468 }
469
470 /* EOF */