]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IpSecDxe/IpSecMain.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecMain.c
1 /** @file
2 The mian interface of IPsec Protocol.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "IpSecConfigImpl.h"
11 #include "IpSecImpl.h"
12
13 EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE };
14
15 /**
16 Handles IPsec packet processing for inbound and outbound IP packets.
17
18 The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.
19 The behavior is that it can perform one of the following actions:
20 bypass the packet, discard the packet, or protect the packet.
21
22 @param[in] This Pointer to the EFI_IPSEC2_PROTOCOL instance.
23 @param[in] NicHandle Instance of the network interface.
24 @param[in] IpVersion IPV4 or IPV6.
25 @param[in, out] IpHead Pointer to the IP Header.
26 @param[in, out] LastHead The protocol of the next layer to be processed by IPsec.
27 @param[in, out] OptionsBuffer Pointer to the options buffer.
28 @param[in, out] OptionsLength Length of the options buffer.
29 @param[in, out] FragmentTable Pointer to a list of fragments.
30 @param[in, out] FragmentCount Number of fragments.
31 @param[in] TrafficDirection Traffic direction.
32 @param[out] RecycleSignal Event for recycling of resources.
33
34 @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.
35 @retval EFI_SUCCESS The packet was protected.
36 @retval EFI_ACCESS_DENIED The packet was discarded.
37
38 **/
39 EFI_STATUS
40 EFIAPI
41 IpSecProcess (
42 IN EFI_IPSEC2_PROTOCOL *This,
43 IN EFI_HANDLE NicHandle,
44 IN UINT8 IpVersion,
45 IN OUT VOID *IpHead,
46 IN OUT UINT8 *LastHead,
47 IN OUT VOID **OptionsBuffer,
48 IN OUT UINT32 *OptionsLength,
49 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
50 IN OUT UINT32 *FragmentCount,
51 IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection,
52 OUT EFI_EVENT *RecycleSignal
53 )
54 {
55 IPSEC_PRIVATE_DATA *Private;
56 IPSEC_SPD_ENTRY *SpdEntry;
57 EFI_IPSEC_SPD_SELECTOR *SpdSelector;
58 IPSEC_SAD_ENTRY *SadEntry;
59 LIST_ENTRY *SpdList;
60 LIST_ENTRY *Entry;
61 EFI_IPSEC_ACTION Action;
62 EFI_STATUS Status;
63 UINT8 *IpPayload;
64 UINT8 OldLastHead;
65 BOOLEAN IsOutbound;
66
67 if (OptionsBuffer == NULL ||
68 OptionsLength == NULL ||
69 FragmentTable == NULL ||
70 FragmentCount == NULL
71 ) {
72 return EFI_INVALID_PARAMETER;
73 }
74 Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);
75 IpPayload = (*FragmentTable)[0].FragmentBuffer;
76 IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);
77 OldLastHead = *LastHead;
78 *RecycleSignal = NULL;
79 SpdList = &mConfigData[IPsecConfigDataTypeSpd];
80
81 if (!IsOutbound) {
82 //
83 // For inbound traffic, process the ipsec header of the packet.
84 //
85 Status = IpSecProtectInboundPacket (
86 IpVersion,
87 IpHead,
88 LastHead,
89 OptionsBuffer,
90 OptionsLength,
91 FragmentTable,
92 FragmentCount,
93 &SpdSelector,
94 RecycleSignal
95 );
96
97 if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) {
98 //
99 // The packet is denied to access.
100 //
101 goto ON_EXIT;
102 }
103
104 if (Status == EFI_SUCCESS) {
105
106 //
107 // Check the spd entry if the packet is accessible.
108 //
109 if (SpdSelector == NULL) {
110 Status = EFI_ACCESS_DENIED;
111 goto ON_EXIT;
112 }
113
114 Status = EFI_ACCESS_DENIED;
115 NET_LIST_FOR_EACH (Entry, SpdList) {
116 SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
117 if (IsSubSpdSelector (
118 (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector,
119 (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
120 )) {
121 Status = EFI_SUCCESS;
122 }
123 }
124 goto ON_EXIT;
125 }
126 }
127
128 Status = EFI_ACCESS_DENIED;
129
130 NET_LIST_FOR_EACH (Entry, SpdList) {
131 //
132 // For outbound and non-ipsec Inbound traffic: check the spd entry.
133 //
134 SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
135
136 if (EFI_ERROR (IpSecLookupSpdEntry (
137 SpdEntry,
138 IpVersion,
139 IpHead,
140 IpPayload,
141 OldLastHead,
142 IsOutbound,
143 &Action
144 ))) {
145 //
146 // If the related SPD not find
147 //
148 continue;
149 }
150
151 switch (Action) {
152
153 case EfiIPsecActionProtect:
154
155 if (IsOutbound) {
156 //
157 // For outbound traffic, lookup the sad entry.
158 //
159 Status = IpSecLookupSadEntry (
160 Private,
161 NicHandle,
162 IpVersion,
163 IpHead,
164 IpPayload,
165 OldLastHead,
166 SpdEntry,
167 &SadEntry
168 );
169
170 if (SadEntry != NULL) {
171 //
172 // Process the packet by the found sad entry.
173 //
174 Status = IpSecProtectOutboundPacket (
175 IpVersion,
176 IpHead,
177 LastHead,
178 OptionsBuffer,
179 OptionsLength,
180 FragmentTable,
181 FragmentCount,
182 SadEntry,
183 RecycleSignal
184 );
185
186 } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
187 //
188 // TODO: if no need return not ready to upper layer, change here.
189 //
190 Status = EFI_SUCCESS;
191 }
192 } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
193 //
194 // For inbound icmpv6 traffic except ping request, accept the packet
195 // although no sad entry associated with protect spd entry.
196 //
197 Status = IpSecLookupSadEntry (
198 Private,
199 NicHandle,
200 IpVersion,
201 IpHead,
202 IpPayload,
203 OldLastHead,
204 SpdEntry,
205 &SadEntry
206 );
207 if (SadEntry == NULL) {
208 Status = EFI_SUCCESS;
209 }
210 }
211
212 goto ON_EXIT;
213
214 case EfiIPsecActionBypass:
215 Status = EFI_SUCCESS;
216 goto ON_EXIT;
217
218 case EfiIPsecActionDiscard:
219 goto ON_EXIT;
220 }
221 }
222
223 //
224 // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it.
225 // But it the packet is NS/NA, it should be by passed even not find the related SPD entry.
226 //
227 if (OldLastHead == IP6_ICMP &&
228 (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE)
229 ){
230 Status = EFI_SUCCESS;
231 }
232
233 ON_EXIT:
234 return Status;
235 }
236