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