2 Dhcp6 support functions implementation.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "Dhcp6Impl.h"
15 Generate client Duid in the format of Duid-llt.
17 @param[in] Mode The pointer to the mode of SNP.
19 @retval NULL If it failed to generate a client Id.
20 @retval others The pointer to the new client id.
24 Dhcp6GenerateClientId (
25 IN EFI_SIMPLE_NETWORK_MODE
*Mode
36 // Attempt to get client Id from variable to keep it constant.
37 // See details in section-9 of rfc-3315.
39 GetVariable2 (L
"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid
, (VOID
**)&Duid
, NULL
);
45 // The format of client identifier option:
47 // 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
48 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 // | OPTION_CLIENTID | option-len |
50 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 // . (variable length) .
55 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 // If System UUID is found from SMBIOS Table, use DUID-UUID type.
61 if ((PcdGet8 (PcdDhcp6UidType
) == Dhcp6DuidTypeUuid
) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid
)) && !CompareGuid (&Uuid
, &gZeroGuid
)) {
64 // The format of DUID-UUID:
66 // 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
67 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68 // | DUID-Type (4) | UUID (128 bits) |
69 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
72 // | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
77 // sizeof (option-len + Duid-type + UUID-size) = 20 bytes
79 Duid
= AllocateZeroPool (2 + 2 + sizeof (EFI_GUID
));
85 // sizeof (Duid-type + UUID-size) = 18 bytes
87 Duid
->Length
= (UINT16
) (18);
90 // Set the Duid-type and copy UUID.
92 WriteUnaligned16 ((UINT16
*) (Duid
->Duid
), HTONS (Dhcp6DuidTypeUuid
));
94 CopyMem (Duid
->Duid
+ 2, &Uuid
, sizeof(EFI_GUID
));
100 // The format of DUID-LLT:
102 // 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
103 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 // | Duid type (1) | hardware type (16 bits) |
105 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 // | time (32 bits) |
107 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109 // . link-layer address (variable length) .
111 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.
117 gRT
->GetTime (&Time
, NULL
);
120 ((((UINT32
)(Time
.Year
- 2000) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) *
126 // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes
128 Duid
= AllocateZeroPool (10 + Mode
->HwAddressSize
);
134 // sizeof (Duid-type + hardware-type + time) = 8 bytes
136 Duid
->Length
= (UINT16
) (Mode
->HwAddressSize
+ 8);
139 // Set the Duid-type, hardware-type, time and copy the hardware address.
141 WriteUnaligned16 ((UINT16
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
)), HTONS (Dhcp6DuidTypeLlt
));
142 WriteUnaligned16 ((UINT16
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 2), HTONS (NET_IFTYPE_ETHERNET
));
143 WriteUnaligned32 ((UINT32
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 4), HTONL (Stamp
));
145 CopyMem (Duid
->Duid
+ 8, &Mode
->CurrentAddress
, Mode
->HwAddressSize
);
148 Status
= gRT
->SetVariable (
150 &gEfiDhcp6ServiceBindingProtocolGuid
,
151 (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
),
155 if (EFI_ERROR (Status
)) {
165 Copy the Dhcp6 configure data.
167 @param[in] DstCfg The pointer to the destination configure data.
168 @param[in] SorCfg The pointer to the source configure data.
170 @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully.
171 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
175 Dhcp6CopyConfigData (
176 IN EFI_DHCP6_CONFIG_DATA
*DstCfg
,
177 IN EFI_DHCP6_CONFIG_DATA
*SorCfg
181 UINTN OptionListSize
;
184 CopyMem (DstCfg
, SorCfg
, sizeof (EFI_DHCP6_CONFIG_DATA
));
187 // Allocate another buffer for solicitretransmission, and copy it.
189 if (SorCfg
->SolicitRetransmission
!= NULL
) {
191 DstCfg
->SolicitRetransmission
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
193 if (DstCfg
->SolicitRetransmission
== NULL
) {
195 // Error will be handled out of this function.
197 return EFI_OUT_OF_RESOURCES
;
201 DstCfg
->SolicitRetransmission
,
202 SorCfg
->SolicitRetransmission
,
203 sizeof (EFI_DHCP6_RETRANSMISSION
)
207 if (SorCfg
->OptionList
!= NULL
&& SorCfg
->OptionCount
!= 0) {
209 OptionListSize
= SorCfg
->OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*);
210 DstCfg
->OptionList
= AllocateZeroPool (OptionListSize
);
212 if (DstCfg
->OptionList
== NULL
) {
214 // Error will be handled out of this function.
216 return EFI_OUT_OF_RESOURCES
;
219 for (Index
= 0; Index
< SorCfg
->OptionCount
; Index
++) {
221 OptionSize
= NTOHS (SorCfg
->OptionList
[Index
]->OpLen
) + 4;
222 DstCfg
->OptionList
[Index
] = AllocateZeroPool (OptionSize
);
224 if (DstCfg
->OptionList
[Index
] == NULL
) {
226 // Error will be handled out of this function.
228 return EFI_OUT_OF_RESOURCES
;
232 DstCfg
->OptionList
[Index
],
233 SorCfg
->OptionList
[Index
],
244 Clean up the configure data.
246 @param[in, out] CfgData The pointer to the configure data.
250 Dhcp6CleanupConfigData (
251 IN OUT EFI_DHCP6_CONFIG_DATA
*CfgData
256 ASSERT (CfgData
!= NULL
);
258 // Clean up all fields in config data including the reference buffers, but do
259 // not free the config data buffer itself.
261 if (CfgData
->OptionList
!= NULL
) {
262 for (Index
= 0; Index
< CfgData
->OptionCount
; Index
++) {
263 if (CfgData
->OptionList
[Index
] != NULL
) {
264 FreePool (CfgData
->OptionList
[Index
]);
267 FreePool (CfgData
->OptionList
);
270 if (CfgData
->SolicitRetransmission
!= NULL
) {
271 FreePool (CfgData
->SolicitRetransmission
);
274 ZeroMem (CfgData
, sizeof (EFI_DHCP6_CONFIG_DATA
));
279 Clean up the mode data.
281 @param[in, out] ModeData The pointer to the mode data.
285 Dhcp6CleanupModeData (
286 IN OUT EFI_DHCP6_MODE_DATA
*ModeData
289 ASSERT (ModeData
!= NULL
);
291 // Clean up all fields in mode data including the reference buffers, but do
292 // not free the mode data buffer itself.
294 if (ModeData
->ClientId
!= NULL
) {
295 FreePool (ModeData
->ClientId
);
298 if (ModeData
->Ia
!= NULL
) {
300 if (ModeData
->Ia
->ReplyPacket
!= NULL
) {
301 FreePool (ModeData
->Ia
->ReplyPacket
);
303 FreePool (ModeData
->Ia
);
306 ZeroMem (ModeData
, sizeof (EFI_DHCP6_MODE_DATA
));
311 Calculate the expire time by the algorithm defined in rfc.
313 @param[in] Base The base value of the time.
314 @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time.
315 @param[in] NeedSigned If TRUE, the the signed factor is needed.
317 @return Expire The calculated result for the new expire time.
321 Dhcp6CalculateExpireTime (
323 IN BOOLEAN IsFirstRt
,
324 IN BOOLEAN NeedSigned
333 // Take the 10bits of microsecond in system time as a uniform distribution.
334 // Take the 10th bit as a flag to determine it's signed or not.
336 gRT
->GetTime (&Time
, NULL
);
337 Seed
= ((Time
.Nanosecond
>> 10) & DHCP6_10_BIT_MASK
);
338 Signed
= (BOOLEAN
) ((((Time
.Nanosecond
>> 9) & 0x01) != 0) ? TRUE
: FALSE
);
339 Signed
= (BOOLEAN
) (NeedSigned
? Signed
: FALSE
);
342 // Calculate expire by the following algo:
343 // 1. base + base * (-0.1 ~ 0) for the first solicit
344 // 2. base + base * (-0.1 ~ 0.1) for the first other messages
345 // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages
346 // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout
348 // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).
350 if (IsFirstRt
&& Signed
) {
352 Expire
= Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
354 } else if (IsFirstRt
&& !Signed
) {
356 Expire
= Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
358 } else if (!IsFirstRt
&& Signed
) {
360 Expire
= 2 * Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
364 Expire
= 2 * Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
367 Expire
= (Expire
!= 0) ? Expire
: 1;
374 Calculate the lease time by the algorithm defined in rfc.
376 @param[in] IaCb The pointer to the Ia control block.
380 Dhcp6CalculateLeaseTime (
388 ASSERT (IaCb
->Ia
->IaAddressCount
> 0);
390 MinLt
= (UINT32
) (-1);
394 // Calculate minlt as min of all valid life time, and maxlt as max of all
397 for (Index
= 0; Index
< IaCb
->Ia
->IaAddressCount
; Index
++) {
398 MinLt
= MIN (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
399 MaxLt
= MAX (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
403 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
406 IaCb
->T1
= (IaCb
->T1
!= 0) ? IaCb
->T1
: (UINT32
)(MinLt
* 5 / 10);
407 IaCb
->T2
= (IaCb
->T2
!= 0) ? IaCb
->T2
: (UINT32
)(MinLt
* 8 / 10);
408 IaCb
->AllExpireTime
= MaxLt
;
414 Check whether the addresses are all included by the configured Ia.
416 @param[in] Ia The pointer to the Ia.
417 @param[in] AddressCount The number of addresses.
418 @param[in] Addresses The pointer to the addresses buffer.
420 @retval EFI_SUCCESS The addresses are all included by the configured IA.
421 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.
427 IN UINT32 AddressCount
,
428 IN EFI_IPv6_ADDRESS
*Addresses
436 // Check whether the addresses are all included by the configured IA. And it
437 // will return success if address count is zero, which means all addresses.
439 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
443 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
447 &Ia
->IaAddress
[Index2
],
448 sizeof (EFI_IPv6_ADDRESS
)
457 return EFI_NOT_FOUND
;
466 Deprive the addresses from current Ia, and generate another eliminated Ia.
468 @param[in] Ia The pointer to the Ia.
469 @param[in] AddressCount The number of addresses.
470 @param[in] Addresses The pointer to the addresses buffer.
472 @retval NULL If it failed to generate the deprived Ia.
473 @retval others The pointer to the deprived Ia.
477 Dhcp6DepriveAddress (
479 IN UINT32 AddressCount
,
480 IN EFI_IPv6_ADDRESS
*Addresses
483 EFI_DHCP6_IA
*IaCopy
;
489 if (AddressCount
== 0) {
491 // It means release all Ia addresses if address count is zero.
493 AddressCount
= Ia
->IaAddressCount
;
496 ASSERT (AddressCount
!= 0);
498 IaCopySize
= sizeof (EFI_DHCP6_IA
) + (AddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
499 IaCopy
= AllocateZeroPool (IaCopySize
);
501 if (IaCopy
== NULL
) {
505 if (AddressCount
== Ia
->IaAddressCount
) {
507 // If release all Ia addresses, just copy the configured Ia and then set
508 // its address count as zero.
509 // We may decline/release part of addresses at the begining. So it's a
510 // forwarding step to update address infor for decline/release, while the
511 // other infor such as Ia state will be updated when receiving reply.
513 CopyMem (IaCopy
, Ia
, IaCopySize
);
514 Ia
->IaAddressCount
= 0;
518 CopyMem (IaCopy
, Ia
, sizeof (EFI_DHCP6_IA
));
521 // Move the addresses from the Ia of instance to the deprived Ia.
523 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
527 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
531 &Ia
->IaAddress
[Index2
],
532 sizeof (EFI_IPv6_ADDRESS
)
535 // Copy the deprived address to the copy of Ia
538 &IaCopy
->IaAddress
[Index1
],
539 &Ia
->IaAddress
[Index2
],
540 sizeof (EFI_DHCP6_IA_ADDRESS
)
543 // Delete the deprived address from the instance Ia
545 if (Index2
+ 1 < Ia
->IaAddressCount
) {
547 &Ia
->IaAddress
[Index2
],
548 &Ia
->IaAddress
[Index2
+ 1],
549 (Ia
->IaAddressCount
- Index2
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
)
556 ASSERT (Found
== TRUE
);
559 Ia
->IaAddressCount
-= AddressCount
;
560 IaCopy
->IaAddressCount
= AddressCount
;
567 The dummy ext buffer free callback routine.
569 @param[in] Arg The pointer to the parameter.
582 The callback routine once message transmitted.
584 @param[in] Wrap The pointer to the received net buffer.
585 @param[in] EndPoint The pointer to the udp end point.
586 @param[in] IoStatus The return status from udp io.
587 @param[in] Context The opaque parameter to the function.
594 IN UDP_END_POINT
*EndPoint
,
595 IN EFI_STATUS IoStatus
,
604 Append the option to Buf, and move Buf to the end.
606 @param[in, out] Buf The pointer to the buffer.
607 @param[in] OptType The option type.
608 @param[in] OptLen The length of option contents.
609 @param[in] Data The pointer to the option content.
611 @return Buf The position to append the next option.
623 // The format of Dhcp6 option:
625 // 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
626 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
627 // | option-code | option-len (option data) |
628 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
630 // | (option-len octets) |
631 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
634 ASSERT (OptLen
!= 0);
636 WriteUnaligned16 ((UINT16
*) Buf
, OptType
);
638 WriteUnaligned16 ((UINT16
*) Buf
, OptLen
);
640 CopyMem (Buf
, Data
, NTOHS (OptLen
));
641 Buf
+= NTOHS (OptLen
);
647 Append the appointed IA Address option to Buf, and move Buf to the end.
649 @param[in, out] Buf The pointer to the position to append.
650 @param[in] IaAddr The pointer to the IA Address.
651 @param[in] MessageType Message type of DHCP6 package.
653 @return Buf The position to append the next option.
657 Dhcp6AppendIaAddrOption (
659 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
660 IN UINT32 MessageType
664 // The format of the IA Address option is:
667 // 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
668 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
669 // | OPTION_IAADDR | option-len |
670 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676 // | preferred-lifetime |
677 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678 // | valid-lifetime |
679 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
681 // . IAaddr-options .
683 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
686 // Fill the value of Ia Address option type
688 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Dhcp6OptIaAddr
));
691 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS
)));
694 CopyMem (Buf
, &IaAddr
->IpAddress
, sizeof(EFI_IPv6_ADDRESS
));
695 Buf
+= sizeof(EFI_IPv6_ADDRESS
);
698 // Fill the value of preferred-lifetime and valid-lifetime.
699 // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields
700 // should set to 0 when initiate a Confirm message.
702 if (MessageType
!= Dhcp6MsgConfirm
) {
703 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (IaAddr
->PreferredLifetime
));
707 if (MessageType
!= Dhcp6MsgConfirm
) {
708 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (IaAddr
->ValidLifetime
));
717 Append the appointed Ia option to Buf, and move Buf to the end.
719 @param[in, out] Buf The pointer to the position to append.
720 @param[in] Ia The pointer to the Ia.
721 @param[in] T1 The time of T1.
722 @param[in] T2 The time of T2.
723 @param[in] MessageType Message type of DHCP6 package.
725 @return Buf The position to append the next Ia option.
729 Dhcp6AppendIaOption (
734 IN UINT32 MessageType
742 // The format of IA_NA and IA_TA option:
744 // 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
745 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
746 // | OPTION_IA_NA | option-len |
747 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748 // | IAID (4 octets) |
749 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
750 // | T1 (only for IA_NA) |
751 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
752 // | T2 (only for IA_NA) |
753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
755 // . IA_NA-options/IA_TA-options .
757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // Fill the value of Ia option type
763 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Ia
->Descriptor
.Type
));
767 // Fill the len of Ia option later, keep the pointer first
769 Len
= (UINT16
*) Buf
;
773 // Fill the value of iaid
775 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (Ia
->Descriptor
.IaId
));
779 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
781 if (Ia
->Descriptor
.Type
== Dhcp6OptIana
) {
782 WriteUnaligned32 ((UINT32
*) Buf
, HTONL ((T1
!= 0) ? T1
: 0xffffffff));
784 WriteUnaligned32 ((UINT32
*) Buf
, HTONL ((T2
!= 0) ? T2
: 0xffffffff));
789 // Fill all the addresses belong to the Ia
791 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
792 AddrOpt
= (UINT8
*) Ia
->IaAddress
+ Index
* sizeof (EFI_DHCP6_IA_ADDRESS
);
793 Buf
= Dhcp6AppendIaAddrOption (Buf
, (EFI_DHCP6_IA_ADDRESS
*) AddrOpt
, MessageType
);
797 // Fill the value of Ia option length
799 *Len
= HTONS ((UINT16
) (Buf
- (UINT8
*) Len
- 2));
805 Append the appointed Elapsed time option to Buf, and move Buf to the end.
807 @param[in, out] Buf The pointer to the position to append.
808 @param[in] Instance The pointer to the Dhcp6 instance.
809 @param[out] Elapsed The pointer to the elapsed time value in
810 the generated packet.
812 @return Buf The position to append the next Ia option.
816 Dhcp6AppendETOption (
818 IN DHCP6_INSTANCE
*Instance
,
823 // The format of elapsed time option:
825 // 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
826 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
827 // | OPTION_ELAPSED_TIME | option-len |
828 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
830 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
834 // Fill the value of elapsed-time option type.
836 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Dhcp6OptElapsedTime
));
840 // Fill the len of elapsed-time option, which is fixed.
842 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(2));
846 // Fill in elapsed time value with 0 value for now. The actual value is
847 // filled in later just before the packet is transmitted.
849 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(0));
850 *Elapsed
= (UINT16
*) Buf
;
857 Set the elapsed time based on the given instance and the pointer to the
860 @param[in] Elapsed The pointer to the position to append.
861 @param[in] Instance The pointer to the Dhcp6 instance.
867 IN DHCP6_INSTANCE
*Instance
872 UINT64 ElapsedTimeValue
;
875 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
877 gRT
->GetTime (&Time
, NULL
);
878 CurrentStamp
= MultU64x32 (
879 ((((UINT32
)(Time
.Year
- 2000) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) * 60 + Time
.Second
,
888 // Sentinel value of 0 means that this is the first DHCP packet that we are
889 // sending and that we need to initialize the value. First DHCP message
890 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
892 if (Instance
->StartTime
== 0) {
893 ElapsedTimeValue
= 0;
894 Instance
->StartTime
= CurrentStamp
;
896 ElapsedTimeValue
= CurrentStamp
- Instance
->StartTime
;
899 // If elapsed time cannot fit in two bytes, set it to 0xffff.
901 if (ElapsedTimeValue
> 0xffff) {
902 ElapsedTimeValue
= 0xffff;
905 WriteUnaligned16 (Elapsed
, HTONS((UINT16
) ElapsedTimeValue
));
910 Seek the address of the first byte of the option header.
912 @param[in] Buf The pointer to the buffer.
913 @param[in] SeekLen The length to seek.
914 @param[in] OptType The option type.
916 @retval NULL If it failed to seek the option.
917 @retval others The position to the option.
936 // The format of Dhcp6 option refers to Dhcp6AppendOption().
938 while (Cursor
< Buf
+ SeekLen
) {
939 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
940 if (OpCode
== HTONS (OptType
)) {
944 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
945 Cursor
+= (DataLen
+ 4);
953 Seek the address of the first byte of the Ia option header.
955 @param[in] Buf The pointer to the buffer.
956 @param[in] SeekLen The length to seek.
957 @param[in] IaDesc The pointer to the Ia descriptor.
959 @retval NULL If it failed to seek the Ia option.
960 @retval others The position to the Ia option.
967 IN EFI_DHCP6_IA_DESCRIPTOR
*IaDesc
977 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
982 while (Cursor
< Buf
+ SeekLen
) {
983 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
984 IaId
= ReadUnaligned32 ((UINT32
*) (Cursor
+ 4));
985 if (OpCode
== HTONS (IaDesc
->Type
) && IaId
== HTONL (IaDesc
->IaId
)) {
989 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
990 Cursor
+= (DataLen
+ 4);
997 Check whether the incoming IPv6 address in IaAddr is one of the maintained
998 addresses in the IA control blcok.
1000 @param[in] IaAddr The pointer to the IA Address to be checked.
1001 @param[in] CurrentIa The pointer to the IA in IA control block.
1003 @retval TRUE Yes, this Address is already in IA control block.
1004 @retval FALSE No, this Address is NOT in IA control block.
1008 Dhcp6AddrIsInCurrentIa (
1009 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
1010 IN EFI_DHCP6_IA
*CurrentIa
1015 ASSERT (IaAddr
!= NULL
&& CurrentIa
!= NULL
);
1017 for (Index
= 0; Index
< CurrentIa
->IaAddressCount
; Index
++) {
1018 if (EFI_IP6_EQUAL(&IaAddr
->IpAddress
, &CurrentIa
->IaAddress
[Index
].IpAddress
)) {
1026 Parse the address option and update the address infomation.
1028 @param[in] CurrentIa The pointer to the Ia Address in control blcok.
1029 @param[in] IaInnerOpt The pointer to the buffer.
1030 @param[in] IaInnerLen The length to parse.
1031 @param[out] AddrNum The number of addresses.
1032 @param[in, out] AddrBuf The pointer to the address buffer.
1036 Dhcp6ParseAddrOption (
1037 IN EFI_DHCP6_IA
*CurrentIa
,
1038 IN UINT8
*IaInnerOpt
,
1039 IN UINT16 IaInnerLen
,
1040 OUT UINT32
*AddrNum
,
1041 IN OUT EFI_DHCP6_IA_ADDRESS
*AddrBuf
1049 EFI_DHCP6_IA_ADDRESS
*IaAddr
;
1052 // The format of the IA Address option:
1054 // 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
1055 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1056 // | OPTION_IAADDR | option-len |
1057 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1062 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1063 // | preferred-lifetime |
1064 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1065 // | valid-lifetime |
1066 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1068 // . IAaddr-options .
1070 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1076 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
1077 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner
1078 // options to the addrbuf.
1081 Cursor
= IaInnerOpt
;
1084 while (Cursor
< IaInnerOpt
+ IaInnerLen
) {
1086 // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option
1087 // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.
1089 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
1090 PreferredLt
= NTOHL (ReadUnaligned32 ((UINT32
*) (Cursor
+ 20)));
1091 ValidLt
= NTOHL (ReadUnaligned32 ((UINT32
*) (Cursor
+ 24)));
1092 IaAddr
= (EFI_DHCP6_IA_ADDRESS
*) (Cursor
+ 4);
1093 if (OpCode
== HTONS (Dhcp6OptIaAddr
) && ValidLt
>= PreferredLt
&&
1094 (Dhcp6AddrIsInCurrentIa(IaAddr
, CurrentIa
) || ValidLt
!=0)) {
1095 if (AddrBuf
!= NULL
) {
1096 CopyMem (AddrBuf
, IaAddr
, sizeof (EFI_DHCP6_IA_ADDRESS
));
1097 AddrBuf
->PreferredLifetime
= PreferredLt
;
1098 AddrBuf
->ValidLifetime
= ValidLt
;
1099 AddrBuf
= (EFI_DHCP6_IA_ADDRESS
*) ((UINT8
*) AddrBuf
+ sizeof (EFI_DHCP6_IA_ADDRESS
));
1103 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
1104 Cursor
+= (DataLen
+ 4);
1110 Create a control blcok for the Ia according to the corresponding options.
1112 @param[in] Instance The pointer to DHCP6 Instance.
1113 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.
1114 @param[in] IaInnerLen The length of all the inner options in the Ia option.
1115 @param[in] T1 T1 time in the Ia option.
1116 @param[in] T2 T2 time in the Ia option.
1118 @retval EFI_NOT_FOUND No valid IA option is found.
1119 @retval EFI_SUCCESS Create an IA control block successfully.
1120 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1121 @retval EFI_DEVICE_ERROR An unexpected error.
1126 IN DHCP6_INSTANCE
*Instance
,
1127 IN UINT8
*IaInnerOpt
,
1128 IN UINT16 IaInnerLen
,
1137 if (Instance
->IaCb
.Ia
== NULL
) {
1138 return EFI_DEVICE_ERROR
;
1142 // Calculate the number of addresses for this Ia, excluding the addresses with
1143 // the value 0 of valid lifetime.
1145 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, NULL
);
1148 return EFI_NOT_FOUND
;
1152 // Allocate for new IA.
1154 IaSize
= sizeof (EFI_DHCP6_IA
) + (AddrNum
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1155 Ia
= AllocateZeroPool (IaSize
);
1158 return EFI_OUT_OF_RESOURCES
;
1162 // Fill up this new IA fields.
1164 Ia
->State
= Instance
->IaCb
.Ia
->State
;
1165 Ia
->IaAddressCount
= AddrNum
;
1166 CopyMem (&Ia
->Descriptor
, &Instance
->Config
->IaDescriptor
, sizeof (EFI_DHCP6_IA_DESCRIPTOR
));
1167 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, Ia
->IaAddress
);
1170 // Free original IA resource.
1172 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
1173 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
1175 FreePool (Instance
->IaCb
.Ia
);
1178 ZeroMem (&Instance
->IaCb
, sizeof (DHCP6_IA_CB
));
1181 // Update IaCb to use new IA.
1183 Instance
->IaCb
.Ia
= Ia
;
1187 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
1189 Instance
->IaCb
.T1
= T1
;
1190 Instance
->IaCb
.T2
= T2
;
1191 Dhcp6CalculateLeaseTime (&Instance
->IaCb
);
1198 Cache the current IA configuration information.
1200 @param[in] Instance The pointer to DHCP6 Instance.
1202 @retval EFI_SUCCESS Cache the current IA successfully.
1203 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1208 IN DHCP6_INSTANCE
*Instance
1214 Ia
= Instance
->IaCb
.Ia
;
1216 if ((Instance
->CacheIa
== NULL
) && (Ia
!= NULL
)) {
1218 // Cache the current IA.
1220 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1222 Instance
->CacheIa
= AllocateZeroPool (IaSize
);
1223 if (Instance
->CacheIa
== NULL
) {
1224 return EFI_OUT_OF_RESOURCES
;
1226 CopyMem (Instance
->CacheIa
, Ia
, IaSize
);
1232 Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
1234 @param[in] Instance The pointer to DHCP6 instance.
1238 Dhcp6AppendCacheIa (
1239 IN DHCP6_INSTANCE
*Instance
1247 EFI_DHCP6_IA
*NewIa
;
1248 EFI_DHCP6_IA
*CacheIa
;
1250 Ia
= Instance
->IaCb
.Ia
;
1251 CacheIa
= Instance
->CacheIa
;
1253 if ((CacheIa
!= NULL
) && (CacheIa
->IaAddressCount
!= 0)) {
1255 // There are old addresses existing. Merge with current addresses.
1257 NewIaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
+ CacheIa
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1258 NewIa
= AllocateZeroPool (NewIaSize
);
1259 if (NewIa
== NULL
) {
1263 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1264 CopyMem (NewIa
, Ia
, IaSize
);
1267 // Clear old address.ValidLifetime
1269 for (Index
= 0; Index
< CacheIa
->IaAddressCount
; Index
++) {
1270 CacheIa
->IaAddress
[Index
].ValidLifetime
= 0;
1273 NewIa
->IaAddressCount
+= CacheIa
->IaAddressCount
;
1274 Ptr
= (UINT8
*)&NewIa
->IaAddress
[Ia
->IaAddressCount
];
1275 CopyMem (Ptr
, CacheIa
->IaAddress
, CacheIa
->IaAddressCount
* sizeof (EFI_DHCP6_IA_ADDRESS
));
1278 // Migrate to the NewIa and free previous.
1280 FreePool (Instance
->CacheIa
);
1281 FreePool (Instance
->IaCb
.Ia
);
1282 Instance
->CacheIa
= NULL
;
1283 Instance
->IaCb
.Ia
= NewIa
;
1288 Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.
1290 @param[in] Ip6Cfg The pointer to Ip6 config protocol.
1291 @param[out] TimeOut The time out value in 100ns units.
1293 @retval EFI_INVALID_PARAMETER Input parameters are invalid.
1294 @retval EFI_SUCCESS Calculate the time out value successfully.
1297 Dhcp6GetMappingTimeOut (
1298 IN EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
,
1304 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
1306 if (Ip6Cfg
== NULL
|| TimeOut
== NULL
) {
1307 return EFI_INVALID_PARAMETER
;
1310 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
1311 Status
= Ip6Cfg
->GetData (
1313 Ip6ConfigDataTypeDupAddrDetectTransmits
,
1317 if (EFI_ERROR (Status
)) {
1321 *TimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ DHCP6_DAD_ADDITIONAL_DELAY
;