1 /** @file
2   The implementation of IPSEC_CONFIG_PROTOCOL.
3 
4   Copyright (c) 2009 - 2015, 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->TrafficDirection = SpdData->TrafficDirection;
1172   SpdEntry->Data->Action           = SpdData->Action;
1173 
1174   //
1175   // Fix the address of ProcessingPolicy and copy it if need, which is continous
1176   // memory and close to the base structure of SAD data.
1177   //
1178   if (SpdData->Action != EfiIPsecActionProtect) {
1179     SpdEntry->Data->ProcessingPolicy = NULL;
1180   } else {
1181     SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER (
1182                                                                       SpdEntry->Data + 1,
1183                                                                       sizeof (UINTN)
1184                                                                       );
1185     IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);
1186   }
1187   //
1188   // Update the sas list of the new SPD entry.
1189   //
1190   InitializeListHead (&SpdEntry->Data->Sas);
1191 
1192   SadList = &mConfigData[IPsecConfigDataTypeSad];
1193 
1194   NET_LIST_FOR_EACH (Entry, SadList) {
1195     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1196 
1197     for (Index = 0; Index < SpdData->SaIdCount; Index++) {
1198 
1199       if (CompareSaId (
1200             (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],
1201             (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
1202             )) {
1203         if (SadEntry->Data->SpdEntry != NULL) {
1204           RemoveEntryList (&SadEntry->BySpd);
1205         }
1206         InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1207         SadEntry->Data->SpdEntry = SpdEntry;
1208       }
1209     }
1210   }
1211   //
1212   // Insert the new SPD entry.
1213   //
1214   InsertTailList (EntryInsertBefore, &SpdEntry->List);
1215 
1216   return EFI_SUCCESS;
1217 }
1218 
1219 /**
1220   Set the security association information for the EFI IPsec driver.
1221 
1222   The IPsec configuration data has a unique selector/identifier separately to
1223   identify a data entry.
1224 
1225   @param[in]  Selector           Pointer to an entry selector on operated
1226                                  configuration data specified by DataType.
1227                                  A NULL Selector causes the entire specified-type
1228                                  configuration information to be flushed.
1229   @param[in]  Data               The data buffer to be set. The structure
1230                                  of the data buffer should be EFI_IPSEC_SA_DATA.
1231   @param[in]  Context            Pointer to one entry selector which describes
1232                                  the expected position the new data entry will
1233                                  be added. If Context is NULL,the new entry will
1234                                  be appended the end of database.
1235 
1236   @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.
1237   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1238 
1239 **/
1240 EFI_STATUS
SetSadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1241 SetSadEntry (
1242   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1243   IN VOID                            *Data,
1244   IN VOID                            *Context OPTIONAL
1245   )
1246 {
1247   IPSEC_SAD_ENTRY   *SadEntry;
1248   IPSEC_SPD_ENTRY   *SpdEntry;
1249   LIST_ENTRY        *Entry;
1250   LIST_ENTRY        *NextEntry;
1251   LIST_ENTRY        *SadList;
1252   LIST_ENTRY        *SpdList;
1253   EFI_IPSEC_SA_ID   *SaId;
1254   EFI_IPSEC_SA_DATA2 *SaData;
1255   EFI_IPSEC_SA_ID   *InsertBefore;
1256   LIST_ENTRY        *EntryInsertBefore;
1257   UINTN             SadEntrySize;
1258 
1259   SaId          = (Selector == NULL) ? NULL : &Selector->SaId;
1260   SaData        = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data;
1261   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;
1262   SadList       = &mConfigData[IPsecConfigDataTypeSad];
1263 
1264   //
1265   // The default behavior is to insert the node ahead of the header.
1266   //
1267   EntryInsertBefore = SadList;
1268 
1269   //
1270   // Remove the existed SAD entry.
1271   //
1272   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {
1273 
1274     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1275 
1276     if (SaId == NULL ||
1277         CompareSaId (
1278           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1279           (EFI_IPSEC_CONFIG_SELECTOR *) SaId
1280           )) {
1281       //
1282       // Record the existed entry position to keep the original order.
1283       //
1284       EntryInsertBefore = SadEntry->List.ForwardLink;
1285 
1286       //
1287       // Update the related SAD.byspd field.
1288       //
1289       if (SadEntry->Data->SpdEntry != NULL) {
1290         RemoveEntryList (&SadEntry->BySpd);
1291       }
1292 
1293       RemoveEntryList (&SadEntry->List);
1294       FreePool (SadEntry);
1295     }
1296   }
1297   //
1298   // Return success here if only want to remove the SAD entry
1299   //
1300   if (SaData == NULL || SaId == NULL) {
1301     return EFI_SUCCESS;
1302   }
1303   //
1304   // Search the appointed entry position if InsertBefore is not NULL.
1305   //
1306   if (InsertBefore != NULL) {
1307 
1308     NET_LIST_FOR_EACH (Entry, SadList) {
1309       SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
1310 
1311       if (CompareSaId (
1312            (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
1313            (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1314            )) {
1315         EntryInsertBefore = Entry;
1316         break;
1317       }
1318     }
1319   }
1320 
1321   //
1322   // Do Padding for different Arch.
1323   //
1324   SadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY));
1325   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_ID));
1326   SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA));
1327 
1328   if (SaId->Proto == EfiIPsecAH) {
1329     SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength;
1330   } else {
1331     SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength);
1332     SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength);
1333   }
1334 
1335   if (SaData->SpdSelector != NULL) {
1336     SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);
1337   }
1338   SadEntry      = AllocateZeroPool (SadEntrySize);
1339 
1340   if (SadEntry == NULL) {
1341     return EFI_OUT_OF_RESOURCES;
1342   }
1343   //
1344   // Fix the address of Id and Data buffer and copy them, which is
1345   // continous memory and close to the base structure of SAD entry.
1346   //
1347   SadEntry->Id    = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN));
1348   SadEntry->Data  = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN));
1349 
1350   CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID));
1351 
1352   SadEntry->Data->Mode                  = SaData->Mode;
1353   SadEntry->Data->SequenceNumber        = SaData->SNCount;
1354   SadEntry->Data->AntiReplayWindowSize  = SaData->AntiReplayWindows;
1355 
1356   ZeroMem (
1357     &SadEntry->Data->AntiReplayBitmap,
1358     sizeof (SadEntry->Data->AntiReplayBitmap)
1359     );
1360 
1361   ZeroMem (
1362     &SadEntry->Data->AlgoInfo,
1363     sizeof (EFI_IPSEC_ALGO_INFO)
1364     );
1365 
1366   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId;
1367   SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength;
1368 
1369   if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
1370     SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN));
1371     CopyMem (
1372       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1373       SaData->AlgoInfo.EspAlgoInfo.AuthKey,
1374       SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength
1375       );
1376   }
1377 
1378   if (SaId->Proto == EfiIPsecESP) {
1379     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId    = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId;
1380     SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;
1381 
1382     if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
1383       SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
1384                                                                ((UINT8 *) (SadEntry->Data + 1) +
1385                                                                  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),
1386                                                                  sizeof (UINTN)
1387                                                                  );
1388       CopyMem (
1389         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1390         SaData->AlgoInfo.EspAlgoInfo.EncKey,
1391         SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength
1392         );
1393     }
1394   }
1395 
1396   CopyMem (
1397     &SadEntry->Data->SaLifetime,
1398     &SaData->SaLifetime,
1399     sizeof (EFI_IPSEC_SA_LIFETIME)
1400     );
1401 
1402   SadEntry->Data->PathMTU     = SaData->PathMTU;
1403   SadEntry->Data->SpdSelector = NULL;
1404   SadEntry->Data->ESNEnabled  = FALSE;
1405   SadEntry->Data->ManualSet   = SaData->ManualSet;
1406 
1407   //
1408   // Copy Tunnel Source/Destination Address
1409   //
1410   if (SaData->Mode == EfiIPsecTunnel) {
1411     CopyMem (
1412       &SadEntry->Data->TunnelDestAddress,
1413       &SaData->TunnelDestinationAddress,
1414       sizeof (EFI_IP_ADDRESS)
1415       );
1416     CopyMem (
1417       &SadEntry->Data->TunnelSourceAddress,
1418       &SaData->TunnelSourceAddress,
1419       sizeof (EFI_IP_ADDRESS)
1420       );
1421   }
1422   //
1423   // Update the spd.sas list of the spd entry specified by SAD selector
1424   //
1425   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1426 
1427   for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) {
1428 
1429     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1430     if (IsSubSpdSelector (
1431           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1432           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1433           ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {
1434       SadEntry->Data->SpdEntry = SpdEntry;
1435       SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry +
1436                                                                 SadEntrySize -
1437                                                                 (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector)
1438                                                                 );
1439       DuplicateSpdSelector (
1440        (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
1441        (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
1442        NULL
1443        );
1444       InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
1445     }
1446   }
1447   //
1448   // Insert the new SAD entry.
1449   //
1450   InsertTailList (EntryInsertBefore, &SadEntry->List);
1451 
1452   return EFI_SUCCESS;
1453 }
1454 
1455 /**
1456   Set the peer authorization configuration information for the EFI IPsec driver.
1457 
1458   The IPsec configuration data has a unique selector/identifier separately to
1459   identify a data entry.
1460 
1461   @param[in]  Selector           Pointer to an entry selector on operated
1462                                  configuration data specified by DataType.
1463                                  A NULL Selector causes the entire specified-type
1464                                  configuration information to be flushed.
1465   @param[in]  Data               The data buffer to be set. The structure
1466                                  of the data buffer should be EFI_IPSEC_PAD_DATA.
1467   @param[in]  Context            Pointer to one entry selector that describes
1468                                  the expected position the new data entry will
1469                                  be added. If Context is NULL, the new entry will
1470                                  be appended the end of database.
1471 
1472   @retval EFI_OUT_OF_RESOURCES  The required system resources could not be allocated.
1473   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1474 
1475 **/
1476 EFI_STATUS
SetPadEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN VOID * Data,IN VOID * Context OPTIONAL)1477 SetPadEntry (
1478   IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1479   IN VOID                            *Data,
1480   IN VOID                            *Context OPTIONAL
1481   )
1482 {
1483   IPSEC_PAD_ENTRY     *PadEntry;
1484   EFI_IPSEC_PAD_ID    *PadId;
1485   EFI_IPSEC_PAD_DATA  *PadData;
1486   LIST_ENTRY          *PadList;
1487   LIST_ENTRY          *Entry;
1488   LIST_ENTRY          *NextEntry;
1489   EFI_IPSEC_PAD_ID    *InsertBefore;
1490   LIST_ENTRY          *EntryInsertBefore;
1491   UINTN               PadEntrySize;
1492 
1493   PadId         = (Selector == NULL) ? NULL : &Selector->PadId;
1494   PadData       = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data;
1495   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId;
1496   PadList       = &mConfigData[IPsecConfigDataTypePad];
1497 
1498   //
1499   // The default behavior is to insert the node ahead of the header.
1500   //
1501   EntryInsertBefore = PadList;
1502 
1503   //
1504   // Remove the existed pad entry.
1505   //
1506   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) {
1507 
1508     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1509 
1510     if (PadId == NULL ||
1511         ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)
1512         ) {
1513       //
1514       // Record the existed entry position to keep the original order.
1515       //
1516       EntryInsertBefore = PadEntry->List.ForwardLink;
1517       RemoveEntryList (&PadEntry->List);
1518 
1519       FreePool (PadEntry);
1520     }
1521   }
1522   //
1523   // Return success here if only want to remove the pad entry
1524   //
1525   if (PadData == NULL || PadId == NULL) {
1526     return EFI_SUCCESS;
1527   }
1528   //
1529   // Search the appointed entry position if InsertBefore is not NULL.
1530   //
1531   if (InsertBefore != NULL) {
1532 
1533     NET_LIST_FOR_EACH (Entry, PadList) {
1534       PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
1535 
1536       if (ComparePadId (
1537             (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id,
1538             (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
1539             )) {
1540         EntryInsertBefore = Entry;
1541         break;
1542       }
1543     }
1544   }
1545 
1546   //
1547   // Do PADDING for different arch.
1548   //
1549   PadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY));
1550   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID));
1551   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA));
1552   PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0));
1553   PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0;
1554 
1555   PadEntry      = AllocateZeroPool (PadEntrySize);
1556 
1557   if (PadEntry == NULL) {
1558     return EFI_OUT_OF_RESOURCES;
1559   }
1560   //
1561   // Fix the address of Id and Data buffer and copy them, which is
1562   // continous memory and close to the base structure of pad entry.
1563   //
1564   PadEntry->Id    = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN));
1565   PadEntry->Data  = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN));
1566 
1567   CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID));
1568 
1569   PadEntry->Data->AuthProtocol  = PadData->AuthProtocol;
1570   PadEntry->Data->AuthMethod    = PadData->AuthMethod;
1571   PadEntry->Data->IkeIdFlag     = PadData->IkeIdFlag;
1572 
1573   if (PadData->AuthData != NULL) {
1574     PadEntry->Data->AuthDataSize  = PadData->AuthDataSize;
1575     PadEntry->Data->AuthData      = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN));
1576     CopyMem (
1577       PadEntry->Data->AuthData,
1578       PadData->AuthData,
1579       PadData->AuthDataSize
1580       );
1581   } else {
1582     PadEntry->Data->AuthDataSize  = 0;
1583     PadEntry->Data->AuthData      = NULL;
1584   }
1585 
1586   if (PadData->RevocationData != NULL) {
1587     PadEntry->Data->RevocationDataSize  = PadData->RevocationDataSize;
1588     PadEntry->Data->RevocationData      = (VOID *) ALIGN_POINTER (
1589                                                     ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize),
1590                                                     sizeof (UINTN)
1591                                                     );
1592     CopyMem (
1593       PadEntry->Data->RevocationData,
1594       PadData->RevocationData,
1595       PadData->RevocationDataSize
1596       );
1597   } else {
1598     PadEntry->Data->RevocationDataSize  = 0;
1599     PadEntry->Data->RevocationData      = NULL;
1600   }
1601   //
1602   // Insert the new pad entry.
1603   //
1604   InsertTailList (EntryInsertBefore, &PadEntry->List);
1605 
1606   return EFI_SUCCESS;
1607 }
1608 
1609 /**
1610   This function lookup the data entry from IPsec SPD. Return the configuration
1611   value of the specified SPD Entry.
1612 
1613   @param[in]      Selector      Pointer to an entry selector which is an identifier
1614                                 of the SPD entry.
1615   @param[in, out] DataSize      On output the size of data returned in Data.
1616   @param[out]     Data          The buffer to return the contents of the IPsec
1617                                 configuration data. The type of the data buffer
1618                                 is associated with the DataType.
1619 
1620   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1621   @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
1622   @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.
1623   @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been
1624                                 updated with the size needed to complete the request.
1625 
1626 **/
1627 EFI_STATUS
GetSpdEntry(IN EFI_IPSEC_CONFIG_SELECTOR * Selector,IN OUT UINTN * DataSize,OUT VOID * Data)1628 GetSpdEntry (
1629   IN     EFI_IPSEC_CONFIG_SELECTOR       *Selector,
1630   IN OUT UINTN                           *DataSize,
1631      OUT VOID                            *Data
1632   )
1633 {
1634   IPSEC_SPD_ENTRY         *SpdEntry;
1635   IPSEC_SAD_ENTRY         *SadEntry;
1636   EFI_IPSEC_SPD_SELECTOR  *SpdSel;
1637   EFI_IPSEC_SPD_DATA      *SpdData;
1638   LIST_ENTRY              *SpdList;
1639   LIST_ENTRY              *SpdSas;
1640   LIST_ENTRY              *Entry;
1641   UINTN                   RequiredSize;
1642 
1643   SpdSel  = &Selector->SpdSelector;
1644   SpdData = (EFI_IPSEC_SPD_DATA *) Data;
1645   SpdList = &mConfigData[IPsecConfigDataTypeSpd];
1646 
1647   NET_LIST_FOR_EACH (Entry, SpdList) {
1648     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
1649 
1650     //
1651     // Find the required SPD entry
1652     //
1653     if (CompareSpdSelector (
1654           (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
1655           (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
1656           )) {
1657 
1658       RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data);
1659       if (*DataSize < RequiredSize) {
1660         *DataSize = RequiredSize;
1661         return EFI_BUFFER_TOO_SMALL;
1662       }
1663 
1664       if (SpdData == NULL) {
1665         return EFI_INVALID_PARAMETER;
1666       }
1667 
1668       *DataSize = RequiredSize;
1669 
1670       //
1671       // Extract and fill all SaId array from the SPD.sas list
1672       //
1673       SpdSas              = &SpdEntry->Data->Sas;
1674       SpdData->SaIdCount  = 0;
1675 
1676       NET_LIST_FOR_EACH (Entry, SpdSas) {
1677         SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
1678         CopyMem (
1679           &SpdData->SaId[SpdData->SaIdCount++],
1680           SadEntry->Id,
1681           sizeof (EFI_IPSEC_SA_ID)
1682           );
1683       }
1684       //
1685       // Fill the other fields in SPD data.
1686       //
1687       CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name));
1688 
1689       SpdData->PackageFlag      = SpdEntry->Data->PackageFlag;
1690       SpdData->TrafficDirection = SpdEntry->Data->TrafficDirection;
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