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