d6c05872e816869ef3f163d554cc19001edcf605
[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 = (PVOID)((ULONG_PTR)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 /*
278 * FUNCTION: Processes an IP datagram or fragment
279 * ARGUMENTS:
280 * IF = Pointer to IP interface packet was receive on
281 * IPPacket = Pointer to IP packet
282 * NOTES:
283 * This routine reassembles fragments and, if a whole datagram can
284 * be assembled, passes the datagram on to the IP protocol dispatcher
285 */
286 {
287 KIRQL OldIrql;
288 PIPDATAGRAM_REASSEMBLY IPDR;
289 PLIST_ENTRY CurrentEntry;
290 PIPDATAGRAM_HOLE Hole, NewHole;
291 USHORT FragFirst;
292 USHORT FragLast;
293 BOOLEAN MoreFragments;
294 PIPv4_HEADER IPv4Header;
295 PIP_PACKET Datagram;
296 PIP_FRAGMENT Fragment;
297
298 /* FIXME: Assume IPv4 */
299
300 IPv4Header = (PIPv4_HEADER)IPPacket->Header;
301
302 /* Check if we already have an reassembly structure for this datagram */
303 IPDR = GetReassemblyInfo(IPPacket);
304 if (IPDR) {
305 TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
306 /* We have a reassembly structure */
307 TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
308 CurrentEntry = IPDR->HoleListHead.Flink;
309 Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
310 } else {
311 TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
312
313 /* We don't have a reassembly structure, create one */
314 IPDR = TcpipAllocateFromNPagedLookasideList(&IPDRList);
315 if (!IPDR)
316 /* We don't have the resources to process this packet, discard it */
317 return;
318
319 /* Create a descriptor spanning from zero to infinity.
320 Actually, we use a value slightly greater than the
321 maximum number of octets an IP datagram can contain */
322 Hole = CreateHoleDescriptor(0, 65536);
323 if (!Hole) {
324 /* We don't have the resources to process this packet, discard it */
325 TcpipFreeToNPagedLookasideList(&IPDRList, IPDR);
326 return;
327 }
328 AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
329 AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
330 IPDR->Id = IPv4Header->Id;
331 IPDR->Protocol = IPv4Header->Protocol;
332 InitializeListHead(&IPDR->FragmentListHead);
333 InitializeListHead(&IPDR->HoleListHead);
334 InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
335 CurrentEntry = IPDR->HoleListHead.Flink;
336
337 TcpipInitializeSpinLock(&IPDR->Lock);
338
339 TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
340
341 /* Update the reassembly list */
342 TcpipInterlockedInsertTailList(
343 &ReassemblyListHead,
344 &IPDR->ListEntry,
345 &ReassemblyListLock);
346 }
347
348 FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
349 FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
350 MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
351
352 for (;;) {
353 if (CurrentEntry == &IPDR->HoleListHead)
354 /* No more entries */
355 break;
356
357 TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
358 FragFirst, FragLast, Hole->First, Hole->Last));
359
360 if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
361 TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
362 /* The fragment does not overlap with the hole, try next
363 descriptor in the list */
364
365 CurrentEntry = CurrentEntry->Flink;
366 if (CurrentEntry != &IPDR->HoleListHead)
367 Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
368 continue;
369 }
370
371 /* The fragment overlap with the hole, unlink the descriptor */
372 RemoveEntryList(CurrentEntry);
373
374 if (FragFirst > Hole->First) {
375 NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
376 if (!NewHole) {
377 /* We don't have the resources to process this packet, discard it */
378 Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
379 return;
380 }
381
382 /* Put the new descriptor in the list */
383 InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
384 }
385
386 if ((FragLast < Hole->Last) && (MoreFragments)) {
387 /* We can reuse the descriptor for the new hole */
388 Hole->First = FragLast + 1;
389
390 /* Put the new hole descriptor in the list */
391 InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
392 } else
393 TcpipFreeToNPagedLookasideList(&IPHoleList, Hole);
394
395 /* If this is the first fragment, save the IP header */
396 if (FragFirst == 0) {
397 TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
398 "Header size is (%d).\n", &IPDR->IPv4Header, IPPacket->HeaderSize));
399
400 RtlCopyMemory(&IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
401 IPDR->HeaderSize = IPPacket->HeaderSize;
402 }
403
404 /* Create a buffer, copy the data into it and put it
405 in the fragment list */
406
407 Fragment = TcpipAllocateFromNPagedLookasideList(&IPFragmentList);
408 if (!Fragment) {
409 /* We don't have the resources to process this packet, discard it */
410 Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
411 return;
412 }
413
414 TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
415
416 Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
417 Fragment->Data = exAllocatePool(NonPagedPool, Fragment->Size);
418 if (!Fragment->Data) {
419 /* We don't have the resources to process this packet, discard it */
420 Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
421 return;
422 }
423
424 /* Position here is an offset from the NdisPacket start, not the header */
425 TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d) Pos (%d).\n",
426 Fragment->Data, Fragment->Size, IPPacket->Position));
427
428 /* Copy datagram data into fragment buffer */
429 CopyPacketToBuffer(Fragment->Data,
430 IPPacket->NdisPacket,
431 IPPacket->Position,
432 Fragment->Size);
433 Fragment->Offset = FragFirst;
434
435 /* If this is the last fragment, compute and save the datagram data size */
436 if (!MoreFragments)
437 IPDR->DataSize = FragFirst + Fragment->Size;
438
439 /* Put the fragment in the list */
440 InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
441 break;
442 }
443
444 TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
445
446 if (IsListEmpty(&IPDR->HoleListHead)) {
447 /* Hole list is empty which means a complete datagram can be assembled.
448 Assemble the datagram and pass it to an upper layer protocol */
449
450 TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
451
452 Datagram = ReassembleDatagram(IPDR);
453
454 RemoveIPDR(IPDR);
455 TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
456
457 FreeIPDR(IPDR);
458
459 if (!Datagram)
460 /* Not enough free resources, discard the packet */
461 return;
462
463 DISPLAY_IP_PACKET(Datagram);
464
465 /* Give the packet to the protocol dispatcher */
466 IPDispatchProtocol(IF, Datagram);
467
468 /* We're done with this datagram */
469 exFreePool(Datagram->Header);
470 TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
471 (*Datagram->Free)(Datagram);
472 } else
473 TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
474 }
475
476
477 VOID IPFreeReassemblyList(
478 VOID)
479 /*
480 * FUNCTION: Frees all IP datagram reassembly structures in the list
481 */
482 {
483 KIRQL OldIrql;
484 PLIST_ENTRY CurrentEntry;
485 PIPDATAGRAM_REASSEMBLY Current;
486
487 TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
488
489 CurrentEntry = ReassemblyListHead.Flink;
490 while (CurrentEntry != &ReassemblyListHead) {
491 Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
492 /* Unlink it from the list */
493 RemoveEntryList(CurrentEntry);
494
495 /* And free the descriptor */
496 FreeIPDR(Current);
497
498 CurrentEntry = CurrentEntry->Flink;
499 }
500
501 TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
502 }
503
504
505 VOID IPDatagramReassemblyTimeout(
506 VOID)
507 /*
508 * FUNCTION: IP datagram reassembly timeout handler
509 * NOTES:
510 * This routine is called by IPTimeout to free any resources used
511 * to hold IP fragments that have taken too long to reassemble
512 */
513 {
514 }
515
516 VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)
517 /*
518 * FUNCTION: Receives an IPv4 datagram (or fragment)
519 * ARGUMENTS:
520 * Context = Pointer to context information (IP_INTERFACE)
521 * IPPacket = Pointer to IP packet
522 */
523 {
524 TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
525
526 IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;
527 TI_DbgPrint(DEBUG_IP, ("IPPacket->HeaderSize = %d\n", IPPacket->HeaderSize));
528
529 if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
530 TI_DbgPrint
531 (MIN_TRACE,
532 ("Datagram received with incorrect header size (%d).\n",
533 IPPacket->HeaderSize));
534 /* Discard packet */
535 return;
536 }
537
538 /* Checksum IPv4 header */
539 if (!IPv4CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
540 TI_DbgPrint
541 (MIN_TRACE,
542 ("Datagram received with bad checksum. Checksum field (0x%X)\n",
543 WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
544 /* Discard packet */
545 return;
546 }
547
548 IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
549
550 AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
551 AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
552
553 IPPacket->Position += IPPacket->HeaderSize;
554 IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);
555
556 TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
557 IPPacket->Position));
558
559 //OskitDumpBuffer(IPPacket->Header, IPPacket->TotalSize);
560
561 /* FIXME: Possibly forward packets with multicast addresses */
562
563 /* FIXME: Should we allow packets to be received on the wrong interface? */
564 /* XXX Find out if this packet is destined for us */
565 ProcessFragment(IF, IPPacket);
566 #if 0
567 } else {
568 /* This packet is not destined for us. If we are a router,
569 try to find a route and forward the packet */
570
571 /* FIXME: Check if acting as a router */
572 NCE = NULL;
573 if (NCE) {
574 PROUTE_CACHE_NODE RCN;
575
576 /* FIXME: Possibly fragment datagram */
577 /* Forward the packet */
578 if(!RouteGetRouteToDestination( &IPPacket->DstAddr, NULL, &RCN ))
579 IPSendDatagram(IPPacket, RCN, ReflectPacketComplete, IPPacket);
580 } else {
581 TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
582 IPPacket->DstAddr.Address.IPv4Address));
583
584 /* FIXME: Send ICMP error code */
585 }
586 }
587 #endif
588 }
589
590
591 VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
592 /*
593 * FUNCTION: Receives an IP datagram (or fragment)
594 * ARGUMENTS:
595 * IF = Interface
596 * IPPacket = Pointer to IP packet
597 */
598 {
599 UINT Version;
600
601 /* Check that IP header has a supported version */
602 Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
603
604 switch (Version) {
605 case 4:
606 IPPacket->Type = IP_ADDRESS_V4;
607 IPv4Receive(IF, IPPacket);
608 break;
609 case 6:
610 IPPacket->Type = IP_ADDRESS_V6;
611 TI_DbgPrint(MAX_TRACE, ("Datagram of type IPv6 discarded.\n"));
612 return;
613 default:
614 TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
615 return;
616 }
617 }
618
619 /* EOF */