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