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
23 LIST_ENTRY InterfaceListHead
;
24 KSPIN_LOCK InterfaceListLock
;
25 LIST_ENTRY NetTableListHead
;
26 KSPIN_LOCK NetTableListLock
;
27 LIST_ENTRY PrefixListHead
;
28 KSPIN_LOCK PrefixListLock
;
29 UINT MaxLLHeaderSize
; /* Largest maximum header size */
30 UINT MinLLFrameSize
; /* Largest minimum frame size */
31 BOOLEAN IPInitialized
= FALSE
;
33 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
36 PADDRESS_ENTRY
CreateADE(
42 * FUNCTION: Creates an address entry and binds it to an interface
44 * IF = Pointer to interface
45 * Address = Pointer to referenced interface address
46 * Type = Type of address (ADE_*)
47 * NTE = Pointer to net table entry
49 * Pointer to ADE, NULL if there was not enough free resources
51 * The interface lock must be held when called. The address entry
52 * retains a reference to the provided address and NTE. The caller
53 * is responsible for referencing the these before calling.
54 * As long as you have referenced an ADE you can safely use the
55 * address and NTE as the ADE references both
60 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n",
61 IF
, Address
, Type
, NTE
));
63 /* Allocate space for an ADE and set it up */
64 ADE
= PoolAllocateBuffer(sizeof(ADDRESS_ENTRY
));
66 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
73 ADE
->Address
= Address
;
75 /* Add ADE to the list on the interface */
76 InsertTailList(&IF
->ADEListHead
, &ADE
->ListEntry
);
86 * FUNCTION: Destroys an address entry
88 * IF = Pointer to interface
89 * ADE = Pointer to address entry
91 * The interface lock must be held when called
94 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) ADE (0x%X).\n", IF
, ADE
));
96 /* Unlink the address entry from the list */
97 RemoveEntryList(&ADE
->ListEntry
);
99 /* Dereference the address */
100 DereferenceObject(ADE
->Address
);
102 /* Dereference the NTE */
103 DereferenceObject(ADE
->NTE
);
108 if (ADE
->RefCount
!= 0) {
109 TI_DbgPrint(MIN_TRACE
, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE
, ADE
->RefCount
));
113 /* And free the ADE */
115 TI_DbgPrint(MIN_TRACE
, ("Check.\n"));
122 * FUNCTION: Destroys all address entries on an interface
124 * IF = Pointer to interface
126 * The interface lock must be held when called
129 PLIST_ENTRY CurrentEntry
;
130 PLIST_ENTRY NextEntry
;
131 PADDRESS_ENTRY Current
;
133 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
135 /* Search the list and remove every ADE we find */
136 CurrentEntry
= IF
->ADEListHead
.Flink
;
137 while (CurrentEntry
!= &IF
->ADEListHead
) {
138 NextEntry
= CurrentEntry
->Flink
;
139 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
140 /* Destroy the ADE */
141 DestroyADE(IF
, Current
);
142 CurrentEntry
= NextEntry
;
147 PPREFIX_LIST_ENTRY
CreatePLE(
152 * FUNCTION: Creates a prefix list entry and binds it to an interface
154 * IF = Pointer to interface
155 * Prefix = Pointer to prefix
156 * Length = Length of prefix
158 * Pointer to PLE, NULL if there was not enough free resources
160 * The prefix list entry retains a reference to the interface and
161 * the provided address. The caller is responsible for providing
165 PPREFIX_LIST_ENTRY PLE
;
167 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF
, Prefix
, Length
));
169 /* Allocate space for an PLE and set it up */
170 PLE
= PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY
));
172 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
178 PLE
->Prefix
= Prefix
;
179 PLE
->PrefixLength
= Length
;
181 /* Add PLE to the global prefix list */
182 ExInterlockedInsertTailList(&PrefixListHead
, &PLE
->ListEntry
, &PrefixListLock
);
189 PPREFIX_LIST_ENTRY PLE
)
191 * FUNCTION: Destroys an prefix list entry
193 * PLE = Pointer to prefix list entry
195 * The prefix list lock must be held when called
198 TI_DbgPrint(DEBUG_IP
, ("Called. PLE (0x%X).\n", PLE
));
200 /* Unlink the prefix list entry from the list */
201 RemoveEntryList(&PLE
->ListEntry
);
203 /* Dereference the address */
204 DereferenceObject(PLE
->Prefix
);
206 /* Dereference the interface */
207 DereferenceObject(PLE
->Interface
);
212 if (PLE
->RefCount
!= 0) {
213 TI_DbgPrint(MIN_TRACE
, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE
, PLE
->RefCount
));
217 /* And free the PLE */
225 * FUNCTION: Destroys all prefix list entries
229 PLIST_ENTRY CurrentEntry
;
230 PLIST_ENTRY NextEntry
;
231 PPREFIX_LIST_ENTRY Current
;
233 TI_DbgPrint(DEBUG_IP
, ("Called.\n"));
235 KeAcquireSpinLock(&PrefixListLock
, &OldIrql
);
237 /* Search the list and remove every PLE we find */
238 CurrentEntry
= PrefixListHead
.Flink
;
239 while (CurrentEntry
!= &PrefixListHead
) {
240 NextEntry
= CurrentEntry
->Flink
;
241 Current
= CONTAINING_RECORD(CurrentEntry
, PREFIX_LIST_ENTRY
, ListEntry
);
242 /* Destroy the PLE */
244 CurrentEntry
= NextEntry
;
246 KeReleaseSpinLock(&PrefixListLock
, OldIrql
);
250 PNET_TABLE_ENTRY
IPCreateNTE(
255 * FUNCTION: Creates a net table entry and binds it to an interface
257 * IF = Pointer to interface
258 * Address = Pointer to interface address
259 * PrefixLength = Length of prefix
261 * Pointer to NTE, NULL if there was not enough free resources
263 * The interface lock must be held when called.
264 * The net table entry retains a reference to the interface and
265 * the provided address. The caller is responsible for providing
269 PNET_TABLE_ENTRY NTE
;
272 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF
, Address
, PrefixLength
));
274 /* Allocate room for an NTE */
275 NTE
= PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY
));
277 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
283 /* One reference is for beeing alive and one reference is for the ADE */
286 NTE
->Address
= Address
;
287 /* One reference is for NTE, one reference is given to the
288 address entry, and one reference is given to the prefix
290 ReferenceObject(Address
);
291 ReferenceObject(Address
);
292 ReferenceObject(Address
);
294 /* Create an address entry and add it to the list */
295 ADE
= CreateADE(IF
, NTE
->Address
, ADE_UNICAST
, NTE
);
297 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
302 /* Create a prefix list entry for unicast address */
303 NTE
->PLE
= CreatePLE(IF
, NTE
->Address
, PrefixLength
);
310 /* Reference the interface for the prefix list entry */
313 /* Add NTE to the list on the interface */
314 InsertTailList(&IF
->NTEListHead
, &NTE
->IFListEntry
);
316 /* Add NTE to the global net table list */
317 ExInterlockedInsertTailList(&NetTableListHead
, &NTE
->NTListEntry
, &NetTableListLock
);
325 PNET_TABLE_ENTRY NTE
)
327 * FUNCTION: Destroys a net table entry
329 * IF = Pointer to interface
330 * NTE = Pointer to net table entry
332 * The net table list lock must be held when called
333 * The interface lock must be held when called
338 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) NTE (0x%X).\n", IF
, NTE
));
340 /* Invalidate the prefix list entry for this NTE */
341 KeAcquireSpinLock(&PrefixListLock
, &OldIrql
);
342 DestroyPLE(NTE
->PLE
);
343 KeReleaseSpinLock(&PrefixListLock
, OldIrql
);
345 /* Remove NTE from the interface list */
346 RemoveEntryList(&NTE
->IFListEntry
);
347 /* Remove NTE from the net table list */
348 RemoveEntryList(&NTE
->NTListEntry
);
349 /* Dereference the objects that are referenced */
350 DereferenceObject(NTE
->Address
);
351 DereferenceObject(NTE
->Interface
);
355 if (NTE
->RefCount
!= 0) {
356 TI_DbgPrint(MIN_TRACE
, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE
, NTE
->RefCount
));
359 /* And free the NTE */
367 * FUNCTION: Destroys all net table entries on an interface
369 * IF = Pointer to interface
371 * The net table list lock must be held when called
372 * The interface lock may be held when called
375 PLIST_ENTRY CurrentEntry
;
376 PLIST_ENTRY NextEntry
;
377 PNET_TABLE_ENTRY Current
;
379 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
381 /* Search the list and remove every NTE we find */
382 CurrentEntry
= IF
->NTEListHead
.Flink
;
383 while (CurrentEntry
!= &IF
->NTEListHead
) {
384 NextEntry
= CurrentEntry
->Flink
;
385 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
386 /* Destroy the NTE */
387 DestroyNTE(IF
, Current
);
388 CurrentEntry
= NextEntry
;
393 PNET_TABLE_ENTRY
IPLocateNTEOnInterface(
398 * FUNCTION: Locates an NTE on an interface
400 * IF = Pointer to interface
401 * Address = Pointer to IP address
402 * AddressType = Address of type of IP address
404 * If found, the NTE is referenced for the caller. The caller is
405 * responsible for dereferencing after use
407 * Pointer to net table entry, NULL if none was found
411 PLIST_ENTRY CurrentEntry
;
412 PADDRESS_ENTRY Current
;
414 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
415 IF
, Address
, AddressType
));
417 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
419 /* Search the list and return the NTE if found */
420 CurrentEntry
= IF
->ADEListHead
.Flink
;
421 while (CurrentEntry
!= &IF
->ADEListHead
) {
422 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
423 if (AddrIsEqual(Address
, Current
->Address
)) {
424 ReferenceObject(Current
->NTE
);
425 *AddressType
= Current
->Type
;
426 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
429 CurrentEntry
= CurrentEntry
->Flink
;
432 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
438 PNET_TABLE_ENTRY
IPLocateNTE(
442 * FUNCTION: Locates an NTE for the network Address is on
444 * Address = Pointer to an address to find associated NTE of
445 * AddressType = Address of address type
447 * If found the NTE is referenced for the caller. The caller is
448 * responsible for dereferencing after use
450 * Pointer to NTE if the address was found, NULL if not.
454 PLIST_ENTRY CurrentEntry
;
455 PNET_TABLE_ENTRY Current
;
456 PNET_TABLE_ENTRY NTE
;
458 TI_DbgPrint(DEBUG_IP
, ("Called. Address (0x%X) AddressType (0x%X).\n",
459 Address
, AddressType
));
461 KeAcquireSpinLock(&NetTableListLock
, &OldIrql
);
463 /* Search the list and return the NTE if found */
464 CurrentEntry
= NetTableListHead
.Flink
;
465 while (CurrentEntry
!= &NetTableListHead
) {
466 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, NTListEntry
);
467 NTE
= IPLocateNTEOnInterface(Current
->Interface
, Address
, AddressType
);
469 ReferenceObject(NTE
);
470 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
473 CurrentEntry
= CurrentEntry
->Flink
;
476 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
482 PADDRESS_ENTRY
IPLocateADE(
486 * FUNCTION: Locates an ADE for the address
488 * Address = Pointer to an address to find associated ADE of
489 * AddressType = Type of address
491 * Pointer to ADE if the address was found, NULL if not.
493 * If found the ADE is referenced for the caller. The caller is
494 * responsible for dereferencing after use
498 PLIST_ENTRY CurrentIFEntry
;
499 PLIST_ENTRY CurrentADEEntry
;
500 PIP_INTERFACE CurrentIF
;
501 PADDRESS_ENTRY CurrentADE
;
503 TI_DbgPrint(DEBUG_IP
, ("Called. Address (0x%X) AddressType (0x%X).\n",
504 Address
, AddressType
));
506 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
508 /* Search the interface list */
509 CurrentIFEntry
= InterfaceListHead
.Flink
;
510 while (CurrentIFEntry
!= &InterfaceListHead
) {
511 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
513 /* Search the address entry list and return the ADE if found */
514 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
515 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
516 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
517 if ((AddrIsEqual(Address
, CurrentADE
->Address
)) &&
518 (CurrentADE
->Type
== AddressType
)) {
519 ReferenceObject(CurrentADE
);
520 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
523 CurrentADEEntry
= CurrentADEEntry
->Flink
;
525 CurrentIFEntry
= CurrentIFEntry
->Flink
;
528 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
534 PADDRESS_ENTRY
IPGetDefaultADE(
537 * FUNCTION: Returns a default address entry
539 * AddressType = Type of address
541 * Pointer to ADE if found, NULL if not.
543 * Loopback interface is only considered if it is the only interface.
544 * If found, the address entry is referenced
548 PLIST_ENTRY CurrentIFEntry
;
549 PLIST_ENTRY CurrentADEEntry
;
550 PIP_INTERFACE CurrentIF
;
551 PADDRESS_ENTRY CurrentADE
;
553 BOOLEAN LoopbackIsRegistered
= FALSE
;
555 TI_DbgPrint(DEBUG_IP
, ("Called. AddressType (0x%X).\n", AddressType
));
557 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
559 /* Search the interface list */
560 CurrentIFEntry
= InterfaceListHead
.Flink
;
561 while (CurrentIFEntry
!= &InterfaceListHead
) {
562 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
564 if (CurrentIF
!= Loopback
) {
566 /* Search the address entry list and return the first appropriate ADE found */
567 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
568 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
569 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
570 if (CurrentADE
->Type
== AddressType
)
571 ReferenceObject(CurrentADE
);
572 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
575 CurrentADEEntry
= CurrentADEEntry
->Flink
;
578 LoopbackIsRegistered
= TRUE
;
580 CurrentIFEntry
= CurrentIFEntry
->Flink
;
583 /* No address was found. Use loopback interface if available */
584 if (LoopbackIsRegistered
) {
585 CurrentADEEntry
= Loopback
->ADEListHead
.Flink
;
586 while (CurrentADEEntry
!= &Loopback
->ADEListHead
) {
587 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
588 if (CurrentADE
->Type
== AddressType
) {
589 ReferenceObject(CurrentADE
);
590 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
593 CurrentADEEntry
= CurrentADEEntry
->Flink
;
597 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
605 PVOID DeferredContext
,
606 PVOID SystemArgument1
,
607 PVOID SystemArgument2
)
609 * FUNCTION: Timeout DPC
611 * Dpc = Pointer to our DPC object
612 * DeferredContext = Pointer to context information (unused)
613 * SystemArgument1 = Unused
614 * SystemArgument2 = Unused
616 * This routine is dispatched once in a while to do maintainance jobs
619 /* Check if datagram fragments have taken too long to assemble */
620 IPDatagramReassemblyTimeout();
622 /* Clean possible outdated cached neighbor addresses */
627 VOID
IPDispatchProtocol(
628 PNET_TABLE_ENTRY NTE
,
631 * FUNCTION: IP protocol dispatcher
633 * NTE = Pointer to net table entry which the packet was received on
634 * IPPacket = Pointer to an IP packet that was received
636 * This routine examines the IP header and passes the packet on to the
637 * right upper level protocol receive handler
642 switch (IPPacket
->Type
) {
644 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
647 /* FIXME: IPv6 adresses not supported */
648 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
654 /* Call the appropriate protocol handler */
655 (*ProtocolTable
[Protocol
])(NTE
, IPPacket
);
659 PIP_INTERFACE
IPCreateInterface(
660 PLLIP_BIND_INFO BindInfo
)
662 * FUNCTION: Creates an IP interface
664 * BindInfo = Pointer to link layer to IP binding information
666 * Pointer to IP_INTERFACE structure, NULL if there was
667 * not enough free resources
672 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
674 IF
= PoolAllocateBuffer(sizeof(IP_INTERFACE
));
676 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
681 IF
->Context
= BindInfo
->Context
;
682 IF
->HeaderSize
= BindInfo
->HeaderSize
;
683 if (IF
->HeaderSize
> MaxLLHeaderSize
)
684 MaxLLHeaderSize
= IF
->HeaderSize
;
686 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
687 if (IF
->MinFrameSize
> MinLLFrameSize
)
688 MinLLFrameSize
= IF
->MinFrameSize
;
690 IF
->MTU
= BindInfo
->MTU
;
691 IF
->Address
= BindInfo
->Address
;
692 IF
->AddressLength
= BindInfo
->AddressLength
;
693 IF
->Transmit
= BindInfo
->Transmit
;
695 InitializeListHead(&IF
->ADEListHead
);
696 InitializeListHead(&IF
->NTEListHead
);
698 KeInitializeSpinLock(&IF
->Lock
);
704 VOID
IPDestroyInterface(
707 * FUNCTION: Destroys an IP interface
709 * IF = Pointer to interface to destroy
715 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
717 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
718 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
721 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
722 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
727 if (IF
->RefCount
!= 0) {
728 TI_DbgPrint(MIN_TRACE
, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF
, IF
->RefCount
));
735 BOOLEAN
IPRegisterInterface(
738 * FUNCTION: Registers an IP interface with IP layer
740 * IF = Pointer to interface to register
742 * TRUE if interface was successfully registered, FALSE if not
746 PLIST_ENTRY CurrentEntry
;
747 PNET_TABLE_ENTRY Current
;
748 PROUTE_CACHE_NODE RCN
;
749 PNEIGHBOR_CACHE_ENTRY NCE
;
751 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
753 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
755 /* Add routes to all NTEs on this interface */
756 CurrentEntry
= IF
->NTEListHead
.Flink
;
757 while (CurrentEntry
!= &IF
->NTEListHead
) {
758 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
760 /* Add a permanent neighbor for this NTE */
761 ReferenceObject(Current
->Address
);
762 NCE
= NBAddNeighbor(IF
, Current
->Address
, IF
->Address
,
763 IF
->AddressLength
, NUD_PERMANENT
);
765 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
766 DereferenceObject(Current
->Address
);
767 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
770 RCN
= RouteAddRouteToDestination(Current
->Address
, Current
, IF
, NCE
);
772 TI_DbgPrint(MIN_TRACE
, ("Could not create RCN.\n"));
773 DereferenceObject(Current
->Address
);
774 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
777 /* Don't need this any more since the route cache references the NCE */
778 DereferenceObject(NCE
);
780 CurrentEntry
= CurrentEntry
->Flink
;
783 /* Add interface to the global interface list */
784 ExInterlockedInsertTailList(&InterfaceListHead
, &IF
->ListEntry
, &InterfaceListLock
);
786 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
792 VOID
IPUnregisterInterface(
795 * FUNCTION: Unregisters an IP interface with IP layer
797 * IF = Pointer to interface to unregister
803 PLIST_ENTRY CurrentEntry
;
804 PNET_TABLE_ENTRY Current
;
805 PNEIGHBOR_CACHE_ENTRY NCE
;
807 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
809 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
810 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
812 /* Remove routes to all NTEs on this interface */
813 CurrentEntry
= IF
->NTEListHead
.Flink
;
814 while (CurrentEntry
!= &IF
->NTEListHead
) {
815 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
817 /* Remove NTE from global net table list */
818 RemoveEntryList(&Current
->NTListEntry
);
820 /* Remove all references from route cache to NTE */
821 RouteInvalidateNTE(Current
);
823 /* Remove permanent NCE, but first we have to find it */
824 NCE
= NBLocateNeighbor(Current
->Address
);
826 DereferenceObject(NCE
);
827 NBRemoveNeighbor(NCE
);
830 CurrentEntry
= CurrentEntry
->Flink
;
833 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
834 /* Ouch...three spinlocks acquired! Fortunately
835 we don't unregister interfaces very often */
836 RemoveEntryList(&IF
->ListEntry
);
837 KeReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
839 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
840 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
844 VOID
IPRegisterProtocol(
846 IP_PROTOCOL_HANDLER Handler
)
848 * FUNCTION: Registers a handler for an IP protocol number
850 * ProtocolNumber = Internet Protocol number for which to register handler
851 * Handler = Pointer to handler to be called when a packet is received
853 * To unregister a protocol handler, call this function with Handler = NULL
857 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
)
858 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
861 ProtocolTable
[ProtocolNumber
] = Handler
;
865 VOID
DefaultProtocolHandler(
866 PNET_TABLE_ENTRY NTE
,
869 * FUNCTION: Default handler for Internet protocols
871 * NTE = Pointer to net table entry which the packet was received on
872 * IPPacket = Pointer to an IP packet that was received
875 TI_DbgPrint(MID_TRACE
, ("Packet of unknown Internet protocol discarded.\n"));
880 PDRIVER_OBJECT DriverObject
,
881 PUNICODE_STRING RegistryPath
)
883 * FUNCTION: Initializes the IP subsystem
885 * DriverObject = Pointer to a driver object for this driver
886 * RegistryPath = Our registry node for configuration parameters
888 * Status of operation
892 LARGE_INTEGER DueTime
;
894 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
899 /* Start routing subsystem */
902 /* Start route cache subsystem */
905 /* Start neighbor cache subsystem */
908 /* Fill the protocol dispatch table with pointers
909 to the default protocol handler */
910 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
911 IPRegisterProtocol(i
, DefaultProtocolHandler
);
913 /* Register network level protocol receive handlers */
914 IPRegisterProtocol(IPPROTO_ICMP
, ICMPReceive
);
916 /* Initialize NTE list and protecting lock */
917 InitializeListHead(&NetTableListHead
);
918 KeInitializeSpinLock(&NetTableListLock
);
920 /* Initialize reassembly list and protecting lock */
921 InitializeListHead(&ReassemblyListHead
);
922 KeInitializeSpinLock(&ReassemblyListLock
);
924 /* Initialize the prefix list and protecting lock */
925 InitializeListHead(&PrefixListHead
);
926 KeInitializeSpinLock(&PrefixListLock
);
928 /* Initialize our periodic timer and its associated DPC object. When the
929 timer expires, the IPTimeout deferred procedure call (DPC) is queued */
930 KeInitializeDpc(&IPTimeoutDpc
, IPTimeout
, NULL
);
931 KeInitializeTimer(&IPTimer
);
933 /* Start the periodic timer with an initial and periodic
934 relative expiration time of IP_TIMEOUT milliseconds */
935 DueTime
.QuadPart
= -(LONGLONG
)IP_TIMEOUT
* 10000;
936 KeSetTimerEx(&IPTimer
, DueTime
, IP_TIMEOUT
, &IPTimeoutDpc
);
938 IPInitialized
= TRUE
;
940 return STATUS_SUCCESS
;
947 * FUNCTION: Shuts down the IP subsystem
949 * Status of operation
952 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
955 return STATUS_SUCCESS
;
958 KeCancelTimer(&IPTimer
);
960 /* Shutdown neighbor cache subsystem */
963 /* Shutdown route cache subsystem */
966 /* Shutdown routing subsystem */
969 IPFreeReassemblyList();
971 /* Clear prefix list */
974 IPInitialized
= FALSE
;
976 return STATUS_SUCCESS
;