Home | History | Annotate | Download | only in IpSecDxe
      1 /** @file
      2   The implementation of IPsec.
      3 
      4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<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 "IpSecImpl.h"
     18 #include "IkeService.h"
     19 #include "IpSecDebug.h"
     20 #include "IpSecCryptIo.h"
     21 #include "IpSecConfigImpl.h"
     22 
     23 /**
     24   Check if the specified Address is the Valid Address Range.
     25 
     26   This function checks if the bytes after prefixed length are all Zero in this
     27   Address. This Address is supposed to point to a range address. That means it
     28   should gives the correct prefixed address and the bytes outside the prefixed are
     29   zero.
     30 
     31   @param[in]  IpVersion         The IP version.
     32   @param[in]  Address           Points to EFI_IP_ADDRESS to be checked.
     33   @param[in]  PrefixLength      The PrefixeLength of this address.
     34 
     35   @retval     TRUE      The address is a vaild address range.
     36   @retval     FALSE     The address is not a vaild address range.
     37 
     38 **/
     39 BOOLEAN
     40 IpSecValidAddressRange (
     41   IN UINT8                     IpVersion,
     42   IN EFI_IP_ADDRESS            *Address,
     43   IN UINT8                     PrefixLength
     44   )
     45 {
     46   UINT8           Div;
     47   UINT8           Mod;
     48   UINT8           Mask;
     49   UINT8           AddrLen;
     50   UINT8           *Addr;
     51   EFI_IP_ADDRESS  ZeroAddr;
     52 
     53   if (PrefixLength == 0) {
     54     return TRUE;
     55   }
     56 
     57   AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);
     58 
     59   if (AddrLen <= PrefixLength) {
     60     return FALSE;
     61   }
     62 
     63   Div   = (UINT8) (PrefixLength / 8);
     64   Mod   = (UINT8) (PrefixLength % 8);
     65   Addr  = (UINT8 *) Address;
     66   ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));
     67 
     68   //
     69   // Check whether the mod part of host scope is zero or not.
     70   //
     71   if (Mod > 0) {
     72     Mask = (UINT8) (0xFF << (8 - Mod));
     73 
     74     if ((Addr[Div] | Mask) != Mask) {
     75       return FALSE;
     76     }
     77 
     78     Div++;
     79   }
     80   //
     81   // Check whether the div part of host scope is zero or not.
     82   //
     83   if (CompareMem (
     84         &Addr[Div],
     85         &ZeroAddr,
     86         sizeof (EFI_IP_ADDRESS) - Div
     87         ) != 0) {
     88     return FALSE;
     89   }
     90 
     91   return TRUE;
     92 }
     93 
     94 /**
     95   Extrct the Address Range from a Address.
     96 
     97   This function keep the prefix address and zero other part address.
     98 
     99   @param[in]  Address           Point to a specified address.
    100   @param[in]  PrefixLength      The prefix length.
    101   @param[out] Range             Contain the return Address Range.
    102 
    103 **/
    104 VOID
    105 IpSecExtractAddressRange (
    106   IN EFI_IP_ADDRESS            *Address,
    107   IN UINT8                     PrefixLength,
    108   OUT EFI_IP_ADDRESS           *Range
    109   )
    110 {
    111   UINT8 Div;
    112   UINT8 Mod;
    113   UINT8 Mask;
    114   UINT8 *Addr;
    115 
    116   if (PrefixLength == 0) {
    117     return ;
    118   }
    119 
    120   Div   = (UINT8) (PrefixLength / 8);
    121   Mod   = (UINT8) (PrefixLength % 8);
    122   Addr  = (UINT8 *) Range;
    123 
    124   CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));
    125 
    126   //
    127   // Zero the mod part of host scope.
    128   //
    129   if (Mod > 0) {
    130     Mask      = (UINT8) (0xFF << (8 - Mod));
    131     Addr[Div] = (UINT8) (Addr[Div] & Mask);
    132     Div++;
    133   }
    134   //
    135   // Zero the div part of host scope.
    136   //
    137   ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);
    138 
    139 }
    140 
    141 /**
    142   Checks if the IP Address in the address range of AddressInfos specified.
    143 
    144   @param[in]  IpVersion         The IP version.
    145   @param[in]  IpAddr            Point to EFI_IP_ADDRESS to be check.
    146   @param[in]  AddressInfo       A list of EFI_IP_ADDRESS_INFO that is used to check
    147                                 the IP Address is matched.
    148   @param[in]  AddressCount      The total numbers of the AddressInfo.
    149 
    150   @retval   TRUE    If the Specified IP Address is in the range of the AddressInfos specified.
    151   @retval   FALSE   If the Specified IP Address is not in the range of the AddressInfos specified.
    152 
    153 **/
    154 BOOLEAN
    155 IpSecMatchIpAddress (
    156   IN UINT8                     IpVersion,
    157   IN EFI_IP_ADDRESS            *IpAddr,
    158   IN EFI_IP_ADDRESS_INFO       *AddressInfo,
    159   IN UINT32                    AddressCount
    160   )
    161 {
    162   EFI_IP_ADDRESS  Range;
    163   UINT32          Index;
    164   BOOLEAN         IsMatch;
    165 
    166   IsMatch = FALSE;
    167 
    168   for (Index = 0; Index < AddressCount; Index++) {
    169     //
    170     // Check whether the target address is in the address range
    171     // if it's a valid range of address.
    172     //
    173     if (IpSecValidAddressRange (
    174           IpVersion,
    175           &AddressInfo[Index].Address,
    176           AddressInfo[Index].PrefixLength
    177           )) {
    178       //
    179       // Get the range of the target address belongs to.
    180       //
    181       ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));
    182       IpSecExtractAddressRange (
    183         IpAddr,
    184         AddressInfo[Index].PrefixLength,
    185         &Range
    186         );
    187 
    188       if (CompareMem (
    189             &Range,
    190             &AddressInfo[Index].Address,
    191             sizeof (EFI_IP_ADDRESS)
    192             ) == 0) {
    193         //
    194         // The target address is in the address range.
    195         //
    196         IsMatch = TRUE;
    197         break;
    198       }
    199     }
    200 
    201     if (CompareMem (
    202           IpAddr,
    203           &AddressInfo[Index].Address,
    204           sizeof (EFI_IP_ADDRESS)
    205           ) == 0) {
    206       //
    207       // The target address is exact same as the address.
    208       //
    209       IsMatch = TRUE;
    210       break;
    211     }
    212   }
    213   return IsMatch;
    214 }
    215 
    216 /**
    217   Check if the specified Protocol and Prot is supported by the specified SPD Entry.
    218 
    219   This function is the subfunction of IPsecLookUpSpdEntry() that is used to
    220   check if the sent/received IKE packet has the related SPD entry support.
    221 
    222   @param[in]  Protocol          The Protocol to be checked.
    223   @param[in]  IpPayload         Point to IP Payload to be check.
    224   @param[in]  SpdProtocol       The Protocol supported by SPD.
    225   @param[in]  SpdLocalPort      The Local Port in SPD.
    226   @param[in]  SpdRemotePort     The Remote Port in SPD.
    227   @param[in]  IsOutbound        Flag to indicate the is for IKE Packet sending or recieving.
    228 
    229   @retval     TRUE      The Protocol and Port are supported by the SPD Entry.
    230   @retval     FALSE     The Protocol and Port are not supported by the SPD Entry.
    231 
    232 **/
    233 BOOLEAN
    234 IpSecMatchNextLayerProtocol (
    235   IN UINT8                     Protocol,
    236   IN UINT8                     *IpPayload,
    237   IN UINT16                    SpdProtocol,
    238   IN UINT16                    SpdLocalPort,
    239   IN UINT16                    SpdRemotePort,
    240   IN BOOLEAN                   IsOutbound
    241   )
    242 {
    243   BOOLEAN IsMatch;
    244 
    245   if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) {
    246     return TRUE;
    247   }
    248 
    249   IsMatch = FALSE;
    250 
    251   if (SpdProtocol == Protocol) {
    252     switch (Protocol) {
    253     case EFI_IP_PROTO_UDP:
    254     case EFI_IP_PROTO_TCP:
    255       //
    256       // For udp and tcp, (0, 0) means no need to check local and remote
    257       // port. The payload is passed from upper level, which means it should
    258       // be in network order.
    259       //
    260       IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
    261       IsMatch = (BOOLEAN) (IsMatch ||
    262                            (IsOutbound &&
    263                            (BOOLEAN)(
    264                               NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort &&
    265                               NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort
    266                               )
    267                             ));
    268 
    269       IsMatch = (BOOLEAN) (IsMatch ||
    270                            (!IsOutbound &&
    271                            (BOOLEAN)(
    272                               NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort &&
    273                               NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort
    274                               )
    275                            ));
    276       break;
    277 
    278     case EFI_IP_PROTO_ICMP:
    279       //
    280       // For icmpv4, type code is replaced with local port and remote port,
    281       // and (0, 0) means no need to check.
    282       //
    283       IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
    284       IsMatch = (BOOLEAN) (IsMatch ||
    285                            (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
    286                                       ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
    287                                       )
    288                            );
    289       break;
    290 
    291     case IP6_ICMP:
    292       //
    293       // For icmpv6, type code is replaced with local port and remote port,
    294       // and (0, 0) means no need to check.
    295       //
    296       IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
    297 
    298       IsMatch = (BOOLEAN) (IsMatch ||
    299                            (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
    300                                       ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
    301                                       )
    302                           );
    303       break;
    304 
    305     default:
    306       IsMatch = TRUE;
    307       break;
    308     }
    309   }
    310 
    311   return IsMatch;
    312 }
    313 
    314 /**
    315   Find the SAD through a specified SPD's SAD list.
    316 
    317   @param[in]  SadList           SAD list related to a specified SPD entry.
    318   @param[in]  DestAddress       The destination address used to find the SAD entry.
    319   @param[in]  IpVersion         The IP version. Ip4 or Ip6.
    320 
    321   @return  The pointer to a certain SAD entry.
    322 
    323 **/
    324 IPSEC_SAD_ENTRY *
    325 IpSecLookupSadBySpd (
    326   IN LIST_ENTRY                 *SadList,
    327   IN EFI_IP_ADDRESS             *DestAddress,
    328   IN UINT8                      IpVersion
    329   )
    330 {
    331   LIST_ENTRY      *Entry;
    332   IPSEC_SAD_ENTRY *SadEntry;
    333 
    334   NET_LIST_FOR_EACH (Entry, SadList) {
    335 
    336     SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
    337     //
    338     // Find the right SAD entry which contains the appointed dest address.
    339     //
    340     if (IpSecMatchIpAddress (
    341           IpVersion,
    342           DestAddress,
    343           SadEntry->Data->SpdSelector->RemoteAddress,
    344           SadEntry->Data->SpdSelector->RemoteAddressCount
    345           )){
    346       return SadEntry;
    347     }
    348   }
    349 
    350   return NULL;
    351 }
    352 
    353 /**
    354   Find the SAD through whole SAD list.
    355 
    356   @param[in]  Spi               The SPI used to search the SAD entry.
    357   @param[in]  DestAddress       The destination used to search the SAD entry.
    358   @param[in]  IpVersion         The IP version. Ip4 or Ip6.
    359 
    360   @return  the pointer to a certain SAD entry.
    361 
    362 **/
    363 IPSEC_SAD_ENTRY *
    364 IpSecLookupSadBySpi (
    365   IN UINT32                   Spi,
    366   IN EFI_IP_ADDRESS           *DestAddress,
    367   IN UINT8                    IpVersion
    368   )
    369 {
    370   LIST_ENTRY      *Entry;
    371   LIST_ENTRY      *SadList;
    372   IPSEC_SAD_ENTRY *SadEntry;
    373 
    374   SadList = &mConfigData[IPsecConfigDataTypeSad];
    375 
    376   NET_LIST_FOR_EACH (Entry, SadList) {
    377 
    378     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
    379 
    380     //
    381     // Find the right SAD entry which contain the appointed spi and dest addr.
    382     //
    383     if (SadEntry->Id->Spi == Spi) {
    384       if (SadEntry->Data->Mode == EfiIPsecTunnel) {
    385         if (CompareMem (
    386               &DestAddress,
    387               &SadEntry->Data->TunnelDestAddress,
    388               sizeof (EFI_IP_ADDRESS)
    389               )) {
    390           return SadEntry;
    391         }
    392       } else {
    393         if (SadEntry->Data->SpdSelector != NULL &&
    394             IpSecMatchIpAddress (
    395               IpVersion,
    396               DestAddress,
    397               SadEntry->Data->SpdSelector->RemoteAddress,
    398               SadEntry->Data->SpdSelector->RemoteAddressCount
    399               )
    400             ) {
    401           return SadEntry;
    402         }
    403       }
    404     }
    405   }
    406   return NULL;
    407 }
    408 
    409 /**
    410   Look up if there is existing SAD entry for specified IP packet sending.
    411 
    412   This function is called by the IPsecProcess when there is some IP packet needed to
    413   send out. This function checks if there is an existing SAD entry that can be serviced
    414   to this IP packet sending. If no existing SAD entry could be used, this
    415   function will invoke an IPsec Key Exchange Negotiation.
    416 
    417   @param[in]  Private           Points to private data.
    418   @param[in]  NicHandle         Points to a NIC handle.
    419   @param[in]  IpVersion         The version of IP.
    420   @param[in]  IpHead            The IP Header of packet to be sent out.
    421   @param[in]  IpPayload         The IP Payload to be sent out.
    422   @param[in]  OldLastHead       The Last protocol of the IP packet.
    423   @param[in]  SpdEntry          Points to a related SPD entry.
    424   @param[out] SadEntry          Contains the Point of a related SAD entry.
    425 
    426   @retval EFI_DEVICE_ERROR  One of following conditions is TRUE:
    427                             - If don't find related UDP service.
    428                             - Sequence Number is used up.
    429                             - Extension Sequence Number is used up.
    430   @retval EFI_NOT_READY     No existing SAD entry could be used.
    431   @retval EFI_SUCCESS       Find the related SAD entry.
    432 
    433 **/
    434 EFI_STATUS
    435 IpSecLookupSadEntry (
    436   IN IPSEC_PRIVATE_DATA      *Private,
    437   IN EFI_HANDLE              NicHandle,
    438   IN UINT8                   IpVersion,
    439   IN VOID                    *IpHead,
    440   IN UINT8                   *IpPayload,
    441   IN UINT8                   OldLastHead,
    442   IN IPSEC_SPD_ENTRY         *SpdEntry,
    443   OUT IPSEC_SAD_ENTRY        **SadEntry
    444   )
    445 {
    446   IKE_UDP_SERVICE *UdpService;
    447   IPSEC_SAD_ENTRY *Entry;
    448   IPSEC_SAD_DATA  *Data;
    449   EFI_IP_ADDRESS  DestIp;
    450   UINT32          SeqNum32;
    451 
    452   *SadEntry   = NULL;
    453   UdpService  = IkeLookupUdp (Private, NicHandle, IpVersion);
    454 
    455   if (UdpService == NULL) {
    456     return EFI_DEVICE_ERROR;
    457   }
    458   //
    459   // Parse the destination address from ip header.
    460   //
    461   ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
    462   if (IpVersion == IP_VERSION_4) {
    463     CopyMem (
    464       &DestIp,
    465       &((IP4_HEAD *) IpHead)->Dst,
    466       sizeof (IP4_ADDR)
    467       );
    468   } else {
    469     CopyMem (
    470       &DestIp,
    471       &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
    472       sizeof (EFI_IP_ADDRESS)
    473       );
    474   }
    475 
    476   //
    477   // Find the SAD entry in the spd.sas list according to the dest address.
    478   //
    479   Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);
    480 
    481   if (Entry == NULL) {
    482     if (OldLastHead != IP6_ICMP ||
    483         (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)
    484         ) {
    485       //
    486       // Start ike negotiation process except the request packet of ping.
    487       //
    488       if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
    489         IkeNegotiate (
    490           UdpService,
    491           SpdEntry,
    492           &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress
    493           );
    494       } else {
    495         IkeNegotiate (
    496           UdpService,
    497           SpdEntry,
    498           &DestIp
    499         );
    500       }
    501 
    502     }
    503 
    504     return EFI_NOT_READY;
    505   }
    506 
    507   Data = Entry->Data;
    508 
    509   if (!Data->ManualSet) {
    510     if (Data->ESNEnabled) {
    511       //
    512       // Validate the 64bit sn number if 64bit sn enabled.
    513       //
    514       if ((UINT64) (Data->SequenceNumber + 1) == 0) {
    515         //
    516         // TODO: Re-negotiate SA
    517         //
    518         return EFI_DEVICE_ERROR;
    519       }
    520     } else {
    521       //
    522       // Validate the 32bit sn number if 64bit sn disabled.
    523       //
    524       SeqNum32 = (UINT32) Data->SequenceNumber;
    525       if ((UINT32) (SeqNum32 + 1) == 0) {
    526         //
    527         // TODO: Re-negotiate SA
    528         //
    529         return EFI_DEVICE_ERROR;
    530       }
    531     }
    532   }
    533 
    534   *SadEntry = Entry;
    535 
    536   return EFI_SUCCESS;
    537 }
    538 
    539 /**
    540   Find a PAD entry according to a remote IP address.
    541 
    542   @param[in]  IpVersion         The version of IP.
    543   @param[in]  IpAddr            Points to remote IP address.
    544 
    545   @return the pointer of related PAD entry.
    546 
    547 **/
    548 IPSEC_PAD_ENTRY *
    549 IpSecLookupPadEntry (
    550   IN UINT8                   IpVersion,
    551   IN EFI_IP_ADDRESS          *IpAddr
    552   )
    553 {
    554   LIST_ENTRY          *PadList;
    555   LIST_ENTRY          *Entry;
    556   EFI_IP_ADDRESS_INFO *IpAddrInfo;
    557   IPSEC_PAD_ENTRY     *PadEntry;
    558 
    559   PadList = &mConfigData[IPsecConfigDataTypePad];
    560 
    561   for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {
    562 
    563     PadEntry    = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
    564     IpAddrInfo  = &PadEntry->Id->Id.IpAddress;
    565     //
    566     // Find the right pad entry which contain the appointed dest addr.
    567     //
    568     if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {
    569       return PadEntry;
    570     }
    571   }
    572 
    573   return NULL;
    574 }
    575 
    576 /**
    577   Check if the specified IP packet can be serviced by this SPD entry.
    578 
    579   @param[in]  SpdEntry          Point to SPD entry.
    580   @param[in]  IpVersion         Version of IP.
    581   @param[in]  IpHead            Point to IP header.
    582   @param[in]  IpPayload         Point to IP payload.
    583   @param[in]  Protocol          The Last protocol of IP packet.
    584   @param[in]  IsOutbound        Traffic direction.
    585   @param[out] Action            The support action of SPD entry.
    586 
    587   @retval EFI_SUCCESS       Find the related SPD.
    588   @retval EFI_NOT_FOUND     Not find the related SPD entry;
    589 
    590 **/
    591 EFI_STATUS
    592 IpSecLookupSpdEntry (
    593   IN     IPSEC_SPD_ENTRY         *SpdEntry,
    594   IN     UINT8                   IpVersion,
    595   IN     VOID                    *IpHead,
    596   IN     UINT8                   *IpPayload,
    597   IN     UINT8                   Protocol,
    598   IN     BOOLEAN                 IsOutbound,
    599      OUT EFI_IPSEC_ACTION        *Action
    600   )
    601 {
    602   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
    603   IP4_HEAD                *Ip4;
    604   EFI_IP6_HEADER          *Ip6;
    605   EFI_IP_ADDRESS          SrcAddr;
    606   EFI_IP_ADDRESS          DstAddr;
    607   BOOLEAN                 SpdMatch;
    608 
    609   ASSERT (SpdEntry != NULL);
    610   SpdSel  = SpdEntry->Selector;
    611   Ip4     = (IP4_HEAD *) IpHead;
    612   Ip6     = (EFI_IP6_HEADER *) IpHead;
    613 
    614   ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));
    615   ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));
    616 
    617   //
    618   // Parse the source and destination address from ip header.
    619   //
    620   if (IpVersion == IP_VERSION_4) {
    621     CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));
    622     CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));
    623   } else {
    624     CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));
    625     CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
    626   }
    627   //
    628   // Check the local and remote addresses for outbound traffic
    629   //
    630   SpdMatch = (BOOLEAN)(IsOutbound &&
    631                        IpSecMatchIpAddress (
    632                          IpVersion,
    633                          &SrcAddr,
    634                          SpdSel->LocalAddress,
    635                          SpdSel->LocalAddressCount
    636                          ) &&
    637                        IpSecMatchIpAddress (
    638                          IpVersion,
    639                          &DstAddr,
    640                          SpdSel->RemoteAddress,
    641                          SpdSel->RemoteAddressCount
    642                          )
    643                        );
    644 
    645   //
    646   // Check the local and remote addresses for inbound traffic
    647   //
    648   SpdMatch = (BOOLEAN) (SpdMatch ||
    649                         (!IsOutbound &&
    650                         IpSecMatchIpAddress (
    651                           IpVersion,
    652                           &DstAddr,
    653                           SpdSel->LocalAddress,
    654                           SpdSel->LocalAddressCount
    655                           ) &&
    656                         IpSecMatchIpAddress (
    657                           IpVersion,
    658                           &SrcAddr,
    659                           SpdSel->RemoteAddress,
    660                           SpdSel->RemoteAddressCount
    661                           )
    662                         ));
    663 
    664   //
    665   // Check the next layer protocol and local and remote ports.
    666   //
    667   SpdMatch = (BOOLEAN) (SpdMatch &&
    668                         IpSecMatchNextLayerProtocol (
    669                           Protocol,
    670                           IpPayload,
    671                           SpdSel->NextLayerProtocol,
    672                           SpdSel->LocalPort,
    673                           SpdSel->RemotePort,
    674                           IsOutbound
    675                           )
    676                         );
    677 
    678   if (SpdMatch) {
    679     //
    680     // Find the right SPD entry if match the 5 key elements.
    681     //
    682     *Action = SpdEntry->Data->Action;
    683     return EFI_SUCCESS;
    684   }
    685 
    686   return EFI_NOT_FOUND;
    687 }
    688 
    689 /**
    690   The call back function of NetbufFromExt.
    691 
    692   @param[in]  Arg            The argument passed from the caller.
    693 
    694 **/
    695 VOID
    696 EFIAPI
    697 IpSecOnRecyclePacket (
    698   IN VOID                            *Arg
    699   )
    700 {
    701 }
    702 
    703 /**
    704   This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP
    705   is released.
    706 
    707   @param[in]  Event              The related event.
    708   @param[in]  Context            The data passed by the caller.
    709 
    710 **/
    711 VOID
    712 EFIAPI
    713 IpSecRecycleCallback (
    714   IN EFI_EVENT                       Event,
    715   IN VOID                            *Context
    716   )
    717 {
    718   IPSEC_RECYCLE_CONTEXT *RecycleContext;
    719 
    720   RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;
    721 
    722   if (RecycleContext->FragmentTable != NULL) {
    723     FreePool (RecycleContext->FragmentTable);
    724   }
    725 
    726   if (RecycleContext->PayloadBuffer != NULL) {
    727     FreePool (RecycleContext->PayloadBuffer);
    728   }
    729 
    730   FreePool (RecycleContext);
    731   gBS->CloseEvent (Event);
    732 
    733 }
    734 
    735 /**
    736   Calculate the extension hader of IP. The return length only doesn't contain
    737   the fixed IP header length.
    738 
    739   @param[in]  IpHead             Points to an IP head to be calculated.
    740   @param[in]  LastHead           Points to the last header of the IP header.
    741 
    742   @return The length of the extension header.
    743 
    744 **/
    745 UINT16
    746 IpSecGetPlainExtHeadSize (
    747   IN VOID                             *IpHead,
    748   IN UINT8                            *LastHead
    749   )
    750 {
    751   UINT16  Size;
    752 
    753   Size = (UINT16) (LastHead - (UINT8 *) IpHead);
    754 
    755   if (Size > sizeof (EFI_IP6_HEADER)) {
    756     //
    757     // * (LastHead+1) point the last header's length but not include the first
    758     // 8 octers, so this formluation add 8 at the end.
    759     //
    760     Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);
    761   } else {
    762     Size = 0;
    763   }
    764 
    765   return Size;
    766 }
    767 
    768 /**
    769   Verify if the Authentication payload is correct.
    770 
    771   @param[in]  EspBuffer          Points to the ESP wrapped buffer.
    772   @param[in]  EspSize            The size of the ESP wrapped buffer.
    773   @param[in]  SadEntry           The related SAD entry to store the authentication
    774                                  algorithm key.
    775   @param[in]  IcvSize            The length of ICV.
    776 
    777   @retval EFI_SUCCESS        The authentication data is correct.
    778   @retval EFI_ACCESS_DENIED  The authentication data is not correct.
    779 
    780 **/
    781 EFI_STATUS
    782 IpSecEspAuthVerifyPayload (
    783   IN UINT8                           *EspBuffer,
    784   IN UINTN                           EspSize,
    785   IN IPSEC_SAD_ENTRY                 *SadEntry,
    786   IN UINTN                           IcvSize
    787   )
    788 {
    789   EFI_STATUS           Status;
    790   UINTN                AuthSize;
    791   UINT8                IcvBuffer[12];
    792   HASH_DATA_FRAGMENT   HashFragment[1];
    793 
    794   //
    795   // Calculate the size of authentication payload.
    796   //
    797   AuthSize  = EspSize - IcvSize;
    798 
    799   //
    800   // Calculate the icv buffer and size of the payload.
    801   //
    802   HashFragment[0].Data     = EspBuffer;
    803   HashFragment[0].DataSize = AuthSize;
    804 
    805   Status = IpSecCryptoIoHmac (
    806              SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
    807              SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
    808              SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
    809              HashFragment,
    810              1,
    811              IcvBuffer,
    812              IcvSize
    813              );
    814   if (EFI_ERROR (Status)) {
    815     return Status;
    816   }
    817 
    818   //
    819   // Compare the calculated icv and the appended original icv.
    820   //
    821   if (CompareMem (EspBuffer + AuthSize, IcvBuffer, IcvSize) == 0) {
    822     return EFI_SUCCESS;
    823   }
    824 
    825   DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
    826   return EFI_ACCESS_DENIED;
    827 }
    828 
    829 /**
    830   Search the related SAD entry by the input .
    831 
    832   @param[in]  IpHead       The pointer to IP header.
    833   @param[in]  IpVersion    The version of IP (IP4 or IP6).
    834   @param[in]  Spi          The SPI used to search the related SAD entry.
    835 
    836 
    837   @retval     NULL             Not find the related SAD entry.
    838   @retval     IPSEC_SAD_ENTRY  Return the related SAD entry.
    839 
    840 **/
    841 IPSEC_SAD_ENTRY *
    842 IpSecFoundSadFromInboundPacket (
    843    UINT8   *IpHead,
    844    UINT8   IpVersion,
    845    UINT32  Spi
    846    )
    847 {
    848   EFI_IP_ADDRESS   DestIp;
    849 
    850   //
    851   // Parse destination address from ip header.
    852   //
    853   ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
    854   if (IpVersion == IP_VERSION_4) {
    855     CopyMem (
    856       &DestIp,
    857       &((IP4_HEAD *) IpHead)->Dst,
    858       sizeof (IP4_ADDR)
    859       );
    860   } else {
    861     CopyMem (
    862       &DestIp,
    863       &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
    864       sizeof (EFI_IPv6_ADDRESS)
    865       );
    866   }
    867 
    868   //
    869   // Lookup SAD entry according to the spi and dest address.
    870   //
    871   return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);
    872 }
    873 
    874 /**
    875   Validate the IP6 extension header format for both the packets we received
    876   and that we will transmit.
    877 
    878   @param[in]  NextHeader    The next header field in IPv6 basic header.
    879   @param[in]  ExtHdrs       The first bye of the option.
    880   @param[in]  ExtHdrsLen    The length of the whole option.
    881   @param[out] LastHeader    The pointer of NextHeader of the last extension
    882                             header processed by IP6.
    883   @param[out] RealExtsLen   The length of extension headers processed by IP6 layer.
    884                             This is an optional parameter that may be NULL.
    885 
    886   @retval     TRUE          The option is properly formated.
    887   @retval     FALSE         The option is malformated.
    888 
    889 **/
    890 BOOLEAN
    891 IpSecIsIp6ExtsValid (
    892   IN UINT8                  *NextHeader,
    893   IN UINT8                  *ExtHdrs,
    894   IN UINT32                 ExtHdrsLen,
    895   OUT UINT8                 **LastHeader,
    896   OUT UINT32                *RealExtsLen    OPTIONAL
    897   )
    898 {
    899   UINT32                     Pointer;
    900   UINT8                      *Option;
    901   UINT8                      OptionLen;
    902   UINT8                      CountD;
    903   UINT8                      CountF;
    904   UINT8                      CountA;
    905 
    906   if (RealExtsLen != NULL) {
    907     *RealExtsLen = 0;
    908   }
    909 
    910   *LastHeader = NextHeader;
    911 
    912   if (ExtHdrs == NULL && ExtHdrsLen == 0) {
    913     return TRUE;
    914   }
    915 
    916   if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {
    917     return FALSE;
    918   }
    919 
    920   Pointer = 0;
    921   CountD  = 0;
    922   CountF  = 0;
    923   CountA  = 0;
    924 
    925   while (Pointer <= ExtHdrsLen) {
    926 
    927     switch (*NextHeader) {
    928     case IP6_HOP_BY_HOP:
    929       if (Pointer != 0) {
    930         return FALSE;
    931       }
    932 
    933     //
    934     // Fall through
    935     //
    936     case IP6_DESTINATION:
    937       if (*NextHeader == IP6_DESTINATION) {
    938         CountD++;
    939       }
    940 
    941       if (CountD > 2) {
    942         return FALSE;
    943       }
    944 
    945       NextHeader = ExtHdrs + Pointer;
    946 
    947       Pointer++;
    948       Option     = ExtHdrs + Pointer;
    949       OptionLen  = (UINT8) ((*Option + 1) * 8 - 2);
    950       Option++;
    951       Pointer++;
    952 
    953       Pointer = Pointer + OptionLen;
    954       break;
    955 
    956     case IP6_FRAGMENT:
    957       if (++CountF > 1) {
    958         return FALSE;
    959       }
    960       //
    961       // RFC2402, AH header should after fragment header.
    962       //
    963       if (CountA > 1) {
    964         return FALSE;
    965       }
    966 
    967       NextHeader = ExtHdrs + Pointer;
    968       Pointer    = Pointer + 8;
    969       break;
    970 
    971     case IP6_AH:
    972       if (++CountA > 1) {
    973         return FALSE;
    974       }
    975 
    976       Option     = ExtHdrs + Pointer;
    977       NextHeader = Option;
    978       Option++;
    979       //
    980       // RFC2402, Payload length is specified in 32-bit words, minus "2".
    981       //
    982       OptionLen  = (UINT8) ((*Option + 2) * 4);
    983       Pointer    = Pointer + OptionLen;
    984       break;
    985 
    986     default:
    987       *LastHeader = NextHeader;
    988        if (RealExtsLen != NULL) {
    989          *RealExtsLen = Pointer;
    990        }
    991 
    992        return TRUE;
    993     }
    994   }
    995 
    996   *LastHeader = NextHeader;
    997 
    998   if (RealExtsLen != NULL) {
    999     *RealExtsLen = Pointer;
   1000   }
   1001 
   1002   return TRUE;
   1003 }
   1004 
   1005 /**
   1006   The actual entry to process the tunnel header and inner header for tunnel mode
   1007   outbound traffic.
   1008 
   1009   This function is the subfunction of IpSecEspInboundPacket(). It change the destination
   1010   Ip address to the station address and recalculate the uplayyer's checksum.
   1011 
   1012 
   1013   @param[in, out] IpHead             Points to the IP header containing the ESP header
   1014                                      to be trimed on input, and without ESP header
   1015                                      on return.
   1016   @param[in]      IpPayload          The decrypted Ip payload. It start from the inner
   1017                                      header.
   1018   @param[in]      IpVersion          The version of IP.
   1019   @param[in]      SadData            Pointer of the relevant SAD.
   1020   @param[in, out] LastHead           The Last Header in IP header on return.
   1021 
   1022 **/
   1023 VOID
   1024 IpSecTunnelInboundPacket (
   1025   IN OUT UINT8           *IpHead,
   1026   IN     UINT8           *IpPayload,
   1027   IN     UINT8           IpVersion,
   1028   IN     IPSEC_SAD_DATA  *SadData,
   1029   IN OUT UINT8           *LastHead
   1030   )
   1031 {
   1032   EFI_UDP_HEADER   *UdpHeader;
   1033   TCP_HEAD         *TcpHeader;
   1034   UINT16            *Checksum;
   1035   UINT16           PseudoChecksum;
   1036   UINT16           PacketChecksum;
   1037   UINT32           OptionLen;
   1038   IP6_ICMP_HEAD    *Icmp6Head;
   1039 
   1040   Checksum = NULL;
   1041 
   1042   if (IpVersion == IP_VERSION_4) {
   1043     //
   1044     // Zero OutIP header use this to indicate the input packet is under
   1045     // IPsec Tunnel protected.
   1046     //
   1047     ZeroMem (
   1048       (IP4_HEAD *)IpHead,
   1049       sizeof (IP4_HEAD)
   1050       );
   1051     CopyMem (
   1052       &((IP4_HEAD *)IpPayload)->Dst,
   1053       &SadData->TunnelDestAddress.v4,
   1054       sizeof (EFI_IPv4_ADDRESS)
   1055       );
   1056 
   1057     //
   1058     // Recalculate IpHeader Checksum
   1059     //
   1060     if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {
   1061       ((IP4_HEAD *)(IpPayload))->Checksum = 0;
   1062       ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (
   1063                                                         (UINT8 *)IpPayload,
   1064                                                         ((IP4_HEAD *)IpPayload)->HeadLen << 2
   1065                                                         ));
   1066 
   1067 
   1068     }
   1069 
   1070     //
   1071     // Recalcualte PseudoChecksum
   1072     //
   1073     switch (((IP4_HEAD *)IpPayload)->Protocol) {
   1074     case EFI_IP_PROTO_UDP :
   1075       UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
   1076       Checksum  = & UdpHeader->Checksum;
   1077       *Checksum = 0;
   1078       break;
   1079 
   1080     case EFI_IP_PROTO_TCP:
   1081       TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
   1082       Checksum  = &TcpHeader->Checksum;
   1083       *Checksum = 0;
   1084       break;
   1085 
   1086     default:
   1087       break;
   1088       }
   1089     PacketChecksum = NetblockChecksum (
   1090                        (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2),
   1091                        NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)
   1092                        );
   1093     PseudoChecksum = NetPseudoHeadChecksum (
   1094                        ((IP4_HEAD *)IpPayload)->Src,
   1095                        ((IP4_HEAD *)IpPayload)->Dst,
   1096                        ((IP4_HEAD *)IpPayload)->Protocol,
   1097                        0
   1098                        );
   1099 
   1100       if (Checksum != NULL) {
   1101         *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
   1102         *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));
   1103       }
   1104     }else {
   1105       //
   1106       //  Zero OutIP header use this to indicate the input packet is under
   1107       //  IPsec Tunnel protected.
   1108       //
   1109       ZeroMem (
   1110         IpHead,
   1111         sizeof (EFI_IP6_HEADER)
   1112         );
   1113       CopyMem (
   1114         &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,
   1115         &SadData->TunnelDestAddress.v6,
   1116         sizeof (EFI_IPv6_ADDRESS)
   1117         );
   1118 
   1119       //
   1120       // Get the Extension Header and Header length.
   1121       //
   1122       IpSecIsIp6ExtsValid (
   1123         &((EFI_IP6_HEADER *)IpPayload)->NextHeader,
   1124         IpPayload + sizeof (EFI_IP6_HEADER),
   1125         ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,
   1126         &LastHead,
   1127         &OptionLen
   1128         );
   1129 
   1130       //
   1131       // Recalcualte PseudoChecksum
   1132       //
   1133       switch (*LastHead) {
   1134       case EFI_IP_PROTO_UDP:
   1135         UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
   1136         Checksum  = &UdpHeader->Checksum;
   1137         *Checksum = 0;
   1138         break;
   1139 
   1140       case EFI_IP_PROTO_TCP:
   1141         TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
   1142         Checksum  = &TcpHeader->Checksum;
   1143         *Checksum = 0;
   1144         break;
   1145 
   1146       case IP6_ICMP:
   1147         Icmp6Head  = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
   1148         Checksum   = &Icmp6Head->Checksum;
   1149         *Checksum  = 0;
   1150         break;
   1151       }
   1152       PacketChecksum = NetblockChecksum (
   1153                          IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen,
   1154                          NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen
   1155                          );
   1156       PseudoChecksum = NetIp6PseudoHeadChecksum (
   1157                          &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,
   1158                          &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,
   1159                          *LastHead,
   1160                          0
   1161                          );
   1162 
   1163     if (Checksum != NULL) {
   1164       *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
   1165       *Checksum = (UINT16) ~(NetAddChecksum (
   1166                                *Checksum,
   1167                                HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))
   1168                                ));
   1169     }
   1170   }
   1171 }
   1172 
   1173 /**
   1174   The actual entry to create inner header for tunnel mode inbound traffic.
   1175 
   1176   This function is the subfunction of IpSecEspOutboundPacket(). It create
   1177   the sending packet by encrypting its payload and inserting ESP header in the orginal
   1178   IP header, then return the IpHeader and IPsec protected Fragmentable.
   1179 
   1180   @param[in, out] IpHead             Points to IP header containing the orginal IP header
   1181                                      to be processed on input, and inserted ESP header
   1182                                      on return.
   1183   @param[in]      IpVersion          The version of IP.
   1184   @param[in]      SadData            The related SAD data.
   1185   @param[in, out] LastHead           The Last Header in IP header.
   1186   @param[in]      OptionsBuffer      Pointer to the options buffer.
   1187   @param[in]      OptionsLength      Length of the options buffer.
   1188   @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by
   1189                                      IPsec on input, and with IPsec protected
   1190                                      on return.
   1191   @param[in]      FragmentCount      The number of fragments.
   1192 
   1193   @retval EFI_SUCCESS              The operation was successful.
   1194   @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.
   1195 
   1196 **/
   1197 UINT8 *
   1198 IpSecTunnelOutboundPacket (
   1199   IN OUT UINT8                   *IpHead,
   1200   IN     UINT8                   IpVersion,
   1201   IN     IPSEC_SAD_DATA          *SadData,
   1202   IN OUT UINT8                   *LastHead,
   1203   IN     VOID                    **OptionsBuffer,
   1204   IN     UINT32                  *OptionsLength,
   1205   IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
   1206   IN     UINT32                  *FragmentCount
   1207   )
   1208 {
   1209   UINT8         *InnerHead;
   1210   NET_BUF       *Packet;
   1211   UINT16        PacketChecksum;
   1212   UINT16        *Checksum;
   1213   UINT16        PseudoChecksum;
   1214   IP6_ICMP_HEAD *IcmpHead;
   1215 
   1216   Checksum = NULL;
   1217   if (OptionsLength == NULL) {
   1218     return NULL;
   1219   }
   1220 
   1221   if (IpVersion == IP_VERSION_4) {
   1222     InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);
   1223     ASSERT (InnerHead != NULL);
   1224     CopyMem (
   1225       InnerHead,
   1226       IpHead,
   1227       sizeof (IP4_HEAD)
   1228       );
   1229     CopyMem (
   1230       InnerHead + sizeof (IP4_HEAD),
   1231       *OptionsBuffer,
   1232       *OptionsLength
   1233       );
   1234   } else {
   1235     InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);
   1236     ASSERT (InnerHead != NULL);
   1237     CopyMem (
   1238       InnerHead,
   1239       IpHead,
   1240       sizeof (EFI_IP6_HEADER)
   1241       );
   1242     CopyMem (
   1243       InnerHead + sizeof (EFI_IP6_HEADER),
   1244       *OptionsBuffer,
   1245       *OptionsLength
   1246       );
   1247   }
   1248   if (OptionsBuffer != NULL) {
   1249     if (*OptionsLength != 0) {
   1250 
   1251       *OptionsBuffer = NULL;
   1252       *OptionsLength = 0;
   1253     }
   1254   }
   1255 
   1256   //
   1257   // 2. Reassamlbe Fragment into Packet
   1258   //
   1259   Packet = NetbufFromExt (
   1260              (NET_FRAGMENT *)(*FragmentTable),
   1261              *FragmentCount,
   1262              0,
   1263              0,
   1264              IpSecOnRecyclePacket,
   1265              NULL
   1266              );
   1267   ASSERT (Packet != NULL);
   1268   //
   1269   // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
   1270   //    CheckSum.
   1271   //
   1272   switch (*LastHead) {
   1273   case EFI_IP_PROTO_UDP:
   1274     Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);
   1275     ASSERT (Packet->Udp != NULL);
   1276     Checksum = &Packet->Udp->Checksum;
   1277     *Checksum = 0;
   1278     break;
   1279 
   1280   case EFI_IP_PROTO_TCP:
   1281     Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);
   1282     ASSERT (Packet->Tcp != NULL);
   1283     Checksum = &Packet->Tcp->Checksum;
   1284     *Checksum = 0;
   1285     break;
   1286 
   1287   case IP6_ICMP:
   1288     IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
   1289     ASSERT (IcmpHead != NULL);
   1290     Checksum = &IcmpHead->Checksum;
   1291     *Checksum = 0;
   1292     break;
   1293 
   1294   default:
   1295     break;
   1296   }
   1297 
   1298   PacketChecksum = NetbufChecksum (Packet);
   1299 
   1300   if (IpVersion == IP_VERSION_4) {
   1301     //
   1302     // Replace the source address of Inner Header.
   1303     //
   1304     CopyMem (
   1305       &((IP4_HEAD *)InnerHead)->Src,
   1306       &SadData->SpdSelector->LocalAddress[0].Address.v4,
   1307       sizeof (EFI_IPv4_ADDRESS)
   1308       );
   1309 
   1310     PacketChecksum = NetbufChecksum (Packet);
   1311     PseudoChecksum = NetPseudoHeadChecksum (
   1312                        ((IP4_HEAD *)InnerHead)->Src,
   1313                        ((IP4_HEAD *)InnerHead)->Dst,
   1314                        *LastHead,
   1315                        0
   1316                        );
   1317 
   1318    } else {
   1319      //
   1320      // Replace the source address of Inner Header.
   1321      //
   1322      CopyMem (
   1323        &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
   1324        &(SadData->SpdSelector->LocalAddress[0].Address.v6),
   1325        sizeof (EFI_IPv6_ADDRESS)
   1326        );
   1327      PacketChecksum = NetbufChecksum (Packet);
   1328      PseudoChecksum = NetIp6PseudoHeadChecksum (
   1329                       &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
   1330                       &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,
   1331                       *LastHead,
   1332                       0
   1333                       );
   1334 
   1335    }
   1336    if (Checksum != NULL) {
   1337      *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
   1338      *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));
   1339    }
   1340 
   1341   if (Packet != NULL) {
   1342     NetbufFree (Packet);
   1343   }
   1344   return InnerHead;
   1345 }
   1346 
   1347 /**
   1348   The actual entry to relative function processes the inbound traffic of ESP header.
   1349 
   1350   This function is the subfunction of IpSecProtectInboundPacket(). It checks the
   1351   received packet security property and trim the ESP header and then returns without
   1352   an IPsec protected IP Header and FramgmentTable.
   1353 
   1354   @param[in]      IpVersion          The version of IP.
   1355   @param[in, out] IpHead             Points to the IP header containing the ESP header
   1356                                      to be trimed on input, and without ESP header
   1357                                      on return.
   1358   @param[out]     LastHead           The Last Header in IP header on return.
   1359   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   1360   @param[in, out] OptionsLength      Length of the options buffer.
   1361   @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec
   1362                                      protected on input, and without IPsec protected
   1363                                      on return.
   1364   @param[in, out] FragmentCount      The number of fragments.
   1365   @param[out]     SpdSelector        Pointer to contain the address of SPD selector on return.
   1366   @param[out]     RecycleEvent       The event for recycling of resources.
   1367 
   1368   @retval EFI_SUCCESS              The operation was successful.
   1369   @retval EFI_ACCESS_DENIED        One or more following conditions is TRUE:
   1370                                    - ESP header was not found or mal-format.
   1371                                    - The related SAD entry was not found.
   1372                                    - The related SAD entry does not support the ESP protocol.
   1373   @retval EFI_OUT_OF_RESOURCES     The required system resource can't be allocated.
   1374 
   1375 **/
   1376 EFI_STATUS
   1377 IpSecEspInboundPacket (
   1378   IN     UINT8                       IpVersion,
   1379   IN OUT VOID                        *IpHead,
   1380      OUT UINT8                       *LastHead,
   1381   IN OUT VOID                        **OptionsBuffer,
   1382   IN OUT UINT32                      *OptionsLength,
   1383   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   1384   IN OUT UINT32                      *FragmentCount,
   1385      OUT EFI_IPSEC_SPD_SELECTOR      **SpdSelector,
   1386      OUT EFI_EVENT                   *RecycleEvent
   1387   )
   1388 {
   1389   EFI_STATUS            Status;
   1390   NET_BUF               *Payload;
   1391   UINTN                 EspSize;
   1392   UINTN                 IvSize;
   1393   UINTN                 BlockSize;
   1394   UINTN                 MiscSize;
   1395   UINTN                 PlainPayloadSize;
   1396   UINTN                 PaddingSize;
   1397   UINTN                 IcvSize;
   1398   UINT8                 *ProcessBuffer;
   1399   EFI_ESP_HEADER        *EspHeader;
   1400   EFI_ESP_TAIL          *EspTail;
   1401   EFI_IPSEC_SA_ID       *SaId;
   1402   IPSEC_SAD_DATA        *SadData;
   1403   IPSEC_SAD_ENTRY       *SadEntry;
   1404   IPSEC_RECYCLE_CONTEXT *RecycleContext;
   1405   UINT8                 NextHeader;
   1406   UINT16                IpSecHeadSize;
   1407   UINT8                 *InnerHead;
   1408 
   1409   Status            = EFI_SUCCESS;
   1410   Payload           = NULL;
   1411   ProcessBuffer     = NULL;
   1412   RecycleContext    = NULL;
   1413   *RecycleEvent     = NULL;
   1414   PlainPayloadSize  = 0;
   1415   NextHeader        = 0;
   1416 
   1417   //
   1418   // Build netbuf from fragment table first.
   1419   //
   1420   Payload = NetbufFromExt (
   1421               (NET_FRAGMENT *) *FragmentTable,
   1422               *FragmentCount,
   1423               0,
   1424               sizeof (EFI_ESP_HEADER),
   1425               IpSecOnRecyclePacket,
   1426               NULL
   1427               );
   1428   if (Payload == NULL) {
   1429     Status = EFI_OUT_OF_RESOURCES;
   1430     goto ON_EXIT;
   1431   }
   1432 
   1433   //
   1434   // Get the esp size and esp header from netbuf.
   1435   //
   1436   EspSize   = Payload->TotalSize;
   1437   EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);
   1438 
   1439   if (EspHeader == NULL) {
   1440     Status = EFI_ACCESS_DENIED;
   1441     goto ON_EXIT;
   1442   }
   1443 
   1444   //
   1445   // Parse destination address from ip header and found the related SAD Entry.
   1446   //
   1447   SadEntry = IpSecFoundSadFromInboundPacket (
   1448                IpHead,
   1449                IpVersion,
   1450                NTOHL (EspHeader->Spi)
   1451                );
   1452 
   1453   if (SadEntry == NULL) {
   1454     Status = EFI_ACCESS_DENIED;
   1455     goto ON_EXIT;
   1456   }
   1457 
   1458   SaId    = SadEntry->Id;
   1459   SadData = SadEntry->Data;
   1460 
   1461   //
   1462   // Only support esp protocol currently.
   1463   //
   1464   if (SaId->Proto != EfiIPsecESP) {
   1465     Status = EFI_ACCESS_DENIED;
   1466     goto ON_EXIT;
   1467   }
   1468 
   1469   if (!SadData->ManualSet) {
   1470     //
   1471     // TODO: Check SA lifetime and sequence number
   1472     //
   1473   }
   1474 
   1475   //
   1476   // Allocate buffer for decryption and authentication.
   1477   //
   1478   ProcessBuffer = AllocateZeroPool (EspSize);
   1479   if (ProcessBuffer == NULL) {
   1480     Status = EFI_OUT_OF_RESOURCES;
   1481     goto ON_EXIT;
   1482   }
   1483 
   1484   NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);
   1485 
   1486   //
   1487   // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.
   1488   //
   1489   IcvSize   = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
   1490   IvSize    = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1491   BlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1492 
   1493   //
   1494   // Make sure the ESP packet is not mal-formt.
   1495   // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.
   1496   // 2. Check whether the left payload size is multiple of IvSize.
   1497   //
   1498   MiscSize = sizeof (EFI_ESP_HEADER) + IvSize + IcvSize;
   1499   if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL))) {
   1500     Status = EFI_ACCESS_DENIED;
   1501     goto ON_EXIT;
   1502   }
   1503   if ((EspSize - MiscSize) % BlockSize != 0) {
   1504     Status = EFI_ACCESS_DENIED;
   1505     goto ON_EXIT;
   1506   }
   1507 
   1508   //
   1509   // Authenticate the ESP packet.
   1510   //
   1511   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1512     Status = IpSecEspAuthVerifyPayload (
   1513                ProcessBuffer,
   1514                EspSize,
   1515                SadEntry,
   1516                IcvSize
   1517                );
   1518     if (EFI_ERROR (Status)) {
   1519       goto ON_EXIT;
   1520     }
   1521   }
   1522   //
   1523   // Decrypt the payload by the SAD entry if it has decrypt key.
   1524   //
   1525   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1526     Status = IpSecCryptoIoDecrypt (
   1527                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
   1528                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
   1529                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
   1530                ProcessBuffer + sizeof (EFI_ESP_HEADER),
   1531                ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,
   1532                EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,
   1533                ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize
   1534                );
   1535     if (EFI_ERROR (Status)) {
   1536       goto ON_EXIT;
   1537     }
   1538   }
   1539 
   1540   //
   1541   // Parse EspTail and compute the plain payload size.
   1542   //
   1543   EspTail           = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));
   1544   PaddingSize       = EspTail->PaddingLength;
   1545   NextHeader        = EspTail->NextHeader;
   1546 
   1547   if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL) + PaddingSize)) {
   1548     Status = EFI_ACCESS_DENIED;
   1549     goto ON_EXIT;
   1550   }
   1551   PlainPayloadSize  = EspSize - MiscSize - sizeof (EFI_ESP_TAIL) - PaddingSize;
   1552 
   1553   //
   1554   // TODO: handle anti-replay window
   1555   //
   1556   //
   1557   // Decryption and authentication with esp has been done, so it's time to
   1558   // reload the new packet, create recycle event and fixup ip header.
   1559   //
   1560   RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
   1561   if (RecycleContext == NULL) {
   1562     Status = EFI_OUT_OF_RESOURCES;
   1563     goto ON_EXIT;
   1564   }
   1565 
   1566   Status = gBS->CreateEvent (
   1567                   EVT_NOTIFY_SIGNAL,
   1568                   TPL_NOTIFY,
   1569                   IpSecRecycleCallback,
   1570                   RecycleContext,
   1571                   RecycleEvent
   1572                   );
   1573   if (EFI_ERROR (Status)) {
   1574     goto ON_EXIT;
   1575   }
   1576 
   1577   //
   1578   // The caller will take responsible to handle the original fragment table
   1579   //
   1580   *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
   1581   if (*FragmentTable == NULL) {
   1582     Status = EFI_OUT_OF_RESOURCES;
   1583     goto ON_EXIT;
   1584   }
   1585 
   1586   RecycleContext->PayloadBuffer       = ProcessBuffer;
   1587   RecycleContext->FragmentTable       = *FragmentTable;
   1588 
   1589   //
   1590   // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
   1591   //
   1592   if (SadData->Mode == EfiIPsecTunnel) {
   1593     InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
   1594     IpSecTunnelInboundPacket (
   1595       IpHead,
   1596       InnerHead,
   1597       IpVersion,
   1598       SadData,
   1599       LastHead
   1600       );
   1601 
   1602     if (IpVersion == IP_VERSION_4) {
   1603       (*FragmentTable)[0].FragmentBuffer  = InnerHead ;
   1604       (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1605 
   1606     }else {
   1607       (*FragmentTable)[0].FragmentBuffer  = InnerHead;
   1608       (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1609     }
   1610   } else {
   1611     (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
   1612     (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1613   }
   1614 
   1615   *FragmentCount                      = 1;
   1616 
   1617   //
   1618   // Update the total length field in ip header since processed by esp.
   1619   //
   1620   if (SadData->Mode != EfiIPsecTunnel) {
   1621     if (IpVersion == IP_VERSION_4) {
   1622       ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + PlainPayloadSize));
   1623     } else {
   1624       IpSecHeadSize                              = IpSecGetPlainExtHeadSize (IpHead, LastHead);
   1625       ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));
   1626     }
   1627     //
   1628     // Update the next layer field in ip header since esp header inserted.
   1629     //
   1630     *LastHead = NextHeader;
   1631   }
   1632 
   1633 
   1634   //
   1635   // Update the SPD association of the SAD entry.
   1636   //
   1637   *SpdSelector = SadData->SpdSelector;
   1638 
   1639 ON_EXIT:
   1640   if (Payload != NULL) {
   1641     NetbufFree (Payload);
   1642   }
   1643 
   1644   if (EFI_ERROR (Status)) {
   1645     if (ProcessBuffer != NULL) {
   1646       FreePool (ProcessBuffer);
   1647     }
   1648 
   1649     if (RecycleContext != NULL) {
   1650       FreePool (RecycleContext);
   1651     }
   1652 
   1653     if (*RecycleEvent != NULL) {
   1654       gBS->CloseEvent (*RecycleEvent);
   1655     }
   1656   }
   1657 
   1658   return Status;
   1659 }
   1660 
   1661 /**
   1662   The actual entry to the relative function processes the output traffic using the ESP protocol.
   1663 
   1664   This function is the subfunction of IpSecProtectOutboundPacket(). It protected
   1665   the sending packet by encrypting its payload and inserting ESP header in the orginal
   1666   IP header, then return the IpHeader and IPsec protected Fragmentable.
   1667 
   1668   @param[in]      IpVersion          The version of IP.
   1669   @param[in, out] IpHead             Points to IP header containing the orginal IP header
   1670                                      to be processed on input, and inserted ESP header
   1671                                      on return.
   1672   @param[in, out] LastHead           The Last Header in IP header.
   1673   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   1674   @param[in, out] OptionsLength      Length of the options buffer.
   1675   @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by
   1676                                      IPsec on input, and with IPsec protected
   1677                                      on return.
   1678   @param[in, out] FragmentCount      The number of fragments.
   1679   @param[in]      SadEntry           The related SAD entry.
   1680   @param[out]     RecycleEvent       The event for recycling of resources.
   1681 
   1682   @retval EFI_SUCCESS              The operation was successful.
   1683   @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.
   1684 
   1685 **/
   1686 EFI_STATUS
   1687 IpSecEspOutboundPacket (
   1688   IN UINT8                           IpVersion,
   1689   IN OUT VOID                        *IpHead,
   1690   IN OUT UINT8                       *LastHead,
   1691   IN OUT VOID                        **OptionsBuffer,
   1692   IN OUT UINT32                      *OptionsLength,
   1693   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   1694   IN OUT UINT32                      *FragmentCount,
   1695   IN     IPSEC_SAD_ENTRY             *SadEntry,
   1696      OUT EFI_EVENT                   *RecycleEvent
   1697   )
   1698 {
   1699   EFI_STATUS            Status;
   1700   UINTN                 Index;
   1701   EFI_IPSEC_SA_ID       *SaId;
   1702   IPSEC_SAD_DATA        *SadData;
   1703   IPSEC_RECYCLE_CONTEXT *RecycleContext;
   1704   UINT8                 *ProcessBuffer;
   1705   UINTN                 BytesCopied;
   1706   INTN                  EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4
   1707   UINTN                 EspSize;         // Total size of esp wrapped ip payload
   1708   UINTN                 IvSize;          // Size of IV, optional, might be 0
   1709   UINTN                 PlainPayloadSize;// Original IP payload size
   1710   UINTN                 PaddingSize;     // Size of padding
   1711   UINTN                 EncryptSize;     // Size of data to be encrypted, start after IV and
   1712                                          // stop before ICV
   1713   UINTN                 IcvSize;         // Size of ICV, optional, might be 0
   1714   UINT8                 *RestOfPayload;  // Start of Payload after IV
   1715   UINT8                 *Padding;        // Start address of padding
   1716   EFI_ESP_HEADER        *EspHeader;      // Start address of ESP frame
   1717   EFI_ESP_TAIL          *EspTail;        // Address behind padding
   1718   UINT8                 *InnerHead;
   1719   HASH_DATA_FRAGMENT    HashFragment[1];
   1720 
   1721   Status          = EFI_ACCESS_DENIED;
   1722   SaId            = SadEntry->Id;
   1723   SadData         = SadEntry->Data;
   1724   ProcessBuffer   = NULL;
   1725   RecycleContext  = NULL;
   1726   *RecycleEvent   = NULL;
   1727   InnerHead       = NULL;
   1728 
   1729   if (!SadData->ManualSet &&
   1730       SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&
   1731       SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL
   1732       ) {
   1733     //
   1734     // Invalid manual SAD entry configuration.
   1735     //
   1736     goto ON_EXIT;
   1737   }
   1738 
   1739   //
   1740   // Create OutHeader according to Inner Header
   1741   //
   1742   if (SadData->Mode == EfiIPsecTunnel) {
   1743     InnerHead = IpSecTunnelOutboundPacket (
   1744                   IpHead,
   1745                   IpVersion,
   1746                   SadData,
   1747                   LastHead,
   1748                   OptionsBuffer,
   1749                   OptionsLength,
   1750                   FragmentTable,
   1751                   FragmentCount
   1752                   );
   1753 
   1754     if (InnerHead == NULL) {
   1755       return EFI_INVALID_PARAMETER;
   1756     }
   1757 
   1758   }
   1759 
   1760   //
   1761   // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
   1762   //
   1763   EncryptBlockSize  = 4;
   1764 
   1765   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1766     EncryptBlockSize  = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1767 
   1768     if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {
   1769       goto ON_EXIT;
   1770     }
   1771   }
   1772 
   1773   //
   1774   // Calculate the plain payload size according to the fragment table.
   1775   //
   1776   PlainPayloadSize = 0;
   1777   for (Index = 0; Index < *FragmentCount; Index++) {
   1778     PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;
   1779   }
   1780 
   1781   //
   1782   // Add IPHeader size for Tunnel Mode
   1783   //
   1784   if (SadData->Mode == EfiIPsecTunnel) {
   1785     if (IpVersion == IP_VERSION_4) {
   1786       PlainPayloadSize += sizeof (IP4_HEAD);
   1787     } else {
   1788       PlainPayloadSize += sizeof (EFI_IP6_HEADER);
   1789     }
   1790     //
   1791     // OPtions should be encryption into it
   1792     //
   1793     PlainPayloadSize += *OptionsLength;
   1794   }
   1795 
   1796 
   1797   //
   1798   // Calculate icv size, optional by default and 4 bytes alignment.
   1799   //
   1800   IcvSize = 0;
   1801   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1802     IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
   1803     if (IcvSize % 4 != 0) {
   1804       goto ON_EXIT;
   1805     }
   1806   }
   1807 
   1808   //
   1809   // Calcuate the total size of esp wrapped ip payload.
   1810   //
   1811   IvSize        = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1812   EncryptSize   = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;
   1813   PaddingSize   = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);
   1814   EspSize       = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;
   1815 
   1816   ProcessBuffer = AllocateZeroPool (EspSize);
   1817   if (ProcessBuffer == NULL) {
   1818     Status = EFI_OUT_OF_RESOURCES;
   1819     goto ON_EXIT;
   1820   }
   1821 
   1822   //
   1823   // Calculate esp header and esp tail including header, payload and padding.
   1824   //
   1825   EspHeader     = (EFI_ESP_HEADER *) ProcessBuffer;
   1826   RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;
   1827   Padding       = RestOfPayload + PlainPayloadSize;
   1828   EspTail       = (EFI_ESP_TAIL *) (Padding + PaddingSize);
   1829 
   1830   //
   1831   // Fill the sn and spi fields in esp header.
   1832   //
   1833   EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);
   1834   //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
   1835   EspHeader->Spi            = HTONL (SaId->Spi);
   1836 
   1837   //
   1838   // Copy the rest of payload (after iv) from the original fragment buffer.
   1839   //
   1840   BytesCopied = 0;
   1841 
   1842   //
   1843   // For Tunnel Mode
   1844   //
   1845   if (SadData->Mode == EfiIPsecTunnel) {
   1846     if (IpVersion == IP_VERSION_4) {
   1847       //
   1848       // HeadLen, Total Length
   1849       //
   1850       ((IP4_HEAD *)InnerHead)->HeadLen  = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);
   1851       ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);
   1852       ((IP4_HEAD *)InnerHead)->Checksum = 0;
   1853       ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (
   1854                                                   (UINT8 *)InnerHead,
   1855                                                   sizeof(IP4_HEAD)
   1856                                                   ));
   1857       CopyMem (
   1858         RestOfPayload + BytesCopied,
   1859         InnerHead,
   1860         sizeof (IP4_HEAD) + *OptionsLength
   1861         );
   1862       BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;
   1863 
   1864     } else {
   1865     ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));
   1866       CopyMem (
   1867         RestOfPayload + BytesCopied,
   1868         InnerHead,
   1869         sizeof (EFI_IP6_HEADER) + *OptionsLength
   1870         );
   1871       BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;
   1872     }
   1873   }
   1874 
   1875   for (Index = 0; Index < *FragmentCount; Index++) {
   1876     CopyMem (
   1877       (RestOfPayload + BytesCopied),
   1878       (*FragmentTable)[Index].FragmentBuffer,
   1879       (*FragmentTable)[Index].FragmentLength
   1880       );
   1881     BytesCopied += (*FragmentTable)[Index].FragmentLength;
   1882   }
   1883   //
   1884   // Fill the padding buffer by natural number sequence.
   1885   //
   1886   for (Index = 0; Index < PaddingSize; Index++) {
   1887     Padding[Index] = (UINT8) (Index + 1);
   1888   }
   1889   //
   1890   // Fill the padding length and next header fields in esp tail.
   1891   //
   1892   EspTail->PaddingLength  = (UINT8) PaddingSize;
   1893   EspTail->NextHeader     = *LastHead;
   1894 
   1895   //
   1896   // Fill the next header for Tunnel mode.
   1897   //
   1898   if (SadData->Mode == EfiIPsecTunnel) {
   1899     if (IpVersion == IP_VERSION_4) {
   1900       EspTail->NextHeader = 4;
   1901     } else {
   1902       EspTail->NextHeader = 41;
   1903     }
   1904   }
   1905 
   1906   //
   1907   // Generate iv at random by crypt library.
   1908   //
   1909   Status = IpSecGenerateIv (
   1910              (UINT8 *) (EspHeader + 1),
   1911              IvSize
   1912              );
   1913 
   1914 
   1915   if (EFI_ERROR (Status)) {
   1916     goto ON_EXIT;
   1917   }
   1918 
   1919   //
   1920   // Encryption the payload (after iv) by the SAD entry if has encrypt key.
   1921   //
   1922   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1923     Status = IpSecCryptoIoEncrypt (
   1924                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
   1925                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
   1926                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
   1927                (UINT8 *)(EspHeader + 1),
   1928                RestOfPayload,
   1929                EncryptSize,
   1930                RestOfPayload
   1931                );
   1932 
   1933     if (EFI_ERROR (Status)) {
   1934       goto ON_EXIT;
   1935     }
   1936   }
   1937 
   1938   //
   1939   // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
   1940   //
   1941   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1942 
   1943     HashFragment[0].Data     = ProcessBuffer;
   1944     HashFragment[0].DataSize = EspSize - IcvSize;
   1945     Status = IpSecCryptoIoHmac (
   1946                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
   1947                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
   1948                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
   1949                HashFragment,
   1950                1,
   1951                ProcessBuffer + EspSize - IcvSize,
   1952                IcvSize
   1953                );
   1954     if (EFI_ERROR (Status)) {
   1955       goto ON_EXIT;
   1956     }
   1957   }
   1958 
   1959   //
   1960   // Encryption and authentication with esp has been done, so it's time to
   1961   // reload the new packet, create recycle event and fixup ip header.
   1962   //
   1963   RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
   1964   if (RecycleContext == NULL) {
   1965     Status = EFI_OUT_OF_RESOURCES;
   1966     goto ON_EXIT;
   1967   }
   1968 
   1969   Status = gBS->CreateEvent (
   1970                   EVT_NOTIFY_SIGNAL,
   1971                   TPL_NOTIFY,
   1972                   IpSecRecycleCallback,
   1973                   RecycleContext,
   1974                   RecycleEvent
   1975                   );
   1976   if (EFI_ERROR (Status)) {
   1977     goto ON_EXIT;
   1978   }
   1979   //
   1980   // Caller take responsible to handle the original fragment table.
   1981   //
   1982   *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
   1983   if (*FragmentTable == NULL) {
   1984     Status = EFI_OUT_OF_RESOURCES;
   1985     goto ON_EXIT;
   1986   }
   1987 
   1988   RecycleContext->FragmentTable       = *FragmentTable;
   1989   RecycleContext->PayloadBuffer       = ProcessBuffer;
   1990   (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer;
   1991   (*FragmentTable)[0].FragmentLength  = (UINT32) EspSize;
   1992   *FragmentCount                      = 1;
   1993 
   1994   //
   1995   // Update the total length field in ip header since processed by esp.
   1996   //
   1997   if (IpVersion == IP_VERSION_4) {
   1998     ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));
   1999   } else {
   2000     ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);
   2001   }
   2002 
   2003   //
   2004   // If tunnel mode, it should change the outer Ip header with tunnel source address
   2005   // and destination tunnel address.
   2006   //
   2007   if (SadData->Mode == EfiIPsecTunnel) {
   2008     if (IpVersion == IP_VERSION_4) {
   2009       CopyMem (
   2010         &((IP4_HEAD *) IpHead)->Src,
   2011         &SadData->TunnelSourceAddress.v4,
   2012         sizeof (EFI_IPv4_ADDRESS)
   2013         );
   2014       CopyMem (
   2015         &((IP4_HEAD *) IpHead)->Dst,
   2016         &SadData->TunnelDestAddress.v4,
   2017         sizeof (EFI_IPv4_ADDRESS)
   2018         );
   2019     } else {
   2020       CopyMem (
   2021         &((EFI_IP6_HEADER *) IpHead)->SourceAddress,
   2022         &SadData->TunnelSourceAddress.v6,
   2023         sizeof (EFI_IPv6_ADDRESS)
   2024         );
   2025       CopyMem (
   2026         &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
   2027         &SadData->TunnelDestAddress.v6,
   2028         sizeof (EFI_IPv6_ADDRESS)
   2029         );
   2030     }
   2031   }
   2032 
   2033   //
   2034   // Update the next layer field in ip header since esp header inserted.
   2035   //
   2036   *LastHead = IPSEC_ESP_PROTOCOL;
   2037 
   2038   //
   2039   // Increase the sn number in SAD entry according to rfc4303.
   2040   //
   2041   SadData->SequenceNumber++;
   2042 
   2043 ON_EXIT:
   2044   if (EFI_ERROR (Status)) {
   2045     if (ProcessBuffer != NULL) {
   2046       FreePool (ProcessBuffer);
   2047     }
   2048 
   2049     if (RecycleContext != NULL) {
   2050       FreePool (RecycleContext);
   2051     }
   2052 
   2053     if (*RecycleEvent != NULL) {
   2054       gBS->CloseEvent (*RecycleEvent);
   2055     }
   2056   }
   2057 
   2058   return Status;
   2059 }
   2060 
   2061 /**
   2062   This function processes the inbound traffic with IPsec.
   2063 
   2064   It checks the received packet security property, trims the ESP/AH header, and then
   2065   returns without an IPsec protected IP Header and FragmentTable.
   2066 
   2067   @param[in]      IpVersion          The version of IP.
   2068   @param[in, out] IpHead             Points to IP header containing the ESP/AH header
   2069                                      to be trimed on input, and without ESP/AH header
   2070                                      on return.
   2071   @param[in, out] LastHead           The Last Header in IP header on return.
   2072   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   2073   @param[in, out] OptionsLength      Length of the options buffer.
   2074   @param[in, out] FragmentTable      Pointer to a list of fragments in form of IPsec
   2075                                      protected on input, and without IPsec protected
   2076                                      on return.
   2077   @param[in, out] FragmentCount      The number of fragments.
   2078   @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.
   2079   @param[out]     RecycleEvent       The event for recycling of resources.
   2080 
   2081   @retval EFI_SUCCESS              The operation was successful.
   2082   @retval EFI_UNSUPPORTED          The IPSEC protocol is not supported.
   2083 
   2084 **/
   2085 EFI_STATUS
   2086 IpSecProtectInboundPacket (
   2087   IN     UINT8                       IpVersion,
   2088   IN OUT VOID                        *IpHead,
   2089   IN OUT UINT8                       *LastHead,
   2090   IN OUT VOID                        **OptionsBuffer,
   2091   IN OUT UINT32                      *OptionsLength,
   2092   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   2093   IN OUT UINT32                      *FragmentCount,
   2094      OUT EFI_IPSEC_SPD_SELECTOR      **SpdEntry,
   2095      OUT EFI_EVENT                   *RecycleEvent
   2096   )
   2097 {
   2098   if (*LastHead == IPSEC_ESP_PROTOCOL) {
   2099     //
   2100     // Process the esp ipsec header of the inbound traffic.
   2101     //
   2102     return IpSecEspInboundPacket (
   2103              IpVersion,
   2104              IpHead,
   2105              LastHead,
   2106              OptionsBuffer,
   2107              OptionsLength,
   2108              FragmentTable,
   2109              FragmentCount,
   2110              SpdEntry,
   2111              RecycleEvent
   2112              );
   2113   }
   2114   //
   2115   // The other protocols are not supported.
   2116   //
   2117   return EFI_UNSUPPORTED;
   2118 }
   2119 
   2120 /**
   2121   This fucntion processes the output traffic with IPsec.
   2122 
   2123   It protected the sending packet by encrypting it payload and inserting ESP/AH header
   2124   in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
   2125 
   2126   @param[in]      IpVersion          The version of IP.
   2127   @param[in, out] IpHead             Point to IP header containing the orginal IP header
   2128                                      to be processed on input, and inserted ESP/AH header
   2129                                      on return.
   2130   @param[in, out] LastHead           The Last Header in IP header.
   2131   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   2132   @param[in, out] OptionsLength      Length of the options buffer.
   2133   @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by
   2134                                      IPsec on input, and with IPsec protected
   2135                                      on return.
   2136   @param[in, out] FragmentCount      Number of fragments.
   2137   @param[in]      SadEntry           Related SAD entry.
   2138   @param[out]     RecycleEvent       Event for recycling of resources.
   2139 
   2140   @retval EFI_SUCCESS              The operation is successful.
   2141   @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.
   2142 
   2143 **/
   2144 EFI_STATUS
   2145 IpSecProtectOutboundPacket (
   2146   IN     UINT8                       IpVersion,
   2147   IN OUT VOID                        *IpHead,
   2148   IN OUT UINT8                       *LastHead,
   2149   IN OUT VOID                        **OptionsBuffer,
   2150   IN OUT UINT32                      *OptionsLength,
   2151   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   2152   IN OUT UINT32                      *FragmentCount,
   2153   IN     IPSEC_SAD_ENTRY             *SadEntry,
   2154      OUT EFI_EVENT                   *RecycleEvent
   2155   )
   2156 {
   2157   if (SadEntry->Id->Proto == EfiIPsecESP) {
   2158     //
   2159     // Process the esp ipsec header of the outbound traffic.
   2160     //
   2161     return IpSecEspOutboundPacket (
   2162              IpVersion,
   2163              IpHead,
   2164              LastHead,
   2165              OptionsBuffer,
   2166              OptionsLength,
   2167              FragmentTable,
   2168              FragmentCount,
   2169              SadEntry,
   2170              RecycleEvent
   2171              );
   2172   }
   2173   //
   2174   // The other protocols are not supported.
   2175   //
   2176   return EFI_UNSUPPORTED;
   2177 }
   2178