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