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