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