2 Dhcp6 internal functions implementation.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Dhcp6Impl.h"
20 Enqueue the packet into the retry list in case of timeout.
22 @param[in] Instance The pointer to the Dhcp6 instance.
23 @param[in] Packet The pointer to the Dhcp6 packet to retry.
24 @param[in] Elapsed The pointer to the elapsed time value in the packet.
25 @param[in] RetryCtl The pointer to the transmission control of the packet.
26 This parameter is optional and may be NULL.
28 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according
30 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
31 @retval EFI_DEVICE_ERROR An unexpected message type.
36 IN DHCP6_INSTANCE
*Instance
,
37 IN EFI_DHCP6_PACKET
*Packet
,
39 IN EFI_DHCP6_RETRANSMISSION
*RetryCtl OPTIONAL
45 ASSERT (Packet
!= NULL
);
47 IaCb
= &Instance
->IaCb
;
48 TxCb
= AllocateZeroPool (sizeof (DHCP6_TX_CB
));
51 return EFI_OUT_OF_RESOURCES
;
55 // Save tx packet pointer, and it will be destroyed when reply received.
57 TxCb
->TxPacket
= Packet
;
58 TxCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
61 // Save pointer to elapsed-time value so we can update it on retransmits.
63 TxCb
->Elapsed
= Elapsed
;
66 // Calculate the retransmission according to the the message type.
68 switch (Packet
->Dhcp6
.Header
.MessageType
) {
71 // Calculate the retransmission threshold value for solicit packet.
72 // Use the default value by rfc-3315 if user doesn't configure.
74 if (RetryCtl
== NULL
) {
75 TxCb
->RetryCtl
.Irt
= DHCP6_SOL_IRT
;
76 TxCb
->RetryCtl
.Mrc
= DHCP6_SOL_MRC
;
77 TxCb
->RetryCtl
.Mrt
= DHCP6_SOL_MRT
;
78 TxCb
->RetryCtl
.Mrd
= DHCP6_SOL_MRD
;
80 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_SOL_IRT
;
81 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_SOL_MRC
;
82 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_SOL_MRT
;
83 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_SOL_MRD
;
86 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
95 // Calculate the retransmission threshold value for request packet.
97 TxCb
->RetryCtl
.Irt
= DHCP6_REQ_IRT
;
98 TxCb
->RetryCtl
.Mrc
= DHCP6_REQ_MRC
;
99 TxCb
->RetryCtl
.Mrt
= DHCP6_REQ_MRT
;
100 TxCb
->RetryCtl
.Mrd
= DHCP6_REQ_MRD
;
101 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
108 case Dhcp6MsgConfirm
:
110 // Calculate the retransmission threshold value for confirm packet.
112 TxCb
->RetryCtl
.Irt
= DHCP6_CNF_IRT
;
113 TxCb
->RetryCtl
.Mrc
= DHCP6_CNF_MRC
;
114 TxCb
->RetryCtl
.Mrt
= DHCP6_CNF_MRT
;
115 TxCb
->RetryCtl
.Mrd
= DHCP6_CNF_MRD
;
116 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
125 // Calculate the retransmission threshold value for renew packet.
127 TxCb
->RetryCtl
.Irt
= DHCP6_REB_IRT
;
128 TxCb
->RetryCtl
.Mrc
= DHCP6_REB_MRC
;
129 TxCb
->RetryCtl
.Mrt
= DHCP6_REB_MRT
;
130 TxCb
->RetryCtl
.Mrd
= IaCb
->T2
- IaCb
->T1
;
131 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
140 // Calculate the retransmission threshold value for rebind packet.
142 TxCb
->RetryCtl
.Irt
= DHCP6_REN_IRT
;
143 TxCb
->RetryCtl
.Mrc
= DHCP6_REN_MRC
;
144 TxCb
->RetryCtl
.Mrt
= DHCP6_REN_MRT
;
145 TxCb
->RetryCtl
.Mrd
= IaCb
->AllExpireTime
- IaCb
->T2
;
146 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
153 case Dhcp6MsgDecline
:
155 // Calculate the retransmission threshold value for decline packet.
157 TxCb
->RetryCtl
.Irt
= DHCP6_DEC_IRT
;
158 TxCb
->RetryCtl
.Mrc
= DHCP6_DEC_MRC
;
159 TxCb
->RetryCtl
.Mrt
= DHCP6_DEC_MRT
;
160 TxCb
->RetryCtl
.Mrd
= DHCP6_DEC_MRD
;
161 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
168 case Dhcp6MsgRelease
:
170 // Calculate the retransmission threshold value for release packet.
172 TxCb
->RetryCtl
.Irt
= DHCP6_REL_IRT
;
173 TxCb
->RetryCtl
.Mrc
= DHCP6_REL_MRC
;
174 TxCb
->RetryCtl
.Mrt
= DHCP6_REL_MRT
;
175 TxCb
->RetryCtl
.Mrd
= DHCP6_REL_MRD
;
176 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
183 case Dhcp6MsgInfoRequest
:
185 // Calculate the retransmission threshold value for info-request packet.
186 // Use the default value by rfc-3315 if user doesn't configure.
188 if (RetryCtl
== NULL
) {
189 TxCb
->RetryCtl
.Irt
= DHCP6_INF_IRT
;
190 TxCb
->RetryCtl
.Mrc
= DHCP6_INF_MRC
;
191 TxCb
->RetryCtl
.Mrt
= DHCP6_INF_MRT
;
192 TxCb
->RetryCtl
.Mrd
= DHCP6_INF_MRD
;
194 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_INF_IRT
;
195 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_INF_MRC
;
196 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_INF_MRT
;
197 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_INF_MRD
;
200 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
209 // Unexpected message type.
211 return EFI_DEVICE_ERROR
;
215 // Insert into the retransmit list of the instance.
217 InsertTailList (&Instance
->TxList
, &TxCb
->Link
);
224 Dequeue the packet from retry list if reply received or timeout at last.
226 @param[in] Instance The pointer to the Dhcp6 instance.
227 @param[in] PacketXid The packet transaction id to match.
228 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
229 Otherwise, this parameter is ignored.
231 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
232 @retval EFI_NOT_FOUND There is no xid matched in retry list.
237 IN DHCP6_INSTANCE
*Instance
,
239 IN BOOLEAN NeedSignal
243 LIST_ENTRY
*NextEntry
;
248 // Seek the retransmit node in the retransmit list by packet xid.
250 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
252 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
253 ASSERT(TxCb
->TxPacket
);
255 if (TxCb
->Xid
== PacketXid
) {
257 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
260 // Seek the info-request node in the info-request list by packet xid.
262 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
264 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
266 if (InfCb
->Xid
== PacketXid
) {
268 // Remove the info-request node, and signal the event if timeout.
270 if (InfCb
->TimeoutEvent
!= NULL
&& NeedSignal
) {
271 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
274 RemoveEntryList (&InfCb
->Link
);
280 // Remove the retransmit node.
282 RemoveEntryList (&TxCb
->Link
);
283 ASSERT(TxCb
->TxPacket
);
284 FreePool (TxCb
->TxPacket
);
290 return EFI_NOT_FOUND
;
295 Clean up the specific nodes in the retry list.
297 @param[in] Instance The pointer to the Dhcp6 instance.
298 @param[in] Scope The scope of cleanup nodes.
303 IN DHCP6_INSTANCE
*Instance
,
308 LIST_ENTRY
*NextEntry
;
313 // Clean up all the stateful messages from the retransmit list.
315 if (Scope
== DHCP6_PACKET_STATEFUL
|| Scope
== DHCP6_PACKET_ALL
) {
317 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
319 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
320 ASSERT(TxCb
->TxPacket
);
322 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgInfoRequest
) {
323 RemoveEntryList (&TxCb
->Link
);
324 FreePool (TxCb
->TxPacket
);
331 // Clean up all the stateless messages from the retransmit list.
333 if (Scope
== DHCP6_PACKET_STATELESS
|| Scope
== DHCP6_PACKET_ALL
) {
336 // Clean up all the retransmit list for stateless messages.
338 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
340 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
341 ASSERT(TxCb
->TxPacket
);
343 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
344 RemoveEntryList (&TxCb
->Link
);
345 FreePool (TxCb
->TxPacket
);
351 // Clean up all the info-request messages list.
353 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
355 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
357 if (InfCb
->TimeoutEvent
!= NULL
) {
358 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
360 RemoveEntryList (&InfCb
->Link
);
368 Clean up the session of the instance stateful exchange.
370 @param[in, out] Instance The pointer to the Dhcp6 instance.
371 @param[in] Status The return status from udp.
375 Dhcp6CleanupSession (
376 IN OUT DHCP6_INSTANCE
*Instance
,
383 ASSERT(Instance
->Config
);
384 ASSERT(Instance
->IaCb
.Ia
);
387 // Clean up the retransmit list for stateful messages.
389 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
391 if (Instance
->Unicast
!= NULL
) {
392 FreePool (Instance
->Unicast
);
395 if (Instance
->AdSelect
!= NULL
) {
396 FreePool (Instance
->AdSelect
);
399 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
400 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
404 // Reinitialize the Ia fields of the instance.
406 Instance
->UdpSts
= Status
;
407 Instance
->AdSelect
= NULL
;
408 Instance
->AdPref
= 0;
409 Instance
->Unicast
= NULL
;
410 Instance
->IaCb
.T1
= 0;
411 Instance
->IaCb
.T2
= 0;
412 Instance
->IaCb
.AllExpireTime
= 0;
413 Instance
->IaCb
.LeaseTime
= 0;
418 Instance
->StartTime
= 0;
420 Ia
= Instance
->IaCb
.Ia
;
421 Ia
->State
= Dhcp6Init
;
422 Ia
->ReplyPacket
= NULL
;
425 // Set the addresses as zero lifetime, and then the notify
426 // function in Ip6Config will remove these timeout address.
428 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
429 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
430 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
435 // Signal the Ia information updated event to informal user.
437 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
438 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
444 Callback to user when Dhcp6 transmit/receive occurs.
446 @param[in] Instance The pointer to the Dhcp6 instance.
447 @param[in] Event The current Dhcp6 event.
448 @param[in, out] Packet The pointer to the packet sending or received.
450 @retval EFI_SUCCESS The user function returns success.
451 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
452 @retval EFI_ABORTED The user function ask it to abort.
458 IN DHCP6_INSTANCE
*Instance
,
459 IN EFI_DHCP6_EVENT Event
,
460 IN OUT EFI_DHCP6_PACKET
**Packet
464 EFI_DHCP6_PACKET
*NewPacket
;
465 EFI_DHCP6_CALLBACK Callback
;
468 ASSERT (Packet
!= NULL
);
469 ASSERT (Instance
->Config
!= NULL
);
470 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
473 Status
= EFI_SUCCESS
;
474 Callback
= Instance
->Config
->Dhcp6Callback
;
475 Context
= Instance
->Config
->CallbackContext
;
478 // Callback to user with the new message if has.
480 if (Callback
!= NULL
) {
485 Instance
->IaCb
.Ia
->State
,
491 // Updated the new packet from user to replace the original one.
493 if (NewPacket
!= NULL
) {
494 ASSERT (*Packet
!= NULL
);
505 Update Ia according to the new reply message.
507 @param[in, out] Instance The pointer to the Dhcp6 instance.
508 @param[in] Packet The pointer to reply messages.
510 @retval EFI_SUCCESS Updated the Ia information successfully.
511 @retval EFI_DEVICE_ERROR An unexpected error.
516 IN OUT DHCP6_INSTANCE
*Instance
,
517 IN EFI_DHCP6_PACKET
*Packet
521 EFI_DHCP6_STATE State
;
529 ASSERT (Instance
->Config
!= NULL
);
531 // If the reply was received in reponse to a solicit with rapid commit option,
532 // request, renew or rebind message, the client updates the information it has
533 // recorded about IAs from the IA options contained in the reply message:
534 // 1. record the T1 and T2 times
535 // 2. add any new addresses in the IA
536 // 3. discard any addresses from the IA, that have a valid lifetime of 0
537 // 4. update lifetimes for any addresses that alread recorded
538 // 5. leave unchanged any information about addresses
540 // See details in the section-18.1.8 of rfc-3315.
543 Option
= Dhcp6SeekIaOption (
544 Packet
->Dhcp6
.Option
,
545 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
546 &Instance
->Config
->IaDescriptor
548 if (Option
== NULL
) {
549 return EFI_DEVICE_ERROR
;
553 // The format of the IA_NA option is:
556 // 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
557 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
558 // | OPTION_IA_NA | option-len |
559 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
560 // | IAID (4 octets) |
561 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
563 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
569 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571 // The format of the IA_TA option is:
574 // 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
575 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
576 // | OPTION_IA_TA | option-len |
577 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
578 // | IAID (4 octets) |
579 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587 // sizeof (option-code + option-len + IaId) = 8
588 // sizeof (option-code + option-len + IaId + T1) = 12
589 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
591 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
593 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
594 T1
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 8)));
595 T2
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 12)));
597 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
598 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
599 // the remainder of the message as though the server had not included the invalid IA_NA option.
601 if (T1
> T2
&& T2
> 0) {
602 return EFI_DEVICE_ERROR
;
604 IaInnerOpt
= Option
+ 16;
605 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
609 IaInnerOpt
= Option
+ 8;
610 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
614 // The format of the Status Code option is:
617 // 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
618 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
619 // | OPTION_STATUS_CODE | option-len |
620 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
622 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
624 // . status-message .
626 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
630 // sizeof (option-code + option-len) = 4
632 StsCode
= Dhcp6StsSuccess
;
633 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
635 if (Option
!= NULL
) {
636 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
637 if (StsCode
!= Dhcp6StsSuccess
) {
638 return EFI_DEVICE_ERROR
;
643 // Generate control block for the Ia.
645 Status
= Dhcp6GenerateIaCb (
659 Seek StatusCode Option in package. A Status Code option may appear in the
660 options field of a DHCP message and/or in the options field of another option.
661 See details in section 22.13, RFC3315.
663 @param[in] Instance The pointer to the Dhcp6 instance.
664 @param[in] Packet The pointer to reply messages.
665 @param[out] Option The pointer to status code option.
667 @retval EFI_SUCCESS Seek status code option successfully.
668 @retval EFI_DEVICE_ERROR An unexpected error.
673 IN DHCP6_INSTANCE
*Instance
,
674 IN EFI_DHCP6_PACKET
*Packet
,
683 // Seek StatusCode option directly in DHCP message body. That is, search in
684 // non-encapsulated option fields.
686 *Option
= Dhcp6SeekOption (
687 Packet
->Dhcp6
.Option
,
692 if (*Option
!= NULL
) {
693 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
694 if (StsCode
!= Dhcp6StsSuccess
) {
695 return EFI_DEVICE_ERROR
;
700 // Seek in encapsulated options, IA_NA and IA_TA.
702 *Option
= Dhcp6SeekIaOption (
703 Packet
->Dhcp6
.Option
,
704 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
705 &Instance
->Config
->IaDescriptor
707 if (*Option
== NULL
) {
712 // The format of the IA_NA option is:
715 // 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
716 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
717 // | OPTION_IA_NA | option-len |
718 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
719 // | IAID (4 octets) |
720 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
722 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
724 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
728 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
730 // The format of the IA_TA option is:
733 // 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
734 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
735 // | OPTION_IA_TA | option-len |
736 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737 // | IAID (4 octets) |
738 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
746 // sizeof (option-code + option-len + IaId) = 8
747 // sizeof (option-code + option-len + IaId + T1) = 12
748 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
750 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
752 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
753 IaInnerOpt
= *Option
+ 16;
754 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
756 IaInnerOpt
= *Option
+ 8;
757 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
761 // The format of the Status Code option is:
764 // 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
765 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
766 // | OPTION_STATUS_CODE | option-len |
767 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
769 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
771 // . status-message .
773 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
777 // sizeof (option-code + option-len) = 4
779 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
780 if (*Option
!= NULL
) {
781 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
782 if (StsCode
!= Dhcp6StsSuccess
) {
783 return EFI_DEVICE_ERROR
;
792 Transmit Dhcp6 message by udpio.
794 @param[in] Instance The pointer to the Dhcp6 instance.
795 @param[in] Packet The pointer to transmit message.
796 @param[in] Elapsed The pointer to the elapsed time value to fill in.
798 @retval EFI_SUCCESS Successfully transmitted the packet.
799 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
800 @retval Others Failed to transmit the packet.
804 Dhcp6TransmitPacket (
805 IN DHCP6_INSTANCE
*Instance
,
806 IN EFI_DHCP6_PACKET
*Packet
,
814 DHCP6_SERVICE
*Service
;
816 Service
= Instance
->Service
;
819 // Wrap it into a netbuf then send it.
821 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
822 Frag
.Len
= Packet
->Length
;
825 // Do not register free packet here, which will be handled in retry list.
827 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
830 return EFI_OUT_OF_RESOURCES
;
834 // Multicast the Dhcp6 message, unless get the unicast server address by option.
836 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
838 if (Instance
->Unicast
!= NULL
) {
842 sizeof (EFI_IPv6_ADDRESS
)
847 &mAllDhcpRelayAndServersAddress
,
848 sizeof (EFI_IPv6_ADDRESS
)
852 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
853 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
856 // Update the elapsed time value.
858 if (Elapsed
!= NULL
) {
859 SetElapsedTime (Elapsed
, Instance
);
863 // Send out the message by the configured Udp6Io.
865 Status
= UdpIoSendDatagram (
874 if (EFI_ERROR (Status
)) {
884 Create the solicit message and send it.
886 @param[in] Instance The pointer to the Dhcp6 instance.
888 @retval EFI_SUCCESS Created and sent the solicit message successfully.
889 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
890 @retval Others Failed to send the solicit message.
894 Dhcp6SendSolicitMsg (
895 IN DHCP6_INSTANCE
*Instance
899 EFI_DHCP6_PACKET
*Packet
;
900 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
901 EFI_DHCP6_DUID
*ClientId
;
902 DHCP6_SERVICE
*Service
;
909 Service
= Instance
->Service
;
910 ClientId
= Service
->ClientId
;
913 ASSERT (Service
->ClientId
!= NULL
);
914 ASSERT (Instance
->Config
!= NULL
);
915 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
918 // Calculate the added length of customized option list.
920 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
921 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
925 // Create the Dhcp6 packet and initialize commone fields.
927 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
928 if (Packet
== NULL
) {
929 return EFI_OUT_OF_RESOURCES
;
932 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
933 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
934 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
935 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
938 // Assembly Dhcp6 options for solicit message.
940 Cursor
= Packet
->Dhcp6
.Option
;
942 Length
= HTONS (ClientId
->Length
);
943 Cursor
= Dhcp6AppendOption (
945 HTONS (Dhcp6OptClientId
),
950 Cursor
= Dhcp6AppendETOption (
956 Cursor
= Dhcp6AppendIaOption (
961 Packet
->Dhcp6
.Header
.MessageType
965 // Append user-defined when configurate Dhcp6 service.
967 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
969 UserOpt
= Instance
->Config
->OptionList
[Index
];
970 Cursor
= Dhcp6AppendOption(
979 // Determine the size/length of packet.
981 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
982 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
985 // Callback to user with the packet to be sent and check the user's feedback.
987 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
989 if (EFI_ERROR (Status
)) {
995 // Send solicit packet with the state transition from Dhcp6init to
998 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1000 // Clear initial time for current transaction.
1002 Instance
->StartTime
= 0;
1004 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1006 if (EFI_ERROR (Status
)) {
1012 // Enqueue the sent packet for the retransmission in case reply timeout.
1014 return Dhcp6EnqueueRetry (
1018 Instance
->Config
->SolicitRetransmission
1023 Configure some parameter to initiate SolicitMsg.
1025 @param[in] Instance The pointer to the Dhcp6 instance.
1027 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1028 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1029 @retval Others Failed to send the solicit message.
1033 Dhcp6InitSolicitMsg (
1034 IN DHCP6_INSTANCE
*Instance
1037 Instance
->IaCb
.T1
= 0;
1038 Instance
->IaCb
.T2
= 0;
1039 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1041 return Dhcp6SendSolicitMsg (Instance
);
1046 Create the request message and send it.
1048 @param[in] Instance The pointer to the Dhcp6 instance.
1050 @retval EFI_SUCCESS Created and sent the request message successfully.
1051 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1052 @retval EFI_DEVICE_ERROR An unexpected error.
1053 @retval Others Failed to send the request message.
1057 Dhcp6SendRequestMsg (
1058 IN DHCP6_INSTANCE
*Instance
1062 EFI_DHCP6_PACKET
*Packet
;
1063 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1064 EFI_DHCP6_DUID
*ClientId
;
1065 EFI_DHCP6_DUID
*ServerId
;
1066 DHCP6_SERVICE
*Service
;
1074 ASSERT(Instance
->AdSelect
!= NULL
);
1075 ASSERT(Instance
->Config
!= NULL
);
1076 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1077 ASSERT(Instance
->Service
!= NULL
);
1079 Service
= Instance
->Service
;
1080 ClientId
= Service
->ClientId
;
1082 ASSERT(ClientId
!= NULL
);
1085 // Get the server Id from the selected advertisement message.
1087 Option
= Dhcp6SeekOption (
1088 Instance
->AdSelect
->Dhcp6
.Option
,
1089 Instance
->AdSelect
->Length
- 4,
1092 if (Option
== NULL
) {
1093 return EFI_DEVICE_ERROR
;
1096 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1099 // Calculate the added length of customized option list.
1102 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1103 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1107 // Create the Dhcp6 packet and initialize commone fields.
1109 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1110 if (Packet
== NULL
) {
1111 return EFI_OUT_OF_RESOURCES
;
1114 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1115 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1116 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1117 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1120 // Assembly Dhcp6 options for request message.
1122 Cursor
= Packet
->Dhcp6
.Option
;
1124 Length
= HTONS (ClientId
->Length
);
1125 Cursor
= Dhcp6AppendOption (
1127 HTONS (Dhcp6OptClientId
),
1132 Cursor
= Dhcp6AppendETOption (
1138 Cursor
= Dhcp6AppendOption (
1140 HTONS (Dhcp6OptServerId
),
1145 Cursor
= Dhcp6AppendIaOption (
1150 Packet
->Dhcp6
.Header
.MessageType
1154 // Append user-defined when configurate Dhcp6 service.
1156 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1158 UserOpt
= Instance
->Config
->OptionList
[Index
];
1159 Cursor
= Dhcp6AppendOption(
1168 // Determine the size/length of packet.
1170 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1171 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1174 // Callback to user with the packet to be sent and check the user's feedback.
1176 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1178 if (EFI_ERROR (Status
)) {
1184 // Send request packet with the state transition from Dhcp6selecting to
1187 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1189 // Clear initial time for current transaction.
1191 Instance
->StartTime
= 0;
1193 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1195 if (EFI_ERROR (Status
)) {
1201 // Enqueue the sent packet for the retransmission in case reply timeout.
1203 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 commone 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
);
1346 Create the release message and send it.
1348 @param[in] Instance The pointer to the Dhcp6 instance.
1349 @param[in] RelIa The pointer to the release Ia.
1351 @retval EFI_SUCCESS Created and sent the release message successfully.
1352 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1353 @retval EFI_DEVICE_ERROR An unexpected error.
1354 @retval Others Failed to send the release message.
1358 Dhcp6SendReleaseMsg (
1359 IN DHCP6_INSTANCE
*Instance
,
1360 IN EFI_DHCP6_IA
*RelIa
1364 EFI_DHCP6_PACKET
*Packet
;
1365 EFI_DHCP6_PACKET
*LastReply
;
1366 EFI_DHCP6_DUID
*ClientId
;
1367 EFI_DHCP6_DUID
*ServerId
;
1368 DHCP6_SERVICE
*Service
;
1374 ASSERT(Instance
->Config
);
1375 ASSERT(Instance
->IaCb
.Ia
);
1377 Service
= Instance
->Service
;
1378 ClientId
= Service
->ClientId
;
1379 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1385 // Get the server Id from the last reply message.
1387 Option
= Dhcp6SeekOption (
1388 LastReply
->Dhcp6
.Option
,
1389 LastReply
->Length
- 4,
1392 if (Option
== NULL
) {
1393 return EFI_DEVICE_ERROR
;
1396 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1399 // Create the Dhcp6 packet and initialize commone fields.
1401 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1402 if (Packet
== NULL
) {
1403 return EFI_OUT_OF_RESOURCES
;
1406 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1407 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1408 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1409 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1412 // Assembly Dhcp6 options for rebind/renew message
1414 Cursor
= Packet
->Dhcp6
.Option
;
1416 Length
= HTONS (ClientId
->Length
);
1417 Cursor
= Dhcp6AppendOption (
1419 HTONS (Dhcp6OptClientId
),
1425 // ServerId is extracted from packet, it's network order.
1427 Cursor
= Dhcp6AppendOption (
1429 HTONS (Dhcp6OptServerId
),
1434 Cursor
= Dhcp6AppendETOption (
1440 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1443 // Determine the size/length of packet
1445 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1446 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1449 // Callback to user with the packet to be sent and check the user's feedback.
1451 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1453 if (EFI_ERROR (Status
)) {
1459 // Send release packet with the state transition from Dhcp6bound to
1462 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1464 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1466 if (EFI_ERROR (Status
)) {
1472 // Enqueue the sent packet for the retransmission in case reply timeout.
1474 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1479 Create the renew/rebind message and send it.
1481 @param[in] Instance The pointer to the Dhcp6 instance.
1482 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1483 Otherwise, it is a Renew type message.
1485 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1486 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1487 @retval EFI_DEVICE_ERROR An unexpected error.
1488 @retval Others Failed to send the renew/rebind message.
1492 Dhcp6SendRenewRebindMsg (
1493 IN DHCP6_INSTANCE
*Instance
,
1494 IN BOOLEAN RebindRequest
1498 EFI_DHCP6_PACKET
*Packet
;
1499 EFI_DHCP6_PACKET
*LastReply
;
1500 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1501 EFI_DHCP6_DUID
*ClientId
;
1502 EFI_DHCP6_DUID
*ServerId
;
1503 EFI_DHCP6_STATE State
;
1504 EFI_DHCP6_EVENT Event
;
1505 DHCP6_SERVICE
*Service
;
1513 ASSERT(Instance
->Config
);
1514 ASSERT(Instance
->IaCb
.Ia
);
1516 Service
= Instance
->Service
;
1517 ClientId
= Service
->ClientId
;
1522 // Calculate the added length of customized option list.
1525 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1526 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1530 // Create the Dhcp6 packet and initialize commone fields.
1532 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1533 if (Packet
== NULL
) {
1534 return EFI_OUT_OF_RESOURCES
;
1537 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1538 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1539 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1540 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1543 // Assembly Dhcp6 options for rebind/renew message.
1545 Cursor
= Packet
->Dhcp6
.Option
;
1547 Length
= HTONS (ClientId
->Length
);
1548 Cursor
= Dhcp6AppendOption (
1550 HTONS (Dhcp6OptClientId
),
1555 Cursor
= Dhcp6AppendETOption (
1561 Cursor
= Dhcp6AppendIaOption (
1566 Packet
->Dhcp6
.Header
.MessageType
1569 if (!RebindRequest
) {
1571 // Get the server Id from the last reply message and
1572 // insert it for rebind request.
1574 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1577 Option
= Dhcp6SeekOption (
1578 LastReply
->Dhcp6
.Option
,
1579 LastReply
->Length
- 4,
1582 if (Option
== NULL
) {
1584 return EFI_DEVICE_ERROR
;
1587 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1589 Cursor
= Dhcp6AppendOption (
1591 HTONS (Dhcp6OptServerId
),
1598 // Append user-defined when configurate Dhcp6 service.
1600 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1602 UserOpt
= Instance
->Config
->OptionList
[Index
];
1603 Cursor
= Dhcp6AppendOption(
1612 // Determine the size/length of packet.
1614 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1615 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1618 // Callback to user with the packet to be sent and check the user's feedback.
1620 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1621 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1623 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1625 if (EFI_ERROR (Status
)) {
1631 // Send renew/rebind packet with the state transition from Dhcp6bound to
1632 // Dhcp6renew/rebind.
1633 // And sync the lease time when send renew/rebind, in case that user send
1634 // renew/rebind actively.
1636 Instance
->IaCb
.Ia
->State
= State
;
1637 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1639 // Clear initial time for current transaction.
1641 Instance
->StartTime
= 0;
1643 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1645 if (EFI_ERROR (Status
)) {
1651 // Enqueue the sent packet for the retransmission in case reply timeout.
1653 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1657 Start the information request process.
1659 @param[in] Instance The pointer to the Dhcp6 instance.
1660 @param[in] SendClientId If TRUE, the client identifier option will be included in
1661 information request message. Otherwise, the client identifier
1662 option will not be included.
1663 @param[in] OptionRequest The pointer to the option request option.
1664 @param[in] OptionCount The number options in the OptionList.
1665 @param[in] OptionList The array pointers to the appended options.
1666 @param[in] Retransmission The pointer to the retransmission control.
1667 @param[in] TimeoutEvent The event of timeout.
1668 @param[in] ReplyCallback The callback function when the reply was received.
1669 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1671 @retval EFI_SUCCESS Start the info-request process successfully.
1672 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1673 @retval EFI_NO_MAPPING No source address is available for use.
1674 @retval Others Failed to start the info-request process.
1678 Dhcp6StartInfoRequest (
1679 IN DHCP6_INSTANCE
*Instance
,
1680 IN BOOLEAN SendClientId
,
1681 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1682 IN UINT32 OptionCount
,
1683 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1684 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1685 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1686 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1687 IN VOID
*CallbackContext OPTIONAL
1691 DHCP6_INF_CB
*InfCb
;
1692 DHCP6_SERVICE
*Service
;
1695 Service
= Instance
->Service
;
1697 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1698 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1700 // Create and initialize the control block for the info-request.
1702 InfCb
= AllocateZeroPool (sizeof(DHCP6_INF_CB
));
1704 if (InfCb
== NULL
) {
1705 gBS
->RestoreTPL (OldTpl
);
1706 return EFI_OUT_OF_RESOURCES
;
1709 InfCb
->ReplyCallback
= ReplyCallback
;
1710 InfCb
->CallbackContext
= CallbackContext
;
1711 InfCb
->TimeoutEvent
= TimeoutEvent
;
1713 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1716 // Send the info-request message to start exchange process.
1718 Status
= Dhcp6SendInfoRequestMsg (
1728 if (EFI_ERROR (Status
)) {
1733 // Register receive callback for the stateless exchange process.
1735 Status
= UdpIoRecvDatagram(
1742 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1746 gBS
->RestoreTPL (OldTpl
);
1750 gBS
->RestoreTPL (OldTpl
);
1751 RemoveEntryList (&InfCb
->Link
);
1758 Create the information request message and send it.
1760 @param[in] Instance The pointer to the Dhcp6 instance.
1761 @param[in] InfCb The pointer to the information request control block.
1762 @param[in] SendClientId If TRUE, the client identifier option will be included in
1763 information request message. Otherwise, the client identifier
1764 option will not be included.
1765 @param[in] OptionRequest The pointer to the option request option.
1766 @param[in] OptionCount The number options in the OptionList.
1767 @param[in] OptionList The array pointers to the appended options.
1768 @param[in] Retransmission The pointer to the retransmission control.
1770 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1771 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1772 @retval Others Failed to send the info-request message.
1776 Dhcp6SendInfoRequestMsg (
1777 IN DHCP6_INSTANCE
*Instance
,
1778 IN DHCP6_INF_CB
*InfCb
,
1779 IN BOOLEAN SendClientId
,
1780 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1781 IN UINT32 OptionCount
,
1782 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1783 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1787 EFI_DHCP6_PACKET
*Packet
;
1788 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1789 EFI_DHCP6_DUID
*ClientId
;
1790 DHCP6_SERVICE
*Service
;
1797 ASSERT(OptionRequest
);
1799 Service
= Instance
->Service
;
1800 ClientId
= Service
->ClientId
;
1801 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1806 // Calculate the added length of customized option list.
1808 for (Index
= 0; Index
< OptionCount
; Index
++) {
1809 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1813 // Create the Dhcp6 packet and initialize commone fields.
1815 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1816 if (Packet
== NULL
) {
1817 return EFI_OUT_OF_RESOURCES
;
1820 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1821 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1822 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1823 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1825 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1828 // Assembly Dhcp6 options for info-request message.
1830 Cursor
= Packet
->Dhcp6
.Option
;
1833 Length
= HTONS (ClientId
->Length
);
1834 Cursor
= Dhcp6AppendOption (
1836 HTONS (Dhcp6OptClientId
),
1842 Cursor
= Dhcp6AppendETOption (
1848 Cursor
= Dhcp6AppendOption (
1850 OptionRequest
->OpCode
,
1851 OptionRequest
->OpLen
,
1856 // Append user-defined when configurate Dhcp6 service.
1858 for (Index
= 0; Index
< OptionCount
; Index
++) {
1860 UserOpt
= OptionList
[Index
];
1861 Cursor
= Dhcp6AppendOption(
1870 // Determine the size/length of packet.
1872 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1873 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1876 // Clear initial time for current transaction.
1878 Instance
->StartTime
= 0;
1881 // Send info-request packet with no state.
1883 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1885 if (EFI_ERROR (Status
)) {
1891 // Enqueue the sent packet for the retransmission in case reply timeout.
1893 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1898 Create the Confirm message and send it.
1900 @param[in] Instance The pointer to the Dhcp6 instance.
1902 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1903 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1904 @retval EFI_DEVICE_ERROR An unexpected error.
1905 @retval Others Failed to send the confirm message.
1909 Dhcp6SendConfirmMsg (
1910 IN DHCP6_INSTANCE
*Instance
1918 DHCP6_SERVICE
*Service
;
1919 EFI_DHCP6_DUID
*ClientId
;
1920 EFI_DHCP6_PACKET
*Packet
;
1921 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1924 ASSERT (Instance
->Config
!= NULL
);
1925 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1926 ASSERT (Instance
->Service
!= NULL
);
1928 Service
= Instance
->Service
;
1929 ClientId
= Service
->ClientId
;
1930 ASSERT (ClientId
!= NULL
);
1933 // Calculate the added length of customized option list.
1936 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1937 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1941 // Create the Dhcp6 packet and initialize common fields.
1943 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1944 if (Packet
== NULL
) {
1945 return EFI_OUT_OF_RESOURCES
;
1948 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1949 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1950 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1951 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1954 // Assembly Dhcp6 options for solicit message.
1956 Cursor
= Packet
->Dhcp6
.Option
;
1958 Length
= HTONS (ClientId
->Length
);
1959 Cursor
= Dhcp6AppendOption (
1961 HTONS (Dhcp6OptClientId
),
1966 Cursor
= Dhcp6AppendETOption (
1972 Cursor
= Dhcp6AppendIaOption (
1977 Packet
->Dhcp6
.Header
.MessageType
1981 // Append user-defined when configurate Dhcp6 service.
1983 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1984 UserOpt
= Instance
->Config
->OptionList
[Index
];
1985 Cursor
= Dhcp6AppendOption (
1994 // Determine the size/length of packet.
1996 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1997 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
2000 // Callback to user with the packet to be sent and check the user's feedback.
2002 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
2004 if (EFI_ERROR (Status
)) {
2010 // Send confirm packet with the state transition from Dhcp6Bound to
2013 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2015 // Clear initial time for current transaction.
2017 Instance
->StartTime
= 0;
2019 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2021 if (EFI_ERROR (Status
)) {
2027 // Enqueue the sent packet for the retransmission in case reply timeout.
2029 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2035 Handle with the Dhcp6 reply message.
2037 @param[in] Instance The pointer to Dhcp6 instance.
2038 @param[in] Packet The pointer to the Dhcp6 reply message.
2040 @retval EFI_SUCCESS Processed the reply message successfully.
2041 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2042 @retval EFI_DEVICE_ERROR An unexpected error.
2043 @retval Others Failed to process the reply message.
2047 Dhcp6HandleReplyMsg (
2048 IN DHCP6_INSTANCE
*Instance
,
2049 IN EFI_DHCP6_PACKET
*Packet
2056 ASSERT (Instance
->Config
!= NULL
);
2057 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2058 ASSERT (Packet
!= NULL
);
2060 Status
= EFI_SUCCESS
;
2062 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2063 return EFI_DEVICE_ERROR
;
2067 // If the client subsequently receives a valid reply message that includes a
2068 // rapid commit option since send a solicit with rapid commit option before,
2069 // preocess the reply message and discard any reply messages received in
2070 // response to the request message.
2071 // See details in the section-17.1.4 of rfc-3315.
2073 Option
= Dhcp6SeekOption (
2074 Packet
->Dhcp6
.Option
,
2079 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
2080 return EFI_DEVICE_ERROR
;
2084 // As to a valid reply packet in response to a request/renew/rebind packet,
2085 // ignore the packet if not contains the Ia option
2087 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
2088 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
2089 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
2092 Option
= Dhcp6SeekIaOption (
2093 Packet
->Dhcp6
.Option
,
2095 &Instance
->Config
->IaDescriptor
2097 if (Option
== NULL
) {
2103 // Callback to user with the received packet and check the user's feedback.
2105 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2107 if (EFI_ERROR (Status
)) {
2112 // When receive a valid reply packet in response to a decline/release packet,
2113 // the client considers the decline/release event completed regardless of the
2116 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
2118 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2119 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2121 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2122 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2123 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2124 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2128 // For sync, set the success flag out of polling in decline/release.
2130 Instance
->UdpSts
= EFI_SUCCESS
;
2133 // For async, signal the Ia event to inform Ia infomation update.
2135 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2136 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2140 // Reset start time for next exchange.
2142 Instance
->StartTime
= 0;
2144 Status
= EFI_SUCCESS
;
2149 // Upon the receipt of a valid reply packet in response to a solicit, request,
2150 // confirm, renew and rebind, the behavior depends on the status code option.
2151 // See the details in the section-18.1.8 of rfc-3315.
2154 Status
= Dhcp6SeekStsOption (
2160 if (!EFI_ERROR (Status
)) {
2162 // No status code or no error status code means succeed to reply.
2164 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2165 if (!EFI_ERROR (Status
)) {
2167 // Reset start time for next exchange.
2169 Instance
->StartTime
= 0;
2172 // Set bound state and store the reply packet.
2174 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2175 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2178 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2180 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2181 Status
= EFI_OUT_OF_RESOURCES
;
2185 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2187 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2190 // For sync, set the success flag out of polling in start/renewrebind.
2192 Instance
->UdpSts
= EFI_SUCCESS
;
2195 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2196 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2197 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2198 // consumers can be notified to flush old address.
2200 Dhcp6AppendCacheIa (Instance
);
2203 // For async, signal the Ia event to inform Ia infomation update.
2205 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2206 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2208 } else if (Status
== EFI_NOT_FOUND
) {
2210 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2211 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2212 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2219 } else if (Option
!= NULL
) {
2221 // Any error status code option is found.
2223 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2225 case Dhcp6StsUnspecFail
:
2227 // It indicates the server is unable to process the message due to an
2228 // unspecified failure condition, so just retry if possible.
2232 case Dhcp6StsUseMulticast
:
2234 // It indicates the server receives a message via unicast from a client
2235 // to which the server has not sent a unicast option, so retry it by
2236 // multi-cast address.
2238 if (Instance
->Unicast
!= NULL
) {
2239 FreePool (Instance
->Unicast
);
2240 Instance
->Unicast
= NULL
;
2244 case Dhcp6StsNotOnLink
:
2245 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2247 // Before initiate new round DHCP, cache the current IA.
2249 Status
= Dhcp6CacheIa (Instance
);
2250 if (EFI_ERROR (Status
)) {
2255 // Restart S.A.R.R process to acquire new address.
2257 Status
= Dhcp6InitSolicitMsg (Instance
);
2258 if (EFI_ERROR (Status
)) {
2264 case Dhcp6StsNoBinding
:
2265 if (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
|| Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
) {
2267 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2268 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2270 Status
= Dhcp6SendRequestMsg(Instance
);
2271 if (EFI_ERROR (Status
)) {
2279 // The other status code, just restart solicitation.
2289 if (!EFI_ERROR(Status
)) {
2290 Status
= Dhcp6DequeueRetry (
2292 Packet
->Dhcp6
.Header
.TransactionId
,
2302 Select the appointed Dhcp6 advertisement message.
2304 @param[in] Instance The pointer to the Dhcp6 instance.
2305 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2307 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2308 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2309 @retval Others Failed to select the advertise message.
2313 Dhcp6SelectAdvertiseMsg (
2314 IN DHCP6_INSTANCE
*Instance
,
2315 IN EFI_DHCP6_PACKET
*AdSelect
2321 ASSERT (AdSelect
!= NULL
);
2324 // Callback to user with the selected advertisement packet, and the user
2325 // might overwrite it.
2327 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2329 if (EFI_ERROR (Status
)) {
2333 Instance
->AdSelect
= AdSelect
;
2336 // Dequeue the sent packet for the retransmission since advertisement selected.
2338 Status
= Dhcp6DequeueRetry (
2340 AdSelect
->Dhcp6
.Header
.TransactionId
,
2344 if (EFI_ERROR(Status
)) {
2349 // Check whether there is server unicast option in the selected advertise
2350 // packet, and update it.
2352 Option
= Dhcp6SeekOption(
2353 AdSelect
->Dhcp6
.Option
,
2354 AdSelect
->Length
- 4,
2355 Dhcp6OptServerUnicast
2358 if (Option
!= NULL
) {
2360 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2362 if (Instance
->Unicast
== NULL
) {
2363 return EFI_OUT_OF_RESOURCES
;
2366 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2370 // Update the information of the Ia by the selected advertisement message.
2372 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2374 if (EFI_ERROR (Status
)) {
2379 // Send the request message to continue the S.A.R.R. process.
2381 return Dhcp6SendRequestMsg (Instance
);
2386 Handle with the Dhcp6 advertisement message.
2388 @param[in] Instance The pointer to the Dhcp6 instance.
2389 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2391 @retval EFI_SUCCESS Processed the advertisement message successfully.
2392 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2393 @retval EFI_DEVICE_ERROR An unexpected error.
2394 @retval Others Failed to process the advertise message.
2398 Dhcp6HandleAdvertiseMsg (
2399 IN DHCP6_INSTANCE
*Instance
,
2400 IN EFI_DHCP6_PACKET
*Packet
2408 ASSERT(Instance
->Config
);
2409 ASSERT(Instance
->IaCb
.Ia
);
2412 StsCode
= Dhcp6StsSuccess
;
2415 // If the client does receives a valid reply message that includes a rapid
2416 // commit option since a solicit with rapid commit optioin sent before, select
2417 // this reply message. Or else, process the advertise messages as normal.
2418 // See details in the section-17.1.4 of rfc-3315.
2420 Option
= Dhcp6SeekOption(
2421 Packet
->Dhcp6
.Option
,
2426 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2428 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2431 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2432 return EFI_DEVICE_ERROR
;
2436 // Client must ignore any advertise message that includes a status code option
2437 // containing the value noaddrsavail, with the exception that the client may
2438 // display the associated status message to the user.
2439 // See the details in the section-17.1.3 of rfc-3315.
2441 Status
= Dhcp6SeekStsOption (
2446 if (EFI_ERROR (Status
)) {
2447 return EFI_DEVICE_ERROR
;
2451 // Callback to user with the received packet and check the user's feedback.
2453 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2455 if (!EFI_ERROR (Status
)) {
2457 // Success means user choose the current advertisement packet.
2459 if (Instance
->AdSelect
!= NULL
) {
2460 FreePool (Instance
->AdSelect
);
2464 // Store the selected advertisement packet and set a flag.
2466 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2468 if (Instance
->AdSelect
== NULL
) {
2469 return EFI_OUT_OF_RESOURCES
;
2472 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2474 Instance
->AdPref
= 0xff;
2476 } else if (Status
== EFI_NOT_READY
) {
2478 // Not_ready means user wants to continue to receive more advertise packets.
2480 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2482 // It's a tricky point. The timer routine set adpref as 0xff if the first
2483 // rt timeout and no advertisement received, which means any advertisement
2484 // received will be selected after the first rt.
2490 // Check whether the current packet has a 255 preference option or not.
2491 // Take non-preference option as 0 value.
2493 Option
= Dhcp6SeekOption(
2494 Packet
->Dhcp6
.Option
,
2499 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2501 // No advertisements received before or preference is more than other
2502 // advertisements received before. Then store the new packet and the
2503 // preference value.
2505 if (Instance
->AdSelect
!= NULL
) {
2506 FreePool (Instance
->AdSelect
);
2509 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2511 if (Instance
->AdSelect
== NULL
) {
2512 return EFI_OUT_OF_RESOURCES
;
2515 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2517 if (Option
!= NULL
) {
2518 Instance
->AdPref
= *(Option
+ 4);
2522 // Non-preference and other advertisements received before or current
2523 // preference is less than other advertisements received before.
2524 // Leave the packet alone.
2529 // Other error status means termination.
2535 // Client must collect advertise messages as more as possible until the first
2536 // RT has elapsed, or get a highest preference 255 advertise.
2537 // See details in the section-17.1.2 of rfc-3315.
2539 if (Instance
->AdPref
== 0xff || Timeout
) {
2540 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2548 The Dhcp6 stateful exchange process routine.
2550 @param[in] Instance The pointer to the Dhcp6 instance.
2551 @param[in] Packet The pointer to the received Dhcp6 message.
2555 Dhcp6HandleStateful (
2556 IN DHCP6_INSTANCE
*Instance
,
2557 IN EFI_DHCP6_PACKET
*Packet
2561 EFI_DHCP6_DUID
*ClientId
;
2562 DHCP6_SERVICE
*Service
;
2565 Service
= Instance
->Service
;
2566 ClientId
= Service
->ClientId
;
2567 Status
= EFI_SUCCESS
;
2569 if (Instance
->Config
== NULL
) {
2574 ASSERT (Instance
->Config
);
2575 ASSERT (Instance
->IaCb
.Ia
);
2578 // Discard the packet if not advertisement or reply packet.
2580 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2585 // Check whether include client Id or not.
2587 Option
= Dhcp6SeekOption(
2588 Packet
->Dhcp6
.Option
,
2593 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2598 // Check whether include server Id or not.
2600 Option
= Dhcp6SeekOption(
2601 Packet
->Dhcp6
.Option
,
2606 if (Option
== NULL
) {
2610 switch (Instance
->IaCb
.Ia
->State
) {
2611 case Dhcp6Selecting
:
2613 // Handle the advertisement message when in the Dhcp6Selecting state.
2614 // Do not need check return status, if failed, just continue to the next.
2616 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2619 case Dhcp6Requesting
:
2620 case Dhcp6Confirming
:
2622 case Dhcp6Rebinding
:
2623 case Dhcp6Releasing
:
2624 case Dhcp6Declining
:
2626 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2627 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2628 // If failed here, it should reset the current session.
2630 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2631 if (EFI_ERROR (Status
)) {
2637 // Other state has not supported yet.
2644 // Continue to receive the following Dhcp6 message.
2646 Status
= UdpIoRecvDatagram (
2653 if (EFI_ERROR (Status
)) {
2654 Dhcp6CleanupSession (Instance
, Status
);
2660 The Dhcp6 stateless exchange process routine.
2662 @param[in] Instance The pointer to the Dhcp6 instance.
2663 @param[in] Packet The pointer to the received Dhcp6 message.
2667 Dhcp6HandleStateless (
2668 IN DHCP6_INSTANCE
*Instance
,
2669 IN EFI_DHCP6_PACKET
*Packet
2673 DHCP6_SERVICE
*Service
;
2674 DHCP6_INF_CB
*InfCb
;
2678 Service
= Instance
->Service
;
2679 Status
= EFI_SUCCESS
;
2683 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2688 // Check whether it's a desired Info-request message by Xid.
2690 while (!IsListEmpty (&Instance
->InfList
)) {
2691 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2692 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2703 // Check whether include server Id or not.
2705 Option
= Dhcp6SeekOption (
2706 Packet
->Dhcp6
.Option
,
2711 if (Option
== NULL
) {
2716 // Callback to user with the received packet and check the user's feedback.
2718 Status
= InfCb
->ReplyCallback (
2720 InfCb
->CallbackContext
,
2724 if (Status
== EFI_NOT_READY
) {
2726 // Success or aborted will both stop this info-request exchange process,
2727 // but not ready means user wants to continue to receive reply.
2733 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2734 // if no xid matched.
2738 Packet
->Dhcp6
.Header
.TransactionId
,
2743 // For sync, set the status out of polling for info-request.
2745 Instance
->UdpSts
= Status
;
2749 Status
= UdpIoRecvDatagram (
2756 if (EFI_ERROR (Status
)) {
2757 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2763 The receive callback function for Dhcp6 exchange process.
2765 @param[in] Udp6Wrap The pointer to the received net buffer.
2766 @param[in] EndPoint The pointer to the udp end point.
2767 @param[in] IoStatus The return status from udp io.
2768 @param[in] Context The opaque parameter to the function.
2773 Dhcp6ReceivePacket (
2774 IN NET_BUF
*Udp6Wrap
,
2775 IN UDP_END_POINT
*EndPoint
,
2776 IN EFI_STATUS IoStatus
,
2780 EFI_DHCP6_HEADER
*Head
;
2781 EFI_DHCP6_PACKET
*Packet
;
2782 DHCP6_SERVICE
*Service
;
2783 DHCP6_INSTANCE
*Instance
;
2786 BOOLEAN IsDispatched
;
2787 BOOLEAN IsStateless
;
2793 ASSERT (Udp6Wrap
!= NULL
);
2794 ASSERT (Context
!= NULL
);
2796 Service
= (DHCP6_SERVICE
*) Context
;
2799 IsDispatched
= FALSE
;
2800 IsStateless
= FALSE
;
2802 if (EFI_ERROR (IoStatus
)) {
2807 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2809 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2810 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2812 if (Packet
== NULL
) {
2816 Packet
->Size
= Size
;
2817 Head
= &Packet
->Dhcp6
.Header
;
2818 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2820 if (Packet
->Length
== 0) {
2825 // Dispatch packet to right instance by transaction id.
2827 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2829 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2831 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2833 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2835 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2837 // Find the corresponding packet in tx list, and check it whether belongs
2838 // to stateful exchange process.
2840 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2843 IsDispatched
= TRUE
;
2854 // Skip this packet if not dispatched to any instance.
2856 if (!IsDispatched
) {
2861 // Dispatch the received packet ot the right instance.
2864 Dhcp6HandleStateless (Instance
, Packet
);
2866 Dhcp6HandleStateful (Instance
, Packet
);
2871 NetbufFree (Udp6Wrap
);
2873 if (Packet
!= NULL
) {
2879 Detect Link movement for specified network device.
2881 This routine will try to invoke Snp->GetStatus() to get the media status.
2882 If media present status switches from unpresent to present, a link movement
2883 is detected. Note that the underlying UNDI driver may not support reporting
2884 media status from GET_STATUS command. If that, fail to detect link movement.
2886 @param[in] Instance The pointer to DHCP6_INSTANCE.
2888 @retval TRUE A link movement is detected.
2889 @retval FALSE A link movement is not detected.
2893 Dhcp6LinkMovDetect (
2894 IN DHCP6_INSTANCE
*Instance
2897 UINT32 InterruptStatus
;
2898 BOOLEAN MediaPresent
;
2900 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2902 ASSERT (Instance
!= NULL
);
2903 Snp
= Instance
->Service
->Snp
;
2904 MediaPresent
= Instance
->MediaPresent
;
2907 // Check whether SNP support media detection
2909 if (!Snp
->Mode
->MediaPresentSupported
) {
2914 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2916 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2917 if (EFI_ERROR (Status
)) {
2921 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2923 // Media transimit Unpresent to Present means new link movement is detected.
2925 if (!MediaPresent
&& Instance
->MediaPresent
) {
2933 The timer routine of the Dhcp6 instance for each second.
2935 @param[in] Event The timer event.
2936 @param[in] Context The opaque parameter to the function.
2947 LIST_ENTRY
*NextEntry
;
2948 DHCP6_INSTANCE
*Instance
;
2954 ASSERT (Context
!= NULL
);
2956 Instance
= (DHCP6_INSTANCE
*) Context
;
2959 // 1. Loop the tx list, count live time of every tx packet to check whether
2960 // need re-transmit or not.
2962 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
2964 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
2968 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
2970 // Handle the first rt in the transmission of solicit specially.
2972 if ((TxCb
->RetryCnt
== 0 || TxCb
->SolicitRetry
) && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
2973 if (Instance
->AdSelect
== NULL
) {
2975 // Set adpref as 0xff here to indicate select any advertisement
2978 Instance
->AdPref
= 0xff;
2981 // Select the advertisement received before.
2983 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2984 if (EFI_ERROR (Status
)) {
2991 // Increase the retry count for the packet and add up the total loss time.
2994 TxCb
->RetryLos
+= TxCb
->RetryExp
;
2997 // Check whether overflow the max retry count limit for this packet
2999 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
3004 // Check whether overflow the max retry duration for this packet
3006 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
3011 // Re-calculate retry expire timeout for the next time.
3013 // Firstly, Check the new calculated time whether overflow the max retry
3016 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3022 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
3023 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3031 // Secondly, Check the new calculated time whether overflow the max retry
3034 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3035 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
3036 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3040 // Reset the tick time for the next retransmission
3045 // Retransmit the last sent packet again.
3047 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3048 TxCb
->SolicitRetry
= FALSE
;
3049 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3050 TxCb
->SolicitRetry
= TRUE
;
3056 // 2. Check the configured Ia, count lease time of every valid Ia to check
3057 // whether need to renew or rebind this Ia.
3059 IaCb
= &Instance
->IaCb
;
3061 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
3065 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
3069 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3071 // Exceed t2, send rebind packet to extend the Ia lease.
3073 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3075 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3078 // Exceed t1, send renew packet to extend the Ia lease.
3080 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3085 // 3. In any situation when a client may have moved to a new link, the
3086 // client MUST initiate a Confirm/Reply message exchange.
3088 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3089 Dhcp6SendConfirmMsg (Instance
);
3096 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
3097 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
3098 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
3101 // The failure of renew/Confirm will still switch to the bound state.
3103 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3104 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
3105 ASSERT (Instance
->IaCb
.Ia
);
3106 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3109 // The failure of info-request will return no response.
3111 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3112 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3121 // The failure of the others will terminate current state machine if timeout.
3123 Dhcp6CleanupSession (Instance
, EFI_NO_RESPONSE
);