update for HEAD-2003091401
[reactos.git] / drivers / net / tcpip / 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 #include <tcpip.h>
11 #include <ip.h>
12 #include <tcp.h>
13 #include <loopback.h>
14 #include <neighbor.h>
15 #include <receive.h>
16 #include <address.h>
17 #include <route.h>
18 #include <icmp.h>
19 #include <pool.h>
20
21
22 KTIMER IPTimer;
23 KDPC IPTimeoutDpc;
24 LIST_ENTRY InterfaceListHead;
25 KSPIN_LOCK InterfaceListLock;
26 LIST_ENTRY NetTableListHead;
27 KSPIN_LOCK NetTableListLock;
28 LIST_ENTRY PrefixListHead;
29 KSPIN_LOCK PrefixListLock;
30 UINT MaxLLHeaderSize; /* Largest maximum header size */
31 UINT MinLLFrameSize;  /* Largest minimum frame size */
32 BOOLEAN IPInitialized = FALSE;
33 NPAGED_LOOKASIDE_LIST IPPacketList;
34
35 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
36
37
38 VOID FreePacket(
39     PVOID Object)
40 /*
41  * FUNCTION: Frees an IP packet object
42  * ARGUMENTS:
43  *     Object = Pointer to an IP packet structure
44  */
45 {
46     ExFreeToNPagedLookasideList(&IPPacketList, Object);
47 }
48
49
50 VOID FreeADE(
51     PVOID Object)
52 /*
53  * FUNCTION: Frees an address entry object
54  * ARGUMENTS:
55  *     Object = Pointer to an address entry structure
56  */
57 {
58     ExFreePool(Object);
59 }
60
61
62 VOID FreeNTE(
63     PVOID Object)
64 /*
65  * FUNCTION: Frees a net table entry object
66  * ARGUMENTS:
67  *     Object = Pointer to an net table entry structure
68  */
69 {
70     ExFreePool(Object);
71 }
72
73
74 VOID FreeIF(
75     PVOID Object)
76 /*
77  * FUNCTION: Frees an interface object
78  * ARGUMENTS:
79  *     Object = Pointer to an interface structure
80  */
81 {
82     ExFreePool(Object);
83 }
84
85
86 PADDRESS_ENTRY CreateADE(
87     PIP_INTERFACE IF,    PIP_ADDRESS Address,
88     UCHAR Type,
89     PNET_TABLE_ENTRY NTE)
90 /*
91  * FUNCTION: Creates an address entry and binds it to an interface
92  * ARGUMENTS:
93  *     IF      = Pointer to interface
94  *     Address = Pointer to referenced interface address
95  *     Type    = Type of address (ADE_*)
96  *     NTE     = Pointer to net table entry
97  * RETURNS:
98  *     Pointer to ADE, NULL if there was not enough free resources
99  * NOTES:
100  *     The interface lock must be held when called. The address entry
101  *     retains a reference to the provided address and NTE. The caller
102  *     is responsible for referencing the these before calling.
103  *     As long as you have referenced an ADE you can safely use the
104  *     address and NTE as the ADE references both
105  */
106 {
107     PADDRESS_ENTRY ADE;
108
109     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  Type (0x%X)  NTE (0x%X).\n",
110         IF, Address, Type, NTE));
111
112     TI_DbgPrint(DEBUG_IP, ("Address (%s)  NTE (%s).\n",
113         A2S(Address), A2S(NTE->Address)));
114
115     /* Allocate space for an ADE and set it up */
116     ADE = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_ENTRY));
117     if (!ADE) {
118         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
119         return NULL;
120     }
121
122     INIT_TAG(ADE, TAG('A','D','E',' '));
123     ADE->Free     = FreeADE;
124     ADE->RefCount = 1;
125     ADE->NTE      = NTE;
126     ADE->Type     = Type;
127     ADE->Address  = Address;
128
129     /* Add ADE to the list on the interface */
130     InsertTailList(&IF->ADEListHead, &ADE->ListEntry);
131
132     return ADE;
133 }
134
135
136 VOID DestroyADE(
137     PIP_INTERFACE IF,
138     PADDRESS_ENTRY ADE)
139 /*
140  * FUNCTION: Destroys an address entry
141  * ARGUMENTS:
142  *     IF  = Pointer to interface
143  *     ADE = Pointer to address entry
144  * NOTES:
145  *     The interface lock must be held when called
146  */
147 {
148     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  ADE (0x%X).\n", IF, ADE));
149
150     TI_DbgPrint(DEBUG_IP, ("ADE (%s).\n", ADE->Address));
151
152     /* Unlink the address entry from the list */
153     RemoveEntryList(&ADE->ListEntry);
154
155     /* Dereference the address */
156     DereferenceObject(ADE->Address);
157
158     /* Dereference the NTE */
159     DereferenceObject(ADE->NTE);
160
161 #ifdef DBG
162     ADE->RefCount--;
163
164     if (ADE->RefCount != 0) {
165         TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount));
166     }
167 #endif
168
169     /* And free the ADE */
170     FreeADE(ADE);
171 }
172
173
174 VOID DestroyADEs(
175     PIP_INTERFACE IF)
176 /*
177  * FUNCTION: Destroys all address entries on an interface
178  * ARGUMENTS:
179  *     IF  = Pointer to interface
180  * NOTES:
181  *     The interface lock must be held when called
182  */
183 {
184     PLIST_ENTRY CurrentEntry;
185     PLIST_ENTRY NextEntry;
186     PADDRESS_ENTRY Current;
187
188     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
189
190     /* Search the list and remove every ADE we find */
191     CurrentEntry = IF->ADEListHead.Flink;
192     while (CurrentEntry != &IF->ADEListHead) {
193         NextEntry = CurrentEntry->Flink;
194             Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
195         /* Destroy the ADE */
196         DestroyADE(IF, Current);
197         CurrentEntry = NextEntry;
198     }
199 }
200
201
202 PIP_PACKET IPCreatePacket(
203   ULONG Type)
204 /*
205  * FUNCTION: Creates an IP packet object
206  * ARGUMENTS:
207  *     Type = Type of IP packet
208  * RETURNS:
209  *     Pointer to the created IP packet. NULL if there was not enough free resources.
210  */
211 {
212   PIP_PACKET IPPacket;
213
214   IPPacket = ExAllocateFromNPagedLookasideList(&IPPacketList);
215   if (!IPPacket)
216     return NULL;
217
218     /* FIXME: Is this needed? */
219   RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
220
221   INIT_TAG(IPPacket, TAG('I','P','K','T'));
222
223   IPPacket->Free     = FreePacket;
224   IPPacket->RefCount = 1;
225   IPPacket->Type     = Type;
226
227   return IPPacket;
228 }
229
230
231 PPREFIX_LIST_ENTRY CreatePLE(
232     PIP_INTERFACE IF,
233     PIP_ADDRESS Prefix,
234     UINT Length)
235 /*
236  * FUNCTION: Creates a prefix list entry and binds it to an interface
237  * ARGUMENTS:
238  *     IF     = Pointer to interface
239  *     Prefix = Pointer to prefix
240  *     Length = Length of prefix
241  * RETURNS:
242  *     Pointer to PLE, NULL if there was not enough free resources
243  * NOTES:
244  *     The prefix list entry retains a reference to the interface and
245  *     the provided address.  The caller is responsible for providing
246  *     these references
247  */
248 {
249     PPREFIX_LIST_ENTRY PLE;
250
251     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Prefix (0x%X)  Length (%d).\n", IF, Prefix, Length));
252
253     TI_DbgPrint(DEBUG_IP, ("Prefix (%s).\n", A2S(Prefix)));
254
255     /* Allocate space for an PLE and set it up */
256     PLE = ExAllocatePool(NonPagedPool, sizeof(PREFIX_LIST_ENTRY));
257     if (!PLE) {
258         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
259         return NULL;
260     }
261
262     INIT_TAG(PLE, TAG('P','L','E',' '));
263     PLE->RefCount     = 1;
264     PLE->Interface    = IF;
265     PLE->Prefix       = Prefix;
266     PLE->PrefixLength = Length;
267
268     /* Add PLE to the global prefix list */
269     ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock);
270
271     return PLE;
272 }
273
274
275 VOID DestroyPLE(
276     PPREFIX_LIST_ENTRY PLE)
277 /*
278  * FUNCTION: Destroys an prefix list entry
279  * ARGUMENTS:
280  *     PLE = Pointer to prefix list entry
281  * NOTES:
282  *     The prefix list lock must be held when called
283  */
284 {
285     TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE));
286
287     TI_DbgPrint(DEBUG_IP, ("PLE (%s).\n", PLE->Prefix));
288
289     /* Unlink the prefix list entry from the list */
290     RemoveEntryList(&PLE->ListEntry);
291
292     /* Dereference the address */
293     DereferenceObject(PLE->Prefix);
294
295     /* Dereference the interface */
296     DereferenceObject(PLE->Interface);
297
298 #ifdef DBG
299     PLE->RefCount--;
300
301     if (PLE->RefCount != 0) {
302         TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount));
303     }
304 #endif
305
306     /* And free the PLE */
307     ExFreePool(PLE);
308 }
309
310
311 VOID DestroyPLEs(
312     VOID)
313 /*
314  * FUNCTION: Destroys all prefix list entries
315  */
316 {
317     KIRQL OldIrql;
318     PLIST_ENTRY CurrentEntry;
319     PLIST_ENTRY NextEntry;
320     PPREFIX_LIST_ENTRY Current;
321
322     TI_DbgPrint(DEBUG_IP, ("Called.\n"));
323
324     KeAcquireSpinLock(&PrefixListLock, &OldIrql);
325
326     /* Search the list and remove every PLE we find */
327     CurrentEntry = PrefixListHead.Flink;
328     while (CurrentEntry != &PrefixListHead) {
329         NextEntry = CurrentEntry->Flink;
330               Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);
331         /* Destroy the PLE */
332         DestroyPLE(Current);
333         CurrentEntry = NextEntry;
334     }
335     KeReleaseSpinLock(&PrefixListLock, OldIrql);
336 }
337
338
339 PNET_TABLE_ENTRY IPCreateNTE(
340     PIP_INTERFACE IF,
341     PIP_ADDRESS Address,
342     UINT PrefixLength)
343 /*
344  * FUNCTION: Creates a net table entry and binds it to an interface
345  * ARGUMENTS:
346  *     IF           = Pointer to interface
347  *     Address      = Pointer to interface address
348  *     PrefixLength = Length of prefix
349  * RETURNS:
350  *     Pointer to NTE, NULL if there was not enough free resources
351  * NOTES:
352  *     The interface lock must be held when called.
353  *     The net table entry retains a reference to the interface and
354  *     the provided address. The caller is responsible for providing
355  *     these references
356  */
357 {
358     PNET_TABLE_ENTRY NTE;
359     PADDRESS_ENTRY ADE;
360
361     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  PrefixLength (%d).\n", IF, Address, PrefixLength));
362
363     TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
364
365     /* Allocate room for an NTE */
366     NTE = ExAllocatePool(NonPagedPool, sizeof(NET_TABLE_ENTRY));
367     if (!NTE) {
368         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
369         return NULL;
370     }
371
372     INIT_TAG(NTE, TAG('N','T','E',' '));
373     INIT_TAG(Address, TAG('A','D','R','S'));
374
375     NTE->Free = FreeNTE;
376
377     NTE->Interface = IF;
378
379     /* One reference is for beeing alive and one reference is for the ADE */
380     NTE->RefCount = 2;
381
382     NTE->Address = Address;
383     /* One reference is for NTE, one reference is given to the
384        address entry, and one reference is given to the prefix
385        list entry */
386     ReferenceObject(Address);
387     ReferenceObject(Address);
388     ReferenceObject(Address);
389
390     /* Create an address entry and add it to the list */
391     ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
392     if (!ADE) {
393         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
394         ExFreePool(NTE);
395         return NULL;
396     }
397
398     /* Create a prefix list entry for unicast address */
399     NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
400     if (!NTE->PLE) {
401         DestroyADE(IF, ADE);
402         ExFreePool(NTE);
403         return NULL;
404     }
405
406     /* Reference the interface for the prefix list entry */
407     ReferenceObject(IF);
408
409     /* Add NTE to the list on the interface */
410     InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
411
412     /* Add NTE to the global net table list */
413     ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
414
415     return NTE;
416 }
417
418
419 VOID DestroyNTE(
420     PIP_INTERFACE IF,
421     PNET_TABLE_ENTRY NTE)
422 /*
423  * FUNCTION: Destroys a net table entry
424  * ARGUMENTS:
425  *     IF  = Pointer to interface
426  *     NTE = Pointer to net table entry
427  * NOTES:
428  *     The net table list lock must be held when called
429  *     The interface lock must be held when called
430  */
431 {
432     KIRQL OldIrql;
433
434     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  NTE (0x%X).\n", IF, NTE));
435
436     TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
437
438     /* Invalidate the prefix list entry for this NTE */
439     KeAcquireSpinLock(&PrefixListLock, &OldIrql);
440     DestroyPLE(NTE->PLE);
441     KeReleaseSpinLock(&PrefixListLock, OldIrql);
442
443     /* Remove NTE from the interface list */
444     RemoveEntryList(&NTE->IFListEntry);
445     /* Remove NTE from the net table list */
446
447 /* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
448
449     RemoveEntryList(&NTE->NTListEntry);
450
451  */
452
453     /* Dereference the objects that are referenced */
454     DereferenceObject(NTE->Address);
455     DereferenceObject(NTE->Interface);
456 #ifdef DBG
457     NTE->RefCount--;
458
459     if (NTE->RefCount != 0) {
460         TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount));
461     }
462 #endif
463     /* And free the NTE */
464     ExFreePool(NTE);
465 }
466
467
468 VOID DestroyNTEs(
469     PIP_INTERFACE IF)
470 /*
471  * FUNCTION: Destroys all net table entries on an interface
472  * ARGUMENTS:
473  *     IF  = Pointer to interface
474  * NOTES:
475  *     The net table list lock must be held when called
476  *     The interface lock may be held when called
477  */
478 {
479     PLIST_ENTRY CurrentEntry;
480     PLIST_ENTRY NextEntry;
481     PNET_TABLE_ENTRY Current;
482
483     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
484
485     /* Search the list and remove every NTE we find */
486     CurrentEntry = IF->NTEListHead.Flink;
487     while (CurrentEntry != &IF->NTEListHead) {
488         NextEntry = CurrentEntry->Flink;
489               Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
490         /* Destroy the NTE */
491         DestroyNTE(IF, Current);
492         CurrentEntry = NextEntry;
493     }
494 }
495
496
497 PNET_TABLE_ENTRY IPLocateNTEOnInterface(
498     PIP_INTERFACE IF,
499     PIP_ADDRESS Address,
500     PUINT AddressType)
501 /*
502  * FUNCTION: Locates an NTE on an interface
503  * ARGUMENTS:
504  *     IF          = Pointer to interface
505  *     Address     = Pointer to IP address
506  *     AddressType = Address of type of IP address
507  * NOTES:
508  *     If found, the NTE is referenced for the caller. The caller is
509  *     responsible for dereferencing after use
510  * RETURNS:
511  *     Pointer to net table entry, NULL if none was found
512  */
513 {
514     KIRQL OldIrql;
515     PLIST_ENTRY CurrentEntry;
516     PADDRESS_ENTRY Current;
517
518 //    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  AddressType (0x%X).\n",
519 //        IF, Address, AddressType));
520
521 //    TI_DbgPrint(DEBUG_IP, ("Address (%s)  AddressType (0x%X).\n", A2S(Address)));
522
523     KeAcquireSpinLock(&IF->Lock, &OldIrql);
524
525     /* Search the list and return the NTE if found */
526     CurrentEntry = IF->ADEListHead.Flink;
527
528     if (CurrentEntry == &IF->ADEListHead) {
529         TI_DbgPrint(DEBUG_IP, ("NTE list is empty!!!\n"));
530     }
531
532     while (CurrentEntry != &IF->ADEListHead) {
533               Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
534         if (AddrIsEqual(Address, Current->Address)) {
535             ReferenceObject(Current->NTE);
536             *AddressType = Current->Type;
537             KeReleaseSpinLock(&IF->Lock, OldIrql);
538             return Current->NTE;
539         }
540         else {
541             TI_DbgPrint(DEBUG_IP, ("CurrentEntry = 0x%X != &IF->ADEListHead = 0x%X.\n", CurrentEntry, &IF->ADEListHead));
542         }
543         CurrentEntry = CurrentEntry->Flink;
544     }
545
546     KeReleaseSpinLock(&IF->Lock, OldIrql);
547
548     return NULL;
549 }
550
551
552 PNET_TABLE_ENTRY IPLocateNTE(
553     PIP_ADDRESS Address,
554     PUINT AddressType)
555 /*
556  * FUNCTION: Locates an NTE for the network Address is on 
557  * ARGUMENTS:
558  *     Address     = Pointer to an address to find associated NTE of
559  *     AddressType = Address of address type
560  * NOTES:
561  *     If found the NTE is referenced for the caller. The caller is
562  *     responsible for dereferencing after use
563  * RETURNS:
564  *     Pointer to NTE if the address was found, NULL if not.
565  */
566 {
567     KIRQL OldIrql;
568     PLIST_ENTRY CurrentEntry;
569     PNET_TABLE_ENTRY Current;
570     PNET_TABLE_ENTRY NTE;
571
572 //    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",
573 //        Address, AddressType));
574
575 //    TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
576
577     KeAcquireSpinLock(&NetTableListLock, &OldIrql);
578
579     /* Search the list and return the NTE if found */
580     CurrentEntry = NetTableListHead.Flink;
581     while (CurrentEntry != &NetTableListHead) {
582               Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);
583         NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);
584         if (NTE) {
585             ReferenceObject(NTE);
586             KeReleaseSpinLock(&NetTableListLock, OldIrql);
587             return NTE;
588         }
589         CurrentEntry = CurrentEntry->Flink;
590     }
591
592     KeReleaseSpinLock(&NetTableListLock, OldIrql);
593
594     return NULL;
595 }
596
597
598 PADDRESS_ENTRY IPLocateADE(
599     PIP_ADDRESS Address,
600     UINT AddressType)
601 /*
602  * FUNCTION: Locates an ADE for the address
603  * ARGUMENTS:
604  *     Address     = Pointer to an address to find associated ADE of
605  *     AddressType = Type of address
606  * RETURNS:
607  *     Pointer to ADE if the address was found, NULL if not.
608  * NOTES:
609  *     If found the ADE is referenced for the caller. The caller is
610  *     responsible for dereferencing after use
611  */
612 {
613     KIRQL OldIrql;
614     PLIST_ENTRY CurrentIFEntry;
615     PLIST_ENTRY CurrentADEEntry;
616     PIP_INTERFACE CurrentIF;
617     PADDRESS_ENTRY CurrentADE;
618
619 //    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",
620 //        Address, AddressType));
621
622 //    TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
623
624     KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
625
626     /* Search the interface list */
627     CurrentIFEntry = InterfaceListHead.Flink;
628     while (CurrentIFEntry != &InterfaceListHead) {
629               CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
630
631         /* Search the address entry list and return the ADE if found */
632         CurrentADEEntry = CurrentIF->ADEListHead.Flink;
633         while (CurrentADEEntry != &CurrentIF->ADEListHead) {
634                 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
635             if ((AddrIsEqual(Address, CurrentADE->Address)) && 
636                 (CurrentADE->Type == AddressType)) {
637                 ReferenceObject(CurrentADE);
638                 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
639                 return CurrentADE;
640             }
641             CurrentADEEntry = CurrentADEEntry->Flink;
642         }
643         CurrentIFEntry = CurrentIFEntry->Flink;
644     }
645
646     KeReleaseSpinLock(&InterfaceListLock, OldIrql);
647
648     return NULL;
649 }
650
651
652 PADDRESS_ENTRY IPGetDefaultADE(
653     UINT AddressType)
654 /*
655  * FUNCTION: Returns a default address entry
656  * ARGUMENTS:
657  *     AddressType = Type of address
658  * RETURNS:
659  *     Pointer to ADE if found, NULL if not.
660  * NOTES:
661  *     Loopback interface is only considered if it is the only interface.
662  *     If found, the address entry is referenced
663  */
664 {
665     KIRQL OldIrql;
666     PLIST_ENTRY CurrentIFEntry;
667     PLIST_ENTRY CurrentADEEntry;
668     PIP_INTERFACE CurrentIF;
669     PADDRESS_ENTRY CurrentADE;
670     BOOLEAN LoopbackIsRegistered = FALSE;
671
672     TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
673
674     KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
675
676     /* Search the interface list */
677     CurrentIFEntry = InterfaceListHead.Flink;
678     while (CurrentIFEntry != &InterfaceListHead) {
679               CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
680
681         if (CurrentIF != Loopback) {
682             /* Search the address entry list and return the first appropriate ADE found */
683             CurrentADEEntry = CurrentIF->ADEListHead.Flink;
684             while (CurrentADEEntry != &CurrentIF->ADEListHead) {
685                     CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
686                 if (CurrentADE->Type == AddressType)
687                     ReferenceObject(CurrentADE);
688                     KeReleaseSpinLock(&InterfaceListLock, OldIrql);
689                     return CurrentADE;
690                 }
691                 CurrentADEEntry = CurrentADEEntry->Flink;
692         } else
693             LoopbackIsRegistered = TRUE;
694         CurrentIFEntry = CurrentIFEntry->Flink;
695     }
696
697     /* No address was found. Use loopback interface if available */
698     if (LoopbackIsRegistered) {
699         CurrentADEEntry = Loopback->ADEListHead.Flink;
700         while (CurrentADEEntry != &Loopback->ADEListHead) {
701                 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
702             if (CurrentADE->Type == AddressType) {
703                 ReferenceObject(CurrentADE);
704                 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
705                 return CurrentADE;
706             }
707             CurrentADEEntry = CurrentADEEntry->Flink;
708         }
709     }
710
711     KeReleaseSpinLock(&InterfaceListLock, OldIrql);
712
713     return NULL;
714 }
715
716
717 VOID STDCALL IPTimeout(
718     PKDPC Dpc,
719     PVOID DeferredContext,
720     PVOID SystemArgument1,
721     PVOID SystemArgument2)
722 /*
723  * FUNCTION: Timeout DPC
724  * ARGUMENTS:
725  *     Dpc             = Pointer to our DPC object
726  *     DeferredContext = Pointer to context information (unused)
727  *     SystemArgument1 = Unused
728  *     SystemArgument2 = Unused
729  * NOTES:
730  *     This routine is dispatched once in a while to do maintainance jobs
731  */
732 {
733     /* Check if datagram fragments have taken too long to assemble */
734     IPDatagramReassemblyTimeout();
735
736     /* Clean possible outdated cached neighbor addresses */
737     NBTimeout();
738
739     /* Call upper layer timeout routines */
740     TCPTimeout();
741 }
742
743
744 VOID IPDispatchProtocol(
745     PNET_TABLE_ENTRY NTE,
746     PIP_PACKET IPPacket)
747 /*
748  * FUNCTION: IP protocol dispatcher
749  * ARGUMENTS:
750  *     NTE      = Pointer to net table entry which the packet was received on
751  *     IPPacket = Pointer to an IP packet that was received
752  * NOTES:
753  *     This routine examines the IP header and passes the packet on to the
754  *     right upper level protocol receive handler
755  */
756 {
757     UINT Protocol;
758
759     switch (IPPacket->Type) {
760     case IP_ADDRESS_V4:
761         Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
762         break;
763     case IP_ADDRESS_V6:
764         /* FIXME: IPv6 adresses not supported */
765         TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
766         return;
767     default:
768         Protocol = 0;
769     }
770
771     /* Call the appropriate protocol handler */
772     (*ProtocolTable[Protocol])(NTE, IPPacket);
773 }
774
775
776 PIP_INTERFACE IPCreateInterface(
777     PLLIP_BIND_INFO BindInfo)
778 /*
779  * FUNCTION: Creates an IP interface
780  * ARGUMENTS:
781  *     BindInfo = Pointer to link layer to IP binding information
782  * RETURNS:
783  *     Pointer to IP_INTERFACE structure, NULL if there was
784  *     not enough free resources
785  */
786 {
787     PIP_INTERFACE IF;
788
789     TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
790
791 #ifdef DBG
792     if (BindInfo->Address) {
793         PUCHAR A = BindInfo->Address;
794         TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
795             A[0], A[1], A[2], A[3], A[4], A[5]));
796     }
797 #endif
798
799     IF = ExAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
800     if (!IF) {
801         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
802         return NULL;
803     }
804
805     INIT_TAG(IF, TAG('F','A','C','E'));
806
807     IF->Free       = FreeIF;
808     IF->RefCount   = 1;
809     IF->Context    = BindInfo->Context;
810     IF->HeaderSize = BindInfo->HeaderSize;
811           if (IF->HeaderSize > MaxLLHeaderSize)
812                 MaxLLHeaderSize = IF->HeaderSize;
813
814     IF->MinFrameSize = BindInfo->MinFrameSize;
815           if (IF->MinFrameSize > MinLLFrameSize)
816                 MinLLFrameSize = IF->MinFrameSize;
817
818     IF->MTU           = BindInfo->MTU;
819     IF->Address       = BindInfo->Address;
820     IF->AddressLength = BindInfo->AddressLength;
821     IF->Transmit      = BindInfo->Transmit;
822
823     InitializeListHead(&IF->ADEListHead);
824     InitializeListHead(&IF->NTEListHead);
825
826     KeInitializeSpinLock(&IF->Lock);
827
828     return IF;
829 }
830
831
832 VOID IPDestroyInterface(
833     PIP_INTERFACE IF)
834 /*
835  * FUNCTION: Destroys an IP interface
836  * ARGUMENTS:
837  *     IF = Pointer to interface to destroy
838  */
839 {
840     KIRQL OldIrql1;
841     KIRQL OldIrql2;
842
843     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
844
845     KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
846     KeAcquireSpinLock(&IF->Lock, &OldIrql2);
847     DestroyADEs(IF);
848     DestroyNTEs(IF);
849     KeReleaseSpinLock(&IF->Lock, OldIrql2);
850     KeReleaseSpinLock(&NetTableListLock, OldIrql1);
851
852 #ifdef DBG
853     IF->RefCount--;
854
855     if (IF->RefCount != 0) {
856         TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));
857     }
858 #endif
859     ExFreePool(IF);
860 }
861
862
863 BOOLEAN IPRegisterInterface(
864     PIP_INTERFACE IF)
865 /*
866  * FUNCTION: Registers an IP interface with IP layer
867  * ARGUMENTS:
868  *     IF = Pointer to interface to register
869  * RETURNS;
870  *     TRUE if interface was successfully registered, FALSE if not
871  */
872 {
873     KIRQL OldIrql;
874     PLIST_ENTRY CurrentEntry;
875     PNET_TABLE_ENTRY Current;
876     PROUTE_CACHE_NODE RCN;
877     PNEIGHBOR_CACHE_ENTRY NCE;
878
879     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
880
881     KeAcquireSpinLock(&IF->Lock, &OldIrql);
882
883     /* Add routes to all NTEs on this interface */
884     CurrentEntry = IF->NTEListHead.Flink;
885     while (CurrentEntry != &IF->NTEListHead) {
886             Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
887
888         /* Add a permanent neighbor for this NTE */
889         ReferenceObject(Current->Address);
890         NCE = NBAddNeighbor(IF, Current->Address, IF->Address,
891             IF->AddressLength, NUD_PERMANENT);
892         if (!NCE) {
893             TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
894             DereferenceObject(Current->Address);
895             KeReleaseSpinLock(&IF->Lock, OldIrql);
896             return FALSE;
897         }
898 #if 1
899         /* Reference objects for forward information base */
900         ReferenceObject(Current->Address);
901         ReferenceObject(Current->PLE->Prefix);
902         ReferenceObject(Current);
903         /* NCE is already referenced */
904         if (!RouterAddRoute(Current->Address, Current->PLE->Prefix, Current, NCE, 1)) {
905             TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
906             DereferenceObject(Current->Address);
907             DereferenceObject(Current->PLE->Prefix);
908             DereferenceObject(Current);
909             DereferenceObject(NCE);
910         }
911 #else
912         RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
913         if (!RCN) {
914             TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
915             DereferenceObject(Current->Address);
916             KeReleaseSpinLock(&IF->Lock, OldIrql);
917             return FALSE;
918         }
919         /* Don't need this any more since the route cache references the NCE */
920         DereferenceObject(NCE);
921 #endif
922         CurrentEntry = CurrentEntry->Flink;
923     }
924
925     /* Add interface to the global interface list */
926     ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);
927
928     KeReleaseSpinLock(&IF->Lock, OldIrql);
929
930     return TRUE;
931 }
932
933
934 VOID IPUnregisterInterface(
935     PIP_INTERFACE IF)
936 /*
937  * FUNCTION: Unregisters an IP interface with IP layer
938  * ARGUMENTS:
939  *     IF = Pointer to interface to unregister
940  */
941 {
942     KIRQL OldIrql1;
943     KIRQL OldIrql2;
944     KIRQL OldIrql3;
945     PLIST_ENTRY CurrentEntry;
946     PNET_TABLE_ENTRY Current;
947     PNEIGHBOR_CACHE_ENTRY NCE;
948
949     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
950
951     KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
952     KeAcquireSpinLock(&IF->Lock, &OldIrql2);
953
954     /* Remove routes to all NTEs on this interface */
955     CurrentEntry = IF->NTEListHead.Flink;
956     while (CurrentEntry != &IF->NTEListHead) {
957         Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
958
959         /* Remove NTE from global net table list */
960         RemoveEntryList(&Current->NTListEntry);
961
962         /* Remove all references from route cache to NTE */
963         RouteInvalidateNTE(Current);
964
965         /* Remove permanent NCE, but first we have to find it */
966         NCE = NBLocateNeighbor(Current->Address);
967         if (NCE) {
968             DereferenceObject(NCE);
969             NBRemoveNeighbor(NCE);
970         }
971
972         CurrentEntry = CurrentEntry->Flink;
973     }
974
975     KeAcquireSpinLock(&InterfaceListLock, &OldIrql3);
976     /* Ouch...three spinlocks acquired! Fortunately
977        we don't unregister interfaces very often */
978     RemoveEntryList(&IF->ListEntry);
979     KeReleaseSpinLock(&InterfaceListLock, OldIrql3);
980
981     KeReleaseSpinLock(&IF->Lock, OldIrql2);
982     KeReleaseSpinLock(&NetTableListLock, OldIrql1);
983 }
984
985
986 VOID IPRegisterProtocol(
987     UINT ProtocolNumber,
988     IP_PROTOCOL_HANDLER Handler)
989 /*
990  * FUNCTION: Registers a handler for an IP protocol number
991  * ARGUMENTS:
992  *     ProtocolNumber = Internet Protocol number for which to register handler
993  *     Handler        = Pointer to handler to be called when a packet is received
994  * NOTES:
995  *     To unregister a protocol handler, call this function with Handler = NULL
996  */
997 {
998 #ifdef DBG
999     if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
1000         TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
1001 #endif
1002
1003     ProtocolTable[ProtocolNumber] = Handler;
1004 }
1005
1006
1007 VOID DefaultProtocolHandler(
1008     PNET_TABLE_ENTRY NTE,
1009     PIP_PACKET IPPacket)
1010 /*
1011  * FUNCTION: Default handler for Internet protocols
1012  * ARGUMENTS:
1013  *     NTE      = Pointer to net table entry which the packet was received on
1014  *     IPPacket = Pointer to an IP packet that was received
1015  */
1016 {
1017     TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
1018 }
1019
1020
1021 NTSTATUS IPStartup(
1022     PDRIVER_OBJECT DriverObject,
1023     PUNICODE_STRING RegistryPath)
1024 /*
1025  * FUNCTION: Initializes the IP subsystem
1026  * ARGUMENTS:
1027  *     DriverObject = Pointer to a driver object for this driver
1028  *     RegistryPath = Our registry node for configuration parameters
1029  * RETURNS:
1030  *     Status of operation
1031  */
1032 {
1033     UINT i;
1034     LARGE_INTEGER DueTime;
1035
1036     TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1037
1038         MaxLLHeaderSize = 0;
1039     MinLLFrameSize  = 0;
1040
1041     /* Initialize lookaside lists */
1042     ExInitializeNPagedLookasideList(
1043       &IPDRList,                      /* Lookaside list */
1044             NULL,                           /* Allocate routine */
1045             NULL,                           /* Free routine */
1046             0,                              /* Flags */
1047             sizeof(IPDATAGRAM_REASSEMBLY),  /* Size of each entry */
1048             TAG('I','P','D','R'),           /* Tag */
1049             0);                             /* Depth */
1050
1051     ExInitializeNPagedLookasideList(
1052       &IPPacketList,                  /* Lookaside list */
1053             NULL,                           /* Allocate routine */
1054             NULL,                           /* Free routine */
1055             0,                              /* Flags */
1056             sizeof(IP_PACKET),              /* Size of each entry */
1057             TAG('I','P','P','K'),           /* Tag */
1058             0);                             /* Depth */
1059
1060     ExInitializeNPagedLookasideList(
1061       &IPFragmentList,                /* Lookaside list */
1062             NULL,                           /* Allocate routine */
1063             NULL,                           /* Free routine */
1064             0,                              /* Flags */
1065             sizeof(IP_FRAGMENT),            /* Size of each entry */
1066             TAG('I','P','F','G'),           /* Tag */
1067             0);                             /* Depth */
1068
1069     ExInitializeNPagedLookasideList(
1070       &IPHoleList,                    /* Lookaside list */
1071             NULL,                           /* Allocate routine */
1072             NULL,                           /* Free routine */
1073             0,                              /* Flags */
1074             sizeof(IPDATAGRAM_HOLE),        /* Size of each entry */
1075             TAG('I','P','H','L'),           /* Tag */
1076             0);                             /* Depth */
1077
1078     /* Start routing subsystem */
1079     RouterStartup();
1080
1081     /* Start route cache subsystem */
1082     RouteStartup();
1083
1084     /* Start neighbor cache subsystem */
1085     NBStartup();
1086
1087     /* Fill the protocol dispatch table with pointers
1088        to the default protocol handler */
1089     for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
1090         IPRegisterProtocol(i, DefaultProtocolHandler);
1091
1092     /* Register network level protocol receive handlers */
1093     IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
1094
1095     /* Initialize NTE list and protecting lock */
1096     InitializeListHead(&NetTableListHead);
1097     KeInitializeSpinLock(&NetTableListLock);
1098
1099     /* Initialize reassembly list and protecting lock */
1100     InitializeListHead(&ReassemblyListHead);
1101     KeInitializeSpinLock(&ReassemblyListLock);
1102
1103     /* Initialize the prefix list and protecting lock */
1104     InitializeListHead(&PrefixListHead);
1105     KeInitializeSpinLock(&PrefixListLock);
1106
1107     /* Initialize our periodic timer and its associated DPC object. When the
1108        timer expires, the IPTimeout deferred procedure call (DPC) is queued */
1109     KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL);
1110     KeInitializeTimer(&IPTimer);
1111
1112     /* Start the periodic timer with an initial and periodic
1113        relative expiration time of IP_TIMEOUT milliseconds */
1114     DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;
1115     KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);
1116
1117     IPInitialized = TRUE;
1118
1119     return STATUS_SUCCESS;
1120 }
1121
1122
1123 NTSTATUS IPShutdown(
1124     VOID)
1125 /*
1126  * FUNCTION: Shuts down the IP subsystem
1127  * RETURNS:
1128  *     Status of operation
1129  */
1130 {
1131     TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1132
1133     if (!IPInitialized)
1134         return STATUS_SUCCESS;
1135
1136     /* Cancel timer */
1137     KeCancelTimer(&IPTimer);
1138
1139     /* Shutdown neighbor cache subsystem */
1140     NBShutdown();
1141
1142     /* Shutdown route cache subsystem */
1143     RouteShutdown();
1144
1145     /* Shutdown routing subsystem */
1146     RouterShutdown();
1147
1148     IPFreeReassemblyList();
1149
1150     /* Clear prefix list */
1151     DestroyPLEs();
1152
1153     /* Destroy lookaside lists */
1154     ExDeleteNPagedLookasideList(&IPHoleList);
1155     ExDeleteNPagedLookasideList(&IPDRList);
1156     ExDeleteNPagedLookasideList(&IPPacketList);
1157     ExDeleteNPagedLookasideList(&IPFragmentList);
1158
1159     IPInitialized = FALSE;
1160
1161     return STATUS_SUCCESS;
1162 }
1163
1164 /* EOF */