Home | History | Annotate | Download | only in IpSecDxe
      1 /** @file
      2   The mian interface of IPsec Protocol.
      3 
      4   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "IpSecConfigImpl.h"
     17 #include "IpSecImpl.h"
     18 
     19 EFI_IPSEC2_PROTOCOL  mIpSecInstance = { IpSecProcess, NULL, TRUE };
     20 
     21 /**
     22   Handles IPsec packet processing for inbound and outbound IP packets.
     23 
     24   The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.
     25   The behavior is that it can perform one of the following actions:
     26   bypass the packet, discard the packet, or protect the packet.
     27 
     28   @param[in]      This             Pointer to the EFI_IPSEC2_PROTOCOL instance.
     29   @param[in]      NicHandle        Instance of the network interface.
     30   @param[in]      IpVersion        IPV4 or IPV6.
     31   @param[in, out] IpHead           Pointer to the IP Header.
     32   @param[in, out] LastHead         The protocol of the next layer to be processed by IPsec.
     33   @param[in, out] OptionsBuffer    Pointer to the options buffer.
     34   @param[in, out] OptionsLength    Length of the options buffer.
     35   @param[in, out] FragmentTable    Pointer to a list of fragments.
     36   @param[in, out] FragmentCount    Number of fragments.
     37   @param[in]      TrafficDirection Traffic direction.
     38   @param[out]     RecycleSignal    Event for recycling of resources.
     39 
     40   @retval EFI_SUCCESS              The packet was bypassed and all buffers remain the same.
     41   @retval EFI_SUCCESS              The packet was protected.
     42   @retval EFI_ACCESS_DENIED        The packet was discarded.
     43 
     44 **/
     45 EFI_STATUS
     46 EFIAPI
     47 IpSecProcess (
     48   IN     EFI_IPSEC2_PROTOCOL             *This,
     49   IN     EFI_HANDLE                      NicHandle,
     50   IN     UINT8                           IpVersion,
     51   IN OUT VOID                            *IpHead,
     52   IN OUT UINT8                           *LastHead,
     53   IN OUT VOID                            **OptionsBuffer,
     54   IN OUT UINT32                          *OptionsLength,
     55   IN OUT EFI_IPSEC_FRAGMENT_DATA         **FragmentTable,
     56   IN OUT UINT32                          *FragmentCount,
     57   IN     EFI_IPSEC_TRAFFIC_DIR           TrafficDirection,
     58      OUT EFI_EVENT                       *RecycleSignal
     59   )
     60 {
     61   IPSEC_PRIVATE_DATA     *Private;
     62   IPSEC_SPD_ENTRY        *SpdEntry;
     63   EFI_IPSEC_SPD_SELECTOR *SpdSelector;
     64   IPSEC_SAD_ENTRY        *SadEntry;
     65   LIST_ENTRY             *SpdList;
     66   LIST_ENTRY             *Entry;
     67   EFI_IPSEC_ACTION       Action;
     68   EFI_STATUS             Status;
     69   UINT8                  *IpPayload;
     70   UINT8                  OldLastHead;
     71   BOOLEAN                IsOutbound;
     72 
     73   if (OptionsBuffer == NULL ||
     74       OptionsLength == NULL ||
     75       FragmentTable == NULL ||
     76       FragmentCount == NULL
     77       ) {
     78     return EFI_INVALID_PARAMETER;
     79   }
     80   Private         = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);
     81   IpPayload       = (*FragmentTable)[0].FragmentBuffer;
     82   IsOutbound      = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);
     83   OldLastHead     = *LastHead;
     84   *RecycleSignal  = NULL;
     85   SpdList         = &mConfigData[IPsecConfigDataTypeSpd];
     86 
     87   if (!IsOutbound) {
     88     //
     89     // For inbound traffic, process the ipsec header of the packet.
     90     //
     91     Status = IpSecProtectInboundPacket (
     92               IpVersion,
     93               IpHead,
     94               LastHead,
     95               OptionsBuffer,
     96               OptionsLength,
     97               FragmentTable,
     98               FragmentCount,
     99               &SpdSelector,
    100               RecycleSignal
    101               );
    102 
    103     if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) {
    104       //
    105       // The packet is denied to access.
    106       //
    107       goto ON_EXIT;
    108     }
    109 
    110     if (Status == EFI_SUCCESS) {
    111 
    112       //
    113       // Check the spd entry if the packet is accessible.
    114       //
    115       if (SpdSelector == NULL) {
    116         Status = EFI_ACCESS_DENIED;
    117         goto ON_EXIT;
    118       }
    119 
    120       Status =  EFI_ACCESS_DENIED;
    121       NET_LIST_FOR_EACH (Entry, SpdList) {
    122         SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
    123         if (IsSubSpdSelector (
    124               (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector,
    125               (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
    126               )) {
    127           Status = EFI_SUCCESS;
    128         }
    129       }
    130       goto ON_EXIT;
    131     }
    132   }
    133 
    134   Status  = EFI_ACCESS_DENIED;
    135 
    136   NET_LIST_FOR_EACH (Entry, SpdList) {
    137     //
    138     // For outbound and non-ipsec Inbound traffic: check the spd entry.
    139     //
    140     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
    141 
    142     if (EFI_ERROR (IpSecLookupSpdEntry (
    143                      SpdEntry,
    144                      IpVersion,
    145                      IpHead,
    146                      IpPayload,
    147                      OldLastHead,
    148                      IsOutbound,
    149                      &Action
    150                      ))) {
    151       //
    152       // If the related SPD not find
    153       //
    154       continue;
    155     }
    156 
    157     switch (Action) {
    158 
    159     case EfiIPsecActionProtect:
    160 
    161       if (IsOutbound) {
    162         //
    163         // For outbound traffic, lookup the sad entry.
    164         //
    165         Status = IpSecLookupSadEntry (
    166                    Private,
    167                    NicHandle,
    168                    IpVersion,
    169                    IpHead,
    170                    IpPayload,
    171                    OldLastHead,
    172                    SpdEntry,
    173                    &SadEntry
    174                    );
    175 
    176         if (SadEntry != NULL) {
    177           //
    178           // Process the packet by the found sad entry.
    179           //
    180           Status = IpSecProtectOutboundPacket (
    181                     IpVersion,
    182                     IpHead,
    183                     LastHead,
    184                     OptionsBuffer,
    185                     OptionsLength,
    186                     FragmentTable,
    187                     FragmentCount,
    188                     SadEntry,
    189                     RecycleSignal
    190                     );
    191 
    192         } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
    193           //
    194           // TODO: if no need return not ready to upper layer, change here.
    195           //
    196           Status = EFI_SUCCESS;
    197         }
    198       } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
    199         //
    200         // For inbound icmpv6 traffic except ping request, accept the packet
    201         // although no sad entry associated with protect spd entry.
    202         //
    203         Status = IpSecLookupSadEntry (
    204                    Private,
    205                    NicHandle,
    206                    IpVersion,
    207                    IpHead,
    208                    IpPayload,
    209                    OldLastHead,
    210                    SpdEntry,
    211                    &SadEntry
    212                    );
    213         if (SadEntry == NULL) {
    214           Status = EFI_SUCCESS;
    215         }
    216       }
    217 
    218       goto ON_EXIT;
    219 
    220     case EfiIPsecActionBypass:
    221       Status = EFI_SUCCESS;
    222       goto ON_EXIT;
    223 
    224     case EfiIPsecActionDiscard:
    225       goto ON_EXIT;
    226     }
    227   }
    228 
    229   //
    230   // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it.
    231   // But it the packet is NS/NA, it should be by passed even not find the related SPD entry.
    232   //
    233   if (OldLastHead == IP6_ICMP &&
    234       (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE)
    235       ){
    236     Status = EFI_SUCCESS;
    237   }
    238 
    239 ON_EXIT:
    240   return Status;
    241 }
    242 
    243