1 /** @file
2   This EFI_DHCP6_PROTOCOL interface implementation.
3 
4   Copyright (c) 2009 - 2012, 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 "Dhcp6Impl.h"
17 
18 //
19 // Well-known multi-cast address defined in section-24.1 of rfc-3315
20 //
21 //   ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
22 //   ALL_DHCP_Servers address:                  FF05::1:3
23 //
24 EFI_IPv6_ADDRESS   mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
25 EFI_IPv6_ADDRESS   mAllDhcpServersAddress         = {{0xFF, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3}};
26 
27 EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate = {
28   EfiDhcp6GetModeData,
29   EfiDhcp6Configure,
30   EfiDhcp6Start,
31   EfiDhcp6InfoRequest,
32   EfiDhcp6RenewRebind,
33   EfiDhcp6Decline,
34   EfiDhcp6Release,
35   EfiDhcp6Stop,
36   EfiDhcp6Parse
37 };
38 
39 /**
40   Starts the DHCPv6 standard S.A.R.R. process.
41 
42   The Start() function starts the DHCPv6 standard process. This function can
43   be called only when the state of Dhcp6 instance is in the Dhcp6Init state.
44   If the DHCP process completes successfully, the state of the Dhcp6 instance
45   will be transferred through Dhcp6Selecting and Dhcp6Requesting to the
46   Dhcp6Bound state.
47   Refer to rfc-3315 for precise state transitions during this process. At the
48   time when each event occurs in this process, the callback function that was set
49   by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this
50   opportunity to control the process.
51 
52   @param[in]  This              The pointer to Dhcp6 protocol.
53 
54   @retval EFI_SUCCESS           The DHCPv6 standard process has started, or it has
55                                 completed when CompletionEvent is NULL.
56   @retval EFI_ACCESS_DENIED     The EFI DHCPv6 Child instance hasn't been configured.
57   @retval EFI_INVALID_PARAMETER This is NULL.
58   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
59   @retval EFI_TIMEOUT           The DHCPv6 configuration process failed because no
60                                 response was received from the server within the
61                                 specified timeout value.
62   @retval EFI_ABORTED           The user aborted the DHCPv6 process.
63   @retval EFI_ALREADY_STARTED   Some other Dhcp6 instance already started the DHCPv6
64                                 standard process.
65   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
66   @retval EFI_NO_MEDIA          There was a media error.
67 
68 **/
69 EFI_STATUS
70 EFIAPI
EfiDhcp6Start(IN EFI_DHCP6_PROTOCOL * This)71 EfiDhcp6Start (
72   IN EFI_DHCP6_PROTOCOL        *This
73   )
74 {
75   EFI_STATUS                   Status;
76   EFI_TPL                      OldTpl;
77   DHCP6_INSTANCE               *Instance;
78   DHCP6_SERVICE                *Service;
79 
80   if (This == NULL) {
81     return EFI_INVALID_PARAMETER;
82   }
83 
84   Instance = DHCP6_INSTANCE_FROM_THIS (This);
85   Service  = Instance->Service;
86 
87   //
88   // The instance hasn't been configured.
89   //
90   if (Instance->Config == NULL) {
91     return EFI_ACCESS_DENIED;
92   }
93 
94   ASSERT (Instance->IaCb.Ia != NULL);
95 
96   //
97   // The instance has already been started.
98   //
99   if (Instance->IaCb.Ia->State != Dhcp6Init) {
100     return EFI_ALREADY_STARTED;
101   }
102 
103   OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);
104   Instance->UdpSts = EFI_ALREADY_STARTED;
105 
106   //
107   // Send the solicit message to start S.A.R.R process.
108   //
109   Status = Dhcp6SendSolicitMsg (Instance);
110 
111   if (EFI_ERROR (Status)) {
112     goto ON_ERROR;
113   }
114 
115   //
116   // Register receive callback for the stateful exchange process.
117   //
118   Status = UdpIoRecvDatagram(
119              Service->UdpIo,
120              Dhcp6ReceivePacket,
121              Service,
122              0
123              );
124 
125   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
126     goto ON_ERROR;
127   }
128 
129   gBS->RestoreTPL (OldTpl);
130 
131   //
132   // Poll udp out of the net tpl if synchronous call.
133   //
134   if (Instance->Config->IaInfoEvent == NULL) {
135 
136     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
137       Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
138     }
139     return Instance->UdpSts;
140   }
141 
142   return EFI_SUCCESS;
143 
144 ON_ERROR:
145 
146   gBS->RestoreTPL (OldTpl);
147   return Status;
148 }
149 
150 
151 /**
152   Stops the DHCPv6 standard S.A.R.R. process.
153 
154   The Stop() function is used to stop the DHCPv6 standard process. After this
155   function is called successfully, the state of Dhcp6 instance is transferred
156   into Dhcp6Init. EFI_DHCP6_PROTOCOL.Configure() needs to be called
157   before DHCPv6 standard process can be started again. This function can be
158   called when the Dhcp6 instance is in any state.
159 
160   @param[in]  This              The pointer to the Dhcp6 protocol.
161 
162   @retval EFI_SUCCESS           The Dhcp6 instance is now in the Dhcp6Init state.
163   @retval EFI_INVALID_PARAMETER This is NULL.
164 
165 **/
166 EFI_STATUS
167 EFIAPI
EfiDhcp6Stop(IN EFI_DHCP6_PROTOCOL * This)168 EfiDhcp6Stop (
169   IN EFI_DHCP6_PROTOCOL        *This
170   )
171 {
172   EFI_TPL                      OldTpl;
173   EFI_STATUS                   Status;
174   EFI_UDP6_PROTOCOL            *Udp6;
175   DHCP6_INSTANCE               *Instance;
176   DHCP6_SERVICE                *Service;
177 
178   if (This == NULL) {
179     return EFI_INVALID_PARAMETER;
180   }
181 
182   Instance = DHCP6_INSTANCE_FROM_THIS (This);
183   Service  = Instance->Service;
184   Udp6     = Service->UdpIo->Protocol.Udp6;
185   Status   = EFI_SUCCESS;
186 
187   //
188   // The instance hasn't been configured.
189   //
190   if (Instance->Config == NULL) {
191     return Status;
192   }
193 
194   ASSERT (Instance->IaCb.Ia != NULL);
195 
196   //
197   // No valid REPLY message received yet, cleanup this instance directly.
198   //
199   if (Instance->IaCb.Ia->State == Dhcp6Init ||
200       Instance->IaCb.Ia->State == Dhcp6Selecting ||
201       Instance->IaCb.Ia->State == Dhcp6Requesting
202       ) {
203     goto ON_EXIT;
204   }
205 
206   //
207   // Release the current ready Ia.
208   //
209   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
210 
211   Instance->UdpSts = EFI_ALREADY_STARTED;
212   Status = Dhcp6SendReleaseMsg (Instance, Instance->IaCb.Ia);
213   gBS->RestoreTPL (OldTpl);
214   if (EFI_ERROR (Status)) {
215     goto ON_EXIT;
216   }
217 
218   //
219   // Poll udp out of the net tpl if synchoronus call.
220   //
221   if (Instance->Config->IaInfoEvent == NULL) {
222     ASSERT (Udp6 != NULL);
223     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
224       Udp6->Poll (Udp6);
225     }
226     Status = Instance->UdpSts;
227   }
228 
229 ON_EXIT:
230   //
231   // Clean up the session data for the released Ia.
232   //
233   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
234   Dhcp6CleanupSession (Instance, EFI_SUCCESS);
235   gBS->RestoreTPL (OldTpl);
236 
237   return Status;
238 }
239 
240 
241 /**
242   Returns the current operating mode data for the Dhcp6 instance.
243 
244   The GetModeData() function returns the current operating mode and
245   cached data packet for the Dhcp6 instance.
246 
247   @param[in]  This              The pointer to the Dhcp6 protocol.
248   @param[out] Dhcp6ModeData     The pointer to the Dhcp6 mode data.
249   @param[out] Dhcp6ConfigData   The pointer to the Dhcp6 configure data.
250 
251   @retval EFI_SUCCESS           The mode data was returned.
252   @retval EFI_INVALID_PARAMETER This is NULL.
253   @retval EFI_ACCESS_DENIED     The EFI DHCPv6 Protocol instance was not
254                                 configured.
255 **/
256 EFI_STATUS
257 EFIAPI
EfiDhcp6GetModeData(IN EFI_DHCP6_PROTOCOL * This,OUT EFI_DHCP6_MODE_DATA * Dhcp6ModeData OPTIONAL,OUT EFI_DHCP6_CONFIG_DATA * Dhcp6ConfigData OPTIONAL)258 EfiDhcp6GetModeData (
259   IN  EFI_DHCP6_PROTOCOL       *This,
260   OUT EFI_DHCP6_MODE_DATA      *Dhcp6ModeData      OPTIONAL,
261   OUT EFI_DHCP6_CONFIG_DATA    *Dhcp6ConfigData    OPTIONAL
262   )
263 {
264   EFI_TPL                      OldTpl;
265   EFI_DHCP6_IA                 *Ia;
266   DHCP6_INSTANCE               *Instance;
267   DHCP6_SERVICE                *Service;
268   UINT32                       IaSize;
269   UINT32                       IdSize;
270 
271   if (This == NULL || (Dhcp6ModeData == NULL && Dhcp6ConfigData == NULL)) {
272     return EFI_INVALID_PARAMETER;
273   }
274 
275   Instance = DHCP6_INSTANCE_FROM_THIS (This);
276   Service  = Instance->Service;
277 
278   if (Instance->Config == NULL && Dhcp6ConfigData != NULL) {
279     return EFI_ACCESS_DENIED;
280   }
281 
282   ASSERT (Service->ClientId != NULL);
283 
284   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
285 
286   //
287   // User needs a copy of instance config data.
288   //
289   if (Dhcp6ConfigData != NULL) {
290     ZeroMem (Dhcp6ConfigData, sizeof(EFI_DHCP6_CONFIG_DATA));
291     //
292     // Duplicate config data, including all reference buffers.
293     //
294     if (EFI_ERROR (Dhcp6CopyConfigData (Dhcp6ConfigData, Instance->Config))) {
295       goto ON_ERROR;
296     }
297   }
298 
299   //
300   // User need a copy of instance mode data.
301   //
302   if (Dhcp6ModeData != NULL) {
303     ZeroMem (Dhcp6ModeData, sizeof (EFI_DHCP6_MODE_DATA));
304     //
305     // Duplicate a copy of EFI_DHCP6_DUID for client Id.
306     //
307     IdSize = Service->ClientId->Length + sizeof (Service->ClientId->Length);
308 
309     Dhcp6ModeData->ClientId = AllocateZeroPool (IdSize);
310     if (Dhcp6ModeData->ClientId == NULL) {
311       goto ON_ERROR;
312     }
313 
314     CopyMem (
315       Dhcp6ModeData->ClientId,
316       Service->ClientId,
317       IdSize
318       );
319 
320     Ia = Instance->IaCb.Ia;
321     if (Ia != NULL) {
322       //
323       // Duplicate a copy of EFI_DHCP6_IA for configured Ia.
324       //
325       IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount -1) * sizeof (EFI_DHCP6_IA_ADDRESS);
326 
327       Dhcp6ModeData->Ia = AllocateZeroPool (IaSize);
328       if (Dhcp6ModeData->Ia == NULL) {
329         goto ON_ERROR;
330       }
331 
332       CopyMem (
333         Dhcp6ModeData->Ia,
334         Ia,
335         IaSize
336         );
337 
338       //
339       // Duplicate a copy of reply packet if has.
340       //
341       if (Ia->ReplyPacket != NULL) {
342         Dhcp6ModeData->Ia->ReplyPacket = AllocateZeroPool (Ia->ReplyPacket->Size);
343         if (Dhcp6ModeData->Ia->ReplyPacket == NULL) {
344           goto ON_ERROR;
345         }
346         CopyMem (
347           Dhcp6ModeData->Ia->ReplyPacket,
348           Ia->ReplyPacket,
349           Ia->ReplyPacket->Size
350           );
351       }
352     }
353   }
354 
355   gBS->RestoreTPL (OldTpl);
356 
357   return EFI_SUCCESS;
358 
359 ON_ERROR:
360 
361   if (Dhcp6ConfigData != NULL) {
362     Dhcp6CleanupConfigData (Dhcp6ConfigData);
363   }
364   if (Dhcp6ModeData != NULL) {
365     Dhcp6CleanupModeData (Dhcp6ModeData);
366   }
367   gBS->RestoreTPL (OldTpl);
368 
369   return EFI_OUT_OF_RESOURCES;
370 }
371 
372 
373 /**
374   Initializes, changes, or resets the operational settings for the Dhcp6 instance.
375 
376   The Configure() function is used to initialize or clean up the configuration
377   data of the Dhcp6 instance:
378   - When Dhcp6CfgData is not NULL and Configure() is called successfully, the
379     configuration data will be initialized in the Dhcp6 instance, and the state
380     of the configured IA will be transferred into Dhcp6Init.
381   - When Dhcp6CfgData is NULL and Configure() is called successfully, the
382     configuration data will be cleaned up and no IA will be associated with
383     the Dhcp6 instance.
384   To update the configuration data for an Dhcp6 instance, the original data
385   must be cleaned up before setting the new configuration data.
386 
387   @param[in]  This                   The pointer to the Dhcp6 protocol
388   @param[in]  Dhcp6CfgData           The pointer to the EFI_DHCP6_CONFIG_DATA.
389 
390   @retval EFI_SUCCESS           The Dhcp6 is configured successfully with the
391                                 Dhcp6Init state, or cleaned up the original
392                                 configuration setting.
393   @retval EFI_ACCESS_DENIED     The Dhcp6 instance was already configured.
394                                 The Dhcp6 instance has already started the
395                                 DHCPv6 S.A.R.R when Dhcp6CfgData is NULL.
396   @retval EFI_INVALID_PARAMETER Some of the parameter is invalid.
397   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
398   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
399 
400 **/
401 EFI_STATUS
402 EFIAPI
EfiDhcp6Configure(IN EFI_DHCP6_PROTOCOL * This,IN EFI_DHCP6_CONFIG_DATA * Dhcp6CfgData OPTIONAL)403 EfiDhcp6Configure (
404   IN EFI_DHCP6_PROTOCOL        *This,
405   IN EFI_DHCP6_CONFIG_DATA     *Dhcp6CfgData    OPTIONAL
406   )
407 {
408   EFI_TPL                      OldTpl;
409   EFI_STATUS                   Status;
410   LIST_ENTRY                   *Entry;
411   DHCP6_INSTANCE               *Other;
412   DHCP6_INSTANCE               *Instance;
413   DHCP6_SERVICE                *Service;
414   UINTN                        Index;
415 
416   if (This == NULL) {
417     return EFI_INVALID_PARAMETER;
418   }
419 
420   Instance = DHCP6_INSTANCE_FROM_THIS (This);
421   Service  = Instance->Service;
422 
423   //
424   // Check the parameter of configure data.
425   //
426   if (Dhcp6CfgData != NULL) {
427     if (Dhcp6CfgData->OptionCount > 0 && Dhcp6CfgData->OptionList == NULL) {
428       return EFI_INVALID_PARAMETER;
429     }
430     if (Dhcp6CfgData->OptionList != NULL) {
431       for (Index = 0; Index < Dhcp6CfgData->OptionCount; Index++) {
432         if (Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptClientId ||
433             Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptRapidCommit ||
434             Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptReconfigureAccept ||
435             Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIana ||
436             Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIata
437             ) {
438           return EFI_INVALID_PARAMETER;
439         }
440       }
441     }
442 
443     if (Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_NA &&
444         Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_TA
445         ) {
446       return EFI_INVALID_PARAMETER;
447     }
448 
449     if (Dhcp6CfgData->IaInfoEvent == NULL && Dhcp6CfgData->SolicitRetransmission == NULL) {
450       return EFI_INVALID_PARAMETER;
451     }
452 
453     if (Dhcp6CfgData->SolicitRetransmission != NULL &&
454         Dhcp6CfgData->SolicitRetransmission->Mrc == 0 &&
455         Dhcp6CfgData->SolicitRetransmission->Mrd == 0
456         ) {
457       return EFI_INVALID_PARAMETER;
458     }
459 
460     //
461     // Make sure the (IaId, IaType) is unique over all the instances.
462     //
463     NET_LIST_FOR_EACH (Entry, &Service->Child) {
464       Other = NET_LIST_USER_STRUCT (Entry, DHCP6_INSTANCE, Link);
465       if (Other->IaCb.Ia != NULL &&
466           Other->IaCb.Ia->Descriptor.Type == Dhcp6CfgData->IaDescriptor.Type &&
467           Other->IaCb.Ia->Descriptor.IaId == Dhcp6CfgData->IaDescriptor.IaId
468           ) {
469         return EFI_INVALID_PARAMETER;
470       }
471     }
472   }
473 
474   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
475 
476   if (Dhcp6CfgData != NULL) {
477     //
478     // It's not allowed to configure one instance twice without configure null.
479     //
480     if (Instance->Config != NULL) {
481       gBS->RestoreTPL (OldTpl);
482       return EFI_ACCESS_DENIED;
483     }
484 
485     //
486     // Duplicate config data including all reference buffers.
487     //
488     Instance->Config = AllocateZeroPool (sizeof (EFI_DHCP6_CONFIG_DATA));
489     if (Instance->Config == NULL) {
490       gBS->RestoreTPL (OldTpl);
491       return EFI_OUT_OF_RESOURCES;
492     }
493 
494     Status = Dhcp6CopyConfigData (Instance->Config, Dhcp6CfgData);
495     if (EFI_ERROR(Status)) {
496       FreePool (Instance->Config);
497       gBS->RestoreTPL (OldTpl);
498       return EFI_OUT_OF_RESOURCES;
499     }
500 
501     //
502     // Initialize the Ia descriptor from the config data, and leave the other
503     // fields of the Ia as default value 0.
504     //
505     Instance->IaCb.Ia = AllocateZeroPool (sizeof(EFI_DHCP6_IA));
506     if (Instance->IaCb.Ia == NULL) {
507       Dhcp6CleanupConfigData (Instance->Config);
508       FreePool (Instance->Config);
509       gBS->RestoreTPL (OldTpl);
510       return EFI_OUT_OF_RESOURCES;
511     }
512     CopyMem (
513       &Instance->IaCb.Ia->Descriptor,
514       &Dhcp6CfgData->IaDescriptor,
515       sizeof(EFI_DHCP6_IA_DESCRIPTOR)
516       );
517 
518   } else {
519 
520     if (Instance->Config == NULL) {
521       ASSERT (Instance->IaCb.Ia == NULL);
522       gBS->RestoreTPL (OldTpl);
523       return EFI_SUCCESS;
524     }
525 
526     //
527     // It's not allowed to configure a started instance as null.
528     //
529     if (Instance->IaCb.Ia->State != Dhcp6Init) {
530       gBS->RestoreTPL (OldTpl);
531       return EFI_ACCESS_DENIED;
532     }
533 
534     Dhcp6CleanupConfigData (Instance->Config);
535     FreePool (Instance->Config);
536     Instance->Config = NULL;
537 
538     FreePool (Instance->IaCb.Ia);
539     Instance->IaCb.Ia = NULL;
540   }
541 
542   gBS->RestoreTPL (OldTpl);
543 
544   return EFI_SUCCESS;
545 }
546 
547 
548 /**
549   Request configuration information without the assignment of any
550   Ia addresses of the client.
551 
552   The InfoRequest() function is used to request configuration information
553   without the assignment of any IPv6 address of the client. The client sends
554   out an Information Request packet to obtain the required configuration
555   information, and DHCPv6 server responds with a Reply packet containing
556   the information for the client. The received Reply packet will be passed
557   to the user by ReplyCallback function. If the user returns EFI_NOT_READY from
558   ReplyCallback, the Dhcp6 instance will continue to receive other Reply
559   packets unless timeout according to the Retransmission parameter.
560   Otherwise, the Information Request exchange process will be finished
561   successfully if user returns EFI_SUCCESS from ReplyCallback.
562 
563   @param[in]  This              The pointer to the Dhcp6 protocol.
564   @param[in]  SendClientId      If TRUE, the DHCPv6 protocol instance will build Client
565                                 Identifier option and include it into Information Request
566                                 packet. Otherwise, Client Identifier option will not be included.
567   @param[in]  OptionRequest     The pointer to the buffer of option request options.
568   @param[in]  OptionCount       The option number in the OptionList.
569   @param[in]  OptionList        The list of appended options.
570   @param[in]  Retransmission    The pointer to the retransmission of the message.
571   @param[in]  TimeoutEvent      The event of timeout.
572   @param[in]  ReplyCallback     The callback function when the reply was received.
573   @param[in]  CallbackContext   The pointer to the parameter passed to the callback.
574 
575   @retval EFI_SUCCESS           The DHCPv6 information request exchange process
576                                 completed when TimeoutEvent is NULL. Information
577                                 Request packet has been sent to DHCPv6 server when
578                                 TimeoutEvent is not NULL.
579   @retval EFI_NO_RESPONSE       The DHCPv6 information request exchange process failed
580                                 because of no response, or not all requested-options
581                                 are responded by DHCPv6 servers when Timeout happened.
582   @retval EFI_ABORTED           The DHCPv6 information request exchange process was aborted
583                                 by user.
584   @retval EFI_INVALID_PARAMETER Some parameter is NULL.
585   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
586   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
587 
588 **/
589 EFI_STATUS
590 EFIAPI
EfiDhcp6InfoRequest(IN EFI_DHCP6_PROTOCOL * This,IN BOOLEAN SendClientId,IN EFI_DHCP6_PACKET_OPTION * OptionRequest,IN UINT32 OptionCount,IN EFI_DHCP6_PACKET_OPTION * OptionList[]OPTIONAL,IN EFI_DHCP6_RETRANSMISSION * Retransmission,IN EFI_EVENT TimeoutEvent OPTIONAL,IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,IN VOID * CallbackContext OPTIONAL)591 EfiDhcp6InfoRequest (
592   IN EFI_DHCP6_PROTOCOL        *This,
593   IN BOOLEAN                   SendClientId,
594   IN EFI_DHCP6_PACKET_OPTION   *OptionRequest,
595   IN UINT32                    OptionCount,
596   IN EFI_DHCP6_PACKET_OPTION   *OptionList[]    OPTIONAL,
597   IN EFI_DHCP6_RETRANSMISSION  *Retransmission,
598   IN EFI_EVENT                 TimeoutEvent     OPTIONAL,
599   IN EFI_DHCP6_INFO_CALLBACK   ReplyCallback,
600   IN VOID                      *CallbackContext OPTIONAL
601   )
602 {
603   EFI_STATUS                   Status;
604   DHCP6_INSTANCE               *Instance;
605   DHCP6_SERVICE                *Service;
606   UINTN                        Index;
607   EFI_EVENT                    Timer;
608   EFI_STATUS                   TimerStatus;
609   UINTN                        GetMappingTimeOut;
610 
611   if (This == NULL || OptionRequest == NULL || Retransmission == NULL || ReplyCallback == NULL) {
612     return EFI_INVALID_PARAMETER;
613   }
614 
615   if (Retransmission != NULL && Retransmission->Mrc == 0 && Retransmission->Mrd == 0) {
616     return EFI_INVALID_PARAMETER;
617   }
618 
619   if (OptionCount > 0 && OptionList == NULL) {
620     return EFI_INVALID_PARAMETER;
621   }
622 
623   if (OptionList != NULL) {
624     for (Index = 0; Index < OptionCount; Index++) {
625       if (OptionList[Index]->OpCode == Dhcp6OptClientId || OptionList[Index]->OpCode == Dhcp6OptRequestOption) {
626         return EFI_INVALID_PARAMETER;
627       }
628     }
629   }
630 
631   Instance = DHCP6_INSTANCE_FROM_THIS (This);
632   Service  = Instance->Service;
633 
634   Status = Dhcp6StartInfoRequest (
635              Instance,
636              SendClientId,
637              OptionRequest,
638              OptionCount,
639              OptionList,
640              Retransmission,
641              TimeoutEvent,
642              ReplyCallback,
643              CallbackContext
644              );
645   if (Status == EFI_NO_MAPPING) {
646     //
647     // The link local address is not ready, wait for some time and restart
648     // the DHCP6 information request process.
649     //
650     Status = Dhcp6GetMappingTimeOut(Service->Ip6Cfg, &GetMappingTimeOut);
651     if (EFI_ERROR(Status)) {
652       return Status;
653     }
654 
655     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
656     if (EFI_ERROR (Status)) {
657       return Status;
658     }
659 
660     //
661     // Start the timer, wait for link local address DAD to finish.
662     //
663     Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
664     if (EFI_ERROR (Status)) {
665       gBS->CloseEvent (Timer);
666       return Status;
667     }
668 
669     do {
670       TimerStatus = gBS->CheckEvent (Timer);
671       if (!EFI_ERROR (TimerStatus)) {
672         Status = Dhcp6StartInfoRequest (
673                    Instance,
674                    SendClientId,
675                    OptionRequest,
676                    OptionCount,
677                    OptionList,
678                    Retransmission,
679                    TimeoutEvent,
680                    ReplyCallback,
681                    CallbackContext
682                    );
683       }
684     } while (TimerStatus == EFI_NOT_READY);
685 
686     gBS->CloseEvent (Timer);
687   }
688   if (EFI_ERROR (Status)) {
689     return Status;
690   }
691 
692   //
693   // Poll udp out of the net tpl if synchoronus call.
694   //
695   if (TimeoutEvent == NULL) {
696 
697     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
698       Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
699     }
700     return Instance->UdpSts;
701   }
702 
703   return EFI_SUCCESS;
704 }
705 
706 
707 /**
708   Manually extend the valid and preferred lifetimes for the IPv6 addresses
709   of the configured IA and update other configuration parameters by sending a
710   Renew or Rebind packet.
711 
712   The RenewRebind() function is used to manually extend the valid and preferred
713   lifetimes for the IPv6 addresses of the configured IA, and update other
714   configuration parameters by sending Renew or Rebind packet.
715   - When RebindRequest is FALSE and the state of the configured IA is Dhcp6Bound,
716     it sends Renew packet to the previously DHCPv6 server and transfer the
717     state of the configured IA to Dhcp6Renewing. If valid Reply packet received,
718     the state transfers to Dhcp6Bound and the valid and preferred timer restarts.
719     If fails, the state transfers to Dhcp6Bound, but the timer continues.
720   - When RebindRequest is TRUE and the state of the configured IA is Dhcp6Bound,
721     it will send a Rebind packet. If valid Reply packet is received, the state transfers
722     to Dhcp6Bound and the valid and preferred timer restarts. If it fails, the state
723     transfers to Dhcp6Init, and the IA can't be used.
724 
725   @param[in]  This              The pointer to the Dhcp6 protocol.
726   @param[in]  RebindRequest     If TRUE, Rebind packet will be sent and enter Dhcp6Rebinding state.
727                                 Otherwise, Renew packet will be sent and enter Dhcp6Renewing state.
728 
729   @retval EFI_SUCCESS           The DHCPv6 renew/rebind exchange process has
730                                 completed and at least one IPv6 address of the
731                                 configured IA has been bound again when
732                                 EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
733                                 The EFI DHCPv6 Protocol instance has sent Renew
734                                 or Rebind packet when
735                                 EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
736   @retval EFI_ACCESS_DENIED     The Dhcp6 instance hasn't been configured, or the
737                                 state of the configured IA is not in Dhcp6Bound.
738   @retval EFI_ALREADY_STARTED   The state of the configured IA has already entered
739                                 Dhcp6Renewing when RebindRequest is FALSE.
740                                 The state of the configured IA has already entered
741                                 Dhcp6Rebinding when RebindRequest is TRUE.
742   @retval EFI_ABORTED           The DHCPv6 renew/rebind exchange process aborted
743                                 by the user.
744   @retval EFI_NO_RESPONSE       The DHCPv6 renew/rebind exchange process failed
745                                 because of no response.
746   @retval EFI_NO_MAPPING        No IPv6 address has been bound to the configured
747                                 IA after the DHCPv6 renew/rebind exchange process.
748   @retval EFI_INVALID_PARAMETER Some parameter is NULL.
749   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
750 
751 **/
752 EFI_STATUS
753 EFIAPI
EfiDhcp6RenewRebind(IN EFI_DHCP6_PROTOCOL * This,IN BOOLEAN RebindRequest)754 EfiDhcp6RenewRebind (
755   IN EFI_DHCP6_PROTOCOL        *This,
756   IN BOOLEAN                   RebindRequest
757   )
758 {
759   EFI_STATUS                   Status;
760   EFI_TPL                      OldTpl;
761   DHCP6_INSTANCE               *Instance;
762   DHCP6_SERVICE                *Service;
763 
764   if (This == NULL) {
765     return EFI_INVALID_PARAMETER;
766   }
767 
768   Instance = DHCP6_INSTANCE_FROM_THIS (This);
769   Service  = Instance->Service;
770 
771   //
772   // The instance hasn't been configured.
773   //
774   if (Instance->Config == NULL) {
775     return EFI_ACCESS_DENIED;
776   }
777 
778   ASSERT (Instance->IaCb.Ia != NULL);
779 
780   //
781   // The instance has already entered renewing or rebinding state.
782   //
783   if ((Instance->IaCb.Ia->State == Dhcp6Rebinding && RebindRequest) ||
784       (Instance->IaCb.Ia->State == Dhcp6Renewing && !RebindRequest)
785       ) {
786     return EFI_ALREADY_STARTED;
787   }
788 
789   if (Instance->IaCb.Ia->State != Dhcp6Bound) {
790     return EFI_ACCESS_DENIED;
791   }
792 
793   OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);
794   Instance->UdpSts = EFI_ALREADY_STARTED;
795 
796   //
797   // Send renew/rebind message to start exchange process.
798   //
799   Status = Dhcp6SendRenewRebindMsg (Instance, RebindRequest);
800 
801   if (EFI_ERROR (Status)) {
802     goto ON_ERROR;
803   }
804 
805   //
806   // Register receive callback for the stateful exchange process.
807   //
808   Status = UdpIoRecvDatagram(
809              Service->UdpIo,
810              Dhcp6ReceivePacket,
811              Service,
812              0
813              );
814 
815   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
816     goto ON_ERROR;
817   }
818 
819   gBS->RestoreTPL (OldTpl);
820 
821   //
822   // Poll udp out of the net tpl if synchoronus call.
823   //
824   if (Instance->Config->IaInfoEvent == NULL) {
825 
826     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
827       Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
828     }
829     return Instance->UdpSts;
830   }
831 
832   return EFI_SUCCESS;
833 
834 ON_ERROR:
835 
836   gBS->RestoreTPL (OldTpl);
837   return Status;
838 }
839 
840 
841 /**
842   Inform that one or more addresses assigned by a server are already
843   in use by another node.
844 
845   The Decline() function is used to manually decline the assignment of
846   IPv6 addresses, which have been already used by another node. If all
847   IPv6 addresses of the configured IA are declined through this function,
848   the state of the IA will switch through Dhcp6Declining to Dhcp6Init.
849   Otherwise, the state of the IA will restore to Dhcp6Bound after the
850   declining process. The Decline() can only be called when the IA is in
851   Dhcp6Bound state. If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL,
852   this function is a blocking operation. It will return after the
853   declining process finishes, or aborted by user.
854 
855   @param[in]  This              The pointer to EFI_DHCP6_PROTOCOL.
856   @param[in]  AddressCount      The number of declining addresses.
857   @param[in]  Addresses         The pointer to the buffer stored the declining
858                                 addresses.
859 
860   @retval EFI_SUCCESS           The DHCPv6 decline exchange process completed
861                                 when EFI_DHCP6_CONFIG_DATA.IaInfoEvent was NULL.
862                                 The Dhcp6 instance sent Decline packet when
863                                 EFI_DHCP6_CONFIG_DATA.IaInfoEvent was not NULL.
864   @retval EFI_ACCESS_DENIED     The Dhcp6 instance hasn't been configured, or the
865                                 state of the configured IA is not in Dhcp6Bound.
866   @retval EFI_ABORTED           The DHCPv6 decline exchange process aborted by user.
867   @retval EFI_NOT_FOUND         Any specified IPv6 address is not correlated with
868                                 the configured IA for this instance.
869   @retval EFI_INVALID_PARAMETER Some parameter is NULL.
870   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
871 
872 **/
873 EFI_STATUS
874 EFIAPI
EfiDhcp6Decline(IN EFI_DHCP6_PROTOCOL * This,IN UINT32 AddressCount,IN EFI_IPv6_ADDRESS * Addresses)875 EfiDhcp6Decline (
876   IN EFI_DHCP6_PROTOCOL        *This,
877   IN UINT32                    AddressCount,
878   IN EFI_IPv6_ADDRESS          *Addresses
879   )
880 {
881   EFI_STATUS                   Status;
882   EFI_TPL                      OldTpl;
883   EFI_DHCP6_IA                 *DecIa;
884   DHCP6_INSTANCE               *Instance;
885   DHCP6_SERVICE                *Service;
886 
887   if (This == NULL || AddressCount == 0 || Addresses == NULL) {
888     return EFI_INVALID_PARAMETER;
889   }
890 
891   Instance = DHCP6_INSTANCE_FROM_THIS (This);
892   Service  = Instance->Service;
893 
894   //
895   // The instance hasn't been configured.
896   //
897   if (Instance->Config == NULL) {
898     return EFI_ACCESS_DENIED;
899   }
900 
901   ASSERT (Instance->IaCb.Ia != NULL);
902 
903   if (Instance->IaCb.Ia->State != Dhcp6Bound) {
904     return EFI_ACCESS_DENIED;
905   }
906 
907   //
908   // Check whether all the declined addresses belongs to the configured Ia.
909   //
910   Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);
911 
912   if (EFI_ERROR(Status)) {
913     return Status;
914   }
915 
916   OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);
917   Instance->UdpSts = EFI_ALREADY_STARTED;
918 
919   //
920   // Deprive of all the declined addresses from the configured Ia, and create a
921   // DeclineIa used to create decline message.
922   //
923   DecIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);
924 
925   if (DecIa == NULL) {
926     Status = EFI_OUT_OF_RESOURCES;
927     goto ON_ERROR;
928   }
929 
930   //
931   // Send the decline message to start exchange process.
932   //
933   Status = Dhcp6SendDeclineMsg (Instance, DecIa);
934 
935   if (EFI_ERROR (Status)) {
936     goto ON_ERROR;
937   }
938 
939   //
940   // Register receive callback for the stateful exchange process.
941   //
942   Status = UdpIoRecvDatagram(
943              Service->UdpIo,
944              Dhcp6ReceivePacket,
945              Service,
946              0
947              );
948 
949   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
950     goto ON_ERROR;
951   }
952 
953   FreePool (DecIa);
954   gBS->RestoreTPL (OldTpl);
955 
956   //
957   // Poll udp out of the net tpl if synchoronus call.
958   //
959   if (Instance->Config->IaInfoEvent == NULL) {
960 
961     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
962       Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
963     }
964     return Instance->UdpSts;
965   }
966 
967   return EFI_SUCCESS;
968 
969 ON_ERROR:
970 
971   if (DecIa != NULL) {
972     FreePool (DecIa);
973   }
974   gBS->RestoreTPL (OldTpl);
975 
976   return Status;
977 }
978 
979 
980 /**
981   Release one or more addresses associated with the configured Ia
982   for current instance.
983 
984   The Release() function is used to manually release one or more
985   IPv6 addresses. If AddressCount is zero, it will release all IPv6
986   addresses of the configured IA. If all IPv6 addresses of the IA are
987   released through this function, the state of the IA will switch
988   through Dhcp6Releasing to Dhcp6Init, otherwise, the state of the
989   IA will restore to Dhcp6Bound after the releasing process.
990   The Release() can only be called when the IA is in Dhcp6Bound state.
991   If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the function is
992   a blocking operation. It will return after the releasing process
993   finishes, or is aborted by user.
994 
995   @param[in]  This              The pointer to the Dhcp6 protocol.
996   @param[in]  AddressCount      The number of releasing addresses.
997   @param[in]  Addresses         The pointer to the buffer stored the releasing
998                                 addresses.
999 
1000   @retval EFI_SUCCESS           The DHCPv6 release exchange process
1001                                 completed when EFI_DHCP6_CONFIG_DATA.IaInfoEvent
1002                                 was NULL. The Dhcp6 instance was sent Release
1003                                 packet when EFI_DHCP6_CONFIG_DATA.IaInfoEvent
1004                                 was not NULL.
1005   @retval EFI_ACCESS_DENIED     The Dhcp6 instance hasn't been configured, or the
1006                                 state of the configured IA is not in Dhcp6Bound.
1007   @retval EFI_ABORTED           The DHCPv6 release exchange process aborted by user.
1008   @retval EFI_NOT_FOUND         Any specified IPv6 address is not correlated with
1009                                 the configured IA for this instance.
1010   @retval EFI_INVALID_PARAMETER Some parameter is NULL.
1011   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
1012 
1013 **/
1014 EFI_STATUS
1015 EFIAPI
EfiDhcp6Release(IN EFI_DHCP6_PROTOCOL * This,IN UINT32 AddressCount,IN EFI_IPv6_ADDRESS * Addresses)1016 EfiDhcp6Release (
1017   IN EFI_DHCP6_PROTOCOL        *This,
1018   IN UINT32                    AddressCount,
1019   IN EFI_IPv6_ADDRESS          *Addresses
1020   )
1021 {
1022   EFI_STATUS                   Status;
1023   EFI_TPL                      OldTpl;
1024   EFI_DHCP6_IA                 *RelIa;
1025   DHCP6_INSTANCE               *Instance;
1026   DHCP6_SERVICE                *Service;
1027 
1028   if (This == NULL || (AddressCount != 0 && Addresses == NULL)) {
1029     return EFI_INVALID_PARAMETER;
1030   }
1031 
1032   Instance = DHCP6_INSTANCE_FROM_THIS (This);
1033   Service  = Instance->Service;
1034 
1035   //
1036   // The instance hasn't been configured.
1037   //
1038   if (Instance->Config == NULL) {
1039     return EFI_ACCESS_DENIED;
1040   }
1041 
1042   ASSERT (Instance->IaCb.Ia != NULL);
1043 
1044   if (Instance->IaCb.Ia->State != Dhcp6Bound) {
1045     return EFI_ACCESS_DENIED;
1046   }
1047 
1048   //
1049   // Check whether all the released addresses belongs to the configured Ia.
1050   //
1051   Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);
1052 
1053   if (EFI_ERROR(Status)) {
1054     return Status;
1055   }
1056 
1057   OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);
1058   Instance->UdpSts = EFI_ALREADY_STARTED;
1059 
1060   //
1061   // Deprive of all the released addresses from the configured Ia, and create a
1062   // ReleaseIa used to create release message.
1063   //
1064   RelIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);
1065 
1066   if (RelIa == NULL) {
1067     Status = EFI_OUT_OF_RESOURCES;
1068     goto ON_ERROR;
1069   }
1070 
1071   //
1072   // Send the release message to start exchange process.
1073   //
1074   Status = Dhcp6SendReleaseMsg (Instance, RelIa);
1075 
1076   if (EFI_ERROR (Status)) {
1077     goto ON_ERROR;
1078   }
1079 
1080   //
1081   // Register receive callback for the stateful exchange process.
1082   //
1083   Status = UdpIoRecvDatagram(
1084              Service->UdpIo,
1085              Dhcp6ReceivePacket,
1086              Service,
1087              0
1088              );
1089 
1090   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
1091     goto ON_ERROR;
1092   }
1093 
1094   FreePool (RelIa);
1095   gBS->RestoreTPL (OldTpl);
1096 
1097   //
1098   // Poll udp out of the net tpl if synchoronus call.
1099   //
1100   if (Instance->Config->IaInfoEvent == NULL) {
1101     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
1102       Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
1103     }
1104     return Instance->UdpSts;
1105   }
1106 
1107   return EFI_SUCCESS;
1108 
1109 ON_ERROR:
1110 
1111   if (RelIa != NULL) {
1112     FreePool (RelIa);
1113   }
1114   gBS->RestoreTPL (OldTpl);
1115 
1116   return Status;
1117 }
1118 
1119 
1120 /**
1121   Parse the option data in the Dhcp6 packet.
1122 
1123   The Parse() function is used to retrieve the option list in the DHCPv6 packet.
1124 
1125   @param[in]      This              The pointer to the Dhcp6 protocol.
1126   @param[in]      Packet            The pointer to the Dhcp6 packet.
1127   @param[in, out] OptionCount       The number of option in the packet.
1128   @param[out]     PacketOptionList  The array of pointers to each option in the packet.
1129 
1130   @retval EFI_SUCCESS           The packet was successfully parsed.
1131   @retval EFI_INVALID_PARAMETER Some parameter is NULL.
1132   @retval EFI_BUFFER_TOO_SMALL  *OptionCount is smaller than the number of options
1133                                 that were found in the Packet.
1134 
1135 **/
1136 EFI_STATUS
1137 EFIAPI
EfiDhcp6Parse(IN EFI_DHCP6_PROTOCOL * This,IN EFI_DHCP6_PACKET * Packet,IN OUT UINT32 * OptionCount,OUT EFI_DHCP6_PACKET_OPTION * PacketOptionList[]OPTIONAL)1138 EfiDhcp6Parse (
1139   IN EFI_DHCP6_PROTOCOL        *This,
1140   IN EFI_DHCP6_PACKET          *Packet,
1141   IN OUT UINT32                *OptionCount,
1142   OUT EFI_DHCP6_PACKET_OPTION  *PacketOptionList[]  OPTIONAL
1143   )
1144 {
1145   UINT32                       OptCnt;
1146   UINT32                       OptLen;
1147   UINT16                       DataLen;
1148   UINT8                        *Start;
1149   UINT8                        *End;
1150 
1151   if (This == NULL || Packet == NULL || OptionCount == NULL) {
1152     return EFI_INVALID_PARAMETER;
1153   }
1154 
1155   if (*OptionCount != 0 && PacketOptionList == NULL) {
1156     return EFI_INVALID_PARAMETER;
1157   }
1158 
1159   if (Packet->Length > Packet->Size || Packet->Length < sizeof (EFI_DHCP6_HEADER)) {
1160     return EFI_INVALID_PARAMETER;
1161   }
1162 
1163   //
1164   //  The format of Dhcp6 option:
1165   //
1166   //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1167   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1168   //    |          option-code          |   option-len (option data)    |
1169   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1170   //    |                          option-data                          |
1171   //    |                      (option-len octets)                      |
1172   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1173   //
1174 
1175   OptCnt = 0;
1176   OptLen = Packet->Length - sizeof (EFI_DHCP6_HEADER);
1177   Start  = Packet->Dhcp6.Option;
1178   End    = Start + OptLen;
1179 
1180   //
1181   // Calculate the number of option in the packet.
1182   //
1183   while (Start < End) {
1184     DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;
1185     Start  += (NTOHS (DataLen) + 4);
1186     OptCnt++;
1187   }
1188 
1189   //
1190   // It will return buffer too small if pass-in option count is smaller than the
1191   // actual count of options in the packet.
1192   //
1193   if (OptCnt > *OptionCount) {
1194     *OptionCount = OptCnt;
1195     return EFI_BUFFER_TOO_SMALL;
1196   }
1197 
1198   ZeroMem (
1199     PacketOptionList,
1200     (*OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *))
1201     );
1202 
1203   OptCnt = 0;
1204   Start  = Packet->Dhcp6.Option;
1205 
1206   while (Start < End) {
1207 
1208     PacketOptionList[OptCnt] = (EFI_DHCP6_PACKET_OPTION *) Start;
1209     DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;
1210     Start  += (NTOHS (DataLen) + 4);
1211     OptCnt++;
1212   }
1213 
1214   return EFI_SUCCESS;
1215 }
1216 
1217