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