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