xref: /reactos/drivers/network/tcpip/ip/network/ip.c (revision ffb20d33)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        network/ip.c
5  * PURPOSE:     Internet Protocol module
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 
11 #include "precomp.h"
12 
13 #define __LWIP_INET_H__
14 #include "lwip/netifapi.h"
15 
16 
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 */
24 
25 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
26 
27 ULONG IpTimerExpirations;
28 
29 VOID
30 TCPRegisterInterface(PIP_INTERFACE IF);
31 
32 VOID
33 TCPUnregisterInterface(PIP_INTERFACE IF);
34 
DeinitializePacket(PVOID Object)35 VOID DeinitializePacket(
36     PVOID Object)
37 /*
38  * FUNCTION: Frees buffers attached to the packet
39  * ARGUMENTS:
40  *     Object = Pointer to an IP packet structure
41  */
42 {
43     PIP_PACKET IPPacket = Object;
44 
45     TI_DbgPrint(MAX_TRACE, ("Freeing object: 0x%p\n", Object));
46 
47     /* Detect double free */
48     ASSERT(IPPacket->Type != 0xFF);
49     IPPacket->Type = 0xFF;
50 
51     /* Check if there's a packet to free */
52     if (IPPacket->NdisPacket != NULL)
53     {
54         if (IPPacket->ReturnPacket)
55         {
56             /* Return the packet to the miniport driver */
57             TI_DbgPrint(MAX_TRACE, ("Returning packet 0x%p\n",
58                                     IPPacket->NdisPacket));
59             NdisReturnPackets(&IPPacket->NdisPacket, 1);
60         }
61         else
62         {
63             /* Free it the conventional way */
64             TI_DbgPrint(MAX_TRACE, ("Freeing packet 0x%p\n",
65                                     IPPacket->NdisPacket));
66             FreeNdisPacket(IPPacket->NdisPacket);
67         }
68     }
69 
70     /* Check if we have a pool-allocated header */
71     if (!IPPacket->MappedHeader && IPPacket->Header)
72     {
73         /* Free it */
74         TI_DbgPrint(MAX_TRACE, ("Freeing header: 0x%p\n",
75                                 IPPacket->Header));
76         ExFreePoolWithTag(IPPacket->Header,
77                           PACKET_BUFFER_TAG);
78     }
79 }
80 
FreeIF(PVOID Object)81 VOID FreeIF(
82     PVOID Object)
83 /*
84  * FUNCTION: Frees an interface object
85  * ARGUMENTS:
86  *     Object = Pointer to an interface structure
87  */
88 {
89     ExFreePoolWithTag(Object, IP_INTERFACE_TAG);
90 }
91 
IPInitializePacket(PIP_PACKET IPPacket,ULONG Type)92 PIP_PACKET IPInitializePacket(
93     PIP_PACKET IPPacket,
94     ULONG Type)
95 /*
96  * FUNCTION: Creates an IP packet object
97  * ARGUMENTS:
98  *     Type = Type of IP packet
99  * RETURNS:
100  *     Pointer to the created IP packet. NULL if there was not enough free resources.
101  */
102 {
103     RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
104 
105     IPPacket->Free     = DeinitializePacket;
106     IPPacket->Type     = Type;
107 
108     return IPPacket;
109 }
110 
111 
IPTimeoutDpcFn(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)112 VOID NTAPI IPTimeoutDpcFn(PKDPC Dpc,
113                           PVOID DeferredContext,
114                           PVOID SystemArgument1,
115                           PVOID SystemArgument2)
116 /*
117  * FUNCTION: Timeout DPC
118  * ARGUMENTS:
119  *     Dpc             = Pointer to our DPC object
120  *     DeferredContext = Pointer to context information (unused)
121  *     SystemArgument1 = Unused
122  *     SystemArgument2 = Unused
123  * NOTES:
124  *     This routine is dispatched once in a while to do maintenance jobs
125  */
126 {
127     IpTimerExpirations++;
128 
129     if ((IpTimerExpirations % 10) == 0)
130     {
131         LogActiveObjects();
132     }
133 
134     /* Check if datagram fragments have taken too long to assemble */
135     IPDatagramReassemblyTimeout();
136 
137     /* Clean possible outdated cached neighbor addresses */
138     NBTimeout();
139 }
140 
141 
IPDispatchProtocol(PIP_INTERFACE Interface,PIP_PACKET IPPacket)142 VOID IPDispatchProtocol(
143     PIP_INTERFACE Interface,
144     PIP_PACKET IPPacket)
145 /*
146  * FUNCTION: IP protocol dispatcher
147  * ARGUMENTS:
148  *     NTE      = Pointer to net table entry which the packet was received on
149  *     IPPacket = Pointer to an IP packet that was received
150  * NOTES:
151  *     This routine examines the IP header and passes the packet on to the
152  *     right upper level protocol receive handler
153  */
154 {
155     UINT Protocol;
156     IP_ADDRESS SrcAddress;
157 
158     switch (IPPacket->Type) {
159     case IP_ADDRESS_V4:
160         Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
161         AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr);
162         break;
163     case IP_ADDRESS_V6:
164         /* FIXME: IPv6 addresses not supported */
165         TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
166         return;
167     default:
168         TI_DbgPrint(MIN_TRACE, ("Unrecognized datagram discarded.\n"));
169         return;
170     }
171 
172     NBResetNeighborTimeout(&SrcAddress);
173 
174     if (Protocol < IP_PROTOCOL_TABLE_SIZE)
175     {
176        /* Call the appropriate protocol handler */
177        (*ProtocolTable[Protocol])(Interface, IPPacket);
178     }
179 }
180 
181 
IPCreateInterface(PLLIP_BIND_INFO BindInfo)182 PIP_INTERFACE IPCreateInterface(
183     PLLIP_BIND_INFO BindInfo)
184 /*
185  * FUNCTION: Creates an IP interface
186  * ARGUMENTS:
187  *     BindInfo = Pointer to link layer to IP binding information
188  * RETURNS:
189  *     Pointer to IP_INTERFACE structure, NULL if there was
190  *     not enough free resources
191  */
192 {
193     PIP_INTERFACE IF;
194 
195     TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
196 
197 #if DBG
198     if (BindInfo->Address) {
199         PUCHAR A = BindInfo->Address;
200         TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
201             A[0], A[1], A[2], A[3], A[4], A[5]));
202     }
203 #endif
204 
205     IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(IP_INTERFACE),
206                                IP_INTERFACE_TAG);
207     if (!IF) {
208         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
209         return NULL;
210     }
211 
212 	RtlZeroMemory(IF, sizeof(IP_INTERFACE));
213 
214     IF->Free       = FreeIF;
215     IF->Context    = BindInfo->Context;
216     IF->HeaderSize = BindInfo->HeaderSize;
217     IF->MinFrameSize = BindInfo->MinFrameSize;
218     IF->Address       = BindInfo->Address;
219     IF->AddressLength = BindInfo->AddressLength;
220     IF->Transmit      = BindInfo->Transmit;
221 
222 	IF->Unicast.Type = IP_ADDRESS_V4;
223 	IF->PointToPoint.Type = IP_ADDRESS_V4;
224 	IF->Netmask.Type = IP_ADDRESS_V4;
225 	IF->Broadcast.Type = IP_ADDRESS_V4;
226 
227     TcpipInitializeSpinLock(&IF->Lock);
228 
229     IF->TCPContext = ExAllocatePool
230 	( NonPagedPool, sizeof(struct netif));
231     if (!IF->TCPContext) {
232         ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
233         return NULL;
234     }
235 
236     TCPRegisterInterface(IF);
237 
238     InsertTDIInterfaceEntity( IF );
239 
240     return IF;
241 }
242 
243 
IPDestroyInterface(PIP_INTERFACE IF)244 VOID IPDestroyInterface(
245     PIP_INTERFACE IF)
246 /*
247  * FUNCTION: Destroys an IP interface
248  * ARGUMENTS:
249  *     IF = Pointer to interface to destroy
250  */
251 {
252     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
253 
254     RemoveTDIInterfaceEntity( IF );
255 
256     TCPUnregisterInterface(IF);
257 
258     ExFreePool(IF->TCPContext);
259     ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
260 }
261 
IPAddInterfaceRoute(PIP_INTERFACE IF)262 VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
263     PNEIGHBOR_CACHE_ENTRY NCE;
264     IP_ADDRESS NetworkAddress;
265 
266     /* Add a permanent neighbor for this NTE */
267     NCE = NBAddNeighbor(IF, &IF->Unicast,
268 			IF->Address, IF->AddressLength,
269 			NUD_PERMANENT, 0);
270     if (!NCE) {
271 	TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
272         return;
273     }
274 
275     AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask );
276 
277     if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) {
278 	TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
279     }
280 
281     /* Send a gratuitous ARP packet to update the route caches of
282      * other computers */
283     if (IF != Loopback)
284        ARPTransmit(NULL, NULL, IF);
285 
286     TCPUpdateInterfaceIPInformation(IF);
287 }
288 
IPRegisterInterface(PIP_INTERFACE IF)289 BOOLEAN IPRegisterInterface(
290     PIP_INTERFACE IF)
291 /*
292  * FUNCTION: Registers an IP interface with IP layer
293  * ARGUMENTS:
294  *     IF = Pointer to interface to register
295  * RETURNS;
296  *     TRUE if interface was successfully registered, FALSE if not
297  */
298 {
299     KIRQL OldIrql;
300     UINT ChosenIndex = 0;
301     BOOLEAN IndexHasBeenChosen;
302     IF_LIST_ITER(Interface);
303 
304     TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
305 
306     TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
307 
308     /* Choose an index */
309     do {
310         IndexHasBeenChosen = TRUE;
311         ForEachInterface(Interface) {
312             if( Interface->Index == ChosenIndex ) {
313                 ChosenIndex++;
314                 IndexHasBeenChosen = FALSE;
315             }
316         } EndFor(Interface);
317     } while( !IndexHasBeenChosen );
318 
319     IF->Index = ChosenIndex;
320 
321     /* Add interface to the global interface list */
322     TcpipInterlockedInsertTailList(&InterfaceListHead,
323 				   &IF->ListEntry,
324 				   &InterfaceListLock);
325 
326     TcpipReleaseSpinLock(&IF->Lock, OldIrql);
327 
328     return TRUE;
329 }
330 
IPRemoveInterfaceRoute(PIP_INTERFACE IF)331 VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) {
332     PNEIGHBOR_CACHE_ENTRY NCE;
333     IP_ADDRESS GeneralRoute;
334 
335     NCE = NBLocateNeighbor(&IF->Unicast, IF);
336     if (NCE)
337     {
338        TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast)));
339        TI_DbgPrint(DEBUG_IP,("                   Mask %s\n", A2S(&IF->Netmask)));
340 
341        AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask);
342 
343        RouterRemoveRoute(&GeneralRoute, &IF->Unicast);
344 
345        NBRemoveNeighbor(NCE);
346     }
347 }
348 
IPUnregisterInterface(PIP_INTERFACE IF)349 VOID IPUnregisterInterface(
350     PIP_INTERFACE IF)
351 /*
352  * FUNCTION: Unregisters an IP interface with IP layer
353  * ARGUMENTS:
354  *     IF = Pointer to interface to unregister
355  */
356 {
357     KIRQL OldIrql3;
358 
359     TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
360 
361     IPRemoveInterfaceRoute( IF );
362 
363     TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
364     RemoveEntryList(&IF->ListEntry);
365     TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
366 }
367 
368 
DefaultProtocolHandler(PIP_INTERFACE Interface,PIP_PACKET IPPacket)369 VOID DefaultProtocolHandler(
370     PIP_INTERFACE Interface,
371     PIP_PACKET IPPacket)
372 /*
373  * FUNCTION: Default handler for Internet protocols
374  * ARGUMENTS:
375  *     NTE      = Pointer to net table entry which the packet was received on
376  *     IPPacket = Pointer to an IP packet that was received
377  */
378 {
379     TI_DbgPrint(MID_TRACE, ("[IF %x] Packet of unknown Internet protocol "
380 			    "discarded.\n", Interface));
381 
382     Interface->Stats.InDiscardedUnknownProto++;
383 }
384 
385 
IPRegisterProtocol(UINT ProtocolNumber,IP_PROTOCOL_HANDLER Handler)386 VOID IPRegisterProtocol(
387     UINT ProtocolNumber,
388     IP_PROTOCOL_HANDLER Handler)
389 /*
390  * FUNCTION: Registers a handler for an IP protocol number
391  * ARGUMENTS:
392  *     ProtocolNumber = Internet Protocol number for which to register handler
393  *     Handler        = Pointer to handler to be called when a packet is received
394  * NOTES:
395  *     To unregister a protocol handler, call this function with Handler = NULL
396  */
397 {
398     if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) {
399         TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
400         return;
401     }
402 
403     ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler;
404 }
405 
406 
IPStartup(PUNICODE_STRING RegistryPath)407 NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
408 /*
409  * FUNCTION: Initializes the IP subsystem
410  * ARGUMENTS:
411  *     RegistryPath = Our registry node for configuration parameters
412  * RETURNS:
413  *     Status of operation
414  */
415 {
416     UINT i;
417 
418     TI_DbgPrint(MAX_TRACE, ("Called.\n"));
419 
420     /* Initialize lookaside lists */
421     ExInitializeNPagedLookasideList(
422       &IPDRList,                      /* Lookaside list */
423 	    NULL,                           /* Allocate routine */
424 	    NULL,                           /* Free routine */
425 	    0,                              /* Flags */
426 	    sizeof(IPDATAGRAM_REASSEMBLY),  /* Size of each entry */
427 	    DATAGRAM_REASSEMBLY_TAG,        /* Tag */
428 	    0);                             /* Depth */
429 
430     ExInitializeNPagedLookasideList(
431       &IPFragmentList,                /* Lookaside list */
432 	    NULL,                           /* Allocate routine */
433 	    NULL,                           /* Free routine */
434 	    0,                              /* Flags */
435 	    sizeof(IP_FRAGMENT),            /* Size of each entry */
436 	    DATAGRAM_FRAGMENT_TAG,          /* Tag */
437 	    0);                             /* Depth */
438 
439     ExInitializeNPagedLookasideList(
440       &IPHoleList,                    /* Lookaside list */
441 	    NULL,                           /* Allocate routine */
442 	    NULL,                           /* Free routine */
443 	    0,                              /* Flags */
444 	    sizeof(IPDATAGRAM_HOLE),        /* Size of each entry */
445 	    DATAGRAM_HOLE_TAG,              /* Tag */
446 	    0);                             /* Depth */
447 
448     /* Start routing subsystem */
449     RouterStartup();
450 
451     /* Start neighbor cache subsystem */
452     NBStartup();
453 
454     /* Fill the protocol dispatch table with pointers
455        to the default protocol handler */
456     for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
457         IPRegisterProtocol(i, DefaultProtocolHandler);
458 
459     /* Initialize NTE list and protecting lock */
460     InitializeListHead(&NetTableListHead);
461     TcpipInitializeSpinLock(&NetTableListLock);
462 
463     /* Initialize reassembly list and protecting lock */
464     InitializeListHead(&ReassemblyListHead);
465     TcpipInitializeSpinLock(&ReassemblyListLock);
466 
467     IPInitialized = TRUE;
468 
469     return STATUS_SUCCESS;
470 }
471 
472 
IPShutdown(VOID)473 NTSTATUS IPShutdown(
474     VOID)
475 /*
476  * FUNCTION: Shuts down the IP subsystem
477  * RETURNS:
478  *     Status of operation
479  */
480 {
481     TI_DbgPrint(MAX_TRACE, ("Called.\n"));
482 
483     if (!IPInitialized)
484         return STATUS_SUCCESS;
485 
486     /* Shutdown neighbor cache subsystem */
487     NBShutdown();
488 
489     /* Shutdown routing subsystem */
490     RouterShutdown();
491 
492     IPFreeReassemblyList();
493 
494     /* Destroy lookaside lists */
495     ExDeleteNPagedLookasideList(&IPHoleList);
496     ExDeleteNPagedLookasideList(&IPDRList);
497     ExDeleteNPagedLookasideList(&IPFragmentList);
498 
499     IPInitialized = FALSE;
500 
501     return STATUS_SUCCESS;
502 }
503 
504 /* EOF */
505