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