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
;