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"
14 Generate client Duid in the format of Duid-llt.
16 @param[in] Mode The pointer to the mode of SNP.
18 @retval NULL If it failed to generate a client Id.
19 @retval others The pointer to the new client id.
23 Dhcp6GenerateClientId (
24 IN EFI_SIMPLE_NETWORK_MODE
*Mode
34 // Attempt to get client Id from variable to keep it constant.
35 // See details in section-9 of rfc-3315.
37 GetVariable2 (L
"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid
, (VOID
**)&Duid
, NULL
);
43 // The format of client identifier option:
45 // 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
46 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 // | OPTION_CLIENTID | option-len |
48 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 // . (variable length) .
53 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 // If System UUID is found from SMBIOS Table, use DUID-UUID type.
59 if ((PcdGet8 (PcdDhcp6UidType
) == Dhcp6DuidTypeUuid
) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid
)) && !CompareGuid (&Uuid
, &gZeroGuid
)) {
62 // The format of DUID-UUID:
64 // 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
65 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 // | DUID-Type (4) | UUID (128 bits) |
67 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
70 // | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
75 // sizeof (option-len + Duid-type + UUID-size) = 20 bytes
77 Duid
= AllocateZeroPool (2 + 2 + sizeof (EFI_GUID
));
83 // sizeof (Duid-type + UUID-size) = 18 bytes
85 Duid
->Length
= (UINT16
)(18);
88 // Set the Duid-type and copy UUID.
90 WriteUnaligned16 ((UINT16
*)(Duid
->Duid
), HTONS (Dhcp6DuidTypeUuid
));
92 CopyMem (Duid
->Duid
+ 2, &Uuid
, sizeof (EFI_GUID
));
96 // The format of DUID-LLT:
98 // 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
99 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 // | Duid type (1) | hardware type (16 bits) |
101 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 // | time (32 bits) |
103 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 // . link-layer address (variable length) .
107 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.
113 gRT
->GetTime (&Time
, NULL
);
116 ((((UINT32
)(Time
.Year
- 2000) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) *
122 // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes
124 Duid
= AllocateZeroPool (10 + Mode
->HwAddressSize
);
130 // sizeof (Duid-type + hardware-type + time) = 8 bytes
132 Duid
->Length
= (UINT16
)(Mode
->HwAddressSize
+ 8);
135 // Set the Duid-type, hardware-type, time and copy the hardware address.
137 WriteUnaligned16 ((UINT16
*)((UINT8
*)Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
)), HTONS (Dhcp6DuidTypeLlt
));
138 WriteUnaligned16 ((UINT16
*)((UINT8
*)Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 2), HTONS (NET_IFTYPE_ETHERNET
));
139 WriteUnaligned32 ((UINT32
*)((UINT8
*)Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 4), HTONL (Stamp
));
141 CopyMem (Duid
->Duid
+ 8, &Mode
->CurrentAddress
, Mode
->HwAddressSize
);
144 Status
= gRT
->SetVariable (
146 &gEfiDhcp6ServiceBindingProtocolGuid
,
147 (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
),
151 if (EFI_ERROR (Status
)) {
160 Copy the Dhcp6 configure data.
162 @param[in] DstCfg The pointer to the destination configure data.
163 @param[in] SorCfg The pointer to the source configure data.
165 @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully.
166 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
170 Dhcp6CopyConfigData (
171 IN EFI_DHCP6_CONFIG_DATA
*DstCfg
,
172 IN EFI_DHCP6_CONFIG_DATA
*SorCfg
176 UINTN OptionListSize
;
179 CopyMem (DstCfg
, SorCfg
, sizeof (EFI_DHCP6_CONFIG_DATA
));
182 // Allocate another buffer for solicitretransmission, and copy it.
184 if (SorCfg
->SolicitRetransmission
!= NULL
) {
185 DstCfg
->SolicitRetransmission
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
187 if (DstCfg
->SolicitRetransmission
== NULL
) {
189 // Error will be handled out of this function.
191 return EFI_OUT_OF_RESOURCES
;
195 DstCfg
->SolicitRetransmission
,
196 SorCfg
->SolicitRetransmission
,
197 sizeof (EFI_DHCP6_RETRANSMISSION
)
201 if ((SorCfg
->OptionList
!= NULL
) && (SorCfg
->OptionCount
!= 0)) {
202 OptionListSize
= SorCfg
->OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*);
203 DstCfg
->OptionList
= AllocateZeroPool (OptionListSize
);
205 if (DstCfg
->OptionList
== NULL
) {
207 // Error will be handled out of this function.
209 return EFI_OUT_OF_RESOURCES
;
212 for (Index
= 0; Index
< SorCfg
->OptionCount
; Index
++) {
213 OptionSize
= NTOHS (SorCfg
->OptionList
[Index
]->OpLen
) + 4;
214 DstCfg
->OptionList
[Index
] = AllocateZeroPool (OptionSize
);
216 if (DstCfg
->OptionList
[Index
] == NULL
) {
218 // Error will be handled out of this function.
220 return EFI_OUT_OF_RESOURCES
;
224 DstCfg
->OptionList
[Index
],
225 SorCfg
->OptionList
[Index
],
235 Clean up the configure data.
237 @param[in, out] CfgData The pointer to the configure data.
241 Dhcp6CleanupConfigData (
242 IN OUT EFI_DHCP6_CONFIG_DATA
*CfgData
247 ASSERT (CfgData
!= NULL
);
249 // Clean up all fields in config data including the reference buffers, but do
250 // not free the config data buffer itself.
252 if (CfgData
->OptionList
!= NULL
) {
253 for (Index
= 0; Index
< CfgData
->OptionCount
; Index
++) {
254 if (CfgData
->OptionList
[Index
] != NULL
) {
255 FreePool (CfgData
->OptionList
[Index
]);
259 FreePool (CfgData
->OptionList
);
262 if (CfgData
->SolicitRetransmission
!= NULL
) {
263 FreePool (CfgData
->SolicitRetransmission
);
266 ZeroMem (CfgData
, sizeof (EFI_DHCP6_CONFIG_DATA
));
270 Clean up the mode data.
272 @param[in, out] ModeData The pointer to the mode data.
276 Dhcp6CleanupModeData (
277 IN OUT EFI_DHCP6_MODE_DATA
*ModeData
280 ASSERT (ModeData
!= NULL
);
282 // Clean up all fields in mode data including the reference buffers, but do
283 // not free the mode data buffer itself.
285 if (ModeData
->ClientId
!= NULL
) {
286 FreePool (ModeData
->ClientId
);
289 if (ModeData
->Ia
!= NULL
) {
290 if (ModeData
->Ia
->ReplyPacket
!= NULL
) {
291 FreePool (ModeData
->Ia
->ReplyPacket
);
294 FreePool (ModeData
->Ia
);
297 ZeroMem (ModeData
, sizeof (EFI_DHCP6_MODE_DATA
));
301 Calculate the expire time by the algorithm defined in rfc.
303 @param[in] Base The base value of the time.
304 @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time.
305 @param[in] NeedSigned If TRUE, the signed factor is needed.
307 @return Expire The calculated result for the new expire time.
311 Dhcp6CalculateExpireTime (
313 IN BOOLEAN IsFirstRt
,
314 IN BOOLEAN NeedSigned
323 // Take the 10bits of microsecond in system time as a uniform distribution.
324 // Take the 10th bit as a flag to determine it's signed or not.
326 gRT
->GetTime (&Time
, NULL
);
327 Seed
= ((Time
.Nanosecond
>> 10) & DHCP6_10_BIT_MASK
);
328 Signed
= (BOOLEAN
)((((Time
.Nanosecond
>> 9) & 0x01) != 0) ? TRUE
: FALSE
);
329 Signed
= (BOOLEAN
)(NeedSigned
? Signed
: FALSE
);
332 // Calculate expire by the following algo:
333 // 1. base + base * (-0.1 ~ 0) for the first solicit
334 // 2. base + base * (-0.1 ~ 0.1) for the first other messages
335 // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages
336 // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout
338 // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).
340 if (IsFirstRt
&& Signed
) {
341 Expire
= Base
- (UINT32
)(Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
342 } else if (IsFirstRt
&& !Signed
) {
343 Expire
= Base
+ (UINT32
)(Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
344 } else if (!IsFirstRt
&& Signed
) {
345 Expire
= 2 * Base
- (UINT32
)(Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
347 Expire
= 2 * Base
+ (UINT32
)(Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
350 Expire
= (Expire
!= 0) ? Expire
: 1;
356 Calculate the lease time by the algorithm defined in rfc.
358 @param[in] IaCb The pointer to the Ia control block.
362 Dhcp6CalculateLeaseTime (
370 ASSERT (IaCb
->Ia
->IaAddressCount
> 0);
372 MinLt
= (UINT32
)(-1);
376 // Calculate minlt as min of all valid life time, and maxlt as max of all
379 for (Index
= 0; Index
< IaCb
->Ia
->IaAddressCount
; Index
++) {
380 MinLt
= MIN (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
381 MaxLt
= MAX (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
385 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
388 IaCb
->T1
= (IaCb
->T1
!= 0) ? IaCb
->T1
: (UINT32
)(MinLt
* 5 / 10);
389 IaCb
->T2
= (IaCb
->T2
!= 0) ? IaCb
->T2
: (UINT32
)(MinLt
* 8 / 10);
390 IaCb
->AllExpireTime
= MaxLt
;
395 Check whether the addresses are all included by the configured Ia.
397 @param[in] Ia The pointer to the Ia.
398 @param[in] AddressCount The number of addresses.
399 @param[in] Addresses The pointer to the addresses buffer.
401 @retval EFI_SUCCESS The addresses are all included by the configured IA.
402 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.
408 IN UINT32 AddressCount
,
409 IN EFI_IPv6_ADDRESS
*Addresses
417 // Check whether the addresses are all included by the configured IA. And it
418 // will return success if address count is zero, which means all addresses.
420 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
423 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
426 &Ia
->IaAddress
[Index2
],
427 sizeof (EFI_IPv6_ADDRESS
)
436 return EFI_NOT_FOUND
;
444 Deprive the addresses from current Ia, and generate another eliminated Ia.
446 @param[in] Ia The pointer to the Ia.
447 @param[in] AddressCount The number of addresses.
448 @param[in] Addresses The pointer to the addresses buffer.
450 @retval NULL If it failed to generate the deprived Ia.
451 @retval others The pointer to the deprived Ia.
455 Dhcp6DepriveAddress (
457 IN UINT32 AddressCount
,
458 IN EFI_IPv6_ADDRESS
*Addresses
461 EFI_DHCP6_IA
*IaCopy
;
467 if (AddressCount
== 0) {
469 // It means release all Ia addresses if address count is zero.
471 AddressCount
= Ia
->IaAddressCount
;
474 ASSERT (AddressCount
!= 0);
476 IaCopySize
= sizeof (EFI_DHCP6_IA
) + (AddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
477 IaCopy
= AllocateZeroPool (IaCopySize
);
479 if (IaCopy
== NULL
) {
483 if (AddressCount
== Ia
->IaAddressCount
) {
485 // If release all Ia addresses, just copy the configured Ia and then set
486 // its address count as zero.
487 // We may decline/release part of addresses at the beginning. So it's a
488 // forwarding step to update address infor for decline/release, while the
489 // other infor such as Ia state will be updated when receiving reply.
491 CopyMem (IaCopy
, Ia
, IaCopySize
);
492 Ia
->IaAddressCount
= 0;
496 CopyMem (IaCopy
, Ia
, sizeof (EFI_DHCP6_IA
));
499 // Move the addresses from the Ia of instance to the deprived Ia.
501 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
504 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
507 &Ia
->IaAddress
[Index2
],
508 sizeof (EFI_IPv6_ADDRESS
)
512 // Copy the deprived address to the copy of Ia
515 &IaCopy
->IaAddress
[Index1
],
516 &Ia
->IaAddress
[Index2
],
517 sizeof (EFI_DHCP6_IA_ADDRESS
)
520 // Delete the deprived address from the instance Ia
522 if (Index2
+ 1 < Ia
->IaAddressCount
) {
524 &Ia
->IaAddress
[Index2
],
525 &Ia
->IaAddress
[Index2
+ 1],
526 (Ia
->IaAddressCount
- Index2
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
)
535 ASSERT (Found
== TRUE
);
538 Ia
->IaAddressCount
-= AddressCount
;
539 IaCopy
->IaAddressCount
= AddressCount
;
545 The dummy ext buffer free callback routine.
547 @param[in] Arg The pointer to the parameter.
559 The callback routine once message transmitted.
561 @param[in] Wrap The pointer to the received net buffer.
562 @param[in] EndPoint The pointer to the udp end point.
563 @param[in] IoStatus The return status from udp io.
564 @param[in] Context The opaque parameter to the function.
571 IN UDP_END_POINT
*EndPoint
,
572 IN EFI_STATUS IoStatus
,
580 Append the option to Buf, and move Buf to the end.
582 @param[in, out] Buf The pointer to the buffer.
583 @param[in] OptType The option type.
584 @param[in] OptLen The length of option contents.
585 @param[in] Data The pointer to the option content.
587 @return Buf The position to append the next option.
599 // The format of Dhcp6 option:
601 // 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
602 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
603 // | option-code | option-len (option data) |
604 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
606 // | (option-len octets) |
607 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610 ASSERT (OptLen
!= 0);
612 WriteUnaligned16 ((UINT16
*)Buf
, OptType
);
614 WriteUnaligned16 ((UINT16
*)Buf
, OptLen
);
616 CopyMem (Buf
, Data
, NTOHS (OptLen
));
617 Buf
+= NTOHS (OptLen
);
623 Append the appointed IA Address option to Buf, and move Buf to the end.
625 @param[in, out] Buf The pointer to the position to append.
626 @param[in] IaAddr The pointer to the IA Address.
627 @param[in] MessageType Message type of DHCP6 package.
629 @return Buf The position to append the next option.
633 Dhcp6AppendIaAddrOption (
635 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
636 IN UINT32 MessageType
639 // The format of the IA Address 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_IAADDR | option-len |
645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
650 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
651 // | preferred-lifetime |
652 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
653 // | valid-lifetime |
654 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
656 // . IAaddr-options .
658 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
661 // Fill the value of Ia Address option type
663 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (Dhcp6OptIaAddr
));
666 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS
)));
669 CopyMem (Buf
, &IaAddr
->IpAddress
, sizeof (EFI_IPv6_ADDRESS
));
670 Buf
+= sizeof (EFI_IPv6_ADDRESS
);
673 // Fill the value of preferred-lifetime and valid-lifetime.
674 // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields
675 // should set to 0 when initiate a Confirm message.
677 if (MessageType
!= Dhcp6MsgConfirm
) {
678 WriteUnaligned32 ((UINT32
*)Buf
, HTONL (IaAddr
->PreferredLifetime
));
683 if (MessageType
!= Dhcp6MsgConfirm
) {
684 WriteUnaligned32 ((UINT32
*)Buf
, HTONL (IaAddr
->ValidLifetime
));
693 Append the appointed Ia option to Buf, and move Buf to the end.
695 @param[in, out] Buf The pointer to the position to append.
696 @param[in] Ia The pointer to the Ia.
697 @param[in] T1 The time of T1.
698 @param[in] T2 The time of T2.
699 @param[in] MessageType Message type of DHCP6 package.
701 @return Buf The position to append the next Ia option.
705 Dhcp6AppendIaOption (
710 IN UINT32 MessageType
718 // The format of IA_NA and IA_TA option:
720 // 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
721 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
722 // | OPTION_IA_NA | option-len |
723 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
724 // | IAID (4 octets) |
725 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
726 // | T1 (only for IA_NA) |
727 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
728 // | T2 (only for IA_NA) |
729 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
731 // . IA_NA-options/IA_TA-options .
733 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737 // Fill the value of Ia option type
739 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (Ia
->Descriptor
.Type
));
743 // Fill the len of Ia option later, keep the pointer first
749 // Fill the value of iaid
751 WriteUnaligned32 ((UINT32
*)Buf
, HTONL (Ia
->Descriptor
.IaId
));
755 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
757 if (Ia
->Descriptor
.Type
== Dhcp6OptIana
) {
758 WriteUnaligned32 ((UINT32
*)Buf
, HTONL ((T1
!= 0) ? T1
: 0xffffffff));
760 WriteUnaligned32 ((UINT32
*)Buf
, HTONL ((T2
!= 0) ? T2
: 0xffffffff));
765 // Fill all the addresses belong to the Ia
767 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
768 AddrOpt
= (UINT8
*)Ia
->IaAddress
+ Index
* sizeof (EFI_DHCP6_IA_ADDRESS
);
769 Buf
= Dhcp6AppendIaAddrOption (Buf
, (EFI_DHCP6_IA_ADDRESS
*)AddrOpt
, MessageType
);
773 // Fill the value of Ia option length
775 *Len
= HTONS ((UINT16
)(Buf
- (UINT8
*)Len
- 2));
781 Append the appointed Elapsed time option to Buf, and move Buf to the end.
783 @param[in, out] Buf The pointer to the position to append.
784 @param[in] Instance The pointer to the Dhcp6 instance.
785 @param[out] Elapsed The pointer to the elapsed time value in
786 the generated packet.
788 @return Buf The position to append the next Ia option.
792 Dhcp6AppendETOption (
794 IN DHCP6_INSTANCE
*Instance
,
799 // The format of elapsed time option:
801 // 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
802 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
803 // | OPTION_ELAPSED_TIME | option-len |
804 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
806 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
810 // Fill the value of elapsed-time option type.
812 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (Dhcp6OptElapsedTime
));
816 // Fill the len of elapsed-time option, which is fixed.
818 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (2));
822 // Fill in elapsed time value with 0 value for now. The actual value is
823 // filled in later just before the packet is transmitted.
825 WriteUnaligned16 ((UINT16
*)Buf
, HTONS (0));
826 *Elapsed
= (UINT16
*)Buf
;
833 Set the elapsed time based on the given instance and the pointer to the
836 @param[in] Elapsed The pointer to the position to append.
837 @param[in] Instance The pointer to the Dhcp6 instance.
843 IN DHCP6_INSTANCE
*Instance
848 UINT64 ElapsedTimeValue
;
851 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
853 gRT
->GetTime (&Time
, NULL
);
854 CurrentStamp
= MultU64x32 (
855 ((((UINT32
)(Time
.Year
- 2000) * 360 + (Time
.Month
- 1) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) * 60 + Time
.Second
,
864 // Sentinel value of 0 means that this is the first DHCP packet that we are
865 // sending and that we need to initialize the value. First DHCP message
866 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
868 if (Instance
->StartTime
== 0) {
869 ElapsedTimeValue
= 0;
870 Instance
->StartTime
= CurrentStamp
;
872 ElapsedTimeValue
= CurrentStamp
- Instance
->StartTime
;
875 // If elapsed time cannot fit in two bytes, set it to 0xffff.
877 if (ElapsedTimeValue
> 0xffff) {
878 ElapsedTimeValue
= 0xffff;
882 WriteUnaligned16 (Elapsed
, HTONS ((UINT16
)ElapsedTimeValue
));
886 Seek the address of the first byte of the option header.
888 @param[in] Buf The pointer to the buffer.
889 @param[in] SeekLen The length to seek.
890 @param[in] OptType The option type.
892 @retval NULL If it failed to seek the option.
893 @retval others The position to the option.
912 // The format of Dhcp6 option refers to Dhcp6AppendOption().
914 while (Cursor
< Buf
+ SeekLen
) {
915 OpCode
= ReadUnaligned16 ((UINT16
*)Cursor
);
916 if (OpCode
== HTONS (OptType
)) {
921 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*)(Cursor
+ 2)));
922 Cursor
+= (DataLen
+ 4);
929 Seek the address of the first byte of the Ia option header.
931 @param[in] Buf The pointer to the buffer.
932 @param[in] SeekLen The length to seek.
933 @param[in] IaDesc The pointer to the Ia descriptor.
935 @retval NULL If it failed to seek the Ia option.
936 @retval others The position to the Ia option.
943 IN EFI_DHCP6_IA_DESCRIPTOR
*IaDesc
953 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
958 while (Cursor
< Buf
+ SeekLen
) {
959 OpCode
= ReadUnaligned16 ((UINT16
*)Cursor
);
960 IaId
= ReadUnaligned32 ((UINT32
*)(Cursor
+ 4));
961 if ((OpCode
== HTONS (IaDesc
->Type
)) && (IaId
== HTONL (IaDesc
->IaId
))) {
966 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*)(Cursor
+ 2)));
967 Cursor
+= (DataLen
+ 4);
974 Check whether the incoming IPv6 address in IaAddr is one of the maintained
975 addresses in the IA control block.
977 @param[in] IaAddr The pointer to the IA Address to be checked.
978 @param[in] CurrentIa The pointer to the IA in IA control block.
980 @retval TRUE Yes, this Address is already in IA control block.
981 @retval FALSE No, this Address is NOT in IA control block.
985 Dhcp6AddrIsInCurrentIa (
986 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
987 IN EFI_DHCP6_IA
*CurrentIa
992 ASSERT (IaAddr
!= NULL
&& CurrentIa
!= NULL
);
994 for (Index
= 0; Index
< CurrentIa
->IaAddressCount
; Index
++) {
995 if (EFI_IP6_EQUAL (&IaAddr
->IpAddress
, &CurrentIa
->IaAddress
[Index
].IpAddress
)) {
1004 Parse the address option and update the address information.
1006 @param[in] CurrentIa The pointer to the Ia Address in control block.
1007 @param[in] IaInnerOpt The pointer to the buffer.
1008 @param[in] IaInnerLen The length to parse.
1009 @param[out] AddrNum The number of addresses.
1010 @param[in, out] AddrBuf The pointer to the address buffer.
1014 Dhcp6ParseAddrOption (
1015 IN EFI_DHCP6_IA
*CurrentIa
,
1016 IN UINT8
*IaInnerOpt
,
1017 IN UINT16 IaInnerLen
,
1018 OUT UINT32
*AddrNum
,
1019 IN OUT EFI_DHCP6_IA_ADDRESS
*AddrBuf
1027 EFI_DHCP6_IA_ADDRESS
*IaAddr
;
1030 // The format of the IA Address option:
1032 // 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
1033 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1034 // | OPTION_IAADDR | option-len |
1035 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1040 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1041 // | preferred-lifetime |
1042 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1043 // | valid-lifetime |
1044 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1046 // . IAaddr-options .
1048 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1054 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
1055 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner
1056 // options to the addrbuf.
1059 Cursor
= IaInnerOpt
;
1062 while (Cursor
< IaInnerOpt
+ IaInnerLen
) {
1064 // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option
1065 // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.
1067 OpCode
= ReadUnaligned16 ((UINT16
*)Cursor
);
1068 PreferredLt
= NTOHL (ReadUnaligned32 ((UINT32
*)(Cursor
+ 20)));
1069 ValidLt
= NTOHL (ReadUnaligned32 ((UINT32
*)(Cursor
+ 24)));
1070 IaAddr
= (EFI_DHCP6_IA_ADDRESS
*)(Cursor
+ 4);
1071 if ((OpCode
== HTONS (Dhcp6OptIaAddr
)) && (ValidLt
>= PreferredLt
) &&
1072 (Dhcp6AddrIsInCurrentIa (IaAddr
, CurrentIa
) || (ValidLt
!= 0)))
1074 if (AddrBuf
!= NULL
) {
1075 CopyMem (AddrBuf
, IaAddr
, sizeof (EFI_DHCP6_IA_ADDRESS
));
1076 AddrBuf
->PreferredLifetime
= PreferredLt
;
1077 AddrBuf
->ValidLifetime
= ValidLt
;
1078 AddrBuf
= (EFI_DHCP6_IA_ADDRESS
*)((UINT8
*)AddrBuf
+ sizeof (EFI_DHCP6_IA_ADDRESS
));
1084 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*)(Cursor
+ 2)));
1085 Cursor
+= (DataLen
+ 4);
1090 Create a control block for the Ia according to the corresponding options.
1092 @param[in] Instance The pointer to DHCP6 Instance.
1093 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.
1094 @param[in] IaInnerLen The length of all the inner options in the Ia option.
1095 @param[in] T1 T1 time in the Ia option.
1096 @param[in] T2 T2 time in the Ia option.
1098 @retval EFI_NOT_FOUND No valid IA option is found.
1099 @retval EFI_SUCCESS Create an IA control block successfully.
1100 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1101 @retval EFI_DEVICE_ERROR An unexpected error.
1106 IN DHCP6_INSTANCE
*Instance
,
1107 IN UINT8
*IaInnerOpt
,
1108 IN UINT16 IaInnerLen
,
1117 if (Instance
->IaCb
.Ia
== NULL
) {
1118 return EFI_DEVICE_ERROR
;
1122 // Calculate the number of addresses for this Ia, excluding the addresses with
1123 // the value 0 of valid lifetime.
1125 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, NULL
);
1128 return EFI_NOT_FOUND
;
1132 // Allocate for new IA.
1134 IaSize
= sizeof (EFI_DHCP6_IA
) + (AddrNum
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1135 Ia
= AllocateZeroPool (IaSize
);
1138 return EFI_OUT_OF_RESOURCES
;
1142 // Fill up this new IA fields.
1144 Ia
->State
= Instance
->IaCb
.Ia
->State
;
1145 Ia
->IaAddressCount
= AddrNum
;
1146 CopyMem (&Ia
->Descriptor
, &Instance
->Config
->IaDescriptor
, sizeof (EFI_DHCP6_IA_DESCRIPTOR
));
1147 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, Ia
->IaAddress
);
1150 // Free original IA resource.
1152 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
1153 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
1156 FreePool (Instance
->IaCb
.Ia
);
1158 ZeroMem (&Instance
->IaCb
, sizeof (DHCP6_IA_CB
));
1161 // Update IaCb to use new IA.
1163 Instance
->IaCb
.Ia
= Ia
;
1167 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
1169 Instance
->IaCb
.T1
= T1
;
1170 Instance
->IaCb
.T2
= T2
;
1171 Dhcp6CalculateLeaseTime (&Instance
->IaCb
);
1177 Cache the current IA configuration information.
1179 @param[in] Instance The pointer to DHCP6 Instance.
1181 @retval EFI_SUCCESS Cache the current IA successfully.
1182 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1187 IN DHCP6_INSTANCE
*Instance
1193 Ia
= Instance
->IaCb
.Ia
;
1195 if ((Instance
->CacheIa
== NULL
) && (Ia
!= NULL
)) {
1197 // Cache the current IA.
1199 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1201 Instance
->CacheIa
= AllocateZeroPool (IaSize
);
1202 if (Instance
->CacheIa
== NULL
) {
1203 return EFI_OUT_OF_RESOURCES
;
1206 CopyMem (Instance
->CacheIa
, Ia
, IaSize
);
1213 Append CacheIa to the current IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
1215 @param[in] Instance The pointer to DHCP6 instance.
1219 Dhcp6AppendCacheIa (
1220 IN DHCP6_INSTANCE
*Instance
1228 EFI_DHCP6_IA
*NewIa
;
1229 EFI_DHCP6_IA
*CacheIa
;
1231 Ia
= Instance
->IaCb
.Ia
;
1232 CacheIa
= Instance
->CacheIa
;
1234 if ((CacheIa
!= NULL
) && (CacheIa
->IaAddressCount
!= 0)) {
1236 // There are old addresses existing. Merge with current addresses.
1238 NewIaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
+ CacheIa
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1239 NewIa
= AllocateZeroPool (NewIaSize
);
1240 if (NewIa
== NULL
) {
1244 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1245 CopyMem (NewIa
, Ia
, IaSize
);
1248 // Clear old address.ValidLifetime
1250 for (Index
= 0; Index
< CacheIa
->IaAddressCount
; Index
++) {
1251 CacheIa
->IaAddress
[Index
].ValidLifetime
= 0;
1254 NewIa
->IaAddressCount
+= CacheIa
->IaAddressCount
;
1255 Ptr
= (UINT8
*)&NewIa
->IaAddress
[Ia
->IaAddressCount
];
1256 CopyMem (Ptr
, CacheIa
->IaAddress
, CacheIa
->IaAddressCount
* sizeof (EFI_DHCP6_IA_ADDRESS
));
1259 // Migrate to the NewIa and free previous.
1261 FreePool (Instance
->CacheIa
);
1262 FreePool (Instance
->IaCb
.Ia
);
1263 Instance
->CacheIa
= NULL
;
1264 Instance
->IaCb
.Ia
= NewIa
;
1269 Calculate the Dhcp6 get mapping timeout by adding additional delay to the IP6 DAD transmits count.
1271 @param[in] Ip6Cfg The pointer to Ip6 config protocol.
1272 @param[out] TimeOut The time out value in 100ns units.
1274 @retval EFI_INVALID_PARAMETER Input parameters are invalid.
1275 @retval EFI_SUCCESS Calculate the time out value successfully.
1278 Dhcp6GetMappingTimeOut (
1279 IN EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
,
1285 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
1287 if ((Ip6Cfg
== NULL
) || (TimeOut
== NULL
)) {
1288 return EFI_INVALID_PARAMETER
;
1291 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
1292 Status
= Ip6Cfg
->GetData (
1294 Ip6ConfigDataTypeDupAddrDetectTransmits
,
1298 if (EFI_ERROR (Status
)) {
1302 *TimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ DHCP6_DAD_ADDITIONAL_DELAY
;