]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IpSecDxe/IpSecImpl.c
Update the IPsec driver to check in invalid parameter of ProcessExt() according to...
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecImpl.c
1 /** @file
2 The implementation of IPsec.
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 "IpSecImpl.h"
17 #include "IkeService.h"
18 #include "IpSecDebug.h"
19 #include "IpSecCryptIo.h"
20 #include "IpSecConfigImpl.h"
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. That means it
27 should gives the correct prefixed address and the bytes outside the prefixed are
28 zero.
29
30 @param[in] IpVersion The IP version.
31 @param[in] Address Points to EFI_IP_ADDRESS to be checked.
32 @param[in] PrefixLength The PrefixeLength of this address.
33
34 @retval TRUE The address is a vaild address range.
35 @retval FALSE The address is not a vaild address range.
36
37 **/
38 BOOLEAN
39 IpSecValidAddressRange (
40 IN UINT8 IpVersion,
41 IN EFI_IP_ADDRESS *Address,
42 IN UINT8 PrefixLength
43 )
44 {
45 UINT8 Div;
46 UINT8 Mod;
47 UINT8 Mask;
48 UINT8 AddrLen;
49 UINT8 *Addr;
50 EFI_IP_ADDRESS ZeroAddr;
51
52 if (PrefixLength == 0) {
53 return TRUE;
54 }
55
56 AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);
57
58 if (AddrLen <= PrefixLength) {
59 return FALSE;
60 }
61
62 Div = (UINT8) (PrefixLength / 8);
63 Mod = (UINT8) (PrefixLength % 8);
64 Addr = (UINT8 *) Address;
65 ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));
66
67 //
68 // Check whether the mod part of host scope is zero or not.
69 //
70 if (Mod > 0) {
71 Mask = (UINT8) (0xFF << (8 - Mod));
72
73 if ((Addr[Div] | Mask) != Mask) {
74 return FALSE;
75 }
76
77 Div++;
78 }
79 //
80 // Check whether the div part of host scope is zero or not.
81 //
82 if (CompareMem (
83 &Addr[Div],
84 &ZeroAddr,
85 sizeof (EFI_IP_ADDRESS) - Div
86 ) != 0) {
87 return FALSE;
88 }
89
90 return TRUE;
91 }
92
93 /**
94 Extrct the Address Range from a Address.
95
96 This function keep the prefix address and zero other part address.
97
98 @param[in] Address Point to a specified address.
99 @param[in] PrefixLength The prefix length.
100 @param[out] Range Contain the return Address Range.
101
102 **/
103 VOID
104 IpSecExtractAddressRange (
105 IN EFI_IP_ADDRESS *Address,
106 IN UINT8 PrefixLength,
107 OUT EFI_IP_ADDRESS *Range
108 )
109 {
110 UINT8 Div;
111 UINT8 Mod;
112 UINT8 Mask;
113 UINT8 *Addr;
114
115 if (PrefixLength == 0) {
116 return ;
117 }
118
119 Div = (UINT8) (PrefixLength / 8);
120 Mod = (UINT8) (PrefixLength % 8);
121 Addr = (UINT8 *) Range;
122
123 CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));
124
125 //
126 // Zero the mod part of host scope.
127 //
128 if (Mod > 0) {
129 Mask = (UINT8) (0xFF << (8 - Mod));
130 Addr[Div] = (UINT8) (Addr[Div] & Mask);
131 Div++;
132 }
133 //
134 // Zero the div part of host scope.
135 //
136 ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);
137
138 }
139
140 /**
141 Checks if the IP Address in the address range of AddressInfos specified.
142
143 @param[in] IpVersion The IP version.
144 @param[in] IpAddr Point to EFI_IP_ADDRESS to be check.
145 @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check
146 the IP Address is matched.
147 @param[in] AddressCount The total numbers of the AddressInfo.
148
149 @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified.
150 @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified.
151
152 **/
153 BOOLEAN
154 IpSecMatchIpAddress (
155 IN UINT8 IpVersion,
156 IN EFI_IP_ADDRESS *IpAddr,
157 IN EFI_IP_ADDRESS_INFO *AddressInfo,
158 IN UINT32 AddressCount
159 )
160 {
161 EFI_IP_ADDRESS Range;
162 UINT32 Index;
163 BOOLEAN IsMatch;
164
165 IsMatch = FALSE;
166
167 for (Index = 0; Index < AddressCount; Index++) {
168 //
169 // Check whether the target address is in the address range
170 // if it's a valid range of address.
171 //
172 if (IpSecValidAddressRange (
173 IpVersion,
174 &AddressInfo[Index].Address,
175 AddressInfo[Index].PrefixLength
176 )) {
177 //
178 // Get the range of the target address belongs to.
179 //
180 ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));
181 IpSecExtractAddressRange (
182 IpAddr,
183 AddressInfo[Index].PrefixLength,
184 &Range
185 );
186
187 if (CompareMem (
188 &Range,
189 &AddressInfo[Index].Address,
190 sizeof (EFI_IP_ADDRESS)
191 ) == 0) {
192 //
193 // The target address is in the address range.
194 //
195 IsMatch = TRUE;
196 break;
197 }
198 }
199
200 if (CompareMem (
201 IpAddr,
202 &AddressInfo[Index].Address,
203 sizeof (EFI_IP_ADDRESS)
204 ) == 0) {
205 //
206 // The target address is exact same as the address.
207 //
208 IsMatch = TRUE;
209 break;
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 @param[in] IpVersion The IP version. Ip4 or Ip6.
319
320 @return The pointer to a certain SAD entry.
321
322 **/
323 IPSEC_SAD_ENTRY *
324 IpSecLookupSadBySpd (
325 IN LIST_ENTRY *SadList,
326 IN EFI_IP_ADDRESS *DestAddress,
327 IN UINT8 IpVersion
328 )
329 {
330 LIST_ENTRY *Entry;
331 IPSEC_SAD_ENTRY *SadEntry;
332
333 NET_LIST_FOR_EACH (Entry, SadList) {
334
335 SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
336 //
337 // Find the right SAD entry which contains the appointed dest address.
338 //
339 if (IpSecMatchIpAddress (
340 IpVersion,
341 DestAddress,
342 SadEntry->Data->SpdSelector->RemoteAddress,
343 SadEntry->Data->SpdSelector->RemoteAddressCount
344 )){
345 return SadEntry;
346 }
347 }
348
349 return NULL;
350 }
351
352 /**
353 Find the SAD through whole SAD list.
354
355 @param[in] Spi The SPI used to search the SAD entry.
356 @param[in] DestAddress The destination used to search the SAD entry.
357 @param[in] IpVersion The IP version. Ip4 or Ip6.
358
359 @return the pointer to a certain SAD entry.
360
361 **/
362 IPSEC_SAD_ENTRY *
363 IpSecLookupSadBySpi (
364 IN UINT32 Spi,
365 IN EFI_IP_ADDRESS *DestAddress,
366 IN UINT8 IpVersion
367 )
368 {
369 LIST_ENTRY *Entry;
370 LIST_ENTRY *SadList;
371 IPSEC_SAD_ENTRY *SadEntry;
372
373 SadList = &mConfigData[IPsecConfigDataTypeSad];
374
375 NET_LIST_FOR_EACH (Entry, SadList) {
376
377 SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
378
379 //
380 // Find the right SAD entry which contain the appointed spi and dest addr.
381 //
382 if (SadEntry->Id->Spi == Spi) {
383 if (SadEntry->Data->Mode == EfiIPsecTunnel) {
384 if (CompareMem (
385 &DestAddress,
386 &SadEntry->Data->TunnelDestAddress,
387 sizeof (EFI_IP_ADDRESS)
388 )) {
389 return SadEntry;
390 }
391 } else {
392 if (SadEntry->Data->SpdSelector != NULL &&
393 IpSecMatchIpAddress (
394 IpVersion,
395 DestAddress,
396 SadEntry->Data->SpdSelector->RemoteAddress,
397 SadEntry->Data->SpdSelector->RemoteAddressCount
398 )
399 ) {
400 return SadEntry;
401 }
402 }
403 }
404 }
405 return NULL;
406 }
407
408 /**
409 Look up if there is existing SAD entry for specified IP packet sending.
410
411 This function is called by the IPsecProcess when there is some IP packet needed to
412 send out. This function checks if there is an existing SAD entry that can be serviced
413 to this IP packet sending. If no existing SAD entry could be used, this
414 function will invoke an IPsec Key Exchange Negotiation.
415
416 @param[in] Private Points to private data.
417 @param[in] NicHandle Points to a NIC handle.
418 @param[in] IpVersion The version of IP.
419 @param[in] IpHead The IP Header of packet to be sent out.
420 @param[in] IpPayload The IP Payload to be sent out.
421 @param[in] OldLastHead The Last protocol of the IP packet.
422 @param[in] SpdEntry Points to a related SPD entry.
423 @param[out] SadEntry Contains the Point of a related SAD entry.
424
425 @retval EFI_DEVICE_ERROR One of following conditions is TRUE:
426 - If don't find related UDP service.
427 - Sequence Number is used up.
428 - Extension Sequence Number is used up.
429 @retval EFI_NOT_READY No existing SAD entry could be used.
430 @retval EFI_SUCCESS Find the related SAD entry.
431
432 **/
433 EFI_STATUS
434 IpSecLookupSadEntry (
435 IN IPSEC_PRIVATE_DATA *Private,
436 IN EFI_HANDLE NicHandle,
437 IN UINT8 IpVersion,
438 IN VOID *IpHead,
439 IN UINT8 *IpPayload,
440 IN UINT8 OldLastHead,
441 IN IPSEC_SPD_ENTRY *SpdEntry,
442 OUT IPSEC_SAD_ENTRY **SadEntry
443 )
444 {
445 IKE_UDP_SERVICE *UdpService;
446 IPSEC_SAD_ENTRY *Entry;
447 IPSEC_SAD_DATA *Data;
448 EFI_IP_ADDRESS DestIp;
449 UINT32 SeqNum32;
450
451 *SadEntry = NULL;
452 UdpService = IkeLookupUdp (Private, NicHandle, IpVersion);
453
454 if (UdpService == NULL) {
455 return EFI_DEVICE_ERROR;
456 }
457 //
458 // Parse the destination address from ip header.
459 //
460 ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
461 if (IpVersion == IP_VERSION_4) {
462 CopyMem (
463 &DestIp,
464 &((IP4_HEAD *) IpHead)->Dst,
465 sizeof (IP4_ADDR)
466 );
467 } else {
468 CopyMem (
469 &DestIp,
470 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
471 sizeof (EFI_IP_ADDRESS)
472 );
473 }
474
475 //
476 // Find the SAD entry in the spd.sas list according to the dest address.
477 //
478 Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);
479
480 if (Entry == NULL) {
481
482 if (OldLastHead != IP6_ICMP ||
483 (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)
484 ) {
485 //
486 // Start ike negotiation process except the request packet of ping.
487 //
488 if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
489 IkeNegotiate (
490 UdpService,
491 SpdEntry,
492 &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress
493 );
494 } else {
495 IkeNegotiate (
496 UdpService,
497 SpdEntry,
498 &DestIp
499 );
500 }
501
502 }
503
504 return EFI_NOT_READY;
505 }
506
507 Data = Entry->Data;
508
509 if (!Data->ManualSet) {
510 if (Data->ESNEnabled) {
511 //
512 // Validate the 64bit sn number if 64bit sn enabled.
513 //
514 if ((UINT64) (Data->SequenceNumber + 1) == 0) {
515 //
516 // TODO: Re-negotiate SA
517 //
518 return EFI_DEVICE_ERROR;
519 }
520 } else {
521 //
522 // Validate the 32bit sn number if 64bit sn disabled.
523 //
524 SeqNum32 = (UINT32) Data->SequenceNumber;
525 if ((UINT32) (SeqNum32 + 1) == 0) {
526 //
527 // TODO: Re-negotiate SA
528 //
529 return EFI_DEVICE_ERROR;
530 }
531 }
532 }
533
534 *SadEntry = Entry;
535
536 return EFI_SUCCESS;
537 }
538
539 /**
540 Find a PAD entry according to a remote IP address.
541
542 @param[in] IpVersion The version of IP.
543 @param[in] IpAddr Points to remote IP address.
544
545 @return the pointer of related PAD entry.
546
547 **/
548 IPSEC_PAD_ENTRY *
549 IpSecLookupPadEntry (
550 IN UINT8 IpVersion,
551 IN EFI_IP_ADDRESS *IpAddr
552 )
553 {
554 LIST_ENTRY *PadList;
555 LIST_ENTRY *Entry;
556 EFI_IP_ADDRESS_INFO *IpAddrInfo;
557 IPSEC_PAD_ENTRY *PadEntry;
558
559 PadList = &mConfigData[IPsecConfigDataTypePad];
560
561 for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {
562
563 PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
564 IpAddrInfo = &PadEntry->Id->Id.IpAddress;
565 //
566 // Find the right pad entry which contain the appointed dest addr.
567 //
568 if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {
569 return PadEntry;
570 }
571 }
572
573 return NULL;
574 }
575
576 /**
577 Check if the specified IP packet can be serviced by this SPD entry.
578
579 @param[in] SpdEntry Point to SPD entry.
580 @param[in] IpVersion Version of IP.
581 @param[in] IpHead Point to IP header.
582 @param[in] IpPayload Point to IP payload.
583 @param[in] Protocol The Last protocol of IP packet.
584 @param[in] IsOutbound Traffic direction.
585 @param[out] Action The support action of SPD entry.
586
587 @retval EFI_SUCCESS Find the related SPD.
588 @retval EFI_NOT_FOUND Not find the related SPD entry;
589
590 **/
591 EFI_STATUS
592 IpSecLookupSpdEntry (
593 IN IPSEC_SPD_ENTRY *SpdEntry,
594 IN UINT8 IpVersion,
595 IN VOID *IpHead,
596 IN UINT8 *IpPayload,
597 IN UINT8 Protocol,
598 IN BOOLEAN IsOutbound,
599 OUT EFI_IPSEC_ACTION *Action
600 )
601 {
602 EFI_IPSEC_SPD_SELECTOR *SpdSel;
603 IP4_HEAD *Ip4;
604 EFI_IP6_HEADER *Ip6;
605 EFI_IP_ADDRESS SrcAddr;
606 EFI_IP_ADDRESS DstAddr;
607 BOOLEAN SpdMatch;
608
609 ASSERT (SpdEntry != NULL);
610 SpdSel = SpdEntry->Selector;
611 Ip4 = (IP4_HEAD *) IpHead;
612 Ip6 = (EFI_IP6_HEADER *) IpHead;
613
614 ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));
615 ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));
616
617 //
618 // Parse the source and destination address from ip header.
619 //
620 if (IpVersion == IP_VERSION_4) {
621 CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));
622 CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));
623 } else {
624 CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));
625 CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
626 }
627 //
628 // Check the local and remote addresses for outbound traffic
629 //
630 SpdMatch = (BOOLEAN)(IsOutbound &&
631 IpSecMatchIpAddress (
632 IpVersion,
633 &SrcAddr,
634 SpdSel->LocalAddress,
635 SpdSel->LocalAddressCount
636 ) &&
637 IpSecMatchIpAddress (
638 IpVersion,
639 &DstAddr,
640 SpdSel->RemoteAddress,
641 SpdSel->RemoteAddressCount
642 )
643 );
644
645 //
646 // Check the local and remote addresses for inbound traffic
647 //
648 SpdMatch = (BOOLEAN) (SpdMatch ||
649 (!IsOutbound &&
650 IpSecMatchIpAddress (
651 IpVersion,
652 &DstAddr,
653 SpdSel->LocalAddress,
654 SpdSel->LocalAddressCount
655 ) &&
656 IpSecMatchIpAddress (
657 IpVersion,
658 &SrcAddr,
659 SpdSel->RemoteAddress,
660 SpdSel->RemoteAddressCount
661 )
662 ));
663
664 //
665 // Check the next layer protocol and local and remote ports.
666 //
667 SpdMatch = (BOOLEAN) (SpdMatch &&
668 IpSecMatchNextLayerProtocol (
669 Protocol,
670 IpPayload,
671 SpdSel->NextLayerProtocol,
672 SpdSel->LocalPort,
673 SpdSel->RemotePort,
674 IsOutbound
675 )
676 );
677
678 if (SpdMatch) {
679 //
680 // Find the right SPD entry if match the 5 key elements.
681 //
682 *Action = SpdEntry->Data->Action;
683 return EFI_SUCCESS;
684 }
685
686 return EFI_NOT_FOUND;
687 }
688
689 /**
690 The call back function of NetbufFromExt.
691
692 @param[in] Arg The argument passed from the caller.
693
694 **/
695 VOID
696 EFIAPI
697 IpSecOnRecyclePacket (
698 IN VOID *Arg
699 )
700 {
701 }
702
703 /**
704 This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP
705 is released.
706
707 @param[in] Event The related event.
708 @param[in] Context The data passed by the caller.
709
710 **/
711 VOID
712 EFIAPI
713 IpSecRecycleCallback (
714 IN EFI_EVENT Event,
715 IN VOID *Context
716 )
717 {
718 IPSEC_RECYCLE_CONTEXT *RecycleContext;
719
720 RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;
721
722 if (RecycleContext->FragmentTable != NULL) {
723 FreePool (RecycleContext->FragmentTable);
724 }
725
726 if (RecycleContext->PayloadBuffer != NULL) {
727 FreePool (RecycleContext->PayloadBuffer);
728 }
729
730 FreePool (RecycleContext);
731 gBS->CloseEvent (Event);
732
733 }
734
735 /**
736 Calculate the extension hader of IP. The return length only doesn't contain
737 the fixed IP header length.
738
739 @param[in] IpHead Points to an IP head to be calculated.
740 @param[in] LastHead Points to the last header of the IP header.
741
742 @return The length of the extension header.
743
744 **/
745 UINT16
746 IpSecGetPlainExtHeadSize (
747 IN VOID *IpHead,
748 IN UINT8 *LastHead
749 )
750 {
751 UINT16 Size;
752
753 Size = (UINT16) (LastHead - (UINT8 *) IpHead);
754
755 if (Size > sizeof (EFI_IP6_HEADER)) {
756 //
757 // * (LastHead+1) point the last header's length but not include the first
758 // 8 octers, so this formluation add 8 at the end.
759 //
760 Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);
761 } else {
762 Size = 0;
763 }
764
765 return Size;
766 }
767
768 /**
769 Verify if the Authentication payload is correct.
770
771 @param[in] EspBuffer Points to the ESP wrapped buffer.
772 @param[in] EspSize The size of the ESP wrapped buffer.
773 @param[in] SadEntry The related SAD entry to store the authentication
774 algorithm key.
775 @param[in] IcvSize The length of ICV.
776
777 @retval EFI_SUCCESS The authentication data is correct.
778 @retval EFI_ACCESS_DENIED The authentication data is not correct.
779
780 **/
781 EFI_STATUS
782 IpSecEspAuthVerifyPayload (
783 IN UINT8 *EspBuffer,
784 IN UINTN EspSize,
785 IN IPSEC_SAD_ENTRY *SadEntry,
786 IN UINTN *IcvSize
787 )
788 {
789 EFI_STATUS Status;
790 UINTN AuthSize;
791 UINT8 IcvBuffer[12];
792 HASH_DATA_FRAGMENT HashFragment[1];
793
794 //
795 // Calculate the size of authentication payload.
796 //
797 *IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
798 AuthSize = EspSize - *IcvSize;
799
800 //
801 // Calculate the icv buffer and size of the payload.
802 //
803 HashFragment[0].Data = EspBuffer;
804 HashFragment[0].DataSize = AuthSize;
805
806 Status = IpSecCryptoIoHmac (
807 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
808 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
809 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
810 HashFragment,
811 1,
812 IcvBuffer,
813 *IcvSize
814 );
815 if (EFI_ERROR (Status)) {
816 return Status;
817 }
818
819 //
820 // Compare the calculated icv and the appended original icv.
821 //
822 if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) {
823 return EFI_SUCCESS;
824 }
825
826 DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
827 return EFI_ACCESS_DENIED;
828 }
829
830 /**
831 Search the related SAD entry by the input .
832
833 @param[in] IpHead The pointer to IP header.
834 @param[in] IpVersion The version of IP (IP4 or IP6).
835 @param[in] Spi The SPI used to search the related SAD entry.
836
837
838 @retval NULL Not find the related SAD entry.
839 @retval IPSEC_SAD_ENTRY Return the related SAD entry.
840
841 **/
842 IPSEC_SAD_ENTRY *
843 IpSecFoundSadFromInboundPacket (
844 UINT8 *IpHead,
845 UINT8 IpVersion,
846 UINT32 Spi
847 )
848 {
849 EFI_IP_ADDRESS DestIp;
850
851 //
852 // Parse destination address from ip header.
853 //
854 ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
855 if (IpVersion == IP_VERSION_4) {
856 CopyMem (
857 &DestIp,
858 &((IP4_HEAD *) IpHead)->Dst,
859 sizeof (IP4_ADDR)
860 );
861 } else {
862 CopyMem (
863 &DestIp,
864 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
865 sizeof (EFI_IPv6_ADDRESS)
866 );
867 }
868
869 //
870 // Lookup SAD entry according to the spi and dest address.
871 //
872 return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);
873 }
874
875 /**
876 Validate the IP6 extension header format for both the packets we received
877 and that we will transmit.
878
879 @param[in] NextHeader The next header field in IPv6 basic header.
880 @param[in] ExtHdrs The first bye of the option.
881 @param[in] ExtHdrsLen The length of the whole option.
882 @param[out] LastHeader The pointer of NextHeader of the last extension
883 header processed by IP6.
884 @param[out] RealExtsLen The length of extension headers processed by IP6 layer.
885 This is an optional parameter that may be NULL.
886
887 @retval TRUE The option is properly formated.
888 @retval FALSE The option is malformated.
889
890 **/
891 BOOLEAN
892 IpSecIsIp6ExtsValid (
893 IN UINT8 *NextHeader,
894 IN UINT8 *ExtHdrs,
895 IN UINT32 ExtHdrsLen,
896 OUT UINT8 **LastHeader,
897 OUT UINT32 *RealExtsLen OPTIONAL
898 )
899 {
900 UINT32 Pointer;
901 UINT8 *Option;
902 UINT8 OptionLen;
903 BOOLEAN Flag;
904 UINT8 CountD;
905 UINT8 CountF;
906 UINT8 CountA;
907
908 if (RealExtsLen != NULL) {
909 *RealExtsLen = 0;
910 }
911
912 *LastHeader = NextHeader;
913
914 if (ExtHdrs == NULL && ExtHdrsLen == 0) {
915 return TRUE;
916 }
917
918 if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {
919 return FALSE;
920 }
921
922 Pointer = 0;
923 Flag = FALSE;
924 CountD = 0;
925 CountF = 0;
926 CountA = 0;
927
928 while (Pointer <= ExtHdrsLen) {
929
930 switch (*NextHeader) {
931 case IP6_HOP_BY_HOP:
932 if (Pointer != 0) {
933 return FALSE;
934 }
935
936 Flag = TRUE;
937
938 //
939 // Fall through
940 //
941 case IP6_DESTINATION:
942 if (*NextHeader == IP6_DESTINATION) {
943 CountD++;
944 }
945
946 if (CountD > 2) {
947 return FALSE;
948 }
949
950 NextHeader = ExtHdrs + Pointer;
951
952 Pointer++;
953 Option = ExtHdrs + Pointer;
954 OptionLen = (UINT8) ((*Option + 1) * 8 - 2);
955 Option++;
956 Pointer++;
957
958 Pointer = Pointer + OptionLen;
959 break;
960
961 case IP6_FRAGMENT:
962 if (++CountF > 1) {
963 return FALSE;
964 }
965 //
966 // RFC2402, AH header should after fragment header.
967 //
968 if (CountA > 1) {
969 return FALSE;
970 }
971
972 NextHeader = ExtHdrs + Pointer;
973 Pointer = Pointer + 8;
974 break;
975
976 case IP6_AH:
977 if (++CountA > 1) {
978 return FALSE;
979 }
980
981 Option = ExtHdrs + Pointer;
982 NextHeader = Option;
983 Option++;
984 //
985 // RFC2402, Payload length is specified in 32-bit words, minus "2".
986 //
987 OptionLen = (UINT8) ((*Option + 2) * 4);
988 Pointer = Pointer + OptionLen;
989 break;
990
991 default:
992 *LastHeader = NextHeader;
993 if (RealExtsLen != NULL) {
994 *RealExtsLen = Pointer;
995 }
996
997 return TRUE;
998 }
999 }
1000
1001 *LastHeader = NextHeader;
1002
1003 if (RealExtsLen != NULL) {
1004 *RealExtsLen = Pointer;
1005 }
1006
1007 return TRUE;
1008 }
1009
1010 /**
1011 The actual entry to process the tunnel header and inner header for tunnel mode
1012 outbound traffic.
1013
1014 This function is the subfunction of IpSecEspInboundPacket(). It change the destination
1015 Ip address to the station address and recalculate the uplayyer's checksum.
1016
1017
1018 @param[in, out] IpHead Points to the IP header containing the ESP header
1019 to be trimed on input, and without ESP header
1020 on return.
1021 @param[in] IpPayload The decrypted Ip payload. It start from the inner
1022 header.
1023 @param[in] IpVersion The version of IP.
1024 @param[in] SadData Pointer of the relevant SAD.
1025 @param[in, out] LastHead The Last Header in IP header on return.
1026
1027 **/
1028 VOID
1029 IpSecTunnelInboundPacket (
1030 IN OUT UINT8 *IpHead,
1031 IN UINT8 *IpPayload,
1032 IN UINT8 IpVersion,
1033 IN IPSEC_SAD_DATA *SadData,
1034 IN OUT UINT8 *LastHead
1035 )
1036 {
1037 EFI_UDP_HEADER *UdpHeader;
1038 TCP_HEAD *TcpHeader;
1039 UINT16 *Checksum;
1040 UINT16 PseudoChecksum;
1041 UINT16 PacketChecksum;
1042 UINT32 OptionLen;
1043 IP6_ICMP_HEAD *Icmp6Head;
1044
1045 Checksum = NULL;
1046
1047 if (IpVersion == IP_VERSION_4) {
1048 //
1049 // Zero OutIP header use this to indicate the input packet is under
1050 // IPsec Tunnel protected.
1051 //
1052 ZeroMem (
1053 (IP4_HEAD *)IpHead,
1054 sizeof (IP4_HEAD)
1055 );
1056 CopyMem (
1057 &((IP4_HEAD *)IpPayload)->Dst,
1058 &SadData->TunnelDestAddress.v4,
1059 sizeof (EFI_IPv4_ADDRESS)
1060 );
1061
1062 //
1063 // Recalculate IpHeader Checksum
1064 //
1065 if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {
1066 ((IP4_HEAD *)(IpPayload))->Checksum = 0;
1067 ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (
1068 (UINT8 *)IpPayload,
1069 ((IP4_HEAD *)IpPayload)->HeadLen << 2
1070 ));
1071
1072
1073 }
1074
1075 //
1076 // Recalcualte PseudoChecksum
1077 //
1078 switch (((IP4_HEAD *)IpPayload)->Protocol) {
1079 case EFI_IP_PROTO_UDP :
1080 UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
1081 Checksum = & UdpHeader->Checksum;
1082 *Checksum = 0;
1083 break;
1084
1085 case EFI_IP_PROTO_TCP:
1086 TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
1087 Checksum = &TcpHeader->Checksum;
1088 *Checksum = 0;
1089 break;
1090
1091 default:
1092 break;
1093 }
1094 PacketChecksum = NetblockChecksum (
1095 (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2),
1096 NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)
1097 );
1098 PseudoChecksum = NetPseudoHeadChecksum (
1099 ((IP4_HEAD *)IpPayload)->Src,
1100 ((IP4_HEAD *)IpPayload)->Dst,
1101 ((IP4_HEAD *)IpPayload)->Protocol,
1102 0
1103 );
1104
1105 if (Checksum != NULL) {
1106 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1107 *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));
1108 }
1109 }else {
1110 //
1111 // Zero OutIP header use this to indicate the input packet is under
1112 // IPsec Tunnel protected.
1113 //
1114 ZeroMem (
1115 IpHead,
1116 sizeof (EFI_IP6_HEADER)
1117 );
1118 CopyMem (
1119 &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,
1120 &SadData->TunnelDestAddress.v6,
1121 sizeof (EFI_IPv6_ADDRESS)
1122 );
1123
1124 //
1125 // Get the Extension Header and Header length.
1126 //
1127 IpSecIsIp6ExtsValid (
1128 &((EFI_IP6_HEADER *)IpPayload)->NextHeader,
1129 IpPayload + sizeof (EFI_IP6_HEADER),
1130 ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,
1131 &LastHead,
1132 &OptionLen
1133 );
1134
1135 //
1136 // Recalcualte PseudoChecksum
1137 //
1138 switch (*LastHead) {
1139 case EFI_IP_PROTO_UDP:
1140 UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1141 Checksum = &UdpHeader->Checksum;
1142 *Checksum = 0;
1143 break;
1144
1145 case EFI_IP_PROTO_TCP:
1146 TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1147 Checksum = &TcpHeader->Checksum;
1148 *Checksum = 0;
1149 break;
1150
1151 case IP6_ICMP:
1152 Icmp6Head = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1153 Checksum = &Icmp6Head->Checksum;
1154 *Checksum = 0;
1155 break;
1156 }
1157 PacketChecksum = NetblockChecksum (
1158 IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen,
1159 NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen
1160 );
1161 PseudoChecksum = NetIp6PseudoHeadChecksum (
1162 &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,
1163 &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,
1164 *LastHead,
1165 0
1166 );
1167
1168 if (Checksum != NULL) {
1169 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1170 *Checksum = (UINT16) ~(NetAddChecksum (
1171 *Checksum,
1172 HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))
1173 ));
1174 }
1175 }
1176 }
1177
1178 /**
1179 The actual entry to create inner header for tunnel mode inbound traffic.
1180
1181 This function is the subfunction of IpSecEspOutboundPacket(). It create
1182 the sending packet by encrypting its payload and inserting ESP header in the orginal
1183 IP header, then return the IpHeader and IPsec protected Fragmentable.
1184
1185 @param[in, out] IpHead Points to IP header containing the orginal IP header
1186 to be processed on input, and inserted ESP header
1187 on return.
1188 @param[in] IpVersion The version of IP.
1189 @param[in] SadData The related SAD data.
1190 @param[in, out] LastHead The Last Header in IP header.
1191 @param[in] OptionsBuffer Pointer to the options buffer.
1192 @param[in] OptionsLength Length of the options buffer.
1193 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
1194 IPsec on input, and with IPsec protected
1195 on return.
1196 @param[in] FragmentCount The number of fragments.
1197
1198 @retval EFI_SUCCESS The operation was successful.
1199 @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
1200
1201 **/
1202 UINT8 *
1203 IpSecTunnelOutboundPacket (
1204 IN OUT UINT8 *IpHead,
1205 IN UINT8 IpVersion,
1206 IN IPSEC_SAD_DATA *SadData,
1207 IN OUT UINT8 *LastHead,
1208 IN VOID **OptionsBuffer,
1209 IN UINT32 *OptionsLength,
1210 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1211 IN UINT32 *FragmentCount
1212 )
1213 {
1214 UINT8 *InnerHead;
1215 NET_BUF *Packet;
1216 UINT16 PacketChecksum;
1217 UINT16 *Checksum;
1218 UINT16 PseudoChecksum;
1219 IP6_ICMP_HEAD *IcmpHead;
1220
1221 Checksum = NULL;
1222 if (OptionsLength == NULL) {
1223 return NULL;
1224 }
1225
1226 if (IpVersion == IP_VERSION_4) {
1227 InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);
1228 ASSERT (InnerHead != NULL);
1229 CopyMem (
1230 InnerHead,
1231 IpHead,
1232 sizeof (IP4_HEAD)
1233 );
1234 CopyMem (
1235 InnerHead + sizeof (IP4_HEAD),
1236 *OptionsBuffer,
1237 *OptionsLength
1238 );
1239 } else {
1240 InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);
1241 CopyMem (
1242 InnerHead,
1243 IpHead,
1244 sizeof (EFI_IP6_HEADER)
1245 );
1246 CopyMem (
1247 InnerHead + sizeof (EFI_IP6_HEADER),
1248 *OptionsBuffer,
1249 *OptionsLength
1250 );
1251 }
1252 if (OptionsBuffer != NULL) {
1253 if (*OptionsLength != 0) {
1254
1255 *OptionsBuffer = NULL;
1256 *OptionsLength = 0;
1257 }
1258 }
1259
1260 //
1261 // 2. Reassamlbe Fragment into Packet
1262 //
1263 Packet = NetbufFromExt (
1264 (NET_FRAGMENT *)(*FragmentTable),
1265 *FragmentCount,
1266 0,
1267 0,
1268 IpSecOnRecyclePacket,
1269 NULL
1270 );
1271 ASSERT (Packet != NULL);
1272 //
1273 // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
1274 // CheckSum.
1275 //
1276 switch (*LastHead) {
1277 case EFI_IP_PROTO_UDP:
1278 Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);
1279 ASSERT (Packet->Udp != NULL);
1280 Checksum = &Packet->Udp->Checksum;
1281 *Checksum = 0;
1282 break;
1283
1284 case EFI_IP_PROTO_TCP:
1285 Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);
1286 ASSERT (Packet->Tcp != NULL);
1287 Checksum = &Packet->Tcp->Checksum;
1288 *Checksum = 0;
1289 break;
1290
1291 case IP6_ICMP:
1292 IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
1293 ASSERT (IcmpHead != NULL);
1294 Checksum = &IcmpHead->Checksum;
1295 *Checksum = 0;
1296 break;
1297
1298 default:
1299 break;
1300 }
1301
1302 PacketChecksum = NetbufChecksum (Packet);
1303
1304 if (IpVersion == IP_VERSION_4) {
1305 //
1306 // Replace the source address of Inner Header.
1307 //
1308 CopyMem (
1309 &((IP4_HEAD *)InnerHead)->Src,
1310 &SadData->SpdSelector->LocalAddress[0].Address.v4,
1311 sizeof (EFI_IPv4_ADDRESS)
1312 );
1313
1314 PacketChecksum = NetbufChecksum (Packet);
1315 PseudoChecksum = NetPseudoHeadChecksum (
1316 ((IP4_HEAD *)InnerHead)->Src,
1317 ((IP4_HEAD *)InnerHead)->Dst,
1318 *LastHead,
1319 0
1320 );
1321
1322 } else {
1323 //
1324 // Replace the source address of Inner Header.
1325 //
1326 CopyMem (
1327 &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
1328 &(SadData->SpdSelector->LocalAddress[0].Address.v6),
1329 sizeof (EFI_IPv6_ADDRESS)
1330 );
1331 PacketChecksum = NetbufChecksum (Packet);
1332 PseudoChecksum = NetIp6PseudoHeadChecksum (
1333 &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
1334 &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,
1335 *LastHead,
1336 0
1337 );
1338
1339 }
1340 if (Checksum != NULL) {
1341 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1342 *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));
1343 }
1344
1345 if (Packet != NULL) {
1346 NetbufFree (Packet);
1347 }
1348 return InnerHead;
1349 }
1350
1351 /**
1352 The actual entry to relative function processes the inbound traffic of ESP header.
1353
1354 This function is the subfunction of IpSecProtectInboundPacket(). It checks the
1355 received packet security property and trim the ESP header and then returns without
1356 an IPsec protected IP Header and FramgmentTable.
1357
1358 @param[in] IpVersion The version of IP.
1359 @param[in, out] IpHead Points to the IP header containing the ESP header
1360 to be trimed on input, and without ESP header
1361 on return.
1362 @param[out] LastHead The Last Header in IP header on return.
1363 @param[in, out] OptionsBuffer Pointer to the options buffer.
1364 @param[in, out] OptionsLength Length of the options buffer.
1365 @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec
1366 protected on input, and without IPsec protected
1367 on return.
1368 @param[in, out] FragmentCount The number of fragments.
1369 @param[out] SpdSelector Pointer to contain the address of SPD selector on return.
1370 @param[out] RecycleEvent The event for recycling of resources.
1371
1372 @retval EFI_SUCCESS The operation was successful.
1373 @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:
1374 - ESP header was not found.
1375 - The related SAD entry was not found.
1376 - The related SAD entry does not support the ESP protocol.
1377 @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
1378
1379 **/
1380 EFI_STATUS
1381 IpSecEspInboundPacket (
1382 IN UINT8 IpVersion,
1383 IN OUT VOID *IpHead,
1384 OUT UINT8 *LastHead,
1385 IN OUT VOID **OptionsBuffer,
1386 IN OUT UINT32 *OptionsLength,
1387 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1388 IN OUT UINT32 *FragmentCount,
1389 OUT EFI_IPSEC_SPD_SELECTOR **SpdSelector,
1390 OUT EFI_EVENT *RecycleEvent
1391 )
1392 {
1393 EFI_STATUS Status;
1394 NET_BUF *Payload;
1395 UINTN EspSize;
1396 UINTN IvSize;
1397 UINTN PlainPayloadSize;
1398 UINTN PaddingSize;
1399 UINTN IcvSize;
1400 UINT8 *ProcessBuffer;
1401 EFI_ESP_HEADER *EspHeader;
1402 EFI_ESP_TAIL *EspTail;
1403 EFI_IPSEC_SA_ID *SaId;
1404 IPSEC_SAD_DATA *SadData;
1405 IPSEC_SAD_ENTRY *SadEntry;
1406 IPSEC_RECYCLE_CONTEXT *RecycleContext;
1407 UINT8 NextHeader;
1408 UINT16 IpSecHeadSize;
1409 UINT8 *InnerHead;
1410
1411 Status = EFI_SUCCESS;
1412 Payload = NULL;
1413 ProcessBuffer = NULL;
1414 RecycleContext = NULL;
1415 *RecycleEvent = NULL;
1416 PlainPayloadSize = 0;
1417 NextHeader = 0;
1418
1419 //
1420 // Build netbuf from fragment table first.
1421 //
1422 Payload = NetbufFromExt (
1423 (NET_FRAGMENT *) *FragmentTable,
1424 *FragmentCount,
1425 0,
1426 sizeof (EFI_ESP_HEADER),
1427 IpSecOnRecyclePacket,
1428 NULL
1429 );
1430 if (Payload == NULL) {
1431 Status = EFI_OUT_OF_RESOURCES;
1432 goto ON_EXIT;
1433 }
1434
1435 //
1436 // Get the esp size and esp header from netbuf.
1437 //
1438 EspSize = Payload->TotalSize;
1439 EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);
1440
1441 if (EspHeader == NULL) {
1442 Status = EFI_ACCESS_DENIED;
1443 goto ON_EXIT;
1444 }
1445
1446 //
1447 // Parse destination address from ip header and found the related SAD Entry.
1448 //
1449 SadEntry = IpSecFoundSadFromInboundPacket (
1450 IpHead,
1451 IpVersion,
1452 NTOHL (EspHeader->Spi)
1453 );
1454
1455 if (SadEntry == NULL) {
1456 Status = EFI_ACCESS_DENIED;
1457 goto ON_EXIT;
1458 }
1459
1460 SaId = SadEntry->Id;
1461 SadData = SadEntry->Data;
1462
1463 //
1464 // Only support esp protocol currently.
1465 //
1466 if (SaId->Proto != EfiIPsecESP) {
1467 Status = EFI_ACCESS_DENIED;
1468 goto ON_EXIT;
1469 }
1470
1471 if (!SadData->ManualSet) {
1472 //
1473 // TODO: Check SA lifetime and sequence number
1474 //
1475 }
1476
1477 //
1478 // Allocate buffer for decryption and authentication.
1479 //
1480 ProcessBuffer = AllocateZeroPool (EspSize);
1481 if (ProcessBuffer == NULL) {
1482 Status = EFI_OUT_OF_RESOURCES;
1483 goto ON_EXIT;
1484 }
1485
1486 NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);
1487
1488 //
1489 // Authenticate the esp wrapped buffer by the auth keys which is from SAD entry.
1490 //
1491 IcvSize = 0;
1492 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1493 Status = IpSecEspAuthVerifyPayload (
1494 ProcessBuffer,
1495 EspSize,
1496 SadEntry,
1497 &IcvSize
1498 );
1499 if (EFI_ERROR (Status)) {
1500 goto ON_EXIT;
1501 }
1502 }
1503 //
1504 // Decrypt the payload by the SAD entry if it has decrypt key.
1505 //
1506 IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1507 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1508 Status = IpSecCryptoIoDecrypt (
1509 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
1510 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1511 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
1512 ProcessBuffer + sizeof (EFI_ESP_HEADER),
1513 ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,
1514 EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,
1515 ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize
1516 );
1517 if (EFI_ERROR (Status)) {
1518 goto ON_EXIT;
1519 }
1520 }
1521
1522 //
1523 // Parse EspTail and compute the plain payload size.
1524 //
1525 EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));
1526 PaddingSize = EspTail->PaddingLength;
1527 NextHeader = EspTail->NextHeader;
1528 PlainPayloadSize = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize;
1529
1530 //
1531 // TODO: handle anti-replay window
1532 //
1533 //
1534 // Decryption and authentication with esp has been done, so it's time to
1535 // reload the new packet, create recycle event and fixup ip header.
1536 //
1537 RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
1538 if (RecycleContext == NULL) {
1539 Status = EFI_OUT_OF_RESOURCES;
1540 goto ON_EXIT;
1541 }
1542
1543 Status = gBS->CreateEvent (
1544 EVT_NOTIFY_SIGNAL,
1545 TPL_NOTIFY,
1546 IpSecRecycleCallback,
1547 RecycleContext,
1548 RecycleEvent
1549 );
1550 if (EFI_ERROR (Status)) {
1551 goto ON_EXIT;
1552 }
1553
1554 //
1555 // The caller will take responsible to handle the original fragment table
1556 //
1557 *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
1558 if (*FragmentTable == NULL) {
1559 Status = EFI_OUT_OF_RESOURCES;
1560 goto ON_EXIT;
1561 }
1562
1563 RecycleContext->PayloadBuffer = ProcessBuffer;
1564 RecycleContext->FragmentTable = *FragmentTable;
1565
1566 //
1567 // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
1568 //
1569 if (SadData->Mode == EfiIPsecTunnel) {
1570 InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
1571 IpSecTunnelInboundPacket (
1572 IpHead,
1573 InnerHead,
1574 IpVersion,
1575 SadData,
1576 LastHead
1577 );
1578
1579 if (IpVersion == IP_VERSION_4) {
1580 (*FragmentTable)[0].FragmentBuffer = InnerHead ;
1581 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1582
1583 }else {
1584 (*FragmentTable)[0].FragmentBuffer = InnerHead;
1585 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1586 }
1587 } else {
1588 (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
1589 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1590 }
1591
1592 *FragmentCount = 1;
1593
1594 //
1595 // Update the total length field in ip header since processed by esp.
1596 //
1597 if (!SadData->Mode == EfiIPsecTunnel) {
1598 if (IpVersion == IP_VERSION_4) {
1599 ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize));
1600 } else {
1601 IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead);
1602 ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));
1603 }
1604 //
1605 // Update the next layer field in ip header since esp header inserted.
1606 //
1607 *LastHead = NextHeader;
1608 }
1609
1610
1611 //
1612 // Update the SPD association of the SAD entry.
1613 //
1614 *SpdSelector = SadData->SpdSelector;
1615
1616 ON_EXIT:
1617 if (Payload != NULL) {
1618 NetbufFree (Payload);
1619 }
1620
1621 if (EFI_ERROR (Status)) {
1622 if (ProcessBuffer != NULL) {
1623 FreePool (ProcessBuffer);
1624 }
1625
1626 if (RecycleContext != NULL) {
1627 FreePool (RecycleContext);
1628 }
1629
1630 if (*RecycleEvent != NULL) {
1631 gBS->CloseEvent (*RecycleEvent);
1632 }
1633 }
1634
1635 return Status;
1636 }
1637
1638 /**
1639 The actual entry to the relative function processes the output traffic using the ESP protocol.
1640
1641 This function is the subfunction of IpSecProtectOutboundPacket(). It protected
1642 the sending packet by encrypting its payload and inserting ESP header in the orginal
1643 IP header, then return the IpHeader and IPsec protected Fragmentable.
1644
1645 @param[in] IpVersion The version of IP.
1646 @param[in, out] IpHead Points to IP header containing the orginal IP header
1647 to be processed on input, and inserted ESP header
1648 on return.
1649 @param[in, out] LastHead The Last Header in IP header.
1650 @param[in, out] OptionsBuffer Pointer to the options buffer.
1651 @param[in, out] OptionsLength Length of the options buffer.
1652 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
1653 IPsec on input, and with IPsec protected
1654 on return.
1655 @param[in, out] FragmentCount The number of fragments.
1656 @param[in] SadEntry The related SAD entry.
1657 @param[out] RecycleEvent The event for recycling of resources.
1658
1659 @retval EFI_SUCCESS The operation was successful.
1660 @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
1661
1662 **/
1663 EFI_STATUS
1664 IpSecEspOutboundPacket (
1665 IN UINT8 IpVersion,
1666 IN OUT VOID *IpHead,
1667 IN OUT UINT8 *LastHead,
1668 IN OUT VOID **OptionsBuffer,
1669 IN OUT UINT32 *OptionsLength,
1670 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1671 IN OUT UINT32 *FragmentCount,
1672 IN IPSEC_SAD_ENTRY *SadEntry,
1673 OUT EFI_EVENT *RecycleEvent
1674 )
1675 {
1676 EFI_STATUS Status;
1677 UINTN Index;
1678 EFI_IPSEC_SA_ID *SaId;
1679 IPSEC_SAD_DATA *SadData;
1680 IPSEC_RECYCLE_CONTEXT *RecycleContext;
1681 UINT8 *ProcessBuffer;
1682 UINTN BytesCopied;
1683 INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4
1684 UINTN EspSize; // Total size of esp wrapped ip payload
1685 UINTN IvSize; // Size of IV, optional, might be 0
1686 UINTN PlainPayloadSize;// Original IP payload size
1687 UINTN PaddingSize; // Size of padding
1688 UINTN EncryptSize; // Size of data to be encrypted, start after IV and
1689 // stop before ICV
1690 UINTN IcvSize; // Size of ICV, optional, might be 0
1691 UINT8 *RestOfPayload; // Start of Payload after IV
1692 UINT8 *Padding; // Start address of padding
1693 EFI_ESP_HEADER *EspHeader; // Start address of ESP frame
1694 EFI_ESP_TAIL *EspTail; // Address behind padding
1695 UINT8 *InnerHead;
1696 HASH_DATA_FRAGMENT HashFragment[1];
1697
1698 Status = EFI_ACCESS_DENIED;
1699 SaId = SadEntry->Id;
1700 SadData = SadEntry->Data;
1701 ProcessBuffer = NULL;
1702 RecycleContext = NULL;
1703 *RecycleEvent = NULL;
1704 InnerHead = NULL;
1705
1706 if (!SadData->ManualSet &&
1707 SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&
1708 SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL
1709 ) {
1710 //
1711 // Invalid manual SAD entry configuration.
1712 //
1713 goto ON_EXIT;
1714 }
1715
1716 //
1717 // Create OutHeader according to Inner Header
1718 //
1719 if (SadData->Mode == EfiIPsecTunnel) {
1720 InnerHead = IpSecTunnelOutboundPacket (
1721 IpHead,
1722 IpVersion,
1723 SadData,
1724 LastHead,
1725 OptionsBuffer,
1726 OptionsLength,
1727 FragmentTable,
1728 FragmentCount
1729 );
1730
1731 if (InnerHead == NULL) {
1732 return EFI_INVALID_PARAMETER;
1733 }
1734
1735 }
1736
1737 //
1738 // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
1739 //
1740 EncryptBlockSize = 4;
1741
1742 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1743 EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1744
1745 if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {
1746 goto ON_EXIT;
1747 }
1748 }
1749
1750 //
1751 // Calculate the plain payload size accroding to the fragment table.
1752 //
1753 PlainPayloadSize = 0;
1754 for (Index = 0; Index < *FragmentCount; Index++) {
1755 PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;
1756 }
1757
1758 //
1759 // Add IPHeader size for Tunnel Mode
1760 //
1761 if (SadData->Mode == EfiIPsecTunnel) {
1762 if (IpVersion == IP_VERSION_4) {
1763 PlainPayloadSize += sizeof (IP4_HEAD);
1764 } else {
1765 PlainPayloadSize += sizeof (EFI_IP6_HEADER);
1766 }
1767 //
1768 // OPtions should be encryption into it
1769 //
1770 PlainPayloadSize += *OptionsLength;
1771 }
1772
1773
1774 //
1775 // Calculate icv size, optional by default and 4 bytes alignment.
1776 //
1777 IcvSize = 0;
1778 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1779 IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
1780 if (IcvSize % 4 != 0) {
1781 goto ON_EXIT;
1782 }
1783 }
1784
1785 //
1786 // Calcuate the total size of esp wrapped ip payload.
1787 //
1788 IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1789 EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;
1790 PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);
1791 EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;
1792
1793 ProcessBuffer = AllocateZeroPool (EspSize);
1794 if (ProcessBuffer == NULL) {
1795 Status = EFI_OUT_OF_RESOURCES;
1796 goto ON_EXIT;
1797 }
1798
1799 //
1800 // Calculate esp header and esp tail including header, payload and padding.
1801 //
1802 EspHeader = (EFI_ESP_HEADER *) ProcessBuffer;
1803 RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;
1804 Padding = RestOfPayload + PlainPayloadSize;
1805 EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize);
1806
1807 //
1808 // Fill the sn and spi fields in esp header.
1809 //
1810 EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);
1811 //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
1812 EspHeader->Spi = HTONL (SaId->Spi);
1813
1814 //
1815 // Copy the rest of payload (after iv) from the original fragment buffer.
1816 //
1817 BytesCopied = 0;
1818
1819 //
1820 // For Tunnel Mode
1821 //
1822 if (SadData->Mode == EfiIPsecTunnel) {
1823 if (IpVersion == IP_VERSION_4) {
1824 //
1825 // HeadLen, Total Length
1826 //
1827 ((IP4_HEAD *)InnerHead)->HeadLen = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);
1828 ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);
1829 ((IP4_HEAD *)InnerHead)->Checksum = 0;
1830 ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (
1831 (UINT8 *)InnerHead,
1832 sizeof(IP4_HEAD)
1833 ));
1834 CopyMem (
1835 RestOfPayload + BytesCopied,
1836 InnerHead,
1837 sizeof (IP4_HEAD) + *OptionsLength
1838 );
1839 BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;
1840
1841 } else {
1842 ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));
1843 CopyMem (
1844 RestOfPayload + BytesCopied,
1845 InnerHead,
1846 sizeof (EFI_IP6_HEADER) + *OptionsLength
1847 );
1848 BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;
1849 }
1850 }
1851
1852 for (Index = 0; Index < *FragmentCount; Index++) {
1853 CopyMem (
1854 (RestOfPayload + BytesCopied),
1855 (*FragmentTable)[Index].FragmentBuffer,
1856 (*FragmentTable)[Index].FragmentLength
1857 );
1858 BytesCopied += (*FragmentTable)[Index].FragmentLength;
1859 }
1860 //
1861 // Fill the padding buffer by natural number sequence.
1862 //
1863 for (Index = 0; Index < PaddingSize; Index++) {
1864 Padding[Index] = (UINT8) (Index + 1);
1865 }
1866 //
1867 // Fill the padding length and next header fields in esp tail.
1868 //
1869 EspTail->PaddingLength = (UINT8) PaddingSize;
1870 EspTail->NextHeader = *LastHead;
1871
1872 //
1873 // Fill the next header for Tunnel mode.
1874 //
1875 if (SadData->Mode == EfiIPsecTunnel) {
1876 if (IpVersion == IP_VERSION_4) {
1877 EspTail->NextHeader = 4;
1878 } else {
1879 EspTail->NextHeader = 41;
1880 }
1881 }
1882
1883 //
1884 // Generate iv at random by crypt library.
1885 //
1886 Status = IpSecGenerateIv (
1887 (UINT8 *) (EspHeader + 1),
1888 IvSize
1889 );
1890
1891
1892 if (EFI_ERROR (Status)) {
1893 goto ON_EXIT;
1894 }
1895
1896 //
1897 // Encryption the payload (after iv) by the SAD entry if has encrypt key.
1898 //
1899 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1900 Status = IpSecCryptoIoEncrypt (
1901 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
1902 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1903 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
1904 (UINT8 *)(EspHeader + 1),
1905 RestOfPayload,
1906 EncryptSize,
1907 RestOfPayload
1908 );
1909
1910 if (EFI_ERROR (Status)) {
1911 goto ON_EXIT;
1912 }
1913 }
1914
1915 //
1916 // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
1917 //
1918 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1919
1920 HashFragment[0].Data = ProcessBuffer;
1921 HashFragment[0].DataSize = EspSize - IcvSize;
1922 Status = IpSecCryptoIoHmac (
1923 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
1924 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1925 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
1926 HashFragment,
1927 1,
1928 ProcessBuffer + EspSize - IcvSize,
1929 IcvSize
1930 );
1931 if (EFI_ERROR (Status)) {
1932 goto ON_EXIT;
1933 }
1934 }
1935
1936 //
1937 // Encryption and authentication with esp has been done, so it's time to
1938 // reload the new packet, create recycle event and fixup ip header.
1939 //
1940 RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
1941 if (RecycleContext == NULL) {
1942 Status = EFI_OUT_OF_RESOURCES;
1943 goto ON_EXIT;
1944 }
1945
1946 Status = gBS->CreateEvent (
1947 EVT_NOTIFY_SIGNAL,
1948 TPL_NOTIFY,
1949 IpSecRecycleCallback,
1950 RecycleContext,
1951 RecycleEvent
1952 );
1953 if (EFI_ERROR (Status)) {
1954 goto ON_EXIT;
1955 }
1956 //
1957 // Caller take responsible to handle the original fragment table.
1958 //
1959 *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
1960 if (*FragmentTable == NULL) {
1961 Status = EFI_OUT_OF_RESOURCES;
1962 goto ON_EXIT;
1963 }
1964
1965 RecycleContext->FragmentTable = *FragmentTable;
1966 RecycleContext->PayloadBuffer = ProcessBuffer;
1967 (*FragmentTable)[0].FragmentBuffer = ProcessBuffer;
1968 (*FragmentTable)[0].FragmentLength = (UINT32) EspSize;
1969 *FragmentCount = 1;
1970
1971 //
1972 // Update the total length field in ip header since processed by esp.
1973 //
1974 if (IpVersion == IP_VERSION_4) {
1975 ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));
1976 } else {
1977 ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);
1978 }
1979
1980 //
1981 // If tunnel mode, it should change the outer Ip header with tunnel source address
1982 // and destination tunnel address.
1983 //
1984 if (SadData->Mode == EfiIPsecTunnel) {
1985 if (IpVersion == IP_VERSION_4) {
1986 CopyMem (
1987 &((IP4_HEAD *) IpHead)->Src,
1988 &SadData->TunnelSourceAddress.v4,
1989 sizeof (EFI_IPv4_ADDRESS)
1990 );
1991 CopyMem (
1992 &((IP4_HEAD *) IpHead)->Dst,
1993 &SadData->TunnelDestAddress.v4,
1994 sizeof (EFI_IPv4_ADDRESS)
1995 );
1996 } else {
1997 CopyMem (
1998 &((EFI_IP6_HEADER *) IpHead)->SourceAddress,
1999 &SadData->TunnelSourceAddress.v6,
2000 sizeof (EFI_IPv6_ADDRESS)
2001 );
2002 CopyMem (
2003 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
2004 &SadData->TunnelDestAddress.v6,
2005 sizeof (EFI_IPv6_ADDRESS)
2006 );
2007 }
2008 }
2009
2010 //
2011 // Update the next layer field in ip header since esp header inserted.
2012 //
2013 *LastHead = IPSEC_ESP_PROTOCOL;
2014
2015 //
2016 // Increase the sn number in SAD entry according to rfc4303.
2017 //
2018 SadData->SequenceNumber++;
2019
2020 ON_EXIT:
2021 if (EFI_ERROR (Status)) {
2022 if (ProcessBuffer != NULL) {
2023 FreePool (ProcessBuffer);
2024 }
2025
2026 if (RecycleContext != NULL) {
2027 FreePool (RecycleContext);
2028 }
2029
2030 if (*RecycleEvent != NULL) {
2031 gBS->CloseEvent (*RecycleEvent);
2032 }
2033 }
2034
2035 return Status;
2036 }
2037
2038 /**
2039 This function processes the inbound traffic with IPsec.
2040
2041 It checks the received packet security property, trims the ESP/AH header, and then
2042 returns without an IPsec protected IP Header and FragmentTable.
2043
2044 @param[in] IpVersion The version of IP.
2045 @param[in, out] IpHead Points to IP header containing the ESP/AH header
2046 to be trimed on input, and without ESP/AH header
2047 on return.
2048 @param[in, out] LastHead The Last Header in IP header on return.
2049 @param[in, out] OptionsBuffer Pointer to the options buffer.
2050 @param[in, out] OptionsLength Length of the options buffer.
2051 @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec
2052 protected on input, and without IPsec protected
2053 on return.
2054 @param[in, out] FragmentCount The number of fragments.
2055 @param[out] SpdEntry Pointer to contain the address of SPD entry on return.
2056 @param[out] RecycleEvent The event for recycling of resources.
2057
2058 @retval EFI_SUCCESS The operation was successful.
2059 @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.
2060
2061 **/
2062 EFI_STATUS
2063 IpSecProtectInboundPacket (
2064 IN UINT8 IpVersion,
2065 IN OUT VOID *IpHead,
2066 IN OUT UINT8 *LastHead,
2067 IN OUT VOID **OptionsBuffer,
2068 IN OUT UINT32 *OptionsLength,
2069 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
2070 IN OUT UINT32 *FragmentCount,
2071 OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry,
2072 OUT EFI_EVENT *RecycleEvent
2073 )
2074 {
2075 if (*LastHead == IPSEC_ESP_PROTOCOL) {
2076 //
2077 // Process the esp ipsec header of the inbound traffic.
2078 //
2079 return IpSecEspInboundPacket (
2080 IpVersion,
2081 IpHead,
2082 LastHead,
2083 OptionsBuffer,
2084 OptionsLength,
2085 FragmentTable,
2086 FragmentCount,
2087 SpdEntry,
2088 RecycleEvent
2089 );
2090 }
2091 //
2092 // The other protocols are not supported.
2093 //
2094 return EFI_UNSUPPORTED;
2095 }
2096
2097 /**
2098 This fucntion processes the output traffic with IPsec.
2099
2100 It protected the sending packet by encrypting it payload and inserting ESP/AH header
2101 in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
2102
2103 @param[in] IpVersion The version of IP.
2104 @param[in, out] IpHead Point to IP header containing the orginal IP header
2105 to be processed on input, and inserted ESP/AH header
2106 on return.
2107 @param[in, out] LastHead The Last Header in IP header.
2108 @param[in, out] OptionsBuffer Pointer to the options buffer.
2109 @param[in, out] OptionsLength Length of the options buffer.
2110 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
2111 IPsec on input, and with IPsec protected
2112 on return.
2113 @param[in, out] FragmentCount Number of fragments.
2114 @param[in] SadEntry Related SAD entry.
2115 @param[out] RecycleEvent Event for recycling of resources.
2116
2117 @retval EFI_SUCCESS The operation is successful.
2118 @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.
2119
2120 **/
2121 EFI_STATUS
2122 IpSecProtectOutboundPacket (
2123 IN UINT8 IpVersion,
2124 IN OUT VOID *IpHead,
2125 IN OUT UINT8 *LastHead,
2126 IN OUT VOID **OptionsBuffer,
2127 IN OUT UINT32 *OptionsLength,
2128 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
2129 IN OUT UINT32 *FragmentCount,
2130 IN IPSEC_SAD_ENTRY *SadEntry,
2131 OUT EFI_EVENT *RecycleEvent
2132 )
2133 {
2134 if (SadEntry->Id->Proto == EfiIPsecESP) {
2135 //
2136 // Process the esp ipsec header of the outbound traffic.
2137 //
2138 return IpSecEspOutboundPacket (
2139 IpVersion,
2140 IpHead,
2141 LastHead,
2142 OptionsBuffer,
2143 OptionsLength,
2144 FragmentTable,
2145 FragmentCount,
2146 SadEntry,
2147 RecycleEvent
2148 );
2149 }
2150 //
2151 // The other protocols are not supported.
2152 //
2153 return EFI_UNSUPPORTED;
2154 }