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