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 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.
207 return EFI_DEVICE_ERROR
;
211 // Insert into the retransmit list of the instance.
213 InsertTailList (&Instance
->TxList
, &TxCb
->Link
);
220 Dequeue the packet from retry list if reply received or timeout at last.
222 @param[in] Instance The pointer to the Dhcp6 instance.
223 @param[in] PacketXid The packet transaction id to match.
224 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
225 Otherwise, this parameter is ignored.
227 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
228 @retval EFI_NOT_FOUND There is no xid matched in retry list.
233 IN DHCP6_INSTANCE
*Instance
,
235 IN BOOLEAN NeedSignal
239 LIST_ENTRY
*NextEntry
;
244 // Seek the retransmit node in the retransmit list by packet xid.
246 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
248 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
249 ASSERT(TxCb
->TxPacket
);
251 if (TxCb
->Xid
== PacketXid
) {
253 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
256 // Seek the info-request node in the info-request list by packet xid.
258 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
260 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
262 if (InfCb
->Xid
== PacketXid
) {
264 // Remove the info-request node, and signal the event if timeout.
266 if (InfCb
->TimeoutEvent
!= NULL
&& NeedSignal
) {
267 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
270 RemoveEntryList (&InfCb
->Link
);
276 // Remove the retransmit node.
278 RemoveEntryList (&TxCb
->Link
);
279 ASSERT(TxCb
->TxPacket
);
280 FreePool (TxCb
->TxPacket
);
286 return EFI_NOT_FOUND
;
291 Clean up the specific nodes in the retry list.
293 @param[in] Instance The pointer to the Dhcp6 instance.
294 @param[in] Scope The scope of cleanup nodes.
299 IN DHCP6_INSTANCE
*Instance
,
304 LIST_ENTRY
*NextEntry
;
309 // Clean up all the stateful messages from the retransmit list.
311 if (Scope
== DHCP6_PACKET_STATEFUL
|| Scope
== DHCP6_PACKET_ALL
) {
313 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
315 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
316 ASSERT(TxCb
->TxPacket
);
318 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgInfoRequest
) {
319 RemoveEntryList (&TxCb
->Link
);
320 FreePool (TxCb
->TxPacket
);
327 // Clean up all the stateless messages from the retransmit list.
329 if (Scope
== DHCP6_PACKET_STATELESS
|| Scope
== DHCP6_PACKET_ALL
) {
332 // Clean up all the retransmit list for stateless messages.
334 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
336 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
337 ASSERT(TxCb
->TxPacket
);
339 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
340 RemoveEntryList (&TxCb
->Link
);
341 FreePool (TxCb
->TxPacket
);
347 // Clean up all the info-request messages list.
349 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
351 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
353 if (InfCb
->TimeoutEvent
!= NULL
) {
354 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
356 RemoveEntryList (&InfCb
->Link
);
363 Check whether the TxCb is still a valid control block in the instance's retry list.
365 @param[in] Instance The pointer to DHCP6_INSTANCE.
366 @param[in] TxCb The control block for a transmitted message.
368 @retval TRUE The control block is in Instance's retry list.
369 @retval FALSE The control block is NOT in Instance's retry list.
374 IN DHCP6_INSTANCE
*Instance
,
380 NET_LIST_FOR_EACH (Entry
, &Instance
->TxList
) {
381 if (TxCb
== NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
)) {
390 Clean up the session of the instance stateful exchange.
392 @param[in, out] Instance The pointer to the Dhcp6 instance.
393 @param[in] Status The return status from udp.
397 Dhcp6CleanupSession (
398 IN OUT DHCP6_INSTANCE
*Instance
,
405 ASSERT(Instance
->Config
);
406 ASSERT(Instance
->IaCb
.Ia
);
409 // Clean up the retransmit list for stateful messages.
411 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
413 if (Instance
->Unicast
!= NULL
) {
414 FreePool (Instance
->Unicast
);
417 if (Instance
->AdSelect
!= NULL
) {
418 FreePool (Instance
->AdSelect
);
421 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
422 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
426 // Reinitialize the Ia fields of the instance.
428 Instance
->UdpSts
= Status
;
429 Instance
->AdSelect
= NULL
;
430 Instance
->AdPref
= 0;
431 Instance
->Unicast
= NULL
;
432 Instance
->IaCb
.T1
= 0;
433 Instance
->IaCb
.T2
= 0;
434 Instance
->IaCb
.AllExpireTime
= 0;
435 Instance
->IaCb
.LeaseTime
= 0;
440 Instance
->StartTime
= 0;
442 Ia
= Instance
->IaCb
.Ia
;
443 Ia
->State
= Dhcp6Init
;
444 Ia
->ReplyPacket
= NULL
;
447 // Set the addresses as zero lifetime, and then the notify
448 // function in Ip6Config will remove these timeout address.
450 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
451 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
452 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
457 // Signal the Ia information updated event to informal user.
459 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
460 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
466 Callback to user when Dhcp6 transmit/receive occurs.
468 @param[in] Instance The pointer to the Dhcp6 instance.
469 @param[in] Event The current Dhcp6 event.
470 @param[in, out] Packet The pointer to the packet sending or received.
472 @retval EFI_SUCCESS The user function returns success.
473 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
474 @retval EFI_ABORTED The user function ask it to abort.
480 IN DHCP6_INSTANCE
*Instance
,
481 IN EFI_DHCP6_EVENT Event
,
482 IN OUT EFI_DHCP6_PACKET
**Packet
486 EFI_DHCP6_PACKET
*NewPacket
;
487 EFI_DHCP6_CALLBACK Callback
;
490 ASSERT (Packet
!= NULL
);
491 ASSERT (Instance
->Config
!= NULL
);
492 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
495 Status
= EFI_SUCCESS
;
496 Callback
= Instance
->Config
->Dhcp6Callback
;
497 Context
= Instance
->Config
->CallbackContext
;
500 // Callback to user with the new message if has.
502 if (Callback
!= NULL
) {
507 Instance
->IaCb
.Ia
->State
,
513 // Updated the new packet from user to replace the original one.
515 if (NewPacket
!= NULL
) {
516 ASSERT (*Packet
!= NULL
);
527 Update Ia according to the new reply message.
529 @param[in, out] Instance The pointer to the Dhcp6 instance.
530 @param[in] Packet The pointer to reply messages.
532 @retval EFI_SUCCESS Updated the Ia information successfully.
533 @retval EFI_DEVICE_ERROR An unexpected error.
538 IN OUT DHCP6_INSTANCE
*Instance
,
539 IN EFI_DHCP6_PACKET
*Packet
550 ASSERT (Instance
->Config
!= NULL
);
552 // If the reply was received in response to a solicit with rapid commit option,
553 // request, renew or rebind message, the client updates the information it has
554 // recorded about IAs from the IA options contained in the reply message:
555 // 1. record the T1 and T2 times
556 // 2. add any new addresses in the IA
557 // 3. discard any addresses from the IA, that have a valid lifetime of 0
558 // 4. update lifetimes for any addresses that already recorded
559 // 5. leave unchanged any information about addresses
561 // See details in the section-18.1.8 of rfc-3315.
563 Option
= Dhcp6SeekIaOption (
564 Packet
->Dhcp6
.Option
,
565 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
566 &Instance
->Config
->IaDescriptor
568 if (Option
== NULL
) {
569 return EFI_DEVICE_ERROR
;
573 // The format of the IA_NA option is:
576 // 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
577 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
578 // | OPTION_IA_NA | option-len |
579 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
580 // | IAID (4 octets) |
581 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 // The format of the IA_TA option is:
594 // 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
595 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
596 // | OPTION_IA_TA | option-len |
597 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
598 // | IAID (4 octets) |
599 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
603 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
607 // sizeof (option-code + option-len + IaId) = 8
608 // sizeof (option-code + option-len + IaId + T1) = 12
609 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
611 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
613 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
614 T1
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 8)));
615 T2
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 12)));
617 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
618 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
619 // the remainder of the message as though the server had not included the invalid IA_NA option.
621 if (T1
> T2
&& T2
> 0) {
622 return EFI_DEVICE_ERROR
;
624 IaInnerOpt
= Option
+ 16;
625 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
629 IaInnerOpt
= Option
+ 8;
630 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
634 // The format of the Status Code option is:
637 // 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
638 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
639 // | OPTION_STATUS_CODE | option-len |
640 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
642 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
644 // . status-message .
646 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
650 // sizeof (option-code + option-len) = 4
652 StsCode
= Dhcp6StsSuccess
;
653 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
655 if (Option
!= NULL
) {
656 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
657 if (StsCode
!= Dhcp6StsSuccess
) {
658 return EFI_DEVICE_ERROR
;
663 // Generate control block for the Ia.
665 Status
= Dhcp6GenerateIaCb (
679 Seek StatusCode Option in package. A Status Code option may appear in the
680 options field of a DHCP message and/or in the options field of another option.
681 See details in section 22.13, RFC3315.
683 @param[in] Instance The pointer to the Dhcp6 instance.
684 @param[in] Packet The pointer to reply messages.
685 @param[out] Option The pointer to status code option.
687 @retval EFI_SUCCESS Seek status code option successfully.
688 @retval EFI_DEVICE_ERROR An unexpected error.
693 IN DHCP6_INSTANCE
*Instance
,
694 IN EFI_DHCP6_PACKET
*Packet
,
703 // Seek StatusCode option directly in DHCP message body. That is, search in
704 // non-encapsulated option fields.
706 *Option
= Dhcp6SeekOption (
707 Packet
->Dhcp6
.Option
,
712 if (*Option
!= NULL
) {
713 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
714 if (StsCode
!= Dhcp6StsSuccess
) {
715 return EFI_DEVICE_ERROR
;
720 // Seek in encapsulated options, IA_NA and IA_TA.
722 *Option
= Dhcp6SeekIaOption (
723 Packet
->Dhcp6
.Option
,
724 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
725 &Instance
->Config
->IaDescriptor
727 if (*Option
== NULL
) {
732 // The format of the IA_NA option is:
735 // 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
736 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737 // | OPTION_IA_NA | option-len |
738 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
739 // | IAID (4 octets) |
740 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
744 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
750 // The format of the IA_TA option is:
753 // 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
754 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
755 // | OPTION_IA_TA | option-len |
756 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
757 // | IAID (4 octets) |
758 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
762 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
766 // sizeof (option-code + option-len + IaId) = 8
767 // sizeof (option-code + option-len + IaId + T1) = 12
768 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
770 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
772 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
773 IaInnerOpt
= *Option
+ 16;
774 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
776 IaInnerOpt
= *Option
+ 8;
777 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
781 // The format of the Status Code option is:
784 // 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
785 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
786 // | OPTION_STATUS_CODE | option-len |
787 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
789 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
791 // . status-message .
793 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
797 // sizeof (option-code + option-len) = 4
799 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
800 if (*Option
!= NULL
) {
801 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
802 if (StsCode
!= Dhcp6StsSuccess
) {
803 return EFI_DEVICE_ERROR
;
812 Transmit Dhcp6 message by udpio.
814 @param[in] Instance The pointer to the Dhcp6 instance.
815 @param[in] Packet The pointer to transmit message.
816 @param[in] Elapsed The pointer to the elapsed time value to fill in.
818 @retval EFI_SUCCESS Successfully transmitted the packet.
819 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
820 @retval Others Failed to transmit the packet.
824 Dhcp6TransmitPacket (
825 IN DHCP6_INSTANCE
*Instance
,
826 IN EFI_DHCP6_PACKET
*Packet
,
834 DHCP6_SERVICE
*Service
;
836 Service
= Instance
->Service
;
839 // Wrap it into a netbuf then send it.
841 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
842 Frag
.Len
= Packet
->Length
;
845 // Do not register free packet here, which will be handled in retry list.
847 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
850 return EFI_OUT_OF_RESOURCES
;
854 // Multicast the Dhcp6 message, unless get the unicast server address by option.
856 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
858 if (Instance
->Unicast
!= NULL
) {
862 sizeof (EFI_IPv6_ADDRESS
)
867 &mAllDhcpRelayAndServersAddress
,
868 sizeof (EFI_IPv6_ADDRESS
)
872 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
873 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
876 // Update the elapsed time value.
878 if (Elapsed
!= NULL
) {
879 SetElapsedTime (Elapsed
, Instance
);
883 // Send out the message by the configured Udp6Io.
885 Status
= UdpIoSendDatagram (
894 if (EFI_ERROR (Status
)) {
904 Create the solicit message and send it.
906 @param[in] Instance The pointer to the Dhcp6 instance.
908 @retval EFI_SUCCESS Created and sent the solicit message successfully.
909 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
910 @retval Others Failed to send the solicit message.
914 Dhcp6SendSolicitMsg (
915 IN DHCP6_INSTANCE
*Instance
919 EFI_DHCP6_PACKET
*Packet
;
920 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
921 EFI_DHCP6_DUID
*ClientId
;
922 DHCP6_SERVICE
*Service
;
929 Service
= Instance
->Service
;
930 ClientId
= Service
->ClientId
;
933 ASSERT (Service
->ClientId
!= NULL
);
934 ASSERT (Instance
->Config
!= NULL
);
935 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
938 // Calculate the added length of customized option list.
940 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
941 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
945 // Create the Dhcp6 packet and initialize common fields.
947 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
948 if (Packet
== NULL
) {
949 return EFI_OUT_OF_RESOURCES
;
952 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
953 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
954 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
955 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
958 // Assembly Dhcp6 options for solicit message.
960 Cursor
= Packet
->Dhcp6
.Option
;
962 Length
= HTONS (ClientId
->Length
);
963 Cursor
= Dhcp6AppendOption (
965 HTONS (Dhcp6OptClientId
),
970 Cursor
= Dhcp6AppendETOption (
976 Cursor
= Dhcp6AppendIaOption (
981 Packet
->Dhcp6
.Header
.MessageType
985 // Append user-defined when configurate Dhcp6 service.
987 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
989 UserOpt
= Instance
->Config
->OptionList
[Index
];
990 Cursor
= Dhcp6AppendOption(
999 // Determine the size/length of packet.
1001 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1002 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1005 // Callback to user with the packet to be sent and check the user's feedback.
1007 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
1009 if (EFI_ERROR (Status
)) {
1015 // Send solicit packet with the state transition from Dhcp6init to
1018 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1020 // Clear initial time for current transaction.
1022 Instance
->StartTime
= 0;
1024 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1026 if (EFI_ERROR (Status
)) {
1032 // Enqueue the sent packet for the retransmission in case reply timeout.
1034 return Dhcp6EnqueueRetry (
1038 Instance
->Config
->SolicitRetransmission
1043 Configure some parameter to initiate SolicitMsg.
1045 @param[in] Instance The pointer to the Dhcp6 instance.
1047 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1048 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1049 @retval Others Failed to send the solicit message.
1053 Dhcp6InitSolicitMsg (
1054 IN DHCP6_INSTANCE
*Instance
1057 Instance
->IaCb
.T1
= 0;
1058 Instance
->IaCb
.T2
= 0;
1059 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1061 return Dhcp6SendSolicitMsg (Instance
);
1066 Create the request message and send it.
1068 @param[in] Instance The pointer to the Dhcp6 instance.
1070 @retval EFI_SUCCESS Created and sent the request message successfully.
1071 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1072 @retval EFI_DEVICE_ERROR An unexpected error.
1073 @retval Others Failed to send the request message.
1077 Dhcp6SendRequestMsg (
1078 IN DHCP6_INSTANCE
*Instance
1082 EFI_DHCP6_PACKET
*Packet
;
1083 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1084 EFI_DHCP6_DUID
*ClientId
;
1085 EFI_DHCP6_DUID
*ServerId
;
1086 DHCP6_SERVICE
*Service
;
1094 ASSERT(Instance
->AdSelect
!= NULL
);
1095 ASSERT(Instance
->Config
!= NULL
);
1096 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1097 ASSERT(Instance
->Service
!= NULL
);
1099 Service
= Instance
->Service
;
1100 ClientId
= Service
->ClientId
;
1102 ASSERT(ClientId
!= NULL
);
1105 // Get the server Id from the selected advertisement message.
1107 Option
= Dhcp6SeekOption (
1108 Instance
->AdSelect
->Dhcp6
.Option
,
1109 Instance
->AdSelect
->Length
- 4,
1112 if (Option
== NULL
) {
1113 return EFI_DEVICE_ERROR
;
1116 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1119 // Calculate the added length of customized option list.
1122 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1123 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1127 // Create the Dhcp6 packet and initialize common fields.
1129 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1130 if (Packet
== NULL
) {
1131 return EFI_OUT_OF_RESOURCES
;
1134 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1135 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1136 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1137 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1140 // Assembly Dhcp6 options for request message.
1142 Cursor
= Packet
->Dhcp6
.Option
;
1144 Length
= HTONS (ClientId
->Length
);
1145 Cursor
= Dhcp6AppendOption (
1147 HTONS (Dhcp6OptClientId
),
1152 Cursor
= Dhcp6AppendETOption (
1158 Cursor
= Dhcp6AppendOption (
1160 HTONS (Dhcp6OptServerId
),
1165 Cursor
= Dhcp6AppendIaOption (
1170 Packet
->Dhcp6
.Header
.MessageType
1174 // Append user-defined when configurate Dhcp6 service.
1176 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1178 UserOpt
= Instance
->Config
->OptionList
[Index
];
1179 Cursor
= Dhcp6AppendOption(
1188 // Determine the size/length of packet.
1190 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1191 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1194 // Callback to user with the packet to be sent and check the user's feedback.
1196 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1198 if (EFI_ERROR (Status
)) {
1204 // Send request packet with the state transition from Dhcp6selecting to
1207 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1209 // Clear initial time for current transaction.
1211 Instance
->StartTime
= 0;
1213 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1215 if (EFI_ERROR (Status
)) {
1221 // Enqueue the sent packet for the retransmission in case reply timeout.
1223 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1228 Create the decline message and send it.
1230 @param[in] Instance The pointer to the Dhcp6 instance.
1231 @param[in] DecIa The pointer to the decline Ia.
1233 @retval EFI_SUCCESS Created and sent the decline message successfully.
1234 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1235 @retval EFI_DEVICE_ERROR An unexpected error.
1236 @retval Others Failed to send the decline message.
1240 Dhcp6SendDeclineMsg (
1241 IN DHCP6_INSTANCE
*Instance
,
1242 IN EFI_DHCP6_IA
*DecIa
1246 EFI_DHCP6_PACKET
*Packet
;
1247 EFI_DHCP6_PACKET
*LastReply
;
1248 EFI_DHCP6_DUID
*ClientId
;
1249 EFI_DHCP6_DUID
*ServerId
;
1250 DHCP6_SERVICE
*Service
;
1256 ASSERT (Instance
->Config
!= NULL
);
1257 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1258 ASSERT (Instance
->Service
!= NULL
);
1260 Service
= Instance
->Service
;
1261 ClientId
= Service
->ClientId
;
1262 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1264 ASSERT (ClientId
!= NULL
);
1265 ASSERT (LastReply
!= NULL
);
1268 // Get the server Id from the last reply message.
1270 Option
= Dhcp6SeekOption (
1271 LastReply
->Dhcp6
.Option
,
1272 LastReply
->Length
- 4,
1275 if (Option
== NULL
) {
1276 return EFI_DEVICE_ERROR
;
1280 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1282 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1285 // Create the Dhcp6 packet and initialize common fields.
1287 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1288 if (Packet
== NULL
) {
1289 return EFI_OUT_OF_RESOURCES
;
1292 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1293 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1294 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1295 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1298 // Assembly Dhcp6 options for rebind/renew message.
1300 Cursor
= Packet
->Dhcp6
.Option
;
1302 Length
= HTONS (ClientId
->Length
);
1303 Cursor
= Dhcp6AppendOption (
1305 HTONS (Dhcp6OptClientId
),
1310 Cursor
= Dhcp6AppendETOption (
1316 Cursor
= Dhcp6AppendOption (
1318 HTONS (Dhcp6OptServerId
),
1323 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1326 // Determine the size/length of packet.
1328 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1329 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1332 // Callback to user with the packet to be sent and check the user's feedback.
1334 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1336 if (EFI_ERROR (Status
)) {
1342 // Send decline packet with the state transition from Dhcp6bound to
1345 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1347 // Clear initial time for current transaction.
1349 Instance
->StartTime
= 0;
1351 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1353 if (EFI_ERROR (Status
)) {
1359 // Enqueue the sent packet for the retransmission in case reply timeout.
1361 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1366 Create the release message and send it.
1368 @param[in] Instance The pointer to the Dhcp6 instance.
1369 @param[in] RelIa The pointer to the release Ia.
1371 @retval EFI_SUCCESS Created and sent the release message successfully.
1372 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1373 @retval EFI_DEVICE_ERROR An unexpected error.
1374 @retval Others Failed to send the release message.
1378 Dhcp6SendReleaseMsg (
1379 IN DHCP6_INSTANCE
*Instance
,
1380 IN EFI_DHCP6_IA
*RelIa
1384 EFI_DHCP6_PACKET
*Packet
;
1385 EFI_DHCP6_PACKET
*LastReply
;
1386 EFI_DHCP6_DUID
*ClientId
;
1387 EFI_DHCP6_DUID
*ServerId
;
1388 DHCP6_SERVICE
*Service
;
1394 ASSERT(Instance
->Config
);
1395 ASSERT(Instance
->IaCb
.Ia
);
1397 Service
= Instance
->Service
;
1398 ClientId
= Service
->ClientId
;
1399 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1405 // Get the server Id from the last reply message.
1407 Option
= Dhcp6SeekOption (
1408 LastReply
->Dhcp6
.Option
,
1409 LastReply
->Length
- 4,
1412 if (Option
== NULL
) {
1413 return EFI_DEVICE_ERROR
;
1416 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1419 // Create the Dhcp6 packet and initialize common fields.
1421 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1422 if (Packet
== NULL
) {
1423 return EFI_OUT_OF_RESOURCES
;
1426 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1427 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1428 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1429 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1432 // Assembly Dhcp6 options for rebind/renew message
1434 Cursor
= Packet
->Dhcp6
.Option
;
1436 Length
= HTONS (ClientId
->Length
);
1437 Cursor
= Dhcp6AppendOption (
1439 HTONS (Dhcp6OptClientId
),
1445 // ServerId is extracted from packet, it's network order.
1447 Cursor
= Dhcp6AppendOption (
1449 HTONS (Dhcp6OptServerId
),
1454 Cursor
= Dhcp6AppendETOption (
1460 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1463 // Determine the size/length of packet
1465 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1466 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1469 // Callback to user with the packet to be sent and check the user's feedback.
1471 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1473 if (EFI_ERROR (Status
)) {
1479 // Send release packet with the state transition from Dhcp6bound to
1482 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1484 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1486 if (EFI_ERROR (Status
)) {
1492 // Enqueue the sent packet for the retransmission in case reply timeout.
1494 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1499 Create the renew/rebind message and send it.
1501 @param[in] Instance The pointer to the Dhcp6 instance.
1502 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1503 Otherwise, it is a Renew type message.
1505 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1506 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1507 @retval EFI_DEVICE_ERROR An unexpected error.
1508 @retval Others Failed to send the renew/rebind message.
1512 Dhcp6SendRenewRebindMsg (
1513 IN DHCP6_INSTANCE
*Instance
,
1514 IN BOOLEAN RebindRequest
1518 EFI_DHCP6_PACKET
*Packet
;
1519 EFI_DHCP6_PACKET
*LastReply
;
1520 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1521 EFI_DHCP6_DUID
*ClientId
;
1522 EFI_DHCP6_DUID
*ServerId
;
1523 EFI_DHCP6_STATE State
;
1524 EFI_DHCP6_EVENT Event
;
1525 DHCP6_SERVICE
*Service
;
1533 ASSERT(Instance
->Config
);
1534 ASSERT(Instance
->IaCb
.Ia
);
1536 Service
= Instance
->Service
;
1537 ClientId
= Service
->ClientId
;
1542 // Calculate the added length of customized option list.
1545 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1546 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1550 // Create the Dhcp6 packet and initialize common fields.
1552 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1553 if (Packet
== NULL
) {
1554 return EFI_OUT_OF_RESOURCES
;
1557 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1558 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1559 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1560 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1563 // Assembly Dhcp6 options for rebind/renew message.
1565 Cursor
= Packet
->Dhcp6
.Option
;
1567 Length
= HTONS (ClientId
->Length
);
1568 Cursor
= Dhcp6AppendOption (
1570 HTONS (Dhcp6OptClientId
),
1575 Cursor
= Dhcp6AppendETOption (
1581 Cursor
= Dhcp6AppendIaOption (
1586 Packet
->Dhcp6
.Header
.MessageType
1589 if (!RebindRequest
) {
1591 // Get the server Id from the last reply message and
1592 // insert it for rebind request.
1594 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1597 Option
= Dhcp6SeekOption (
1598 LastReply
->Dhcp6
.Option
,
1599 LastReply
->Length
- 4,
1602 if (Option
== NULL
) {
1604 return EFI_DEVICE_ERROR
;
1607 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1609 Cursor
= Dhcp6AppendOption (
1611 HTONS (Dhcp6OptServerId
),
1618 // Append user-defined when configurate Dhcp6 service.
1620 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1622 UserOpt
= Instance
->Config
->OptionList
[Index
];
1623 Cursor
= Dhcp6AppendOption(
1632 // Determine the size/length of packet.
1634 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1635 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1638 // Callback to user with the packet to be sent and check the user's feedback.
1640 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1641 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1643 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1645 if (EFI_ERROR (Status
)) {
1651 // Send renew/rebind packet with the state transition from Dhcp6bound to
1652 // Dhcp6renew/rebind.
1653 // And sync the lease time when send renew/rebind, in case that user send
1654 // renew/rebind actively.
1656 Instance
->IaCb
.Ia
->State
= State
;
1657 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1659 // Clear initial time for current transaction.
1661 Instance
->StartTime
= 0;
1663 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1665 if (EFI_ERROR (Status
)) {
1671 // Enqueue the sent packet for the retransmission in case reply timeout.
1673 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1677 Start the information request process.
1679 @param[in] Instance The pointer to the Dhcp6 instance.
1680 @param[in] SendClientId If TRUE, the client identifier option will be included in
1681 information request message. Otherwise, the client identifier
1682 option will not be included.
1683 @param[in] OptionRequest The pointer to the option request option.
1684 @param[in] OptionCount The number options in the OptionList.
1685 @param[in] OptionList The array pointers to the appended options.
1686 @param[in] Retransmission The pointer to the retransmission control.
1687 @param[in] TimeoutEvent The event of timeout.
1688 @param[in] ReplyCallback The callback function when the reply was received.
1689 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1691 @retval EFI_SUCCESS Start the info-request process successfully.
1692 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1693 @retval EFI_NO_MAPPING No source address is available for use.
1694 @retval Others Failed to start the info-request process.
1698 Dhcp6StartInfoRequest (
1699 IN DHCP6_INSTANCE
*Instance
,
1700 IN BOOLEAN SendClientId
,
1701 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1702 IN UINT32 OptionCount
,
1703 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1704 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1705 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1706 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1707 IN VOID
*CallbackContext OPTIONAL
1711 DHCP6_INF_CB
*InfCb
;
1712 DHCP6_SERVICE
*Service
;
1715 Service
= Instance
->Service
;
1717 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1718 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1720 // Create and initialize the control block for the info-request.
1722 InfCb
= AllocateZeroPool (sizeof(DHCP6_INF_CB
));
1724 if (InfCb
== NULL
) {
1725 gBS
->RestoreTPL (OldTpl
);
1726 return EFI_OUT_OF_RESOURCES
;
1729 InfCb
->ReplyCallback
= ReplyCallback
;
1730 InfCb
->CallbackContext
= CallbackContext
;
1731 InfCb
->TimeoutEvent
= TimeoutEvent
;
1733 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1736 // Send the info-request message to start exchange process.
1738 Status
= Dhcp6SendInfoRequestMsg (
1748 if (EFI_ERROR (Status
)) {
1753 // Register receive callback for the stateless exchange process.
1755 Status
= UdpIoRecvDatagram(
1762 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1766 gBS
->RestoreTPL (OldTpl
);
1770 gBS
->RestoreTPL (OldTpl
);
1771 RemoveEntryList (&InfCb
->Link
);
1778 Create the information request message and send it.
1780 @param[in] Instance The pointer to the Dhcp6 instance.
1781 @param[in] InfCb The pointer to the information request control block.
1782 @param[in] SendClientId If TRUE, the client identifier option will be included in
1783 information request message. Otherwise, the client identifier
1784 option will not be included.
1785 @param[in] OptionRequest The pointer to the option request option.
1786 @param[in] OptionCount The number options in the OptionList.
1787 @param[in] OptionList The array pointers to the appended options.
1788 @param[in] Retransmission The pointer to the retransmission control.
1790 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1791 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1792 @retval Others Failed to send the info-request message.
1796 Dhcp6SendInfoRequestMsg (
1797 IN DHCP6_INSTANCE
*Instance
,
1798 IN DHCP6_INF_CB
*InfCb
,
1799 IN BOOLEAN SendClientId
,
1800 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1801 IN UINT32 OptionCount
,
1802 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1803 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1807 EFI_DHCP6_PACKET
*Packet
;
1808 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1809 EFI_DHCP6_DUID
*ClientId
;
1810 DHCP6_SERVICE
*Service
;
1817 ASSERT(OptionRequest
);
1819 Service
= Instance
->Service
;
1820 ClientId
= Service
->ClientId
;
1821 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1826 // Calculate the added length of customized option list.
1828 for (Index
= 0; Index
< OptionCount
; Index
++) {
1829 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1833 // Create the Dhcp6 packet and initialize common fields.
1835 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1836 if (Packet
== NULL
) {
1837 return EFI_OUT_OF_RESOURCES
;
1840 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1841 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1842 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1843 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1845 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1848 // Assembly Dhcp6 options for info-request message.
1850 Cursor
= Packet
->Dhcp6
.Option
;
1853 Length
= HTONS (ClientId
->Length
);
1854 Cursor
= Dhcp6AppendOption (
1856 HTONS (Dhcp6OptClientId
),
1862 Cursor
= Dhcp6AppendETOption (
1868 Cursor
= Dhcp6AppendOption (
1870 OptionRequest
->OpCode
,
1871 OptionRequest
->OpLen
,
1876 // Append user-defined when configurate Dhcp6 service.
1878 for (Index
= 0; Index
< OptionCount
; Index
++) {
1880 UserOpt
= OptionList
[Index
];
1881 Cursor
= Dhcp6AppendOption(
1890 // Determine the size/length of packet.
1892 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1893 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1896 // Clear initial time for current transaction.
1898 Instance
->StartTime
= 0;
1901 // Send info-request packet with no state.
1903 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1905 if (EFI_ERROR (Status
)) {
1911 // Enqueue the sent packet for the retransmission in case reply timeout.
1913 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1918 Create the Confirm message and send it.
1920 @param[in] Instance The pointer to the Dhcp6 instance.
1922 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1923 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1924 @retval EFI_DEVICE_ERROR An unexpected error.
1925 @retval Others Failed to send the confirm message.
1929 Dhcp6SendConfirmMsg (
1930 IN DHCP6_INSTANCE
*Instance
1938 DHCP6_SERVICE
*Service
;
1939 EFI_DHCP6_DUID
*ClientId
;
1940 EFI_DHCP6_PACKET
*Packet
;
1941 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1944 ASSERT (Instance
->Config
!= NULL
);
1945 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1946 ASSERT (Instance
->Service
!= NULL
);
1948 Service
= Instance
->Service
;
1949 ClientId
= Service
->ClientId
;
1950 ASSERT (ClientId
!= NULL
);
1953 // Calculate the added length of customized option list.
1956 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1957 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1961 // Create the Dhcp6 packet and initialize common fields.
1963 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1964 if (Packet
== NULL
) {
1965 return EFI_OUT_OF_RESOURCES
;
1968 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1969 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1970 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1971 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1974 // Assembly Dhcp6 options for solicit message.
1976 Cursor
= Packet
->Dhcp6
.Option
;
1978 Length
= HTONS (ClientId
->Length
);
1979 Cursor
= Dhcp6AppendOption (
1981 HTONS (Dhcp6OptClientId
),
1986 Cursor
= Dhcp6AppendETOption (
1992 Cursor
= Dhcp6AppendIaOption (
1997 Packet
->Dhcp6
.Header
.MessageType
2001 // Append user-defined when configurate Dhcp6 service.
2003 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
2004 UserOpt
= Instance
->Config
->OptionList
[Index
];
2005 Cursor
= Dhcp6AppendOption (
2014 // Determine the size/length of packet.
2016 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
2017 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
2020 // Callback to user with the packet to be sent and check the user's feedback.
2022 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
2024 if (EFI_ERROR (Status
)) {
2030 // Send confirm packet with the state transition from Dhcp6Bound to
2033 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2035 // Clear initial time for current transaction.
2037 Instance
->StartTime
= 0;
2039 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2041 if (EFI_ERROR (Status
)) {
2047 // Enqueue the sent packet for the retransmission in case reply timeout.
2049 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2055 Handle with the Dhcp6 reply message.
2057 @param[in] Instance The pointer to Dhcp6 instance.
2058 @param[in] Packet The pointer to the Dhcp6 reply message.
2060 @retval EFI_SUCCESS Processed the reply message successfully.
2061 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2062 @retval EFI_DEVICE_ERROR An unexpected error.
2063 @retval Others Failed to process the reply message.
2067 Dhcp6HandleReplyMsg (
2068 IN DHCP6_INSTANCE
*Instance
,
2069 IN EFI_DHCP6_PACKET
*Packet
2076 ASSERT (Instance
->Config
!= NULL
);
2077 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2078 ASSERT (Packet
!= NULL
);
2080 Status
= EFI_SUCCESS
;
2082 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2083 return EFI_DEVICE_ERROR
;
2087 // If the client subsequently receives a valid reply message that includes a
2088 // rapid commit option since send a solicit with rapid commit option before,
2089 // preocess the reply message and discard any reply messages received in
2090 // response to the request message.
2091 // See details in the section-17.1.4 of rfc-3315.
2093 Option
= Dhcp6SeekOption (
2094 Packet
->Dhcp6
.Option
,
2099 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
2100 return EFI_DEVICE_ERROR
;
2104 // As to a valid reply packet in response to a request/renew/rebind packet,
2105 // ignore the packet if not contains the Ia option
2107 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
2108 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
2109 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
2112 Option
= Dhcp6SeekIaOption (
2113 Packet
->Dhcp6
.Option
,
2115 &Instance
->Config
->IaDescriptor
2117 if (Option
== NULL
) {
2123 // Callback to user with the received packet and check the user's feedback.
2125 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2127 if (EFI_ERROR (Status
)) {
2132 // When receive a valid reply packet in response to a decline/release packet,
2133 // the client considers the decline/release event completed regardless of the
2136 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
2138 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2139 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2141 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2142 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2143 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2144 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2148 // For sync, set the success flag out of polling in decline/release.
2150 Instance
->UdpSts
= EFI_SUCCESS
;
2153 // For async, signal the Ia event to inform Ia information update.
2155 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2156 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2160 // Reset start time for next exchange.
2162 Instance
->StartTime
= 0;
2164 Status
= EFI_SUCCESS
;
2169 // Upon the receipt of a valid reply packet in response to a solicit, request,
2170 // confirm, renew and rebind, the behavior depends on the status code option.
2171 // See the details in the section-18.1.8 of rfc-3315.
2174 Status
= Dhcp6SeekStsOption (
2180 if (!EFI_ERROR (Status
)) {
2182 // No status code or no error status code means succeed to reply.
2184 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2185 if (!EFI_ERROR (Status
)) {
2187 // Reset start time for next exchange.
2189 Instance
->StartTime
= 0;
2192 // Set bound state and store the reply packet.
2194 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2195 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2198 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2200 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2201 Status
= EFI_OUT_OF_RESOURCES
;
2205 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2207 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2210 // For sync, set the success flag out of polling in start/renewrebind.
2212 Instance
->UdpSts
= EFI_SUCCESS
;
2215 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2216 // ReplyMsg for ConfirmMsg should trigger new round to acquire new address. In that
2217 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2218 // consumers can be notified to flush old address.
2220 Dhcp6AppendCacheIa (Instance
);
2223 // For async, signal the Ia event to inform Ia information update.
2225 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2226 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2228 } else if (Status
== EFI_NOT_FOUND
) {
2230 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2231 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2232 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2239 } else if (Option
!= NULL
) {
2241 // Any error status code option is found.
2243 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2245 case Dhcp6StsUnspecFail
:
2247 // It indicates the server is unable to process the message due to an
2248 // unspecified failure condition, so just retry if possible.
2252 case Dhcp6StsUseMulticast
:
2254 // It indicates the server receives a message via unicast from a client
2255 // to which the server has not sent a unicast option, so retry it by
2256 // multi-cast address.
2258 if (Instance
->Unicast
!= NULL
) {
2259 FreePool (Instance
->Unicast
);
2260 Instance
->Unicast
= NULL
;
2264 case Dhcp6StsNotOnLink
:
2265 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2267 // Before initiate new round DHCP, cache the current IA.
2269 Status
= Dhcp6CacheIa (Instance
);
2270 if (EFI_ERROR (Status
)) {
2275 // Restart S.A.R.R process to acquire new address.
2277 Status
= Dhcp6InitSolicitMsg (Instance
);
2278 if (EFI_ERROR (Status
)) {
2284 case Dhcp6StsNoBinding
:
2285 if (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
|| Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
) {
2287 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2288 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2290 Status
= Dhcp6SendRequestMsg(Instance
);
2291 if (EFI_ERROR (Status
)) {
2299 // The other status code, just restart solicitation.
2309 if (!EFI_ERROR(Status
)) {
2310 Status
= Dhcp6DequeueRetry (
2312 Packet
->Dhcp6
.Header
.TransactionId
,
2322 Select the appointed Dhcp6 advertisement message.
2324 @param[in] Instance The pointer to the Dhcp6 instance.
2325 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2327 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2328 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2329 @retval Others Failed to select the advertise message.
2333 Dhcp6SelectAdvertiseMsg (
2334 IN DHCP6_INSTANCE
*Instance
,
2335 IN EFI_DHCP6_PACKET
*AdSelect
2341 ASSERT (AdSelect
!= NULL
);
2344 // Callback to user with the selected advertisement packet, and the user
2345 // might overwrite it.
2347 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2349 if (EFI_ERROR (Status
)) {
2353 Instance
->AdSelect
= AdSelect
;
2356 // Dequeue the sent packet for the retransmission since advertisement selected.
2358 Status
= Dhcp6DequeueRetry (
2360 AdSelect
->Dhcp6
.Header
.TransactionId
,
2364 if (EFI_ERROR(Status
)) {
2369 // Check whether there is server unicast option in the selected advertise
2370 // packet, and update it.
2372 Option
= Dhcp6SeekOption(
2373 AdSelect
->Dhcp6
.Option
,
2374 AdSelect
->Length
- 4,
2375 Dhcp6OptServerUnicast
2378 if (Option
!= NULL
) {
2380 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2382 if (Instance
->Unicast
== NULL
) {
2383 return EFI_OUT_OF_RESOURCES
;
2386 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2390 // Update the information of the Ia by the selected advertisement message.
2392 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2394 if (EFI_ERROR (Status
)) {
2399 // Send the request message to continue the S.A.R.R. process.
2401 return Dhcp6SendRequestMsg (Instance
);
2406 Handle with the Dhcp6 advertisement message.
2408 @param[in] Instance The pointer to the Dhcp6 instance.
2409 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2411 @retval EFI_SUCCESS Processed the advertisement message successfully.
2412 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2413 @retval EFI_DEVICE_ERROR An unexpected error.
2414 @retval Others Failed to process the advertise message.
2418 Dhcp6HandleAdvertiseMsg (
2419 IN DHCP6_INSTANCE
*Instance
,
2420 IN EFI_DHCP6_PACKET
*Packet
2427 ASSERT(Instance
->Config
);
2428 ASSERT(Instance
->IaCb
.Ia
);
2433 // If the client does receives a valid reply message that includes a rapid
2434 // commit option since a solicit with rapid commit option sent before, select
2435 // this reply message. Or else, process the advertise messages as normal.
2436 // See details in the section-17.1.4 of rfc-3315.
2438 Option
= Dhcp6SeekOption(
2439 Packet
->Dhcp6
.Option
,
2444 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2446 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2449 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2450 return EFI_DEVICE_ERROR
;
2454 // Client must ignore any advertise message that includes a status code option
2455 // containing the value noaddrsavail, with the exception that the client may
2456 // display the associated status message to the user.
2457 // See the details in the section-17.1.3 of rfc-3315.
2459 Status
= Dhcp6SeekStsOption (
2464 if (EFI_ERROR (Status
)) {
2465 return EFI_DEVICE_ERROR
;
2469 // Callback to user with the received packet and check the user's feedback.
2471 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2473 if (!EFI_ERROR (Status
)) {
2475 // Success means user choose the current advertisement packet.
2477 if (Instance
->AdSelect
!= NULL
) {
2478 FreePool (Instance
->AdSelect
);
2482 // Store the selected advertisement packet and set a flag.
2484 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2486 if (Instance
->AdSelect
== NULL
) {
2487 return EFI_OUT_OF_RESOURCES
;
2490 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2492 Instance
->AdPref
= 0xff;
2494 } else if (Status
== EFI_NOT_READY
) {
2496 // Not_ready means user wants to continue to receive more advertise packets.
2498 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2500 // It's a tricky point. The timer routine set adpref as 0xff if the first
2501 // rt timeout and no advertisement received, which means any advertisement
2502 // received will be selected after the first rt.
2508 // Check whether the current packet has a 255 preference option or not.
2509 // Take non-preference option as 0 value.
2511 Option
= Dhcp6SeekOption(
2512 Packet
->Dhcp6
.Option
,
2517 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2519 // No advertisements received before or preference is more than other
2520 // advertisements received before. Then store the new packet and the
2521 // preference value.
2523 if (Instance
->AdSelect
!= NULL
) {
2524 FreePool (Instance
->AdSelect
);
2527 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2529 if (Instance
->AdSelect
== NULL
) {
2530 return EFI_OUT_OF_RESOURCES
;
2533 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2535 if (Option
!= NULL
) {
2536 Instance
->AdPref
= *(Option
+ 4);
2540 // Non-preference and other advertisements received before or current
2541 // preference is less than other advertisements received before.
2542 // Leave the packet alone.
2547 // Other error status means termination.
2553 // Client must collect advertise messages as more as possible until the first
2554 // RT has elapsed, or get a highest preference 255 advertise.
2555 // See details in the section-17.1.2 of rfc-3315.
2557 if (Instance
->AdPref
== 0xff || Timeout
) {
2558 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2566 The Dhcp6 stateful exchange process routine.
2568 @param[in] Instance The pointer to the Dhcp6 instance.
2569 @param[in] Packet The pointer to the received Dhcp6 message.
2573 Dhcp6HandleStateful (
2574 IN DHCP6_INSTANCE
*Instance
,
2575 IN EFI_DHCP6_PACKET
*Packet
2579 EFI_DHCP6_DUID
*ClientId
;
2580 DHCP6_SERVICE
*Service
;
2583 Service
= Instance
->Service
;
2584 ClientId
= Service
->ClientId
;
2585 Status
= EFI_SUCCESS
;
2587 if (Instance
->Config
== NULL
) {
2592 ASSERT (Instance
->Config
);
2593 ASSERT (Instance
->IaCb
.Ia
);
2596 // Discard the packet if not advertisement or reply packet.
2598 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2603 // Check whether include client Id or not.
2605 Option
= Dhcp6SeekOption(
2606 Packet
->Dhcp6
.Option
,
2611 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2616 // Check whether include server Id or not.
2618 Option
= Dhcp6SeekOption(
2619 Packet
->Dhcp6
.Option
,
2624 if (Option
== NULL
) {
2628 switch (Instance
->IaCb
.Ia
->State
) {
2629 case Dhcp6Selecting
:
2631 // Handle the advertisement message when in the Dhcp6Selecting state.
2632 // Do not need check return status, if failed, just continue to the next.
2634 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2637 case Dhcp6Requesting
:
2638 case Dhcp6Confirming
:
2640 case Dhcp6Rebinding
:
2641 case Dhcp6Releasing
:
2642 case Dhcp6Declining
:
2644 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2645 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2646 // If failed here, it should reset the current session.
2648 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2649 if (EFI_ERROR (Status
)) {
2655 // Other state has not supported yet.
2662 // Continue to receive the following Dhcp6 message.
2664 Status
= UdpIoRecvDatagram (
2671 if (EFI_ERROR (Status
)) {
2672 Dhcp6CleanupSession (Instance
, Status
);
2678 The Dhcp6 stateless exchange process routine.
2680 @param[in] Instance The pointer to the Dhcp6 instance.
2681 @param[in] Packet The pointer to the received Dhcp6 message.
2685 Dhcp6HandleStateless (
2686 IN DHCP6_INSTANCE
*Instance
,
2687 IN EFI_DHCP6_PACKET
*Packet
2691 DHCP6_SERVICE
*Service
;
2692 DHCP6_INF_CB
*InfCb
;
2696 Service
= Instance
->Service
;
2697 Status
= EFI_SUCCESS
;
2701 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2706 // Check whether it's a desired Info-request message by Xid.
2708 while (!IsListEmpty (&Instance
->InfList
)) {
2709 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2710 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2721 // Check whether include server Id or not.
2723 Option
= Dhcp6SeekOption (
2724 Packet
->Dhcp6
.Option
,
2729 if (Option
== NULL
) {
2734 // Callback to user with the received packet and check the user's feedback.
2736 Status
= InfCb
->ReplyCallback (
2738 InfCb
->CallbackContext
,
2742 if (Status
== EFI_NOT_READY
) {
2744 // Success or aborted will both stop this info-request exchange process,
2745 // but not ready means user wants to continue to receive reply.
2751 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2752 // if no xid matched.
2756 Packet
->Dhcp6
.Header
.TransactionId
,
2761 // For sync, set the status out of polling for info-request.
2763 Instance
->UdpSts
= Status
;
2767 Status
= UdpIoRecvDatagram (
2774 if (EFI_ERROR (Status
)) {
2775 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2781 The receive callback function for Dhcp6 exchange process.
2783 @param[in] Udp6Wrap The pointer to the received net buffer.
2784 @param[in] EndPoint The pointer to the udp end point.
2785 @param[in] IoStatus The return status from udp io.
2786 @param[in] Context The opaque parameter to the function.
2791 Dhcp6ReceivePacket (
2792 IN NET_BUF
*Udp6Wrap
,
2793 IN UDP_END_POINT
*EndPoint
,
2794 IN EFI_STATUS IoStatus
,
2798 EFI_DHCP6_HEADER
*Head
;
2799 EFI_DHCP6_PACKET
*Packet
;
2800 DHCP6_SERVICE
*Service
;
2801 DHCP6_INSTANCE
*Instance
;
2804 BOOLEAN IsDispatched
;
2805 BOOLEAN IsStateless
;
2812 ASSERT (Udp6Wrap
!= NULL
);
2813 ASSERT (Context
!= NULL
);
2815 Service
= (DHCP6_SERVICE
*) Context
;
2818 IsDispatched
= FALSE
;
2819 IsStateless
= FALSE
;
2821 if (EFI_ERROR (IoStatus
)) {
2825 if (Udp6Wrap
->TotalSize
< sizeof (EFI_DHCP6_HEADER
)) {
2830 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2832 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2833 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2835 if (Packet
== NULL
) {
2839 Packet
->Size
= Size
;
2840 Head
= &Packet
->Dhcp6
.Header
;
2841 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2843 if (Packet
->Length
== 0) {
2848 // Dispatch packet to right instance by transaction id.
2850 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2852 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2854 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2856 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2858 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2860 // Find the corresponding packet in tx list, and check it whether belongs
2861 // to stateful exchange process.
2863 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2866 IsDispatched
= TRUE
;
2877 // Skip this packet if not dispatched to any instance.
2879 if (!IsDispatched
) {
2884 // Dispatch the received packet ot the right instance.
2887 Dhcp6HandleStateless (Instance
, Packet
);
2889 Dhcp6HandleStateful (Instance
, Packet
);
2894 if (!IsDispatched
) {
2895 Status
= UdpIoRecvDatagram (
2901 if (EFI_ERROR (Status
)) {
2902 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2903 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2904 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_ALL
);
2909 NetbufFree (Udp6Wrap
);
2911 if (Packet
!= NULL
) {
2917 Detect Link movement for specified network device.
2919 This routine will try to invoke Snp->GetStatus() to get the media status.
2920 If media present status switches from unpresent to present, a link movement
2921 is detected. Note that the underlying UNDI driver may not support reporting
2922 media status from GET_STATUS command. If that, fail to detect link movement.
2924 @param[in] Instance The pointer to DHCP6_INSTANCE.
2926 @retval TRUE A link movement is detected.
2927 @retval FALSE A link movement is not detected.
2931 Dhcp6LinkMovDetect (
2932 IN DHCP6_INSTANCE
*Instance
2935 UINT32 InterruptStatus
;
2936 BOOLEAN MediaPresent
;
2938 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2940 ASSERT (Instance
!= NULL
);
2941 Snp
= Instance
->Service
->Snp
;
2942 MediaPresent
= Instance
->MediaPresent
;
2945 // Check whether SNP support media detection
2947 if (!Snp
->Mode
->MediaPresentSupported
) {
2952 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2954 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2955 if (EFI_ERROR (Status
)) {
2959 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2961 // Media transimit Unpresent to Present means new link movement is detected.
2963 if (!MediaPresent
&& Instance
->MediaPresent
) {
2971 The timer routine of the Dhcp6 instance for each second.
2973 @param[in] Event The timer event.
2974 @param[in] Context The opaque parameter to the function.
2985 LIST_ENTRY
*NextEntry
;
2986 DHCP6_INSTANCE
*Instance
;
2992 ASSERT (Context
!= NULL
);
2994 Instance
= (DHCP6_INSTANCE
*) Context
;
2997 // 1. Loop the tx list, count live time of every tx packet to check whether
2998 // need re-transmit or not.
3000 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
3002 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
3006 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
3008 // Handle the first rt in the transmission of solicit specially.
3010 if ((TxCb
->RetryCnt
== 0 || TxCb
->SolicitRetry
) && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3011 if (Instance
->AdSelect
== NULL
) {
3013 // Set adpref as 0xff here to indicate select any advertisement
3016 Instance
->AdPref
= 0xff;
3019 // Select the advertisement received before.
3021 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
3022 if (Status
== EFI_ABORTED
) {
3024 } else if (EFI_ERROR (Status
)) {
3031 // Increase the retry count for the packet and add up the total loss time.
3034 TxCb
->RetryLos
+= TxCb
->RetryExp
;
3037 // Check whether overflow the max retry count limit for this packet
3039 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
3040 Status
= EFI_NO_RESPONSE
;
3045 // Check whether overflow the max retry duration for this packet
3047 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
3048 Status
= EFI_NO_RESPONSE
;
3053 // Re-calculate retry expire timeout for the next time.
3055 // Firstly, Check the new calculated time whether overflow the max retry
3058 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3064 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
3065 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3073 // Secondly, Check the new calculated time whether overflow the max retry
3076 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3077 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
3078 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3082 // Reset the tick time for the next retransmission
3087 // Retransmit the last sent packet again.
3089 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3090 TxCb
->SolicitRetry
= FALSE
;
3091 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3092 TxCb
->SolicitRetry
= TRUE
;
3098 // 2. Check the configured Ia, count lease time of every valid Ia to check
3099 // whether need to renew or rebind this Ia.
3101 IaCb
= &Instance
->IaCb
;
3103 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
3107 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
3111 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3113 // Exceed t2, send rebind packet to extend the Ia lease.
3115 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3117 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3120 // Exceed t1, send renew packet to extend the Ia lease.
3122 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3127 // 3. In any situation when a client may have moved to a new link, the
3128 // client MUST initiate a Confirm/Reply message exchange.
3130 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3131 Dhcp6SendConfirmMsg (Instance
);
3138 if (Dhcp6IsValidTxCb (Instance
, TxCb
) &&
3139 TxCb
->TxPacket
!= NULL
&&
3140 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
3141 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
3142 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)
3145 // The failure of renew/Confirm will still switch to the bound state.
3147 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3148 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
3149 ASSERT (Instance
->IaCb
.Ia
);
3150 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3153 // The failure of info-request will return no response.
3155 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3156 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3165 // The failure of the others will terminate current state machine if timeout.
3167 Dhcp6CleanupSession (Instance
, Status
);