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