2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Internet Protocol module
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
14 LIST_ENTRY InterfaceListHead
;
15 KSPIN_LOCK InterfaceListLock
;
16 LIST_ENTRY NetTableListHead
;
17 KSPIN_LOCK NetTableListLock
;
18 UINT MaxLLHeaderSize
; /* Largest maximum header size */
19 UINT MinLLFrameSize
; /* Largest minimum frame size */
20 BOOLEAN IPInitialized
= FALSE
;
21 BOOLEAN IpWorkItemQueued
= FALSE
;
22 NPAGED_LOOKASIDE_LIST IPPacketList
;
23 /* Work around calling timer at Dpc level */
25 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
31 * FUNCTION: Frees an IP packet object
33 * Object = Pointer to an IP packet structure
36 TcpipFreeToNPagedLookasideList(&IPPacketList
, Object
);
43 * FUNCTION: Do nothing for when the IPPacket struct is part of another
45 * Object = Pointer to an IP packet structure
53 * FUNCTION: Frees an interface object
55 * Object = Pointer to an interface structure
62 PIP_PACKET
IPCreatePacket(ULONG Type
)
64 * FUNCTION: Creates an IP packet object
66 * Type = Type of IP packet
68 * Pointer to the created IP packet. NULL if there was not enough free resources.
73 IPPacket
= TcpipAllocateFromNPagedLookasideList(&IPPacketList
);
77 /* FIXME: Is this needed? */
78 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
80 INIT_TAG(IPPacket
, TAG('I','P','K','T'));
82 IPPacket
->Free
= FreePacket
;
83 IPPacket
->Type
= Type
;
84 IPPacket
->HeaderSize
= 20;
89 PIP_PACKET
IPInitializePacket(
93 * FUNCTION: Creates an IP packet object
95 * Type = Type of IP packet
97 * Pointer to the created IP packet. NULL if there was not enough free resources.
100 /* FIXME: Is this needed? */
101 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
103 INIT_TAG(IPPacket
, TAG('I','P','K','T'));
105 IPPacket
->Free
= DontFreePacket
;
106 IPPacket
->Type
= Type
;
112 void STDCALL
IPTimeout( PVOID Context
) {
113 IpWorkItemQueued
= FALSE
;
115 /* Check if datagram fragments have taken too long to assemble */
116 IPDatagramReassemblyTimeout();
118 /* Clean possible outdated cached neighbor addresses */
121 /* Call upper layer timeout routines */
126 VOID
IPDispatchProtocol(
127 PIP_INTERFACE Interface
,
130 * FUNCTION: IP protocol dispatcher
132 * NTE = Pointer to net table entry which the packet was received on
133 * IPPacket = Pointer to an IP packet that was received
135 * This routine examines the IP header and passes the packet on to the
136 * right upper level protocol receive handler
141 switch (IPPacket
->Type
) {
143 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
146 /* FIXME: IPv6 adresses not supported */
147 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
153 /* Call the appropriate protocol handler */
154 (*ProtocolTable
[Protocol
])(Interface
, IPPacket
);
155 /* Special case for ICMP -- ICMP can be caught by a SOCK_RAW but also
156 * must be handled here. */
157 if( Protocol
== IPPROTO_ICMP
)
158 ICMPReceive( Interface
, IPPacket
);
162 PIP_INTERFACE
IPCreateInterface(
163 PLLIP_BIND_INFO BindInfo
)
165 * FUNCTION: Creates an IP interface
167 * BindInfo = Pointer to link layer to IP binding information
169 * Pointer to IP_INTERFACE structure, NULL if there was
170 * not enough free resources
175 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
178 if (BindInfo
->Address
) {
179 PUCHAR A
= BindInfo
->Address
;
180 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
181 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
185 IF
= exAllocatePool(NonPagedPool
, sizeof(IP_INTERFACE
));
187 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
191 INIT_TAG(IF
, TAG('F','A','C','E'));
194 IF
->Context
= BindInfo
->Context
;
195 IF
->HeaderSize
= BindInfo
->HeaderSize
;
196 if (IF
->HeaderSize
> MaxLLHeaderSize
)
197 MaxLLHeaderSize
= IF
->HeaderSize
;
199 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
200 if (IF
->MinFrameSize
> MinLLFrameSize
)
201 MinLLFrameSize
= IF
->MinFrameSize
;
203 IF
->MTU
= BindInfo
->MTU
;
204 IF
->Address
= BindInfo
->Address
;
205 IF
->AddressLength
= BindInfo
->AddressLength
;
206 IF
->Transmit
= BindInfo
->Transmit
;
208 TcpipInitializeSpinLock(&IF
->Lock
);
211 InsertTDIInterfaceEntity( IF
);
218 VOID
IPDestroyInterface(
221 * FUNCTION: Destroys an IP interface
223 * IF = Pointer to interface to destroy
226 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
229 RemoveTDIInterfaceEntity( IF
);
235 VOID
IPAddInterfaceRoute( PIP_INTERFACE IF
) {
236 PNEIGHBOR_CACHE_ENTRY NCE
;
237 IP_ADDRESS NetworkAddress
;
239 /* Add a permanent neighbor for this NTE */
240 NCE
= NBAddNeighbor(IF
, &IF
->Unicast
,
241 IF
->Address
, IF
->AddressLength
,
244 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
247 AddrWidenAddress( &NetworkAddress
, &IF
->Unicast
, &IF
->Netmask
);
249 if (!RouterAddRoute(&NetworkAddress
, &IF
->Netmask
, NCE
, 1)) {
250 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
253 /* Allow TCP to hang some configuration on this interface */
254 IF
->TCPContext
= TCPPrepareInterface( IF
);
257 BOOLEAN
IPRegisterInterface(
260 * FUNCTION: Registers an IP interface with IP layer
262 * IF = Pointer to interface to register
264 * TRUE if interface was successfully registered, FALSE if not
268 UINT ChosenIndex
= 1;
269 BOOLEAN IndexHasBeenChosen
;
270 IF_LIST_ITER(Interface
);
272 TI_DbgPrint(MID_TRACE
, ("Called. IF (0x%X).\n", IF
));
274 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
276 /* Choose an index */
278 IndexHasBeenChosen
= TRUE
;
279 ForEachInterface(Interface
) {
280 if( Interface
->Index
== ChosenIndex
) {
282 IndexHasBeenChosen
= FALSE
;
285 } while( !IndexHasBeenChosen
);
287 IF
->Index
= ChosenIndex
;
289 IPAddInterfaceRoute( IF
);
291 /* Add interface to the global interface list */
292 TcpipInterlockedInsertTailList(&InterfaceListHead
,
296 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
301 VOID
IPRemoveInterfaceRoute( PIP_INTERFACE IF
) {
302 PNEIGHBOR_CACHE_ENTRY NCE
;
303 IP_ADDRESS GeneralRoute
;
305 TCPDisposeInterfaceData( IF
->TCPContext
);
306 IF
->TCPContext
= NULL
;
308 TI_DbgPrint(DEBUG_IP
,("Removing interface Addr %s\n", A2S(&IF
->Unicast
)));
309 TI_DbgPrint(DEBUG_IP
,(" Mask %s\n", A2S(&IF
->Netmask
)));
311 AddrWidenAddress(&GeneralRoute
,&IF
->Unicast
,&IF
->Netmask
);
313 RouterRemoveRoute(&GeneralRoute
, &IF
->Unicast
);
315 /* Remove permanent NCE, but first we have to find it */
316 NCE
= NBLocateNeighbor(&IF
->Unicast
);
318 NBRemoveNeighbor(NCE
);
320 TI_DbgPrint(DEBUG_IP
, ("Could not delete IF route (0x%X)\n", IF
));
323 VOID
IPUnregisterInterface(
326 * FUNCTION: Unregisters an IP interface with IP layer
328 * IF = Pointer to interface to unregister
333 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
335 IPRemoveInterfaceRoute( IF
);
337 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
338 RemoveEntryList(&IF
->ListEntry
);
339 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
343 VOID
IPRegisterProtocol(
345 IP_PROTOCOL_HANDLER Handler
)
347 * FUNCTION: Registers a handler for an IP protocol number
349 * ProtocolNumber = Internet Protocol number for which to register handler
350 * Handler = Pointer to handler to be called when a packet is received
352 * To unregister a protocol handler, call this function with Handler = NULL
355 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
) {
356 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
360 ProtocolTable
[ProtocolNumber
] = Handler
;
364 VOID
DefaultProtocolHandler(
365 PIP_INTERFACE Interface
,
368 * FUNCTION: Default handler for Internet protocols
370 * NTE = Pointer to net table entry which the packet was received on
371 * IPPacket = Pointer to an IP packet that was received
374 TI_DbgPrint(MID_TRACE
, ("[IF %x] Packet of unknown Internet protocol "
375 "discarded.\n", Interface
));
379 NTSTATUS
IPStartup(PUNICODE_STRING RegistryPath
)
381 * FUNCTION: Initializes the IP subsystem
383 * RegistryPath = Our registry node for configuration parameters
385 * Status of operation
390 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
395 /* Initialize lookaside lists */
396 ExInitializeNPagedLookasideList(
397 &IPDRList
, /* Lookaside list */
398 NULL
, /* Allocate routine */
399 NULL
, /* Free routine */
401 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
402 TAG('I','P','D','R'), /* Tag */
405 ExInitializeNPagedLookasideList(
406 &IPPacketList
, /* Lookaside list */
407 NULL
, /* Allocate routine */
408 NULL
, /* Free routine */
410 sizeof(IP_PACKET
), /* Size of each entry */
411 TAG('I','P','P','K'), /* Tag */
414 ExInitializeNPagedLookasideList(
415 &IPFragmentList
, /* Lookaside list */
416 NULL
, /* Allocate routine */
417 NULL
, /* Free routine */
419 sizeof(IP_FRAGMENT
), /* Size of each entry */
420 TAG('I','P','F','G'), /* Tag */
423 ExInitializeNPagedLookasideList(
424 &IPHoleList
, /* Lookaside list */
425 NULL
, /* Allocate routine */
426 NULL
, /* Free routine */
428 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
429 TAG('I','P','H','L'), /* Tag */
432 /* Start routing subsystem */
435 /* Start neighbor cache subsystem */
438 /* Fill the protocol dispatch table with pointers
439 to the default protocol handler */
440 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
441 IPRegisterProtocol(i
, DefaultProtocolHandler
);
443 /* Initialize NTE list and protecting lock */
444 InitializeListHead(&NetTableListHead
);
445 TcpipInitializeSpinLock(&NetTableListLock
);
447 /* Initialize reassembly list and protecting lock */
448 InitializeListHead(&ReassemblyListHead
);
449 TcpipInitializeSpinLock(&ReassemblyListLock
);
451 IPInitialized
= TRUE
;
453 return STATUS_SUCCESS
;
460 * FUNCTION: Shuts down the IP subsystem
462 * Status of operation
465 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
468 return STATUS_SUCCESS
;
470 /* Shutdown neighbor cache subsystem */
473 /* Shutdown routing subsystem */
476 IPFreeReassemblyList();
478 /* Destroy lookaside lists */
479 ExDeleteNPagedLookasideList(&IPHoleList
);
480 ExDeleteNPagedLookasideList(&IPDRList
);
481 ExDeleteNPagedLookasideList(&IPPacketList
);
482 ExDeleteNPagedLookasideList(&IPFragmentList
);
484 IPInitialized
= FALSE
;
486 return STATUS_SUCCESS
;