2 Dhcp6 internal functions implementation.
4 Copyright (c) 2009 - 2010, 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 destoryed 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)));
596 IaInnerOpt
= Option
+ 16;
597 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
601 IaInnerOpt
= Option
+ 8;
602 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
606 // The format of the Status Code option is:
609 // 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
610 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
611 // | OPTION_STATUS_CODE | option-len |
612 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
614 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
616 // . status-message .
618 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
622 // sizeof (option-code + option-len) = 4
624 StsCode
= Dhcp6StsSuccess
;
625 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
627 if (Option
!= NULL
) {
628 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
629 if (StsCode
!= Dhcp6StsSuccess
) {
630 return EFI_DEVICE_ERROR
;
635 // Generate control block for the Ia.
637 Status
= Dhcp6GenerateIaCb (
651 Seek StatusCode Option in package. A Status Code option may appear in the
652 options field of a DHCP message and/or in the options field of another option.
653 See details in section 22.13, RFC3315.
655 @param[in] Instance The pointer to the Dhcp6 instance.
656 @param[in] Packet The pointer to reply messages.
657 @param[out] Option The pointer to status code option.
659 @retval EFI_SUCCESS Seek status code option successfully.
660 @retval EFI_DEVICE_ERROR An unexpected error.
665 IN DHCP6_INSTANCE
*Instance
,
666 IN EFI_DHCP6_PACKET
*Packet
,
675 // Seek StatusCode option directly in DHCP message body. That is, search in
676 // non-encapsulated option fields.
678 *Option
= Dhcp6SeekOption (
679 Packet
->Dhcp6
.Option
,
684 if (*Option
!= NULL
) {
685 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
686 if (StsCode
!= Dhcp6StsSuccess
) {
687 return EFI_DEVICE_ERROR
;
692 // Seek in encapsulated options, IA_NA and IA_TA.
694 *Option
= Dhcp6SeekIaOption (
695 Packet
->Dhcp6
.Option
,
696 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
697 &Instance
->Config
->IaDescriptor
699 if (*Option
== NULL
) {
700 return EFI_DEVICE_ERROR
;
704 // The format of the IA_NA option is:
707 // 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
708 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
709 // | OPTION_IA_NA | option-len |
710 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
711 // | IAID (4 octets) |
712 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
714 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
716 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
720 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
722 // The format of the IA_TA option is:
725 // 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
726 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
727 // | OPTION_IA_TA | option-len |
728 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
729 // | IAID (4 octets) |
730 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
734 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
738 // sizeof (option-code + option-len + IaId) = 8
739 // sizeof (option-code + option-len + IaId + T1) = 12
740 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
742 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
744 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
745 IaInnerOpt
= *Option
+ 16;
746 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
748 IaInnerOpt
= *Option
+ 8;
749 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
753 // The format of the Status Code option is:
756 // 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
757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
758 // | OPTION_STATUS_CODE | option-len |
759 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
763 // . status-message .
765 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
769 // sizeof (option-code + option-len) = 4
771 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
772 if (*Option
!= NULL
) {
773 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
774 if (StsCode
!= Dhcp6StsSuccess
) {
775 return EFI_DEVICE_ERROR
;
784 Transmit Dhcp6 message by udpio.
786 @param[in] Instance The pointer to the Dhcp6 instance.
787 @param[in] Packet The pointer to transmit message.
788 @param[in] Elapsed The pointer to the elapsed time value to fill in.
790 @retval EFI_SUCCESS Successfully transmitted the packet.
791 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
792 @retval Others Failed to transmit the packet.
796 Dhcp6TransmitPacket (
797 IN DHCP6_INSTANCE
*Instance
,
798 IN EFI_DHCP6_PACKET
*Packet
,
806 DHCP6_SERVICE
*Service
;
808 Service
= Instance
->Service
;
811 // Wrap it into a netbuf then send it.
813 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
814 Frag
.Len
= Packet
->Length
;
817 // Do not register free packet here, which will be handled in retry list.
819 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
822 return EFI_OUT_OF_RESOURCES
;
826 // Multicast the Dhcp6 message, unless get the unicast server address by option.
828 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
830 if (Instance
->Unicast
!= NULL
) {
834 sizeof (EFI_IPv6_ADDRESS
)
839 &mAllDhcpRelayAndServersAddress
,
840 sizeof (EFI_IPv6_ADDRESS
)
844 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
845 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
848 // Update the elapsed time value.
850 if (Elapsed
!= NULL
) {
851 SetElapsedTime (Elapsed
, Instance
);
855 // Send out the message by the configured Udp6Io.
857 Status
= UdpIoSendDatagram (
866 if (EFI_ERROR (Status
)) {
876 Create the solicit message and send it.
878 @param[in] Instance The pointer to the Dhcp6 instance.
880 @retval EFI_SUCCESS Created and sent the solicit message successfully.
881 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
882 @retval Others Failed to send the solicit message.
886 Dhcp6SendSolicitMsg (
887 IN DHCP6_INSTANCE
*Instance
891 EFI_DHCP6_PACKET
*Packet
;
892 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
893 EFI_DHCP6_DUID
*ClientId
;
894 DHCP6_SERVICE
*Service
;
901 Service
= Instance
->Service
;
902 ClientId
= Service
->ClientId
;
905 ASSERT (Service
->ClientId
!= NULL
);
906 ASSERT (Instance
->Config
!= NULL
);
907 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
910 // Calculate the added length of customized option list.
912 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
913 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
917 // Create the Dhcp6 packet and initialize commone fields.
919 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
920 if (Packet
== NULL
) {
921 return EFI_OUT_OF_RESOURCES
;
924 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
925 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
926 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
927 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
930 // Assembly Dhcp6 options for solicit message.
932 Cursor
= Packet
->Dhcp6
.Option
;
934 Length
= HTONS (ClientId
->Length
);
935 Cursor
= Dhcp6AppendOption (
937 HTONS (Dhcp6OptClientId
),
942 Cursor
= Dhcp6AppendETOption (
948 Cursor
= Dhcp6AppendIaOption (
956 // Append user-defined when configurate Dhcp6 service.
958 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
960 UserOpt
= Instance
->Config
->OptionList
[Index
];
961 Cursor
= Dhcp6AppendOption(
970 // Determine the size/length of packet.
972 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
973 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
976 // Callback to user with the packet to be sent and check the user's feedback.
978 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
980 if (EFI_ERROR (Status
)) {
986 // Send solicit packet with the state transition from Dhcp6init to
989 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
991 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
993 if (EFI_ERROR (Status
)) {
999 // Enqueue the sent packet for the retransmission in case reply timeout.
1001 return Dhcp6EnqueueRetry (
1005 Instance
->Config
->SolicitRetransmission
1010 Configure some parameter to initiate SolicitMsg.
1012 @param[in] Instance The pointer to the Dhcp6 instance.
1014 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1015 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1016 @retval Others Failed to send the solicit message.
1020 Dhcp6InitSolicitMsg (
1021 IN DHCP6_INSTANCE
*Instance
1024 Instance
->IaCb
.T1
= 0;
1025 Instance
->IaCb
.T2
= 0;
1026 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1028 return Dhcp6SendSolicitMsg (Instance
);
1033 Create the request message and send it.
1035 @param[in] Instance The pointer to the Dhcp6 instance.
1037 @retval EFI_SUCCESS Created and sent the request message successfully.
1038 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1039 @retval EFI_DEVICE_ERROR An unexpected error.
1040 @retval Others Failed to send the request message.
1044 Dhcp6SendRequestMsg (
1045 IN DHCP6_INSTANCE
*Instance
1049 EFI_DHCP6_PACKET
*Packet
;
1050 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1051 EFI_DHCP6_DUID
*ClientId
;
1052 EFI_DHCP6_DUID
*ServerId
;
1053 DHCP6_SERVICE
*Service
;
1061 ASSERT(Instance
->AdSelect
!= NULL
);
1062 ASSERT(Instance
->Config
!= NULL
);
1063 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1064 ASSERT(Instance
->Service
!= NULL
);
1066 Service
= Instance
->Service
;
1067 ClientId
= Service
->ClientId
;
1069 ASSERT(ClientId
!= NULL
);
1072 // Get the server Id from the selected advertisement message.
1074 Option
= Dhcp6SeekOption (
1075 Instance
->AdSelect
->Dhcp6
.Option
,
1076 Instance
->AdSelect
->Length
- 4,
1079 if (Option
== NULL
) {
1080 return EFI_DEVICE_ERROR
;
1083 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1086 // Calculate the added length of customized option list.
1089 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1090 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1094 // Create the Dhcp6 packet and initialize commone fields.
1096 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1097 if (Packet
== NULL
) {
1098 return EFI_OUT_OF_RESOURCES
;
1101 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1102 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1103 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1104 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1107 // Assembly Dhcp6 options for request message.
1109 Cursor
= Packet
->Dhcp6
.Option
;
1111 Length
= HTONS (ClientId
->Length
);
1112 Cursor
= Dhcp6AppendOption (
1114 HTONS (Dhcp6OptClientId
),
1119 Cursor
= Dhcp6AppendETOption (
1125 Cursor
= Dhcp6AppendOption (
1127 HTONS (Dhcp6OptServerId
),
1132 Cursor
= Dhcp6AppendIaOption (
1140 // Append user-defined when configurate Dhcp6 service.
1142 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1144 UserOpt
= Instance
->Config
->OptionList
[Index
];
1145 Cursor
= Dhcp6AppendOption(
1154 // Determine the size/length of packet.
1156 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1157 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1160 // Callback to user with the packet to be sent and check the user's feedback.
1162 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1164 if (EFI_ERROR (Status
)) {
1170 // Send request packet with the state transition from Dhcp6selecting to
1173 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1175 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1177 if (EFI_ERROR (Status
)) {
1183 // Enqueue the sent packet for the retransmission in case reply timeout.
1185 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1190 Create the decline message and send it.
1192 @param[in] Instance The pointer to the Dhcp6 instance.
1193 @param[in] DecIa The pointer to the decline Ia.
1195 @retval EFI_SUCCESS Created and sent the decline message successfully.
1196 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1197 @retval EFI_DEVICE_ERROR An unexpected error.
1198 @retval Others Failed to send the decline message.
1202 Dhcp6SendDeclineMsg (
1203 IN DHCP6_INSTANCE
*Instance
,
1204 IN EFI_DHCP6_IA
*DecIa
1208 EFI_DHCP6_PACKET
*Packet
;
1209 EFI_DHCP6_PACKET
*LastReply
;
1210 EFI_DHCP6_DUID
*ClientId
;
1211 EFI_DHCP6_DUID
*ServerId
;
1212 DHCP6_SERVICE
*Service
;
1218 ASSERT (Instance
->Config
!= NULL
);
1219 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1220 ASSERT (Instance
->Service
!= NULL
);
1222 Service
= Instance
->Service
;
1223 ClientId
= Service
->ClientId
;
1224 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1226 ASSERT (ClientId
!= NULL
);
1227 ASSERT (LastReply
!= NULL
);
1230 // Get the server Id from the last reply message.
1232 Option
= Dhcp6SeekOption (
1233 LastReply
->Dhcp6
.Option
,
1234 LastReply
->Length
- 4,
1237 if (Option
== NULL
) {
1238 return EFI_DEVICE_ERROR
;
1242 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1244 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1247 // Create the Dhcp6 packet and initialize commone fields.
1249 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1250 if (Packet
== NULL
) {
1251 return EFI_OUT_OF_RESOURCES
;
1254 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1255 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1256 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1257 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1260 // Assembly Dhcp6 options for rebind/renew message.
1262 Cursor
= Packet
->Dhcp6
.Option
;
1264 Length
= HTONS (ClientId
->Length
);
1265 Cursor
= Dhcp6AppendOption (
1267 HTONS (Dhcp6OptClientId
),
1272 Cursor
= Dhcp6AppendETOption (
1278 Cursor
= Dhcp6AppendOption (
1280 HTONS (Dhcp6OptServerId
),
1285 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0);
1288 // Determine the size/length of packet.
1290 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1291 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1294 // Callback to user with the packet to be sent and check the user's feedback.
1296 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1298 if (EFI_ERROR (Status
)) {
1304 // Send decline packet with the state transition from Dhcp6bound to
1307 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1309 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1311 if (EFI_ERROR (Status
)) {
1317 // Enqueue the sent packet for the retransmission in case reply timeout.
1319 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1324 Create the release message and send it.
1326 @param[in] Instance The pointer to the Dhcp6 instance.
1327 @param[in] RelIa The pointer to the release Ia.
1329 @retval EFI_SUCCESS Created and sent the release message successfully.
1330 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1331 @retval EFI_DEVICE_ERROR An unexpected error.
1332 @retval Others Failed to send the release message.
1336 Dhcp6SendReleaseMsg (
1337 IN DHCP6_INSTANCE
*Instance
,
1338 IN EFI_DHCP6_IA
*RelIa
1342 EFI_DHCP6_PACKET
*Packet
;
1343 EFI_DHCP6_PACKET
*LastReply
;
1344 EFI_DHCP6_DUID
*ClientId
;
1345 EFI_DHCP6_DUID
*ServerId
;
1346 DHCP6_SERVICE
*Service
;
1352 ASSERT(Instance
->Config
);
1353 ASSERT(Instance
->IaCb
.Ia
);
1355 Service
= Instance
->Service
;
1356 ClientId
= Service
->ClientId
;
1357 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1363 // Get the server Id from the last reply message.
1365 Option
= Dhcp6SeekOption (
1366 LastReply
->Dhcp6
.Option
,
1367 LastReply
->Length
- 4,
1370 if (Option
== NULL
) {
1371 return EFI_DEVICE_ERROR
;
1374 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1377 // Create the Dhcp6 packet and initialize commone fields.
1379 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1380 if (Packet
== NULL
) {
1381 return EFI_OUT_OF_RESOURCES
;
1384 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1385 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1386 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1387 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1390 // Assembly Dhcp6 options for rebind/renew message
1392 Cursor
= Packet
->Dhcp6
.Option
;
1394 Length
= HTONS (ClientId
->Length
);
1395 Cursor
= Dhcp6AppendOption (
1397 HTONS (Dhcp6OptClientId
),
1403 // ServerId is extracted from packet, it's network order.
1405 Cursor
= Dhcp6AppendOption (
1407 HTONS (Dhcp6OptServerId
),
1412 Cursor
= Dhcp6AppendETOption (
1418 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0);
1421 // Determine the size/length of packet
1423 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1424 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1427 // Callback to user with the packet to be sent and check the user's feedback.
1429 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1431 if (EFI_ERROR (Status
)) {
1437 // Send release packet with the state transition from Dhcp6bound to
1440 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1442 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1444 if (EFI_ERROR (Status
)) {
1450 // Enqueue the sent packet for the retransmission in case reply timeout.
1452 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1457 Create the renew/rebind message and send it.
1459 @param[in] Instance The pointer to the Dhcp6 instance.
1460 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1461 Otherwise, it is a Renew type message.
1463 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1464 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1465 @retval EFI_DEVICE_ERROR An unexpected error.
1466 @retval Others Failed to send the renew/rebind message.
1470 Dhcp6SendRenewRebindMsg (
1471 IN DHCP6_INSTANCE
*Instance
,
1472 IN BOOLEAN RebindRequest
1476 EFI_DHCP6_PACKET
*Packet
;
1477 EFI_DHCP6_PACKET
*LastReply
;
1478 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1479 EFI_DHCP6_DUID
*ClientId
;
1480 EFI_DHCP6_DUID
*ServerId
;
1481 EFI_DHCP6_STATE State
;
1482 EFI_DHCP6_EVENT Event
;
1483 DHCP6_SERVICE
*Service
;
1491 ASSERT(Instance
->Config
);
1492 ASSERT(Instance
->IaCb
.Ia
);
1494 Service
= Instance
->Service
;
1495 ClientId
= Service
->ClientId
;
1500 // Calculate the added length of customized option list.
1503 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1504 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1508 // Create the Dhcp6 packet and initialize commone fields.
1510 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1511 if (Packet
== NULL
) {
1512 return EFI_OUT_OF_RESOURCES
;
1515 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1516 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1517 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1518 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1521 // Assembly Dhcp6 options for rebind/renew message.
1523 Cursor
= Packet
->Dhcp6
.Option
;
1525 Length
= HTONS (ClientId
->Length
);
1526 Cursor
= Dhcp6AppendOption (
1528 HTONS (Dhcp6OptClientId
),
1533 Cursor
= Dhcp6AppendETOption (
1539 Cursor
= Dhcp6AppendIaOption (
1546 if (!RebindRequest
) {
1548 // Get the server Id from the last reply message and
1549 // insert it for rebind request.
1551 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1554 Option
= Dhcp6SeekOption (
1555 LastReply
->Dhcp6
.Option
,
1556 LastReply
->Length
- 4,
1559 if (Option
== NULL
) {
1561 return EFI_DEVICE_ERROR
;
1564 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1566 Cursor
= Dhcp6AppendOption (
1568 HTONS (Dhcp6OptServerId
),
1575 // Append user-defined when configurate Dhcp6 service.
1577 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1579 UserOpt
= Instance
->Config
->OptionList
[Index
];
1580 Cursor
= Dhcp6AppendOption(
1589 // Determine the size/length of packet.
1591 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1592 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1595 // Callback to user with the packet to be sent and check the user's feedback.
1597 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1598 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1600 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1602 if (EFI_ERROR (Status
)) {
1608 // Send renew/rebind packet with the state transition from Dhcp6bound to
1609 // Dhcp6renew/rebind.
1610 // And sync the lease time when send renew/rebind, in case that user send
1611 // renew/rebind actively.
1613 Instance
->IaCb
.Ia
->State
= State
;
1614 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1616 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1618 if (EFI_ERROR (Status
)) {
1624 // Enqueue the sent packet for the retransmission in case reply timeout.
1626 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1631 Create the information request message and send it.
1633 @param[in] Instance The pointer to the Dhcp6 instance.
1634 @param[in] InfCb The pointer to the information request control block.
1635 @param[in] SendClientId If TRUE, the client identifier option will be included in
1636 information request message. Otherwise, the client identifier
1637 option will not be included.
1638 @param[in] OptionRequest The pointer to the option request option.
1639 @param[in] OptionCount The number options in the OptionList.
1640 @param[in] OptionList The array pointers to the appended options.
1641 @param[in] Retransmission The pointer to the retransmission control.
1643 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1644 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1645 @retval Others Failed to send the info-request message.
1649 Dhcp6SendInfoRequestMsg (
1650 IN DHCP6_INSTANCE
*Instance
,
1651 IN DHCP6_INF_CB
*InfCb
,
1652 IN BOOLEAN SendClientId
,
1653 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1654 IN UINT32 OptionCount
,
1655 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1656 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1660 EFI_DHCP6_PACKET
*Packet
;
1661 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1662 EFI_DHCP6_DUID
*ClientId
;
1663 DHCP6_SERVICE
*Service
;
1670 ASSERT(OptionRequest
);
1672 Service
= Instance
->Service
;
1673 ClientId
= Service
->ClientId
;
1674 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1679 // Calculate the added length of customized option list.
1681 for (Index
= 0; Index
< OptionCount
; Index
++) {
1682 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1686 // Create the Dhcp6 packet and initialize commone fields.
1688 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1689 if (Packet
== NULL
) {
1690 return EFI_OUT_OF_RESOURCES
;
1693 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1694 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1695 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1696 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1698 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1701 // Assembly Dhcp6 options for info-request message.
1703 Cursor
= Packet
->Dhcp6
.Option
;
1706 Length
= HTONS (ClientId
->Length
);
1707 Cursor
= Dhcp6AppendOption (
1709 HTONS (Dhcp6OptClientId
),
1715 Cursor
= Dhcp6AppendETOption (
1721 Cursor
= Dhcp6AppendOption (
1723 OptionRequest
->OpCode
,
1724 OptionRequest
->OpLen
,
1729 // Append user-defined when configurate Dhcp6 service.
1731 for (Index
= 0; Index
< OptionCount
; Index
++) {
1733 UserOpt
= OptionList
[Index
];
1734 Cursor
= Dhcp6AppendOption(
1743 // Determine the size/length of packet.
1745 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1746 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1749 // Send info-request packet with no state.
1751 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1753 if (EFI_ERROR (Status
)) {
1759 // Enqueue the sent packet for the retransmission in case reply timeout.
1761 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1766 Create the Confirm message and send it.
1768 @param[in] Instance The pointer to the Dhcp6 instance.
1770 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1771 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1772 @retval EFI_DEVICE_ERROR An unexpected error.
1773 @retval Others Failed to send the confirm message.
1777 Dhcp6SendConfirmMsg (
1778 IN DHCP6_INSTANCE
*Instance
1786 DHCP6_SERVICE
*Service
;
1787 EFI_DHCP6_DUID
*ClientId
;
1788 EFI_DHCP6_PACKET
*Packet
;
1789 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1792 ASSERT (Instance
->Config
!= NULL
);
1793 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1794 ASSERT (Instance
->Service
!= NULL
);
1796 Service
= Instance
->Service
;
1797 ClientId
= Service
->ClientId
;
1798 ASSERT (ClientId
!= NULL
);
1801 // Calculate the added length of customized option list.
1804 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1805 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1809 // Create the Dhcp6 packet and initialize common fields.
1811 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1812 if (Packet
== NULL
) {
1813 return EFI_OUT_OF_RESOURCES
;
1816 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1817 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1818 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1819 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1822 // Assembly Dhcp6 options for solicit message.
1824 Cursor
= Packet
->Dhcp6
.Option
;
1826 Length
= HTONS (ClientId
->Length
);
1827 Cursor
= Dhcp6AppendOption (
1829 HTONS (Dhcp6OptClientId
),
1834 Cursor
= Dhcp6AppendETOption (
1840 Cursor
= Dhcp6AppendIaOption (
1848 // Append user-defined when configurate Dhcp6 service.
1850 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1851 UserOpt
= Instance
->Config
->OptionList
[Index
];
1852 Cursor
= Dhcp6AppendOption (
1861 // Determine the size/length of packet.
1863 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1864 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1867 // Callback to user with the packet to be sent and check the user's feedback.
1869 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
1871 if (EFI_ERROR (Status
)) {
1877 // Send confirm packet with the state transition from Dhcp6Bound to
1880 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
1882 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1884 if (EFI_ERROR (Status
)) {
1890 // Enqueue the sent packet for the retransmission in case reply timeout.
1892 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1898 Handle with the Dhcp6 reply message.
1900 @param[in] Instance The pointer to Dhcp6 instance.
1901 @param[in] Packet The pointer to the Dhcp6 reply message.
1903 @retval EFI_SUCCESS Processed the reply message successfully.
1904 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1905 @retval EFI_DEVICE_ERROR An unexpected error.
1906 @retval Others Failed to process the reply message.
1910 Dhcp6HandleReplyMsg (
1911 IN DHCP6_INSTANCE
*Instance
,
1912 IN EFI_DHCP6_PACKET
*Packet
1919 ASSERT (Instance
->Config
!= NULL
);
1920 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1921 ASSERT (Packet
!= NULL
);
1923 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
1924 return EFI_DEVICE_ERROR
;
1928 // If the client subsequently receives a valid reply message that includes a
1929 // rapid commit option since send a solicit with rapid commit option before,
1930 // preocess the reply message and discard any reply messages received in
1931 // response to the request message.
1932 // See details in the section-17.1.4 of rfc-3315.
1934 Option
= Dhcp6SeekOption (
1935 Packet
->Dhcp6
.Option
,
1940 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
1941 return EFI_DEVICE_ERROR
;
1945 // As to a valid reply packet in response to a request/renew/rebind packet,
1946 // ignore the packet if not contains the Ia option
1948 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
1949 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
1950 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
1953 Option
= Dhcp6SeekIaOption (
1954 Packet
->Dhcp6
.Option
,
1956 &Instance
->Config
->IaDescriptor
1958 if (Option
== NULL
) {
1959 return EFI_DEVICE_ERROR
;
1964 // Callback to user with the received packet and check the user's feedback.
1966 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
1968 if (EFI_ERROR (Status
)) {
1973 // Dequeue the sent packet from retransmit list since reply received.
1975 Status
= Dhcp6DequeueRetry (
1977 Packet
->Dhcp6
.Header
.TransactionId
,
1981 if (EFI_ERROR (Status
)) {
1986 // When receive a valid reply packet in response to a decline/release packet,
1987 // the client considers the decline/release event completed regardless of the
1990 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
1992 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
1993 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
1995 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
1996 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
1997 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
1998 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2002 // For sync, set the success flag out of polling in decline/release.
2004 Instance
->UdpSts
= EFI_SUCCESS
;
2007 // For async, signal the Ia event to inform Ia infomation update.
2009 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2010 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2014 // Reset start time for next exchange.
2016 Instance
->StartTime
= 0;
2022 // Upon the receipt of a valid reply packet in response to a solicit, request,
2023 // confirm, renew and rebind, the behavior depends on the status code option.
2024 // See the details in the section-18.1.8 of rfc-3315.
2027 Status
= Dhcp6SeekStsOption (
2033 if (!EFI_ERROR (Status
)) {
2035 // Reset start time for next exchange.
2037 Instance
->StartTime
= 0;
2040 // No status code or no error status code means succeed to reply.
2042 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2044 if (EFI_ERROR (Status
)) {
2049 // Set bound state and store the reply packet.
2051 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2052 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2055 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2057 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2058 return EFI_OUT_OF_RESOURCES
;
2061 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2063 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2066 // For sync, set the success flag out of polling in start/renewrebind.
2068 Instance
->UdpSts
= EFI_SUCCESS
;
2071 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2072 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2073 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2074 // consumers can be notified to flush old address.
2076 Dhcp6AppendCacheIa (Instance
);
2079 // For async, signal the Ia event to inform Ia infomation update.
2081 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2082 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2084 } else if (Option
!= NULL
) {
2086 // Any error status code option is found.
2088 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2090 case Dhcp6StsUnspecFail
:
2092 // It indicates the server is unable to process the message due to an
2093 // unspecified failure condition, so just retry if possible.
2097 case Dhcp6StsUseMulticast
:
2099 // It indicates the server receives a message via unicast from a client
2100 // to which the server has not sent a unicast option, so retry it by
2101 // multi-cast address.
2103 if (Instance
->Unicast
!= NULL
) {
2104 FreePool (Instance
->Unicast
);
2105 Instance
->Unicast
= NULL
;
2109 case Dhcp6StsNotOnLink
:
2110 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2112 // Before initiate new round DHCP, cache the current IA.
2114 Status
= Dhcp6CacheIa (Instance
);
2115 if (EFI_ERROR (Status
)) {
2120 // Restart S.A.R.R process to acquire new address.
2122 Status
= Dhcp6InitSolicitMsg (Instance
);
2123 if (EFI_ERROR (Status
)) {
2131 // The other status code, just restart solicitation.
2142 Select the appointed Dhcp6 advertisement message.
2144 @param[in] Instance The pointer to the Dhcp6 instance.
2145 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2147 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2148 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2149 @retval Others Failed to select the advertise message.
2153 Dhcp6SelectAdvertiseMsg (
2154 IN DHCP6_INSTANCE
*Instance
,
2155 IN EFI_DHCP6_PACKET
*AdSelect
2161 ASSERT (AdSelect
!= NULL
);
2164 // Callback to user with the selected advertisement packet, and the user
2165 // might overwrite it.
2167 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2169 if (EFI_ERROR (Status
)) {
2173 Instance
->AdSelect
= AdSelect
;
2176 // Dequeue the sent packet for the retransmission since advertisement selected.
2178 Status
= Dhcp6DequeueRetry (
2180 AdSelect
->Dhcp6
.Header
.TransactionId
,
2184 if (EFI_ERROR(Status
)) {
2189 // Check whether there is server unicast option in the selected advertise
2190 // packet, and update it.
2192 Option
= Dhcp6SeekOption(
2193 AdSelect
->Dhcp6
.Option
,
2194 AdSelect
->Length
- 4,
2195 Dhcp6OptServerUnicast
2198 if (Option
!= NULL
) {
2200 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2202 if (Instance
->Unicast
== NULL
) {
2203 return EFI_OUT_OF_RESOURCES
;
2206 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2210 // Update the information of the Ia by the selected advertisement message.
2212 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2214 if (EFI_ERROR (Status
)) {
2219 // Send the request message to continue the S.A.R.R. process.
2221 return Dhcp6SendRequestMsg (Instance
);
2226 Handle with the Dhcp6 advertisement message.
2228 @param[in] Instance The pointer to the Dhcp6 instance.
2229 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2231 @retval EFI_SUCCESS Processed the advertisement message successfully.
2232 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2233 @retval EFI_DEVICE_ERROR An unexpected error.
2234 @retval Others Failed to process the advertise message.
2238 Dhcp6HandleAdvertiseMsg (
2239 IN DHCP6_INSTANCE
*Instance
,
2240 IN EFI_DHCP6_PACKET
*Packet
2248 ASSERT(Instance
->Config
);
2249 ASSERT(Instance
->IaCb
.Ia
);
2252 StsCode
= Dhcp6StsSuccess
;
2255 // If the client does receives a valid reply message that includes a rapid
2256 // commit option since a solicit with rapid commit optioin sent before, select
2257 // this reply message. Or else, process the advertise messages as normal.
2258 // See details in the section-17.1.4 of rfc-3315.
2260 Option
= Dhcp6SeekOption(
2261 Packet
->Dhcp6
.Option
,
2266 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2268 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2271 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2272 return EFI_DEVICE_ERROR
;
2276 // Client must ignore any advertise message that includes a status code option
2277 // containing the value noaddrsavail, with the exception that the client may
2278 // display the associated status message to the user.
2279 // See the details in the section-17.1.3 of rfc-3315.
2281 Option
= Dhcp6SeekOption(
2282 Packet
->Dhcp6
.Option
,
2287 if (Option
!= NULL
) {
2288 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2289 if (StsCode
!= Dhcp6StsSuccess
) {
2290 return EFI_DEVICE_ERROR
;
2295 // Callback to user with the received packet and check the user's feedback.
2297 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2299 if (!EFI_ERROR (Status
)) {
2301 // Success means user choose the current advertisement packet.
2303 if (Instance
->AdSelect
!= NULL
) {
2304 FreePool (Instance
->AdSelect
);
2308 // Store the selected advertisement packet and set a flag.
2310 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2312 if (Instance
->AdSelect
== NULL
) {
2313 return EFI_OUT_OF_RESOURCES
;
2316 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2318 Instance
->AdPref
= 0xff;
2320 } else if (Status
== EFI_NOT_READY
) {
2322 // Not_ready means user wants to continue to receive more advertise packets.
2324 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2326 // It's a tricky point. The timer routine set adpref as 0xff if the first
2327 // rt timeout and no advertisement received, which means any advertisement
2328 // received will be selected after the first rt.
2334 // Check whether the current packet has a 255 preference option or not.
2335 // Take non-preference option as 0 value.
2337 Option
= Dhcp6SeekOption(
2338 Packet
->Dhcp6
.Option
,
2343 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2345 // No advertisements received before or preference is more than other
2346 // advertisements received before. Then store the new packet and the
2347 // preference value.
2349 if (Instance
->AdSelect
!= NULL
) {
2350 FreePool (Instance
->AdSelect
);
2353 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2355 if (Instance
->AdSelect
== NULL
) {
2356 return EFI_OUT_OF_RESOURCES
;
2359 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2361 if (Option
!= NULL
) {
2362 Instance
->AdPref
= *(Option
+ 4);
2366 // Non-preference and other advertisements received before or current
2367 // preference is less than other advertisements received before.
2368 // Leave the packet alone.
2373 // Other error status means termination.
2379 // Client must collect advertise messages as more as possible until the first
2380 // RT has elapsed, or get a highest preference 255 advertise.
2381 // See details in the section-17.1.2 of rfc-3315.
2383 if (Instance
->AdPref
== 0xff || Timeout
) {
2384 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2392 The Dhcp6 stateful exchange process routine.
2394 @param[in] Instance The pointer to the Dhcp6 instance.
2395 @param[in] Packet The pointer to the received Dhcp6 message.
2399 Dhcp6HandleStateful (
2400 IN DHCP6_INSTANCE
*Instance
,
2401 IN EFI_DHCP6_PACKET
*Packet
2405 EFI_DHCP6_DUID
*ClientId
;
2406 DHCP6_SERVICE
*Service
;
2409 Service
= Instance
->Service
;
2410 ClientId
= Service
->ClientId
;
2411 Status
= EFI_SUCCESS
;
2413 if (Instance
->InDestory
|| Instance
->Config
== NULL
) {
2418 ASSERT (Instance
->Config
);
2419 ASSERT (Instance
->IaCb
.Ia
);
2422 // Discard the packet if not advertisement or reply packet.
2424 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2429 // Check whether include client Id or not.
2431 Option
= Dhcp6SeekOption(
2432 Packet
->Dhcp6
.Option
,
2437 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2442 // Check whether include server Id or not.
2444 Option
= Dhcp6SeekOption(
2445 Packet
->Dhcp6
.Option
,
2450 if (Option
== NULL
) {
2454 switch (Instance
->IaCb
.Ia
->State
) {
2455 case Dhcp6Selecting
:
2457 // Handle the advertisement message when in the Dhcp6Selecting state.
2458 // Do not need check return status, if failed, just continue to the next.
2460 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2463 case Dhcp6Requesting
:
2464 case Dhcp6Confirming
:
2466 case Dhcp6Rebinding
:
2467 case Dhcp6Releasing
:
2468 case Dhcp6Declining
:
2470 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2471 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2472 // If failed here, it should reset the current session.
2474 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2475 if (EFI_ERROR (Status
)) {
2481 // Other state has not supported yet.
2488 // Continue to receive the following Dhcp6 message.
2490 Status
= UdpIoRecvDatagram (
2497 if (EFI_ERROR (Status
)) {
2498 Dhcp6CleanupSession (Instance
, Status
);
2504 The Dhcp6 stateless exchange process routine.
2506 @param[in] Instance The pointer to the Dhcp6 instance.
2507 @param[in] Packet The pointer to the received Dhcp6 message.
2511 Dhcp6HandleStateless (
2512 IN DHCP6_INSTANCE
*Instance
,
2513 IN EFI_DHCP6_PACKET
*Packet
2517 DHCP6_SERVICE
*Service
;
2518 DHCP6_INF_CB
*InfCb
;
2522 Service
= Instance
->Service
;
2523 Status
= EFI_SUCCESS
;
2527 if (Instance
->InDestory
) {
2531 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2536 // Check whether it's a desired Info-request message by Xid.
2538 while (!IsListEmpty (&Instance
->InfList
)) {
2539 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2540 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2551 // Check whether include server Id or not.
2553 Option
= Dhcp6SeekOption (
2554 Packet
->Dhcp6
.Option
,
2559 if (Option
== NULL
) {
2564 // Callback to user with the received packet and check the user's feedback.
2566 Status
= InfCb
->ReplyCallback (
2568 InfCb
->CallbackContext
,
2572 if (Status
== EFI_NOT_READY
) {
2574 // Success or aborted will both stop this info-request exchange process,
2575 // but not ready means user wants to continue to receive reply.
2581 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2582 // if no xid matched.
2586 Packet
->Dhcp6
.Header
.TransactionId
,
2591 // For sync, set the status out of polling for info-request.
2593 Instance
->UdpSts
= Status
;
2597 Status
= UdpIoRecvDatagram (
2604 if (EFI_ERROR (Status
)) {
2605 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2611 The receive callback function for Dhcp6 exchange process.
2613 @param[in] Udp6Wrap The pointer to the received net buffer.
2614 @param[in] EndPoint The pointer to the udp end point.
2615 @param[in] IoStatus The return status from udp io.
2616 @param[in] Context The opaque parameter to the function.
2621 Dhcp6ReceivePacket (
2622 IN NET_BUF
*Udp6Wrap
,
2623 IN UDP_END_POINT
*EndPoint
,
2624 IN EFI_STATUS IoStatus
,
2628 EFI_DHCP6_HEADER
*Head
;
2629 EFI_DHCP6_PACKET
*Packet
;
2630 DHCP6_SERVICE
*Service
;
2631 DHCP6_INSTANCE
*Instance
;
2634 BOOLEAN IsDispatched
;
2635 BOOLEAN IsStateless
;
2641 ASSERT (Udp6Wrap
!= NULL
);
2642 ASSERT (Context
!= NULL
);
2644 Service
= (DHCP6_SERVICE
*) Context
;
2647 IsDispatched
= FALSE
;
2648 IsStateless
= FALSE
;
2650 if (EFI_ERROR (IoStatus
)) {
2655 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2657 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2658 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2660 if (Packet
== NULL
) {
2664 Packet
->Size
= Size
;
2665 Head
= &Packet
->Dhcp6
.Header
;
2666 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2668 if (Packet
->Length
== 0) {
2673 // Dispatch packet to right instance by transaction id.
2675 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2677 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2679 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2681 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2683 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2685 // Find the corresponding packet in tx list, and check it whether belongs
2686 // to stateful exchange process.
2688 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2691 IsDispatched
= TRUE
;
2702 // Skip this packet if not dispatched to any instance.
2704 if (!IsDispatched
) {
2709 // Dispatch the received packet ot the right instance.
2712 Dhcp6HandleStateless (Instance
, Packet
);
2714 Dhcp6HandleStateful (Instance
, Packet
);
2719 NetbufFree (Udp6Wrap
);
2721 if (Packet
!= NULL
) {
2727 Detect Link movement for specified network device.
2729 This routine will try to invoke Snp->GetStatus() to get the media status.
2730 If media present status switches from unpresent to present, a link movement
2731 is detected. Note that the underlying UNDI driver may not support reporting
2732 media status from GET_STATUS command. If that, fail to detect link movement.
2734 @param[in] Instance The pointer to DHCP6_INSTANCE.
2736 @retval TRUE A link movement is detected.
2737 @retval FALSE A link movement is not detected.
2741 Dhcp6LinkMovDetect (
2742 IN DHCP6_INSTANCE
*Instance
2745 UINT32 InterruptStatus
;
2746 BOOLEAN MediaPresent
;
2748 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2750 ASSERT (Instance
!= NULL
);
2751 Snp
= Instance
->Service
->Snp
;
2752 MediaPresent
= Instance
->MediaPresent
;
2755 // Check whether SNP support media detection
2757 if (!Snp
->Mode
->MediaPresentSupported
) {
2762 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2764 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2765 if (EFI_ERROR (Status
)) {
2769 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2771 // Media transimit Unpresent to Present means new link movement is detected.
2773 if (!MediaPresent
&& Instance
->MediaPresent
) {
2781 The timer routine of the Dhcp6 instance for each second.
2783 @param[in] Event The timer event.
2784 @param[in] Context The opaque parameter to the function.
2795 LIST_ENTRY
*NextEntry
;
2796 DHCP6_INSTANCE
*Instance
;
2801 ASSERT (Context
!= NULL
);
2803 Instance
= (DHCP6_INSTANCE
*) Context
;
2806 // 1. Loop the tx list, count live time of every tx packet to check whether
2807 // need re-transmit or not.
2809 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
2811 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
2815 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
2817 // Handle the first rt in the transmission of solicit specially.
2819 if (TxCb
->RetryCnt
== 0 && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
2820 if (Instance
->AdSelect
== NULL
) {
2822 // Set adpref as 0xff here to indicate select any advertisement
2825 Instance
->AdPref
= 0xff;
2828 // Select the advertisement received before.
2830 Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2835 // Increase the retry count for the packet and add up the total loss time.
2838 TxCb
->RetryLos
+= TxCb
->RetryExp
;
2841 // Check whether overflow the max retry count limit for this packet
2843 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
2848 // Check whether overflow the max retry duration for this packet
2850 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
2855 // Re-calculate retry expire timeout for the next time.
2857 // Firstly, Check the new calculated time whether overflow the max retry
2860 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
2866 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
2867 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
2875 // Secondly, Check the new calculated time whether overflow the max retry
2878 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
2879 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
2880 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
2884 // Reset the tick time for the next retransmission
2889 // Retransmit the last sent packet again.
2891 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
2896 // 2. Check the configured Ia, count lease time of every valid Ia to check
2897 // whether need to renew or rebind this Ia.
2899 IaCb
= &Instance
->IaCb
;
2901 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
2905 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
2909 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
2911 // Exceed t2, send rebind packet to extend the Ia lease.
2913 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
2915 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
2918 // Exceed t1, send renew packet to extend the Ia lease.
2920 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
2925 // 3. In any situation when a client may have moved to a new link, the
2926 // client MUST initiate a Confirm/Reply message exchange.
2928 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
2929 Dhcp6SendConfirmMsg (Instance
);
2936 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
2937 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
2938 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
2941 // The failure of renew/Confirm will still switch to the bound state.
2943 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
2944 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
2945 ASSERT (Instance
->IaCb
.Ia
);
2946 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2949 // The failure of info-request will return no response.
2951 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2952 Instance
->UdpSts
= EFI_NO_RESPONSE
;
2961 // The failure of the others will terminate current state machine if timeout.
2963 Dhcp6CleanupSession (Instance
, EFI_NO_RESPONSE
);