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