- In Win32 DBG is defined to 0 for a non-debug build and to 1 for a debug build....
[reactos.git] / reactos / 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
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 NPAGED_LOOKASIDE_LIST IPPacketList;
23 /* Work around calling timer at Dpc level */
24
25 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
26
27
28 VOID FreePacket(
29 PVOID Object)
30 /*
31 * FUNCTION: Frees an IP packet object
32 * ARGUMENTS:
33 * Object = Pointer to an IP packet structure
34 */
35 {
36 exFreeToNPagedLookasideList(&IPPacketList, Object);
37 }
38
39
40 VOID DontFreePacket(
41 PVOID Object)
42 /*
43 * FUNCTION: Do nothing for when the IPPacket struct is part of another
44 * ARGUMENTS:
45 * Object = Pointer to an IP packet structure
46 */
47 {
48 }
49
50 VOID FreeIF(
51 PVOID Object)
52 /*
53 * FUNCTION: Frees an interface object
54 * ARGUMENTS:
55 * Object = Pointer to an interface structure
56 */
57 {
58 exFreePool(Object);
59 }
60
61
62 PIP_PACKET IPCreatePacket(ULONG Type)
63 /*
64 * FUNCTION: Creates an IP packet object
65 * ARGUMENTS:
66 * Type = Type of IP packet
67 * RETURNS:
68 * Pointer to the created IP packet. NULL if there was not enough free resources.
69 */
70 {
71 PIP_PACKET IPPacket;
72
73 IPPacket = exAllocateFromNPagedLookasideList(&IPPacketList);
74 if (!IPPacket)
75 return NULL;
76
77 /* FIXME: Is this needed? */
78 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
79
80 INIT_TAG(IPPacket, TAG('I','P','K','T'));
81
82 IPPacket->Free = FreePacket;
83 IPPacket->Type = Type;
84 IPPacket->HeaderSize = 20;
85
86 return IPPacket;
87 }
88
89 PIP_PACKET IPInitializePacket(
90 PIP_PACKET IPPacket,
91 ULONG Type)
92 /*
93 * FUNCTION: Creates an IP packet object
94 * ARGUMENTS:
95 * Type = Type of IP packet
96 * RETURNS:
97 * Pointer to the created IP packet. NULL if there was not enough free resources.
98 */
99 {
100 /* FIXME: Is this needed? */
101 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
102
103 INIT_TAG(IPPacket, TAG('I','P','K','T'));
104
105 IPPacket->Free = DontFreePacket;
106 IPPacket->Type = Type;
107
108 return IPPacket;
109 }
110
111
112 void NTAPI IPTimeout( PVOID Context ) {
113 IpWorkItemQueued = FALSE;
114
115 /* Check if datagram fragments have taken too long to assemble */
116 IPDatagramReassemblyTimeout();
117
118 /* Clean possible outdated cached neighbor addresses */
119 NBTimeout();
120
121 /* Call upper layer timeout routines */
122 TCPTimeout();
123 }
124
125
126 VOID IPDispatchProtocol(
127 PIP_INTERFACE Interface,
128 PIP_PACKET IPPacket)
129 /*
130 * FUNCTION: IP protocol dispatcher
131 * ARGUMENTS:
132 * NTE = Pointer to net table entry which the packet was received on
133 * IPPacket = Pointer to an IP packet that was received
134 * NOTES:
135 * This routine examines the IP header and passes the packet on to the
136 * right upper level protocol receive handler
137 */
138 {
139 UINT Protocol;
140
141 switch (IPPacket->Type) {
142 case IP_ADDRESS_V4:
143 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
144 break;
145 case IP_ADDRESS_V6:
146 /* FIXME: IPv6 adresses not supported */
147 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
148 return;
149 default:
150 TI_DbgPrint(MIN_TRACE, ("Unrecognized datagram discarded.\n"));
151 return;
152 }
153
154 if (Protocol < IP_PROTOCOL_TABLE_SIZE)
155 {
156 /* Call the appropriate protocol handler */
157 (*ProtocolTable[Protocol])(Interface, IPPacket);
158
159 /* Special case for ICMP -- ICMP can be caught by a SOCK_RAW but also
160 * must be handled here. */
161 if( Protocol == IPPROTO_ICMP )
162 ICMPReceive( Interface, IPPacket );
163 }
164 }
165
166
167 PIP_INTERFACE IPCreateInterface(
168 PLLIP_BIND_INFO BindInfo)
169 /*
170 * FUNCTION: Creates an IP interface
171 * ARGUMENTS:
172 * BindInfo = Pointer to link layer to IP binding information
173 * RETURNS:
174 * Pointer to IP_INTERFACE structure, NULL if there was
175 * not enough free resources
176 */
177 {
178 PIP_INTERFACE IF;
179
180 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
181
182 #if DBG
183 if (BindInfo->Address) {
184 PUCHAR A = BindInfo->Address;
185 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
186 A[0], A[1], A[2], A[3], A[4], A[5]));
187 }
188 #endif
189
190 IF = exAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
191 if (!IF) {
192 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
193 return NULL;
194 }
195
196 INIT_TAG(IF, TAG('F','A','C','E'));
197
198 RtlZeroMemory(IF, sizeof(IP_INTERFACE));
199
200 IF->Free = FreeIF;
201 IF->Context = BindInfo->Context;
202 IF->HeaderSize = BindInfo->HeaderSize;
203 if (IF->HeaderSize > MaxLLHeaderSize)
204 MaxLLHeaderSize = IF->HeaderSize;
205
206 IF->MinFrameSize = BindInfo->MinFrameSize;
207 if (IF->MinFrameSize > MinLLFrameSize)
208 MinLLFrameSize = IF->MinFrameSize;
209
210 IF->MTU = BindInfo->MTU;
211 IF->Address = BindInfo->Address;
212 IF->AddressLength = BindInfo->AddressLength;
213 IF->Transmit = BindInfo->Transmit;
214
215 IF->Unicast.Type = IP_ADDRESS_V4;
216 IF->PointToPoint.Type = IP_ADDRESS_V4;
217 IF->Netmask.Type = IP_ADDRESS_V4;
218 IF->Broadcast.Type = IP_ADDRESS_V4;
219
220 TcpipInitializeSpinLock(&IF->Lock);
221
222 IF->TCPContext = exAllocatePool
223 ( NonPagedPool, sizeof(OSK_IFADDR) + 2 * sizeof( struct sockaddr_in ) );
224 if (!IF->TCPContext) {
225 exFreePool(IF);
226 return NULL;
227 }
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 exFreePool(IF->TCPContext);
252 exFreePool(IF);
253 }
254
255 VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
256 PNEIGHBOR_CACHE_ENTRY NCE;
257 IP_ADDRESS NetworkAddress;
258
259 /* Add a permanent neighbor for this NTE */
260 NCE = NBAddNeighbor(IF, &IF->Unicast,
261 IF->Address, IF->AddressLength,
262 NUD_PERMANENT);
263 if (!NCE) {
264 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
265 return;
266 }
267
268 AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask );
269
270 if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) {
271 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
272 return;
273 }
274 }
275
276 BOOLEAN IPRegisterInterface(
277 PIP_INTERFACE IF)
278 /*
279 * FUNCTION: Registers an IP interface with IP layer
280 * ARGUMENTS:
281 * IF = Pointer to interface to register
282 * RETURNS;
283 * TRUE if interface was successfully registered, FALSE if not
284 */
285 {
286 KIRQL OldIrql;
287 UINT ChosenIndex = 1;
288 BOOLEAN IndexHasBeenChosen;
289 IF_LIST_ITER(Interface);
290
291 TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
292
293 TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
294
295 /* Choose an index */
296 do {
297 IndexHasBeenChosen = TRUE;
298 ForEachInterface(Interface) {
299 if( Interface->Index == ChosenIndex ) {
300 ChosenIndex++;
301 IndexHasBeenChosen = FALSE;
302 }
303 } EndFor(Interface);
304 } while( !IndexHasBeenChosen );
305
306 IF->Index = ChosenIndex;
307
308 /* Add interface to the global interface list */
309 TcpipInterlockedInsertTailList(&InterfaceListHead,
310 &IF->ListEntry,
311 &InterfaceListLock);
312
313 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
314
315 return TRUE;
316 }
317
318 VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) {
319 PNEIGHBOR_CACHE_ENTRY NCE;
320 IP_ADDRESS GeneralRoute;
321
322 NCE = NBLocateNeighbor(&IF->Unicast);
323 if (NCE)
324 {
325 TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast)));
326 TI_DbgPrint(DEBUG_IP,(" Mask %s\n", A2S(&IF->Netmask)));
327
328 AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask);
329
330 RouterRemoveRoute(&GeneralRoute, &IF->Unicast);
331
332 NBRemoveNeighbor(NCE);
333 }
334 }
335
336 VOID IPUnregisterInterface(
337 PIP_INTERFACE IF)
338 /*
339 * FUNCTION: Unregisters an IP interface with IP layer
340 * ARGUMENTS:
341 * IF = Pointer to interface to unregister
342 */
343 {
344 KIRQL OldIrql3;
345
346 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
347
348 IPRemoveInterfaceRoute( IF );
349
350 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
351 RemoveEntryList(&IF->ListEntry);
352 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
353 }
354
355
356 VOID DefaultProtocolHandler(
357 PIP_INTERFACE Interface,
358 PIP_PACKET IPPacket)
359 /*
360 * FUNCTION: Default handler for Internet protocols
361 * ARGUMENTS:
362 * NTE = Pointer to net table entry which the packet was received on
363 * IPPacket = Pointer to an IP packet that was received
364 */
365 {
366 TI_DbgPrint(MID_TRACE, ("[IF %x] Packet of unknown Internet protocol "
367 "discarded.\n", Interface));
368 }
369
370
371 VOID IPRegisterProtocol(
372 UINT ProtocolNumber,
373 IP_PROTOCOL_HANDLER Handler)
374 /*
375 * FUNCTION: Registers a handler for an IP protocol number
376 * ARGUMENTS:
377 * ProtocolNumber = Internet Protocol number for which to register handler
378 * Handler = Pointer to handler to be called when a packet is received
379 * NOTES:
380 * To unregister a protocol handler, call this function with Handler = NULL
381 */
382 {
383 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) {
384 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
385 return;
386 }
387
388 ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler;
389 }
390
391
392 NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
393 /*
394 * FUNCTION: Initializes the IP subsystem
395 * ARGUMENTS:
396 * RegistryPath = Our registry node for configuration parameters
397 * RETURNS:
398 * Status of operation
399 */
400 {
401 UINT i;
402
403 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
404
405 MaxLLHeaderSize = 0;
406 MinLLFrameSize = 0;
407
408 /* Initialize lookaside lists */
409 ExInitializeNPagedLookasideList(
410 &IPDRList, /* Lookaside list */
411 NULL, /* Allocate routine */
412 NULL, /* Free routine */
413 0, /* Flags */
414 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
415 TAG('I','P','D','R'), /* Tag */
416 0); /* Depth */
417
418 ExInitializeNPagedLookasideList(
419 &IPPacketList, /* Lookaside list */
420 NULL, /* Allocate routine */
421 NULL, /* Free routine */
422 0, /* Flags */
423 sizeof(IP_PACKET), /* Size of each entry */
424 TAG('I','P','P','K'), /* Tag */
425 0); /* Depth */
426
427 ExInitializeNPagedLookasideList(
428 &IPFragmentList, /* Lookaside list */
429 NULL, /* Allocate routine */
430 NULL, /* Free routine */
431 0, /* Flags */
432 sizeof(IP_FRAGMENT), /* Size of each entry */
433 TAG('I','P','F','G'), /* Tag */
434 0); /* Depth */
435
436 ExInitializeNPagedLookasideList(
437 &IPHoleList, /* Lookaside list */
438 NULL, /* Allocate routine */
439 NULL, /* Free routine */
440 0, /* Flags */
441 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
442 TAG('I','P','H','L'), /* Tag */
443 0); /* Depth */
444
445 /* Start routing subsystem */
446 RouterStartup();
447
448 /* Start neighbor cache subsystem */
449 NBStartup();
450
451 /* Fill the protocol dispatch table with pointers
452 to the default protocol handler */
453 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
454 IPRegisterProtocol(i, DefaultProtocolHandler);
455
456 /* Initialize NTE list and protecting lock */
457 InitializeListHead(&NetTableListHead);
458 TcpipInitializeSpinLock(&NetTableListLock);
459
460 /* Initialize reassembly list and protecting lock */
461 InitializeListHead(&ReassemblyListHead);
462 TcpipInitializeSpinLock(&ReassemblyListLock);
463
464 IPInitialized = TRUE;
465
466 return STATUS_SUCCESS;
467 }
468
469
470 NTSTATUS IPShutdown(
471 VOID)
472 /*
473 * FUNCTION: Shuts down the IP subsystem
474 * RETURNS:
475 * Status of operation
476 */
477 {
478 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
479
480 if (!IPInitialized)
481 return STATUS_SUCCESS;
482
483 /* Shutdown neighbor cache subsystem */
484 NBShutdown();
485
486 /* Shutdown routing subsystem */
487 RouterShutdown();
488
489 IPFreeReassemblyList();
490
491 /* Destroy lookaside lists */
492 ExDeleteNPagedLookasideList(&IPHoleList);
493 ExDeleteNPagedLookasideList(&IPDRList);
494 ExDeleteNPagedLookasideList(&IPPacketList);
495 ExDeleteNPagedLookasideList(&IPFragmentList);
496
497 IPInitialized = FALSE;
498
499 return STATUS_SUCCESS;
500 }
501
502 /* EOF */