2 Dhcp6 internal functions implementation.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "Dhcp6Impl.h"
15 Enqueue the packet into the retry list in case of timeout.
17 @param[in] Instance The pointer to the Dhcp6 instance.
18 @param[in] Packet The pointer to the Dhcp6 packet to retry.
19 @param[in] Elapsed The pointer to the elapsed time value in the packet.
20 @param[in] RetryCtl The pointer to the transmission control of the packet.
21 This parameter is optional and may be NULL.
23 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according
25 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
26 @retval EFI_DEVICE_ERROR An unexpected message type.
31 IN DHCP6_INSTANCE
*Instance
,
32 IN EFI_DHCP6_PACKET
*Packet
,
34 IN EFI_DHCP6_RETRANSMISSION
*RetryCtl OPTIONAL
40 ASSERT (Packet
!= NULL
);
42 IaCb
= &Instance
->IaCb
;
43 TxCb
= AllocateZeroPool (sizeof (DHCP6_TX_CB
));
46 return EFI_OUT_OF_RESOURCES
;
50 // Save tx packet pointer, and it will be destroyed when reply received.
52 TxCb
->TxPacket
= Packet
;
53 TxCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
56 // Save pointer to elapsed-time value so we can update it on retransmits.
58 TxCb
->Elapsed
= Elapsed
;
61 // Calculate the retransmission according to the the message type.
63 switch (Packet
->Dhcp6
.Header
.MessageType
) {
66 // Calculate the retransmission threshold value for solicit packet.
67 // Use the default value by rfc-3315 if user doesn't configure.
69 if (RetryCtl
== NULL
) {
70 TxCb
->RetryCtl
.Irt
= DHCP6_SOL_IRT
;
71 TxCb
->RetryCtl
.Mrc
= DHCP6_SOL_MRC
;
72 TxCb
->RetryCtl
.Mrt
= DHCP6_SOL_MRT
;
73 TxCb
->RetryCtl
.Mrd
= DHCP6_SOL_MRD
;
75 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_SOL_IRT
;
76 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_SOL_MRC
;
77 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_SOL_MRT
;
78 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_SOL_MRD
;
81 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
90 // Calculate the retransmission threshold value for request packet.
92 TxCb
->RetryCtl
.Irt
= DHCP6_REQ_IRT
;
93 TxCb
->RetryCtl
.Mrc
= DHCP6_REQ_MRC
;
94 TxCb
->RetryCtl
.Mrt
= DHCP6_REQ_MRT
;
95 TxCb
->RetryCtl
.Mrd
= DHCP6_REQ_MRD
;
96 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
103 case Dhcp6MsgConfirm
:
105 // Calculate the retransmission threshold value for confirm packet.
107 TxCb
->RetryCtl
.Irt
= DHCP6_CNF_IRT
;
108 TxCb
->RetryCtl
.Mrc
= DHCP6_CNF_MRC
;
109 TxCb
->RetryCtl
.Mrt
= DHCP6_CNF_MRT
;
110 TxCb
->RetryCtl
.Mrd
= DHCP6_CNF_MRD
;
111 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
120 // Calculate the retransmission threshold value for renew packet.
122 TxCb
->RetryCtl
.Irt
= DHCP6_REB_IRT
;
123 TxCb
->RetryCtl
.Mrc
= DHCP6_REB_MRC
;
124 TxCb
->RetryCtl
.Mrt
= DHCP6_REB_MRT
;
125 TxCb
->RetryCtl
.Mrd
= IaCb
->T2
- IaCb
->T1
;
126 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
135 // Calculate the retransmission threshold value for rebind packet.
137 TxCb
->RetryCtl
.Irt
= DHCP6_REN_IRT
;
138 TxCb
->RetryCtl
.Mrc
= DHCP6_REN_MRC
;
139 TxCb
->RetryCtl
.Mrt
= DHCP6_REN_MRT
;
140 TxCb
->RetryCtl
.Mrd
= IaCb
->AllExpireTime
- IaCb
->T2
;
141 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
148 case Dhcp6MsgDecline
:
150 // Calculate the retransmission threshold value for decline packet.
152 TxCb
->RetryCtl
.Irt
= DHCP6_DEC_IRT
;
153 TxCb
->RetryCtl
.Mrc
= DHCP6_DEC_MRC
;
154 TxCb
->RetryCtl
.Mrt
= DHCP6_DEC_MRT
;
155 TxCb
->RetryCtl
.Mrd
= DHCP6_DEC_MRD
;
156 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
163 case Dhcp6MsgRelease
:
165 // Calculate the retransmission threshold value for release packet.
167 TxCb
->RetryCtl
.Irt
= DHCP6_REL_IRT
;
168 TxCb
->RetryCtl
.Mrc
= DHCP6_REL_MRC
;
169 TxCb
->RetryCtl
.Mrt
= DHCP6_REL_MRT
;
170 TxCb
->RetryCtl
.Mrd
= DHCP6_REL_MRD
;
171 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
178 case Dhcp6MsgInfoRequest
:
180 // Calculate the retransmission threshold value for info-request packet.
181 // Use the default value by rfc-3315 if user doesn't configure.
183 if (RetryCtl
== NULL
) {
184 TxCb
->RetryCtl
.Irt
= DHCP6_INF_IRT
;
185 TxCb
->RetryCtl
.Mrc
= DHCP6_INF_MRC
;
186 TxCb
->RetryCtl
.Mrt
= DHCP6_INF_MRT
;
187 TxCb
->RetryCtl
.Mrd
= DHCP6_INF_MRD
;
189 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_INF_IRT
;
190 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_INF_MRC
;
191 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_INF_MRT
;
192 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_INF_MRD
;
195 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
204 // Unexpected message type.
206 return EFI_DEVICE_ERROR
;
210 // Insert into the retransmit list of the instance.
212 InsertTailList (&Instance
->TxList
, &TxCb
->Link
);
219 Dequeue the packet from retry list if reply received or timeout at last.
221 @param[in] Instance The pointer to the Dhcp6 instance.
222 @param[in] PacketXid The packet transaction id to match.
223 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
224 Otherwise, this parameter is ignored.
226 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
227 @retval EFI_NOT_FOUND There is no xid matched in retry list.
232 IN DHCP6_INSTANCE
*Instance
,
234 IN BOOLEAN NeedSignal
238 LIST_ENTRY
*NextEntry
;
243 // Seek the retransmit node in the retransmit list by packet xid.
245 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
247 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
248 ASSERT(TxCb
->TxPacket
);
250 if (TxCb
->Xid
== PacketXid
) {
252 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
255 // Seek the info-request node in the info-request list by packet xid.
257 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
259 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
261 if (InfCb
->Xid
== PacketXid
) {
263 // Remove the info-request node, and signal the event if timeout.
265 if (InfCb
->TimeoutEvent
!= NULL
&& NeedSignal
) {
266 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
269 RemoveEntryList (&InfCb
->Link
);
275 // Remove the retransmit node.
277 RemoveEntryList (&TxCb
->Link
);
278 ASSERT(TxCb
->TxPacket
);
279 FreePool (TxCb
->TxPacket
);
285 return EFI_NOT_FOUND
;
290 Clean up the specific nodes in the retry list.
292 @param[in] Instance The pointer to the Dhcp6 instance.
293 @param[in] Scope The scope of cleanup nodes.
298 IN DHCP6_INSTANCE
*Instance
,
303 LIST_ENTRY
*NextEntry
;
308 // Clean up all the stateful messages from the retransmit list.
310 if (Scope
== DHCP6_PACKET_STATEFUL
|| Scope
== DHCP6_PACKET_ALL
) {
312 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
314 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
315 ASSERT(TxCb
->TxPacket
);
317 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgInfoRequest
) {
318 RemoveEntryList (&TxCb
->Link
);
319 FreePool (TxCb
->TxPacket
);
326 // Clean up all the stateless messages from the retransmit list.
328 if (Scope
== DHCP6_PACKET_STATELESS
|| Scope
== DHCP6_PACKET_ALL
) {
331 // Clean up all the retransmit list for stateless messages.
333 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
335 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
336 ASSERT(TxCb
->TxPacket
);
338 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
339 RemoveEntryList (&TxCb
->Link
);
340 FreePool (TxCb
->TxPacket
);
346 // Clean up all the info-request messages list.
348 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
350 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
352 if (InfCb
->TimeoutEvent
!= NULL
) {
353 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
355 RemoveEntryList (&InfCb
->Link
);
362 Check whether the TxCb is still a valid control block in the instance's retry list.
364 @param[in] Instance The pointer to DHCP6_INSTANCE.
365 @param[in] TxCb The control block for a transmitted message.
367 @retval TRUE The control block is in Instance's retry list.
368 @retval FALSE The control block is NOT in Instance's retry list.
373 IN DHCP6_INSTANCE
*Instance
,
379 NET_LIST_FOR_EACH (Entry
, &Instance
->TxList
) {
380 if (TxCb
== NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
)) {
389 Clean up the session of the instance stateful exchange.
391 @param[in, out] Instance The pointer to the Dhcp6 instance.
392 @param[in] Status The return status from udp.
396 Dhcp6CleanupSession (
397 IN OUT DHCP6_INSTANCE
*Instance
,
404 ASSERT(Instance
->Config
);
405 ASSERT(Instance
->IaCb
.Ia
);
408 // Clean up the retransmit list for stateful messages.
410 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
412 if (Instance
->Unicast
!= NULL
) {
413 FreePool (Instance
->Unicast
);
416 if (Instance
->AdSelect
!= NULL
) {
417 FreePool (Instance
->AdSelect
);
420 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
421 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
425 // Reinitialize the Ia fields of the instance.
427 Instance
->UdpSts
= Status
;
428 Instance
->AdSelect
= NULL
;
429 Instance
->AdPref
= 0;
430 Instance
->Unicast
= NULL
;
431 Instance
->IaCb
.T1
= 0;
432 Instance
->IaCb
.T2
= 0;
433 Instance
->IaCb
.AllExpireTime
= 0;
434 Instance
->IaCb
.LeaseTime
= 0;
439 Instance
->StartTime
= 0;
441 Ia
= Instance
->IaCb
.Ia
;
442 Ia
->State
= Dhcp6Init
;
443 Ia
->ReplyPacket
= NULL
;
446 // Set the addresses as zero lifetime, and then the notify
447 // function in Ip6Config will remove these timeout address.
449 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
450 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
451 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
456 // Signal the Ia information updated event to informal user.
458 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
459 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
465 Callback to user when Dhcp6 transmit/receive occurs.
467 @param[in] Instance The pointer to the Dhcp6 instance.
468 @param[in] Event The current Dhcp6 event.
469 @param[in, out] Packet The pointer to the packet sending or received.
471 @retval EFI_SUCCESS The user function returns success.
472 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
473 @retval EFI_ABORTED The user function ask it to abort.
479 IN DHCP6_INSTANCE
*Instance
,
480 IN EFI_DHCP6_EVENT Event
,
481 IN OUT EFI_DHCP6_PACKET
**Packet
485 EFI_DHCP6_PACKET
*NewPacket
;
486 EFI_DHCP6_CALLBACK Callback
;
489 ASSERT (Packet
!= NULL
);
490 ASSERT (Instance
->Config
!= NULL
);
491 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
494 Status
= EFI_SUCCESS
;
495 Callback
= Instance
->Config
->Dhcp6Callback
;
496 Context
= Instance
->Config
->CallbackContext
;
499 // Callback to user with the new message if has.
501 if (Callback
!= NULL
) {
506 Instance
->IaCb
.Ia
->State
,
512 // Updated the new packet from user to replace the original one.
514 if (NewPacket
!= NULL
) {
515 ASSERT (*Packet
!= NULL
);
526 Update Ia according to the new reply message.
528 @param[in, out] Instance The pointer to the Dhcp6 instance.
529 @param[in] Packet The pointer to reply messages.
531 @retval EFI_SUCCESS Updated the Ia information successfully.
532 @retval EFI_DEVICE_ERROR An unexpected error.
537 IN OUT DHCP6_INSTANCE
*Instance
,
538 IN EFI_DHCP6_PACKET
*Packet
549 ASSERT (Instance
->Config
!= NULL
);
551 // If the reply was received in reponse to a solicit with rapid commit option,
552 // request, renew or rebind message, the client updates the information it has
553 // recorded about IAs from the IA options contained in the reply message:
554 // 1. record the T1 and T2 times
555 // 2. add any new addresses in the IA
556 // 3. discard any addresses from the IA, that have a valid lifetime of 0
557 // 4. update lifetimes for any addresses that alread recorded
558 // 5. leave unchanged any information about addresses
560 // See details in the section-18.1.8 of rfc-3315.
562 Option
= Dhcp6SeekIaOption (
563 Packet
->Dhcp6
.Option
,
564 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
565 &Instance
->Config
->IaDescriptor
567 if (Option
== NULL
) {
568 return EFI_DEVICE_ERROR
;
572 // The format of the IA_NA option is:
575 // 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
576 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577 // | OPTION_IA_NA | option-len |
578 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
579 // | IAID (4 octets) |
580 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
582 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590 // The format of the IA_TA option is:
593 // 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
594 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595 // | OPTION_IA_TA | option-len |
596 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
597 // | IAID (4 octets) |
598 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
602 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
606 // sizeof (option-code + option-len + IaId) = 8
607 // sizeof (option-code + option-len + IaId + T1) = 12
608 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
610 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
612 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
613 T1
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 8)));
614 T2
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 12)));
616 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
617 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
618 // the remainder of the message as though the server had not included the invalid IA_NA option.
620 if (T1
> T2
&& T2
> 0) {
621 return EFI_DEVICE_ERROR
;
623 IaInnerOpt
= Option
+ 16;
624 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
628 IaInnerOpt
= Option
+ 8;
629 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
633 // The format of the Status Code option is:
636 // 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
637 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
638 // | OPTION_STATUS_CODE | option-len |
639 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
641 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
643 // . status-message .
645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
649 // sizeof (option-code + option-len) = 4
651 StsCode
= Dhcp6StsSuccess
;
652 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
654 if (Option
!= NULL
) {
655 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
656 if (StsCode
!= Dhcp6StsSuccess
) {
657 return EFI_DEVICE_ERROR
;
662 // Generate control block for the Ia.
664 Status
= Dhcp6GenerateIaCb (
678 Seek StatusCode Option in package. A Status Code option may appear in the
679 options field of a DHCP message and/or in the options field of another option.
680 See details in section 22.13, RFC3315.
682 @param[in] Instance The pointer to the Dhcp6 instance.
683 @param[in] Packet The pointer to reply messages.
684 @param[out] Option The pointer to status code option.
686 @retval EFI_SUCCESS Seek status code option successfully.
687 @retval EFI_DEVICE_ERROR An unexpected error.
692 IN DHCP6_INSTANCE
*Instance
,
693 IN EFI_DHCP6_PACKET
*Packet
,
702 // Seek StatusCode option directly in DHCP message body. That is, search in
703 // non-encapsulated option fields.
705 *Option
= Dhcp6SeekOption (
706 Packet
->Dhcp6
.Option
,
711 if (*Option
!= NULL
) {
712 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
713 if (StsCode
!= Dhcp6StsSuccess
) {
714 return EFI_DEVICE_ERROR
;
719 // Seek in encapsulated options, IA_NA and IA_TA.
721 *Option
= Dhcp6SeekIaOption (
722 Packet
->Dhcp6
.Option
,
723 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
724 &Instance
->Config
->IaDescriptor
726 if (*Option
== NULL
) {
731 // The format of the IA_NA option is:
734 // 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
735 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
736 // | OPTION_IA_NA | option-len |
737 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
738 // | IAID (4 octets) |
739 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
741 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
747 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749 // The format of the IA_TA option is:
752 // 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
753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
754 // | OPTION_IA_TA | option-len |
755 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
756 // | IAID (4 octets) |
757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
765 // sizeof (option-code + option-len + IaId) = 8
766 // sizeof (option-code + option-len + IaId + T1) = 12
767 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
769 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
771 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
772 IaInnerOpt
= *Option
+ 16;
773 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
775 IaInnerOpt
= *Option
+ 8;
776 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
780 // The format of the Status Code option is:
783 // 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
784 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
785 // | OPTION_STATUS_CODE | option-len |
786 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
788 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
790 // . status-message .
792 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
796 // sizeof (option-code + option-len) = 4
798 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
799 if (*Option
!= NULL
) {
800 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
801 if (StsCode
!= Dhcp6StsSuccess
) {
802 return EFI_DEVICE_ERROR
;
811 Transmit Dhcp6 message by udpio.
813 @param[in] Instance The pointer to the Dhcp6 instance.
814 @param[in] Packet The pointer to transmit message.
815 @param[in] Elapsed The pointer to the elapsed time value to fill in.
817 @retval EFI_SUCCESS Successfully transmitted the packet.
818 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
819 @retval Others Failed to transmit the packet.
823 Dhcp6TransmitPacket (
824 IN DHCP6_INSTANCE
*Instance
,
825 IN EFI_DHCP6_PACKET
*Packet
,
833 DHCP6_SERVICE
*Service
;
835 Service
= Instance
->Service
;
838 // Wrap it into a netbuf then send it.
840 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
841 Frag
.Len
= Packet
->Length
;
844 // Do not register free packet here, which will be handled in retry list.
846 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
849 return EFI_OUT_OF_RESOURCES
;
853 // Multicast the Dhcp6 message, unless get the unicast server address by option.
855 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
857 if (Instance
->Unicast
!= NULL
) {
861 sizeof (EFI_IPv6_ADDRESS
)
866 &mAllDhcpRelayAndServersAddress
,
867 sizeof (EFI_IPv6_ADDRESS
)
871 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
872 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
875 // Update the elapsed time value.
877 if (Elapsed
!= NULL
) {
878 SetElapsedTime (Elapsed
, Instance
);
882 // Send out the message by the configured Udp6Io.
884 Status
= UdpIoSendDatagram (
893 if (EFI_ERROR (Status
)) {
903 Create the solicit message and send it.
905 @param[in] Instance The pointer to the Dhcp6 instance.
907 @retval EFI_SUCCESS Created and sent the solicit message successfully.
908 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
909 @retval Others Failed to send the solicit message.
913 Dhcp6SendSolicitMsg (
914 IN DHCP6_INSTANCE
*Instance
918 EFI_DHCP6_PACKET
*Packet
;
919 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
920 EFI_DHCP6_DUID
*ClientId
;
921 DHCP6_SERVICE
*Service
;
928 Service
= Instance
->Service
;
929 ClientId
= Service
->ClientId
;
932 ASSERT (Service
->ClientId
!= NULL
);
933 ASSERT (Instance
->Config
!= NULL
);
934 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
937 // Calculate the added length of customized option list.
939 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
940 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
944 // Create the Dhcp6 packet and initialize commone fields.
946 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
947 if (Packet
== NULL
) {
948 return EFI_OUT_OF_RESOURCES
;
951 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
952 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
953 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
954 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
957 // Assembly Dhcp6 options for solicit message.
959 Cursor
= Packet
->Dhcp6
.Option
;
961 Length
= HTONS (ClientId
->Length
);
962 Cursor
= Dhcp6AppendOption (
964 HTONS (Dhcp6OptClientId
),
969 Cursor
= Dhcp6AppendETOption (
975 Cursor
= Dhcp6AppendIaOption (
980 Packet
->Dhcp6
.Header
.MessageType
984 // Append user-defined when configurate Dhcp6 service.
986 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
988 UserOpt
= Instance
->Config
->OptionList
[Index
];
989 Cursor
= Dhcp6AppendOption(
998 // Determine the size/length of packet.
1000 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1001 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1004 // Callback to user with the packet to be sent and check the user's feedback.
1006 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
1008 if (EFI_ERROR (Status
)) {
1014 // Send solicit packet with the state transition from Dhcp6init to
1017 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1019 // Clear initial time for current transaction.
1021 Instance
->StartTime
= 0;
1023 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1025 if (EFI_ERROR (Status
)) {
1031 // Enqueue the sent packet for the retransmission in case reply timeout.
1033 return Dhcp6EnqueueRetry (
1037 Instance
->Config
->SolicitRetransmission
1042 Configure some parameter to initiate SolicitMsg.
1044 @param[in] Instance The pointer to the Dhcp6 instance.
1046 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1047 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1048 @retval Others Failed to send the solicit message.
1052 Dhcp6InitSolicitMsg (
1053 IN DHCP6_INSTANCE
*Instance
1056 Instance
->IaCb
.T1
= 0;
1057 Instance
->IaCb
.T2
= 0;
1058 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1060 return Dhcp6SendSolicitMsg (Instance
);
1065 Create the request message and send it.
1067 @param[in] Instance The pointer to the Dhcp6 instance.
1069 @retval EFI_SUCCESS Created and sent the request message successfully.
1070 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1071 @retval EFI_DEVICE_ERROR An unexpected error.
1072 @retval Others Failed to send the request message.
1076 Dhcp6SendRequestMsg (
1077 IN DHCP6_INSTANCE
*Instance
1081 EFI_DHCP6_PACKET
*Packet
;
1082 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1083 EFI_DHCP6_DUID
*ClientId
;
1084 EFI_DHCP6_DUID
*ServerId
;
1085 DHCP6_SERVICE
*Service
;
1093 ASSERT(Instance
->AdSelect
!= NULL
);
1094 ASSERT(Instance
->Config
!= NULL
);
1095 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1096 ASSERT(Instance
->Service
!= NULL
);
1098 Service
= Instance
->Service
;
1099 ClientId
= Service
->ClientId
;
1101 ASSERT(ClientId
!= NULL
);
1104 // Get the server Id from the selected advertisement message.
1106 Option
= Dhcp6SeekOption (
1107 Instance
->AdSelect
->Dhcp6
.Option
,
1108 Instance
->AdSelect
->Length
- 4,
1111 if (Option
== NULL
) {
1112 return EFI_DEVICE_ERROR
;
1115 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1118 // Calculate the added length of customized option list.
1121 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1122 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1126 // Create the Dhcp6 packet and initialize commone fields.
1128 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1129 if (Packet
== NULL
) {
1130 return EFI_OUT_OF_RESOURCES
;
1133 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1134 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1135 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1136 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1139 // Assembly Dhcp6 options for request message.
1141 Cursor
= Packet
->Dhcp6
.Option
;
1143 Length
= HTONS (ClientId
->Length
);
1144 Cursor
= Dhcp6AppendOption (
1146 HTONS (Dhcp6OptClientId
),
1151 Cursor
= Dhcp6AppendETOption (
1157 Cursor
= Dhcp6AppendOption (
1159 HTONS (Dhcp6OptServerId
),
1164 Cursor
= Dhcp6AppendIaOption (
1169 Packet
->Dhcp6
.Header
.MessageType
1173 // Append user-defined when configurate Dhcp6 service.
1175 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1177 UserOpt
= Instance
->Config
->OptionList
[Index
];
1178 Cursor
= Dhcp6AppendOption(
1187 // Determine the size/length of packet.
1189 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1190 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1193 // Callback to user with the packet to be sent and check the user's feedback.
1195 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1197 if (EFI_ERROR (Status
)) {
1203 // Send request packet with the state transition from Dhcp6selecting to
1206 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1208 // Clear initial time for current transaction.
1210 Instance
->StartTime
= 0;
1212 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1214 if (EFI_ERROR (Status
)) {
1220 // Enqueue the sent packet for the retransmission in case reply timeout.
1222 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1227 Create the decline message and send it.
1229 @param[in] Instance The pointer to the Dhcp6 instance.
1230 @param[in] DecIa The pointer to the decline Ia.
1232 @retval EFI_SUCCESS Created and sent the decline message successfully.
1233 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1234 @retval EFI_DEVICE_ERROR An unexpected error.
1235 @retval Others Failed to send the decline message.
1239 Dhcp6SendDeclineMsg (
1240 IN DHCP6_INSTANCE
*Instance
,
1241 IN EFI_DHCP6_IA
*DecIa
1245 EFI_DHCP6_PACKET
*Packet
;
1246 EFI_DHCP6_PACKET
*LastReply
;
1247 EFI_DHCP6_DUID
*ClientId
;
1248 EFI_DHCP6_DUID
*ServerId
;
1249 DHCP6_SERVICE
*Service
;
1255 ASSERT (Instance
->Config
!= NULL
);
1256 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1257 ASSERT (Instance
->Service
!= NULL
);
1259 Service
= Instance
->Service
;
1260 ClientId
= Service
->ClientId
;
1261 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1263 ASSERT (ClientId
!= NULL
);
1264 ASSERT (LastReply
!= NULL
);
1267 // Get the server Id from the last reply message.
1269 Option
= Dhcp6SeekOption (
1270 LastReply
->Dhcp6
.Option
,
1271 LastReply
->Length
- 4,
1274 if (Option
== NULL
) {
1275 return EFI_DEVICE_ERROR
;
1279 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1281 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1284 // Create the Dhcp6 packet and initialize commone fields.
1286 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1287 if (Packet
== NULL
) {
1288 return EFI_OUT_OF_RESOURCES
;
1291 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1292 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1293 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1294 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1297 // Assembly Dhcp6 options for rebind/renew message.
1299 Cursor
= Packet
->Dhcp6
.Option
;
1301 Length
= HTONS (ClientId
->Length
);
1302 Cursor
= Dhcp6AppendOption (
1304 HTONS (Dhcp6OptClientId
),
1309 Cursor
= Dhcp6AppendETOption (
1315 Cursor
= Dhcp6AppendOption (
1317 HTONS (Dhcp6OptServerId
),
1322 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1325 // Determine the size/length of packet.
1327 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1328 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1331 // Callback to user with the packet to be sent and check the user's feedback.
1333 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1335 if (EFI_ERROR (Status
)) {
1341 // Send decline packet with the state transition from Dhcp6bound to
1344 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1346 // Clear initial time for current transaction.
1348 Instance
->StartTime
= 0;
1350 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1352 if (EFI_ERROR (Status
)) {
1358 // Enqueue the sent packet for the retransmission in case reply timeout.
1360 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1365 Create the release message and send it.
1367 @param[in] Instance The pointer to the Dhcp6 instance.
1368 @param[in] RelIa The pointer to the release Ia.
1370 @retval EFI_SUCCESS Created and sent the release message successfully.
1371 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1372 @retval EFI_DEVICE_ERROR An unexpected error.
1373 @retval Others Failed to send the release message.
1377 Dhcp6SendReleaseMsg (
1378 IN DHCP6_INSTANCE
*Instance
,
1379 IN EFI_DHCP6_IA
*RelIa
1383 EFI_DHCP6_PACKET
*Packet
;
1384 EFI_DHCP6_PACKET
*LastReply
;
1385 EFI_DHCP6_DUID
*ClientId
;
1386 EFI_DHCP6_DUID
*ServerId
;
1387 DHCP6_SERVICE
*Service
;
1393 ASSERT(Instance
->Config
);
1394 ASSERT(Instance
->IaCb
.Ia
);
1396 Service
= Instance
->Service
;
1397 ClientId
= Service
->ClientId
;
1398 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1404 // Get the server Id from the last reply message.
1406 Option
= Dhcp6SeekOption (
1407 LastReply
->Dhcp6
.Option
,
1408 LastReply
->Length
- 4,
1411 if (Option
== NULL
) {
1412 return EFI_DEVICE_ERROR
;
1415 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1418 // Create the Dhcp6 packet and initialize commone fields.
1420 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1421 if (Packet
== NULL
) {
1422 return EFI_OUT_OF_RESOURCES
;
1425 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1426 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1427 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1428 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1431 // Assembly Dhcp6 options for rebind/renew message
1433 Cursor
= Packet
->Dhcp6
.Option
;
1435 Length
= HTONS (ClientId
->Length
);
1436 Cursor
= Dhcp6AppendOption (
1438 HTONS (Dhcp6OptClientId
),
1444 // ServerId is extracted from packet, it's network order.
1446 Cursor
= Dhcp6AppendOption (
1448 HTONS (Dhcp6OptServerId
),
1453 Cursor
= Dhcp6AppendETOption (
1459 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1462 // Determine the size/length of packet
1464 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1465 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1468 // Callback to user with the packet to be sent and check the user's feedback.
1470 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1472 if (EFI_ERROR (Status
)) {
1478 // Send release packet with the state transition from Dhcp6bound to
1481 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1483 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1485 if (EFI_ERROR (Status
)) {
1491 // Enqueue the sent packet for the retransmission in case reply timeout.
1493 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1498 Create the renew/rebind message and send it.
1500 @param[in] Instance The pointer to the Dhcp6 instance.
1501 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1502 Otherwise, it is a Renew type message.
1504 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1505 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1506 @retval EFI_DEVICE_ERROR An unexpected error.
1507 @retval Others Failed to send the renew/rebind message.
1511 Dhcp6SendRenewRebindMsg (
1512 IN DHCP6_INSTANCE
*Instance
,
1513 IN BOOLEAN RebindRequest
1517 EFI_DHCP6_PACKET
*Packet
;
1518 EFI_DHCP6_PACKET
*LastReply
;
1519 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1520 EFI_DHCP6_DUID
*ClientId
;
1521 EFI_DHCP6_DUID
*ServerId
;
1522 EFI_DHCP6_STATE State
;
1523 EFI_DHCP6_EVENT Event
;
1524 DHCP6_SERVICE
*Service
;
1532 ASSERT(Instance
->Config
);
1533 ASSERT(Instance
->IaCb
.Ia
);
1535 Service
= Instance
->Service
;
1536 ClientId
= Service
->ClientId
;
1541 // Calculate the added length of customized option list.
1544 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1545 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1549 // Create the Dhcp6 packet and initialize commone fields.
1551 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1552 if (Packet
== NULL
) {
1553 return EFI_OUT_OF_RESOURCES
;
1556 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1557 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1558 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1559 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1562 // Assembly Dhcp6 options for rebind/renew message.
1564 Cursor
= Packet
->Dhcp6
.Option
;
1566 Length
= HTONS (ClientId
->Length
);
1567 Cursor
= Dhcp6AppendOption (
1569 HTONS (Dhcp6OptClientId
),
1574 Cursor
= Dhcp6AppendETOption (
1580 Cursor
= Dhcp6AppendIaOption (
1585 Packet
->Dhcp6
.Header
.MessageType
1588 if (!RebindRequest
) {
1590 // Get the server Id from the last reply message and
1591 // insert it for rebind request.
1593 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1596 Option
= Dhcp6SeekOption (
1597 LastReply
->Dhcp6
.Option
,
1598 LastReply
->Length
- 4,
1601 if (Option
== NULL
) {
1603 return EFI_DEVICE_ERROR
;
1606 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1608 Cursor
= Dhcp6AppendOption (
1610 HTONS (Dhcp6OptServerId
),
1617 // Append user-defined when configurate Dhcp6 service.
1619 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1621 UserOpt
= Instance
->Config
->OptionList
[Index
];
1622 Cursor
= Dhcp6AppendOption(
1631 // Determine the size/length of packet.
1633 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1634 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1637 // Callback to user with the packet to be sent and check the user's feedback.
1639 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1640 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1642 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1644 if (EFI_ERROR (Status
)) {
1650 // Send renew/rebind packet with the state transition from Dhcp6bound to
1651 // Dhcp6renew/rebind.
1652 // And sync the lease time when send renew/rebind, in case that user send
1653 // renew/rebind actively.
1655 Instance
->IaCb
.Ia
->State
= State
;
1656 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1658 // Clear initial time for current transaction.
1660 Instance
->StartTime
= 0;
1662 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1664 if (EFI_ERROR (Status
)) {
1670 // Enqueue the sent packet for the retransmission in case reply timeout.
1672 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1676 Start the information request process.
1678 @param[in] Instance The pointer to the Dhcp6 instance.
1679 @param[in] SendClientId If TRUE, the client identifier option will be included in
1680 information request message. Otherwise, the client identifier
1681 option will not be included.
1682 @param[in] OptionRequest The pointer to the option request option.
1683 @param[in] OptionCount The number options in the OptionList.
1684 @param[in] OptionList The array pointers to the appended options.
1685 @param[in] Retransmission The pointer to the retransmission control.
1686 @param[in] TimeoutEvent The event of timeout.
1687 @param[in] ReplyCallback The callback function when the reply was received.
1688 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1690 @retval EFI_SUCCESS Start the info-request process successfully.
1691 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1692 @retval EFI_NO_MAPPING No source address is available for use.
1693 @retval Others Failed to start the info-request process.
1697 Dhcp6StartInfoRequest (
1698 IN DHCP6_INSTANCE
*Instance
,
1699 IN BOOLEAN SendClientId
,
1700 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1701 IN UINT32 OptionCount
,
1702 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1703 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1704 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1705 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1706 IN VOID
*CallbackContext OPTIONAL
1710 DHCP6_INF_CB
*InfCb
;
1711 DHCP6_SERVICE
*Service
;
1714 Service
= Instance
->Service
;
1716 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1717 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1719 // Create and initialize the control block for the info-request.
1721 InfCb
= AllocateZeroPool (sizeof(DHCP6_INF_CB
));
1723 if (InfCb
== NULL
) {
1724 gBS
->RestoreTPL (OldTpl
);
1725 return EFI_OUT_OF_RESOURCES
;
1728 InfCb
->ReplyCallback
= ReplyCallback
;
1729 InfCb
->CallbackContext
= CallbackContext
;
1730 InfCb
->TimeoutEvent
= TimeoutEvent
;
1732 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1735 // Send the info-request message to start exchange process.
1737 Status
= Dhcp6SendInfoRequestMsg (
1747 if (EFI_ERROR (Status
)) {
1752 // Register receive callback for the stateless exchange process.
1754 Status
= UdpIoRecvDatagram(
1761 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1765 gBS
->RestoreTPL (OldTpl
);
1769 gBS
->RestoreTPL (OldTpl
);
1770 RemoveEntryList (&InfCb
->Link
);
1777 Create the information request message and send it.
1779 @param[in] Instance The pointer to the Dhcp6 instance.
1780 @param[in] InfCb The pointer to the information request control block.
1781 @param[in] SendClientId If TRUE, the client identifier option will be included in
1782 information request message. Otherwise, the client identifier
1783 option will not be included.
1784 @param[in] OptionRequest The pointer to the option request option.
1785 @param[in] OptionCount The number options in the OptionList.
1786 @param[in] OptionList The array pointers to the appended options.
1787 @param[in] Retransmission The pointer to the retransmission control.
1789 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1790 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1791 @retval Others Failed to send the info-request message.
1795 Dhcp6SendInfoRequestMsg (
1796 IN DHCP6_INSTANCE
*Instance
,
1797 IN DHCP6_INF_CB
*InfCb
,
1798 IN BOOLEAN SendClientId
,
1799 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1800 IN UINT32 OptionCount
,
1801 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1802 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1806 EFI_DHCP6_PACKET
*Packet
;
1807 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1808 EFI_DHCP6_DUID
*ClientId
;
1809 DHCP6_SERVICE
*Service
;
1816 ASSERT(OptionRequest
);
1818 Service
= Instance
->Service
;
1819 ClientId
= Service
->ClientId
;
1820 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1825 // Calculate the added length of customized option list.
1827 for (Index
= 0; Index
< OptionCount
; Index
++) {
1828 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1832 // Create the Dhcp6 packet and initialize commone fields.
1834 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1835 if (Packet
== NULL
) {
1836 return EFI_OUT_OF_RESOURCES
;
1839 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1840 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1841 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1842 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1844 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1847 // Assembly Dhcp6 options for info-request message.
1849 Cursor
= Packet
->Dhcp6
.Option
;
1852 Length
= HTONS (ClientId
->Length
);
1853 Cursor
= Dhcp6AppendOption (
1855 HTONS (Dhcp6OptClientId
),
1861 Cursor
= Dhcp6AppendETOption (
1867 Cursor
= Dhcp6AppendOption (
1869 OptionRequest
->OpCode
,
1870 OptionRequest
->OpLen
,
1875 // Append user-defined when configurate Dhcp6 service.
1877 for (Index
= 0; Index
< OptionCount
; Index
++) {
1879 UserOpt
= OptionList
[Index
];
1880 Cursor
= Dhcp6AppendOption(
1889 // Determine the size/length of packet.
1891 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1892 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1895 // Clear initial time for current transaction.
1897 Instance
->StartTime
= 0;
1900 // Send info-request packet with no state.
1902 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1904 if (EFI_ERROR (Status
)) {
1910 // Enqueue the sent packet for the retransmission in case reply timeout.
1912 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1917 Create the Confirm message and send it.
1919 @param[in] Instance The pointer to the Dhcp6 instance.
1921 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1922 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1923 @retval EFI_DEVICE_ERROR An unexpected error.
1924 @retval Others Failed to send the confirm message.
1928 Dhcp6SendConfirmMsg (
1929 IN DHCP6_INSTANCE
*Instance
1937 DHCP6_SERVICE
*Service
;
1938 EFI_DHCP6_DUID
*ClientId
;
1939 EFI_DHCP6_PACKET
*Packet
;
1940 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1943 ASSERT (Instance
->Config
!= NULL
);
1944 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1945 ASSERT (Instance
->Service
!= NULL
);
1947 Service
= Instance
->Service
;
1948 ClientId
= Service
->ClientId
;
1949 ASSERT (ClientId
!= NULL
);
1952 // Calculate the added length of customized option list.
1955 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1956 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1960 // Create the Dhcp6 packet and initialize common fields.
1962 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1963 if (Packet
== NULL
) {
1964 return EFI_OUT_OF_RESOURCES
;
1967 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1968 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1969 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1970 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1973 // Assembly Dhcp6 options for solicit message.
1975 Cursor
= Packet
->Dhcp6
.Option
;
1977 Length
= HTONS (ClientId
->Length
);
1978 Cursor
= Dhcp6AppendOption (
1980 HTONS (Dhcp6OptClientId
),
1985 Cursor
= Dhcp6AppendETOption (
1991 Cursor
= Dhcp6AppendIaOption (
1996 Packet
->Dhcp6
.Header
.MessageType
2000 // Append user-defined when configurate Dhcp6 service.
2002 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
2003 UserOpt
= Instance
->Config
->OptionList
[Index
];
2004 Cursor
= Dhcp6AppendOption (
2013 // Determine the size/length of packet.
2015 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
2016 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
2019 // Callback to user with the packet to be sent and check the user's feedback.
2021 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
2023 if (EFI_ERROR (Status
)) {
2029 // Send confirm packet with the state transition from Dhcp6Bound to
2032 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2034 // Clear initial time for current transaction.
2036 Instance
->StartTime
= 0;
2038 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2040 if (EFI_ERROR (Status
)) {
2046 // Enqueue the sent packet for the retransmission in case reply timeout.
2048 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2054 Handle with the Dhcp6 reply message.
2056 @param[in] Instance The pointer to Dhcp6 instance.
2057 @param[in] Packet The pointer to the Dhcp6 reply message.
2059 @retval EFI_SUCCESS Processed the reply message successfully.
2060 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2061 @retval EFI_DEVICE_ERROR An unexpected error.
2062 @retval Others Failed to process the reply message.
2066 Dhcp6HandleReplyMsg (
2067 IN DHCP6_INSTANCE
*Instance
,
2068 IN EFI_DHCP6_PACKET
*Packet
2075 ASSERT (Instance
->Config
!= NULL
);
2076 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2077 ASSERT (Packet
!= NULL
);
2079 Status
= EFI_SUCCESS
;
2081 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2082 return EFI_DEVICE_ERROR
;
2086 // If the client subsequently receives a valid reply message that includes a
2087 // rapid commit option since send a solicit with rapid commit option before,
2088 // preocess the reply message and discard any reply messages received in
2089 // response to the request message.
2090 // See details in the section-17.1.4 of rfc-3315.
2092 Option
= Dhcp6SeekOption (
2093 Packet
->Dhcp6
.Option
,
2098 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
2099 return EFI_DEVICE_ERROR
;
2103 // As to a valid reply packet in response to a request/renew/rebind packet,
2104 // ignore the packet if not contains the Ia option
2106 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
2107 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
2108 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
2111 Option
= Dhcp6SeekIaOption (
2112 Packet
->Dhcp6
.Option
,
2114 &Instance
->Config
->IaDescriptor
2116 if (Option
== NULL
) {
2122 // Callback to user with the received packet and check the user's feedback.
2124 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2126 if (EFI_ERROR (Status
)) {
2131 // When receive a valid reply packet in response to a decline/release packet,
2132 // the client considers the decline/release event completed regardless of the
2135 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
2137 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2138 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2140 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2141 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2142 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2143 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2147 // For sync, set the success flag out of polling in decline/release.
2149 Instance
->UdpSts
= EFI_SUCCESS
;
2152 // For async, signal the Ia event to inform Ia infomation update.
2154 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2155 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2159 // Reset start time for next exchange.
2161 Instance
->StartTime
= 0;
2163 Status
= EFI_SUCCESS
;
2168 // Upon the receipt of a valid reply packet in response to a solicit, request,
2169 // confirm, renew and rebind, the behavior depends on the status code option.
2170 // See the details in the section-18.1.8 of rfc-3315.
2173 Status
= Dhcp6SeekStsOption (
2179 if (!EFI_ERROR (Status
)) {
2181 // No status code or no error status code means succeed to reply.
2183 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2184 if (!EFI_ERROR (Status
)) {
2186 // Reset start time for next exchange.
2188 Instance
->StartTime
= 0;
2191 // Set bound state and store the reply packet.
2193 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2194 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2197 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2199 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2200 Status
= EFI_OUT_OF_RESOURCES
;
2204 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2206 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2209 // For sync, set the success flag out of polling in start/renewrebind.
2211 Instance
->UdpSts
= EFI_SUCCESS
;
2214 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2215 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2216 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2217 // consumers can be notified to flush old address.
2219 Dhcp6AppendCacheIa (Instance
);
2222 // For async, signal the Ia event to inform Ia infomation update.
2224 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2225 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2227 } else if (Status
== EFI_NOT_FOUND
) {
2229 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2230 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2231 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2238 } else if (Option
!= NULL
) {
2240 // Any error status code option is found.
2242 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2244 case Dhcp6StsUnspecFail
:
2246 // It indicates the server is unable to process the message due to an
2247 // unspecified failure condition, so just retry if possible.
2251 case Dhcp6StsUseMulticast
:
2253 // It indicates the server receives a message via unicast from a client
2254 // to which the server has not sent a unicast option, so retry it by
2255 // multi-cast address.
2257 if (Instance
->Unicast
!= NULL
) {
2258 FreePool (Instance
->Unicast
);
2259 Instance
->Unicast
= NULL
;
2263 case Dhcp6StsNotOnLink
:
2264 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2266 // Before initiate new round DHCP, cache the current IA.
2268 Status
= Dhcp6CacheIa (Instance
);
2269 if (EFI_ERROR (Status
)) {
2274 // Restart S.A.R.R process to acquire new address.
2276 Status
= Dhcp6InitSolicitMsg (Instance
);
2277 if (EFI_ERROR (Status
)) {
2283 case Dhcp6StsNoBinding
:
2284 if (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
|| Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
) {
2286 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2287 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2289 Status
= Dhcp6SendRequestMsg(Instance
);
2290 if (EFI_ERROR (Status
)) {
2298 // The other status code, just restart solicitation.
2308 if (!EFI_ERROR(Status
)) {
2309 Status
= Dhcp6DequeueRetry (
2311 Packet
->Dhcp6
.Header
.TransactionId
,
2321 Select the appointed Dhcp6 advertisement message.
2323 @param[in] Instance The pointer to the Dhcp6 instance.
2324 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2326 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2327 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2328 @retval Others Failed to select the advertise message.
2332 Dhcp6SelectAdvertiseMsg (
2333 IN DHCP6_INSTANCE
*Instance
,
2334 IN EFI_DHCP6_PACKET
*AdSelect
2340 ASSERT (AdSelect
!= NULL
);
2343 // Callback to user with the selected advertisement packet, and the user
2344 // might overwrite it.
2346 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2348 if (EFI_ERROR (Status
)) {
2352 Instance
->AdSelect
= AdSelect
;
2355 // Dequeue the sent packet for the retransmission since advertisement selected.
2357 Status
= Dhcp6DequeueRetry (
2359 AdSelect
->Dhcp6
.Header
.TransactionId
,
2363 if (EFI_ERROR(Status
)) {
2368 // Check whether there is server unicast option in the selected advertise
2369 // packet, and update it.
2371 Option
= Dhcp6SeekOption(
2372 AdSelect
->Dhcp6
.Option
,
2373 AdSelect
->Length
- 4,
2374 Dhcp6OptServerUnicast
2377 if (Option
!= NULL
) {
2379 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2381 if (Instance
->Unicast
== NULL
) {
2382 return EFI_OUT_OF_RESOURCES
;
2385 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2389 // Update the information of the Ia by the selected advertisement message.
2391 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2393 if (EFI_ERROR (Status
)) {
2398 // Send the request message to continue the S.A.R.R. process.
2400 return Dhcp6SendRequestMsg (Instance
);
2405 Handle with the Dhcp6 advertisement message.
2407 @param[in] Instance The pointer to the Dhcp6 instance.
2408 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2410 @retval EFI_SUCCESS Processed the advertisement message successfully.
2411 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2412 @retval EFI_DEVICE_ERROR An unexpected error.
2413 @retval Others Failed to process the advertise message.
2417 Dhcp6HandleAdvertiseMsg (
2418 IN DHCP6_INSTANCE
*Instance
,
2419 IN EFI_DHCP6_PACKET
*Packet
2426 ASSERT(Instance
->Config
);
2427 ASSERT(Instance
->IaCb
.Ia
);
2432 // If the client does receives a valid reply message that includes a rapid
2433 // commit option since a solicit with rapid commit optioin sent before, select
2434 // this reply message. Or else, process the advertise messages as normal.
2435 // See details in the section-17.1.4 of rfc-3315.
2437 Option
= Dhcp6SeekOption(
2438 Packet
->Dhcp6
.Option
,
2443 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2445 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2448 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2449 return EFI_DEVICE_ERROR
;
2453 // Client must ignore any advertise message that includes a status code option
2454 // containing the value noaddrsavail, with the exception that the client may
2455 // display the associated status message to the user.
2456 // See the details in the section-17.1.3 of rfc-3315.
2458 Status
= Dhcp6SeekStsOption (
2463 if (EFI_ERROR (Status
)) {
2464 return EFI_DEVICE_ERROR
;
2468 // Callback to user with the received packet and check the user's feedback.
2470 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2472 if (!EFI_ERROR (Status
)) {
2474 // Success means user choose the current advertisement packet.
2476 if (Instance
->AdSelect
!= NULL
) {
2477 FreePool (Instance
->AdSelect
);
2481 // Store the selected advertisement packet and set a flag.
2483 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2485 if (Instance
->AdSelect
== NULL
) {
2486 return EFI_OUT_OF_RESOURCES
;
2489 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2491 Instance
->AdPref
= 0xff;
2493 } else if (Status
== EFI_NOT_READY
) {
2495 // Not_ready means user wants to continue to receive more advertise packets.
2497 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2499 // It's a tricky point. The timer routine set adpref as 0xff if the first
2500 // rt timeout and no advertisement received, which means any advertisement
2501 // received will be selected after the first rt.
2507 // Check whether the current packet has a 255 preference option or not.
2508 // Take non-preference option as 0 value.
2510 Option
= Dhcp6SeekOption(
2511 Packet
->Dhcp6
.Option
,
2516 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2518 // No advertisements received before or preference is more than other
2519 // advertisements received before. Then store the new packet and the
2520 // preference value.
2522 if (Instance
->AdSelect
!= NULL
) {
2523 FreePool (Instance
->AdSelect
);
2526 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2528 if (Instance
->AdSelect
== NULL
) {
2529 return EFI_OUT_OF_RESOURCES
;
2532 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2534 if (Option
!= NULL
) {
2535 Instance
->AdPref
= *(Option
+ 4);
2539 // Non-preference and other advertisements received before or current
2540 // preference is less than other advertisements received before.
2541 // Leave the packet alone.
2546 // Other error status means termination.
2552 // Client must collect advertise messages as more as possible until the first
2553 // RT has elapsed, or get a highest preference 255 advertise.
2554 // See details in the section-17.1.2 of rfc-3315.
2556 if (Instance
->AdPref
== 0xff || Timeout
) {
2557 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2565 The Dhcp6 stateful exchange process routine.
2567 @param[in] Instance The pointer to the Dhcp6 instance.
2568 @param[in] Packet The pointer to the received Dhcp6 message.
2572 Dhcp6HandleStateful (
2573 IN DHCP6_INSTANCE
*Instance
,
2574 IN EFI_DHCP6_PACKET
*Packet
2578 EFI_DHCP6_DUID
*ClientId
;
2579 DHCP6_SERVICE
*Service
;
2582 Service
= Instance
->Service
;
2583 ClientId
= Service
->ClientId
;
2584 Status
= EFI_SUCCESS
;
2586 if (Instance
->Config
== NULL
) {
2591 ASSERT (Instance
->Config
);
2592 ASSERT (Instance
->IaCb
.Ia
);
2595 // Discard the packet if not advertisement or reply packet.
2597 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2602 // Check whether include client Id or not.
2604 Option
= Dhcp6SeekOption(
2605 Packet
->Dhcp6
.Option
,
2610 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2615 // Check whether include server Id or not.
2617 Option
= Dhcp6SeekOption(
2618 Packet
->Dhcp6
.Option
,
2623 if (Option
== NULL
) {
2627 switch (Instance
->IaCb
.Ia
->State
) {
2628 case Dhcp6Selecting
:
2630 // Handle the advertisement message when in the Dhcp6Selecting state.
2631 // Do not need check return status, if failed, just continue to the next.
2633 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2636 case Dhcp6Requesting
:
2637 case Dhcp6Confirming
:
2639 case Dhcp6Rebinding
:
2640 case Dhcp6Releasing
:
2641 case Dhcp6Declining
:
2643 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2644 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2645 // If failed here, it should reset the current session.
2647 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2648 if (EFI_ERROR (Status
)) {
2654 // Other state has not supported yet.
2661 // Continue to receive the following Dhcp6 message.
2663 Status
= UdpIoRecvDatagram (
2670 if (EFI_ERROR (Status
)) {
2671 Dhcp6CleanupSession (Instance
, Status
);
2677 The Dhcp6 stateless exchange process routine.
2679 @param[in] Instance The pointer to the Dhcp6 instance.
2680 @param[in] Packet The pointer to the received Dhcp6 message.
2684 Dhcp6HandleStateless (
2685 IN DHCP6_INSTANCE
*Instance
,
2686 IN EFI_DHCP6_PACKET
*Packet
2690 DHCP6_SERVICE
*Service
;
2691 DHCP6_INF_CB
*InfCb
;
2695 Service
= Instance
->Service
;
2696 Status
= EFI_SUCCESS
;
2700 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2705 // Check whether it's a desired Info-request message by Xid.
2707 while (!IsListEmpty (&Instance
->InfList
)) {
2708 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2709 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2720 // Check whether include server Id or not.
2722 Option
= Dhcp6SeekOption (
2723 Packet
->Dhcp6
.Option
,
2728 if (Option
== NULL
) {
2733 // Callback to user with the received packet and check the user's feedback.
2735 Status
= InfCb
->ReplyCallback (
2737 InfCb
->CallbackContext
,
2741 if (Status
== EFI_NOT_READY
) {
2743 // Success or aborted will both stop this info-request exchange process,
2744 // but not ready means user wants to continue to receive reply.
2750 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2751 // if no xid matched.
2755 Packet
->Dhcp6
.Header
.TransactionId
,
2760 // For sync, set the status out of polling for info-request.
2762 Instance
->UdpSts
= Status
;
2766 Status
= UdpIoRecvDatagram (
2773 if (EFI_ERROR (Status
)) {
2774 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2780 The receive callback function for Dhcp6 exchange process.
2782 @param[in] Udp6Wrap The pointer to the received net buffer.
2783 @param[in] EndPoint The pointer to the udp end point.
2784 @param[in] IoStatus The return status from udp io.
2785 @param[in] Context The opaque parameter to the function.
2790 Dhcp6ReceivePacket (
2791 IN NET_BUF
*Udp6Wrap
,
2792 IN UDP_END_POINT
*EndPoint
,
2793 IN EFI_STATUS IoStatus
,
2797 EFI_DHCP6_HEADER
*Head
;
2798 EFI_DHCP6_PACKET
*Packet
;
2799 DHCP6_SERVICE
*Service
;
2800 DHCP6_INSTANCE
*Instance
;
2803 BOOLEAN IsDispatched
;
2804 BOOLEAN IsStateless
;
2811 ASSERT (Udp6Wrap
!= NULL
);
2812 ASSERT (Context
!= NULL
);
2814 Service
= (DHCP6_SERVICE
*) Context
;
2817 IsDispatched
= FALSE
;
2818 IsStateless
= FALSE
;
2820 if (EFI_ERROR (IoStatus
)) {
2824 if (Udp6Wrap
->TotalSize
< sizeof (EFI_DHCP6_HEADER
)) {
2829 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2831 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2832 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2834 if (Packet
== NULL
) {
2838 Packet
->Size
= Size
;
2839 Head
= &Packet
->Dhcp6
.Header
;
2840 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2842 if (Packet
->Length
== 0) {
2847 // Dispatch packet to right instance by transaction id.
2849 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2851 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2853 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2855 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2857 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2859 // Find the corresponding packet in tx list, and check it whether belongs
2860 // to stateful exchange process.
2862 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2865 IsDispatched
= TRUE
;
2876 // Skip this packet if not dispatched to any instance.
2878 if (!IsDispatched
) {
2883 // Dispatch the received packet ot the right instance.
2886 Dhcp6HandleStateless (Instance
, Packet
);
2888 Dhcp6HandleStateful (Instance
, Packet
);
2893 if (!IsDispatched
) {
2894 Status
= UdpIoRecvDatagram (
2900 if (EFI_ERROR (Status
)) {
2901 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2902 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2903 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_ALL
);
2908 NetbufFree (Udp6Wrap
);
2910 if (Packet
!= NULL
) {
2916 Detect Link movement for specified network device.
2918 This routine will try to invoke Snp->GetStatus() to get the media status.
2919 If media present status switches from unpresent to present, a link movement
2920 is detected. Note that the underlying UNDI driver may not support reporting
2921 media status from GET_STATUS command. If that, fail to detect link movement.
2923 @param[in] Instance The pointer to DHCP6_INSTANCE.
2925 @retval TRUE A link movement is detected.
2926 @retval FALSE A link movement is not detected.
2930 Dhcp6LinkMovDetect (
2931 IN DHCP6_INSTANCE
*Instance
2934 UINT32 InterruptStatus
;
2935 BOOLEAN MediaPresent
;
2937 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2939 ASSERT (Instance
!= NULL
);
2940 Snp
= Instance
->Service
->Snp
;
2941 MediaPresent
= Instance
->MediaPresent
;
2944 // Check whether SNP support media detection
2946 if (!Snp
->Mode
->MediaPresentSupported
) {
2951 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2953 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2954 if (EFI_ERROR (Status
)) {
2958 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2960 // Media transimit Unpresent to Present means new link movement is detected.
2962 if (!MediaPresent
&& Instance
->MediaPresent
) {
2970 The timer routine of the Dhcp6 instance for each second.
2972 @param[in] Event The timer event.
2973 @param[in] Context The opaque parameter to the function.
2984 LIST_ENTRY
*NextEntry
;
2985 DHCP6_INSTANCE
*Instance
;
2991 ASSERT (Context
!= NULL
);
2993 Instance
= (DHCP6_INSTANCE
*) Context
;
2996 // 1. Loop the tx list, count live time of every tx packet to check whether
2997 // need re-transmit or not.
2999 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
3001 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
3005 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
3007 // Handle the first rt in the transmission of solicit specially.
3009 if ((TxCb
->RetryCnt
== 0 || TxCb
->SolicitRetry
) && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3010 if (Instance
->AdSelect
== NULL
) {
3012 // Set adpref as 0xff here to indicate select any advertisement
3015 Instance
->AdPref
= 0xff;
3018 // Select the advertisement received before.
3020 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
3021 if (Status
== EFI_ABORTED
) {
3023 } else if (EFI_ERROR (Status
)) {
3030 // Increase the retry count for the packet and add up the total loss time.
3033 TxCb
->RetryLos
+= TxCb
->RetryExp
;
3036 // Check whether overflow the max retry count limit for this packet
3038 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
3039 Status
= EFI_NO_RESPONSE
;
3044 // Check whether overflow the max retry duration for this packet
3046 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
3047 Status
= EFI_NO_RESPONSE
;
3052 // Re-calculate retry expire timeout for the next time.
3054 // Firstly, Check the new calculated time whether overflow the max retry
3057 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3063 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
3064 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3072 // Secondly, Check the new calculated time whether overflow the max retry
3075 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3076 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
3077 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3081 // Reset the tick time for the next retransmission
3086 // Retransmit the last sent packet again.
3088 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3089 TxCb
->SolicitRetry
= FALSE
;
3090 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3091 TxCb
->SolicitRetry
= TRUE
;
3097 // 2. Check the configured Ia, count lease time of every valid Ia to check
3098 // whether need to renew or rebind this Ia.
3100 IaCb
= &Instance
->IaCb
;
3102 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
3106 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
3110 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3112 // Exceed t2, send rebind packet to extend the Ia lease.
3114 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3116 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3119 // Exceed t1, send renew packet to extend the Ia lease.
3121 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3126 // 3. In any situation when a client may have moved to a new link, the
3127 // client MUST initiate a Confirm/Reply message exchange.
3129 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3130 Dhcp6SendConfirmMsg (Instance
);
3137 if (Dhcp6IsValidTxCb (Instance
, TxCb
) &&
3138 TxCb
->TxPacket
!= NULL
&&
3139 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
3140 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
3141 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)
3144 // The failure of renew/Confirm will still switch to the bound state.
3146 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3147 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
3148 ASSERT (Instance
->IaCb
.Ia
);
3149 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3152 // The failure of info-request will return no response.
3154 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3155 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3164 // The failure of the others will terminate current state machine if timeout.
3166 Dhcp6CleanupSession (Instance
, Status
);