]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6Input.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Input.c
1 /** @file
2 IP6 internal functions to process the incoming packets.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Ip6Impl.h"
17
18 /**
19 Create an empty assemble entry for the packet identified by
20 (Dst, Src, Id). The default life for the packet is 60 seconds.
21
22 @param[in] Dst The destination address.
23 @param[in] Src The source address.
24 @param[in] Id The ID field in the IP header.
25
26 @return NULL if failed to allocate memory for the entry. Otherwise,
27 the pointer to the just created reassemble entry.
28
29 **/
30 IP6_ASSEMBLE_ENTRY *
31 Ip6CreateAssembleEntry (
32 IN EFI_IPv6_ADDRESS *Dst,
33 IN EFI_IPv6_ADDRESS *Src,
34 IN UINT32 Id
35 )
36 {
37 IP6_ASSEMBLE_ENTRY *Assemble;
38
39 Assemble = AllocatePool (sizeof (IP6_ASSEMBLE_ENTRY));
40 if (Assemble == NULL) {
41 return NULL;
42 }
43
44 IP6_COPY_ADDRESS (&Assemble->Dst, Dst);
45 IP6_COPY_ADDRESS (&Assemble->Src, Src);
46 InitializeListHead (&Assemble->Fragments);
47
48 Assemble->Id = Id;
49 Assemble->Life = IP6_FRAGMENT_LIFE + 1;
50
51 Assemble->TotalLen = 0;
52 Assemble->CurLen = 0;
53 Assemble->Head = NULL;
54 Assemble->Info = NULL;
55 Assemble->Packet = NULL;
56
57 return Assemble;
58 }
59
60 /**
61 Release all the fragments of a packet, then free the assemble entry.
62
63 @param[in] Assemble The assemble entry to free.
64
65 **/
66 VOID
67 Ip6FreeAssembleEntry (
68 IN IP6_ASSEMBLE_ENTRY *Assemble
69 )
70 {
71 LIST_ENTRY *Entry;
72 LIST_ENTRY *Next;
73 NET_BUF *Fragment;
74
75 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {
76 Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
77
78 RemoveEntryList (Entry);
79 NetbufFree (Fragment);
80 }
81
82 if (Assemble->Packet != NULL) {
83 NetbufFree (Assemble->Packet);
84 }
85
86 FreePool (Assemble);
87 }
88
89 /**
90 Release all the fragments of the packet. This is the callback for
91 the assembled packet's OnFree. It will free the assemble entry,
92 which in turn frees all the fragments of the packet.
93
94 @param[in] Arg The assemble entry to free.
95
96 **/
97 VOID
98 EFIAPI
99 Ip6OnFreeFragments (
100 IN VOID *Arg
101 )
102 {
103 Ip6FreeAssembleEntry ((IP6_ASSEMBLE_ENTRY *) Arg);
104 }
105
106 /**
107 Trim the packet to fit in [Start, End), and update per the
108 packet information.
109
110 @param[in, out] Packet Packet to trim.
111 @param[in] Start The sequence of the first byte to fit in.
112 @param[in] End One beyond the sequence of last byte to fit in.
113
114 **/
115 VOID
116 Ip6TrimPacket (
117 IN OUT NET_BUF *Packet,
118 IN INTN Start,
119 IN INTN End
120 )
121 {
122 IP6_CLIP_INFO *Info;
123 INTN Len;
124
125 Info = IP6_GET_CLIP_INFO (Packet);
126
127 ASSERT (Info->Start + Info->Length == Info->End);
128 ASSERT ((Info->Start < End) && (Start < Info->End));
129
130 if (Info->Start < Start) {
131 Len = Start - Info->Start;
132
133 NetbufTrim (Packet, (UINT32) Len, NET_BUF_HEAD);
134 Info->Start = (UINT32) Start;
135 Info->Length -= (UINT32) Len;
136 }
137
138 if (End < Info->End) {
139 Len = End - Info->End;
140
141 NetbufTrim (Packet, (UINT32) Len, NET_BUF_TAIL);
142 Info->End = (UINT32) End;
143 Info->Length -= (UINT32) Len;
144 }
145 }
146
147 /**
148 Reassemble the IP fragments. If all the fragments of the packet
149 have been received, it will wrap the packet in a net buffer then
150 return it to caller. If the packet can't be assembled, NULL is
151 returned.
152
153 @param[in, out] Table The assemble table used. A new assemble entry will be created
154 if the Packet is from a new chain of fragments.
155 @param[in] Packet The fragment to assemble. It might be freed if the fragment
156 can't be re-assembled.
157
158 @return NULL if the packet can't be reassembled. The pointer to the just assembled
159 packet if all the fragments of the packet have arrived.
160
161 **/
162 NET_BUF *
163 Ip6Reassemble (
164 IN OUT IP6_ASSEMBLE_TABLE *Table,
165 IN NET_BUF *Packet
166 )
167 {
168 EFI_IP6_HEADER *Head;
169 IP6_CLIP_INFO *This;
170 IP6_CLIP_INFO *Node;
171 IP6_ASSEMBLE_ENTRY *Assemble;
172 IP6_ASSEMBLE_ENTRY *Entry;
173 LIST_ENTRY *ListHead;
174 LIST_ENTRY *Prev;
175 LIST_ENTRY *Cur;
176 NET_BUF *Fragment;
177 NET_BUF *TmpPacket;
178 NET_BUF *NewPacket;
179 NET_BUF *Duplicate;
180 UINT8 *DupHead;
181 INTN Index;
182 UINT16 UnFragmentLen;
183 UINT8 *NextHeader;
184
185 Head = Packet->Ip.Ip6;
186 This = IP6_GET_CLIP_INFO (Packet);
187
188 ASSERT (Head != NULL);
189
190 //
191 // Find the corresponding assemble entry by (Dst, Src, Id)
192 //
193 Assemble = NULL;
194 Index = IP6_ASSEMBLE_HASH (&Head->DestinationAddress, &Head->SourceAddress, This->Id);
195
196 NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {
197 Entry = NET_LIST_USER_STRUCT (Cur, IP6_ASSEMBLE_ENTRY, Link);
198
199 if (Entry->Id == This->Id &&
200 EFI_IP6_EQUAL (&Entry->Src, &Head->SourceAddress) &&
201 EFI_IP6_EQUAL (&Entry->Dst, &Head->DestinationAddress)
202 ) {
203 Assemble = Entry;
204 break;
205 }
206 }
207
208 //
209 // Create a new entry if can not find an existing one, insert it to assemble table
210 //
211 if (Assemble == NULL) {
212 Assemble = Ip6CreateAssembleEntry (
213 &Head->DestinationAddress,
214 &Head->SourceAddress,
215 This->Id
216 );
217
218 if (Assemble == NULL) {
219 goto Error;
220 }
221
222 InsertHeadList (&Table->Bucket[Index], &Assemble->Link);
223 }
224
225 //
226 // Find the point to insert the packet: before the first
227 // fragment with THIS.Start < CUR.Start. the previous one
228 // has PREV.Start <= THIS.Start < CUR.Start.
229 //
230 ListHead = &Assemble->Fragments;
231
232 NET_LIST_FOR_EACH (Cur, ListHead) {
233 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
234
235 if (This->Start < IP6_GET_CLIP_INFO (Fragment)->Start) {
236 break;
237 }
238 }
239
240 //
241 // Check whether the current fragment overlaps with the previous one.
242 // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to
243 // check whether THIS.Start < PREV.End for overlap. If two fragments
244 // overlaps, trim the overlapped part off THIS fragment.
245 //
246 if ((Cur != ListHead) && ((Prev = Cur->BackLink) != ListHead)) {
247 Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
248 Node = IP6_GET_CLIP_INFO (Fragment);
249
250 if (This->Start < Node->End) {
251 if (This->End <= Node->End) {
252 goto Error;
253 }
254
255 //
256 // Trim the previous fragment from tail.
257 //
258 Ip6TrimPacket (Fragment, Node->Start, This->Start);
259 }
260 }
261
262 //
263 // Insert the fragment into the packet. The fragment may be removed
264 // from the list by the following checks.
265 //
266 NetListInsertBefore (Cur, &Packet->List);
267
268 //
269 // Check the packets after the insert point. It holds that:
270 // THIS.Start <= NODE.Start < NODE.End. The equality holds
271 // if PREV and NEXT are continuous. THIS fragment may fill
272 // several holes. Remove the completely overlapped fragments
273 //
274 while (Cur != ListHead) {
275 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
276 Node = IP6_GET_CLIP_INFO (Fragment);
277
278 //
279 // Remove fragments completely overlapped by this fragment
280 //
281 if (Node->End <= This->End) {
282 Cur = Cur->ForwardLink;
283
284 RemoveEntryList (&Fragment->List);
285 Assemble->CurLen -= Node->Length;
286
287 NetbufFree (Fragment);
288 continue;
289 }
290
291 //
292 // The conditions are: THIS.Start <= NODE.Start, and THIS.End <
293 // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.
294 // If two fragments start at the same offset, remove THIS fragment
295 // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).
296 //
297 if (Node->Start < This->End) {
298 if (This->Start == Node->Start) {
299 RemoveEntryList (&Packet->List);
300 goto Error;
301 }
302
303 Ip6TrimPacket (Packet, This->Start, Node->Start);
304 }
305
306 break;
307 }
308
309 //
310 // Update the assemble info: increase the current length. If it is
311 // the frist fragment, update the packet's IP head and per packet
312 // info. If it is the last fragment, update the total length.
313 //
314 Assemble->CurLen += This->Length;
315
316 if (This->Start == 0) {
317 //
318 // Once the first fragment is enqueued, it can't be removed
319 // from the fragment list. So, Assemble->Head always point
320 // to valid memory area.
321 //
322 if ((Assemble->Head != NULL) || (Assemble->Packet != NULL)) {
323 goto Error;
324 }
325
326 //
327 // Backup the first fragment in case the reasembly of that packet fail.
328 //
329 Duplicate = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));
330 if (Duplicate == NULL) {
331 goto Error;
332 }
333
334 //
335 // Revert IP head to network order.
336 //
337 DupHead = NetbufGetByte (Duplicate, 0, NULL);
338 ASSERT (DupHead != NULL);
339 Duplicate->Ip.Ip6 = Ip6NtohHead ((EFI_IP6_HEADER *) DupHead);
340 Assemble->Packet = Duplicate;
341
342 //
343 // Adjust the unfragmentable part in first fragment
344 //
345 UnFragmentLen = (UINT16) (This->HeadLen - sizeof (EFI_IP6_HEADER));
346 if (UnFragmentLen == 0) {
347 //
348 // There is not any unfragmentable extension header.
349 //
350 ASSERT (Head->NextHeader == IP6_FRAGMENT);
351 Head->NextHeader = This->NextHeader;
352 } else {
353 NextHeader = NetbufGetByte (
354 Packet,
355 This->FormerNextHeader + sizeof (EFI_IP6_HEADER),
356 0
357 );
358 if (NextHeader == NULL) {
359 goto Error;
360 }
361
362 *NextHeader = This->NextHeader;
363 }
364
365 Assemble->Head = Head;
366 Assemble->Info = IP6_GET_CLIP_INFO (Packet);
367 }
368
369 //
370 // Don't update the length more than once.
371 //
372 if ((This->LastFrag != 0) && (Assemble->TotalLen == 0)) {
373 Assemble->TotalLen = This->End;
374 }
375
376 //
377 // Deliver the whole packet if all the fragments received.
378 // All fragments received if:
379 // 1. received the last one, so, the totoal length is know
380 // 2. received all the data. If the last fragment on the
381 // queue ends at the total length, all data is received.
382 //
383 if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {
384
385 RemoveEntryList (&Assemble->Link);
386
387 //
388 // If the packet is properly formated, the last fragment's End
389 // equals to the packet's total length. Otherwise, the packet
390 // is a fake, drop it now.
391 //
392 Fragment = NET_LIST_USER_STRUCT (ListHead->BackLink, NET_BUF, List);
393 if (IP6_GET_CLIP_INFO (Fragment)->End != (INTN) Assemble->TotalLen) {
394 Ip6FreeAssembleEntry (Assemble);
395 goto Error;
396 }
397
398 Fragment = NET_LIST_HEAD (ListHead, NET_BUF, List);
399 This = Assemble->Info;
400
401 //
402 // This TmpPacket is used to hold the unfragmentable part, i.e.,
403 // the IPv6 header and the unfragmentable extension headers. Be noted that
404 // the Fragment Header is exluded.
405 //
406 TmpPacket = NetbufGetFragment (Fragment, 0, This->HeadLen, 0);
407 ASSERT (TmpPacket != NULL);
408
409 NET_LIST_FOR_EACH (Cur, ListHead) {
410 //
411 // Trim off the unfragment part plus the fragment header from all fragments.
412 //
413 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
414 NetbufTrim (Fragment, This->HeadLen + sizeof (IP6_FRAGMENT_HEADER), TRUE);
415 }
416
417 InsertHeadList (ListHead, &TmpPacket->List);
418
419 //
420 // Wrap the packet in a net buffer then deliver it up
421 //
422 NewPacket = NetbufFromBufList (
423 &Assemble->Fragments,
424 0,
425 0,
426 Ip6OnFreeFragments,
427 Assemble
428 );
429
430 if (NewPacket == NULL) {
431 Ip6FreeAssembleEntry (Assemble);
432 goto Error;
433 }
434
435 NewPacket->Ip.Ip6 = Assemble->Head;
436
437 CopyMem (IP6_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (IP6_CLIP_INFO));
438
439 return NewPacket;
440 }
441
442 return NULL;
443
444 Error:
445 NetbufFree (Packet);
446 return NULL;
447 }
448
449
450 /**
451 The callback function for the net buffer that wraps the packet processed by
452 IPsec. It releases the wrap packet and also signals IPsec to free the resources.
453
454 @param[in] Arg The wrap context.
455
456 **/
457 VOID
458 EFIAPI
459 Ip6IpSecFree (
460 IN VOID *Arg
461 )
462 {
463 IP6_IPSEC_WRAP *Wrap;
464
465 Wrap = (IP6_IPSEC_WRAP *) Arg;
466
467 if (Wrap->IpSecRecycleSignal != NULL) {
468 gBS->SignalEvent (Wrap->IpSecRecycleSignal);
469 }
470
471 NetbufFree (Wrap->Packet);
472
473 FreePool (Wrap);
474
475 return;
476 }
477
478 /**
479 The work function to locate the IPsec protocol to process the inbound or
480 outbound IP packets. The process routine handles the packet with the following
481 actions: bypass the packet, discard the packet, or protect the packet.
482
483 @param[in] IpSb The IP6 service instance.
484 @param[in] Head The caller-supplied IP6 header.
485 @param[in, out] LastHead The next header field of last IP header.
486 @param[in, out] Netbuf The IP6 packet to be processed by IPsec.
487 @param[in] ExtHdrs The caller-supplied options.
488 @param[in] ExtHdrsLen The length of the option.
489 @param[in] Direction The directionality in an SPD entry,
490 EfiIPsecInBound, or EfiIPsecOutBound.
491 @param[in] Context The token's wrap.
492
493 @retval EFI_SUCCESS The IPsec protocol is not available or disabled.
494 @retval EFI_SUCCESS The packet was bypassed, and all buffers remain the same.
495 @retval EFI_SUCCESS The packet was protected.
496 @retval EFI_ACCESS_DENIED The packet was discarded.
497 @retval EFI_OUT_OF_RESOURCES There are not suffcient resources to complete the operation.
498 @retval EFI_BUFFER_TOO_SMALL The number of non-empty blocks is bigger than the
499 number of input data blocks when building a fragment table.
500
501 **/
502 EFI_STATUS
503 Ip6IpSecProcessPacket (
504 IN IP6_SERVICE *IpSb,
505 IN EFI_IP6_HEADER *Head,
506 IN OUT UINT8 *LastHead,
507 IN OUT NET_BUF **Netbuf,
508 IN VOID *ExtHdrs,
509 IN UINT32 ExtHdrsLen,
510 IN EFI_IPSEC_TRAFFIC_DIR Direction,
511 IN VOID *Context
512 )
513 {
514 NET_FRAGMENT *FragmentTable;
515 UINT32 FragmentCount;
516 EFI_EVENT RecycleEvent;
517 NET_BUF *Packet;
518 IP6_TXTOKEN_WRAP *TxWrap;
519 IP6_IPSEC_WRAP *IpSecWrap;
520 EFI_STATUS Status;
521 EFI_IP6_HEADER *PacketHead;
522 UINT8 *Buf;
523
524 Status = EFI_SUCCESS;
525 Packet = *Netbuf;
526 RecycleEvent = NULL;
527 IpSecWrap = NULL;
528 FragmentTable = NULL;
529 PacketHead = NULL;
530 Buf = NULL;
531 TxWrap = (IP6_TXTOKEN_WRAP *) Context;
532 FragmentCount = Packet->BlockOpNum;
533
534 if (mIpSec == NULL) {
535 gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &mIpSec);
536
537 //
538 // Check whether the ipsec protocol is available.
539 //
540 if (mIpSec == NULL) {
541 goto ON_EXIT;
542 }
543 }
544
545 //
546 // Check whether the ipsec enable variable is set.
547 //
548 if (mIpSec->DisabledFlag) {
549 //
550 // If IPsec is disabled, restore the original MTU
551 //
552 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;
553 goto ON_EXIT;
554 } else {
555 //
556 // If IPsec is enabled, use the MTU which reduce the IPsec header length.
557 //
558 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP6_MAX_IPSEC_HEADLEN;
559 }
560
561
562 //
563 // Bypass all multicast inbound or outbound traffic.
564 //
565 if (IP6_IS_MULTICAST (&Head->DestinationAddress) || IP6_IS_MULTICAST (&Head->SourceAddress)) {
566 goto ON_EXIT;
567 }
568
569 //
570 // Rebuild fragment table from netbuf to ease ipsec process.
571 //
572 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));
573
574 if (FragmentTable == NULL) {
575 Status = EFI_OUT_OF_RESOURCES;
576 goto ON_EXIT;
577 }
578
579 Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);
580
581 if (EFI_ERROR(Status)) {
582 FreePool (FragmentTable);
583 goto ON_EXIT;
584 }
585
586 //
587 // Convert host byte order to network byte order
588 //
589 Ip6NtohHead (Head);
590
591 Status = mIpSec->Process (
592 mIpSec,
593 IpSb->Controller,
594 IP_VERSION_6,
595 (VOID *) Head,
596 LastHead,
597 NULL,
598 0,
599 (EFI_IPSEC_FRAGMENT_DATA **) (&FragmentTable),
600 &FragmentCount,
601 Direction,
602 &RecycleEvent
603 );
604 //
605 // Convert back to host byte order
606 //
607 Ip6NtohHead (Head);
608
609 if (EFI_ERROR (Status)) {
610 goto ON_EXIT;
611 }
612
613 if (Direction == EfiIPsecOutBound && TxWrap != NULL) {
614
615 TxWrap->IpSecRecycleSignal = RecycleEvent;
616 TxWrap->Packet = NetbufFromExt (
617 FragmentTable,
618 FragmentCount,
619 IP6_MAX_HEADLEN,
620 0,
621 Ip6FreeTxToken,
622 TxWrap
623 );
624 if (TxWrap->Packet == NULL) {
625 Status = EFI_OUT_OF_RESOURCES;
626 goto ON_EXIT;
627 }
628
629 *Netbuf = TxWrap->Packet;
630
631 } else {
632
633 IpSecWrap = AllocateZeroPool (sizeof (IP6_IPSEC_WRAP));
634
635 if (IpSecWrap == NULL) {
636 goto ON_EXIT;
637 }
638
639 IpSecWrap->IpSecRecycleSignal = RecycleEvent;
640 IpSecWrap->Packet = Packet;
641 Packet = NetbufFromExt (
642 FragmentTable,
643 FragmentCount,
644 IP6_MAX_HEADLEN,
645 0,
646 Ip6IpSecFree,
647 IpSecWrap
648 );
649
650 if (Packet == NULL) {
651 Status = EFI_OUT_OF_RESOURCES;
652 goto ON_EXIT;
653 }
654
655 if (Direction == EfiIPsecInBound) {
656
657 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (
658 Packet,
659 sizeof (EFI_IP6_HEADER) + ExtHdrsLen,
660 NET_BUF_HEAD
661 );
662 if (PacketHead == NULL) {
663 Status = EFI_OUT_OF_RESOURCES;
664 goto ON_EXIT;
665 }
666
667 CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));
668 Packet->Ip.Ip6 = PacketHead;
669
670 if (ExtHdrs != NULL) {
671 Buf = (UINT8 *) (PacketHead + 1);
672 CopyMem (Buf, ExtHdrs, ExtHdrsLen);
673 }
674
675 NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + ExtHdrsLen, TRUE);
676 CopyMem (
677 IP6_GET_CLIP_INFO (Packet),
678 IP6_GET_CLIP_INFO (IpSecWrap->Packet),
679 sizeof (IP6_CLIP_INFO)
680 );
681 }
682
683 *Netbuf = Packet;
684 }
685
686 ON_EXIT:
687 return Status;
688 }
689
690 /**
691 The IP6 input routine. It is called by the IP6_INTERFACE when an
692 IP6 fragment is received from MNP.
693
694 @param[in] Packet The IP6 packet received.
695 @param[in] IoStatus The return status of receive request.
696 @param[in] Flag The link layer flag for the packet received, such
697 as multicast.
698 @param[in] Context The IP6 service instance that owns the MNP.
699
700 **/
701 VOID
702 Ip6AcceptFrame (
703 IN NET_BUF *Packet,
704 IN EFI_STATUS IoStatus,
705 IN UINT32 Flag,
706 IN VOID *Context
707 )
708 {
709 IP6_SERVICE *IpSb;
710 IP6_CLIP_INFO *Info;
711 EFI_IP6_HEADER *Head;
712 UINT16 PayloadLen;
713 UINT8 *Payload;
714 UINT16 TotalLen;
715 UINT8 *LastHead;
716 UINT32 FormerHeadOffset;
717 UINT32 UnFragmentLen;
718 UINT32 ExtHdrsLen;
719 UINT32 HeadLen;
720 BOOLEAN Fragmented;
721 IP6_FRAGMENT_HEADER *FragmentHead;
722 UINT16 FragmentOffset;
723 EFI_STATUS Status;
724 EFI_IPv6_ADDRESS Loopback;
725
726 IpSb = (IP6_SERVICE *) Context;
727 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
728
729 Payload = NULL;
730
731 //
732 // Check input parameters
733 //
734 if (EFI_ERROR (IoStatus) || (IpSb->State == IP6_SERVICE_DESTROY)) {
735 goto Drop;
736 }
737
738 //
739 // Check whether the input packet is a valid packet
740 //
741 if (Packet->TotalSize < IP6_MIN_HEADLEN) {
742 goto Restart;
743 }
744
745 //
746 // Get header information of the packet.
747 //
748 Head = (EFI_IP6_HEADER *) NetbufGetByte (Packet, 0, NULL);
749 if (Head == NULL) {
750 goto Restart;
751 }
752
753 //
754 // Multicast addresses must not be used as source addresses in IPv6 packets.
755 //
756 if ((Head->Version != 6) || (IP6_IS_MULTICAST (&Head->SourceAddress))) {
757 goto Restart;
758 }
759
760 //
761 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.
762 //
763 ZeroMem (&Loopback, sizeof (EFI_IPv6_ADDRESS));
764 Loopback.Addr[15] = 0x1;
765 if ((CompareMem (&Loopback, &Head->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) ||
766 (NetIp6IsUnspecifiedAddr (&Head->DestinationAddress))) {
767 goto Restart;
768 }
769
770 //
771 // Convert the IP header to host byte order.
772 //
773 Packet->Ip.Ip6 = Ip6NtohHead (Head);
774
775 //
776 // Get the per packet info.
777 //
778 Info = IP6_GET_CLIP_INFO (Packet);
779 Info->LinkFlag = Flag;
780 Info->CastType = 0;
781
782 if (IpSb->MnpConfigData.EnablePromiscuousReceive) {
783 Info->CastType = Ip6Promiscuous;
784 }
785
786 if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
787 Info->CastType = Ip6Unicast;
788 } else if (IP6_IS_MULTICAST (&Head->DestinationAddress)) {
789 if (Ip6FindMldEntry (IpSb, &Head->DestinationAddress) != NULL) {
790 Info->CastType = Ip6Multicast;
791 }
792 }
793
794 //
795 // Drop the packet that is not delivered to us.
796 //
797 if (Info->CastType == 0) {
798 goto Restart;
799 }
800
801
802 PayloadLen = Head->PayloadLength;
803
804 Info->Start = 0;
805 Info->Length = PayloadLen;
806 Info->End = Info->Start + Info->Length;
807 Info->HeadLen = (UINT16) sizeof (EFI_IP6_HEADER);
808 Info->Status = EFI_SUCCESS;
809 Info->LastFrag = FALSE;
810
811 TotalLen = (UINT16) (PayloadLen + sizeof (EFI_IP6_HEADER));
812
813 //
814 // Mnp may deliver frame trailer sequence up, trim it off.
815 //
816 if (TotalLen < Packet->TotalSize) {
817 NetbufTrim (Packet, Packet->TotalSize - TotalLen, FALSE);
818 }
819
820 if (TotalLen != Packet->TotalSize) {
821 goto Restart;
822 }
823
824 //
825 // Check the extension headers, if exist validate them
826 //
827 if (PayloadLen != 0) {
828 Payload = AllocatePool ((UINTN) PayloadLen);
829 if (Payload == NULL) {
830 goto Restart;
831 }
832
833 NetbufCopy (Packet, sizeof (EFI_IP6_HEADER), PayloadLen, Payload);
834 }
835
836 LastHead = NULL;
837 if (!Ip6IsExtsValid (
838 IpSb,
839 Packet,
840 &Head->NextHeader,
841 Payload,
842 (UINT32) PayloadLen,
843 TRUE,
844 &FormerHeadOffset,
845 &LastHead,
846 &ExtHdrsLen,
847 &UnFragmentLen,
848 &Fragmented
849 )) {
850 goto Restart;
851 }
852
853 HeadLen = sizeof (EFI_IP6_HEADER) + UnFragmentLen;
854
855 if (Fragmented) {
856 //
857 // Get the fragment offset from the Fragment header
858 //
859 FragmentHead = (IP6_FRAGMENT_HEADER *) NetbufGetByte (Packet, HeadLen, NULL);
860 if (FragmentHead == NULL) {
861 goto Restart;
862 }
863
864 FragmentOffset = NTOHS (FragmentHead->FragmentOffset);
865
866 if ((FragmentOffset & 0x1) == 0) {
867 Info->LastFrag = TRUE;
868 }
869
870 FragmentOffset &= (~0x1);
871
872 //
873 // This is the first fragment of the packet
874 //
875 if (FragmentOffset == 0) {
876 Info->NextHeader = FragmentHead->NextHeader;
877 }
878
879 Info->HeadLen = (UINT16) HeadLen;
880 HeadLen += sizeof (IP6_FRAGMENT_HEADER);
881 Info->Start = FragmentOffset;
882 Info->Length = TotalLen - (UINT16) HeadLen;
883 Info->End = Info->Start + Info->Length;
884 Info->Id = FragmentHead->Identification;
885 Info->FormerNextHeader = FormerHeadOffset;
886
887 //
888 // Fragments should in the unit of 8 octets long except the last one.
889 //
890 if ((Info->LastFrag == 0) && (Info->Length % 8 != 0)) {
891 goto Restart;
892 }
893
894 //
895 // Reassemble the packet.
896 //
897 Packet = Ip6Reassemble (&IpSb->Assemble, Packet);
898 if (Packet == NULL) {
899 goto Restart;
900 }
901
902 //
903 // Re-check the assembled packet to get the right values.
904 //
905 Head = Packet->Ip.Ip6;
906 PayloadLen = Head->PayloadLength;
907 if (PayloadLen != 0) {
908 if (Payload != NULL) {
909 FreePool (Payload);
910 }
911
912 Payload = AllocatePool ((UINTN) PayloadLen);
913 if (Payload == NULL) {
914 goto Restart;
915 }
916
917 NetbufCopy (Packet, sizeof (EFI_IP6_HEADER), PayloadLen, Payload);
918 }
919
920 if (!Ip6IsExtsValid (
921 IpSb,
922 Packet,
923 &Head->NextHeader,
924 Payload,
925 (UINT32) PayloadLen,
926 TRUE,
927 NULL,
928 &LastHead,
929 &ExtHdrsLen,
930 &UnFragmentLen,
931 &Fragmented
932 )) {
933 goto Restart;
934 }
935 }
936
937 //
938 // Trim the head off, after this point, the packet is headless.
939 // and Packet->TotalLen == Info->Length.
940 //
941 NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + ExtHdrsLen, TRUE);
942
943 //
944 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,
945 // and no need consider any other ahead ext headers.
946 //
947 Status = Ip6IpSecProcessPacket (
948 IpSb,
949 Head,
950 LastHead, // need get the lasthead value for input
951 &Packet,
952 NULL,
953 0,
954 EfiIPsecInBound,
955 NULL
956 );
957
958 if (EFI_ERROR(Status)) {
959 goto Restart;
960 }
961
962 //
963 // TODO: may check the last head again, the same as the output routine
964 //
965
966 //
967 // Packet may have been changed. The ownership of the packet
968 // is transfered to the packet process logic.
969 //
970 Head = Packet->Ip.Ip6;
971 IP6_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;
972
973 switch (*LastHead) {
974 case IP6_ICMP:
975 Ip6IcmpHandle (IpSb, Head, Packet);
976 break;
977 default:
978 Ip6Demultiplex (IpSb, Head, Packet);
979 }
980
981 Packet = NULL;
982
983 //
984 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
985 // which are signaled with received data.
986 //
987 DispatchDpc ();
988
989 Restart:
990 if (Payload != NULL) {
991 FreePool (Payload);
992 }
993
994 Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
995
996 Drop:
997 if (Packet != NULL) {
998 NetbufFree (Packet);
999 }
1000
1001 return ;
1002 }
1003
1004 /**
1005 Initialize an already allocated assemble table. This is generally
1006 the assemble table embedded in the IP6 service instance.
1007
1008 @param[in, out] Table The assemble table to initialize.
1009
1010 **/
1011 VOID
1012 Ip6CreateAssembleTable (
1013 IN OUT IP6_ASSEMBLE_TABLE *Table
1014 )
1015 {
1016 UINT32 Index;
1017
1018 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1019 InitializeListHead (&Table->Bucket[Index]);
1020 }
1021 }
1022
1023 /**
1024 Clean up the assemble table by removing all of the fragments
1025 and assemble entries.
1026
1027 @param[in, out] Table The assemble table to clean up.
1028
1029 **/
1030 VOID
1031 Ip6CleanAssembleTable (
1032 IN OUT IP6_ASSEMBLE_TABLE *Table
1033 )
1034 {
1035 LIST_ENTRY *Entry;
1036 LIST_ENTRY *Next;
1037 IP6_ASSEMBLE_ENTRY *Assemble;
1038 UINT32 Index;
1039
1040 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1041 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {
1042 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
1043
1044 RemoveEntryList (Entry);
1045 Ip6FreeAssembleEntry (Assemble);
1046 }
1047 }
1048 }
1049
1050
1051 /**
1052 The signal handle of IP6's recycle event. It is called back
1053 when the upper layer releases the packet.
1054
1055 @param[in] Event The IP6's recycle event.
1056 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.
1057
1058 **/
1059 VOID
1060 EFIAPI
1061 Ip6OnRecyclePacket (
1062 IN EFI_EVENT Event,
1063 IN VOID *Context
1064 )
1065 {
1066 IP6_RXDATA_WRAP *Wrap;
1067
1068 Wrap = (IP6_RXDATA_WRAP *) Context;
1069
1070 EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);
1071 RemoveEntryList (&Wrap->Link);
1072 EfiReleaseLock (&Wrap->IpInstance->RecycleLock);
1073
1074 ASSERT (!NET_BUF_SHARED (Wrap->Packet));
1075 NetbufFree (Wrap->Packet);
1076
1077 gBS->CloseEvent (Wrap->RxData.RecycleSignal);
1078 FreePool (Wrap);
1079 }
1080
1081 /**
1082 Wrap the received packet to a IP6_RXDATA_WRAP, which will be
1083 delivered to the upper layer. Each IP6 child that accepts the
1084 packet will get a not-shared copy of the packet which is wrapped
1085 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed
1086 to the upper layer. The upper layer will signal the recycle event in
1087 it when it is done with the packet.
1088
1089 @param[in] IpInstance The IP6 child to receive the packet.
1090 @param[in] Packet The packet to deliver up.
1091
1092 @return NULL if it failed to wrap the packet; otherwise, the wrapper.
1093
1094 **/
1095 IP6_RXDATA_WRAP *
1096 Ip6WrapRxData (
1097 IN IP6_PROTOCOL *IpInstance,
1098 IN NET_BUF *Packet
1099 )
1100 {
1101 IP6_RXDATA_WRAP *Wrap;
1102 EFI_IP6_RECEIVE_DATA *RxData;
1103 EFI_STATUS Status;
1104
1105 Wrap = AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet->BlockOpNum));
1106
1107 if (Wrap == NULL) {
1108 return NULL;
1109 }
1110
1111 InitializeListHead (&Wrap->Link);
1112
1113 Wrap->IpInstance = IpInstance;
1114 Wrap->Packet = Packet;
1115 RxData = &Wrap->RxData;
1116
1117 ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));
1118
1119 Status = gBS->CreateEvent (
1120 EVT_NOTIFY_SIGNAL,
1121 TPL_NOTIFY,
1122 Ip6OnRecyclePacket,
1123 Wrap,
1124 &RxData->RecycleSignal
1125 );
1126
1127 if (EFI_ERROR (Status)) {
1128 FreePool (Wrap);
1129 return NULL;
1130 }
1131
1132 ASSERT (Packet->Ip.Ip6 != NULL);
1133
1134 //
1135 // The application expects a network byte order header.
1136 //
1137 RxData->HeaderLength = sizeof (EFI_IP6_HEADER);
1138 RxData->Header = (EFI_IP6_HEADER *) Ip6NtohHead (Packet->Ip.Ip6);
1139 RxData->DataLength = Packet->TotalSize;
1140
1141 //
1142 // Build the fragment table to be delivered up.
1143 //
1144 RxData->FragmentCount = Packet->BlockOpNum;
1145 NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);
1146
1147 return Wrap;
1148 }
1149
1150 /**
1151 Check whether this IP child accepts the packet.
1152
1153 @param[in] IpInstance The IP child to check.
1154 @param[in] Head The IP header of the packet.
1155 @param[in] Packet The data of the packet.
1156
1157 @retval TRUE The child wants to receive the packet.
1158 @retval FALSE The child does not want to receive the packet.
1159
1160 **/
1161 BOOLEAN
1162 Ip6InstanceFrameAcceptable (
1163 IN IP6_PROTOCOL *IpInstance,
1164 IN EFI_IP6_HEADER *Head,
1165 IN NET_BUF *Packet
1166 )
1167 {
1168 IP6_ICMP_ERROR_HEAD Icmp;
1169 EFI_IP6_CONFIG_DATA *Config;
1170 IP6_CLIP_INFO *Info;
1171 UINT8 *Proto;
1172 UINT32 Index;
1173 UINT8 *ExtHdrs;
1174 UINT16 ErrMsgPayloadLen;
1175 UINT8 *ErrMsgPayload;
1176
1177 Config = &IpInstance->ConfigData;
1178 Proto = NULL;
1179
1180 //
1181 // Dirty trick for the Tiano UEFI network stack implmentation. If
1182 // ReceiveTimeout == -1, the receive of the packet for this instance
1183 // is disabled. The UEFI spec don't have such captibility. We add
1184 // this to improve the performance because IP will make a copy of
1185 // the received packet for each accepting instance. Some IP instances
1186 // used by UDP/TCP only send packets, they don't wants to receive.
1187 //
1188 if (Config->ReceiveTimeout == (UINT32)(-1)) {
1189 return FALSE;
1190 }
1191
1192 if (Config->AcceptPromiscuous) {
1193 return TRUE;
1194 }
1195
1196 //
1197 // Check whether the protocol is acceptable.
1198 //
1199 ExtHdrs = NetbufGetByte (Packet, 0, NULL);
1200
1201 if (!Ip6IsExtsValid (
1202 IpInstance->Service,
1203 Packet,
1204 &Head->NextHeader,
1205 ExtHdrs,
1206 (UINT32) Head->PayloadLength,
1207 TRUE,
1208 NULL,
1209 &Proto,
1210 NULL,
1211 NULL,
1212 NULL
1213 )) {
1214 return FALSE;
1215 }
1216
1217 //
1218 // The upper layer driver may want to receive the ICMPv6 error packet
1219 // invoked by its packet, like UDP.
1220 //
1221 if ((*Proto == IP6_ICMP) && (!Config->AcceptAnyProtocol) && (*Proto != Config->DefaultProtocol)) {
1222 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
1223
1224 if (Icmp.Head.Type <= ICMP_V6_ERROR_MAX) {
1225 if (!Config->AcceptIcmpErrors) {
1226 return FALSE;
1227 }
1228
1229 //
1230 // Get the protocol of the invoking packet of ICMPv6 error packet.
1231 //
1232 ErrMsgPayloadLen = NTOHS (Icmp.IpHead.PayloadLength);
1233 ErrMsgPayload = NetbufGetByte (Packet, sizeof (Icmp), NULL);
1234
1235 if (!Ip6IsExtsValid (
1236 NULL,
1237 NULL,
1238 &Icmp.IpHead.NextHeader,
1239 ErrMsgPayload,
1240 ErrMsgPayloadLen,
1241 TRUE,
1242 NULL,
1243 &Proto,
1244 NULL,
1245 NULL,
1246 NULL
1247 )) {
1248 return FALSE;
1249 }
1250 }
1251 }
1252
1253 //
1254 // Match the protocol
1255 //
1256 if (!Config->AcceptAnyProtocol && (*Proto != Config->DefaultProtocol)) {
1257 return FALSE;
1258 }
1259
1260 //
1261 // Check for broadcast, the caller has computed the packet's
1262 // cast type for this child's interface.
1263 //
1264 Info = IP6_GET_CLIP_INFO (Packet);
1265
1266 //
1267 // If it is a multicast packet, check whether we are in the group.
1268 //
1269 if (Info->CastType == Ip6Multicast) {
1270 //
1271 // Receive the multicast if the instance wants to receive all packets.
1272 //
1273 if (NetIp6IsUnspecifiedAddr (&IpInstance->ConfigData.StationAddress)) {
1274 return TRUE;
1275 }
1276
1277 for (Index = 0; Index < IpInstance->GroupCount; Index++) {
1278 if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, &Head->DestinationAddress)) {
1279 break;
1280 }
1281 }
1282
1283 return (BOOLEAN)(Index < IpInstance->GroupCount);
1284 }
1285
1286 return TRUE;
1287 }
1288
1289 /**
1290 Enqueue a shared copy of the packet to the IP6 child if the
1291 packet is acceptable to it. Here the data of the packet is
1292 shared, but the net buffer isn't.
1293
1294 @param IpInstance The IP6 child to enqueue the packet to.
1295 @param Head The IP header of the received packet.
1296 @param Packet The data of the received packet.
1297
1298 @retval EFI_NOT_STARTED The IP child hasn't been configured.
1299 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.
1300 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources
1301 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
1302
1303 **/
1304 EFI_STATUS
1305 Ip6InstanceEnquePacket (
1306 IN IP6_PROTOCOL *IpInstance,
1307 IN EFI_IP6_HEADER *Head,
1308 IN NET_BUF *Packet
1309 )
1310 {
1311 IP6_CLIP_INFO *Info;
1312 NET_BUF *Clone;
1313
1314 //
1315 // Check whether the packet is acceptable to this instance.
1316 //
1317 if (IpInstance->State != IP6_STATE_CONFIGED) {
1318 return EFI_NOT_STARTED;
1319 }
1320
1321 if (!Ip6InstanceFrameAcceptable (IpInstance, Head, Packet)) {
1322 return EFI_INVALID_PARAMETER;
1323 }
1324
1325 //
1326 // Enque a shared copy of the packet.
1327 //
1328 Clone = NetbufClone (Packet);
1329
1330 if (Clone == NULL) {
1331 return EFI_OUT_OF_RESOURCES;
1332 }
1333
1334 //
1335 // Set the receive time out for the assembled packet. If it expires,
1336 // packet will be removed from the queue.
1337 //
1338 Info = IP6_GET_CLIP_INFO (Clone);
1339 Info->Life = IP6_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);
1340
1341 InsertTailList (&IpInstance->Received, &Clone->List);
1342 return EFI_SUCCESS;
1343 }
1344
1345 /**
1346 Deliver the received packets to the upper layer if there are both received
1347 requests and enqueued packets. If the enqueued packet is shared, it will
1348 duplicate it to a non-shared packet, release the shared packet, then
1349 deliver the non-shared packet up.
1350
1351 @param[in] IpInstance The IP child to deliver the packet up.
1352
1353 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
1354 packets.
1355 @retval EFI_SUCCESS All the enqueued packets that can be delivered
1356 are delivered up.
1357
1358 **/
1359 EFI_STATUS
1360 Ip6InstanceDeliverPacket (
1361 IN IP6_PROTOCOL *IpInstance
1362 )
1363 {
1364 EFI_IP6_COMPLETION_TOKEN *Token;
1365 IP6_RXDATA_WRAP *Wrap;
1366 NET_BUF *Packet;
1367 NET_BUF *Dup;
1368 UINT8 *Head;
1369
1370 //
1371 // Deliver a packet if there are both a packet and a receive token.
1372 //
1373 while (!IsListEmpty (&IpInstance->Received) && !NetMapIsEmpty (&IpInstance->RxTokens)) {
1374
1375 Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);
1376
1377 if (!NET_BUF_SHARED (Packet)) {
1378 //
1379 // If this is the only instance that wants the packet, wrap it up.
1380 //
1381 Wrap = Ip6WrapRxData (IpInstance, Packet);
1382
1383 if (Wrap == NULL) {
1384 return EFI_OUT_OF_RESOURCES;
1385 }
1386
1387 RemoveEntryList (&Packet->List);
1388
1389 } else {
1390 //
1391 // Create a duplicated packet if this packet is shared
1392 //
1393 Dup = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));
1394
1395 if (Dup == NULL) {
1396 return EFI_OUT_OF_RESOURCES;
1397 }
1398
1399 //
1400 // Copy the IP head over. The packet to deliver up is
1401 // headless. Trim the head off after copy. The IP head
1402 // may be not continuous before the data.
1403 //
1404 Head = NetbufAllocSpace (Dup, sizeof (EFI_IP6_HEADER), NET_BUF_HEAD);
1405 ASSERT (Head != NULL);
1406 Dup->Ip.Ip6 = (EFI_IP6_HEADER *) Head;
1407
1408 CopyMem (Head, Packet->Ip.Ip6, sizeof (EFI_IP6_HEADER));
1409 NetbufTrim (Dup, sizeof (EFI_IP6_HEADER), TRUE);
1410
1411 Wrap = Ip6WrapRxData (IpInstance, Dup);
1412
1413 if (Wrap == NULL) {
1414 NetbufFree (Dup);
1415 return EFI_OUT_OF_RESOURCES;
1416 }
1417
1418 RemoveEntryList (&Packet->List);
1419 NetbufFree (Packet);
1420
1421 Packet = Dup;
1422 }
1423
1424 //
1425 // Insert it into the delivered packet, then get a user's
1426 // receive token, pass the wrapped packet up.
1427 //
1428 EfiAcquireLockOrFail (&IpInstance->RecycleLock);
1429 InsertHeadList (&IpInstance->Delivered, &Wrap->Link);
1430 EfiReleaseLock (&IpInstance->RecycleLock);
1431
1432 Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);
1433 Token->Status = IP6_GET_CLIP_INFO (Packet)->Status;
1434 Token->Packet.RxData = &Wrap->RxData;
1435
1436 gBS->SignalEvent (Token->Event);
1437 }
1438
1439 return EFI_SUCCESS;
1440 }
1441
1442 /**
1443 Enqueue a received packet to all the IP children that share
1444 the same interface.
1445
1446 @param[in] IpSb The IP6 service instance that receive the packet.
1447 @param[in] Head The header of the received packet.
1448 @param[in] Packet The data of the received packet.
1449 @param[in] IpIf The interface to enqueue the packet to.
1450
1451 @return The number of the IP6 children that accepts the packet.
1452
1453 **/
1454 INTN
1455 Ip6InterfaceEnquePacket (
1456 IN IP6_SERVICE *IpSb,
1457 IN EFI_IP6_HEADER *Head,
1458 IN NET_BUF *Packet,
1459 IN IP6_INTERFACE *IpIf
1460 )
1461 {
1462 IP6_PROTOCOL *IpInstance;
1463 IP6_CLIP_INFO *Info;
1464 LIST_ENTRY *Entry;
1465 INTN Enqueued;
1466 INTN LocalType;
1467 INTN SavedType;
1468
1469 //
1470 // First, check that the packet is acceptable to this interface
1471 // and find the local cast type for the interface.
1472 //
1473 LocalType = 0;
1474 Info = IP6_GET_CLIP_INFO (Packet);
1475
1476 if (IpIf->PromiscRecv) {
1477 LocalType = Ip6Promiscuous;
1478 } else {
1479 LocalType = Info->CastType;
1480 }
1481
1482 //
1483 // Iterate through the ip instances on the interface, enqueue
1484 // the packet if filter passed. Save the original cast type,
1485 // and pass the local cast type to the IP children on the
1486 // interface. The global cast type will be restored later.
1487 //
1488 SavedType = Info->CastType;
1489 Info->CastType = (UINT32) LocalType;
1490
1491 Enqueued = 0;
1492
1493 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
1494 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
1495 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
1496
1497 if (Ip6InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {
1498 Enqueued++;
1499 }
1500 }
1501
1502 Info->CastType = (UINT32) SavedType;
1503 return Enqueued;
1504 }
1505
1506 /**
1507 Deliver the packet for each IP6 child on the interface.
1508
1509 @param[in] IpSb The IP6 service instance that received the packet.
1510 @param[in] IpIf The IP6 interface to deliver the packet.
1511
1512 **/
1513 VOID
1514 Ip6InterfaceDeliverPacket (
1515 IN IP6_SERVICE *IpSb,
1516 IN IP6_INTERFACE *IpIf
1517 )
1518 {
1519 IP6_PROTOCOL *IpInstance;
1520 LIST_ENTRY *Entry;
1521
1522 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
1523 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
1524 Ip6InstanceDeliverPacket (IpInstance);
1525 }
1526 }
1527
1528 /**
1529 De-multiplex the packet. the packet delivery is processed in two
1530 passes. The first pass will enqueue a shared copy of the packet
1531 to each IP6 child that accepts the packet. The second pass will
1532 deliver a non-shared copy of the packet to each IP6 child that
1533 has pending receive requests. Data is copied if more than one
1534 child wants to consume the packet, because each IP child needs
1535 its own copy of the packet to make changes.
1536
1537 @param[in] IpSb The IP6 service instance that received the packet.
1538 @param[in] Head The header of the received packet.
1539 @param[in] Packet The data of the received packet.
1540
1541 @retval EFI_NOT_FOUND No IP child accepts the packet.
1542 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP
1543 children.
1544
1545 **/
1546 EFI_STATUS
1547 Ip6Demultiplex (
1548 IN IP6_SERVICE *IpSb,
1549 IN EFI_IP6_HEADER *Head,
1550 IN NET_BUF *Packet
1551 )
1552 {
1553
1554 LIST_ENTRY *Entry;
1555 IP6_INTERFACE *IpIf;
1556 INTN Enqueued;
1557
1558 //
1559 // Two pass delivery: first, enque a shared copy of the packet
1560 // to each instance that accept the packet.
1561 //
1562 Enqueued = 0;
1563
1564 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1565 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
1566
1567 if (IpIf->Configured) {
1568 Enqueued += Ip6InterfaceEnquePacket (IpSb, Head, Packet, IpIf);
1569 }
1570 }
1571
1572 //
1573 // Second: deliver a duplicate of the packet to each instance.
1574 // Release the local reference first, so that the last instance
1575 // getting the packet will not copy the data.
1576 //
1577 NetbufFree (Packet);
1578 Packet = NULL;
1579
1580 if (Enqueued == 0) {
1581 return EFI_NOT_FOUND;
1582 }
1583
1584 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1585 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
1586
1587 if (IpIf->Configured) {
1588 Ip6InterfaceDeliverPacket (IpSb, IpIf);
1589 }
1590 }
1591
1592 return EFI_SUCCESS;
1593 }
1594
1595 /**
1596 Decrease the life of the transmitted packets. If it is
1597 decreased to zero, cancel the packet. This function is
1598 called by Ip6packetTimerTicking that provides timeout for both the
1599 received-but-not-delivered and transmitted-but-not-recycle
1600 packets.
1601
1602 @param[in] Map The IP6 child's transmit map.
1603 @param[in] Item Current transmitted packet.
1604 @param[in] Context Not used.
1605
1606 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
1607
1608 **/
1609 EFI_STATUS
1610 EFIAPI
1611 Ip6SentPacketTicking (
1612 IN NET_MAP *Map,
1613 IN NET_MAP_ITEM *Item,
1614 IN VOID *Context
1615 )
1616 {
1617 IP6_TXTOKEN_WRAP *Wrap;
1618
1619 Wrap = (IP6_TXTOKEN_WRAP *) Item->Value;
1620 ASSERT (Wrap != NULL);
1621
1622 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
1623 Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
1624 }
1625
1626 return EFI_SUCCESS;
1627 }
1628
1629 /**
1630 Timeout the fragments, and the enqueued, and transmitted packets.
1631
1632 @param[in] IpSb The IP6 service instance to timeout.
1633
1634 **/
1635 VOID
1636 Ip6PacketTimerTicking (
1637 IN IP6_SERVICE *IpSb
1638 )
1639 {
1640 LIST_ENTRY *InstanceEntry;
1641 LIST_ENTRY *Entry;
1642 LIST_ENTRY *Next;
1643 IP6_PROTOCOL *IpInstance;
1644 IP6_ASSEMBLE_ENTRY *Assemble;
1645 NET_BUF *Packet;
1646 IP6_CLIP_INFO *Info;
1647 UINT32 Index;
1648
1649 //
1650 // First, time out the fragments. The packet's life is counting down
1651 // once the first-arriving fragment of that packet was received.
1652 //
1653 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1654 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(IpSb->Assemble.Bucket[Index])) {
1655 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
1656
1657 if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {
1658 //
1659 // If the first fragment (the one with a Fragment Offset of zero)
1660 // has been received, an ICMP Time Exceeded - Fragment Reassembly
1661 // Time Exceeded message should be sent to the source of that fragment.
1662 //
1663 if ((Assemble->Packet != NULL) &&
1664 !IP6_IS_MULTICAST (&Assemble->Head->DestinationAddress)) {
1665 Ip6SendIcmpError (
1666 IpSb,
1667 Assemble->Packet,
1668 NULL,
1669 &Assemble->Head->SourceAddress,
1670 ICMP_V6_TIME_EXCEEDED,
1671 ICMP_V6_TIMEOUT_REASSEMBLE,
1672 NULL
1673 );
1674 }
1675
1676 //
1677 // If reassembly of a packet is not completed within 60 seconds of
1678 // the reception of the first-arriving fragment of that packet, the
1679 // reassembly must be abandoned and all the fragments that have been
1680 // received for that packet must be discarded.
1681 //
1682 RemoveEntryList (Entry);
1683 Ip6FreeAssembleEntry (Assemble);
1684 }
1685 }
1686 }
1687
1688 NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {
1689 IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP6_PROTOCOL, Link);
1690
1691 //
1692 // Second, time out the assembled packets enqueued on each IP child.
1693 //
1694 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {
1695 Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1696 Info = IP6_GET_CLIP_INFO (Packet);
1697
1698 if ((Info->Life > 0) && (--Info->Life == 0)) {
1699 RemoveEntryList (Entry);
1700 NetbufFree (Packet);
1701 }
1702 }
1703
1704 //
1705 // Third: time out the transmitted packets.
1706 //
1707 NetMapIterate (&IpInstance->TxTokens, Ip6SentPacketTicking, NULL);
1708 }
1709 }
1710