2 Dhcp6 internal functions implementation.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Dhcp6Impl.h"
21 Enqueue the packet into the retry list in case of timeout.
23 @param[in] Instance The pointer to the Dhcp6 instance.
24 @param[in] Packet The pointer to the Dhcp6 packet to retry.
25 @param[in] Elapsed The pointer to the elapsed time value in the packet.
26 @param[in] RetryCtl The pointer to the transmission control of the packet.
27 This parameter is optional and may be NULL.
29 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according
31 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
32 @retval EFI_DEVICE_ERROR An unexpected message type.
37 IN DHCP6_INSTANCE
*Instance
,
38 IN EFI_DHCP6_PACKET
*Packet
,
40 IN EFI_DHCP6_RETRANSMISSION
*RetryCtl OPTIONAL
46 ASSERT (Packet
!= NULL
);
48 IaCb
= &Instance
->IaCb
;
49 TxCb
= AllocateZeroPool (sizeof (DHCP6_TX_CB
));
52 return EFI_OUT_OF_RESOURCES
;
56 // Save tx packet pointer, and it will be destroyed when reply received.
58 TxCb
->TxPacket
= Packet
;
59 TxCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
62 // Save pointer to elapsed-time value so we can update it on retransmits.
64 TxCb
->Elapsed
= Elapsed
;
67 // Calculate the retransmission according to the the message type.
69 switch (Packet
->Dhcp6
.Header
.MessageType
) {
72 // Calculate the retransmission threshold value for solicit packet.
73 // Use the default value by rfc-3315 if user doesn't configure.
75 if (RetryCtl
== NULL
) {
76 TxCb
->RetryCtl
.Irt
= DHCP6_SOL_IRT
;
77 TxCb
->RetryCtl
.Mrc
= DHCP6_SOL_MRC
;
78 TxCb
->RetryCtl
.Mrt
= DHCP6_SOL_MRT
;
79 TxCb
->RetryCtl
.Mrd
= DHCP6_SOL_MRD
;
81 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_SOL_IRT
;
82 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_SOL_MRC
;
83 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_SOL_MRT
;
84 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_SOL_MRD
;
87 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
96 // Calculate the retransmission threshold value for request packet.
98 TxCb
->RetryCtl
.Irt
= DHCP6_REQ_IRT
;
99 TxCb
->RetryCtl
.Mrc
= DHCP6_REQ_MRC
;
100 TxCb
->RetryCtl
.Mrt
= DHCP6_REQ_MRT
;
101 TxCb
->RetryCtl
.Mrd
= DHCP6_REQ_MRD
;
102 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
109 case Dhcp6MsgConfirm
:
111 // Calculate the retransmission threshold value for confirm packet.
113 TxCb
->RetryCtl
.Irt
= DHCP6_CNF_IRT
;
114 TxCb
->RetryCtl
.Mrc
= DHCP6_CNF_MRC
;
115 TxCb
->RetryCtl
.Mrt
= DHCP6_CNF_MRT
;
116 TxCb
->RetryCtl
.Mrd
= DHCP6_CNF_MRD
;
117 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
126 // Calculate the retransmission threshold value for renew packet.
128 TxCb
->RetryCtl
.Irt
= DHCP6_REB_IRT
;
129 TxCb
->RetryCtl
.Mrc
= DHCP6_REB_MRC
;
130 TxCb
->RetryCtl
.Mrt
= DHCP6_REB_MRT
;
131 TxCb
->RetryCtl
.Mrd
= IaCb
->T2
- IaCb
->T1
;
132 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
141 // Calculate the retransmission threshold value for rebind packet.
143 TxCb
->RetryCtl
.Irt
= DHCP6_REN_IRT
;
144 TxCb
->RetryCtl
.Mrc
= DHCP6_REN_MRC
;
145 TxCb
->RetryCtl
.Mrt
= DHCP6_REN_MRT
;
146 TxCb
->RetryCtl
.Mrd
= IaCb
->AllExpireTime
- IaCb
->T2
;
147 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
154 case Dhcp6MsgDecline
:
156 // Calculate the retransmission threshold value for decline packet.
158 TxCb
->RetryCtl
.Irt
= DHCP6_DEC_IRT
;
159 TxCb
->RetryCtl
.Mrc
= DHCP6_DEC_MRC
;
160 TxCb
->RetryCtl
.Mrt
= DHCP6_DEC_MRT
;
161 TxCb
->RetryCtl
.Mrd
= DHCP6_DEC_MRD
;
162 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
169 case Dhcp6MsgRelease
:
171 // Calculate the retransmission threshold value for release packet.
173 TxCb
->RetryCtl
.Irt
= DHCP6_REL_IRT
;
174 TxCb
->RetryCtl
.Mrc
= DHCP6_REL_MRC
;
175 TxCb
->RetryCtl
.Mrt
= DHCP6_REL_MRT
;
176 TxCb
->RetryCtl
.Mrd
= DHCP6_REL_MRD
;
177 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
184 case Dhcp6MsgInfoRequest
:
186 // Calculate the retransmission threshold value for info-request packet.
187 // Use the default value by rfc-3315 if user doesn't configure.
189 if (RetryCtl
== NULL
) {
190 TxCb
->RetryCtl
.Irt
= DHCP6_INF_IRT
;
191 TxCb
->RetryCtl
.Mrc
= DHCP6_INF_MRC
;
192 TxCb
->RetryCtl
.Mrt
= DHCP6_INF_MRT
;
193 TxCb
->RetryCtl
.Mrd
= DHCP6_INF_MRD
;
195 TxCb
->RetryCtl
.Irt
= (RetryCtl
->Irt
!= 0) ? RetryCtl
->Irt
: DHCP6_INF_IRT
;
196 TxCb
->RetryCtl
.Mrc
= (RetryCtl
->Mrc
!= 0) ? RetryCtl
->Mrc
: DHCP6_INF_MRC
;
197 TxCb
->RetryCtl
.Mrt
= (RetryCtl
->Mrt
!= 0) ? RetryCtl
->Mrt
: DHCP6_INF_MRT
;
198 TxCb
->RetryCtl
.Mrd
= (RetryCtl
->Mrd
!= 0) ? RetryCtl
->Mrd
: DHCP6_INF_MRD
;
201 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
210 // Unexpected message type.
212 return EFI_DEVICE_ERROR
;
216 // Insert into the retransmit list of the instance.
218 InsertTailList (&Instance
->TxList
, &TxCb
->Link
);
225 Dequeue the packet from retry list if reply received or timeout at last.
227 @param[in] Instance The pointer to the Dhcp6 instance.
228 @param[in] PacketXid The packet transaction id to match.
229 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
230 Otherwise, this parameter is ignored.
232 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
233 @retval EFI_NOT_FOUND There is no xid matched in retry list.
238 IN DHCP6_INSTANCE
*Instance
,
240 IN BOOLEAN NeedSignal
244 LIST_ENTRY
*NextEntry
;
249 // Seek the retransmit node in the retransmit list by packet xid.
251 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
253 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
254 ASSERT(TxCb
->TxPacket
);
256 if (TxCb
->Xid
== PacketXid
) {
258 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
261 // Seek the info-request node in the info-request list by packet xid.
263 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
265 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
267 if (InfCb
->Xid
== PacketXid
) {
269 // Remove the info-request node, and signal the event if timeout.
271 if (InfCb
->TimeoutEvent
!= NULL
&& NeedSignal
) {
272 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
275 RemoveEntryList (&InfCb
->Link
);
281 // Remove the retransmit node.
283 RemoveEntryList (&TxCb
->Link
);
284 ASSERT(TxCb
->TxPacket
);
285 FreePool (TxCb
->TxPacket
);
291 return EFI_NOT_FOUND
;
296 Clean up the specific nodes in the retry list.
298 @param[in] Instance The pointer to the Dhcp6 instance.
299 @param[in] Scope The scope of cleanup nodes.
304 IN DHCP6_INSTANCE
*Instance
,
309 LIST_ENTRY
*NextEntry
;
314 // Clean up all the stateful messages from the retransmit list.
316 if (Scope
== DHCP6_PACKET_STATEFUL
|| Scope
== DHCP6_PACKET_ALL
) {
318 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
320 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
321 ASSERT(TxCb
->TxPacket
);
323 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgInfoRequest
) {
324 RemoveEntryList (&TxCb
->Link
);
325 FreePool (TxCb
->TxPacket
);
332 // Clean up all the stateless messages from the retransmit list.
334 if (Scope
== DHCP6_PACKET_STATELESS
|| Scope
== DHCP6_PACKET_ALL
) {
337 // Clean up all the retransmit list for stateless messages.
339 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
341 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
342 ASSERT(TxCb
->TxPacket
);
344 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
345 RemoveEntryList (&TxCb
->Link
);
346 FreePool (TxCb
->TxPacket
);
352 // Clean up all the info-request messages list.
354 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->InfList
) {
356 InfCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_INF_CB
, Link
);
358 if (InfCb
->TimeoutEvent
!= NULL
) {
359 gBS
->SignalEvent (InfCb
->TimeoutEvent
);
361 RemoveEntryList (&InfCb
->Link
);
368 Check whether the TxCb is still a valid control block in the instance's retry list.
370 @param[in] Instance The pointer to DHCP6_INSTANCE.
371 @param[in] TxCb The control block for a transmitted message.
373 @retval TRUE The control block is in Instance's retry list.
374 @retval FALSE The control block is NOT in Instance's retry list.
379 IN DHCP6_INSTANCE
*Instance
,
385 NET_LIST_FOR_EACH (Entry
, &Instance
->TxList
) {
386 if (TxCb
== NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
)) {
395 Clean up the session of the instance stateful exchange.
397 @param[in, out] Instance The pointer to the Dhcp6 instance.
398 @param[in] Status The return status from udp.
402 Dhcp6CleanupSession (
403 IN OUT DHCP6_INSTANCE
*Instance
,
410 ASSERT(Instance
->Config
);
411 ASSERT(Instance
->IaCb
.Ia
);
414 // Clean up the retransmit list for stateful messages.
416 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATEFUL
);
418 if (Instance
->Unicast
!= NULL
) {
419 FreePool (Instance
->Unicast
);
422 if (Instance
->AdSelect
!= NULL
) {
423 FreePool (Instance
->AdSelect
);
426 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
427 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
431 // Reinitialize the Ia fields of the instance.
433 Instance
->UdpSts
= Status
;
434 Instance
->AdSelect
= NULL
;
435 Instance
->AdPref
= 0;
436 Instance
->Unicast
= NULL
;
437 Instance
->IaCb
.T1
= 0;
438 Instance
->IaCb
.T2
= 0;
439 Instance
->IaCb
.AllExpireTime
= 0;
440 Instance
->IaCb
.LeaseTime
= 0;
445 Instance
->StartTime
= 0;
447 Ia
= Instance
->IaCb
.Ia
;
448 Ia
->State
= Dhcp6Init
;
449 Ia
->ReplyPacket
= NULL
;
452 // Set the addresses as zero lifetime, and then the notify
453 // function in Ip6Config will remove these timeout address.
455 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
456 Ia
->IaAddress
[Index
].PreferredLifetime
= 0;
457 Ia
->IaAddress
[Index
].ValidLifetime
= 0;
462 // Signal the Ia information updated event to informal user.
464 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
465 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
471 Callback to user when Dhcp6 transmit/receive occurs.
473 @param[in] Instance The pointer to the Dhcp6 instance.
474 @param[in] Event The current Dhcp6 event.
475 @param[in, out] Packet The pointer to the packet sending or received.
477 @retval EFI_SUCCESS The user function returns success.
478 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
479 @retval EFI_ABORTED The user function ask it to abort.
485 IN DHCP6_INSTANCE
*Instance
,
486 IN EFI_DHCP6_EVENT Event
,
487 IN OUT EFI_DHCP6_PACKET
**Packet
491 EFI_DHCP6_PACKET
*NewPacket
;
492 EFI_DHCP6_CALLBACK Callback
;
495 ASSERT (Packet
!= NULL
);
496 ASSERT (Instance
->Config
!= NULL
);
497 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
500 Status
= EFI_SUCCESS
;
501 Callback
= Instance
->Config
->Dhcp6Callback
;
502 Context
= Instance
->Config
->CallbackContext
;
505 // Callback to user with the new message if has.
507 if (Callback
!= NULL
) {
512 Instance
->IaCb
.Ia
->State
,
518 // Updated the new packet from user to replace the original one.
520 if (NewPacket
!= NULL
) {
521 ASSERT (*Packet
!= NULL
);
532 Update Ia according to the new reply message.
534 @param[in, out] Instance The pointer to the Dhcp6 instance.
535 @param[in] Packet The pointer to reply messages.
537 @retval EFI_SUCCESS Updated the Ia information successfully.
538 @retval EFI_DEVICE_ERROR An unexpected error.
543 IN OUT DHCP6_INSTANCE
*Instance
,
544 IN EFI_DHCP6_PACKET
*Packet
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.
568 Option
= Dhcp6SeekIaOption (
569 Packet
->Dhcp6
.Option
,
570 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
571 &Instance
->Config
->IaDescriptor
573 if (Option
== NULL
) {
574 return EFI_DEVICE_ERROR
;
578 // The format of the IA_NA option is:
581 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
582 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 // | OPTION_IA_NA | option-len |
584 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 // | IAID (4 octets) |
586 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
594 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
596 // The format of the IA_TA option is:
599 // 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
600 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
601 // | OPTION_IA_TA | option-len |
602 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
603 // | IAID (4 octets) |
604 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
608 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
612 // sizeof (option-code + option-len + IaId) = 8
613 // sizeof (option-code + option-len + IaId + T1) = 12
614 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
616 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
618 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
619 T1
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 8)));
620 T2
= NTOHL (ReadUnaligned32 ((UINT32
*) (Option
+ 12)));
622 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
623 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
624 // the remainder of the message as though the server had not included the invalid IA_NA option.
626 if (T1
> T2
&& T2
> 0) {
627 return EFI_DEVICE_ERROR
;
629 IaInnerOpt
= Option
+ 16;
630 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 12);
634 IaInnerOpt
= Option
+ 8;
635 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 2))) - 4);
639 // The format of the Status Code option is:
642 // 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
643 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
644 // | OPTION_STATUS_CODE | option-len |
645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
647 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
649 // . status-message .
651 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655 // sizeof (option-code + option-len) = 4
657 StsCode
= Dhcp6StsSuccess
;
658 Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
660 if (Option
!= NULL
) {
661 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
662 if (StsCode
!= Dhcp6StsSuccess
) {
663 return EFI_DEVICE_ERROR
;
668 // Generate control block for the Ia.
670 Status
= Dhcp6GenerateIaCb (
684 Seek StatusCode Option in package. A Status Code option may appear in the
685 options field of a DHCP message and/or in the options field of another option.
686 See details in section 22.13, RFC3315.
688 @param[in] Instance The pointer to the Dhcp6 instance.
689 @param[in] Packet The pointer to reply messages.
690 @param[out] Option The pointer to status code option.
692 @retval EFI_SUCCESS Seek status code option successfully.
693 @retval EFI_DEVICE_ERROR An unexpected error.
698 IN DHCP6_INSTANCE
*Instance
,
699 IN EFI_DHCP6_PACKET
*Packet
,
708 // Seek StatusCode option directly in DHCP message body. That is, search in
709 // non-encapsulated option fields.
711 *Option
= Dhcp6SeekOption (
712 Packet
->Dhcp6
.Option
,
717 if (*Option
!= NULL
) {
718 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
719 if (StsCode
!= Dhcp6StsSuccess
) {
720 return EFI_DEVICE_ERROR
;
725 // Seek in encapsulated options, IA_NA and IA_TA.
727 *Option
= Dhcp6SeekIaOption (
728 Packet
->Dhcp6
.Option
,
729 Packet
->Length
- sizeof (EFI_DHCP6_HEADER
),
730 &Instance
->Config
->IaDescriptor
732 if (*Option
== NULL
) {
737 // The format of the IA_NA option is:
740 // 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
741 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742 // | OPTION_IA_NA | option-len |
743 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
744 // | IAID (4 octets) |
745 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
747 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
755 // The format of the IA_TA option is:
758 // 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
759 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
760 // | OPTION_IA_TA | option-len |
761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
762 // | IAID (4 octets) |
763 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
767 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
771 // sizeof (option-code + option-len + IaId) = 8
772 // sizeof (option-code + option-len + IaId + T1) = 12
773 // sizeof (option-code + option-len + IaId + T1 + T2) = 16
775 // The inner options still start with 2 bytes option-code and 2 bytes option-len.
777 if (Instance
->Config
->IaDescriptor
.Type
== Dhcp6OptIana
) {
778 IaInnerOpt
= *Option
+ 16;
779 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 12);
781 IaInnerOpt
= *Option
+ 8;
782 IaInnerLen
= (UINT16
) (NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 2))) - 4);
786 // The format of the Status Code option is:
789 // 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
790 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
791 // | OPTION_STATUS_CODE | option-len |
792 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
794 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
796 // . status-message .
798 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
802 // sizeof (option-code + option-len) = 4
804 *Option
= Dhcp6SeekOption (IaInnerOpt
, IaInnerLen
, Dhcp6OptStatusCode
);
805 if (*Option
!= NULL
) {
806 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (*Option
+ 4)));
807 if (StsCode
!= Dhcp6StsSuccess
) {
808 return EFI_DEVICE_ERROR
;
817 Transmit Dhcp6 message by udpio.
819 @param[in] Instance The pointer to the Dhcp6 instance.
820 @param[in] Packet The pointer to transmit message.
821 @param[in] Elapsed The pointer to the elapsed time value to fill in.
823 @retval EFI_SUCCESS Successfully transmitted the packet.
824 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
825 @retval Others Failed to transmit the packet.
829 Dhcp6TransmitPacket (
830 IN DHCP6_INSTANCE
*Instance
,
831 IN EFI_DHCP6_PACKET
*Packet
,
839 DHCP6_SERVICE
*Service
;
841 Service
= Instance
->Service
;
844 // Wrap it into a netbuf then send it.
846 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp6
.Header
;
847 Frag
.Len
= Packet
->Length
;
850 // Do not register free packet here, which will be handled in retry list.
852 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, Dhcp6DummyExtFree
, NULL
);
855 return EFI_OUT_OF_RESOURCES
;
859 // Multicast the Dhcp6 message, unless get the unicast server address by option.
861 ZeroMem (&EndPt
, sizeof (UDP_END_POINT
));
863 if (Instance
->Unicast
!= NULL
) {
867 sizeof (EFI_IPv6_ADDRESS
)
872 &mAllDhcpRelayAndServersAddress
,
873 sizeof (EFI_IPv6_ADDRESS
)
877 EndPt
.RemotePort
= DHCP6_PORT_SERVER
;
878 EndPt
.LocalPort
= DHCP6_PORT_CLIENT
;
881 // Update the elapsed time value.
883 if (Elapsed
!= NULL
) {
884 SetElapsedTime (Elapsed
, Instance
);
888 // Send out the message by the configured Udp6Io.
890 Status
= UdpIoSendDatagram (
899 if (EFI_ERROR (Status
)) {
909 Create the solicit message and send it.
911 @param[in] Instance The pointer to the Dhcp6 instance.
913 @retval EFI_SUCCESS Created and sent the solicit message successfully.
914 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
915 @retval Others Failed to send the solicit message.
919 Dhcp6SendSolicitMsg (
920 IN DHCP6_INSTANCE
*Instance
924 EFI_DHCP6_PACKET
*Packet
;
925 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
926 EFI_DHCP6_DUID
*ClientId
;
927 DHCP6_SERVICE
*Service
;
934 Service
= Instance
->Service
;
935 ClientId
= Service
->ClientId
;
938 ASSERT (Service
->ClientId
!= NULL
);
939 ASSERT (Instance
->Config
!= NULL
);
940 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
943 // Calculate the added length of customized option list.
945 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
946 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
950 // Create the Dhcp6 packet and initialize commone fields.
952 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
953 if (Packet
== NULL
) {
954 return EFI_OUT_OF_RESOURCES
;
957 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
958 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
959 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgSolicit
;
960 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
963 // Assembly Dhcp6 options for solicit message.
965 Cursor
= Packet
->Dhcp6
.Option
;
967 Length
= HTONS (ClientId
->Length
);
968 Cursor
= Dhcp6AppendOption (
970 HTONS (Dhcp6OptClientId
),
975 Cursor
= Dhcp6AppendETOption (
981 Cursor
= Dhcp6AppendIaOption (
986 Packet
->Dhcp6
.Header
.MessageType
990 // Append user-defined when configurate Dhcp6 service.
992 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
994 UserOpt
= Instance
->Config
->OptionList
[Index
];
995 Cursor
= Dhcp6AppendOption(
1004 // Determine the size/length of packet.
1006 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1007 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1010 // Callback to user with the packet to be sent and check the user's feedback.
1012 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendSolicit
, &Packet
);
1014 if (EFI_ERROR (Status
)) {
1020 // Send solicit packet with the state transition from Dhcp6init to
1023 Instance
->IaCb
.Ia
->State
= Dhcp6Selecting
;
1025 // Clear initial time for current transaction.
1027 Instance
->StartTime
= 0;
1029 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1031 if (EFI_ERROR (Status
)) {
1037 // Enqueue the sent packet for the retransmission in case reply timeout.
1039 return Dhcp6EnqueueRetry (
1043 Instance
->Config
->SolicitRetransmission
1048 Configure some parameter to initiate SolicitMsg.
1050 @param[in] Instance The pointer to the Dhcp6 instance.
1052 @retval EFI_SUCCESS Created and sent the solicit message successfully.
1053 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1054 @retval Others Failed to send the solicit message.
1058 Dhcp6InitSolicitMsg (
1059 IN DHCP6_INSTANCE
*Instance
1062 Instance
->IaCb
.T1
= 0;
1063 Instance
->IaCb
.T2
= 0;
1064 Instance
->IaCb
.Ia
->IaAddressCount
= 0;
1066 return Dhcp6SendSolicitMsg (Instance
);
1071 Create the request message and send it.
1073 @param[in] Instance The pointer to the Dhcp6 instance.
1075 @retval EFI_SUCCESS Created and sent the request message successfully.
1076 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1077 @retval EFI_DEVICE_ERROR An unexpected error.
1078 @retval Others Failed to send the request message.
1082 Dhcp6SendRequestMsg (
1083 IN DHCP6_INSTANCE
*Instance
1087 EFI_DHCP6_PACKET
*Packet
;
1088 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1089 EFI_DHCP6_DUID
*ClientId
;
1090 EFI_DHCP6_DUID
*ServerId
;
1091 DHCP6_SERVICE
*Service
;
1099 ASSERT(Instance
->AdSelect
!= NULL
);
1100 ASSERT(Instance
->Config
!= NULL
);
1101 ASSERT(Instance
->IaCb
.Ia
!= NULL
);
1102 ASSERT(Instance
->Service
!= NULL
);
1104 Service
= Instance
->Service
;
1105 ClientId
= Service
->ClientId
;
1107 ASSERT(ClientId
!= NULL
);
1110 // Get the server Id from the selected advertisement message.
1112 Option
= Dhcp6SeekOption (
1113 Instance
->AdSelect
->Dhcp6
.Option
,
1114 Instance
->AdSelect
->Length
- 4,
1117 if (Option
== NULL
) {
1118 return EFI_DEVICE_ERROR
;
1121 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1124 // Calculate the added length of customized option list.
1127 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1128 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1132 // Create the Dhcp6 packet and initialize commone fields.
1134 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1135 if (Packet
== NULL
) {
1136 return EFI_OUT_OF_RESOURCES
;
1139 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1140 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1141 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRequest
;
1142 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1145 // Assembly Dhcp6 options for request message.
1147 Cursor
= Packet
->Dhcp6
.Option
;
1149 Length
= HTONS (ClientId
->Length
);
1150 Cursor
= Dhcp6AppendOption (
1152 HTONS (Dhcp6OptClientId
),
1157 Cursor
= Dhcp6AppendETOption (
1163 Cursor
= Dhcp6AppendOption (
1165 HTONS (Dhcp6OptServerId
),
1170 Cursor
= Dhcp6AppendIaOption (
1175 Packet
->Dhcp6
.Header
.MessageType
1179 // Append user-defined when configurate Dhcp6 service.
1181 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1183 UserOpt
= Instance
->Config
->OptionList
[Index
];
1184 Cursor
= Dhcp6AppendOption(
1193 // Determine the size/length of packet.
1195 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1196 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1199 // Callback to user with the packet to be sent and check the user's feedback.
1201 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRequest
, &Packet
);
1203 if (EFI_ERROR (Status
)) {
1209 // Send request packet with the state transition from Dhcp6selecting to
1212 Instance
->IaCb
.Ia
->State
= Dhcp6Requesting
;
1214 // Clear initial time for current transaction.
1216 Instance
->StartTime
= 0;
1218 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1220 if (EFI_ERROR (Status
)) {
1226 // Enqueue the sent packet for the retransmission in case reply timeout.
1228 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1233 Create the decline message and send it.
1235 @param[in] Instance The pointer to the Dhcp6 instance.
1236 @param[in] DecIa The pointer to the decline Ia.
1238 @retval EFI_SUCCESS Created and sent the decline message successfully.
1239 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1240 @retval EFI_DEVICE_ERROR An unexpected error.
1241 @retval Others Failed to send the decline message.
1245 Dhcp6SendDeclineMsg (
1246 IN DHCP6_INSTANCE
*Instance
,
1247 IN EFI_DHCP6_IA
*DecIa
1251 EFI_DHCP6_PACKET
*Packet
;
1252 EFI_DHCP6_PACKET
*LastReply
;
1253 EFI_DHCP6_DUID
*ClientId
;
1254 EFI_DHCP6_DUID
*ServerId
;
1255 DHCP6_SERVICE
*Service
;
1261 ASSERT (Instance
->Config
!= NULL
);
1262 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1263 ASSERT (Instance
->Service
!= NULL
);
1265 Service
= Instance
->Service
;
1266 ClientId
= Service
->ClientId
;
1267 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1269 ASSERT (ClientId
!= NULL
);
1270 ASSERT (LastReply
!= NULL
);
1273 // Get the server Id from the last reply message.
1275 Option
= Dhcp6SeekOption (
1276 LastReply
->Dhcp6
.Option
,
1277 LastReply
->Length
- 4,
1280 if (Option
== NULL
) {
1281 return EFI_DEVICE_ERROR
;
1285 // EFI_DHCP6_DUID contains a length field of 2 bytes.
1287 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1290 // Create the Dhcp6 packet and initialize commone fields.
1292 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1293 if (Packet
== NULL
) {
1294 return EFI_OUT_OF_RESOURCES
;
1297 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1298 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1299 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgDecline
;
1300 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1303 // Assembly Dhcp6 options for rebind/renew message.
1305 Cursor
= Packet
->Dhcp6
.Option
;
1307 Length
= HTONS (ClientId
->Length
);
1308 Cursor
= Dhcp6AppendOption (
1310 HTONS (Dhcp6OptClientId
),
1315 Cursor
= Dhcp6AppendETOption (
1321 Cursor
= Dhcp6AppendOption (
1323 HTONS (Dhcp6OptServerId
),
1328 Cursor
= Dhcp6AppendIaOption (Cursor
, DecIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1331 // Determine the size/length of packet.
1333 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1334 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1337 // Callback to user with the packet to be sent and check the user's feedback.
1339 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendDecline
, &Packet
);
1341 if (EFI_ERROR (Status
)) {
1347 // Send decline packet with the state transition from Dhcp6bound to
1350 Instance
->IaCb
.Ia
->State
= Dhcp6Declining
;
1352 // Clear initial time for current transaction.
1354 Instance
->StartTime
= 0;
1356 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1358 if (EFI_ERROR (Status
)) {
1364 // Enqueue the sent packet for the retransmission in case reply timeout.
1366 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1371 Create the release message and send it.
1373 @param[in] Instance The pointer to the Dhcp6 instance.
1374 @param[in] RelIa The pointer to the release Ia.
1376 @retval EFI_SUCCESS Created and sent the release message successfully.
1377 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1378 @retval EFI_DEVICE_ERROR An unexpected error.
1379 @retval Others Failed to send the release message.
1383 Dhcp6SendReleaseMsg (
1384 IN DHCP6_INSTANCE
*Instance
,
1385 IN EFI_DHCP6_IA
*RelIa
1389 EFI_DHCP6_PACKET
*Packet
;
1390 EFI_DHCP6_PACKET
*LastReply
;
1391 EFI_DHCP6_DUID
*ClientId
;
1392 EFI_DHCP6_DUID
*ServerId
;
1393 DHCP6_SERVICE
*Service
;
1399 ASSERT(Instance
->Config
);
1400 ASSERT(Instance
->IaCb
.Ia
);
1402 Service
= Instance
->Service
;
1403 ClientId
= Service
->ClientId
;
1404 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1410 // Get the server Id from the last reply message.
1412 Option
= Dhcp6SeekOption (
1413 LastReply
->Dhcp6
.Option
,
1414 LastReply
->Length
- 4,
1417 if (Option
== NULL
) {
1418 return EFI_DEVICE_ERROR
;
1421 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1424 // Create the Dhcp6 packet and initialize commone fields.
1426 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
);
1427 if (Packet
== NULL
) {
1428 return EFI_OUT_OF_RESOURCES
;
1431 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
;
1432 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1433 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgRelease
;
1434 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1437 // Assembly Dhcp6 options for rebind/renew message
1439 Cursor
= Packet
->Dhcp6
.Option
;
1441 Length
= HTONS (ClientId
->Length
);
1442 Cursor
= Dhcp6AppendOption (
1444 HTONS (Dhcp6OptClientId
),
1450 // ServerId is extracted from packet, it's network order.
1452 Cursor
= Dhcp6AppendOption (
1454 HTONS (Dhcp6OptServerId
),
1459 Cursor
= Dhcp6AppendETOption (
1465 Cursor
= Dhcp6AppendIaOption (Cursor
, RelIa
, 0, 0, Packet
->Dhcp6
.Header
.MessageType
);
1468 // Determine the size/length of packet
1470 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1471 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1474 // Callback to user with the packet to be sent and check the user's feedback.
1476 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendRelease
, &Packet
);
1478 if (EFI_ERROR (Status
)) {
1484 // Send release packet with the state transition from Dhcp6bound to
1487 Instance
->IaCb
.Ia
->State
= Dhcp6Releasing
;
1489 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1491 if (EFI_ERROR (Status
)) {
1497 // Enqueue the sent packet for the retransmission in case reply timeout.
1499 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1504 Create the renew/rebind message and send it.
1506 @param[in] Instance The pointer to the Dhcp6 instance.
1507 @param[in] RebindRequest If TRUE, it is a Rebind type message.
1508 Otherwise, it is a Renew type message.
1510 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
1511 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1512 @retval EFI_DEVICE_ERROR An unexpected error.
1513 @retval Others Failed to send the renew/rebind message.
1517 Dhcp6SendRenewRebindMsg (
1518 IN DHCP6_INSTANCE
*Instance
,
1519 IN BOOLEAN RebindRequest
1523 EFI_DHCP6_PACKET
*Packet
;
1524 EFI_DHCP6_PACKET
*LastReply
;
1525 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1526 EFI_DHCP6_DUID
*ClientId
;
1527 EFI_DHCP6_DUID
*ServerId
;
1528 EFI_DHCP6_STATE State
;
1529 EFI_DHCP6_EVENT Event
;
1530 DHCP6_SERVICE
*Service
;
1538 ASSERT(Instance
->Config
);
1539 ASSERT(Instance
->IaCb
.Ia
);
1541 Service
= Instance
->Service
;
1542 ClientId
= Service
->ClientId
;
1547 // Calculate the added length of customized option list.
1550 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1551 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1555 // Create the Dhcp6 packet and initialize commone fields.
1557 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1558 if (Packet
== NULL
) {
1559 return EFI_OUT_OF_RESOURCES
;
1562 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1563 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1564 Packet
->Dhcp6
.Header
.MessageType
= RebindRequest
? Dhcp6MsgRebind
: Dhcp6MsgRenew
;
1565 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1568 // Assembly Dhcp6 options for rebind/renew message.
1570 Cursor
= Packet
->Dhcp6
.Option
;
1572 Length
= HTONS (ClientId
->Length
);
1573 Cursor
= Dhcp6AppendOption (
1575 HTONS (Dhcp6OptClientId
),
1580 Cursor
= Dhcp6AppendETOption (
1586 Cursor
= Dhcp6AppendIaOption (
1591 Packet
->Dhcp6
.Header
.MessageType
1594 if (!RebindRequest
) {
1596 // Get the server Id from the last reply message and
1597 // insert it for rebind request.
1599 LastReply
= Instance
->IaCb
.Ia
->ReplyPacket
;
1602 Option
= Dhcp6SeekOption (
1603 LastReply
->Dhcp6
.Option
,
1604 LastReply
->Length
- 4,
1607 if (Option
== NULL
) {
1609 return EFI_DEVICE_ERROR
;
1612 ServerId
= (EFI_DHCP6_DUID
*) (Option
+ 2);
1614 Cursor
= Dhcp6AppendOption (
1616 HTONS (Dhcp6OptServerId
),
1623 // Append user-defined when configurate Dhcp6 service.
1625 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1627 UserOpt
= Instance
->Config
->OptionList
[Index
];
1628 Cursor
= Dhcp6AppendOption(
1637 // Determine the size/length of packet.
1639 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1640 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1643 // Callback to user with the packet to be sent and check the user's feedback.
1645 State
= (RebindRequest
) ? Dhcp6Rebinding
: Dhcp6Renewing
;
1646 Event
= (RebindRequest
) ? Dhcp6EnterRebinding
: Dhcp6EnterRenewing
;
1648 Status
= Dhcp6CallbackUser (Instance
, Event
, &Packet
);
1650 if (EFI_ERROR (Status
)) {
1656 // Send renew/rebind packet with the state transition from Dhcp6bound to
1657 // Dhcp6renew/rebind.
1658 // And sync the lease time when send renew/rebind, in case that user send
1659 // renew/rebind actively.
1661 Instance
->IaCb
.Ia
->State
= State
;
1662 Instance
->IaCb
.LeaseTime
= (RebindRequest
) ? Instance
->IaCb
.T2
: Instance
->IaCb
.T1
;
1664 // Clear initial time for current transaction.
1666 Instance
->StartTime
= 0;
1668 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1670 if (EFI_ERROR (Status
)) {
1676 // Enqueue the sent packet for the retransmission in case reply timeout.
1678 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
1682 Start the information request process.
1684 @param[in] Instance The pointer to the Dhcp6 instance.
1685 @param[in] SendClientId If TRUE, the client identifier option will be included in
1686 information request message. Otherwise, the client identifier
1687 option will not be included.
1688 @param[in] OptionRequest The pointer to the option request option.
1689 @param[in] OptionCount The number options in the OptionList.
1690 @param[in] OptionList The array pointers to the appended options.
1691 @param[in] Retransmission The pointer to the retransmission control.
1692 @param[in] TimeoutEvent The event of timeout.
1693 @param[in] ReplyCallback The callback function when the reply was received.
1694 @param[in] CallbackContext The pointer to the parameter passed to the callback.
1696 @retval EFI_SUCCESS Start the info-request process successfully.
1697 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1698 @retval EFI_NO_MAPPING No source address is available for use.
1699 @retval Others Failed to start the info-request process.
1703 Dhcp6StartInfoRequest (
1704 IN DHCP6_INSTANCE
*Instance
,
1705 IN BOOLEAN SendClientId
,
1706 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1707 IN UINT32 OptionCount
,
1708 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[] OPTIONAL
,
1709 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
,
1710 IN EFI_EVENT TimeoutEvent OPTIONAL
,
1711 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback
,
1712 IN VOID
*CallbackContext OPTIONAL
1716 DHCP6_INF_CB
*InfCb
;
1717 DHCP6_SERVICE
*Service
;
1720 Service
= Instance
->Service
;
1722 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1723 Instance
->UdpSts
= EFI_ALREADY_STARTED
;
1725 // Create and initialize the control block for the info-request.
1727 InfCb
= AllocateZeroPool (sizeof(DHCP6_INF_CB
));
1729 if (InfCb
== NULL
) {
1730 gBS
->RestoreTPL (OldTpl
);
1731 return EFI_OUT_OF_RESOURCES
;
1734 InfCb
->ReplyCallback
= ReplyCallback
;
1735 InfCb
->CallbackContext
= CallbackContext
;
1736 InfCb
->TimeoutEvent
= TimeoutEvent
;
1738 InsertTailList (&Instance
->InfList
, &InfCb
->Link
);
1741 // Send the info-request message to start exchange process.
1743 Status
= Dhcp6SendInfoRequestMsg (
1753 if (EFI_ERROR (Status
)) {
1758 // Register receive callback for the stateless exchange process.
1760 Status
= UdpIoRecvDatagram(
1767 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
1771 gBS
->RestoreTPL (OldTpl
);
1775 gBS
->RestoreTPL (OldTpl
);
1776 RemoveEntryList (&InfCb
->Link
);
1783 Create the information request message and send it.
1785 @param[in] Instance The pointer to the Dhcp6 instance.
1786 @param[in] InfCb The pointer to the information request control block.
1787 @param[in] SendClientId If TRUE, the client identifier option will be included in
1788 information request message. Otherwise, the client identifier
1789 option will not be included.
1790 @param[in] OptionRequest The pointer to the option request option.
1791 @param[in] OptionCount The number options in the OptionList.
1792 @param[in] OptionList The array pointers to the appended options.
1793 @param[in] Retransmission The pointer to the retransmission control.
1795 @retval EFI_SUCCESS Created and sent the info-request message successfully.
1796 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1797 @retval Others Failed to send the info-request message.
1801 Dhcp6SendInfoRequestMsg (
1802 IN DHCP6_INSTANCE
*Instance
,
1803 IN DHCP6_INF_CB
*InfCb
,
1804 IN BOOLEAN SendClientId
,
1805 IN EFI_DHCP6_PACKET_OPTION
*OptionRequest
,
1806 IN UINT32 OptionCount
,
1807 IN EFI_DHCP6_PACKET_OPTION
*OptionList
[],
1808 IN EFI_DHCP6_RETRANSMISSION
*Retransmission
1812 EFI_DHCP6_PACKET
*Packet
;
1813 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1814 EFI_DHCP6_DUID
*ClientId
;
1815 DHCP6_SERVICE
*Service
;
1822 ASSERT(OptionRequest
);
1824 Service
= Instance
->Service
;
1825 ClientId
= Service
->ClientId
;
1826 UserLen
= NTOHS (OptionRequest
->OpLen
) + 4;
1831 // Calculate the added length of customized option list.
1833 for (Index
= 0; Index
< OptionCount
; Index
++) {
1834 UserLen
+= (NTOHS (OptionList
[Index
]->OpLen
) + 4);
1838 // Create the Dhcp6 packet and initialize commone fields.
1840 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1841 if (Packet
== NULL
) {
1842 return EFI_OUT_OF_RESOURCES
;
1845 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1846 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1847 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgInfoRequest
;
1848 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1850 InfCb
->Xid
= Packet
->Dhcp6
.Header
.TransactionId
;
1853 // Assembly Dhcp6 options for info-request message.
1855 Cursor
= Packet
->Dhcp6
.Option
;
1858 Length
= HTONS (ClientId
->Length
);
1859 Cursor
= Dhcp6AppendOption (
1861 HTONS (Dhcp6OptClientId
),
1867 Cursor
= Dhcp6AppendETOption (
1873 Cursor
= Dhcp6AppendOption (
1875 OptionRequest
->OpCode
,
1876 OptionRequest
->OpLen
,
1881 // Append user-defined when configurate Dhcp6 service.
1883 for (Index
= 0; Index
< OptionCount
; Index
++) {
1885 UserOpt
= OptionList
[Index
];
1886 Cursor
= Dhcp6AppendOption(
1895 // Determine the size/length of packet.
1897 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
1898 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
1901 // Clear initial time for current transaction.
1903 Instance
->StartTime
= 0;
1906 // Send info-request packet with no state.
1908 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
1910 if (EFI_ERROR (Status
)) {
1916 // Enqueue the sent packet for the retransmission in case reply timeout.
1918 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, Retransmission
);
1923 Create the Confirm message and send it.
1925 @param[in] Instance The pointer to the Dhcp6 instance.
1927 @retval EFI_SUCCESS Created and sent the confirm message successfully.
1928 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1929 @retval EFI_DEVICE_ERROR An unexpected error.
1930 @retval Others Failed to send the confirm message.
1934 Dhcp6SendConfirmMsg (
1935 IN DHCP6_INSTANCE
*Instance
1943 DHCP6_SERVICE
*Service
;
1944 EFI_DHCP6_DUID
*ClientId
;
1945 EFI_DHCP6_PACKET
*Packet
;
1946 EFI_DHCP6_PACKET_OPTION
*UserOpt
;
1949 ASSERT (Instance
->Config
!= NULL
);
1950 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
1951 ASSERT (Instance
->Service
!= NULL
);
1953 Service
= Instance
->Service
;
1954 ClientId
= Service
->ClientId
;
1955 ASSERT (ClientId
!= NULL
);
1958 // Calculate the added length of customized option list.
1961 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
1962 UserLen
+= (NTOHS (Instance
->Config
->OptionList
[Index
]->OpLen
) + 4);
1966 // Create the Dhcp6 packet and initialize common fields.
1968 Packet
= AllocateZeroPool (DHCP6_BASE_PACKET_SIZE
+ UserLen
);
1969 if (Packet
== NULL
) {
1970 return EFI_OUT_OF_RESOURCES
;
1973 Packet
->Size
= DHCP6_BASE_PACKET_SIZE
+ UserLen
;
1974 Packet
->Length
= sizeof (EFI_DHCP6_HEADER
);
1975 Packet
->Dhcp6
.Header
.MessageType
= Dhcp6MsgConfirm
;
1976 Packet
->Dhcp6
.Header
.TransactionId
= Service
->Xid
++;
1979 // Assembly Dhcp6 options for solicit message.
1981 Cursor
= Packet
->Dhcp6
.Option
;
1983 Length
= HTONS (ClientId
->Length
);
1984 Cursor
= Dhcp6AppendOption (
1986 HTONS (Dhcp6OptClientId
),
1991 Cursor
= Dhcp6AppendETOption (
1997 Cursor
= Dhcp6AppendIaOption (
2002 Packet
->Dhcp6
.Header
.MessageType
2006 // Append user-defined when configurate Dhcp6 service.
2008 for (Index
= 0; Index
< Instance
->Config
->OptionCount
; Index
++) {
2009 UserOpt
= Instance
->Config
->OptionList
[Index
];
2010 Cursor
= Dhcp6AppendOption (
2019 // Determine the size/length of packet.
2021 Packet
->Length
+= (UINT32
) (Cursor
- Packet
->Dhcp6
.Option
);
2022 ASSERT (Packet
->Size
> Packet
->Length
+ 8);
2025 // Callback to user with the packet to be sent and check the user's feedback.
2027 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SendConfirm
, &Packet
);
2029 if (EFI_ERROR (Status
)) {
2035 // Send confirm packet with the state transition from Dhcp6Bound to
2038 Instance
->IaCb
.Ia
->State
= Dhcp6Confirming
;
2040 // Clear initial time for current transaction.
2042 Instance
->StartTime
= 0;
2044 Status
= Dhcp6TransmitPacket (Instance
, Packet
, Elapsed
);
2046 if (EFI_ERROR (Status
)) {
2052 // Enqueue the sent packet for the retransmission in case reply timeout.
2054 return Dhcp6EnqueueRetry (Instance
, Packet
, Elapsed
, NULL
);
2060 Handle with the Dhcp6 reply message.
2062 @param[in] Instance The pointer to Dhcp6 instance.
2063 @param[in] Packet The pointer to the Dhcp6 reply message.
2065 @retval EFI_SUCCESS Processed the reply message successfully.
2066 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2067 @retval EFI_DEVICE_ERROR An unexpected error.
2068 @retval Others Failed to process the reply message.
2072 Dhcp6HandleReplyMsg (
2073 IN DHCP6_INSTANCE
*Instance
,
2074 IN EFI_DHCP6_PACKET
*Packet
2081 ASSERT (Instance
->Config
!= NULL
);
2082 ASSERT (Instance
->IaCb
.Ia
!= NULL
);
2083 ASSERT (Packet
!= NULL
);
2085 Status
= EFI_SUCCESS
;
2087 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2088 return EFI_DEVICE_ERROR
;
2092 // If the client subsequently receives a valid reply message that includes a
2093 // rapid commit option since send a solicit with rapid commit option before,
2094 // preocess the reply message and discard any reply messages received in
2095 // response to the request message.
2096 // See details in the section-17.1.4 of rfc-3315.
2098 Option
= Dhcp6SeekOption (
2099 Packet
->Dhcp6
.Option
,
2104 if ((Option
!= NULL
&& !Instance
->Config
->RapidCommit
) || (Option
== NULL
&& Instance
->Config
->RapidCommit
)) {
2105 return EFI_DEVICE_ERROR
;
2109 // As to a valid reply packet in response to a request/renew/rebind packet,
2110 // ignore the packet if not contains the Ia option
2112 if (Instance
->IaCb
.Ia
->State
== Dhcp6Requesting
||
2113 Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
||
2114 Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
2117 Option
= Dhcp6SeekIaOption (
2118 Packet
->Dhcp6
.Option
,
2120 &Instance
->Config
->IaDescriptor
2122 if (Option
== NULL
) {
2128 // Callback to user with the received packet and check the user's feedback.
2130 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdReply
, &Packet
);
2132 if (EFI_ERROR (Status
)) {
2137 // When receive a valid reply packet in response to a decline/release packet,
2138 // the client considers the decline/release event completed regardless of the
2141 if (Instance
->IaCb
.Ia
->State
== Dhcp6Declining
|| Instance
->IaCb
.Ia
->State
== Dhcp6Releasing
) {
2143 if (Instance
->IaCb
.Ia
->IaAddressCount
!= 0) {
2144 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2146 ASSERT (Instance
->IaCb
.Ia
->ReplyPacket
);
2147 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2148 Instance
->IaCb
.Ia
->ReplyPacket
= NULL
;
2149 Instance
->IaCb
.Ia
->State
= Dhcp6Init
;
2153 // For sync, set the success flag out of polling in decline/release.
2155 Instance
->UdpSts
= EFI_SUCCESS
;
2158 // For async, signal the Ia event to inform Ia infomation update.
2160 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2161 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2165 // Reset start time for next exchange.
2167 Instance
->StartTime
= 0;
2169 Status
= EFI_SUCCESS
;
2174 // Upon the receipt of a valid reply packet in response to a solicit, request,
2175 // confirm, renew and rebind, the behavior depends on the status code option.
2176 // See the details in the section-18.1.8 of rfc-3315.
2179 Status
= Dhcp6SeekStsOption (
2185 if (!EFI_ERROR (Status
)) {
2187 // No status code or no error status code means succeed to reply.
2189 Status
= Dhcp6UpdateIaInfo (Instance
, Packet
);
2190 if (!EFI_ERROR (Status
)) {
2192 // Reset start time for next exchange.
2194 Instance
->StartTime
= 0;
2197 // Set bound state and store the reply packet.
2199 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
2200 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
2203 Instance
->IaCb
.Ia
->ReplyPacket
= AllocateZeroPool (Packet
->Size
);
2205 if (Instance
->IaCb
.Ia
->ReplyPacket
== NULL
) {
2206 Status
= EFI_OUT_OF_RESOURCES
;
2210 CopyMem (Instance
->IaCb
.Ia
->ReplyPacket
, Packet
, Packet
->Size
);
2212 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
2215 // For sync, set the success flag out of polling in start/renewrebind.
2217 Instance
->UdpSts
= EFI_SUCCESS
;
2220 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
2221 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
2222 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
2223 // consumers can be notified to flush old address.
2225 Dhcp6AppendCacheIa (Instance
);
2228 // For async, signal the Ia event to inform Ia infomation update.
2230 if (Instance
->Config
->IaInfoEvent
!= NULL
) {
2231 gBS
->SignalEvent (Instance
->Config
->IaInfoEvent
);
2233 } else if (Status
== EFI_NOT_FOUND
) {
2235 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
2236 // the client sends a Renew or Rebind if the IA is not in the Reply message.
2237 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
2244 } else if (Option
!= NULL
) {
2246 // Any error status code option is found.
2248 StsCode
= NTOHS (ReadUnaligned16 ((UINT16
*) (Option
+ 4)));
2250 case Dhcp6StsUnspecFail
:
2252 // It indicates the server is unable to process the message due to an
2253 // unspecified failure condition, so just retry if possible.
2257 case Dhcp6StsUseMulticast
:
2259 // It indicates the server receives a message via unicast from a client
2260 // to which the server has not sent a unicast option, so retry it by
2261 // multi-cast address.
2263 if (Instance
->Unicast
!= NULL
) {
2264 FreePool (Instance
->Unicast
);
2265 Instance
->Unicast
= NULL
;
2269 case Dhcp6StsNotOnLink
:
2270 if (Instance
->IaCb
.Ia
->State
== Dhcp6Confirming
) {
2272 // Before initiate new round DHCP, cache the current IA.
2274 Status
= Dhcp6CacheIa (Instance
);
2275 if (EFI_ERROR (Status
)) {
2280 // Restart S.A.R.R process to acquire new address.
2282 Status
= Dhcp6InitSolicitMsg (Instance
);
2283 if (EFI_ERROR (Status
)) {
2289 case Dhcp6StsNoBinding
:
2290 if (Instance
->IaCb
.Ia
->State
== Dhcp6Renewing
|| Instance
->IaCb
.Ia
->State
== Dhcp6Rebinding
) {
2292 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
2293 // sends a Request message if the IA contained a Status Code option with the NoBinding status.
2295 Status
= Dhcp6SendRequestMsg(Instance
);
2296 if (EFI_ERROR (Status
)) {
2304 // The other status code, just restart solicitation.
2314 if (!EFI_ERROR(Status
)) {
2315 Status
= Dhcp6DequeueRetry (
2317 Packet
->Dhcp6
.Header
.TransactionId
,
2327 Select the appointed Dhcp6 advertisement message.
2329 @param[in] Instance The pointer to the Dhcp6 instance.
2330 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
2332 @retval EFI_SUCCESS Selected the right advertisement message successfully.
2333 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2334 @retval Others Failed to select the advertise message.
2338 Dhcp6SelectAdvertiseMsg (
2339 IN DHCP6_INSTANCE
*Instance
,
2340 IN EFI_DHCP6_PACKET
*AdSelect
2346 ASSERT (AdSelect
!= NULL
);
2349 // Callback to user with the selected advertisement packet, and the user
2350 // might overwrite it.
2352 Status
= Dhcp6CallbackUser (Instance
, Dhcp6SelectAdvertise
, &AdSelect
);
2354 if (EFI_ERROR (Status
)) {
2358 Instance
->AdSelect
= AdSelect
;
2361 // Dequeue the sent packet for the retransmission since advertisement selected.
2363 Status
= Dhcp6DequeueRetry (
2365 AdSelect
->Dhcp6
.Header
.TransactionId
,
2369 if (EFI_ERROR(Status
)) {
2374 // Check whether there is server unicast option in the selected advertise
2375 // packet, and update it.
2377 Option
= Dhcp6SeekOption(
2378 AdSelect
->Dhcp6
.Option
,
2379 AdSelect
->Length
- 4,
2380 Dhcp6OptServerUnicast
2383 if (Option
!= NULL
) {
2385 Instance
->Unicast
= AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS
));
2387 if (Instance
->Unicast
== NULL
) {
2388 return EFI_OUT_OF_RESOURCES
;
2391 CopyMem (Instance
->Unicast
, Option
+ 4, sizeof(EFI_IPv6_ADDRESS
));
2395 // Update the information of the Ia by the selected advertisement message.
2397 Status
= Dhcp6UpdateIaInfo (Instance
, AdSelect
);
2399 if (EFI_ERROR (Status
)) {
2404 // Send the request message to continue the S.A.R.R. process.
2406 return Dhcp6SendRequestMsg (Instance
);
2411 Handle with the Dhcp6 advertisement message.
2413 @param[in] Instance The pointer to the Dhcp6 instance.
2414 @param[in] Packet The pointer to the Dhcp6 advertisement message.
2416 @retval EFI_SUCCESS Processed the advertisement message successfully.
2417 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2418 @retval EFI_DEVICE_ERROR An unexpected error.
2419 @retval Others Failed to process the advertise message.
2423 Dhcp6HandleAdvertiseMsg (
2424 IN DHCP6_INSTANCE
*Instance
,
2425 IN EFI_DHCP6_PACKET
*Packet
2432 ASSERT(Instance
->Config
);
2433 ASSERT(Instance
->IaCb
.Ia
);
2438 // If the client does receives a valid reply message that includes a rapid
2439 // commit option since a solicit with rapid commit optioin sent before, select
2440 // this reply message. Or else, process the advertise messages as normal.
2441 // See details in the section-17.1.4 of rfc-3315.
2443 Option
= Dhcp6SeekOption(
2444 Packet
->Dhcp6
.Option
,
2449 if (Option
!= NULL
&& Instance
->Config
->RapidCommit
&& Packet
->Dhcp6
.Header
.MessageType
== Dhcp6MsgReply
) {
2451 return Dhcp6HandleReplyMsg (Instance
, Packet
);
2454 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
) {
2455 return EFI_DEVICE_ERROR
;
2459 // Client must ignore any advertise message that includes a status code option
2460 // containing the value noaddrsavail, with the exception that the client may
2461 // display the associated status message to the user.
2462 // See the details in the section-17.1.3 of rfc-3315.
2464 Status
= Dhcp6SeekStsOption (
2469 if (EFI_ERROR (Status
)) {
2470 return EFI_DEVICE_ERROR
;
2474 // Callback to user with the received packet and check the user's feedback.
2476 Status
= Dhcp6CallbackUser (Instance
, Dhcp6RcvdAdvertise
, &Packet
);
2478 if (!EFI_ERROR (Status
)) {
2480 // Success means user choose the current advertisement packet.
2482 if (Instance
->AdSelect
!= NULL
) {
2483 FreePool (Instance
->AdSelect
);
2487 // Store the selected advertisement packet and set a flag.
2489 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2491 if (Instance
->AdSelect
== NULL
) {
2492 return EFI_OUT_OF_RESOURCES
;
2495 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2497 Instance
->AdPref
= 0xff;
2499 } else if (Status
== EFI_NOT_READY
) {
2501 // Not_ready means user wants to continue to receive more advertise packets.
2503 if (Instance
->AdPref
== 0xff && Instance
->AdSelect
== NULL
) {
2505 // It's a tricky point. The timer routine set adpref as 0xff if the first
2506 // rt timeout and no advertisement received, which means any advertisement
2507 // received will be selected after the first rt.
2513 // Check whether the current packet has a 255 preference option or not.
2514 // Take non-preference option as 0 value.
2516 Option
= Dhcp6SeekOption(
2517 Packet
->Dhcp6
.Option
,
2522 if (Instance
->AdSelect
== NULL
|| (Option
!= NULL
&& *(Option
+ 4) > Instance
->AdPref
)) {
2524 // No advertisements received before or preference is more than other
2525 // advertisements received before. Then store the new packet and the
2526 // preference value.
2528 if (Instance
->AdSelect
!= NULL
) {
2529 FreePool (Instance
->AdSelect
);
2532 Instance
->AdSelect
= AllocateZeroPool (Packet
->Size
);
2534 if (Instance
->AdSelect
== NULL
) {
2535 return EFI_OUT_OF_RESOURCES
;
2538 CopyMem (Instance
->AdSelect
, Packet
, Packet
->Size
);
2540 if (Option
!= NULL
) {
2541 Instance
->AdPref
= *(Option
+ 4);
2545 // Non-preference and other advertisements received before or current
2546 // preference is less than other advertisements received before.
2547 // Leave the packet alone.
2552 // Other error status means termination.
2558 // Client must collect advertise messages as more as possible until the first
2559 // RT has elapsed, or get a highest preference 255 advertise.
2560 // See details in the section-17.1.2 of rfc-3315.
2562 if (Instance
->AdPref
== 0xff || Timeout
) {
2563 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
2571 The Dhcp6 stateful exchange process routine.
2573 @param[in] Instance The pointer to the Dhcp6 instance.
2574 @param[in] Packet The pointer to the received Dhcp6 message.
2578 Dhcp6HandleStateful (
2579 IN DHCP6_INSTANCE
*Instance
,
2580 IN EFI_DHCP6_PACKET
*Packet
2584 EFI_DHCP6_DUID
*ClientId
;
2585 DHCP6_SERVICE
*Service
;
2588 Service
= Instance
->Service
;
2589 ClientId
= Service
->ClientId
;
2590 Status
= EFI_SUCCESS
;
2592 if (Instance
->Config
== NULL
) {
2597 ASSERT (Instance
->Config
);
2598 ASSERT (Instance
->IaCb
.Ia
);
2601 // Discard the packet if not advertisement or reply packet.
2603 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgAdvertise
&& Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2608 // Check whether include client Id or not.
2610 Option
= Dhcp6SeekOption(
2611 Packet
->Dhcp6
.Option
,
2616 if (Option
== NULL
|| CompareMem (Option
+ 4, ClientId
->Duid
, ClientId
->Length
) != 0) {
2621 // Check whether include server Id or not.
2623 Option
= Dhcp6SeekOption(
2624 Packet
->Dhcp6
.Option
,
2629 if (Option
== NULL
) {
2633 switch (Instance
->IaCb
.Ia
->State
) {
2634 case Dhcp6Selecting
:
2636 // Handle the advertisement message when in the Dhcp6Selecting state.
2637 // Do not need check return status, if failed, just continue to the next.
2639 Dhcp6HandleAdvertiseMsg (Instance
, Packet
);
2642 case Dhcp6Requesting
:
2643 case Dhcp6Confirming
:
2645 case Dhcp6Rebinding
:
2646 case Dhcp6Releasing
:
2647 case Dhcp6Declining
:
2649 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
2650 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
2651 // If failed here, it should reset the current session.
2653 Status
= Dhcp6HandleReplyMsg (Instance
, Packet
);
2654 if (EFI_ERROR (Status
)) {
2660 // Other state has not supported yet.
2667 // Continue to receive the following Dhcp6 message.
2669 Status
= UdpIoRecvDatagram (
2676 if (EFI_ERROR (Status
)) {
2677 Dhcp6CleanupSession (Instance
, Status
);
2683 The Dhcp6 stateless exchange process routine.
2685 @param[in] Instance The pointer to the Dhcp6 instance.
2686 @param[in] Packet The pointer to the received Dhcp6 message.
2690 Dhcp6HandleStateless (
2691 IN DHCP6_INSTANCE
*Instance
,
2692 IN EFI_DHCP6_PACKET
*Packet
2696 DHCP6_SERVICE
*Service
;
2697 DHCP6_INF_CB
*InfCb
;
2701 Service
= Instance
->Service
;
2702 Status
= EFI_SUCCESS
;
2706 if (Packet
->Dhcp6
.Header
.MessageType
!= Dhcp6MsgReply
) {
2711 // Check whether it's a desired Info-request message by Xid.
2713 while (!IsListEmpty (&Instance
->InfList
)) {
2714 InfCb
= NET_LIST_HEAD (&Instance
->InfList
, DHCP6_INF_CB
, Link
);
2715 if (InfCb
->Xid
== Packet
->Dhcp6
.Header
.TransactionId
) {
2726 // Check whether include server Id or not.
2728 Option
= Dhcp6SeekOption (
2729 Packet
->Dhcp6
.Option
,
2734 if (Option
== NULL
) {
2739 // Callback to user with the received packet and check the user's feedback.
2741 Status
= InfCb
->ReplyCallback (
2743 InfCb
->CallbackContext
,
2747 if (Status
== EFI_NOT_READY
) {
2749 // Success or aborted will both stop this info-request exchange process,
2750 // but not ready means user wants to continue to receive reply.
2756 // Dequeue the sent packet from the txlist if the xid matched, and ignore
2757 // if no xid matched.
2761 Packet
->Dhcp6
.Header
.TransactionId
,
2766 // For sync, set the status out of polling for info-request.
2768 Instance
->UdpSts
= Status
;
2772 Status
= UdpIoRecvDatagram (
2779 if (EFI_ERROR (Status
)) {
2780 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_STATELESS
);
2786 The receive callback function for Dhcp6 exchange process.
2788 @param[in] Udp6Wrap The pointer to the received net buffer.
2789 @param[in] EndPoint The pointer to the udp end point.
2790 @param[in] IoStatus The return status from udp io.
2791 @param[in] Context The opaque parameter to the function.
2796 Dhcp6ReceivePacket (
2797 IN NET_BUF
*Udp6Wrap
,
2798 IN UDP_END_POINT
*EndPoint
,
2799 IN EFI_STATUS IoStatus
,
2803 EFI_DHCP6_HEADER
*Head
;
2804 EFI_DHCP6_PACKET
*Packet
;
2805 DHCP6_SERVICE
*Service
;
2806 DHCP6_INSTANCE
*Instance
;
2809 BOOLEAN IsDispatched
;
2810 BOOLEAN IsStateless
;
2817 ASSERT (Udp6Wrap
!= NULL
);
2818 ASSERT (Context
!= NULL
);
2820 Service
= (DHCP6_SERVICE
*) Context
;
2823 IsDispatched
= FALSE
;
2824 IsStateless
= FALSE
;
2826 if (EFI_ERROR (IoStatus
)) {
2831 // Copy the net buffer received from upd6 to a Dhcp6 packet.
2833 Size
= sizeof (EFI_DHCP6_PACKET
) + Udp6Wrap
->TotalSize
;
2834 Packet
= (EFI_DHCP6_PACKET
*) AllocateZeroPool (Size
);
2836 if (Packet
== NULL
) {
2840 Packet
->Size
= Size
;
2841 Head
= &Packet
->Dhcp6
.Header
;
2842 Packet
->Length
= NetbufCopy (Udp6Wrap
, 0, Udp6Wrap
->TotalSize
, (UINT8
*) Head
);
2844 if (Packet
->Length
== 0) {
2849 // Dispatch packet to right instance by transaction id.
2851 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2853 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2855 NET_LIST_FOR_EACH_SAFE (Entry2
, Next2
, &Instance
->TxList
) {
2857 TxCb
= NET_LIST_USER_STRUCT (Entry2
, DHCP6_TX_CB
, Link
);
2859 if (Packet
->Dhcp6
.Header
.TransactionId
== TxCb
->Xid
) {
2861 // Find the corresponding packet in tx list, and check it whether belongs
2862 // to stateful exchange process.
2864 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
2867 IsDispatched
= TRUE
;
2878 // Skip this packet if not dispatched to any instance.
2880 if (!IsDispatched
) {
2885 // Dispatch the received packet ot the right instance.
2888 Dhcp6HandleStateless (Instance
, Packet
);
2890 Dhcp6HandleStateful (Instance
, Packet
);
2895 if (!IsDispatched
) {
2896 Status
= UdpIoRecvDatagram (
2902 if (EFI_ERROR (Status
)) {
2903 NET_LIST_FOR_EACH_SAFE (Entry1
, Next1
, &Service
->Child
) {
2904 Instance
= NET_LIST_USER_STRUCT (Entry1
, DHCP6_INSTANCE
, Link
);
2905 Dhcp6CleanupRetry (Instance
, DHCP6_PACKET_ALL
);
2910 NetbufFree (Udp6Wrap
);
2912 if (Packet
!= NULL
) {
2918 Detect Link movement for specified network device.
2920 This routine will try to invoke Snp->GetStatus() to get the media status.
2921 If media present status switches from unpresent to present, a link movement
2922 is detected. Note that the underlying UNDI driver may not support reporting
2923 media status from GET_STATUS command. If that, fail to detect link movement.
2925 @param[in] Instance The pointer to DHCP6_INSTANCE.
2927 @retval TRUE A link movement is detected.
2928 @retval FALSE A link movement is not detected.
2932 Dhcp6LinkMovDetect (
2933 IN DHCP6_INSTANCE
*Instance
2936 UINT32 InterruptStatus
;
2937 BOOLEAN MediaPresent
;
2939 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2941 ASSERT (Instance
!= NULL
);
2942 Snp
= Instance
->Service
->Snp
;
2943 MediaPresent
= Instance
->MediaPresent
;
2946 // Check whether SNP support media detection
2948 if (!Snp
->Mode
->MediaPresentSupported
) {
2953 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2955 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2956 if (EFI_ERROR (Status
)) {
2960 Instance
->MediaPresent
= Snp
->Mode
->MediaPresent
;
2962 // Media transimit Unpresent to Present means new link movement is detected.
2964 if (!MediaPresent
&& Instance
->MediaPresent
) {
2972 The timer routine of the Dhcp6 instance for each second.
2974 @param[in] Event The timer event.
2975 @param[in] Context The opaque parameter to the function.
2986 LIST_ENTRY
*NextEntry
;
2987 DHCP6_INSTANCE
*Instance
;
2993 ASSERT (Context
!= NULL
);
2995 Instance
= (DHCP6_INSTANCE
*) Context
;
2998 // 1. Loop the tx list, count live time of every tx packet to check whether
2999 // need re-transmit or not.
3001 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Instance
->TxList
) {
3003 TxCb
= NET_LIST_USER_STRUCT (Entry
, DHCP6_TX_CB
, Link
);
3007 if (TxCb
->TickTime
> TxCb
->RetryExp
) {
3009 // Handle the first rt in the transmission of solicit specially.
3011 if ((TxCb
->RetryCnt
== 0 || TxCb
->SolicitRetry
) && TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3012 if (Instance
->AdSelect
== NULL
) {
3014 // Set adpref as 0xff here to indicate select any advertisement
3017 Instance
->AdPref
= 0xff;
3020 // Select the advertisement received before.
3022 Status
= Dhcp6SelectAdvertiseMsg (Instance
, Instance
->AdSelect
);
3023 if (Status
== EFI_ABORTED
) {
3025 } else if (EFI_ERROR (Status
)) {
3032 // Increase the retry count for the packet and add up the total loss time.
3035 TxCb
->RetryLos
+= TxCb
->RetryExp
;
3038 // Check whether overflow the max retry count limit for this packet
3040 if (TxCb
->RetryCtl
.Mrc
!= 0 && TxCb
->RetryCtl
.Mrc
< TxCb
->RetryCnt
) {
3041 Status
= EFI_NO_RESPONSE
;
3046 // Check whether overflow the max retry duration for this packet
3048 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
<= TxCb
->RetryLos
) {
3049 Status
= EFI_NO_RESPONSE
;
3054 // Re-calculate retry expire timeout for the next time.
3056 // Firstly, Check the new calculated time whether overflow the max retry
3059 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3065 if (TxCb
->RetryCtl
.Mrt
!= 0 && TxCb
->RetryCtl
.Mrt
< TxCb
->RetryExp
) {
3066 TxCb
->RetryExp
= Dhcp6CalculateExpireTime (
3074 // Secondly, Check the new calculated time whether overflow the max retry
3077 LossTime
= TxCb
->RetryLos
+ TxCb
->RetryExp
;
3078 if (TxCb
->RetryCtl
.Mrd
!= 0 && TxCb
->RetryCtl
.Mrd
< LossTime
) {
3079 TxCb
->RetryExp
= TxCb
->RetryCtl
.Mrd
- TxCb
->RetryLos
;
3083 // Reset the tick time for the next retransmission
3088 // Retransmit the last sent packet again.
3090 Dhcp6TransmitPacket (Instance
, TxCb
->TxPacket
, TxCb
->Elapsed
);
3091 TxCb
->SolicitRetry
= FALSE
;
3092 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgSolicit
) {
3093 TxCb
->SolicitRetry
= TRUE
;
3099 // 2. Check the configured Ia, count lease time of every valid Ia to check
3100 // whether need to renew or rebind this Ia.
3102 IaCb
= &Instance
->IaCb
;
3104 if (Instance
->Config
== NULL
|| IaCb
->Ia
== NULL
) {
3108 if (IaCb
->Ia
->State
== Dhcp6Bound
|| IaCb
->Ia
->State
== Dhcp6Renewing
|| IaCb
->Ia
->State
== Dhcp6Rebinding
) {
3112 if (IaCb
->LeaseTime
> IaCb
->T2
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3114 // Exceed t2, send rebind packet to extend the Ia lease.
3116 Dhcp6SendRenewRebindMsg (Instance
, TRUE
);
3118 } else if (IaCb
->LeaseTime
> IaCb
->T1
&& IaCb
->Ia
->State
== Dhcp6Bound
) {
3121 // Exceed t1, send renew packet to extend the Ia lease.
3123 Dhcp6SendRenewRebindMsg (Instance
, FALSE
);
3128 // 3. In any situation when a client may have moved to a new link, the
3129 // client MUST initiate a Confirm/Reply message exchange.
3131 if (Dhcp6LinkMovDetect (Instance
) && (IaCb
->Ia
->State
== Dhcp6Bound
)) {
3132 Dhcp6SendConfirmMsg (Instance
);
3139 if (Dhcp6IsValidTxCb (Instance
, TxCb
) &&
3140 TxCb
->TxPacket
!= NULL
&&
3141 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
||
3142 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
||
3143 TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)
3146 // The failure of renew/Confirm will still switch to the bound state.
3148 if ((TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgRenew
) ||
3149 (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgConfirm
)) {
3150 ASSERT (Instance
->IaCb
.Ia
);
3151 Instance
->IaCb
.Ia
->State
= Dhcp6Bound
;
3154 // The failure of info-request will return no response.
3156 if (TxCb
->TxPacket
->Dhcp6
.Header
.MessageType
== Dhcp6MsgInfoRequest
) {
3157 Instance
->UdpSts
= EFI_NO_RESPONSE
;
3166 // The failure of the others will terminate current state machine if timeout.
3168 Dhcp6CleanupSession (Instance
, Status
);