mirror of https://github.com/acidanthera/audk.git
243 lines
7.6 KiB
C
243 lines
7.6 KiB
C
/** @file
|
|
The mian interface of IPsec Protocol.
|
|
|
|
Copyright (c) 2009 - 2018, 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;
|
|
}
|
|
|