1 /** @file
2   The implementation of IPSEC_CONFIG_PROTOCOL.
3 
4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "IpSecConfigImpl.h"
17 #include "IpSecDebug.h"
18 
19 LIST_ENTRY                mConfigData[IPsecConfigDataTypeMaximum];
20 BOOLEAN                   mSetBySelf = FALSE;
21 
22 //
23 // Common CompareSelector routine entry for SPD/SAD/PAD.
24 //
25 IPSEC_COMPARE_SELECTOR    mCompareSelector[] = {
26   (IPSEC_COMPARE_SELECTOR) CompareSpdSelector,
27   (IPSEC_COMPARE_SELECTOR) CompareSaId,
28   (IPSEC_COMPARE_SELECTOR) ComparePadId
29 };
30 
31 //
32 // Common IsZeroSelector routine entry for SPD/SAD/PAD.
33 //
34 IPSEC_IS_ZERO_SELECTOR    mIsZeroSelector[] = {
35   (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector,
36   (IPSEC_IS_ZERO_SELECTOR) IsZeroSaId,
37   (IPSEC_IS_ZERO_SELECTOR) IsZeroPadId
38 };
39 
40 //
41 // Common DuplicateSelector routine entry for SPD/SAD/PAD.
42 //
43 IPSEC_DUPLICATE_SELECTOR  mDuplicateSelector[] = {
44   (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector,
45   (IPSEC_DUPLICATE_SELECTOR) DuplicateSaId,
46   (IPSEC_DUPLICATE_SELECTOR) DuplicatePadId
47 };
48 
49 //
50 // Common FixPolicyEntry routine entry for SPD/SAD/PAD.
51 //
52 IPSEC_FIX_POLICY_ENTRY    mFixPolicyEntry[] = {
53   (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry,
54   (IPSEC_FIX_POLICY_ENTRY) FixSadEntry,
55   (IPSEC_FIX_POLICY_ENTRY) FixPadEntry
56 };
57 
58 //
59 // Common UnfixPolicyEntry routine entry for SPD/SAD/PAD.
60 //
61 IPSEC_FIX_POLICY_ENTRY    mUnfixPolicyEntry[] = {
62   (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry,
63   (IPSEC_FIX_POLICY_ENTRY) UnfixSadEntry,
64   (IPSEC_FIX_POLICY_ENTRY) UnfixPadEntry
65 };
66 
67 //
68 // Common SetPolicyEntry routine entry for SPD/SAD/PAD.
69 //
70 IPSEC_SET_POLICY_ENTRY    mSetPolicyEntry[] = {
71   (IPSEC_SET_POLICY_ENTRY) SetSpdEntry,
72   (IPSEC_SET_POLICY_ENTRY) SetSadEntry,
73   (IPSEC_SET_POLICY_ENTRY) SetPadEntry
74 };
75 
76 //
77 // Common GetPolicyEntry routine entry for SPD/SAD/PAD.
78 //
79 IPSEC_GET_POLICY_ENTRY    mGetPolicyEntry[] = {
80   (IPSEC_GET_POLICY_ENTRY) GetSpdEntry,
81   (IPSEC_GET_POLICY_ENTRY) GetSadEntry,
82   (IPSEC_GET_POLICY_ENTRY) GetPadEntry
83 };
84 
85 //
86 // Routine entry for IpSecConfig protocol.
87 //
88 EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = {
89   EfiIpSecConfigSetData,
90   EfiIpSecConfigGetData,
91   EfiIpSecConfigGetNextSelector,
92   EfiIpSecConfigRegisterNotify,
93   EfiIpSecConfigUnregisterNotify
94 };
95 
96 /**
97   Get the all IPSec configuration variables and store those variables
98   to the internal data structure.
99 
100   This founction is called by IpSecConfigInitialize() that is to intialize the
101   IPsecConfiguration Protocol.
102 
103   @param[in]  Private            Point to IPSEC_PRIVATE_DATA.
104 
105   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.
106   @retval EFI_SUCCESS            Restore the IPsec Configuration successfully.
107   @retval  others                Other errors is found during the variable getting.
108 
109 **/
110 EFI_STATUS
111 IpSecConfigRestore (
112   IN IPSEC_PRIVATE_DATA               *Private
113   );
114 
115 /**
116   Check if the specified EFI_IP_ADDRESS_INFO is in EFI_IP_ADDRESS_INFO list.
117 
118   @param[in]   AddressInfo         Pointer of IP_ADDRESS_INFO to be search in AddressInfo list.
119   @param[in]   AddressInfoList     A list that contains IP_ADDRESS_INFOs.
120   @param[in]   AddressCount        Point out how many IP_ADDRESS_INFO in the list.
121 
122   @retval  TRUE    The specified AddressInfo is in the AddressInfoList.
123   @retval  FALSE   The specified AddressInfo is not in the AddressInfoList.
124 
125 **/
126 BOOLEAN
IsInAddressInfoList(IN EFI_IP_ADDRESS_INFO * AddressInfo,IN EFI_IP_ADDRESS_INFO * AddressInfoList,IN UINT32 AddressCount)127 IsInAddressInfoList(
128   IN EFI_IP_ADDRESS_INFO              *AddressInfo,
129   IN EFI_IP_ADDRESS_INFO              *AddressInfoList,
130   IN UINT32                           AddressCount
131   )
132 {
133   UINT8           Index;
134   EFI_IP_ADDRESS  ZeroAddress;
135 
136   ZeroMem(&ZeroAddress, sizeof (EFI_IP_ADDRESS));
137 
138   //
139   // Zero Address means any address is matched.
140   //
141   if (AddressCount == 1) {
142     if (CompareMem (
143           &AddressInfoList[0].Address,
144           &ZeroAddress,
145           sizeof (EFI_IP_ADDRESS)
146           ) == 0) {
147       return TRUE;
148     }
149   }
150   for (Index = 0; Index < AddressCount ; Index++) {
151     if (CompareMem (
152           AddressInfo,
153           &AddressInfoList[Index].Address,
154           sizeof (EFI_IP_ADDRESS)
155           ) == 0 &&
156           AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength
157           ) {
158        return TRUE;
159      }
160   }
161   return FALSE;
162 }
163 
164 /**
165   Compare two SPD Selectors.
166 
167   Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
168   NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
169   Local Addresses and remote Addresses.
170 
171   @param[in]   Selector1           Pointer of first SPD Selector.
172   @param[in]   Selector2           Pointer of second SPD Selector.
173 
174   @retval  TRUE    This two Selector have the same value in above fields.
175   @retval  FALSE   Not all above fields have the same value in these two Selectors.
176 
177 **/
178 BOOLEAN
CompareSpdSelector(IN EFI_IPSEC_CONFIG_SELECTOR * Selector1,IN EFI_IPSEC_CONFIG_SELECTOR * Selector2)179 CompareSpdSelector (
180   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,
181   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2
182   )
183 {
184   EFI_IPSEC_SPD_SELECTOR  *SpdSel1;
185   EFI_IPSEC_SPD_SELECTOR  *SpdSel2;
186   BOOLEAN                 IsMatch;
187   UINTN                   Index;
188 
189   SpdSel1 = &Selector1->SpdSelector;
190   SpdSel2 = &Selector2->SpdSelector;
191   IsMatch = TRUE;
192 
193   //
194   // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
195   // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
196   // two Spdselectors. Since the SPD supports two directions, it needs to
197   // compare two directions.
198   //
199   if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount &&
200        SpdSel1->LocalAddressCount != SpdSel2->RemoteAddressCount) ||
201       (SpdSel1->RemoteAddressCount != SpdSel2->RemoteAddressCount &&
202        SpdSel1->RemoteAddressCount != SpdSel2->LocalAddressCount) ||
203        SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol ||
204        SpdSel1->LocalPort != SpdSel2->LocalPort ||
205        SpdSel1->LocalPortRange != SpdSel2->LocalPortRange ||
206        SpdSel1->RemotePort != SpdSel2->RemotePort ||
207        SpdSel1->RemotePortRange != SpdSel2->RemotePortRange
208        ) {
209     IsMatch = FALSE;
210     return IsMatch;
211   }
212 
213   //
214   // Compare the all LocalAddress and RemoteAddress fields in the two Spdselectors.
215   // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
216   // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return
217   // TRUE.
218   //
219   for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
220     if (!IsInAddressInfoList (
221           &SpdSel1->LocalAddress[Index],
222           SpdSel2->LocalAddress,
223           SpdSel2->LocalAddressCount
224           )) {
225       IsMatch = FALSE;
226       break;
227     }
228   }
229   if (IsMatch) {
230     for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {
231       if (!IsInAddressInfoList (
232             &SpdSel2->LocalAddress[Index],
233             SpdSel1->LocalAddress,
234             SpdSel1->LocalAddressCount
235             )) {
236         IsMatch = FALSE;
237         break;
238       }
239     }
240   }
241   if (IsMatch) {
242     for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
243       if (!IsInAddressInfoList (
244             &SpdSel1->RemoteAddress[Index],
245             SpdSel2->RemoteAddress,
246             SpdSel2->RemoteAddressCount
247             )) {
248         IsMatch = FALSE;
249         break;
250       }
251     }
252   }
253   if (IsMatch) {
254     for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {
255       if (!IsInAddressInfoList (
256             &SpdSel2->RemoteAddress[Index],
257             SpdSel1->RemoteAddress,
258             SpdSel1->RemoteAddressCount
259             )) {
260         IsMatch = FALSE;
261         break;
262       }
263     }
264   }
265   //
266   // Finish the one direction compare. If it is matched, return; otherwise,
267   // compare the other direction.
268   //
269   if (IsMatch) {
270     return IsMatch;
271   }
272   //
273   // Secondly, the SpdSel1->LocalAddress doesn't equal to  SpdSel2->LocalAddress and
274   // SpdSel1->RemoteAddress doesn't equal to SpdSel2->RemoteAddress. Try to compare
275   // the RemoteAddress to LocalAddress.
276   //
277   IsMatch = TRUE;
278   for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
279     if (!IsInAddressInfoList (
280           &SpdSel1->RemoteAddress[Index],
281           SpdSel2->LocalAddress,
282           SpdSel2->LocalAddressCount
283           )) {
284       IsMatch = FALSE;
285       break;
286     }
287   }
288   if (IsMatch) {
289     for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {
290       if (!IsInAddressInfoList (
291             &SpdSel2->RemoteAddress[Index],
292             SpdSel1->LocalAddress,
293             SpdSel1->LocalAddressCount
294             )) {
295         IsMatch = FALSE;
296         break;
297       }
298     }
299   }
300   if (IsMatch) {
301     for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
302       if (!IsInAddressInfoList (
303             &SpdSel1->LocalAddress[Index],
304             SpdSel2->RemoteAddress,
305             SpdSel2->RemoteAddressCount
306             )) {
307         IsMatch = FALSE;
308         break;
309       }
310     }
311   }
312   if (IsMatch) {
313     for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {
314       if (!IsInAddressInfoList (
315             &SpdSel2->LocalAddress[Index],
316             SpdSel1->RemoteAddress,
317             SpdSel1->RemoteAddressCount
318             )) {
319         IsMatch = FALSE;
320         break;
321       }
322     }
323   }
324   return IsMatch;
325 }
326 
327 /**
328   Find if the two SPD Selectors has subordinative.
329 
330   Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
331   NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
332   Local Addresses and remote Addresses.
333 
334   @param[in]   Selector1           Pointer of first SPD Selector.
335   @param[in]   Selector2           Pointer of second SPD Selector.
336 
337   @retval  TRUE    The first SPD Selector is subordinate Selector of second SPD Selector.
338   @retval  FALSE   The first SPD Selector is not subordinate Selector of second
339                    SPD Selector.
340 
341 **/
342 BOOLEAN
IsSubSpdSelector(IN EFI_IPSEC_CONFIG_SELECTOR * Selector1,IN EFI_IPSEC_CONFIG_SELECTOR * Selector2)343 IsSubSpdSelector (
344   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,
345   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2
346   )
347 {
348   EFI_IPSEC_SPD_SELECTOR  *SpdSel1;
349   EFI_IPSEC_SPD_SELECTOR  *SpdSel2;
350   BOOLEAN                 IsMatch;
351   UINTN                   Index;
352 
353   SpdSel1 = &Selector1->SpdSelector;
354   SpdSel2 = &Selector2->SpdSelector;
355   IsMatch = TRUE;
356 
357   //
358   // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
359   // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
360   // two Spdselectors. Since the SPD supports two directions, it needs to
361   // compare two directions.
362   //
363   if (SpdSel1->LocalAddressCount > SpdSel2->LocalAddressCount ||
364       SpdSel1->RemoteAddressCount > SpdSel2->RemoteAddressCount ||
365       (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||
366       (SpdSel1->LocalPort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0)||
367       (SpdSel1->LocalPortRange > SpdSel2->LocalPortRange && SpdSel1->LocalPort != 0)||
368       (SpdSel1->RemotePort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0) ||
369       (SpdSel1->RemotePortRange > SpdSel2->RemotePortRange && SpdSel2->RemotePort != 0)
370       ) {
371     IsMatch = FALSE;
372   }
373 
374   //
375   // Compare the all LocalAddress and RemoteAddress fields in the two Spdselectors.
376   // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
377   // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return
378   // TRUE.
379   //
380   if (IsMatch) {
381     for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
382       if (!IsInAddressInfoList (
383             &SpdSel1->LocalAddress[Index],
384             SpdSel2->LocalAddress,
385             SpdSel2->LocalAddressCount
386             )) {
387         IsMatch = FALSE;
388         break;
389       }
390     }
391 
392     if (IsMatch) {
393       for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
394         if (!IsInAddressInfoList (
395               &SpdSel1->RemoteAddress[Index],
396               SpdSel2->RemoteAddress,
397               SpdSel2->RemoteAddressCount
398               )) {
399           IsMatch = FALSE;
400           break;
401         }
402       }
403     }
404   }
405   if (IsMatch) {
406     return IsMatch;
407   }
408 
409   //
410   //
411   // The SPD selector in SPD entry is two way.
412   //
413   // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
414   // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
415   // two Spdselectors. Since the SPD supports two directions, it needs to
416   // compare two directions.
417   //
418   IsMatch = TRUE;
419   if (SpdSel1->LocalAddressCount > SpdSel2->RemoteAddressCount ||
420       SpdSel1->RemoteAddressCount > SpdSel2->LocalAddressCount ||
421       (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||
422       (SpdSel1->LocalPort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0)||
423       (SpdSel1->LocalPortRange > SpdSel2->RemotePortRange && SpdSel1->RemotePort != 0)||
424       (SpdSel1->RemotePort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0) ||
425       (SpdSel1->RemotePortRange > SpdSel2->LocalPortRange && SpdSel2->LocalPort != 0)
426       ) {
427     IsMatch = FALSE;
428     return IsMatch;
429   }
430 
431   //
432   // Compare the all LocalAddress and RemoteAddress fields in the two Spdselectors.
433   // First, SpdSel1->LocalAddress to SpdSel2->RemoteAddress && Compare
434   // SpdSel1->RemoteAddress to SpdSel2->LocalAddress. If all match, return
435   // TRUE.
436   //
437   for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
438     if (!IsInAddressInfoList (
439           &SpdSel1->LocalAddress[Index],
440           SpdSel2->RemoteAddress,
441           SpdSel2->RemoteAddressCount
442           )) {
443       IsMatch = FALSE;
444       break;
445     }
446   }
447 
448   if (IsMatch) {
449     for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
450       if (!IsInAddressInfoList (
451             &SpdSel1->RemoteAddress[Index],
452             SpdSel2->LocalAddress,
453             SpdSel2->LocalAddressCount
454             )) {
455         IsMatch = FALSE;
456         break;
457       }
458     }
459   }
460   return IsMatch;
461 
462 }
463 
464 /**
465   Compare two SA IDs.
466 
467   @param[in]   Selector1           Pointer of first SA ID.
468   @param[in]   Selector2           Pointer of second SA ID.
469 
470   @retval  TRUE    This two Selectors have the same SA ID.
471   @retval  FALSE   This two Selecotrs don't have the same SA ID.
472 
473 **/
474 BOOLEAN
CompareSaId(IN EFI_IPSEC_CONFIG_SELECTOR * Selector1,IN EFI_IPSEC_CONFIG_SELECTOR * Selector2)475 CompareSaId (
476   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,
477   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2
478   )
479 {
480   EFI_IPSEC_SA_ID *SaId1;
481   EFI_IPSEC_SA_ID *SaId2;
482   BOOLEAN         IsMatch;
483 
484   SaId1   = &Selector1->SaId;
485   SaId2   = &Selector2->SaId;
486   IsMatch = TRUE;
487 
488   if (CompareMem (SaId1, SaId2, sizeof (EFI_IPSEC_SA_ID)) != 0) {
489     IsMatch = FALSE;
490   }
491 
492   return IsMatch;
493 }
494 
495 /**
496   Compare two PAD IDs.
497 
498   @param[in]   Selector1           Pointer of first PAD ID.
499   @param[in]   Selector2           Pointer of second PAD ID.
500 
501   @retval  TRUE    This two Selectors have the same PAD ID.
502   @retval  FALSE   This two Selecotrs don't have the same PAD ID.
503 
504 **/
505 BOOLEAN
ComparePadId(IN EFI_IPSEC_CONFIG_SELECTOR * Selector1,IN EFI_IPSEC_CONFIG_SELECTOR * Selector2)506 ComparePadId (
507   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,
508   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2
509   )
510 {
511   EFI_IPSEC_PAD_ID  *PadId1;
512   EFI_IPSEC_PAD_ID  *PadId2;
513   BOOLEAN           IsMatch;
514 
515   PadId1  = &Selector1->PadId;
516   PadId2  = &Selector2->PadId;
517   IsMatch = TRUE;
518 
519   //
520   // Compare the PeerIdValid fields in PadId.
521   //
522   if (PadId1->PeerIdValid != PadId2->PeerIdValid) {
523     IsMatch = FALSE;
524   }
525   //
526   // Compare the PeerId fields in PadId if PeerIdValid is true.
527   //
528   if (IsMatch &&
529       PadId1->PeerIdValid &&
530       AsciiStriCmp ((CONST CHAR8 *) PadId1->Id.PeerId, (CONST CHAR8 *) PadId2->Id.PeerId) != 0
531       ) {
532     IsMatch = FALSE;
533   }
534   //
535   // Compare the IpAddress fields in PadId if PeerIdValid is false.
536   //
537   if (IsMatch &&
538       !PadId1->PeerIdValid &&
539       (PadId1->Id.IpAddress.PrefixLength != PadId2->Id.IpAddress.PrefixLength ||
540        CompareMem (&PadId1->Id.IpAddress.Address, &PadId2->Id.IpAddress.Address, sizeof (EFI_IP_ADDRESS)) != 0)
541       ) {
542     IsMatch = FALSE;
543   }
544 
545   return IsMatch;
546 }
547 
548 /**
549   Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount
550   fields.
551 
552   @param[in]  Selector      Pointer of the SPD Selector.
553 
554   @retval     TRUE          If the SPD Selector is Zero.
555   @retval     FALSE         If the SPD Selector is not Zero.
556 
557 **/
558 BOOLEAN
IsZeroSpdSelector(IN EFI_IPSEC_CONFIG_SELECTOR * Selector)559 IsZeroSpdSelector (
560   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector
561   )
562 {
563   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
564   BOOLEAN                 IsZero;
565 
566   SpdSel  = &Selector->SpdSelector;
567   IsZero  = FALSE;
568 
569   if (SpdSel->LocalAddressCount == 0 && SpdSel->RemoteAddressCount == 0) {
570     IsZero = TRUE;
571   }
572 
573   return IsZero;
574 }
575 
576 /**
577   Check if the SA ID is Zero by its DestAddress.
578 
579   @param[in]  Selector      Pointer of the SA ID.
580 
581   @retval     TRUE          If the SA ID is Zero.
582   @retval     FALSE         If the SA ID is not Zero.
583 
584 **/
585 BOOLEAN
IsZeroSaId(IN EFI_IPSEC_CONFIG_SELECTOR * Selector)586 IsZeroSaId (
587   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector
588   )
589 {
590   BOOLEAN                   IsZero;
591   EFI_IPSEC_CONFIG_SELECTOR ZeroSelector;
592 
593   IsZero    = FALSE;
594 
595   ZeroMem (&ZeroSelector, sizeof (EFI_IPSEC_CONFIG_SELECTOR));
596 
597   if (CompareMem (&ZeroSelector, Selector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)) == 0) {
598     IsZero = TRUE;
599   }
600 
601   return IsZero;
602 }
603 
604 /**
605   Check if the PAD ID is Zero.
606 
607   @param[in]  Selector      Pointer of the PAD ID.
608 
609   @retval     TRUE          If the PAD ID is Zero.
610   @retval     FALSE         If the PAD ID is not Zero.
611 
612 **/
613 BOOLEAN
IsZeroPadId(IN EFI_IPSEC_CONFIG_SELECTOR * Selector)614 IsZeroPadId (
615   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector
616   )
617 {
618   EFI_IPSEC_PAD_ID  *PadId;
619   EFI_IPSEC_PAD_ID  ZeroId;
620   BOOLEAN           IsZero;
621 
622   PadId   = &Selector->PadId;
623   IsZero  = FALSE;
624 
625   ZeroMem (&ZeroId, sizeof (EFI_IPSEC_PAD_ID));
626 
627   if (CompareMem (PadId, &ZeroId, sizeof (EFI_IPSEC_PAD_ID)) == 0) {
628     IsZero = TRUE;
629   }
630 
631   return IsZero;
632 }
633 
634 /**
635   Copy Source SPD Selector to the Destination SPD Selector.
636 
637   @param[in, out] DstSel             Pointer of Destination SPD Selector.
638   @param[in]      SrcSel             Pointer of Source SPD Selector.
639   @param[in, out] Size               The size of the Destination SPD Selector. If it
640                                      not NULL and its value less than the size of
641                                      Source SPD Selector, the value of Source SPD
642                                      Selector's size will be passed to caller by this
643                                      parameter.
644 
645   @retval EFI_INVALID_PARAMETER  If the Destination or Source SPD Selector is NULL
646   @retval EFI_BUFFER_TOO_SMALL   If the input Size is less than size of the Source SPD Selector.
647   @retval EFI_SUCCESS            Copy Source SPD Selector to the Destination SPD
648                                  Selector successfully.
649 
650 **/
651 EFI_STATUS
DuplicateSpdSelector(IN OUT EFI_IPSEC_CONFIG_SELECTOR * DstSel,IN EFI_IPSEC_CONFIG_SELECTOR * SrcSel,IN OUT UINTN * Size)652 DuplicateSpdSelector (
653   IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,
654   IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,
655   IN OUT UINTN                        *Size
656   )
657 {
658   EFI_IPSEC_SPD_SELECTOR  *Dst;
659   EFI_IPSEC_SPD_SELECTOR  *Src;
660 
661   Dst = &DstSel->SpdSelector;
662   Src = &SrcSel->SpdSelector;
663 
664   if (Dst == NULL || Src == NULL) {
665     return EFI_INVALID_PARAMETER;
666   }
667 
668   if (Size != NULL && (*Size) < SIZE_OF_SPD_SELECTOR (Src)) {
669     *Size = SIZE_OF_SPD_SELECTOR (Src);
670     return EFI_BUFFER_TOO_SMALL;
671   }
672   //
673   // Copy the base structure of SPD selector.
674   //
675   CopyMem (Dst, Src, sizeof (EFI_IPSEC_SPD_SELECTOR));
676 
677   //
678   // Copy the local address array of SPD selector.
679   //
680   Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1);
681   CopyMem (
682     Dst->LocalAddress,
683     Src->LocalAddress,
684     sizeof (EFI_IP_ADDRESS_INFO) * Dst->LocalAddressCount
685     );
686 
687   //
688   // Copy the remote address array of SPD selector.
689   //
690   Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount;
691   CopyMem (
692     Dst->RemoteAddress,
693     Src->RemoteAddress,
694     sizeof (EFI_IP_ADDRESS_INFO) * Dst->RemoteAddressCount
695     );
696 
697   return EFI_SUCCESS;
698 }
699 
700 /**
701   Copy Source SA ID to the Destination SA ID.
702 
703   @param[in, out] DstSel             Pointer of Destination SA ID.
704   @param[in]      SrcSel             Pointer of Source SA ID.
705   @param[in, out] Size               The size of the Destination SA ID. If it
706                                      not NULL and its value less than the size of
707                                      Source SA ID, the value of Source SA ID's size
708                                      will be passed to caller by this parameter.
709 
710   @retval EFI_INVALID_PARAMETER  If the Destination or Source SA ID is NULL.
711   @retval EFI_BUFFER_TOO_SMALL   If the input Size less than size of source SA ID.
712   @retval EFI_SUCCESS            Copy Source SA ID  to the Destination SA ID successfully.
713 
714 **/
715 EFI_STATUS
DuplicateSaId(IN OUT EFI_IPSEC_CONFIG_SELECTOR * DstSel,IN EFI_IPSEC_CONFIG_SELECTOR * SrcSel,IN OUT UINTN * Size)716 DuplicateSaId (
717   IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,
718   IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,
719   IN OUT UINTN                        *Size
720   )
721 {
722   EFI_IPSEC_SA_ID *Dst;
723   EFI_IPSEC_SA_ID *Src;
724 
725   Dst = &DstSel->SaId;
726   Src = &SrcSel->SaId;
727 
728   if (Dst == NULL || Src == NULL) {
729     return EFI_INVALID_PARAMETER;
730   }
731 
732   if (Size != NULL && *Size < sizeof (EFI_IPSEC_SA_ID)) {
733     *Size = sizeof (EFI_IPSEC_SA_ID);
734     return EFI_BUFFER_TOO_SMALL;
735   }
736 
737   CopyMem (Dst, Src, sizeof (EFI_IPSEC_SA_ID));
738 
739   return EFI_SUCCESS;
740 }
741 
742 /**
743   Copy Source PAD ID to the Destination PAD ID.
744 
745   @param[in, out] DstSel             Pointer of Destination PAD ID.
746   @param[in]      SrcSel             Pointer of Source PAD ID.
747   @param[in, out] Size               The size of the Destination PAD ID. If it
748                                      not NULL and its value less than the size of
749                                      Source PAD ID, the value of Source PAD ID's size
750                                      will be passed to caller by this parameter.
751 
752   @retval EFI_INVALID_PARAMETER  If the Destination or Source PAD ID is NULL.
753   @retval EFI_BUFFER_TOO_SMALL   If the input Size less than size of source PAD ID .
754   @retval EFI_SUCCESS            Copy Source PAD ID  to the Destination PAD ID successfully.
755 
756 **/
757 EFI_STATUS
DuplicatePadId(IN OUT EFI_IPSEC_CONFIG_SELECTOR * DstSel,IN EFI_IPSEC_CONFIG_SELECTOR * SrcSel,IN OUT UINTN * Size)758 DuplicatePadId (
759   IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,
760   IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,
761   IN OUT UINTN                        *Size
762   )
763 {
764   EFI_IPSEC_PAD_ID  *Dst;
765   EFI_IPSEC_PAD_ID  *Src;
766 
767   Dst = &DstSel->PadId;
768   Src = &SrcSel->PadId;
769 
770   if (Dst == NULL || Src == NULL) {
771     return EFI_INVALID_PARAMETER;
772   }
773 
774   if (Size != NULL && *Size < sizeof (EFI_IPSEC_PAD_ID)) {
775     *Size = sizeof (EFI_IPSEC_PAD_ID);
776     return EFI_BUFFER_TOO_SMALL;
777   }
778 
779   CopyMem (Dst, Src, sizeof (EFI_IPSEC_PAD_ID));
780 
781   return EFI_SUCCESS;
782 }
783 
784 /**
785   Fix the value of some members of SPD Selector.
786 
787   This function is called by IpSecCopyPolicyEntry()which copy the Policy
788   Entry into the Variable. Since some members in SPD Selector are pointers,
789   a physical address to relative address convertion is required before copying
790   this SPD entry into the variable.
791 
792   @param[in]       Selector              Pointer of SPD Selector.
793   @param[in, out]  Data                  Pointer of SPD Data.
794 
795 **/
796 VOID
FixSpdEntry(IN EFI_IPSEC_SPD_SELECTOR * Selector,IN OUT EFI_IPSEC_SPD_DATA * Data)797 FixSpdEntry (
798   IN     EFI_IPSEC_SPD_SELECTOR            *Selector,
799   IN OUT EFI_IPSEC_SPD_DATA                *Data
800   )
801 {
802   //
803   // It assumes that all ref buffers in SPD selector and data are
804   // stored in the continous memory and close to the base structure.
805   //
806   FIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);
807   FIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);
808 
809   if (Data->ProcessingPolicy != NULL) {
810     if (Data->ProcessingPolicy->TunnelOption != NULL) {
811       FIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);
812     }
813 
814     FIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);
815   }
816 
817 }
818 
819 /**
820   Fix the value of some members of SA ID.
821 
822   This function is called by IpSecCopyPolicyEntry()which copy the Policy
823   Entry into the Variable. Since some members in SA ID are pointers,
824   a physical address to relative address conversion is required before copying
825   this SAD into the variable.
826 
827   @param[in]       SaId                  Pointer of SA ID
828   @param[in, out]  Data                  Pointer of SA Data.
829 
830 **/
831 VOID
FixSadEntry(IN EFI_IPSEC_SA_ID * SaId,IN OUT EFI_IPSEC_SA_DATA2 * Data)832 FixSadEntry (
833   IN     EFI_IPSEC_SA_ID                  *SaId,
834   IN OUT EFI_IPSEC_SA_DATA2                *Data
835   )
836 {
837   //
838   // It assumes that all ref buffers in SAD selector and data are
839   // stored in the continous memory and close to the base structure.
840   //
841   if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
842     FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);
843   }
844 
845   if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
846     FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);
847   }
848 
849   if (Data->SpdSelector != NULL) {
850     if (Data->SpdSelector->LocalAddress != NULL) {
851       FIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);
852     }
853 
854     FIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);
855     FIX_REF_BUF_ADDR (Data->SpdSelector, Data);
856   }
857 
858 }
859 
860 /**
861   Fix the value of some members of PAD ID.
862 
863   This function is called by IpSecCopyPolicyEntry()which copy the Policy
864   Entry into the Variable. Since some members in PAD ID are pointers,
865   a physical address to relative address conversion is required before copying
866   this PAD into the variable.
867 
868   @param[in]       PadId              Pointer of PAD ID.
869   @param[in, out]  Data               Pointer of PAD Data.
870 
871 **/
872 VOID
FixPadEntry(IN EFI_IPSEC_PAD_ID * PadId,IN OUT EFI_IPSEC_PAD_DATA * Data)873 FixPadEntry (
874   IN     EFI_IPSEC_PAD_ID                  *PadId,
875   IN OUT EFI_IPSEC_PAD_DATA                *Data
876   )
877 {
878   //
879   // It assumes that all ref buffers in pad selector and data are
880   // stored in the continous memory and close to the base structure.
881   //
882   if (Data->AuthData != NULL) {
883     FIX_REF_BUF_ADDR (Data->AuthData, Data);
884   }
885 
886   if (Data->RevocationData != NULL) {
887     FIX_REF_BUF_ADDR (Data->RevocationData, Data);
888   }
889 
890 }
891 
892 /**
893   Recover the value of some members of SPD Selector.
894 
895   This function is corresponding to FixSpdEntry(). It recovers the value of members
896   of SPD Selector that are fixed by FixSpdEntry().
897 
898   @param[in, out]  Selector              Pointer of SPD Selector.
899   @param[in, out]  Data                  Pointer of SPD Data.
900 
901 **/
902 VOID
UnfixSpdEntry(IN OUT EFI_IPSEC_SPD_SELECTOR * Selector,IN OUT EFI_IPSEC_SPD_DATA * Data)903 UnfixSpdEntry (
904   IN OUT EFI_IPSEC_SPD_SELECTOR           *Selector,
905   IN OUT EFI_IPSEC_SPD_DATA               *Data
906   )
907 {
908   //
909   // It assumes that all ref buffers in SPD selector and data are
910   // stored in the continous memory and close to the base structure.
911   //
912   UNFIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);
913   UNFIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);
914 
915   if (Data->ProcessingPolicy != NULL) {
916     UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);
917     if (Data->ProcessingPolicy->TunnelOption != NULL) {
918       UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);
919     }
920   }
921 
922 }
923 
924 /**
925   Recover the value of some members of SA ID.
926 
927   This function is corresponding to FixSadEntry(). It recovers the value of members
928   of SAD ID that are fixed by FixSadEntry().
929 
930   @param[in, out]  SaId              Pointer of SAD ID.
931   @param[in, out]  Data              Pointer of SAD Data.
932 
933 **/
934 VOID
UnfixSadEntry(IN OUT EFI_IPSEC_SA_ID * SaId,IN OUT EFI_IPSEC_SA_DATA2 * Data)935 UnfixSadEntry (
936   IN OUT EFI_IPSEC_SA_ID                     *SaId,
937   IN OUT EFI_IPSEC_SA_DATA2                   *Data
938   )
939 {
940   //
941   // It assumes that all ref buffers in SAD selector and data are
942   // stored in the continous memory and close to the base structure.
943   //
944   if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
945     UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);
946   }
947 
948   if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
949     UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);
950   }
951 
952   if (Data->SpdSelector != NULL) {
953     UNFIX_REF_BUF_ADDR (Data->SpdSelector, Data);
954     if (Data->SpdSelector->LocalAddress != NULL) {
955       UNFIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);
956     }
957 
958     UNFIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);
959   }
960 
961 }
962 
963 /**
964   Recover the value of some members of PAD ID.
965 
966   This function is corresponding to FixPadEntry(). It recovers the value of members
967   of PAD ID that are fixed by FixPadEntry().
968 
969   @param[in]       PadId              Pointer of PAD ID.
970   @param[in, out]  Data               Pointer of PAD Data.
971 
972 **/
973 VOID
UnfixPadEntry(IN EFI_IPSEC_PAD_ID * PadId,IN OUT EFI_IPSEC_PAD_DATA * Data)974 UnfixPadEntry (
975   IN     EFI_IPSEC_PAD_ID                 *PadId,
976   IN OUT EFI_IPSEC_PAD_DATA               *Data
977   )
978 {
979   //
980   // It assumes that all ref buffers in pad selector and data are
981   // stored in the continous memory and close to the base structure.
982   //
983   if (Data->AuthData != NULL) {
984     UNFIX_REF_BUF_ADDR (Data->AuthData, Data);
985   }
986 
987   if (Data->RevocationData != NULL) {
988     UNFIX_REF_BUF_ADDR (Data->RevocationData, Data);
989   }
990 
991 }
992 
993 /**
994   Set the security policy information for the EFI IPsec driver.
995 
996   The IPsec configuration data has a unique selector/identifier separately to
997   identify a data entry.
998 
999   @param[in]  Selector           Pointer to an entry selector on operated
1000                                  configuration data specified by DataType.
1001                                  A NULL Selector causes the entire specified-type
1002                                  configuration information to be flushed.
1003   @param[in]  Data               The data buffer to be set. The structure
1004                                  of the data buffer should be EFI_IPSEC_SPD_DATA.
1005   @param[in]  Context            Pointer to one entry selector that describes
1006                                  the expected position the new data entry will
1007                                  be added. If Context is NULL, the new entry will
1008                                  be appended the end of database.
1009 
1010   @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:
1011                                    - Selector is not NULL and its LocalAddress
1012                                      is NULL or its RemoteAddress is NULL.
1013                                    - Data is not NULL and its Action is Protected
1014                                      and its plolicy is NULL.
1015                                    - Data is not NULL, its Action is not protected,
1016                                      and its policy is not NULL.
1017                                    - The Action of Data is Protected, its policy
1018                                      mode is Tunnel, and its tunnel option is NULL.
1019                                    - The Action of Data is protected and its policy
1020                                      mode is not Tunnel and it tunnel option is not NULL.
1021                                    - SadEntry requied to be set into new SpdEntry's Sas has
1022                                      been found but it is invalid.
1023   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
1024   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1025 
1026 **/
1027 EFI_STATUS
SetSpdEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1028 SetSpdEntry (
1029   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1030   IN VOID                            *Data,
1031   IN VOID                            *Context OPTIONAL
1032   )
1033 {
1034   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
1035   EFI_IPSEC_SPD_DATA      *SpdData;
1036   EFI_IPSEC_SPD_SELECTOR  *InsertBefore;
1037   LIST_ENTRY              *SpdList;
1038   LIST_ENTRY              *SadList;
1039   LIST_ENTRY              *SpdSas;
1040   LIST_ENTRY              *EntryInsertBefore;
1041   LIST_ENTRY              *Entry;
1042   LIST_ENTRY              *Entry2;
1043   LIST_ENTRY              *NextEntry;
1044   LIST_ENTRY              *NextEntry2;
1045   IPSEC_SPD_ENTRY         *SpdEntry;
1046   IPSEC_SAD_ENTRY         *SadEntry;
1047   UINTN                   SpdEntrySize;
1048   UINTN                   Index;
1049 
1050   SpdSel        = (Selector == NULL) ? NULL : &Selector->SpdSelector;
1051   SpdData       = (Data == NULL) ? NULL : (EFI_IPSEC_SPD_DATA *) Data;
1052   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SpdSelector;
1053   SpdList       = &mConfigData[IPsecConfigDataTypeSpd];
1054 
1055   if (SpdSel != NULL) {
1056     if (SpdSel->LocalAddress == NULL || SpdSel->RemoteAddress == NULL) {
1057       return EFI_INVALID_PARAMETER;
1058     }
1059   }
1060 
1061   if (SpdData != NULL) {
1062     if ((SpdData->Action == EfiIPsecActionProtect && SpdData->ProcessingPolicy == NULL) ||
1063         (SpdData->Action != EfiIPsecActionProtect && SpdData->ProcessingPolicy != NULL)
1064         ) {
1065       return EFI_INVALID_PARAMETER;
1066     }
1067 
1068     if (SpdData->Action == EfiIPsecActionProtect) {
1069       if ((SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption == NULL) ||
1070           (SpdData->ProcessingPolicy->Mode != EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption != NULL)
1071           ) {
1072         return EFI_INVALID_PARAMETER;
1073       }
1074     }
1075   }
1076   //
1077   // The default behavior is to insert the node ahead of the header.
1078   //
1079   EntryInsertBefore = SpdList;
1080 
1081   //
1082   // Remove the existed SPD entry.
1083   //
1084   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) {
1085 
1086     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1087 
1088     if (SpdSel == NULL ||
1089         CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel)
1090         ) {
1091       //
1092       // Record the existed entry position to keep the original order.
1093       //
1094       EntryInsertBefore = SpdEntry->List.ForwardLink;
1095       RemoveEntryList (&SpdEntry->List);
1096 
1097       //
1098       // Update the reverse ref of SAD entry in the SPD.sas list.
1099       //
1100       SpdSas = &SpdEntry->Data->Sas;
1101 
1102       //
1103       // Remove the related SAs from Sas(SadEntry->BySpd). If the SA entry is established by
1104       // IKE, remove from mConfigData list(SadEntry->List) and then free it directly since its
1105       // SpdEntry will be freed later.
1106       //
1107       NET_LIST_FOR_EACH_SAFE (Entry2, NextEntry2, SpdSas) {
1108         SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);
1109 
1110         if (SadEntry->Data->SpdEntry != NULL) {
1111           RemoveEntryList (&SadEntry->BySpd);
1112           SadEntry->Data->SpdEntry = NULL;
1113         }
1114 
1115         if (!(SadEntry->Data->ManualSet)) {
1116           RemoveEntryList (&SadEntry->List);
1117           FreePool (SadEntry);
1118         }
1119       }
1120 
1121       //
1122       // Free the existed SPD entry
1123       //
1124       FreePool (SpdEntry);
1125     }
1126   }
1127   //
1128   // Return success here if only want to remove the SPD entry.
1129   //
1130   if (SpdData == NULL || SpdSel == NULL) {
1131     return EFI_SUCCESS;
1132   }
1133   //
1134   // Search the appointed entry position if InsertBefore is not NULL.
1135   //
1136   if (InsertBefore != NULL) {
1137 
1138     NET_LIST_FOR_EACH (Entry, SpdList) {
1139       SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1140 
1141       if (CompareSpdSelector (
1142             (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
1143             (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1144             )) {
1145         EntryInsertBefore = Entry;
1146         break;
1147       }
1148     }
1149   }
1150 
1151   //
1152   // Do Padding for the different Arch.
1153   //
1154   SpdEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SPD_ENTRY));
1155   SpdEntrySize  = ALIGN_VARIABLE (SpdEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SpdSel));
1156   SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData);
1157 
1158   SpdEntry = AllocateZeroPool (SpdEntrySize);
1159 
1160   if (SpdEntry == NULL) {
1161     return EFI_OUT_OF_RESOURCES;
1162   }
1163   //
1164   // Fix the address of Selector and Data buffer and copy them, which is
1165   // continous memory and close to the base structure of SPD entry.
1166   //
1167   SpdEntry->Selector  = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN));
1168   SpdEntry->Data      = (IPSEC_SPD_DATA *) ALIGN_POINTER (
1169                                             ((UINT8 *) SpdEntry->Selector + SIZE_OF_SPD_SELECTOR (SpdSel)),
1170                                             sizeof (UINTN)
1171                                             );
1172 
1173   DuplicateSpdSelector (
1174     (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
1175     (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
1176     NULL
1177     );
1178 
1179   CopyMem (
1180     SpdEntry->Data->Name,
1181     SpdData->Name,
1182     sizeof (SpdData->Name)
1183     );
1184   SpdEntry->Data->PackageFlag      = SpdData->PackageFlag;
1185   SpdEntry->Data->TrafficDirection = SpdData->TrafficDirection;
1186   SpdEntry->Data->Action           = SpdData->Action;
1187 
1188   //
1189   // Fix the address of ProcessingPolicy and copy it if need, which is continous
1190   // memory and close to the base structure of SAD data.
1191   //
1192   if (SpdData->Action != EfiIPsecActionProtect) {
1193     SpdEntry->Data->ProcessingPolicy = NULL;
1194   } else {
1195     SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER (
1196                                                                       SpdEntry->Data + 1,
1197                                                                       sizeof (UINTN)
1198                                                                       );
1199     IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);
1200   }
1201   //
1202   // Update the sas list of the new SPD entry.
1203   //
1204   InitializeListHead (&SpdEntry->Data->Sas);
1205 
1206   SadList = &mConfigData[IPsecConfigDataTypeSad];
1207 
1208   NET_LIST_FOR_EACH (Entry, SadList) {
1209     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1210 
1211       for (Index = 0; Index < SpdData->SaIdCount; Index++) {
1212         if (CompareSaId (
1213               (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],
1214               (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
1215               )) {
1216           //
1217           // Check whether the found SadEntry is vaild.
1218           //
1219           if (IsSubSpdSelector (
1220                 (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1221                 (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1222                 )) {
1223             if (SadEntry->Data->SpdEntry != NULL) {
1224               RemoveEntryList (&SadEntry->BySpd);
1225             }
1226             InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1227             SadEntry->Data->SpdEntry = SpdEntry;
1228           } else {
1229             return EFI_INVALID_PARAMETER;
1230           }
1231         }
1232       }
1233   }
1234 
1235   //
1236   // Insert the new SPD entry.
1237   //
1238   InsertTailList (EntryInsertBefore, &SpdEntry->List);
1239 
1240   return EFI_SUCCESS;
1241 }
1242 
1243 /**
1244   Set the security association information for the EFI IPsec driver.
1245 
1246   The IPsec configuration data has a unique selector/identifier separately to
1247   identify a data entry.
1248 
1249   @param[in]  Selector           Pointer to an entry selector on operated
1250                                  configuration data specified by DataType.
1251                                  A NULL Selector causes the entire specified-type
1252                                  configuration information to be flushed.
1253   @param[in]  Data               The data buffer to be set. The structure
1254                                  of the data buffer should be EFI_IPSEC_SA_DATA.
1255   @param[in]  Context            Pointer to one entry selector which describes
1256                                  the expected position the new data entry will
1257                                  be added. If Context is NULL,the new entry will
1258                                  be appended the end of database.
1259 
1260   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
1261   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1262 
1263 **/
1264 EFI_STATUS
SetSadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1265 SetSadEntry (
1266   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1267   IN VOID                            *Data,
1268   IN VOID                            *Context OPTIONAL
1269   )
1270 {
1271   IPSEC_SAD_ENTRY   *SadEntry;
1272   IPSEC_SPD_ENTRY   *SpdEntry;
1273   LIST_ENTRY        *Entry;
1274   LIST_ENTRY        *NextEntry;
1275   LIST_ENTRY        *SadList;
1276   LIST_ENTRY        *SpdList;
1277   EFI_IPSEC_SA_ID   *SaId;
1278   EFI_IPSEC_SA_DATA2 *SaData;
1279   EFI_IPSEC_SA_ID   *InsertBefore;
1280   LIST_ENTRY        *EntryInsertBefore;
1281   UINTN             SadEntrySize;
1282 
1283   SaId          = (Selector == NULL) ? NULL : &Selector->SaId;
1284   SaData        = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data;
1285   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;
1286   SadList       = &mConfigData[IPsecConfigDataTypeSad];
1287 
1288   //
1289   // The default behavior is to insert the node ahead of the header.
1290   //
1291   EntryInsertBefore = SadList;
1292 
1293   //
1294   // Remove the existed SAD entry.
1295   //
1296   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {
1297 
1298     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1299 
1300     if (SaId == NULL ||
1301         CompareSaId (
1302           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1303           (EFI_IPSEC_CONFIG_SELECTOR *) SaId
1304           )) {
1305       //
1306       // Record the existed entry position to keep the original order.
1307       //
1308       EntryInsertBefore = SadEntry->List.ForwardLink;
1309 
1310       //
1311       // Update the related SAD.byspd field.
1312       //
1313       if (SadEntry->Data->SpdEntry != NULL) {
1314         RemoveEntryList (&SadEntry->BySpd);
1315       }
1316 
1317       RemoveEntryList (&SadEntry->List);
1318       FreePool (SadEntry);
1319     }
1320   }
1321   //
1322   // Return success here if only want to remove the SAD entry
1323   //
1324   if (SaData == NULL || SaId == NULL) {
1325     return EFI_SUCCESS;
1326   }
1327   //
1328   // Search the appointed entry position if InsertBefore is not NULL.
1329   //
1330   if (InsertBefore != NULL) {
1331 
1332     NET_LIST_FOR_EACH (Entry, SadList) {
1333       SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1334 
1335       if (CompareSaId (
1336            (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1337            (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1338            )) {
1339         EntryInsertBefore = Entry;
1340         break;
1341       }
1342     }
1343   }
1344 
1345   //
1346   // Do Padding for different Arch.
1347   //
1348   SadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY));
1349   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_ID));
1350   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA));
1351 
1352   if (SaId->Proto == EfiIPsecAH) {
1353     SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength;
1354   } else {
1355     SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength);
1356     SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength);
1357   }
1358 
1359   if (SaData->SpdSelector != NULL) {
1360     SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);
1361   }
1362   SadEntry      = AllocateZeroPool (SadEntrySize);
1363 
1364   if (SadEntry == NULL) {
1365     return EFI_OUT_OF_RESOURCES;
1366   }
1367   //
1368   // Fix the address of Id and Data buffer and copy them, which is
1369   // continous memory and close to the base structure of SAD entry.
1370   //
1371   SadEntry->Id    = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN));
1372   SadEntry->Data  = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN));
1373 
1374   CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID));
1375 
1376   SadEntry->Data->Mode                  = SaData->Mode;
1377   SadEntry->Data->SequenceNumber        = SaData->SNCount;
1378   SadEntry->Data->AntiReplayWindowSize  = SaData->AntiReplayWindows;
1379 
1380   ZeroMem (
1381     &SadEntry->Data->AntiReplayBitmap,
1382     sizeof (SadEntry->Data->AntiReplayBitmap)
1383     );
1384 
1385   ZeroMem (
1386     &SadEntry->Data->AlgoInfo,
1387     sizeof (EFI_IPSEC_ALGO_INFO)
1388     );
1389 
1390   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId;
1391   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength;
1392 
1393   if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
1394     SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN));
1395     CopyMem (
1396       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1397       SaData->AlgoInfo.EspAlgoInfo.AuthKey,
1398       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength
1399       );
1400   }
1401 
1402   if (SaId->Proto == EfiIPsecESP) {
1403     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId    = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId;
1404     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;
1405 
1406     if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
1407       SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
1408                                                                ((UINT8 *) (SadEntry->Data + 1) +
1409                                                                  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),
1410                                                                  sizeof (UINTN)
1411                                                                  );
1412       CopyMem (
1413         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1414         SaData->AlgoInfo.EspAlgoInfo.EncKey,
1415         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength
1416         );
1417     }
1418   }
1419 
1420   CopyMem (
1421     &SadEntry->Data->SaLifetime,
1422     &SaData->SaLifetime,
1423     sizeof (EFI_IPSEC_SA_LIFETIME)
1424     );
1425 
1426   SadEntry->Data->PathMTU     = SaData->PathMTU;
1427   SadEntry->Data->SpdSelector = NULL;
1428   SadEntry->Data->ESNEnabled  = FALSE;
1429   SadEntry->Data->ManualSet   = SaData->ManualSet;
1430 
1431   //
1432   // Copy Tunnel Source/Destination Address
1433   //
1434   if (SaData->Mode == EfiIPsecTunnel) {
1435     CopyMem (
1436       &SadEntry->Data->TunnelDestAddress,
1437       &SaData->TunnelDestinationAddress,
1438       sizeof (EFI_IP_ADDRESS)
1439       );
1440     CopyMem (
1441       &SadEntry->Data->TunnelSourceAddress,
1442       &SaData->TunnelSourceAddress,
1443       sizeof (EFI_IP_ADDRESS)
1444       );
1445   }
1446   //
1447   // Update the spd.sas list of the spd entry specified by SAD selector
1448   //
1449   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1450 
1451   for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) {
1452 
1453     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1454     if (IsSubSpdSelector (
1455           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1456           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1457           ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {
1458       SadEntry->Data->SpdEntry = SpdEntry;
1459       SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry +
1460                                                                 SadEntrySize -
1461                                                                 (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector)
1462                                                                 );
1463       DuplicateSpdSelector (
1464        (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1465        (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1466        NULL
1467        );
1468       InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1469     }
1470   }
1471   //
1472   // Insert the new SAD entry.
1473   //
1474   InsertTailList (EntryInsertBefore, &SadEntry->List);
1475 
1476   return EFI_SUCCESS;
1477 }
1478 
1479 /**
1480   Set the peer authorization configuration information for the EFI IPsec driver.
1481 
1482   The IPsec configuration data has a unique selector/identifier separately to
1483   identify a data entry.
1484 
1485   @param[in]  Selector           Pointer to an entry selector on operated
1486                                  configuration data specified by DataType.
1487                                  A NULL Selector causes the entire specified-type
1488                                  configuration information to be flushed.
1489   @param[in]  Data               The data buffer to be set. The structure
1490                                  of the data buffer should be EFI_IPSEC_PAD_DATA.
1491   @param[in]  Context            Pointer to one entry selector that describes
1492                                  the expected position the new data entry will
1493                                  be added. If Context is NULL, the new entry will
1494                                  be appended the end of database.
1495 
1496   @retval EFI_OUT_OF_RESOURCES  The required system resources could not be allocated.
1497   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1498 
1499 **/
1500 EFI_STATUS
SetPadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1501 SetPadEntry (
1502   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1503   IN VOID                            *Data,
1504   IN VOID                            *Context OPTIONAL
1505   )
1506 {
1507   IPSEC_PAD_ENTRY     *PadEntry;
1508   EFI_IPSEC_PAD_ID    *PadId;
1509   EFI_IPSEC_PAD_DATA  *PadData;
1510   LIST_ENTRY          *PadList;
1511   LIST_ENTRY          *Entry;
1512   LIST_ENTRY          *NextEntry;
1513   EFI_IPSEC_PAD_ID    *InsertBefore;
1514   LIST_ENTRY          *EntryInsertBefore;
1515   UINTN               PadEntrySize;
1516 
1517   PadId         = (Selector == NULL) ? NULL : &Selector->PadId;
1518   PadData       = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data;
1519   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId;
1520   PadList       = &mConfigData[IPsecConfigDataTypePad];
1521 
1522   //
1523   // The default behavior is to insert the node ahead of the header.
1524   //
1525   EntryInsertBefore = PadList;
1526 
1527   //
1528   // Remove the existed pad entry.
1529   //
1530   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) {
1531 
1532     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1533 
1534     if (PadId == NULL ||
1535         ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)
1536         ) {
1537       //
1538       // Record the existed entry position to keep the original order.
1539       //
1540       EntryInsertBefore = PadEntry->List.ForwardLink;
1541       RemoveEntryList (&PadEntry->List);
1542 
1543       FreePool (PadEntry);
1544     }
1545   }
1546   //
1547   // Return success here if only want to remove the pad entry
1548   //
1549   if (PadData == NULL || PadId == NULL) {
1550     return EFI_SUCCESS;
1551   }
1552   //
1553   // Search the appointed entry position if InsertBefore is not NULL.
1554   //
1555   if (InsertBefore != NULL) {
1556 
1557     NET_LIST_FOR_EACH (Entry, PadList) {
1558       PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1559 
1560       if (ComparePadId (
1561             (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id,
1562             (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1563             )) {
1564         EntryInsertBefore = Entry;
1565         break;
1566       }
1567     }
1568   }
1569 
1570   //
1571   // Do PADDING for different arch.
1572   //
1573   PadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY));
1574   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID));
1575   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA));
1576   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0));
1577   PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0;
1578 
1579   PadEntry      = AllocateZeroPool (PadEntrySize);
1580 
1581   if (PadEntry == NULL) {
1582     return EFI_OUT_OF_RESOURCES;
1583   }
1584   //
1585   // Fix the address of Id and Data buffer and copy them, which is
1586   // continous memory and close to the base structure of pad entry.
1587   //
1588   PadEntry->Id    = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN));
1589   PadEntry->Data  = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN));
1590 
1591   CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID));
1592 
1593   PadEntry->Data->AuthProtocol  = PadData->AuthProtocol;
1594   PadEntry->Data->AuthMethod    = PadData->AuthMethod;
1595   PadEntry->Data->IkeIdFlag     = PadData->IkeIdFlag;
1596 
1597   if (PadData->AuthData != NULL) {
1598     PadEntry->Data->AuthDataSize  = PadData->AuthDataSize;
1599     PadEntry->Data->AuthData      = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN));
1600     CopyMem (
1601       PadEntry->Data->AuthData,
1602       PadData->AuthData,
1603       PadData->AuthDataSize
1604       );
1605   } else {
1606     PadEntry->Data->AuthDataSize  = 0;
1607     PadEntry->Data->AuthData      = NULL;
1608   }
1609 
1610   if (PadData->RevocationData != NULL) {
1611     PadEntry->Data->RevocationDataSize  = PadData->RevocationDataSize;
1612     PadEntry->Data->RevocationData      = (VOID *) ALIGN_POINTER (
1613                                                     ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize),
1614                                                     sizeof (UINTN)
1615                                                     );
1616     CopyMem (
1617       PadEntry->Data->RevocationData,
1618       PadData->RevocationData,
1619       PadData->RevocationDataSize
1620       );
1621   } else {
1622     PadEntry->Data->RevocationDataSize  = 0;
1623     PadEntry->Data->RevocationData      = NULL;
1624   }
1625   //
1626   // Insert the new pad entry.
1627   //
1628   InsertTailList (EntryInsertBefore, &PadEntry->List);
1629 
1630   return EFI_SUCCESS;
1631 }
1632 
1633 /**
1634   This function lookup the data entry from IPsec SPD. Return the configuration
1635   value of the specified SPD Entry.
1636 
1637   @param[in]      Selector      Pointer to an entry selector which is an identifier
1638                                 of the SPD entry.
1639   @param[in, out] DataSize      On output the size of data returned in Data.
1640   @param[out]     Data          The buffer to return the contents of the IPsec
1641                                 configuration data. The type of the data buffer
1642                                 is associated with the DataType.
1643 
1644   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1645   @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
1646   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1647   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1648                                 updated with the size needed to complete the request.
1649 
1650 **/
1651 EFI_STATUS
GetSpdEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1652 GetSpdEntry (
1653   IN     EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1654   IN OUT UINTN                           *DataSize,
1655      OUT VOID                            *Data
1656   )
1657 {
1658   IPSEC_SPD_ENTRY         *SpdEntry;
1659   IPSEC_SAD_ENTRY         *SadEntry;
1660   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
1661   EFI_IPSEC_SPD_DATA      *SpdData;
1662   LIST_ENTRY              *SpdList;
1663   LIST_ENTRY              *SpdSas;
1664   LIST_ENTRY              *Entry;
1665   UINTN                   RequiredSize;
1666 
1667   SpdSel  = &Selector->SpdSelector;
1668   SpdData = (EFI_IPSEC_SPD_DATA *) Data;
1669   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1670 
1671   NET_LIST_FOR_EACH (Entry, SpdList) {
1672     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1673 
1674     //
1675     // Find the required SPD entry
1676     //
1677     if (CompareSpdSelector (
1678           (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
1679           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1680           )) {
1681 
1682       RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data);
1683       if (*DataSize < RequiredSize) {
1684         *DataSize = RequiredSize;
1685         return EFI_BUFFER_TOO_SMALL;
1686       }
1687 
1688       if (SpdData == NULL) {
1689         return EFI_INVALID_PARAMETER;
1690       }
1691 
1692       *DataSize = RequiredSize;
1693 
1694       //
1695       // Extract and fill all SaId array from the SPD.sas list
1696       //
1697       SpdSas              = &SpdEntry->Data->Sas;
1698       SpdData->SaIdCount  = 0;
1699 
1700       NET_LIST_FOR_EACH (Entry, SpdSas) {
1701         SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
1702         CopyMem (
1703           &SpdData->SaId[SpdData->SaIdCount++],
1704           SadEntry->Id,
1705           sizeof (EFI_IPSEC_SA_ID)
1706           );
1707       }
1708       //
1709       // Fill the other fields in SPD data.
1710       //
1711       CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name));
1712 
1713       SpdData->PackageFlag      = SpdEntry->Data->PackageFlag;
1714       SpdData->TrafficDirection = SpdEntry->Data->TrafficDirection;
1715       SpdData->Action           = SpdEntry->Data->Action;
1716 
1717       if (SpdData->Action != EfiIPsecActionProtect) {
1718         SpdData->ProcessingPolicy = NULL;
1719       } else {
1720         SpdData->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ((UINT8 *) SpdData + sizeof (EFI_IPSEC_SPD_DATA) + (SpdData->SaIdCount - 1) * sizeof (EFI_IPSEC_SA_ID));
1721 
1722         IpSecDuplicateProcessPolicy (
1723           SpdData->ProcessingPolicy,
1724           SpdEntry->Data->ProcessingPolicy
1725           );
1726       }
1727 
1728       return EFI_SUCCESS;
1729     }
1730   }
1731 
1732   return EFI_NOT_FOUND;
1733 }
1734 
1735 /**
1736   This function lookup the data entry from IPsec SAD. Return the configuration
1737   value of the specified SAD Entry.
1738 
1739   @param[in]      Selector      Pointer to an entry selector which is an identifier
1740                                 of the SAD entry.
1741   @param[in, out] DataSize      On output, the size of data returned in Data.
1742   @param[out]     Data          The buffer to return the contents of the IPsec
1743                                 configuration data. The type of the data buffer
1744                                 is associated with the DataType.
1745 
1746   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1747   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1748   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1749                                 updated with the size needed to complete the request.
1750 
1751 **/
1752 EFI_STATUS
GetSadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1753 GetSadEntry (
1754   IN     EFI_IPSEC_CONFIG_SELECTOR     *Selector,
1755   IN OUT UINTN                         *DataSize,
1756      OUT VOID                          *Data
1757   )
1758 {
1759   IPSEC_SAD_ENTRY   *SadEntry;
1760   LIST_ENTRY        *Entry;
1761   LIST_ENTRY        *SadList;
1762   EFI_IPSEC_SA_ID   *SaId;
1763   EFI_IPSEC_SA_DATA2 *SaData;
1764   UINTN             RequiredSize;
1765 
1766   SaId    = &Selector->SaId;
1767   SaData  = (EFI_IPSEC_SA_DATA2 *) Data;
1768   SadList = &mConfigData[IPsecConfigDataTypeSad];
1769 
1770   NET_LIST_FOR_EACH (Entry, SadList) {
1771     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1772 
1773     //
1774     // Find the required SAD entry.
1775     //
1776     if (CompareSaId (
1777          (EFI_IPSEC_CONFIG_SELECTOR *) SaId,
1778          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
1779          )) {
1780       //
1781       // Calculate the required size of the SAD entry.
1782       // Data Layout is follows:
1783       // |EFI_IPSEC_SA_DATA
1784       // |AuthKey
1785       // |EncryptKey  (Optional)
1786       // |SpdSelector (Optional)
1787       //
1788       RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA2));
1789 
1790       if (SaId->Proto == EfiIPsecAH) {
1791         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength);
1792       } else {
1793         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength);
1794         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength);
1795       }
1796 
1797       if (SadEntry->Data->SpdSelector != NULL) {
1798         RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector);
1799       }
1800 
1801       if (*DataSize < RequiredSize) {
1802         *DataSize = RequiredSize;
1803         return EFI_BUFFER_TOO_SMALL;
1804       }
1805 
1806       //
1807       // Fill the data fields of SAD entry.
1808       //
1809       *DataSize                 = RequiredSize;
1810       SaData->Mode              = SadEntry->Data->Mode;
1811       SaData->SNCount           = SadEntry->Data->SequenceNumber;
1812       SaData->AntiReplayWindows = SadEntry->Data->AntiReplayWindowSize;
1813 
1814       CopyMem (
1815         &SaData->SaLifetime,
1816         &SadEntry->Data->SaLifetime,
1817         sizeof (EFI_IPSEC_SA_LIFETIME)
1818         );
1819 
1820       ZeroMem (
1821         &SaData->AlgoInfo,
1822         sizeof (EFI_IPSEC_ALGO_INFO)
1823         );
1824 
1825       if (SaId->Proto == EfiIPsecAH) {
1826         //
1827         // Copy AH alogrithm INFO to SaData
1828         //
1829         SaData->AlgoInfo.AhAlgoInfo.AuthAlgoId    = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthAlgoId;
1830         SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength;
1831         if (SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength != 0) {
1832           SaData->AlgoInfo.AhAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
1833           CopyMem (
1834             SaData->AlgoInfo.AhAlgoInfo.AuthKey,
1835             SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKey,
1836             SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength
1837             );
1838         }
1839       } else if (SaId->Proto == EfiIPsecESP) {
1840         //
1841         // Copy ESP alogrithem INFO to SaData
1842         //
1843         SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId;
1844         SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength;
1845         if (SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
1846           SaData->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
1847           CopyMem (
1848             SaData->AlgoInfo.EspAlgoInfo.AuthKey,
1849             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1850             SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength
1851             );
1852         }
1853 
1854         SaData->AlgoInfo.EspAlgoInfo.EncAlgoId    = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId;
1855         SaData->AlgoInfo.EspAlgoInfo.EncKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength;
1856 
1857         if (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
1858           SaData->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
1859                                                           ((UINT8 *) (SaData + 1) +
1860                                                             SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength),
1861                                                             sizeof (UINTN)
1862                                                             );
1863           CopyMem (
1864             SaData->AlgoInfo.EspAlgoInfo.EncKey,
1865             SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1866             SaData->AlgoInfo.EspAlgoInfo.EncKeyLength
1867             );
1868         }
1869       }
1870 
1871       SaData->PathMTU = SadEntry->Data->PathMTU;
1872 
1873       //
1874       // Fill Tunnel Address if it is Tunnel Mode
1875       //
1876       if (SadEntry->Data->Mode == EfiIPsecTunnel) {
1877         CopyMem (
1878           &SaData->TunnelDestinationAddress,
1879           &SadEntry->Data->TunnelDestAddress,
1880           sizeof (EFI_IP_ADDRESS)
1881           );
1882         CopyMem (
1883           &SaData->TunnelSourceAddress,
1884           &SadEntry->Data->TunnelSourceAddress,
1885           sizeof (EFI_IP_ADDRESS)
1886           );
1887       }
1888       //
1889       // Fill the spd selector field of SAD data
1890       //
1891       if (SadEntry->Data->SpdSelector != NULL) {
1892 
1893         SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) (
1894                                 (UINT8 *)SaData +
1895                                 RequiredSize -
1896                                 SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector)
1897                                 );
1898 
1899         DuplicateSpdSelector (
1900           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1901           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1902           NULL
1903           );
1904 
1905       } else {
1906 
1907         SaData->SpdSelector = NULL;
1908       }
1909 
1910       SaData->ManualSet = SadEntry->Data->ManualSet;
1911 
1912       return EFI_SUCCESS;
1913     }
1914   }
1915 
1916   return EFI_NOT_FOUND;
1917 }
1918 
1919 /**
1920   This function lookup the data entry from IPsec PAD. Return the configuration
1921   value of the specified PAD Entry.
1922 
1923   @param[in]      Selector      Pointer to an entry selector which is an identifier
1924                                 of the PAD entry.
1925   @param[in, out] DataSize      On output the size of data returned in Data.
1926   @param[out]     Data          The buffer to return the contents of the IPsec
1927                                 configuration data. The type of the data buffer
1928                                 is associated with the DataType.
1929 
1930   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1931   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1932   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1933                                 updated with the size needed to complete the request.
1934 
1935 **/
1936 EFI_STATUS
GetPadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1937 GetPadEntry (
1938   IN     EFI_IPSEC_CONFIG_SELECTOR   *Selector,
1939   IN OUT UINTN                       *DataSize,
1940      OUT VOID                        *Data
1941   )
1942 {
1943   IPSEC_PAD_ENTRY     *PadEntry;
1944   LIST_ENTRY          *PadList;
1945   LIST_ENTRY          *Entry;
1946   EFI_IPSEC_PAD_ID    *PadId;
1947   EFI_IPSEC_PAD_DATA  *PadData;
1948   UINTN               RequiredSize;
1949 
1950   PadId   = &Selector->PadId;
1951   PadData = (EFI_IPSEC_PAD_DATA *) Data;
1952   PadList = &mConfigData[IPsecConfigDataTypePad];
1953 
1954   NET_LIST_FOR_EACH (Entry, PadList) {
1955     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1956 
1957     //
1958     // Find the required pad entry.
1959     //
1960     if (ComparePadId (
1961           (EFI_IPSEC_CONFIG_SELECTOR *) PadId,
1962           (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id
1963           )) {
1964       //
1965       // Calculate the required size of the pad entry.
1966       //
1967       RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_PAD_DATA));
1968       RequiredSize  = ALIGN_VARIABLE (RequiredSize + PadEntry->Data->AuthDataSize);
1969       RequiredSize += PadEntry->Data->RevocationDataSize;
1970 
1971       if (*DataSize < RequiredSize) {
1972         *DataSize = RequiredSize;
1973         return EFI_BUFFER_TOO_SMALL;
1974       }
1975       //
1976       // Fill the data fields of pad entry
1977       //
1978       *DataSize             = RequiredSize;
1979       PadData->AuthProtocol = PadEntry->Data->AuthProtocol;
1980       PadData->AuthMethod   = PadEntry->Data->AuthMethod;
1981       PadData->IkeIdFlag    = PadEntry->Data->IkeIdFlag;
1982 
1983       //
1984       // Copy Authentication data.
1985       //
1986       if (PadEntry->Data->AuthData != NULL) {
1987 
1988         PadData->AuthDataSize = PadEntry->Data->AuthDataSize;
1989         PadData->AuthData     = (VOID *) ALIGN_POINTER ((PadData + 1), sizeof (UINTN));
1990         CopyMem (
1991           PadData->AuthData,
1992           PadEntry->Data->AuthData,
1993           PadData->AuthDataSize
1994           );
1995       } else {
1996 
1997         PadData->AuthDataSize = 0;
1998         PadData->AuthData     = NULL;
1999       }
2000       //
2001       // Copy Revocation Data.
2002       //
2003       if (PadEntry->Data->RevocationData != NULL) {
2004 
2005         PadData->RevocationDataSize = PadEntry->Data->RevocationDataSize;
2006         PadData->RevocationData     = (VOID *) ALIGN_POINTER (
2007                                                  ((UINT8 *) (PadData + 1) + PadData->AuthDataSize),
2008                                                   sizeof (UINTN)
2009                                                   );
2010         CopyMem (
2011           PadData->RevocationData,
2012           PadEntry->Data->RevocationData,
2013           PadData->RevocationDataSize
2014           );
2015       } else {
2016 
2017         PadData->RevocationDataSize = 0;
2018         PadData->RevocationData     = NULL;
2019       }
2020 
2021       return EFI_SUCCESS;
2022     }
2023   }
2024 
2025   return EFI_NOT_FOUND;
2026 }
2027 
2028 /**
2029   Copy Source Process Policy to the Destination Process Policy.
2030 
2031   @param[in]  Dst                  Pointer to the Source Process Policy.
2032   @param[in]  Src                  Pointer to the Destination Process Policy.
2033 
2034 **/
2035 VOID
IpSecDuplicateProcessPolicy(IN EFI_IPSEC_PROCESS_POLICY * Dst,IN EFI_IPSEC_PROCESS_POLICY * Src)2036 IpSecDuplicateProcessPolicy (
2037   IN EFI_IPSEC_PROCESS_POLICY            *Dst,
2038   IN EFI_IPSEC_PROCESS_POLICY            *Src
2039   )
2040 {
2041   //
2042   // Firstly copy the structure content itself.
2043   //
2044   CopyMem (Dst, Src, sizeof (EFI_IPSEC_PROCESS_POLICY));
2045 
2046   //
2047   // Recursively copy the tunnel option if needed.
2048   //
2049   if (Dst->Mode != EfiIPsecTunnel) {
2050     ASSERT (Dst->TunnelOption == NULL);
2051   } else {
2052     Dst->TunnelOption = (EFI_IPSEC_TUNNEL_OPTION *) ALIGN_POINTER ((Dst + 1), sizeof (UINTN));
2053     CopyMem (
2054       Dst->TunnelOption,
2055       Src->TunnelOption,
2056       sizeof (EFI_IPSEC_TUNNEL_OPTION)
2057       );
2058   }
2059 }
2060 
2061 /**
2062   Calculate the a whole size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed
2063   to by the pointer members.
2064 
2065   @param[in]  SpdData             Pointer to a specified EFI_IPSEC_SPD_DATA.
2066 
2067   @return the whole size the specified EFI_IPSEC_SPD_DATA.
2068 
2069 **/
2070 UINTN
IpSecGetSizeOfEfiSpdData(IN EFI_IPSEC_SPD_DATA * SpdData)2071 IpSecGetSizeOfEfiSpdData (
2072   IN EFI_IPSEC_SPD_DATA               *SpdData
2073   )
2074 {
2075   UINTN Size;
2076 
2077   Size = ALIGN_VARIABLE (sizeof (IPSEC_SPD_DATA));
2078 
2079   if (SpdData->Action == EfiIPsecActionProtect) {
2080     Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_PROCESS_POLICY));
2081 
2082     if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
2083       Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_TUNNEL_OPTION));
2084     }
2085   }
2086 
2087   return Size;
2088 }
2089 
2090 /**
2091   Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed
2092   to by the pointer members and the buffer size used by the Sa List.
2093 
2094   @param[in]  SpdData       Pointer to the specified IPSEC_SPD_DATA.
2095 
2096   @return the whole size of IPSEC_SPD_DATA.
2097 
2098 **/
2099 UINTN
IpSecGetSizeOfSpdData(IN IPSEC_SPD_DATA * SpdData)2100 IpSecGetSizeOfSpdData (
2101   IN IPSEC_SPD_DATA                   *SpdData
2102   )
2103 {
2104   UINTN       Size;
2105   LIST_ENTRY  *Link;
2106 
2107   Size = sizeof (EFI_IPSEC_SPD_DATA) - sizeof (EFI_IPSEC_SA_ID);
2108 
2109   if (SpdData->Action == EfiIPsecActionProtect) {
2110     Size += sizeof (EFI_IPSEC_PROCESS_POLICY);
2111 
2112     if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
2113       Size += sizeof (EFI_IPSEC_TUNNEL_OPTION);
2114     }
2115   }
2116 
2117   NET_LIST_FOR_EACH (Link, &SpdData->Sas) {
2118     Size += sizeof (EFI_IPSEC_SA_ID);
2119   }
2120 
2121   return Size;
2122 }
2123 
2124 /**
2125   Get the IPsec Variable.
2126 
2127   Get the all variables which start with the string contained in VaraiableName.
2128   Since all IPsec related variable store in continual space, those kinds of
2129   variable can be searched by the EfiGetNextVariableName. Those variables also are
2130   returned in a continual buffer.
2131 
2132   @param[in]      VariableName          Pointer to a specified Variable Name.
2133   @param[in]      VendorGuid            Pointer to a specified Vendor Guid.
2134   @param[in]      Attributes            Point to memory location to return the attributes
2135                                         of variable. If the point is NULL, the parameter
2136                                         would be ignored.
2137   @param[in, out] DataSize              As input, point to the maximum size of return
2138                                         Data-Buffer. As output, point to the actual
2139                                         size of the returned Data-Buffer.
2140   @param[in]      Data                  Point to return Data-Buffer.
2141 
2142   @retval  EFI_ABORTED           If the Variable size which contained in the variable
2143                                  structure doesn't match the variable size obtained
2144                                  from the EFIGetVariable.
2145   @retval  EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has
2146                                  been updated with the size needed to complete the request.
2147   @retval  EFI_SUCCESS           The function completed successfully.
2148   @retval  others                Other errors found during the variable getting.
2149 **/
2150 EFI_STATUS
IpSecGetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 * Attributes,OPTIONAL IN OUT UINTN * DataSize,IN VOID * Data)2151 IpSecGetVariable (
2152   IN     CHAR16                       *VariableName,
2153   IN     EFI_GUID                     *VendorGuid,
2154   IN     UINT32                       *Attributes, OPTIONAL
2155   IN OUT UINTN                        *DataSize,
2156   IN     VOID                         *Data
2157   )
2158 {
2159   EFI_STATUS            Status;
2160   EFI_GUID              VendorGuidI;
2161   UINTN                 VariableNameLength;
2162   CHAR16                *VariableNameI;
2163   UINTN                 VariableNameISize;
2164   UINTN                 VariableNameISizeNew;
2165   UINTN                 VariableIndex;
2166   UINTN                 VariableCount;
2167   IP_SEC_VARIABLE_INFO  IpSecVariableInfo;
2168   UINTN                 DataSizeI;
2169 
2170   //
2171   // The variable name constructor is "VariableName + Info/0001/0002/... + NULL".
2172   // So the varialbe name is like "VariableNameInfo", "VariableName0001", ...
2173   // "VariableNameNULL".
2174   //
2175   VariableNameLength  = StrLen (VariableName);
2176   VariableNameISize   = (VariableNameLength + 5) * sizeof (CHAR16);
2177   VariableNameI       = AllocateZeroPool (VariableNameISize);
2178   if (VariableNameI == NULL) {
2179     Status = EFI_OUT_OF_RESOURCES;
2180     goto ON_EXIT;
2181   }
2182 
2183   //
2184   // Construct the varible name of ipsecconfig meta data.
2185   //
2186   UnicodeSPrint (VariableNameI, VariableNameISize, L"%s%s", VariableName, L"Info");
2187 
2188   DataSizeI = sizeof (IpSecVariableInfo);
2189 
2190   Status = gRT->GetVariable (
2191                   VariableNameI,
2192                   VendorGuid,
2193                   Attributes,
2194                   &DataSizeI,
2195                   &IpSecVariableInfo
2196                   );
2197   if (EFI_ERROR (Status)) {
2198     goto ON_EXIT;
2199   }
2200 
2201   if (*DataSize < IpSecVariableInfo.VariableSize) {
2202     *DataSize = IpSecVariableInfo.VariableSize;
2203     Status    = EFI_BUFFER_TOO_SMALL;
2204     goto ON_EXIT;
2205   }
2206 
2207   VariableCount     = IpSecVariableInfo.VariableCount;
2208   VariableNameI[0]  = L'\0';
2209 
2210   while (VariableCount != 0) {
2211     //
2212     // Get the variable name one by one in the variable database.
2213     //
2214     VariableNameISizeNew = VariableNameISize;
2215     Status = gRT->GetNextVariableName (
2216                     &VariableNameISizeNew,
2217                     VariableNameI,
2218                     &VendorGuidI
2219                     );
2220     if (Status == EFI_BUFFER_TOO_SMALL) {
2221       VariableNameI = ReallocatePool (
2222                         VariableNameISize,
2223                         VariableNameISizeNew,
2224                         VariableNameI
2225                         );
2226       if (VariableNameI == NULL) {
2227         Status = EFI_OUT_OF_RESOURCES;
2228         break;
2229       }
2230       VariableNameISize = VariableNameISizeNew;
2231 
2232       Status = gRT->GetNextVariableName (
2233                       &VariableNameISizeNew,
2234                       VariableNameI,
2235                       &VendorGuidI
2236                       );
2237     }
2238 
2239     if (EFI_ERROR (Status)) {
2240       break;
2241     }
2242     //
2243     // Check whether the current variable is the required "ipsecconfig".
2244     //
2245     if (StrnCmp (VariableNameI, VariableName, VariableNameLength) == 0 ||
2246         CompareGuid (VendorGuid, &VendorGuidI)
2247         ) {
2248       //
2249       // Parse the variable count of the current ipsecconfig data.
2250       //
2251       VariableIndex = StrDecimalToUintn (VariableNameI + VariableNameLength);
2252       if (VariableIndex!= 0 && VariableIndex <= IpSecVariableInfo.VariableCount) {
2253         //
2254         // Get the variable size of the current ipsecconfig data.
2255         //
2256         DataSizeI = 0;
2257         Status = gRT->GetVariable (
2258                         VariableNameI,
2259                         VendorGuid,
2260                         Attributes,
2261                         &DataSizeI,
2262                         NULL
2263                         );
2264         ASSERT (Status == EFI_BUFFER_TOO_SMALL);
2265         //
2266         // Validate the variable count and variable size.
2267         //
2268         if (VariableIndex != IpSecVariableInfo.VariableCount) {
2269           //
2270           // If the varaibe is not the last one, its size should be the max
2271           // size of the single variable.
2272           //
2273           if (DataSizeI != IpSecVariableInfo.SingleVariableSize) {
2274             return EFI_ABORTED;
2275           }
2276         } else {
2277           if (DataSizeI != IpSecVariableInfo.VariableSize % IpSecVariableInfo.SingleVariableSize) {
2278             return EFI_ABORTED;
2279           }
2280         }
2281         //
2282         // Get the variable data of the current ipsecconfig data and
2283         // store it into user buffer continously.
2284         //
2285         Status = gRT->GetVariable (
2286                         VariableNameI,
2287                         VendorGuid,
2288                         Attributes,
2289                         &DataSizeI,
2290                         (UINT8 *) Data + (VariableIndex - 1) * IpSecVariableInfo.SingleVariableSize
2291                         );
2292         ASSERT_EFI_ERROR (Status);
2293         VariableCount--;
2294       }
2295     }
2296   }
2297   //
2298   // The VariableCount in "VariableNameInfo" varaible should have the correct
2299   // numbers of variables which name starts with VariableName.
2300   //
2301   if (VariableCount != 0) {
2302     Status = EFI_ABORTED;
2303   }
2304 
2305 ON_EXIT:
2306   if (VariableNameI != NULL) {
2307     FreePool (VariableNameI);
2308   }
2309   return Status;
2310 }
2311 
2312 /**
2313   Set the IPsec variables.
2314 
2315   Set all IPsec variables which start with the specified variable name. Those variables
2316   are set one by one.
2317 
2318   @param[in]  VariableName  The name of the vendor's variable. It is a
2319                             Null-Terminated Unicode String.
2320   @param[in]  VendorGuid    Unify identifier for vendor.
2321   @param[in]  Attributes    Point to memory location to return the attributes of
2322                             variable. If the point is NULL, the parameter would be ignored.
2323   @param[in]  DataSize      The size in bytes of Data-Buffer.
2324   @param[in]  Data          Points to the content of the variable.
2325 
2326   @retval  EFI_SUCCESS      The firmware successfully stored the variable and its data, as
2327                             defined by the Attributes.
2328   @retval  others           Storing the variables failed.
2329 
2330 **/
2331 EFI_STATUS
IpSecSetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)2332 IpSecSetVariable (
2333   IN CHAR16                           *VariableName,
2334   IN EFI_GUID                         *VendorGuid,
2335   IN UINT32                           Attributes,
2336   IN UINTN                            DataSize,
2337   IN VOID                             *Data
2338   )
2339 {
2340   EFI_STATUS            Status;
2341   CHAR16                *VariableNameI;
2342   UINTN                 VariableNameSize;
2343   UINTN                 VariableIndex;
2344   IP_SEC_VARIABLE_INFO  IpSecVariableInfo;
2345   UINT64                MaximumVariableStorageSize;
2346   UINT64                RemainingVariableStorageSize;
2347   UINT64                MaximumVariableSize;
2348 
2349   Status = gRT->QueryVariableInfo (
2350                   Attributes,
2351                   &MaximumVariableStorageSize,
2352                   &RemainingVariableStorageSize,
2353                   &MaximumVariableSize
2354                   );
2355   if (EFI_ERROR (Status)) {
2356     return Status;
2357   }
2358 
2359   //
2360   // "VariableName + Info/0001/0002/... + NULL"
2361   //
2362   VariableNameSize  = (StrLen (VariableName) + 5) * sizeof (CHAR16);
2363   VariableNameI     = AllocateZeroPool (VariableNameSize);
2364 
2365   if (VariableNameI == NULL) {
2366     Status = EFI_OUT_OF_RESOURCES;
2367     goto ON_EXIT;
2368   }
2369   //
2370   // Construct the variable of ipsecconfig general information. Like the total
2371   // numbers of the Ipsecconfig variables, the total size of all ipsecconfig variables.
2372   //
2373   UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info");
2374   MaximumVariableSize -= VariableNameSize;
2375 
2376   IpSecVariableInfo.VariableCount       = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize);
2377   IpSecVariableInfo.VariableSize        = (UINT32) DataSize;
2378   IpSecVariableInfo.SingleVariableSize  = (UINT32) MaximumVariableSize;
2379 
2380   //
2381   // Set the variable of ipsecconfig general information.
2382   //
2383   Status = gRT->SetVariable (
2384                   VariableNameI,
2385                   VendorGuid,
2386                   Attributes,
2387                   sizeof (IpSecVariableInfo),
2388                   &IpSecVariableInfo
2389                   );
2390   if (EFI_ERROR (Status)) {
2391     DEBUG ((DEBUG_ERROR, "Error set ipsecconfig meta data with %r\n", Status));
2392     goto ON_EXIT;
2393   }
2394 
2395   for (VariableIndex = 0; VariableIndex < IpSecVariableInfo.VariableCount; VariableIndex++) {
2396     //
2397     // Construct and set the variable of ipsecconfig data one by one.
2398     // The index of variable name begin from 0001, and the varaible name
2399     // likes "VariableName0001", "VaraiableName0002"....
2400     //
2401     UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1);
2402     Status = gRT->SetVariable (
2403                     VariableNameI,
2404                     VendorGuid,
2405                     Attributes,
2406                     (VariableIndex == IpSecVariableInfo.VariableCount - 1) ?
2407                     (DataSize % (UINTN) MaximumVariableSize) :
2408                     (UINTN) MaximumVariableSize,
2409                     (UINT8 *) Data + VariableIndex * (UINTN) MaximumVariableSize
2410                     );
2411 
2412     if (EFI_ERROR (Status)) {
2413       DEBUG ((DEBUG_ERROR, "Error set ipsecconfig variable data with %r\n", Status));
2414       goto ON_EXIT;
2415     }
2416   }
2417 
2418 ON_EXIT:
2419   if (VariableNameI != NULL) {
2420     FreePool (VariableNameI);
2421   }
2422 
2423   return Status;
2424 }
2425 
2426 /**
2427   Return the configuration value for the EFI IPsec driver.
2428 
2429   This function lookup the data entry from IPsec database or IKEv2 configuration
2430   information. The expected data type and unique identification are described in
2431   DataType and Selector parameters.
2432 
2433   @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2434   @param[in]      DataType      The type of data to retrieve.
2435   @param[in]      Selector      Pointer to an entry selector that is an identifier of the IPsec
2436                                 configuration data entry.
2437   @param[in, out] DataSize      On output the size of data returned in Data.
2438   @param[out]     Data          The buffer to return the contents of the IPsec configuration data.
2439                                 The type of the data buffer associated with the DataType.
2440 
2441   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
2442   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
2443                                 - This is NULL.
2444                                 - Selector is NULL.
2445                                 - DataSize is NULL.
2446                                 - Data is NULL and *DataSize is not zero
2447   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
2448   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2449   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
2450                                 updated with the size needed to complete the request.
2451 
2452 **/
2453 EFI_STATUS
2454 EFIAPI
EfiIpSecConfigGetData(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)2455 EfiIpSecConfigGetData (
2456   IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,
2457   IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,
2458   IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,
2459   IN OUT UINTN                        *DataSize,
2460      OUT VOID                         *Data
2461   )
2462 {
2463   if (This == NULL || Selector == NULL || DataSize == NULL) {
2464     return EFI_INVALID_PARAMETER;
2465   }
2466 
2467   if (*DataSize != 0 && Data == NULL) {
2468     return EFI_INVALID_PARAMETER;
2469   }
2470 
2471   if (DataType >= IPsecConfigDataTypeMaximum) {
2472     return EFI_UNSUPPORTED;
2473   }
2474 
2475   return mGetPolicyEntry[DataType](Selector, DataSize, Data);
2476 }
2477 
2478 /**
2479   Set the security association, security policy and peer authorization configuration
2480   information for the EFI IPsec driver.
2481 
2482   This function is used to set the IPsec configuration information of type DataType for
2483   the EFI IPsec driver.
2484   The IPsec configuration data has a unique selector/identifier separately to identify
2485   a data entry. The selector structure depends on DataType's definition.
2486   Using SetData() with a Data of NULL causes the IPsec configuration data entry identified
2487   by DataType and Selector to be deleted.
2488 
2489   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2490   @param[in] DataType           The type of data to be set.
2491   @param[in] Selector           Pointer to an entry selector on operated configuration data
2492                                 specified by DataType. A NULL Selector causes the entire
2493                                 specified-type configuration information to be flushed.
2494   @param[in] Data               The data buffer to be set. The structure of the data buffer is
2495                                 associated with the DataType.
2496   @param[in] InsertBefore       Pointer to one entry selector which describes the expected
2497                                 position the new data entry will be added. If InsertBefore is NULL,
2498                                 the new entry will be appended to the end of the database.
2499 
2500   @retval EFI_SUCCESS           The specified configuration entry data was set successfully.
2501   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
2502                                 - This is NULL.
2503   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2504   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
2505 
2506 **/
2507 EFI_STATUS
2508 EFIAPI
EfiIpSecConfigSetData(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN EFI_IPSEC_CONFIG_SELECTOR * InsertBefore OPTIONAL)2509 EfiIpSecConfigSetData (
2510   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2511   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2512   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector,
2513   IN VOID                             *Data,
2514   IN EFI_IPSEC_CONFIG_SELECTOR        *InsertBefore OPTIONAL
2515   )
2516 {
2517   EFI_STATUS  Status;
2518 
2519   if (This == NULL) {
2520     return EFI_INVALID_PARAMETER;
2521   }
2522 
2523   if (DataType >= IPsecConfigDataTypeMaximum) {
2524     return EFI_UNSUPPORTED;
2525   }
2526 
2527   Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore);
2528 
2529   if (!EFI_ERROR (Status) && !mSetBySelf) {
2530     //
2531     // Save the updated config data into variable.
2532     //
2533     IpSecConfigSave ();
2534   }
2535 
2536   return Status;
2537 }
2538 
2539 /**
2540   Enumerates the current selector for IPsec configuration data entry.
2541 
2542   This function is called multiple times to retrieve the entry Selector in IPsec
2543   configuration database. On each call to GetNextSelector(), the next entry
2544   Selector are retrieved into the output interface.
2545 
2546   If the entire IPsec configuration database has been iterated, the error
2547   EFI_NOT_FOUND is returned.
2548   If the Selector buffer is too small for the next Selector copy, an
2549   EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect
2550   the size of buffer needed.
2551 
2552   On the initial call to GetNextSelector() to start the IPsec configuration database
2553   search, a pointer to the buffer with all zero value is passed in Selector. Calls
2554   to SetData() between calls to GetNextSelector may produce unpredictable results.
2555 
2556   @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2557   @param[in]      DataType      The type of IPsec configuration data to retrieve.
2558   @param[in, out] SelectorSize  The size of the Selector buffer.
2559   @param[in, out] Selector      On input, supplies the pointer to last Selector that was
2560                                 returned by GetNextSelector().
2561                                 On output, returns one copy of the current entry Selector
2562                                 of a given DataType.
2563 
2564   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
2565   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
2566                                 - This is NULL.
2567                                 - SelectorSize is NULL.
2568                                 - Selector is NULL.
2569   @retval EFI_NOT_FOUND         The next configuration data entry was not found.
2570   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2571   @retval EFI_BUFFER_TOO_SMALL  The SelectorSize is too small for the result. This parameter
2572                                 has been updated with the size needed to complete the search
2573                                 request.
2574 
2575 **/
2576 EFI_STATUS
2577 EFIAPI
EfiIpSecConfigGetNextSelector(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN OUT UINTN * SelectorSize,IN OUT EFI_IPSEC_CONFIG_SELECTOR * Selector)2578 EfiIpSecConfigGetNextSelector (
2579   IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,
2580   IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,
2581   IN OUT UINTN                        *SelectorSize,
2582   IN OUT EFI_IPSEC_CONFIG_SELECTOR    *Selector
2583   )
2584 {
2585   LIST_ENTRY                *Link;
2586   IPSEC_COMMON_POLICY_ENTRY *CommonEntry;
2587   BOOLEAN                   IsFound;
2588 
2589   if (This == NULL || Selector == NULL || SelectorSize == NULL) {
2590     return EFI_INVALID_PARAMETER;
2591   }
2592 
2593   if (DataType >= IPsecConfigDataTypeMaximum) {
2594     return EFI_UNSUPPORTED;
2595   }
2596 
2597   IsFound = FALSE;
2598 
2599   NET_LIST_FOR_EACH (Link, &mConfigData[DataType]) {
2600     CommonEntry = BASE_CR (Link, IPSEC_COMMON_POLICY_ENTRY, List);
2601 
2602     if (IsFound || (BOOLEAN)(mIsZeroSelector[DataType](Selector))) {
2603       //
2604       // If found the appointed entry, then duplicate the next one and return,
2605       // or if the appointed entry is zero, then return the first one directly.
2606       //
2607       return mDuplicateSelector[DataType](Selector, CommonEntry->Selector, SelectorSize);
2608     } else {
2609       //
2610       // Set the flag if find the appointed entry.
2611       //
2612       IsFound = mCompareSelector[DataType](Selector, CommonEntry->Selector);
2613     }
2614   }
2615 
2616   return EFI_NOT_FOUND;
2617 }
2618 
2619 /**
2620   Register an event that is to be signaled whenever a configuration process on the
2621   specified IPsec configuration information is done.
2622 
2623   The register function is not surpport now and always returns EFI_UNSUPPORTED.
2624 
2625   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2626   @param[in] DataType           The type of data to be registered the event for.
2627   @param[in] Event              The event to be registered.
2628 
2629   @retval EFI_SUCCESS           The event is registered successfully.
2630   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2631   @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.
2632   @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified
2633                                 DataType is not supported.
2634 
2635 **/
2636 EFI_STATUS
2637 EFIAPI
EfiIpSecConfigRegisterNotify(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2638 EfiIpSecConfigRegisterNotify (
2639   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2640   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2641   IN EFI_EVENT                        Event
2642   )
2643 {
2644   return EFI_UNSUPPORTED;
2645 }
2646 
2647 /**
2648   Remove the specified event that was previously registered on the specified IPsec
2649   configuration data.
2650 
2651   This function is not support now and alwasy return EFI_UNSUPPORTED.
2652 
2653   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2654   @param[in] DataType           The configuration data type to remove the registered event for.
2655   @param[in] Event              The event to be unregistered.
2656 
2657   @retval EFI_SUCCESS           The event was removed successfully.
2658   @retval EFI_NOT_FOUND         The Event specified by DataType could not be found in the
2659                                 database.
2660   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2661   @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified
2662                                 DataType is not supported.
2663 
2664 **/
2665 EFI_STATUS
2666 EFIAPI
EfiIpSecConfigUnregisterNotify(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2667 EfiIpSecConfigUnregisterNotify (
2668   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2669   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2670   IN EFI_EVENT                        Event
2671   )
2672 {
2673   return EFI_UNSUPPORTED;
2674 }
2675 
2676 /**
2677   Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer.
2678 
2679   This function is a caller defined function, and it is called by the IpSecVisitConfigData().
2680   The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to
2681   copy all types of IPsec Config datas into one buffer and store this buffer into firmware in
2682   the form of several variables.
2683 
2684   @param[in]      Type              A specified IPSEC_CONFIG_DATA_TYPE.
2685   @param[in]      Selector          Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied
2686                                     to the buffer.
2687   @param[in]      Data              Points to data to be copied to the buffer. The
2688                                     Data type is related to the Type.
2689   @param[in]      SelectorSize      The size of the Selector.
2690   @param[in]      DataSize          The size of the Data.
2691   @param[in, out] Buffer            The buffer to store the Selector and Data.
2692 
2693   @retval EFI_SUCCESS            Copy the Selector and Data to a buffer successfully.
2694   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.
2695 
2696 **/
2697 EFI_STATUS
IpSecCopyPolicyEntry(IN EFI_IPSEC_CONFIG_DATA_TYPE Type,IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN UINTN SelectorSize,IN UINTN DataSize,IN OUT IPSEC_VARIABLE_BUFFER * Buffer)2698 IpSecCopyPolicyEntry (
2699   IN     EFI_IPSEC_CONFIG_DATA_TYPE   Type,
2700   IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,
2701   IN     VOID                         *Data,
2702   IN     UINTN                        SelectorSize,
2703   IN     UINTN                        DataSize,
2704   IN OUT IPSEC_VARIABLE_BUFFER        *Buffer
2705   )
2706 {
2707   IPSEC_VAR_ITEM_HEADER SelectorHeader;
2708   IPSEC_VAR_ITEM_HEADER DataHeader;
2709   UINTN                 EntrySize;
2710   UINT8                 *TempPoint;
2711 
2712   if (Type == IPsecConfigDataTypeSad) {
2713     //
2714     // Don't save automatically-generated SA entry into variable.
2715     //
2716     if (((EFI_IPSEC_SA_DATA2 *) Data)->ManualSet == FALSE) {
2717       return EFI_SUCCESS;
2718     }
2719   }
2720   //
2721   // Increase the capacity size of the buffer if needed.
2722   //
2723   EntrySize  = ALIGN_VARIABLE (sizeof (SelectorHeader));
2724   EntrySize  = ALIGN_VARIABLE (EntrySize + SelectorSize);
2725   EntrySize  = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader));
2726   EntrySize  = ALIGN_VARIABLE (EntrySize + DataSize);
2727 
2728   //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader);
2729   if (Buffer->Capacity - Buffer->Size < EntrySize) {
2730     //
2731     // Calculate the required buffer
2732     //
2733     Buffer->Capacity += EntrySize;
2734     TempPoint         = AllocatePool (Buffer->Capacity);
2735 
2736     if (TempPoint == NULL) {
2737       return EFI_OUT_OF_RESOURCES;
2738     }
2739     //
2740     // Copy the old Buffer to new buffer and free the old one.
2741     //
2742     CopyMem (TempPoint, Buffer->Ptr, Buffer->Size);
2743     FreePool (Buffer->Ptr);
2744 
2745     Buffer->Ptr       =  TempPoint;
2746   }
2747 
2748   mFixPolicyEntry[Type](Selector, Data);
2749 
2750   //
2751   // Fill the selector header and copy it into buffer.
2752   //
2753   SelectorHeader.Type = (UINT8) (Type | IPSEC_VAR_ITEM_HEADER_LOGO_BIT);
2754   SelectorHeader.Size = (UINT16) SelectorSize;
2755 
2756   CopyMem (
2757     Buffer->Ptr + Buffer->Size,
2758     &SelectorHeader,
2759     sizeof (SelectorHeader)
2760     );
2761   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader));
2762 
2763   //
2764   // Copy the selector into buffer.
2765   //
2766   CopyMem (
2767     Buffer->Ptr + Buffer->Size,
2768     Selector,
2769     SelectorSize
2770     );
2771   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + SelectorSize);
2772 
2773   //
2774   // Fill the data header and copy it into buffer.
2775   //
2776   DataHeader.Type = (UINT8) Type;
2777   DataHeader.Size = (UINT16) DataSize;
2778 
2779   CopyMem (
2780     Buffer->Ptr + Buffer->Size,
2781     &DataHeader,
2782     sizeof (DataHeader)
2783     );
2784   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (DataHeader));
2785   //
2786   // Copy the data into buffer.
2787   //
2788   CopyMem (
2789     Buffer->Ptr + Buffer->Size,
2790     Data,
2791     DataSize
2792     );
2793   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + DataSize);
2794 
2795   mUnfixPolicyEntry[Type](Selector, Data);
2796 
2797   return EFI_SUCCESS;
2798 }
2799 
2800 /**
2801   Visit all IPsec Configurations of specified Type and call the caller defined
2802   interface.
2803 
2804   @param[in]  DataType          The specified IPsec Config Data Type.
2805   @param[in]  Routine           The function defined by the caller.
2806   @param[in]  Context           The data passed to the Routine.
2807 
2808   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated
2809   @retval EFI_SUCCESS            This function completed successfully.
2810 
2811 **/
2812 EFI_STATUS
IpSecVisitConfigData(IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN IPSEC_COPY_POLICY_ENTRY Routine,IN VOID * Context)2813 IpSecVisitConfigData (
2814   IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
2815   IN IPSEC_COPY_POLICY_ENTRY    Routine,
2816   IN VOID                       *Context
2817   )
2818 {
2819   EFI_STATUS                GetNextStatus;
2820   EFI_STATUS                GetDataStatus;
2821   EFI_STATUS                RoutineStatus;
2822   EFI_IPSEC_CONFIG_SELECTOR *Selector;
2823   VOID                      *Data;
2824   UINTN                     SelectorSize;
2825   UINTN                     DataSize;
2826   UINTN                     SelectorBufferSize;
2827   UINTN                     DataBufferSize;
2828   BOOLEAN                   FirstGetNext;
2829 
2830   FirstGetNext        = TRUE;
2831   DataBufferSize      = 0;
2832   Data                = NULL;
2833   SelectorBufferSize  = sizeof (EFI_IPSEC_CONFIG_SELECTOR);
2834   Selector            = AllocateZeroPool (SelectorBufferSize);
2835 
2836   if (Selector == NULL) {
2837     return EFI_OUT_OF_RESOURCES;
2838   }
2839 
2840   while (TRUE) {
2841     //
2842     // Get the real size of the selector.
2843     //
2844     SelectorSize = SelectorBufferSize;
2845     GetNextStatus = EfiIpSecConfigGetNextSelector (
2846                       &mIpSecConfigInstance,
2847                       DataType,
2848                       &SelectorSize,
2849                       Selector
2850                       );
2851     if (GetNextStatus == EFI_BUFFER_TOO_SMALL) {
2852       FreePool (Selector);
2853       SelectorBufferSize = SelectorSize;
2854       //
2855       // Allocate zero pool for the first selector, while store the last
2856       // selector content for the other selectors.
2857       //
2858       if (FirstGetNext) {
2859         Selector = AllocateZeroPool (SelectorBufferSize);
2860       } else {
2861         Selector = AllocateCopyPool (SelectorBufferSize, Selector);
2862       }
2863 
2864       if (Selector == NULL) {
2865         return EFI_OUT_OF_RESOURCES;
2866       }
2867       //
2868       // Get the content of the selector.
2869       //
2870       GetNextStatus = EfiIpSecConfigGetNextSelector (
2871                         &mIpSecConfigInstance,
2872                         DataType,
2873                         &SelectorSize,
2874                         Selector
2875                         );
2876     }
2877 
2878     if (EFI_ERROR (GetNextStatus)) {
2879       break;
2880     }
2881 
2882     FirstGetNext = FALSE;
2883 
2884     //
2885     // Get the real size of the policy entry according to the selector.
2886     //
2887     DataSize = DataBufferSize;
2888     GetDataStatus = EfiIpSecConfigGetData (
2889                       &mIpSecConfigInstance,
2890                       DataType,
2891                       Selector,
2892                       &DataSize,
2893                       Data
2894                       );
2895     if (GetDataStatus == EFI_BUFFER_TOO_SMALL) {
2896       if (Data != NULL) {
2897         FreePool (Data);
2898       }
2899 
2900       DataBufferSize  = DataSize;
2901       Data            = AllocateZeroPool (DataBufferSize);
2902 
2903       if (Data == NULL) {
2904         return EFI_OUT_OF_RESOURCES;
2905       }
2906       //
2907       // Get the content of the policy entry according to the selector.
2908       //
2909       GetDataStatus = EfiIpSecConfigGetData (
2910                         &mIpSecConfigInstance,
2911                         DataType,
2912                         Selector,
2913                         &DataSize,
2914                         Data
2915                         );
2916     }
2917 
2918     if (EFI_ERROR (GetDataStatus)) {
2919       break;
2920     }
2921     //
2922     // Prepare the buffer of updated policy entry, which is stored in
2923     // the continous memory, and then save into variable later.
2924     //
2925     RoutineStatus = Routine (
2926                       DataType,
2927                       Selector,
2928                       Data,
2929                       SelectorSize,
2930                       DataSize,
2931                       Context
2932                       );
2933     if (EFI_ERROR (RoutineStatus)) {
2934       break;
2935     }
2936   }
2937 
2938   if (Data != NULL) {
2939     FreePool (Data);
2940   }
2941 
2942   if (Selector != NULL) {
2943     FreePool (Selector);
2944   }
2945 
2946   return EFI_SUCCESS;
2947 }
2948 
2949 /**
2950   This function is the subfunction of  EFIIpSecConfigSetData.
2951 
2952   This function call IpSecSetVaraible to set the IPsec Configuration into the firmware.
2953 
2954   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.
2955   @retval EFI_SUCCESS            Saved the configration successfully.
2956   @retval Others                 Other errors were found while obtaining the variable.
2957 
2958 **/
2959 EFI_STATUS
IpSecConfigSave(VOID)2960 IpSecConfigSave (
2961   VOID
2962   )
2963 {
2964   IPSEC_VARIABLE_BUFFER       Buffer;
2965   EFI_STATUS                  Status;
2966   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
2967 
2968   Buffer.Size     = 0;
2969   Buffer.Capacity = IPSEC_DEFAULT_VARIABLE_SIZE;
2970   Buffer.Ptr      = AllocateZeroPool (Buffer.Capacity);
2971 
2972   if (Buffer.Ptr == NULL) {
2973     return EFI_OUT_OF_RESOURCES;
2974   }
2975   //
2976   // For each policy database, prepare the contious buffer to save into variable.
2977   //
2978   for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
2979     IpSecVisitConfigData (
2980       Type,
2981       (IPSEC_COPY_POLICY_ENTRY) IpSecCopyPolicyEntry,
2982       &Buffer
2983       );
2984   }
2985   //
2986   // Save the updated policy database into variable.
2987   //
2988   Status = IpSecSetVariable (
2989              IPSECCONFIG_VARIABLE_NAME,
2990              &gEfiIpSecConfigProtocolGuid,
2991              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2992              Buffer.Size,
2993              Buffer.Ptr
2994              );
2995 
2996   FreePool (Buffer.Ptr);
2997 
2998   return Status;
2999 }
3000 
3001 /**
3002   Get the all IPSec configuration variables and store those variables
3003   to the internal data structure.
3004 
3005   This founction is called by IpSecConfigInitialize() which is to intialize the
3006   IPsecConfiguration Protocol.
3007 
3008   @param[in]  Private            Point to IPSEC_PRIVATE_DATA.
3009 
3010   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated
3011   @retval EFI_SUCCESS            Restore the IPsec Configuration successfully.
3012   @retval  others                Other errors is found while obtaining the variable.
3013 
3014 **/
3015 EFI_STATUS
IpSecConfigRestore(IN IPSEC_PRIVATE_DATA * Private)3016 IpSecConfigRestore (
3017   IN IPSEC_PRIVATE_DATA           *Private
3018   )
3019 {
3020   EFI_STATUS                  Status;
3021   UINTN                       BufferSize;
3022   UINT8                       *Buffer;
3023   IPSEC_VAR_ITEM_HEADER       *Header;
3024   UINT8                       *Ptr;
3025   EFI_IPSEC_CONFIG_SELECTOR   *Selector;
3026   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
3027   VOID                        *Data;
3028   UINT8                       Value;
3029   UINTN                       Size;
3030 
3031   Value       = 0;
3032   Size        = sizeof (Value);
3033   BufferSize  = 0;
3034   Buffer      = NULL;
3035 
3036   Status = gRT->GetVariable (
3037                   IPSECCONFIG_STATUS_NAME,
3038                   &gEfiIpSecConfigProtocolGuid,
3039                   NULL,
3040                   &Size,
3041                   &Value
3042              );
3043 
3044   if (!EFI_ERROR (Status) && Value == IPSEC_STATUS_ENABLED) {
3045     Private->IpSec.DisabledFlag = FALSE;
3046   }
3047   //
3048   // Get the real size of policy database in variable.
3049   //
3050   Status = IpSecGetVariable (
3051              IPSECCONFIG_VARIABLE_NAME,
3052              &gEfiIpSecConfigProtocolGuid,
3053              NULL,
3054              &BufferSize,
3055              Buffer
3056              );
3057   if (Status == EFI_BUFFER_TOO_SMALL) {
3058 
3059     Buffer = AllocateZeroPool (BufferSize);
3060     if (Buffer == NULL) {
3061       return EFI_OUT_OF_RESOURCES;
3062     }
3063     //
3064     // Get the content of policy database in variable.
3065     //
3066     Status = IpSecGetVariable (
3067                IPSECCONFIG_VARIABLE_NAME,
3068                &gEfiIpSecConfigProtocolGuid,
3069                NULL,
3070                &BufferSize,
3071                Buffer
3072                );
3073     if (EFI_ERROR (Status)) {
3074       FreePool (Buffer);
3075       return Status;
3076     }
3077 
3078     for (Ptr = Buffer; Ptr < Buffer + BufferSize;) {
3079 
3080       Header  = (IPSEC_VAR_ITEM_HEADER *) Ptr;
3081       Type    = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT);
3082       ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum));
3083 
3084       Selector  = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN));
3085       Header    = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER (
3086                                               (UINT8 *) Selector + Header->Size,
3087                                               sizeof (UINTN)
3088                                               );
3089       ASSERT (Header->Type == Type);
3090 
3091       Data = ALIGN_POINTER (Header + 1, sizeof (UINTN));
3092 
3093       mUnfixPolicyEntry[Type](Selector, Data);
3094 
3095       //
3096       // Update each policy entry according to the content in variable.
3097       //
3098       mSetBySelf = TRUE;
3099       Status = EfiIpSecConfigSetData (
3100                  &Private->IpSecConfig,
3101                  Type,
3102                  Selector,
3103                  Data,
3104                  NULL
3105                  );
3106       mSetBySelf = FALSE;
3107 
3108       if (EFI_ERROR (Status)) {
3109         FreePool (Buffer);
3110         return Status;
3111       }
3112 
3113       Ptr =  ALIGN_POINTER ((UINT8 *) Data + Header->Size, sizeof (UINTN));
3114     }
3115 
3116     FreePool (Buffer);
3117   }
3118 
3119   return EFI_SUCCESS;
3120 }
3121 
3122 /**
3123   Install and Initialize IPsecConfig protocol
3124 
3125   @param[in, out]  Private   Pointer to IPSEC_PRIVATE_DATA. After this function finish,
3126                              the pointer of IPsecConfig Protocol implementation will copy
3127                              into its IPsecConfig member.
3128 
3129   @retval     EFI_SUCCESS    Initialized the IPsecConfig Protocol successfully.
3130   @retval     Others         Initializing the IPsecConfig Protocol failed.
3131 **/
3132 EFI_STATUS
IpSecConfigInitialize(IN OUT IPSEC_PRIVATE_DATA * Private)3133 IpSecConfigInitialize (
3134   IN OUT IPSEC_PRIVATE_DATA        *Private
3135   )
3136 {
3137   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
3138 
3139   CopyMem (
3140     &Private->IpSecConfig,
3141     &mIpSecConfigInstance,
3142     sizeof (EFI_IPSEC_CONFIG_PROTOCOL)
3143     );
3144 
3145   //
3146   // Initialize the list head of policy database.
3147   //
3148   for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
3149     InitializeListHead (&mConfigData[Type]);
3150   }
3151   //
3152   // Restore the content of policy database according to the variable.
3153   //
3154   IpSecConfigRestore (Private);
3155 
3156   return gBS->InstallMultipleProtocolInterfaces (
3157                 &Private->Handle,
3158                 &gEfiIpSecConfigProtocolGuid,
3159                 &Private->IpSecConfig,
3160                 NULL
3161                 );
3162 }
3163