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
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 NPAGED_LOOKASIDE_LIST IPPacketList
;
22 /* Work around calling timer at Dpc level */
24 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
30 * FUNCTION: Frees an IP packet object
32 * Object = Pointer to an IP packet structure
35 TcpipFreeToNPagedLookasideList(&IPPacketList
, Object
);
42 * FUNCTION: Do nothing for when the IPPacket struct is part of another
44 * Object = Pointer to an IP packet structure
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(
92 * FUNCTION: Creates an address entry and binds it to an interface
94 * IF = Pointer to interface
95 * Address = Pointer to referenced interface address
96 * Type = Type of address (ADE_*)
97 * NTE = Pointer to net table entry
99 * Pointer to ADE, NULL if there was not enough free resources
101 * The interface lock must be held when called. The address entry
102 * retains a reference to the provided address and NTE. The caller
103 * is responsible for referencing the these before calling.
104 * As long as you have referenced an ADE you can safely use the
105 * address and NTE as the ADE references both
110 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n",
111 IF
, Address
, Type
, NTE
));
113 TI_DbgPrint(DEBUG_IP
, ("Address (%s) NTE (%s).\n",
114 A2S(Address
), A2S(NTE
->Address
)));
116 /* Allocate space for an ADE and set it up */
117 ADE
= exAllocatePool(NonPagedPool
, sizeof(ADDRESS_ENTRY
));
119 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
123 INIT_TAG(ADE
, TAG('A','D','E',' '));
127 RtlCopyMemory(&ADE
->Address
,Address
,sizeof(ADE
->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 /* And free the ADE */
163 * FUNCTION: Destroys all address entries on an interface
165 * IF = Pointer to interface
167 * The interface lock must be held when called
170 PLIST_ENTRY CurrentEntry
;
171 PLIST_ENTRY NextEntry
;
172 PADDRESS_ENTRY Current
;
174 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
176 /* Search the list and remove every ADE we find */
177 CurrentEntry
= IF
->ADEListHead
.Flink
;
178 while (CurrentEntry
!= &IF
->ADEListHead
) {
179 NextEntry
= CurrentEntry
->Flink
;
180 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
181 /* Destroy the ADE */
182 DestroyADE(IF
, Current
);
183 CurrentEntry
= NextEntry
;
188 PIP_PACKET
IPCreatePacket(ULONG Type
)
190 * FUNCTION: Creates an IP packet object
192 * Type = Type of IP packet
194 * Pointer to the created IP packet. NULL if there was not enough free resources.
199 IPPacket
= TcpipAllocateFromNPagedLookasideList(&IPPacketList
);
203 /* FIXME: Is this needed? */
204 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
206 INIT_TAG(IPPacket
, TAG('I','P','K','T'));
208 IPPacket
->Free
= FreePacket
;
209 IPPacket
->Type
= Type
;
210 IPPacket
->HeaderSize
= 20;
215 PIP_PACKET
IPInitializePacket(
219 * FUNCTION: Creates an IP packet object
221 * Type = Type of IP packet
223 * Pointer to the created IP packet. NULL if there was not enough free resources.
226 /* FIXME: Is this needed? */
227 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
229 INIT_TAG(IPPacket
, TAG('I','P','K','T'));
231 IPPacket
->Free
= DontFreePacket
;
232 IPPacket
->Type
= Type
;
238 PNET_TABLE_ENTRY
IPCreateNTE(
243 * FUNCTION: Creates a net table entry and binds it to an interface
245 * IF = Pointer to interface
246 * Address = Pointer to interface address
247 * PrefixLength = Length of prefix
249 * Pointer to NTE, NULL if there was not enough free resources
251 * The interface lock must be held when called.
252 * The net table entry retains a reference to the interface and
253 * the provided address. The caller is responsible for providing
257 PNET_TABLE_ENTRY NTE
;
260 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF
, Address
, PrefixLength
));
262 TI_DbgPrint(DEBUG_IP
, ("Address (%s).\n", A2S(Address
)));
264 /* Allocate room for an NTE */
265 NTE
= exAllocatePool(NonPagedPool
, sizeof(NET_TABLE_ENTRY
));
267 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
271 INIT_TAG(NTE
, TAG('N','T','E',' '));
272 INIT_TAG(Address
, TAG('A','D','R','S'));
278 NTE
->Address
= Address
;
280 /* Create an address entry and add it to the list */
281 ADE
= CreateADE(IF
, NTE
->Address
, ADE_UNICAST
, NTE
);
283 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
288 /* Create a prefix list entry for unicast address */
289 NTE
->PLE
= CreatePLE(IF
, NTE
->Address
, PrefixLength
);
296 /* Add NTE to the list on the interface */
297 InsertTailList(&IF
->NTEListHead
, &NTE
->IFListEntry
);
299 /* Add NTE to the global net table list */
300 TcpipInterlockedInsertTailList(&NetTableListHead
, &NTE
->NTListEntry
, &NetTableListLock
);
308 PNET_TABLE_ENTRY NTE
)
310 * FUNCTION: Destroys a net table entry
312 * IF = Pointer to interface
313 * NTE = Pointer to net table entry
315 * The net table list lock must be held when called
316 * The interface lock must be held when called
321 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) NTE (0x%X).\n", IF
, NTE
));
323 TI_DbgPrint(DEBUG_IP
, ("NTE (%s).\n", NTE
->Address
));
325 /* Invalidate the prefix list entry for this NTE */
326 TcpipAcquireSpinLock(&PrefixListLock
, &OldIrql
);
327 DestroyPLE(NTE
->PLE
);
328 TcpipReleaseSpinLock(&PrefixListLock
, OldIrql
);
330 /* Remove NTE from the interface list */
331 RemoveEntryList(&NTE
->IFListEntry
);
332 /* Remove NTE from the net table list */
334 /* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
336 RemoveEntryList(&NTE->NTListEntry);
340 /* And free the NTE */
348 * FUNCTION: Destroys all net table entries on an interface
350 * IF = Pointer to interface
352 * The net table list lock must be held when called
353 * The interface lock may be held when called
356 PLIST_ENTRY CurrentEntry
;
357 PLIST_ENTRY NextEntry
;
358 PNET_TABLE_ENTRY Current
;
360 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
362 /* Search the list and remove every NTE we find */
363 CurrentEntry
= IF
->NTEListHead
.Flink
;
364 while (CurrentEntry
!= &IF
->NTEListHead
) {
365 NextEntry
= CurrentEntry
->Flink
;
366 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
367 /* Destroy the NTE */
368 DestroyNTE(IF
, Current
);
369 CurrentEntry
= NextEntry
;
374 PNET_TABLE_ENTRY
IPLocateNTEOnInterface(
379 * FUNCTION: Locates an NTE on an interface
381 * IF = Pointer to interface
382 * Address = Pointer to IP address
383 * AddressType = Address of type of IP address
385 * If found, the NTE is referenced for the caller. The caller is
386 * responsible for dereferencing after use
388 * Pointer to net table entry, NULL if none was found
392 PLIST_ENTRY CurrentEntry
;
393 PADDRESS_ENTRY Current
;
395 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (%s) AddressType (0x%X).\n",
396 IF
, A2S(Address
), AddressType
));
398 if( !IF
) return NULL
;
400 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
402 /* Search the list and return the NTE if found */
403 CurrentEntry
= IF
->ADEListHead
.Flink
;
405 if (CurrentEntry
== &IF
->ADEListHead
) {
406 TI_DbgPrint(DEBUG_IP
, ("NTE list is empty!!!\n"));
409 while (CurrentEntry
!= &IF
->ADEListHead
) {
410 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
411 if (AddrIsEqual(Address
, &Current
->Address
)) {
412 *AddressType
= Current
->Type
;
413 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
416 CurrentEntry
= CurrentEntry
->Flink
;
419 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
425 PNET_TABLE_ENTRY
IPLocateNTE(
429 * FUNCTION: Locates an NTE for the network Address is on
431 * Address = Pointer to an address to find associated NTE of
432 * AddressType = Address of address type
434 * If found the NTE is referenced for the caller. The caller is
435 * responsible for dereferencing after use
437 * Pointer to NTE if the address was found, NULL if not.
441 PLIST_ENTRY CurrentEntry
;
442 PNET_TABLE_ENTRY Current
;
443 PNET_TABLE_ENTRY NTE
;
445 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
446 // Address, AddressType));
448 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
450 TcpipAcquireSpinLock(&NetTableListLock
, &OldIrql
);
452 /* Search the list and return the NTE if found */
453 CurrentEntry
= NetTableListHead
.Flink
;
454 while (CurrentEntry
!= &NetTableListHead
) {
455 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, NTListEntry
);
456 NTE
= IPLocateNTEOnInterface(Current
->Interface
, Address
, AddressType
);
458 TcpipReleaseSpinLock(&NetTableListLock
, OldIrql
);
461 CurrentEntry
= CurrentEntry
->Flink
;
464 TcpipReleaseSpinLock(&NetTableListLock
, OldIrql
);
470 PADDRESS_ENTRY
IPLocateADE(
474 * FUNCTION: Locates an ADE for the address
476 * Address = Pointer to an address to find associated ADE of
477 * AddressType = Type of address
479 * Pointer to ADE if the address was found, NULL if not.
481 * If found the ADE is referenced for the caller. The caller is
482 * responsible for dereferencing after use
486 IF_LIST_ITER(CurrentIF
);
487 ADE_LIST_ITER(CurrentADE
);
489 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
490 // Address, AddressType));
492 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
494 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
496 /* Search the interface list */
497 ForEachInterface(CurrentIF
) {
498 /* Search the address entry list and return the ADE if found */
499 ForEachADE(CurrentIF
->ADEListHead
,CurrentADE
) {
500 if ((AddrIsEqual(Address
, &CurrentADE
->Address
)) &&
501 (CurrentADE
->Type
== AddressType
)) {
502 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql
);
505 } EndFor(CurrentADE
);
508 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql
);
514 PADDRESS_ENTRY
IPGetDefaultADE(
517 * FUNCTION: Returns a default address entry
519 * AddressType = Type of address
521 * Pointer to ADE if found, NULL if not.
523 * Loopback interface is only considered if it is the only interface.
524 * If found, the address entry is referenced
528 ADE_LIST_ITER(CurrentADE
);
529 IF_LIST_ITER(CurrentIF
);
530 BOOLEAN LoopbackIsRegistered
= FALSE
;
532 TI_DbgPrint(DEBUG_IP
, ("Called. AddressType (0x%X).\n", AddressType
));
534 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
536 /* Search the interface list */
537 ForEachInterface(CurrentIF
) {
538 if (CurrentIF
!= Loopback
) {
539 /* Search the address entry list and return the first appropriate ADE found */
540 TI_DbgPrint(DEBUG_IP
,("Checking interface %x\n", CurrentIF
));
541 ForEachADE(CurrentIF
->ADEListHead
,CurrentADE
) {
542 if (CurrentADE
->Type
== AddressType
) {
543 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql
);
546 } EndFor(CurrentADE
);
548 LoopbackIsRegistered
= TRUE
;
551 /* No address was found. Use loopback interface if available */
552 if (LoopbackIsRegistered
) {
553 ForEachADE(CurrentIF
->ADEListHead
,CurrentADE
) {
554 if (CurrentADE
->Type
== AddressType
) {
555 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql
);
558 } EndFor(CurrentADE
);
561 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql
);
566 void STDCALL
IPTimeout( PVOID Context
) {
567 /* Check if datagram fragments have taken too long to assemble */
568 IPDatagramReassemblyTimeout();
570 /* Clean possible outdated cached neighbor addresses */
573 /* Call upper layer timeout routines */
578 VOID
IPDispatchProtocol(
579 PNET_TABLE_ENTRY NTE
,
582 * FUNCTION: IP protocol dispatcher
584 * NTE = Pointer to net table entry which the packet was received on
585 * IPPacket = Pointer to an IP packet that was received
587 * This routine examines the IP header and passes the packet on to the
588 * right upper level protocol receive handler
593 switch (IPPacket
->Type
) {
595 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
598 /* FIXME: IPv6 adresses not supported */
599 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
605 /* Call the appropriate protocol handler */
606 (*ProtocolTable
[Protocol
])(NTE
, IPPacket
);
610 PIP_INTERFACE
IPCreateInterface(
611 PLLIP_BIND_INFO BindInfo
)
613 * FUNCTION: Creates an IP interface
615 * BindInfo = Pointer to link layer to IP binding information
617 * Pointer to IP_INTERFACE structure, NULL if there was
618 * not enough free resources
623 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
626 if (BindInfo
->Address
) {
627 PUCHAR A
= BindInfo
->Address
;
628 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
629 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
633 IF
= exAllocatePool(NonPagedPool
, sizeof(IP_INTERFACE
));
635 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
639 INIT_TAG(IF
, TAG('F','A','C','E'));
642 IF
->Context
= BindInfo
->Context
;
643 IF
->HeaderSize
= BindInfo
->HeaderSize
;
644 if (IF
->HeaderSize
> MaxLLHeaderSize
)
645 MaxLLHeaderSize
= IF
->HeaderSize
;
647 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
648 if (IF
->MinFrameSize
> MinLLFrameSize
)
649 MinLLFrameSize
= IF
->MinFrameSize
;
651 IF
->MTU
= BindInfo
->MTU
;
652 IF
->Address
= BindInfo
->Address
;
653 IF
->AddressLength
= BindInfo
->AddressLength
;
654 IF
->Transmit
= BindInfo
->Transmit
;
656 InitializeListHead(&IF
->ADEListHead
);
657 InitializeListHead(&IF
->NTEListHead
);
659 TcpipInitializeSpinLock(&IF
->Lock
);
662 InsertTDIInterfaceEntity( IF
);
669 VOID
IPDestroyInterface(
672 * FUNCTION: Destroys an IP interface
674 * IF = Pointer to interface to destroy
680 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
683 RemoveTDIInterfaceEntity( IF
);
686 TcpipAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
687 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
690 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql2
);
691 TcpipReleaseSpinLock(&NetTableListLock
, OldIrql1
);
697 BOOLEAN
IPRegisterInterface(
700 * FUNCTION: Registers an IP interface with IP layer
702 * IF = Pointer to interface to register
704 * TRUE if interface was successfully registered, FALSE if not
708 PLIST_ENTRY CurrentEntry
;
709 PNET_TABLE_ENTRY Current
;
710 PROUTE_CACHE_NODE RCN
;
711 PNEIGHBOR_CACHE_ENTRY NCE
;
713 TI_DbgPrint(MID_TRACE
, ("Called. IF (0x%X).\n", IF
));
715 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
717 /* Add routes to all NTEs on this interface */
718 CurrentEntry
= IF
->NTEListHead
.Flink
;
719 while (CurrentEntry
!= &IF
->NTEListHead
) {
720 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
722 /* Add a permanent neighbor for this NTE */
723 NCE
= NBAddNeighbor(IF
, Current
->Address
, IF
->Address
,
724 IF
->AddressLength
, NUD_PERMANENT
);
726 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
727 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
731 /* NCE is already referenced */
732 if (!RouterAddRoute(Current
->Address
, &Current
->PLE
->Prefix
, NCE
, 1)) {
733 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
736 RCN
= RouteAddRouteToDestination(Current
->Address
, Current
, IF
, NCE
);
738 TI_DbgPrint(MIN_TRACE
, ("Could not create RCN.\n"));
739 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
741 CurrentEntry
= CurrentEntry
->Flink
;
744 /* Add interface to the global interface list */
745 ASSERT(&IF
->ListEntry
);
746 TcpipInterlockedInsertTailList(&InterfaceListHead
,
750 /* Allow TCP to hang some configuration on this interface */
751 IF
->TCPContext
= TCPPrepareInterface( IF
);
753 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
759 VOID
IPUnregisterInterface(
762 * FUNCTION: Unregisters an IP interface with IP layer
764 * IF = Pointer to interface to unregister
770 PLIST_ENTRY CurrentEntry
;
771 PNET_TABLE_ENTRY Current
;
772 PNEIGHBOR_CACHE_ENTRY NCE
;
774 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
776 TcpipAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
777 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
779 /* Remove routes to all NTEs on this interface */
780 CurrentEntry
= IF
->NTEListHead
.Flink
;
781 while (CurrentEntry
!= &IF
->NTEListHead
) {
782 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
784 /* Remove NTE from global net table list */
785 RemoveEntryList(&Current
->NTListEntry
);
787 /* Remove all references from route cache to NTE */
788 RouteInvalidateNTE(Current
);
790 /* Remove permanent NCE, but first we have to find it */
791 NCE
= NBLocateNeighbor(Current
->Address
);
793 NBRemoveNeighbor(NCE
);
795 CurrentEntry
= CurrentEntry
->Flink
;
798 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
799 /* Ouch...three spinlocks acquired! Fortunately
800 we don't unregister interfaces very often */
801 RemoveEntryList(&IF
->ListEntry
);
802 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
804 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql2
);
805 TcpipReleaseSpinLock(&NetTableListLock
, OldIrql1
);
809 VOID
IPRegisterProtocol(
811 IP_PROTOCOL_HANDLER Handler
)
813 * FUNCTION: Registers a handler for an IP protocol number
815 * ProtocolNumber = Internet Protocol number for which to register handler
816 * Handler = Pointer to handler to be called when a packet is received
818 * To unregister a protocol handler, call this function with Handler = NULL
822 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
)
823 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
826 ProtocolTable
[ProtocolNumber
] = Handler
;
830 VOID
DefaultProtocolHandler(
831 PNET_TABLE_ENTRY NTE
,
834 * FUNCTION: Default handler for Internet protocols
836 * NTE = Pointer to net table entry which the packet was received on
837 * IPPacket = Pointer to an IP packet that was received
840 TI_DbgPrint(MID_TRACE
, ("Packet of unknown Internet protocol discarded.\n"));
844 NTSTATUS
IPStartup(PUNICODE_STRING RegistryPath
)
846 * FUNCTION: Initializes the IP subsystem
848 * RegistryPath = Our registry node for configuration parameters
850 * Status of operation
855 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
860 /* Initialize lookaside lists */
861 ExInitializeNPagedLookasideList(
862 &IPDRList
, /* Lookaside list */
863 NULL
, /* Allocate routine */
864 NULL
, /* Free routine */
866 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
867 TAG('I','P','D','R'), /* Tag */
870 ExInitializeNPagedLookasideList(
871 &IPPacketList
, /* Lookaside list */
872 NULL
, /* Allocate routine */
873 NULL
, /* Free routine */
875 sizeof(IP_PACKET
), /* Size of each entry */
876 TAG('I','P','P','K'), /* Tag */
879 ExInitializeNPagedLookasideList(
880 &IPFragmentList
, /* Lookaside list */
881 NULL
, /* Allocate routine */
882 NULL
, /* Free routine */
884 sizeof(IP_FRAGMENT
), /* Size of each entry */
885 TAG('I','P','F','G'), /* Tag */
888 ExInitializeNPagedLookasideList(
889 &IPHoleList
, /* Lookaside list */
890 NULL
, /* Allocate routine */
891 NULL
, /* Free routine */
893 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
894 TAG('I','P','H','L'), /* Tag */
897 /* Start routing subsystem */
900 /* Start route cache subsystem */
903 /* Start neighbor cache subsystem */
906 /* Fill the protocol dispatch table with pointers
907 to the default protocol handler */
908 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
909 IPRegisterProtocol(i
, DefaultProtocolHandler
);
911 /* Register network level protocol receive handlers */
912 IPRegisterProtocol(IPPROTO_ICMP
, ICMPReceive
);
914 /* Initialize NTE list and protecting lock */
915 InitializeListHead(&NetTableListHead
);
916 TcpipInitializeSpinLock(&NetTableListLock
);
918 /* Initialize reassembly list and protecting lock */
919 InitializeListHead(&ReassemblyListHead
);
920 TcpipInitializeSpinLock(&ReassemblyListLock
);
924 IPInitialized
= TRUE
;
926 return STATUS_SUCCESS
;
933 * FUNCTION: Shuts down the IP subsystem
935 * Status of operation
938 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
941 return STATUS_SUCCESS
;
943 /* Shutdown neighbor cache subsystem */
946 /* Shutdown route cache subsystem */
949 /* Shutdown routing subsystem */
952 IPFreeReassemblyList();
954 /* Clear prefix list */
957 /* Destroy lookaside lists */
958 ExDeleteNPagedLookasideList(&IPHoleList
);
959 ExDeleteNPagedLookasideList(&IPDRList
);
960 ExDeleteNPagedLookasideList(&IPPacketList
);
961 ExDeleteNPagedLookasideList(&IPFragmentList
);
963 IPInitialized
= FALSE
;
965 return STATUS_SUCCESS
;