Fixed callback calling conventions (part 2).
[reactos.git] / reactos / drivers / net / tcpip / 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 #include <tcpip.h>
11 #include <ip.h>
12 #include <tcp.h>
13 #include <loopback.h>
14 #include <neighbor.h>
15 #include <receive.h>
16 #include <address.h>
17 #include <route.h>
18 #include <icmp.h>
19 #include <pool.h>
20
21
22 KTIMER IPTimer;
23 KDPC IPTimeoutDpc;
24 LIST_ENTRY InterfaceListHead;
25 KSPIN_LOCK InterfaceListLock;
26 LIST_ENTRY NetTableListHead;
27 KSPIN_LOCK NetTableListLock;
28 LIST_ENTRY PrefixListHead;
29 KSPIN_LOCK PrefixListLock;
30 UINT MaxLLHeaderSize; /* Largest maximum header size */
31 UINT MinLLFrameSize; /* Largest minimum frame size */
32 BOOLEAN IPInitialized = FALSE;
33 NPAGED_LOOKASIDE_LIST IPPacketList;
34
35 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
36
37
38 VOID FreePacket(
39 PVOID Object)
40 /*
41 * FUNCTION: Frees an IP packet object
42 * ARGUMENTS:
43 * Object = Pointer to an IP packet structure
44 */
45 {
46 ExFreeToNPagedLookasideList(&IPPacketList, Object);
47 }
48
49
50 VOID FreeADE(
51 PVOID Object)
52 /*
53 * FUNCTION: Frees an address entry object
54 * ARGUMENTS:
55 * Object = Pointer to an address entry structure
56 */
57 {
58 ExFreePool(Object);
59 }
60
61
62 VOID FreeNTE(
63 PVOID Object)
64 /*
65 * FUNCTION: Frees a net table entry object
66 * ARGUMENTS:
67 * Object = Pointer to an net table entry structure
68 */
69 {
70 ExFreePool(Object);
71 }
72
73
74 VOID FreeIF(
75 PVOID Object)
76 /*
77 * FUNCTION: Frees an interface object
78 * ARGUMENTS:
79 * Object = Pointer to an interface structure
80 */
81 {
82 ExFreePool(Object);
83 }
84
85
86 PADDRESS_ENTRY CreateADE(
87 PIP_INTERFACE IF, PIP_ADDRESS Address,
88 UCHAR Type,
89 PNET_TABLE_ENTRY NTE)
90 /*
91 * FUNCTION: Creates an address entry and binds it to an interface
92 * ARGUMENTS:
93 * IF = Pointer to interface
94 * Address = Pointer to referenced interface address
95 * Type = Type of address (ADE_*)
96 * NTE = Pointer to net table entry
97 * RETURNS:
98 * Pointer to ADE, NULL if there was not enough free resources
99 * NOTES:
100 * The interface lock must be held when called. The address entry
101 * retains a reference to the provided address and NTE. The caller
102 * is responsible for referencing the these before calling.
103 * As long as you have referenced an ADE you can safely use the
104 * address and NTE as the ADE references both
105 */
106 {
107 PADDRESS_ENTRY ADE;
108
109 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n",
110 IF, Address, Type, NTE));
111
112 TI_DbgPrint(DEBUG_IP, ("Address (%s) NTE (%s).\n",
113 A2S(Address), A2S(NTE->Address)));
114
115 /* Allocate space for an ADE and set it up */
116 ADE = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_ENTRY));
117 if (!ADE) {
118 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
119 return NULL;
120 }
121
122 INIT_TAG(ADE, TAG('A','D','E',' '));
123 ADE->Free = FreeADE;
124 ADE->RefCount = 1;
125 ADE->NTE = NTE;
126 ADE->Type = Type;
127 ADE->Address = Address;
128
129 /* Add ADE to the list on the interface */
130 InsertTailList(&IF->ADEListHead, &ADE->ListEntry);
131
132 return ADE;
133 }
134
135
136 VOID DestroyADE(
137 PIP_INTERFACE IF,
138 PADDRESS_ENTRY ADE)
139 /*
140 * FUNCTION: Destroys an address entry
141 * ARGUMENTS:
142 * IF = Pointer to interface
143 * ADE = Pointer to address entry
144 * NOTES:
145 * The interface lock must be held when called
146 */
147 {
148 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) ADE (0x%X).\n", IF, ADE));
149
150 TI_DbgPrint(DEBUG_IP, ("ADE (%s).\n", ADE->Address));
151
152 /* Unlink the address entry from the list */
153 RemoveEntryList(&ADE->ListEntry);
154
155 /* Dereference the address */
156 DereferenceObject(ADE->Address);
157
158 /* Dereference the NTE */
159 DereferenceObject(ADE->NTE);
160
161 #ifdef DBG
162 ADE->RefCount--;
163
164 if (ADE->RefCount != 0) {
165 TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount));
166 }
167 #endif
168
169 /* And free the ADE */
170 FreeADE(ADE);
171 }
172
173
174 VOID DestroyADEs(
175 PIP_INTERFACE IF)
176 /*
177 * FUNCTION: Destroys all address entries on an interface
178 * ARGUMENTS:
179 * IF = Pointer to interface
180 * NOTES:
181 * The interface lock must be held when called
182 */
183 {
184 PLIST_ENTRY CurrentEntry;
185 PLIST_ENTRY NextEntry;
186 PADDRESS_ENTRY Current;
187
188 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
189
190 /* Search the list and remove every ADE we find */
191 CurrentEntry = IF->ADEListHead.Flink;
192 while (CurrentEntry != &IF->ADEListHead) {
193 NextEntry = CurrentEntry->Flink;
194 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
195 /* Destroy the ADE */
196 DestroyADE(IF, Current);
197 CurrentEntry = NextEntry;
198 }
199 }
200
201
202 PIP_PACKET IPCreatePacket(
203 ULONG Type)
204 /*
205 * FUNCTION: Creates an IP packet object
206 * ARGUMENTS:
207 * Type = Type of IP packet
208 * RETURNS:
209 * Pointer to the created IP packet. NULL if there was not enough free resources.
210 */
211 {
212 PIP_PACKET IPPacket;
213
214 IPPacket = ExAllocateFromNPagedLookasideList(&IPPacketList);
215 if (!IPPacket)
216 return NULL;
217
218 /* FIXME: Is this needed? */
219 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
220
221 INIT_TAG(IPPacket, TAG('I','P','K','T'));
222
223 IPPacket->Free = FreePacket;
224 IPPacket->RefCount = 1;
225 IPPacket->Type = Type;
226
227 return IPPacket;
228 }
229
230
231 PPREFIX_LIST_ENTRY CreatePLE(
232 PIP_INTERFACE IF,
233 PIP_ADDRESS Prefix,
234 UINT Length)
235 /*
236 * FUNCTION: Creates a prefix list entry and binds it to an interface
237 * ARGUMENTS:
238 * IF = Pointer to interface
239 * Prefix = Pointer to prefix
240 * Length = Length of prefix
241 * RETURNS:
242 * Pointer to PLE, NULL if there was not enough free resources
243 * NOTES:
244 * The prefix list entry retains a reference to the interface and
245 * the provided address. The caller is responsible for providing
246 * these references
247 */
248 {
249 PPREFIX_LIST_ENTRY PLE;
250
251 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF, Prefix, Length));
252
253 TI_DbgPrint(DEBUG_IP, ("Prefix (%s).\n", A2S(Prefix)));
254
255 /* Allocate space for an PLE and set it up */
256 PLE = ExAllocatePool(NonPagedPool, sizeof(PREFIX_LIST_ENTRY));
257 if (!PLE) {
258 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
259 return NULL;
260 }
261
262 INIT_TAG(PLE, TAG('P','L','E',' '));
263 PLE->RefCount = 1;
264 PLE->Interface = IF;
265 PLE->Prefix = Prefix;
266 PLE->PrefixLength = Length;
267
268 /* Add PLE to the global prefix list */
269 ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock);
270
271 return PLE;
272 }
273
274
275 VOID DestroyPLE(
276 PPREFIX_LIST_ENTRY PLE)
277 /*
278 * FUNCTION: Destroys an prefix list entry
279 * ARGUMENTS:
280 * PLE = Pointer to prefix list entry
281 * NOTES:
282 * The prefix list lock must be held when called
283 */
284 {
285 TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE));
286
287 TI_DbgPrint(DEBUG_IP, ("PLE (%s).\n", PLE->Prefix));
288
289 /* Unlink the prefix list entry from the list */
290 RemoveEntryList(&PLE->ListEntry);
291
292 /* Dereference the address */
293 DereferenceObject(PLE->Prefix);
294
295 /* Dereference the interface */
296 DereferenceObject(PLE->Interface);
297
298 #ifdef DBG
299 PLE->RefCount--;
300
301 if (PLE->RefCount != 0) {
302 TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount));
303 }
304 #endif
305
306 /* And free the PLE */
307 ExFreePool(PLE);
308 }
309
310
311 VOID DestroyPLEs(
312 VOID)
313 /*
314 * FUNCTION: Destroys all prefix list entries
315 */
316 {
317 KIRQL OldIrql;
318 PLIST_ENTRY CurrentEntry;
319 PLIST_ENTRY NextEntry;
320 PPREFIX_LIST_ENTRY Current;
321
322 TI_DbgPrint(DEBUG_IP, ("Called.\n"));
323
324 KeAcquireSpinLock(&PrefixListLock, &OldIrql);
325
326 /* Search the list and remove every PLE we find */
327 CurrentEntry = PrefixListHead.Flink;
328 while (CurrentEntry != &PrefixListHead) {
329 NextEntry = CurrentEntry->Flink;
330 Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);
331 /* Destroy the PLE */
332 DestroyPLE(Current);
333 CurrentEntry = NextEntry;
334 }
335 KeReleaseSpinLock(&PrefixListLock, OldIrql);
336 }
337
338
339 PNET_TABLE_ENTRY IPCreateNTE(
340 PIP_INTERFACE IF,
341 PIP_ADDRESS Address,
342 UINT PrefixLength)
343 /*
344 * FUNCTION: Creates a net table entry and binds it to an interface
345 * ARGUMENTS:
346 * IF = Pointer to interface
347 * Address = Pointer to interface address
348 * PrefixLength = Length of prefix
349 * RETURNS:
350 * Pointer to NTE, NULL if there was not enough free resources
351 * NOTES:
352 * The interface lock must be held when called.
353 * The net table entry retains a reference to the interface and
354 * the provided address. The caller is responsible for providing
355 * these references
356 */
357 {
358 PNET_TABLE_ENTRY NTE;
359 PADDRESS_ENTRY ADE;
360
361 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF, Address, PrefixLength));
362
363 TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
364
365 /* Allocate room for an NTE */
366 NTE = ExAllocatePool(NonPagedPool, sizeof(NET_TABLE_ENTRY));
367 if (!NTE) {
368 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
369 return NULL;
370 }
371
372 INIT_TAG(NTE, TAG('N','T','E',' '));
373
374 NTE->Free = FreeNTE;
375
376 NTE->Interface = IF;
377
378 /* One reference is for beeing alive and one reference is for the ADE */
379 NTE->RefCount = 2;
380
381 NTE->Address = Address;
382 /* One reference is for NTE, one reference is given to the
383 address entry, and one reference is given to the prefix
384 list entry */
385 ReferenceObject(Address);
386 ReferenceObject(Address);
387 ReferenceObject(Address);
388
389 /* Create an address entry and add it to the list */
390 ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
391 if (!ADE) {
392 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
393 ExFreePool(NTE);
394 return NULL;
395 }
396
397 /* Create a prefix list entry for unicast address */
398 NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
399 if (!NTE->PLE) {
400 DestroyADE(IF, ADE);
401 ExFreePool(NTE);
402 return NULL;
403 }
404
405 /* Reference the interface for the prefix list entry */
406 ReferenceObject(IF);
407
408 /* Add NTE to the list on the interface */
409 InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
410
411 /* Add NTE to the global net table list */
412 ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
413
414 return NTE;
415 }
416
417
418 VOID DestroyNTE(
419 PIP_INTERFACE IF,
420 PNET_TABLE_ENTRY NTE)
421 /*
422 * FUNCTION: Destroys a net table entry
423 * ARGUMENTS:
424 * IF = Pointer to interface
425 * NTE = Pointer to net table entry
426 * NOTES:
427 * The net table list lock must be held when called
428 * The interface lock must be held when called
429 */
430 {
431 KIRQL OldIrql;
432
433 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE));
434
435 TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
436
437 /* Invalidate the prefix list entry for this NTE */
438 KeAcquireSpinLock(&PrefixListLock, &OldIrql);
439 DestroyPLE(NTE->PLE);
440 KeReleaseSpinLock(&PrefixListLock, OldIrql);
441
442 /* Remove NTE from the interface list */
443 RemoveEntryList(&NTE->IFListEntry);
444 /* Remove NTE from the net table list */
445 RemoveEntryList(&NTE->NTListEntry);
446 /* Dereference the objects that are referenced */
447 DereferenceObject(NTE->Address);
448 DereferenceObject(NTE->Interface);
449 #ifdef DBG
450 NTE->RefCount--;
451
452 if (NTE->RefCount != 0) {
453 TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount));
454 }
455 #endif
456 /* And free the NTE */
457 ExFreePool(NTE);
458 }
459
460
461 VOID DestroyNTEs(
462 PIP_INTERFACE IF)
463 /*
464 * FUNCTION: Destroys all net table entries on an interface
465 * ARGUMENTS:
466 * IF = Pointer to interface
467 * NOTES:
468 * The net table list lock must be held when called
469 * The interface lock may be held when called
470 */
471 {
472 PLIST_ENTRY CurrentEntry;
473 PLIST_ENTRY NextEntry;
474 PNET_TABLE_ENTRY Current;
475
476 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
477
478 /* Search the list and remove every NTE we find */
479 CurrentEntry = IF->NTEListHead.Flink;
480 while (CurrentEntry != &IF->NTEListHead) {
481 NextEntry = CurrentEntry->Flink;
482 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
483 /* Destroy the NTE */
484 DestroyNTE(IF, Current);
485 CurrentEntry = NextEntry;
486 }
487 }
488
489
490 PNET_TABLE_ENTRY IPLocateNTEOnInterface(
491 PIP_INTERFACE IF,
492 PIP_ADDRESS Address,
493 PUINT AddressType)
494 /*
495 * FUNCTION: Locates an NTE on an interface
496 * ARGUMENTS:
497 * IF = Pointer to interface
498 * Address = Pointer to IP address
499 * AddressType = Address of type of IP address
500 * NOTES:
501 * If found, the NTE is referenced for the caller. The caller is
502 * responsible for dereferencing after use
503 * RETURNS:
504 * Pointer to net table entry, NULL if none was found
505 */
506 {
507 KIRQL OldIrql;
508 PLIST_ENTRY CurrentEntry;
509 PADDRESS_ENTRY Current;
510
511 // TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
512 // IF, Address, AddressType));
513
514 // TI_DbgPrint(DEBUG_IP, ("Address (%s) AddressType (0x%X).\n", A2S(Address)));
515
516 KeAcquireSpinLock(&IF->Lock, &OldIrql);
517
518 /* Search the list and return the NTE if found */
519 CurrentEntry = IF->ADEListHead.Flink;
520 while (CurrentEntry != &IF->ADEListHead) {
521 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
522 if (AddrIsEqual(Address, Current->Address)) {
523 ReferenceObject(Current->NTE);
524 *AddressType = Current->Type;
525 KeReleaseSpinLock(&IF->Lock, OldIrql);
526 return Current->NTE;
527 }
528 CurrentEntry = CurrentEntry->Flink;
529 }
530
531 KeReleaseSpinLock(&IF->Lock, OldIrql);
532
533 return NULL;
534 }
535
536
537 PNET_TABLE_ENTRY IPLocateNTE(
538 PIP_ADDRESS Address,
539 PUINT AddressType)
540 /*
541 * FUNCTION: Locates an NTE for the network Address is on
542 * ARGUMENTS:
543 * Address = Pointer to an address to find associated NTE of
544 * AddressType = Address of address type
545 * NOTES:
546 * If found the NTE is referenced for the caller. The caller is
547 * responsible for dereferencing after use
548 * RETURNS:
549 * Pointer to NTE if the address was found, NULL if not.
550 */
551 {
552 KIRQL OldIrql;
553 PLIST_ENTRY CurrentEntry;
554 PNET_TABLE_ENTRY Current;
555 PNET_TABLE_ENTRY NTE;
556
557 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
558 // Address, AddressType));
559
560 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
561
562 KeAcquireSpinLock(&NetTableListLock, &OldIrql);
563
564 /* Search the list and return the NTE if found */
565 CurrentEntry = NetTableListHead.Flink;
566 while (CurrentEntry != &NetTableListHead) {
567 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);
568 NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);
569 if (NTE) {
570 ReferenceObject(NTE);
571 KeReleaseSpinLock(&NetTableListLock, OldIrql);
572 return NTE;
573 }
574 CurrentEntry = CurrentEntry->Flink;
575 }
576
577 KeReleaseSpinLock(&NetTableListLock, OldIrql);
578
579 return NULL;
580 }
581
582
583 PADDRESS_ENTRY IPLocateADE(
584 PIP_ADDRESS Address,
585 UINT AddressType)
586 /*
587 * FUNCTION: Locates an ADE for the address
588 * ARGUMENTS:
589 * Address = Pointer to an address to find associated ADE of
590 * AddressType = Type of address
591 * RETURNS:
592 * Pointer to ADE if the address was found, NULL if not.
593 * NOTES:
594 * If found the ADE is referenced for the caller. The caller is
595 * responsible for dereferencing after use
596 */
597 {
598 KIRQL OldIrql;
599 PLIST_ENTRY CurrentIFEntry;
600 PLIST_ENTRY CurrentADEEntry;
601 PIP_INTERFACE CurrentIF;
602 PADDRESS_ENTRY CurrentADE;
603
604 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
605 // Address, AddressType));
606
607 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
608
609 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
610
611 /* Search the interface list */
612 CurrentIFEntry = InterfaceListHead.Flink;
613 while (CurrentIFEntry != &InterfaceListHead) {
614 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
615
616 /* Search the address entry list and return the ADE if found */
617 CurrentADEEntry = CurrentIF->ADEListHead.Flink;
618 while (CurrentADEEntry != &CurrentIF->ADEListHead) {
619 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
620 if ((AddrIsEqual(Address, CurrentADE->Address)) &&
621 (CurrentADE->Type == AddressType)) {
622 ReferenceObject(CurrentADE);
623 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
624 return CurrentADE;
625 }
626 CurrentADEEntry = CurrentADEEntry->Flink;
627 }
628 CurrentIFEntry = CurrentIFEntry->Flink;
629 }
630
631 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
632
633 return NULL;
634 }
635
636
637 PADDRESS_ENTRY IPGetDefaultADE(
638 UINT AddressType)
639 /*
640 * FUNCTION: Returns a default address entry
641 * ARGUMENTS:
642 * AddressType = Type of address
643 * RETURNS:
644 * Pointer to ADE if found, NULL if not.
645 * NOTES:
646 * Loopback interface is only considered if it is the only interface.
647 * If found, the address entry is referenced
648 */
649 {
650 KIRQL OldIrql;
651 PLIST_ENTRY CurrentIFEntry;
652 PLIST_ENTRY CurrentADEEntry;
653 PIP_INTERFACE CurrentIF;
654 PADDRESS_ENTRY CurrentADE;
655 BOOLEAN LoopbackIsRegistered = FALSE;
656
657 TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
658
659 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
660
661 /* Search the interface list */
662 CurrentIFEntry = InterfaceListHead.Flink;
663 while (CurrentIFEntry != &InterfaceListHead) {
664 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
665
666 if (CurrentIF != Loopback) {
667 /* Search the address entry list and return the first appropriate ADE found */
668 CurrentADEEntry = CurrentIF->ADEListHead.Flink;
669 while (CurrentADEEntry != &CurrentIF->ADEListHead) {
670 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
671 if (CurrentADE->Type == AddressType)
672 ReferenceObject(CurrentADE);
673 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
674 return CurrentADE;
675 }
676 CurrentADEEntry = CurrentADEEntry->Flink;
677 } else
678 LoopbackIsRegistered = TRUE;
679 CurrentIFEntry = CurrentIFEntry->Flink;
680 }
681
682 /* No address was found. Use loopback interface if available */
683 if (LoopbackIsRegistered) {
684 CurrentADEEntry = Loopback->ADEListHead.Flink;
685 while (CurrentADEEntry != &Loopback->ADEListHead) {
686 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
687 if (CurrentADE->Type == AddressType) {
688 ReferenceObject(CurrentADE);
689 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
690 return CurrentADE;
691 }
692 CurrentADEEntry = CurrentADEEntry->Flink;
693 }
694 }
695
696 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
697
698 return NULL;
699 }
700
701
702 VOID STDCALL IPTimeout(
703 PKDPC Dpc,
704 PVOID DeferredContext,
705 PVOID SystemArgument1,
706 PVOID SystemArgument2)
707 /*
708 * FUNCTION: Timeout DPC
709 * ARGUMENTS:
710 * Dpc = Pointer to our DPC object
711 * DeferredContext = Pointer to context information (unused)
712 * SystemArgument1 = Unused
713 * SystemArgument2 = Unused
714 * NOTES:
715 * This routine is dispatched once in a while to do maintainance jobs
716 */
717 {
718 /* Check if datagram fragments have taken too long to assemble */
719 IPDatagramReassemblyTimeout();
720
721 /* Clean possible outdated cached neighbor addresses */
722 NBTimeout();
723
724 /* Call upper layer timeout routines */
725 TCPTimeout();
726 }
727
728
729 VOID IPDispatchProtocol(
730 PNET_TABLE_ENTRY NTE,
731 PIP_PACKET IPPacket)
732 /*
733 * FUNCTION: IP protocol dispatcher
734 * ARGUMENTS:
735 * NTE = Pointer to net table entry which the packet was received on
736 * IPPacket = Pointer to an IP packet that was received
737 * NOTES:
738 * This routine examines the IP header and passes the packet on to the
739 * right upper level protocol receive handler
740 */
741 {
742 UINT Protocol;
743
744 switch (IPPacket->Type) {
745 case IP_ADDRESS_V4:
746 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
747 break;
748 case IP_ADDRESS_V6:
749 /* FIXME: IPv6 adresses not supported */
750 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
751 return;
752 default:
753 Protocol = 0;
754 }
755
756 /* Call the appropriate protocol handler */
757 (*ProtocolTable[Protocol])(NTE, IPPacket);
758 }
759
760
761 PIP_INTERFACE IPCreateInterface(
762 PLLIP_BIND_INFO BindInfo)
763 /*
764 * FUNCTION: Creates an IP interface
765 * ARGUMENTS:
766 * BindInfo = Pointer to link layer to IP binding information
767 * RETURNS:
768 * Pointer to IP_INTERFACE structure, NULL if there was
769 * not enough free resources
770 */
771 {
772 PIP_INTERFACE IF;
773
774 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
775
776 #ifdef DBG
777 if (BindInfo->Address) {
778 PUCHAR A = BindInfo->Address;
779 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
780 A[0], A[1], A[2], A[3], A[4], A[5]));
781 }
782 #endif
783
784 IF = ExAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
785 if (!IF) {
786 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
787 return NULL;
788 }
789
790 INIT_TAG(IF, TAG('F','A','C','E'));
791
792 IF->Free = FreeIF;
793 IF->RefCount = 1;
794 IF->Context = BindInfo->Context;
795 IF->HeaderSize = BindInfo->HeaderSize;
796 if (IF->HeaderSize > MaxLLHeaderSize)
797 MaxLLHeaderSize = IF->HeaderSize;
798
799 IF->MinFrameSize = BindInfo->MinFrameSize;
800 if (IF->MinFrameSize > MinLLFrameSize)
801 MinLLFrameSize = IF->MinFrameSize;
802
803 IF->MTU = BindInfo->MTU;
804 IF->Address = BindInfo->Address;
805 IF->AddressLength = BindInfo->AddressLength;
806 IF->Transmit = BindInfo->Transmit;
807
808 InitializeListHead(&IF->ADEListHead);
809 InitializeListHead(&IF->NTEListHead);
810
811 KeInitializeSpinLock(&IF->Lock);
812
813 return IF;
814 }
815
816
817 VOID IPDestroyInterface(
818 PIP_INTERFACE IF)
819 /*
820 * FUNCTION: Destroys an IP interface
821 * ARGUMENTS:
822 * IF = Pointer to interface to destroy
823 */
824 {
825 KIRQL OldIrql1;
826 KIRQL OldIrql2;
827
828 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
829
830 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
831 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
832 DestroyADEs(IF);
833 DestroyNTEs(IF);
834 KeReleaseSpinLock(&IF->Lock, OldIrql2);
835 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
836
837 #ifdef DBG
838 IF->RefCount--;
839
840 if (IF->RefCount != 0) {
841 TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));
842 }
843 #endif
844 ExFreePool(IF);
845 }
846
847
848 BOOLEAN IPRegisterInterface(
849 PIP_INTERFACE IF)
850 /*
851 * FUNCTION: Registers an IP interface with IP layer
852 * ARGUMENTS:
853 * IF = Pointer to interface to register
854 * RETURNS;
855 * TRUE if interface was successfully registered, FALSE if not
856 */
857 {
858 KIRQL OldIrql;
859 PLIST_ENTRY CurrentEntry;
860 PNET_TABLE_ENTRY Current;
861 PROUTE_CACHE_NODE RCN;
862 PNEIGHBOR_CACHE_ENTRY NCE;
863
864 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
865
866 KeAcquireSpinLock(&IF->Lock, &OldIrql);
867
868 /* Add routes to all NTEs on this interface */
869 CurrentEntry = IF->NTEListHead.Flink;
870 while (CurrentEntry != &IF->NTEListHead) {
871 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
872
873 /* Add a permanent neighbor for this NTE */
874 ReferenceObject(Current->Address);
875 NCE = NBAddNeighbor(IF, Current->Address, IF->Address,
876 IF->AddressLength, NUD_PERMANENT);
877 if (!NCE) {
878 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
879 DereferenceObject(Current->Address);
880 KeReleaseSpinLock(&IF->Lock, OldIrql);
881 return FALSE;
882 }
883 #if 1
884 /* Reference objects for forward information base */
885 ReferenceObject(Current->Address);
886 ReferenceObject(Current->PLE->Prefix);
887 ReferenceObject(Current);
888 /* NCE is already referenced */
889 if (!RouterAddRoute(Current->Address, Current->PLE->Prefix, Current, NCE, 1)) {
890 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
891 DereferenceObject(Current->Address);
892 DereferenceObject(Current->PLE->Prefix);
893 DereferenceObject(Current);
894 DereferenceObject(NCE);
895 }
896 #else
897 RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
898 if (!RCN) {
899 TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
900 DereferenceObject(Current->Address);
901 KeReleaseSpinLock(&IF->Lock, OldIrql);
902 return FALSE;
903 }
904 /* Don't need this any more since the route cache references the NCE */
905 DereferenceObject(NCE);
906 #endif
907 CurrentEntry = CurrentEntry->Flink;
908 }
909
910 /* Add interface to the global interface list */
911 ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);
912
913 KeReleaseSpinLock(&IF->Lock, OldIrql);
914
915 return TRUE;
916 }
917
918
919 VOID IPUnregisterInterface(
920 PIP_INTERFACE IF)
921 /*
922 * FUNCTION: Unregisters an IP interface with IP layer
923 * ARGUMENTS:
924 * IF = Pointer to interface to unregister
925 */
926 {
927 KIRQL OldIrql1;
928 KIRQL OldIrql2;
929 KIRQL OldIrql3;
930 PLIST_ENTRY CurrentEntry;
931 PNET_TABLE_ENTRY Current;
932 PNEIGHBOR_CACHE_ENTRY NCE;
933
934 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
935
936 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
937 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
938
939 /* Remove routes to all NTEs on this interface */
940 CurrentEntry = IF->NTEListHead.Flink;
941 while (CurrentEntry != &IF->NTEListHead) {
942 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
943
944 /* Remove NTE from global net table list */
945 RemoveEntryList(&Current->NTListEntry);
946
947 /* Remove all references from route cache to NTE */
948 RouteInvalidateNTE(Current);
949
950 /* Remove permanent NCE, but first we have to find it */
951 NCE = NBLocateNeighbor(Current->Address);
952 if (NCE) {
953 DereferenceObject(NCE);
954 NBRemoveNeighbor(NCE);
955 }
956
957 CurrentEntry = CurrentEntry->Flink;
958 }
959
960 KeAcquireSpinLock(&InterfaceListLock, &OldIrql3);
961 /* Ouch...three spinlocks acquired! Fortunately
962 we don't unregister interfaces very often */
963 RemoveEntryList(&IF->ListEntry);
964 KeReleaseSpinLock(&InterfaceListLock, OldIrql3);
965
966 KeReleaseSpinLock(&IF->Lock, OldIrql2);
967 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
968 }
969
970
971 VOID IPRegisterProtocol(
972 UINT ProtocolNumber,
973 IP_PROTOCOL_HANDLER Handler)
974 /*
975 * FUNCTION: Registers a handler for an IP protocol number
976 * ARGUMENTS:
977 * ProtocolNumber = Internet Protocol number for which to register handler
978 * Handler = Pointer to handler to be called when a packet is received
979 * NOTES:
980 * To unregister a protocol handler, call this function with Handler = NULL
981 */
982 {
983 #ifdef DBG
984 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
985 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
986 #endif
987
988 ProtocolTable[ProtocolNumber] = Handler;
989 }
990
991
992 VOID DefaultProtocolHandler(
993 PNET_TABLE_ENTRY NTE,
994 PIP_PACKET IPPacket)
995 /*
996 * FUNCTION: Default handler for Internet protocols
997 * ARGUMENTS:
998 * NTE = Pointer to net table entry which the packet was received on
999 * IPPacket = Pointer to an IP packet that was received
1000 */
1001 {
1002 TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
1003 }
1004
1005
1006 NTSTATUS IPStartup(
1007 PDRIVER_OBJECT DriverObject,
1008 PUNICODE_STRING RegistryPath)
1009 /*
1010 * FUNCTION: Initializes the IP subsystem
1011 * ARGUMENTS:
1012 * DriverObject = Pointer to a driver object for this driver
1013 * RegistryPath = Our registry node for configuration parameters
1014 * RETURNS:
1015 * Status of operation
1016 */
1017 {
1018 UINT i;
1019 LARGE_INTEGER DueTime;
1020
1021 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1022
1023 MaxLLHeaderSize = 0;
1024 MinLLFrameSize = 0;
1025
1026 /* Initialize lookaside lists */
1027 ExInitializeNPagedLookasideList(
1028 &IPDRList, /* Lookaside list */
1029 NULL, /* Allocate routine */
1030 NULL, /* Free routine */
1031 0, /* Flags */
1032 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
1033 TAG('I','P','D','R'), /* Tag */
1034 0); /* Depth */
1035
1036 ExInitializeNPagedLookasideList(
1037 &IPPacketList, /* Lookaside list */
1038 NULL, /* Allocate routine */
1039 NULL, /* Free routine */
1040 0, /* Flags */
1041 sizeof(IP_PACKET), /* Size of each entry */
1042 TAG('I','P','P','K'), /* Tag */
1043 0); /* Depth */
1044
1045 ExInitializeNPagedLookasideList(
1046 &IPFragmentList, /* Lookaside list */
1047 NULL, /* Allocate routine */
1048 NULL, /* Free routine */
1049 0, /* Flags */
1050 sizeof(IP_FRAGMENT), /* Size of each entry */
1051 TAG('I','P','F','G'), /* Tag */
1052 0); /* Depth */
1053
1054 ExInitializeNPagedLookasideList(
1055 &IPHoleList, /* Lookaside list */
1056 NULL, /* Allocate routine */
1057 NULL, /* Free routine */
1058 0, /* Flags */
1059 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
1060 TAG('I','P','H','L'), /* Tag */
1061 0); /* Depth */
1062
1063 /* Start routing subsystem */
1064 RouterStartup();
1065
1066 /* Start route cache subsystem */
1067 RouteStartup();
1068
1069 /* Start neighbor cache subsystem */
1070 NBStartup();
1071
1072 /* Fill the protocol dispatch table with pointers
1073 to the default protocol handler */
1074 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
1075 IPRegisterProtocol(i, DefaultProtocolHandler);
1076
1077 /* Register network level protocol receive handlers */
1078 IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
1079
1080 /* Initialize NTE list and protecting lock */
1081 InitializeListHead(&NetTableListHead);
1082 KeInitializeSpinLock(&NetTableListLock);
1083
1084 /* Initialize reassembly list and protecting lock */
1085 InitializeListHead(&ReassemblyListHead);
1086 KeInitializeSpinLock(&ReassemblyListLock);
1087
1088 /* Initialize the prefix list and protecting lock */
1089 InitializeListHead(&PrefixListHead);
1090 KeInitializeSpinLock(&PrefixListLock);
1091
1092 /* Initialize our periodic timer and its associated DPC object. When the
1093 timer expires, the IPTimeout deferred procedure call (DPC) is queued */
1094 KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL);
1095 KeInitializeTimer(&IPTimer);
1096
1097 /* Start the periodic timer with an initial and periodic
1098 relative expiration time of IP_TIMEOUT milliseconds */
1099 DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;
1100 KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);
1101
1102 IPInitialized = TRUE;
1103
1104 return STATUS_SUCCESS;
1105 }
1106
1107
1108 NTSTATUS IPShutdown(
1109 VOID)
1110 /*
1111 * FUNCTION: Shuts down the IP subsystem
1112 * RETURNS:
1113 * Status of operation
1114 */
1115 {
1116 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1117
1118 if (!IPInitialized)
1119 return STATUS_SUCCESS;
1120
1121 /* Cancel timer */
1122 KeCancelTimer(&IPTimer);
1123
1124 /* Shutdown neighbor cache subsystem */
1125 NBShutdown();
1126
1127 /* Shutdown route cache subsystem */
1128 RouteShutdown();
1129
1130 /* Shutdown routing subsystem */
1131 RouterShutdown();
1132
1133 IPFreeReassemblyList();
1134
1135 /* Clear prefix list */
1136 DestroyPLEs();
1137
1138 /* Destroy lookaside lists */
1139 ExDeleteNPagedLookasideList(&IPHoleList);
1140 ExDeleteNPagedLookasideList(&IPDRList);
1141 ExDeleteNPagedLookasideList(&IPPacketList);
1142 ExDeleteNPagedLookasideList(&IPFragmentList);
1143
1144 IPInitialized = FALSE;
1145
1146 return STATUS_SUCCESS;
1147 }
1148
1149 /* EOF */