no message
[reactos.git] / reactos / 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
25
26 PIPDATAGRAM_HOLE CreateHoleDescriptor(
27 ULONG First,
28 ULONG Last)
29 /*
30 * FUNCTION: Returns a pointer to a IP datagram hole descriptor
31 * ARGUMENTS:
32 * First = Offset of first octet of the hole
33 * Last = Offset of last octet of the hole
34 * RETURNS:
35 * Pointer to descriptor, NULL if there was not enough free
36 * resources
37 */
38 {
39 PIPDATAGRAM_HOLE Hole;
40
41 TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last));
42
43 Hole = PoolAllocateBuffer(sizeof(IPDATAGRAM_HOLE));
44 if (!Hole) {
45 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
46 return NULL;
47 }
48
49 Hole->First = First;
50 Hole->Last = Last;
51
52 TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
53
54 return Hole;
55 }
56
57
58 VOID FreeIPDR(
59 PIPDATAGRAM_REASSEMBLY IPDR)
60 /*
61 * FUNCTION: Frees an IP datagram reassembly structure
62 * ARGUMENTS:
63 * IPDR = Pointer to IP datagram reassembly structure
64 */
65 {
66 PLIST_ENTRY CurrentEntry;
67 PLIST_ENTRY NextEntry;
68 PIPDATAGRAM_HOLE CurrentH;
69 PIP_FRAGMENT CurrentF;
70
71 TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
72
73 /* Free all descriptors */
74 CurrentEntry = IPDR->HoleListHead.Flink;
75 while (CurrentEntry != &IPDR->HoleListHead) {
76 NextEntry = CurrentEntry->Flink;
77 CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
78 /* Unlink it from the list */
79 RemoveEntryList(CurrentEntry);
80
81 TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
82
83 /* And free the hole descriptor */
84 PoolFreeBuffer(CurrentH);
85
86 CurrentEntry = NextEntry;
87 }
88
89 /* Free all fragments */
90 CurrentEntry = IPDR->FragmentListHead.Flink;
91 while (CurrentEntry != &IPDR->FragmentListHead) {
92 NextEntry = CurrentEntry->Flink;
93 CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
94 /* Unlink it from the list */
95 RemoveEntryList(CurrentEntry);
96
97 TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));
98
99 /* Free the fragment data buffer */
100 ExFreePool(CurrentF->Data);
101
102 TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
103
104 /* And free the fragment descriptor */
105 PoolFreeBuffer(CurrentF);
106 CurrentEntry = NextEntry;
107 }
108
109 /* Free resources for the header, if it exists */
110 if (IPDR->IPv4Header) {
111 TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));
112 ExFreePool(IPDR->IPv4Header);
113 }
114
115 TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
116
117 PoolFreeBuffer(IPDR);
118 }
119
120
121 VOID RemoveIPDR(
122 PIPDATAGRAM_REASSEMBLY IPDR)
123 /*
124 * FUNCTION: Removes an IP datagram reassembly structure from the global list
125 * ARGUMENTS:
126 * IPDR = Pointer to IP datagram reassembly structure
127 */
128 {
129 KIRQL OldIrql;
130
131 TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
132
133 KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
134 RemoveEntryList(&IPDR->ListEntry);
135 KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
136 }
137
138
139 PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
140 PIP_PACKET IPPacket)
141 /*
142 * FUNCTION: Returns a pointer to an IP datagram reassembly structure
143 * ARGUMENTS:
144 * IPPacket = Pointer to IP packet
145 * NOTES:
146 * A datagram is identified by four paramters, which are
147 * Source and destination address, protocol number and
148 * identification number
149 */
150 {
151 KIRQL OldIrql;
152 PLIST_ENTRY CurrentEntry;
153 PIPDATAGRAM_REASSEMBLY Current;
154 PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
155
156 TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
157
158 KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
159
160 /* FIXME: Assume IPv4 */
161
162 CurrentEntry = ReassemblyListHead.Flink;
163 while (CurrentEntry != &ReassemblyListHead) {
164 Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
165 if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
166 (Header->Id == Current->Id) &&
167 (Header->Protocol == Current->Protocol) &&
168 (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
169 KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
170
171 return Current;
172 }
173 CurrentEntry = CurrentEntry->Flink;
174 }
175
176 KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
177
178 return NULL;
179 }
180
181
182 PIP_PACKET ReassembleDatagram(
183 PIPDATAGRAM_REASSEMBLY IPDR)
184 /*
185 * FUNCTION: Reassembles an IP datagram
186 * ARGUMENTS:
187 * IPDR = Pointer to IP datagram reassembly structure
188 * NOTES:
189 * This routine concatenates fragments into a complete IP datagram.
190 * The lock is held when this routine is called
191 * RETURNS:
192 * Pointer to IP packet, NULL if there was not enough free resources
193 */
194 {
195 PIP_PACKET IPPacket;
196 PLIST_ENTRY CurrentEntry;
197 PIP_FRAGMENT Current;
198 PVOID Data;
199
200 TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
201
202 IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET));
203 if (!IPPacket) {
204 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
205 return NULL;
206 }
207
208 /* FIXME: Assume IPv4 */
209
210 IPPacket->Type = IP_ADDRESS_V4;
211 IPPacket->RefCount = 1;
212 IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
213 IPPacket->HeaderSize = IPDR->HeaderSize;
214 IPPacket->Position = IPDR->HeaderSize;
215
216 RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
217 RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
218
219 /* Allocate space for full IP datagram */
220 IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize);
221 if (!IPPacket->Header) {
222 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
223 PoolFreeBuffer(IPPacket);
224 return NULL;
225 }
226
227 /* Copy the header into the buffer */
228 RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
229
230 Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
231 IPPacket->Data = Data;
232
233 /* Copy data from all fragments into buffer */
234 CurrentEntry = IPDR->FragmentListHead.Flink;
235 while (CurrentEntry != &IPDR->FragmentListHead) {
236 Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
237
238 TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
239 Current->Size, Data, Current->Offset));
240 /* Copy fragment data to the destination buffer at the correct offset */
241 RtlCopyMemory((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 PoolFreeBuffer(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 = PoolAllocateBuffer(sizeof(IPDATAGRAM_REASSEMBLY));
319 if (!IPDR) {
320 /* We don't have the resources to process this packet, discard it */
321 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
322 return;
323 }
324
325 /* Create a descriptor spanning from zero to infinity.
326 Actually, we use a value slightly greater than the
327 maximum number of octets an IP datagram can contain */
328 Hole = CreateHoleDescriptor(0, 65536);
329 if (!Hole) {
330 /* We don't have the resources to process this packet, discard it */
331 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
332 PoolFreeBuffer(IPDR);
333 return;
334 }
335 AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
336 AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
337 IPDR->Id = IPv4Header->Id;
338 IPDR->Protocol = IPv4Header->Protocol;
339 IPDR->IPv4Header = NULL;
340 InitializeListHead(&IPDR->FragmentListHead);
341 InitializeListHead(&IPDR->HoleListHead);
342 InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
343 CurrentEntry = IPDR->HoleListHead.Flink;
344
345 KeInitializeSpinLock(&IPDR->Lock);
346
347 KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
348
349 /* Update the reassembly list */
350 ExInterlockedInsertTailList(&ReassemblyListHead,
351 &IPDR->ListEntry,
352 &ReassemblyListLock);
353 }
354
355 FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
356 FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
357 MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
358
359 for (;;) {
360 if (CurrentEntry == &IPDR->HoleListHead)
361 /* No more entries */
362 break;
363
364 TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
365 FragFirst, FragLast, Hole->First, Hole->Last));
366
367 if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
368 TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
369 /* The fragment does not overlap with the hole, try next
370 descriptor in the list */
371
372 CurrentEntry = CurrentEntry->Flink;
373 if (CurrentEntry != &IPDR->HoleListHead)
374 Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
375 continue;
376 }
377
378 /* The fragment overlap with the hole, unlink the descriptor */
379 RemoveEntryList(CurrentEntry);
380
381 if (FragFirst > Hole->First) {
382 NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
383 if (!NewHole) {
384 /* We don't have the resources to process this packet, discard it */
385 Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
386 return;
387 }
388
389 /* Put the new descriptor in the list */
390 InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
391 }
392
393 if ((FragLast < Hole->Last) && (MoreFragments)) {
394 /* We can reuse the descriptor for the new hole */
395 Hole->First = FragLast + 1;
396
397 /* Put the new hole descriptor in the list */
398 InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
399 } else
400 PoolFreeBuffer(Hole);
401
402 /* If this is the first fragment, save the IP header */
403 if (FragFirst == 0) {
404 IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize);
405 if (!IPDR->IPv4Header) {
406 /* We don't have the resources to process this packet, discard it */
407 Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
408 return;
409 }
410
411 TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
412 "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize));
413
414 RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
415 IPDR->HeaderSize = IPPacket->HeaderSize;
416 }
417
418 /* Create a buffer, copy the data into it and put it
419 in the fragment list */
420
421 Fragment = PoolAllocateBuffer(sizeof(IP_FRAGMENT));
422 if (!Fragment) {
423 /* We don't have the resources to process this packet, discard it */
424 Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
425 return;
426 }
427
428 TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
429
430 Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
431 Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size);
432 if (!Fragment->Data) {
433 /* We don't have the resources to process this packet, discard it */
434 Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
435 return;
436 }
437
438 TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d).\n",
439 Fragment->Data, Fragment->Size));
440
441 /* Copy datagram data into fragment buffer */
442 CopyPacketToBuffer(Fragment->Data,
443 IPPacket->NdisPacket,
444 IPPacket->Position,
445 Fragment->Size);
446 Fragment->Offset = FragFirst;
447
448 /* If this is the last fragment, compute and save the datagram data size */
449 if (!MoreFragments)
450 IPDR->DataSize = FragFirst + Fragment->Size;
451
452 /* Put the fragment in the list */
453 InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
454 break;
455 }
456
457 TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
458
459 if (IsListEmpty(&IPDR->HoleListHead)) {
460 /* Hole list is empty which means a complete datagram can be assembled.
461 Assemble the datagram and pass it to an upper layer protocol */
462
463 TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
464
465 Datagram = ReassembleDatagram(IPDR);
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 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
474 return;
475 }
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 PoolFreeBuffer(Datagram);
483 } else
484 KeReleaseSpinLock(&IPDR->Lock, OldIrql);
485 }
486
487
488 VOID IPFreeReassemblyList(
489 VOID)
490 /*
491 * FUNCTION: Frees all IP datagram reassembly structures in the list
492 */
493 {
494 KIRQL OldIrql;
495 PLIST_ENTRY CurrentEntry;
496 PIPDATAGRAM_REASSEMBLY Current;
497
498 KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
499
500 CurrentEntry = ReassemblyListHead.Flink;
501 while (CurrentEntry != &ReassemblyListHead) {
502 Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
503 /* Unlink it from the list */
504 RemoveEntryList(CurrentEntry);
505
506 /* And free the descriptor */
507 FreeIPDR(Current);
508
509 CurrentEntry = CurrentEntry->Flink;
510 }
511
512 KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
513 }
514
515
516 VOID IPDatagramReassemblyTimeout(
517 VOID)
518 /*
519 * FUNCTION: IP datagram reassembly timeout handler
520 * NOTES:
521 * This routine is called by IPTimeout to free any resources used
522 * to hold IP fragments that are being reassembled to form a
523 * complete IP datagram
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(MAX_TRACE, ("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(MAX_TRACE, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize));
563
564 IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
565
566 TI_DbgPrint(MAX_TRACE, ("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 /* Done with this NTE */
586 DereferenceObject(NTE);
587 } else {
588 /* This packet is not destined for us. If we are a router,
589 try to find a route and forward the packet */
590
591 /* FIXME: Check if acting as a router */
592 #if 0
593 NCE = RouteFindRouter(&IPPacket->DstAddr, NULL);
594 if (NCE) {
595 /* FIXME: Possibly fragment datagram */
596 /* Forward the packet */
597 IPSendFragment(IPPacket, NCE);
598 } else {
599 TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
600 IPPacket->DstAddr.Address.IPv4Address));
601
602 /* FIXME: Send ICMP error code */
603 }
604 #endif
605 }
606 }
607
608
609 VOID IPReceive(
610 PVOID Context,
611 PIP_PACKET IPPacket)
612 /*
613 * FUNCTION: Receives an IP datagram (or fragment)
614 * ARGUMENTS:
615 * Context = Pointer to context information (IP_INTERFACE)
616 * IPPacket = Pointer to IP packet
617 */
618 {
619 UINT Version;
620
621 /* Check that IP header has a supported version */
622 Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
623 switch (Version) {
624 case 4:
625 IPPacket->Type = IP_ADDRESS_V4;
626 IPv4Receive(Context, IPPacket);
627 break;
628 case 6:
629 IPPacket->Type = IP_ADDRESS_V6;
630 TI_DbgPrint(MIN_TRACE, ("Datagram of type IPv6 discarded.\n"));
631 return;
632 default:
633 TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
634
635 DISPLAY_IP_PACKET(IPPacket);
636
637 return;
638 }
639 }
640
641 /* EOF */