summaryrefslogtreecommitdiff
path: root/Core/NetworkPkg/IpSecDxe/IpSecMain.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/NetworkPkg/IpSecDxe/IpSecMain.c')
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecMain.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecMain.c b/Core/NetworkPkg/IpSecDxe/IpSecMain.c
new file mode 100644
index 0000000000..a2fefa70d7
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecMain.c
@@ -0,0 +1,242 @@
+/** @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;
+}
+