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"
14 Enqueue the packet into the retry list in case of timeout.
16 @param[in] Instance The pointer to the Dhcp6 instance.
17 @param[in] Packet The pointer to the Dhcp6 packet to retry.
18 @param[in] Elapsed The pointer to the elapsed time value in the packet.
19 @param[in] RetryCtl The pointer to the transmission control of the packet.
20 This parameter is optional and may be NULL.
22 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according
24 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
25 @retval EFI_DEVICE_ERROR An unexpected message type.
30 IN DHCP6_INSTANCE
*Instance
,
31 IN EFI_DHCP6_PACKET
*Packet
,
33 IN EFI_DHCP6_RETRANSMISSION
*RetryCtl OPTIONAL
39 ASSERT (Packet
!= NULL
);
41 IaCb
= &Instance
->IaCb
;
42 TxCb
= AllocateZeroPool (sizeof (DHCP6_TX_CB
));
45 return EFI_OUT_OF_RESOURCES
;
49 // Save tx packet pointer, and it will be destroyed when reply received.
51 TxCb
->TxPacket
= Packet
;
52 TxCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
55 // Save pointer to elapsed-time value so we can update it on retransmits.
57 TxCb
->Elapsed
= Elapsed
;
60 // Calculate the retransmission according to the message type.
62 switch (Packet
->Dhcp6
.Header
.MessageType
) {
65 // Calculate the retransmission threshold value for solicit packet.
66 // Use the default value by rfc-3315 if user doesn't configure.
68 if (RetryCtl
== NULL
) {
69 TxCb
->RetryCtl
.Irt
= DHCP6_SOL_IRT
;
70 TxCb
->RetryCtl
.Mrc
= DHCP6_SOL_MRC
;
71 TxCb
->RetryCtl
.Mrt
= DHCP6_SOL_MRT
;
72 TxCb
->RetryCtl
.Mrd
= DHCP6_SOL_MRD
;
74 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_SOL_IRT
;
75 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_SOL_MRC
;
76 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_SOL_MRT
;
77 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_SOL_MRD
;
80 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
89 // Calculate the retransmission threshold value for request packet.
91 TxCb
->RetryCtl
.Irt
= DHCP6_REQ_IRT
;
92 TxCb
->RetryCtl
.Mrc
= DHCP6_REQ_MRC
;
93 TxCb
->RetryCtl
.Mrt
= DHCP6_REQ_MRT
;
94 TxCb
->RetryCtl
.Mrd
= DHCP6_REQ_MRD
;
95 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
102 case Dhcp6MsgConfirm
:
104 // Calculate the retransmission threshold value for confirm packet.
106 TxCb
->RetryCtl
.Irt
= DHCP6_CNF_IRT
;
107 TxCb
->RetryCtl
.Mrc
= DHCP6_CNF_MRC
;
108 TxCb
->RetryCtl
.Mrt
= DHCP6_CNF_MRT
;
109 TxCb
->RetryCtl
.Mrd
= DHCP6_CNF_MRD
;
110 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
119 // Calculate the retransmission threshold value for renew packet.
121 TxCb
->RetryCtl
.Irt
= DHCP6_REB_IRT
;
122 TxCb
->RetryCtl
.Mrc
= DHCP6_REB_MRC
;
123 TxCb
->RetryCtl
.Mrt
= DHCP6_REB_MRT
;
124 TxCb
->RetryCtl
.Mrd
= IaCb
->T2
- IaCb
->T1
;
125 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
134 // Calculate the retransmission threshold value for rebind packet.
136 TxCb
->RetryCtl
.Irt
= DHCP6_REN_IRT
;
137 TxCb
->RetryCtl
.Mrc
= DHCP6_REN_MRC
;
138 TxCb
->RetryCtl
.Mrt
= DHCP6_REN_MRT
;
139 TxCb
->RetryCtl
.Mrd
= IaCb
->AllExpireTime
- IaCb
->T2
;
140 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
147 case Dhcp6MsgDecline
:
149 // Calculate the retransmission threshold value for decline packet.
151 TxCb
->RetryCtl
.Irt
= DHCP6_DEC_IRT
;
152 TxCb
->RetryCtl
.Mrc
= DHCP6_DEC_MRC
;
153 TxCb
->RetryCtl
.Mrt
= DHCP6_DEC_MRT
;
154 TxCb
->RetryCtl
.Mrd
= DHCP6_DEC_MRD
;
155 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
162 case Dhcp6MsgRelease
:
164 // Calculate the retransmission threshold value for release packet.
166 TxCb
->RetryCtl
.Irt
= DHCP6_REL_IRT
;
167 TxCb
->RetryCtl
.Mrc
= DHCP6_REL_MRC
;
168 TxCb
->RetryCtl
.Mrt
= DHCP6_REL_MRT
;
169 TxCb
->RetryCtl
.Mrd
= DHCP6_REL_MRD
;
170 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
177 case Dhcp6MsgInfoRequest
:
179 // Calculate the retransmission threshold value for info-request packet.
180 // Use the default value by rfc-3315 if user doesn't configure.
182 if (RetryCtl
== NULL
) {
183 TxCb
->RetryCtl
.Irt
= DHCP6_INF_IRT
;
184 TxCb
->RetryCtl
.Mrc
= DHCP6_INF_MRC
;
185 TxCb
->RetryCtl
.Mrt
= DHCP6_INF_MRT
;
186 TxCb
->RetryCtl
.Mrd
= DHCP6_INF_MRD
;
188 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_INF_IRT
;
189 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_INF_MRC
;
190 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_INF_MRT
;
191 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_INF_MRD
;
194 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
203 // Unexpected message type.
206 return EFI_DEVICE_ERROR
;
210 // Insert into the retransmit list of the instance.
212 InsertTailList (&Instance
->TxList
, &TxCb
->Link
);
218 Dequeue the packet from retry list if reply received or timeout at last.
220 @param[in] Instance The pointer to the Dhcp6 instance.
221 @param[in] PacketXid The packet transaction id to match.
222 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
223 Otherwise, this parameter is ignored.
225 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
226 @retval EFI_NOT_FOUND There is no xid matched in retry list.
231 IN DHCP6_INSTANCE
*Instance
,
233 IN BOOLEAN NeedSignal
237 LIST_ENTRY
*NextEntry
;
242 // Seek the retransmit node in the retransmit list by packet xid.
244 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
245 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
246 ASSERT (TxCb
->TxPacket
);
248 if (TxCb
->Xid
== PacketXid
) {
249 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
251 // Seek the info-request node in the info-request list by packet xid.
253 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
254 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
256 if (InfCb
->Xid
== PacketXid
) {
258 // Remove the info-request node, and signal the event if timeout.
260 if ((InfCb
->TimeoutEvent
!= NULL
) && NeedSignal
) {
261 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
264 RemoveEntryList (&InfCb
->Link
);
271 // Remove the retransmit node.
273 RemoveEntryList (&TxCb
->Link
);
274 ASSERT (TxCb
->TxPacket
);
275 FreePool (TxCb
->TxPacket
);
281 return EFI_NOT_FOUND
;
285 Clean up the specific nodes in the retry list.
287 @param[in] Instance The pointer to the Dhcp6 instance.
288 @param[in] Scope The scope of cleanup nodes.
293 IN DHCP6_INSTANCE
*Instance
,
298 LIST_ENTRY
*NextEntry
;
303 // Clean up all the stateful messages from the retransmit list.
305 if ((Scope
== DHCP6_PACKET_STATEFUL
) || (Scope
== DHCP6_PACKET_ALL
)) {
306 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
307 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
308 ASSERT (TxCb
->TxPacket
);
310 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgInfoRequest
) {
311 RemoveEntryList (&TxCb
->Link
);
312 FreePool (TxCb
->TxPacket
);
319 // Clean up all the stateless messages from the retransmit list.
321 if ((Scope
== DHCP6_PACKET_STATELESS
) || (Scope
== DHCP6_PACKET_ALL
)) {
323 // Clean up all the retransmit list for stateless messages.
325 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
326 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
327 ASSERT (TxCb
->TxPacket
);
329 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
330 RemoveEntryList (&TxCb
->Link
);
331 FreePool (TxCb
->TxPacket
);
337 // Clean up all the info-request messages list.
339 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
340 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
342 if (InfCb
->TimeoutEvent
!= NULL
) {
343 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
346 RemoveEntryList (&InfCb
->Link
);
353 Check whether the TxCb is still a valid control block in the instance's retry list.
355 @param[in] Instance The pointer to DHCP6_INSTANCE.
356 @param[in] TxCb The control block for a transmitted message.
358 @retval TRUE The control block is in Instance's retry list.
359 @retval FALSE The control block is NOT in Instance's retry list.
364 IN DHCP6_INSTANCE
*Instance
,
370 NET_LIST_FOR_EACH (Entry
, &Instance
->TxList
) {
371 if (TxCb
== NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
)) {
380 Clean up the session of the instance stateful exchange.
382 @param[in, out] Instance The pointer to the Dhcp6 instance.
383 @param[in] Status The return status from udp.
387 Dhcp6CleanupSession (
388 IN OUT DHCP6_INSTANCE
*Instance
,
395 ASSERT (Instance
->Config
);
396 ASSERT (Instance
->IaCb
.Ia
);
399 // Clean up the retransmit list for stateful messages.
401 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
403 if (Instance
->Unicast
!= NULL
) {
404 FreePool (Instance
->Unicast
);
407 if (Instance
->AdSelect
!= NULL
) {
408 FreePool (Instance
->AdSelect
);
411 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
412 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
416 // Reinitialize the Ia fields of the instance.
418 Instance
->UdpSts
= Status
;
419 Instance
->AdSelect
= NULL
;
420 Instance
->AdPref
= 0;
421 Instance
->Unicast
= NULL
;
422 Instance
->IaCb
.T1
= 0;
423 Instance
->IaCb
.T2
= 0;
424 Instance
->IaCb
.AllExpireTime
= 0;
425 Instance
->IaCb
.LeaseTime
= 0;
430 Instance
->StartTime
= 0;
432 Ia
= Instance
->IaCb
.Ia
;
433 Ia
->State
= Dhcp6Init
;
434 Ia
->ReplyPacket
= NULL
;
437 // Set the addresses as zero lifetime, and then the notify
438 // function in Ip6Config will remove these timeout address.
440 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
441 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
442 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
447 // Signal the Ia information updated event to informal user.
449 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
450 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
455 Callback to user when Dhcp6 transmit/receive occurs.
457 @param[in] Instance The pointer to the Dhcp6 instance.
458 @param[in] Event The current Dhcp6 event.
459 @param[in, out] Packet The pointer to the packet sending or received.
461 @retval EFI_SUCCESS The user function returns success.
462 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
463 @retval EFI_ABORTED The user function ask it to abort.
469 IN DHCP6_INSTANCE
*Instance
,
470 IN EFI_DHCP6_EVENT Event
,
471 IN OUT EFI_DHCP6_PACKET
**Packet
475 EFI_DHCP6_PACKET
*NewPacket
;
476 EFI_DHCP6_CALLBACK Callback
;
479 ASSERT (Packet
!= NULL
);
480 ASSERT (Instance
->Config
!= NULL
);
481 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
484 Status
= EFI_SUCCESS
;
485 Callback
= Instance
->Config
->Dhcp6Callback
;
486 Context
= Instance
->Config
->CallbackContext
;
489 // Callback to user with the new message if has.
491 if (Callback
!= NULL
) {
495 Instance
->IaCb
.Ia
->State
,
501 // Updated the new packet from user to replace the original one.
503 if (NewPacket
!= NULL
) {
504 ASSERT (*Packet
!= NULL
);
514 Update Ia according to the new reply message.
516 @param[in, out] Instance The pointer to the Dhcp6 instance.
517 @param[in] Packet The pointer to reply messages.
519 @retval EFI_SUCCESS Updated the Ia information successfully.
520 @retval EFI_DEVICE_ERROR An unexpected error.
525 IN OUT DHCP6_INSTANCE
*Instance
,
526 IN EFI_DHCP6_PACKET
*Packet
537 ASSERT (Instance
->Config
!= NULL
);
539 // If the reply was received in response to a solicit with rapid commit option,
540 // request, renew or rebind message, the client updates the information it has
541 // recorded about IAs from the IA options contained in the reply message:
542 // 1. record the T1 and T2 times
543 // 2. add any new addresses in the IA
544 // 3. discard any addresses from the IA, that have a valid lifetime of 0
545 // 4. update lifetimes for any addresses that already recorded
546 // 5. leave unchanged any information about addresses
548 // See details in the section-18.1.8 of rfc-3315.
550 Option
= Dhcp6SeekIaOption (
551 Packet
->Dhcp6
.Option
,
552 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
553 &Instance
->Config
->IaDescriptor
555 if (Option
== NULL
) {
556 return EFI_DEVICE_ERROR
;
560 // The format of the IA_NA option is:
563 // 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
564 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565 // | OPTION_IA_NA | option-len |
566 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
567 // | IAID (4 octets) |
568 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
572 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
576 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
578 // The format of the IA_TA option is:
581 // 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
582 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 // | OPTION_IA_TA | option-len |
584 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 // | IAID (4 octets) |
586 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
594 // sizeof (option-code + option-len + IaId) = 8
595 // sizeof (option-code + option-len + IaId + T1) = 12
596 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
598 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
600 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
601 T1
= NTOHL (ReadUnaligned32 ((UINT32
*)(Option
+ 8)));
602 T2
= NTOHL (ReadUnaligned32 ((UINT32
*)(Option
+ 12)));
604 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
605 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
606 // the remainder of the message as though the server had not included the invalid IA_NA option.
608 if ((T1
> T2
) && (T2
> 0)) {
609 return EFI_DEVICE_ERROR
;
612 IaInnerOpt
= Option
+ 16;
613 IaInnerLen
= (UINT16
)(NTOHS (ReadUnaligned16 ((UINT16
*)(Option
+ 2))) - 12);
617 IaInnerOpt
= Option
+ 8;
618 IaInnerLen
= (UINT16
)(NTOHS (ReadUnaligned16 ((UINT16
*)(Option
+ 2))) - 4);
622 // The format of the Status Code option is:
625 // 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
626 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
627 // | OPTION_STATUS_CODE | option-len |
628 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
630 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
632 // . status-message .
634 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
638 // sizeof (option-code + option-len) = 4
640 StsCode
= Dhcp6StsSuccess
;
641 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
643 if (Option
!= NULL
) {
644 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*)(Option
+ 4)));
645 if (StsCode
!= Dhcp6StsSuccess
) {
646 return EFI_DEVICE_ERROR
;
651 // Generate control block for the Ia.
653 Status
= Dhcp6GenerateIaCb (
665 Seek StatusCode Option in package. A Status Code option may appear in the
666 options field of a DHCP message and/or in the options field of another option.
667 See details in section 22.13, RFC3315.
669 @param[in] Instance The pointer to the Dhcp6 instance.
670 @param[in] Packet The pointer to reply messages.
671 @param[out] Option The pointer to status code option.
673 @retval EFI_SUCCESS Seek status code option successfully.
674 @retval EFI_DEVICE_ERROR An unexpected error.
679 IN DHCP6_INSTANCE
*Instance
,
680 IN EFI_DHCP6_PACKET
*Packet
,
689 // Seek StatusCode option directly in DHCP message body. That is, search in
690 // non-encapsulated option fields.
692 *Option
= Dhcp6SeekOption (
693 Packet
->Dhcp6
.Option
,
698 if (*Option
!= NULL
) {
699 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*)(*Option
+ 4)));
700 if (StsCode
!= Dhcp6StsSuccess
) {
701 return EFI_DEVICE_ERROR
;
706 // Seek in encapsulated options, IA_NA and IA_TA.
708 *Option
= Dhcp6SeekIaOption (
709 Packet
->Dhcp6
.Option
,
710 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
711 &Instance
->Config
->IaDescriptor
713 if (*Option
== NULL
) {
718 // The format of the IA_NA option is:
721 // 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
722 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
723 // | OPTION_IA_NA | option-len |
724 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
725 // | IAID (4 octets) |
726 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
728 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
730 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
734 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
736 // The format of the IA_TA option is:
739 // 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
740 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
741 // | OPTION_IA_TA | option-len |
742 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743 // | IAID (4 octets) |
744 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
752 // sizeof (option-code + option-len + IaId) = 8
753 // sizeof (option-code + option-len + IaId + T1) = 12
754 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
756 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
758 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
759 IaInnerOpt
= *Option
+ 16;
760 IaInnerLen
= (UINT16
)(NTOHS (ReadUnaligned16 ((UINT16
*)(*Option
+ 2))) - 12);
762 IaInnerOpt
= *Option
+ 8;
763 IaInnerLen
= (UINT16
)(NTOHS (ReadUnaligned16 ((UINT16
*)(*Option
+ 2))) - 4);
767 // The format of the Status Code option is:
770 // 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
771 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
772 // | OPTION_STATUS_CODE | option-len |
773 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
775 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
777 // . status-message .
779 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
783 // sizeof (option-code + option-len) = 4
785 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
786 if (*Option
!= NULL
) {
787 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*)(*Option
+ 4)));
788 if (StsCode
!= Dhcp6StsSuccess
) {
789 return EFI_DEVICE_ERROR
;
797 Transmit Dhcp6 message by udpio.
799 @param[in] Instance The pointer to the Dhcp6 instance.
800 @param[in] Packet The pointer to transmit message.
801 @param[in] Elapsed The pointer to the elapsed time value to fill in.
803 @retval EFI_SUCCESS Successfully transmitted the packet.
804 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
805 @retval Others Failed to transmit the packet.
809 Dhcp6TransmitPacket (
810 IN DHCP6_INSTANCE
*Instance
,
811 IN EFI_DHCP6_PACKET
*Packet
,
819 DHCP6_SERVICE
*Service
;
821 Service
= Instance
->Service
;
824 // Wrap it into a netbuf then send it.
826 Frag
.Bulk
= (UINT8
*)&Packet
->Dhcp6
.Header
;
827 Frag
.Len
= Packet
->Length
;
830 // Do not register free packet here, which will be handled in retry list.
832 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
835 return EFI_OUT_OF_RESOURCES
;
839 // Multicast the Dhcp6 message, unless get the unicast server address by option.
841 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
843 if (Instance
->Unicast
!= NULL
) {
847 sizeof (EFI_IPv6_ADDRESS
)
852 &mAllDhcpRelayAndServersAddress
,
853 sizeof (EFI_IPv6_ADDRESS
)
857 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
858 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
861 // Update the elapsed time value.
863 if (Elapsed
!= NULL
) {
864 SetElapsedTime (Elapsed
, Instance
);
868 // Send out the message by the configured Udp6Io.
870 Status
= UdpIoSendDatagram (
879 if (EFI_ERROR (Status
)) {
888 Create the solicit message and send it.
890 @param[in] Instance The pointer to the Dhcp6 instance.
892 @retval EFI_SUCCESS Created and sent the solicit message successfully.
893 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
894 @retval Others Failed to send the solicit message.
898 Dhcp6SendSolicitMsg (
899 IN DHCP6_INSTANCE
*Instance
903 EFI_DHCP6_PACKET
*Packet
;
904 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
905 EFI_DHCP6_DUID
*ClientId
;
906 DHCP6_SERVICE
*Service
;
913 Service
= Instance
->Service
;
914 ClientId
= Service
->ClientId
;
917 ASSERT (Service
->ClientId
!= NULL
);
918 ASSERT (Instance
->Config
!= NULL
);
919 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
922 // Calculate the added length of customized option list.
924 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
925 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
929 // Create the Dhcp6 packet and initialize common fields.
931 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
932 if (Packet
== NULL
) {
933 return EFI_OUT_OF_RESOURCES
;
936 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
937 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
938 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
939 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
942 // Assembly Dhcp6 options for solicit message.
944 Cursor
= Packet
->Dhcp6
.Option
;
946 Length
= HTONS (ClientId
->Length
);
947 Cursor
= Dhcp6AppendOption (
949 HTONS (Dhcp6OptClientId
),
954 Cursor
= Dhcp6AppendETOption (
960 Cursor
= Dhcp6AppendIaOption (
965 Packet
->Dhcp6
.Header
.MessageType
969 // Append user-defined when configurate Dhcp6 service.
971 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
972 UserOpt
= Instance
->Config
->OptionList
[Index
];
973 Cursor
= Dhcp6AppendOption (
982 // Determine the size/length of packet.
984 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
985 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
988 // Callback to user with the packet to be sent and check the user's feedback.
990 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
992 if (EFI_ERROR (Status
)) {
998 // Send solicit packet with the state transition from Dhcp6init to
1001 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1003 // Clear initial time for current transaction.
1005 Instance
->StartTime
= 0;
1007 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1009 if (EFI_ERROR (Status
)) {
1015 // Enqueue the sent packet for the retransmission in case reply timeout.
1017 return Dhcp6EnqueueRetry (
1021 Instance
->Config
->SolicitRetransmission
1026 Configure some parameter to initiate SolicitMsg.
1028 @param[in] Instance The pointer to the Dhcp6 instance.
1030 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1031 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1032 @retval Others Failed to send the solicit message.
1036 Dhcp6InitSolicitMsg (
1037 IN DHCP6_INSTANCE
*Instance
1040 Instance
->IaCb
.T1
= 0;
1041 Instance
->IaCb
.T2
= 0;
1042 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1044 return Dhcp6SendSolicitMsg (Instance
);
1048 Create the request message and send it.
1050 @param[in] Instance The pointer to the Dhcp6 instance.
1052 @retval EFI_SUCCESS Created and sent the request message successfully.
1053 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1054 @retval EFI_DEVICE_ERROR An unexpected error.
1055 @retval Others Failed to send the request message.
1059 Dhcp6SendRequestMsg (
1060 IN DHCP6_INSTANCE
*Instance
1064 EFI_DHCP6_PACKET
*Packet
;
1065 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1066 EFI_DHCP6_DUID
*ClientId
;
1067 EFI_DHCP6_DUID
*ServerId
;
1068 DHCP6_SERVICE
*Service
;
1076 ASSERT (Instance
->AdSelect
!= NULL
);
1077 ASSERT (Instance
->Config
!= NULL
);
1078 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1079 ASSERT (Instance
->Service
!= NULL
);
1081 Service
= Instance
->Service
;
1082 ClientId
= Service
->ClientId
;
1084 ASSERT (ClientId
!= NULL
);
1087 // Get the server Id from the selected advertisement message.
1089 Option
= Dhcp6SeekOption (
1090 Instance
->AdSelect
->Dhcp6
.Option
,
1091 Instance
->AdSelect
->Length
- 4,
1094 if (Option
== NULL
) {
1095 return EFI_DEVICE_ERROR
;
1098 ServerId
= (EFI_DHCP6_DUID
*)(Option
+ 2);
1101 // Calculate the added length of customized option list.
1104 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1105 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1109 // Create the Dhcp6 packet and initialize common fields.
1111 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1112 if (Packet
== NULL
) {
1113 return EFI_OUT_OF_RESOURCES
;
1116 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1117 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1118 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1119 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1122 // Assembly Dhcp6 options for request message.
1124 Cursor
= Packet
->Dhcp6
.Option
;
1126 Length
= HTONS (ClientId
->Length
);
1127 Cursor
= Dhcp6AppendOption (
1129 HTONS (Dhcp6OptClientId
),
1134 Cursor
= Dhcp6AppendETOption (
1140 Cursor
= Dhcp6AppendOption (
1142 HTONS (Dhcp6OptServerId
),
1147 Cursor
= Dhcp6AppendIaOption (
1152 Packet
->Dhcp6
.Header
.MessageType
1156 // Append user-defined when configurate Dhcp6 service.
1158 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1159 UserOpt
= Instance
->Config
->OptionList
[Index
];
1160 Cursor
= Dhcp6AppendOption (
1169 // Determine the size/length of packet.
1171 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1172 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1175 // Callback to user with the packet to be sent and check the user's feedback.
1177 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1179 if (EFI_ERROR (Status
)) {
1185 // Send request packet with the state transition from Dhcp6selecting to
1188 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1190 // Clear initial time for current transaction.
1192 Instance
->StartTime
= 0;
1194 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1196 if (EFI_ERROR (Status
)) {
1202 // Enqueue the sent packet for the retransmission in case reply timeout.
1204 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1208 Create the decline message and send it.
1210 @param[in] Instance The pointer to the Dhcp6 instance.
1211 @param[in] DecIa The pointer to the decline Ia.
1213 @retval EFI_SUCCESS Created and sent the decline message successfully.
1214 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1215 @retval EFI_DEVICE_ERROR An unexpected error.
1216 @retval Others Failed to send the decline message.
1220 Dhcp6SendDeclineMsg (
1221 IN DHCP6_INSTANCE
*Instance
,
1222 IN EFI_DHCP6_IA
*DecIa
1226 EFI_DHCP6_PACKET
*Packet
;
1227 EFI_DHCP6_PACKET
*LastReply
;
1228 EFI_DHCP6_DUID
*ClientId
;
1229 EFI_DHCP6_DUID
*ServerId
;
1230 DHCP6_SERVICE
*Service
;
1236 ASSERT (Instance
->Config
!= NULL
);
1237 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1238 ASSERT (Instance
->Service
!= NULL
);
1240 Service
= Instance
->Service
;
1241 ClientId
= Service
->ClientId
;
1242 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1244 ASSERT (ClientId
!= NULL
);
1245 ASSERT (LastReply
!= NULL
);
1248 // Get the server Id from the last reply message.
1250 Option
= Dhcp6SeekOption (
1251 LastReply
->Dhcp6
.Option
,
1252 LastReply
->Length
- 4,
1255 if (Option
== NULL
) {
1256 return EFI_DEVICE_ERROR
;
1260 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1262 ServerId
= (EFI_DHCP6_DUID
*)(Option
+ 2);
1265 // Create the Dhcp6 packet and initialize common fields.
1267 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1268 if (Packet
== NULL
) {
1269 return EFI_OUT_OF_RESOURCES
;
1272 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1273 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1274 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1275 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1278 // Assembly Dhcp6 options for rebind/renew message.
1280 Cursor
= Packet
->Dhcp6
.Option
;
1282 Length
= HTONS (ClientId
->Length
);
1283 Cursor
= Dhcp6AppendOption (
1285 HTONS (Dhcp6OptClientId
),
1290 Cursor
= Dhcp6AppendETOption (
1296 Cursor
= Dhcp6AppendOption (
1298 HTONS (Dhcp6OptServerId
),
1303 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1306 // Determine the size/length of packet.
1308 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1309 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1312 // Callback to user with the packet to be sent and check the user's feedback.
1314 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1316 if (EFI_ERROR (Status
)) {
1322 // Send decline packet with the state transition from Dhcp6bound to
1325 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1327 // Clear initial time for current transaction.
1329 Instance
->StartTime
= 0;
1331 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1333 if (EFI_ERROR (Status
)) {
1339 // Enqueue the sent packet for the retransmission in case reply timeout.
1341 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1345 Create the release message and send it.
1347 @param[in] Instance The pointer to the Dhcp6 instance.
1348 @param[in] RelIa The pointer to the release Ia.
1350 @retval EFI_SUCCESS Created and sent the release message successfully.
1351 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1352 @retval EFI_DEVICE_ERROR An unexpected error.
1353 @retval Others Failed to send the release message.
1357 Dhcp6SendReleaseMsg (
1358 IN DHCP6_INSTANCE
*Instance
,
1359 IN EFI_DHCP6_IA
*RelIa
1363 EFI_DHCP6_PACKET
*Packet
;
1364 EFI_DHCP6_PACKET
*LastReply
;
1365 EFI_DHCP6_DUID
*ClientId
;
1366 EFI_DHCP6_DUID
*ServerId
;
1367 DHCP6_SERVICE
*Service
;
1373 ASSERT (Instance
->Config
);
1374 ASSERT (Instance
->IaCb
.Ia
);
1376 Service
= Instance
->Service
;
1377 ClientId
= Service
->ClientId
;
1378 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1384 // Get the server Id from the last reply message.
1386 Option
= Dhcp6SeekOption (
1387 LastReply
->Dhcp6
.Option
,
1388 LastReply
->Length
- 4,
1391 if (Option
== NULL
) {
1392 return EFI_DEVICE_ERROR
;
1395 ServerId
= (EFI_DHCP6_DUID
*)(Option
+ 2);
1398 // Create the Dhcp6 packet and initialize common fields.
1400 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1401 if (Packet
== NULL
) {
1402 return EFI_OUT_OF_RESOURCES
;
1405 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1406 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1407 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1408 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1411 // Assembly Dhcp6 options for rebind/renew message
1413 Cursor
= Packet
->Dhcp6
.Option
;
1415 Length
= HTONS (ClientId
->Length
);
1416 Cursor
= Dhcp6AppendOption (
1418 HTONS (Dhcp6OptClientId
),
1424 // ServerId is extracted from packet, it's network order.
1426 Cursor
= Dhcp6AppendOption (
1428 HTONS (Dhcp6OptServerId
),
1433 Cursor
= Dhcp6AppendETOption (
1439 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1442 // Determine the size/length of packet
1444 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1445 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1448 // Callback to user with the packet to be sent and check the user's feedback.
1450 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1452 if (EFI_ERROR (Status
)) {
1458 // Send release packet with the state transition from Dhcp6bound to
1461 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1463 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1465 if (EFI_ERROR (Status
)) {
1471 // Enqueue the sent packet for the retransmission in case reply timeout.
1473 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1477 Create the renew/rebind message and send it.
1479 @param[in] Instance The pointer to the Dhcp6 instance.
1480 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1481 Otherwise, it is a Renew type message.
1483 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1484 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1485 @retval EFI_DEVICE_ERROR An unexpected error.
1486 @retval Others Failed to send the renew/rebind message.
1490 Dhcp6SendRenewRebindMsg (
1491 IN DHCP6_INSTANCE
*Instance
,
1492 IN BOOLEAN RebindRequest
1496 EFI_DHCP6_PACKET
*Packet
;
1497 EFI_DHCP6_PACKET
*LastReply
;
1498 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1499 EFI_DHCP6_DUID
*ClientId
;
1500 EFI_DHCP6_DUID
*ServerId
;
1501 EFI_DHCP6_STATE State
;
1502 EFI_DHCP6_EVENT Event
;
1503 DHCP6_SERVICE
*Service
;
1511 ASSERT (Instance
->Config
);
1512 ASSERT (Instance
->IaCb
.Ia
);
1514 Service
= Instance
->Service
;
1515 ClientId
= Service
->ClientId
;
1520 // Calculate the added length of customized option list.
1523 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1524 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1528 // Create the Dhcp6 packet and initialize common fields.
1530 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1531 if (Packet
== NULL
) {
1532 return EFI_OUT_OF_RESOURCES
;
1535 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1536 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1537 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1538 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1541 // Assembly Dhcp6 options for rebind/renew message.
1543 Cursor
= Packet
->Dhcp6
.Option
;
1545 Length
= HTONS (ClientId
->Length
);
1546 Cursor
= Dhcp6AppendOption (
1548 HTONS (Dhcp6OptClientId
),
1553 Cursor
= Dhcp6AppendETOption (
1559 Cursor
= Dhcp6AppendIaOption (
1564 Packet
->Dhcp6
.Header
.MessageType
1567 if (!RebindRequest
) {
1569 // Get the server Id from the last reply message and
1570 // insert it for rebind request.
1572 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1575 Option
= Dhcp6SeekOption (
1576 LastReply
->Dhcp6
.Option
,
1577 LastReply
->Length
- 4,
1580 if (Option
== NULL
) {
1582 return EFI_DEVICE_ERROR
;
1585 ServerId
= (EFI_DHCP6_DUID
*)(Option
+ 2);
1587 Cursor
= Dhcp6AppendOption (
1589 HTONS (Dhcp6OptServerId
),
1596 // Append user-defined when configurate Dhcp6 service.
1598 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1599 UserOpt
= Instance
->Config
->OptionList
[Index
];
1600 Cursor
= Dhcp6AppendOption (
1609 // Determine the size/length of packet.
1611 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1612 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1615 // Callback to user with the packet to be sent and check the user's feedback.
1617 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1618 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1620 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1622 if (EFI_ERROR (Status
)) {
1628 // Send renew/rebind packet with the state transition from Dhcp6bound to
1629 // Dhcp6renew/rebind.
1630 // And sync the lease time when send renew/rebind, in case that user send
1631 // renew/rebind actively.
1633 Instance
->IaCb
.Ia
->State
= State
;
1634 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1636 // Clear initial time for current transaction.
1638 Instance
->StartTime
= 0;
1640 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1642 if (EFI_ERROR (Status
)) {
1648 // Enqueue the sent packet for the retransmission in case reply timeout.
1650 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1654 Start the information request process.
1656 @param[in] Instance The pointer to the Dhcp6 instance.
1657 @param[in] SendClientId If TRUE, the client identifier option will be included in
1658 information request message. Otherwise, the client identifier
1659 option will not be included.
1660 @param[in] OptionRequest The pointer to the option request option.
1661 @param[in] OptionCount The number options in the OptionList.
1662 @param[in] OptionList The array pointers to the appended options.
1663 @param[in] Retransmission The pointer to the retransmission control.
1664 @param[in] TimeoutEvent The event of timeout.
1665 @param[in] ReplyCallback The callback function when the reply was received.
1666 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1668 @retval EFI_SUCCESS Start the info-request process successfully.
1669 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1670 @retval EFI_NO_MAPPING No source address is available for use.
1671 @retval Others Failed to start the info-request process.
1675 Dhcp6StartInfoRequest (
1676 IN DHCP6_INSTANCE
*Instance
,
1677 IN BOOLEAN SendClientId
,
1678 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1679 IN UINT32 OptionCount
,
1680 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1681 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1682 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1683 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1684 IN VOID
*CallbackContext OPTIONAL
1688 DHCP6_INF_CB
*InfCb
;
1689 DHCP6_SERVICE
*Service
;
1692 Service
= Instance
->Service
;
1694 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1695 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1697 // Create and initialize the control block for the info-request.
1699 InfCb
= AllocateZeroPool (sizeof (DHCP6_INF_CB
));
1701 if (InfCb
== NULL
) {
1702 gBS
->RestoreTPL (OldTpl
);
1703 return EFI_OUT_OF_RESOURCES
;
1706 InfCb
->ReplyCallback
= ReplyCallback
;
1707 InfCb
->CallbackContext
= CallbackContext
;
1708 InfCb
->TimeoutEvent
= TimeoutEvent
;
1710 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1713 // Send the info-request message to start exchange process.
1715 Status
= Dhcp6SendInfoRequestMsg (
1725 if (EFI_ERROR (Status
)) {
1730 // Register receive callback for the stateless exchange process.
1732 Status
= UdpIoRecvDatagram (
1739 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1743 gBS
->RestoreTPL (OldTpl
);
1747 gBS
->RestoreTPL (OldTpl
);
1748 RemoveEntryList (&InfCb
->Link
);
1755 Create the information request message and send it.
1757 @param[in] Instance The pointer to the Dhcp6 instance.
1758 @param[in] InfCb The pointer to the information request control block.
1759 @param[in] SendClientId If TRUE, the client identifier option will be included in
1760 information request message. Otherwise, the client identifier
1761 option will not be included.
1762 @param[in] OptionRequest The pointer to the option request option.
1763 @param[in] OptionCount The number options in the OptionList.
1764 @param[in] OptionList The array pointers to the appended options.
1765 @param[in] Retransmission The pointer to the retransmission control.
1767 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1768 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1769 @retval Others Failed to send the info-request message.
1773 Dhcp6SendInfoRequestMsg (
1774 IN DHCP6_INSTANCE
*Instance
,
1775 IN DHCP6_INF_CB
*InfCb
,
1776 IN BOOLEAN SendClientId
,
1777 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1778 IN UINT32 OptionCount
,
1779 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1780 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1784 EFI_DHCP6_PACKET
*Packet
;
1785 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1786 EFI_DHCP6_DUID
*ClientId
;
1787 DHCP6_SERVICE
*Service
;
1794 ASSERT (OptionRequest
);
1796 Service
= Instance
->Service
;
1797 ClientId
= Service
->ClientId
;
1798 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1803 // Calculate the added length of customized option list.
1805 for (Index
= 0; Index
< OptionCount
; Index
++) {
1806 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1810 // Create the Dhcp6 packet and initialize common fields.
1812 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1813 if (Packet
== NULL
) {
1814 return EFI_OUT_OF_RESOURCES
;
1817 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1818 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1819 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1820 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1822 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1825 // Assembly Dhcp6 options for info-request message.
1827 Cursor
= Packet
->Dhcp6
.Option
;
1830 Length
= HTONS (ClientId
->Length
);
1831 Cursor
= Dhcp6AppendOption (
1833 HTONS (Dhcp6OptClientId
),
1839 Cursor
= Dhcp6AppendETOption (
1845 Cursor
= Dhcp6AppendOption (
1847 OptionRequest
->OpCode
,
1848 OptionRequest
->OpLen
,
1853 // Append user-defined when configurate Dhcp6 service.
1855 for (Index
= 0; Index
< OptionCount
; Index
++) {
1856 UserOpt
= OptionList
[Index
];
1857 Cursor
= Dhcp6AppendOption (
1866 // Determine the size/length of packet.
1868 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1869 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1872 // Clear initial time for current transaction.
1874 Instance
->StartTime
= 0;
1877 // Send info-request packet with no state.
1879 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1881 if (EFI_ERROR (Status
)) {
1887 // Enqueue the sent packet for the retransmission in case reply timeout.
1889 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1893 Create the Confirm message and send it.
1895 @param[in] Instance The pointer to the Dhcp6 instance.
1897 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1898 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1899 @retval EFI_DEVICE_ERROR An unexpected error.
1900 @retval Others Failed to send the confirm message.
1904 Dhcp6SendConfirmMsg (
1905 IN DHCP6_INSTANCE
*Instance
1913 DHCP6_SERVICE
*Service
;
1914 EFI_DHCP6_DUID
*ClientId
;
1915 EFI_DHCP6_PACKET
*Packet
;
1916 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1919 ASSERT (Instance
->Config
!= NULL
);
1920 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1921 ASSERT (Instance
->Service
!= NULL
);
1923 Service
= Instance
->Service
;
1924 ClientId
= Service
->ClientId
;
1925 ASSERT (ClientId
!= NULL
);
1928 // Calculate the added length of customized option list.
1931 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1932 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1936 // Create the Dhcp6 packet and initialize common fields.
1938 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1939 if (Packet
== NULL
) {
1940 return EFI_OUT_OF_RESOURCES
;
1943 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1944 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1945 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1946 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1949 // Assembly Dhcp6 options for solicit message.
1951 Cursor
= Packet
->Dhcp6
.Option
;
1953 Length
= HTONS (ClientId
->Length
);
1954 Cursor
= Dhcp6AppendOption (
1956 HTONS (Dhcp6OptClientId
),
1961 Cursor
= Dhcp6AppendETOption (
1967 Cursor
= Dhcp6AppendIaOption (
1972 Packet
->Dhcp6
.Header
.MessageType
1976 // Append user-defined when configurate Dhcp6 service.
1978 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1979 UserOpt
= Instance
->Config
->OptionList
[Index
];
1980 Cursor
= Dhcp6AppendOption (
1989 // Determine the size/length of packet.
1991 Packet
->Length
+= (UINT32
)(Cursor
- Packet
->Dhcp6
.Option
);
1992 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1995 // Callback to user with the packet to be sent and check the user's feedback.
1997 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
1999 if (EFI_ERROR (Status
)) {
2005 // Send confirm packet with the state transition from Dhcp6Bound to
2008 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2010 // Clear initial time for current transaction.
2012 Instance
->StartTime
= 0;
2014 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2016 if (EFI_ERROR (Status
)) {
2022 // Enqueue the sent packet for the retransmission in case reply timeout.
2024 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2028 Handle with the Dhcp6 reply message.
2030 @param[in] Instance The pointer to Dhcp6 instance.
2031 @param[in] Packet The pointer to the Dhcp6 reply message.
2033 @retval EFI_SUCCESS Processed the reply message successfully.
2034 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2035 @retval EFI_DEVICE_ERROR An unexpected error.
2036 @retval Others Failed to process the reply message.
2040 Dhcp6HandleReplyMsg (
2041 IN DHCP6_INSTANCE
*Instance
,
2042 IN EFI_DHCP6_PACKET
*Packet
2049 ASSERT (Instance
->Config
!= NULL
);
2050 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2051 ASSERT (Packet
!= NULL
);
2053 Status
= EFI_SUCCESS
;
2055 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2056 return EFI_DEVICE_ERROR
;
2060 // If the client subsequently receives a valid reply message that includes a
2061 // rapid commit option since send a solicit with rapid commit option before,
2062 // preocess the reply message and discard any reply messages received in
2063 // response to the request message.
2064 // See details in the section-17.1.4 of rfc-3315.
2066 Option
= Dhcp6SeekOption (
2067 Packet
->Dhcp6
.Option
,
2072 if (((Option
!= NULL
) && !Instance
->Config
->RapidCommit
) || ((Option
== NULL
) && Instance
->Config
->RapidCommit
)) {
2073 return EFI_DEVICE_ERROR
;
2077 // As to a valid reply packet in response to a request/renew/rebind packet,
2078 // ignore the packet if not contains the Ia option
2080 if ((Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
) ||
2081 (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
) ||
2082 (Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
)
2085 Option
= Dhcp6SeekIaOption (
2086 Packet
->Dhcp6
.Option
,
2088 &Instance
->Config
->IaDescriptor
2090 if (Option
== NULL
) {
2096 // Callback to user with the received packet and check the user's feedback.
2098 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2100 if (EFI_ERROR (Status
)) {
2105 // When receive a valid reply packet in response to a decline/release packet,
2106 // the client considers the decline/release event completed regardless of the
2109 if ((Instance
->IaCb
.Ia
->State
== Dhcp6Declining
) || (Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
)) {
2110 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2111 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2113 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2114 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2115 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2116 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2120 // For sync, set the success flag out of polling in decline/release.
2122 Instance
->UdpSts
= EFI_SUCCESS
;
2125 // For async, signal the Ia event to inform Ia information update.
2127 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2128 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2132 // Reset start time for next exchange.
2134 Instance
->StartTime
= 0;
2136 Status
= EFI_SUCCESS
;
2141 // Upon the receipt of a valid reply packet in response to a solicit, request,
2142 // confirm, renew and rebind, the behavior depends on the status code option.
2143 // See the details in the section-18.1.8 of rfc-3315.
2146 Status
= Dhcp6SeekStsOption (
2152 if (!EFI_ERROR (Status
)) {
2154 // No status code or no error status code means succeed to reply.
2156 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2157 if (!EFI_ERROR (Status
)) {
2159 // Reset start time for next exchange.
2161 Instance
->StartTime
= 0;
2164 // Set bound state and store the reply packet.
2166 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2167 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2170 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2172 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2173 Status
= EFI_OUT_OF_RESOURCES
;
2177 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2179 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2182 // For sync, set the success flag out of polling in start/renewrebind.
2184 Instance
->UdpSts
= EFI_SUCCESS
;
2187 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2188 // ReplyMsg for ConfirmMsg should trigger new round to acquire new address. In that
2189 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2190 // consumers can be notified to flush old address.
2192 Dhcp6AppendCacheIa (Instance
);
2195 // For async, signal the Ia event to inform Ia information update.
2197 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2198 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2200 } else if (Status
== EFI_NOT_FOUND
) {
2202 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2203 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2204 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2210 } else if (Option
!= NULL
) {
2212 // Any error status code option is found.
2214 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*)(Option
+ 4)));
2216 case Dhcp6StsUnspecFail
:
2218 // It indicates the server is unable to process the message due to an
2219 // unspecified failure condition, so just retry if possible.
2223 case Dhcp6StsUseMulticast
:
2225 // It indicates the server receives a message via unicast from a client
2226 // to which the server has not sent a unicast option, so retry it by
2227 // multi-cast address.
2229 if (Instance
->Unicast
!= NULL
) {
2230 FreePool (Instance
->Unicast
);
2231 Instance
->Unicast
= NULL
;
2236 case Dhcp6StsNotOnLink
:
2237 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2239 // Before initiate new round DHCP, cache the current IA.
2241 Status
= Dhcp6CacheIa (Instance
);
2242 if (EFI_ERROR (Status
)) {
2247 // Restart S.A.R.R process to acquire new address.
2249 Status
= Dhcp6InitSolicitMsg (Instance
);
2250 if (EFI_ERROR (Status
)) {
2257 case Dhcp6StsNoBinding
:
2258 if ((Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
) || (Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
)) {
2260 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2261 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2263 Status
= Dhcp6SendRequestMsg (Instance
);
2264 if (EFI_ERROR (Status
)) {
2273 // The other status code, just restart solicitation.
2283 if (!EFI_ERROR (Status
)) {
2284 Status
= Dhcp6DequeueRetry (
2286 Packet
->Dhcp6
.Header
.TransactionId
,
2295 Select the appointed Dhcp6 advertisement message.
2297 @param[in] Instance The pointer to the Dhcp6 instance.
2298 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2300 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2301 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2302 @retval Others Failed to select the advertise message.
2306 Dhcp6SelectAdvertiseMsg (
2307 IN DHCP6_INSTANCE
*Instance
,
2308 IN EFI_DHCP6_PACKET
*AdSelect
2314 ASSERT (AdSelect
!= NULL
);
2317 // Callback to user with the selected advertisement packet, and the user
2318 // might overwrite it.
2320 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2322 if (EFI_ERROR (Status
)) {
2326 Instance
->AdSelect
= AdSelect
;
2329 // Dequeue the sent packet for the retransmission since advertisement selected.
2331 Status
= Dhcp6DequeueRetry (
2333 AdSelect
->Dhcp6
.Header
.TransactionId
,
2337 if (EFI_ERROR (Status
)) {
2342 // Check whether there is server unicast option in the selected advertise
2343 // packet, and update it.
2345 Option
= Dhcp6SeekOption (
2346 AdSelect
->Dhcp6
.Option
,
2347 AdSelect
->Length
- 4,
2348 Dhcp6OptServerUnicast
2351 if (Option
!= NULL
) {
2352 Instance
->Unicast
= AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS
));
2354 if (Instance
->Unicast
== NULL
) {
2355 return EFI_OUT_OF_RESOURCES
;
2358 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof (EFI_IPv6_ADDRESS
));
2362 // Update the information of the Ia by the selected advertisement message.
2364 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2366 if (EFI_ERROR (Status
)) {
2371 // Send the request message to continue the S.A.R.R. process.
2373 return Dhcp6SendRequestMsg (Instance
);
2377 Handle with the Dhcp6 advertisement message.
2379 @param[in] Instance The pointer to the Dhcp6 instance.
2380 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2382 @retval EFI_SUCCESS Processed the advertisement message successfully.
2383 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2384 @retval EFI_DEVICE_ERROR An unexpected error.
2385 @retval Others Failed to process the advertise message.
2389 Dhcp6HandleAdvertiseMsg (
2390 IN DHCP6_INSTANCE
*Instance
,
2391 IN EFI_DHCP6_PACKET
*Packet
2398 ASSERT (Instance
->Config
);
2399 ASSERT (Instance
->IaCb
.Ia
);
2404 // If the client does receives a valid reply message that includes a rapid
2405 // commit option since a solicit with rapid commit option sent before, select
2406 // this reply message. Or else, process the advertise messages as normal.
2407 // See details in the section-17.1.4 of rfc-3315.
2409 Option
= Dhcp6SeekOption (
2410 Packet
->Dhcp6
.Option
,
2415 if ((Option
!= NULL
) && Instance
->Config
->RapidCommit
&& (Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
)) {
2416 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2419 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2420 return EFI_DEVICE_ERROR
;
2424 // Client must ignore any advertise message that includes a status code option
2425 // containing the value noaddrsavail, with the exception that the client may
2426 // display the associated status message to the user.
2427 // See the details in the section-17.1.3 of rfc-3315.
2429 Status
= Dhcp6SeekStsOption (
2434 if (EFI_ERROR (Status
)) {
2435 return EFI_DEVICE_ERROR
;
2439 // Callback to user with the received packet and check the user's feedback.
2441 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2443 if (!EFI_ERROR (Status
)) {
2445 // Success means user choose the current advertisement packet.
2447 if (Instance
->AdSelect
!= NULL
) {
2448 FreePool (Instance
->AdSelect
);
2452 // Store the selected advertisement packet and set a flag.
2454 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2456 if (Instance
->AdSelect
== NULL
) {
2457 return EFI_OUT_OF_RESOURCES
;
2460 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2462 Instance
->AdPref
= 0xff;
2463 } else if (Status
== EFI_NOT_READY
) {
2465 // Not_ready means user wants to continue to receive more advertise packets.
2467 if ((Instance
->AdPref
== 0xff) && (Instance
->AdSelect
== NULL
)) {
2469 // It's a tricky point. The timer routine set adpref as 0xff if the first
2470 // rt timeout and no advertisement received, which means any advertisement
2471 // received will be selected after the first rt.
2477 // Check whether the current packet has a 255 preference option or not.
2478 // Take non-preference option as 0 value.
2480 Option
= Dhcp6SeekOption (
2481 Packet
->Dhcp6
.Option
,
2486 if ((Instance
->AdSelect
== NULL
) || ((Option
!= NULL
) && (*(Option
+ 4) > Instance
->AdPref
))) {
2488 // No advertisements received before or preference is more than other
2489 // advertisements received before. Then store the new packet and the
2490 // preference value.
2492 if (Instance
->AdSelect
!= NULL
) {
2493 FreePool (Instance
->AdSelect
);
2496 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2498 if (Instance
->AdSelect
== NULL
) {
2499 return EFI_OUT_OF_RESOURCES
;
2502 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2504 if (Option
!= NULL
) {
2505 Instance
->AdPref
= *(Option
+ 4);
2509 // Non-preference and other advertisements received before or current
2510 // preference is less than other advertisements received before.
2511 // Leave the packet alone.
2515 // Other error status means termination.
2521 // Client must collect advertise messages as more as possible until the first
2522 // RT has elapsed, or get a highest preference 255 advertise.
2523 // See details in the section-17.1.2 of rfc-3315.
2525 if ((Instance
->AdPref
== 0xff) || Timeout
) {
2526 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2533 The Dhcp6 stateful exchange process routine.
2535 @param[in] Instance The pointer to the Dhcp6 instance.
2536 @param[in] Packet The pointer to the received Dhcp6 message.
2540 Dhcp6HandleStateful (
2541 IN DHCP6_INSTANCE
*Instance
,
2542 IN EFI_DHCP6_PACKET
*Packet
2546 EFI_DHCP6_DUID
*ClientId
;
2547 DHCP6_SERVICE
*Service
;
2550 Service
= Instance
->Service
;
2551 ClientId
= Service
->ClientId
;
2552 Status
= EFI_SUCCESS
;
2554 if (Instance
->Config
== NULL
) {
2559 ASSERT (Instance
->Config
);
2560 ASSERT (Instance
->IaCb
.Ia
);
2563 // Discard the packet if not advertisement or reply packet.
2565 if ((Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) && (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
)) {
2570 // Check whether include client Id or not.
2572 Option
= Dhcp6SeekOption (
2573 Packet
->Dhcp6
.Option
,
2578 if ((Option
== NULL
) || (CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0)) {
2583 // Check whether include server Id or not.
2585 Option
= Dhcp6SeekOption (
2586 Packet
->Dhcp6
.Option
,
2591 if (Option
== NULL
) {
2595 switch (Instance
->IaCb
.Ia
->State
) {
2596 case Dhcp6Selecting
:
2598 // Handle the advertisement message when in the Dhcp6Selecting state.
2599 // Do not need check return status, if failed, just continue to the next.
2601 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2604 case Dhcp6Requesting
:
2605 case Dhcp6Confirming
:
2607 case Dhcp6Rebinding
:
2608 case Dhcp6Releasing
:
2609 case Dhcp6Declining
:
2611 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2612 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2613 // If failed here, it should reset the current session.
2615 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2616 if (EFI_ERROR (Status
)) {
2623 // Other state has not supported yet.
2630 // Continue to receive the following Dhcp6 message.
2632 Status
= UdpIoRecvDatagram (
2639 if (EFI_ERROR (Status
)) {
2640 Dhcp6CleanupSession (Instance
, Status
);
2645 The Dhcp6 stateless exchange process routine.
2647 @param[in] Instance The pointer to the Dhcp6 instance.
2648 @param[in] Packet The pointer to the received Dhcp6 message.
2652 Dhcp6HandleStateless (
2653 IN DHCP6_INSTANCE
*Instance
,
2654 IN EFI_DHCP6_PACKET
*Packet
2658 DHCP6_SERVICE
*Service
;
2659 DHCP6_INF_CB
*InfCb
;
2663 Service
= Instance
->Service
;
2664 Status
= EFI_SUCCESS
;
2668 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2673 // Check whether it's a desired Info-request message by Xid.
2675 while (!IsListEmpty (&Instance
->InfList
)) {
2676 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2677 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2688 // Check whether include server Id or not.
2690 Option
= Dhcp6SeekOption (
2691 Packet
->Dhcp6
.Option
,
2696 if (Option
== NULL
) {
2701 // Callback to user with the received packet and check the user's feedback.
2703 Status
= InfCb
->ReplyCallback (
2705 InfCb
->CallbackContext
,
2709 if (Status
== EFI_NOT_READY
) {
2711 // Success or aborted will both stop this info-request exchange process,
2712 // but not ready means user wants to continue to receive reply.
2718 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2719 // if no xid matched.
2723 Packet
->Dhcp6
.Header
.TransactionId
,
2728 // For sync, set the status out of polling for info-request.
2730 Instance
->UdpSts
= Status
;
2734 Status
= UdpIoRecvDatagram (
2741 if (EFI_ERROR (Status
)) {
2742 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2747 The receive callback function for Dhcp6 exchange process.
2749 @param[in] Udp6Wrap The pointer to the received net buffer.
2750 @param[in] EndPoint The pointer to the udp end point.
2751 @param[in] IoStatus The return status from udp io.
2752 @param[in] Context The opaque parameter to the function.
2757 Dhcp6ReceivePacket (
2758 IN NET_BUF
*Udp6Wrap
,
2759 IN UDP_END_POINT
*EndPoint
,
2760 IN EFI_STATUS IoStatus
,
2764 EFI_DHCP6_HEADER
*Head
;
2765 EFI_DHCP6_PACKET
*Packet
;
2766 DHCP6_SERVICE
*Service
;
2767 DHCP6_INSTANCE
*Instance
;
2770 BOOLEAN IsDispatched
;
2771 BOOLEAN IsStateless
;
2778 ASSERT (Udp6Wrap
!= NULL
);
2779 ASSERT (Context
!= NULL
);
2781 Service
= (DHCP6_SERVICE
*)Context
;
2784 IsDispatched
= FALSE
;
2785 IsStateless
= FALSE
;
2787 if (EFI_ERROR (IoStatus
)) {
2791 if (Udp6Wrap
->TotalSize
< sizeof (EFI_DHCP6_HEADER
)) {
2796 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2798 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2799 Packet
= (EFI_DHCP6_PACKET
*)AllocateZeroPool (Size
);
2801 if (Packet
== NULL
) {
2805 Packet
->Size
= Size
;
2806 Head
= &Packet
->Dhcp6
.Header
;
2807 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*)Head
);
2809 if (Packet
->Length
== 0) {
2814 // Dispatch packet to right instance by transaction id.
2816 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2817 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2819 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2820 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2822 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2824 // Find the corresponding packet in tx list, and check it whether belongs
2825 // to stateful exchange process.
2827 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2831 IsDispatched
= TRUE
;
2842 // Skip this packet if not dispatched to any instance.
2844 if (!IsDispatched
) {
2849 // Dispatch the received packet ot the right instance.
2852 Dhcp6HandleStateless (Instance
, Packet
);
2854 Dhcp6HandleStateful (Instance
, Packet
);
2859 if (!IsDispatched
) {
2860 Status
= UdpIoRecvDatagram (
2866 if (EFI_ERROR (Status
)) {
2867 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2868 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2869 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_ALL
);
2874 NetbufFree (Udp6Wrap
);
2876 if (Packet
!= NULL
) {
2882 Detect Link movement for specified network device.
2884 This routine will try to invoke Snp->GetStatus() to get the media status.
2885 If media present status switches from unpresent to present, a link movement
2886 is detected. Note that the underlying UNDI driver may not support reporting
2887 media status from GET_STATUS command. If that, fail to detect link movement.
2889 @param[in] Instance The pointer to DHCP6_INSTANCE.
2891 @retval TRUE A link movement is detected.
2892 @retval FALSE A link movement is not detected.
2896 Dhcp6LinkMovDetect (
2897 IN DHCP6_INSTANCE
*Instance
2900 UINT32 InterruptStatus
;
2901 BOOLEAN MediaPresent
;
2903 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2905 ASSERT (Instance
!= NULL
);
2906 Snp
= Instance
->Service
->Snp
;
2907 MediaPresent
= Instance
->MediaPresent
;
2910 // Check whether SNP support media detection
2912 if (!Snp
->Mode
->MediaPresentSupported
) {
2917 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2919 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2920 if (EFI_ERROR (Status
)) {
2924 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2926 // Media transimit Unpresent to Present means new link movement is detected.
2928 if (!MediaPresent
&& Instance
->MediaPresent
) {
2936 The timer routine of the Dhcp6 instance for each second.
2938 @param[in] Event The timer event.
2939 @param[in] Context The opaque parameter to the function.
2950 LIST_ENTRY
*NextEntry
;
2951 DHCP6_INSTANCE
*Instance
;
2957 ASSERT (Context
!= NULL
);
2959 Instance
= (DHCP6_INSTANCE
*)Context
;
2962 // 1. Loop the tx list, count live time of every tx packet to check whether
2963 // need re-transmit or not.
2965 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
2966 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
2970 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
2972 // Handle the first rt in the transmission of solicit specially.
2974 if (((TxCb
->RetryCnt
== 0) || TxCb
->SolicitRetry
) && (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
)) {
2975 if (Instance
->AdSelect
== NULL
) {
2977 // Set adpref as 0xff here to indicate select any advertisement
2980 Instance
->AdPref
= 0xff;
2983 // Select the advertisement received before.
2985 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2986 if (Status
== EFI_ABORTED
) {
2988 } else if (EFI_ERROR (Status
)) {
2997 // Increase the retry count for the packet and add up the total loss time.
3000 TxCb
->RetryLos
+= TxCb
->RetryExp
;
3003 // Check whether overflow the max retry count limit for this packet
3005 if ((TxCb
->RetryCtl
.Mrc
!= 0) && (TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
)) {
3006 Status
= EFI_NO_RESPONSE
;
3011 // Check whether overflow the max retry duration for this packet
3013 if ((TxCb
->RetryCtl
.Mrd
!= 0) && (TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
)) {
3014 Status
= EFI_NO_RESPONSE
;
3019 // Re-calculate retry expire timeout for the next time.
3021 // Firstly, Check the new calculated time whether overflow the max retry
3024 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3030 if ((TxCb
->RetryCtl
.Mrt
!= 0) && (TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
)) {
3031 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3039 // Secondly, Check the new calculated time whether overflow the max retry
3042 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3043 if ((TxCb
->RetryCtl
.Mrd
!= 0) && (TxCb
->RetryCtl
.Mrd
< LossTime
)) {
3044 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3048 // Reset the tick time for the next retransmission
3053 // Retransmit the last sent packet again.
3055 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3056 TxCb
->SolicitRetry
= FALSE
;
3057 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3058 TxCb
->SolicitRetry
= TRUE
;
3064 // 2. Check the configured Ia, count lease time of every valid Ia to check
3065 // whether need to renew or rebind this Ia.
3067 IaCb
= &Instance
->IaCb
;
3069 if ((Instance
->Config
== NULL
) || (IaCb
->Ia
== NULL
)) {
3073 if ((IaCb
->Ia
->State
== Dhcp6Bound
) || (IaCb
->Ia
->State
== Dhcp6Renewing
) || (IaCb
->Ia
->State
== Dhcp6Rebinding
)) {
3076 if ((IaCb
->LeaseTime
> IaCb
->T2
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3078 // Exceed t2, send rebind packet to extend the Ia lease.
3080 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3081 } else if ((IaCb
->LeaseTime
> IaCb
->T1
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3083 // Exceed t1, send renew packet to extend the Ia lease.
3085 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3090 // 3. In any situation when a client may have moved to a new link, the
3091 // client MUST initiate a Confirm/Reply message exchange.
3093 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3094 Dhcp6SendConfirmMsg (Instance
);
3101 if (Dhcp6IsValidTxCb (Instance
, TxCb
) &&
3102 (TxCb
->TxPacket
!= NULL
) &&
3103 ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) ||
3104 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3105 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
))
3109 // The failure of renew/Confirm will still switch to the bound state.
3111 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3112 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
))
3114 ASSERT (Instance
->IaCb
.Ia
);
3115 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3119 // The failure of info-request will return no response.
3121 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3122 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3132 // The failure of the others will terminate current state machine if timeout.
3134 Dhcp6CleanupSession (Instance
, Status
);