:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / net / tcpip / network / receive.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        network/receive.c
5  * PURPOSE:     Internet Protocol receive routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * NOTES:       The IP datagram reassembly algorithm is taken from
8  *              from RFC 815
9  * REVISIONS:
10  *   CSH 01/08-2000 Created
11  */
12 #include <tcpip.h>
13 #include <receive.h>
14 #include <routines.h>
15 #include <checksum.h>
16 #include <transmit.h>
17 #include <address.h>
18 #include <pool.h>
19 #include <route.h>
20
21
22 LIST_ENTRY ReassemblyListHead;
23 KSPIN_LOCK ReassemblyListLock;
24 NPAGED_LOOKASIDE_LIST IPDRList;
25 NPAGED_LOOKASIDE_LIST IPFragmentList;
26 NPAGED_LOOKASIDE_LIST IPHoleList;
27
28
29 PIPDATAGRAM_HOLE CreateHoleDescriptor(
30   ULONG First,
31   ULONG Last)
32 /*
33  * FUNCTION: Returns a pointer to a IP datagram hole descriptor
34  * ARGUMENTS:
35  *     First = Offset of first octet of the hole
36  *     Last  = Offset of last octet of the hole
37  * RETURNS:
38  *     Pointer to descriptor, NULL if there was not enough free
39  *     resources
40  */
41 {
42         PIPDATAGRAM_HOLE Hole;
43
44         TI_DbgPrint(DEBUG_IP, ("Called. First (%d)  Last (%d).\n", First, Last));
45
46         Hole = ExAllocateFromNPagedLookasideList(&IPHoleList);
47         if (!Hole) {
48             TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
49             return NULL;
50         }
51
52         Hole->First = First;
53         Hole->Last  = Last;
54
55         TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
56
57         return Hole;
58 }
59
60
61 VOID FreeIPDR(
62   PIPDATAGRAM_REASSEMBLY IPDR)
63 /*
64  * FUNCTION: Frees an IP datagram reassembly structure
65  * ARGUMENTS:
66  *     IPDR = Pointer to IP datagram reassembly structure
67  */
68 {
69   PLIST_ENTRY CurrentEntry;
70   PLIST_ENTRY NextEntry;
71   PIPDATAGRAM_HOLE CurrentH;
72   PIP_FRAGMENT CurrentF;
73
74   TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
75
76   /* Free all descriptors */
77   CurrentEntry = IPDR->HoleListHead.Flink;
78   while (CurrentEntry != &IPDR->HoleListHead) {
79     NextEntry = CurrentEntry->Flink;
80           CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
81     /* Unlink it from the list */
82     RemoveEntryList(CurrentEntry);
83
84     TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
85
86     /* And free the hole descriptor */
87     ExFreeToNPagedLookasideList(&IPHoleList, CurrentH);
88
89     CurrentEntry = NextEntry;
90   }
91
92   /* Free all fragments */
93   CurrentEntry = IPDR->FragmentListHead.Flink;
94   while (CurrentEntry != &IPDR->FragmentListHead) {
95     NextEntry = CurrentEntry->Flink;
96           CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
97     /* Unlink it from the list */
98     RemoveEntryList(CurrentEntry);
99
100     TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));
101
102     /* Free the fragment data buffer */
103     ExFreePool(CurrentF->Data);
104
105     TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
106
107     /* And free the fragment descriptor */
108     ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
109     CurrentEntry = NextEntry;
110   }
111
112   /* Free resources for the header, if it exists */
113   if (IPDR->IPv4Header) {
114     TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));
115     ExFreePool(IPDR->IPv4Header);
116   }
117
118   TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
119
120   ExFreeToNPagedLookasideList(&IPDRList, IPDR);
121 }
122
123
124 VOID RemoveIPDR(
125   PIPDATAGRAM_REASSEMBLY IPDR)
126 /*
127  * FUNCTION: Removes an IP datagram reassembly structure from the global list
128  * ARGUMENTS:
129  *     IPDR = Pointer to IP datagram reassembly structure
130  */
131 {
132   KIRQL OldIrql;
133
134   TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
135
136   KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
137   RemoveEntryList(&IPDR->ListEntry);
138   KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
139 }
140
141
142 PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
143   PIP_PACKET IPPacket)
144 /*
145  * FUNCTION: Returns a pointer to an IP datagram reassembly structure
146  * ARGUMENTS:
147  *     IPPacket = Pointer to IP packet
148  * NOTES:
149  *     A datagram is identified by four paramters, which are
150  *     Source and destination address, protocol number and
151  *     identification number
152  */
153 {
154   KIRQL OldIrql;
155   PLIST_ENTRY CurrentEntry;
156   PIPDATAGRAM_REASSEMBLY Current;
157   PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
158
159   TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
160
161   KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
162
163   /* FIXME: Assume IPv4 */
164
165   CurrentEntry = ReassemblyListHead.Flink;
166   while (CurrentEntry != &ReassemblyListHead) {
167           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
168     if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
169       (Header->Id == Current->Id) &&
170       (Header->Protocol == Current->Protocol) &&
171       (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
172       KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
173
174       return Current;
175     }
176     CurrentEntry = CurrentEntry->Flink;
177   }
178
179   KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
180
181   return NULL;
182 }
183
184
185 PIP_PACKET ReassembleDatagram(
186   PIPDATAGRAM_REASSEMBLY IPDR)
187 /*
188  * FUNCTION: Reassembles an IP datagram
189  * ARGUMENTS:
190  *     IPDR = Pointer to IP datagram reassembly structure
191  * NOTES:
192  *     This routine concatenates fragments into a complete IP datagram.
193  *     The lock is held when this routine is called
194  * RETURNS:
195  *     Pointer to IP packet, NULL if there was not enough free resources
196  */
197 {
198   PIP_PACKET IPPacket;
199   PLIST_ENTRY CurrentEntry;
200   PIP_FRAGMENT Current;
201   PVOID Data;
202
203   TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
204
205   /* FIXME: Assume IPv4 */
206   IPPacket = IPCreatePacket(IP_ADDRESS_V4);
207   if (!IPPacket)
208     return NULL;
209
210   IPPacket->TotalSize  = IPDR->HeaderSize + IPDR->DataSize;
211   IPPacket->ContigSize = IPPacket->TotalSize;
212   IPPacket->HeaderSize = IPDR->HeaderSize;
213   IPPacket->Position   = IPDR->HeaderSize;
214
215   RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
216   RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
217
218   /* Allocate space for full IP datagram */
219   IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize);
220   if (!IPPacket->Header) {
221     TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
222     (*IPPacket->Free)(IPPacket);
223     return NULL;
224   }
225
226   /* Copy the header into the buffer */
227   RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);  
228   
229   Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
230   IPPacket->Data = Data;
231
232   /* Copy data from all fragments into buffer */
233   CurrentEntry = IPDR->FragmentListHead.Flink;
234   while (CurrentEntry != &IPDR->FragmentListHead) {
235     Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
236
237     TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
238       Current->Size, Data, Current->Offset));
239     /* Copy fragment data to the destination buffer at the correct offset */
240     RtlCopyMemory(
241                   (PVOID)((ULONG_PTR)Data + Current->Offset),
242       Current->Data,
243       Current->Size);
244
245     CurrentEntry = CurrentEntry->Flink;
246   }
247
248   return IPPacket;
249 }
250
251
252 __inline VOID Cleanup(
253   PKSPIN_LOCK Lock,
254   KIRQL OldIrql,
255   PIPDATAGRAM_REASSEMBLY IPDR,
256   PVOID Buffer OPTIONAL)
257 /*
258  * FUNCTION: Performs cleaning operations on errors
259  * ARGUMENTS:
260  *     Lock     = Pointer to spin lock to be released
261  *     OldIrql  = Value of IRQL when spin lock was acquired
262  *     IPDR     = Pointer to IP datagram reassembly structure to free
263  *     Buffer   = Optional pointer to a buffer to free
264  */
265 {
266   TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
267
268   KeReleaseSpinLock(Lock, OldIrql);
269   RemoveIPDR(IPDR);
270   FreeIPDR(IPDR);
271   if (Buffer)
272     ExFreePool(Buffer);
273 }
274
275
276 VOID ProcessFragment(
277   PIP_INTERFACE IF,
278   PIP_PACKET IPPacket,
279   PNET_TABLE_ENTRY NTE)
280 /*
281  * FUNCTION: Processes an IP datagram or fragment
282  * ARGUMENTS:
283  *     IF       = Pointer to IP interface packet was receive on
284  *     IPPacket = Pointer to IP packet
285  *     NTE      = Pointer to NTE packet was received on
286  * NOTES:
287  *     This routine reassembles fragments and, if a whole datagram can
288  *     be assembled, passes the datagram on to the IP protocol dispatcher
289  */
290 {
291   KIRQL OldIrql;
292   PIPDATAGRAM_REASSEMBLY IPDR;
293   PLIST_ENTRY CurrentEntry;
294   PIPDATAGRAM_HOLE Hole, NewHole;
295   USHORT FragFirst;
296   USHORT FragLast;
297   BOOLEAN MoreFragments;
298   PIPv4_HEADER IPv4Header;
299   PIP_PACKET Datagram;
300   PIP_FRAGMENT Fragment;
301
302   /* FIXME: Assume IPv4 */
303
304   IPv4Header = (PIPv4_HEADER)IPPacket->Header;
305
306   /* Check if we already have an reassembly structure for this datagram */
307   IPDR = GetReassemblyInfo(IPPacket);
308   if (IPDR) {
309     TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
310     /* We have a reassembly structure */
311     KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
312     CurrentEntry = IPDR->HoleListHead.Flink;
313     Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
314   } else {
315     TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
316
317     /* We don't have a reassembly structure, create one */
318     IPDR = ExAllocateFromNPagedLookasideList(&IPDRList);
319     if (!IPDR)
320       /* We don't have the resources to process this packet, discard it */
321       return;
322
323     /* Create a descriptor spanning from zero to infinity.
324        Actually, we use a value slightly greater than the
325        maximum number of octets an IP datagram can contain */
326     Hole = CreateHoleDescriptor(0, 65536);
327     if (!Hole) {
328       /* We don't have the resources to process this packet, discard it */
329       ExFreeToNPagedLookasideList(&IPDRList, IPDR);
330       return;
331     }
332     AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
333     AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
334     IPDR->Id         = IPv4Header->Id;
335     IPDR->Protocol   = IPv4Header->Protocol;
336     IPDR->IPv4Header = NULL;
337     InitializeListHead(&IPDR->FragmentListHead);
338     InitializeListHead(&IPDR->HoleListHead);
339     InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
340     CurrentEntry = IPDR->HoleListHead.Flink;
341
342     KeInitializeSpinLock(&IPDR->Lock);
343
344     KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
345
346     /* Update the reassembly list */
347     ExInterlockedInsertTailList(
348                   &ReassemblyListHead,
349       &IPDR->ListEntry,
350       &ReassemblyListLock);
351   }
352
353   FragFirst     = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
354   FragLast      = FragFirst + WN2H(IPv4Header->TotalLength);
355   MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
356
357   for (;;) {
358     if (CurrentEntry == &IPDR->HoleListHead)
359       /* No more entries */
360       break;
361
362     TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
363       FragFirst, FragLast, Hole->First, Hole->Last));
364
365     if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
366       TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
367       /* The fragment does not overlap with the hole, try next
368          descriptor in the list */
369
370       CurrentEntry = CurrentEntry->Flink;
371       if (CurrentEntry != &IPDR->HoleListHead)
372           Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
373       continue;
374     }
375
376     /* The fragment overlap with the hole, unlink the descriptor */
377     RemoveEntryList(CurrentEntry);
378
379     if (FragFirst > Hole->First) {
380       NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
381       if (!NewHole) {
382         /* We don't have the resources to process this packet, discard it */
383         Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
384         return;
385       }
386
387       /* Put the new descriptor in the list */
388       InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
389     }
390
391     if ((FragLast < Hole->Last) && (MoreFragments)) {
392       /* We can reuse the descriptor for the new hole */
393                   Hole->First = FragLast + 1;
394
395                   /* Put the new hole descriptor in the list */
396       InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
397     } else
398       ExFreeToNPagedLookasideList(&IPHoleList, Hole);
399
400     /* If this is the first fragment, save the IP header */
401     if (FragFirst == 0) {
402       IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize);
403       if (!IPDR->IPv4Header) {
404         /* We don't have the resources to process this packet, discard it */
405         Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
406         return;
407       }
408
409       TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
410         "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize));
411
412       RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
413       IPDR->HeaderSize = IPPacket->HeaderSize;
414     }
415
416     /* Create a buffer, copy the data into it and put it
417        in the fragment list */
418
419     Fragment = ExAllocateFromNPagedLookasideList(&IPFragmentList);
420     if (!Fragment) {
421       /* We don't have the resources to process this packet, discard it */
422       Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
423       return;
424     }
425
426     TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
427
428     Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
429     Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size);
430     if (!Fragment->Data) {
431       /* We don't have the resources to process this packet, discard it */
432       Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
433       return;
434     }
435
436     TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X)  Size (%d).\n",
437       Fragment->Data, Fragment->Size));
438
439     /* Copy datagram data into fragment buffer */
440     CopyPacketToBuffer(
441                   Fragment->Data,
442       IPPacket->NdisPacket,
443       IPPacket->Position,
444       Fragment->Size);
445       Fragment->Offset = FragFirst;
446
447     /* If this is the last fragment, compute and save the datagram data size */
448     if (!MoreFragments)
449       IPDR->DataSize = FragFirst + Fragment->Size;
450
451     /* Put the fragment in the list */
452     InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
453           break;
454   }
455
456   TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
457
458   if (IsListEmpty(&IPDR->HoleListHead)) {
459     /* Hole list is empty which means a complete datagram can be assembled.
460        Assemble the datagram and pass it to an upper layer protocol */
461
462     TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
463
464     Datagram = ReassembleDatagram(IPDR);
465
466           KeReleaseSpinLock(&IPDR->Lock, OldIrql);
467
468     RemoveIPDR(IPDR);
469     FreeIPDR(IPDR);
470
471     if (!Datagram)
472       /* Not enough free resources, discard the packet */
473       return;
474
475     DISPLAY_IP_PACKET(Datagram);
476
477     /* Give the packet to the protocol dispatcher */
478     IPDispatchProtocol(NTE, Datagram);
479
480     /* We're done with this datagram */
481     ExFreePool(Datagram->Header);
482     TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
483     (*Datagram->Free)(Datagram);
484   } else
485     KeReleaseSpinLock(&IPDR->Lock, OldIrql);
486 }
487
488
489 VOID IPFreeReassemblyList(
490   VOID)
491 /*
492  * FUNCTION: Frees all IP datagram reassembly structures in the list
493  */
494 {
495   KIRQL OldIrql;
496   PLIST_ENTRY CurrentEntry;
497   PIPDATAGRAM_REASSEMBLY Current;
498
499   KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
500
501   CurrentEntry = ReassemblyListHead.Flink;
502   while (CurrentEntry != &ReassemblyListHead) {
503           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
504     /* Unlink it from the list */
505     RemoveEntryList(CurrentEntry);
506
507     /* And free the descriptor */
508     FreeIPDR(Current);
509
510     CurrentEntry = CurrentEntry->Flink;
511   }
512
513   KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
514 }
515
516
517 VOID IPDatagramReassemblyTimeout(
518   VOID)
519 /*
520  * FUNCTION: IP datagram reassembly timeout handler
521  * NOTES:
522  *     This routine is called by IPTimeout to free any resources used
523  *     to hold IP fragments that have taken too long to reassemble
524  */
525 {
526 }
527
528
529 VOID IPv4Receive(
530   PVOID Context,
531   PIP_PACKET IPPacket)
532 /*
533  * FUNCTION: Receives an IPv4 datagram (or fragment)
534  * ARGUMENTS:
535  *     Context  = Pointer to context information (IP_INTERFACE)
536  *     IPPacket = Pointer to IP packet
537  */
538 {
539 //PNEIGHBOR_CACHE_ENTRY NCE;
540   PNET_TABLE_ENTRY NTE;
541   UINT AddressType;
542
543   TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
544
545   IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;
546
547   if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
548     TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n",
549       IPPacket->HeaderSize));
550     /* Discard packet */
551     return;
552   }
553
554   /* Checksum IPv4 header */
555   if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
556     TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n",
557       WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
558     /* Discard packet */
559     return;
560   }
561
562 //    TI_DbgPrint(DEBUG_IP, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize));
563
564   IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
565
566 //    TI_DbgPrint(DEBUG_IP, ("TotalSize (IPv4) is (%d).\n", IPPacket->TotalSize));
567
568         AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
569         AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
570
571   IPPacket->Position = IPPacket->HeaderSize;
572   IPPacket->Data     = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);
573
574   /* FIXME: Possibly forward packets with multicast addresses */
575
576   /* FIXME: Should we allow packets to be received on the wrong interface? */
577 #if 0
578   NTE = IPLocateNTE(&IPPacket->DstAddr, &AddressType);
579 #else
580   NTE = IPLocateNTEOnInterface((PIP_INTERFACE)Context, &IPPacket->DstAddr, &AddressType);
581 #endif
582   if (NTE) {
583     /* This packet is destined for us */
584     ProcessFragment((PIP_INTERFACE)Context, IPPacket, NTE);
585
586     /* Done with this NTE */
587     DereferenceObject(NTE);
588   } else {
589     /* This packet is not destined for us. If we are a router,
590        try to find a route and forward the packet */
591
592     /* FIXME: Check if acting as a router */
593 #if 0
594     NCE = RouteFindRouter(&IPPacket->DstAddr, NULL);
595     if (NCE) {
596       /* FIXME: Possibly fragment datagram */
597       /* Forward the packet */
598       IPSendFragment(IPPacket, NCE);
599     } else {
600       TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
601         IPPacket->DstAddr.Address.IPv4Address));
602
603       /* FIXME: Send ICMP error code */
604     }
605 #endif
606   }
607 }
608
609
610 VOID IPReceive(
611   PVOID Context,
612   PIP_PACKET IPPacket)
613 /*
614  * FUNCTION: Receives an IP datagram (or fragment)
615  * ARGUMENTS:
616  *     Context  = Pointer to context information (IP_INTERFACE)
617  *     IPPacket = Pointer to IP packet
618  */
619 {
620   UINT Version;
621
622   /* Check that IP header has a supported version */
623   Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
624
625   switch (Version) {
626   case 4:
627     IPPacket->Type = IP_ADDRESS_V4;
628     IPv4Receive(Context, IPPacket);
629     break;
630   case 6:
631     IPPacket->Type = IP_ADDRESS_V6;
632     TI_DbgPrint(MAX_TRACE, ("Datagram of type IPv6 discarded.\n"));
633     return;
634   default:
635           TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
636     return;
637   }
638 }
639
640 /* EOF */