2 Dhcp6 support functions implementation.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2014, 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 Generate client Duid in the format of Duid-llt.
23 @param[in] Mode The pointer to the mode of SNP.
25 @retval NULL If it failed to generate a client Id.
26 @retval others The pointer to the new client id.
30 Dhcp6GenerateClientId (
31 IN EFI_SIMPLE_NETWORK_MODE
*Mode
42 // Attempt to get client Id from variable to keep it constant.
43 // See details in section-9 of rfc-3315.
45 GetVariable2 (L
"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid
, (VOID
**)&Duid
, NULL
);
51 // The format of client identifier option:
53 // 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
54 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 // | OPTION_CLIENTID | option-len |
56 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 // . (variable length) .
61 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 // If System UUID is found from SMBIOS Table, use DUID-UUID type.
67 if ((PcdGet8 (PcdDhcp6UidType
) == Dhcp6DuidTypeUuid
) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid
))) {
70 // The format of DUID-UUID:
72 // 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
73 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 // | DUID-Type (4) | UUID (128 bits) |
75 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
78 // | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
83 // sizeof (option-len + Duid-type + UUID-size) = 20 bytes
85 Duid
= AllocateZeroPool (2 + 2 + sizeof (EFI_GUID
));
91 // sizeof (Duid-type + UUID-size) = 18 bytes
93 Duid
->Length
= (UINT16
) (18);
96 // Set the Duid-type and copy UUID.
98 WriteUnaligned16 ((UINT16
*) (Duid
->Duid
), HTONS (Dhcp6DuidTypeUuid
));
100 CopyMem (Duid
->Duid
+ 2, &Uuid
, sizeof(EFI_GUID
));
106 // The format of DUID-LLT:
108 // 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
109 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110 // | Duid type (1) | hardware type (16 bits) |
111 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 // | time (32 bits) |
113 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 // . link-layer address (variable length) .
117 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121 // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.
123 gRT
->GetTime (&Time
, NULL
);
126 (((((Time
.Year
- 2000) * 360 + (Time
.Month
- 1)) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) *
132 // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes
134 Duid
= AllocateZeroPool (10 + Mode
->HwAddressSize
);
140 // sizeof (Duid-type + hardware-type + time) = 8 bytes
142 Duid
->Length
= (UINT16
) (Mode
->HwAddressSize
+ 8);
145 // Set the Duid-type, hardware-type, time and copy the hardware address.
147 WriteUnaligned16 ((UINT16
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
)), HTONS (Dhcp6DuidTypeLlt
));
148 WriteUnaligned16 ((UINT16
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 2), HTONS (NET_IFTYPE_ETHERNET
));
149 WriteUnaligned32 ((UINT32
*) ((UINT8
*) Duid
+ OFFSET_OF (EFI_DHCP6_DUID
, Duid
) + 4), HTONL (Stamp
));
151 CopyMem (Duid
->Duid
+ 8, &Mode
->CurrentAddress
, Mode
->HwAddressSize
);
154 Status
= gRT
->SetVariable (
156 &gEfiDhcp6ServiceBindingProtocolGuid
,
157 (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
),
161 if (EFI_ERROR (Status
)) {
171 Copy the Dhcp6 configure data.
173 @param[in] DstCfg The pointer to the destination configure data.
174 @param[in] SorCfg The pointer to the source configure data.
176 @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully.
177 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
181 Dhcp6CopyConfigData (
182 IN EFI_DHCP6_CONFIG_DATA
*DstCfg
,
183 IN EFI_DHCP6_CONFIG_DATA
*SorCfg
187 UINTN OptionListSize
;
190 CopyMem (DstCfg
, SorCfg
, sizeof (EFI_DHCP6_CONFIG_DATA
));
193 // Allocate another buffer for solicitretransmission, and copy it.
195 if (SorCfg
->SolicitRetransmission
!= NULL
) {
197 DstCfg
->SolicitRetransmission
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
199 if (DstCfg
->SolicitRetransmission
== NULL
) {
201 // Error will be handled out of this function.
203 return EFI_OUT_OF_RESOURCES
;
207 DstCfg
->SolicitRetransmission
,
208 SorCfg
->SolicitRetransmission
,
209 sizeof (EFI_DHCP6_RETRANSMISSION
)
213 if (SorCfg
->OptionList
!= NULL
&& SorCfg
->OptionCount
!= 0) {
215 OptionListSize
= SorCfg
->OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*);
216 DstCfg
->OptionList
= AllocateZeroPool (OptionListSize
);
218 if (DstCfg
->OptionList
== NULL
) {
220 // Error will be handled out of this function.
222 return EFI_OUT_OF_RESOURCES
;
225 for (Index
= 0; Index
< SorCfg
->OptionCount
; Index
++) {
227 OptionSize
= NTOHS (SorCfg
->OptionList
[Index
]->OpLen
) + 4;
228 DstCfg
->OptionList
[Index
] = AllocateZeroPool (OptionSize
);
230 if (DstCfg
->OptionList
[Index
] == NULL
) {
232 // Error will be handled out of this function.
234 return EFI_OUT_OF_RESOURCES
;
238 DstCfg
->OptionList
[Index
],
239 SorCfg
->OptionList
[Index
],
250 Clean up the configure data.
252 @param[in, out] CfgData The pointer to the configure data.
256 Dhcp6CleanupConfigData (
257 IN OUT EFI_DHCP6_CONFIG_DATA
*CfgData
262 ASSERT (CfgData
!= NULL
);
264 // Clean up all fields in config data including the reference buffers, but do
265 // not free the config data buffer itself.
267 if (CfgData
->OptionList
!= NULL
) {
268 for (Index
= 0; Index
< CfgData
->OptionCount
; Index
++) {
269 if (CfgData
->OptionList
[Index
] != NULL
) {
270 FreePool (CfgData
->OptionList
[Index
]);
273 FreePool (CfgData
->OptionList
);
276 if (CfgData
->SolicitRetransmission
!= NULL
) {
277 FreePool (CfgData
->SolicitRetransmission
);
280 ZeroMem (CfgData
, sizeof (EFI_DHCP6_CONFIG_DATA
));
285 Clean up the mode data.
287 @param[in, out] ModeData The pointer to the mode data.
291 Dhcp6CleanupModeData (
292 IN OUT EFI_DHCP6_MODE_DATA
*ModeData
295 ASSERT (ModeData
!= NULL
);
297 // Clean up all fields in mode data including the reference buffers, but do
298 // not free the mode data buffer itself.
300 if (ModeData
->ClientId
!= NULL
) {
301 FreePool (ModeData
->ClientId
);
304 if (ModeData
->Ia
!= NULL
) {
306 if (ModeData
->Ia
->ReplyPacket
!= NULL
) {
307 FreePool (ModeData
->Ia
->ReplyPacket
);
309 FreePool (ModeData
->Ia
);
312 ZeroMem (ModeData
, sizeof (EFI_DHCP6_MODE_DATA
));
317 Calculate the expire time by the algorithm defined in rfc.
319 @param[in] Base The base value of the time.
320 @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time.
321 @param[in] NeedSigned If TRUE, the the signed factor is needed.
323 @return Expire The calculated result for the new expire time.
327 Dhcp6CalculateExpireTime (
329 IN BOOLEAN IsFirstRt
,
330 IN BOOLEAN NeedSigned
339 // Take the 10bits of microsecond in system time as a uniform distribution.
340 // Take the 10th bit as a flag to determine it's signed or not.
342 gRT
->GetTime (&Time
, NULL
);
343 Seed
= ((Time
.Nanosecond
>> 10) & DHCP6_10_BIT_MASK
);
344 Signed
= (BOOLEAN
) ((((Time
.Nanosecond
>> 9) & 0x01) != 0) ? TRUE
: FALSE
);
345 Signed
= (BOOLEAN
) (NeedSigned
? Signed
: FALSE
);
348 // Calculate expire by the following algo:
349 // 1. base + base * (-0.1 ~ 0) for the first solicit
350 // 2. base + base * (-0.1 ~ 0.1) for the first other messages
351 // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages
352 // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout
354 // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).
356 if (IsFirstRt
&& Signed
) {
358 Expire
= Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
360 } else if (IsFirstRt
&& !Signed
) {
362 Expire
= Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
364 } else if (!IsFirstRt
&& Signed
) {
366 Expire
= 2 * Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
370 Expire
= 2 * Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
373 Expire
= (Expire
!= 0) ? Expire
: 1;
380 Calculate the lease time by the algorithm defined in rfc.
382 @param[in] IaCb The pointer to the Ia control block.
386 Dhcp6CalculateLeaseTime (
394 ASSERT (IaCb
->Ia
->IaAddressCount
> 0);
396 MinLt
= (UINT32
) (-1);
400 // Calculate minlt as min of all valid life time, and maxlt as max of all
403 for (Index
= 0; Index
< IaCb
->Ia
->IaAddressCount
; Index
++) {
404 MinLt
= MIN (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
405 MaxLt
= MAX (MinLt
, IaCb
->Ia
->IaAddress
[Index
].ValidLifetime
);
409 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
412 IaCb
->T1
= (IaCb
->T1
!= 0) ? IaCb
->T1
: (UINT32
)(MinLt
* 5 / 10);
413 IaCb
->T2
= (IaCb
->T2
!= 0) ? IaCb
->T2
: (UINT32
)(MinLt
* 8 / 10);
414 IaCb
->AllExpireTime
= MaxLt
;
420 Check whether the addresses are all included by the configured Ia.
422 @param[in] Ia The pointer to the Ia.
423 @param[in] AddressCount The number of addresses.
424 @param[in] Addresses The pointer to the addresses buffer.
426 @retval EFI_SUCCESS The addresses are all included by the configured IA.
427 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.
433 IN UINT32 AddressCount
,
434 IN EFI_IPv6_ADDRESS
*Addresses
442 // Check whether the addresses are all included by the configured IA. And it
443 // will return success if address count is zero, which means all addresses.
445 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
449 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
453 &Ia
->IaAddress
[Index2
],
454 sizeof (EFI_IPv6_ADDRESS
)
463 return EFI_NOT_FOUND
;
472 Deprive the addresses from current Ia, and generate another eliminated Ia.
474 @param[in] Ia The pointer to the Ia.
475 @param[in] AddressCount The number of addresses.
476 @param[in] Addresses The pointer to the addresses buffer.
478 @retval NULL If it failed to generate the deprived Ia.
479 @retval others The pointer to the deprived Ia.
483 Dhcp6DepriveAddress (
485 IN UINT32 AddressCount
,
486 IN EFI_IPv6_ADDRESS
*Addresses
489 EFI_DHCP6_IA
*IaCopy
;
495 if (AddressCount
== 0) {
497 // It means release all Ia addresses if address count is zero.
499 AddressCount
= Ia
->IaAddressCount
;
502 ASSERT (AddressCount
!= 0);
504 IaCopySize
= sizeof (EFI_DHCP6_IA
) + (AddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
505 IaCopy
= AllocateZeroPool (IaCopySize
);
507 if (IaCopy
== NULL
) {
511 if (AddressCount
== Ia
->IaAddressCount
) {
513 // If release all Ia addresses, just copy the configured Ia and then set
514 // its address count as zero.
515 // We may decline/release part of addresses at the begining. So it's a
516 // forwarding step to update address infor for decline/release, while the
517 // other infor such as Ia state will be updated when receiving reply.
519 CopyMem (IaCopy
, Ia
, IaCopySize
);
520 Ia
->IaAddressCount
= 0;
524 CopyMem (IaCopy
, Ia
, sizeof (EFI_DHCP6_IA
));
527 // Move the addresses from the Ia of instance to the deprived Ia.
529 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
533 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
537 &Ia
->IaAddress
[Index2
],
538 sizeof (EFI_IPv6_ADDRESS
)
541 // Copy the deprived address to the copy of Ia
544 &IaCopy
->IaAddress
[Index1
],
545 &Ia
->IaAddress
[Index2
],
546 sizeof (EFI_DHCP6_IA_ADDRESS
)
549 // Delete the deprived address from the instance Ia
551 if (Index2
+ 1 < Ia
->IaAddressCount
) {
553 &Ia
->IaAddress
[Index2
],
554 &Ia
->IaAddress
[Index2
+ 1],
555 (Ia
->IaAddressCount
- Index2
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
)
562 ASSERT (Found
== TRUE
);
565 Ia
->IaAddressCount
-= AddressCount
;
566 IaCopy
->IaAddressCount
= AddressCount
;
573 The dummy ext buffer free callback routine.
575 @param[in] Arg The pointer to the parameter.
588 The callback routine once message transmitted.
590 @param[in] Wrap The pointer to the received net buffer.
591 @param[in] EndPoint The pointer to the udp end point.
592 @param[in] IoStatus The return status from udp io.
593 @param[in] Context The opaque parameter to the function.
600 IN UDP_END_POINT
*EndPoint
,
601 IN EFI_STATUS IoStatus
,
610 Append the option to Buf, and move Buf to the end.
612 @param[in, out] Buf The pointer to the buffer.
613 @param[in] OptType The option type.
614 @param[in] OptLen The length of option contents.
615 @param[in] Data The pointer to the option content.
617 @return Buf The position to append the next option.
629 // The format of Dhcp6 option:
631 // 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
632 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
633 // | option-code | option-len (option data) |
634 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
636 // | (option-len octets) |
637 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
640 ASSERT (OptLen
!= 0);
642 WriteUnaligned16 ((UINT16
*) Buf
, OptType
);
644 WriteUnaligned16 ((UINT16
*) Buf
, OptLen
);
646 CopyMem (Buf
, Data
, NTOHS (OptLen
));
647 Buf
+= NTOHS (OptLen
);
653 Append the appointed IA Address option to Buf, and move Buf to the end.
655 @param[in, out] Buf The pointer to the position to append.
656 @param[in] IaAddr The pointer to the IA Address.
657 @param[in] MessageType Message type of DHCP6 package.
659 @return Buf The position to append the next option.
663 Dhcp6AppendIaAddrOption (
665 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
666 IN UINT32 MessageType
670 // The format of the IA Address option is:
673 // 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
674 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675 // | OPTION_IAADDR | option-len |
676 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
681 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
682 // | preferred-lifetime |
683 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
684 // | valid-lifetime |
685 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
687 // . IAaddr-options .
689 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
692 // Fill the value of Ia Address option type
694 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Dhcp6OptIaAddr
));
697 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS
)));
700 CopyMem (Buf
, &IaAddr
->IpAddress
, sizeof(EFI_IPv6_ADDRESS
));
701 Buf
+= sizeof(EFI_IPv6_ADDRESS
);
704 // Fill the value of preferred-lifetime and valid-lifetime.
705 // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields
706 // should set to 0 when initiate a Confirm message.
708 if (MessageType
!= Dhcp6MsgConfirm
) {
709 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (IaAddr
->PreferredLifetime
));
713 if (MessageType
!= Dhcp6MsgConfirm
) {
714 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (IaAddr
->ValidLifetime
));
723 Append the appointed Ia option to Buf, and move Buf to the end.
725 @param[in, out] Buf The pointer to the position to append.
726 @param[in] Ia The pointer to the Ia.
727 @param[in] T1 The time of T1.
728 @param[in] T2 The time of T2.
729 @param[in] MessageType Message type of DHCP6 package.
731 @return Buf The position to append the next Ia option.
735 Dhcp6AppendIaOption (
740 IN UINT32 MessageType
748 // The format of IA_NA and IA_TA option:
750 // 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
751 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
752 // | OPTION_IA_NA | option-len |
753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
754 // | IAID (4 octets) |
755 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
756 // | T1 (only for IA_NA) |
757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
758 // | T2 (only for IA_NA) |
759 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // . IA_NA-options/IA_TA-options .
763 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
767 // Fill the value of Ia option type
769 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Ia
->Descriptor
.Type
));
773 // Fill the len of Ia option later, keep the pointer first
775 Len
= (UINT16
*) Buf
;
779 // Fill the value of iaid
781 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (Ia
->Descriptor
.IaId
));
785 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
787 if (Ia
->Descriptor
.Type
== Dhcp6OptIana
) {
788 WriteUnaligned32 ((UINT32
*) Buf
, HTONL ((T1
!= 0) ? T1
: 0xffffffff));
790 WriteUnaligned32 ((UINT32
*) Buf
, HTONL ((T2
!= 0) ? T2
: 0xffffffff));
795 // Fill all the addresses belong to the Ia
797 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
798 AddrOpt
= (UINT8
*) Ia
->IaAddress
+ Index
* sizeof (EFI_DHCP6_IA_ADDRESS
);
799 Buf
= Dhcp6AppendIaAddrOption (Buf
, (EFI_DHCP6_IA_ADDRESS
*) AddrOpt
, MessageType
);
803 // Fill the value of Ia option length
805 *Len
= HTONS ((UINT16
) (Buf
- (UINT8
*) Len
- 2));
811 Append the appointed Elapsed time option to Buf, and move Buf to the end.
813 @param[in, out] Buf The pointer to the position to append.
814 @param[in] Instance The pointer to the Dhcp6 instance.
815 @param[out] Elapsed The pointer to the elapsed time value in
816 the generated packet.
818 @return Buf The position to append the next Ia option.
822 Dhcp6AppendETOption (
824 IN DHCP6_INSTANCE
*Instance
,
829 // The format of elapsed time option:
831 // 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
832 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
833 // | OPTION_ELAPSED_TIME | option-len |
834 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
836 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
840 // Fill the value of elapsed-time option type.
842 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Dhcp6OptElapsedTime
));
846 // Fill the len of elapsed-time option, which is fixed.
848 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(2));
852 // Fill in elapsed time value with 0 value for now. The actual value is
853 // filled in later just before the packet is transmitted.
855 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(0));
856 *Elapsed
= (UINT16
*) Buf
;
863 Set the elapsed time based on the given instance and the pointer to the
866 @param[in] Elapsed The pointer to the position to append.
867 @param[in] Instance The pointer to the Dhcp6 instance.
873 IN DHCP6_INSTANCE
*Instance
878 UINT64 ElapsedTimeValue
;
881 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
883 gRT
->GetTime (&Time
, NULL
);
884 CurrentStamp
= (UINT64
)
886 ((((((Time
.Year
- 2000) * 360 +
887 (Time
.Month
- 1)) * 30 +
888 (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 +
889 Time
.Minute
) * 60 + Time
.Second
) * 100
890 + DivU64x32(Time
.Nanosecond
, 10000000)
894 // Sentinel value of 0 means that this is the first DHCP packet that we are
895 // sending and that we need to initialize the value. First DHCP message
896 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
898 if (Instance
->StartTime
== 0) {
899 ElapsedTimeValue
= 0;
900 Instance
->StartTime
= CurrentStamp
;
902 ElapsedTimeValue
= CurrentStamp
- Instance
->StartTime
;
905 // If elapsed time cannot fit in two bytes, set it to 0xffff.
907 if (ElapsedTimeValue
> 0xffff) {
908 ElapsedTimeValue
= 0xffff;
911 WriteUnaligned16 (Elapsed
, HTONS((UINT16
) ElapsedTimeValue
));
916 Seek the address of the first byte of the option header.
918 @param[in] Buf The pointer to the buffer.
919 @param[in] SeekLen The length to seek.
920 @param[in] OptType The option type.
922 @retval NULL If it failed to seek the option.
923 @retval others The position to the option.
942 // The format of Dhcp6 option refers to Dhcp6AppendOption().
944 while (Cursor
< Buf
+ SeekLen
) {
945 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
946 if (OpCode
== HTONS (OptType
)) {
950 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
951 Cursor
+= (DataLen
+ 4);
959 Seek the address of the first byte of the Ia option header.
961 @param[in] Buf The pointer to the buffer.
962 @param[in] SeekLen The length to seek.
963 @param[in] IaDesc The pointer to the Ia descriptor.
965 @retval NULL If it failed to seek the Ia option.
966 @retval others The position to the Ia option.
973 IN EFI_DHCP6_IA_DESCRIPTOR
*IaDesc
983 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
988 while (Cursor
< Buf
+ SeekLen
) {
989 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
990 IaId
= ReadUnaligned32 ((UINT32
*) (Cursor
+ 4));
991 if (OpCode
== HTONS (IaDesc
->Type
) && IaId
== HTONL (IaDesc
->IaId
)) {
995 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
996 Cursor
+= (DataLen
+ 4);
1003 Check whether the incoming IPv6 address in IaAddr is one of the maintained
1004 addresses in the IA control blcok.
1006 @param[in] IaAddr The pointer to the IA Address to be checked.
1007 @param[in] CurrentIa The pointer to the IA in IA control block.
1009 @retval TRUE Yes, this Address is already in IA control block.
1010 @retval FALSE No, this Address is NOT in IA control block.
1014 Dhcp6AddrIsInCurrentIa (
1015 IN EFI_DHCP6_IA_ADDRESS
*IaAddr
,
1016 IN EFI_DHCP6_IA
*CurrentIa
1021 ASSERT (IaAddr
!= NULL
&& CurrentIa
!= NULL
);
1023 for (Index
= 0; Index
< CurrentIa
->IaAddressCount
; Index
++) {
1024 if (EFI_IP6_EQUAL(&IaAddr
->IpAddress
, &CurrentIa
->IaAddress
[Index
].IpAddress
)) {
1032 Parse the address option and update the address infomation.
1034 @param[in] CurrentIa The pointer to the Ia Address in control blcok.
1035 @param[in] IaInnerOpt The pointer to the buffer.
1036 @param[in] IaInnerLen The length to parse.
1037 @param[out] AddrNum The number of addresses.
1038 @param[in, out] AddrBuf The pointer to the address buffer.
1042 Dhcp6ParseAddrOption (
1043 IN EFI_DHCP6_IA
*CurrentIa
,
1044 IN UINT8
*IaInnerOpt
,
1045 IN UINT16 IaInnerLen
,
1046 OUT UINT32
*AddrNum
,
1047 IN OUT EFI_DHCP6_IA_ADDRESS
*AddrBuf
1055 EFI_DHCP6_IA_ADDRESS
*IaAddr
;
1058 // The format of the IA Address option:
1060 // 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
1061 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1062 // | OPTION_IAADDR | option-len |
1063 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1068 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1069 // | preferred-lifetime |
1070 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1071 // | valid-lifetime |
1072 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1074 // . IAaddr-options .
1076 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1082 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
1083 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner
1084 // options to the addrbuf.
1087 Cursor
= IaInnerOpt
;
1090 while (Cursor
< IaInnerOpt
+ IaInnerLen
) {
1092 // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option
1093 // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.
1095 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
1096 PreferredLt
= NTOHL (ReadUnaligned32 ((UINT32
*) (Cursor
+ 20)));
1097 ValidLt
= NTOHL (ReadUnaligned32 ((UINT32
*) (Cursor
+ 24)));
1098 IaAddr
= (EFI_DHCP6_IA_ADDRESS
*) (Cursor
+ 4);
1099 if (OpCode
== HTONS (Dhcp6OptIaAddr
) && ValidLt
>= PreferredLt
&&
1100 (Dhcp6AddrIsInCurrentIa(IaAddr
, CurrentIa
) || ValidLt
!=0)) {
1101 if (AddrBuf
!= NULL
) {
1102 CopyMem (AddrBuf
, IaAddr
, sizeof (EFI_DHCP6_IA_ADDRESS
));
1103 AddrBuf
->PreferredLifetime
= PreferredLt
;
1104 AddrBuf
->ValidLifetime
= ValidLt
;
1105 AddrBuf
= (EFI_DHCP6_IA_ADDRESS
*) ((UINT8
*) AddrBuf
+ sizeof (EFI_DHCP6_IA_ADDRESS
));
1109 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
1110 Cursor
+= (DataLen
+ 4);
1116 Create a control blcok for the Ia according to the corresponding options.
1118 @param[in] Instance The pointer to DHCP6 Instance.
1119 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.
1120 @param[in] IaInnerLen The length of all the inner options in the Ia option.
1121 @param[in] T1 T1 time in the Ia option.
1122 @param[in] T2 T2 time in the Ia option.
1124 @retval EFI_NOT_FOUND No valid IA option is found.
1125 @retval EFI_SUCCESS Create an IA control block successfully.
1126 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1127 @retval EFI_DEVICE_ERROR An unexpected error.
1132 IN DHCP6_INSTANCE
*Instance
,
1133 IN UINT8
*IaInnerOpt
,
1134 IN UINT16 IaInnerLen
,
1143 if (Instance
->IaCb
.Ia
== NULL
) {
1144 return EFI_DEVICE_ERROR
;
1148 // Calculate the number of addresses for this Ia, excluding the addresses with
1149 // the value 0 of valid lifetime.
1151 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, NULL
);
1154 return EFI_NOT_FOUND
;
1158 // Allocate for new IA.
1160 IaSize
= sizeof (EFI_DHCP6_IA
) + (AddrNum
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1161 Ia
= AllocateZeroPool (IaSize
);
1164 return EFI_OUT_OF_RESOURCES
;
1168 // Fill up this new IA fields.
1170 Ia
->State
= Instance
->IaCb
.Ia
->State
;
1171 Ia
->IaAddressCount
= AddrNum
;
1172 CopyMem (&Ia
->Descriptor
, &Instance
->Config
->IaDescriptor
, sizeof (EFI_DHCP6_IA_DESCRIPTOR
));
1173 Dhcp6ParseAddrOption (Instance
->IaCb
.Ia
, IaInnerOpt
, IaInnerLen
, &AddrNum
, Ia
->IaAddress
);
1176 // Free original IA resource.
1178 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
1179 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
1181 FreePool (Instance
->IaCb
.Ia
);
1184 ZeroMem (&Instance
->IaCb
, sizeof (DHCP6_IA_CB
));
1187 // Update IaCb to use new IA.
1189 Instance
->IaCb
.Ia
= Ia
;
1193 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
1195 Instance
->IaCb
.T1
= T1
;
1196 Instance
->IaCb
.T2
= T2
;
1197 Dhcp6CalculateLeaseTime (&Instance
->IaCb
);
1204 Cache the current IA configuration information.
1206 @param[in] Instance The pointer to DHCP6 Instance.
1208 @retval EFI_SUCCESS Cache the current IA successfully.
1209 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1214 IN DHCP6_INSTANCE
*Instance
1220 Ia
= Instance
->IaCb
.Ia
;
1222 if ((Instance
->CacheIa
== NULL
) && (Ia
!= NULL
)) {
1224 // Cache the current IA.
1226 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1228 Instance
->CacheIa
= AllocateZeroPool (IaSize
);
1229 if (Instance
->CacheIa
== NULL
) {
1230 return EFI_OUT_OF_RESOURCES
;
1232 CopyMem (Instance
->CacheIa
, Ia
, IaSize
);
1238 Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
1240 @param[in] Instance The pointer to DHCP6 instance.
1244 Dhcp6AppendCacheIa (
1245 IN DHCP6_INSTANCE
*Instance
1253 EFI_DHCP6_IA
*NewIa
;
1254 EFI_DHCP6_IA
*CacheIa
;
1256 Ia
= Instance
->IaCb
.Ia
;
1257 CacheIa
= Instance
->CacheIa
;
1259 if ((CacheIa
!= NULL
) && (CacheIa
->IaAddressCount
!= 0)) {
1261 // There are old addresses existing. Merge with current addresses.
1263 NewIaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
+ CacheIa
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1264 NewIa
= AllocateZeroPool (NewIaSize
);
1265 if (NewIa
== NULL
) {
1269 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1270 CopyMem (NewIa
, Ia
, IaSize
);
1273 // Clear old address.ValidLifetime
1275 for (Index
= 0; Index
< CacheIa
->IaAddressCount
; Index
++) {
1276 CacheIa
->IaAddress
[Index
].ValidLifetime
= 0;
1279 NewIa
->IaAddressCount
+= CacheIa
->IaAddressCount
;
1280 Ptr
= (UINT8
*)&NewIa
->IaAddress
[Ia
->IaAddressCount
];
1281 CopyMem (Ptr
, CacheIa
->IaAddress
, CacheIa
->IaAddressCount
* sizeof (EFI_DHCP6_IA_ADDRESS
));
1284 // Migrate to the NewIa and free previous.
1286 FreePool (Instance
->CacheIa
);
1287 FreePool (Instance
->IaCb
.Ia
);
1288 Instance
->CacheIa
= NULL
;
1289 Instance
->IaCb
.Ia
= NewIa
;
1294 Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.
1296 @param[in] Ip6Cfg The pointer to Ip6 config protocol.
1297 @param[out] TimeOut The time out value in 100ns units.
1299 @retval EFI_INVALID_PARAMETER Input parameters are invalid.
1300 @retval EFI_SUCCESS Calculate the time out value successfully.
1303 Dhcp6GetMappingTimeOut (
1304 IN EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
,
1310 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits
;
1312 if (Ip6Cfg
== NULL
|| TimeOut
== NULL
) {
1313 return EFI_INVALID_PARAMETER
;
1316 DataSize
= sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
);
1317 Status
= Ip6Cfg
->GetData (
1319 Ip6ConfigDataTypeDupAddrDetectTransmits
,
1323 if (EFI_ERROR (Status
)) {
1327 *TimeOut
= TICKS_PER_SECOND
* DadXmits
.DupAddrDetectTransmits
+ DHCP6_DAD_ADDITIONAL_DELAY
;