2 This EFI_DHCP6_PROTOCOL interface implementation.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
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.
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.
16 #include "Dhcp6Impl.h"
19 // Well-known multi-cast address defined in section-24.1 of rfc-3315
21 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
22 // ALL_DHCP_Servers address: FF05::1:3
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}};
27 EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate
= {
40 Starts the DHCPv6 standard S.A.R.R. process.
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
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.
52 @param[in] This The pointer to Dhcp6 protocol.
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
65 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
66 @retval EFI_NO_MEDIA There was a media error.
72 IN EFI_DHCP6_PROTOCOL
*This
77 DHCP6_INSTANCE
*Instance
;
78 DHCP6_SERVICE
*Service
;
81 return EFI_INVALID_PARAMETER
;
84 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
85 Service
= Instance
->Service
;
88 // The instance hasn't been configured.
90 if (Instance
->Config
== NULL
) {
91 return EFI_ACCESS_DENIED
;
94 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
97 // The instance has already been started.
99 if (Instance
->IaCb
.Ia
->State
!= Dhcp6Init
) {
100 return EFI_ALREADY_STARTED
;
103 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
104 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
107 // Send the solicit message to start S.A.R.R process.
109 Status
= Dhcp6SendSolicitMsg (Instance
);
111 if (EFI_ERROR (Status
)) {
116 // Register receive callback for the stateful exchange process.
118 Status
= UdpIoRecvDatagram(
125 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
129 gBS
->RestoreTPL (OldTpl
);
132 // Poll udp out of the net tpl if synchronous call.
134 if (Instance
->Config
->IaInfoEvent
== NULL
) {
136 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
137 Service
->UdpIo
->Protocol
.Udp6
->Poll (Service
->UdpIo
->Protocol
.Udp6
);
139 return Instance
->UdpSts
;
146 gBS
->RestoreTPL (OldTpl
);
152 Stops the DHCPv6 standard S.A.R.R. process.
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.
160 @param[in] This The pointer to the Dhcp6 protocol.
162 @retval EFI_SUCCESS The Dhcp6 instance is now in the Dhcp6Init state.
163 @retval EFI_INVALID_PARAMETER This is NULL.
169 IN EFI_DHCP6_PROTOCOL
*This
174 EFI_UDP6_PROTOCOL
*Udp6
;
175 DHCP6_INSTANCE
*Instance
;
176 DHCP6_SERVICE
*Service
;
179 return EFI_INVALID_PARAMETER
;
182 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
183 Service
= Instance
->Service
;
184 Udp6
= Service
->UdpIo
->Protocol
.Udp6
;
185 Status
= EFI_SUCCESS
;
188 // The instance hasn't been configured.
190 if (Instance
->Config
== NULL
) {
194 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
197 // No valid REPLY message received yet, cleanup this instance directly.
199 if (Instance
->IaCb
.Ia
->State
== Dhcp6Init
||
200 Instance
->IaCb
.Ia
->State
== Dhcp6Selecting
||
201 Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
207 // Release the current ready Ia.
209 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
211 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
212 Status
= Dhcp6SendReleaseMsg (Instance
, Instance
->IaCb
.Ia
);
213 gBS
->RestoreTPL (OldTpl
);
214 if (EFI_ERROR (Status
)) {
219 // Poll udp out of the net tpl if synchoronus call.
221 if (Instance
->Config
->IaInfoEvent
== NULL
) {
222 ASSERT (Udp6
!= NULL
);
223 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
226 Status
= Instance
->UdpSts
;
231 // Clean up the session data for the released Ia.
233 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
234 Dhcp6CleanupSession (Instance
, EFI_SUCCESS
);
235 gBS
->RestoreTPL (OldTpl
);
242 Returns the current operating mode data for the Dhcp6 instance.
244 The GetModeData() function returns the current operating mode and
245 cached data packet for the Dhcp6 instance.
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.
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
258 EfiDhcp6GetModeData (
259 IN EFI_DHCP6_PROTOCOL
*This
,
260 OUT EFI_DHCP6_MODE_DATA
*Dhcp6ModeData OPTIONAL
,
261 OUT EFI_DHCP6_CONFIG_DATA
*Dhcp6ConfigData OPTIONAL
266 DHCP6_INSTANCE
*Instance
;
267 DHCP6_SERVICE
*Service
;
271 if (This
== NULL
|| (Dhcp6ModeData
== NULL
&& Dhcp6ConfigData
== NULL
)) {
272 return EFI_INVALID_PARAMETER
;
275 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
276 Service
= Instance
->Service
;
278 if (Instance
->Config
== NULL
&& Dhcp6ConfigData
!= NULL
) {
279 return EFI_ACCESS_DENIED
;
282 ASSERT (Service
->ClientId
!= NULL
);
284 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
287 // User needs a copy of instance config data.
289 if (Dhcp6ConfigData
!= NULL
) {
290 ZeroMem (Dhcp6ConfigData
, sizeof(EFI_DHCP6_CONFIG_DATA
));
292 // Duplicate config data, including all reference buffers.
294 if (EFI_ERROR (Dhcp6CopyConfigData (Dhcp6ConfigData
, Instance
->Config
))) {
300 // User need a copy of instance mode data.
302 if (Dhcp6ModeData
!= NULL
) {
303 ZeroMem (Dhcp6ModeData
, sizeof (EFI_DHCP6_MODE_DATA
));
305 // Duplicate a copy of EFI_DHCP6_DUID for client Id.
307 IdSize
= Service
->ClientId
->Length
+ sizeof (Service
->ClientId
->Length
);
309 Dhcp6ModeData
->ClientId
= AllocateZeroPool (IdSize
);
310 if (Dhcp6ModeData
->ClientId
== NULL
) {
315 Dhcp6ModeData
->ClientId
,
320 Ia
= Instance
->IaCb
.Ia
;
323 // Duplicate a copy of EFI_DHCP6_IA for configured Ia.
325 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
-1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
327 Dhcp6ModeData
->Ia
= AllocateZeroPool (IaSize
);
328 if (Dhcp6ModeData
->Ia
== NULL
) {
339 // Duplicate a copy of reply packet if has.
341 if (Ia
->ReplyPacket
!= NULL
) {
342 Dhcp6ModeData
->Ia
->ReplyPacket
= AllocateZeroPool (Ia
->ReplyPacket
->Size
);
343 if (Dhcp6ModeData
->Ia
->ReplyPacket
== NULL
) {
347 Dhcp6ModeData
->Ia
->ReplyPacket
,
349 Ia
->ReplyPacket
->Size
355 gBS
->RestoreTPL (OldTpl
);
361 if (Dhcp6ConfigData
!= NULL
) {
362 Dhcp6CleanupConfigData (Dhcp6ConfigData
);
364 if (Dhcp6ModeData
!= NULL
) {
365 Dhcp6CleanupModeData (Dhcp6ModeData
);
367 gBS
->RestoreTPL (OldTpl
);
369 return EFI_OUT_OF_RESOURCES
;
374 Initializes, changes, or resets the operational settings for the Dhcp6 instance.
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
384 To update the configuration data for an Dhcp6 instance, the original data
385 must be cleaned up before setting the new configuration data.
387 @param[in] This The pointer to the Dhcp6 protocol
388 @param[in] Dhcp6CfgData The pointer to the EFI_DHCP6_CONFIG_DATA.
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.
404 IN EFI_DHCP6_PROTOCOL
*This
,
405 IN EFI_DHCP6_CONFIG_DATA
*Dhcp6CfgData OPTIONAL
411 DHCP6_INSTANCE
*Other
;
412 DHCP6_INSTANCE
*Instance
;
413 DHCP6_SERVICE
*Service
;
417 return EFI_INVALID_PARAMETER
;
420 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
421 Service
= Instance
->Service
;
424 // Check the parameter of configure data.
426 if (Dhcp6CfgData
!= NULL
) {
427 if (Dhcp6CfgData
->OptionCount
> 0 && Dhcp6CfgData
->OptionList
== NULL
) {
428 return EFI_INVALID_PARAMETER
;
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
438 return EFI_INVALID_PARAMETER
;
443 if (Dhcp6CfgData
->IaDescriptor
.Type
!= EFI_DHCP6_IA_TYPE_NA
&&
444 Dhcp6CfgData
->IaDescriptor
.Type
!= EFI_DHCP6_IA_TYPE_TA
446 return EFI_INVALID_PARAMETER
;
449 if (Dhcp6CfgData
->IaInfoEvent
== NULL
&& Dhcp6CfgData
->SolicitRetransmission
== NULL
) {
450 return EFI_INVALID_PARAMETER
;
453 if (Dhcp6CfgData
->SolicitRetransmission
!= NULL
&&
454 Dhcp6CfgData
->SolicitRetransmission
->Mrc
== 0 &&
455 Dhcp6CfgData
->SolicitRetransmission
->Mrd
== 0
457 return EFI_INVALID_PARAMETER
;
461 // Make sure the (IaId, IaType) is unique over all the instances.
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
469 return EFI_INVALID_PARAMETER
;
474 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
476 if (Dhcp6CfgData
!= NULL
) {
478 // It's not allowed to configure one instance twice without configure null.
480 if (Instance
->Config
!= NULL
) {
481 gBS
->RestoreTPL (OldTpl
);
482 return EFI_ACCESS_DENIED
;
486 // Duplicate config data including all reference buffers.
488 Instance
->Config
= AllocateZeroPool (sizeof (EFI_DHCP6_CONFIG_DATA
));
489 if (Instance
->Config
== NULL
) {
490 gBS
->RestoreTPL (OldTpl
);
491 return EFI_OUT_OF_RESOURCES
;
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
;
502 // Initialize the Ia descriptor from the config data, and leave the other
503 // fields of the Ia as default value 0.
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
;
513 &Instance
->IaCb
.Ia
->Descriptor
,
514 &Dhcp6CfgData
->IaDescriptor
,
515 sizeof(EFI_DHCP6_IA_DESCRIPTOR
)
520 if (Instance
->Config
== NULL
) {
521 ASSERT (Instance
->IaCb
.Ia
== NULL
);
522 gBS
->RestoreTPL (OldTpl
);
527 // It's not allowed to configure a started instance as null.
529 if (Instance
->IaCb
.Ia
->State
!= Dhcp6Init
) {
530 gBS
->RestoreTPL (OldTpl
);
531 return EFI_ACCESS_DENIED
;
534 Dhcp6CleanupConfigData (Instance
->Config
);
535 FreePool (Instance
->Config
);
536 Instance
->Config
= NULL
;
538 FreePool (Instance
->IaCb
.Ia
);
539 Instance
->IaCb
.Ia
= NULL
;
542 gBS
->RestoreTPL (OldTpl
);
549 Request configuration information without the assignment of any
550 Ia addresses of the client.
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.
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.
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
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.
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
604 DHCP6_INSTANCE
*Instance
;
605 DHCP6_SERVICE
*Service
;
608 EFI_STATUS TimerStatus
;
609 UINTN GetMappingTimeOut
;
611 if (This
== NULL
|| OptionRequest
== NULL
|| Retransmission
== NULL
|| ReplyCallback
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
615 if (Retransmission
!= NULL
&& Retransmission
->Mrc
== 0 && Retransmission
->Mrd
== 0) {
616 return EFI_INVALID_PARAMETER
;
619 if (OptionCount
> 0 && OptionList
== NULL
) {
620 return EFI_INVALID_PARAMETER
;
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
;
631 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
632 Service
= Instance
->Service
;
634 Status
= Dhcp6StartInfoRequest (
645 if (Status
== EFI_NO_MAPPING
) {
647 // The link local address is not ready, wait for some time and restart
648 // the DHCP6 information request process.
650 Status
= Dhcp6GetMappingTimeOut(Service
->Ip6Cfg
, &GetMappingTimeOut
);
651 if (EFI_ERROR(Status
)) {
655 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
656 if (EFI_ERROR (Status
)) {
661 // Start the timer, wait for link local address DAD to finish.
663 Status
= gBS
->SetTimer (Timer
, TimerRelative
, GetMappingTimeOut
);
664 if (EFI_ERROR (Status
)) {
665 gBS
->CloseEvent (Timer
);
670 TimerStatus
= gBS
->CheckEvent (Timer
);
671 if (!EFI_ERROR (TimerStatus
)) {
672 Status
= Dhcp6StartInfoRequest (
684 } while (TimerStatus
== EFI_NOT_READY
);
686 gBS
->CloseEvent (Timer
);
688 if (EFI_ERROR (Status
)) {
693 // Poll udp out of the net tpl if synchoronus call.
695 if (TimeoutEvent
== NULL
) {
697 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
698 Service
->UdpIo
->Protocol
.Udp6
->Poll (Service
->UdpIo
->Protocol
.Udp6
);
700 return Instance
->UdpSts
;
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.
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.
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.
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
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.
754 EfiDhcp6RenewRebind (
755 IN EFI_DHCP6_PROTOCOL
*This
,
756 IN BOOLEAN RebindRequest
761 DHCP6_INSTANCE
*Instance
;
762 DHCP6_SERVICE
*Service
;
765 return EFI_INVALID_PARAMETER
;
768 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
769 Service
= Instance
->Service
;
772 // The instance hasn't been configured.
774 if (Instance
->Config
== NULL
) {
775 return EFI_ACCESS_DENIED
;
778 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
781 // The instance has already entered renewing or rebinding state.
783 if ((Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
&& RebindRequest
) ||
784 (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
&& !RebindRequest
)
786 return EFI_ALREADY_STARTED
;
789 if (Instance
->IaCb
.Ia
->State
!= Dhcp6Bound
) {
790 return EFI_ACCESS_DENIED
;
793 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
794 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
797 // Send renew/rebind message to start exchange process.
799 Status
= Dhcp6SendRenewRebindMsg (Instance
, RebindRequest
);
801 if (EFI_ERROR (Status
)) {
806 // Register receive callback for the stateful exchange process.
808 Status
= UdpIoRecvDatagram(
815 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
819 gBS
->RestoreTPL (OldTpl
);
822 // Poll udp out of the net tpl if synchoronus call.
824 if (Instance
->Config
->IaInfoEvent
== NULL
) {
826 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
827 Service
->UdpIo
->Protocol
.Udp6
->Poll (Service
->UdpIo
->Protocol
.Udp6
);
829 return Instance
->UdpSts
;
836 gBS
->RestoreTPL (OldTpl
);
842 Inform that one or more addresses assigned by a server are already
843 in use by another node.
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.
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
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.
876 IN EFI_DHCP6_PROTOCOL
*This
,
877 IN UINT32 AddressCount
,
878 IN EFI_IPv6_ADDRESS
*Addresses
884 DHCP6_INSTANCE
*Instance
;
885 DHCP6_SERVICE
*Service
;
887 if (This
== NULL
|| AddressCount
== 0 || Addresses
== NULL
) {
888 return EFI_INVALID_PARAMETER
;
891 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
892 Service
= Instance
->Service
;
895 // The instance hasn't been configured.
897 if (Instance
->Config
== NULL
) {
898 return EFI_ACCESS_DENIED
;
901 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
903 if (Instance
->IaCb
.Ia
->State
!= Dhcp6Bound
) {
904 return EFI_ACCESS_DENIED
;
908 // Check whether all the declined addresses belongs to the configured Ia.
910 Status
= Dhcp6CheckAddress (Instance
->IaCb
.Ia
, AddressCount
, Addresses
);
912 if (EFI_ERROR(Status
)) {
916 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
917 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
920 // Deprive of all the declined addresses from the configured Ia, and create a
921 // DeclineIa used to create decline message.
923 DecIa
= Dhcp6DepriveAddress (Instance
->IaCb
.Ia
, AddressCount
, Addresses
);
926 Status
= EFI_OUT_OF_RESOURCES
;
931 // Send the decline message to start exchange process.
933 Status
= Dhcp6SendDeclineMsg (Instance
, DecIa
);
935 if (EFI_ERROR (Status
)) {
940 // Register receive callback for the stateful exchange process.
942 Status
= UdpIoRecvDatagram(
949 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
954 gBS
->RestoreTPL (OldTpl
);
957 // Poll udp out of the net tpl if synchoronus call.
959 if (Instance
->Config
->IaInfoEvent
== NULL
) {
961 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
962 Service
->UdpIo
->Protocol
.Udp6
->Poll (Service
->UdpIo
->Protocol
.Udp6
);
964 return Instance
->UdpSts
;
974 gBS
->RestoreTPL (OldTpl
);
981 Release one or more addresses associated with the configured Ia
982 for current instance.
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.
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
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
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.
1017 IN EFI_DHCP6_PROTOCOL
*This
,
1018 IN UINT32 AddressCount
,
1019 IN EFI_IPv6_ADDRESS
*Addresses
1024 EFI_DHCP6_IA
*RelIa
;
1025 DHCP6_INSTANCE
*Instance
;
1026 DHCP6_SERVICE
*Service
;
1028 if (This
== NULL
|| (AddressCount
!= 0 && Addresses
== NULL
)) {
1029 return EFI_INVALID_PARAMETER
;
1032 Instance
= DHCP6_INSTANCE_FROM_THIS (This
);
1033 Service
= Instance
->Service
;
1036 // The instance hasn't been configured.
1038 if (Instance
->Config
== NULL
) {
1039 return EFI_ACCESS_DENIED
;
1042 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1044 if (Instance
->IaCb
.Ia
->State
!= Dhcp6Bound
) {
1045 return EFI_ACCESS_DENIED
;
1049 // Check whether all the released addresses belongs to the configured Ia.
1051 Status
= Dhcp6CheckAddress (Instance
->IaCb
.Ia
, AddressCount
, Addresses
);
1053 if (EFI_ERROR(Status
)) {
1057 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1058 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1061 // Deprive of all the released addresses from the configured Ia, and create a
1062 // ReleaseIa used to create release message.
1064 RelIa
= Dhcp6DepriveAddress (Instance
->IaCb
.Ia
, AddressCount
, Addresses
);
1066 if (RelIa
== NULL
) {
1067 Status
= EFI_OUT_OF_RESOURCES
;
1072 // Send the release message to start exchange process.
1074 Status
= Dhcp6SendReleaseMsg (Instance
, RelIa
);
1076 if (EFI_ERROR (Status
)) {
1081 // Register receive callback for the stateful exchange process.
1083 Status
= UdpIoRecvDatagram(
1090 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1095 gBS
->RestoreTPL (OldTpl
);
1098 // Poll udp out of the net tpl if synchoronus call.
1100 if (Instance
->Config
->IaInfoEvent
== NULL
) {
1101 while (Instance
->UdpSts
== EFI_ALREADY_STARTED
) {
1102 Service
->UdpIo
->Protocol
.Udp6
->Poll (Service
->UdpIo
->Protocol
.Udp6
);
1104 return Instance
->UdpSts
;
1111 if (RelIa
!= NULL
) {
1114 gBS
->RestoreTPL (OldTpl
);
1121 Parse the option data in the Dhcp6 packet.
1123 The Parse() function is used to retrieve the option list in the DHCPv6 packet.
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.
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.
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
1151 if (This
== NULL
|| Packet
== NULL
|| OptionCount
== NULL
) {
1152 return EFI_INVALID_PARAMETER
;
1155 if (*OptionCount
!= 0 && PacketOptionList
== NULL
) {
1156 return EFI_INVALID_PARAMETER
;
1159 if (Packet
->Length
> Packet
->Size
|| Packet
->Length
< sizeof (EFI_DHCP6_HEADER
)) {
1160 return EFI_INVALID_PARAMETER
;
1164 // The format of Dhcp6 option:
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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1171 // | (option-len octets) |
1172 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1176 OptLen
= Packet
->Length
- sizeof (EFI_DHCP6_HEADER
);
1177 Start
= Packet
->Dhcp6
.Option
;
1178 End
= Start
+ OptLen
;
1181 // Calculate the number of option in the packet.
1183 while (Start
< End
) {
1184 DataLen
= ((EFI_DHCP6_PACKET_OPTION
*) Start
)->OpLen
;
1185 Start
+= (NTOHS (DataLen
) + 4);
1190 // It will return buffer too small if pass-in option count is smaller than the
1191 // actual count of options in the packet.
1193 if (OptCnt
> *OptionCount
) {
1194 *OptionCount
= OptCnt
;
1195 return EFI_BUFFER_TOO_SMALL
;
1200 (*OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*))
1204 Start
= Packet
->Dhcp6
.Option
;
1206 while (Start
< End
) {
1208 PacketOptionList
[OptCnt
] = (EFI_DHCP6_PACKET_OPTION
*) Start
;
1209 DataLen
= ((EFI_DHCP6_PACKET_OPTION
*) Start
)->OpLen
;
1210 Start
+= (NTOHS (DataLen
) + 4);