]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6Input.c
f63c1afa82ab51100d72a351bf21b60dd8dbca70
[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, out] 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, out] ExtHdrs The caller-supplied options.
488 @param[in, out] 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 OUT EFI_IP6_HEADER **Head,
506 IN OUT UINT8 *LastHead,
507 IN OUT NET_BUF **Netbuf,
508 IN OUT UINT8 **ExtHdrs,
509 IN OUT UINT32 *ExtHdrsLen,
510 IN EFI_IPSEC_TRAFFIC_DIR Direction,
511 IN VOID *Context
512 )
513 {
514 NET_FRAGMENT *FragmentTable;
515 NET_FRAGMENT *OriginalFragmentTable;
516 UINT32 FragmentCount;
517 UINT32 OriginalFragmentCount;
518 EFI_EVENT RecycleEvent;
519 NET_BUF *Packet;
520 IP6_TXTOKEN_WRAP *TxWrap;
521 IP6_IPSEC_WRAP *IpSecWrap;
522 EFI_STATUS Status;
523 EFI_IP6_HEADER *PacketHead;
524 UINT8 *Buf;
525 EFI_IP6_HEADER ZeroHead;
526
527 Status = EFI_SUCCESS;
528 Packet = *Netbuf;
529 RecycleEvent = NULL;
530 IpSecWrap = NULL;
531 FragmentTable = NULL;
532 PacketHead = NULL;
533 Buf = NULL;
534 TxWrap = (IP6_TXTOKEN_WRAP *) Context;
535 FragmentCount = Packet->BlockOpNum;
536 ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));
537
538 if (mIpSec == NULL) {
539 gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &mIpSec);
540
541 //
542 // Check whether the ipsec protocol is available.
543 //
544 if (mIpSec == NULL) {
545 goto ON_EXIT;
546 }
547 }
548
549 //
550 // Check whether the ipsec enable variable is set.
551 //
552 if (mIpSec->DisabledFlag) {
553 //
554 // If IPsec is disabled, restore the original MTU
555 //
556 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;
557 goto ON_EXIT;
558 } else {
559 //
560 // If IPsec is enabled, use the MTU which reduce the IPsec header length.
561 //
562 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP6_MAX_IPSEC_HEADLEN;
563 }
564
565
566 //
567 // Bypass all multicast inbound or outbound traffic.
568 //
569 if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress) || IP6_IS_MULTICAST (&(*Head)->SourceAddress)) {
570 goto ON_EXIT;
571 }
572
573 //
574 // Rebuild fragment table from netbuf to ease ipsec process.
575 //
576 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));
577
578 if (FragmentTable == NULL) {
579 Status = EFI_OUT_OF_RESOURCES;
580 goto ON_EXIT;
581 }
582
583 Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);
584 OriginalFragmentTable = FragmentTable;
585 OriginalFragmentCount = FragmentCount;
586
587 if (EFI_ERROR(Status)) {
588 FreePool (FragmentTable);
589 goto ON_EXIT;
590 }
591
592 //
593 // Convert host byte order to network byte order
594 //
595 Ip6NtohHead (*Head);
596
597 Status = mIpSec->ProcessExt (
598 mIpSec,
599 IpSb->Controller,
600 IP_VERSION_6,
601 (VOID *) (*Head),
602 LastHead,
603 (VOID **) ExtHdrs,
604 ExtHdrsLen,
605 (EFI_IPSEC_FRAGMENT_DATA **) (&FragmentTable),
606 &FragmentCount,
607 Direction,
608 &RecycleEvent
609 );
610 //
611 // Convert back to host byte order
612 //
613 Ip6NtohHead (*Head);
614
615 if (EFI_ERROR (Status)) {
616 goto ON_EXIT;
617 }
618
619 if (OriginalFragmentCount == FragmentCount && OriginalFragmentTable == FragmentTable) {
620 //
621 // For ByPass Packet
622 //
623 goto ON_EXIT;
624 }
625
626 if (Direction == EfiIPsecOutBound && TxWrap != NULL) {
627 TxWrap->IpSecRecycleSignal = RecycleEvent;
628 TxWrap->Packet = NetbufFromExt (
629 FragmentTable,
630 FragmentCount,
631 IP6_MAX_HEADLEN,
632 0,
633 Ip6FreeTxToken,
634 TxWrap
635 );
636 if (TxWrap->Packet == NULL) {
637 Status = EFI_OUT_OF_RESOURCES;
638 goto ON_EXIT;
639 }
640
641 CopyMem (
642 IP6_GET_CLIP_INFO (TxWrap->Packet),
643 IP6_GET_CLIP_INFO (Packet),
644 sizeof (IP6_CLIP_INFO)
645 );
646
647 NetIpSecNetbufFree(Packet);
648 *Netbuf = TxWrap->Packet;
649
650 } else {
651
652 IpSecWrap = AllocateZeroPool (sizeof (IP6_IPSEC_WRAP));
653
654 if (IpSecWrap == NULL) {
655 goto ON_EXIT;
656 }
657
658 IpSecWrap->IpSecRecycleSignal = RecycleEvent;
659 IpSecWrap->Packet = Packet;
660 Packet = NetbufFromExt (
661 FragmentTable,
662 FragmentCount,
663 IP6_MAX_HEADLEN,
664 0,
665 Ip6IpSecFree,
666 IpSecWrap
667 );
668
669 if (Packet == NULL) {
670 Status = EFI_OUT_OF_RESOURCES;
671 goto ON_EXIT;
672 }
673
674 if (Direction == EfiIPsecInBound && 0 != CompareMem (&ZeroHead, *Head, sizeof (EFI_IP6_HEADER))) {
675
676 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (
677 Packet,
678 sizeof (EFI_IP6_HEADER) + *ExtHdrsLen,
679 NET_BUF_HEAD
680 );
681 if (PacketHead == NULL) {
682 Status = EFI_OUT_OF_RESOURCES;
683 goto ON_EXIT;
684 }
685
686 CopyMem (PacketHead, *Head, sizeof (EFI_IP6_HEADER));
687 *Head = PacketHead;
688 Packet->Ip.Ip6 = PacketHead;
689
690 if (*ExtHdrs != NULL) {
691 Buf = (UINT8 *) (PacketHead + 1);
692 CopyMem (Buf, *ExtHdrs, *ExtHdrsLen);
693 }
694
695 NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);
696 CopyMem (
697 IP6_GET_CLIP_INFO (Packet),
698 IP6_GET_CLIP_INFO (IpSecWrap->Packet),
699 sizeof (IP6_CLIP_INFO)
700 );
701 }
702 *Netbuf = Packet;
703 }
704
705 ON_EXIT:
706 return Status;
707 }
708
709 /**
710 Pre-process the IPv6 packet. First validates the IPv6 packet, and
711 then reassembles packet if it is necessary.
712
713 @param[in] IpSb The IP6 service instance.
714 @param[in, out] Packet The received IP6 packet to be processed.
715 @param[in] Flag The link layer flag for the packet received, such
716 as multicast.
717 @param[out] Payload The pointer to the payload of the recieved packet.
718 it starts from the first byte of the extension header.
719 @param[out] LastHead The pointer of NextHeader of the last extension
720 header processed by IP6.
721 @param[out] ExtHdrsLen The length of the whole option.
722 @param[out] UnFragmentLen The length of unfragmented length of extension headers.
723 @param[out] Fragmented Indicate whether the packet is fragmented.
724 @param[out] Head The pointer to the EFI_IP6_Header.
725
726 @retval EFI_SUCCESS The received packet is well format.
727 @retval EFI_INVALID_PARAMETER The received packet is malformed.
728
729 **/
730 EFI_STATUS
731 Ip6PreProcessPacket (
732 IN IP6_SERVICE *IpSb,
733 IN OUT NET_BUF **Packet,
734 IN UINT32 Flag,
735 OUT UINT8 **Payload,
736 OUT UINT8 **LastHead,
737 OUT UINT32 *ExtHdrsLen,
738 OUT UINT32 *UnFragmentLen,
739 OUT BOOLEAN *Fragmented,
740 OUT EFI_IP6_HEADER **Head
741
742
743 )
744 {
745 UINT16 PayloadLen;
746 UINT16 TotalLen;
747 UINT32 FormerHeadOffset;
748 UINT32 HeadLen;
749 IP6_FRAGMENT_HEADER *FragmentHead;
750 UINT16 FragmentOffset;
751 IP6_CLIP_INFO *Info;
752 EFI_IPv6_ADDRESS Loopback;
753
754 HeadLen = 0;
755 PayloadLen = 0;
756 //
757 // Check whether the input packet is a valid packet
758 //
759 if ((*Packet)->TotalSize < IP6_MIN_HEADLEN) {
760 return EFI_INVALID_PARAMETER;
761 }
762
763 //
764 // Get header information of the packet.
765 //
766 *Head = (EFI_IP6_HEADER *) NetbufGetByte (*Packet, 0, NULL);
767 if (*Head == NULL) {
768 return EFI_INVALID_PARAMETER;
769 }
770
771 //
772 // Multicast addresses must not be used as source addresses in IPv6 packets.
773 //
774 if (((*Head)->Version != 6) || (IP6_IS_MULTICAST (&(*Head)->SourceAddress))) {
775 return EFI_INVALID_PARAMETER;
776 }
777
778 //
779 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.
780 //
781 ZeroMem (&Loopback, sizeof (EFI_IPv6_ADDRESS));
782 Loopback.Addr[15] = 0x1;
783 if ((CompareMem (&Loopback, &(*Head)->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) ||
784 (NetIp6IsUnspecifiedAddr (&(*Head)->DestinationAddress))) {
785 return EFI_INVALID_PARAMETER;
786 }
787
788 //
789 // Convert the IP header to host byte order.
790 //
791 (*Packet)->Ip.Ip6 = Ip6NtohHead (*Head);
792
793 //
794 // Get the per packet info.
795 //
796 Info = IP6_GET_CLIP_INFO (*Packet);
797 Info->LinkFlag = Flag;
798 Info->CastType = 0;
799
800 if (IpSb->MnpConfigData.EnablePromiscuousReceive) {
801 Info->CastType = Ip6Promiscuous;
802 }
803
804 if (Ip6IsOneOfSetAddress (IpSb, &(*Head)->DestinationAddress, NULL, NULL)) {
805 Info->CastType = Ip6Unicast;
806 } else if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress)) {
807 if (Ip6FindMldEntry (IpSb, &(*Head)->DestinationAddress) != NULL) {
808 Info->CastType = Ip6Multicast;
809 }
810 }
811
812 //
813 // Drop the packet that is not delivered to us.
814 //
815 if (Info->CastType == 0) {
816 return EFI_INVALID_PARAMETER;
817 }
818
819
820 PayloadLen = (*Head)->PayloadLength;
821
822 Info->Start = 0;
823 Info->Length = PayloadLen;
824 Info->End = Info->Start + Info->Length;
825 Info->HeadLen = (UINT16) sizeof (EFI_IP6_HEADER);
826 Info->Status = EFI_SUCCESS;
827 Info->LastFrag = FALSE;
828
829 TotalLen = (UINT16) (PayloadLen + sizeof (EFI_IP6_HEADER));
830
831 //
832 // Mnp may deliver frame trailer sequence up, trim it off.
833 //
834 if (TotalLen < (*Packet)->TotalSize) {
835 NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);
836 }
837
838 if (TotalLen != (*Packet)->TotalSize) {
839 return EFI_INVALID_PARAMETER;
840 }
841
842 //
843 // Check the extension headers, if exist validate them
844 //
845 if (PayloadLen != 0) {
846 *Payload = AllocatePool ((UINTN) PayloadLen);
847 if (*Payload == NULL) {
848 return EFI_INVALID_PARAMETER;
849 }
850
851 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);
852 }
853
854 if (!Ip6IsExtsValid (
855 IpSb,
856 *Packet,
857 &(*Head)->NextHeader,
858 *Payload,
859 (UINT32) PayloadLen,
860 TRUE,
861 &FormerHeadOffset,
862 LastHead,
863 ExtHdrsLen,
864 UnFragmentLen,
865 Fragmented
866 )) {
867 return EFI_INVALID_PARAMETER;
868 }
869
870 HeadLen = sizeof (EFI_IP6_HEADER) + *UnFragmentLen;
871
872 if (*Fragmented) {
873 //
874 // Get the fragment offset from the Fragment header
875 //
876 FragmentHead = (IP6_FRAGMENT_HEADER *) NetbufGetByte (*Packet, HeadLen, NULL);
877 if (FragmentHead == NULL) {
878 return EFI_INVALID_PARAMETER;
879 }
880
881 FragmentOffset = NTOHS (FragmentHead->FragmentOffset);
882
883 if ((FragmentOffset & 0x1) == 0) {
884 Info->LastFrag = TRUE;
885 }
886
887 FragmentOffset &= (~0x1);
888
889 //
890 // This is the first fragment of the packet
891 //
892 if (FragmentOffset == 0) {
893 Info->NextHeader = FragmentHead->NextHeader;
894 }
895
896 Info->HeadLen = (UINT16) HeadLen;
897 HeadLen += sizeof (IP6_FRAGMENT_HEADER);
898 Info->Start = FragmentOffset;
899 Info->Length = TotalLen - (UINT16) HeadLen;
900 Info->End = Info->Start + Info->Length;
901 Info->Id = FragmentHead->Identification;
902 Info->FormerNextHeader = FormerHeadOffset;
903
904 //
905 // Fragments should in the unit of 8 octets long except the last one.
906 //
907 if ((Info->LastFrag == 0) && (Info->Length % 8 != 0)) {
908 return EFI_INVALID_PARAMETER;
909 }
910
911 //
912 // Reassemble the packet.
913 //
914 *Packet = Ip6Reassemble (&IpSb->Assemble, *Packet);
915 if (*Packet == NULL) {
916 return EFI_INVALID_PARAMETER;
917 }
918
919 //
920 // Re-check the assembled packet to get the right values.
921 //
922 *Head = (*Packet)->Ip.Ip6;
923 PayloadLen = (*Head)->PayloadLength;
924 if (PayloadLen != 0) {
925 if (*Payload != NULL) {
926 FreePool (*Payload);
927 }
928
929 *Payload = AllocatePool ((UINTN) PayloadLen);
930 if (*Payload == NULL) {
931 return EFI_INVALID_PARAMETER;
932 }
933
934 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);
935 }
936
937 if (!Ip6IsExtsValid (
938 IpSb,
939 *Packet,
940 &(*Head)->NextHeader,
941 *Payload,
942 (UINT32) PayloadLen,
943 TRUE,
944 NULL,
945 LastHead,
946 ExtHdrsLen,
947 UnFragmentLen,
948 Fragmented
949 )) {
950 return EFI_INVALID_PARAMETER;
951 }
952 }
953
954 //
955 // Trim the head off, after this point, the packet is headless.
956 // and Packet->TotalLen == Info->Length.
957 //
958 NetbufTrim (*Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);
959
960 return EFI_SUCCESS;
961 }
962
963 /**
964 The IP6 input routine. It is called by the IP6_INTERFACE when an
965 IP6 fragment is received from MNP.
966
967 @param[in] Packet The IP6 packet received.
968 @param[in] IoStatus The return status of receive request.
969 @param[in] Flag The link layer flag for the packet received, such
970 as multicast.
971 @param[in] Context The IP6 service instance that owns the MNP.
972
973 **/
974 VOID
975 Ip6AcceptFrame (
976 IN NET_BUF *Packet,
977 IN EFI_STATUS IoStatus,
978 IN UINT32 Flag,
979 IN VOID *Context
980 )
981 {
982 IP6_SERVICE *IpSb;
983 EFI_IP6_HEADER *Head;
984 UINT8 *Payload;
985 UINT8 *LastHead;
986 UINT32 UnFragmentLen;
987 UINT32 ExtHdrsLen;
988 BOOLEAN Fragmented;
989 EFI_STATUS Status;
990 EFI_IP6_HEADER ZeroHead;
991
992 IpSb = (IP6_SERVICE *) Context;
993 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
994
995 Payload = NULL;
996 LastHead = NULL;
997
998 //
999 // Check input parameters
1000 //
1001 if (EFI_ERROR (IoStatus) || (IpSb->State == IP6_SERVICE_DESTROY)) {
1002 goto Drop;
1003 }
1004
1005 //
1006 // Pre-Process the Ipv6 Packet and then reassemble if it is necessary.
1007 //
1008 Status = Ip6PreProcessPacket (
1009 IpSb,
1010 &Packet,
1011 Flag,
1012 &Payload,
1013 &LastHead,
1014 &ExtHdrsLen,
1015 &UnFragmentLen,
1016 &Fragmented,
1017 &Head
1018 );
1019 if (EFI_ERROR (Status)) {
1020 goto Restart;
1021 }
1022 //
1023 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,
1024 // and no need consider any other ahead ext headers.
1025 //
1026 Status = Ip6IpSecProcessPacket (
1027 IpSb,
1028 &Head,
1029 LastHead, // need get the lasthead value for input
1030 &Packet,
1031 &Payload,
1032 &ExtHdrsLen,
1033 EfiIPsecInBound,
1034 NULL
1035 );
1036
1037 if (EFI_ERROR (Status)) {
1038 goto Restart;
1039 }
1040
1041 //
1042 // If the packet is protected by IPsec Tunnel Mode, Check the Inner Ip Packet.
1043 //
1044 ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));
1045 if (0 == CompareMem (Head, &ZeroHead, sizeof (EFI_IP6_HEADER))) {
1046 Status = Ip6PreProcessPacket (
1047 IpSb,
1048 &Packet,
1049 Flag,
1050 &Payload,
1051 &LastHead,
1052 &ExtHdrsLen,
1053 &UnFragmentLen,
1054 &Fragmented,
1055 &Head
1056 );
1057 if (EFI_ERROR (Status)) {
1058 goto Restart;
1059 }
1060 }
1061
1062 //
1063 // Packet may have been changed. The ownership of the packet
1064 // is transfered to the packet process logic.
1065 //
1066 Head = Packet->Ip.Ip6;
1067 IP6_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;
1068
1069 switch (*LastHead) {
1070 case IP6_ICMP:
1071 Ip6IcmpHandle (IpSb, Head, Packet);
1072 break;
1073 default:
1074 Ip6Demultiplex (IpSb, Head, Packet);
1075 }
1076
1077 Packet = NULL;
1078
1079 //
1080 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
1081 // which are signaled with received data.
1082 //
1083 DispatchDpc ();
1084
1085 Restart:
1086 if (Payload != NULL) {
1087 FreePool (Payload);
1088 }
1089
1090 Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
1091
1092 Drop:
1093 if (Packet != NULL) {
1094 NetbufFree (Packet);
1095 }
1096
1097 return ;
1098 }
1099
1100 /**
1101 Initialize an already allocated assemble table. This is generally
1102 the assemble table embedded in the IP6 service instance.
1103
1104 @param[in, out] Table The assemble table to initialize.
1105
1106 **/
1107 VOID
1108 Ip6CreateAssembleTable (
1109 IN OUT IP6_ASSEMBLE_TABLE *Table
1110 )
1111 {
1112 UINT32 Index;
1113
1114 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1115 InitializeListHead (&Table->Bucket[Index]);
1116 }
1117 }
1118
1119 /**
1120 Clean up the assemble table by removing all of the fragments
1121 and assemble entries.
1122
1123 @param[in, out] Table The assemble table to clean up.
1124
1125 **/
1126 VOID
1127 Ip6CleanAssembleTable (
1128 IN OUT IP6_ASSEMBLE_TABLE *Table
1129 )
1130 {
1131 LIST_ENTRY *Entry;
1132 LIST_ENTRY *Next;
1133 IP6_ASSEMBLE_ENTRY *Assemble;
1134 UINT32 Index;
1135
1136 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1137 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {
1138 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
1139
1140 RemoveEntryList (Entry);
1141 Ip6FreeAssembleEntry (Assemble);
1142 }
1143 }
1144 }
1145
1146
1147 /**
1148 The signal handle of IP6's recycle event. It is called back
1149 when the upper layer releases the packet.
1150
1151 @param[in] Event The IP6's recycle event.
1152 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.
1153
1154 **/
1155 VOID
1156 EFIAPI
1157 Ip6OnRecyclePacket (
1158 IN EFI_EVENT Event,
1159 IN VOID *Context
1160 )
1161 {
1162 IP6_RXDATA_WRAP *Wrap;
1163
1164 Wrap = (IP6_RXDATA_WRAP *) Context;
1165
1166 EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);
1167 RemoveEntryList (&Wrap->Link);
1168 EfiReleaseLock (&Wrap->IpInstance->RecycleLock);
1169
1170 ASSERT (!NET_BUF_SHARED (Wrap->Packet));
1171 NetbufFree (Wrap->Packet);
1172
1173 gBS->CloseEvent (Wrap->RxData.RecycleSignal);
1174 FreePool (Wrap);
1175 }
1176
1177 /**
1178 Wrap the received packet to a IP6_RXDATA_WRAP, which will be
1179 delivered to the upper layer. Each IP6 child that accepts the
1180 packet will get a not-shared copy of the packet which is wrapped
1181 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed
1182 to the upper layer. The upper layer will signal the recycle event in
1183 it when it is done with the packet.
1184
1185 @param[in] IpInstance The IP6 child to receive the packet.
1186 @param[in] Packet The packet to deliver up.
1187
1188 @return NULL if it failed to wrap the packet; otherwise, the wrapper.
1189
1190 **/
1191 IP6_RXDATA_WRAP *
1192 Ip6WrapRxData (
1193 IN IP6_PROTOCOL *IpInstance,
1194 IN NET_BUF *Packet
1195 )
1196 {
1197 IP6_RXDATA_WRAP *Wrap;
1198 EFI_IP6_RECEIVE_DATA *RxData;
1199 EFI_STATUS Status;
1200
1201 Wrap = AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet->BlockOpNum));
1202
1203 if (Wrap == NULL) {
1204 return NULL;
1205 }
1206
1207 InitializeListHead (&Wrap->Link);
1208
1209 Wrap->IpInstance = IpInstance;
1210 Wrap->Packet = Packet;
1211 RxData = &Wrap->RxData;
1212
1213 ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));
1214
1215 Status = gBS->CreateEvent (
1216 EVT_NOTIFY_SIGNAL,
1217 TPL_NOTIFY,
1218 Ip6OnRecyclePacket,
1219 Wrap,
1220 &RxData->RecycleSignal
1221 );
1222
1223 if (EFI_ERROR (Status)) {
1224 FreePool (Wrap);
1225 return NULL;
1226 }
1227
1228 ASSERT (Packet->Ip.Ip6 != NULL);
1229
1230 //
1231 // The application expects a network byte order header.
1232 //
1233 RxData->HeaderLength = sizeof (EFI_IP6_HEADER);
1234 RxData->Header = (EFI_IP6_HEADER *) Ip6NtohHead (Packet->Ip.Ip6);
1235 RxData->DataLength = Packet->TotalSize;
1236
1237 //
1238 // Build the fragment table to be delivered up.
1239 //
1240 RxData->FragmentCount = Packet->BlockOpNum;
1241 NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);
1242
1243 return Wrap;
1244 }
1245
1246 /**
1247 Check whether this IP child accepts the packet.
1248
1249 @param[in] IpInstance The IP child to check.
1250 @param[in] Head The IP header of the packet.
1251 @param[in] Packet The data of the packet.
1252
1253 @retval TRUE The child wants to receive the packet.
1254 @retval FALSE The child does not want to receive the packet.
1255
1256 **/
1257 BOOLEAN
1258 Ip6InstanceFrameAcceptable (
1259 IN IP6_PROTOCOL *IpInstance,
1260 IN EFI_IP6_HEADER *Head,
1261 IN NET_BUF *Packet
1262 )
1263 {
1264 IP6_ICMP_ERROR_HEAD Icmp;
1265 EFI_IP6_CONFIG_DATA *Config;
1266 IP6_CLIP_INFO *Info;
1267 UINT8 *Proto;
1268 UINT32 Index;
1269 UINT8 *ExtHdrs;
1270 UINT16 ErrMsgPayloadLen;
1271 UINT8 *ErrMsgPayload;
1272
1273 Config = &IpInstance->ConfigData;
1274 Proto = NULL;
1275
1276 //
1277 // Dirty trick for the Tiano UEFI network stack implmentation. If
1278 // ReceiveTimeout == -1, the receive of the packet for this instance
1279 // is disabled. The UEFI spec don't have such captibility. We add
1280 // this to improve the performance because IP will make a copy of
1281 // the received packet for each accepting instance. Some IP instances
1282 // used by UDP/TCP only send packets, they don't wants to receive.
1283 //
1284 if (Config->ReceiveTimeout == (UINT32)(-1)) {
1285 return FALSE;
1286 }
1287
1288 if (Config->AcceptPromiscuous) {
1289 return TRUE;
1290 }
1291
1292 //
1293 // Check whether the protocol is acceptable.
1294 //
1295 ExtHdrs = NetbufGetByte (Packet, 0, NULL);
1296
1297 if (!Ip6IsExtsValid (
1298 IpInstance->Service,
1299 Packet,
1300 &Head->NextHeader,
1301 ExtHdrs,
1302 (UINT32) Head->PayloadLength,
1303 TRUE,
1304 NULL,
1305 &Proto,
1306 NULL,
1307 NULL,
1308 NULL
1309 )) {
1310 return FALSE;
1311 }
1312
1313 //
1314 // The upper layer driver may want to receive the ICMPv6 error packet
1315 // invoked by its packet, like UDP.
1316 //
1317 if ((*Proto == IP6_ICMP) && (!Config->AcceptAnyProtocol) && (*Proto != Config->DefaultProtocol)) {
1318 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
1319
1320 if (Icmp.Head.Type <= ICMP_V6_ERROR_MAX) {
1321 if (!Config->AcceptIcmpErrors) {
1322 return FALSE;
1323 }
1324
1325 //
1326 // Get the protocol of the invoking packet of ICMPv6 error packet.
1327 //
1328 ErrMsgPayloadLen = NTOHS (Icmp.IpHead.PayloadLength);
1329 ErrMsgPayload = NetbufGetByte (Packet, sizeof (Icmp), NULL);
1330
1331 if (!Ip6IsExtsValid (
1332 NULL,
1333 NULL,
1334 &Icmp.IpHead.NextHeader,
1335 ErrMsgPayload,
1336 ErrMsgPayloadLen,
1337 TRUE,
1338 NULL,
1339 &Proto,
1340 NULL,
1341 NULL,
1342 NULL
1343 )) {
1344 return FALSE;
1345 }
1346 }
1347 }
1348
1349 //
1350 // Match the protocol
1351 //
1352 if (!Config->AcceptAnyProtocol && (*Proto != Config->DefaultProtocol)) {
1353 return FALSE;
1354 }
1355
1356 //
1357 // Check for broadcast, the caller has computed the packet's
1358 // cast type for this child's interface.
1359 //
1360 Info = IP6_GET_CLIP_INFO (Packet);
1361
1362 //
1363 // If it is a multicast packet, check whether we are in the group.
1364 //
1365 if (Info->CastType == Ip6Multicast) {
1366 //
1367 // Receive the multicast if the instance wants to receive all packets.
1368 //
1369 if (NetIp6IsUnspecifiedAddr (&IpInstance->ConfigData.StationAddress)) {
1370 return TRUE;
1371 }
1372
1373 for (Index = 0; Index < IpInstance->GroupCount; Index++) {
1374 if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, &Head->DestinationAddress)) {
1375 break;
1376 }
1377 }
1378
1379 return (BOOLEAN)(Index < IpInstance->GroupCount);
1380 }
1381
1382 return TRUE;
1383 }
1384
1385 /**
1386 Enqueue a shared copy of the packet to the IP6 child if the
1387 packet is acceptable to it. Here the data of the packet is
1388 shared, but the net buffer isn't.
1389
1390 @param IpInstance The IP6 child to enqueue the packet to.
1391 @param Head The IP header of the received packet.
1392 @param Packet The data of the received packet.
1393
1394 @retval EFI_NOT_STARTED The IP child hasn't been configured.
1395 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.
1396 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources
1397 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
1398
1399 **/
1400 EFI_STATUS
1401 Ip6InstanceEnquePacket (
1402 IN IP6_PROTOCOL *IpInstance,
1403 IN EFI_IP6_HEADER *Head,
1404 IN NET_BUF *Packet
1405 )
1406 {
1407 IP6_CLIP_INFO *Info;
1408 NET_BUF *Clone;
1409
1410 //
1411 // Check whether the packet is acceptable to this instance.
1412 //
1413 if (IpInstance->State != IP6_STATE_CONFIGED) {
1414 return EFI_NOT_STARTED;
1415 }
1416
1417 if (!Ip6InstanceFrameAcceptable (IpInstance, Head, Packet)) {
1418 return EFI_INVALID_PARAMETER;
1419 }
1420
1421 //
1422 // Enque a shared copy of the packet.
1423 //
1424 Clone = NetbufClone (Packet);
1425
1426 if (Clone == NULL) {
1427 return EFI_OUT_OF_RESOURCES;
1428 }
1429
1430 //
1431 // Set the receive time out for the assembled packet. If it expires,
1432 // packet will be removed from the queue.
1433 //
1434 Info = IP6_GET_CLIP_INFO (Clone);
1435 Info->Life = IP6_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);
1436
1437 InsertTailList (&IpInstance->Received, &Clone->List);
1438 return EFI_SUCCESS;
1439 }
1440
1441 /**
1442 Deliver the received packets to the upper layer if there are both received
1443 requests and enqueued packets. If the enqueued packet is shared, it will
1444 duplicate it to a non-shared packet, release the shared packet, then
1445 deliver the non-shared packet up.
1446
1447 @param[in] IpInstance The IP child to deliver the packet up.
1448
1449 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
1450 packets.
1451 @retval EFI_SUCCESS All the enqueued packets that can be delivered
1452 are delivered up.
1453
1454 **/
1455 EFI_STATUS
1456 Ip6InstanceDeliverPacket (
1457 IN IP6_PROTOCOL *IpInstance
1458 )
1459 {
1460 EFI_IP6_COMPLETION_TOKEN *Token;
1461 IP6_RXDATA_WRAP *Wrap;
1462 NET_BUF *Packet;
1463 NET_BUF *Dup;
1464 UINT8 *Head;
1465
1466 //
1467 // Deliver a packet if there are both a packet and a receive token.
1468 //
1469 while (!IsListEmpty (&IpInstance->Received) && !NetMapIsEmpty (&IpInstance->RxTokens)) {
1470
1471 Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);
1472
1473 if (!NET_BUF_SHARED (Packet)) {
1474 //
1475 // If this is the only instance that wants the packet, wrap it up.
1476 //
1477 Wrap = Ip6WrapRxData (IpInstance, Packet);
1478
1479 if (Wrap == NULL) {
1480 return EFI_OUT_OF_RESOURCES;
1481 }
1482
1483 RemoveEntryList (&Packet->List);
1484
1485 } else {
1486 //
1487 // Create a duplicated packet if this packet is shared
1488 //
1489 Dup = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));
1490
1491 if (Dup == NULL) {
1492 return EFI_OUT_OF_RESOURCES;
1493 }
1494
1495 //
1496 // Copy the IP head over. The packet to deliver up is
1497 // headless. Trim the head off after copy. The IP head
1498 // may be not continuous before the data.
1499 //
1500 Head = NetbufAllocSpace (Dup, sizeof (EFI_IP6_HEADER), NET_BUF_HEAD);
1501 ASSERT (Head != NULL);
1502 Dup->Ip.Ip6 = (EFI_IP6_HEADER *) Head;
1503
1504 CopyMem (Head, Packet->Ip.Ip6, sizeof (EFI_IP6_HEADER));
1505 NetbufTrim (Dup, sizeof (EFI_IP6_HEADER), TRUE);
1506
1507 Wrap = Ip6WrapRxData (IpInstance, Dup);
1508
1509 if (Wrap == NULL) {
1510 NetbufFree (Dup);
1511 return EFI_OUT_OF_RESOURCES;
1512 }
1513
1514 RemoveEntryList (&Packet->List);
1515 NetbufFree (Packet);
1516
1517 Packet = Dup;
1518 }
1519
1520 //
1521 // Insert it into the delivered packet, then get a user's
1522 // receive token, pass the wrapped packet up.
1523 //
1524 EfiAcquireLockOrFail (&IpInstance->RecycleLock);
1525 InsertHeadList (&IpInstance->Delivered, &Wrap->Link);
1526 EfiReleaseLock (&IpInstance->RecycleLock);
1527
1528 Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);
1529 Token->Status = IP6_GET_CLIP_INFO (Packet)->Status;
1530 Token->Packet.RxData = &Wrap->RxData;
1531
1532 gBS->SignalEvent (Token->Event);
1533 }
1534
1535 return EFI_SUCCESS;
1536 }
1537
1538 /**
1539 Enqueue a received packet to all the IP children that share
1540 the same interface.
1541
1542 @param[in] IpSb The IP6 service instance that receive the packet.
1543 @param[in] Head The header of the received packet.
1544 @param[in] Packet The data of the received packet.
1545 @param[in] IpIf The interface to enqueue the packet to.
1546
1547 @return The number of the IP6 children that accepts the packet.
1548
1549 **/
1550 INTN
1551 Ip6InterfaceEnquePacket (
1552 IN IP6_SERVICE *IpSb,
1553 IN EFI_IP6_HEADER *Head,
1554 IN NET_BUF *Packet,
1555 IN IP6_INTERFACE *IpIf
1556 )
1557 {
1558 IP6_PROTOCOL *IpInstance;
1559 IP6_CLIP_INFO *Info;
1560 LIST_ENTRY *Entry;
1561 INTN Enqueued;
1562 INTN LocalType;
1563 INTN SavedType;
1564
1565 //
1566 // First, check that the packet is acceptable to this interface
1567 // and find the local cast type for the interface.
1568 //
1569 LocalType = 0;
1570 Info = IP6_GET_CLIP_INFO (Packet);
1571
1572 if (IpIf->PromiscRecv) {
1573 LocalType = Ip6Promiscuous;
1574 } else {
1575 LocalType = Info->CastType;
1576 }
1577
1578 //
1579 // Iterate through the ip instances on the interface, enqueue
1580 // the packet if filter passed. Save the original cast type,
1581 // and pass the local cast type to the IP children on the
1582 // interface. The global cast type will be restored later.
1583 //
1584 SavedType = Info->CastType;
1585 Info->CastType = (UINT32) LocalType;
1586
1587 Enqueued = 0;
1588
1589 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
1590 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
1591 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
1592
1593 if (Ip6InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {
1594 Enqueued++;
1595 }
1596 }
1597
1598 Info->CastType = (UINT32) SavedType;
1599 return Enqueued;
1600 }
1601
1602 /**
1603 Deliver the packet for each IP6 child on the interface.
1604
1605 @param[in] IpSb The IP6 service instance that received the packet.
1606 @param[in] IpIf The IP6 interface to deliver the packet.
1607
1608 **/
1609 VOID
1610 Ip6InterfaceDeliverPacket (
1611 IN IP6_SERVICE *IpSb,
1612 IN IP6_INTERFACE *IpIf
1613 )
1614 {
1615 IP6_PROTOCOL *IpInstance;
1616 LIST_ENTRY *Entry;
1617
1618 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
1619 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
1620 Ip6InstanceDeliverPacket (IpInstance);
1621 }
1622 }
1623
1624 /**
1625 De-multiplex the packet. the packet delivery is processed in two
1626 passes. The first pass will enqueue a shared copy of the packet
1627 to each IP6 child that accepts the packet. The second pass will
1628 deliver a non-shared copy of the packet to each IP6 child that
1629 has pending receive requests. Data is copied if more than one
1630 child wants to consume the packet, because each IP child needs
1631 its own copy of the packet to make changes.
1632
1633 @param[in] IpSb The IP6 service instance that received the packet.
1634 @param[in] Head The header of the received packet.
1635 @param[in] Packet The data of the received packet.
1636
1637 @retval EFI_NOT_FOUND No IP child accepts the packet.
1638 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP
1639 children.
1640
1641 **/
1642 EFI_STATUS
1643 Ip6Demultiplex (
1644 IN IP6_SERVICE *IpSb,
1645 IN EFI_IP6_HEADER *Head,
1646 IN NET_BUF *Packet
1647 )
1648 {
1649
1650 LIST_ENTRY *Entry;
1651 IP6_INTERFACE *IpIf;
1652 INTN Enqueued;
1653
1654 //
1655 // Two pass delivery: first, enque a shared copy of the packet
1656 // to each instance that accept the packet.
1657 //
1658 Enqueued = 0;
1659
1660 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1661 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
1662
1663 if (IpIf->Configured) {
1664 Enqueued += Ip6InterfaceEnquePacket (IpSb, Head, Packet, IpIf);
1665 }
1666 }
1667
1668 //
1669 // Second: deliver a duplicate of the packet to each instance.
1670 // Release the local reference first, so that the last instance
1671 // getting the packet will not copy the data.
1672 //
1673 NetbufFree (Packet);
1674 Packet = NULL;
1675
1676 if (Enqueued == 0) {
1677 return EFI_NOT_FOUND;
1678 }
1679
1680 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1681 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
1682
1683 if (IpIf->Configured) {
1684 Ip6InterfaceDeliverPacket (IpSb, IpIf);
1685 }
1686 }
1687
1688 return EFI_SUCCESS;
1689 }
1690
1691 /**
1692 Decrease the life of the transmitted packets. If it is
1693 decreased to zero, cancel the packet. This function is
1694 called by Ip6packetTimerTicking that provides timeout for both the
1695 received-but-not-delivered and transmitted-but-not-recycle
1696 packets.
1697
1698 @param[in] Map The IP6 child's transmit map.
1699 @param[in] Item Current transmitted packet.
1700 @param[in] Context Not used.
1701
1702 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
1703
1704 **/
1705 EFI_STATUS
1706 EFIAPI
1707 Ip6SentPacketTicking (
1708 IN NET_MAP *Map,
1709 IN NET_MAP_ITEM *Item,
1710 IN VOID *Context
1711 )
1712 {
1713 IP6_TXTOKEN_WRAP *Wrap;
1714
1715 Wrap = (IP6_TXTOKEN_WRAP *) Item->Value;
1716 ASSERT (Wrap != NULL);
1717
1718 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
1719 Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
1720 }
1721
1722 return EFI_SUCCESS;
1723 }
1724
1725 /**
1726 Timeout the fragments, and the enqueued, and transmitted packets.
1727
1728 @param[in] IpSb The IP6 service instance to timeout.
1729
1730 **/
1731 VOID
1732 Ip6PacketTimerTicking (
1733 IN IP6_SERVICE *IpSb
1734 )
1735 {
1736 LIST_ENTRY *InstanceEntry;
1737 LIST_ENTRY *Entry;
1738 LIST_ENTRY *Next;
1739 IP6_PROTOCOL *IpInstance;
1740 IP6_ASSEMBLE_ENTRY *Assemble;
1741 NET_BUF *Packet;
1742 IP6_CLIP_INFO *Info;
1743 UINT32 Index;
1744
1745 //
1746 // First, time out the fragments. The packet's life is counting down
1747 // once the first-arriving fragment of that packet was received.
1748 //
1749 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
1750 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(IpSb->Assemble.Bucket[Index])) {
1751 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
1752
1753 if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {
1754 //
1755 // If the first fragment (the one with a Fragment Offset of zero)
1756 // has been received, an ICMP Time Exceeded - Fragment Reassembly
1757 // Time Exceeded message should be sent to the source of that fragment.
1758 //
1759 if ((Assemble->Packet != NULL) &&
1760 !IP6_IS_MULTICAST (&Assemble->Head->DestinationAddress)) {
1761 Ip6SendIcmpError (
1762 IpSb,
1763 Assemble->Packet,
1764 NULL,
1765 &Assemble->Head->SourceAddress,
1766 ICMP_V6_TIME_EXCEEDED,
1767 ICMP_V6_TIMEOUT_REASSEMBLE,
1768 NULL
1769 );
1770 }
1771
1772 //
1773 // If reassembly of a packet is not completed within 60 seconds of
1774 // the reception of the first-arriving fragment of that packet, the
1775 // reassembly must be abandoned and all the fragments that have been
1776 // received for that packet must be discarded.
1777 //
1778 RemoveEntryList (Entry);
1779 Ip6FreeAssembleEntry (Assemble);
1780 }
1781 }
1782 }
1783
1784 NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {
1785 IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP6_PROTOCOL, Link);
1786
1787 //
1788 // Second, time out the assembled packets enqueued on each IP child.
1789 //
1790 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {
1791 Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1792 Info = IP6_GET_CLIP_INFO (Packet);
1793
1794 if ((Info->Life > 0) && (--Info->Life == 0)) {
1795 RemoveEntryList (Entry);
1796 NetbufFree (Packet);
1797 }
1798 }
1799
1800 //
1801 // Third: time out the transmitted packets.
1802 //
1803 NetMapIterate (&IpInstance->TxTokens, Ip6SentPacketTicking, NULL);
1804 }
1805 }
1806