]>
Commit | Line | Data |
---|---|---|
a3bcde70 HT |
1 | /** @file\r |
2 | The implementation of IPsec Protocol\r | |
3 | \r | |
4 | Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r | |
5 | \r | |
6 | This program and the accompanying materials\r | |
7 | are licensed and made available under the terms and conditions of the BSD License\r | |
8 | which accompanies this distribution. The full text of the license may be found at\r | |
9 | http://opensource.org/licenses/bsd-license.php.\r | |
10 | \r | |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
13 | \r | |
14 | **/\r | |
15 | \r | |
16 | #include "IpSecConfigImpl.h"\r | |
17 | \r | |
68d3f2fb | 18 | EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE };\r |
a3bcde70 HT |
19 | \r |
20 | extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum];\r | |
21 | \r | |
22 | /**\r | |
23 | Check if the specified Address is the Valid Address Range.\r | |
24 | \r | |
25 | This function checks if the bytes after prefixed length are all Zero in this\r | |
26 | Address. This Address is supposed to point to a range address, meaning it only\r | |
27 | gives the correct prefixed address.\r | |
28 | \r | |
29 | @param[in] IpVersion The IP version.\r | |
30 | @param[in] Address Points to EFI_IP_ADDRESS to be checked.\r | |
31 | @param[in] PrefixLength The PrefixeLength of this address.\r | |
32 | \r | |
33 | @retval TRUE The address is a vaild address range.\r | |
34 | @retval FALSE The address is not a vaild address range.\r | |
35 | \r | |
36 | **/\r | |
37 | BOOLEAN\r | |
38 | IpSecValidAddressRange (\r | |
39 | IN UINT8 IpVersion,\r | |
40 | IN EFI_IP_ADDRESS *Address,\r | |
41 | IN UINT8 PrefixLength\r | |
42 | )\r | |
43 | {\r | |
44 | UINT8 Div;\r | |
45 | UINT8 Mod;\r | |
46 | UINT8 Mask;\r | |
47 | UINT8 AddrLen;\r | |
48 | UINT8 *Addr;\r | |
49 | EFI_IP_ADDRESS ZeroAddr;\r | |
50 | \r | |
51 | if (PrefixLength == 0) {\r | |
52 | return TRUE;\r | |
53 | }\r | |
54 | \r | |
55 | AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);\r | |
56 | \r | |
57 | if (AddrLen <= PrefixLength) {\r | |
58 | return FALSE;\r | |
59 | }\r | |
60 | \r | |
61 | Div = (UINT8) (PrefixLength / 8);\r | |
62 | Mod = (UINT8) (PrefixLength % 8);\r | |
63 | Addr = (UINT8 *) Address;\r | |
64 | ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));\r | |
65 | \r | |
66 | //\r | |
67 | // Check whether the mod part of host scope is zero or not.\r | |
68 | //\r | |
69 | if (Mod > 0) {\r | |
70 | Mask = (UINT8) (0xFF << (8 - Mod));\r | |
71 | \r | |
72 | if ((Addr[Div] | Mask) != Mask) {\r | |
73 | return FALSE;\r | |
74 | }\r | |
75 | \r | |
76 | Div++;\r | |
77 | }\r | |
78 | //\r | |
79 | // Check whether the div part of host scope is zero or not.\r | |
80 | //\r | |
81 | if (CompareMem (\r | |
82 | &Addr[Div],\r | |
83 | &ZeroAddr,\r | |
84 | sizeof (EFI_IP_ADDRESS) - Div\r | |
85 | ) != 0) {\r | |
86 | return FALSE;\r | |
87 | }\r | |
88 | \r | |
89 | return TRUE;\r | |
90 | }\r | |
91 | \r | |
92 | /**\r | |
93 | Extrct the Address Range from a Address.\r | |
94 | \r | |
95 | This function keep the prefix address and zero other part address.\r | |
96 | \r | |
97 | @param[in] Address Point to a specified address.\r | |
98 | @param[in] PrefixLength The prefix length.\r | |
99 | @param[out] Range Contain the return Address Range.\r | |
100 | \r | |
101 | **/\r | |
102 | VOID\r | |
103 | IpSecExtractAddressRange (\r | |
104 | IN EFI_IP_ADDRESS *Address,\r | |
105 | IN UINT8 PrefixLength,\r | |
106 | OUT EFI_IP_ADDRESS *Range\r | |
107 | )\r | |
108 | {\r | |
109 | UINT8 Div;\r | |
110 | UINT8 Mod;\r | |
111 | UINT8 Mask;\r | |
112 | UINT8 *Addr;\r | |
113 | \r | |
114 | if (PrefixLength == 0) {\r | |
115 | return ;\r | |
116 | }\r | |
117 | \r | |
118 | Div = (UINT8) (PrefixLength / 8);\r | |
119 | Mod = (UINT8) (PrefixLength % 8);\r | |
120 | Addr = (UINT8 *) Range;\r | |
121 | \r | |
122 | CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));\r | |
123 | \r | |
124 | //\r | |
125 | // Zero the mod part of host scope.\r | |
126 | //\r | |
127 | if (Mod > 0) {\r | |
128 | Mask = (UINT8) (0xFF << (8 - Mod));\r | |
129 | Addr[Div] = (UINT8) (Addr[Div] & Mask);\r | |
130 | Div++;\r | |
131 | }\r | |
132 | //\r | |
133 | // Zero the div part of host scope.\r | |
134 | //\r | |
135 | ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);\r | |
136 | \r | |
137 | }\r | |
138 | \r | |
139 | /**\r | |
140 | Checks if the IP Address in the address range of AddressInfos specified.\r | |
141 | \r | |
142 | @param[in] IpVersion The IP version.\r | |
143 | @param[in] IpAddr Point to EFI_IP_ADDRESS to be check.\r | |
144 | @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check\r | |
145 | the IP Address is matched.\r | |
146 | @param[in] AddressCount The total numbers of the AddressInfo.\r | |
147 | \r | |
148 | @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified.\r | |
149 | @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified.\r | |
150 | \r | |
151 | **/\r | |
152 | BOOLEAN\r | |
153 | IpSecMatchIpAddress (\r | |
154 | IN UINT8 IpVersion,\r | |
155 | IN EFI_IP_ADDRESS *IpAddr,\r | |
156 | IN EFI_IP_ADDRESS_INFO *AddressInfo,\r | |
157 | IN UINT32 AddressCount\r | |
158 | )\r | |
159 | {\r | |
160 | EFI_IP_ADDRESS Range;\r | |
161 | UINT32 Index;\r | |
162 | BOOLEAN IsMatch;\r | |
163 | \r | |
164 | IsMatch = FALSE;\r | |
165 | \r | |
166 | for (Index = 0; Index < AddressCount; Index++) {\r | |
167 | //\r | |
168 | // Check whether the target address is in the address range\r | |
169 | // if it's a valid range of address.\r | |
170 | //\r | |
171 | if (IpSecValidAddressRange (\r | |
172 | IpVersion,\r | |
173 | &AddressInfo[Index].Address,\r | |
174 | AddressInfo[Index].PrefixLength\r | |
175 | )) {\r | |
176 | //\r | |
177 | // Get the range of the target address belongs to.\r | |
178 | //\r | |
179 | ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));\r | |
180 | IpSecExtractAddressRange (\r | |
181 | IpAddr,\r | |
182 | AddressInfo[Index].PrefixLength,\r | |
183 | &Range\r | |
184 | );\r | |
185 | \r | |
186 | if (CompareMem (\r | |
187 | &Range,\r | |
188 | &AddressInfo[Index].Address,\r | |
189 | sizeof (EFI_IP_ADDRESS)\r | |
190 | ) == 0) {\r | |
191 | //\r | |
192 | // The target address is in the address range.\r | |
193 | //\r | |
194 | IsMatch = TRUE;\r | |
195 | break;\r | |
196 | }\r | |
197 | }\r | |
198 | \r | |
199 | if (CompareMem (\r | |
200 | IpAddr,\r | |
201 | &AddressInfo[Index].Address,\r | |
202 | sizeof (EFI_IP_ADDRESS)\r | |
203 | ) == 0) {\r | |
204 | //\r | |
205 | // The target address is exact same as the address.\r | |
206 | //\r | |
207 | IsMatch = TRUE;\r | |
208 | break;\r | |
209 | }\r | |
210 | }\r | |
211 | \r | |
212 | return IsMatch;\r | |
213 | }\r | |
214 | \r | |
215 | /**\r | |
216 | Check if the specified Protocol and Prot is supported by the specified SPD Entry.\r | |
217 | \r | |
218 | This function is the subfunction of IPsecLookUpSpdEntry() that is used to\r | |
219 | check if the sent/received IKE packet has the related SPD entry support.\r | |
220 | \r | |
221 | @param[in] Protocol The Protocol to be checked.\r | |
222 | @param[in] IpPayload Point to IP Payload to be check.\r | |
223 | @param[in] SpdProtocol The Protocol supported by SPD.\r | |
224 | @param[in] SpdLocalPort The Local Port in SPD.\r | |
225 | @param[in] SpdRemotePort The Remote Port in SPD.\r | |
226 | @param[in] IsOutbound Flag to indicate the is for IKE Packet sending or recieving.\r | |
227 | \r | |
228 | @retval TRUE The Protocol and Port are supported by the SPD Entry.\r | |
229 | @retval FALSE The Protocol and Port are not supported by the SPD Entry.\r | |
230 | \r | |
231 | **/\r | |
232 | BOOLEAN\r | |
233 | IpSecMatchNextLayerProtocol (\r | |
234 | IN UINT8 Protocol,\r | |
235 | IN UINT8 *IpPayload,\r | |
236 | IN UINT16 SpdProtocol,\r | |
237 | IN UINT16 SpdLocalPort,\r | |
238 | IN UINT16 SpdRemotePort,\r | |
239 | IN BOOLEAN IsOutbound\r | |
240 | )\r | |
241 | {\r | |
242 | BOOLEAN IsMatch;\r | |
243 | \r | |
244 | if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) {\r | |
245 | return TRUE;\r | |
246 | }\r | |
247 | \r | |
248 | IsMatch = FALSE;\r | |
249 | \r | |
250 | if (SpdProtocol == Protocol) {\r | |
251 | switch (Protocol) {\r | |
252 | case EFI_IP_PROTO_UDP:\r | |
253 | case EFI_IP_PROTO_TCP:\r | |
254 | //\r | |
255 | // For udp and tcp, (0, 0) means no need to check local and remote\r | |
256 | // port. The payload is passed from upper level, which means it should\r | |
257 | // be in network order.\r | |
258 | //\r | |
259 | IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r | |
260 | IsMatch = (BOOLEAN) (IsMatch ||\r | |
261 | (IsOutbound &&\r | |
262 | (BOOLEAN)(\r | |
263 | NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort &&\r | |
264 | NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort\r | |
265 | )\r | |
266 | ));\r | |
267 | \r | |
268 | IsMatch = (BOOLEAN) (IsMatch ||\r | |
269 | (!IsOutbound &&\r | |
270 | (BOOLEAN)(\r | |
271 | NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort &&\r | |
272 | NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort\r | |
273 | )\r | |
274 | ));\r | |
275 | break;\r | |
276 | \r | |
277 | case EFI_IP_PROTO_ICMP:\r | |
278 | //\r | |
279 | // For icmpv4, type code is replaced with local port and remote port,\r | |
280 | // and (0, 0) means no need to check.\r | |
281 | //\r | |
282 | IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r | |
283 | IsMatch = (BOOLEAN) (IsMatch ||\r | |
284 | (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&\r | |
285 | ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort\r | |
286 | )\r | |
287 | );\r | |
288 | break;\r | |
289 | \r | |
290 | case IP6_ICMP:\r | |
291 | //\r | |
292 | // For icmpv6, type code is replaced with local port and remote port,\r | |
293 | // and (0, 0) means no need to check.\r | |
294 | //\r | |
295 | IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r | |
296 | \r | |
297 | IsMatch = (BOOLEAN) (IsMatch ||\r | |
298 | (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&\r | |
299 | ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort\r | |
300 | )\r | |
301 | );\r | |
302 | break;\r | |
303 | \r | |
304 | default:\r | |
305 | IsMatch = TRUE;\r | |
306 | break;\r | |
307 | }\r | |
308 | }\r | |
309 | \r | |
310 | return IsMatch;\r | |
311 | }\r | |
312 | \r | |
313 | /**\r | |
314 | Find the SAD through a specified SPD's SAD list.\r | |
315 | \r | |
316 | @param[in] SadList SAD list related to a specified SPD entry.\r | |
317 | @param[in] DestAddress The destination address used to find the SAD entry.\r | |
318 | \r | |
319 | @return The pointer to a certain SAD entry.\r | |
320 | \r | |
321 | **/\r | |
322 | IPSEC_SAD_ENTRY *\r | |
323 | IpSecLookupSadBySpd (\r | |
324 | IN LIST_ENTRY *SadList,\r | |
325 | IN EFI_IP_ADDRESS *DestAddress\r | |
326 | )\r | |
327 | {\r | |
328 | LIST_ENTRY *Entry;\r | |
329 | IPSEC_SAD_ENTRY *SadEntry;\r | |
330 | \r | |
331 | for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\r | |
332 | \r | |
333 | SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);\r | |
334 | //\r | |
335 | // Find the right sad entry which contains the appointed dest address.\r | |
336 | //\r | |
337 | if (CompareMem (\r | |
338 | &SadEntry->Id->DestAddress,\r | |
339 | DestAddress,\r | |
340 | sizeof (EFI_IP_ADDRESS)\r | |
341 | ) == 0) {\r | |
342 | return SadEntry;\r | |
343 | }\r | |
344 | }\r | |
345 | \r | |
346 | return NULL;\r | |
347 | }\r | |
348 | \r | |
349 | /**\r | |
350 | Find the SAD through whole SAD list.\r | |
351 | \r | |
352 | @param[in] Spi The SPI used to search the SAD entry.\r | |
353 | @param[in] DestAddress The destination used to search the SAD entry.\r | |
354 | \r | |
355 | @return the pointer to a certain SAD entry.\r | |
356 | \r | |
357 | **/\r | |
358 | IPSEC_SAD_ENTRY *\r | |
359 | IpSecLookupSadBySpi (\r | |
360 | IN UINT32 Spi,\r | |
361 | IN EFI_IP_ADDRESS *DestAddress\r | |
362 | )\r | |
363 | {\r | |
364 | LIST_ENTRY *Entry;\r | |
365 | LIST_ENTRY *SadList;\r | |
366 | IPSEC_SAD_ENTRY *SadEntry;\r | |
367 | \r | |
368 | SadList = &mConfigData[IPsecConfigDataTypeSad];\r | |
369 | \r | |
370 | for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\r | |
371 | \r | |
372 | SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r | |
373 | //\r | |
374 | // Find the right sad entry which contain the appointed spi and dest addr.\r | |
375 | //\r | |
376 | if (SadEntry->Id->Spi == Spi && CompareMem (\r | |
377 | &SadEntry->Id->DestAddress,\r | |
378 | DestAddress,\r | |
379 | sizeof (EFI_IP_ADDRESS)\r | |
380 | ) == 0) {\r | |
381 | \r | |
382 | return SadEntry;\r | |
383 | }\r | |
384 | }\r | |
385 | \r | |
386 | return NULL;\r | |
387 | }\r | |
388 | \r | |
389 | /**\r | |
390 | Look up if there is existing SAD entry for specified IP packet sending.\r | |
391 | \r | |
392 | This function is called by the IPsecProcess when there is some IP packet needed to\r | |
393 | send out. This function checks if there is an existing SAD entry that can be serviced\r | |
394 | to this IP packet sending. If no existing SAD entry could be used, this\r | |
395 | function will invoke an IPsec Key Exchange Negotiation.\r | |
396 | \r | |
397 | @param[in] Private Points to private data.\r | |
398 | @param[in] NicHandle Points to a NIC handle.\r | |
399 | @param[in] IpVersion The version of IP.\r | |
400 | @param[in] IpHead The IP Header of packet to be sent out.\r | |
401 | @param[in] IpPayload The IP Payload to be sent out.\r | |
402 | @param[in] OldLastHead The Last protocol of the IP packet.\r | |
403 | @param[in] SpdEntry Points to a related SPD entry.\r | |
404 | @param[out] SadEntry Contains the Point of a related SAD entry.\r | |
405 | \r | |
406 | @retval EFI_DEVICE_ERROR One of following conditions is TRUE:\r | |
407 | - If don't find related UDP service.\r | |
408 | - Sequence Number is used up.\r | |
409 | - Extension Sequence Number is used up.\r | |
410 | @retval EFI_DEVICE_ERROR GC_TODO: Add description for return value.\r | |
411 | @retval EFI_NOT_READY No existing SAD entry could be used.\r | |
412 | @retval EFI_SUCCESS Find the related SAD entry.\r | |
413 | \r | |
414 | **/\r | |
415 | EFI_STATUS\r | |
416 | IpSecLookupSadEntry (\r | |
417 | IN IPSEC_PRIVATE_DATA *Private,\r | |
418 | IN EFI_HANDLE NicHandle,\r | |
419 | IN UINT8 IpVersion,\r | |
420 | IN VOID *IpHead,\r | |
421 | IN UINT8 *IpPayload,\r | |
422 | IN UINT8 OldLastHead,\r | |
423 | IN IPSEC_SPD_ENTRY *SpdEntry,\r | |
424 | OUT IPSEC_SAD_ENTRY **SadEntry\r | |
425 | )\r | |
426 | {\r | |
427 | IPSEC_SAD_ENTRY *Entry;\r | |
428 | IPSEC_SAD_DATA *Data;\r | |
429 | EFI_IP_ADDRESS DestIp;\r | |
430 | UINT32 SeqNum32;\r | |
431 | \r | |
432 | *SadEntry = NULL;\r | |
433 | //\r | |
434 | // Parse the destination address from ip header.\r | |
435 | //\r | |
436 | ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r | |
437 | if (IpVersion == IP_VERSION_4) {\r | |
438 | CopyMem (\r | |
439 | &DestIp,\r | |
440 | &((IP4_HEAD *) IpHead)->Dst,\r | |
441 | sizeof (IP4_ADDR)\r | |
442 | );\r | |
443 | } else {\r | |
444 | CopyMem (\r | |
445 | &DestIp,\r | |
446 | &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r | |
447 | sizeof (EFI_IP_ADDRESS)\r | |
448 | );\r | |
449 | }\r | |
450 | //\r | |
451 | // Find the sad entry in the spd.sas list according to the dest address.\r | |
452 | //\r | |
453 | Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp);\r | |
454 | \r | |
455 | if (Entry == NULL) {\r | |
456 | \r | |
457 | if (OldLastHead != IP6_ICMP ||\r | |
458 | (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)\r | |
459 | ) {\r | |
460 | //\r | |
461 | // TODO: Start ike negotiation process except the request packet of ping.\r | |
462 | //\r | |
463 | //IkeNegotiate (UdpService, SpdEntry, &DestIp);\r | |
464 | }\r | |
465 | \r | |
466 | return EFI_NOT_READY;\r | |
467 | }\r | |
468 | \r | |
469 | Data = Entry->Data;\r | |
470 | \r | |
471 | if (!Data->ManualSet) {\r | |
472 | if (Data->ESNEnabled) {\r | |
473 | //\r | |
474 | // Validate the 64bit sn number if 64bit sn enabled.\r | |
475 | //\r | |
476 | if (Data->SequenceNumber + 1 < Data->SequenceNumber) {\r | |
477 | //\r | |
478 | // TODO: Re-negotiate SA\r | |
479 | //\r | |
480 | return EFI_DEVICE_ERROR;\r | |
481 | }\r | |
482 | } else {\r | |
483 | //\r | |
484 | // Validate the 32bit sn number if 64bit sn disabled.\r | |
485 | //\r | |
486 | SeqNum32 = (UINT32) Data->SequenceNumber;\r | |
487 | if (SeqNum32 + 1 < SeqNum32) {\r | |
488 | //\r | |
489 | // TODO: Re-negotiate SA\r | |
490 | //\r | |
491 | return EFI_DEVICE_ERROR;\r | |
492 | }\r | |
493 | }\r | |
494 | }\r | |
495 | \r | |
496 | *SadEntry = Entry;\r | |
497 | \r | |
498 | return EFI_SUCCESS;\r | |
499 | }\r | |
500 | \r | |
501 | /**\r | |
502 | Find a PAD entry according to a remote IP address.\r | |
503 | \r | |
504 | @param[in] IpVersion The version of IP.\r | |
505 | @param[in] IpAddr Points to remote IP address.\r | |
506 | \r | |
507 | @return the pointer of related PAD entry.\r | |
508 | \r | |
509 | **/\r | |
510 | IPSEC_PAD_ENTRY *\r | |
511 | IpSecLookupPadEntry (\r | |
512 | IN UINT8 IpVersion,\r | |
513 | IN EFI_IP_ADDRESS *IpAddr\r | |
514 | )\r | |
515 | {\r | |
516 | LIST_ENTRY *PadList;\r | |
517 | LIST_ENTRY *Entry;\r | |
518 | EFI_IP_ADDRESS_INFO *IpAddrInfo;\r | |
519 | IPSEC_PAD_ENTRY *PadEntry;\r | |
520 | \r | |
521 | PadList = &mConfigData[IPsecConfigDataTypePad];\r | |
522 | \r | |
523 | for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {\r | |
524 | \r | |
525 | PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r | |
526 | IpAddrInfo = &PadEntry->Id->Id.IpAddress;\r | |
527 | //\r | |
528 | // Find the right pad entry which contain the appointed dest addr.\r | |
529 | //\r | |
530 | if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {\r | |
531 | return PadEntry;\r | |
532 | }\r | |
533 | }\r | |
534 | \r | |
535 | return NULL;\r | |
536 | }\r | |
537 | \r | |
538 | /**\r | |
539 | Check if the specified IP packet can be serviced by this SPD entry.\r | |
540 | \r | |
541 | @param[in] SpdEntry Point to SPD entry.\r | |
542 | @param[in] IpVersion Version of IP.\r | |
543 | @param[in] IpHead Point to IP header.\r | |
544 | @param[in] IpPayload Point to IP payload.\r | |
545 | @param[in] Protocol The Last protocol of IP packet.\r | |
546 | @param[in] IsOutbound Traffic direction.\r | |
547 | \r | |
548 | @retval EFI_IPSEC_ACTION The support action of SPD entry.\r | |
549 | @retval -1 If the input packet header doesn't match the SpdEntry.\r | |
550 | \r | |
551 | **/\r | |
552 | EFI_IPSEC_ACTION\r | |
553 | IpSecLookupSpdEntry (\r | |
554 | IN IPSEC_SPD_ENTRY *SpdEntry,\r | |
555 | IN UINT8 IpVersion,\r | |
556 | IN VOID *IpHead,\r | |
557 | IN UINT8 *IpPayload,\r | |
558 | IN UINT8 Protocol,\r | |
559 | IN BOOLEAN IsOutbound\r | |
560 | )\r | |
561 | {\r | |
562 | EFI_IPSEC_SPD_SELECTOR *SpdSel;\r | |
563 | IP4_HEAD *Ip4;\r | |
564 | EFI_IP6_HEADER *Ip6;\r | |
565 | EFI_IP_ADDRESS SrcAddr;\r | |
566 | EFI_IP_ADDRESS DstAddr;\r | |
567 | BOOLEAN SpdMatch;\r | |
568 | \r | |
569 | ASSERT (SpdEntry != NULL);\r | |
570 | SpdSel = SpdEntry->Selector;\r | |
571 | Ip4 = (IP4_HEAD *) IpHead;\r | |
572 | Ip6 = (EFI_IP6_HEADER *) IpHead;\r | |
573 | \r | |
574 | ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));\r | |
575 | ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));\r | |
576 | \r | |
577 | //\r | |
578 | // Parse the source and destination address from ip header.\r | |
579 | //\r | |
580 | if (IpVersion == IP_VERSION_4) {\r | |
581 | CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));\r | |
582 | CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));\r | |
583 | } else {\r | |
584 | CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));\r | |
585 | CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));\r | |
586 | }\r | |
587 | //\r | |
588 | // Check the local and remote addresses for outbound traffic\r | |
589 | //\r | |
590 | SpdMatch = (BOOLEAN)(IsOutbound &&\r | |
591 | IpSecMatchIpAddress (\r | |
592 | IpVersion,\r | |
593 | &SrcAddr,\r | |
594 | SpdSel->LocalAddress,\r | |
595 | SpdSel->LocalAddressCount\r | |
596 | ) &&\r | |
597 | IpSecMatchIpAddress (\r | |
598 | IpVersion,\r | |
599 | &DstAddr,\r | |
600 | SpdSel->RemoteAddress,\r | |
601 | SpdSel->RemoteAddressCount\r | |
602 | )\r | |
603 | );\r | |
604 | \r | |
605 | //\r | |
606 | // Check the local and remote addresses for inbound traffic\r | |
607 | //\r | |
608 | SpdMatch = (BOOLEAN) (SpdMatch ||\r | |
609 | (!IsOutbound &&\r | |
610 | IpSecMatchIpAddress (\r | |
611 | IpVersion,\r | |
612 | &DstAddr,\r | |
613 | SpdSel->LocalAddress,\r | |
614 | SpdSel->LocalAddressCount\r | |
615 | ) &&\r | |
616 | IpSecMatchIpAddress (\r | |
617 | IpVersion,\r | |
618 | &SrcAddr,\r | |
619 | SpdSel->RemoteAddress,\r | |
620 | SpdSel->RemoteAddressCount\r | |
621 | )\r | |
622 | ));\r | |
623 | \r | |
624 | //\r | |
625 | // Check the next layer protocol and local and remote ports.\r | |
626 | //\r | |
627 | SpdMatch = (BOOLEAN) (SpdMatch &&\r | |
628 | IpSecMatchNextLayerProtocol (\r | |
629 | Protocol,\r | |
630 | IpPayload,\r | |
631 | SpdSel->NextLayerProtocol,\r | |
632 | SpdSel->LocalPort,\r | |
633 | SpdSel->RemotePort,\r | |
634 | IsOutbound\r | |
635 | )\r | |
636 | );\r | |
637 | \r | |
638 | if (SpdMatch) {\r | |
639 | //\r | |
640 | // Find the right spd entry if match the 5 key elements.\r | |
641 | //\r | |
642 | return SpdEntry->Data->Action;\r | |
643 | }\r | |
644 | \r | |
645 | return (EFI_IPSEC_ACTION) - 1;\r | |
646 | }\r | |
647 | \r | |
648 | /**\r | |
649 | Handles IPsec packet processing for inbound and outbound IP packets.\r | |
650 | \r | |
651 | The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.\r | |
652 | The behavior is that it can perform one of the following actions:\r | |
653 | bypass the packet, discard the packet, or protect the packet.\r | |
654 | \r | |
655 | @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance.\r | |
656 | @param[in] NicHandle Instance of the network interface.\r | |
657 | @param[in] IpVersion IPV4 or IPV6.\r | |
658 | @param[in, out] IpHead Pointer to the IP Header.\r | |
68d3f2fb | 659 | @param[in, out] LastHead The protocol of the next layer to be processed by IPsec.\r |
660 | @param[in, out] OptionsBuffer Pointer to the options buffer.\r | |
661 | @param[in, out] OptionsLength Length of the options buffer.\r | |
a3bcde70 | 662 | @param[in, out] FragmentTable Pointer to a list of fragments.\r |
68d3f2fb | 663 | @param[in, out] FragmentCount Number of fragments.\r |
a3bcde70 HT |
664 | @param[in] TrafficDirection Traffic direction.\r |
665 | @param[out] RecycleSignal Event for recycling of resources.\r | |
666 | \r | |
667 | @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.\r | |
668 | @retval EFI_SUCCESS The packet was protected.\r | |
669 | @retval EFI_ACCESS_DENIED The packet was discarded.\r | |
670 | \r | |
671 | **/\r | |
672 | EFI_STATUS\r | |
673 | EFIAPI\r | |
674 | IpSecProcess (\r | |
68d3f2fb | 675 | IN EFI_IPSEC2_PROTOCOL *This,\r |
a3bcde70 HT |
676 | IN EFI_HANDLE NicHandle,\r |
677 | IN UINT8 IpVersion,\r | |
678 | IN OUT VOID *IpHead,\r | |
68d3f2fb | 679 | IN OUT UINT8 *LastHead,\r |
680 | IN OUT VOID **OptionsBuffer,\r | |
681 | IN OUT UINT32 *OptionsLength,\r | |
a3bcde70 | 682 | IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r |
68d3f2fb | 683 | IN OUT UINT32 *FragmentCount,\r |
a3bcde70 HT |
684 | IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection,\r |
685 | OUT EFI_EVENT *RecycleSignal\r | |
686 | )\r | |
687 | {\r | |
688 | IPSEC_PRIVATE_DATA *Private;\r | |
689 | IPSEC_SPD_ENTRY *SpdEntry;\r | |
690 | IPSEC_SAD_ENTRY *SadEntry;\r | |
691 | LIST_ENTRY *SpdList;\r | |
692 | LIST_ENTRY *Entry;\r | |
693 | EFI_IPSEC_ACTION Action;\r | |
694 | EFI_STATUS Status;\r | |
695 | UINT8 *IpPayload;\r | |
696 | UINT8 OldLastHead;\r | |
697 | BOOLEAN IsOutbound;\r | |
698 | \r | |
699 | Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);\r | |
700 | IpPayload = (*FragmentTable)[0].FragmentBuffer;\r | |
701 | IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);\r | |
702 | OldLastHead = *LastHead;\r | |
703 | *RecycleSignal = NULL;\r | |
704 | \r | |
705 | if (!IsOutbound) {\r | |
706 | //\r | |
707 | // For inbound traffic, process the ipsec header of the packet.\r | |
708 | //\r | |
709 | Status = IpSecProtectInboundPacket (\r | |
710 | IpVersion,\r | |
711 | IpHead,\r | |
712 | LastHead,\r | |
713 | OptionsBuffer,\r | |
714 | OptionsLength,\r | |
715 | FragmentTable,\r | |
716 | FragmentCount,\r | |
717 | &SpdEntry,\r | |
718 | RecycleSignal\r | |
719 | );\r | |
720 | \r | |
721 | if (Status == EFI_ACCESS_DENIED) {\r | |
722 | //\r | |
723 | // The packet is denied to access.\r | |
724 | //\r | |
725 | goto ON_EXIT;\r | |
726 | }\r | |
727 | \r | |
728 | if (Status == EFI_SUCCESS) {\r | |
729 | //\r | |
730 | // Check the spd entry if the packet is accessible.\r | |
731 | //\r | |
732 | if (SpdEntry == NULL) {\r | |
733 | Status = EFI_ACCESS_DENIED;\r | |
734 | goto ON_EXIT;\r | |
735 | }\r | |
736 | Action = IpSecLookupSpdEntry (\r | |
737 | SpdEntry,\r | |
738 | IpVersion,\r | |
739 | IpHead,\r | |
740 | IpPayload,\r | |
741 | *LastHead,\r | |
742 | IsOutbound\r | |
743 | );\r | |
744 | \r | |
745 | if (Action != EfiIPsecActionProtect) {\r | |
746 | //\r | |
747 | // Discard the packet if the spd entry is not protect.\r | |
748 | //\r | |
749 | gBS->SignalEvent (*RecycleSignal);\r | |
750 | *RecycleSignal = NULL;\r | |
751 | Status = EFI_ACCESS_DENIED;\r | |
752 | }\r | |
753 | \r | |
754 | goto ON_EXIT;\r | |
755 | }\r | |
756 | }\r | |
757 | \r | |
758 | Status = EFI_ACCESS_DENIED;\r | |
759 | SpdList = &mConfigData[IPsecConfigDataTypeSpd];\r | |
760 | \r | |
761 | for (Entry = SpdList->ForwardLink; Entry != SpdList; Entry = Entry->ForwardLink) {\r | |
762 | //\r | |
763 | // For outbound and non-ipsec Inbound traffic: check the spd entry.\r | |
764 | //\r | |
765 | SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r | |
766 | Action = IpSecLookupSpdEntry (\r | |
767 | SpdEntry,\r | |
768 | IpVersion,\r | |
769 | IpHead,\r | |
770 | IpPayload,\r | |
771 | OldLastHead,\r | |
772 | IsOutbound\r | |
773 | );\r | |
774 | \r | |
775 | switch (Action) {\r | |
776 | \r | |
777 | case EfiIPsecActionProtect:\r | |
778 | \r | |
779 | if (IsOutbound) {\r | |
780 | //\r | |
781 | // For outbound traffic, lookup the sad entry.\r | |
782 | //\r | |
783 | Status = IpSecLookupSadEntry (\r | |
784 | Private,\r | |
785 | NicHandle,\r | |
786 | IpVersion,\r | |
787 | IpHead,\r | |
788 | IpPayload,\r | |
789 | OldLastHead,\r | |
790 | SpdEntry,\r | |
791 | &SadEntry\r | |
792 | );\r | |
793 | \r | |
794 | if (SadEntry != NULL) {\r | |
795 | //\r | |
796 | // Process the packet by the found sad entry.\r | |
797 | //\r | |
798 | Status = IpSecProtectOutboundPacket (\r | |
799 | IpVersion,\r | |
800 | IpHead,\r | |
801 | LastHead,\r | |
802 | OptionsBuffer,\r | |
803 | OptionsLength,\r | |
804 | FragmentTable,\r | |
805 | FragmentCount,\r | |
806 | SadEntry,\r | |
807 | RecycleSignal\r | |
808 | );\r | |
809 | \r | |
810 | } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r | |
811 | //\r | |
812 | // TODO: if no need return not ready to upper layer, change here.\r | |
813 | //\r | |
814 | Status = EFI_SUCCESS;\r | |
815 | }\r | |
816 | } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r | |
817 | //\r | |
818 | // For inbound icmpv6 traffic except ping request, accept the packet\r | |
819 | // although no sad entry associated with protect spd entry.\r | |
820 | //\r | |
821 | IpSecLookupSadEntry (\r | |
822 | Private,\r | |
823 | NicHandle,\r | |
824 | IpVersion,\r | |
825 | IpHead,\r | |
826 | IpPayload,\r | |
827 | OldLastHead,\r | |
828 | SpdEntry,\r | |
829 | &SadEntry\r | |
830 | );\r | |
831 | if (SadEntry == NULL) {\r | |
832 | Status = EFI_SUCCESS;\r | |
833 | }\r | |
834 | }\r | |
835 | \r | |
836 | goto ON_EXIT;\r | |
837 | \r | |
838 | case EfiIPsecActionBypass:\r | |
839 | Status = EFI_SUCCESS;\r | |
840 | goto ON_EXIT;\r | |
841 | \r | |
842 | case EfiIPsecActionDiscard:\r | |
843 | goto ON_EXIT;\r | |
844 | \r | |
845 | default:\r | |
846 | //\r | |
847 | // Discard the packet if no spd entry match.\r | |
848 | //\r | |
849 | break;\r | |
850 | }\r | |
851 | }\r | |
852 | \r | |
853 | ON_EXIT:\r | |
854 | return Status;\r | |
855 | }\r | |
856 | \r |