- Return early if ProtocolNumber is too large
[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
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 TcpipFreeToNPagedLookasideList(&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 = TcpipAllocateFromNPagedLookasideList(&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 STDCALL 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 Protocol = 0;
151 }
152
153 /* Call the appropriate protocol handler */
154 (*ProtocolTable[Protocol])(Interface, IPPacket);
155 /* Special case for ICMP -- ICMP can be caught by a SOCK_RAW but also
156 * must be handled here. */
157 if( Protocol == IPPROTO_ICMP )
158 ICMPReceive( Interface, IPPacket );
159 }
160
161
162 PIP_INTERFACE IPCreateInterface(
163 PLLIP_BIND_INFO BindInfo)
164 /*
165 * FUNCTION: Creates an IP interface
166 * ARGUMENTS:
167 * BindInfo = Pointer to link layer to IP binding information
168 * RETURNS:
169 * Pointer to IP_INTERFACE structure, NULL if there was
170 * not enough free resources
171 */
172 {
173 PIP_INTERFACE IF;
174
175 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
176
177 #ifdef DBG
178 if (BindInfo->Address) {
179 PUCHAR A = BindInfo->Address;
180 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
181 A[0], A[1], A[2], A[3], A[4], A[5]));
182 }
183 #endif
184
185 IF = exAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
186 if (!IF) {
187 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
188 return NULL;
189 }
190
191 INIT_TAG(IF, TAG('F','A','C','E'));
192
193 IF->Free = FreeIF;
194 IF->Context = BindInfo->Context;
195 IF->HeaderSize = BindInfo->HeaderSize;
196 if (IF->HeaderSize > MaxLLHeaderSize)
197 MaxLLHeaderSize = IF->HeaderSize;
198
199 IF->MinFrameSize = BindInfo->MinFrameSize;
200 if (IF->MinFrameSize > MinLLFrameSize)
201 MinLLFrameSize = IF->MinFrameSize;
202
203 IF->MTU = BindInfo->MTU;
204 IF->Address = BindInfo->Address;
205 IF->AddressLength = BindInfo->AddressLength;
206 IF->Transmit = BindInfo->Transmit;
207
208 TcpipInitializeSpinLock(&IF->Lock);
209
210 #ifdef __NTDRIVER__
211 InsertTDIInterfaceEntity( IF );
212 #endif
213
214 return IF;
215 }
216
217
218 VOID IPDestroyInterface(
219 PIP_INTERFACE IF)
220 /*
221 * FUNCTION: Destroys an IP interface
222 * ARGUMENTS:
223 * IF = Pointer to interface to destroy
224 */
225 {
226 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
227
228 #ifdef __NTDRIVER__
229 RemoveTDIInterfaceEntity( IF );
230 #endif
231
232 exFreePool(IF);
233 }
234
235 VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
236 PNEIGHBOR_CACHE_ENTRY NCE;
237 IP_ADDRESS NetworkAddress;
238
239 /* Add a permanent neighbor for this NTE */
240 NCE = NBAddNeighbor(IF, &IF->Unicast,
241 IF->Address, IF->AddressLength,
242 NUD_PERMANENT);
243 if (!NCE) {
244 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
245 }
246
247 AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask );
248
249 if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) {
250 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
251 }
252
253 /* Allow TCP to hang some configuration on this interface */
254 IF->TCPContext = TCPPrepareInterface( IF );
255 }
256
257 BOOLEAN IPRegisterInterface(
258 PIP_INTERFACE IF)
259 /*
260 * FUNCTION: Registers an IP interface with IP layer
261 * ARGUMENTS:
262 * IF = Pointer to interface to register
263 * RETURNS;
264 * TRUE if interface was successfully registered, FALSE if not
265 */
266 {
267 KIRQL OldIrql;
268 UINT ChosenIndex = 1;
269 BOOLEAN IndexHasBeenChosen;
270 IF_LIST_ITER(Interface);
271
272 TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
273
274 TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
275
276 /* Choose an index */
277 do {
278 IndexHasBeenChosen = TRUE;
279 ForEachInterface(Interface) {
280 if( Interface->Index == ChosenIndex ) {
281 ChosenIndex++;
282 IndexHasBeenChosen = FALSE;
283 }
284 } EndFor(Interface);
285 } while( !IndexHasBeenChosen );
286
287 IF->Index = ChosenIndex;
288
289 IPAddInterfaceRoute( IF );
290
291 /* Add interface to the global interface list */
292 TcpipInterlockedInsertTailList(&InterfaceListHead,
293 &IF->ListEntry,
294 &InterfaceListLock);
295
296 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
297
298 return TRUE;
299 }
300
301 VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) {
302 PNEIGHBOR_CACHE_ENTRY NCE;
303 IP_ADDRESS GeneralRoute;
304
305 TCPDisposeInterfaceData( IF->TCPContext );
306 IF->TCPContext = NULL;
307
308 TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast)));
309 TI_DbgPrint(DEBUG_IP,(" Mask %s\n", A2S(&IF->Netmask)));
310
311 AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask);
312
313 RouterRemoveRoute(&GeneralRoute, &IF->Unicast);
314
315 /* Remove permanent NCE, but first we have to find it */
316 NCE = NBLocateNeighbor(&IF->Unicast);
317 if (NCE)
318 NBRemoveNeighbor(NCE);
319 else
320 TI_DbgPrint(DEBUG_IP, ("Could not delete IF route (0x%X)\n", IF));
321 }
322
323 VOID IPUnregisterInterface(
324 PIP_INTERFACE IF)
325 /*
326 * FUNCTION: Unregisters an IP interface with IP layer
327 * ARGUMENTS:
328 * IF = Pointer to interface to unregister
329 */
330 {
331 KIRQL OldIrql3;
332
333 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
334
335 IPRemoveInterfaceRoute( IF );
336
337 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
338 RemoveEntryList(&IF->ListEntry);
339 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
340 }
341
342
343 VOID IPRegisterProtocol(
344 UINT ProtocolNumber,
345 IP_PROTOCOL_HANDLER Handler)
346 /*
347 * FUNCTION: Registers a handler for an IP protocol number
348 * ARGUMENTS:
349 * ProtocolNumber = Internet Protocol number for which to register handler
350 * Handler = Pointer to handler to be called when a packet is received
351 * NOTES:
352 * To unregister a protocol handler, call this function with Handler = NULL
353 */
354 {
355 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) {
356 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
357 return;
358 }
359
360 ProtocolTable[ProtocolNumber] = Handler;
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
378
379 NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
380 /*
381 * FUNCTION: Initializes the IP subsystem
382 * ARGUMENTS:
383 * RegistryPath = Our registry node for configuration parameters
384 * RETURNS:
385 * Status of operation
386 */
387 {
388 UINT i;
389
390 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
391
392 MaxLLHeaderSize = 0;
393 MinLLFrameSize = 0;
394
395 /* Initialize lookaside lists */
396 ExInitializeNPagedLookasideList(
397 &IPDRList, /* Lookaside list */
398 NULL, /* Allocate routine */
399 NULL, /* Free routine */
400 0, /* Flags */
401 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
402 TAG('I','P','D','R'), /* Tag */
403 0); /* Depth */
404
405 ExInitializeNPagedLookasideList(
406 &IPPacketList, /* Lookaside list */
407 NULL, /* Allocate routine */
408 NULL, /* Free routine */
409 0, /* Flags */
410 sizeof(IP_PACKET), /* Size of each entry */
411 TAG('I','P','P','K'), /* Tag */
412 0); /* Depth */
413
414 ExInitializeNPagedLookasideList(
415 &IPFragmentList, /* Lookaside list */
416 NULL, /* Allocate routine */
417 NULL, /* Free routine */
418 0, /* Flags */
419 sizeof(IP_FRAGMENT), /* Size of each entry */
420 TAG('I','P','F','G'), /* Tag */
421 0); /* Depth */
422
423 ExInitializeNPagedLookasideList(
424 &IPHoleList, /* Lookaside list */
425 NULL, /* Allocate routine */
426 NULL, /* Free routine */
427 0, /* Flags */
428 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
429 TAG('I','P','H','L'), /* Tag */
430 0); /* Depth */
431
432 /* Start routing subsystem */
433 RouterStartup();
434
435 /* Start neighbor cache subsystem */
436 NBStartup();
437
438 /* Fill the protocol dispatch table with pointers
439 to the default protocol handler */
440 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
441 IPRegisterProtocol(i, DefaultProtocolHandler);
442
443 /* Initialize NTE list and protecting lock */
444 InitializeListHead(&NetTableListHead);
445 TcpipInitializeSpinLock(&NetTableListLock);
446
447 /* Initialize reassembly list and protecting lock */
448 InitializeListHead(&ReassemblyListHead);
449 TcpipInitializeSpinLock(&ReassemblyListLock);
450
451 IPInitialized = TRUE;
452
453 return STATUS_SUCCESS;
454 }
455
456
457 NTSTATUS IPShutdown(
458 VOID)
459 /*
460 * FUNCTION: Shuts down the IP subsystem
461 * RETURNS:
462 * Status of operation
463 */
464 {
465 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
466
467 if (!IPInitialized)
468 return STATUS_SUCCESS;
469
470 /* Shutdown neighbor cache subsystem */
471 NBShutdown();
472
473 /* Shutdown routing subsystem */
474 RouterShutdown();
475
476 IPFreeReassemblyList();
477
478 /* Destroy lookaside lists */
479 ExDeleteNPagedLookasideList(&IPHoleList);
480 ExDeleteNPagedLookasideList(&IPDRList);
481 ExDeleteNPagedLookasideList(&IPPacketList);
482 ExDeleteNPagedLookasideList(&IPFragmentList);
483
484 IPInitialized = FALSE;
485
486 return STATUS_SUCCESS;
487 }
488
489 /* EOF */