2 Dhcp6 internal functions implementation.
4 Copyright (c) 2009 - 2014, 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
);
367 Check whether the TxCb is still a valid control block in the instance's retry list.
369 @param[in] Instance The pointer to DHCP6_INSTANCE.
370 @param[in] TxCb The control block for a transmitted message.
372 @retval TRUE The control block is in Instance's retry list.
373 @retval FALSE The control block is NOT in Instance's retry list.
378 IN DHCP6_INSTANCE
*Instance
,
384 NET_LIST_FOR_EACH (Entry
, &Instance
->TxList
) {
385 if (TxCb
== NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
)) {
394 Clean up the session of the instance stateful exchange.
396 @param[in, out] Instance The pointer to the Dhcp6 instance.
397 @param[in] Status The return status from udp.
401 Dhcp6CleanupSession (
402 IN OUT DHCP6_INSTANCE
*Instance
,
409 ASSERT(Instance
->Config
);
410 ASSERT(Instance
->IaCb
.Ia
);
413 // Clean up the retransmit list for stateful messages.
415 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
417 if (Instance
->Unicast
!= NULL
) {
418 FreePool (Instance
->Unicast
);
421 if (Instance
->AdSelect
!= NULL
) {
422 FreePool (Instance
->AdSelect
);
425 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
426 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
430 // Reinitialize the Ia fields of the instance.
432 Instance
->UdpSts
= Status
;
433 Instance
->AdSelect
= NULL
;
434 Instance
->AdPref
= 0;
435 Instance
->Unicast
= NULL
;
436 Instance
->IaCb
.T1
= 0;
437 Instance
->IaCb
.T2
= 0;
438 Instance
->IaCb
.AllExpireTime
= 0;
439 Instance
->IaCb
.LeaseTime
= 0;
444 Instance
->StartTime
= 0;
446 Ia
= Instance
->IaCb
.Ia
;
447 Ia
->State
= Dhcp6Init
;
448 Ia
->ReplyPacket
= NULL
;
451 // Set the addresses as zero lifetime, and then the notify
452 // function in Ip6Config will remove these timeout address.
454 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
455 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
456 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
461 // Signal the Ia information updated event to informal user.
463 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
464 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
470 Callback to user when Dhcp6 transmit/receive occurs.
472 @param[in] Instance The pointer to the Dhcp6 instance.
473 @param[in] Event The current Dhcp6 event.
474 @param[in, out] Packet The pointer to the packet sending or received.
476 @retval EFI_SUCCESS The user function returns success.
477 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
478 @retval EFI_ABORTED The user function ask it to abort.
484 IN DHCP6_INSTANCE
*Instance
,
485 IN EFI_DHCP6_EVENT Event
,
486 IN OUT EFI_DHCP6_PACKET
**Packet
490 EFI_DHCP6_PACKET
*NewPacket
;
491 EFI_DHCP6_CALLBACK Callback
;
494 ASSERT (Packet
!= NULL
);
495 ASSERT (Instance
->Config
!= NULL
);
496 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
499 Status
= EFI_SUCCESS
;
500 Callback
= Instance
->Config
->Dhcp6Callback
;
501 Context
= Instance
->Config
->CallbackContext
;
504 // Callback to user with the new message if has.
506 if (Callback
!= NULL
) {
511 Instance
->IaCb
.Ia
->State
,
517 // Updated the new packet from user to replace the original one.
519 if (NewPacket
!= NULL
) {
520 ASSERT (*Packet
!= NULL
);
531 Update Ia according to the new reply message.
533 @param[in, out] Instance The pointer to the Dhcp6 instance.
534 @param[in] Packet The pointer to reply messages.
536 @retval EFI_SUCCESS Updated the Ia information successfully.
537 @retval EFI_DEVICE_ERROR An unexpected error.
542 IN OUT DHCP6_INSTANCE
*Instance
,
543 IN EFI_DHCP6_PACKET
*Packet
547 EFI_DHCP6_STATE State
;
555 ASSERT (Instance
->Config
!= NULL
);
557 // If the reply was received in reponse to a solicit with rapid commit option,
558 // request, renew or rebind message, the client updates the information it has
559 // recorded about IAs from the IA options contained in the reply message:
560 // 1. record the T1 and T2 times
561 // 2. add any new addresses in the IA
562 // 3. discard any addresses from the IA, that have a valid lifetime of 0
563 // 4. update lifetimes for any addresses that alread recorded
564 // 5. leave unchanged any information about addresses
566 // See details in the section-18.1.8 of rfc-3315.
569 Option
= Dhcp6SeekIaOption (
570 Packet
->Dhcp6
.Option
,
571 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
572 &Instance
->Config
->IaDescriptor
574 if (Option
== NULL
) {
575 return EFI_DEVICE_ERROR
;
579 // The format of the IA_NA option is:
582 // 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
583 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584 // | OPTION_IA_NA | option-len |
585 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586 // | IAID (4 octets) |
587 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
597 // The format of the IA_TA option is:
600 // 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
601 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
602 // | OPTION_IA_TA | option-len |
603 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
604 // | IAID (4 octets) |
605 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613 // sizeof (option-code + option-len + IaId) = 8
614 // sizeof (option-code + option-len + IaId + T1) = 12
615 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
617 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
619 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
620 T1
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 8)));
621 T2
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 12)));
623 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
624 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
625 // the remainder of the message as though the server had not included the invalid IA_NA option.
627 if (T1
> T2
&& T2
> 0) {
628 return EFI_DEVICE_ERROR
;
630 IaInnerOpt
= Option
+ 16;
631 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
635 IaInnerOpt
= Option
+ 8;
636 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
640 // The format of the Status Code option is:
643 // 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
644 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
645 // | OPTION_STATUS_CODE | option-len |
646 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
648 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
650 // . status-message .
652 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
656 // sizeof (option-code + option-len) = 4
658 StsCode
= Dhcp6StsSuccess
;
659 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
661 if (Option
!= NULL
) {
662 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
663 if (StsCode
!= Dhcp6StsSuccess
) {
664 return EFI_DEVICE_ERROR
;
669 // Generate control block for the Ia.
671 Status
= Dhcp6GenerateIaCb (
685 Seek StatusCode Option in package. A Status Code option may appear in the
686 options field of a DHCP message and/or in the options field of another option.
687 See details in section 22.13, RFC3315.
689 @param[in] Instance The pointer to the Dhcp6 instance.
690 @param[in] Packet The pointer to reply messages.
691 @param[out] Option The pointer to status code option.
693 @retval EFI_SUCCESS Seek status code option successfully.
694 @retval EFI_DEVICE_ERROR An unexpected error.
699 IN DHCP6_INSTANCE
*Instance
,
700 IN EFI_DHCP6_PACKET
*Packet
,
709 // Seek StatusCode option directly in DHCP message body. That is, search in
710 // non-encapsulated option fields.
712 *Option
= Dhcp6SeekOption (
713 Packet
->Dhcp6
.Option
,
718 if (*Option
!= NULL
) {
719 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
720 if (StsCode
!= Dhcp6StsSuccess
) {
721 return EFI_DEVICE_ERROR
;
726 // Seek in encapsulated options, IA_NA and IA_TA.
728 *Option
= Dhcp6SeekIaOption (
729 Packet
->Dhcp6
.Option
,
730 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
731 &Instance
->Config
->IaDescriptor
733 if (*Option
== NULL
) {
738 // The format of the IA_NA option is:
741 // 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
742 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743 // | OPTION_IA_NA | option-len |
744 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
745 // | IAID (4 octets) |
746 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
750 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
754 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
756 // The format of the IA_TA option is:
759 // 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
760 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // | OPTION_IA_TA | option-len |
762 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
763 // | IAID (4 octets) |
764 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
768 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
772 // sizeof (option-code + option-len + IaId) = 8
773 // sizeof (option-code + option-len + IaId + T1) = 12
774 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
776 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
778 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
779 IaInnerOpt
= *Option
+ 16;
780 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
782 IaInnerOpt
= *Option
+ 8;
783 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
787 // The format of the Status Code option is:
790 // 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
791 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
792 // | OPTION_STATUS_CODE | option-len |
793 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
795 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
797 // . status-message .
799 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
803 // sizeof (option-code + option-len) = 4
805 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
806 if (*Option
!= NULL
) {
807 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
808 if (StsCode
!= Dhcp6StsSuccess
) {
809 return EFI_DEVICE_ERROR
;
818 Transmit Dhcp6 message by udpio.
820 @param[in] Instance The pointer to the Dhcp6 instance.
821 @param[in] Packet The pointer to transmit message.
822 @param[in] Elapsed The pointer to the elapsed time value to fill in.
824 @retval EFI_SUCCESS Successfully transmitted the packet.
825 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
826 @retval Others Failed to transmit the packet.
830 Dhcp6TransmitPacket (
831 IN DHCP6_INSTANCE
*Instance
,
832 IN EFI_DHCP6_PACKET
*Packet
,
840 DHCP6_SERVICE
*Service
;
842 Service
= Instance
->Service
;
845 // Wrap it into a netbuf then send it.
847 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
848 Frag
.Len
= Packet
->Length
;
851 // Do not register free packet here, which will be handled in retry list.
853 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
856 return EFI_OUT_OF_RESOURCES
;
860 // Multicast the Dhcp6 message, unless get the unicast server address by option.
862 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
864 if (Instance
->Unicast
!= NULL
) {
868 sizeof (EFI_IPv6_ADDRESS
)
873 &mAllDhcpRelayAndServersAddress
,
874 sizeof (EFI_IPv6_ADDRESS
)
878 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
879 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
882 // Update the elapsed time value.
884 if (Elapsed
!= NULL
) {
885 SetElapsedTime (Elapsed
, Instance
);
889 // Send out the message by the configured Udp6Io.
891 Status
= UdpIoSendDatagram (
900 if (EFI_ERROR (Status
)) {
910 Create the solicit message and send it.
912 @param[in] Instance The pointer to the Dhcp6 instance.
914 @retval EFI_SUCCESS Created and sent the solicit message successfully.
915 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
916 @retval Others Failed to send the solicit message.
920 Dhcp6SendSolicitMsg (
921 IN DHCP6_INSTANCE
*Instance
925 EFI_DHCP6_PACKET
*Packet
;
926 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
927 EFI_DHCP6_DUID
*ClientId
;
928 DHCP6_SERVICE
*Service
;
935 Service
= Instance
->Service
;
936 ClientId
= Service
->ClientId
;
939 ASSERT (Service
->ClientId
!= NULL
);
940 ASSERT (Instance
->Config
!= NULL
);
941 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
944 // Calculate the added length of customized option list.
946 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
947 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
951 // Create the Dhcp6 packet and initialize commone fields.
953 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
954 if (Packet
== NULL
) {
955 return EFI_OUT_OF_RESOURCES
;
958 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
959 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
960 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
961 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
964 // Assembly Dhcp6 options for solicit message.
966 Cursor
= Packet
->Dhcp6
.Option
;
968 Length
= HTONS (ClientId
->Length
);
969 Cursor
= Dhcp6AppendOption (
971 HTONS (Dhcp6OptClientId
),
976 Cursor
= Dhcp6AppendETOption (
982 Cursor
= Dhcp6AppendIaOption (
987 Packet
->Dhcp6
.Header
.MessageType
991 // Append user-defined when configurate Dhcp6 service.
993 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
995 UserOpt
= Instance
->Config
->OptionList
[Index
];
996 Cursor
= Dhcp6AppendOption(
1005 // Determine the size/length of packet.
1007 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1008 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1011 // Callback to user with the packet to be sent and check the user's feedback.
1013 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
1015 if (EFI_ERROR (Status
)) {
1021 // Send solicit packet with the state transition from Dhcp6init to
1024 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1026 // Clear initial time for current transaction.
1028 Instance
->StartTime
= 0;
1030 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1032 if (EFI_ERROR (Status
)) {
1038 // Enqueue the sent packet for the retransmission in case reply timeout.
1040 return Dhcp6EnqueueRetry (
1044 Instance
->Config
->SolicitRetransmission
1049 Configure some parameter to initiate SolicitMsg.
1051 @param[in] Instance The pointer to the Dhcp6 instance.
1053 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1054 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1055 @retval Others Failed to send the solicit message.
1059 Dhcp6InitSolicitMsg (
1060 IN DHCP6_INSTANCE
*Instance
1063 Instance
->IaCb
.T1
= 0;
1064 Instance
->IaCb
.T2
= 0;
1065 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1067 return Dhcp6SendSolicitMsg (Instance
);
1072 Create the request message and send it.
1074 @param[in] Instance The pointer to the Dhcp6 instance.
1076 @retval EFI_SUCCESS Created and sent the request message successfully.
1077 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1078 @retval EFI_DEVICE_ERROR An unexpected error.
1079 @retval Others Failed to send the request message.
1083 Dhcp6SendRequestMsg (
1084 IN DHCP6_INSTANCE
*Instance
1088 EFI_DHCP6_PACKET
*Packet
;
1089 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1090 EFI_DHCP6_DUID
*ClientId
;
1091 EFI_DHCP6_DUID
*ServerId
;
1092 DHCP6_SERVICE
*Service
;
1100 ASSERT(Instance
->AdSelect
!= NULL
);
1101 ASSERT(Instance
->Config
!= NULL
);
1102 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1103 ASSERT(Instance
->Service
!= NULL
);
1105 Service
= Instance
->Service
;
1106 ClientId
= Service
->ClientId
;
1108 ASSERT(ClientId
!= NULL
);
1111 // Get the server Id from the selected advertisement message.
1113 Option
= Dhcp6SeekOption (
1114 Instance
->AdSelect
->Dhcp6
.Option
,
1115 Instance
->AdSelect
->Length
- 4,
1118 if (Option
== NULL
) {
1119 return EFI_DEVICE_ERROR
;
1122 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1125 // Calculate the added length of customized option list.
1128 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1129 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1133 // Create the Dhcp6 packet and initialize commone fields.
1135 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1136 if (Packet
== NULL
) {
1137 return EFI_OUT_OF_RESOURCES
;
1140 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1141 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1142 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1143 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1146 // Assembly Dhcp6 options for request message.
1148 Cursor
= Packet
->Dhcp6
.Option
;
1150 Length
= HTONS (ClientId
->Length
);
1151 Cursor
= Dhcp6AppendOption (
1153 HTONS (Dhcp6OptClientId
),
1158 Cursor
= Dhcp6AppendETOption (
1164 Cursor
= Dhcp6AppendOption (
1166 HTONS (Dhcp6OptServerId
),
1171 Cursor
= Dhcp6AppendIaOption (
1176 Packet
->Dhcp6
.Header
.MessageType
1180 // Append user-defined when configurate Dhcp6 service.
1182 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1184 UserOpt
= Instance
->Config
->OptionList
[Index
];
1185 Cursor
= Dhcp6AppendOption(
1194 // Determine the size/length of packet.
1196 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1197 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1200 // Callback to user with the packet to be sent and check the user's feedback.
1202 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1204 if (EFI_ERROR (Status
)) {
1210 // Send request packet with the state transition from Dhcp6selecting to
1213 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1215 // Clear initial time for current transaction.
1217 Instance
->StartTime
= 0;
1219 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1221 if (EFI_ERROR (Status
)) {
1227 // Enqueue the sent packet for the retransmission in case reply timeout.
1229 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1234 Create the decline message and send it.
1236 @param[in] Instance The pointer to the Dhcp6 instance.
1237 @param[in] DecIa The pointer to the decline Ia.
1239 @retval EFI_SUCCESS Created and sent the decline message successfully.
1240 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1241 @retval EFI_DEVICE_ERROR An unexpected error.
1242 @retval Others Failed to send the decline message.
1246 Dhcp6SendDeclineMsg (
1247 IN DHCP6_INSTANCE
*Instance
,
1248 IN EFI_DHCP6_IA
*DecIa
1252 EFI_DHCP6_PACKET
*Packet
;
1253 EFI_DHCP6_PACKET
*LastReply
;
1254 EFI_DHCP6_DUID
*ClientId
;
1255 EFI_DHCP6_DUID
*ServerId
;
1256 DHCP6_SERVICE
*Service
;
1262 ASSERT (Instance
->Config
!= NULL
);
1263 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1264 ASSERT (Instance
->Service
!= NULL
);
1266 Service
= Instance
->Service
;
1267 ClientId
= Service
->ClientId
;
1268 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1270 ASSERT (ClientId
!= NULL
);
1271 ASSERT (LastReply
!= NULL
);
1274 // Get the server Id from the last reply message.
1276 Option
= Dhcp6SeekOption (
1277 LastReply
->Dhcp6
.Option
,
1278 LastReply
->Length
- 4,
1281 if (Option
== NULL
) {
1282 return EFI_DEVICE_ERROR
;
1286 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1288 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1291 // Create the Dhcp6 packet and initialize commone fields.
1293 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1294 if (Packet
== NULL
) {
1295 return EFI_OUT_OF_RESOURCES
;
1298 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1299 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1300 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1301 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1304 // Assembly Dhcp6 options for rebind/renew message.
1306 Cursor
= Packet
->Dhcp6
.Option
;
1308 Length
= HTONS (ClientId
->Length
);
1309 Cursor
= Dhcp6AppendOption (
1311 HTONS (Dhcp6OptClientId
),
1316 Cursor
= Dhcp6AppendETOption (
1322 Cursor
= Dhcp6AppendOption (
1324 HTONS (Dhcp6OptServerId
),
1329 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1332 // Determine the size/length of packet.
1334 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1335 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1338 // Callback to user with the packet to be sent and check the user's feedback.
1340 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1342 if (EFI_ERROR (Status
)) {
1348 // Send decline packet with the state transition from Dhcp6bound to
1351 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1353 // Clear initial time for current transaction.
1355 Instance
->StartTime
= 0;
1357 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1359 if (EFI_ERROR (Status
)) {
1365 // Enqueue the sent packet for the retransmission in case reply timeout.
1367 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1372 Create the release message and send it.
1374 @param[in] Instance The pointer to the Dhcp6 instance.
1375 @param[in] RelIa The pointer to the release Ia.
1377 @retval EFI_SUCCESS Created and sent the release message successfully.
1378 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1379 @retval EFI_DEVICE_ERROR An unexpected error.
1380 @retval Others Failed to send the release message.
1384 Dhcp6SendReleaseMsg (
1385 IN DHCP6_INSTANCE
*Instance
,
1386 IN EFI_DHCP6_IA
*RelIa
1390 EFI_DHCP6_PACKET
*Packet
;
1391 EFI_DHCP6_PACKET
*LastReply
;
1392 EFI_DHCP6_DUID
*ClientId
;
1393 EFI_DHCP6_DUID
*ServerId
;
1394 DHCP6_SERVICE
*Service
;
1400 ASSERT(Instance
->Config
);
1401 ASSERT(Instance
->IaCb
.Ia
);
1403 Service
= Instance
->Service
;
1404 ClientId
= Service
->ClientId
;
1405 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1411 // Get the server Id from the last reply message.
1413 Option
= Dhcp6SeekOption (
1414 LastReply
->Dhcp6
.Option
,
1415 LastReply
->Length
- 4,
1418 if (Option
== NULL
) {
1419 return EFI_DEVICE_ERROR
;
1422 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1425 // Create the Dhcp6 packet and initialize commone fields.
1427 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1428 if (Packet
== NULL
) {
1429 return EFI_OUT_OF_RESOURCES
;
1432 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1433 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1434 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1435 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1438 // Assembly Dhcp6 options for rebind/renew message
1440 Cursor
= Packet
->Dhcp6
.Option
;
1442 Length
= HTONS (ClientId
->Length
);
1443 Cursor
= Dhcp6AppendOption (
1445 HTONS (Dhcp6OptClientId
),
1451 // ServerId is extracted from packet, it's network order.
1453 Cursor
= Dhcp6AppendOption (
1455 HTONS (Dhcp6OptServerId
),
1460 Cursor
= Dhcp6AppendETOption (
1466 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1469 // Determine the size/length of packet
1471 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1472 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1475 // Callback to user with the packet to be sent and check the user's feedback.
1477 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1479 if (EFI_ERROR (Status
)) {
1485 // Send release packet with the state transition from Dhcp6bound to
1488 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1490 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1492 if (EFI_ERROR (Status
)) {
1498 // Enqueue the sent packet for the retransmission in case reply timeout.
1500 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1505 Create the renew/rebind message and send it.
1507 @param[in] Instance The pointer to the Dhcp6 instance.
1508 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1509 Otherwise, it is a Renew type message.
1511 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1512 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1513 @retval EFI_DEVICE_ERROR An unexpected error.
1514 @retval Others Failed to send the renew/rebind message.
1518 Dhcp6SendRenewRebindMsg (
1519 IN DHCP6_INSTANCE
*Instance
,
1520 IN BOOLEAN RebindRequest
1524 EFI_DHCP6_PACKET
*Packet
;
1525 EFI_DHCP6_PACKET
*LastReply
;
1526 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1527 EFI_DHCP6_DUID
*ClientId
;
1528 EFI_DHCP6_DUID
*ServerId
;
1529 EFI_DHCP6_STATE State
;
1530 EFI_DHCP6_EVENT Event
;
1531 DHCP6_SERVICE
*Service
;
1539 ASSERT(Instance
->Config
);
1540 ASSERT(Instance
->IaCb
.Ia
);
1542 Service
= Instance
->Service
;
1543 ClientId
= Service
->ClientId
;
1548 // Calculate the added length of customized option list.
1551 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1552 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1556 // Create the Dhcp6 packet and initialize commone fields.
1558 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1559 if (Packet
== NULL
) {
1560 return EFI_OUT_OF_RESOURCES
;
1563 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1564 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1565 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1566 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1569 // Assembly Dhcp6 options for rebind/renew message.
1571 Cursor
= Packet
->Dhcp6
.Option
;
1573 Length
= HTONS (ClientId
->Length
);
1574 Cursor
= Dhcp6AppendOption (
1576 HTONS (Dhcp6OptClientId
),
1581 Cursor
= Dhcp6AppendETOption (
1587 Cursor
= Dhcp6AppendIaOption (
1592 Packet
->Dhcp6
.Header
.MessageType
1595 if (!RebindRequest
) {
1597 // Get the server Id from the last reply message and
1598 // insert it for rebind request.
1600 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1603 Option
= Dhcp6SeekOption (
1604 LastReply
->Dhcp6
.Option
,
1605 LastReply
->Length
- 4,
1608 if (Option
== NULL
) {
1610 return EFI_DEVICE_ERROR
;
1613 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1615 Cursor
= Dhcp6AppendOption (
1617 HTONS (Dhcp6OptServerId
),
1624 // Append user-defined when configurate Dhcp6 service.
1626 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1628 UserOpt
= Instance
->Config
->OptionList
[Index
];
1629 Cursor
= Dhcp6AppendOption(
1638 // Determine the size/length of packet.
1640 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1641 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1644 // Callback to user with the packet to be sent and check the user's feedback.
1646 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1647 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1649 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1651 if (EFI_ERROR (Status
)) {
1657 // Send renew/rebind packet with the state transition from Dhcp6bound to
1658 // Dhcp6renew/rebind.
1659 // And sync the lease time when send renew/rebind, in case that user send
1660 // renew/rebind actively.
1662 Instance
->IaCb
.Ia
->State
= State
;
1663 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1665 // Clear initial time for current transaction.
1667 Instance
->StartTime
= 0;
1669 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1671 if (EFI_ERROR (Status
)) {
1677 // Enqueue the sent packet for the retransmission in case reply timeout.
1679 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1683 Start the information request process.
1685 @param[in] Instance The pointer to the Dhcp6 instance.
1686 @param[in] SendClientId If TRUE, the client identifier option will be included in
1687 information request message. Otherwise, the client identifier
1688 option will not be included.
1689 @param[in] OptionRequest The pointer to the option request option.
1690 @param[in] OptionCount The number options in the OptionList.
1691 @param[in] OptionList The array pointers to the appended options.
1692 @param[in] Retransmission The pointer to the retransmission control.
1693 @param[in] TimeoutEvent The event of timeout.
1694 @param[in] ReplyCallback The callback function when the reply was received.
1695 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1697 @retval EFI_SUCCESS Start the info-request process successfully.
1698 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1699 @retval EFI_NO_MAPPING No source address is available for use.
1700 @retval Others Failed to start the info-request process.
1704 Dhcp6StartInfoRequest (
1705 IN DHCP6_INSTANCE
*Instance
,
1706 IN BOOLEAN SendClientId
,
1707 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1708 IN UINT32 OptionCount
,
1709 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1710 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1711 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1712 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1713 IN VOID
*CallbackContext OPTIONAL
1717 DHCP6_INF_CB
*InfCb
;
1718 DHCP6_SERVICE
*Service
;
1721 Service
= Instance
->Service
;
1723 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1724 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1726 // Create and initialize the control block for the info-request.
1728 InfCb
= AllocateZeroPool (sizeof(DHCP6_INF_CB
));
1730 if (InfCb
== NULL
) {
1731 gBS
->RestoreTPL (OldTpl
);
1732 return EFI_OUT_OF_RESOURCES
;
1735 InfCb
->ReplyCallback
= ReplyCallback
;
1736 InfCb
->CallbackContext
= CallbackContext
;
1737 InfCb
->TimeoutEvent
= TimeoutEvent
;
1739 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1742 // Send the info-request message to start exchange process.
1744 Status
= Dhcp6SendInfoRequestMsg (
1754 if (EFI_ERROR (Status
)) {
1759 // Register receive callback for the stateless exchange process.
1761 Status
= UdpIoRecvDatagram(
1768 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1772 gBS
->RestoreTPL (OldTpl
);
1776 gBS
->RestoreTPL (OldTpl
);
1777 RemoveEntryList (&InfCb
->Link
);
1784 Create the information request message and send it.
1786 @param[in] Instance The pointer to the Dhcp6 instance.
1787 @param[in] InfCb The pointer to the information request control block.
1788 @param[in] SendClientId If TRUE, the client identifier option will be included in
1789 information request message. Otherwise, the client identifier
1790 option will not be included.
1791 @param[in] OptionRequest The pointer to the option request option.
1792 @param[in] OptionCount The number options in the OptionList.
1793 @param[in] OptionList The array pointers to the appended options.
1794 @param[in] Retransmission The pointer to the retransmission control.
1796 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1797 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1798 @retval Others Failed to send the info-request message.
1802 Dhcp6SendInfoRequestMsg (
1803 IN DHCP6_INSTANCE
*Instance
,
1804 IN DHCP6_INF_CB
*InfCb
,
1805 IN BOOLEAN SendClientId
,
1806 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1807 IN UINT32 OptionCount
,
1808 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1809 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1813 EFI_DHCP6_PACKET
*Packet
;
1814 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1815 EFI_DHCP6_DUID
*ClientId
;
1816 DHCP6_SERVICE
*Service
;
1823 ASSERT(OptionRequest
);
1825 Service
= Instance
->Service
;
1826 ClientId
= Service
->ClientId
;
1827 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1832 // Calculate the added length of customized option list.
1834 for (Index
= 0; Index
< OptionCount
; Index
++) {
1835 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1839 // Create the Dhcp6 packet and initialize commone fields.
1841 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1842 if (Packet
== NULL
) {
1843 return EFI_OUT_OF_RESOURCES
;
1846 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1847 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1848 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1849 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1851 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1854 // Assembly Dhcp6 options for info-request message.
1856 Cursor
= Packet
->Dhcp6
.Option
;
1859 Length
= HTONS (ClientId
->Length
);
1860 Cursor
= Dhcp6AppendOption (
1862 HTONS (Dhcp6OptClientId
),
1868 Cursor
= Dhcp6AppendETOption (
1874 Cursor
= Dhcp6AppendOption (
1876 OptionRequest
->OpCode
,
1877 OptionRequest
->OpLen
,
1882 // Append user-defined when configurate Dhcp6 service.
1884 for (Index
= 0; Index
< OptionCount
; Index
++) {
1886 UserOpt
= OptionList
[Index
];
1887 Cursor
= Dhcp6AppendOption(
1896 // Determine the size/length of packet.
1898 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1899 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1902 // Clear initial time for current transaction.
1904 Instance
->StartTime
= 0;
1907 // Send info-request packet with no state.
1909 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1911 if (EFI_ERROR (Status
)) {
1917 // Enqueue the sent packet for the retransmission in case reply timeout.
1919 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1924 Create the Confirm message and send it.
1926 @param[in] Instance The pointer to the Dhcp6 instance.
1928 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1929 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1930 @retval EFI_DEVICE_ERROR An unexpected error.
1931 @retval Others Failed to send the confirm message.
1935 Dhcp6SendConfirmMsg (
1936 IN DHCP6_INSTANCE
*Instance
1944 DHCP6_SERVICE
*Service
;
1945 EFI_DHCP6_DUID
*ClientId
;
1946 EFI_DHCP6_PACKET
*Packet
;
1947 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1950 ASSERT (Instance
->Config
!= NULL
);
1951 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1952 ASSERT (Instance
->Service
!= NULL
);
1954 Service
= Instance
->Service
;
1955 ClientId
= Service
->ClientId
;
1956 ASSERT (ClientId
!= NULL
);
1959 // Calculate the added length of customized option list.
1962 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1963 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1967 // Create the Dhcp6 packet and initialize common fields.
1969 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1970 if (Packet
== NULL
) {
1971 return EFI_OUT_OF_RESOURCES
;
1974 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1975 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1976 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1977 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1980 // Assembly Dhcp6 options for solicit message.
1982 Cursor
= Packet
->Dhcp6
.Option
;
1984 Length
= HTONS (ClientId
->Length
);
1985 Cursor
= Dhcp6AppendOption (
1987 HTONS (Dhcp6OptClientId
),
1992 Cursor
= Dhcp6AppendETOption (
1998 Cursor
= Dhcp6AppendIaOption (
2003 Packet
->Dhcp6
.Header
.MessageType
2007 // Append user-defined when configurate Dhcp6 service.
2009 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
2010 UserOpt
= Instance
->Config
->OptionList
[Index
];
2011 Cursor
= Dhcp6AppendOption (
2020 // Determine the size/length of packet.
2022 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
2023 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
2026 // Callback to user with the packet to be sent and check the user's feedback.
2028 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
2030 if (EFI_ERROR (Status
)) {
2036 // Send confirm packet with the state transition from Dhcp6Bound to
2039 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2041 // Clear initial time for current transaction.
2043 Instance
->StartTime
= 0;
2045 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2047 if (EFI_ERROR (Status
)) {
2053 // Enqueue the sent packet for the retransmission in case reply timeout.
2055 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2061 Handle with the Dhcp6 reply message.
2063 @param[in] Instance The pointer to Dhcp6 instance.
2064 @param[in] Packet The pointer to the Dhcp6 reply message.
2066 @retval EFI_SUCCESS Processed the reply message successfully.
2067 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2068 @retval EFI_DEVICE_ERROR An unexpected error.
2069 @retval Others Failed to process the reply message.
2073 Dhcp6HandleReplyMsg (
2074 IN DHCP6_INSTANCE
*Instance
,
2075 IN EFI_DHCP6_PACKET
*Packet
2082 ASSERT (Instance
->Config
!= NULL
);
2083 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2084 ASSERT (Packet
!= NULL
);
2086 Status
= EFI_SUCCESS
;
2088 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2089 return EFI_DEVICE_ERROR
;
2093 // If the client subsequently receives a valid reply message that includes a
2094 // rapid commit option since send a solicit with rapid commit option before,
2095 // preocess the reply message and discard any reply messages received in
2096 // response to the request message.
2097 // See details in the section-17.1.4 of rfc-3315.
2099 Option
= Dhcp6SeekOption (
2100 Packet
->Dhcp6
.Option
,
2105 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
2106 return EFI_DEVICE_ERROR
;
2110 // As to a valid reply packet in response to a request/renew/rebind packet,
2111 // ignore the packet if not contains the Ia option
2113 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
2114 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
2115 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
2118 Option
= Dhcp6SeekIaOption (
2119 Packet
->Dhcp6
.Option
,
2121 &Instance
->Config
->IaDescriptor
2123 if (Option
== NULL
) {
2129 // Callback to user with the received packet and check the user's feedback.
2131 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2133 if (EFI_ERROR (Status
)) {
2138 // When receive a valid reply packet in response to a decline/release packet,
2139 // the client considers the decline/release event completed regardless of the
2142 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
2144 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2145 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2147 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2148 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2149 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2150 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2154 // For sync, set the success flag out of polling in decline/release.
2156 Instance
->UdpSts
= EFI_SUCCESS
;
2159 // For async, signal the Ia event to inform Ia infomation update.
2161 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2162 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2166 // Reset start time for next exchange.
2168 Instance
->StartTime
= 0;
2170 Status
= EFI_SUCCESS
;
2175 // Upon the receipt of a valid reply packet in response to a solicit, request,
2176 // confirm, renew and rebind, the behavior depends on the status code option.
2177 // See the details in the section-18.1.8 of rfc-3315.
2180 Status
= Dhcp6SeekStsOption (
2186 if (!EFI_ERROR (Status
)) {
2188 // No status code or no error status code means succeed to reply.
2190 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2191 if (!EFI_ERROR (Status
)) {
2193 // Reset start time for next exchange.
2195 Instance
->StartTime
= 0;
2198 // Set bound state and store the reply packet.
2200 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2201 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2204 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2206 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2207 Status
= EFI_OUT_OF_RESOURCES
;
2211 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2213 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2216 // For sync, set the success flag out of polling in start/renewrebind.
2218 Instance
->UdpSts
= EFI_SUCCESS
;
2221 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2222 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2223 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2224 // consumers can be notified to flush old address.
2226 Dhcp6AppendCacheIa (Instance
);
2229 // For async, signal the Ia event to inform Ia infomation update.
2231 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2232 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2234 } else if (Status
== EFI_NOT_FOUND
) {
2236 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2237 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2238 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2245 } else if (Option
!= NULL
) {
2247 // Any error status code option is found.
2249 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2251 case Dhcp6StsUnspecFail
:
2253 // It indicates the server is unable to process the message due to an
2254 // unspecified failure condition, so just retry if possible.
2258 case Dhcp6StsUseMulticast
:
2260 // It indicates the server receives a message via unicast from a client
2261 // to which the server has not sent a unicast option, so retry it by
2262 // multi-cast address.
2264 if (Instance
->Unicast
!= NULL
) {
2265 FreePool (Instance
->Unicast
);
2266 Instance
->Unicast
= NULL
;
2270 case Dhcp6StsNotOnLink
:
2271 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2273 // Before initiate new round DHCP, cache the current IA.
2275 Status
= Dhcp6CacheIa (Instance
);
2276 if (EFI_ERROR (Status
)) {
2281 // Restart S.A.R.R process to acquire new address.
2283 Status
= Dhcp6InitSolicitMsg (Instance
);
2284 if (EFI_ERROR (Status
)) {
2290 case Dhcp6StsNoBinding
:
2291 if (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
|| Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
) {
2293 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2294 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2296 Status
= Dhcp6SendRequestMsg(Instance
);
2297 if (EFI_ERROR (Status
)) {
2305 // The other status code, just restart solicitation.
2315 if (!EFI_ERROR(Status
)) {
2316 Status
= Dhcp6DequeueRetry (
2318 Packet
->Dhcp6
.Header
.TransactionId
,
2328 Select the appointed Dhcp6 advertisement message.
2330 @param[in] Instance The pointer to the Dhcp6 instance.
2331 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2333 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2334 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2335 @retval Others Failed to select the advertise message.
2339 Dhcp6SelectAdvertiseMsg (
2340 IN DHCP6_INSTANCE
*Instance
,
2341 IN EFI_DHCP6_PACKET
*AdSelect
2347 ASSERT (AdSelect
!= NULL
);
2350 // Callback to user with the selected advertisement packet, and the user
2351 // might overwrite it.
2353 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2355 if (EFI_ERROR (Status
)) {
2359 Instance
->AdSelect
= AdSelect
;
2362 // Dequeue the sent packet for the retransmission since advertisement selected.
2364 Status
= Dhcp6DequeueRetry (
2366 AdSelect
->Dhcp6
.Header
.TransactionId
,
2370 if (EFI_ERROR(Status
)) {
2375 // Check whether there is server unicast option in the selected advertise
2376 // packet, and update it.
2378 Option
= Dhcp6SeekOption(
2379 AdSelect
->Dhcp6
.Option
,
2380 AdSelect
->Length
- 4,
2381 Dhcp6OptServerUnicast
2384 if (Option
!= NULL
) {
2386 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2388 if (Instance
->Unicast
== NULL
) {
2389 return EFI_OUT_OF_RESOURCES
;
2392 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2396 // Update the information of the Ia by the selected advertisement message.
2398 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2400 if (EFI_ERROR (Status
)) {
2405 // Send the request message to continue the S.A.R.R. process.
2407 return Dhcp6SendRequestMsg (Instance
);
2412 Handle with the Dhcp6 advertisement message.
2414 @param[in] Instance The pointer to the Dhcp6 instance.
2415 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2417 @retval EFI_SUCCESS Processed the advertisement message successfully.
2418 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2419 @retval EFI_DEVICE_ERROR An unexpected error.
2420 @retval Others Failed to process the advertise message.
2424 Dhcp6HandleAdvertiseMsg (
2425 IN DHCP6_INSTANCE
*Instance
,
2426 IN EFI_DHCP6_PACKET
*Packet
2434 ASSERT(Instance
->Config
);
2435 ASSERT(Instance
->IaCb
.Ia
);
2438 StsCode
= Dhcp6StsSuccess
;
2441 // If the client does receives a valid reply message that includes a rapid
2442 // commit option since a solicit with rapid commit optioin sent before, select
2443 // this reply message. Or else, process the advertise messages as normal.
2444 // See details in the section-17.1.4 of rfc-3315.
2446 Option
= Dhcp6SeekOption(
2447 Packet
->Dhcp6
.Option
,
2452 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2454 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2457 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2458 return EFI_DEVICE_ERROR
;
2462 // Client must ignore any advertise message that includes a status code option
2463 // containing the value noaddrsavail, with the exception that the client may
2464 // display the associated status message to the user.
2465 // See the details in the section-17.1.3 of rfc-3315.
2467 Status
= Dhcp6SeekStsOption (
2472 if (EFI_ERROR (Status
)) {
2473 return EFI_DEVICE_ERROR
;
2477 // Callback to user with the received packet and check the user's feedback.
2479 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2481 if (!EFI_ERROR (Status
)) {
2483 // Success means user choose the current advertisement packet.
2485 if (Instance
->AdSelect
!= NULL
) {
2486 FreePool (Instance
->AdSelect
);
2490 // Store the selected advertisement packet and set a flag.
2492 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2494 if (Instance
->AdSelect
== NULL
) {
2495 return EFI_OUT_OF_RESOURCES
;
2498 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2500 Instance
->AdPref
= 0xff;
2502 } else if (Status
== EFI_NOT_READY
) {
2504 // Not_ready means user wants to continue to receive more advertise packets.
2506 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2508 // It's a tricky point. The timer routine set adpref as 0xff if the first
2509 // rt timeout and no advertisement received, which means any advertisement
2510 // received will be selected after the first rt.
2516 // Check whether the current packet has a 255 preference option or not.
2517 // Take non-preference option as 0 value.
2519 Option
= Dhcp6SeekOption(
2520 Packet
->Dhcp6
.Option
,
2525 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2527 // No advertisements received before or preference is more than other
2528 // advertisements received before. Then store the new packet and the
2529 // preference value.
2531 if (Instance
->AdSelect
!= NULL
) {
2532 FreePool (Instance
->AdSelect
);
2535 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2537 if (Instance
->AdSelect
== NULL
) {
2538 return EFI_OUT_OF_RESOURCES
;
2541 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2543 if (Option
!= NULL
) {
2544 Instance
->AdPref
= *(Option
+ 4);
2548 // Non-preference and other advertisements received before or current
2549 // preference is less than other advertisements received before.
2550 // Leave the packet alone.
2555 // Other error status means termination.
2561 // Client must collect advertise messages as more as possible until the first
2562 // RT has elapsed, or get a highest preference 255 advertise.
2563 // See details in the section-17.1.2 of rfc-3315.
2565 if (Instance
->AdPref
== 0xff || Timeout
) {
2566 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2574 The Dhcp6 stateful exchange process routine.
2576 @param[in] Instance The pointer to the Dhcp6 instance.
2577 @param[in] Packet The pointer to the received Dhcp6 message.
2581 Dhcp6HandleStateful (
2582 IN DHCP6_INSTANCE
*Instance
,
2583 IN EFI_DHCP6_PACKET
*Packet
2587 EFI_DHCP6_DUID
*ClientId
;
2588 DHCP6_SERVICE
*Service
;
2591 Service
= Instance
->Service
;
2592 ClientId
= Service
->ClientId
;
2593 Status
= EFI_SUCCESS
;
2595 if (Instance
->Config
== NULL
) {
2600 ASSERT (Instance
->Config
);
2601 ASSERT (Instance
->IaCb
.Ia
);
2604 // Discard the packet if not advertisement or reply packet.
2606 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2611 // Check whether include client Id or not.
2613 Option
= Dhcp6SeekOption(
2614 Packet
->Dhcp6
.Option
,
2619 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2624 // Check whether include server Id or not.
2626 Option
= Dhcp6SeekOption(
2627 Packet
->Dhcp6
.Option
,
2632 if (Option
== NULL
) {
2636 switch (Instance
->IaCb
.Ia
->State
) {
2637 case Dhcp6Selecting
:
2639 // Handle the advertisement message when in the Dhcp6Selecting state.
2640 // Do not need check return status, if failed, just continue to the next.
2642 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2645 case Dhcp6Requesting
:
2646 case Dhcp6Confirming
:
2648 case Dhcp6Rebinding
:
2649 case Dhcp6Releasing
:
2650 case Dhcp6Declining
:
2652 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2653 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2654 // If failed here, it should reset the current session.
2656 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2657 if (EFI_ERROR (Status
)) {
2663 // Other state has not supported yet.
2670 // Continue to receive the following Dhcp6 message.
2672 Status
= UdpIoRecvDatagram (
2679 if (EFI_ERROR (Status
)) {
2680 Dhcp6CleanupSession (Instance
, Status
);
2686 The Dhcp6 stateless exchange process routine.
2688 @param[in] Instance The pointer to the Dhcp6 instance.
2689 @param[in] Packet The pointer to the received Dhcp6 message.
2693 Dhcp6HandleStateless (
2694 IN DHCP6_INSTANCE
*Instance
,
2695 IN EFI_DHCP6_PACKET
*Packet
2699 DHCP6_SERVICE
*Service
;
2700 DHCP6_INF_CB
*InfCb
;
2704 Service
= Instance
->Service
;
2705 Status
= EFI_SUCCESS
;
2709 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2714 // Check whether it's a desired Info-request message by Xid.
2716 while (!IsListEmpty (&Instance
->InfList
)) {
2717 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2718 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2729 // Check whether include server Id or not.
2731 Option
= Dhcp6SeekOption (
2732 Packet
->Dhcp6
.Option
,
2737 if (Option
== NULL
) {
2742 // Callback to user with the received packet and check the user's feedback.
2744 Status
= InfCb
->ReplyCallback (
2746 InfCb
->CallbackContext
,
2750 if (Status
== EFI_NOT_READY
) {
2752 // Success or aborted will both stop this info-request exchange process,
2753 // but not ready means user wants to continue to receive reply.
2759 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2760 // if no xid matched.
2764 Packet
->Dhcp6
.Header
.TransactionId
,
2769 // For sync, set the status out of polling for info-request.
2771 Instance
->UdpSts
= Status
;
2775 Status
= UdpIoRecvDatagram (
2782 if (EFI_ERROR (Status
)) {
2783 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2789 The receive callback function for Dhcp6 exchange process.
2791 @param[in] Udp6Wrap The pointer to the received net buffer.
2792 @param[in] EndPoint The pointer to the udp end point.
2793 @param[in] IoStatus The return status from udp io.
2794 @param[in] Context The opaque parameter to the function.
2799 Dhcp6ReceivePacket (
2800 IN NET_BUF
*Udp6Wrap
,
2801 IN UDP_END_POINT
*EndPoint
,
2802 IN EFI_STATUS IoStatus
,
2806 EFI_DHCP6_HEADER
*Head
;
2807 EFI_DHCP6_PACKET
*Packet
;
2808 DHCP6_SERVICE
*Service
;
2809 DHCP6_INSTANCE
*Instance
;
2812 BOOLEAN IsDispatched
;
2813 BOOLEAN IsStateless
;
2819 ASSERT (Udp6Wrap
!= NULL
);
2820 ASSERT (Context
!= NULL
);
2822 Service
= (DHCP6_SERVICE
*) Context
;
2825 IsDispatched
= FALSE
;
2826 IsStateless
= FALSE
;
2828 if (EFI_ERROR (IoStatus
)) {
2833 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2835 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2836 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2838 if (Packet
== NULL
) {
2842 Packet
->Size
= Size
;
2843 Head
= &Packet
->Dhcp6
.Header
;
2844 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2846 if (Packet
->Length
== 0) {
2851 // Dispatch packet to right instance by transaction id.
2853 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2855 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2857 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2859 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2861 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2863 // Find the corresponding packet in tx list, and check it whether belongs
2864 // to stateful exchange process.
2866 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2869 IsDispatched
= TRUE
;
2880 // Skip this packet if not dispatched to any instance.
2882 if (!IsDispatched
) {
2887 // Dispatch the received packet ot the right instance.
2890 Dhcp6HandleStateless (Instance
, Packet
);
2892 Dhcp6HandleStateful (Instance
, Packet
);
2897 NetbufFree (Udp6Wrap
);
2899 if (Packet
!= NULL
) {
2905 Detect Link movement for specified network device.
2907 This routine will try to invoke Snp->GetStatus() to get the media status.
2908 If media present status switches from unpresent to present, a link movement
2909 is detected. Note that the underlying UNDI driver may not support reporting
2910 media status from GET_STATUS command. If that, fail to detect link movement.
2912 @param[in] Instance The pointer to DHCP6_INSTANCE.
2914 @retval TRUE A link movement is detected.
2915 @retval FALSE A link movement is not detected.
2919 Dhcp6LinkMovDetect (
2920 IN DHCP6_INSTANCE
*Instance
2923 UINT32 InterruptStatus
;
2924 BOOLEAN MediaPresent
;
2926 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2928 ASSERT (Instance
!= NULL
);
2929 Snp
= Instance
->Service
->Snp
;
2930 MediaPresent
= Instance
->MediaPresent
;
2933 // Check whether SNP support media detection
2935 if (!Snp
->Mode
->MediaPresentSupported
) {
2940 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2942 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2943 if (EFI_ERROR (Status
)) {
2947 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2949 // Media transimit Unpresent to Present means new link movement is detected.
2951 if (!MediaPresent
&& Instance
->MediaPresent
) {
2959 The timer routine of the Dhcp6 instance for each second.
2961 @param[in] Event The timer event.
2962 @param[in] Context The opaque parameter to the function.
2973 LIST_ENTRY
*NextEntry
;
2974 DHCP6_INSTANCE
*Instance
;
2980 ASSERT (Context
!= NULL
);
2982 Instance
= (DHCP6_INSTANCE
*) Context
;
2985 // 1. Loop the tx list, count live time of every tx packet to check whether
2986 // need re-transmit or not.
2988 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
2990 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
2994 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
2996 // Handle the first rt in the transmission of solicit specially.
2998 if ((TxCb
->RetryCnt
== 0 || TxCb
->SolicitRetry
) && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
2999 if (Instance
->AdSelect
== NULL
) {
3001 // Set adpref as 0xff here to indicate select any advertisement
3004 Instance
->AdPref
= 0xff;
3007 // Select the advertisement received before.
3009 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
3010 if (Status
== EFI_ABORTED
) {
3012 } else if (EFI_ERROR (Status
)) {
3019 // Increase the retry count for the packet and add up the total loss time.
3022 TxCb
->RetryLos
+= TxCb
->RetryExp
;
3025 // Check whether overflow the max retry count limit for this packet
3027 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
3028 Status
= EFI_NO_RESPONSE
;
3033 // Check whether overflow the max retry duration for this packet
3035 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
3036 Status
= EFI_NO_RESPONSE
;
3041 // Re-calculate retry expire timeout for the next time.
3043 // Firstly, Check the new calculated time whether overflow the max retry
3046 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3052 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
3053 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3061 // Secondly, Check the new calculated time whether overflow the max retry
3064 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3065 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
3066 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3070 // Reset the tick time for the next retransmission
3075 // Retransmit the last sent packet again.
3077 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3078 TxCb
->SolicitRetry
= FALSE
;
3079 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3080 TxCb
->SolicitRetry
= TRUE
;
3086 // 2. Check the configured Ia, count lease time of every valid Ia to check
3087 // whether need to renew or rebind this Ia.
3089 IaCb
= &Instance
->IaCb
;
3091 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
3095 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
3099 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3101 // Exceed t2, send rebind packet to extend the Ia lease.
3103 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3105 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3108 // Exceed t1, send renew packet to extend the Ia lease.
3110 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3115 // 3. In any situation when a client may have moved to a new link, the
3116 // client MUST initiate a Confirm/Reply message exchange.
3118 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3119 Dhcp6SendConfirmMsg (Instance
);
3126 if (Dhcp6IsValidTxCb (Instance
, TxCb
) &&
3127 TxCb
->TxPacket
!= NULL
&&
3128 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
3129 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
3130 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)
3133 // The failure of renew/Confirm will still switch to the bound state.
3135 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3136 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
3137 ASSERT (Instance
->IaCb
.Ia
);
3138 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3141 // The failure of info-request will return no response.
3143 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3144 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3153 // The failure of the others will terminate current state machine if timeout.
3155 Dhcp6CleanupSession (Instance
, Status
);