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
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)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