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