1 /** @file
2   The implementation of IPSEC_CONFIG_PROTOCOL.
3 
4   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "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 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 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 fields in the two Spdselectors.
433   // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
434   // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. 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   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
1022   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1023 
1024 **/
1025 EFI_STATUS
SetSpdEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1026 SetSpdEntry (
1027   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1028   IN VOID                            *Data,
1029   IN VOID                            *Context OPTIONAL
1030   )
1031 {
1032   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
1033   EFI_IPSEC_SPD_DATA      *SpdData;
1034   EFI_IPSEC_SPD_SELECTOR  *InsertBefore;
1035   LIST_ENTRY              *SpdList;
1036   LIST_ENTRY              *SadList;
1037   LIST_ENTRY              *SpdSas;
1038   LIST_ENTRY              *EntryInsertBefore;
1039   LIST_ENTRY              *Entry;
1040   LIST_ENTRY              *Entry2;
1041   LIST_ENTRY              *NextEntry;
1042   IPSEC_SPD_ENTRY         *SpdEntry;
1043   IPSEC_SAD_ENTRY         *SadEntry;
1044   UINTN                   SpdEntrySize;
1045   UINTN                   Index;
1046 
1047   SpdSel        = (Selector == NULL) ? NULL : &Selector->SpdSelector;
1048   SpdData       = (Data == NULL) ? NULL : (EFI_IPSEC_SPD_DATA *) Data;
1049   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SpdSelector;
1050   SpdList       = &mConfigData[IPsecConfigDataTypeSpd];
1051 
1052   if (SpdSel != NULL) {
1053     if (SpdSel->LocalAddress == NULL || SpdSel->RemoteAddress == NULL) {
1054       return EFI_INVALID_PARAMETER;
1055     }
1056   }
1057 
1058   if (SpdData != NULL) {
1059     if ((SpdData->Action == EfiIPsecActionProtect && SpdData->ProcessingPolicy == NULL) ||
1060         (SpdData->Action != EfiIPsecActionProtect && SpdData->ProcessingPolicy != NULL)
1061         ) {
1062       return EFI_INVALID_PARAMETER;
1063     }
1064 
1065     if (SpdData->Action == EfiIPsecActionProtect) {
1066       if ((SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption == NULL) ||
1067           (SpdData->ProcessingPolicy->Mode != EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption != NULL)
1068           ) {
1069         return EFI_INVALID_PARAMETER;
1070       }
1071     }
1072   }
1073   //
1074   // The default behavior is to insert the node ahead of the header.
1075   //
1076   EntryInsertBefore = SpdList;
1077 
1078   //
1079   // Remove the existed SPD entry.
1080   //
1081   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) {
1082 
1083     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1084 
1085     if (SpdSel == NULL ||
1086         CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel)
1087         ) {
1088       //
1089       // Record the existed entry position to keep the original order.
1090       //
1091       EntryInsertBefore = SpdEntry->List.ForwardLink;
1092       RemoveEntryList (&SpdEntry->List);
1093 
1094       //
1095       // Update the reverse ref of SAD entry in the SPD.sas list.
1096       //
1097       SpdSas = &SpdEntry->Data->Sas;
1098 
1099       //
1100       // TODO: Deleted the related SAs.
1101       //
1102       NET_LIST_FOR_EACH (Entry2, SpdSas) {
1103         SadEntry                  = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);
1104         SadEntry->Data->SpdEntry  = NULL;
1105       }
1106 
1107       //
1108       // Free the existed SPD entry
1109       //
1110       FreePool (SpdEntry);
1111     }
1112   }
1113   //
1114   // Return success here if only want to remove the SPD entry.
1115   //
1116   if (SpdData == NULL || SpdSel == NULL) {
1117     return EFI_SUCCESS;
1118   }
1119   //
1120   // Search the appointed entry position if InsertBefore is not NULL.
1121   //
1122   if (InsertBefore != NULL) {
1123 
1124     NET_LIST_FOR_EACH (Entry, SpdList) {
1125       SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1126 
1127       if (CompareSpdSelector (
1128             (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
1129             (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1130             )) {
1131         EntryInsertBefore = Entry;
1132         break;
1133       }
1134     }
1135   }
1136 
1137   //
1138   // Do Padding for the different Arch.
1139   //
1140   SpdEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SPD_ENTRY));
1141   SpdEntrySize  = ALIGN_VARIABLE (SpdEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SpdSel));
1142   SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData);
1143 
1144   SpdEntry = AllocateZeroPool (SpdEntrySize);
1145 
1146   if (SpdEntry == NULL) {
1147     return EFI_OUT_OF_RESOURCES;
1148   }
1149   //
1150   // Fix the address of Selector and Data buffer and copy them, which is
1151   // continous memory and close to the base structure of SPD entry.
1152   //
1153   SpdEntry->Selector  = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN));
1154   SpdEntry->Data      = (IPSEC_SPD_DATA *) ALIGN_POINTER (
1155                                             ((UINT8 *) SpdEntry->Selector + SIZE_OF_SPD_SELECTOR (SpdSel)),
1156                                             sizeof (UINTN)
1157                                             );
1158 
1159   DuplicateSpdSelector (
1160     (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
1161     (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
1162     NULL
1163     );
1164 
1165   CopyMem (
1166     SpdEntry->Data->Name,
1167     SpdData->Name,
1168     sizeof (SpdData->Name)
1169     );
1170   SpdEntry->Data->PackageFlag = SpdData->PackageFlag;
1171   SpdEntry->Data->Action      = SpdData->Action;
1172 
1173   //
1174   // Fix the address of ProcessingPolicy and copy it if need, which is continous
1175   // memory and close to the base structure of SAD data.
1176   //
1177   if (SpdData->Action != EfiIPsecActionProtect) {
1178     SpdEntry->Data->ProcessingPolicy = NULL;
1179   } else {
1180     SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER (
1181                                                                       SpdEntry->Data + 1,
1182                                                                       sizeof (UINTN)
1183                                                                       );
1184     IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);
1185   }
1186   //
1187   // Update the sas list of the new SPD entry.
1188   //
1189   InitializeListHead (&SpdEntry->Data->Sas);
1190 
1191   SadList = &mConfigData[IPsecConfigDataTypeSad];
1192 
1193   NET_LIST_FOR_EACH (Entry, SadList) {
1194     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1195 
1196     for (Index = 0; Index < SpdData->SaIdCount; Index++) {
1197 
1198       if (CompareSaId (
1199             (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],
1200             (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
1201             )) {
1202         InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1203         SadEntry->Data->SpdEntry = SpdEntry;
1204         DuplicateSpdSelector (
1205           (EFI_IPSEC_CONFIG_SELECTOR *)SadEntry->Data->SpdSelector,
1206           (EFI_IPSEC_CONFIG_SELECTOR *)SpdEntry->Selector,
1207           NULL
1208           );
1209       }
1210     }
1211   }
1212   //
1213   // Insert the new SPD entry.
1214   //
1215   InsertTailList (EntryInsertBefore, &SpdEntry->List);
1216 
1217   return EFI_SUCCESS;
1218 }
1219 
1220 /**
1221   Set the security association information for the EFI IPsec driver.
1222 
1223   The IPsec configuration data has a unique selector/identifier separately to
1224   identify a data entry.
1225 
1226   @param[in]  Selector           Pointer to an entry selector on operated
1227                                  configuration data specified by DataType.
1228                                  A NULL Selector causes the entire specified-type
1229                                  configuration information to be flushed.
1230   @param[in]  Data               The data buffer to be set. The structure
1231                                  of the data buffer should be EFI_IPSEC_SA_DATA.
1232   @param[in]  Context            Pointer to one entry selector which describes
1233                                  the expected position the new data entry will
1234                                  be added. If Context is NULL,the new entry will
1235                                  be appended the end of database.
1236 
1237   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
1238   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1239 
1240 **/
1241 EFI_STATUS
SetSadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1242 SetSadEntry (
1243   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1244   IN VOID                            *Data,
1245   IN VOID                            *Context OPTIONAL
1246   )
1247 {
1248   IPSEC_SAD_ENTRY   *SadEntry;
1249   IPSEC_SPD_ENTRY   *SpdEntry;
1250   LIST_ENTRY        *Entry;
1251   LIST_ENTRY        *NextEntry;
1252   LIST_ENTRY        *SadList;
1253   LIST_ENTRY        *SpdList;
1254   EFI_IPSEC_SA_ID   *SaId;
1255   EFI_IPSEC_SA_DATA2 *SaData;
1256   EFI_IPSEC_SA_ID   *InsertBefore;
1257   LIST_ENTRY        *EntryInsertBefore;
1258   UINTN             SadEntrySize;
1259 
1260   SaId          = (Selector == NULL) ? NULL : &Selector->SaId;
1261   SaData        = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data;
1262   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;
1263   SadList       = &mConfigData[IPsecConfigDataTypeSad];
1264 
1265   //
1266   // The default behavior is to insert the node ahead of the header.
1267   //
1268   EntryInsertBefore = SadList;
1269 
1270   //
1271   // Remove the existed SAD entry.
1272   //
1273   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {
1274 
1275     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1276 
1277     if (SaId == NULL ||
1278         CompareSaId (
1279           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1280           (EFI_IPSEC_CONFIG_SELECTOR *) SaId
1281           )) {
1282       //
1283       // Record the existed entry position to keep the original order.
1284       //
1285       EntryInsertBefore = SadEntry->List.ForwardLink;
1286 
1287       //
1288       // Update the related SAD.byspd field.
1289       //
1290       if (SadEntry->Data->SpdEntry != NULL) {
1291         RemoveEntryList (&SadEntry->BySpd);
1292       }
1293 
1294       RemoveEntryList (&SadEntry->List);
1295       FreePool (SadEntry);
1296     }
1297   }
1298   //
1299   // Return success here if only want to remove the SAD entry
1300   //
1301   if (SaData == NULL || SaId == NULL) {
1302     return EFI_SUCCESS;
1303   }
1304   //
1305   // Search the appointed entry position if InsertBefore is not NULL.
1306   //
1307   if (InsertBefore != NULL) {
1308 
1309     NET_LIST_FOR_EACH (Entry, SadList) {
1310       SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1311 
1312       if (CompareSaId (
1313            (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1314            (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1315            )) {
1316         EntryInsertBefore = Entry;
1317         break;
1318       }
1319     }
1320   }
1321 
1322   //
1323   // Do Padding for different Arch.
1324   //
1325   SadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY));
1326   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_ID));
1327   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA));
1328 
1329   if (SaId->Proto == EfiIPsecAH) {
1330     SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength;
1331   } else {
1332     SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength);
1333     SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength);
1334   }
1335 
1336   if (SaData->SpdSelector != NULL) {
1337     SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);
1338   }
1339   SadEntry      = AllocateZeroPool (SadEntrySize);
1340 
1341   if (SadEntry == NULL) {
1342     return EFI_OUT_OF_RESOURCES;
1343   }
1344   //
1345   // Fix the address of Id and Data buffer and copy them, which is
1346   // continous memory and close to the base structure of SAD entry.
1347   //
1348   SadEntry->Id    = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN));
1349   SadEntry->Data  = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN));
1350 
1351   CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID));
1352 
1353   SadEntry->Data->Mode                  = SaData->Mode;
1354   SadEntry->Data->SequenceNumber        = SaData->SNCount;
1355   SadEntry->Data->AntiReplayWindowSize  = SaData->AntiReplayWindows;
1356 
1357   ZeroMem (
1358     &SadEntry->Data->AntiReplayBitmap,
1359     sizeof (SadEntry->Data->AntiReplayBitmap)
1360     );
1361 
1362   ZeroMem (
1363     &SadEntry->Data->AlgoInfo,
1364     sizeof (EFI_IPSEC_ALGO_INFO)
1365     );
1366 
1367   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId;
1368   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength;
1369 
1370   if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
1371     SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN));
1372     CopyMem (
1373       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1374       SaData->AlgoInfo.EspAlgoInfo.AuthKey,
1375       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength
1376       );
1377   }
1378 
1379   if (SaId->Proto == EfiIPsecESP) {
1380     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId    = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId;
1381     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;
1382 
1383     if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
1384       SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
1385                                                                ((UINT8 *) (SadEntry->Data + 1) +
1386                                                                  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),
1387                                                                  sizeof (UINTN)
1388                                                                  );
1389       CopyMem (
1390         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1391         SaData->AlgoInfo.EspAlgoInfo.EncKey,
1392         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength
1393         );
1394     }
1395   }
1396 
1397   CopyMem (
1398     &SadEntry->Data->SaLifetime,
1399     &SaData->SaLifetime,
1400     sizeof (EFI_IPSEC_SA_LIFETIME)
1401     );
1402 
1403   SadEntry->Data->PathMTU     = SaData->PathMTU;
1404   SadEntry->Data->SpdSelector = NULL;
1405   SadEntry->Data->ESNEnabled  = FALSE;
1406   SadEntry->Data->ManualSet   = SaData->ManualSet;
1407 
1408   //
1409   // Copy Tunnel Source/Destination Address
1410   //
1411   if (SaData->Mode == EfiIPsecTunnel) {
1412     CopyMem (
1413       &SadEntry->Data->TunnelDestAddress,
1414       &SaData->TunnelDestinationAddress,
1415       sizeof (EFI_IP_ADDRESS)
1416       );
1417     CopyMem (
1418       &SadEntry->Data->TunnelSourceAddress,
1419       &SaData->TunnelSourceAddress,
1420       sizeof (EFI_IP_ADDRESS)
1421       );
1422   }
1423   //
1424   // Update the spd.sas list of the spd entry specified by SAD selector
1425   //
1426   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1427 
1428   for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) {
1429 
1430     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1431     if (IsSubSpdSelector (
1432           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1433           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1434           ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {
1435       SadEntry->Data->SpdEntry = SpdEntry;
1436       SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry +
1437                                                                 SadEntrySize -
1438                                                                 (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector)
1439                                                                 );
1440       DuplicateSpdSelector (
1441        (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1442        (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1443        NULL
1444        );
1445       InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1446     }
1447   }
1448   //
1449   // Insert the new SAD entry.
1450   //
1451   InsertTailList (EntryInsertBefore, &SadEntry->List);
1452 
1453   return EFI_SUCCESS;
1454 }
1455 
1456 /**
1457   Set the peer authorization configuration information for the EFI IPsec driver.
1458 
1459   The IPsec configuration data has a unique selector/identifier separately to
1460   identify a data entry.
1461 
1462   @param[in]  Selector           Pointer to an entry selector on operated
1463                                  configuration data specified by DataType.
1464                                  A NULL Selector causes the entire specified-type
1465                                  configuration information to be flushed.
1466   @param[in]  Data               The data buffer to be set. The structure
1467                                  of the data buffer should be EFI_IPSEC_PAD_DATA.
1468   @param[in]  Context            Pointer to one entry selector that describes
1469                                  the expected position the new data entry will
1470                                  be added. If Context is NULL, the new entry will
1471                                  be appended the end of database.
1472 
1473   @retval EFI_OUT_OF_RESOURCES  The required system resources could not be allocated.
1474   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1475 
1476 **/
1477 EFI_STATUS
SetPadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1478 SetPadEntry (
1479   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1480   IN VOID                            *Data,
1481   IN VOID                            *Context OPTIONAL
1482   )
1483 {
1484   IPSEC_PAD_ENTRY     *PadEntry;
1485   EFI_IPSEC_PAD_ID    *PadId;
1486   EFI_IPSEC_PAD_DATA  *PadData;
1487   LIST_ENTRY          *PadList;
1488   LIST_ENTRY          *Entry;
1489   LIST_ENTRY          *NextEntry;
1490   EFI_IPSEC_PAD_ID    *InsertBefore;
1491   LIST_ENTRY          *EntryInsertBefore;
1492   UINTN               PadEntrySize;
1493 
1494   PadId         = (Selector == NULL) ? NULL : &Selector->PadId;
1495   PadData       = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data;
1496   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId;
1497   PadList       = &mConfigData[IPsecConfigDataTypePad];
1498 
1499   //
1500   // The default behavior is to insert the node ahead of the header.
1501   //
1502   EntryInsertBefore = PadList;
1503 
1504   //
1505   // Remove the existed pad entry.
1506   //
1507   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) {
1508 
1509     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1510 
1511     if (PadId == NULL ||
1512         ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)
1513         ) {
1514       //
1515       // Record the existed entry position to keep the original order.
1516       //
1517       EntryInsertBefore = PadEntry->List.ForwardLink;
1518       RemoveEntryList (&PadEntry->List);
1519 
1520       FreePool (PadEntry);
1521     }
1522   }
1523   //
1524   // Return success here if only want to remove the pad entry
1525   //
1526   if (PadData == NULL || PadId == NULL) {
1527     return EFI_SUCCESS;
1528   }
1529   //
1530   // Search the appointed entry position if InsertBefore is not NULL.
1531   //
1532   if (InsertBefore != NULL) {
1533 
1534     NET_LIST_FOR_EACH (Entry, PadList) {
1535       PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1536 
1537       if (ComparePadId (
1538             (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id,
1539             (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1540             )) {
1541         EntryInsertBefore = Entry;
1542         break;
1543       }
1544     }
1545   }
1546 
1547   //
1548   // Do PADDING for different arch.
1549   //
1550   PadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY));
1551   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID));
1552   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA));
1553   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0));
1554   PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0;
1555 
1556   PadEntry      = AllocateZeroPool (PadEntrySize);
1557 
1558   if (PadEntry == NULL) {
1559     return EFI_OUT_OF_RESOURCES;
1560   }
1561   //
1562   // Fix the address of Id and Data buffer and copy them, which is
1563   // continous memory and close to the base structure of pad entry.
1564   //
1565   PadEntry->Id    = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN));
1566   PadEntry->Data  = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN));
1567 
1568   CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID));
1569 
1570   PadEntry->Data->AuthProtocol  = PadData->AuthProtocol;
1571   PadEntry->Data->AuthMethod    = PadData->AuthMethod;
1572   PadEntry->Data->IkeIdFlag     = PadData->IkeIdFlag;
1573 
1574   if (PadData->AuthData != NULL) {
1575     PadEntry->Data->AuthDataSize  = PadData->AuthDataSize;
1576     PadEntry->Data->AuthData      = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN));
1577     CopyMem (
1578       PadEntry->Data->AuthData,
1579       PadData->AuthData,
1580       PadData->AuthDataSize
1581       );
1582   } else {
1583     PadEntry->Data->AuthDataSize  = 0;
1584     PadEntry->Data->AuthData      = NULL;
1585   }
1586 
1587   if (PadData->RevocationData != NULL) {
1588     PadEntry->Data->RevocationDataSize  = PadData->RevocationDataSize;
1589     PadEntry->Data->RevocationData      = (VOID *) ALIGN_POINTER (
1590                                                     ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize),
1591                                                     sizeof (UINTN)
1592                                                     );
1593     CopyMem (
1594       PadEntry->Data->RevocationData,
1595       PadData->RevocationData,
1596       PadData->RevocationDataSize
1597       );
1598   } else {
1599     PadEntry->Data->RevocationDataSize  = 0;
1600     PadEntry->Data->RevocationData      = NULL;
1601   }
1602   //
1603   // Insert the new pad entry.
1604   //
1605   InsertTailList (EntryInsertBefore, &PadEntry->List);
1606 
1607   return EFI_SUCCESS;
1608 }
1609 
1610 /**
1611   This function lookup the data entry from IPsec SPD. Return the configuration
1612   value of the specified SPD Entry.
1613 
1614   @param[in]      Selector      Pointer to an entry selector which is an identifier
1615                                 of the SPD entry.
1616   @param[in, out] DataSize      On output the size of data returned in Data.
1617   @param[out]     Data          The buffer to return the contents of the IPsec
1618                                 configuration data. The type of the data buffer
1619                                 is associated with the DataType.
1620 
1621   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1622   @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
1623   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1624   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1625                                 updated with the size needed to complete the request.
1626 
1627 **/
1628 EFI_STATUS
GetSpdEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1629 GetSpdEntry (
1630   IN     EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1631   IN OUT UINTN                           *DataSize,
1632      OUT VOID                            *Data
1633   )
1634 {
1635   IPSEC_SPD_ENTRY         *SpdEntry;
1636   IPSEC_SAD_ENTRY         *SadEntry;
1637   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
1638   EFI_IPSEC_SPD_DATA      *SpdData;
1639   LIST_ENTRY              *SpdList;
1640   LIST_ENTRY              *SpdSas;
1641   LIST_ENTRY              *Entry;
1642   UINTN                   RequiredSize;
1643 
1644   SpdSel  = &Selector->SpdSelector;
1645   SpdData = (EFI_IPSEC_SPD_DATA *) Data;
1646   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1647 
1648   NET_LIST_FOR_EACH (Entry, SpdList) {
1649     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1650 
1651     //
1652     // Find the required SPD entry
1653     //
1654     if (CompareSpdSelector (
1655           (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
1656           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1657           )) {
1658 
1659       RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data);
1660       if (*DataSize < RequiredSize) {
1661         *DataSize = RequiredSize;
1662         return EFI_BUFFER_TOO_SMALL;
1663       }
1664 
1665       if (SpdData == NULL) {
1666         return EFI_INVALID_PARAMETER;
1667       }
1668 
1669       *DataSize = RequiredSize;
1670 
1671       //
1672       // Extract and fill all SaId array from the SPD.sas list
1673       //
1674       SpdSas              = &SpdEntry->Data->Sas;
1675       SpdData->SaIdCount  = 0;
1676 
1677       NET_LIST_FOR_EACH (Entry, SpdSas) {
1678         SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
1679         CopyMem (
1680           &SpdData->SaId[SpdData->SaIdCount++],
1681           SadEntry->Id,
1682           sizeof (EFI_IPSEC_SA_ID)
1683           );
1684       }
1685       //
1686       // Fill the other fields in SPD data.
1687       //
1688       CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name));
1689 
1690       SpdData->PackageFlag  = SpdEntry->Data->PackageFlag;
1691       SpdData->Action       = SpdEntry->Data->Action;
1692 
1693       if (SpdData->Action != EfiIPsecActionProtect) {
1694         SpdData->ProcessingPolicy = NULL;
1695       } else {
1696         SpdData->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ((UINT8 *) SpdData + sizeof (EFI_IPSEC_SPD_DATA) + (SpdData->SaIdCount - 1) * sizeof (EFI_IPSEC_SA_ID));
1697 
1698         IpSecDuplicateProcessPolicy (
1699           SpdData->ProcessingPolicy,
1700           SpdEntry->Data->ProcessingPolicy
1701           );
1702       }
1703 
1704       return EFI_SUCCESS;
1705     }
1706   }
1707 
1708   return EFI_NOT_FOUND;
1709 }
1710 
1711 /**
1712   This function lookup the data entry from IPsec SAD. Return the configuration
1713   value of the specified SAD Entry.
1714 
1715   @param[in]      Selector      Pointer to an entry selector which is an identifier
1716                                 of the SAD entry.
1717   @param[in, out] DataSize      On output, the size of data returned in Data.
1718   @param[out]     Data          The buffer to return the contents of the IPsec
1719                                 configuration data. The type of the data buffer
1720                                 is associated with the DataType.
1721 
1722   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1723   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1724   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1725                                 updated with the size needed to complete the request.
1726 
1727 **/
1728 EFI_STATUS
GetSadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1729 GetSadEntry (
1730   IN     EFI_IPSEC_CONFIG_SELECTOR     *Selector,
1731   IN OUT UINTN                         *DataSize,
1732      OUT VOID                          *Data
1733   )
1734 {
1735   IPSEC_SAD_ENTRY   *SadEntry;
1736   LIST_ENTRY        *Entry;
1737   LIST_ENTRY        *SadList;
1738   EFI_IPSEC_SA_ID   *SaId;
1739   EFI_IPSEC_SA_DATA2 *SaData;
1740   UINTN             RequiredSize;
1741 
1742   SaId    = &Selector->SaId;
1743   SaData  = (EFI_IPSEC_SA_DATA2 *) Data;
1744   SadList = &mConfigData[IPsecConfigDataTypeSad];
1745 
1746   NET_LIST_FOR_EACH (Entry, SadList) {
1747     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1748 
1749     //
1750     // Find the required SAD entry.
1751     //
1752     if (CompareSaId (
1753          (EFI_IPSEC_CONFIG_SELECTOR *) SaId,
1754          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
1755          )) {
1756       //
1757       // Calculate the required size of the SAD entry.
1758       // Data Layout is follows:
1759       // |EFI_IPSEC_SA_DATA
1760       // |AuthKey
1761       // |EncryptKey  (Optional)
1762       // |SpdSelector (Optional)
1763       //
1764       RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA2));
1765 
1766       if (SaId->Proto == EfiIPsecAH) {
1767         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength);
1768       } else {
1769         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength);
1770         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength);
1771       }
1772 
1773       if (SadEntry->Data->SpdSelector != NULL) {
1774         RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector);
1775       }
1776 
1777       if (*DataSize < RequiredSize) {
1778         *DataSize = RequiredSize;
1779         return EFI_BUFFER_TOO_SMALL;
1780       }
1781 
1782       //
1783       // Fill the data fields of SAD entry.
1784       //
1785       *DataSize                 = RequiredSize;
1786       SaData->Mode              = SadEntry->Data->Mode;
1787       SaData->SNCount           = SadEntry->Data->SequenceNumber;
1788       SaData->AntiReplayWindows = SadEntry->Data->AntiReplayWindowSize;
1789 
1790       CopyMem (
1791         &SaData->SaLifetime,
1792         &SadEntry->Data->SaLifetime,
1793         sizeof (EFI_IPSEC_SA_LIFETIME)
1794         );
1795 
1796       ZeroMem (
1797         &SaData->AlgoInfo,
1798         sizeof (EFI_IPSEC_ALGO_INFO)
1799         );
1800 
1801       if (SaId->Proto == EfiIPsecAH) {
1802         //
1803         // Copy AH alogrithm INFO to SaData
1804         //
1805         SaData->AlgoInfo.AhAlgoInfo.AuthAlgoId    = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthAlgoId;
1806         SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength;
1807         if (SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength != 0) {
1808           SaData->AlgoInfo.AhAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
1809           CopyMem (
1810             SaData->AlgoInfo.AhAlgoInfo.AuthKey,
1811             SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKey,
1812             SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength
1813             );
1814         }
1815       } else if (SaId->Proto == EfiIPsecESP) {
1816         //
1817         // Copy ESP alogrithem INFO to SaData
1818         //
1819         SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId;
1820         SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength;
1821         if (SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
1822           SaData->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
1823           CopyMem (
1824             SaData->AlgoInfo.EspAlgoInfo.AuthKey,
1825             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1826             SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength
1827             );
1828         }
1829 
1830         SaData->AlgoInfo.EspAlgoInfo.EncAlgoId    = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId;
1831         SaData->AlgoInfo.EspAlgoInfo.EncKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength;
1832 
1833         if (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
1834           SaData->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
1835                                                           ((UINT8 *) (SaData + 1) +
1836                                                             SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength),
1837                                                             sizeof (UINTN)
1838                                                             );
1839           CopyMem (
1840             SaData->AlgoInfo.EspAlgoInfo.EncKey,
1841             SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1842             SaData->AlgoInfo.EspAlgoInfo.EncKeyLength
1843             );
1844         }
1845       }
1846 
1847       SaData->PathMTU = SadEntry->Data->PathMTU;
1848 
1849       //
1850       // Fill Tunnel Address if it is Tunnel Mode
1851       //
1852       if (SadEntry->Data->Mode == EfiIPsecTunnel) {
1853         CopyMem (
1854           &SaData->TunnelDestinationAddress,
1855           &SadEntry->Data->TunnelDestAddress,
1856           sizeof (EFI_IP_ADDRESS)
1857           );
1858         CopyMem (
1859           &SaData->TunnelSourceAddress,
1860           &SadEntry->Data->TunnelSourceAddress,
1861           sizeof (EFI_IP_ADDRESS)
1862           );
1863       }
1864       //
1865       // Fill the spd selector field of SAD data
1866       //
1867       if (SadEntry->Data->SpdSelector != NULL) {
1868 
1869         SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) (
1870                                 (UINT8 *)SaData +
1871                                 RequiredSize -
1872                                 SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector)
1873                                 );
1874 
1875         DuplicateSpdSelector (
1876           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1877           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1878           NULL
1879           );
1880 
1881       } else {
1882 
1883         SaData->SpdSelector = NULL;
1884       }
1885 
1886       SaData->ManualSet = SadEntry->Data->ManualSet;
1887 
1888       return EFI_SUCCESS;
1889     }
1890   }
1891 
1892   return EFI_NOT_FOUND;
1893 }
1894 
1895 /**
1896   This function lookup the data entry from IPsec PAD. Return the configuration
1897   value of the specified PAD Entry.
1898 
1899   @param[in]      Selector      Pointer to an entry selector which is an identifier
1900                                 of the PAD entry.
1901   @param[in, out] DataSize      On output the size of data returned in Data.
1902   @param[out]     Data          The buffer to return the contents of the IPsec
1903                                 configuration data. The type of the data buffer
1904                                 is associated with the DataType.
1905 
1906   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1907   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1908   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1909                                 updated with the size needed to complete the request.
1910 
1911 **/
1912 EFI_STATUS
GetPadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1913 GetPadEntry (
1914   IN     EFI_IPSEC_CONFIG_SELECTOR   *Selector,
1915   IN OUT UINTN                       *DataSize,
1916      OUT VOID                        *Data
1917   )
1918 {
1919   IPSEC_PAD_ENTRY     *PadEntry;
1920   LIST_ENTRY          *PadList;
1921   LIST_ENTRY          *Entry;
1922   EFI_IPSEC_PAD_ID    *PadId;
1923   EFI_IPSEC_PAD_DATA  *PadData;
1924   UINTN               RequiredSize;
1925 
1926   PadId   = &Selector->PadId;
1927   PadData = (EFI_IPSEC_PAD_DATA *) Data;
1928   PadList = &mConfigData[IPsecConfigDataTypePad];
1929 
1930   NET_LIST_FOR_EACH (Entry, PadList) {
1931     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1932 
1933     //
1934     // Find the required pad entry.
1935     //
1936     if (ComparePadId (
1937           (EFI_IPSEC_CONFIG_SELECTOR *) PadId,
1938           (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id
1939           )) {
1940       //
1941       // Calculate the required size of the pad entry.
1942       //
1943       RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_PAD_DATA));
1944       RequiredSize  = ALIGN_VARIABLE (RequiredSize + PadEntry->Data->AuthDataSize);
1945       RequiredSize += PadEntry->Data->RevocationDataSize;
1946 
1947       if (*DataSize < RequiredSize) {
1948         *DataSize = RequiredSize;
1949         return EFI_BUFFER_TOO_SMALL;
1950       }
1951       //
1952       // Fill the data fields of pad entry
1953       //
1954       *DataSize             = RequiredSize;
1955       PadData->AuthProtocol = PadEntry->Data->AuthProtocol;
1956       PadData->AuthMethod   = PadEntry->Data->AuthMethod;
1957       PadData->IkeIdFlag    = PadEntry->Data->IkeIdFlag;
1958 
1959       //
1960       // Copy Authentication data.
1961       //
1962       if (PadEntry->Data->AuthData != NULL) {
1963 
1964         PadData->AuthDataSize = PadEntry->Data->AuthDataSize;
1965         PadData->AuthData     = (VOID *) ALIGN_POINTER ((PadData + 1), sizeof (UINTN));
1966         CopyMem (
1967           PadData->AuthData,
1968           PadEntry->Data->AuthData,
1969           PadData->AuthDataSize
1970           );
1971       } else {
1972 
1973         PadData->AuthDataSize = 0;
1974         PadData->AuthData     = NULL;
1975       }
1976       //
1977       // Copy Revocation Data.
1978       //
1979       if (PadEntry->Data->RevocationData != NULL) {
1980 
1981         PadData->RevocationDataSize = PadEntry->Data->RevocationDataSize;
1982         PadData->RevocationData     = (VOID *) ALIGN_POINTER (
1983                                                  ((UINT8 *) (PadData + 1) + PadData->AuthDataSize),
1984                                                   sizeof (UINTN)
1985                                                   );
1986         CopyMem (
1987           PadData->RevocationData,
1988           PadEntry->Data->RevocationData,
1989           PadData->RevocationDataSize
1990           );
1991       } else {
1992 
1993         PadData->RevocationDataSize = 0;
1994         PadData->RevocationData     = NULL;
1995       }
1996 
1997       return EFI_SUCCESS;
1998     }
1999   }
2000 
2001   return EFI_NOT_FOUND;
2002 }
2003 
2004 /**
2005   Copy Source Process Policy to the Destination Process Policy.
2006 
2007   @param[in]  Dst                  Pointer to the Source Process Policy.
2008   @param[in]  Src                  Pointer to the Destination Process Policy.
2009 
2010 **/
2011 VOID
IpSecDuplicateProcessPolicy(IN EFI_IPSEC_PROCESS_POLICY * Dst,IN EFI_IPSEC_PROCESS_POLICY * Src)2012 IpSecDuplicateProcessPolicy (
2013   IN EFI_IPSEC_PROCESS_POLICY            *Dst,
2014   IN EFI_IPSEC_PROCESS_POLICY            *Src
2015   )
2016 {
2017   //
2018   // Firstly copy the structure content itself.
2019   //
2020   CopyMem (Dst, Src, sizeof (EFI_IPSEC_PROCESS_POLICY));
2021 
2022   //
2023   // Recursively copy the tunnel option if needed.
2024   //
2025   if (Dst->Mode != EfiIPsecTunnel) {
2026     ASSERT (Dst->TunnelOption == NULL);
2027   } else {
2028     Dst->TunnelOption = (EFI_IPSEC_TUNNEL_OPTION *) ALIGN_POINTER ((Dst + 1), sizeof (UINTN));
2029     CopyMem (
2030       Dst->TunnelOption,
2031       Src->TunnelOption,
2032       sizeof (EFI_IPSEC_TUNNEL_OPTION)
2033       );
2034   }
2035 }
2036 
2037 /**
2038   Calculate the a whole size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed
2039   to by the pointer members.
2040 
2041   @param[in]  SpdData             Pointer to a specified EFI_IPSEC_SPD_DATA.
2042 
2043   @return the whole size the specified EFI_IPSEC_SPD_DATA.
2044 
2045 **/
2046 UINTN
IpSecGetSizeOfEfiSpdData(IN EFI_IPSEC_SPD_DATA * SpdData)2047 IpSecGetSizeOfEfiSpdData (
2048   IN EFI_IPSEC_SPD_DATA               *SpdData
2049   )
2050 {
2051   UINTN Size;
2052 
2053   Size = ALIGN_VARIABLE (sizeof (IPSEC_SPD_DATA));
2054 
2055   if (SpdData->Action == EfiIPsecActionProtect) {
2056     Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_PROCESS_POLICY));
2057 
2058     if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
2059       Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_TUNNEL_OPTION));
2060     }
2061   }
2062 
2063   return Size;
2064 }
2065 
2066 /**
2067   Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed
2068   to by the pointer members and the buffer size used by the Sa List.
2069 
2070   @param[in]  SpdData       Pointer to the specified IPSEC_SPD_DATA.
2071 
2072   @return the whole size of IPSEC_SPD_DATA.
2073 
2074 **/
2075 UINTN
IpSecGetSizeOfSpdData(IN IPSEC_SPD_DATA * SpdData)2076 IpSecGetSizeOfSpdData (
2077   IN IPSEC_SPD_DATA                   *SpdData
2078   )
2079 {
2080   UINTN       Size;
2081   LIST_ENTRY  *Link;
2082 
2083   Size = sizeof (EFI_IPSEC_SPD_DATA) - sizeof (EFI_IPSEC_SA_ID);
2084 
2085   if (SpdData->Action == EfiIPsecActionProtect) {
2086     Size += sizeof (EFI_IPSEC_PROCESS_POLICY);
2087 
2088     if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
2089       Size += sizeof (EFI_IPSEC_TUNNEL_OPTION);
2090     }
2091   }
2092 
2093   NET_LIST_FOR_EACH (Link, &SpdData->Sas) {
2094     Size += sizeof (EFI_IPSEC_SA_ID);
2095   }
2096 
2097   return Size;
2098 }
2099 
2100 /**
2101   Get the IPsec Variable.
2102 
2103   Get the all variables which start with the string contained in VaraiableName.
2104   Since all IPsec related variable store in continual space, those kinds of
2105   variable can be searched by the EfiGetNextVariableName. Those variables also are
2106   returned in a continual buffer.
2107 
2108   @param[in]      VariableName          Pointer to a specified Variable Name.
2109   @param[in]      VendorGuid            Pointer to a specified Vendor Guid.
2110   @param[in]      Attributes            Point to memory location to return the attributes
2111                                         of variable. If the point is NULL, the parameter
2112                                         would be ignored.
2113   @param[in, out] DataSize              As input, point to the maximum size of return
2114                                         Data-Buffer. As output, point to the actual
2115                                         size of the returned Data-Buffer.
2116   @param[in]      Data                  Point to return Data-Buffer.
2117 
2118   @retval  EFI_ABORTED           If the Variable size which contained in the variable
2119                                  structure doesn't match the variable size obtained
2120                                  from the EFIGetVariable.
2121   @retval  EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has
2122                                  been updated with the size needed to complete the request.
2123   @retval  EFI_SUCCESS           The function completed successfully.
2124   @retval  others                Other errors found during the variable getting.
2125 **/
2126 EFI_STATUS
IpSecGetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 * Attributes,OPTIONAL IN OUT UINTN * DataSize,IN VOID * Data)2127 IpSecGetVariable (
2128   IN     CHAR16                       *VariableName,
2129   IN     EFI_GUID                     *VendorGuid,
2130   IN     UINT32                       *Attributes, OPTIONAL
2131   IN OUT UINTN                        *DataSize,
2132   IN     VOID                         *Data
2133   )
2134 {
2135   EFI_STATUS            Status;
2136   EFI_GUID              VendorGuidI;
2137   UINTN                 VariableNameLength;
2138   CHAR16                *VariableNameI;
2139   UINTN                 VariableNameISize;
2140   UINTN                 VariableNameISizeNew;
2141   UINTN                 VariableIndex;
2142   UINTN                 VariableCount;
2143   IP_SEC_VARIABLE_INFO  IpSecVariableInfo;
2144   UINTN                 DataSizeI;
2145 
2146   //
2147   // The variable name constructor is "VariableName + Info/0001/0002/... + NULL".
2148   // So the varialbe name is like "VariableNameInfo", "VariableName0001", ...
2149   // "VariableNameNULL".
2150   //
2151   VariableNameLength  = StrLen (VariableName);
2152   VariableNameISize   = (VariableNameLength + 5) * sizeof (CHAR16);
2153   VariableNameI       = AllocateZeroPool (VariableNameISize);
2154   ASSERT (VariableNameI != NULL);
2155 
2156   //
2157   // Construct the varible name of ipsecconfig meta data.
2158   //
2159   UnicodeSPrint (VariableNameI, VariableNameISize, L"%s%s", VariableName, L"Info");
2160 
2161   DataSizeI = sizeof (IpSecVariableInfo);
2162 
2163   Status = gRT->GetVariable (
2164                   VariableNameI,
2165                   VendorGuid,
2166                   Attributes,
2167                   &DataSizeI,
2168                   &IpSecVariableInfo
2169                   );
2170   if (EFI_ERROR (Status)) {
2171     goto ON_EXIT;
2172   }
2173 
2174   if (*DataSize < IpSecVariableInfo.VariableSize) {
2175     *DataSize = IpSecVariableInfo.VariableSize;
2176     Status    = EFI_BUFFER_TOO_SMALL;
2177     goto ON_EXIT;
2178   }
2179 
2180   VariableCount     = IpSecVariableInfo.VariableCount;
2181   VariableNameI[0]  = L'\0';
2182 
2183   while (VariableCount != 0) {
2184     //
2185     // Get the variable name one by one in the variable database.
2186     //
2187     VariableNameISizeNew = VariableNameISize;
2188     Status = gRT->GetNextVariableName (
2189                     &VariableNameISizeNew,
2190                     VariableNameI,
2191                     &VendorGuidI
2192                     );
2193     if (Status == EFI_BUFFER_TOO_SMALL) {
2194       VariableNameI = ReallocatePool (
2195                         VariableNameISize,
2196                         VariableNameISizeNew,
2197                         VariableNameI
2198                         );
2199       if (VariableNameI == NULL) {
2200         Status = EFI_OUT_OF_RESOURCES;
2201         break;
2202       }
2203       VariableNameISize = VariableNameISizeNew;
2204 
2205       Status = gRT->GetNextVariableName (
2206                       &VariableNameISizeNew,
2207                       VariableNameI,
2208                       &VendorGuidI
2209                       );
2210     }
2211 
2212     if (EFI_ERROR (Status)) {
2213       break;
2214     }
2215     //
2216     // Check whether the current variable is the required "ipsecconfig".
2217     //
2218     if (StrnCmp (VariableNameI, VariableName, VariableNameLength) == 0 ||
2219         CompareGuid (VendorGuid, &VendorGuidI)
2220         ) {
2221       //
2222       // Parse the variable count of the current ipsecconfig data.
2223       //
2224       VariableIndex = StrDecimalToUintn (VariableNameI + VariableNameLength);
2225       if (VariableIndex!= 0 && VariableIndex <= IpSecVariableInfo.VariableCount) {
2226         //
2227         // Get the variable size of the current ipsecconfig data.
2228         //
2229         DataSizeI = 0;
2230         Status = gRT->GetVariable (
2231                         VariableNameI,
2232                         VendorGuid,
2233                         Attributes,
2234                         &DataSizeI,
2235                         NULL
2236                         );
2237         ASSERT (Status == EFI_BUFFER_TOO_SMALL);
2238         //
2239         // Validate the variable count and variable size.
2240         //
2241         if (VariableIndex != IpSecVariableInfo.VariableCount) {
2242           //
2243           // If the varaibe is not the last one, its size should be the max
2244           // size of the single variable.
2245           //
2246           if (DataSizeI != IpSecVariableInfo.SingleVariableSize) {
2247             return EFI_ABORTED;
2248           }
2249         } else {
2250           if (DataSizeI != IpSecVariableInfo.VariableSize % IpSecVariableInfo.SingleVariableSize) {
2251             return EFI_ABORTED;
2252           }
2253         }
2254         //
2255         // Get the variable data of the current ipsecconfig data and
2256         // store it into user buffer continously.
2257         //
2258         Status = gRT->GetVariable (
2259                         VariableNameI,
2260                         VendorGuid,
2261                         Attributes,
2262                         &DataSizeI,
2263                         (UINT8 *) Data + (VariableIndex - 1) * IpSecVariableInfo.SingleVariableSize
2264                         );
2265         ASSERT_EFI_ERROR (Status);
2266         VariableCount--;
2267       }
2268     }
2269   }
2270   //
2271   // The VariableCount in "VariableNameInfo" varaible should have the correct
2272   // numbers of variables which name starts with VariableName.
2273   //
2274   if (VariableCount != 0) {
2275     Status = EFI_ABORTED;
2276   }
2277 
2278 ON_EXIT:
2279   if (VariableNameI != NULL) {
2280     FreePool (VariableNameI);
2281   }
2282   return Status;
2283 }
2284 
2285 /**
2286   Set the IPsec variables.
2287 
2288   Set all IPsec variables which start with the specified variable name. Those variables
2289   are set one by one.
2290 
2291   @param[in]  VariableName  The name of the vendor's variable. It is a
2292                             Null-Terminated Unicode String.
2293   @param[in]  VendorGuid    Unify identifier for vendor.
2294   @param[in]  Attributes    Point to memory location to return the attributes of
2295                             variable. If the point is NULL, the parameter would be ignored.
2296   @param[in]  DataSize      The size in bytes of Data-Buffer.
2297   @param[in]  Data          Points to the content of the variable.
2298 
2299   @retval  EFI_SUCCESS      The firmware successfully stored the variable and its data, as
2300                             defined by the Attributes.
2301   @retval  others           Storing the variables failed.
2302 
2303 **/
2304 EFI_STATUS
IpSecSetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)2305 IpSecSetVariable (
2306   IN CHAR16                           *VariableName,
2307   IN EFI_GUID                         *VendorGuid,
2308   IN UINT32                           Attributes,
2309   IN UINTN                            DataSize,
2310   IN VOID                             *Data
2311   )
2312 {
2313   EFI_STATUS            Status;
2314   CHAR16                *VariableNameI;
2315   UINTN                 VariableNameSize;
2316   UINTN                 VariableIndex;
2317   IP_SEC_VARIABLE_INFO  IpSecVariableInfo;
2318   UINT64                MaximumVariableStorageSize;
2319   UINT64                RemainingVariableStorageSize;
2320   UINT64                MaximumVariableSize;
2321 
2322   Status = gRT->QueryVariableInfo (
2323                   Attributes,
2324                   &MaximumVariableStorageSize,
2325                   &RemainingVariableStorageSize,
2326                   &MaximumVariableSize
2327                   );
2328   if (EFI_ERROR (Status)) {
2329     return Status;
2330   }
2331 
2332   //
2333   // "VariableName + Info/0001/0002/... + NULL"
2334   //
2335   VariableNameSize  = (StrLen (VariableName) + 5) * sizeof (CHAR16);
2336   VariableNameI     = AllocateZeroPool (VariableNameSize);
2337 
2338   if (VariableNameI == NULL) {
2339     Status = EFI_OUT_OF_RESOURCES;
2340     goto ON_EXIT;
2341   }
2342   //
2343   // Construct the variable of ipsecconfig general information. Like the total
2344   // numbers of the Ipsecconfig variables, the total size of all ipsecconfig variables.
2345   //
2346   UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info");
2347   MaximumVariableSize -= VariableNameSize;
2348 
2349   IpSecVariableInfo.VariableCount       = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize);
2350   IpSecVariableInfo.VariableSize        = (UINT32) DataSize;
2351   IpSecVariableInfo.SingleVariableSize  = (UINT32) MaximumVariableSize;
2352 
2353   //
2354   // Set the variable of ipsecconfig general information.
2355   //
2356   Status = gRT->SetVariable (
2357                   VariableNameI,
2358                   VendorGuid,
2359                   Attributes,
2360                   sizeof (IpSecVariableInfo),
2361                   &IpSecVariableInfo
2362                   );
2363   if (EFI_ERROR (Status)) {
2364     DEBUG ((DEBUG_ERROR, "Error set ipsecconfig meta data with %r\n", Status));
2365     goto ON_EXIT;
2366   }
2367 
2368   for (VariableIndex = 0; VariableIndex < IpSecVariableInfo.VariableCount; VariableIndex++) {
2369     //
2370     // Construct and set the variable of ipsecconfig data one by one.
2371     // The index of variable name begin from 0001, and the varaible name
2372     // likes "VariableName0001", "VaraiableName0002"....
2373     //
2374     UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1);
2375     Status = gRT->SetVariable (
2376                     VariableNameI,
2377                     VendorGuid,
2378                     Attributes,
2379                     (VariableIndex == IpSecVariableInfo.VariableCount - 1) ?
2380                     (DataSize % (UINTN) MaximumVariableSize) :
2381                     (UINTN) MaximumVariableSize,
2382                     (UINT8 *) Data + VariableIndex * (UINTN) MaximumVariableSize
2383                     );
2384 
2385     if (EFI_ERROR (Status)) {
2386       DEBUG ((DEBUG_ERROR, "Error set ipsecconfig variable data with %r\n", Status));
2387       goto ON_EXIT;
2388     }
2389   }
2390 
2391 ON_EXIT:
2392   if (VariableNameI != NULL) {
2393     FreePool (VariableNameI);
2394   }
2395 
2396   return Status;
2397 }
2398 
2399 /**
2400   Return the configuration value for the EFI IPsec driver.
2401 
2402   This function lookup the data entry from IPsec database or IKEv2 configuration
2403   information. The expected data type and unique identification are described in
2404   DataType and Selector parameters.
2405 
2406   @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2407   @param[in]      DataType      The type of data to retrieve.
2408   @param[in]      Selector      Pointer to an entry selector that is an identifier of the IPsec
2409                                 configuration data entry.
2410   @param[in, out] DataSize      On output the size of data returned in Data.
2411   @param[out]     Data          The buffer to return the contents of the IPsec configuration data.
2412                                 The type of the data buffer associated with the DataType.
2413 
2414   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
2415   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
2416                                 - This is NULL.
2417                                 - Selector is NULL.
2418                                 - DataSize is NULL.
2419                                 - Data is NULL and *DataSize is not zero
2420   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
2421   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2422   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
2423                                 updated with the size needed to complete the request.
2424 
2425 **/
2426 EFI_STATUS
2427 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)2428 EfiIpSecConfigGetData (
2429   IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,
2430   IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,
2431   IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,
2432   IN OUT UINTN                        *DataSize,
2433      OUT VOID                         *Data
2434   )
2435 {
2436   if (This == NULL || Selector == NULL || DataSize == NULL) {
2437     return EFI_INVALID_PARAMETER;
2438   }
2439 
2440   if (*DataSize != 0 && Data == NULL) {
2441     return EFI_INVALID_PARAMETER;
2442   }
2443 
2444   if (DataType >= IPsecConfigDataTypeMaximum) {
2445     return EFI_UNSUPPORTED;
2446   }
2447 
2448   return mGetPolicyEntry[DataType](Selector, DataSize, Data);
2449 }
2450 
2451 /**
2452   Set the security association, security policy and peer authorization configuration
2453   information for the EFI IPsec driver.
2454 
2455   This function is used to set the IPsec configuration information of type DataType for
2456   the EFI IPsec driver.
2457   The IPsec configuration data has a unique selector/identifier separately to identify
2458   a data entry. The selector structure depends on DataType's definition.
2459   Using SetData() with a Data of NULL causes the IPsec configuration data entry identified
2460   by DataType and Selector to be deleted.
2461 
2462   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2463   @param[in] DataType           The type of data to be set.
2464   @param[in] Selector           Pointer to an entry selector on operated configuration data
2465                                 specified by DataType. A NULL Selector causes the entire
2466                                 specified-type configuration information to be flushed.
2467   @param[in] Data               The data buffer to be set. The structure of the data buffer is
2468                                 associated with the DataType.
2469   @param[in] InsertBefore       Pointer to one entry selector which describes the expected
2470                                 position the new data entry will be added. If InsertBefore is NULL,
2471                                 the new entry will be appended to the end of the database.
2472 
2473   @retval EFI_SUCCESS           The specified configuration entry data was set successfully.
2474   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
2475                                 - This is NULL.
2476   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2477   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
2478 
2479 **/
2480 EFI_STATUS
2481 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)2482 EfiIpSecConfigSetData (
2483   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2484   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2485   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector,
2486   IN VOID                             *Data,
2487   IN EFI_IPSEC_CONFIG_SELECTOR        *InsertBefore OPTIONAL
2488   )
2489 {
2490   EFI_STATUS  Status;
2491 
2492   if (This == NULL) {
2493     return EFI_INVALID_PARAMETER;
2494   }
2495 
2496   if (DataType >= IPsecConfigDataTypeMaximum) {
2497     return EFI_UNSUPPORTED;
2498   }
2499 
2500   Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore);
2501 
2502   if (!EFI_ERROR (Status) && !mSetBySelf) {
2503     //
2504     // Save the updated config data into variable.
2505     //
2506     IpSecConfigSave ();
2507   }
2508 
2509   return Status;
2510 }
2511 
2512 /**
2513   Enumerates the current selector for IPsec configuration data entry.
2514 
2515   This function is called multiple times to retrieve the entry Selector in IPsec
2516   configuration database. On each call to GetNextSelector(), the next entry
2517   Selector are retrieved into the output interface.
2518 
2519   If the entire IPsec configuration database has been iterated, the error
2520   EFI_NOT_FOUND is returned.
2521   If the Selector buffer is too small for the next Selector copy, an
2522   EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect
2523   the size of buffer needed.
2524 
2525   On the initial call to GetNextSelector() to start the IPsec configuration database
2526   search, a pointer to the buffer with all zero value is passed in Selector. Calls
2527   to SetData() between calls to GetNextSelector may produce unpredictable results.
2528 
2529   @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2530   @param[in]      DataType      The type of IPsec configuration data to retrieve.
2531   @param[in, out] SelectorSize  The size of the Selector buffer.
2532   @param[in, out] Selector      On input, supplies the pointer to last Selector that was
2533                                 returned by GetNextSelector().
2534                                 On output, returns one copy of the current entry Selector
2535                                 of a given DataType.
2536 
2537   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
2538   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
2539                                 - This is NULL.
2540                                 - SelectorSize is NULL.
2541                                 - Selector is NULL.
2542   @retval EFI_NOT_FOUND         The next configuration data entry was not found.
2543   @retval EFI_UNSUPPORTED       The specified DataType is not supported.
2544   @retval EFI_BUFFER_TOO_SMALL  The SelectorSize is too small for the result. This parameter
2545                                 has been updated with the size needed to complete the search
2546                                 request.
2547 
2548 **/
2549 EFI_STATUS
2550 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)2551 EfiIpSecConfigGetNextSelector (
2552   IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,
2553   IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,
2554   IN OUT UINTN                        *SelectorSize,
2555   IN OUT EFI_IPSEC_CONFIG_SELECTOR    *Selector
2556   )
2557 {
2558   LIST_ENTRY                *Link;
2559   IPSEC_COMMON_POLICY_ENTRY *CommonEntry;
2560   BOOLEAN                   IsFound;
2561 
2562   if (This == NULL || Selector == NULL || SelectorSize == NULL) {
2563     return EFI_INVALID_PARAMETER;
2564   }
2565 
2566   if (DataType >= IPsecConfigDataTypeMaximum) {
2567     return EFI_UNSUPPORTED;
2568   }
2569 
2570   IsFound = FALSE;
2571 
2572   NET_LIST_FOR_EACH (Link, &mConfigData[DataType]) {
2573     CommonEntry = BASE_CR (Link, IPSEC_COMMON_POLICY_ENTRY, List);
2574 
2575     if (IsFound || (BOOLEAN)(mIsZeroSelector[DataType](Selector))) {
2576       //
2577       // If found the appointed entry, then duplicate the next one and return,
2578       // or if the appointed entry is zero, then return the first one directly.
2579       //
2580       return mDuplicateSelector[DataType](Selector, CommonEntry->Selector, SelectorSize);
2581     } else {
2582       //
2583       // Set the flag if find the appointed entry.
2584       //
2585       IsFound = mCompareSelector[DataType](Selector, CommonEntry->Selector);
2586     }
2587   }
2588 
2589   return EFI_NOT_FOUND;
2590 }
2591 
2592 /**
2593   Register an event that is to be signaled whenever a configuration process on the
2594   specified IPsec configuration information is done.
2595 
2596   The register function is not surpport now and always returns EFI_UNSUPPORTED.
2597 
2598   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2599   @param[in] DataType           The type of data to be registered the event for.
2600   @param[in] Event              The event to be registered.
2601 
2602   @retval EFI_SUCCESS           The event is registered successfully.
2603   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2604   @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.
2605   @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified
2606                                 DataType is not supported.
2607 
2608 **/
2609 EFI_STATUS
2610 EFIAPI
EfiIpSecConfigRegisterNotify(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2611 EfiIpSecConfigRegisterNotify (
2612   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2613   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2614   IN EFI_EVENT                        Event
2615   )
2616 {
2617   return EFI_UNSUPPORTED;
2618 }
2619 
2620 /**
2621   Remove the specified event that was previously registered on the specified IPsec
2622   configuration data.
2623 
2624   This function is not support now and alwasy return EFI_UNSUPPORTED.
2625 
2626   @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
2627   @param[in] DataType           The configuration data type to remove the registered event for.
2628   @param[in] Event              The event to be unregistered.
2629 
2630   @retval EFI_SUCCESS           The event was removed successfully.
2631   @retval EFI_NOT_FOUND         The Event specified by DataType could not be found in the
2632                                 database.
2633   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2634   @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified
2635                                 DataType is not supported.
2636 
2637 **/
2638 EFI_STATUS
2639 EFIAPI
EfiIpSecConfigUnregisterNotify(IN EFI_IPSEC_CONFIG_PROTOCOL * This,IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2640 EfiIpSecConfigUnregisterNotify (
2641   IN EFI_IPSEC_CONFIG_PROTOCOL        *This,
2642   IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,
2643   IN EFI_EVENT                        Event
2644   )
2645 {
2646   return EFI_UNSUPPORTED;
2647 }
2648 
2649 /**
2650   Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer.
2651 
2652   This function is a caller defined function, and it is called by the IpSecVisitConfigData().
2653   The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to
2654   copy all types of IPsec Config datas into one buffer and store this buffer into firmware in
2655   the form of several variables.
2656 
2657   @param[in]      Type              A specified IPSEC_CONFIG_DATA_TYPE.
2658   @param[in]      Selector          Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied
2659                                     to the buffer.
2660   @param[in]      Data              Points to data to be copied to the buffer. The
2661                                     Data type is related to the Type.
2662   @param[in]      SelectorSize      The size of the Selector.
2663   @param[in]      DataSize          The size of the Data.
2664   @param[in, out] Buffer            The buffer to store the Selector and Data.
2665 
2666   @retval EFI_SUCCESS            Copy the Selector and Data to a buffer successfully.
2667   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.
2668 
2669 **/
2670 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)2671 IpSecCopyPolicyEntry (
2672   IN     EFI_IPSEC_CONFIG_DATA_TYPE   Type,
2673   IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,
2674   IN     VOID                         *Data,
2675   IN     UINTN                        SelectorSize,
2676   IN     UINTN                        DataSize,
2677   IN OUT IPSEC_VARIABLE_BUFFER        *Buffer
2678   )
2679 {
2680   IPSEC_VAR_ITEM_HEADER SelectorHeader;
2681   IPSEC_VAR_ITEM_HEADER DataHeader;
2682   UINTN                 EntrySize;
2683   UINT8                 *TempPoint;
2684 
2685   if (Type == IPsecConfigDataTypeSad) {
2686     //
2687     // Don't save automatically-generated SA entry into variable.
2688     //
2689     if (((EFI_IPSEC_SA_DATA2 *) Data)->ManualSet == FALSE) {
2690       return EFI_SUCCESS;
2691     }
2692   }
2693   //
2694   // Increase the capacity size of the buffer if needed.
2695   //
2696   EntrySize  = ALIGN_VARIABLE (sizeof (SelectorHeader));
2697   EntrySize  = ALIGN_VARIABLE (EntrySize + SelectorSize);
2698   EntrySize  = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader));
2699   EntrySize  = ALIGN_VARIABLE (EntrySize + DataSize);
2700 
2701   //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader);
2702   if (Buffer->Capacity - Buffer->Size < EntrySize) {
2703     //
2704     // Calculate the required buffer
2705     //
2706     Buffer->Capacity += EntrySize;
2707     TempPoint         = AllocatePool (Buffer->Capacity);
2708 
2709     if (TempPoint == NULL) {
2710       return EFI_OUT_OF_RESOURCES;
2711     }
2712     //
2713     // Copy the old Buffer to new buffer and free the old one.
2714     //
2715     CopyMem (TempPoint, Buffer->Ptr, Buffer->Size);
2716     FreePool (Buffer->Ptr);
2717 
2718     Buffer->Ptr       =  TempPoint;
2719   }
2720 
2721   mFixPolicyEntry[Type](Selector, Data);
2722 
2723   //
2724   // Fill the selector header and copy it into buffer.
2725   //
2726   SelectorHeader.Type = (UINT8) (Type | IPSEC_VAR_ITEM_HEADER_LOGO_BIT);
2727   SelectorHeader.Size = (UINT16) SelectorSize;
2728 
2729   CopyMem (
2730     Buffer->Ptr + Buffer->Size,
2731     &SelectorHeader,
2732     sizeof (SelectorHeader)
2733     );
2734   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader));
2735 
2736   //
2737   // Copy the selector into buffer.
2738   //
2739   CopyMem (
2740     Buffer->Ptr + Buffer->Size,
2741     Selector,
2742     SelectorSize
2743     );
2744   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + SelectorSize);
2745 
2746   //
2747   // Fill the data header and copy it into buffer.
2748   //
2749   DataHeader.Type = (UINT8) Type;
2750   DataHeader.Size = (UINT16) DataSize;
2751 
2752   CopyMem (
2753     Buffer->Ptr + Buffer->Size,
2754     &DataHeader,
2755     sizeof (DataHeader)
2756     );
2757   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (DataHeader));
2758   //
2759   // Copy the data into buffer.
2760   //
2761   CopyMem (
2762     Buffer->Ptr + Buffer->Size,
2763     Data,
2764     DataSize
2765     );
2766   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + DataSize);
2767 
2768   mUnfixPolicyEntry[Type](Selector, Data);
2769 
2770   return EFI_SUCCESS;
2771 }
2772 
2773 /**
2774   Visit all IPsec Configurations of specified Type and call the caller defined
2775   interface.
2776 
2777   @param[in]  DataType          The specified IPsec Config Data Type.
2778   @param[in]  Routine           The function defined by the caller.
2779   @param[in]  Context           The data passed to the Routine.
2780 
2781   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated
2782   @retval EFI_SUCCESS            This function completed successfully.
2783 
2784 **/
2785 EFI_STATUS
IpSecVisitConfigData(IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,IN IPSEC_COPY_POLICY_ENTRY Routine,IN VOID * Context)2786 IpSecVisitConfigData (
2787   IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
2788   IN IPSEC_COPY_POLICY_ENTRY    Routine,
2789   IN VOID                       *Context
2790   )
2791 {
2792   EFI_STATUS                GetNextStatus;
2793   EFI_STATUS                GetDataStatus;
2794   EFI_STATUS                RoutineStatus;
2795   EFI_IPSEC_CONFIG_SELECTOR *Selector;
2796   VOID                      *Data;
2797   UINTN                     SelectorSize;
2798   UINTN                     DataSize;
2799   UINTN                     SelectorBufferSize;
2800   UINTN                     DataBufferSize;
2801   BOOLEAN                   FirstGetNext;
2802 
2803   FirstGetNext        = TRUE;
2804   DataBufferSize      = 0;
2805   Data                = NULL;
2806   SelectorBufferSize  = sizeof (EFI_IPSEC_CONFIG_SELECTOR);
2807   Selector            = AllocateZeroPool (SelectorBufferSize);
2808 
2809   if (Selector == NULL) {
2810     return EFI_OUT_OF_RESOURCES;
2811   }
2812 
2813   while (TRUE) {
2814     //
2815     // Get the real size of the selector.
2816     //
2817     SelectorSize = SelectorBufferSize;
2818     GetNextStatus = EfiIpSecConfigGetNextSelector (
2819                       &mIpSecConfigInstance,
2820                       DataType,
2821                       &SelectorSize,
2822                       Selector
2823                       );
2824     if (GetNextStatus == EFI_BUFFER_TOO_SMALL) {
2825       FreePool (Selector);
2826       SelectorBufferSize = SelectorSize;
2827       //
2828       // Allocate zero pool for the first selector, while store the last
2829       // selector content for the other selectors.
2830       //
2831       if (FirstGetNext) {
2832         Selector = AllocateZeroPool (SelectorBufferSize);
2833       } else {
2834         Selector = AllocateCopyPool (SelectorBufferSize, Selector);
2835       }
2836 
2837       if (Selector == NULL) {
2838         return EFI_OUT_OF_RESOURCES;
2839       }
2840       //
2841       // Get the content of the selector.
2842       //
2843       GetNextStatus = EfiIpSecConfigGetNextSelector (
2844                         &mIpSecConfigInstance,
2845                         DataType,
2846                         &SelectorSize,
2847                         Selector
2848                         );
2849     }
2850 
2851     if (EFI_ERROR (GetNextStatus)) {
2852       break;
2853     }
2854 
2855     FirstGetNext = FALSE;
2856 
2857     //
2858     // Get the real size of the policy entry according to the selector.
2859     //
2860     DataSize = DataBufferSize;
2861     GetDataStatus = EfiIpSecConfigGetData (
2862                       &mIpSecConfigInstance,
2863                       DataType,
2864                       Selector,
2865                       &DataSize,
2866                       Data
2867                       );
2868     if (GetDataStatus == EFI_BUFFER_TOO_SMALL) {
2869       if (Data != NULL) {
2870         FreePool (Data);
2871       }
2872 
2873       DataBufferSize  = DataSize;
2874       Data            = AllocateZeroPool (DataBufferSize);
2875 
2876       if (Data == NULL) {
2877         return EFI_OUT_OF_RESOURCES;
2878       }
2879       //
2880       // Get the content of the policy entry according to the selector.
2881       //
2882       GetDataStatus = EfiIpSecConfigGetData (
2883                         &mIpSecConfigInstance,
2884                         DataType,
2885                         Selector,
2886                         &DataSize,
2887                         Data
2888                         );
2889     }
2890 
2891     if (EFI_ERROR (GetDataStatus)) {
2892       break;
2893     }
2894     //
2895     // Prepare the buffer of updated policy entry, which is stored in
2896     // the continous memory, and then save into variable later.
2897     //
2898     RoutineStatus = Routine (
2899                       DataType,
2900                       Selector,
2901                       Data,
2902                       SelectorSize,
2903                       DataSize,
2904                       Context
2905                       );
2906     if (EFI_ERROR (RoutineStatus)) {
2907       break;
2908     }
2909   }
2910 
2911   if (Data != NULL) {
2912     FreePool (Data);
2913   }
2914 
2915   if (Selector != NULL) {
2916     FreePool (Selector);
2917   }
2918 
2919   return EFI_SUCCESS;
2920 }
2921 
2922 /**
2923   This function is the subfunction of  EFIIpSecConfigSetData.
2924 
2925   This function call IpSecSetVaraible to set the IPsec Configuration into the firmware.
2926 
2927   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.
2928   @retval EFI_SUCCESS            Saved the configration successfully.
2929   @retval Others                 Other errors were found while obtaining the variable.
2930 
2931 **/
2932 EFI_STATUS
IpSecConfigSave(VOID)2933 IpSecConfigSave (
2934   VOID
2935   )
2936 {
2937   IPSEC_VARIABLE_BUFFER       Buffer;
2938   EFI_STATUS                  Status;
2939   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
2940 
2941   Buffer.Size     = 0;
2942   Buffer.Capacity = IPSEC_DEFAULT_VARIABLE_SIZE;
2943   Buffer.Ptr      = AllocateZeroPool (Buffer.Capacity);
2944 
2945   if (Buffer.Ptr == NULL) {
2946     return EFI_OUT_OF_RESOURCES;
2947   }
2948   //
2949   // For each policy database, prepare the contious buffer to save into variable.
2950   //
2951   for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
2952     IpSecVisitConfigData (
2953       Type,
2954       (IPSEC_COPY_POLICY_ENTRY) IpSecCopyPolicyEntry,
2955       &Buffer
2956       );
2957   }
2958   //
2959   // Save the updated policy database into variable.
2960   //
2961   Status = IpSecSetVariable (
2962              IPSECCONFIG_VARIABLE_NAME,
2963              &gEfiIpSecConfigProtocolGuid,
2964              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2965              Buffer.Size,
2966              Buffer.Ptr
2967              );
2968 
2969   FreePool (Buffer.Ptr);
2970 
2971   return Status;
2972 }
2973 
2974 /**
2975   Get the all IPSec configuration variables and store those variables
2976   to the internal data structure.
2977 
2978   This founction is called by IpSecConfigInitialize() which is to intialize the
2979   IPsecConfiguration Protocol.
2980 
2981   @param[in]  Private            Point to IPSEC_PRIVATE_DATA.
2982 
2983   @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated
2984   @retval EFI_SUCCESS            Restore the IPsec Configuration successfully.
2985   @retval  others                Other errors is found while obtaining the variable.
2986 
2987 **/
2988 EFI_STATUS
IpSecConfigRestore(IN IPSEC_PRIVATE_DATA * Private)2989 IpSecConfigRestore (
2990   IN IPSEC_PRIVATE_DATA           *Private
2991   )
2992 {
2993   EFI_STATUS                  Status;
2994   UINTN                       BufferSize;
2995   UINT8                       *Buffer;
2996   IPSEC_VAR_ITEM_HEADER       *Header;
2997   UINT8                       *Ptr;
2998   EFI_IPSEC_CONFIG_SELECTOR   *Selector;
2999   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
3000   VOID                        *Data;
3001   UINT8                       Value;
3002   UINTN                       Size;
3003 
3004   Value       = 0;
3005   Size        = sizeof (Value);
3006   BufferSize  = 0;
3007   Buffer      = NULL;
3008 
3009   Status = gRT->GetVariable (
3010                   IPSECCONFIG_STATUS_NAME,
3011                   &gEfiIpSecConfigProtocolGuid,
3012                   NULL,
3013                   &Size,
3014                   &Value
3015              );
3016 
3017   if (!EFI_ERROR (Status) && Value == IPSEC_STATUS_ENABLED) {
3018     Private->IpSec.DisabledFlag = FALSE;
3019   }
3020   //
3021   // Get the real size of policy database in variable.
3022   //
3023   Status = IpSecGetVariable (
3024              IPSECCONFIG_VARIABLE_NAME,
3025              &gEfiIpSecConfigProtocolGuid,
3026              NULL,
3027              &BufferSize,
3028              Buffer
3029              );
3030   if (Status == EFI_BUFFER_TOO_SMALL) {
3031 
3032     Buffer = AllocateZeroPool (BufferSize);
3033     if (Buffer == NULL) {
3034       return EFI_OUT_OF_RESOURCES;
3035     }
3036     //
3037     // Get the content of policy database in variable.
3038     //
3039     Status = IpSecGetVariable (
3040                IPSECCONFIG_VARIABLE_NAME,
3041                &gEfiIpSecConfigProtocolGuid,
3042                NULL,
3043                &BufferSize,
3044                Buffer
3045                );
3046     if (EFI_ERROR (Status)) {
3047       FreePool (Buffer);
3048       return Status;
3049     }
3050 
3051     for (Ptr = Buffer; Ptr < Buffer + BufferSize;) {
3052 
3053       Header  = (IPSEC_VAR_ITEM_HEADER *) Ptr;
3054       Type    = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT);
3055       ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum));
3056 
3057       Selector  = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN));
3058       Header    = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER (
3059                                               (UINT8 *) Selector + Header->Size,
3060                                               sizeof (UINTN)
3061                                               );
3062       ASSERT (Header->Type == Type);
3063 
3064       Data = ALIGN_POINTER (Header + 1, sizeof (UINTN));
3065 
3066       mUnfixPolicyEntry[Type](Selector, Data);
3067 
3068       //
3069       // Update each policy entry according to the content in variable.
3070       //
3071       mSetBySelf = TRUE;
3072       Status = EfiIpSecConfigSetData (
3073                  &Private->IpSecConfig,
3074                  Type,
3075                  Selector,
3076                  Data,
3077                  NULL
3078                  );
3079       mSetBySelf = FALSE;
3080 
3081       if (EFI_ERROR (Status)) {
3082         FreePool (Buffer);
3083         return Status;
3084       }
3085 
3086       Ptr =  ALIGN_POINTER ((UINT8 *) Data + Header->Size, sizeof (UINTN));
3087     }
3088 
3089     FreePool (Buffer);
3090   }
3091 
3092   return EFI_SUCCESS;
3093 }
3094 
3095 /**
3096   Install and Initialize IPsecConfig protocol
3097 
3098   @param[in, out]  Private   Pointer to IPSEC_PRIVATE_DATA. After this function finish,
3099                              the pointer of IPsecConfig Protocol implementation will copy
3100                              into its IPsecConfig member.
3101 
3102   @retval     EFI_SUCCESS    Initialized the IPsecConfig Protocol successfully.
3103   @retval     Others         Initializing the IPsecConfig Protocol failed.
3104 **/
3105 EFI_STATUS
IpSecConfigInitialize(IN OUT IPSEC_PRIVATE_DATA * Private)3106 IpSecConfigInitialize (
3107   IN OUT IPSEC_PRIVATE_DATA        *Private
3108   )
3109 {
3110   EFI_IPSEC_CONFIG_DATA_TYPE  Type;
3111 
3112   CopyMem (
3113     &Private->IpSecConfig,
3114     &mIpSecConfigInstance,
3115     sizeof (EFI_IPSEC_CONFIG_PROTOCOL)
3116     );
3117 
3118   //
3119   // Initialize the list head of policy database.
3120   //
3121   for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
3122     InitializeListHead (&mConfigData[Type]);
3123   }
3124   //
3125   // Restore the content of policy database according to the variable.
3126   //
3127   IpSecConfigRestore (Private);
3128 
3129   return gBS->InstallMultipleProtocolInterfaces (
3130                 &Private->Handle,
3131                 &gEfiIpSecConfigProtocolGuid,
3132                 &Private->IpSecConfig,
3133                 NULL
3134                 );
3135 }
3136