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