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',' '));
378 /* One reference is for beeing alive and one reference is for the ADE */
381 NTE
->Address
= Address
;
382 /* One reference is for NTE, one reference is given to the
383 address entry, and one reference is given to the prefix
385 ReferenceObject(Address
);
386 ReferenceObject(Address
);
387 ReferenceObject(Address
);
389 /* Create an address entry and add it to the list */
390 ADE
= CreateADE(IF
, NTE
->Address
, ADE_UNICAST
, NTE
);
392 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
397 /* Create a prefix list entry for unicast address */
398 NTE
->PLE
= CreatePLE(IF
, NTE
->Address
, PrefixLength
);
405 /* Reference the interface for the prefix list entry */
408 /* Add NTE to the list on the interface */
409 InsertTailList(&IF
->NTEListHead
, &NTE
->IFListEntry
);
411 /* Add NTE to the global net table list */
412 ExInterlockedInsertTailList(&NetTableListHead
, &NTE
->NTListEntry
, &NetTableListLock
);
420 PNET_TABLE_ENTRY NTE
)
422 * FUNCTION: Destroys a net table entry
424 * IF = Pointer to interface
425 * NTE = Pointer to net table entry
427 * The net table list lock must be held when called
428 * The interface lock must be held when called
433 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) NTE (0x%X).\n", IF
, NTE
));
435 TI_DbgPrint(DEBUG_IP
, ("NTE (%s).\n", NTE
->Address
));
437 /* Invalidate the prefix list entry for this NTE */
438 KeAcquireSpinLock(&PrefixListLock
, &OldIrql
);
439 DestroyPLE(NTE
->PLE
);
440 KeReleaseSpinLock(&PrefixListLock
, OldIrql
);
442 /* Remove NTE from the interface list */
443 RemoveEntryList(&NTE
->IFListEntry
);
444 /* Remove NTE from the net table list */
445 RemoveEntryList(&NTE
->NTListEntry
);
446 /* Dereference the objects that are referenced */
447 DereferenceObject(NTE
->Address
);
448 DereferenceObject(NTE
->Interface
);
452 if (NTE
->RefCount
!= 0) {
453 TI_DbgPrint(MIN_TRACE
, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE
, NTE
->RefCount
));
456 /* And free the NTE */
464 * FUNCTION: Destroys all net table entries on an interface
466 * IF = Pointer to interface
468 * The net table list lock must be held when called
469 * The interface lock may be held when called
472 PLIST_ENTRY CurrentEntry
;
473 PLIST_ENTRY NextEntry
;
474 PNET_TABLE_ENTRY Current
;
476 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
478 /* Search the list and remove every NTE we find */
479 CurrentEntry
= IF
->NTEListHead
.Flink
;
480 while (CurrentEntry
!= &IF
->NTEListHead
) {
481 NextEntry
= CurrentEntry
->Flink
;
482 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
483 /* Destroy the NTE */
484 DestroyNTE(IF
, Current
);
485 CurrentEntry
= NextEntry
;
490 PNET_TABLE_ENTRY
IPLocateNTEOnInterface(
495 * FUNCTION: Locates an NTE on an interface
497 * IF = Pointer to interface
498 * Address = Pointer to IP address
499 * AddressType = Address of type of IP address
501 * If found, the NTE is referenced for the caller. The caller is
502 * responsible for dereferencing after use
504 * Pointer to net table entry, NULL if none was found
508 PLIST_ENTRY CurrentEntry
;
509 PADDRESS_ENTRY Current
;
511 // TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
512 // IF, Address, AddressType));
514 // TI_DbgPrint(DEBUG_IP, ("Address (%s) AddressType (0x%X).\n", A2S(Address)));
516 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
518 /* Search the list and return the NTE if found */
519 CurrentEntry
= IF
->ADEListHead
.Flink
;
520 while (CurrentEntry
!= &IF
->ADEListHead
) {
521 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
522 if (AddrIsEqual(Address
, Current
->Address
)) {
523 ReferenceObject(Current
->NTE
);
524 *AddressType
= Current
->Type
;
525 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
528 CurrentEntry
= CurrentEntry
->Flink
;
531 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
537 PNET_TABLE_ENTRY
IPLocateNTE(
541 * FUNCTION: Locates an NTE for the network Address is on
543 * Address = Pointer to an address to find associated NTE of
544 * AddressType = Address of address type
546 * If found the NTE is referenced for the caller. The caller is
547 * responsible for dereferencing after use
549 * Pointer to NTE if the address was found, NULL if not.
553 PLIST_ENTRY CurrentEntry
;
554 PNET_TABLE_ENTRY Current
;
555 PNET_TABLE_ENTRY NTE
;
557 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
558 // Address, AddressType));
560 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
562 KeAcquireSpinLock(&NetTableListLock
, &OldIrql
);
564 /* Search the list and return the NTE if found */
565 CurrentEntry
= NetTableListHead
.Flink
;
566 while (CurrentEntry
!= &NetTableListHead
) {
567 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, NTListEntry
);
568 NTE
= IPLocateNTEOnInterface(Current
->Interface
, Address
, AddressType
);
570 ReferenceObject(NTE
);
571 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
574 CurrentEntry
= CurrentEntry
->Flink
;
577 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
583 PADDRESS_ENTRY
IPLocateADE(
587 * FUNCTION: Locates an ADE for the address
589 * Address = Pointer to an address to find associated ADE of
590 * AddressType = Type of address
592 * Pointer to ADE if the address was found, NULL if not.
594 * If found the ADE is referenced for the caller. The caller is
595 * responsible for dereferencing after use
599 PLIST_ENTRY CurrentIFEntry
;
600 PLIST_ENTRY CurrentADEEntry
;
601 PIP_INTERFACE CurrentIF
;
602 PADDRESS_ENTRY CurrentADE
;
604 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
605 // Address, AddressType));
607 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
609 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
611 /* Search the interface list */
612 CurrentIFEntry
= InterfaceListHead
.Flink
;
613 while (CurrentIFEntry
!= &InterfaceListHead
) {
614 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
616 /* Search the address entry list and return the ADE if found */
617 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
618 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
619 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
620 if ((AddrIsEqual(Address
, CurrentADE
->Address
)) &&
621 (CurrentADE
->Type
== AddressType
)) {
622 ReferenceObject(CurrentADE
);
623 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
626 CurrentADEEntry
= CurrentADEEntry
->Flink
;
628 CurrentIFEntry
= CurrentIFEntry
->Flink
;
631 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
637 PADDRESS_ENTRY
IPGetDefaultADE(
640 * FUNCTION: Returns a default address entry
642 * AddressType = Type of address
644 * Pointer to ADE if found, NULL if not.
646 * Loopback interface is only considered if it is the only interface.
647 * If found, the address entry is referenced
651 PLIST_ENTRY CurrentIFEntry
;
652 PLIST_ENTRY CurrentADEEntry
;
653 PIP_INTERFACE CurrentIF
;
654 PADDRESS_ENTRY CurrentADE
;
655 BOOLEAN LoopbackIsRegistered
= FALSE
;
657 TI_DbgPrint(DEBUG_IP
, ("Called. AddressType (0x%X).\n", AddressType
));
659 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
661 /* Search the interface list */
662 CurrentIFEntry
= InterfaceListHead
.Flink
;
663 while (CurrentIFEntry
!= &InterfaceListHead
) {
664 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
666 if (CurrentIF
!= Loopback
) {
667 /* Search the address entry list and return the first appropriate ADE found */
668 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
669 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
670 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
671 if (CurrentADE
->Type
== AddressType
)
672 ReferenceObject(CurrentADE
);
673 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
676 CurrentADEEntry
= CurrentADEEntry
->Flink
;
678 LoopbackIsRegistered
= TRUE
;
679 CurrentIFEntry
= CurrentIFEntry
->Flink
;
682 /* No address was found. Use loopback interface if available */
683 if (LoopbackIsRegistered
) {
684 CurrentADEEntry
= Loopback
->ADEListHead
.Flink
;
685 while (CurrentADEEntry
!= &Loopback
->ADEListHead
) {
686 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
687 if (CurrentADE
->Type
== AddressType
) {
688 ReferenceObject(CurrentADE
);
689 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
692 CurrentADEEntry
= CurrentADEEntry
->Flink
;
696 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
702 VOID STDCALL
IPTimeout(
704 PVOID DeferredContext
,
705 PVOID SystemArgument1
,
706 PVOID SystemArgument2
)
708 * FUNCTION: Timeout DPC
710 * Dpc = Pointer to our DPC object
711 * DeferredContext = Pointer to context information (unused)
712 * SystemArgument1 = Unused
713 * SystemArgument2 = Unused
715 * This routine is dispatched once in a while to do maintainance jobs
718 /* Check if datagram fragments have taken too long to assemble */
719 IPDatagramReassemblyTimeout();
721 /* Clean possible outdated cached neighbor addresses */
724 /* Call upper layer timeout routines */
729 VOID
IPDispatchProtocol(
730 PNET_TABLE_ENTRY NTE
,
733 * FUNCTION: IP protocol dispatcher
735 * NTE = Pointer to net table entry which the packet was received on
736 * IPPacket = Pointer to an IP packet that was received
738 * This routine examines the IP header and passes the packet on to the
739 * right upper level protocol receive handler
744 switch (IPPacket
->Type
) {
746 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
749 /* FIXME: IPv6 adresses not supported */
750 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
756 /* Call the appropriate protocol handler */
757 (*ProtocolTable
[Protocol
])(NTE
, IPPacket
);
761 PIP_INTERFACE
IPCreateInterface(
762 PLLIP_BIND_INFO BindInfo
)
764 * FUNCTION: Creates an IP interface
766 * BindInfo = Pointer to link layer to IP binding information
768 * Pointer to IP_INTERFACE structure, NULL if there was
769 * not enough free resources
774 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
777 if (BindInfo
->Address
) {
778 PUCHAR A
= BindInfo
->Address
;
779 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
780 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
784 IF
= ExAllocatePool(NonPagedPool
, sizeof(IP_INTERFACE
));
786 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
790 INIT_TAG(IF
, TAG('F','A','C','E'));
794 IF
->Context
= BindInfo
->Context
;
795 IF
->HeaderSize
= BindInfo
->HeaderSize
;
796 if (IF
->HeaderSize
> MaxLLHeaderSize
)
797 MaxLLHeaderSize
= IF
->HeaderSize
;
799 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
800 if (IF
->MinFrameSize
> MinLLFrameSize
)
801 MinLLFrameSize
= IF
->MinFrameSize
;
803 IF
->MTU
= BindInfo
->MTU
;
804 IF
->Address
= BindInfo
->Address
;
805 IF
->AddressLength
= BindInfo
->AddressLength
;
806 IF
->Transmit
= BindInfo
->Transmit
;
808 InitializeListHead(&IF
->ADEListHead
);
809 InitializeListHead(&IF
->NTEListHead
);
811 KeInitializeSpinLock(&IF
->Lock
);
817 VOID
IPDestroyInterface(
820 * FUNCTION: Destroys an IP interface
822 * IF = Pointer to interface to destroy
828 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
830 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
831 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
834 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
835 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
840 if (IF
->RefCount
!= 0) {
841 TI_DbgPrint(MIN_TRACE
, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF
, IF
->RefCount
));
848 BOOLEAN
IPRegisterInterface(
851 * FUNCTION: Registers an IP interface with IP layer
853 * IF = Pointer to interface to register
855 * TRUE if interface was successfully registered, FALSE if not
859 PLIST_ENTRY CurrentEntry
;
860 PNET_TABLE_ENTRY Current
;
861 PROUTE_CACHE_NODE RCN
;
862 PNEIGHBOR_CACHE_ENTRY NCE
;
864 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
866 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
868 /* Add routes to all NTEs on this interface */
869 CurrentEntry
= IF
->NTEListHead
.Flink
;
870 while (CurrentEntry
!= &IF
->NTEListHead
) {
871 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
873 /* Add a permanent neighbor for this NTE */
874 ReferenceObject(Current
->Address
);
875 NCE
= NBAddNeighbor(IF
, Current
->Address
, IF
->Address
,
876 IF
->AddressLength
, NUD_PERMANENT
);
878 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
879 DereferenceObject(Current
->Address
);
880 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
884 /* Reference objects for forward information base */
885 ReferenceObject(Current
->Address
);
886 ReferenceObject(Current
->PLE
->Prefix
);
887 ReferenceObject(Current
);
888 /* NCE is already referenced */
889 if (!RouterAddRoute(Current
->Address
, Current
->PLE
->Prefix
, Current
, NCE
, 1)) {
890 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
891 DereferenceObject(Current
->Address
);
892 DereferenceObject(Current
->PLE
->Prefix
);
893 DereferenceObject(Current
);
894 DereferenceObject(NCE
);
897 RCN
= RouteAddRouteToDestination(Current
->Address
, Current
, IF
, NCE
);
899 TI_DbgPrint(MIN_TRACE
, ("Could not create RCN.\n"));
900 DereferenceObject(Current
->Address
);
901 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
904 /* Don't need this any more since the route cache references the NCE */
905 DereferenceObject(NCE
);
907 CurrentEntry
= CurrentEntry
->Flink
;
910 /* Add interface to the global interface list */
911 ExInterlockedInsertTailList(&InterfaceListHead
, &IF
->ListEntry
, &InterfaceListLock
);
913 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
919 VOID
IPUnregisterInterface(
922 * FUNCTION: Unregisters an IP interface with IP layer
924 * IF = Pointer to interface to unregister
930 PLIST_ENTRY CurrentEntry
;
931 PNET_TABLE_ENTRY Current
;
932 PNEIGHBOR_CACHE_ENTRY NCE
;
934 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
936 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
937 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
939 /* Remove routes to all NTEs on this interface */
940 CurrentEntry
= IF
->NTEListHead
.Flink
;
941 while (CurrentEntry
!= &IF
->NTEListHead
) {
942 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
944 /* Remove NTE from global net table list */
945 RemoveEntryList(&Current
->NTListEntry
);
947 /* Remove all references from route cache to NTE */
948 RouteInvalidateNTE(Current
);
950 /* Remove permanent NCE, but first we have to find it */
951 NCE
= NBLocateNeighbor(Current
->Address
);
953 DereferenceObject(NCE
);
954 NBRemoveNeighbor(NCE
);
957 CurrentEntry
= CurrentEntry
->Flink
;
960 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
961 /* Ouch...three spinlocks acquired! Fortunately
962 we don't unregister interfaces very often */
963 RemoveEntryList(&IF
->ListEntry
);
964 KeReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
966 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
967 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
971 VOID
IPRegisterProtocol(
973 IP_PROTOCOL_HANDLER Handler
)
975 * FUNCTION: Registers a handler for an IP protocol number
977 * ProtocolNumber = Internet Protocol number for which to register handler
978 * Handler = Pointer to handler to be called when a packet is received
980 * To unregister a protocol handler, call this function with Handler = NULL
984 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
)
985 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
988 ProtocolTable
[ProtocolNumber
] = Handler
;
992 VOID
DefaultProtocolHandler(
993 PNET_TABLE_ENTRY NTE
,
996 * FUNCTION: Default handler for Internet protocols
998 * NTE = Pointer to net table entry which the packet was received on
999 * IPPacket = Pointer to an IP packet that was received
1002 TI_DbgPrint(MID_TRACE
, ("Packet of unknown Internet protocol discarded.\n"));
1007 PDRIVER_OBJECT DriverObject
,
1008 PUNICODE_STRING RegistryPath
)
1010 * FUNCTION: Initializes the IP subsystem
1012 * DriverObject = Pointer to a driver object for this driver
1013 * RegistryPath = Our registry node for configuration parameters
1015 * Status of operation
1019 LARGE_INTEGER DueTime
;
1021 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
1023 MaxLLHeaderSize
= 0;
1026 /* Initialize lookaside lists */
1027 ExInitializeNPagedLookasideList(
1028 &IPDRList
, /* Lookaside list */
1029 NULL
, /* Allocate routine */
1030 NULL
, /* Free routine */
1032 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
1033 TAG('I','P','D','R'), /* Tag */
1036 ExInitializeNPagedLookasideList(
1037 &IPPacketList
, /* Lookaside list */
1038 NULL
, /* Allocate routine */
1039 NULL
, /* Free routine */
1041 sizeof(IP_PACKET
), /* Size of each entry */
1042 TAG('I','P','P','K'), /* Tag */
1045 ExInitializeNPagedLookasideList(
1046 &IPFragmentList
, /* Lookaside list */
1047 NULL
, /* Allocate routine */
1048 NULL
, /* Free routine */
1050 sizeof(IP_FRAGMENT
), /* Size of each entry */
1051 TAG('I','P','F','G'), /* Tag */
1054 ExInitializeNPagedLookasideList(
1055 &IPHoleList
, /* Lookaside list */
1056 NULL
, /* Allocate routine */
1057 NULL
, /* Free routine */
1059 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
1060 TAG('I','P','H','L'), /* Tag */
1063 /* Start routing subsystem */
1066 /* Start route cache subsystem */
1069 /* Start neighbor cache subsystem */
1072 /* Fill the protocol dispatch table with pointers
1073 to the default protocol handler */
1074 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
1075 IPRegisterProtocol(i
, DefaultProtocolHandler
);
1077 /* Register network level protocol receive handlers */
1078 IPRegisterProtocol(IPPROTO_ICMP
, ICMPReceive
);
1080 /* Initialize NTE list and protecting lock */
1081 InitializeListHead(&NetTableListHead
);
1082 KeInitializeSpinLock(&NetTableListLock
);
1084 /* Initialize reassembly list and protecting lock */
1085 InitializeListHead(&ReassemblyListHead
);
1086 KeInitializeSpinLock(&ReassemblyListLock
);
1088 /* Initialize the prefix list and protecting lock */
1089 InitializeListHead(&PrefixListHead
);
1090 KeInitializeSpinLock(&PrefixListLock
);
1092 /* Initialize our periodic timer and its associated DPC object. When the
1093 timer expires, the IPTimeout deferred procedure call (DPC) is queued */
1094 KeInitializeDpc(&IPTimeoutDpc
, IPTimeout
, NULL
);
1095 KeInitializeTimer(&IPTimer
);
1097 /* Start the periodic timer with an initial and periodic
1098 relative expiration time of IP_TIMEOUT milliseconds */
1099 DueTime
.QuadPart
= -(LONGLONG
)IP_TIMEOUT
* 10000;
1100 KeSetTimerEx(&IPTimer
, DueTime
, IP_TIMEOUT
, &IPTimeoutDpc
);
1102 IPInitialized
= TRUE
;
1104 return STATUS_SUCCESS
;
1108 NTSTATUS
IPShutdown(
1111 * FUNCTION: Shuts down the IP subsystem
1113 * Status of operation
1116 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
1119 return STATUS_SUCCESS
;
1122 KeCancelTimer(&IPTimer
);
1124 /* Shutdown neighbor cache subsystem */
1127 /* Shutdown route cache subsystem */
1130 /* Shutdown routing subsystem */
1133 IPFreeReassemblyList();
1135 /* Clear prefix list */
1138 /* Destroy lookaside lists */
1139 ExDeleteNPagedLookasideList(&IPHoleList
);
1140 ExDeleteNPagedLookasideList(&IPDRList
);
1141 ExDeleteNPagedLookasideList(&IPPacketList
);
1142 ExDeleteNPagedLookasideList(&IPFragmentList
);
1144 IPInitialized
= FALSE
;
1146 return STATUS_SUCCESS
;