]>
Commit | Line | Data |
---|---|---|
a3bcde70 HT |
1 | /** @file\r |
2 | Dhcp6 support functions implementation.\r | |
3 | \r | |
c413813d | 4 | (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r |
f75a7f56 | 5 | Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r |
a3bcde70 | 6 | \r |
ecf98fbc | 7 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
a3bcde70 HT |
8 | \r |
9 | **/\r | |
10 | \r | |
11 | #include "Dhcp6Impl.h"\r | |
12 | \r | |
a3bcde70 HT |
13 | /**\r |
14 | Generate client Duid in the format of Duid-llt.\r | |
15 | \r | |
16 | @param[in] Mode The pointer to the mode of SNP.\r | |
17 | \r | |
18 | @retval NULL If it failed to generate a client Id.\r | |
19 | @retval others The pointer to the new client id.\r | |
20 | \r | |
21 | **/\r | |
22 | EFI_DHCP6_DUID *\r | |
23 | Dhcp6GenerateClientId (\r | |
d1050b9d | 24 | IN EFI_SIMPLE_NETWORK_MODE *Mode\r |
a3bcde70 HT |
25 | )\r |
26 | {\r | |
d1050b9d MK |
27 | EFI_STATUS Status;\r |
28 | EFI_DHCP6_DUID *Duid;\r | |
29 | EFI_TIME Time;\r | |
30 | UINT32 Stamp;\r | |
31 | EFI_GUID Uuid;\r | |
a3bcde70 HT |
32 | \r |
33 | //\r | |
34 | // Attempt to get client Id from variable to keep it constant.\r | |
35 | // See details in section-9 of rfc-3315.\r | |
36 | //\r | |
d1050b9d | 37 | GetVariable2 (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid, (VOID **)&Duid, NULL);\r |
a3bcde70 HT |
38 | if (Duid != NULL) {\r |
39 | return Duid;\r | |
40 | }\r | |
41 | \r | |
a3bcde70 HT |
42 | //\r |
43 | // The format of client identifier option:\r | |
44 | //\r | |
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\r | |
46 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
47 | // | OPTION_CLIENTID | option-len |\r | |
48 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
49 | // . .\r | |
50 | // . DUID .\r | |
51 | // . (variable length) .\r | |
52 | // . .\r | |
53 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
54 | //\r | |
a3bcde70 HT |
55 | \r |
56 | //\r | |
33c09637 | 57 | // If System UUID is found from SMBIOS Table, use DUID-UUID type.\r |
58 | //\r | |
03f9cc20 | 59 | if ((PcdGet8 (PcdDhcp6UidType) == Dhcp6DuidTypeUuid) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid)) && !CompareGuid (&Uuid, &gZeroGuid)) {\r |
33c09637 | 60 | //\r |
61 | //\r | |
62 | // The format of DUID-UUID:\r | |
f75a7f56 | 63 | //\r |
33c09637 | 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\r |
65 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
66 | // | DUID-Type (4) | UUID (128 bits) |\r | |
67 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |\r | |
68 | // | |\r | |
69 | // | |\r | |
70 | // | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
71 | // | |\r | |
72 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\r | |
73 | \r | |
74 | //\r | |
75 | // sizeof (option-len + Duid-type + UUID-size) = 20 bytes\r | |
76 | //\r | |
77 | Duid = AllocateZeroPool (2 + 2 + sizeof (EFI_GUID));\r | |
78 | if (Duid == NULL) {\r | |
79 | return NULL;\r | |
80 | }\r | |
81 | \r | |
82 | //\r | |
83 | // sizeof (Duid-type + UUID-size) = 18 bytes\r | |
84 | //\r | |
d1050b9d | 85 | Duid->Length = (UINT16)(18);\r |
f75a7f56 | 86 | \r |
33c09637 | 87 | //\r |
88 | // Set the Duid-type and copy UUID.\r | |
89 | //\r | |
d1050b9d | 90 | WriteUnaligned16 ((UINT16 *)(Duid->Duid), HTONS (Dhcp6DuidTypeUuid));\r |
33c09637 | 91 | \r |
d1050b9d | 92 | CopyMem (Duid->Duid + 2, &Uuid, sizeof (EFI_GUID));\r |
33c09637 | 93 | } else {\r |
33c09637 | 94 | //\r |
95 | //\r | |
96 | // The format of DUID-LLT:\r | |
97 | //\r | |
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\r | |
99 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
100 | // | Duid type (1) | hardware type (16 bits) |\r | |
101 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
102 | // | time (32 bits) |\r | |
103 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
104 | // . .\r | |
105 | // . link-layer address (variable length) .\r | |
106 | // . .\r | |
107 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
108 | //\r | |
109 | \r | |
110 | //\r | |
111 | // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.\r | |
112 | //\r | |
113 | gRT->GetTime (&Time, NULL);\r | |
114 | Stamp = (UINT32)\r | |
d1050b9d MK |
115 | (\r |
116 | ((((UINT32)(Time.Year - 2000) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) *\r | |
117 | 60 +\r | |
118 | Time.Second\r | |
119 | );\r | |
33c09637 | 120 | \r |
121 | //\r | |
122 | // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes\r | |
123 | //\r | |
124 | Duid = AllocateZeroPool (10 + Mode->HwAddressSize);\r | |
125 | if (Duid == NULL) {\r | |
126 | return NULL;\r | |
127 | }\r | |
f75a7f56 | 128 | \r |
33c09637 | 129 | //\r |
130 | // sizeof (Duid-type + hardware-type + time) = 8 bytes\r | |
131 | //\r | |
d1050b9d | 132 | Duid->Length = (UINT16)(Mode->HwAddressSize + 8);\r |
f75a7f56 | 133 | \r |
33c09637 | 134 | //\r |
135 | // Set the Duid-type, hardware-type, time and copy the hardware address.\r | |
136 | //\r | |
d1050b9d MK |
137 | WriteUnaligned16 ((UINT16 *)((UINT8 *)Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid)), HTONS (Dhcp6DuidTypeLlt));\r |
138 | WriteUnaligned16 ((UINT16 *)((UINT8 *)Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 2), HTONS (NET_IFTYPE_ETHERNET));\r | |
139 | WriteUnaligned32 ((UINT32 *)((UINT8 *)Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 4), HTONL (Stamp));\r | |
393a3169 | 140 | \r |
33c09637 | 141 | CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize);\r |
a3bcde70 HT |
142 | }\r |
143 | \r | |
a3bcde70 HT |
144 | Status = gRT->SetVariable (\r |
145 | L"ClientId",\r | |
146 | &gEfiDhcp6ServiceBindingProtocolGuid,\r | |
147 | (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),\r | |
148 | Duid->Length + 2,\r | |
d1050b9d | 149 | (VOID *)Duid\r |
a3bcde70 | 150 | );\r |
9c12f2d7 FS |
151 | if (EFI_ERROR (Status)) {\r |
152 | FreePool (Duid);\r | |
153 | return NULL;\r | |
154 | }\r | |
a3bcde70 HT |
155 | \r |
156 | return Duid;\r | |
157 | }\r | |
158 | \r | |
a3bcde70 HT |
159 | /**\r |
160 | Copy the Dhcp6 configure data.\r | |
161 | \r | |
162 | @param[in] DstCfg The pointer to the destination configure data.\r | |
163 | @param[in] SorCfg The pointer to the source configure data.\r | |
164 | \r | |
165 | @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully.\r | |
166 | @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r | |
167 | \r | |
168 | **/\r | |
169 | EFI_STATUS\r | |
170 | Dhcp6CopyConfigData (\r | |
d1050b9d MK |
171 | IN EFI_DHCP6_CONFIG_DATA *DstCfg,\r |
172 | IN EFI_DHCP6_CONFIG_DATA *SorCfg\r | |
a3bcde70 HT |
173 | )\r |
174 | {\r | |
d1050b9d MK |
175 | UINTN Index;\r |
176 | UINTN OptionListSize;\r | |
177 | UINTN OptionSize;\r | |
a3bcde70 HT |
178 | \r |
179 | CopyMem (DstCfg, SorCfg, sizeof (EFI_DHCP6_CONFIG_DATA));\r | |
180 | \r | |
181 | //\r | |
182 | // Allocate another buffer for solicitretransmission, and copy it.\r | |
183 | //\r | |
184 | if (SorCfg->SolicitRetransmission != NULL) {\r | |
a3bcde70 HT |
185 | DstCfg->SolicitRetransmission = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r |
186 | \r | |
187 | if (DstCfg->SolicitRetransmission == NULL) {\r | |
188 | //\r | |
189 | // Error will be handled out of this function.\r | |
190 | //\r | |
191 | return EFI_OUT_OF_RESOURCES;\r | |
192 | }\r | |
193 | \r | |
194 | CopyMem (\r | |
195 | DstCfg->SolicitRetransmission,\r | |
196 | SorCfg->SolicitRetransmission,\r | |
197 | sizeof (EFI_DHCP6_RETRANSMISSION)\r | |
198 | );\r | |
199 | }\r | |
200 | \r | |
d1050b9d | 201 | if ((SorCfg->OptionList != NULL) && (SorCfg->OptionCount != 0)) {\r |
a3bcde70 HT |
202 | OptionListSize = SorCfg->OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *);\r |
203 | DstCfg->OptionList = AllocateZeroPool (OptionListSize);\r | |
204 | \r | |
205 | if (DstCfg->OptionList == NULL) {\r | |
206 | //\r | |
207 | // Error will be handled out of this function.\r | |
208 | //\r | |
209 | return EFI_OUT_OF_RESOURCES;\r | |
210 | }\r | |
211 | \r | |
212 | for (Index = 0; Index < SorCfg->OptionCount; Index++) {\r | |
a3bcde70 HT |
213 | OptionSize = NTOHS (SorCfg->OptionList[Index]->OpLen) + 4;\r |
214 | DstCfg->OptionList[Index] = AllocateZeroPool (OptionSize);\r | |
215 | \r | |
216 | if (DstCfg->OptionList[Index] == NULL) {\r | |
217 | //\r | |
218 | // Error will be handled out of this function.\r | |
219 | //\r | |
220 | return EFI_OUT_OF_RESOURCES;\r | |
221 | }\r | |
222 | \r | |
223 | CopyMem (\r | |
224 | DstCfg->OptionList[Index],\r | |
225 | SorCfg->OptionList[Index],\r | |
226 | OptionSize\r | |
227 | );\r | |
228 | }\r | |
229 | }\r | |
230 | \r | |
231 | return EFI_SUCCESS;\r | |
232 | }\r | |
233 | \r | |
a3bcde70 HT |
234 | /**\r |
235 | Clean up the configure data.\r | |
236 | \r | |
237 | @param[in, out] CfgData The pointer to the configure data.\r | |
238 | \r | |
239 | **/\r | |
240 | VOID\r | |
241 | Dhcp6CleanupConfigData (\r | |
d1050b9d | 242 | IN OUT EFI_DHCP6_CONFIG_DATA *CfgData\r |
a3bcde70 HT |
243 | )\r |
244 | {\r | |
d1050b9d | 245 | UINTN Index;\r |
a3bcde70 HT |
246 | \r |
247 | ASSERT (CfgData != NULL);\r | |
248 | //\r | |
249 | // Clean up all fields in config data including the reference buffers, but do\r | |
250 | // not free the config data buffer itself.\r | |
251 | //\r | |
252 | if (CfgData->OptionList != NULL) {\r | |
253 | for (Index = 0; Index < CfgData->OptionCount; Index++) {\r | |
254 | if (CfgData->OptionList[Index] != NULL) {\r | |
255 | FreePool (CfgData->OptionList[Index]);\r | |
256 | }\r | |
257 | }\r | |
d1050b9d | 258 | \r |
a3bcde70 HT |
259 | FreePool (CfgData->OptionList);\r |
260 | }\r | |
261 | \r | |
262 | if (CfgData->SolicitRetransmission != NULL) {\r | |
263 | FreePool (CfgData->SolicitRetransmission);\r | |
264 | }\r | |
265 | \r | |
266 | ZeroMem (CfgData, sizeof (EFI_DHCP6_CONFIG_DATA));\r | |
267 | }\r | |
268 | \r | |
a3bcde70 HT |
269 | /**\r |
270 | Clean up the mode data.\r | |
271 | \r | |
272 | @param[in, out] ModeData The pointer to the mode data.\r | |
273 | \r | |
274 | **/\r | |
275 | VOID\r | |
276 | Dhcp6CleanupModeData (\r | |
d1050b9d | 277 | IN OUT EFI_DHCP6_MODE_DATA *ModeData\r |
a3bcde70 HT |
278 | )\r |
279 | {\r | |
280 | ASSERT (ModeData != NULL);\r | |
281 | //\r | |
282 | // Clean up all fields in mode data including the reference buffers, but do\r | |
283 | // not free the mode data buffer itself.\r | |
284 | //\r | |
285 | if (ModeData->ClientId != NULL) {\r | |
286 | FreePool (ModeData->ClientId);\r | |
287 | }\r | |
288 | \r | |
289 | if (ModeData->Ia != NULL) {\r | |
a3bcde70 HT |
290 | if (ModeData->Ia->ReplyPacket != NULL) {\r |
291 | FreePool (ModeData->Ia->ReplyPacket);\r | |
292 | }\r | |
d1050b9d | 293 | \r |
a3bcde70 HT |
294 | FreePool (ModeData->Ia);\r |
295 | }\r | |
296 | \r | |
297 | ZeroMem (ModeData, sizeof (EFI_DHCP6_MODE_DATA));\r | |
298 | }\r | |
299 | \r | |
a3bcde70 HT |
300 | /**\r |
301 | Calculate the expire time by the algorithm defined in rfc.\r | |
302 | \r | |
303 | @param[in] Base The base value of the time.\r | |
304 | @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time.\r | |
f97117ba | 305 | @param[in] NeedSigned If TRUE, the signed factor is needed.\r |
a3bcde70 HT |
306 | \r |
307 | @return Expire The calculated result for the new expire time.\r | |
308 | \r | |
309 | **/\r | |
310 | UINT32\r | |
311 | Dhcp6CalculateExpireTime (\r | |
d1050b9d MK |
312 | IN UINT32 Base,\r |
313 | IN BOOLEAN IsFirstRt,\r | |
314 | IN BOOLEAN NeedSigned\r | |
a3bcde70 HT |
315 | )\r |
316 | {\r | |
d1050b9d MK |
317 | EFI_TIME Time;\r |
318 | BOOLEAN Signed;\r | |
319 | UINT32 Seed;\r | |
320 | UINT32 Expire;\r | |
a3bcde70 HT |
321 | \r |
322 | //\r | |
323 | // Take the 10bits of microsecond in system time as a uniform distribution.\r | |
324 | // Take the 10th bit as a flag to determine it's signed or not.\r | |
325 | //\r | |
326 | gRT->GetTime (&Time, NULL);\r | |
327 | Seed = ((Time.Nanosecond >> 10) & DHCP6_10_BIT_MASK);\r | |
d1050b9d MK |
328 | Signed = (BOOLEAN)((((Time.Nanosecond >> 9) & 0x01) != 0) ? TRUE : FALSE);\r |
329 | Signed = (BOOLEAN)(NeedSigned ? Signed : FALSE);\r | |
a3bcde70 HT |
330 | \r |
331 | //\r | |
332 | // Calculate expire by the following algo:\r | |
333 | // 1. base + base * (-0.1 ~ 0) for the first solicit\r | |
334 | // 2. base + base * (-0.1 ~ 0.1) for the first other messages\r | |
335 | // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages\r | |
336 | // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout\r | |
337 | //\r | |
338 | // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).\r | |
339 | //\r | |
340 | if (IsFirstRt && Signed) {\r | |
d1050b9d | 341 | Expire = Base - (UINT32)(Base * Seed / DHCP6_10_BIT_MASK / 10);\r |
a3bcde70 | 342 | } else if (IsFirstRt && !Signed) {\r |
d1050b9d | 343 | Expire = Base + (UINT32)(Base * Seed / DHCP6_10_BIT_MASK / 10);\r |
a3bcde70 | 344 | } else if (!IsFirstRt && Signed) {\r |
d1050b9d | 345 | Expire = 2 * Base - (UINT32)(Base * Seed / DHCP6_10_BIT_MASK / 10);\r |
a3bcde70 | 346 | } else {\r |
d1050b9d | 347 | Expire = 2 * Base + (UINT32)(Base * Seed / DHCP6_10_BIT_MASK / 10);\r |
a3bcde70 HT |
348 | }\r |
349 | \r | |
350 | Expire = (Expire != 0) ? Expire : 1;\r | |
351 | \r | |
352 | return Expire;\r | |
353 | }\r | |
354 | \r | |
a3bcde70 HT |
355 | /**\r |
356 | Calculate the lease time by the algorithm defined in rfc.\r | |
357 | \r | |
358 | @param[in] IaCb The pointer to the Ia control block.\r | |
359 | \r | |
360 | **/\r | |
361 | VOID\r | |
362 | Dhcp6CalculateLeaseTime (\r | |
d1050b9d | 363 | IN DHCP6_IA_CB *IaCb\r |
a3bcde70 HT |
364 | )\r |
365 | {\r | |
d1050b9d MK |
366 | UINT32 MinLt;\r |
367 | UINT32 MaxLt;\r | |
368 | UINTN Index;\r | |
a3bcde70 HT |
369 | \r |
370 | ASSERT (IaCb->Ia->IaAddressCount > 0);\r | |
371 | \r | |
d1050b9d MK |
372 | MinLt = (UINT32)(-1);\r |
373 | MaxLt = 0;\r | |
a3bcde70 HT |
374 | \r |
375 | //\r | |
376 | // Calculate minlt as min of all valid life time, and maxlt as max of all\r | |
377 | // valid life time.\r | |
378 | //\r | |
379 | for (Index = 0; Index < IaCb->Ia->IaAddressCount; Index++) {\r | |
d1050b9d MK |
380 | MinLt = MIN (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime);\r |
381 | MaxLt = MAX (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime);\r | |
a3bcde70 HT |
382 | }\r |
383 | \r | |
384 | //\r | |
385 | // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer\r | |
386 | // such information.\r | |
387 | //\r | |
388 | IaCb->T1 = (IaCb->T1 != 0) ? IaCb->T1 : (UINT32)(MinLt * 5 / 10);\r | |
389 | IaCb->T2 = (IaCb->T2 != 0) ? IaCb->T2 : (UINT32)(MinLt * 8 / 10);\r | |
390 | IaCb->AllExpireTime = MaxLt;\r | |
391 | IaCb->LeaseTime = 0;\r | |
392 | }\r | |
393 | \r | |
a3bcde70 HT |
394 | /**\r |
395 | Check whether the addresses are all included by the configured Ia.\r | |
396 | \r | |
397 | @param[in] Ia The pointer to the Ia.\r | |
398 | @param[in] AddressCount The number of addresses.\r | |
399 | @param[in] Addresses The pointer to the addresses buffer.\r | |
400 | \r | |
401 | @retval EFI_SUCCESS The addresses are all included by the configured IA.\r | |
402 | @retval EFI_NOT_FOUND The addresses are not included by the configured IA.\r | |
403 | \r | |
404 | **/\r | |
405 | EFI_STATUS\r | |
406 | Dhcp6CheckAddress (\r | |
d1050b9d MK |
407 | IN EFI_DHCP6_IA *Ia,\r |
408 | IN UINT32 AddressCount,\r | |
409 | IN EFI_IPv6_ADDRESS *Addresses\r | |
a3bcde70 HT |
410 | )\r |
411 | {\r | |
d1050b9d MK |
412 | UINTN Index1;\r |
413 | UINTN Index2;\r | |
414 | BOOLEAN Found;\r | |
a3bcde70 HT |
415 | \r |
416 | //\r | |
417 | // Check whether the addresses are all included by the configured IA. And it\r | |
418 | // will return success if address count is zero, which means all addresses.\r | |
419 | //\r | |
420 | for (Index1 = 0; Index1 < AddressCount; Index1++) {\r | |
a3bcde70 HT |
421 | Found = FALSE;\r |
422 | \r | |
423 | for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r | |
a3bcde70 HT |
424 | if (CompareMem (\r |
425 | &Addresses[Index1],\r | |
426 | &Ia->IaAddress[Index2],\r | |
427 | sizeof (EFI_IPv6_ADDRESS)\r | |
d1050b9d MK |
428 | ) == 0)\r |
429 | {\r | |
a3bcde70 HT |
430 | Found = TRUE;\r |
431 | break;\r | |
432 | }\r | |
433 | }\r | |
434 | \r | |
435 | if (!Found) {\r | |
436 | return EFI_NOT_FOUND;\r | |
437 | }\r | |
438 | }\r | |
439 | \r | |
440 | return EFI_SUCCESS;\r | |
441 | }\r | |
442 | \r | |
a3bcde70 HT |
443 | /**\r |
444 | Deprive the addresses from current Ia, and generate another eliminated Ia.\r | |
445 | \r | |
446 | @param[in] Ia The pointer to the Ia.\r | |
447 | @param[in] AddressCount The number of addresses.\r | |
448 | @param[in] Addresses The pointer to the addresses buffer.\r | |
449 | \r | |
450 | @retval NULL If it failed to generate the deprived Ia.\r | |
451 | @retval others The pointer to the deprived Ia.\r | |
452 | \r | |
453 | **/\r | |
454 | EFI_DHCP6_IA *\r | |
455 | Dhcp6DepriveAddress (\r | |
d1050b9d MK |
456 | IN EFI_DHCP6_IA *Ia,\r |
457 | IN UINT32 AddressCount,\r | |
458 | IN EFI_IPv6_ADDRESS *Addresses\r | |
a3bcde70 HT |
459 | )\r |
460 | {\r | |
d1050b9d MK |
461 | EFI_DHCP6_IA *IaCopy;\r |
462 | UINTN IaCopySize;\r | |
463 | UINTN Index1;\r | |
464 | UINTN Index2;\r | |
465 | BOOLEAN Found;\r | |
a3bcde70 HT |
466 | \r |
467 | if (AddressCount == 0) {\r | |
468 | //\r | |
469 | // It means release all Ia addresses if address count is zero.\r | |
470 | //\r | |
471 | AddressCount = Ia->IaAddressCount;\r | |
472 | }\r | |
473 | \r | |
474 | ASSERT (AddressCount != 0);\r | |
475 | \r | |
476 | IaCopySize = sizeof (EFI_DHCP6_IA) + (AddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r | |
477 | IaCopy = AllocateZeroPool (IaCopySize);\r | |
478 | \r | |
479 | if (IaCopy == NULL) {\r | |
480 | return NULL;\r | |
481 | }\r | |
482 | \r | |
483 | if (AddressCount == Ia->IaAddressCount) {\r | |
484 | //\r | |
485 | // If release all Ia addresses, just copy the configured Ia and then set\r | |
486 | // its address count as zero.\r | |
f97117ba | 487 | // We may decline/release part of addresses at the beginning. So it's a\r |
a3bcde70 HT |
488 | // forwarding step to update address infor for decline/release, while the\r |
489 | // other infor such as Ia state will be updated when receiving reply.\r | |
490 | //\r | |
491 | CopyMem (IaCopy, Ia, IaCopySize);\r | |
492 | Ia->IaAddressCount = 0;\r | |
493 | return IaCopy;\r | |
494 | }\r | |
495 | \r | |
496 | CopyMem (IaCopy, Ia, sizeof (EFI_DHCP6_IA));\r | |
497 | \r | |
498 | //\r | |
499 | // Move the addresses from the Ia of instance to the deprived Ia.\r | |
500 | //\r | |
501 | for (Index1 = 0; Index1 < AddressCount; Index1++) {\r | |
a3bcde70 HT |
502 | Found = FALSE;\r |
503 | \r | |
504 | for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r | |
a3bcde70 HT |
505 | if (CompareMem (\r |
506 | &Addresses[Index1],\r | |
507 | &Ia->IaAddress[Index2],\r | |
508 | sizeof (EFI_IPv6_ADDRESS)\r | |
d1050b9d MK |
509 | ) == 0)\r |
510 | {\r | |
a3bcde70 HT |
511 | //\r |
512 | // Copy the deprived address to the copy of Ia\r | |
513 | //\r | |
514 | CopyMem (\r | |
515 | &IaCopy->IaAddress[Index1],\r | |
516 | &Ia->IaAddress[Index2],\r | |
517 | sizeof (EFI_DHCP6_IA_ADDRESS)\r | |
518 | );\r | |
519 | //\r | |
520 | // Delete the deprived address from the instance Ia\r | |
521 | //\r | |
522 | if (Index2 + 1 < Ia->IaAddressCount) {\r | |
523 | CopyMem (\r | |
524 | &Ia->IaAddress[Index2],\r | |
525 | &Ia->IaAddress[Index2 + 1],\r | |
526 | (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)\r | |
527 | );\r | |
528 | }\r | |
d1050b9d | 529 | \r |
a3bcde70 HT |
530 | Found = TRUE;\r |
531 | break;\r | |
532 | }\r | |
533 | }\r | |
d1050b9d | 534 | \r |
a3bcde70 HT |
535 | ASSERT (Found == TRUE);\r |
536 | }\r | |
537 | \r | |
538 | Ia->IaAddressCount -= AddressCount;\r | |
539 | IaCopy->IaAddressCount = AddressCount;\r | |
540 | \r | |
541 | return IaCopy;\r | |
542 | }\r | |
543 | \r | |
a3bcde70 HT |
544 | /**\r |
545 | The dummy ext buffer free callback routine.\r | |
546 | \r | |
547 | @param[in] Arg The pointer to the parameter.\r | |
548 | \r | |
549 | **/\r | |
550 | VOID\r | |
551 | EFIAPI\r | |
552 | Dhcp6DummyExtFree (\r | |
d1050b9d | 553 | IN VOID *Arg\r |
a3bcde70 HT |
554 | )\r |
555 | {\r | |
556 | }\r | |
557 | \r | |
a3bcde70 HT |
558 | /**\r |
559 | The callback routine once message transmitted.\r | |
560 | \r | |
76389e18 | 561 | @param[in] Wrap The pointer to the received net buffer.\r |
a3bcde70 HT |
562 | @param[in] EndPoint The pointer to the udp end point.\r |
563 | @param[in] IoStatus The return status from udp io.\r | |
564 | @param[in] Context The opaque parameter to the function.\r | |
565 | \r | |
566 | **/\r | |
567 | VOID\r | |
568 | EFIAPI\r | |
569 | Dhcp6OnTransmitted (\r | |
d1050b9d MK |
570 | IN NET_BUF *Wrap,\r |
571 | IN UDP_END_POINT *EndPoint,\r | |
572 | IN EFI_STATUS IoStatus,\r | |
573 | IN VOID *Context\r | |
a3bcde70 HT |
574 | )\r |
575 | {\r | |
576 | NetbufFree (Wrap);\r | |
577 | }\r | |
578 | \r | |
a3bcde70 HT |
579 | /**\r |
580 | Append the option to Buf, and move Buf to the end.\r | |
581 | \r | |
582 | @param[in, out] Buf The pointer to the buffer.\r | |
583 | @param[in] OptType The option type.\r | |
584 | @param[in] OptLen The length of option contents.\r | |
585 | @param[in] Data The pointer to the option content.\r | |
586 | \r | |
587 | @return Buf The position to append the next option.\r | |
588 | \r | |
589 | **/\r | |
590 | UINT8 *\r | |
591 | Dhcp6AppendOption (\r | |
d1050b9d MK |
592 | IN OUT UINT8 *Buf,\r |
593 | IN UINT16 OptType,\r | |
594 | IN UINT16 OptLen,\r | |
595 | IN UINT8 *Data\r | |
a3bcde70 HT |
596 | )\r |
597 | {\r | |
598 | //\r | |
599 | // The format of Dhcp6 option:\r | |
600 | //\r | |
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\r | |
602 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
603 | // | option-code | option-len (option data) |\r | |
604 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
605 | // | option-data |\r | |
606 | // | (option-len octets) |\r | |
607 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
608 | //\r | |
609 | \r | |
610 | ASSERT (OptLen != 0);\r | |
611 | \r | |
d1050b9d MK |
612 | WriteUnaligned16 ((UINT16 *)Buf, OptType);\r |
613 | Buf += 2;\r | |
614 | WriteUnaligned16 ((UINT16 *)Buf, OptLen);\r | |
615 | Buf += 2;\r | |
a3bcde70 | 616 | CopyMem (Buf, Data, NTOHS (OptLen));\r |
d1050b9d | 617 | Buf += NTOHS (OptLen);\r |
a3bcde70 HT |
618 | \r |
619 | return Buf;\r | |
620 | }\r | |
621 | \r | |
685e44a5 | 622 | /**\r |
623 | Append the appointed IA Address option to Buf, and move Buf to the end.\r | |
624 | \r | |
625 | @param[in, out] Buf The pointer to the position to append.\r | |
626 | @param[in] IaAddr The pointer to the IA Address.\r | |
627 | @param[in] MessageType Message type of DHCP6 package.\r | |
628 | \r | |
629 | @return Buf The position to append the next option.\r | |
630 | \r | |
631 | **/\r | |
632 | UINT8 *\r | |
633 | Dhcp6AppendIaAddrOption (\r | |
d1050b9d MK |
634 | IN OUT UINT8 *Buf,\r |
635 | IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r | |
636 | IN UINT32 MessageType\r | |
637 | )\r | |
685e44a5 | 638 | {\r |
685e44a5 | 639 | // The format of the IA Address option is:\r |
640 | //\r | |
641 | // 0 1 2 3\r | |
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\r | |
643 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
644 | // | OPTION_IAADDR | option-len |\r | |
645 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
646 | // | |\r | |
647 | // | IPv6 address |\r | |
648 | // | |\r | |
649 | // | |\r | |
650 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
651 | // | preferred-lifetime |\r | |
652 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
653 | // | valid-lifetime |\r | |
654 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
655 | // . .\r | |
656 | // . IAaddr-options .\r | |
657 | // . .\r | |
658 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
f75a7f56 | 659 | \r |
685e44a5 | 660 | //\r |
661 | // Fill the value of Ia Address option type\r | |
662 | //\r | |
d1050b9d MK |
663 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptIaAddr));\r |
664 | Buf += 2;\r | |
685e44a5 | 665 | \r |
d1050b9d MK |
666 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r |
667 | Buf += 2;\r | |
685e44a5 | 668 | \r |
d1050b9d MK |
669 | CopyMem (Buf, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS));\r |
670 | Buf += sizeof (EFI_IPv6_ADDRESS);\r | |
685e44a5 | 671 | \r |
672 | //\r | |
673 | // Fill the value of preferred-lifetime and valid-lifetime.\r | |
674 | // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields\r | |
675 | // should set to 0 when initiate a Confirm message.\r | |
676 | //\r | |
677 | if (MessageType != Dhcp6MsgConfirm) {\r | |
d1050b9d | 678 | WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->PreferredLifetime));\r |
685e44a5 | 679 | }\r |
d1050b9d MK |
680 | \r |
681 | Buf += 4;\r | |
685e44a5 | 682 | \r |
683 | if (MessageType != Dhcp6MsgConfirm) {\r | |
d1050b9d | 684 | WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->ValidLifetime));\r |
685e44a5 | 685 | }\r |
d1050b9d MK |
686 | \r |
687 | Buf += 4;\r | |
685e44a5 | 688 | \r |
689 | return Buf;\r | |
690 | }\r | |
691 | \r | |
a3bcde70 HT |
692 | /**\r |
693 | Append the appointed Ia option to Buf, and move Buf to the end.\r | |
694 | \r | |
695 | @param[in, out] Buf The pointer to the position to append.\r | |
696 | @param[in] Ia The pointer to the Ia.\r | |
697 | @param[in] T1 The time of T1.\r | |
698 | @param[in] T2 The time of T2.\r | |
685e44a5 | 699 | @param[in] MessageType Message type of DHCP6 package.\r |
a3bcde70 HT |
700 | \r |
701 | @return Buf The position to append the next Ia option.\r | |
702 | \r | |
703 | **/\r | |
704 | UINT8 *\r | |
705 | Dhcp6AppendIaOption (\r | |
d1050b9d MK |
706 | IN OUT UINT8 *Buf,\r |
707 | IN EFI_DHCP6_IA *Ia,\r | |
708 | IN UINT32 T1,\r | |
709 | IN UINT32 T2,\r | |
710 | IN UINT32 MessageType\r | |
a3bcde70 HT |
711 | )\r |
712 | {\r | |
d1050b9d MK |
713 | UINT8 *AddrOpt;\r |
714 | UINT16 *Len;\r | |
715 | UINTN Index;\r | |
a3bcde70 HT |
716 | \r |
717 | //\r | |
718 | // The format of IA_NA and IA_TA option:\r | |
719 | //\r | |
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\r | |
721 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
722 | // | OPTION_IA_NA | option-len |\r | |
723 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
724 | // | IAID (4 octets) |\r | |
725 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
726 | // | T1 (only for IA_NA) |\r | |
727 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
728 | // | T2 (only for IA_NA) |\r | |
729 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
730 | // | |\r | |
731 | // . IA_NA-options/IA_TA-options .\r | |
732 | // . .\r | |
733 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
734 | //\r | |
735 | \r | |
736 | //\r | |
737 | // Fill the value of Ia option type\r | |
738 | //\r | |
d1050b9d MK |
739 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (Ia->Descriptor.Type));\r |
740 | Buf += 2;\r | |
a3bcde70 HT |
741 | \r |
742 | //\r | |
743 | // Fill the len of Ia option later, keep the pointer first\r | |
744 | //\r | |
d1050b9d MK |
745 | Len = (UINT16 *)Buf;\r |
746 | Buf += 2;\r | |
a3bcde70 HT |
747 | \r |
748 | //\r | |
749 | // Fill the value of iaid\r | |
750 | //\r | |
d1050b9d MK |
751 | WriteUnaligned32 ((UINT32 *)Buf, HTONL (Ia->Descriptor.IaId));\r |
752 | Buf += 4;\r | |
a3bcde70 HT |
753 | \r |
754 | //\r | |
755 | // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.\r | |
756 | //\r | |
757 | if (Ia->Descriptor.Type == Dhcp6OptIana) {\r | |
d1050b9d MK |
758 | WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r |
759 | Buf += 4;\r | |
760 | WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r | |
761 | Buf += 4;\r | |
a3bcde70 HT |
762 | }\r |
763 | \r | |
764 | //\r | |
765 | // Fill all the addresses belong to the Ia\r | |
766 | //\r | |
767 | for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r | |
d1050b9d MK |
768 | AddrOpt = (UINT8 *)Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r |
769 | Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType);\r | |
a3bcde70 HT |
770 | }\r |
771 | \r | |
772 | //\r | |
773 | // Fill the value of Ia option length\r | |
774 | //\r | |
d1050b9d | 775 | *Len = HTONS ((UINT16)(Buf - (UINT8 *)Len - 2));\r |
a3bcde70 HT |
776 | \r |
777 | return Buf;\r | |
778 | }\r | |
779 | \r | |
780 | /**\r | |
781 | Append the appointed Elapsed time option to Buf, and move Buf to the end.\r | |
782 | \r | |
783 | @param[in, out] Buf The pointer to the position to append.\r | |
784 | @param[in] Instance The pointer to the Dhcp6 instance.\r | |
785 | @param[out] Elapsed The pointer to the elapsed time value in\r | |
786 | the generated packet.\r | |
787 | \r | |
788 | @return Buf The position to append the next Ia option.\r | |
789 | \r | |
790 | **/\r | |
791 | UINT8 *\r | |
792 | Dhcp6AppendETOption (\r | |
d1050b9d MK |
793 | IN OUT UINT8 *Buf,\r |
794 | IN DHCP6_INSTANCE *Instance,\r | |
795 | OUT UINT16 **Elapsed\r | |
a3bcde70 HT |
796 | )\r |
797 | {\r | |
798 | //\r | |
799 | // The format of elapsed time option:\r | |
800 | //\r | |
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\r | |
802 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
803 | // | OPTION_ELAPSED_TIME | option-len |\r | |
804 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
805 | // | elapsed-time |\r | |
806 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
807 | //\r | |
808 | \r | |
809 | //\r | |
810 | // Fill the value of elapsed-time option type.\r | |
811 | //\r | |
d1050b9d MK |
812 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptElapsedTime));\r |
813 | Buf += 2;\r | |
a3bcde70 HT |
814 | \r |
815 | //\r | |
816 | // Fill the len of elapsed-time option, which is fixed.\r | |
817 | //\r | |
d1050b9d MK |
818 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (2));\r |
819 | Buf += 2;\r | |
a3bcde70 HT |
820 | \r |
821 | //\r | |
822 | // Fill in elapsed time value with 0 value for now. The actual value is\r | |
823 | // filled in later just before the packet is transmitted.\r | |
824 | //\r | |
d1050b9d MK |
825 | WriteUnaligned16 ((UINT16 *)Buf, HTONS (0));\r |
826 | *Elapsed = (UINT16 *)Buf;\r | |
827 | Buf += 2;\r | |
a3bcde70 HT |
828 | \r |
829 | return Buf;\r | |
830 | }\r | |
831 | \r | |
832 | /**\r | |
833 | Set the elapsed time based on the given instance and the pointer to the\r | |
834 | elapsed time option.\r | |
835 | \r | |
836 | @param[in] Elapsed The pointer to the position to append.\r | |
837 | @param[in] Instance The pointer to the Dhcp6 instance.\r | |
838 | \r | |
839 | **/\r | |
840 | VOID\r | |
841 | SetElapsedTime (\r | |
d1050b9d MK |
842 | IN UINT16 *Elapsed,\r |
843 | IN DHCP6_INSTANCE *Instance\r | |
a3bcde70 HT |
844 | )\r |
845 | {\r | |
d1050b9d MK |
846 | EFI_TIME Time;\r |
847 | UINT64 CurrentStamp;\r | |
848 | UINT64 ElapsedTimeValue;\r | |
a3bcde70 HT |
849 | \r |
850 | //\r | |
851 | // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.\r | |
852 | //\r | |
853 | gRT->GetTime (&Time, NULL);\r | |
ddc6d41d JW |
854 | CurrentStamp = MultU64x32 (\r |
855 | ((((UINT32)(Time.Year - 2000) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second,\r | |
856 | 100\r | |
857 | ) +\r | |
d1050b9d | 858 | DivU64x32 (\r |
ddc6d41d JW |
859 | Time.Nanosecond,\r |
860 | 10000000\r | |
861 | );\r | |
a3bcde70 HT |
862 | \r |
863 | //\r | |
864 | // Sentinel value of 0 means that this is the first DHCP packet that we are\r | |
685e44a5 | 865 | // sending and that we need to initialize the value. First DHCP message\r |
a3bcde70 HT |
866 | // gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r |
867 | //\r | |
868 | if (Instance->StartTime == 0) {\r | |
d1050b9d | 869 | ElapsedTimeValue = 0;\r |
a3bcde70 HT |
870 | Instance->StartTime = CurrentStamp;\r |
871 | } else {\r | |
872 | ElapsedTimeValue = CurrentStamp - Instance->StartTime;\r | |
873 | \r | |
874 | //\r | |
875 | // If elapsed time cannot fit in two bytes, set it to 0xffff.\r | |
876 | //\r | |
877 | if (ElapsedTimeValue > 0xffff) {\r | |
878 | ElapsedTimeValue = 0xffff;\r | |
879 | }\r | |
880 | }\r | |
a3bcde70 | 881 | \r |
d1050b9d MK |
882 | WriteUnaligned16 (Elapsed, HTONS ((UINT16)ElapsedTimeValue));\r |
883 | }\r | |
a3bcde70 HT |
884 | \r |
885 | /**\r | |
886 | Seek the address of the first byte of the option header.\r | |
887 | \r | |
888 | @param[in] Buf The pointer to the buffer.\r | |
889 | @param[in] SeekLen The length to seek.\r | |
890 | @param[in] OptType The option type.\r | |
891 | \r | |
892 | @retval NULL If it failed to seek the option.\r | |
893 | @retval others The position to the option.\r | |
894 | \r | |
895 | **/\r | |
896 | UINT8 *\r | |
897 | Dhcp6SeekOption (\r | |
d1050b9d MK |
898 | IN UINT8 *Buf,\r |
899 | IN UINT32 SeekLen,\r | |
900 | IN UINT16 OptType\r | |
a3bcde70 HT |
901 | )\r |
902 | {\r | |
d1050b9d MK |
903 | UINT8 *Cursor;\r |
904 | UINT8 *Option;\r | |
905 | UINT16 DataLen;\r | |
906 | UINT16 OpCode;\r | |
a3bcde70 HT |
907 | \r |
908 | Option = NULL;\r | |
909 | Cursor = Buf;\r | |
910 | \r | |
911 | //\r | |
912 | // The format of Dhcp6 option refers to Dhcp6AppendOption().\r | |
913 | //\r | |
914 | while (Cursor < Buf + SeekLen) {\r | |
d1050b9d | 915 | OpCode = ReadUnaligned16 ((UINT16 *)Cursor);\r |
a3bcde70 HT |
916 | if (OpCode == HTONS (OptType)) {\r |
917 | Option = Cursor;\r | |
918 | break;\r | |
919 | }\r | |
d1050b9d MK |
920 | \r |
921 | DataLen = NTOHS (ReadUnaligned16 ((UINT16 *)(Cursor + 2)));\r | |
a3bcde70 HT |
922 | Cursor += (DataLen + 4);\r |
923 | }\r | |
924 | \r | |
925 | return Option;\r | |
926 | }\r | |
927 | \r | |
a3bcde70 HT |
928 | /**\r |
929 | Seek the address of the first byte of the Ia option header.\r | |
930 | \r | |
931 | @param[in] Buf The pointer to the buffer.\r | |
932 | @param[in] SeekLen The length to seek.\r | |
933 | @param[in] IaDesc The pointer to the Ia descriptor.\r | |
934 | \r | |
935 | @retval NULL If it failed to seek the Ia option.\r | |
936 | @retval others The position to the Ia option.\r | |
937 | \r | |
938 | **/\r | |
939 | UINT8 *\r | |
940 | Dhcp6SeekIaOption (\r | |
941 | IN UINT8 *Buf,\r | |
942 | IN UINT32 SeekLen,\r | |
943 | IN EFI_DHCP6_IA_DESCRIPTOR *IaDesc\r | |
944 | )\r | |
945 | {\r | |
d1050b9d MK |
946 | UINT8 *Cursor;\r |
947 | UINT8 *Option;\r | |
948 | UINT16 DataLen;\r | |
949 | UINT16 OpCode;\r | |
950 | UINT32 IaId;\r | |
a3bcde70 HT |
951 | \r |
952 | //\r | |
953 | // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().\r | |
954 | //\r | |
955 | Option = NULL;\r | |
956 | Cursor = Buf;\r | |
957 | \r | |
958 | while (Cursor < Buf + SeekLen) {\r | |
d1050b9d MK |
959 | OpCode = ReadUnaligned16 ((UINT16 *)Cursor);\r |
960 | IaId = ReadUnaligned32 ((UINT32 *)(Cursor + 4));\r | |
961 | if ((OpCode == HTONS (IaDesc->Type)) && (IaId == HTONL (IaDesc->IaId))) {\r | |
a3bcde70 HT |
962 | Option = Cursor;\r |
963 | break;\r | |
964 | }\r | |
d1050b9d MK |
965 | \r |
966 | DataLen = NTOHS (ReadUnaligned16 ((UINT16 *)(Cursor + 2)));\r | |
a3bcde70 HT |
967 | Cursor += (DataLen + 4);\r |
968 | }\r | |
969 | \r | |
970 | return Option;\r | |
971 | }\r | |
972 | \r | |
685e44a5 | 973 | /**\r |
f75a7f56 | 974 | Check whether the incoming IPv6 address in IaAddr is one of the maintained\r |
f97117ba | 975 | addresses in the IA control block.\r |
685e44a5 | 976 | \r |
977 | @param[in] IaAddr The pointer to the IA Address to be checked.\r | |
978 | @param[in] CurrentIa The pointer to the IA in IA control block.\r | |
979 | \r | |
980 | @retval TRUE Yes, this Address is already in IA control block.\r | |
981 | @retval FALSE No, this Address is NOT in IA control block.\r | |
982 | \r | |
983 | **/\r | |
984 | BOOLEAN\r | |
985 | Dhcp6AddrIsInCurrentIa (\r | |
d1050b9d MK |
986 | IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r |
987 | IN EFI_DHCP6_IA *CurrentIa\r | |
685e44a5 | 988 | )\r |
989 | {\r | |
d1050b9d | 990 | UINT32 Index;\r |
685e44a5 | 991 | \r |
992 | ASSERT (IaAddr != NULL && CurrentIa != NULL);\r | |
f75a7f56 | 993 | \r |
685e44a5 | 994 | for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {\r |
d1050b9d | 995 | if (EFI_IP6_EQUAL (&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {\r |
685e44a5 | 996 | return TRUE;\r |
997 | }\r | |
998 | }\r | |
d1050b9d | 999 | \r |
685e44a5 | 1000 | return FALSE;\r |
1001 | }\r | |
a3bcde70 HT |
1002 | \r |
1003 | /**\r | |
f97117ba | 1004 | Parse the address option and update the address information.\r |
a3bcde70 | 1005 | \r |
f97117ba | 1006 | @param[in] CurrentIa The pointer to the Ia Address in control block.\r |
a3bcde70 HT |
1007 | @param[in] IaInnerOpt The pointer to the buffer.\r |
1008 | @param[in] IaInnerLen The length to parse.\r | |
1009 | @param[out] AddrNum The number of addresses.\r | |
1010 | @param[in, out] AddrBuf The pointer to the address buffer.\r | |
1011 | \r | |
1012 | **/\r | |
1013 | VOID\r | |
1014 | Dhcp6ParseAddrOption (\r | |
d1050b9d MK |
1015 | IN EFI_DHCP6_IA *CurrentIa,\r |
1016 | IN UINT8 *IaInnerOpt,\r | |
1017 | IN UINT16 IaInnerLen,\r | |
1018 | OUT UINT32 *AddrNum,\r | |
1019 | IN OUT EFI_DHCP6_IA_ADDRESS *AddrBuf\r | |
a3bcde70 HT |
1020 | )\r |
1021 | {\r | |
d1050b9d MK |
1022 | UINT8 *Cursor;\r |
1023 | UINT16 DataLen;\r | |
1024 | UINT16 OpCode;\r | |
1025 | UINT32 ValidLt;\r | |
1026 | UINT32 PreferredLt;\r | |
1027 | EFI_DHCP6_IA_ADDRESS *IaAddr;\r | |
a3bcde70 HT |
1028 | \r |
1029 | //\r | |
1030 | // The format of the IA Address option:\r | |
1031 | //\r | |
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\r | |
1033 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1034 | // | OPTION_IAADDR | option-len |\r | |
1035 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1036 | // | |\r | |
1037 | // | IPv6 address |\r | |
1038 | // | |\r | |
1039 | // | |\r | |
1040 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1041 | // | preferred-lifetime |\r | |
1042 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1043 | // | valid-lifetime |\r | |
1044 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1045 | // . .\r | |
1046 | // . IAaddr-options .\r | |
1047 | // . .\r | |
1048 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r | |
1049 | //\r | |
1050 | \r | |
1051 | //\r | |
1052 | // Two usage model:\r | |
1053 | //\r | |
1054 | // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.\r | |
1055 | // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner\r | |
1056 | // options to the addrbuf.\r | |
1057 | //\r | |
1058 | \r | |
1059 | Cursor = IaInnerOpt;\r | |
1060 | *AddrNum = 0;\r | |
1061 | \r | |
1062 | while (Cursor < IaInnerOpt + IaInnerLen) {\r | |
1063 | //\r | |
685e44a5 | 1064 | // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option\r |
1065 | // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.\r | |
a3bcde70 | 1066 | //\r |
d1050b9d MK |
1067 | OpCode = ReadUnaligned16 ((UINT16 *)Cursor);\r |
1068 | PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *)(Cursor + 20)));\r | |
1069 | ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *)(Cursor + 24)));\r | |
1070 | IaAddr = (EFI_DHCP6_IA_ADDRESS *)(Cursor + 4);\r | |
1071 | if ((OpCode == HTONS (Dhcp6OptIaAddr)) && (ValidLt >= PreferredLt) &&\r | |
1072 | (Dhcp6AddrIsInCurrentIa (IaAddr, CurrentIa) || (ValidLt != 0)))\r | |
1073 | {\r | |
a3bcde70 | 1074 | if (AddrBuf != NULL) {\r |
685e44a5 | 1075 | CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));\r |
1076 | AddrBuf->PreferredLifetime = PreferredLt;\r | |
1077 | AddrBuf->ValidLifetime = ValidLt;\r | |
d1050b9d | 1078 | AddrBuf = (EFI_DHCP6_IA_ADDRESS *)((UINT8 *)AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));\r |
a3bcde70 | 1079 | }\r |
d1050b9d | 1080 | \r |
a3bcde70 HT |
1081 | (*AddrNum)++;\r |
1082 | }\r | |
d1050b9d MK |
1083 | \r |
1084 | DataLen = NTOHS (ReadUnaligned16 ((UINT16 *)(Cursor + 2)));\r | |
a3bcde70 HT |
1085 | Cursor += (DataLen + 4);\r |
1086 | }\r | |
1087 | }\r | |
1088 | \r | |
a3bcde70 | 1089 | /**\r |
f97117ba | 1090 | Create a control block for the Ia according to the corresponding options.\r |
a3bcde70 HT |
1091 | \r |
1092 | @param[in] Instance The pointer to DHCP6 Instance.\r | |
1093 | @param[in] IaInnerOpt The pointer to the inner options in the Ia option.\r | |
1094 | @param[in] IaInnerLen The length of all the inner options in the Ia option.\r | |
1095 | @param[in] T1 T1 time in the Ia option.\r | |
1096 | @param[in] T2 T2 time in the Ia option.\r | |
1097 | \r | |
1098 | @retval EFI_NOT_FOUND No valid IA option is found.\r | |
1099 | @retval EFI_SUCCESS Create an IA control block successfully.\r | |
1100 | @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r | |
685e44a5 | 1101 | @retval EFI_DEVICE_ERROR An unexpected error.\r |
a3bcde70 HT |
1102 | \r |
1103 | **/\r | |
1104 | EFI_STATUS\r | |
1105 | Dhcp6GenerateIaCb (\r | |
d1050b9d MK |
1106 | IN DHCP6_INSTANCE *Instance,\r |
1107 | IN UINT8 *IaInnerOpt,\r | |
1108 | IN UINT16 IaInnerLen,\r | |
1109 | IN UINT32 T1,\r | |
1110 | IN UINT32 T2\r | |
a3bcde70 HT |
1111 | )\r |
1112 | {\r | |
d1050b9d MK |
1113 | UINT32 AddrNum;\r |
1114 | UINT32 IaSize;\r | |
1115 | EFI_DHCP6_IA *Ia;\r | |
a3bcde70 HT |
1116 | \r |
1117 | if (Instance->IaCb.Ia == NULL) {\r | |
685e44a5 | 1118 | return EFI_DEVICE_ERROR;\r |
a3bcde70 HT |
1119 | }\r |
1120 | \r | |
1121 | //\r | |
1122 | // Calculate the number of addresses for this Ia, excluding the addresses with\r | |
1123 | // the value 0 of valid lifetime.\r | |
1124 | //\r | |
685e44a5 | 1125 | Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r |
a3bcde70 HT |
1126 | \r |
1127 | if (AddrNum == 0) {\r | |
1128 | return EFI_NOT_FOUND;\r | |
1129 | }\r | |
1130 | \r | |
1131 | //\r | |
1132 | // Allocate for new IA.\r | |
1133 | //\r | |
1134 | IaSize = sizeof (EFI_DHCP6_IA) + (AddrNum - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r | |
d1050b9d | 1135 | Ia = AllocateZeroPool (IaSize);\r |
a3bcde70 HT |
1136 | \r |
1137 | if (Ia == NULL) {\r | |
1138 | return EFI_OUT_OF_RESOURCES;\r | |
1139 | }\r | |
1140 | \r | |
1141 | //\r | |
1142 | // Fill up this new IA fields.\r | |
1143 | //\r | |
1144 | Ia->State = Instance->IaCb.Ia->State;\r | |
1145 | Ia->IaAddressCount = AddrNum;\r | |
1146 | CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));\r | |
685e44a5 | 1147 | Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r |
a3bcde70 HT |
1148 | \r |
1149 | //\r | |
1150 | // Free original IA resource.\r | |
1151 | //\r | |
1152 | if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r | |
1153 | FreePool (Instance->IaCb.Ia->ReplyPacket);\r | |
1154 | }\r | |
a3bcde70 | 1155 | \r |
d1050b9d | 1156 | FreePool (Instance->IaCb.Ia);\r |
a3bcde70 HT |
1157 | \r |
1158 | ZeroMem (&Instance->IaCb, sizeof (DHCP6_IA_CB));\r | |
1159 | \r | |
1160 | //\r | |
1161 | // Update IaCb to use new IA.\r | |
1162 | //\r | |
d1050b9d | 1163 | Instance->IaCb.Ia = Ia;\r |
a3bcde70 HT |
1164 | \r |
1165 | //\r | |
1166 | \r | |
d1050b9d | 1167 | // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.\r |
a3bcde70 HT |
1168 | //\r |
1169 | Instance->IaCb.T1 = T1;\r | |
1170 | Instance->IaCb.T2 = T2;\r | |
1171 | Dhcp6CalculateLeaseTime (&Instance->IaCb);\r | |
1172 | \r | |
1173 | return EFI_SUCCESS;\r | |
1174 | }\r | |
1175 | \r | |
a3bcde70 HT |
1176 | /**\r |
1177 | Cache the current IA configuration information.\r | |
1178 | \r | |
1179 | @param[in] Instance The pointer to DHCP6 Instance.\r | |
1180 | \r | |
1181 | @retval EFI_SUCCESS Cache the current IA successfully.\r | |
1182 | @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r | |
1183 | \r | |
1184 | **/\r | |
1185 | EFI_STATUS\r | |
1186 | Dhcp6CacheIa (\r | |
d1050b9d | 1187 | IN DHCP6_INSTANCE *Instance\r |
a3bcde70 HT |
1188 | )\r |
1189 | {\r | |
d1050b9d MK |
1190 | UINTN IaSize;\r |
1191 | EFI_DHCP6_IA *Ia;\r | |
a3bcde70 HT |
1192 | \r |
1193 | Ia = Instance->IaCb.Ia;\r | |
1194 | \r | |
1195 | if ((Instance->CacheIa == NULL) && (Ia != NULL)) {\r | |
1196 | //\r | |
1197 | // Cache the current IA.\r | |
1198 | //\r | |
1199 | IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r | |
1200 | \r | |
1201 | Instance->CacheIa = AllocateZeroPool (IaSize);\r | |
1202 | if (Instance->CacheIa == NULL) {\r | |
1203 | return EFI_OUT_OF_RESOURCES;\r | |
1204 | }\r | |
d1050b9d | 1205 | \r |
a3bcde70 HT |
1206 | CopyMem (Instance->CacheIa, Ia, IaSize);\r |
1207 | }\r | |
d1050b9d | 1208 | \r |
a3bcde70 HT |
1209 | return EFI_SUCCESS;\r |
1210 | }\r | |
1211 | \r | |
1212 | /**\r | |
f97117ba | 1213 | Append CacheIa to the current IA. Meanwhile, clear CacheIa.ValidLifetime to 0.\r |
a3bcde70 HT |
1214 | \r |
1215 | @param[in] Instance The pointer to DHCP6 instance.\r | |
1216 | \r | |
1217 | **/\r | |
1218 | VOID\r | |
1219 | Dhcp6AppendCacheIa (\r | |
d1050b9d | 1220 | IN DHCP6_INSTANCE *Instance\r |
a3bcde70 HT |
1221 | )\r |
1222 | {\r | |
d1050b9d MK |
1223 | UINT8 *Ptr;\r |
1224 | UINTN Index;\r | |
1225 | UINTN IaSize;\r | |
1226 | UINTN NewIaSize;\r | |
1227 | EFI_DHCP6_IA *Ia;\r | |
1228 | EFI_DHCP6_IA *NewIa;\r | |
1229 | EFI_DHCP6_IA *CacheIa;\r | |
a3bcde70 HT |
1230 | \r |
1231 | Ia = Instance->IaCb.Ia;\r | |
1232 | CacheIa = Instance->CacheIa;\r | |
1233 | \r | |
1234 | if ((CacheIa != NULL) && (CacheIa->IaAddressCount != 0)) {\r | |
1235 | //\r | |
1236 | // There are old addresses existing. Merge with current addresses.\r | |
1237 | //\r | |
1238 | NewIaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount + CacheIa->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r | |
1239 | NewIa = AllocateZeroPool (NewIaSize);\r | |
1240 | if (NewIa == NULL) {\r | |
1241 | return;\r | |
1242 | }\r | |
1243 | \r | |
1244 | IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r | |
1245 | CopyMem (NewIa, Ia, IaSize);\r | |
1246 | \r | |
1247 | //\r | |
1248 | // Clear old address.ValidLifetime\r | |
1249 | //\r | |
1250 | for (Index = 0; Index < CacheIa->IaAddressCount; Index++) {\r | |
d1050b9d | 1251 | CacheIa->IaAddress[Index].ValidLifetime = 0;\r |
a3bcde70 HT |
1252 | }\r |
1253 | \r | |
1254 | NewIa->IaAddressCount += CacheIa->IaAddressCount;\r | |
d1050b9d | 1255 | Ptr = (UINT8 *)&NewIa->IaAddress[Ia->IaAddressCount];\r |
a3bcde70 HT |
1256 | CopyMem (Ptr, CacheIa->IaAddress, CacheIa->IaAddressCount * sizeof (EFI_DHCP6_IA_ADDRESS));\r |
1257 | \r | |
1258 | //\r | |
1259 | // Migrate to the NewIa and free previous.\r | |
1260 | //\r | |
1261 | FreePool (Instance->CacheIa);\r | |
1262 | FreePool (Instance->IaCb.Ia);\r | |
d1050b9d MK |
1263 | Instance->CacheIa = NULL;\r |
1264 | Instance->IaCb.Ia = NewIa;\r | |
a3bcde70 HT |
1265 | }\r |
1266 | }\r | |
cc658224 | 1267 | \r |
1268 | /**\r | |
f97117ba | 1269 | Calculate the Dhcp6 get mapping timeout by adding additional delay to the IP6 DAD transmits count.\r |
cc658224 | 1270 | \r |
1271 | @param[in] Ip6Cfg The pointer to Ip6 config protocol.\r | |
1272 | @param[out] TimeOut The time out value in 100ns units.\r | |
1273 | \r | |
1274 | @retval EFI_INVALID_PARAMETER Input parameters are invalid.\r | |
1275 | @retval EFI_SUCCESS Calculate the time out value successfully.\r | |
1276 | **/\r | |
1277 | EFI_STATUS\r | |
1278 | Dhcp6GetMappingTimeOut (\r | |
d1050b9d MK |
1279 | IN EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg,\r |
1280 | OUT UINTN *TimeOut\r | |
f75a7f56 | 1281 | )\r |
cc658224 | 1282 | {\r |
d1050b9d MK |
1283 | EFI_STATUS Status;\r |
1284 | UINTN DataSize;\r | |
1285 | EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;\r | |
cc658224 | 1286 | \r |
d1050b9d | 1287 | if ((Ip6Cfg == NULL) || (TimeOut == NULL)) {\r |
cc658224 | 1288 | return EFI_INVALID_PARAMETER;\r |
1289 | }\r | |
1290 | \r | |
1291 | DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r | |
d1050b9d MK |
1292 | Status = Ip6Cfg->GetData (\r |
1293 | Ip6Cfg,\r | |
1294 | Ip6ConfigDataTypeDupAddrDetectTransmits,\r | |
1295 | &DataSize,\r | |
1296 | &DadXmits\r | |
1297 | );\r | |
cc658224 | 1298 | if (EFI_ERROR (Status)) {\r |
1299 | return Status;\r | |
1300 | }\r | |
f75a7f56 | 1301 | \r |
cc658224 | 1302 | *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY;\r |
f75a7f56 | 1303 | \r |
cc658224 | 1304 | return EFI_SUCCESS;\r |
1305 | }\r |