2 Dhcp6 support functions implementation.
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Dhcp6Impl.h"
20 Generate client Duid in the format of Duid-llt.
22 @param[in] Mode The pointer to the mode of SNP.
24 @retval NULL If it failed to generate a client Id.
25 @retval others The pointer to the new client id.
29 Dhcp6GenerateClientId (
30 IN EFI_SIMPLE_NETWORK_MODE
*Mode
39 // Attempt to get client Id from variable to keep it constant.
40 // See details in section-9 of rfc-3315.
42 Duid
= GetVariable (L
"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid
);
48 // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.
50 gRT
->GetTime (&Time
, NULL
);
53 (((((Time
.Year
- 2000) * 360 + (Time
.Month
- 1)) * 30 + (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 + Time
.Minute
) *
59 // The format of client identifier option:
61 // 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
62 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 // | OPTION_CLIENTID | option-len |
64 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 // . (variable length) .
69 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 // The format of DUID-LLT:
74 // 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
75 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 // | Duid type (1) | hardware type (16 bits) |
77 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 // . link-layer address (variable length) .
83 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes
89 Duid
= AllocateZeroPool (10 + Mode
->HwAddressSize
);
95 // sizeof (Duid-type + hardware-type + time) = 8 bytes
97 Duid
->Length
= (UINT16
) (Mode
->HwAddressSize
+ 8);
100 // Set the Duid-type, hardware-type, time and copy the hardware address.
102 WriteUnaligned16 ((UINT16
*) (Duid
->Duid
), HTONS (Dhcp6DuidTypeLlt
));
103 WriteUnaligned16 ((UINT16
*) (Duid
->Duid
+ 2), HTONS (NET_IFTYPE_ETHERNET
));
104 WriteUnaligned32 ((UINT32
*) (Duid
->Duid
+ 4), HTONL (Stamp
));
106 CopyMem (Duid
->Duid
+ 8, &Mode
->CurrentAddress
, Mode
->HwAddressSize
);
108 Status
= gRT
->SetVariable (
110 &gEfiDhcp6ServiceBindingProtocolGuid
,
111 (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
),
115 ASSERT_EFI_ERROR (Status
);
122 Copy the Dhcp6 configure data.
124 @param[in] DstCfg The pointer to the destination configure data.
125 @param[in] SorCfg The pointer to the source configure data.
127 @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully.
128 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
132 Dhcp6CopyConfigData (
133 IN EFI_DHCP6_CONFIG_DATA
*DstCfg
,
134 IN EFI_DHCP6_CONFIG_DATA
*SorCfg
138 UINTN OptionListSize
;
141 CopyMem (DstCfg
, SorCfg
, sizeof (EFI_DHCP6_CONFIG_DATA
));
144 // Allocate another buffer for solicitretransmission, and copy it.
146 if (SorCfg
->SolicitRetransmission
!= NULL
) {
148 DstCfg
->SolicitRetransmission
= AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION
));
150 if (DstCfg
->SolicitRetransmission
== NULL
) {
152 // Error will be handled out of this function.
154 return EFI_OUT_OF_RESOURCES
;
158 DstCfg
->SolicitRetransmission
,
159 SorCfg
->SolicitRetransmission
,
160 sizeof (EFI_DHCP6_RETRANSMISSION
)
164 if (SorCfg
->OptionList
!= NULL
&& SorCfg
->OptionCount
!= 0) {
166 OptionListSize
= SorCfg
->OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*);
167 DstCfg
->OptionList
= AllocateZeroPool (OptionListSize
);
169 if (DstCfg
->OptionList
== NULL
) {
171 // Error will be handled out of this function.
173 return EFI_OUT_OF_RESOURCES
;
176 for (Index
= 0; Index
< SorCfg
->OptionCount
; Index
++) {
178 OptionSize
= NTOHS (SorCfg
->OptionList
[Index
]->OpLen
) + 4;
179 DstCfg
->OptionList
[Index
] = AllocateZeroPool (OptionSize
);
181 if (DstCfg
->OptionList
[Index
] == NULL
) {
183 // Error will be handled out of this function.
185 return EFI_OUT_OF_RESOURCES
;
189 DstCfg
->OptionList
[Index
],
190 SorCfg
->OptionList
[Index
],
201 Clean up the configure data.
203 @param[in, out] CfgData The pointer to the configure data.
207 Dhcp6CleanupConfigData (
208 IN OUT EFI_DHCP6_CONFIG_DATA
*CfgData
213 ASSERT (CfgData
!= NULL
);
215 // Clean up all fields in config data including the reference buffers, but do
216 // not free the config data buffer itself.
218 if (CfgData
->OptionList
!= NULL
) {
219 for (Index
= 0; Index
< CfgData
->OptionCount
; Index
++) {
220 if (CfgData
->OptionList
[Index
] != NULL
) {
221 FreePool (CfgData
->OptionList
[Index
]);
224 FreePool (CfgData
->OptionList
);
227 if (CfgData
->SolicitRetransmission
!= NULL
) {
228 FreePool (CfgData
->SolicitRetransmission
);
231 ZeroMem (CfgData
, sizeof (EFI_DHCP6_CONFIG_DATA
));
236 Clean up the mode data.
238 @param[in, out] ModeData The pointer to the mode data.
242 Dhcp6CleanupModeData (
243 IN OUT EFI_DHCP6_MODE_DATA
*ModeData
246 ASSERT (ModeData
!= NULL
);
248 // Clean up all fields in mode data including the reference buffers, but do
249 // not free the mode data buffer itself.
251 if (ModeData
->ClientId
!= NULL
) {
252 FreePool (ModeData
->ClientId
);
255 if (ModeData
->Ia
!= NULL
) {
257 if (ModeData
->Ia
->ReplyPacket
!= NULL
) {
258 FreePool (ModeData
->Ia
->ReplyPacket
);
260 FreePool (ModeData
->Ia
);
263 ZeroMem (ModeData
, sizeof (EFI_DHCP6_MODE_DATA
));
268 Calculate the expire time by the algorithm defined in rfc.
270 @param[in] Base The base value of the time.
271 @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time.
272 @param[in] NeedSigned If TRUE, the the signed factor is needed.
274 @return Expire The calculated result for the new expire time.
278 Dhcp6CalculateExpireTime (
280 IN BOOLEAN IsFirstRt
,
281 IN BOOLEAN NeedSigned
290 // Take the 10bits of microsecond in system time as a uniform distribution.
291 // Take the 10th bit as a flag to determine it's signed or not.
293 gRT
->GetTime (&Time
, NULL
);
294 Seed
= ((Time
.Nanosecond
>> 10) & DHCP6_10_BIT_MASK
);
295 Signed
= (BOOLEAN
) ((((Time
.Nanosecond
>> 9) & 0x01) != 0) ? TRUE
: FALSE
);
296 Signed
= (BOOLEAN
) (NeedSigned
? Signed
: FALSE
);
299 // Calculate expire by the following algo:
300 // 1. base + base * (-0.1 ~ 0) for the first solicit
301 // 2. base + base * (-0.1 ~ 0.1) for the first other messages
302 // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages
303 // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout
305 // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).
307 if (IsFirstRt
&& Signed
) {
309 Expire
= Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
311 } else if (IsFirstRt
&& !Signed
) {
313 Expire
= Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
315 } else if (!IsFirstRt
&& Signed
) {
317 Expire
= 2 * Base
- (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
321 Expire
= 2 * Base
+ (UINT32
) (Base
* Seed
/ DHCP6_10_BIT_MASK
/ 10);
324 Expire
= (Expire
!= 0) ? Expire
: 1;
331 Calculate the lease time by the algorithm defined in rfc.
333 @param[in] IaCb The pointer to the Ia control block.
337 Dhcp6CalculateLeaseTime (
341 EFI_DHCP6_IA_ADDRESS
*IaAddr
;
346 ASSERT (IaCb
->Ia
->IaAddressCount
> 0);
348 MinLt
= (UINT32
) (-1);
352 // Calculate minlt as min of all valid life time, and maxlt as max of all
355 for (Index
= 0; Index
< IaCb
->Ia
->IaAddressCount
; Index
++) {
356 IaAddr
= IaCb
->Ia
->IaAddress
+ Index
* sizeof (EFI_DHCP6_IA_ADDRESS
);
357 MinLt
= MIN (MinLt
, IaAddr
->ValidLifetime
);
358 MaxLt
= MAX (MinLt
, IaAddr
->ValidLifetime
);
362 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
365 IaCb
->T1
= (IaCb
->T1
!= 0) ? IaCb
->T1
: (UINT32
)(MinLt
* 5 / 10);
366 IaCb
->T2
= (IaCb
->T2
!= 0) ? IaCb
->T2
: (UINT32
)(MinLt
* 8 / 10);
367 IaCb
->AllExpireTime
= MaxLt
;
373 Check whether the addresses are all included by the configured Ia.
375 @param[in] Ia The pointer to the Ia.
376 @param[in] AddressCount The number of addresses.
377 @param[in] Addresses The pointer to the addresses buffer.
379 @retval EFI_SUCCESS The addresses are all included by the configured IA.
380 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.
386 IN UINT32 AddressCount
,
387 IN EFI_IPv6_ADDRESS
*Addresses
395 // Check whether the addresses are all included by the configured IA. And it
396 // will return success if address count is zero, which means all addresses.
398 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
402 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
406 &Ia
->IaAddress
[Index2
],
407 sizeof (EFI_IPv6_ADDRESS
)
416 return EFI_NOT_FOUND
;
425 Deprive the addresses from current Ia, and generate another eliminated Ia.
427 @param[in] Ia The pointer to the Ia.
428 @param[in] AddressCount The number of addresses.
429 @param[in] Addresses The pointer to the addresses buffer.
431 @retval NULL If it failed to generate the deprived Ia.
432 @retval others The pointer to the deprived Ia.
436 Dhcp6DepriveAddress (
438 IN UINT32 AddressCount
,
439 IN EFI_IPv6_ADDRESS
*Addresses
442 EFI_DHCP6_IA
*IaCopy
;
448 if (AddressCount
== 0) {
450 // It means release all Ia addresses if address count is zero.
452 AddressCount
= Ia
->IaAddressCount
;
455 ASSERT (AddressCount
!= 0);
457 IaCopySize
= sizeof (EFI_DHCP6_IA
) + (AddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
458 IaCopy
= AllocateZeroPool (IaCopySize
);
460 if (IaCopy
== NULL
) {
464 if (AddressCount
== Ia
->IaAddressCount
) {
466 // If release all Ia addresses, just copy the configured Ia and then set
467 // its address count as zero.
468 // We may decline/release part of addresses at the begining. So it's a
469 // forwarding step to update address infor for decline/release, while the
470 // other infor such as Ia state will be updated when receiving reply.
472 CopyMem (IaCopy
, Ia
, IaCopySize
);
473 Ia
->IaAddressCount
= 0;
477 CopyMem (IaCopy
, Ia
, sizeof (EFI_DHCP6_IA
));
480 // Move the addresses from the Ia of instance to the deprived Ia.
482 for (Index1
= 0; Index1
< AddressCount
; Index1
++) {
486 for (Index2
= 0; Index2
< Ia
->IaAddressCount
; Index2
++) {
490 &Ia
->IaAddress
[Index2
],
491 sizeof (EFI_IPv6_ADDRESS
)
494 // Copy the deprived address to the copy of Ia
497 &IaCopy
->IaAddress
[Index1
],
498 &Ia
->IaAddress
[Index2
],
499 sizeof (EFI_DHCP6_IA_ADDRESS
)
502 // Delete the deprived address from the instance Ia
504 if (Index2
+ 1 < Ia
->IaAddressCount
) {
506 &Ia
->IaAddress
[Index2
],
507 &Ia
->IaAddress
[Index2
+ 1],
508 (Ia
->IaAddressCount
- Index2
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
)
515 ASSERT (Found
== TRUE
);
518 Ia
->IaAddressCount
-= AddressCount
;
519 IaCopy
->IaAddressCount
= AddressCount
;
526 The dummy ext buffer free callback routine.
528 @param[in] Arg The pointer to the parameter.
541 The callback routine once message transmitted.
543 @param[in] Wrap The pointer to the received net buffer.
544 @param[in] EndPoint The pointer to the udp end point.
545 @param[in] IoStatus The return status from udp io.
546 @param[in] Context The opaque parameter to the function.
553 IN UDP_END_POINT
*EndPoint
,
554 IN EFI_STATUS IoStatus
,
563 Append the option to Buf, and move Buf to the end.
565 @param[in, out] Buf The pointer to the buffer.
566 @param[in] OptType The option type.
567 @param[in] OptLen The length of option contents.
568 @param[in] Data The pointer to the option content.
570 @return Buf The position to append the next option.
582 // The format of Dhcp6 option:
584 // 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
585 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586 // | option-code | option-len (option data) |
587 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589 // | (option-len octets) |
590 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
593 ASSERT (OptLen
!= 0);
595 WriteUnaligned16 ((UINT16
*) Buf
, OptType
);
597 WriteUnaligned16 ((UINT16
*) Buf
, OptLen
);
599 CopyMem (Buf
, Data
, NTOHS (OptLen
));
600 Buf
+= NTOHS (OptLen
);
607 Append the appointed Ia option to Buf, and move Buf to the end.
609 @param[in, out] Buf The pointer to the position to append.
610 @param[in] Ia The pointer to the Ia.
611 @param[in] T1 The time of T1.
612 @param[in] T2 The time of T2.
614 @return Buf The position to append the next Ia option.
618 Dhcp6AppendIaOption (
631 // The format of IA_NA and IA_TA option:
633 // 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
634 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
635 // | OPTION_IA_NA | option-len |
636 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
637 // | IAID (4 octets) |
638 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
639 // | T1 (only for IA_NA) |
640 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
641 // | T2 (only for IA_NA) |
642 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
644 // . IA_NA-options/IA_TA-options .
646 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
650 // Fill the value of Ia option type
652 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Ia
->Descriptor
.Type
));
656 // Fill the len of Ia option later, keep the pointer first
658 Len
= (UINT16
*) Buf
;
662 // Fill the value of iaid
664 WriteUnaligned32 ((UINT32
*) Buf
, HTONL (Ia
->Descriptor
.IaId
));
668 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
670 if (Ia
->Descriptor
.Type
== Dhcp6OptIana
) {
671 WriteUnaligned32 ((UINT32
*) Buf
, ((T1
!= 0) ? T1
: 0xffffffff));
673 WriteUnaligned32 ((UINT32
*) Buf
, ((T2
!= 0) ? T2
: 0xffffffff));
678 // Fill all the addresses belong to the Ia
680 for (Index
= 0; Index
< Ia
->IaAddressCount
; Index
++) {
682 AddrOpt
= (UINT8
*) Ia
->IaAddress
+ Index
* sizeof (EFI_DHCP6_IA_ADDRESS
);
683 Length
= HTONS ((UINT16
) sizeof (EFI_DHCP6_IA_ADDRESS
));
684 Buf
= Dhcp6AppendOption (
686 HTONS (Dhcp6OptIaAddr
),
693 // Fill the value of Ia option length
695 *Len
= HTONS ((UINT16
) (Buf
- (UINT8
*) Len
- 2));
701 Append the appointed Elapsed time option to Buf, and move Buf to the end.
703 @param[in, out] Buf The pointer to the position to append.
704 @param[in] Instance The pointer to the Dhcp6 instance.
705 @param[out] Elapsed The pointer to the elapsed time value in
706 the generated packet.
708 @return Buf The position to append the next Ia option.
712 Dhcp6AppendETOption (
714 IN DHCP6_INSTANCE
*Instance
,
719 // The format of elapsed time option:
721 // 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
722 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
723 // | OPTION_ELAPSED_TIME | option-len |
724 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
726 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
730 // Fill the value of elapsed-time option type.
732 WriteUnaligned16 ((UINT16
*) Buf
, HTONS (Dhcp6OptElapsedTime
));
736 // Fill the len of elapsed-time option, which is fixed.
738 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(2));
742 // Fill in elapsed time value with 0 value for now. The actual value is
743 // filled in later just before the packet is transmitted.
745 WriteUnaligned16 ((UINT16
*) Buf
, HTONS(0));
746 *Elapsed
= (UINT16
*) Buf
;
753 Set the elapsed time based on the given instance and the pointer to the
756 @param[in] Elapsed The pointer to the position to append.
757 @param[in] Instance The pointer to the Dhcp6 instance.
763 IN DHCP6_INSTANCE
*Instance
768 UINT64 ElapsedTimeValue
;
771 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
773 gRT
->GetTime (&Time
, NULL
);
774 CurrentStamp
= (UINT64
)
776 ((((((Time
.Year
- 2000) * 360 +
777 (Time
.Month
- 1)) * 30 +
778 (Time
.Day
- 1)) * 24 + Time
.Hour
) * 60 +
779 Time
.Minute
) * 60 + Time
.Second
) * 100
780 + DivU64x32(Time
.Nanosecond
, 10000000)
784 // Sentinel value of 0 means that this is the first DHCP packet that we are
785 // sending and that we need to initialize the value. First DHCP Solicit
786 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
788 if (Instance
->StartTime
== 0) {
789 ElapsedTimeValue
= 0;
790 Instance
->StartTime
= CurrentStamp
;
792 ElapsedTimeValue
= CurrentStamp
- Instance
->StartTime
;
795 // If elapsed time cannot fit in two bytes, set it to 0xffff.
797 if (ElapsedTimeValue
> 0xffff) {
798 ElapsedTimeValue
= 0xffff;
801 WriteUnaligned16 (Elapsed
, HTONS((UINT16
) ElapsedTimeValue
));
806 Seek the address of the first byte of the option header.
808 @param[in] Buf The pointer to the buffer.
809 @param[in] SeekLen The length to seek.
810 @param[in] OptType The option type.
812 @retval NULL If it failed to seek the option.
813 @retval others The position to the option.
832 // The format of Dhcp6 option refers to Dhcp6AppendOption().
834 while (Cursor
< Buf
+ SeekLen
) {
835 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
836 if (OpCode
== HTONS (OptType
)) {
840 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
841 Cursor
+= (DataLen
+ 4);
849 Seek the address of the first byte of the Ia option header.
851 @param[in] Buf The pointer to the buffer.
852 @param[in] SeekLen The length to seek.
853 @param[in] IaDesc The pointer to the Ia descriptor.
855 @retval NULL If it failed to seek the Ia option.
856 @retval others The position to the Ia option.
863 IN EFI_DHCP6_IA_DESCRIPTOR
*IaDesc
873 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
878 while (Cursor
< Buf
+ SeekLen
) {
879 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
880 IaId
= ReadUnaligned32 ((UINT32
*) (Cursor
+ 4));
881 if (OpCode
== HTONS (IaDesc
->Type
) && IaId
== HTONL (IaDesc
->IaId
)) {
885 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
886 Cursor
+= (DataLen
+ 4);
894 Parse the address option and update the address infomation.
896 @param[in] IaInnerOpt The pointer to the buffer.
897 @param[in] IaInnerLen The length to parse.
898 @param[out] AddrNum The number of addresses.
899 @param[in, out] AddrBuf The pointer to the address buffer.
903 Dhcp6ParseAddrOption (
904 IN UINT8
*IaInnerOpt
,
905 IN UINT16 IaInnerLen
,
907 IN OUT EFI_DHCP6_IA_ADDRESS
*AddrBuf
916 // The format of the IA Address option:
918 // 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
919 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920 // | OPTION_IAADDR | option-len |
921 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
926 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
927 // | preferred-lifetime |
928 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
929 // | valid-lifetime |
930 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
932 // . IAaddr-options .
934 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
940 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
941 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner
942 // options to the addrbuf.
948 while (Cursor
< IaInnerOpt
+ IaInnerLen
) {
950 // Count the Ia address option with non-0 valid time.
952 OpCode
= ReadUnaligned16 ((UINT16
*) Cursor
);
953 ValidLt
= ReadUnaligned32 ((UINT32
*) (Cursor
+ 24));
954 if (OpCode
== HTONS (Dhcp6OptIaAddr
) && ValidLt
!= 0) {
956 if (AddrBuf
!= NULL
) {
957 CopyMem (AddrBuf
, Cursor
+ 4, sizeof (EFI_DHCP6_IA_ADDRESS
));
958 AddrBuf
->PreferredLifetime
= NTOHL (AddrBuf
->PreferredLifetime
);
959 AddrBuf
->ValidLifetime
= NTOHL (AddrBuf
->ValidLifetime
);
960 AddrBuf
= (EFI_DHCP6_IA_ADDRESS
*) ((UINT8
*) AddrBuf
+ sizeof (EFI_DHCP6_IA_ADDRESS
));
965 DataLen
= NTOHS (ReadUnaligned16 ((UINT16
*) (Cursor
+ 2)));
966 Cursor
+= (DataLen
+ 4);
972 Create a control blcok for the Ia according to the corresponding options.
974 @param[in] Instance The pointer to DHCP6 Instance.
975 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.
976 @param[in] IaInnerLen The length of all the inner options in the Ia option.
977 @param[in] T1 T1 time in the Ia option.
978 @param[in] T2 T2 time in the Ia option.
980 @retval EFI_NOT_FOUND No valid IA option is found.
981 @retval EFI_SUCCESS Create an IA control block successfully.
982 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
987 IN DHCP6_INSTANCE
*Instance
,
988 IN UINT8
*IaInnerOpt
,
989 IN UINT16 IaInnerLen
,
998 if (Instance
->IaCb
.Ia
== NULL
) {
999 return EFI_NOT_FOUND
;
1003 // Calculate the number of addresses for this Ia, excluding the addresses with
1004 // the value 0 of valid lifetime.
1006 Dhcp6ParseAddrOption (IaInnerOpt
, IaInnerLen
, &AddrNum
, NULL
);
1009 return EFI_NOT_FOUND
;
1013 // Allocate for new IA.
1015 IaSize
= sizeof (EFI_DHCP6_IA
) + (AddrNum
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1016 Ia
= AllocateZeroPool (IaSize
);
1019 return EFI_OUT_OF_RESOURCES
;
1023 // Fill up this new IA fields.
1025 Ia
->State
= Instance
->IaCb
.Ia
->State
;
1026 Ia
->IaAddressCount
= AddrNum
;
1027 CopyMem (&Ia
->Descriptor
, &Instance
->Config
->IaDescriptor
, sizeof (EFI_DHCP6_IA_DESCRIPTOR
));
1028 Dhcp6ParseAddrOption (IaInnerOpt
, IaInnerLen
, &AddrNum
, Ia
->IaAddress
);
1031 // Free original IA resource.
1033 if (Instance
->IaCb
.Ia
->ReplyPacket
!= NULL
) {
1034 FreePool (Instance
->IaCb
.Ia
->ReplyPacket
);
1036 FreePool (Instance
->IaCb
.Ia
);
1039 ZeroMem (&Instance
->IaCb
, sizeof (DHCP6_IA_CB
));
1042 // Update IaCb to use new IA.
1044 Instance
->IaCb
.Ia
= Ia
;
1048 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
1050 Instance
->IaCb
.T1
= T1
;
1051 Instance
->IaCb
.T2
= T2
;
1052 Dhcp6CalculateLeaseTime (&Instance
->IaCb
);
1059 Cache the current IA configuration information.
1061 @param[in] Instance The pointer to DHCP6 Instance.
1063 @retval EFI_SUCCESS Cache the current IA successfully.
1064 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1069 IN DHCP6_INSTANCE
*Instance
1075 Ia
= Instance
->IaCb
.Ia
;
1077 if ((Instance
->CacheIa
== NULL
) && (Ia
!= NULL
)) {
1079 // Cache the current IA.
1081 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1083 Instance
->CacheIa
= AllocateZeroPool (IaSize
);
1084 if (Instance
->CacheIa
== NULL
) {
1085 return EFI_OUT_OF_RESOURCES
;
1087 CopyMem (Instance
->CacheIa
, Ia
, IaSize
);
1093 Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
1095 @param[in] Instance The pointer to DHCP6 instance.
1099 Dhcp6AppendCacheIa (
1100 IN DHCP6_INSTANCE
*Instance
1108 EFI_DHCP6_IA
*NewIa
;
1109 EFI_DHCP6_IA
*CacheIa
;
1111 Ia
= Instance
->IaCb
.Ia
;
1112 CacheIa
= Instance
->CacheIa
;
1114 if ((CacheIa
!= NULL
) && (CacheIa
->IaAddressCount
!= 0)) {
1116 // There are old addresses existing. Merge with current addresses.
1118 NewIaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
+ CacheIa
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1119 NewIa
= AllocateZeroPool (NewIaSize
);
1120 if (NewIa
== NULL
) {
1124 IaSize
= sizeof (EFI_DHCP6_IA
) + (Ia
->IaAddressCount
- 1) * sizeof (EFI_DHCP6_IA_ADDRESS
);
1125 CopyMem (NewIa
, Ia
, IaSize
);
1128 // Clear old address.ValidLifetime
1130 for (Index
= 0; Index
< CacheIa
->IaAddressCount
; Index
++) {
1131 CacheIa
->IaAddress
[Index
].ValidLifetime
= 0;
1134 NewIa
->IaAddressCount
+= CacheIa
->IaAddressCount
;
1135 Ptr
= (UINT8
*)&NewIa
->IaAddress
[Ia
->IaAddressCount
];
1136 CopyMem (Ptr
, CacheIa
->IaAddress
, CacheIa
->IaAddressCount
* sizeof (EFI_DHCP6_IA_ADDRESS
));
1139 // Migrate to the NewIa and free previous.
1141 FreePool (Instance
->CacheIa
);
1142 FreePool (Instance
->IaCb
.Ia
);
1143 Instance
->CacheIa
= NULL
;
1144 Instance
->IaCb
.Ia
= NewIa
;