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 BOOLEAN IPInitialized
= FALSE
;
19 BOOLEAN IpWorkItemQueued
= FALSE
;
20 /* Work around calling timer at Dpc level */
22 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
27 * FUNCTION: Do nothing for when the IPPacket struct is part of another
29 * Object = Pointer to an IP packet structure
37 * FUNCTION: Frees an interface object
39 * Object = Pointer to an interface structure
45 PIP_PACKET
IPInitializePacket(
49 * FUNCTION: Creates an IP packet object
51 * Type = Type of IP packet
53 * Pointer to the created IP packet. NULL if there was not enough free resources.
56 /* FIXME: Is this needed? */
57 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
59 INIT_TAG(IPPacket
, 'TKPI');
61 IPPacket
->Free
= DontFreePacket
;
62 IPPacket
->Type
= Type
;
68 void NTAPI
IPTimeout( PVOID Context
) {
69 IpWorkItemQueued
= FALSE
;
71 /* Check if datagram fragments have taken too long to assemble */
72 IPDatagramReassemblyTimeout();
74 /* Clean possible outdated cached neighbor addresses */
77 /* Call upper layer timeout routines */
82 VOID
IPDispatchProtocol(
83 PIP_INTERFACE Interface
,
86 * FUNCTION: IP protocol dispatcher
88 * NTE = Pointer to net table entry which the packet was received on
89 * IPPacket = Pointer to an IP packet that was received
91 * This routine examines the IP header and passes the packet on to the
92 * right upper level protocol receive handler
97 switch (IPPacket
->Type
) {
99 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
102 /* FIXME: IPv6 adresses not supported */
103 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
106 TI_DbgPrint(MIN_TRACE
, ("Unrecognized datagram discarded.\n"));
110 if (Protocol
< IP_PROTOCOL_TABLE_SIZE
)
112 /* Call the appropriate protocol handler */
113 (*ProtocolTable
[Protocol
])(Interface
, IPPacket
);
118 PIP_INTERFACE
IPCreateInterface(
119 PLLIP_BIND_INFO BindInfo
)
121 * FUNCTION: Creates an IP interface
123 * BindInfo = Pointer to link layer to IP binding information
125 * Pointer to IP_INTERFACE structure, NULL if there was
126 * not enough free resources
131 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
134 if (BindInfo
->Address
) {
135 PUCHAR A
= BindInfo
->Address
;
136 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
137 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
141 IF
= exAllocatePool(NonPagedPool
, sizeof(IP_INTERFACE
));
143 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
147 INIT_TAG(IF
, 'ECAF');
149 RtlZeroMemory(IF
, sizeof(IP_INTERFACE
));
152 IF
->Context
= BindInfo
->Context
;
153 IF
->HeaderSize
= BindInfo
->HeaderSize
;
154 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
155 IF
->MTU
= BindInfo
->MTU
;
156 IF
->Address
= BindInfo
->Address
;
157 IF
->AddressLength
= BindInfo
->AddressLength
;
158 IF
->Transmit
= BindInfo
->Transmit
;
160 IF
->Unicast
.Type
= IP_ADDRESS_V4
;
161 IF
->PointToPoint
.Type
= IP_ADDRESS_V4
;
162 IF
->Netmask
.Type
= IP_ADDRESS_V4
;
163 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
165 TcpipInitializeSpinLock(&IF
->Lock
);
167 IF
->TCPContext
= exAllocatePool
168 ( NonPagedPool
, sizeof(OSK_IFADDR
) + 2 * sizeof( struct sockaddr_in
) );
169 if (!IF
->TCPContext
) {
175 InsertTDIInterfaceEntity( IF
);
182 VOID
IPDestroyInterface(
185 * FUNCTION: Destroys an IP interface
187 * IF = Pointer to interface to destroy
190 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
193 RemoveTDIInterfaceEntity( IF
);
196 exFreePool(IF
->TCPContext
);
200 VOID
IPAddInterfaceRoute( PIP_INTERFACE IF
) {
201 PNEIGHBOR_CACHE_ENTRY NCE
;
202 IP_ADDRESS NetworkAddress
;
204 /* Add a permanent neighbor for this NTE */
205 NCE
= NBAddNeighbor(IF
, &IF
->Unicast
,
206 IF
->Address
, IF
->AddressLength
,
209 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
213 AddrWidenAddress( &NetworkAddress
, &IF
->Unicast
, &IF
->Netmask
);
215 if (!RouterAddRoute(&NetworkAddress
, &IF
->Netmask
, NCE
, 1)) {
216 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
219 /* Send a gratuitous ARP packet to update the route caches of
222 ARPTransmit(NULL
, IF
);
225 BOOLEAN
IPRegisterInterface(
228 * FUNCTION: Registers an IP interface with IP layer
230 * IF = Pointer to interface to register
232 * TRUE if interface was successfully registered, FALSE if not
236 UINT ChosenIndex
= 0;
237 BOOLEAN IndexHasBeenChosen
;
238 IF_LIST_ITER(Interface
);
240 TI_DbgPrint(MID_TRACE
, ("Called. IF (0x%X).\n", IF
));
242 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
244 /* Choose an index */
246 IndexHasBeenChosen
= TRUE
;
247 ForEachInterface(Interface
) {
248 if( Interface
->Index
== ChosenIndex
) {
250 IndexHasBeenChosen
= FALSE
;
253 } while( !IndexHasBeenChosen
);
255 IF
->Index
= ChosenIndex
;
257 /* Add interface to the global interface list */
258 TcpipInterlockedInsertTailList(&InterfaceListHead
,
262 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
267 VOID
IPRemoveInterfaceRoute( PIP_INTERFACE IF
) {
268 PNEIGHBOR_CACHE_ENTRY NCE
;
269 IP_ADDRESS GeneralRoute
;
271 NCE
= NBLocateNeighbor(&IF
->Unicast
);
274 TI_DbgPrint(DEBUG_IP
,("Removing interface Addr %s\n", A2S(&IF
->Unicast
)));
275 TI_DbgPrint(DEBUG_IP
,(" Mask %s\n", A2S(&IF
->Netmask
)));
277 AddrWidenAddress(&GeneralRoute
,&IF
->Unicast
,&IF
->Netmask
);
279 RouterRemoveRoute(&GeneralRoute
, &IF
->Unicast
);
281 NBRemoveNeighbor(NCE
);
285 VOID
IPUnregisterInterface(
288 * FUNCTION: Unregisters an IP interface with IP layer
290 * IF = Pointer to interface to unregister
295 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
297 IPRemoveInterfaceRoute( IF
);
299 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
300 RemoveEntryList(&IF
->ListEntry
);
301 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
305 VOID
DefaultProtocolHandler(
306 PIP_INTERFACE Interface
,
309 * FUNCTION: Default handler for Internet protocols
311 * NTE = Pointer to net table entry which the packet was received on
312 * IPPacket = Pointer to an IP packet that was received
315 TI_DbgPrint(MID_TRACE
, ("[IF %x] Packet of unknown Internet protocol "
316 "discarded.\n", Interface
));
318 Interface
->Stats
.InDiscardedUnknownProto
++;
322 VOID
IPRegisterProtocol(
324 IP_PROTOCOL_HANDLER Handler
)
326 * FUNCTION: Registers a handler for an IP protocol number
328 * ProtocolNumber = Internet Protocol number for which to register handler
329 * Handler = Pointer to handler to be called when a packet is received
331 * To unregister a protocol handler, call this function with Handler = NULL
334 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
) {
335 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
339 ProtocolTable
[ProtocolNumber
] = Handler
? Handler
: DefaultProtocolHandler
;
343 NTSTATUS
IPStartup(PUNICODE_STRING RegistryPath
)
345 * FUNCTION: Initializes the IP subsystem
347 * RegistryPath = Our registry node for configuration parameters
349 * Status of operation
354 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
356 /* Initialize lookaside lists */
357 ExInitializeNPagedLookasideList(
358 &IPDRList
, /* Lookaside list */
359 NULL
, /* Allocate routine */
360 NULL
, /* Free routine */
362 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
366 ExInitializeNPagedLookasideList(
367 &IPFragmentList
, /* Lookaside list */
368 NULL
, /* Allocate routine */
369 NULL
, /* Free routine */
371 sizeof(IP_FRAGMENT
), /* Size of each entry */
375 ExInitializeNPagedLookasideList(
376 &IPHoleList
, /* Lookaside list */
377 NULL
, /* Allocate routine */
378 NULL
, /* Free routine */
380 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
384 /* Start routing subsystem */
387 /* Start neighbor cache subsystem */
390 /* Fill the protocol dispatch table with pointers
391 to the default protocol handler */
392 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
393 IPRegisterProtocol(i
, DefaultProtocolHandler
);
395 /* Initialize NTE list and protecting lock */
396 InitializeListHead(&NetTableListHead
);
397 TcpipInitializeSpinLock(&NetTableListLock
);
399 /* Initialize reassembly list and protecting lock */
400 InitializeListHead(&ReassemblyListHead
);
401 TcpipInitializeSpinLock(&ReassemblyListLock
);
403 IPInitialized
= TRUE
;
405 return STATUS_SUCCESS
;
412 * FUNCTION: Shuts down the IP subsystem
414 * Status of operation
417 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
420 return STATUS_SUCCESS
;
422 /* Shutdown neighbor cache subsystem */
425 /* Shutdown routing subsystem */
428 IPFreeReassemblyList();
430 /* Destroy lookaside lists */
431 ExDeleteNPagedLookasideList(&IPHoleList
);
432 ExDeleteNPagedLookasideList(&IPDRList
);
433 ExDeleteNPagedLookasideList(&IPFragmentList
);
435 IPInitialized
= FALSE
;
437 return STATUS_SUCCESS
;