3273e272ac34d25ab14ea3b12e2f884748c7c1e5
[reactos.git] / reactos / 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 packet at (0x%X).\n", CurrentF->Packet));
93
94 /* Free the fragment data buffer */
95 if (CurrentF->ReturnPacket)
96 {
97 NdisReturnPackets(&CurrentF->Packet, 1);
98 }
99 else
100 {
101 FreeNdisPacket(CurrentF->Packet);
102 }
103
104 TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
105
106 /* And free the fragment descriptor */
107 ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
108 CurrentEntry = NextEntry;
109 }
110
111 TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
112
113 ExFreeToNPagedLookasideList(&IPDRList, IPDR);
114 }
115
116
117 VOID RemoveIPDR(
118 PIPDATAGRAM_REASSEMBLY IPDR)
119 /*
120 * FUNCTION: Removes an IP datagram reassembly structure from the global list
121 * ARGUMENTS:
122 * IPDR = Pointer to IP datagram reassembly structure
123 */
124 {
125 KIRQL OldIrql;
126
127 TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
128
129 TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
130 RemoveEntryList(&IPDR->ListEntry);
131 TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
132 }
133
134
135 PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
136 PIP_PACKET IPPacket)
137 /*
138 * FUNCTION: Returns a pointer to an IP datagram reassembly structure
139 * ARGUMENTS:
140 * IPPacket = Pointer to IP packet
141 * NOTES:
142 * A datagram is identified by four paramters, which are
143 * Source and destination address, protocol number and
144 * identification number
145 */
146 {
147 KIRQL OldIrql;
148 PLIST_ENTRY CurrentEntry;
149 PIPDATAGRAM_REASSEMBLY Current;
150 PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
151
152 TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
153
154 TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
155
156 /* FIXME: Assume IPv4 */
157
158 CurrentEntry = ReassemblyListHead.Flink;
159 while (CurrentEntry != &ReassemblyListHead) {
160 Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
161 if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
162 (Header->Id == Current->Id) &&
163 (Header->Protocol == Current->Protocol) &&
164 (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
165 TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
166
167 return Current;
168 }
169 CurrentEntry = CurrentEntry->Flink;
170 }
171
172 TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
173
174 return NULL;
175 }
176
177
178 BOOLEAN
179 ReassembleDatagram(
180 PIP_PACKET IPPacket,
181 PIPDATAGRAM_REASSEMBLY IPDR)
182 /*
183 * FUNCTION: Reassembles an IP datagram
184 * ARGUMENTS:
185 * IPDR = Pointer to IP datagram reassembly structure
186 * NOTES:
187 * This routine concatenates fragments into a complete IP datagram.
188 * The lock is held when this routine is called
189 * RETURNS:
190 * Pointer to IP packet, NULL if there was not enough free resources
191 * NOTES:
192 * At this point, header is expected to point to the IP header
193 */
194 {
195 PLIST_ENTRY CurrentEntry;
196 PIP_FRAGMENT Fragment;
197 PCHAR Data;
198
199 PAGED_CODE();
200
201 TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
202 TI_DbgPrint(DEBUG_IP, ("IPDR->HeaderSize = %d\n", IPDR->HeaderSize));
203 TI_DbgPrint(DEBUG_IP, ("IPDR->DataSize = %d\n", IPDR->DataSize));
204
205 IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
206 IPPacket->HeaderSize = IPDR->HeaderSize;
207
208 RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
209 RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
210
211 /* Allocate space for full IP datagram */
212 IPPacket->Header = ExAllocatePoolWithTag(PagedPool, IPPacket->TotalSize, PACKET_BUFFER_TAG);
213 if (!IPPacket->Header) {
214 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
215 (*IPPacket->Free)(IPPacket);
216 return FALSE;
217 }
218 IPPacket->MappedHeader = FALSE;
219
220 /* Copy the header into the buffer */
221 RtlCopyMemory(IPPacket->Header, &IPDR->IPv4Header, sizeof(IPDR->IPv4Header));
222
223 Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
224 IPPacket->Data = Data;
225
226 /* Copy data from all fragments into buffer */
227 CurrentEntry = IPDR->FragmentListHead.Flink;
228 while (CurrentEntry != &IPDR->FragmentListHead) {
229 Fragment = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
230
231 /* Copy fragment data into datagram buffer */
232 CopyPacketToBuffer(Data + Fragment->Offset,
233 Fragment->Packet,
234 Fragment->PacketOffset,
235 Fragment->Size);
236
237 CurrentEntry = CurrentEntry->Flink;
238 }
239
240 return TRUE;
241 }
242
243
244 __inline VOID Cleanup(
245 PKSPIN_LOCK Lock,
246 KIRQL OldIrql,
247 PIPDATAGRAM_REASSEMBLY IPDR)
248 /*
249 * FUNCTION: Performs cleaning operations on errors
250 * ARGUMENTS:
251 * Lock = Pointer to spin lock to be released
252 * OldIrql = Value of IRQL when spin lock was acquired
253 * IPDR = Pointer to IP datagram reassembly structure to free
254 * Buffer = Optional pointer to a buffer to free
255 */
256 {
257 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
258
259 TcpipReleaseSpinLock(Lock, OldIrql);
260 RemoveIPDR(IPDR);
261 FreeIPDR(IPDR);
262 }
263
264
265 VOID ProcessFragment(
266 PIP_INTERFACE IF,
267 PIP_PACKET IPPacket)
268 /*
269 * FUNCTION: Processes an IP datagram or fragment
270 * ARGUMENTS:
271 * IF = Pointer to IP interface packet was receive on
272 * IPPacket = Pointer to IP packet
273 * NOTES:
274 * This routine reassembles fragments and, if a whole datagram can
275 * be assembled, passes the datagram on to the IP protocol dispatcher
276 */
277 {
278 KIRQL OldIrql;
279 PIPDATAGRAM_REASSEMBLY IPDR;
280 PLIST_ENTRY CurrentEntry;
281 PIPDATAGRAM_HOLE Hole, NewHole;
282 USHORT FragFirst;
283 USHORT FragLast;
284 BOOLEAN MoreFragments;
285 PIPv4_HEADER IPv4Header;
286 IP_PACKET Datagram;
287 PIP_FRAGMENT Fragment;
288 BOOLEAN Success;
289
290 /* FIXME: Assume IPv4 */
291
292 IPv4Header = (PIPv4_HEADER)IPPacket->Header;
293
294 /* Check if we already have an reassembly structure for this datagram */
295 IPDR = GetReassemblyInfo(IPPacket);
296 if (IPDR) {
297 TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
298 /* We have a reassembly structure */
299 TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
300
301 /* Reset the timeout since we received a fragment */
302 IPDR->TimeoutCount = 0;
303 } else {
304 TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
305
306 /* We don't have a reassembly structure, create one */
307 IPDR = ExAllocateFromNPagedLookasideList(&IPDRList);
308 if (!IPDR)
309 /* We don't have the resources to process this packet, discard it */
310 return;
311
312 /* Create a descriptor spanning from zero to infinity.
313 Actually, we use a value slightly greater than the
314 maximum number of octets an IP datagram can contain */
315 Hole = CreateHoleDescriptor(0, 65536);
316 if (!Hole) {
317 /* We don't have the resources to process this packet, discard it */
318 ExFreeToNPagedLookasideList(&IPDRList, IPDR);
319 return;
320 }
321 AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
322 AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
323 IPDR->Id = IPv4Header->Id;
324 IPDR->Protocol = IPv4Header->Protocol;
325 IPDR->TimeoutCount = 0;
326 InitializeListHead(&IPDR->FragmentListHead);
327 InitializeListHead(&IPDR->HoleListHead);
328 InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
329
330 TcpipInitializeSpinLock(&IPDR->Lock);
331
332 TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
333
334 /* Update the reassembly list */
335 TcpipInterlockedInsertTailList(
336 &ReassemblyListHead,
337 &IPDR->ListEntry,
338 &ReassemblyListLock);
339 }
340
341 FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
342 FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
343 MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
344
345 CurrentEntry = IPDR->HoleListHead.Flink;
346 for (;;) {
347 if (CurrentEntry == &IPDR->HoleListHead)
348 break;
349
350 Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
351
352 TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
353 FragFirst, FragLast, Hole->First, Hole->Last));
354
355 if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
356 TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
357 /* The fragment does not overlap with the hole, try next
358 descriptor in the list */
359
360 CurrentEntry = CurrentEntry->Flink;
361 continue;
362 }
363
364 /* The fragment overlap with the hole, unlink the descriptor */
365 RemoveEntryList(CurrentEntry);
366
367 if (FragFirst > Hole->First) {
368 NewHole = CreateHoleDescriptor(Hole->First, FragFirst - 1);
369 if (!NewHole) {
370 /* We don't have the resources to process this packet, discard it */
371 ExFreeToNPagedLookasideList(&IPHoleList, Hole);
372 Cleanup(&IPDR->Lock, OldIrql, IPDR);
373 return;
374 }
375
376 /* Put the new descriptor in the list */
377 InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
378 }
379
380 if ((FragLast < Hole->Last) && MoreFragments) {
381 NewHole = CreateHoleDescriptor(FragLast + 1, Hole->Last);
382 if (!NewHole) {
383 /* We don't have the resources to process this packet, discard it */
384 ExFreeToNPagedLookasideList(&IPHoleList, Hole);
385 Cleanup(&IPDR->Lock, OldIrql, IPDR);
386 return;
387 }
388
389 /* Put the new hole descriptor in the list */
390 InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
391 }
392
393 ExFreeToNPagedLookasideList(&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, sizeof(IPDR->IPv4Header));
401 IPDR->HeaderSize = sizeof(IPDR->IPv4Header);
402 }
403
404 /* Create a buffer, copy the data into it and put it
405 in the fragment list */
406
407 Fragment = ExAllocateFromNPagedLookasideList(&IPFragmentList);
408 if (!Fragment) {
409 /* We don't have the resources to process this packet, discard it */
410 Cleanup(&IPDR->Lock, OldIrql, IPDR);
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->Packet = IPPacket->NdisPacket;
418 Fragment->ReturnPacket = IPPacket->ReturnPacket;
419 Fragment->PacketOffset = IPPacket->Position + IPPacket->HeaderSize;
420 Fragment->Offset = FragFirst;
421
422 /* Disassociate the NDIS packet so it isn't freed upon return from IPReceive() */
423 IPPacket->NdisPacket = NULL;
424
425 /* If this is the last fragment, compute and save the datagram data size */
426 if (!MoreFragments)
427 IPDR->DataSize = FragFirst + Fragment->Size;
428
429 /* Put the fragment in the list */
430 InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
431 break;
432 }
433
434 TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
435
436 if (IsListEmpty(&IPDR->HoleListHead)) {
437 /* Hole list is empty which means a complete datagram can be assembled.
438 Assemble the datagram and pass it to an upper layer protocol */
439
440 TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
441
442 RemoveIPDR(IPDR);
443 TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
444
445 /* FIXME: Assumes IPv4 */
446 IPInitializePacket(&Datagram, IP_ADDRESS_V4);
447
448 Success = ReassembleDatagram(&Datagram, IPDR);
449
450 FreeIPDR(IPDR);
451
452 if (!Success)
453 /* Not enough free resources, discard the packet */
454 return;
455
456 DISPLAY_IP_PACKET(&Datagram);
457
458 /* Give the packet to the protocol dispatcher */
459 IPDispatchProtocol(IF, &Datagram);
460
461 /* We're done with this datagram */
462 TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
463 Datagram.Free(&Datagram);
464 } else
465 TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
466 }
467
468
469 VOID IPFreeReassemblyList(
470 VOID)
471 /*
472 * FUNCTION: Frees all IP datagram reassembly structures in the list
473 */
474 {
475 KIRQL OldIrql;
476 PLIST_ENTRY CurrentEntry;
477 PIPDATAGRAM_REASSEMBLY Current;
478
479 TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
480
481 CurrentEntry = ReassemblyListHead.Flink;
482 while (CurrentEntry != &ReassemblyListHead) {
483 Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
484 /* Unlink it from the list */
485 RemoveEntryList(CurrentEntry);
486
487 /* And free the descriptor */
488 FreeIPDR(Current);
489
490 CurrentEntry = CurrentEntry->Flink;
491 }
492
493 TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
494 }
495
496
497 VOID IPDatagramReassemblyTimeout(
498 VOID)
499 /*
500 * FUNCTION: IP datagram reassembly timeout handler
501 * NOTES:
502 * This routine is called by IPTimeout to free any resources used
503 * to hold IP fragments that have taken too long to reassemble
504 */
505 {
506 PLIST_ENTRY CurrentEntry, NextEntry;
507 PIPDATAGRAM_REASSEMBLY CurrentIPDR;
508
509 TcpipAcquireSpinLockAtDpcLevel(&ReassemblyListLock);
510
511 CurrentEntry = ReassemblyListHead.Flink;
512 while (CurrentEntry != &ReassemblyListHead)
513 {
514 NextEntry = CurrentEntry->Flink;
515 CurrentIPDR = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
516
517 TcpipAcquireSpinLockAtDpcLevel(&CurrentIPDR->Lock);
518
519 if (++CurrentIPDR->TimeoutCount == MAX_TIMEOUT_COUNT)
520 {
521 TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
522 RemoveEntryList(CurrentEntry);
523 FreeIPDR(CurrentIPDR);
524 }
525 else
526 {
527 ASSERT(CurrentIPDR->TimeoutCount < MAX_TIMEOUT_COUNT);
528 TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
529 }
530
531 CurrentEntry = NextEntry;
532 }
533
534 TcpipReleaseSpinLockFromDpcLevel(&ReassemblyListLock);
535 }
536
537 VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)
538 /*
539 * FUNCTION: Receives an IPv4 datagram (or fragment)
540 * ARGUMENTS:
541 * Context = Pointer to context information (IP_INTERFACE)
542 * IPPacket = Pointer to IP packet
543 */
544 {
545 UCHAR FirstByte;
546 ULONG BytesCopied;
547
548 TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
549
550 /* Read in the first IP header byte for size information */
551 BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
552 IPPacket->NdisPacket,
553 IPPacket->Position,
554 sizeof(UCHAR));
555 if (BytesCopied != sizeof(UCHAR))
556 {
557 TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
558 /* Discard packet */
559 return;
560 }
561
562 IPPacket->HeaderSize = (FirstByte & 0x0F) << 2;
563 TI_DbgPrint(DEBUG_IP, ("IPPacket->HeaderSize = %d\n", IPPacket->HeaderSize));
564
565 if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
566 TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n",
567 IPPacket->HeaderSize));
568 /* Discard packet */
569 return;
570 }
571
572 /* This is freed by IPPacket->Free() */
573 IPPacket->Header = ExAllocatePoolWithTag(NonPagedPool,
574 IPPacket->HeaderSize,
575 PACKET_BUFFER_TAG);
576 if (!IPPacket->Header)
577 {
578 TI_DbgPrint(MIN_TRACE, ("No resources to allocate header\n"));
579 /* Discard packet */
580 return;
581 }
582
583 IPPacket->MappedHeader = FALSE;
584
585 BytesCopied = CopyPacketToBuffer((PCHAR)IPPacket->Header,
586 IPPacket->NdisPacket,
587 IPPacket->Position,
588 IPPacket->HeaderSize);
589 if (BytesCopied != IPPacket->HeaderSize)
590 {
591 TI_DbgPrint(MIN_TRACE, ("Failed to copy in header\n"));
592 /* Discard packet */
593 return;
594 }
595
596 /* Checksum IPv4 header */
597 if (!IPv4CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
598 TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n",
599 WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
600 /* Discard packet */
601 return;
602 }
603
604 IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
605
606 AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
607 AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
608
609 TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
610 IPPacket->Position));
611
612 /* FIXME: Possibly forward packets with multicast addresses */
613
614 /* FIXME: Should we allow packets to be received on the wrong interface? */
615 /* XXX Find out if this packet is destined for us */
616 ProcessFragment(IF, IPPacket);
617 }
618
619
620 VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
621 /*
622 * FUNCTION: Receives an IP datagram (or fragment)
623 * ARGUMENTS:
624 * IF = Interface
625 * IPPacket = Pointer to IP packet
626 */
627 {
628 UCHAR FirstByte;
629 UINT Version, BytesCopied;
630
631 /* Read in the first IP header byte for version information */
632 BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
633 IPPacket->NdisPacket,
634 IPPacket->Position,
635 sizeof(UCHAR));
636 if (BytesCopied != sizeof(UCHAR))
637 {
638 TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
639 IPPacket->Free(IPPacket);
640 return;
641 }
642
643 /* Check that IP header has a supported version */
644 Version = (FirstByte >> 4);
645
646 switch (Version) {
647 case 4:
648 IPPacket->Type = IP_ADDRESS_V4;
649 IPv4Receive(IF, IPPacket);
650 break;
651 case 6:
652 IPPacket->Type = IP_ADDRESS_V6;
653 TI_DbgPrint(MAX_TRACE, ("Datagram of type IPv6 discarded.\n"));
654 break;
655 default:
656 TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
657 break;
658 }
659
660 IPPacket->Free(IPPacket);
661 }
662
663 /* EOF */