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 - 2016, 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 **/
   1194 UINT8 *
   1195 IpSecTunnelOutboundPacket (
   1196   IN OUT UINT8                   *IpHead,
   1197   IN     UINT8                   IpVersion,
   1198   IN     IPSEC_SAD_DATA          *SadData,
   1199   IN OUT UINT8                   *LastHead,
   1200   IN     VOID                    **OptionsBuffer,
   1201   IN     UINT32                  *OptionsLength,
   1202   IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
   1203   IN     UINT32                  *FragmentCount
   1204   )
   1205 {
   1206   UINT8         *InnerHead;
   1207   NET_BUF       *Packet;
   1208   UINT16        PacketChecksum;
   1209   UINT16        *Checksum;
   1210   UINT16        PseudoChecksum;
   1211   IP6_ICMP_HEAD *IcmpHead;
   1212 
   1213   Checksum = NULL;
   1214   if (OptionsLength == NULL) {
   1215     return NULL;
   1216   }
   1217 
   1218   if (IpVersion == IP_VERSION_4) {
   1219     InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);
   1220     if (InnerHead == NULL) {
   1221       return NULL;
   1222     }
   1223 
   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     if (InnerHead == NULL) {
   1237       return NULL;
   1238     }
   1239 
   1240     CopyMem (
   1241       InnerHead,
   1242       IpHead,
   1243       sizeof (EFI_IP6_HEADER)
   1244       );
   1245     CopyMem (
   1246       InnerHead + sizeof (EFI_IP6_HEADER),
   1247       *OptionsBuffer,
   1248       *OptionsLength
   1249       );
   1250   }
   1251   if (OptionsBuffer != NULL) {
   1252     if (*OptionsLength != 0) {
   1253 
   1254       *OptionsBuffer = NULL;
   1255       *OptionsLength = 0;
   1256     }
   1257   }
   1258 
   1259   //
   1260   // 2. Reassamlbe Fragment into Packet
   1261   //
   1262   Packet = NetbufFromExt (
   1263              (NET_FRAGMENT *)(*FragmentTable),
   1264              *FragmentCount,
   1265              0,
   1266              0,
   1267              IpSecOnRecyclePacket,
   1268              NULL
   1269              );
   1270   if (Packet == NULL) {
   1271     FreePool (InnerHead);
   1272     return NULL;
   1273   }
   1274 
   1275   //
   1276   // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
   1277   //    CheckSum.
   1278   //
   1279   switch (*LastHead) {
   1280   case EFI_IP_PROTO_UDP:
   1281     Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);
   1282     ASSERT (Packet->Udp != NULL);
   1283     Checksum = &Packet->Udp->Checksum;
   1284     *Checksum = 0;
   1285     break;
   1286 
   1287   case EFI_IP_PROTO_TCP:
   1288     Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);
   1289     ASSERT (Packet->Tcp != NULL);
   1290     Checksum = &Packet->Tcp->Checksum;
   1291     *Checksum = 0;
   1292     break;
   1293 
   1294   case IP6_ICMP:
   1295     IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
   1296     ASSERT (IcmpHead != NULL);
   1297     Checksum = &IcmpHead->Checksum;
   1298     *Checksum = 0;
   1299     break;
   1300 
   1301   default:
   1302     break;
   1303   }
   1304 
   1305   PacketChecksum = NetbufChecksum (Packet);
   1306 
   1307   if (IpVersion == IP_VERSION_4) {
   1308     //
   1309     // Replace the source address of Inner Header.
   1310     //
   1311     CopyMem (
   1312       &((IP4_HEAD *)InnerHead)->Src,
   1313       &SadData->SpdSelector->LocalAddress[0].Address.v4,
   1314       sizeof (EFI_IPv4_ADDRESS)
   1315       );
   1316 
   1317     PacketChecksum = NetbufChecksum (Packet);
   1318     PseudoChecksum = NetPseudoHeadChecksum (
   1319                        ((IP4_HEAD *)InnerHead)->Src,
   1320                        ((IP4_HEAD *)InnerHead)->Dst,
   1321                        *LastHead,
   1322                        0
   1323                        );
   1324 
   1325    } else {
   1326      //
   1327      // Replace the source address of Inner Header.
   1328      //
   1329      CopyMem (
   1330        &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
   1331        &(SadData->SpdSelector->LocalAddress[0].Address.v6),
   1332        sizeof (EFI_IPv6_ADDRESS)
   1333        );
   1334      PacketChecksum = NetbufChecksum (Packet);
   1335      PseudoChecksum = NetIp6PseudoHeadChecksum (
   1336                       &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
   1337                       &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,
   1338                       *LastHead,
   1339                       0
   1340                       );
   1341 
   1342    }
   1343    if (Checksum != NULL) {
   1344      *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
   1345      *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));
   1346    }
   1347 
   1348   if (Packet != NULL) {
   1349     NetbufFree (Packet);
   1350   }
   1351   return InnerHead;
   1352 }
   1353 
   1354 /**
   1355   The actual entry to relative function processes the inbound traffic of ESP header.
   1356 
   1357   This function is the subfunction of IpSecProtectInboundPacket(). It checks the
   1358   received packet security property and trim the ESP header and then returns without
   1359   an IPsec protected IP Header and FramgmentTable.
   1360 
   1361   @param[in]      IpVersion          The version of IP.
   1362   @param[in, out] IpHead             Points to the IP header containing the ESP header
   1363                                      to be trimed on input, and without ESP header
   1364                                      on return.
   1365   @param[out]     LastHead           The Last Header in IP header on return.
   1366   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   1367   @param[in, out] OptionsLength      Length of the options buffer.
   1368   @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec
   1369                                      protected on input, and without IPsec protected
   1370                                      on return.
   1371   @param[in, out] FragmentCount      The number of fragments.
   1372   @param[out]     SpdSelector        Pointer to contain the address of SPD selector on return.
   1373   @param[out]     RecycleEvent       The event for recycling of resources.
   1374 
   1375   @retval EFI_SUCCESS              The operation was successful.
   1376   @retval EFI_ACCESS_DENIED        One or more following conditions is TRUE:
   1377                                    - ESP header was not found or mal-format.
   1378                                    - The related SAD entry was not found.
   1379                                    - The related SAD entry does not support the ESP protocol.
   1380   @retval EFI_OUT_OF_RESOURCES     The required system resource can't be allocated.
   1381 
   1382 **/
   1383 EFI_STATUS
   1384 IpSecEspInboundPacket (
   1385   IN     UINT8                       IpVersion,
   1386   IN OUT VOID                        *IpHead,
   1387      OUT UINT8                       *LastHead,
   1388   IN OUT VOID                        **OptionsBuffer,
   1389   IN OUT UINT32                      *OptionsLength,
   1390   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   1391   IN OUT UINT32                      *FragmentCount,
   1392      OUT EFI_IPSEC_SPD_SELECTOR      **SpdSelector,
   1393      OUT EFI_EVENT                   *RecycleEvent
   1394   )
   1395 {
   1396   EFI_STATUS            Status;
   1397   NET_BUF               *Payload;
   1398   UINTN                 EspSize;
   1399   UINTN                 IvSize;
   1400   UINTN                 BlockSize;
   1401   UINTN                 MiscSize;
   1402   UINTN                 PlainPayloadSize;
   1403   UINTN                 PaddingSize;
   1404   UINTN                 IcvSize;
   1405   UINT8                 *ProcessBuffer;
   1406   EFI_ESP_HEADER        *EspHeader;
   1407   EFI_ESP_TAIL          *EspTail;
   1408   EFI_IPSEC_SA_ID       *SaId;
   1409   IPSEC_SAD_DATA        *SadData;
   1410   IPSEC_SAD_ENTRY       *SadEntry;
   1411   IPSEC_RECYCLE_CONTEXT *RecycleContext;
   1412   UINT8                 NextHeader;
   1413   UINT16                IpSecHeadSize;
   1414   UINT8                 *InnerHead;
   1415 
   1416   Status            = EFI_SUCCESS;
   1417   Payload           = NULL;
   1418   ProcessBuffer     = NULL;
   1419   RecycleContext    = NULL;
   1420   *RecycleEvent     = NULL;
   1421   PlainPayloadSize  = 0;
   1422   NextHeader        = 0;
   1423 
   1424   //
   1425   // Build netbuf from fragment table first.
   1426   //
   1427   Payload = NetbufFromExt (
   1428               (NET_FRAGMENT *) *FragmentTable,
   1429               *FragmentCount,
   1430               0,
   1431               sizeof (EFI_ESP_HEADER),
   1432               IpSecOnRecyclePacket,
   1433               NULL
   1434               );
   1435   if (Payload == NULL) {
   1436     Status = EFI_OUT_OF_RESOURCES;
   1437     goto ON_EXIT;
   1438   }
   1439 
   1440   //
   1441   // Get the esp size and esp header from netbuf.
   1442   //
   1443   EspSize   = Payload->TotalSize;
   1444   EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);
   1445 
   1446   if (EspHeader == NULL) {
   1447     Status = EFI_ACCESS_DENIED;
   1448     goto ON_EXIT;
   1449   }
   1450 
   1451   //
   1452   // Parse destination address from ip header and found the related SAD Entry.
   1453   //
   1454   SadEntry = IpSecFoundSadFromInboundPacket (
   1455                IpHead,
   1456                IpVersion,
   1457                NTOHL (EspHeader->Spi)
   1458                );
   1459 
   1460   if (SadEntry == NULL) {
   1461     Status = EFI_ACCESS_DENIED;
   1462     goto ON_EXIT;
   1463   }
   1464 
   1465   SaId    = SadEntry->Id;
   1466   SadData = SadEntry->Data;
   1467 
   1468   //
   1469   // Only support esp protocol currently.
   1470   //
   1471   if (SaId->Proto != EfiIPsecESP) {
   1472     Status = EFI_ACCESS_DENIED;
   1473     goto ON_EXIT;
   1474   }
   1475 
   1476   if (!SadData->ManualSet) {
   1477     //
   1478     // TODO: Check SA lifetime and sequence number
   1479     //
   1480   }
   1481 
   1482   //
   1483   // Allocate buffer for decryption and authentication.
   1484   //
   1485   ProcessBuffer = AllocateZeroPool (EspSize);
   1486   if (ProcessBuffer == NULL) {
   1487     Status = EFI_OUT_OF_RESOURCES;
   1488     goto ON_EXIT;
   1489   }
   1490 
   1491   NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);
   1492 
   1493   //
   1494   // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.
   1495   //
   1496   IcvSize   = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
   1497   IvSize    = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1498   BlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1499 
   1500   //
   1501   // Make sure the ESP packet is not mal-formt.
   1502   // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.
   1503   // 2. Check whether the left payload size is multiple of IvSize.
   1504   //
   1505   MiscSize = sizeof (EFI_ESP_HEADER) + IvSize + IcvSize;
   1506   if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL))) {
   1507     Status = EFI_ACCESS_DENIED;
   1508     goto ON_EXIT;
   1509   }
   1510   if ((EspSize - MiscSize) % BlockSize != 0) {
   1511     Status = EFI_ACCESS_DENIED;
   1512     goto ON_EXIT;
   1513   }
   1514 
   1515   //
   1516   // Authenticate the ESP packet.
   1517   //
   1518   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1519     Status = IpSecEspAuthVerifyPayload (
   1520                ProcessBuffer,
   1521                EspSize,
   1522                SadEntry,
   1523                IcvSize
   1524                );
   1525     if (EFI_ERROR (Status)) {
   1526       goto ON_EXIT;
   1527     }
   1528   }
   1529   //
   1530   // Decrypt the payload by the SAD entry if it has decrypt key.
   1531   //
   1532   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1533     Status = IpSecCryptoIoDecrypt (
   1534                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
   1535                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
   1536                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
   1537                ProcessBuffer + sizeof (EFI_ESP_HEADER),
   1538                ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,
   1539                EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,
   1540                ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize
   1541                );
   1542     if (EFI_ERROR (Status)) {
   1543       goto ON_EXIT;
   1544     }
   1545   }
   1546 
   1547   //
   1548   // Parse EspTail and compute the plain payload size.
   1549   //
   1550   EspTail           = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));
   1551   PaddingSize       = EspTail->PaddingLength;
   1552   NextHeader        = EspTail->NextHeader;
   1553 
   1554   if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL) + PaddingSize)) {
   1555     Status = EFI_ACCESS_DENIED;
   1556     goto ON_EXIT;
   1557   }
   1558   PlainPayloadSize  = EspSize - MiscSize - sizeof (EFI_ESP_TAIL) - PaddingSize;
   1559 
   1560   //
   1561   // TODO: handle anti-replay window
   1562   //
   1563   //
   1564   // Decryption and authentication with esp has been done, so it's time to
   1565   // reload the new packet, create recycle event and fixup ip header.
   1566   //
   1567   RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
   1568   if (RecycleContext == NULL) {
   1569     Status = EFI_OUT_OF_RESOURCES;
   1570     goto ON_EXIT;
   1571   }
   1572 
   1573   Status = gBS->CreateEvent (
   1574                   EVT_NOTIFY_SIGNAL,
   1575                   TPL_NOTIFY,
   1576                   IpSecRecycleCallback,
   1577                   RecycleContext,
   1578                   RecycleEvent
   1579                   );
   1580   if (EFI_ERROR (Status)) {
   1581     goto ON_EXIT;
   1582   }
   1583 
   1584   //
   1585   // The caller will take responsible to handle the original fragment table
   1586   //
   1587   *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
   1588   if (*FragmentTable == NULL) {
   1589     Status = EFI_OUT_OF_RESOURCES;
   1590     goto ON_EXIT;
   1591   }
   1592 
   1593   RecycleContext->PayloadBuffer       = ProcessBuffer;
   1594   RecycleContext->FragmentTable       = *FragmentTable;
   1595 
   1596   //
   1597   // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
   1598   //
   1599   if (SadData->Mode == EfiIPsecTunnel) {
   1600     InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
   1601     IpSecTunnelInboundPacket (
   1602       IpHead,
   1603       InnerHead,
   1604       IpVersion,
   1605       SadData,
   1606       LastHead
   1607       );
   1608 
   1609     if (IpVersion == IP_VERSION_4) {
   1610       (*FragmentTable)[0].FragmentBuffer  = InnerHead ;
   1611       (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1612 
   1613     }else {
   1614       (*FragmentTable)[0].FragmentBuffer  = InnerHead;
   1615       (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1616     }
   1617   } else {
   1618     (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
   1619     (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;
   1620   }
   1621 
   1622   *FragmentCount                      = 1;
   1623 
   1624   //
   1625   // Update the total length field in ip header since processed by esp.
   1626   //
   1627   if (SadData->Mode != EfiIPsecTunnel) {
   1628     if (IpVersion == IP_VERSION_4) {
   1629       ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + PlainPayloadSize));
   1630     } else {
   1631       IpSecHeadSize                              = IpSecGetPlainExtHeadSize (IpHead, LastHead);
   1632       ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));
   1633     }
   1634     //
   1635     // Update the next layer field in ip header since esp header inserted.
   1636     //
   1637     *LastHead = NextHeader;
   1638   }
   1639 
   1640 
   1641   //
   1642   // Update the SPD association of the SAD entry.
   1643   //
   1644   *SpdSelector = SadData->SpdSelector;
   1645 
   1646 ON_EXIT:
   1647   if (Payload != NULL) {
   1648     NetbufFree (Payload);
   1649   }
   1650 
   1651   if (EFI_ERROR (Status)) {
   1652     if (ProcessBuffer != NULL) {
   1653       FreePool (ProcessBuffer);
   1654     }
   1655 
   1656     if (RecycleContext != NULL) {
   1657       FreePool (RecycleContext);
   1658     }
   1659 
   1660     if (*RecycleEvent != NULL) {
   1661       gBS->CloseEvent (*RecycleEvent);
   1662     }
   1663   }
   1664 
   1665   return Status;
   1666 }
   1667 
   1668 /**
   1669   The actual entry to the relative function processes the output traffic using the ESP protocol.
   1670 
   1671   This function is the subfunction of IpSecProtectOutboundPacket(). It protected
   1672   the sending packet by encrypting its payload and inserting ESP header in the orginal
   1673   IP header, then return the IpHeader and IPsec protected Fragmentable.
   1674 
   1675   @param[in]      IpVersion          The version of IP.
   1676   @param[in, out] IpHead             Points to IP header containing the orginal IP header
   1677                                      to be processed on input, and inserted ESP header
   1678                                      on return.
   1679   @param[in, out] LastHead           The Last Header in IP header.
   1680   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   1681   @param[in, out] OptionsLength      Length of the options buffer.
   1682   @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by
   1683                                      IPsec on input, and with IPsec protected
   1684                                      on return.
   1685   @param[in, out] FragmentCount      The number of fragments.
   1686   @param[in]      SadEntry           The related SAD entry.
   1687   @param[out]     RecycleEvent       The event for recycling of resources.
   1688 
   1689   @retval EFI_SUCCESS              The operation was successful.
   1690   @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.
   1691 
   1692 **/
   1693 EFI_STATUS
   1694 IpSecEspOutboundPacket (
   1695   IN UINT8                           IpVersion,
   1696   IN OUT VOID                        *IpHead,
   1697   IN OUT UINT8                       *LastHead,
   1698   IN OUT VOID                        **OptionsBuffer,
   1699   IN OUT UINT32                      *OptionsLength,
   1700   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   1701   IN OUT UINT32                      *FragmentCount,
   1702   IN     IPSEC_SAD_ENTRY             *SadEntry,
   1703      OUT EFI_EVENT                   *RecycleEvent
   1704   )
   1705 {
   1706   EFI_STATUS            Status;
   1707   UINTN                 Index;
   1708   EFI_IPSEC_SA_ID       *SaId;
   1709   IPSEC_SAD_DATA        *SadData;
   1710   IPSEC_RECYCLE_CONTEXT *RecycleContext;
   1711   UINT8                 *ProcessBuffer;
   1712   UINTN                 BytesCopied;
   1713   INTN                  EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4
   1714   UINTN                 EspSize;         // Total size of esp wrapped ip payload
   1715   UINTN                 IvSize;          // Size of IV, optional, might be 0
   1716   UINTN                 PlainPayloadSize;// Original IP payload size
   1717   UINTN                 PaddingSize;     // Size of padding
   1718   UINTN                 EncryptSize;     // Size of data to be encrypted, start after IV and
   1719                                          // stop before ICV
   1720   UINTN                 IcvSize;         // Size of ICV, optional, might be 0
   1721   UINT8                 *RestOfPayload;  // Start of Payload after IV
   1722   UINT8                 *Padding;        // Start address of padding
   1723   EFI_ESP_HEADER        *EspHeader;      // Start address of ESP frame
   1724   EFI_ESP_TAIL          *EspTail;        // Address behind padding
   1725   UINT8                 *InnerHead;
   1726   HASH_DATA_FRAGMENT    HashFragment[1];
   1727 
   1728   Status          = EFI_ACCESS_DENIED;
   1729   SaId            = SadEntry->Id;
   1730   SadData         = SadEntry->Data;
   1731   ProcessBuffer   = NULL;
   1732   RecycleContext  = NULL;
   1733   *RecycleEvent   = NULL;
   1734   InnerHead       = NULL;
   1735 
   1736   if (!SadData->ManualSet &&
   1737       SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&
   1738       SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL
   1739       ) {
   1740     //
   1741     // Invalid manual SAD entry configuration.
   1742     //
   1743     goto ON_EXIT;
   1744   }
   1745 
   1746   //
   1747   // Create OutHeader according to Inner Header
   1748   //
   1749   if (SadData->Mode == EfiIPsecTunnel) {
   1750     InnerHead = IpSecTunnelOutboundPacket (
   1751                   IpHead,
   1752                   IpVersion,
   1753                   SadData,
   1754                   LastHead,
   1755                   OptionsBuffer,
   1756                   OptionsLength,
   1757                   FragmentTable,
   1758                   FragmentCount
   1759                   );
   1760 
   1761     if (InnerHead == NULL) {
   1762       return EFI_INVALID_PARAMETER;
   1763     }
   1764 
   1765   }
   1766 
   1767   //
   1768   // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
   1769   //
   1770   EncryptBlockSize  = 4;
   1771 
   1772   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1773     EncryptBlockSize  = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1774 
   1775     if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {
   1776       goto ON_EXIT;
   1777     }
   1778   }
   1779 
   1780   //
   1781   // Calculate the plain payload size according to the fragment table.
   1782   //
   1783   PlainPayloadSize = 0;
   1784   for (Index = 0; Index < *FragmentCount; Index++) {
   1785     PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;
   1786   }
   1787 
   1788   //
   1789   // Add IPHeader size for Tunnel Mode
   1790   //
   1791   if (SadData->Mode == EfiIPsecTunnel) {
   1792     if (IpVersion == IP_VERSION_4) {
   1793       PlainPayloadSize += sizeof (IP4_HEAD);
   1794     } else {
   1795       PlainPayloadSize += sizeof (EFI_IP6_HEADER);
   1796     }
   1797     //
   1798     // OPtions should be encryption into it
   1799     //
   1800     PlainPayloadSize += *OptionsLength;
   1801   }
   1802 
   1803 
   1804   //
   1805   // Calculate icv size, optional by default and 4 bytes alignment.
   1806   //
   1807   IcvSize = 0;
   1808   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1809     IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
   1810     if (IcvSize % 4 != 0) {
   1811       goto ON_EXIT;
   1812     }
   1813   }
   1814 
   1815   //
   1816   // Calcuate the total size of esp wrapped ip payload.
   1817   //
   1818   IvSize        = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
   1819   EncryptSize   = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;
   1820   PaddingSize   = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);
   1821   EspSize       = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;
   1822 
   1823   ProcessBuffer = AllocateZeroPool (EspSize);
   1824   if (ProcessBuffer == NULL) {
   1825     Status = EFI_OUT_OF_RESOURCES;
   1826     goto ON_EXIT;
   1827   }
   1828 
   1829   //
   1830   // Calculate esp header and esp tail including header, payload and padding.
   1831   //
   1832   EspHeader     = (EFI_ESP_HEADER *) ProcessBuffer;
   1833   RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;
   1834   Padding       = RestOfPayload + PlainPayloadSize;
   1835   EspTail       = (EFI_ESP_TAIL *) (Padding + PaddingSize);
   1836 
   1837   //
   1838   // Fill the sn and spi fields in esp header.
   1839   //
   1840   EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);
   1841   //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
   1842   EspHeader->Spi            = HTONL (SaId->Spi);
   1843 
   1844   //
   1845   // Copy the rest of payload (after iv) from the original fragment buffer.
   1846   //
   1847   BytesCopied = 0;
   1848 
   1849   //
   1850   // For Tunnel Mode
   1851   //
   1852   if (SadData->Mode == EfiIPsecTunnel) {
   1853     if (IpVersion == IP_VERSION_4) {
   1854       //
   1855       // HeadLen, Total Length
   1856       //
   1857       ((IP4_HEAD *)InnerHead)->HeadLen  = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);
   1858       ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);
   1859       ((IP4_HEAD *)InnerHead)->Checksum = 0;
   1860       ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (
   1861                                                   (UINT8 *)InnerHead,
   1862                                                   sizeof(IP4_HEAD)
   1863                                                   ));
   1864       CopyMem (
   1865         RestOfPayload + BytesCopied,
   1866         InnerHead,
   1867         sizeof (IP4_HEAD) + *OptionsLength
   1868         );
   1869       BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;
   1870 
   1871     } else {
   1872     ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));
   1873       CopyMem (
   1874         RestOfPayload + BytesCopied,
   1875         InnerHead,
   1876         sizeof (EFI_IP6_HEADER) + *OptionsLength
   1877         );
   1878       BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;
   1879     }
   1880   }
   1881 
   1882   for (Index = 0; Index < *FragmentCount; Index++) {
   1883     CopyMem (
   1884       (RestOfPayload + BytesCopied),
   1885       (*FragmentTable)[Index].FragmentBuffer,
   1886       (*FragmentTable)[Index].FragmentLength
   1887       );
   1888     BytesCopied += (*FragmentTable)[Index].FragmentLength;
   1889   }
   1890   //
   1891   // Fill the padding buffer by natural number sequence.
   1892   //
   1893   for (Index = 0; Index < PaddingSize; Index++) {
   1894     Padding[Index] = (UINT8) (Index + 1);
   1895   }
   1896   //
   1897   // Fill the padding length and next header fields in esp tail.
   1898   //
   1899   EspTail->PaddingLength  = (UINT8) PaddingSize;
   1900   EspTail->NextHeader     = *LastHead;
   1901 
   1902   //
   1903   // Fill the next header for Tunnel mode.
   1904   //
   1905   if (SadData->Mode == EfiIPsecTunnel) {
   1906     if (IpVersion == IP_VERSION_4) {
   1907       EspTail->NextHeader = 4;
   1908     } else {
   1909       EspTail->NextHeader = 41;
   1910     }
   1911   }
   1912 
   1913   //
   1914   // Generate iv at random by crypt library.
   1915   //
   1916   Status = IpSecGenerateIv (
   1917              (UINT8 *) (EspHeader + 1),
   1918              IvSize
   1919              );
   1920 
   1921 
   1922   if (EFI_ERROR (Status)) {
   1923     goto ON_EXIT;
   1924   }
   1925 
   1926   //
   1927   // Encryption the payload (after iv) by the SAD entry if has encrypt key.
   1928   //
   1929   if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
   1930     Status = IpSecCryptoIoEncrypt (
   1931                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
   1932                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
   1933                SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
   1934                (UINT8 *)(EspHeader + 1),
   1935                RestOfPayload,
   1936                EncryptSize,
   1937                RestOfPayload
   1938                );
   1939 
   1940     if (EFI_ERROR (Status)) {
   1941       goto ON_EXIT;
   1942     }
   1943   }
   1944 
   1945   //
   1946   // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
   1947   //
   1948   if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
   1949 
   1950     HashFragment[0].Data     = ProcessBuffer;
   1951     HashFragment[0].DataSize = EspSize - IcvSize;
   1952     Status = IpSecCryptoIoHmac (
   1953                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
   1954                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
   1955                SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
   1956                HashFragment,
   1957                1,
   1958                ProcessBuffer + EspSize - IcvSize,
   1959                IcvSize
   1960                );
   1961     if (EFI_ERROR (Status)) {
   1962       goto ON_EXIT;
   1963     }
   1964   }
   1965 
   1966   //
   1967   // Encryption and authentication with esp has been done, so it's time to
   1968   // reload the new packet, create recycle event and fixup ip header.
   1969   //
   1970   RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
   1971   if (RecycleContext == NULL) {
   1972     Status = EFI_OUT_OF_RESOURCES;
   1973     goto ON_EXIT;
   1974   }
   1975 
   1976   Status = gBS->CreateEvent (
   1977                   EVT_NOTIFY_SIGNAL,
   1978                   TPL_NOTIFY,
   1979                   IpSecRecycleCallback,
   1980                   RecycleContext,
   1981                   RecycleEvent
   1982                   );
   1983   if (EFI_ERROR (Status)) {
   1984     goto ON_EXIT;
   1985   }
   1986   //
   1987   // Caller take responsible to handle the original fragment table.
   1988   //
   1989   *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
   1990   if (*FragmentTable == NULL) {
   1991     Status = EFI_OUT_OF_RESOURCES;
   1992     goto ON_EXIT;
   1993   }
   1994 
   1995   RecycleContext->FragmentTable       = *FragmentTable;
   1996   RecycleContext->PayloadBuffer       = ProcessBuffer;
   1997   (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer;
   1998   (*FragmentTable)[0].FragmentLength  = (UINT32) EspSize;
   1999   *FragmentCount                      = 1;
   2000 
   2001   //
   2002   // Update the total length field in ip header since processed by esp.
   2003   //
   2004   if (IpVersion == IP_VERSION_4) {
   2005     ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));
   2006   } else {
   2007     ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);
   2008   }
   2009 
   2010   //
   2011   // If tunnel mode, it should change the outer Ip header with tunnel source address
   2012   // and destination tunnel address.
   2013   //
   2014   if (SadData->Mode == EfiIPsecTunnel) {
   2015     if (IpVersion == IP_VERSION_4) {
   2016       CopyMem (
   2017         &((IP4_HEAD *) IpHead)->Src,
   2018         &SadData->TunnelSourceAddress.v4,
   2019         sizeof (EFI_IPv4_ADDRESS)
   2020         );
   2021       CopyMem (
   2022         &((IP4_HEAD *) IpHead)->Dst,
   2023         &SadData->TunnelDestAddress.v4,
   2024         sizeof (EFI_IPv4_ADDRESS)
   2025         );
   2026     } else {
   2027       CopyMem (
   2028         &((EFI_IP6_HEADER *) IpHead)->SourceAddress,
   2029         &SadData->TunnelSourceAddress.v6,
   2030         sizeof (EFI_IPv6_ADDRESS)
   2031         );
   2032       CopyMem (
   2033         &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
   2034         &SadData->TunnelDestAddress.v6,
   2035         sizeof (EFI_IPv6_ADDRESS)
   2036         );
   2037     }
   2038   }
   2039 
   2040   //
   2041   // Update the next layer field in ip header since esp header inserted.
   2042   //
   2043   *LastHead = IPSEC_ESP_PROTOCOL;
   2044 
   2045   //
   2046   // Increase the sn number in SAD entry according to rfc4303.
   2047   //
   2048   SadData->SequenceNumber++;
   2049 
   2050 ON_EXIT:
   2051   if (EFI_ERROR (Status)) {
   2052     if (ProcessBuffer != NULL) {
   2053       FreePool (ProcessBuffer);
   2054     }
   2055 
   2056     if (RecycleContext != NULL) {
   2057       FreePool (RecycleContext);
   2058     }
   2059 
   2060     if (*RecycleEvent != NULL) {
   2061       gBS->CloseEvent (*RecycleEvent);
   2062     }
   2063   }
   2064 
   2065   return Status;
   2066 }
   2067 
   2068 /**
   2069   This function processes the inbound traffic with IPsec.
   2070 
   2071   It checks the received packet security property, trims the ESP/AH header, and then
   2072   returns without an IPsec protected IP Header and FragmentTable.
   2073 
   2074   @param[in]      IpVersion          The version of IP.
   2075   @param[in, out] IpHead             Points to IP header containing the ESP/AH header
   2076                                      to be trimed on input, and without ESP/AH header
   2077                                      on return.
   2078   @param[in, out] LastHead           The Last Header in IP header on return.
   2079   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   2080   @param[in, out] OptionsLength      Length of the options buffer.
   2081   @param[in, out] FragmentTable      Pointer to a list of fragments in form of IPsec
   2082                                      protected on input, and without IPsec protected
   2083                                      on return.
   2084   @param[in, out] FragmentCount      The number of fragments.
   2085   @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.
   2086   @param[out]     RecycleEvent       The event for recycling of resources.
   2087 
   2088   @retval EFI_SUCCESS              The operation was successful.
   2089   @retval EFI_UNSUPPORTED          The IPSEC protocol is not supported.
   2090 
   2091 **/
   2092 EFI_STATUS
   2093 IpSecProtectInboundPacket (
   2094   IN     UINT8                       IpVersion,
   2095   IN OUT VOID                        *IpHead,
   2096   IN OUT UINT8                       *LastHead,
   2097   IN OUT VOID                        **OptionsBuffer,
   2098   IN OUT UINT32                      *OptionsLength,
   2099   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   2100   IN OUT UINT32                      *FragmentCount,
   2101      OUT EFI_IPSEC_SPD_SELECTOR      **SpdEntry,
   2102      OUT EFI_EVENT                   *RecycleEvent
   2103   )
   2104 {
   2105   if (*LastHead == IPSEC_ESP_PROTOCOL) {
   2106     //
   2107     // Process the esp ipsec header of the inbound traffic.
   2108     //
   2109     return IpSecEspInboundPacket (
   2110              IpVersion,
   2111              IpHead,
   2112              LastHead,
   2113              OptionsBuffer,
   2114              OptionsLength,
   2115              FragmentTable,
   2116              FragmentCount,
   2117              SpdEntry,
   2118              RecycleEvent
   2119              );
   2120   }
   2121   //
   2122   // The other protocols are not supported.
   2123   //
   2124   return EFI_UNSUPPORTED;
   2125 }
   2126 
   2127 /**
   2128   This fucntion processes the output traffic with IPsec.
   2129 
   2130   It protected the sending packet by encrypting it payload and inserting ESP/AH header
   2131   in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
   2132 
   2133   @param[in]      IpVersion          The version of IP.
   2134   @param[in, out] IpHead             Point to IP header containing the orginal IP header
   2135                                      to be processed on input, and inserted ESP/AH header
   2136                                      on return.
   2137   @param[in, out] LastHead           The Last Header in IP header.
   2138   @param[in, out] OptionsBuffer      Pointer to the options buffer.
   2139   @param[in, out] OptionsLength      Length of the options buffer.
   2140   @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by
   2141                                      IPsec on input, and with IPsec protected
   2142                                      on return.
   2143   @param[in, out] FragmentCount      Number of fragments.
   2144   @param[in]      SadEntry           Related SAD entry.
   2145   @param[out]     RecycleEvent       Event for recycling of resources.
   2146 
   2147   @retval EFI_SUCCESS              The operation is successful.
   2148   @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.
   2149 
   2150 **/
   2151 EFI_STATUS
   2152 IpSecProtectOutboundPacket (
   2153   IN     UINT8                       IpVersion,
   2154   IN OUT VOID                        *IpHead,
   2155   IN OUT UINT8                       *LastHead,
   2156   IN OUT VOID                        **OptionsBuffer,
   2157   IN OUT UINT32                      *OptionsLength,
   2158   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,
   2159   IN OUT UINT32                      *FragmentCount,
   2160   IN     IPSEC_SAD_ENTRY             *SadEntry,
   2161      OUT EFI_EVENT                   *RecycleEvent
   2162   )
   2163 {
   2164   if (SadEntry->Id->Proto == EfiIPsecESP) {
   2165     //
   2166     // Process the esp ipsec header of the outbound traffic.
   2167     //
   2168     return IpSecEspOutboundPacket (
   2169              IpVersion,
   2170              IpHead,
   2171              LastHead,
   2172              OptionsBuffer,
   2173              OptionsLength,
   2174              FragmentTable,
   2175              FragmentCount,
   2176              SadEntry,
   2177              RecycleEvent
   2178              );
   2179   }
   2180   //
   2181   // The other protocols are not supported.
   2182   //
   2183   return EFI_UNSUPPORTED;
   2184 }
   2185