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