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