Signed-off-by: qianouyang Reviewed-by: jjin9 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11714 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			243 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The mian interface of IPsec Protocol.
 | |
| 
 | |
|   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "IpSecConfigImpl.h"
 | |
| #include "IpSecImpl.h"
 | |
| 
 | |
| EFI_IPSEC2_PROTOCOL  mIpSecInstance = { IpSecProcess, NULL, TRUE };
 | |
| 
 | |
| /**
 | |
|   Handles IPsec packet processing for inbound and outbound IP packets.
 | |
| 
 | |
|   The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.
 | |
|   The behavior is that it can perform one of the following actions:
 | |
|   bypass the packet, discard the packet, or protect the packet.
 | |
| 
 | |
|   @param[in]      This             Pointer to the EFI_IPSEC2_PROTOCOL instance.
 | |
|   @param[in]      NicHandle        Instance of the network interface.
 | |
|   @param[in]      IpVersion        IPV4 or IPV6.
 | |
|   @param[in, out] IpHead           Pointer to the IP Header.
 | |
|   @param[in, out] LastHead         The protocol of the next layer to be processed by IPsec.
 | |
|   @param[in, out] OptionsBuffer    Pointer to the options buffer.
 | |
|   @param[in, out] OptionsLength    Length of the options buffer.
 | |
|   @param[in, out] FragmentTable    Pointer to a list of fragments.
 | |
|   @param[in, out] FragmentCount    Number of fragments.
 | |
|   @param[in]      TrafficDirection Traffic direction.
 | |
|   @param[out]     RecycleSignal    Event for recycling of resources.
 | |
| 
 | |
|   @retval EFI_SUCCESS              The packet was bypassed and all buffers remain the same.
 | |
|   @retval EFI_SUCCESS              The packet was protected.
 | |
|   @retval EFI_ACCESS_DENIED        The packet was discarded.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpSecProcess (
 | |
|   IN     EFI_IPSEC2_PROTOCOL             *This,
 | |
|   IN     EFI_HANDLE                      NicHandle,
 | |
|   IN     UINT8                           IpVersion,
 | |
|   IN OUT VOID                            *IpHead,
 | |
|   IN OUT UINT8                           *LastHead,
 | |
|   IN OUT VOID                            **OptionsBuffer,
 | |
|   IN OUT UINT32                          *OptionsLength,
 | |
|   IN OUT EFI_IPSEC_FRAGMENT_DATA         **FragmentTable,
 | |
|   IN OUT UINT32                          *FragmentCount,
 | |
|   IN     EFI_IPSEC_TRAFFIC_DIR           TrafficDirection,
 | |
|      OUT EFI_EVENT                       *RecycleSignal
 | |
|   )
 | |
| {
 | |
|   IPSEC_PRIVATE_DATA     *Private;
 | |
|   IPSEC_SPD_ENTRY        *SpdEntry;
 | |
|   EFI_IPSEC_SPD_SELECTOR *SpdSelector;
 | |
|   IPSEC_SAD_ENTRY        *SadEntry;
 | |
|   LIST_ENTRY             *SpdList;
 | |
|   LIST_ENTRY             *Entry;
 | |
|   EFI_IPSEC_ACTION       Action;
 | |
|   EFI_STATUS             Status;
 | |
|   UINT8                  *IpPayload;
 | |
|   UINT8                  OldLastHead;
 | |
|   BOOLEAN                IsOutbound;
 | |
| 
 | |
|   if (OptionsBuffer == NULL || 
 | |
|       OptionsLength == NULL || 
 | |
|       FragmentTable == NULL || 
 | |
|       FragmentCount == NULL
 | |
|       ) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   Private         = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);
 | |
|   IpPayload       = (*FragmentTable)[0].FragmentBuffer;
 | |
|   IsOutbound      = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);
 | |
|   OldLastHead     = *LastHead;
 | |
|   *RecycleSignal  = NULL;
 | |
|   SpdList         = &mConfigData[IPsecConfigDataTypeSpd];
 | |
|   
 | |
|   if (!IsOutbound) {
 | |
|     //
 | |
|     // For inbound traffic, process the ipsec header of the packet.
 | |
|     //
 | |
|     Status = IpSecProtectInboundPacket (
 | |
|               IpVersion,
 | |
|               IpHead,
 | |
|               LastHead,
 | |
|               OptionsBuffer,
 | |
|               OptionsLength,
 | |
|               FragmentTable,
 | |
|               FragmentCount,
 | |
|               &SpdSelector,
 | |
|               RecycleSignal
 | |
|               );
 | |
| 
 | |
|     if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) {
 | |
|       //
 | |
|       // The packet is denied to access.
 | |
|       //
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     if (Status == EFI_SUCCESS) {
 | |
|       
 | |
|       //
 | |
|       // Check the spd entry if the packet is accessible.
 | |
|       //
 | |
|       if (SpdSelector == NULL) {
 | |
|         Status = EFI_ACCESS_DENIED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
| 
 | |
|       Status =  EFI_ACCESS_DENIED;
 | |
|       NET_LIST_FOR_EACH (Entry, SpdList) {
 | |
|         SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
 | |
|         if (IsSubSpdSelector (               
 | |
|               (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector,
 | |
|               (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
 | |
|               )) {
 | |
|           Status = EFI_SUCCESS;
 | |
|         }
 | |
|       }      
 | |
|       goto ON_EXIT;
 | |
|     }       
 | |
|   }
 | |
| 
 | |
|   Status  = EFI_ACCESS_DENIED;  
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Entry, SpdList) {
 | |
|     //
 | |
|     // For outbound and non-ipsec Inbound traffic: check the spd entry.
 | |
|     //
 | |
|     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
 | |
| 
 | |
|     if (EFI_ERROR (IpSecLookupSpdEntry (
 | |
|                      SpdEntry,
 | |
|                      IpVersion,
 | |
|                      IpHead,
 | |
|                      IpPayload,
 | |
|                      OldLastHead,
 | |
|                      IsOutbound, 
 | |
|                      &Action
 | |
|                      ))) {
 | |
|       //
 | |
|       // If the related SPD not find
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     switch (Action) {
 | |
| 
 | |
|     case EfiIPsecActionProtect:
 | |
| 
 | |
|       if (IsOutbound) {
 | |
|         //
 | |
|         // For outbound traffic, lookup the sad entry.
 | |
|         //
 | |
|         Status = IpSecLookupSadEntry (
 | |
|                    Private,
 | |
|                    NicHandle,
 | |
|                    IpVersion,
 | |
|                    IpHead,
 | |
|                    IpPayload,
 | |
|                    OldLastHead,
 | |
|                    SpdEntry,
 | |
|                    &SadEntry
 | |
|                    );
 | |
| 
 | |
|         if (SadEntry != NULL) {
 | |
|           //
 | |
|           // Process the packet by the found sad entry.
 | |
|           //
 | |
|           Status = IpSecProtectOutboundPacket (
 | |
|                     IpVersion,
 | |
|                     IpHead,
 | |
|                     LastHead,
 | |
|                     OptionsBuffer,
 | |
|                     OptionsLength,
 | |
|                     FragmentTable,
 | |
|                     FragmentCount,
 | |
|                     SadEntry,
 | |
|                     RecycleSignal
 | |
|                     );
 | |
| 
 | |
|         } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
 | |
|           //
 | |
|           // TODO: if no need return not ready to upper layer, change here.
 | |
|           //
 | |
|           Status = EFI_SUCCESS;
 | |
|         }
 | |
|       } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
 | |
|         //
 | |
|         // For inbound icmpv6 traffic except ping request, accept the packet
 | |
|         // although no sad entry associated with protect spd entry.
 | |
|         //
 | |
|         Status = IpSecLookupSadEntry (
 | |
|                    Private,
 | |
|                    NicHandle,
 | |
|                    IpVersion,
 | |
|                    IpHead,
 | |
|                    IpPayload,
 | |
|                    OldLastHead,
 | |
|                    SpdEntry,
 | |
|                    &SadEntry
 | |
|                    );
 | |
|         if (SadEntry == NULL) {
 | |
|           Status = EFI_SUCCESS;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       goto ON_EXIT;
 | |
| 
 | |
|     case EfiIPsecActionBypass:
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto ON_EXIT;
 | |
| 
 | |
|     case EfiIPsecActionDiscard:
 | |
|       goto ON_EXIT;   
 | |
|     }
 | |
|   }
 | |
|    
 | |
|   //
 | |
|   // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it.
 | |
|   // But it the packet is NS/NA, it should be by passed even not find the related SPD entry.
 | |
|   //
 | |
|   if (OldLastHead == IP6_ICMP && 
 | |
|       (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE)
 | |
|       ){
 | |
|     Status = EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
| ON_EXIT:
 | |
|   return Status;
 | |
| }
 | |
| 
 |