c9710e751bebb59297455394e51e2c3d94a78ad2
[reactos.git] / reactos / drivers / lib / 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 UINT MaxLLHeaderSize; /* Largest maximum header size */
19 UINT MinLLFrameSize; /* Largest minimum frame size */
20 BOOLEAN IPInitialized = FALSE;
21 NPAGED_LOOKASIDE_LIST IPPacketList;
22 /* Work around calling timer at Dpc level */
23
24 IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
25
26
27 VOID FreePacket(
28 PVOID Object)
29 /*
30 * FUNCTION: Frees an IP packet object
31 * ARGUMENTS:
32 * Object = Pointer to an IP packet structure
33 */
34 {
35 TcpipFreeToNPagedLookasideList(&IPPacketList, Object);
36 }
37
38
39 VOID DontFreePacket(
40 PVOID Object)
41 /*
42 * FUNCTION: Do nothing for when the IPPacket struct is part of another
43 * ARGUMENTS:
44 * Object = Pointer to an IP packet structure
45 */
46 {
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,
88 PIP_ADDRESS Address,
89 UCHAR Type,
90 PNET_TABLE_ENTRY NTE)
91 /*
92 * FUNCTION: Creates an address entry and binds it to an interface
93 * ARGUMENTS:
94 * IF = Pointer to interface
95 * Address = Pointer to referenced interface address
96 * Type = Type of address (ADE_*)
97 * NTE = Pointer to net table entry
98 * RETURNS:
99 * Pointer to ADE, NULL if there was not enough free resources
100 * NOTES:
101 * The interface lock must be held when called. The address entry
102 * retains a reference to the provided address and NTE. The caller
103 * is responsible for referencing the these before calling.
104 * As long as you have referenced an ADE you can safely use the
105 * address and NTE as the ADE references both
106 */
107 {
108 PADDRESS_ENTRY ADE;
109
110 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n",
111 IF, Address, Type, NTE));
112
113 TI_DbgPrint(DEBUG_IP, ("Address (%s) NTE (%s).\n",
114 A2S(Address), A2S(NTE->Address)));
115
116 /* Allocate space for an ADE and set it up */
117 ADE = exAllocatePool(NonPagedPool, sizeof(ADDRESS_ENTRY));
118 if (!ADE) {
119 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
120 return NULL;
121 }
122
123 INIT_TAG(ADE, TAG('A','D','E',' '));
124 ADE->Free = FreeADE;
125 ADE->NTE = NTE;
126 ADE->Type = Type;
127 RtlCopyMemory(&ADE->Address,Address,sizeof(ADE->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 /* And free the ADE */
156 FreeADE(ADE);
157 }
158
159
160 VOID DestroyADEs(
161 PIP_INTERFACE IF)
162 /*
163 * FUNCTION: Destroys all address entries on an interface
164 * ARGUMENTS:
165 * IF = Pointer to interface
166 * NOTES:
167 * The interface lock must be held when called
168 */
169 {
170 PLIST_ENTRY CurrentEntry;
171 PLIST_ENTRY NextEntry;
172 PADDRESS_ENTRY Current;
173
174 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
175
176 /* Search the list and remove every ADE we find */
177 CurrentEntry = IF->ADEListHead.Flink;
178 while (CurrentEntry != &IF->ADEListHead) {
179 NextEntry = CurrentEntry->Flink;
180 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
181 /* Destroy the ADE */
182 DestroyADE(IF, Current);
183 CurrentEntry = NextEntry;
184 }
185 }
186
187
188 PIP_PACKET IPCreatePacket(ULONG Type)
189 /*
190 * FUNCTION: Creates an IP packet object
191 * ARGUMENTS:
192 * Type = Type of IP packet
193 * RETURNS:
194 * Pointer to the created IP packet. NULL if there was not enough free resources.
195 */
196 {
197 PIP_PACKET IPPacket;
198
199 IPPacket = TcpipAllocateFromNPagedLookasideList(&IPPacketList);
200 if (!IPPacket)
201 return NULL;
202
203 /* FIXME: Is this needed? */
204 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
205
206 INIT_TAG(IPPacket, TAG('I','P','K','T'));
207
208 IPPacket->Free = FreePacket;
209 IPPacket->Type = Type;
210 IPPacket->HeaderSize = 20;
211
212 return IPPacket;
213 }
214
215 PIP_PACKET IPInitializePacket(
216 PIP_PACKET IPPacket,
217 ULONG Type)
218 /*
219 * FUNCTION: Creates an IP packet object
220 * ARGUMENTS:
221 * Type = Type of IP packet
222 * RETURNS:
223 * Pointer to the created IP packet. NULL if there was not enough free resources.
224 */
225 {
226 /* FIXME: Is this needed? */
227 RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
228
229 INIT_TAG(IPPacket, TAG('I','P','K','T'));
230
231 IPPacket->Free = DontFreePacket;
232 IPPacket->Type = Type;
233
234 return IPPacket;
235 }
236
237
238 PNET_TABLE_ENTRY IPCreateNTE(
239 PIP_INTERFACE IF,
240 PIP_ADDRESS Address,
241 UINT PrefixLength)
242 /*
243 * FUNCTION: Creates a net table entry and binds it to an interface
244 * ARGUMENTS:
245 * IF = Pointer to interface
246 * Address = Pointer to interface address
247 * PrefixLength = Length of prefix
248 * RETURNS:
249 * Pointer to NTE, NULL if there was not enough free resources
250 * NOTES:
251 * The interface lock must be held when called.
252 * The net table entry retains a reference to the interface and
253 * the provided address. The caller is responsible for providing
254 * these references
255 */
256 {
257 PNET_TABLE_ENTRY NTE;
258 PADDRESS_ENTRY ADE;
259
260 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF, Address, PrefixLength));
261
262 TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
263
264 /* Allocate room for an NTE */
265 NTE = exAllocatePool(NonPagedPool, sizeof(NET_TABLE_ENTRY));
266 if (!NTE) {
267 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
268 return NULL;
269 }
270
271 INIT_TAG(NTE, TAG('N','T','E',' '));
272 INIT_TAG(Address, TAG('A','D','R','S'));
273
274 NTE->Free = FreeNTE;
275
276 NTE->Interface = IF;
277
278 NTE->Address = Address;
279
280 /* Create an address entry and add it to the list */
281 ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
282 if (!ADE) {
283 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
284 exFreePool(NTE);
285 return NULL;
286 }
287
288 /* Create a prefix list entry for unicast address */
289 NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
290 if (!NTE->PLE) {
291 DestroyADE(IF, ADE);
292 exFreePool(NTE);
293 return NULL;
294 }
295
296 /* Add NTE to the list on the interface */
297 InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
298
299 /* Add NTE to the global net table list */
300 TcpipInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
301
302 return NTE;
303 }
304
305
306 VOID DestroyNTE(
307 PIP_INTERFACE IF,
308 PNET_TABLE_ENTRY NTE)
309 /*
310 * FUNCTION: Destroys a net table entry
311 * ARGUMENTS:
312 * IF = Pointer to interface
313 * NTE = Pointer to net table entry
314 * NOTES:
315 * The net table list lock must be held when called
316 * The interface lock must be held when called
317 */
318 {
319 KIRQL OldIrql;
320
321 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE));
322
323 TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
324
325 /* Invalidate the prefix list entry for this NTE */
326 TcpipAcquireSpinLock(&PrefixListLock, &OldIrql);
327 DestroyPLE(NTE->PLE);
328 TcpipReleaseSpinLock(&PrefixListLock, OldIrql);
329
330 /* Remove NTE from the interface list */
331 RemoveEntryList(&NTE->IFListEntry);
332 /* Remove NTE from the net table list */
333
334 /* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
335
336 RemoveEntryList(&NTE->NTListEntry);
337
338 */
339
340 /* And free the NTE */
341 exFreePool(NTE);
342 }
343
344
345 VOID DestroyNTEs(
346 PIP_INTERFACE IF)
347 /*
348 * FUNCTION: Destroys all net table entries on an interface
349 * ARGUMENTS:
350 * IF = Pointer to interface
351 * NOTES:
352 * The net table list lock must be held when called
353 * The interface lock may be held when called
354 */
355 {
356 PLIST_ENTRY CurrentEntry;
357 PLIST_ENTRY NextEntry;
358 PNET_TABLE_ENTRY Current;
359
360 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
361
362 /* Search the list and remove every NTE we find */
363 CurrentEntry = IF->NTEListHead.Flink;
364 while (CurrentEntry != &IF->NTEListHead) {
365 NextEntry = CurrentEntry->Flink;
366 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
367 /* Destroy the NTE */
368 DestroyNTE(IF, Current);
369 CurrentEntry = NextEntry;
370 }
371 }
372
373
374 PNET_TABLE_ENTRY IPLocateNTEOnInterface(
375 PIP_INTERFACE IF,
376 PIP_ADDRESS Address,
377 PUINT AddressType)
378 /*
379 * FUNCTION: Locates an NTE on an interface
380 * ARGUMENTS:
381 * IF = Pointer to interface
382 * Address = Pointer to IP address
383 * AddressType = Address of type of IP address
384 * NOTES:
385 * If found, the NTE is referenced for the caller. The caller is
386 * responsible for dereferencing after use
387 * RETURNS:
388 * Pointer to net table entry, NULL if none was found
389 */
390 {
391 KIRQL OldIrql;
392 PLIST_ENTRY CurrentEntry;
393 PADDRESS_ENTRY Current;
394
395 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (%s) AddressType (0x%X).\n",
396 IF, A2S(Address), AddressType));
397
398 if( !IF ) return NULL;
399
400 TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
401
402 /* Search the list and return the NTE if found */
403 CurrentEntry = IF->ADEListHead.Flink;
404
405 if (CurrentEntry == &IF->ADEListHead) {
406 TI_DbgPrint(DEBUG_IP, ("NTE list is empty!!!\n"));
407 }
408
409 while (CurrentEntry != &IF->ADEListHead) {
410 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
411 if (AddrIsEqual(Address, &Current->Address)) {
412 *AddressType = Current->Type;
413 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
414 return Current->NTE;
415 }
416 CurrentEntry = CurrentEntry->Flink;
417 }
418
419 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
420
421 return NULL;
422 }
423
424
425 PNET_TABLE_ENTRY IPLocateNTE(
426 PIP_ADDRESS Address,
427 PUINT AddressType)
428 /*
429 * FUNCTION: Locates an NTE for the network Address is on
430 * ARGUMENTS:
431 * Address = Pointer to an address to find associated NTE of
432 * AddressType = Address of address type
433 * NOTES:
434 * If found the NTE is referenced for the caller. The caller is
435 * responsible for dereferencing after use
436 * RETURNS:
437 * Pointer to NTE if the address was found, NULL if not.
438 */
439 {
440 KIRQL OldIrql;
441 PLIST_ENTRY CurrentEntry;
442 PNET_TABLE_ENTRY Current;
443 PNET_TABLE_ENTRY NTE;
444
445 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
446 // Address, AddressType));
447
448 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
449
450 TcpipAcquireSpinLock(&NetTableListLock, &OldIrql);
451
452 /* Search the list and return the NTE if found */
453 CurrentEntry = NetTableListHead.Flink;
454 while (CurrentEntry != &NetTableListHead) {
455 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);
456 NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);
457 if (NTE) {
458 TcpipReleaseSpinLock(&NetTableListLock, OldIrql);
459 return NTE;
460 }
461 CurrentEntry = CurrentEntry->Flink;
462 }
463
464 TcpipReleaseSpinLock(&NetTableListLock, OldIrql);
465
466 return NULL;
467 }
468
469
470 PADDRESS_ENTRY IPLocateADE(
471 PIP_ADDRESS Address,
472 UINT AddressType)
473 /*
474 * FUNCTION: Locates an ADE for the address
475 * ARGUMENTS:
476 * Address = Pointer to an address to find associated ADE of
477 * AddressType = Type of address
478 * RETURNS:
479 * Pointer to ADE if the address was found, NULL if not.
480 * NOTES:
481 * If found the ADE is referenced for the caller. The caller is
482 * responsible for dereferencing after use
483 */
484 {
485 KIRQL OldIrql;
486 IF_LIST_ITER(CurrentIF);
487 ADE_LIST_ITER(CurrentADE);
488
489 // TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
490 // Address, AddressType));
491
492 // TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
493
494 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
495
496 /* Search the interface list */
497 ForEachInterface(CurrentIF) {
498 /* Search the address entry list and return the ADE if found */
499 ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
500 if ((AddrIsEqual(Address, &CurrentADE->Address)) &&
501 (CurrentADE->Type == AddressType)) {
502 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
503 return CurrentADE;
504 }
505 } EndFor(CurrentADE);
506 } EndFor(CurrentIF);
507
508 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
509
510 return NULL;
511 }
512
513
514 PADDRESS_ENTRY IPGetDefaultADE(
515 UINT AddressType)
516 /*
517 * FUNCTION: Returns a default address entry
518 * ARGUMENTS:
519 * AddressType = Type of address
520 * RETURNS:
521 * Pointer to ADE if found, NULL if not.
522 * NOTES:
523 * Loopback interface is only considered if it is the only interface.
524 * If found, the address entry is referenced
525 */
526 {
527 KIRQL OldIrql;
528 ADE_LIST_ITER(CurrentADE);
529 IF_LIST_ITER(CurrentIF);
530 BOOLEAN LoopbackIsRegistered = FALSE;
531
532 TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
533
534 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
535
536 /* Search the interface list */
537 ForEachInterface(CurrentIF) {
538 if (CurrentIF != Loopback) {
539 /* Search the address entry list and return the first appropriate ADE found */
540 TI_DbgPrint(DEBUG_IP,("Checking interface %x\n", CurrentIF));
541 ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
542 if (CurrentADE->Type == AddressType) {
543 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
544 return CurrentADE;
545 }
546 } EndFor(CurrentADE);
547 } else
548 LoopbackIsRegistered = TRUE;
549 } EndFor(CurrentIF);
550
551 /* No address was found. Use loopback interface if available */
552 if (LoopbackIsRegistered) {
553 ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
554 if (CurrentADE->Type == AddressType) {
555 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
556 return CurrentADE;
557 }
558 } EndFor(CurrentADE);
559 }
560
561 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
562
563 return NULL;
564 }
565
566 void STDCALL IPTimeout( PVOID Context ) {
567 /* Check if datagram fragments have taken too long to assemble */
568 IPDatagramReassemblyTimeout();
569
570 /* Clean possible outdated cached neighbor addresses */
571 NBTimeout();
572
573 /* Call upper layer timeout routines */
574 TCPTimeout();
575 }
576
577
578 VOID IPDispatchProtocol(
579 PNET_TABLE_ENTRY NTE,
580 PIP_PACKET IPPacket)
581 /*
582 * FUNCTION: IP protocol dispatcher
583 * ARGUMENTS:
584 * NTE = Pointer to net table entry which the packet was received on
585 * IPPacket = Pointer to an IP packet that was received
586 * NOTES:
587 * This routine examines the IP header and passes the packet on to the
588 * right upper level protocol receive handler
589 */
590 {
591 UINT Protocol;
592
593 switch (IPPacket->Type) {
594 case IP_ADDRESS_V4:
595 Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
596 break;
597 case IP_ADDRESS_V6:
598 /* FIXME: IPv6 adresses not supported */
599 TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
600 return;
601 default:
602 Protocol = 0;
603 }
604
605 /* Call the appropriate protocol handler */
606 (*ProtocolTable[Protocol])(NTE, IPPacket);
607 }
608
609
610 PIP_INTERFACE IPCreateInterface(
611 PLLIP_BIND_INFO BindInfo)
612 /*
613 * FUNCTION: Creates an IP interface
614 * ARGUMENTS:
615 * BindInfo = Pointer to link layer to IP binding information
616 * RETURNS:
617 * Pointer to IP_INTERFACE structure, NULL if there was
618 * not enough free resources
619 */
620 {
621 PIP_INTERFACE IF;
622
623 TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
624
625 #ifdef DBG
626 if (BindInfo->Address) {
627 PUCHAR A = BindInfo->Address;
628 TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
629 A[0], A[1], A[2], A[3], A[4], A[5]));
630 }
631 #endif
632
633 IF = exAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
634 if (!IF) {
635 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
636 return NULL;
637 }
638
639 INIT_TAG(IF, TAG('F','A','C','E'));
640
641 IF->Free = FreeIF;
642 IF->Context = BindInfo->Context;
643 IF->HeaderSize = BindInfo->HeaderSize;
644 if (IF->HeaderSize > MaxLLHeaderSize)
645 MaxLLHeaderSize = IF->HeaderSize;
646
647 IF->MinFrameSize = BindInfo->MinFrameSize;
648 if (IF->MinFrameSize > MinLLFrameSize)
649 MinLLFrameSize = IF->MinFrameSize;
650
651 IF->MTU = BindInfo->MTU;
652 IF->Address = BindInfo->Address;
653 IF->AddressLength = BindInfo->AddressLength;
654 IF->Transmit = BindInfo->Transmit;
655
656 InitializeListHead(&IF->ADEListHead);
657 InitializeListHead(&IF->NTEListHead);
658
659 TcpipInitializeSpinLock(&IF->Lock);
660
661 #ifdef __NTDRIVER__
662 InsertTDIInterfaceEntity( IF );
663 #endif
664
665 return IF;
666 }
667
668
669 VOID IPDestroyInterface(
670 PIP_INTERFACE IF)
671 /*
672 * FUNCTION: Destroys an IP interface
673 * ARGUMENTS:
674 * IF = Pointer to interface to destroy
675 */
676 {
677 KIRQL OldIrql1;
678 KIRQL OldIrql2;
679
680 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
681
682 #ifdef __NTDRIVER__
683 RemoveTDIInterfaceEntity( IF );
684 #endif
685
686 TcpipAcquireSpinLock(&NetTableListLock, &OldIrql1);
687 TcpipAcquireSpinLock(&IF->Lock, &OldIrql2);
688 DestroyADEs(IF);
689 DestroyNTEs(IF);
690 TcpipReleaseSpinLock(&IF->Lock, OldIrql2);
691 TcpipReleaseSpinLock(&NetTableListLock, OldIrql1);
692
693 exFreePool(IF);
694 }
695
696
697 BOOLEAN IPRegisterInterface(
698 PIP_INTERFACE IF)
699 /*
700 * FUNCTION: Registers an IP interface with IP layer
701 * ARGUMENTS:
702 * IF = Pointer to interface to register
703 * RETURNS;
704 * TRUE if interface was successfully registered, FALSE if not
705 */
706 {
707 KIRQL OldIrql;
708 PLIST_ENTRY CurrentEntry;
709 PNET_TABLE_ENTRY Current;
710 PROUTE_CACHE_NODE RCN;
711 PNEIGHBOR_CACHE_ENTRY NCE;
712
713 TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
714
715 TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
716
717 /* Add routes to all NTEs on this interface */
718 CurrentEntry = IF->NTEListHead.Flink;
719 while (CurrentEntry != &IF->NTEListHead) {
720 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
721
722 /* Add a permanent neighbor for this NTE */
723 NCE = NBAddNeighbor(IF, Current->Address, IF->Address,
724 IF->AddressLength, NUD_PERMANENT);
725 if (!NCE) {
726 TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
727 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
728 return FALSE;
729 }
730
731 /* NCE is already referenced */
732 if (!RouterAddRoute(Current->Address, &Current->PLE->Prefix, NCE, 1)) {
733 TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
734 }
735
736 RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
737 if (!RCN) {
738 TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
739 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
740 }
741 CurrentEntry = CurrentEntry->Flink;
742 }
743
744 /* Add interface to the global interface list */
745 ASSERT(&IF->ListEntry);
746 TcpipInterlockedInsertTailList(&InterfaceListHead,
747 &IF->ListEntry,
748 &InterfaceListLock);
749
750 /* Allow TCP to hang some configuration on this interface */
751 IF->TCPContext = TCPPrepareInterface( IF );
752
753 TcpipReleaseSpinLock(&IF->Lock, OldIrql);
754
755 return TRUE;
756 }
757
758
759 VOID IPUnregisterInterface(
760 PIP_INTERFACE IF)
761 /*
762 * FUNCTION: Unregisters an IP interface with IP layer
763 * ARGUMENTS:
764 * IF = Pointer to interface to unregister
765 */
766 {
767 KIRQL OldIrql1;
768 KIRQL OldIrql2;
769 KIRQL OldIrql3;
770 PLIST_ENTRY CurrentEntry;
771 PNET_TABLE_ENTRY Current;
772 PNEIGHBOR_CACHE_ENTRY NCE;
773
774 TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
775
776 TcpipAcquireSpinLock(&NetTableListLock, &OldIrql1);
777 TcpipAcquireSpinLock(&IF->Lock, &OldIrql2);
778
779 /* Remove routes to all NTEs on this interface */
780 CurrentEntry = IF->NTEListHead.Flink;
781 while (CurrentEntry != &IF->NTEListHead) {
782 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
783
784 /* Remove NTE from global net table list */
785 RemoveEntryList(&Current->NTListEntry);
786
787 /* Remove all references from route cache to NTE */
788 RouteInvalidateNTE(Current);
789
790 /* Remove permanent NCE, but first we have to find it */
791 NCE = NBLocateNeighbor(Current->Address);
792 if (NCE)
793 NBRemoveNeighbor(NCE);
794
795 CurrentEntry = CurrentEntry->Flink;
796 }
797
798 TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
799 /* Ouch...three spinlocks acquired! Fortunately
800 we don't unregister interfaces very often */
801 RemoveEntryList(&IF->ListEntry);
802 TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
803
804 TcpipReleaseSpinLock(&IF->Lock, OldIrql2);
805 TcpipReleaseSpinLock(&NetTableListLock, OldIrql1);
806 }
807
808
809 VOID IPRegisterProtocol(
810 UINT ProtocolNumber,
811 IP_PROTOCOL_HANDLER Handler)
812 /*
813 * FUNCTION: Registers a handler for an IP protocol number
814 * ARGUMENTS:
815 * ProtocolNumber = Internet Protocol number for which to register handler
816 * Handler = Pointer to handler to be called when a packet is received
817 * NOTES:
818 * To unregister a protocol handler, call this function with Handler = NULL
819 */
820 {
821 #ifdef DBG
822 if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
823 TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
824 #endif
825
826 ProtocolTable[ProtocolNumber] = Handler;
827 }
828
829
830 VOID DefaultProtocolHandler(
831 PNET_TABLE_ENTRY NTE,
832 PIP_PACKET IPPacket)
833 /*
834 * FUNCTION: Default handler for Internet protocols
835 * ARGUMENTS:
836 * NTE = Pointer to net table entry which the packet was received on
837 * IPPacket = Pointer to an IP packet that was received
838 */
839 {
840 TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
841 }
842
843
844 NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
845 /*
846 * FUNCTION: Initializes the IP subsystem
847 * ARGUMENTS:
848 * RegistryPath = Our registry node for configuration parameters
849 * RETURNS:
850 * Status of operation
851 */
852 {
853 UINT i;
854
855 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
856
857 MaxLLHeaderSize = 0;
858 MinLLFrameSize = 0;
859
860 /* Initialize lookaside lists */
861 ExInitializeNPagedLookasideList(
862 &IPDRList, /* Lookaside list */
863 NULL, /* Allocate routine */
864 NULL, /* Free routine */
865 0, /* Flags */
866 sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
867 TAG('I','P','D','R'), /* Tag */
868 0); /* Depth */
869
870 ExInitializeNPagedLookasideList(
871 &IPPacketList, /* Lookaside list */
872 NULL, /* Allocate routine */
873 NULL, /* Free routine */
874 0, /* Flags */
875 sizeof(IP_PACKET), /* Size of each entry */
876 TAG('I','P','P','K'), /* Tag */
877 0); /* Depth */
878
879 ExInitializeNPagedLookasideList(
880 &IPFragmentList, /* Lookaside list */
881 NULL, /* Allocate routine */
882 NULL, /* Free routine */
883 0, /* Flags */
884 sizeof(IP_FRAGMENT), /* Size of each entry */
885 TAG('I','P','F','G'), /* Tag */
886 0); /* Depth */
887
888 ExInitializeNPagedLookasideList(
889 &IPHoleList, /* Lookaside list */
890 NULL, /* Allocate routine */
891 NULL, /* Free routine */
892 0, /* Flags */
893 sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
894 TAG('I','P','H','L'), /* Tag */
895 0); /* Depth */
896
897 /* Start routing subsystem */
898 RouterStartup();
899
900 /* Start route cache subsystem */
901 RouteStartup();
902
903 /* Start neighbor cache subsystem */
904 NBStartup();
905
906 /* Fill the protocol dispatch table with pointers
907 to the default protocol handler */
908 for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
909 IPRegisterProtocol(i, DefaultProtocolHandler);
910
911 /* Register network level protocol receive handlers */
912 IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
913
914 /* Initialize NTE list and protecting lock */
915 InitializeListHead(&NetTableListHead);
916 TcpipInitializeSpinLock(&NetTableListLock);
917
918 /* Initialize reassembly list and protecting lock */
919 InitializeListHead(&ReassemblyListHead);
920 TcpipInitializeSpinLock(&ReassemblyListLock);
921
922 InitPLE();
923
924 IPInitialized = TRUE;
925
926 return STATUS_SUCCESS;
927 }
928
929
930 NTSTATUS IPShutdown(
931 VOID)
932 /*
933 * FUNCTION: Shuts down the IP subsystem
934 * RETURNS:
935 * Status of operation
936 */
937 {
938 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
939
940 if (!IPInitialized)
941 return STATUS_SUCCESS;
942
943 /* Shutdown neighbor cache subsystem */
944 NBShutdown();
945
946 /* Shutdown route cache subsystem */
947 RouteShutdown();
948
949 /* Shutdown routing subsystem */
950 RouterShutdown();
951
952 IPFreeReassemblyList();
953
954 /* Clear prefix list */
955 DestroyPLEs();
956
957 /* Destroy lookaside lists */
958 ExDeleteNPagedLookasideList(&IPHoleList);
959 ExDeleteNPagedLookasideList(&IPDRList);
960 ExDeleteNPagedLookasideList(&IPPacketList);
961 ExDeleteNPagedLookasideList(&IPFragmentList);
962
963 IPInitialized = FALSE;
964
965 return STATUS_SUCCESS;
966 }
967
968 /* EOF */