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 /* Work around calling timer at Dpc level */
24 IP_PROTOCOL_HANDLER ProtocolTable
[IP_PROTOCOL_TABLE_SIZE
];
29 * FUNCTION: Do nothing for when the IPPacket struct is part of another
31 * Object = Pointer to an IP packet structure
39 * FUNCTION: Frees an interface object
41 * Object = Pointer to an interface structure
47 PIP_PACKET
IPInitializePacket(
51 * FUNCTION: Creates an IP packet object
53 * Type = Type of IP packet
55 * Pointer to the created IP packet. NULL if there was not enough free resources.
58 /* FIXME: Is this needed? */
59 RtlZeroMemory(IPPacket
, sizeof(IP_PACKET
));
61 INIT_TAG(IPPacket
, 'TKPI');
63 IPPacket
->Free
= DontFreePacket
;
64 IPPacket
->Type
= Type
;
70 void NTAPI
IPTimeout( PVOID Context
) {
71 IpWorkItemQueued
= FALSE
;
73 /* Check if datagram fragments have taken too long to assemble */
74 IPDatagramReassemblyTimeout();
76 /* Clean possible outdated cached neighbor addresses */
79 /* Call upper layer timeout routines */
84 VOID
IPDispatchProtocol(
85 PIP_INTERFACE Interface
,
88 * FUNCTION: IP protocol dispatcher
90 * NTE = Pointer to net table entry which the packet was received on
91 * IPPacket = Pointer to an IP packet that was received
93 * This routine examines the IP header and passes the packet on to the
94 * right upper level protocol receive handler
99 switch (IPPacket
->Type
) {
101 Protocol
= ((PIPv4_HEADER
)(IPPacket
->Header
))->Protocol
;
104 /* FIXME: IPv6 adresses not supported */
105 TI_DbgPrint(MIN_TRACE
, ("IPv6 datagram discarded.\n"));
108 TI_DbgPrint(MIN_TRACE
, ("Unrecognized datagram discarded.\n"));
112 if (Protocol
< IP_PROTOCOL_TABLE_SIZE
)
114 /* Call the appropriate protocol handler */
115 (*ProtocolTable
[Protocol
])(Interface
, IPPacket
);
120 PIP_INTERFACE
IPCreateInterface(
121 PLLIP_BIND_INFO BindInfo
)
123 * FUNCTION: Creates an IP interface
125 * BindInfo = Pointer to link layer to IP binding information
127 * Pointer to IP_INTERFACE structure, NULL if there was
128 * not enough free resources
133 TI_DbgPrint(DEBUG_IP
, ("Called. BindInfo (0x%X).\n", BindInfo
));
136 if (BindInfo
->Address
) {
137 PUCHAR A
= BindInfo
->Address
;
138 TI_DbgPrint(DEBUG_IP
, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
139 A
[0], A
[1], A
[2], A
[3], A
[4], A
[5]));
143 IF
= exAllocatePool(NonPagedPool
, sizeof(IP_INTERFACE
));
145 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
149 INIT_TAG(IF
, 'ECAF');
151 RtlZeroMemory(IF
, sizeof(IP_INTERFACE
));
154 IF
->Context
= BindInfo
->Context
;
155 IF
->HeaderSize
= BindInfo
->HeaderSize
;
156 if (IF
->HeaderSize
> MaxLLHeaderSize
)
157 MaxLLHeaderSize
= IF
->HeaderSize
;
159 IF
->MinFrameSize
= BindInfo
->MinFrameSize
;
160 if (IF
->MinFrameSize
> MinLLFrameSize
)
161 MinLLFrameSize
= IF
->MinFrameSize
;
163 IF
->MTU
= BindInfo
->MTU
;
164 IF
->Address
= BindInfo
->Address
;
165 IF
->AddressLength
= BindInfo
->AddressLength
;
166 IF
->Transmit
= BindInfo
->Transmit
;
168 IF
->Unicast
.Type
= IP_ADDRESS_V4
;
169 IF
->PointToPoint
.Type
= IP_ADDRESS_V4
;
170 IF
->Netmask
.Type
= IP_ADDRESS_V4
;
171 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
173 TcpipInitializeSpinLock(&IF
->Lock
);
175 IF
->TCPContext
= exAllocatePool
176 ( NonPagedPool
, sizeof(OSK_IFADDR
) + 2 * sizeof( struct sockaddr_in
) );
177 if (!IF
->TCPContext
) {
183 InsertTDIInterfaceEntity( IF
);
190 VOID
IPDestroyInterface(
193 * FUNCTION: Destroys an IP interface
195 * IF = Pointer to interface to destroy
198 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
201 RemoveTDIInterfaceEntity( IF
);
204 exFreePool(IF
->TCPContext
);
208 VOID
IPAddInterfaceRoute( PIP_INTERFACE IF
) {
209 PNEIGHBOR_CACHE_ENTRY NCE
;
210 IP_ADDRESS NetworkAddress
;
212 /* Add a permanent neighbor for this NTE */
213 NCE
= NBAddNeighbor(IF
, &IF
->Unicast
,
214 IF
->Address
, IF
->AddressLength
,
217 TI_DbgPrint(MIN_TRACE
, ("Could not create NCE.\n"));
221 AddrWidenAddress( &NetworkAddress
, &IF
->Unicast
, &IF
->Netmask
);
223 if (!RouterAddRoute(&NetworkAddress
, &IF
->Netmask
, NCE
, 1)) {
224 TI_DbgPrint(MIN_TRACE
, ("Could not add route due to insufficient resources.\n"));
227 /* Send a gratuitous ARP packet to update the route caches of
230 ARPTransmit(NULL
, IF
);
233 BOOLEAN
IPRegisterInterface(
236 * FUNCTION: Registers an IP interface with IP layer
238 * IF = Pointer to interface to register
240 * TRUE if interface was successfully registered, FALSE if not
244 UINT ChosenIndex
= 0;
245 BOOLEAN IndexHasBeenChosen
;
246 IF_LIST_ITER(Interface
);
248 TI_DbgPrint(MID_TRACE
, ("Called. IF (0x%X).\n", IF
));
250 TcpipAcquireSpinLock(&IF
->Lock
, &OldIrql
);
252 /* Choose an index */
254 IndexHasBeenChosen
= TRUE
;
255 ForEachInterface(Interface
) {
256 if( Interface
->Index
== ChosenIndex
) {
258 IndexHasBeenChosen
= FALSE
;
261 } while( !IndexHasBeenChosen
);
263 IF
->Index
= ChosenIndex
;
265 /* Add interface to the global interface list */
266 TcpipInterlockedInsertTailList(&InterfaceListHead
,
270 TcpipReleaseSpinLock(&IF
->Lock
, OldIrql
);
275 VOID
IPRemoveInterfaceRoute( PIP_INTERFACE IF
) {
276 PNEIGHBOR_CACHE_ENTRY NCE
;
277 IP_ADDRESS GeneralRoute
;
279 NCE
= NBLocateNeighbor(&IF
->Unicast
);
282 TI_DbgPrint(DEBUG_IP
,("Removing interface Addr %s\n", A2S(&IF
->Unicast
)));
283 TI_DbgPrint(DEBUG_IP
,(" Mask %s\n", A2S(&IF
->Netmask
)));
285 AddrWidenAddress(&GeneralRoute
,&IF
->Unicast
,&IF
->Netmask
);
287 RouterRemoveRoute(&GeneralRoute
, &IF
->Unicast
);
289 NBRemoveNeighbor(NCE
);
293 VOID
IPUnregisterInterface(
296 * FUNCTION: Unregisters an IP interface with IP layer
298 * IF = Pointer to interface to unregister
303 TI_DbgPrint(DEBUG_IP
, ("Called. IF (0x%X).\n", IF
));
305 IPRemoveInterfaceRoute( IF
);
307 TcpipAcquireSpinLock(&InterfaceListLock
, &OldIrql3
);
308 RemoveEntryList(&IF
->ListEntry
);
309 TcpipReleaseSpinLock(&InterfaceListLock
, OldIrql3
);
313 VOID
DefaultProtocolHandler(
314 PIP_INTERFACE Interface
,
317 * FUNCTION: Default handler for Internet protocols
319 * NTE = Pointer to net table entry which the packet was received on
320 * IPPacket = Pointer to an IP packet that was received
323 TI_DbgPrint(MID_TRACE
, ("[IF %x] Packet of unknown Internet protocol "
324 "discarded.\n", Interface
));
326 Interface
->Stats
.InDiscardedUnknownProto
++;
330 VOID
IPRegisterProtocol(
332 IP_PROTOCOL_HANDLER Handler
)
334 * FUNCTION: Registers a handler for an IP protocol number
336 * ProtocolNumber = Internet Protocol number for which to register handler
337 * Handler = Pointer to handler to be called when a packet is received
339 * To unregister a protocol handler, call this function with Handler = NULL
342 if (ProtocolNumber
>= IP_PROTOCOL_TABLE_SIZE
) {
343 TI_DbgPrint(MIN_TRACE
, ("Protocol number is out of range (%d).\n", ProtocolNumber
));
347 ProtocolTable
[ProtocolNumber
] = Handler
? Handler
: DefaultProtocolHandler
;
351 NTSTATUS
IPStartup(PUNICODE_STRING RegistryPath
)
353 * FUNCTION: Initializes the IP subsystem
355 * RegistryPath = Our registry node for configuration parameters
357 * Status of operation
362 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
367 /* Initialize lookaside lists */
368 ExInitializeNPagedLookasideList(
369 &IPDRList
, /* Lookaside list */
370 NULL
, /* Allocate routine */
371 NULL
, /* Free routine */
373 sizeof(IPDATAGRAM_REASSEMBLY
), /* Size of each entry */
377 ExInitializeNPagedLookasideList(
378 &IPFragmentList
, /* Lookaside list */
379 NULL
, /* Allocate routine */
380 NULL
, /* Free routine */
382 sizeof(IP_FRAGMENT
), /* Size of each entry */
386 ExInitializeNPagedLookasideList(
387 &IPHoleList
, /* Lookaside list */
388 NULL
, /* Allocate routine */
389 NULL
, /* Free routine */
391 sizeof(IPDATAGRAM_HOLE
), /* Size of each entry */
395 /* Start routing subsystem */
398 /* Start neighbor cache subsystem */
401 /* Fill the protocol dispatch table with pointers
402 to the default protocol handler */
403 for (i
= 0; i
< IP_PROTOCOL_TABLE_SIZE
; i
++)
404 IPRegisterProtocol(i
, DefaultProtocolHandler
);
406 /* Initialize NTE list and protecting lock */
407 InitializeListHead(&NetTableListHead
);
408 TcpipInitializeSpinLock(&NetTableListLock
);
410 /* Initialize reassembly list and protecting lock */
411 InitializeListHead(&ReassemblyListHead
);
412 TcpipInitializeSpinLock(&ReassemblyListLock
);
414 IPInitialized
= TRUE
;
416 return STATUS_SUCCESS
;
423 * FUNCTION: Shuts down the IP subsystem
425 * Status of operation
428 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
431 return STATUS_SUCCESS
;
433 /* Shutdown neighbor cache subsystem */
436 /* Shutdown routing subsystem */
439 IPFreeReassemblyList();
441 /* Destroy lookaside lists */
442 ExDeleteNPagedLookasideList(&IPHoleList
);
443 ExDeleteNPagedLookasideList(&IPDRList
);
444 ExDeleteNPagedLookasideList(&IPFragmentList
);
446 IPInitialized
= FALSE
;
448 return STATUS_SUCCESS
;