Temporary workaround to prevent bochs trouble.
[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 INIT_TAG(Address, TAG('A','D','R','S'));
374
375 NTE->Free = FreeNTE;
376
377 NTE->Interface = IF;
378
379 /* One reference is for beeing alive and one reference is for the ADE */
380 NTE->RefCount = 2;
381
382 NTE->Address = Address;
383 /* One reference is for NTE, one reference is given to the
384 address entry, and one reference is given to the prefix
385 list entry */
386 ReferenceObject(Address);
387 ReferenceObject(Address);
388 ReferenceObject(Address);
389
390 /* Create an address entry and add it to the list */
391 ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
392 if (!ADE) {
393 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
394 ExFreePool(NTE);
395 return NULL;
396 }
397
398 /* Create a prefix list entry for unicast address */
399 NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
400 if (!NTE->PLE) {
401 DestroyADE(IF, ADE);
402 ExFreePool(NTE);
403 return NULL;
404 }
405
406 /* Reference the interface for the prefix list entry */
407 ReferenceObject(IF);
408
409 /* Add NTE to the list on the interface */
410 InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
411
412 /* Add NTE to the global net table list */
413 ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
414
415 return NTE;
416 }
417
418
419 VOID DestroyNTE(
420 PIP_INTERFACE IF,
421 PNET_TABLE_ENTRY NTE)
422 /*
423 * FUNCTION: Destroys a net table entry
424 * ARGUMENTS:
425 * IF = Pointer to interface
426 * NTE = Pointer to net table entry
427 * NOTES:
428 * The net table list lock must be held when called
429 * The interface lock must be held when called
430 */
431 {
432 KIRQL OldIrql;
433
434 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE));
435
436 TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
437
438 /* Invalidate the prefix list entry for this NTE */
439 KeAcquireSpinLock(&PrefixListLock, &OldIrql);
440 DestroyPLE(NTE->PLE);
441 KeReleaseSpinLock(&PrefixListLock, OldIrql);
442
443 /* Remove NTE from the interface list */
444 RemoveEntryList(&NTE->IFListEntry);
445 /* Remove NTE from the net table list */
446
447 /* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
448
449 RemoveEntryList(&NTE->NTListEntry);
450
451 */
452
453 /* Dereference the objects that are referenced */
454 DereferenceObject(NTE->Address);
455 DereferenceObject(NTE->Interface);
456 #ifdef DBG
457 NTE->RefCount--;
458
459 if (NTE->RefCount != 0) {
460 TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount));
461 }
462 #endif
463 /* And free the NTE */
464 ExFreePool(NTE);
465 }
466
467
468 VOID DestroyNTEs(
469 PIP_INTERFACE IF)
470 /*
471 * FUNCTION: Destroys all net table entries on an interface
472 * ARGUMENTS:
473 * IF = Pointer to interface
474 * NOTES:
475 * The net table list lock must be held when called
476 * The interface lock may be held when called
477 */
478 {
479 PLIST_ENTRY CurrentEntry;
480 PLIST_ENTRY NextEntry;
481 PNET_TABLE_ENTRY Current;
482
483 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
484
485 /* Search the list and remove every NTE we find */
486 CurrentEntry = IF->NTEListHead.Flink;
487 while (CurrentEntry != &IF->NTEListHead) {
488 NextEntry = CurrentEntry->Flink;
489 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
490 /* Destroy the NTE */
491 DestroyNTE(IF, Current);
492 CurrentEntry = NextEntry;
493 }
494 }
495
496
497 PNET_TABLE_ENTRY IPLocateNTEOnInterface(
498 PIP_INTERFACE IF,
499 PIP_ADDRESS Address,
500 PUINT AddressType)
501 /*
502 * FUNCTION: Locates an NTE on an interface
503 * ARGUMENTS:
504 * IF = Pointer to interface
505 * Address = Pointer to IP address
506 * AddressType = Address of type of IP address
507 * NOTES:
508 * If found, the NTE is referenced for the caller. The caller is
509 * responsible for dereferencing after use
510 * RETURNS:
511 * Pointer to net table entry, NULL if none was found
512 */
513 {
514 KIRQL OldIrql;
515 PLIST_ENTRY CurrentEntry;
516 PADDRESS_ENTRY Current;
517
518 // TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n",
519 // IF, Address, AddressType));
520
521 // TI_DbgPrint(DEBUG_IP, ("Address (%s) AddressType (0x%X).\n", A2S(Address)));
522
523 KeAcquireSpinLock(&IF->Lock, &OldIrql);
524
525 /* Search the list and return the NTE if found */
526 CurrentEntry = IF->ADEListHead.Flink;
527
528 if (CurrentEntry == &IF->ADEListHead) {
529 TI_DbgPrint(DEBUG_IP, ("NTE list is empty!!!\n"));
530 }
531
532 while (CurrentEntry != &IF->ADEListHead) {
533 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
534 if (AddrIsEqual(Address, Current->Address)) {
535 ReferenceObject(Current->NTE);
536 *AddressType = Current->Type;
537 KeReleaseSpinLock(&IF->Lock, OldIrql);
538 return Current->NTE;
539 }
540 else {
541 TI_DbgPrint(DEBUG_IP, ("CurrentEntry = 0x%X != &IF->ADEListHead = 0x%X.\n", CurrentEntry, &IF->ADEListHead));
542 }
543 CurrentEntry = CurrentEntry->Flink;
544 }
545
546 KeReleaseSpinLock(&IF->Lock, OldIrql);
547
548 return NULL;
549 }
550
551
552 PNET_TABLE_ENTRY IPLocateNTE(
553 PIP_ADDRESS Address,
554 PUINT AddressType)
555 /*
556 * FUNCTION: Locates an NTE for the network Address is on
557 * ARGUMENTS:
558 * Address = Pointer to an address to find associated NTE of
559 * AddressType = Address of address type
560 * NOTES:
561 * If found the NTE is referenced for the caller. The caller is
562 * responsible for dereferencing after use
563 * RETURNS:
564 * Pointer to NTE if the address was found, NULL if not.
565 */
566 {
567 KIRQL OldIrql;
568 PLIST_ENTRY CurrentEntry;
569 PNET_TABLE_ENTRY Current;
570 PNET_TABLE_ENTRY NTE;
571
572 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
573 // Address, AddressType));
574
575 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
576
577 KeAcquireSpinLock(&NetTableListLock, &OldIrql);
578
579 /* Search the list and return the NTE if found */
580 CurrentEntry = NetTableListHead.Flink;
581 while (CurrentEntry != &NetTableListHead) {
582 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);
583 NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);
584 if (NTE) {
585 ReferenceObject(NTE);
586 KeReleaseSpinLock(&NetTableListLock, OldIrql);
587 return NTE;
588 }
589 CurrentEntry = CurrentEntry->Flink;
590 }
591
592 KeReleaseSpinLock(&NetTableListLock, OldIrql);
593
594 return NULL;
595 }
596
597
598 PADDRESS_ENTRY IPLocateADE(
599 PIP_ADDRESS Address,
600 UINT AddressType)
601 /*
602 * FUNCTION: Locates an ADE for the address
603 * ARGUMENTS:
604 * Address = Pointer to an address to find associated ADE of
605 * AddressType = Type of address
606 * RETURNS:
607 * Pointer to ADE if the address was found, NULL if not.
608 * NOTES:
609 * If found the ADE is referenced for the caller. The caller is
610 * responsible for dereferencing after use
611 */
612 {
613 KIRQL OldIrql;
614 PLIST_ENTRY CurrentIFEntry;
615 PLIST_ENTRY CurrentADEEntry;
616 PIP_INTERFACE CurrentIF;
617 PADDRESS_ENTRY CurrentADE;
618
619 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
620 // Address, AddressType));
621
622 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
623
624 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
625
626 /* Search the interface list */
627 CurrentIFEntry = InterfaceListHead.Flink;
628 while (CurrentIFEntry != &InterfaceListHead) {
629 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
630
631 /* Search the address entry list and return the ADE if found */
632 CurrentADEEntry = CurrentIF->ADEListHead.Flink;
633 while (CurrentADEEntry != &CurrentIF->ADEListHead) {
634 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
635 if ((AddrIsEqual(Address, CurrentADE->Address)) &&
636 (CurrentADE->Type == AddressType)) {
637 ReferenceObject(CurrentADE);
638 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
639 return CurrentADE;
640 }
641 CurrentADEEntry = CurrentADEEntry->Flink;
642 }
643 CurrentIFEntry = CurrentIFEntry->Flink;
644 }
645
646 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
647
648 return NULL;
649 }
650
651
652 PADDRESS_ENTRY IPGetDefaultADE(
653 UINT AddressType)
654 /*
655 * FUNCTION: Returns a default address entry
656 * ARGUMENTS:
657 * AddressType = Type of address
658 * RETURNS:
659 * Pointer to ADE if found, NULL if not.
660 * NOTES:
661 * Loopback interface is only considered if it is the only interface.
662 * If found, the address entry is referenced
663 */
664 {
665 KIRQL OldIrql;
666 PLIST_ENTRY CurrentIFEntry;
667 PLIST_ENTRY CurrentADEEntry;
668 PIP_INTERFACE CurrentIF;
669 PADDRESS_ENTRY CurrentADE;
670 BOOLEAN LoopbackIsRegistered = FALSE;
671
672 TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
673
674 KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
675
676 /* Search the interface list */
677 CurrentIFEntry = InterfaceListHead.Flink;
678 while (CurrentIFEntry != &InterfaceListHead) {
679 CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
680
681 if (CurrentIF != Loopback) {
682 /* Search the address entry list and return the first appropriate ADE found */
683 CurrentADEEntry = CurrentIF->ADEListHead.Flink;
684 while (CurrentADEEntry != &CurrentIF->ADEListHead) {
685 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
686 if (CurrentADE->Type == AddressType)
687 ReferenceObject(CurrentADE);
688 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
689 return CurrentADE;
690 }
691 CurrentADEEntry = CurrentADEEntry->Flink;
692 } else
693 LoopbackIsRegistered = TRUE;
694 CurrentIFEntry = CurrentIFEntry->Flink;
695 }
696
697 /* No address was found. Use loopback interface if available */
698 if (LoopbackIsRegistered) {
699 CurrentADEEntry = Loopback->ADEListHead.Flink;
700 while (CurrentADEEntry != &Loopback->ADEListHead) {
701 CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
702 if (CurrentADE->Type == AddressType) {
703 ReferenceObject(CurrentADE);
704 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
705 return CurrentADE;
706 }
707 CurrentADEEntry = CurrentADEEntry->Flink;
708 }
709 }
710
711 KeReleaseSpinLock(&InterfaceListLock, OldIrql);
712
713 return NULL;
714 }
715
716
717 VOID STDCALL IPTimeout(
718 PKDPC Dpc,
719 PVOID DeferredContext,
720 PVOID SystemArgument1,
721 PVOID SystemArgument2)
722 /*
723 * FUNCTION: Timeout DPC
724 * ARGUMENTS:
725 * Dpc = Pointer to our DPC object
726 * DeferredContext = Pointer to context information (unused)
727 * SystemArgument1 = Unused
728 * SystemArgument2 = Unused
729 * NOTES:
730 * This routine is dispatched once in a while to do maintainance jobs
731 */
732 {
733 /* Check if datagram fragments have taken too long to assemble */
734 IPDatagramReassemblyTimeout();
735
736 /* Clean possible outdated cached neighbor addresses */
737 NBTimeout();
738
739 /* Call upper layer timeout routines */
740 TCPTimeout();
741 }
742
743
744 VOID IPDispatchProtocol(
745 PNET_TABLE_ENTRY NTE,
746 PIP_PACKET IPPacket)
747 /*
748 * FUNCTION: IP protocol dispatcher
749 * ARGUMENTS:
750 * NTE = Pointer to net table entry which the packet was received on
751 * IPPacket = Pointer to an IP packet that was received
752 * NOTES:
753 * This routine examines the IP header and passes the packet on to the
754 * right upper level protocol receive handler
755 */
756 {
757 UINT Protocol;
758
759 switch (IPPacket->Type) {
760 case IP_ADDRESS_V4:
761 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
762 break;
763 case IP_ADDRESS_V6:
764 /* FIXME: IPv6 adresses not supported */
765 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
766 return;
767 default:
768 Protocol = 0;
769 }
770
771 /* Call the appropriate protocol handler */
772 (*ProtocolTable[Protocol])(NTE, IPPacket);
773 }
774
775
776 PIP_INTERFACE IPCreateInterface(
777 PLLIP_BIND_INFO BindInfo)
778 /*
779 * FUNCTION: Creates an IP interface
780 * ARGUMENTS:
781 * BindInfo = Pointer to link layer to IP binding information
782 * RETURNS:
783 * Pointer to IP_INTERFACE structure, NULL if there was
784 * not enough free resources
785 */
786 {
787 PIP_INTERFACE IF;
788
789 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
790
791 #ifdef DBG
792 if (BindInfo->Address) {
793 PUCHAR A = BindInfo->Address;
794 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
795 A[0], A[1], A[2], A[3], A[4], A[5]));
796 }
797 #endif
798
799 IF = ExAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
800 if (!IF) {
801 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
802 return NULL;
803 }
804
805 INIT_TAG(IF, TAG('F','A','C','E'));
806
807 IF->Free = FreeIF;
808 IF->RefCount = 1;
809 IF->Context = BindInfo->Context;
810 IF->HeaderSize = BindInfo->HeaderSize;
811 if (IF->HeaderSize > MaxLLHeaderSize)
812 MaxLLHeaderSize = IF->HeaderSize;
813
814 IF->MinFrameSize = BindInfo->MinFrameSize;
815 if (IF->MinFrameSize > MinLLFrameSize)
816 MinLLFrameSize = IF->MinFrameSize;
817
818 IF->MTU = BindInfo->MTU;
819 IF->Address = BindInfo->Address;
820 IF->AddressLength = BindInfo->AddressLength;
821 IF->Transmit = BindInfo->Transmit;
822
823 InitializeListHead(&IF->ADEListHead);
824 InitializeListHead(&IF->NTEListHead);
825
826 KeInitializeSpinLock(&IF->Lock);
827
828 return IF;
829 }
830
831
832 VOID IPDestroyInterface(
833 PIP_INTERFACE IF)
834 /*
835 * FUNCTION: Destroys an IP interface
836 * ARGUMENTS:
837 * IF = Pointer to interface to destroy
838 */
839 {
840 KIRQL OldIrql1;
841 KIRQL OldIrql2;
842
843 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
844
845 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
846 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
847 DestroyADEs(IF);
848 DestroyNTEs(IF);
849 KeReleaseSpinLock(&IF->Lock, OldIrql2);
850 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
851
852 #ifdef DBG
853 IF->RefCount--;
854
855 if (IF->RefCount != 0) {
856 TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));
857 }
858 #endif
859 ExFreePool(IF);
860 }
861
862
863 BOOLEAN IPRegisterInterface(
864 PIP_INTERFACE IF)
865 /*
866 * FUNCTION: Registers an IP interface with IP layer
867 * ARGUMENTS:
868 * IF = Pointer to interface to register
869 * RETURNS;
870 * TRUE if interface was successfully registered, FALSE if not
871 */
872 {
873 KIRQL OldIrql;
874 PLIST_ENTRY CurrentEntry;
875 PNET_TABLE_ENTRY Current;
876 PROUTE_CACHE_NODE RCN;
877 PNEIGHBOR_CACHE_ENTRY NCE;
878
879 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
880
881 KeAcquireSpinLock(&IF->Lock, &OldIrql);
882
883 /* Add routes to all NTEs on this interface */
884 CurrentEntry = IF->NTEListHead.Flink;
885 while (CurrentEntry != &IF->NTEListHead) {
886 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
887
888 /* Add a permanent neighbor for this NTE */
889 ReferenceObject(Current->Address);
890 NCE = NBAddNeighbor(IF, Current->Address, IF->Address,
891 IF->AddressLength, NUD_PERMANENT);
892 if (!NCE) {
893 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
894 DereferenceObject(Current->Address);
895 KeReleaseSpinLock(&IF->Lock, OldIrql);
896 return FALSE;
897 }
898 #if 1
899 /* Reference objects for forward information base */
900 ReferenceObject(Current->Address);
901 ReferenceObject(Current->PLE->Prefix);
902 ReferenceObject(Current);
903 /* NCE is already referenced */
904 if (!RouterAddRoute(Current->Address, Current->PLE->Prefix, Current, NCE, 1)) {
905 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
906 DereferenceObject(Current->Address);
907 DereferenceObject(Current->PLE->Prefix);
908 DereferenceObject(Current);
909 DereferenceObject(NCE);
910 }
911 #else
912 RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
913 if (!RCN) {
914 TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
915 DereferenceObject(Current->Address);
916 KeReleaseSpinLock(&IF->Lock, OldIrql);
917 return FALSE;
918 }
919 /* Don't need this any more since the route cache references the NCE */
920 DereferenceObject(NCE);
921 #endif
922 CurrentEntry = CurrentEntry->Flink;
923 }
924
925 /* Add interface to the global interface list */
926 ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);
927
928 KeReleaseSpinLock(&IF->Lock, OldIrql);
929
930 return TRUE;
931 }
932
933
934 VOID IPUnregisterInterface(
935 PIP_INTERFACE IF)
936 /*
937 * FUNCTION: Unregisters an IP interface with IP layer
938 * ARGUMENTS:
939 * IF = Pointer to interface to unregister
940 */
941 {
942 KIRQL OldIrql1;
943 KIRQL OldIrql2;
944 KIRQL OldIrql3;
945 PLIST_ENTRY CurrentEntry;
946 PNET_TABLE_ENTRY Current;
947 PNEIGHBOR_CACHE_ENTRY NCE;
948
949 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
950
951 KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
952 KeAcquireSpinLock(&IF->Lock, &OldIrql2);
953
954 /* Remove routes to all NTEs on this interface */
955 CurrentEntry = IF->NTEListHead.Flink;
956 while (CurrentEntry != &IF->NTEListHead) {
957 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
958
959 /* Remove NTE from global net table list */
960 RemoveEntryList(&Current->NTListEntry);
961
962 /* Remove all references from route cache to NTE */
963 RouteInvalidateNTE(Current);
964
965 /* Remove permanent NCE, but first we have to find it */
966 NCE = NBLocateNeighbor(Current->Address);
967 if (NCE) {
968 DereferenceObject(NCE);
969 NBRemoveNeighbor(NCE);
970 }
971
972 CurrentEntry = CurrentEntry->Flink;
973 }
974
975 KeAcquireSpinLock(&InterfaceListLock, &OldIrql3);
976 /* Ouch...three spinlocks acquired! Fortunately
977 we don't unregister interfaces very often */
978 RemoveEntryList(&IF->ListEntry);
979 KeReleaseSpinLock(&InterfaceListLock, OldIrql3);
980
981 KeReleaseSpinLock(&IF->Lock, OldIrql2);
982 KeReleaseSpinLock(&NetTableListLock, OldIrql1);
983 }
984
985
986 VOID IPRegisterProtocol(
987 UINT ProtocolNumber,
988 IP_PROTOCOL_HANDLER Handler)
989 /*
990 * FUNCTION: Registers a handler for an IP protocol number
991 * ARGUMENTS:
992 * ProtocolNumber = Internet Protocol number for which to register handler
993 * Handler = Pointer to handler to be called when a packet is received
994 * NOTES:
995 * To unregister a protocol handler, call this function with Handler = NULL
996 */
997 {
998 #ifdef DBG
999 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
1000 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
1001 #endif
1002
1003 ProtocolTable[ProtocolNumber] = Handler;
1004 }
1005
1006
1007 VOID DefaultProtocolHandler(
1008 PNET_TABLE_ENTRY NTE,
1009 PIP_PACKET IPPacket)
1010 /*
1011 * FUNCTION: Default handler for Internet protocols
1012 * ARGUMENTS:
1013 * NTE = Pointer to net table entry which the packet was received on
1014 * IPPacket = Pointer to an IP packet that was received
1015 */
1016 {
1017 TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
1018 }
1019
1020
1021 NTSTATUS IPStartup(
1022 PDRIVER_OBJECT DriverObject,
1023 PUNICODE_STRING RegistryPath)
1024 /*
1025 * FUNCTION: Initializes the IP subsystem
1026 * ARGUMENTS:
1027 * DriverObject = Pointer to a driver object for this driver
1028 * RegistryPath = Our registry node for configuration parameters
1029 * RETURNS:
1030 * Status of operation
1031 */
1032 {
1033 UINT i;
1034 LARGE_INTEGER DueTime;
1035
1036 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1037
1038 MaxLLHeaderSize = 0;
1039 MinLLFrameSize = 0;
1040
1041 /* Initialize lookaside lists */
1042 ExInitializeNPagedLookasideList(
1043 &IPDRList, /* Lookaside list */
1044 NULL, /* Allocate routine */
1045 NULL, /* Free routine */
1046 0, /* Flags */
1047 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
1048 TAG('I','P','D','R'), /* Tag */
1049 0); /* Depth */
1050
1051 ExInitializeNPagedLookasideList(
1052 &IPPacketList, /* Lookaside list */
1053 NULL, /* Allocate routine */
1054 NULL, /* Free routine */
1055 0, /* Flags */
1056 sizeof(IP_PACKET), /* Size of each entry */
1057 TAG('I','P','P','K'), /* Tag */
1058 0); /* Depth */
1059
1060 ExInitializeNPagedLookasideList(
1061 &IPFragmentList, /* Lookaside list */
1062 NULL, /* Allocate routine */
1063 NULL, /* Free routine */
1064 0, /* Flags */
1065 sizeof(IP_FRAGMENT), /* Size of each entry */
1066 TAG('I','P','F','G'), /* Tag */
1067 0); /* Depth */
1068
1069 ExInitializeNPagedLookasideList(
1070 &IPHoleList, /* Lookaside list */
1071 NULL, /* Allocate routine */
1072 NULL, /* Free routine */
1073 0, /* Flags */
1074 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
1075 TAG('I','P','H','L'), /* Tag */
1076 0); /* Depth */
1077
1078 /* Start routing subsystem */
1079 RouterStartup();
1080
1081 /* Start route cache subsystem */
1082 RouteStartup();
1083
1084 /* Start neighbor cache subsystem */
1085 NBStartup();
1086
1087 /* Fill the protocol dispatch table with pointers
1088 to the default protocol handler */
1089 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
1090 IPRegisterProtocol(i, DefaultProtocolHandler);
1091
1092 /* Register network level protocol receive handlers */
1093 IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
1094
1095 /* Initialize NTE list and protecting lock */
1096 InitializeListHead(&NetTableListHead);
1097 KeInitializeSpinLock(&NetTableListLock);
1098
1099 /* Initialize reassembly list and protecting lock */
1100 InitializeListHead(&ReassemblyListHead);
1101 KeInitializeSpinLock(&ReassemblyListLock);
1102
1103 /* Initialize the prefix list and protecting lock */
1104 InitializeListHead(&PrefixListHead);
1105 KeInitializeSpinLock(&PrefixListLock);
1106
1107 /* Initialize our periodic timer and its associated DPC object. When the
1108 timer expires, the IPTimeout deferred procedure call (DPC) is queued */
1109 KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL);
1110 KeInitializeTimer(&IPTimer);
1111
1112 /* Start the periodic timer with an initial and periodic
1113 relative expiration time of IP_TIMEOUT milliseconds */
1114 DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;
1115 KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);
1116
1117 IPInitialized = TRUE;
1118
1119 return STATUS_SUCCESS;
1120 }
1121
1122
1123 NTSTATUS IPShutdown(
1124 VOID)
1125 /*
1126 * FUNCTION: Shuts down the IP subsystem
1127 * RETURNS:
1128 * Status of operation
1129 */
1130 {
1131 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
1132
1133 if (!IPInitialized)
1134 return STATUS_SUCCESS;
1135
1136 /* Cancel timer */
1137 KeCancelTimer(&IPTimer);
1138
1139 /* Shutdown neighbor cache subsystem */
1140 NBShutdown();
1141
1142 /* Shutdown route cache subsystem */
1143 RouteShutdown();
1144
1145 /* Shutdown routing subsystem */
1146 RouterShutdown();
1147
1148 IPFreeReassemblyList();
1149
1150 /* Clear prefix list */
1151 DestroyPLEs();
1152
1153 /* Destroy lookaside lists */
1154 ExDeleteNPagedLookasideList(&IPHoleList);
1155 ExDeleteNPagedLookasideList(&IPDRList);
1156 ExDeleteNPagedLookasideList(&IPPacketList);
1157 ExDeleteNPagedLookasideList(&IPFragmentList);
1158
1159 IPInitialized = FALSE;
1160
1161 return STATUS_SUCCESS;
1162 }
1163
1164 /* EOF */