2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Internet Protocol module
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
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;
35 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
41 * FUNCTION: Frees an IP packet object
43 * Object = Pointer to an IP packet structure
46 ExFreeToNPagedLookasideList(&IPPacketList, Object);
53 * FUNCTION: Frees an address entry object
55 * Object = Pointer to an address entry structure
65 * FUNCTION: Frees a net table entry object
67 * Object = Pointer to an net table entry structure
77 * FUNCTION: Frees an interface object
79 * Object = Pointer to an interface structure
86 PADDRESS_ENTRY CreateADE(
87 PIP_INTERFACE IF, PIP_ADDRESS Address,
91 * FUNCTION: Creates an address entry and binds it to an interface
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
98 * Pointer to ADE, NULL if there was not enough free resources
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
109 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n",
110 IF, Address, Type, NTE));
112 TI_DbgPrint(DEBUG_IP, ("Address (%s) NTE (%s).\n",
113 A2S(Address), A2S(NTE->Address)));
115 /* Allocate space for an ADE and set it up */
116 ADE = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_ENTRY));
118 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
122 INIT_TAG(ADE, TAG('A','D','E',' '));
127 ADE->Address = Address;
129 /* Add ADE to the list on the interface */
130 InsertTailList(&IF->ADEListHead, &ADE->ListEntry);
140 * FUNCTION: Destroys an address entry
142 * IF = Pointer to interface
143 * ADE = Pointer to address entry
145 * The interface lock must be held when called
148 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) ADE (0x%X).\n", IF, ADE));
150 TI_DbgPrint(DEBUG_IP, ("ADE (%s).\n", ADE->Address));
152 /* Unlink the address entry from the list */
153 RemoveEntryList(&ADE->ListEntry);
155 /* Dereference the address */
156 DereferenceObject(ADE->Address);
158 /* Dereference the NTE */
159 DereferenceObject(ADE->NTE);
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));
169 /* And free the ADE */
177 * FUNCTION: Destroys all address entries on an interface
179 * IF = Pointer to interface
181 * The interface lock must be held when called
184 PLIST_ENTRY CurrentEntry;
185 PLIST_ENTRY NextEntry;
186 PADDRESS_ENTRY Current;
188 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
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;
202 PIP_PACKET IPCreatePacket(
205 * FUNCTION: Creates an IP packet object
207 * Type = Type of IP packet
209 * Pointer to the created IP packet. NULL if there was not enough free resources.
214 IPPacket = ExAllocateFromNPagedLookasideList(&IPPacketList);
218 /* FIXME: Is this needed? */
219 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
221 INIT_TAG(IPPacket, TAG('I','P','K','T'));
223 IPPacket->Free = FreePacket;
224 IPPacket->RefCount = 1;
225 IPPacket->Type = Type;
231 PPREFIX_LIST_ENTRY CreatePLE(
236 * FUNCTION: Creates a prefix list entry and binds it to an interface
238 * IF = Pointer to interface
239 * Prefix = Pointer to prefix
240 * Length = Length of prefix
242 * Pointer to PLE, NULL if there was not enough free resources
244 * The prefix list entry retains a reference to the interface and
245 * the provided address. The caller is responsible for providing
249 PPREFIX_LIST_ENTRY PLE;
251 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF, Prefix, Length));
253 TI_DbgPrint(DEBUG_IP, ("Prefix (%s).\n", A2S(Prefix)));
255 /* Allocate space for an PLE and set it up */
256 PLE = ExAllocatePool(NonPagedPool, sizeof(PREFIX_LIST_ENTRY));
258 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
262 INIT_TAG(PLE, TAG('P','L','E',' '));
265 PLE->Prefix = Prefix;
266 PLE->PrefixLength = Length;
268 /* Add PLE to the global prefix list */
269 ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock);
276 PPREFIX_LIST_ENTRY PLE)
278 * FUNCTION: Destroys an prefix list entry
280 * PLE = Pointer to prefix list entry
282 * The prefix list lock must be held when called
285 TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE));
287 TI_DbgPrint(DEBUG_IP, ("PLE (%s).\n", PLE->Prefix));
289 /* Unlink the prefix list entry from the list */
290 RemoveEntryList(&PLE->ListEntry);
292 /* Dereference the address */
293 DereferenceObject(PLE->Prefix);
295 /* Dereference the interface */
296 DereferenceObject(PLE->Interface);
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));
306 /* And free the PLE */
314 * FUNCTION: Destroys all prefix list entries
318 PLIST_ENTRY CurrentEntry;
319 PLIST_ENTRY NextEntry;
320 PPREFIX_LIST_ENTRY Current;
322 TI_DbgPrint(DEBUG_IP, ("Called.\n"));
324 KeAcquireSpinLock(&PrefixListLock, &OldIrql);
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 */
333 CurrentEntry = NextEntry;
335 KeReleaseSpinLock(&PrefixListLock, OldIrql);
339 PNET_TABLE_ENTRY IPCreateNTE(
344 * FUNCTION: Creates a net table entry and binds it to an interface
346 * IF = Pointer to interface
347 * Address = Pointer to interface address
348 * PrefixLength = Length of prefix
350 * Pointer to NTE, NULL if there was not enough free resources
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
358 PNET_TABLE_ENTRY NTE;
361 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF, Address, PrefixLength));
363 TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
365 /* Allocate room for an NTE */
366 NTE = ExAllocatePool(NonPagedPool, sizeof(NET_TABLE_ENTRY));
368 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
372 INIT_TAG(NTE, TAG('N','T','E',' '));
373 INIT_TAG(Address, TAG('A','D','R','S'));
379 /* One reference is for beeing alive and one reference is for the ADE */
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
386 ReferenceObject(Address);
387 ReferenceObject(Address);
388 ReferenceObject(Address);
390 /* Create an address entry and add it to the list */
391 ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
393 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
398 /* Create a prefix list entry for unicast address */
399 NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
406 /* Reference the interface for the prefix list entry */
409 /* Add NTE to the list on the interface */
410 InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
412 /* Add NTE to the global net table list */
413 ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
421 PNET_TABLE_ENTRY NTE)
423 * FUNCTION: Destroys a net table entry
425 * IF = Pointer to interface
426 * NTE = Pointer to net table entry
428 * The net table list lock must be held when called
429 * The interface lock must be held when called
434 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE));
436 TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
438 /* Invalidate the prefix list entry for this NTE */
439 KeAcquireSpinLock(&PrefixListLock, &OldIrql);
440 DestroyPLE(NTE->PLE);
441 KeReleaseSpinLock(&PrefixListLock, OldIrql);
443 /* Remove NTE from the interface list */
444 RemoveEntryList(&NTE->IFListEntry);
445 /* Remove NTE from the net table list */
447 /* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
449 RemoveEntryList(&NTE->NTListEntry);
453 /* Dereference the objects that are referenced */
454 DereferenceObject(NTE->Address);
455 DereferenceObject(NTE->Interface);
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));
463 /* And free the NTE */
471 * FUNCTION: Destroys all net table entries on an interface
473 * IF = Pointer to interface
475 * The net table list lock must be held when called
476 * The interface lock may be held when called
479 PLIST_ENTRY CurrentEntry;
480 PLIST_ENTRY NextEntry;
481 PNET_TABLE_ENTRY Current;
483 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
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;
497 PNET_TABLE_ENTRY IPLocateNTEOnInterface(
502 * FUNCTION: Locates an NTE on an interface
504 * IF = Pointer to interface
505 * Address = Pointer to IP address
506 * AddressType = Address of type of IP address
508 * If found, the NTE is referenced for the caller. The caller is
509 * responsible for dereferencing after use
511 * Pointer to net table entry, NULL if none was found
515 PLIST_ENTRY CurrentEntry;
516 PADDRESS_ENTRY Current;
518 // TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
519 // IF, Address, AddressType));
521 // TI_DbgPrint(DEBUG_IP, ("Address (%s) AddressType (0x%X).\n", A2S(Address)));
523 KeAcquireSpinLock(&IF->Lock, &OldIrql);
525 /* Search the list and return the NTE if found */
526 CurrentEntry = IF->ADEListHead.Flink;
528 if (CurrentEntry == &IF->ADEListHead) {
529 TI_DbgPrint(DEBUG_IP, ("NTE list is empty!!!\n"));
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);
541 TI_DbgPrint(DEBUG_IP, ("CurrentEntry = 0x%X != &IF->ADEListHead = 0x%X.\n", CurrentEntry, &IF->ADEListHead));
543 CurrentEntry = CurrentEntry->Flink;
546 KeReleaseSpinLock(&IF->Lock, OldIrql);
552 PNET_TABLE_ENTRY IPLocateNTE(
556 * FUNCTION: Locates an NTE for the network Address is on
558 * Address = Pointer to an address to find associated NTE of
559 * AddressType = Address of address type
561 * If found the NTE is referenced for the caller. The caller is
562 * responsible for dereferencing after use
564 * Pointer to NTE if the address was found, NULL if not.
568 PLIST_ENTRY CurrentEntry;
569 PNET_TABLE_ENTRY Current;
570 PNET_TABLE_ENTRY NTE;
572 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
573 // Address, AddressType));
575 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
577 KeAcquireSpinLock(&NetTableListLock, &OldIrql);
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);
585 ReferenceObject(NTE);
586 KeReleaseSpinLock(&NetTableListLock, OldIrql);
589 CurrentEntry = CurrentEntry->Flink;
592 KeReleaseSpinLock(&NetTableListLock, OldIrql);
598 PADDRESS_ENTRY IPLocateADE(
602 * FUNCTION: Locates an ADE for the address
604 * Address = Pointer to an address to find associated ADE of
605 * AddressType = Type of address
607 * Pointer to ADE if the address was found, NULL if not.
609 * If found the ADE is referenced for the caller. The caller is
610 * responsible for dereferencing after use
614 PLIST_ENTRY CurrentIFEntry;
615 PLIST_ENTRY CurrentADEEntry;
616 PIP_INTERFACE CurrentIF;
617 PADDRESS_ENTRY CurrentADE;
619 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
620 // Address, AddressType));
622 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
624 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
626 /* Search the interface list */
627 CurrentIFEntry = InterfaceListHead.Flink;
628 while (CurrentIFEntry != &InterfaceListHead) {
629 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
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);
641 CurrentADEEntry = CurrentADEEntry->Flink;
643 CurrentIFEntry = CurrentIFEntry->Flink;
646 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
652 PADDRESS_ENTRY IPGetDefaultADE(
655 * FUNCTION: Returns a default address entry
657 * AddressType = Type of address
659 * Pointer to ADE if found, NULL if not.
661 * Loopback interface is only considered if it is the only interface.
662 * If found, the address entry is referenced
666 PLIST_ENTRY CurrentIFEntry;
667 PLIST_ENTRY CurrentADEEntry;
668 PIP_INTERFACE CurrentIF;
669 PADDRESS_ENTRY CurrentADE;
670 BOOLEAN LoopbackIsRegistered = FALSE;
672 TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
674 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
676 /* Search the interface list */
677 CurrentIFEntry = InterfaceListHead.Flink;
678 while (CurrentIFEntry != &InterfaceListHead) {
679 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
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);
691 CurrentADEEntry = CurrentADEEntry->Flink;
693 LoopbackIsRegistered = TRUE;
694 CurrentIFEntry = CurrentIFEntry->Flink;
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);
707 CurrentADEEntry = CurrentADEEntry->Flink;
711 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
717 VOID STDCALL IPTimeout(
719 PVOID DeferredContext,
720 PVOID SystemArgument1,
721 PVOID SystemArgument2)
723 * FUNCTION: Timeout DPC
725 * Dpc = Pointer to our DPC object
726 * DeferredContext = Pointer to context information (unused)
727 * SystemArgument1 = Unused
728 * SystemArgument2 = Unused
730 * This routine is dispatched once in a while to do maintainance jobs
733 /* Check if datagram fragments have taken too long to assemble */
734 IPDatagramReassemblyTimeout();
736 /* Clean possible outdated cached neighbor addresses */
739 /* Call upper layer timeout routines */
744 VOID IPDispatchProtocol(
745 PNET_TABLE_ENTRY NTE,
748 * FUNCTION: IP protocol dispatcher
750 * NTE = Pointer to net table entry which the packet was received on
751 * IPPacket = Pointer to an IP packet that was received
753 * This routine examines the IP header and passes the packet on to the
754 * right upper level protocol receive handler
759 switch (IPPacket->Type) {
761 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
764 /* FIXME: IPv6 adresses not supported */
765 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
771 /* Call the appropriate protocol handler */
772 (*ProtocolTable[Protocol])(NTE, IPPacket);
776 PIP_INTERFACE IPCreateInterface(
777 PLLIP_BIND_INFO BindInfo)
779 * FUNCTION: Creates an IP interface
781 * BindInfo = Pointer to link layer to IP binding information
783 * Pointer to IP_INTERFACE structure, NULL if there was
784 * not enough free resources
789 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
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]));
799 IF = ExAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
801 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
805 INIT_TAG(IF, TAG('F','A','C','E'));
809 IF->Context = BindInfo->Context;
810 IF->HeaderSize = BindInfo->HeaderSize;
811 if (IF->HeaderSize > MaxLLHeaderSize)
812 MaxLLHeaderSize = IF->HeaderSize;
814 IF->MinFrameSize = BindInfo->MinFrameSize;
815 if (IF->MinFrameSize > MinLLFrameSize)
816 MinLLFrameSize = IF->MinFrameSize;
818 IF->MTU = BindInfo->MTU;
819 IF->Address = BindInfo->Address;
820 IF->AddressLength = BindInfo->AddressLength;
821 IF->Transmit = BindInfo->Transmit;
823 InitializeListHead(&IF->ADEListHead);
824 InitializeListHead(&IF->NTEListHead);
826 KeInitializeSpinLock(&IF->Lock);
832 VOID IPDestroyInterface(
835 * FUNCTION: Destroys an IP interface
837 * IF = Pointer to interface to destroy
843 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
845 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
846 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
849 KeReleaseSpinLock(&IF->Lock, OldIrql2);
850 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
855 if (IF->RefCount != 0) {
856 TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));
863 BOOLEAN IPRegisterInterface(
866 * FUNCTION: Registers an IP interface with IP layer
868 * IF = Pointer to interface to register
870 * TRUE if interface was successfully registered, FALSE if not
874 PLIST_ENTRY CurrentEntry;
875 PNET_TABLE_ENTRY Current;
876 PROUTE_CACHE_NODE RCN;
877 PNEIGHBOR_CACHE_ENTRY NCE;
879 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
881 KeAcquireSpinLock(&IF->Lock, &OldIrql);
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);
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);
893 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
894 DereferenceObject(Current->Address);
895 KeReleaseSpinLock(&IF->Lock, OldIrql);
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);
912 RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
914 TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
915 DereferenceObject(Current->Address);
916 KeReleaseSpinLock(&IF->Lock, OldIrql);
919 /* Don't need this any more since the route cache references the NCE */
920 DereferenceObject(NCE);
922 CurrentEntry = CurrentEntry->Flink;
925 /* Add interface to the global interface list */
926 ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);
928 KeReleaseSpinLock(&IF->Lock, OldIrql);
934 VOID IPUnregisterInterface(
937 * FUNCTION: Unregisters an IP interface with IP layer
939 * IF = Pointer to interface to unregister
945 PLIST_ENTRY CurrentEntry;
946 PNET_TABLE_ENTRY Current;
947 PNEIGHBOR_CACHE_ENTRY NCE;
949 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
951 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
952 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
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);
959 /* Remove NTE from global net table list */
960 RemoveEntryList(&Current->NTListEntry);
962 /* Remove all references from route cache to NTE */
963 RouteInvalidateNTE(Current);
965 /* Remove permanent NCE, but first we have to find it */
966 NCE = NBLocateNeighbor(Current->Address);
968 DereferenceObject(NCE);
969 NBRemoveNeighbor(NCE);
972 CurrentEntry = CurrentEntry->Flink;
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);
981 KeReleaseSpinLock(&IF->Lock, OldIrql2);
982 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
986 VOID IPRegisterProtocol(
988 IP_PROTOCOL_HANDLER Handler)
990 * FUNCTION: Registers a handler for an IP protocol number
992 * ProtocolNumber = Internet Protocol number for which to register handler
993 * Handler = Pointer to handler to be called when a packet is received
995 * To unregister a protocol handler, call this function with Handler = NULL
999 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
1000 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
1003 ProtocolTable[ProtocolNumber] = Handler;
1007 VOID DefaultProtocolHandler(
1008 PNET_TABLE_ENTRY NTE,
1009 PIP_PACKET IPPacket)
1011 * FUNCTION: Default handler for Internet protocols
1013 * NTE = Pointer to net table entry which the packet was received on
1014 * IPPacket = Pointer to an IP packet that was received
1017 TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
1022 PDRIVER_OBJECT DriverObject,
1023 PUNICODE_STRING RegistryPath)
1025 * FUNCTION: Initializes the IP subsystem
1027 * DriverObject = Pointer to a driver object for this driver
1028 * RegistryPath = Our registry node for configuration parameters
1030 * Status of operation
1034 LARGE_INTEGER DueTime;
1036 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1038 MaxLLHeaderSize = 0;
1041 /* Initialize lookaside lists */
1042 ExInitializeNPagedLookasideList(
1043 &IPDRList, /* Lookaside list */
1044 NULL, /* Allocate routine */
1045 NULL, /* Free routine */
1047 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
1048 TAG('I','P','D','R'), /* Tag */
1051 ExInitializeNPagedLookasideList(
1052 &IPPacketList, /* Lookaside list */
1053 NULL, /* Allocate routine */
1054 NULL, /* Free routine */
1056 sizeof(IP_PACKET), /* Size of each entry */
1057 TAG('I','P','P','K'), /* Tag */
1060 ExInitializeNPagedLookasideList(
1061 &IPFragmentList, /* Lookaside list */
1062 NULL, /* Allocate routine */
1063 NULL, /* Free routine */
1065 sizeof(IP_FRAGMENT), /* Size of each entry */
1066 TAG('I','P','F','G'), /* Tag */
1069 ExInitializeNPagedLookasideList(
1070 &IPHoleList, /* Lookaside list */
1071 NULL, /* Allocate routine */
1072 NULL, /* Free routine */
1074 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
1075 TAG('I','P','H','L'), /* Tag */
1078 /* Start routing subsystem */
1081 /* Start route cache subsystem */
1084 /* Start neighbor cache subsystem */
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);
1092 /* Register network level protocol receive handlers */
1093 IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
1095 /* Initialize NTE list and protecting lock */
1096 InitializeListHead(&NetTableListHead);
1097 KeInitializeSpinLock(&NetTableListLock);
1099 /* Initialize reassembly list and protecting lock */
1100 InitializeListHead(&ReassemblyListHead);
1101 KeInitializeSpinLock(&ReassemblyListLock);
1103 /* Initialize the prefix list and protecting lock */
1104 InitializeListHead(&PrefixListHead);
1105 KeInitializeSpinLock(&PrefixListLock);
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);
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);
1117 IPInitialized = TRUE;
1119 return STATUS_SUCCESS;
1123 NTSTATUS IPShutdown(
1126 * FUNCTION: Shuts down the IP subsystem
1128 * Status of operation
1131 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1134 return STATUS_SUCCESS;
1137 KeCancelTimer(&IPTimer);
1139 /* Shutdown neighbor cache subsystem */
1142 /* Shutdown route cache subsystem */
1145 /* Shutdown routing subsystem */
1148 IPFreeReassemblyList();
1150 /* Clear prefix list */
1153 /* Destroy lookaside lists */
1154 ExDeleteNPagedLookasideList(&IPHoleList);
1155 ExDeleteNPagedLookasideList(&IPDRList);
1156 ExDeleteNPagedLookasideList(&IPPacketList);
1157 ExDeleteNPagedLookasideList(&IPFragmentList);
1159 IPInitialized = FALSE;
1161 return STATUS_SUCCESS;