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 TI_DbgPrint(DEBUG_IP
, ("Address (%s) NTE (%s).\n",
64 A2S(Address
), A2S(NTE
->Address
)));
66 /* Allocate space for an ADE and set it up */
67 ADE
= PoolAllocateBuffer(sizeof(ADDRESS_ENTRY
));
69 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
76 ADE
->Address
= Address
;
78 /* Add ADE to the list on the interface */
79 InsertTailList(&IF
->ADEListHead
, &ADE
->ListEntry
);
89 * FUNCTION: Destroys an address entry
91 * IF = Pointer to interface
92 * ADE = Pointer to address entry
94 * The interface lock must be held when called
97 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) ADE (0x%X).\n", IF
, ADE
));
99 TI_DbgPrint(DEBUG_IP
, ("ADE (%s).\n", ADE
->Address
));
101 /* Unlink the address entry from the list */
102 RemoveEntryList(&ADE
->ListEntry
);
104 /* Dereference the address */
105 DereferenceObject(ADE
->Address
);
107 /* Dereference the NTE */
108 DereferenceObject(ADE
->NTE
);
113 if (ADE
->RefCount
!= 0) {
114 TI_DbgPrint(MIN_TRACE
, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE
, ADE
->RefCount
));
118 /* And free the ADE */
120 TI_DbgPrint(MIN_TRACE
, ("Check.\n"));
127 * FUNCTION: Destroys all address entries on an interface
129 * IF = Pointer to interface
131 * The interface lock must be held when called
134 PLIST_ENTRY CurrentEntry
;
135 PLIST_ENTRY NextEntry
;
136 PADDRESS_ENTRY Current
;
138 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
140 /* Search the list and remove every ADE we find */
141 CurrentEntry
= IF
->ADEListHead
.Flink
;
142 while (CurrentEntry
!= &IF
->ADEListHead
) {
143 NextEntry
= CurrentEntry
->Flink
;
144 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
145 /* Destroy the ADE */
146 DestroyADE(IF
, Current
);
147 CurrentEntry
= NextEntry
;
152 PPREFIX_LIST_ENTRY
CreatePLE(
157 * FUNCTION: Creates a prefix list entry and binds it to an interface
159 * IF = Pointer to interface
160 * Prefix = Pointer to prefix
161 * Length = Length of prefix
163 * Pointer to PLE, NULL if there was not enough free resources
165 * The prefix list entry retains a reference to the interface and
166 * the provided address. The caller is responsible for providing
170 PPREFIX_LIST_ENTRY PLE
;
172 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF
, Prefix
, Length
));
174 TI_DbgPrint(DEBUG_IP
, ("Prefix (%s).\n", A2S(Prefix
)));
176 /* Allocate space for an PLE and set it up */
177 PLE
= PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY
));
179 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
185 PLE
->Prefix
= Prefix
;
186 PLE
->PrefixLength
= Length
;
188 /* Add PLE to the global prefix list */
189 ExInterlockedInsertTailList(&PrefixListHead
, &PLE
->ListEntry
, &PrefixListLock
);
196 PPREFIX_LIST_ENTRY PLE
)
198 * FUNCTION: Destroys an prefix list entry
200 * PLE = Pointer to prefix list entry
202 * The prefix list lock must be held when called
205 TI_DbgPrint(DEBUG_IP
, ("Called. PLE (0x%X).\n", PLE
));
207 TI_DbgPrint(DEBUG_IP
, ("PLE (%s).\n", PLE
->Prefix
));
209 /* Unlink the prefix list entry from the list */
210 RemoveEntryList(&PLE
->ListEntry
);
212 /* Dereference the address */
213 DereferenceObject(PLE
->Prefix
);
215 /* Dereference the interface */
216 DereferenceObject(PLE
->Interface
);
221 if (PLE
->RefCount
!= 0) {
222 TI_DbgPrint(MIN_TRACE
, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE
, PLE
->RefCount
));
226 /* And free the PLE */
234 * FUNCTION: Destroys all prefix list entries
238 PLIST_ENTRY CurrentEntry
;
239 PLIST_ENTRY NextEntry
;
240 PPREFIX_LIST_ENTRY Current
;
242 TI_DbgPrint(DEBUG_IP
, ("Called.\n"));
244 KeAcquireSpinLock(&PrefixListLock
, &OldIrql
);
246 /* Search the list and remove every PLE we find */
247 CurrentEntry
= PrefixListHead
.Flink
;
248 while (CurrentEntry
!= &PrefixListHead
) {
249 NextEntry
= CurrentEntry
->Flink
;
250 Current
= CONTAINING_RECORD(CurrentEntry
, PREFIX_LIST_ENTRY
, ListEntry
);
251 /* Destroy the PLE */
253 CurrentEntry
= NextEntry
;
255 KeReleaseSpinLock(&PrefixListLock
, OldIrql
);
259 PNET_TABLE_ENTRY
IPCreateNTE(
264 * FUNCTION: Creates a net table entry and binds it to an interface
266 * IF = Pointer to interface
267 * Address = Pointer to interface address
268 * PrefixLength = Length of prefix
270 * Pointer to NTE, NULL if there was not enough free resources
272 * The interface lock must be held when called.
273 * The net table entry retains a reference to the interface and
274 * the provided address. The caller is responsible for providing
278 PNET_TABLE_ENTRY NTE
;
281 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF
, Address
, PrefixLength
));
283 TI_DbgPrint(DEBUG_IP
, ("Address (%s).\n", A2S(Address
)));
285 /* Allocate room for an NTE */
286 NTE
= PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY
));
288 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
294 /* One reference is for beeing alive and one reference is for the ADE */
297 NTE
->Address
= Address
;
298 /* One reference is for NTE, one reference is given to the
299 address entry, and one reference is given to the prefix
301 ReferenceObject(Address
);
302 ReferenceObject(Address
);
303 ReferenceObject(Address
);
305 /* Create an address entry and add it to the list */
306 ADE
= CreateADE(IF
, NTE
->Address
, ADE_UNICAST
, NTE
);
308 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
313 /* Create a prefix list entry for unicast address */
314 NTE
->PLE
= CreatePLE(IF
, NTE
->Address
, PrefixLength
);
321 /* Reference the interface for the prefix list entry */
324 /* Add NTE to the list on the interface */
325 InsertTailList(&IF
->NTEListHead
, &NTE
->IFListEntry
);
327 /* Add NTE to the global net table list */
328 ExInterlockedInsertTailList(&NetTableListHead
, &NTE
->NTListEntry
, &NetTableListLock
);
336 PNET_TABLE_ENTRY NTE
)
338 * FUNCTION: Destroys a net table entry
340 * IF = Pointer to interface
341 * NTE = Pointer to net table entry
343 * The net table list lock must be held when called
344 * The interface lock must be held when called
349 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X) NTE (0x%X).\n", IF
, NTE
));
351 TI_DbgPrint(DEBUG_IP
, ("NTE (%s).\n", NTE
->Address
));
353 /* Invalidate the prefix list entry for this NTE */
354 KeAcquireSpinLock(&PrefixListLock
, &OldIrql
);
355 DestroyPLE(NTE
->PLE
);
356 KeReleaseSpinLock(&PrefixListLock
, OldIrql
);
358 /* Remove NTE from the interface list */
359 RemoveEntryList(&NTE
->IFListEntry
);
360 /* Remove NTE from the net table list */
361 RemoveEntryList(&NTE
->NTListEntry
);
362 /* Dereference the objects that are referenced */
363 DereferenceObject(NTE
->Address
);
364 DereferenceObject(NTE
->Interface
);
368 if (NTE
->RefCount
!= 0) {
369 TI_DbgPrint(MIN_TRACE
, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE
, NTE
->RefCount
));
372 /* And free the NTE */
380 * FUNCTION: Destroys all net table entries on an interface
382 * IF = Pointer to interface
384 * The net table list lock must be held when called
385 * The interface lock may be held when called
388 PLIST_ENTRY CurrentEntry
;
389 PLIST_ENTRY NextEntry
;
390 PNET_TABLE_ENTRY Current
;
392 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
394 /* Search the list and remove every NTE we find */
395 CurrentEntry
= IF
->NTEListHead
.Flink
;
396 while (CurrentEntry
!= &IF
->NTEListHead
) {
397 NextEntry
= CurrentEntry
->Flink
;
398 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
399 /* Destroy the NTE */
400 DestroyNTE(IF
, Current
);
401 CurrentEntry
= NextEntry
;
406 PNET_TABLE_ENTRY
IPLocateNTEOnInterface(
411 * FUNCTION: Locates an NTE on an interface
413 * IF = Pointer to interface
414 * Address = Pointer to IP address
415 * AddressType = Address of type of IP address
417 * If found, the NTE is referenced for the caller. The caller is
418 * responsible for dereferencing after use
420 * Pointer to net table entry, NULL if none was found
424 PLIST_ENTRY CurrentEntry
;
425 PADDRESS_ENTRY Current
;
427 // TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
428 // IF, Address, AddressType));
430 // TI_DbgPrint(DEBUG_IP, ("Address (%s) AddressType (0x%X).\n", A2S(Address)));
432 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
434 /* Search the list and return the NTE if found */
435 CurrentEntry
= IF
->ADEListHead
.Flink
;
436 while (CurrentEntry
!= &IF
->ADEListHead
) {
437 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_ENTRY
, ListEntry
);
438 if (AddrIsEqual(Address
, Current
->Address
)) {
439 ReferenceObject(Current
->NTE
);
440 *AddressType
= Current
->Type
;
441 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
444 CurrentEntry
= CurrentEntry
->Flink
;
447 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
453 PNET_TABLE_ENTRY
IPLocateNTE(
457 * FUNCTION: Locates an NTE for the network Address is on
459 * Address = Pointer to an address to find associated NTE of
460 * AddressType = Address of address type
462 * If found the NTE is referenced for the caller. The caller is
463 * responsible for dereferencing after use
465 * Pointer to NTE if the address was found, NULL if not.
469 PLIST_ENTRY CurrentEntry
;
470 PNET_TABLE_ENTRY Current
;
471 PNET_TABLE_ENTRY NTE
;
473 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
474 // Address, AddressType));
476 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
478 KeAcquireSpinLock(&NetTableListLock
, &OldIrql
);
480 /* Search the list and return the NTE if found */
481 CurrentEntry
= NetTableListHead
.Flink
;
482 while (CurrentEntry
!= &NetTableListHead
) {
483 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, NTListEntry
);
484 NTE
= IPLocateNTEOnInterface(Current
->Interface
, Address
, AddressType
);
486 ReferenceObject(NTE
);
487 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
490 CurrentEntry
= CurrentEntry
->Flink
;
493 KeReleaseSpinLock(&NetTableListLock
, OldIrql
);
499 PADDRESS_ENTRY
IPLocateADE(
503 * FUNCTION: Locates an ADE for the address
505 * Address = Pointer to an address to find associated ADE of
506 * AddressType = Type of address
508 * Pointer to ADE if the address was found, NULL if not.
510 * If found the ADE is referenced for the caller. The caller is
511 * responsible for dereferencing after use
515 PLIST_ENTRY CurrentIFEntry
;
516 PLIST_ENTRY CurrentADEEntry
;
517 PIP_INTERFACE CurrentIF
;
518 PADDRESS_ENTRY CurrentADE
;
520 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
521 // Address, AddressType));
523 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
525 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
527 /* Search the interface list */
528 CurrentIFEntry
= InterfaceListHead
.Flink
;
529 while (CurrentIFEntry
!= &InterfaceListHead
) {
530 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
532 /* Search the address entry list and return the ADE if found */
533 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
534 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
535 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
536 if ((AddrIsEqual(Address
, CurrentADE
->Address
)) &&
537 (CurrentADE
->Type
== AddressType
)) {
538 ReferenceObject(CurrentADE
);
539 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
542 CurrentADEEntry
= CurrentADEEntry
->Flink
;
544 CurrentIFEntry
= CurrentIFEntry
->Flink
;
547 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
553 PADDRESS_ENTRY
IPGetDefaultADE(
556 * FUNCTION: Returns a default address entry
558 * AddressType = Type of address
560 * Pointer to ADE if found, NULL if not.
562 * Loopback interface is only considered if it is the only interface.
563 * If found, the address entry is referenced
567 PLIST_ENTRY CurrentIFEntry
;
568 PLIST_ENTRY CurrentADEEntry
;
569 PIP_INTERFACE CurrentIF
;
570 PADDRESS_ENTRY CurrentADE
;
571 BOOLEAN LoopbackIsRegistered
= FALSE
;
573 TI_DbgPrint(DEBUG_IP
, ("Called. AddressType (0x%X).\n", AddressType
));
575 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql
);
577 /* Search the interface list */
578 CurrentIFEntry
= InterfaceListHead
.Flink
;
579 while (CurrentIFEntry
!= &InterfaceListHead
) {
580 CurrentIF
= CONTAINING_RECORD(CurrentIFEntry
, IP_INTERFACE
, ListEntry
);
582 if (CurrentIF
!= Loopback
) {
583 /* Search the address entry list and return the first appropriate ADE found */
584 CurrentADEEntry
= CurrentIF
->ADEListHead
.Flink
;
585 while (CurrentADEEntry
!= &CurrentIF
->ADEListHead
) {
586 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
587 if (CurrentADE
->Type
== AddressType
)
588 ReferenceObject(CurrentADE
);
589 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
592 CurrentADEEntry
= CurrentADEEntry
->Flink
;
594 LoopbackIsRegistered
= TRUE
;
595 CurrentIFEntry
= CurrentIFEntry
->Flink
;
598 /* No address was found. Use loopback interface if available */
599 if (LoopbackIsRegistered
) {
600 CurrentADEEntry
= Loopback
->ADEListHead
.Flink
;
601 while (CurrentADEEntry
!= &Loopback
->ADEListHead
) {
602 CurrentADE
= CONTAINING_RECORD(CurrentADEEntry
, ADDRESS_ENTRY
, ListEntry
);
603 if (CurrentADE
->Type
== AddressType
) {
604 ReferenceObject(CurrentADE
);
605 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
608 CurrentADEEntry
= CurrentADEEntry
->Flink
;
612 KeReleaseSpinLock(&InterfaceListLock
, OldIrql
);
620 PVOID DeferredContext
,
621 PVOID SystemArgument1
,
622 PVOID SystemArgument2
)
624 * FUNCTION: Timeout DPC
626 * Dpc = Pointer to our DPC object
627 * DeferredContext = Pointer to context information (unused)
628 * SystemArgument1 = Unused
629 * SystemArgument2 = Unused
631 * This routine is dispatched once in a while to do maintainance jobs
634 /* Check if datagram fragments have taken too long to assemble */
635 IPDatagramReassemblyTimeout();
637 /* Clean possible outdated cached neighbor addresses */
642 VOID
IPDispatchProtocol(
643 PNET_TABLE_ENTRY NTE
,
646 * FUNCTION: IP protocol dispatcher
648 * NTE = Pointer to net table entry which the packet was received on
649 * IPPacket = Pointer to an IP packet that was received
651 * This routine examines the IP header and passes the packet on to the
652 * right upper level protocol receive handler
657 switch (IPPacket
->Type
) {
659 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
662 /* FIXME: IPv6 adresses not supported */
663 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
669 /* Call the appropriate protocol handler */
670 (*ProtocolTable
[Protocol
])(NTE
, IPPacket
);
674 PIP_INTERFACE
IPCreateInterface(
675 PLLIP_BIND_INFO BindInfo
)
677 * FUNCTION: Creates an IP interface
679 * BindInfo = Pointer to link layer to IP binding information
681 * Pointer to IP_INTERFACE structure, NULL if there was
682 * not enough free resources
687 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
690 if (BindInfo
->Address
) {
691 PUCHAR A
= BindInfo
->Address
;
692 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
693 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
697 IF
= PoolAllocateBuffer(sizeof(IP_INTERFACE
));
699 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
704 IF
->Context
= BindInfo
->Context
;
705 IF
->HeaderSize
= BindInfo
->HeaderSize
;
706 if (IF
->HeaderSize
> MaxLLHeaderSize
)
707 MaxLLHeaderSize
= IF
->HeaderSize
;
709 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
710 if (IF
->MinFrameSize
> MinLLFrameSize
)
711 MinLLFrameSize
= IF
->MinFrameSize
;
713 IF
->MTU
= BindInfo
->MTU
;
714 IF
->Address
= BindInfo
->Address
;
715 IF
->AddressLength
= BindInfo
->AddressLength
;
716 IF
->Transmit
= BindInfo
->Transmit
;
718 InitializeListHead(&IF
->ADEListHead
);
719 InitializeListHead(&IF
->NTEListHead
);
721 KeInitializeSpinLock(&IF
->Lock
);
727 VOID
IPDestroyInterface(
730 * FUNCTION: Destroys an IP interface
732 * IF = Pointer to interface to destroy
738 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
740 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
741 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
744 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
745 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
750 if (IF
->RefCount
!= 0) {
751 TI_DbgPrint(MIN_TRACE
, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF
, IF
->RefCount
));
758 BOOLEAN
IPRegisterInterface(
761 * FUNCTION: Registers an IP interface with IP layer
763 * IF = Pointer to interface to register
765 * TRUE if interface was successfully registered, FALSE if not
769 PLIST_ENTRY CurrentEntry
;
770 PNET_TABLE_ENTRY Current
;
771 PROUTE_CACHE_NODE RCN
;
772 PNEIGHBOR_CACHE_ENTRY NCE
;
774 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
776 KeAcquireSpinLock(&IF
->Lock
, &OldIrql
);
778 /* Add routes to all NTEs on this interface */
779 CurrentEntry
= IF
->NTEListHead
.Flink
;
780 while (CurrentEntry
!= &IF
->NTEListHead
) {
781 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
783 /* Add a permanent neighbor for this NTE */
784 ReferenceObject(Current
->Address
);
785 NCE
= NBAddNeighbor(IF
, Current
->Address
, IF
->Address
,
786 IF
->AddressLength
, NUD_PERMANENT
);
788 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
789 DereferenceObject(Current
->Address
);
790 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
794 /* Reference objects for forward information base */
795 ReferenceObject(Current
->Address
);
796 ReferenceObject(Current
->PLE
->Prefix
);
797 ReferenceObject(Current
);
798 /* NCE is already referenced */
799 if (!RouterAddRoute(Current
->Address
, Current
->PLE
->Prefix
, Current
, NCE
, 1)) {
800 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
801 DereferenceObject(Current
->Address
);
802 DereferenceObject(Current
->PLE
->Prefix
);
803 DereferenceObject(Current
);
804 DereferenceObject(NCE
);
807 RCN
= RouteAddRouteToDestination(Current
->Address
, Current
, IF
, NCE
);
809 TI_DbgPrint(MIN_TRACE
, ("Could not create RCN.\n"));
810 DereferenceObject(Current
->Address
);
811 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
814 /* Don't need this any more since the route cache references the NCE */
815 DereferenceObject(NCE
);
817 CurrentEntry
= CurrentEntry
->Flink
;
820 /* Add interface to the global interface list */
821 ExInterlockedInsertTailList(&InterfaceListHead
, &IF
->ListEntry
, &InterfaceListLock
);
823 KeReleaseSpinLock(&IF
->Lock
, OldIrql
);
829 VOID
IPUnregisterInterface(
832 * FUNCTION: Unregisters an IP interface with IP layer
834 * IF = Pointer to interface to unregister
840 PLIST_ENTRY CurrentEntry
;
841 PNET_TABLE_ENTRY Current
;
842 PNEIGHBOR_CACHE_ENTRY NCE
;
844 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
846 KeAcquireSpinLock(&NetTableListLock
, &OldIrql1
);
847 KeAcquireSpinLock(&IF
->Lock
, &OldIrql2
);
849 /* Remove routes to all NTEs on this interface */
850 CurrentEntry
= IF
->NTEListHead
.Flink
;
851 while (CurrentEntry
!= &IF
->NTEListHead
) {
852 Current
= CONTAINING_RECORD(CurrentEntry
, NET_TABLE_ENTRY
, IFListEntry
);
854 /* Remove NTE from global net table list */
855 RemoveEntryList(&Current
->NTListEntry
);
857 /* Remove all references from route cache to NTE */
858 RouteInvalidateNTE(Current
);
860 /* Remove permanent NCE, but first we have to find it */
861 NCE
= NBLocateNeighbor(Current
->Address
);
863 DereferenceObject(NCE
);
864 NBRemoveNeighbor(NCE
);
867 CurrentEntry
= CurrentEntry
->Flink
;
870 KeAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
871 /* Ouch...three spinlocks acquired! Fortunately
872 we don't unregister interfaces very often */
873 RemoveEntryList(&IF
->ListEntry
);
874 KeReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
876 KeReleaseSpinLock(&IF
->Lock
, OldIrql2
);
877 KeReleaseSpinLock(&NetTableListLock
, OldIrql1
);
881 VOID
IPRegisterProtocol(
883 IP_PROTOCOL_HANDLER Handler
)
885 * FUNCTION: Registers a handler for an IP protocol number
887 * ProtocolNumber = Internet Protocol number for which to register handler
888 * Handler = Pointer to handler to be called when a packet is received
890 * To unregister a protocol handler, call this function with Handler = NULL
894 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
)
895 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
898 ProtocolTable
[ProtocolNumber
] = Handler
;
902 VOID
DefaultProtocolHandler(
903 PNET_TABLE_ENTRY NTE
,
906 * FUNCTION: Default handler for Internet protocols
908 * NTE = Pointer to net table entry which the packet was received on
909 * IPPacket = Pointer to an IP packet that was received
912 TI_DbgPrint(MID_TRACE
, ("Packet of unknown Internet protocol discarded.\n"));
917 PDRIVER_OBJECT DriverObject
,
918 PUNICODE_STRING RegistryPath
)
920 * FUNCTION: Initializes the IP subsystem
922 * DriverObject = Pointer to a driver object for this driver
923 * RegistryPath = Our registry node for configuration parameters
925 * Status of operation
929 LARGE_INTEGER DueTime
;
931 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
936 /* Start routing subsystem */
939 /* Start route cache subsystem */
942 /* Start neighbor cache subsystem */
945 /* Fill the protocol dispatch table with pointers
946 to the default protocol handler */
947 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
948 IPRegisterProtocol(i
, DefaultProtocolHandler
);
950 /* Register network level protocol receive handlers */
951 IPRegisterProtocol(IPPROTO_ICMP
, ICMPReceive
);
953 /* Initialize NTE list and protecting lock */
954 InitializeListHead(&NetTableListHead
);
955 KeInitializeSpinLock(&NetTableListLock
);
957 /* Initialize reassembly list and protecting lock */
958 InitializeListHead(&ReassemblyListHead
);
959 KeInitializeSpinLock(&ReassemblyListLock
);
961 /* Initialize the prefix list and protecting lock */
962 InitializeListHead(&PrefixListHead
);
963 KeInitializeSpinLock(&PrefixListLock
);
965 /* Initialize our periodic timer and its associated DPC object. When the
966 timer expires, the IPTimeout deferred procedure call (DPC) is queued */
967 KeInitializeDpc(&IPTimeoutDpc
, IPTimeout
, NULL
);
968 KeInitializeTimer(&IPTimer
);
970 /* Start the periodic timer with an initial and periodic
971 relative expiration time of IP_TIMEOUT milliseconds */
972 DueTime
.QuadPart
= -(LONGLONG
)IP_TIMEOUT
* 10000;
973 KeSetTimerEx(&IPTimer
, DueTime
, IP_TIMEOUT
, &IPTimeoutDpc
);
975 IPInitialized
= TRUE
;
977 return STATUS_SUCCESS
;
984 * FUNCTION: Shuts down the IP subsystem
986 * Status of operation
989 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
992 return STATUS_SUCCESS
;
995 KeCancelTimer(&IPTimer
);
997 /* Shutdown neighbor cache subsystem */
1000 /* Shutdown route cache subsystem */
1003 /* Shutdown routing subsystem */
1006 IPFreeReassemblyList();
1008 /* Clear prefix list */
1011 IPInitialized
= FALSE
;
1013 return STATUS_SUCCESS
;