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
13 #define __LWIP_INET_H__
14 #include "lwip/netifapi.h"
17 LIST_ENTRY InterfaceListHead
;
18 KSPIN_LOCK InterfaceListLock
;
19 LIST_ENTRY NetTableListHead
;
20 KSPIN_LOCK NetTableListLock
;
21 BOOLEAN IPInitialized
= FALSE
;
22 BOOLEAN IpWorkItemQueued
= FALSE
;
23 /* Work around calling timer at Dpc level */
25 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
28 TCPRegisterInterface(PIP_INTERFACE IF
);
31 TCPUnregisterInterface(PIP_INTERFACE IF
);
33 VOID
DeinitializePacket(
36 * FUNCTION: Frees buffers attached to the packet
38 * Object = Pointer to an IP packet structure
41 PIP_PACKET IPPacket
= Object
;
43 TI_DbgPrint(MAX_TRACE
, ("Freeing object: 0x%p\n", Object
));
45 /* Detect double free */
46 ASSERT(IPPacket
->Type
!= 0xFF);
47 IPPacket
->Type
= 0xFF;
49 /* Check if there's a packet to free */
50 if (IPPacket
->NdisPacket
!= NULL
)
52 if (IPPacket
->ReturnPacket
)
54 /* Return the packet to the miniport driver */
55 TI_DbgPrint(MAX_TRACE
, ("Returning packet 0x%p\n",
56 IPPacket
->NdisPacket
));
57 NdisReturnPackets(&IPPacket
->NdisPacket
, 1);
61 /* Free it the conventional way */
62 TI_DbgPrint(MAX_TRACE
, ("Freeing packet 0x%p\n",
63 IPPacket
->NdisPacket
));
64 FreeNdisPacket(IPPacket
->NdisPacket
);
68 /* Check if we have a pool-allocated header */
69 if (!IPPacket
->MappedHeader
&& IPPacket
->Header
)
72 TI_DbgPrint(MAX_TRACE
, ("Freeing header: 0x%p\n",
74 ExFreePoolWithTag(IPPacket
->Header
,
82 * FUNCTION: Frees an interface object
84 * Object = Pointer to an interface structure
87 ExFreePoolWithTag(Object
, IP_INTERFACE_TAG
);
90 PIP_PACKET
IPInitializePacket(
94 * FUNCTION: Creates an IP packet object
96 * Type = Type of IP packet
98 * Pointer to the created IP packet. NULL if there was not enough free resources.
101 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
103 IPPacket
->Free
= DeinitializePacket
;
104 IPPacket
->Type
= Type
;
110 VOID NTAPI
IPTimeoutDpcFn(PKDPC Dpc
,
111 PVOID DeferredContext
,
112 PVOID SystemArgument1
,
113 PVOID SystemArgument2
)
115 * FUNCTION: Timeout DPC
117 * Dpc = Pointer to our DPC object
118 * DeferredContext = Pointer to context information (unused)
119 * SystemArgument1 = Unused
120 * SystemArgument2 = Unused
122 * This routine is dispatched once in a while to do maintainance jobs
125 /* Check if datagram fragments have taken too long to assemble */
126 IPDatagramReassemblyTimeout();
128 /* Clean possible outdated cached neighbor addresses */
133 VOID
IPDispatchProtocol(
134 PIP_INTERFACE Interface
,
137 * FUNCTION: IP protocol dispatcher
139 * NTE = Pointer to net table entry which the packet was received on
140 * IPPacket = Pointer to an IP packet that was received
142 * This routine examines the IP header and passes the packet on to the
143 * right upper level protocol receive handler
147 IP_ADDRESS SrcAddress
;
149 switch (IPPacket
->Type
) {
151 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
152 AddrInitIPv4(&SrcAddress
, ((PIPv4_HEADER
)(IPPacket
->Header
))->SrcAddr
);
155 /* FIXME: IPv6 adresses not supported */
156 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
159 TI_DbgPrint(MIN_TRACE
, ("Unrecognized datagram discarded.\n"));
163 NBResetNeighborTimeout(&SrcAddress
);
165 if (Protocol
< IP_PROTOCOL_TABLE_SIZE
)
167 /* Call the appropriate protocol handler */
168 (*ProtocolTable
[Protocol
])(Interface
, IPPacket
);
173 PIP_INTERFACE
IPCreateInterface(
174 PLLIP_BIND_INFO BindInfo
)
176 * FUNCTION: Creates an IP interface
178 * BindInfo = Pointer to link layer to IP binding information
180 * Pointer to IP_INTERFACE structure, NULL if there was
181 * not enough free resources
186 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
189 if (BindInfo
->Address
) {
190 PUCHAR A
= BindInfo
->Address
;
191 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
192 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
196 IF
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IP_INTERFACE
),
199 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
203 RtlZeroMemory(IF
, sizeof(IP_INTERFACE
));
206 IF
->Context
= BindInfo
->Context
;
207 IF
->HeaderSize
= BindInfo
->HeaderSize
;
208 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
209 IF
->Address
= BindInfo
->Address
;
210 IF
->AddressLength
= BindInfo
->AddressLength
;
211 IF
->Transmit
= BindInfo
->Transmit
;
213 IF
->Unicast
.Type
= IP_ADDRESS_V4
;
214 IF
->PointToPoint
.Type
= IP_ADDRESS_V4
;
215 IF
->Netmask
.Type
= IP_ADDRESS_V4
;
216 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
218 TcpipInitializeSpinLock(&IF
->Lock
);
220 IF
->TCPContext
= ExAllocatePool
221 ( NonPagedPool
, sizeof(struct netif
));
222 if (!IF
->TCPContext
) {
223 ExFreePoolWithTag(IF
, IP_INTERFACE_TAG
);
227 TCPRegisterInterface(IF
);
230 InsertTDIInterfaceEntity( IF
);
237 VOID
IPDestroyInterface(
240 * FUNCTION: Destroys an IP interface
242 * IF = Pointer to interface to destroy
245 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
248 RemoveTDIInterfaceEntity( IF
);
251 TCPUnregisterInterface(IF
);
253 ExFreePool(IF
->TCPContext
);
254 ExFreePoolWithTag(IF
, IP_INTERFACE_TAG
);
257 VOID
IPAddInterfaceRoute( PIP_INTERFACE IF
) {
258 PNEIGHBOR_CACHE_ENTRY NCE
;
259 IP_ADDRESS NetworkAddress
;
261 /* Add a permanent neighbor for this NTE */
262 NCE
= NBAddNeighbor(IF
, &IF
->Unicast
,
263 IF
->Address
, IF
->AddressLength
,
266 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
270 AddrWidenAddress( &NetworkAddress
, &IF
->Unicast
, &IF
->Netmask
);
272 if (!RouterAddRoute(&NetworkAddress
, &IF
->Netmask
, NCE
, 1)) {
273 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
276 /* Send a gratuitous ARP packet to update the route caches of
279 ARPTransmit(NULL
, NULL
, IF
);
281 TCPUpdateInterfaceIPInformation(IF
);
284 BOOLEAN
IPRegisterInterface(
287 * FUNCTION: Registers an IP interface with IP layer
289 * IF = Pointer to interface to register
291 * TRUE if interface was successfully registered, FALSE if not
295 UINT ChosenIndex
= 0;
296 BOOLEAN IndexHasBeenChosen
;
297 IF_LIST_ITER(Interface
);
299 TI_DbgPrint(MID_TRACE
, ("Called. IF (0x%X).\n", IF
));
301 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
303 /* Choose an index */
305 IndexHasBeenChosen
= TRUE
;
306 ForEachInterface(Interface
) {
307 if( Interface
->Index
== ChosenIndex
) {
309 IndexHasBeenChosen
= FALSE
;
312 } while( !IndexHasBeenChosen
);
314 IF
->Index
= ChosenIndex
;
316 /* Add interface to the global interface list */
317 TcpipInterlockedInsertTailList(&InterfaceListHead
,
321 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
326 VOID
IPRemoveInterfaceRoute( PIP_INTERFACE IF
) {
327 PNEIGHBOR_CACHE_ENTRY NCE
;
328 IP_ADDRESS GeneralRoute
;
330 NCE
= NBLocateNeighbor(&IF
->Unicast
);
333 TI_DbgPrint(DEBUG_IP
,("Removing interface Addr %s\n", A2S(&IF
->Unicast
)));
334 TI_DbgPrint(DEBUG_IP
,(" Mask %s\n", A2S(&IF
->Netmask
)));
336 AddrWidenAddress(&GeneralRoute
,&IF
->Unicast
,&IF
->Netmask
);
338 RouterRemoveRoute(&GeneralRoute
, &IF
->Unicast
);
340 NBRemoveNeighbor(NCE
);
344 VOID
IPUnregisterInterface(
347 * FUNCTION: Unregisters an IP interface with IP layer
349 * IF = Pointer to interface to unregister
354 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
356 IPRemoveInterfaceRoute( IF
);
358 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
359 RemoveEntryList(&IF
->ListEntry
);
360 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
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
));
377 Interface
->Stats
.InDiscardedUnknownProto
++;
381 VOID
IPRegisterProtocol(
383 IP_PROTOCOL_HANDLER Handler
)
385 * FUNCTION: Registers a handler for an IP protocol number
387 * ProtocolNumber = Internet Protocol number for which to register handler
388 * Handler = Pointer to handler to be called when a packet is received
390 * To unregister a protocol handler, call this function with Handler = NULL
393 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
) {
394 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
398 ProtocolTable
[ProtocolNumber
] = Handler
? Handler
: DefaultProtocolHandler
;
402 NTSTATUS
IPStartup(PUNICODE_STRING RegistryPath
)
404 * FUNCTION: Initializes the IP subsystem
406 * RegistryPath = Our registry node for configuration parameters
408 * Status of operation
413 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
415 /* Initialize lookaside lists */
416 ExInitializeNPagedLookasideList(
417 &IPDRList
, /* Lookaside list */
418 NULL
, /* Allocate routine */
419 NULL
, /* Free routine */
421 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
422 DATAGRAM_REASSEMBLY_TAG
, /* Tag */
425 ExInitializeNPagedLookasideList(
426 &IPFragmentList
, /* Lookaside list */
427 NULL
, /* Allocate routine */
428 NULL
, /* Free routine */
430 sizeof(IP_FRAGMENT
), /* Size of each entry */
431 DATAGRAM_FRAGMENT_TAG
, /* Tag */
434 ExInitializeNPagedLookasideList(
435 &IPHoleList
, /* Lookaside list */
436 NULL
, /* Allocate routine */
437 NULL
, /* Free routine */
439 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
440 DATAGRAM_HOLE_TAG
, /* Tag */
443 /* Start routing subsystem */
446 /* Start neighbor cache subsystem */
449 /* Fill the protocol dispatch table with pointers
450 to the default protocol handler */
451 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
452 IPRegisterProtocol(i
, DefaultProtocolHandler
);
454 /* Initialize NTE list and protecting lock */
455 InitializeListHead(&NetTableListHead
);
456 TcpipInitializeSpinLock(&NetTableListLock
);
458 /* Initialize reassembly list and protecting lock */
459 InitializeListHead(&ReassemblyListHead
);
460 TcpipInitializeSpinLock(&ReassemblyListLock
);
462 IPInitialized
= TRUE
;
464 return STATUS_SUCCESS
;
471 * FUNCTION: Shuts down the IP subsystem
473 * Status of operation
476 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
479 return STATUS_SUCCESS
;
481 /* Shutdown neighbor cache subsystem */
484 /* Shutdown routing subsystem */
487 IPFreeReassemblyList();
489 /* Destroy lookaside lists */
490 ExDeleteNPagedLookasideList(&IPHoleList
);
491 ExDeleteNPagedLookasideList(&IPDRList
);
492 ExDeleteNPagedLookasideList(&IPFragmentList
);
494 IPInitialized
= FALSE
;
496 return STATUS_SUCCESS
;