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