]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
3\r
8f586b85 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
9f4f29cb 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 "PxeBcImpl.h"\r
12\r
d40002ba 13//\r
14// Well-known multi-cast address defined in section-24.1 of rfc-3315\r
15//\r
16// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2\r
17//\r
d1050b9d
MK
18EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {\r
19 { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 }\r
20};\r
a3bcde70
HT
21\r
22/**\r
23 Parse out a DHCPv6 option by OptTag, and find the position in buffer.\r
24\r
25 @param[in] Buffer The pointer to the option buffer.\r
26 @param[in] Length Length of the option buffer.\r
27 @param[in] OptTag The required option tag.\r
28\r
29 @retval NULL Failed to parse the required option.\r
5add2c55 30 @retval Others The position of the required option in buffer.\r
a3bcde70
HT
31\r
32**/\r
33EFI_DHCP6_PACKET_OPTION *\r
34PxeBcParseDhcp6Options (\r
d1050b9d
MK
35 IN UINT8 *Buffer,\r
36 IN UINT32 Length,\r
37 IN UINT16 OptTag\r
a3bcde70
HT
38 )\r
39{\r
d1050b9d
MK
40 EFI_DHCP6_PACKET_OPTION *Option;\r
41 UINT32 Offset;\r
a3bcde70 42\r
d1050b9d
MK
43 Option = (EFI_DHCP6_PACKET_OPTION *)Buffer;\r
44 Offset = 0;\r
a3bcde70
HT
45\r
46 //\r
47 // OpLen and OpCode here are both stored in network order.\r
48 //\r
49 while (Offset < Length) {\r
a3bcde70 50 if (NTOHS (Option->OpCode) == OptTag) {\r
a3bcde70
HT
51 return Option;\r
52 }\r
53\r
d1050b9d
MK
54 Offset += (NTOHS (Option->OpLen) + 4);\r
55 Option = (EFI_DHCP6_PACKET_OPTION *)(Buffer + Offset);\r
a3bcde70
HT
56 }\r
57\r
58 return NULL;\r
59}\r
60\r
a3bcde70
HT
61/**\r
62 Build the options buffer for the DHCPv6 request packet.\r
63\r
64 @param[in] Private The pointer to PxeBc private data.\r
65 @param[out] OptList The pointer to the option pointer array.\r
66 @param[in] Buffer The pointer to the buffer to contain the option list.\r
67\r
68 @return Index The count of the built-in options.\r
69\r
70**/\r
71UINT32\r
72PxeBcBuildDhcp6Options (\r
d1050b9d
MK
73 IN PXEBC_PRIVATE_DATA *Private,\r
74 OUT EFI_DHCP6_PACKET_OPTION **OptList,\r
75 IN UINT8 *Buffer\r
a3bcde70
HT
76 )\r
77{\r
d1050b9d
MK
78 PXEBC_DHCP6_OPTION_ENTRY OptEnt;\r
79 UINT32 Index;\r
80 UINT16 Value;\r
a3bcde70 81\r
d1050b9d
MK
82 Index = 0;\r
83 OptList[0] = (EFI_DHCP6_PACKET_OPTION *)Buffer;\r
a3bcde70
HT
84\r
85 //\r
86 // Append client option request option\r
87 //\r
d1050b9d
MK
88 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO);\r
89 OptList[Index]->OpLen = HTONS (8);\r
90 OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *)OptList[Index]->Data;\r
91 OptEnt.Oro->OpCode[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL);\r
92 OptEnt.Oro->OpCode[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM);\r
93 OptEnt.Oro->OpCode[2] = HTONS (DHCP6_OPT_DNS_SERVERS);\r
94 OptEnt.Oro->OpCode[3] = HTONS (DHCP6_OPT_VENDOR_CLASS);\r
a3bcde70 95 Index++;\r
d1050b9d 96 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
a3bcde70
HT
97\r
98 //\r
99 // Append client network device interface option\r
100 //\r
d1050b9d
MK
101 OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI);\r
102 OptList[Index]->OpLen = HTONS ((UINT16)3);\r
103 OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *)OptList[Index]->Data;\r
a3bcde70
HT
104\r
105 if (Private->Nii != NULL) {\r
d1050b9d
MK
106 OptEnt.Undi->Type = Private->Nii->Type;\r
107 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
108 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
a3bcde70 109 } else {\r
d1050b9d
MK
110 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
111 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
112 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
a3bcde70
HT
113 }\r
114\r
a3bcde70 115 Index++;\r
d1050b9d 116 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
a3bcde70
HT
117\r
118 //\r
119 // Append client system architecture option\r
120 //\r
d1050b9d
MK
121 OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH);\r
122 OptList[Index]->OpLen = HTONS ((UINT16)sizeof (PXEBC_DHCP6_OPTION_ARCH));\r
123 OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *)OptList[Index]->Data;\r
124 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);\r
a3bcde70
HT
125 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
126 Index++;\r
d1050b9d 127 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
a3bcde70
HT
128\r
129 //\r
130 // Append vendor class option to store the PXE class identifier.\r
131 //\r
142c00c3 132 OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS);\r
d1050b9d
MK
133 OptList[Index]->OpLen = HTONS ((UINT16)sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS));\r
134 OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *)OptList[Index]->Data;\r
a3bcde70 135 OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);\r
d1050b9d 136 OptEnt.VendorClass->ClassLen = HTONS ((UINT16)sizeof (PXEBC_CLASS_ID));\r
a3bcde70
HT
137 CopyMem (\r
138 &OptEnt.VendorClass->ClassId,\r
139 DEFAULT_CLASS_ID_DATA,\r
140 sizeof (PXEBC_CLASS_ID)\r
141 );\r
142 PxeBcUintnToAscDecWithFormat (\r
143 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,\r
144 OptEnt.VendorClass->ClassId.ArchitectureType,\r
145 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)\r
146 );\r
147\r
148 if (Private->Nii != NULL) {\r
149 CopyMem (\r
150 OptEnt.VendorClass->ClassId.InterfaceName,\r
151 Private->Nii->StringId,\r
152 sizeof (OptEnt.VendorClass->ClassId.InterfaceName)\r
153 );\r
154 PxeBcUintnToAscDecWithFormat (\r
155 Private->Nii->MajorVer,\r
156 OptEnt.VendorClass->ClassId.UndiMajor,\r
157 sizeof (OptEnt.VendorClass->ClassId.UndiMajor)\r
158 );\r
159 PxeBcUintnToAscDecWithFormat (\r
160 Private->Nii->MinorVer,\r
161 OptEnt.VendorClass->ClassId.UndiMinor,\r
162 sizeof (OptEnt.VendorClass->ClassId.UndiMinor)\r
163 );\r
164 }\r
165\r
166 Index++;\r
167\r
168 return Index;\r
169}\r
170\r
a3bcde70
HT
171/**\r
172 Cache the DHCPv6 packet.\r
173\r
174 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.\r
175 @param[in] Src The pointer to the DHCPv6 packet to be cached.\r
176\r
a35dc649
FS
177 @retval EFI_SUCCESS Packet is copied.\r
178 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
179\r
a3bcde70 180**/\r
a35dc649 181EFI_STATUS\r
a3bcde70 182PxeBcCacheDhcp6Packet (\r
d1050b9d
MK
183 IN EFI_DHCP6_PACKET *Dst,\r
184 IN EFI_DHCP6_PACKET *Src\r
a3bcde70
HT
185 )\r
186{\r
a35dc649
FS
187 if (Dst->Size < Src->Length) {\r
188 return EFI_BUFFER_TOO_SMALL;\r
189 }\r
a3bcde70
HT
190\r
191 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
192 Dst->Length = Src->Length;\r
a35dc649
FS
193\r
194 return EFI_SUCCESS;\r
a3bcde70
HT
195}\r
196\r
6692d519
ZL
197/**\r
198 Retrieve the boot server address using the EFI_DNS6_PROTOCOL.\r
199\r
200 @param[in] Private Pointer to PxeBc private data.\r
201 @param[in] HostName Pointer to buffer containing hostname.\r
202 @param[out] IpAddress On output, pointer to buffer containing IPv6 address.\r
203\r
204 @retval EFI_SUCCESS Operation succeeded.\r
205 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.\r
206 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
207 @retval Others Other errors as indicated.\r
f75a7f56 208\r
6692d519
ZL
209**/\r
210EFI_STATUS\r
211PxeBcDns6 (\r
d1050b9d
MK
212 IN PXEBC_PRIVATE_DATA *Private,\r
213 IN CHAR16 *HostName,\r
214 OUT EFI_IPv6_ADDRESS *IpAddress\r
6692d519
ZL
215 )\r
216{\r
d1050b9d
MK
217 EFI_STATUS Status;\r
218 EFI_DNS6_PROTOCOL *Dns6;\r
219 EFI_DNS6_CONFIG_DATA Dns6ConfigData;\r
220 EFI_DNS6_COMPLETION_TOKEN Token;\r
221 EFI_HANDLE Dns6Handle;\r
222 EFI_IPv6_ADDRESS *DnsServerList;\r
223 BOOLEAN IsDone;\r
224\r
225 Dns6 = NULL;\r
226 Dns6Handle = NULL;\r
227 DnsServerList = Private->DnsServer;\r
6692d519
ZL
228 ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));\r
229\r
230 //\r
231 // Create a DNSv6 child instance and get the protocol.\r
232 //\r
233 Status = NetLibCreateServiceChild (\r
234 Private->Controller,\r
235 Private->Image,\r
236 &gEfiDns6ServiceBindingProtocolGuid,\r
237 &Dns6Handle\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
240 goto Exit;\r
f75a7f56
LG
241 }\r
242\r
6692d519
ZL
243 Status = gBS->OpenProtocol (\r
244 Dns6Handle,\r
245 &gEfiDns6ProtocolGuid,\r
d1050b9d 246 (VOID **)&Dns6,\r
6692d519
ZL
247 Private->Image,\r
248 Private->Controller,\r
249 EFI_OPEN_PROTOCOL_BY_DRIVER\r
250 );\r
251 if (EFI_ERROR (Status)) {\r
252 goto Exit;\r
253 }\r
254\r
255 //\r
256 // Configure DNS6 instance for the DNS server address and protocol.\r
257 //\r
258 ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));\r
259 Dns6ConfigData.DnsServerCount = 1;\r
260 Dns6ConfigData.DnsServerList = DnsServerList;\r
261 Dns6ConfigData.EnableDnsCache = TRUE;\r
262 Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP;\r
263 IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6);\r
264 Status = Dns6->Configure (\r
265 Dns6,\r
266 &Dns6ConfigData\r
267 );\r
268 if (EFI_ERROR (Status)) {\r
269 goto Exit;\r
270 }\r
271\r
272 Token.Status = EFI_NOT_READY;\r
273 IsDone = FALSE;\r
274 //\r
275 // Create event to set the IsDone flag when name resolution is finished.\r
276 //\r
277 Status = gBS->CreateEvent (\r
278 EVT_NOTIFY_SIGNAL,\r
279 TPL_NOTIFY,\r
280 PxeBcCommonNotify,\r
281 &IsDone,\r
282 &Token.Event\r
283 );\r
284 if (EFI_ERROR (Status)) {\r
285 goto Exit;\r
286 }\r
287\r
288 //\r
289 // Start asynchronous name resolution.\r
290 //\r
291 Status = Dns6->HostNameToIp (Dns6, HostName, &Token);\r
292 if (EFI_ERROR (Status)) {\r
293 goto Exit;\r
294 }\r
295\r
296 while (!IsDone) {\r
297 Dns6->Poll (Dns6);\r
298 }\r
299\r
300 //\r
301 // Name resolution is done, check result.\r
302 //\r
f75a7f56 303 Status = Token.Status;\r
6692d519
ZL
304 if (!EFI_ERROR (Status)) {\r
305 if (Token.RspData.H2AData == NULL) {\r
306 Status = EFI_DEVICE_ERROR;\r
307 goto Exit;\r
308 }\r
d1050b9d
MK
309\r
310 if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) {\r
6692d519
ZL
311 Status = EFI_DEVICE_ERROR;\r
312 goto Exit;\r
313 }\r
d1050b9d 314\r
6692d519
ZL
315 //\r
316 // We just return the first IPv6 address from DNS protocol.\r
317 //\r
318 IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);\r
319 Status = EFI_SUCCESS;\r
320 }\r
f75a7f56 321\r
6692d519
ZL
322Exit:\r
323 FreePool (HostName);\r
324\r
325 if (Token.Event != NULL) {\r
326 gBS->CloseEvent (Token.Event);\r
327 }\r
d1050b9d 328\r
6692d519
ZL
329 if (Token.RspData.H2AData != NULL) {\r
330 if (Token.RspData.H2AData->IpList != NULL) {\r
331 FreePool (Token.RspData.H2AData->IpList);\r
332 }\r
d1050b9d 333\r
6692d519
ZL
334 FreePool (Token.RspData.H2AData);\r
335 }\r
336\r
337 if (Dns6 != NULL) {\r
338 Dns6->Configure (Dns6, NULL);\r
f75a7f56 339\r
6692d519
ZL
340 gBS->CloseProtocol (\r
341 Dns6Handle,\r
342 &gEfiDns6ProtocolGuid,\r
343 Private->Image,\r
344 Private->Controller\r
345 );\r
346 }\r
347\r
348 if (Dns6Handle != NULL) {\r
349 NetLibDestroyServiceChild (\r
350 Private->Controller,\r
351 Private->Image,\r
352 &gEfiDns6ServiceBindingProtocolGuid,\r
353 Dns6Handle\r
354 );\r
355 }\r
356\r
357 if (DnsServerList != NULL) {\r
358 FreePool (DnsServerList);\r
359 }\r
f75a7f56
LG
360\r
361 return Status;\r
6692d519 362}\r
a3bcde70
HT
363\r
364/**\r
365 Parse the Boot File URL option.\r
366\r
6692d519 367 @param[in] Private Pointer to PxeBc private data.\r
a3bcde70
HT
368 @param[out] FileName The pointer to the boot file name.\r
369 @param[in, out] SrvAddr The pointer to the boot server address.\r
370 @param[in] BootFile The pointer to the boot file URL option data.\r
371 @param[in] Length The length of the boot file URL option data.\r
372\r
373 @retval EFI_ABORTED User cancel operation.\r
374 @retval EFI_SUCCESS Selected the boot menu successfully.\r
5add2c55 375 @retval EFI_NOT_READY Read the input key from the keyboard has not finish.\r
a3bcde70
HT
376\r
377**/\r
378EFI_STATUS\r
379PxeBcExtractBootFileUrl (\r
d1050b9d
MK
380 IN PXEBC_PRIVATE_DATA *Private,\r
381 OUT UINT8 **FileName,\r
382 IN OUT EFI_IPv6_ADDRESS *SrvAddr,\r
383 IN CHAR8 *BootFile,\r
384 IN UINT16 Length\r
a3bcde70
HT
385 )\r
386{\r
d1050b9d
MK
387 UINT16 PrefixLen;\r
388 CHAR8 *BootFileNamePtr;\r
389 CHAR8 *BootFileName;\r
390 UINT16 BootFileNameLen;\r
391 CHAR8 *TmpStr;\r
392 CHAR8 TmpChar;\r
393 CHAR8 *ServerAddressOption;\r
394 CHAR8 *ServerAddress;\r
395 CHAR8 *ModeStr;\r
396 CHAR16 *HostName;\r
397 BOOLEAN IpExpressedUrl;\r
398 UINTN Len;\r
399 EFI_STATUS Status;\r
a3bcde70 400\r
6692d519 401 IpExpressedUrl = TRUE;\r
a3bcde70
HT
402 //\r
403 // The format of the Boot File URL option is:\r
404 //\r
405 // 0 1 2 3\r
406 // 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
407 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
408 // | OPT_BOOTFILE_URL | option-len |\r
409 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
410 // | |\r
411 // . bootfile-url (variable length) .\r
412 // | |\r
413 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
414 //\r
415\r
416 //\r
6692d519
ZL
417 // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be\r
418 // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME\r
a3bcde70
HT
419 // As an example where the BOOTFILE_NAME is the EFI loader and\r
420 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
421 //\r
d1050b9d 422 PrefixLen = (UINT16)AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX);\r
a3bcde70 423\r
d1050b9d
MK
424 if ((Length <= PrefixLen) ||\r
425 (CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0))\r
426 {\r
a3bcde70
HT
427 return EFI_NOT_FOUND;\r
428 }\r
429\r
430 BootFile = BootFile + PrefixLen;\r
d1050b9d 431 Length = (UINT16)(Length - PrefixLen);\r
a3bcde70 432\r
d1050b9d 433 TmpStr = (CHAR8 *)AllocateZeroPool (Length + 1);\r
a3bcde70
HT
434 if (TmpStr == NULL) {\r
435 return EFI_OUT_OF_RESOURCES;\r
436 }\r
437\r
438 CopyMem (TmpStr, BootFile, Length);\r
439 TmpStr[Length] = '\0';\r
440\r
441 //\r
442 // Get the part of SERVER_ADDRESS string.\r
443 //\r
444 ServerAddressOption = TmpStr;\r
6692d519 445 if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) {\r
d1050b9d 446 ServerAddressOption++;\r
6692d519
ZL
447 ServerAddress = ServerAddressOption;\r
448 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
449 ServerAddress++;\r
450 }\r
f75a7f56 451\r
6692d519
ZL
452 if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
453 FreePool (TmpStr);\r
454 return EFI_INVALID_PARAMETER;\r
455 }\r
f75a7f56 456\r
6692d519 457 *ServerAddress = '\0';\r
f75a7f56 458\r
6692d519
ZL
459 //\r
460 // Convert the string of server address to Ipv6 address format and store it.\r
461 //\r
462 Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
463 if (EFI_ERROR (Status)) {\r
464 FreePool (TmpStr);\r
465 return Status;\r
466 }\r
6692d519
ZL
467 } else {\r
468 IpExpressedUrl = FALSE;\r
d1050b9d 469 ServerAddress = ServerAddressOption;\r
6692d519
ZL
470 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
471 ServerAddress++;\r
472 }\r
a3bcde70 473\r
6692d519
ZL
474 if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) {\r
475 FreePool (TmpStr);\r
476 return EFI_INVALID_PARAMETER;\r
477 }\r
d1050b9d 478\r
6692d519 479 *ServerAddress = '\0';\r
a3bcde70 480\r
d1050b9d 481 Len = AsciiStrSize (ServerAddressOption);\r
6692d519
ZL
482 HostName = AllocateZeroPool (Len * sizeof (CHAR16));\r
483 if (HostName == NULL) {\r
484 FreePool (TmpStr);\r
485 return EFI_OUT_OF_RESOURCES;\r
486 }\r
d1050b9d 487\r
6692d519
ZL
488 AsciiStrToUnicodeStrS (\r
489 ServerAddressOption,\r
490 HostName,\r
491 Len\r
492 );\r
a3bcde70 493\r
6692d519
ZL
494 //\r
495 // Perform DNS resolution.\r
496 //\r
d1050b9d 497 Status = PxeBcDns6 (Private, HostName, SrvAddr);\r
6692d519
ZL
498 if (EFI_ERROR (Status)) {\r
499 FreePool (TmpStr);\r
500 return Status;\r
501 }\r
a3bcde70
HT
502 }\r
503\r
504 //\r
505 // Get the part of BOOTFILE_NAME string.\r
506 //\r
d1050b9d 507 BootFileNamePtr = (CHAR8 *)((UINTN)ServerAddress + 1);\r
6692d519
ZL
508 if (IpExpressedUrl) {\r
509 if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
510 FreePool (TmpStr);\r
511 return EFI_INVALID_PARAMETER;\r
512 }\r
d1050b9d 513\r
6692d519 514 ++BootFileNamePtr;\r
a3bcde70
HT
515 }\r
516\r
d1050b9d
MK
517 BootFileNameLen = (UINT16)(Length - (UINT16)((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
518 if ((BootFileNameLen != 0) || (FileName != NULL)) {\r
eb2710af 519 //\r
520 // Remove trailing mode=octet if present and ignore. All other modes are\r
521 // invalid for netboot6, so reject them.\r
522 //\r
523 ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet");\r
d1050b9d 524 if ((ModeStr != NULL) && (*(ModeStr + AsciiStrLen (";mode=octet")) == '\0')) {\r
eb2710af 525 *ModeStr = '\0';\r
526 } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) {\r
2fad330f 527 FreePool (TmpStr);\r
eb2710af 528 return EFI_INVALID_PARAMETER;\r
529 }\r
530\r
129b8b09 531 //\r
532 // Extract boot file name from URL.\r
533 //\r
d1050b9d 534 BootFileName = (CHAR8 *)AllocateZeroPool (BootFileNameLen);\r
a3bcde70
HT
535 if (BootFileName == NULL) {\r
536 FreePool (TmpStr);\r
537 return EFI_OUT_OF_RESOURCES;\r
538 }\r
d1050b9d
MK
539\r
540 *FileName = (UINT8 *)BootFileName;\r
a3bcde70 541\r
129b8b09 542 //\r
543 // Decode percent-encoding in boot file name.\r
544 //\r
545 while (*BootFileNamePtr != '\0') {\r
546 if (*BootFileNamePtr == '%') {\r
d1050b9d 547 TmpChar = *(BootFileNamePtr+ 3);\r
129b8b09 548 *(BootFileNamePtr+ 3) = '\0';\r
d1050b9d 549 *BootFileName = (UINT8)AsciiStrHexToUintn ((CHAR8 *)(BootFileNamePtr + 1));\r
129b8b09 550 BootFileName++;\r
551 *(BootFileNamePtr+ 3) = TmpChar;\r
d1050b9d 552 BootFileNamePtr += 3;\r
129b8b09 553 } else {\r
554 *BootFileName = *BootFileNamePtr;\r
555 BootFileName++;\r
556 BootFileNamePtr++;\r
557 }\r
558 }\r
d1050b9d 559\r
129b8b09 560 *BootFileName = '\0';\r
561 }\r
a3bcde70
HT
562\r
563 FreePool (TmpStr);\r
564\r
565 return EFI_SUCCESS;\r
566}\r
567\r
a3bcde70
HT
568/**\r
569 Parse the Boot File Parameter option.\r
570\r
571 @param[in] BootFilePara The pointer to boot file parameter option data.\r
572 @param[out] BootFileSize The pointer to the parsed boot file size.\r
573\r
574 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.\r
575 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.\r
576\r
577**/\r
578EFI_STATUS\r
579PxeBcExtractBootFileParam (\r
d1050b9d
MK
580 IN CHAR8 *BootFilePara,\r
581 OUT UINT16 *BootFileSize\r
a3bcde70
HT
582 )\r
583{\r
d1050b9d
MK
584 UINT16 Length;\r
585 UINT8 Index;\r
586 UINT8 Digit;\r
587 UINT32 Size;\r
a3bcde70
HT
588\r
589 CopyMem (&Length, BootFilePara, sizeof (UINT16));\r
590 Length = NTOHS (Length);\r
591\r
592 //\r
593 // The BootFile Size should be 1~5 byte ASCII strings\r
594 //\r
d1050b9d 595 if ((Length < 1) || (Length > 5)) {\r
a3bcde70
HT
596 return EFI_NOT_FOUND;\r
597 }\r
598\r
599 //\r
600 // Extract the value of BootFile Size.\r
601 //\r
602 BootFilePara = BootFilePara + sizeof (UINT16);\r
603 Size = 0;\r
604 for (Index = 0; Index < Length; Index++) {\r
605 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) {\r
606 return EFI_NOT_FOUND;\r
607 }\r
608\r
609 Size = (Size + Digit) * 10;\r
610 }\r
611\r
612 Size = Size / 10;\r
613 if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) {\r
614 return EFI_NOT_FOUND;\r
615 }\r
616\r
d1050b9d 617 *BootFileSize = (UINT16)Size;\r
a3bcde70
HT
618 return EFI_SUCCESS;\r
619}\r
620\r
a3bcde70
HT
621/**\r
622 Parse the cached DHCPv6 packet, including all the options.\r
623\r
624 @param[in] Cache6 The pointer to a cached DHCPv6 packet.\r
625\r
626 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.\r
627 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.\r
628\r
629**/\r
630EFI_STATUS\r
631PxeBcParseDhcp6Packet (\r
632 IN PXEBC_DHCP6_PACKET_CACHE *Cache6\r
633 )\r
634{\r
d1050b9d
MK
635 EFI_DHCP6_PACKET *Offer;\r
636 EFI_DHCP6_PACKET_OPTION **Options;\r
637 EFI_DHCP6_PACKET_OPTION *Option;\r
638 PXEBC_OFFER_TYPE OfferType;\r
639 BOOLEAN IsProxyOffer;\r
640 BOOLEAN IsPxeOffer;\r
641 UINT32 Offset;\r
642 UINT32 Length;\r
643 UINT32 EnterpriseNum;\r
a3bcde70
HT
644\r
645 IsProxyOffer = TRUE;\r
646 IsPxeOffer = FALSE;\r
647 Offer = &Cache6->Packet.Offer;\r
648 Options = Cache6->OptList;\r
649\r
650 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));\r
651\r
d1050b9d
MK
652 Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option);\r
653 Offset = 0;\r
654 Length = GET_DHCP6_OPTION_SIZE (Offer);\r
a3bcde70
HT
655\r
656 //\r
657 // OpLen and OpCode here are both stored in network order, since they are from original packet.\r
658 //\r
659 while (Offset < Length) {\r
142c00c3 660 if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) {\r
a3bcde70 661 Options[PXEBC_DHCP6_IDX_IA_NA] = Option;\r
142c00c3 662 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) {\r
a3bcde70
HT
663 //\r
664 // The server sends this option to inform the client about an URL to a boot file.\r
665 //\r
666 Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option;\r
142c00c3 667 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) {\r
a3bcde70 668 Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
142c00c3 669 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) {\r
a3bcde70 670 Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;\r
6692d519
ZL
671 } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) {\r
672 Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option;\r
a3bcde70
HT
673 }\r
674\r
675 Offset += (NTOHS (Option->OpLen) + 4);\r
d1050b9d 676 Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option + Offset);\r
a3bcde70
HT
677 }\r
678\r
679 //\r
ae97201c 680 // The offer with assigned client address is NOT a proxy offer.\r
5add2c55 681 // An ia_na option, embedded with valid ia_addr option and a status_code of success.\r
a3bcde70
HT
682 //\r
683 Option = Options[PXEBC_DHCP6_IDX_IA_NA];\r
129b8b09 684 if (Option != NULL) {\r
a3bcde70
HT
685 Option = PxeBcParseDhcp6Options (\r
686 Option->Data + 12,\r
687 NTOHS (Option->OpLen),\r
142c00c3 688 DHCP6_OPT_STATUS_CODE\r
a3bcde70 689 );\r
d1050b9d 690 if (((Option != NULL) && (Option->Data[0] == 0)) || (Option == NULL)) {\r
a3bcde70
HT
691 IsProxyOffer = FALSE;\r
692 }\r
693 }\r
694\r
695 //\r
696 // The offer with "PXEClient" is a pxe offer.\r
697 //\r
698 Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];\r
d1050b9d 699 EnterpriseNum = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);\r
129b8b09 700\r
d1050b9d
MK
701 if ((Option != NULL) &&\r
702 (NTOHS (Option->OpLen) >= 13) &&\r
703 (CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0) &&\r
704 (CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0))\r
705 {\r
a3bcde70
HT
706 IsPxeOffer = TRUE;\r
707 }\r
708\r
709 //\r
710 // Determine offer type of the dhcp6 packet.\r
711 //\r
712 if (IsPxeOffer) {\r
713 //\r
714 // It's a binl offer only with PXEClient.\r
715 //\r
716 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;\r
717 } else {\r
718 //\r
719 // It's a dhcp only offer, which is a pure dhcp6 offer packet.\r
720 //\r
721 OfferType = PxeOfferTypeDhcpOnly;\r
722 }\r
723\r
724 Cache6->OfferType = OfferType;\r
725\r
726 return EFI_SUCCESS;\r
727}\r
728\r
a3bcde70
HT
729/**\r
730 Cache the DHCPv6 ack packet, and parse it on demand.\r
731\r
732 @param[in] Private The pointer to PxeBc private data.\r
733 @param[in] Ack The pointer to the DHCPv6 ack packet.\r
734 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.\r
735\r
a35dc649
FS
736 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
737 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
738\r
a3bcde70 739**/\r
a35dc649 740EFI_STATUS\r
a3bcde70 741PxeBcCopyDhcp6Ack (\r
d1050b9d
MK
742 IN PXEBC_PRIVATE_DATA *Private,\r
743 IN EFI_DHCP6_PACKET *Ack,\r
744 IN BOOLEAN Verified\r
a3bcde70
HT
745 )\r
746{\r
747 EFI_PXE_BASE_CODE_MODE *Mode;\r
a35dc649 748 EFI_STATUS Status;\r
a3bcde70
HT
749\r
750 Mode = Private->PxeBc.Mode;\r
751\r
a35dc649
FS
752 Status = PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);\r
753 if (EFI_ERROR (Status)) {\r
754 return Status;\r
755 }\r
a3bcde70
HT
756\r
757 if (Verified) {\r
758 //\r
759 // Parse the ack packet and store it into mode data if needed.\r
760 //\r
761 PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6);\r
762 CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);\r
763 Mode->DhcpAckReceived = TRUE;\r
764 }\r
a35dc649
FS
765\r
766 return EFI_SUCCESS;\r
a3bcde70
HT
767}\r
768\r
a3bcde70
HT
769/**\r
770 Cache the DHCPv6 proxy offer packet according to the received order.\r
771\r
772 @param[in] Private The pointer to PxeBc private data.\r
773 @param[in] OfferIndex The received order of offer packets.\r
774\r
a35dc649
FS
775 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
776 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.\r
777\r
a3bcde70 778**/\r
a35dc649 779EFI_STATUS\r
a3bcde70 780PxeBcCopyDhcp6Proxy (\r
d1050b9d
MK
781 IN PXEBC_PRIVATE_DATA *Private,\r
782 IN UINT32 OfferIndex\r
a3bcde70
HT
783 )\r
784{\r
d1050b9d
MK
785 EFI_PXE_BASE_CODE_MODE *Mode;\r
786 EFI_DHCP6_PACKET *Offer;\r
a35dc649 787 EFI_STATUS Status;\r
a3bcde70
HT
788\r
789 ASSERT (OfferIndex < Private->OfferNum);\r
790 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
791\r
792 Mode = Private->PxeBc.Mode;\r
793 Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer;\r
794\r
795 //\r
796 // Cache the proxy offer packet and parse it.\r
797 //\r
a35dc649 798 Status = PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);\r
d1050b9d 799 if (EFI_ERROR (Status)) {\r
a35dc649
FS
800 return Status;\r
801 }\r
d1050b9d 802\r
a3bcde70
HT
803 PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);\r
804\r
805 //\r
806 // Store this packet into mode data.\r
807 //\r
808 CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);\r
809 Mode->ProxyOfferReceived = TRUE;\r
a35dc649
FS
810\r
811 return EFI_SUCCESS;\r
a3bcde70
HT
812}\r
813\r
129b8b09 814/**\r
815 Seek the address of the first byte of the option header.\r
816\r
817 @param[in] Buf The pointer to the buffer.\r
818 @param[in] SeekLen The length to seek.\r
819 @param[in] OptType The option type.\r
820\r
821 @retval NULL If it failed to seek the option.\r
822 @retval others The position to the option.\r
823\r
824**/\r
825UINT8 *\r
826PxeBcDhcp6SeekOption (\r
d1050b9d
MK
827 IN UINT8 *Buf,\r
828 IN UINT32 SeekLen,\r
829 IN UINT16 OptType\r
129b8b09 830 )\r
831{\r
d1050b9d
MK
832 UINT8 *Cursor;\r
833 UINT8 *Option;\r
834 UINT16 DataLen;\r
835 UINT16 OpCode;\r
129b8b09 836\r
837 Option = NULL;\r
838 Cursor = Buf;\r
839\r
840 while (Cursor < Buf + SeekLen) {\r
d1050b9d 841 OpCode = ReadUnaligned16 ((UINT16 *)Cursor);\r
129b8b09 842 if (OpCode == HTONS (OptType)) {\r
843 Option = Cursor;\r
844 break;\r
845 }\r
d1050b9d
MK
846\r
847 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *)(Cursor + 2)));\r
129b8b09 848 Cursor += (DataLen + 4);\r
849 }\r
850\r
851 return Option;\r
852}\r
853\r
129b8b09 854/**\r
855 Build and send out the request packet for the bootfile, and parse the reply.\r
856\r
857 @param[in] Private The pointer to PxeBc private data.\r
858 @param[in] Index PxeBc option boot item type.\r
859\r
860 @retval EFI_SUCCESS Successfully discovered the boot file.\r
861 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
862 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
863 @retval Others Failed to discover the boot file.\r
864\r
865**/\r
866EFI_STATUS\r
867PxeBcRequestBootService (\r
d1050b9d
MK
868 IN PXEBC_PRIVATE_DATA *Private,\r
869 IN UINT32 Index\r
129b8b09 870 )\r
871{\r
d1050b9d
MK
872 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;\r
873 EFI_PXE_BASE_CODE_UDP_PORT DestPort;\r
874 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
875 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;\r
876 UINTN DiscoverLen;\r
877 EFI_DHCP6_PACKET *Request;\r
878 UINTN RequestLen;\r
879 EFI_DHCP6_PACKET *Reply;\r
880 UINT8 *RequestOpt;\r
881 UINT8 *DiscoverOpt;\r
882 UINTN ReadSize;\r
883 UINT16 OpFlags;\r
884 UINT16 OpCode;\r
885 UINT16 OpLen;\r
886 EFI_STATUS Status;\r
887 EFI_DHCP6_PACKET *IndexOffer;\r
888 UINT8 *Option;\r
889\r
890 PxeBc = &Private->PxeBc;\r
891 Request = Private->Dhcp6Request;\r
892 IndexOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;\r
893 SrcPort = PXEBC_BS_DISCOVER_PORT;\r
894 DestPort = PXEBC_BS_DISCOVER_PORT;\r
895 OpFlags = 0;\r
129b8b09 896\r
897 if (Request == NULL) {\r
898 return EFI_DEVICE_ERROR;\r
899 }\r
900\r
901 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
902 if (Discover == NULL) {\r
903 return EFI_OUT_OF_RESOURCES;\r
904 }\r
905\r
906 //\r
907 // Build the request packet by the cached request packet before.\r
908 //\r
be37315a 909 Discover->TransactionId = IndexOffer->Dhcp6.Header.TransactionId;\r
129b8b09 910 Discover->MessageType = Request->Dhcp6.Header.MessageType;\r
911 RequestOpt = Request->Dhcp6.Option;\r
912 DiscoverOpt = Discover->DhcpOptions;\r
913 DiscoverLen = sizeof (EFI_DHCP6_HEADER);\r
914 RequestLen = DiscoverLen;\r
915\r
916 //\r
917 // Find Server ID Option from ProxyOffer.\r
918 //\r
f75a7f56 919 if (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl) {\r
be37315a
JW
920 Option = PxeBcDhcp6SeekOption (\r
921 IndexOffer->Dhcp6.Option,\r
922 IndexOffer->Length - 4,\r
923 DHCP6_OPT_SERVER_ID\r
924 );\r
925 if (Option == NULL) {\r
926 return EFI_NOT_FOUND;\r
927 }\r
f75a7f56 928\r
be37315a
JW
929 //\r
930 // Add Server ID Option.\r
931 //\r
d1050b9d 932 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen);\r
be37315a
JW
933 CopyMem (DiscoverOpt, Option, OpLen + 4);\r
934 DiscoverOpt += (OpLen + 4);\r
935 DiscoverLen += (OpLen + 4);\r
936 }\r
129b8b09 937\r
938 while (RequestLen < Request->Length) {\r
d1050b9d
MK
939 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode);\r
940 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen);\r
941 if ((OpCode != EFI_DHCP6_IA_TYPE_NA) &&\r
942 (OpCode != EFI_DHCP6_IA_TYPE_TA) &&\r
943 (OpCode != DHCP6_OPT_SERVER_ID)\r
944 )\r
945 {\r
129b8b09 946 //\r
947 // Copy all the options except IA option and Server ID\r
948 //\r
949 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
950 DiscoverOpt += (OpLen + 4);\r
951 DiscoverLen += (OpLen + 4);\r
952 }\r
d1050b9d 953\r
129b8b09 954 RequestOpt += (OpLen + 4);\r
955 RequestLen += (OpLen + 4);\r
956 }\r
957\r
958 //\r
f75a7f56 959 // Update Elapsed option in the package\r
129b8b09 960 //\r
961 Option = PxeBcDhcp6SeekOption (\r
962 Discover->DhcpOptions,\r
963 (UINT32)(RequestLen - 4),\r
142c00c3 964 DHCP6_OPT_ELAPSED_TIME\r
129b8b09 965 );\r
966 if (Option != NULL) {\r
967 CalcElapsedTime (Private);\r
d1050b9d 968 WriteUnaligned16 ((UINT16 *)(Option + 4), HTONS ((UINT16)Private->ElapsedTime));\r
f75a7f56 969 }\r
129b8b09 970\r
971 Status = PxeBc->UdpWrite (\r
972 PxeBc,\r
973 OpFlags,\r
974 &Private->ServerIp,\r
975 &DestPort,\r
976 NULL,\r
977 &Private->StationIp,\r
978 &SrcPort,\r
979 NULL,\r
980 NULL,\r
981 &DiscoverLen,\r
d1050b9d 982 (VOID *)Discover\r
129b8b09 983 );\r
984\r
985 if (EFI_ERROR (Status)) {\r
2fad330f 986 goto ON_ERROR;\r
129b8b09 987 }\r
988\r
989 //\r
990 // Cache the right PXE reply packet here, set valid flag later.\r
991 // Especially for PXE discover packet, store it into mode data here.\r
992 //\r
d1050b9d
MK
993 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;\r
994 ReadSize = (UINTN)Reply->Size;\r
129b8b09 995\r
996 //\r
997 // Start Udp6Read instance\r
998 //\r
999 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
1000 if (EFI_ERROR (Status)) {\r
2fad330f 1001 goto ON_ERROR;\r
129b8b09 1002 }\r
f75a7f56 1003\r
129b8b09 1004 Status = PxeBc->UdpRead (\r
1005 PxeBc,\r
903d1fa9
FS
1006 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,\r
1007 NULL,\r
129b8b09 1008 &SrcPort,\r
1009 &Private->ServerIp,\r
1010 &DestPort,\r
1011 NULL,\r
1012 NULL,\r
1013 &ReadSize,\r
d1050b9d 1014 (VOID *)&Reply->Dhcp6\r
129b8b09 1015 );\r
1016 //\r
1017 // Stop Udp6Read instance\r
1018 //\r
1019 Private->Udp6Read->Configure (Private->Udp6Read, NULL);\r
1020\r
1021 if (EFI_ERROR (Status)) {\r
2fad330f 1022 goto ON_ERROR;\r
129b8b09 1023 }\r
1024\r
1025 //\r
1026 // Update length\r
1027 //\r
d1050b9d 1028 Reply->Length = (UINT32)ReadSize;\r
129b8b09 1029\r
1030 return EFI_SUCCESS;\r
f75a7f56 1031\r
2fad330f
FS
1032ON_ERROR:\r
1033 if (Discover != NULL) {\r
1034 FreePool (Discover);\r
1035 }\r
1036\r
1037 return Status;\r
129b8b09 1038}\r
1039\r
a3bcde70
HT
1040/**\r
1041 Retry to request bootfile name by the BINL offer.\r
1042\r
1043 @param[in] Private The pointer to PxeBc private data.\r
1044 @param[in] Index The received order of offer packets.\r
1045\r
1046 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.\r
1047 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.\r
1048\r
1049**/\r
1050EFI_STATUS\r
1051PxeBcRetryDhcp6Binl (\r
1052 IN PXEBC_PRIVATE_DATA *Private,\r
1053 IN UINT32 Index\r
1054 )\r
1055{\r
1056 EFI_PXE_BASE_CODE_MODE *Mode;\r
1057 PXEBC_DHCP6_PACKET_CACHE *Offer;\r
1058 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
a3bcde70
HT
1059 EFI_STATUS Status;\r
1060\r
1061 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
d1050b9d
MK
1062 ASSERT (\r
1063 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl ||\r
1064 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl\r
1065 );\r
a3bcde70
HT
1066\r
1067 Mode = Private->PxeBc.Mode;\r
1068 Private->IsDoDiscover = FALSE;\r
1069 Offer = &Private->OfferBuffer[Index].Dhcp6;\r
be37315a 1070 if (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
d40002ba 1071 //\r
1072 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.\r
1073 //\r
1074 CopyMem (\r
1075 &Private->ServerIp.v6,\r
1076 &mAllDhcpRelayAndServersAddress,\r
1077 sizeof (EFI_IPv6_ADDRESS)\r
1078 );\r
1079 } else {\r
1080 ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
1081 //\r
1082 // Parse out the next server address from the last offer, and store it\r
1083 //\r
1084 Status = PxeBcExtractBootFileUrl (\r
6692d519 1085 Private,\r
d40002ba 1086 &Private->BootFileName,\r
1087 &Private->ServerIp.v6,\r
d1050b9d 1088 (CHAR8 *)(Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
d40002ba 1089 NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
1090 );\r
1091 if (EFI_ERROR (Status)) {\r
1092 return Status;\r
1093 }\r
a3bcde70
HT
1094 }\r
1095\r
1096 //\r
1097 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.\r
1098 //\r
129b8b09 1099 Status = PxeBcRequestBootService (Private, Index);\r
1100\r
a3bcde70
HT
1101 if (EFI_ERROR (Status)) {\r
1102 return Status;\r
1103 }\r
1104\r
1105 Cache6 = &Private->ProxyOffer.Dhcp6;\r
1106 Status = PxeBcParseDhcp6Packet (Cache6);\r
1107 if (EFI_ERROR (Status)) {\r
1108 return Status;\r
1109 }\r
1110\r
d1050b9d
MK
1111 if ((Cache6->OfferType != PxeOfferTypeProxyPxe10) &&\r
1112 (Cache6->OfferType != PxeOfferTypeProxyWfm11a) &&\r
1113 (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL))\r
1114 {\r
a3bcde70
HT
1115 //\r
1116 // This BINL ack doesn't have discovery option set or multicast option set\r
1117 // or bootfile name specified.\r
1118 //\r
1119 return EFI_DEVICE_ERROR;\r
1120 }\r
1121\r
1122 Mode->ProxyOfferReceived = TRUE;\r
1123 CopyMem (\r
1124 &Mode->ProxyOffer.Dhcpv6,\r
1125 &Cache6->Packet.Offer.Dhcp6,\r
1126 Cache6->Packet.Offer.Length\r
1127 );\r
1128\r
1129 return EFI_SUCCESS;\r
1130}\r
1131\r
a3bcde70
HT
1132/**\r
1133 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.\r
1134\r
1135 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1136 @param[in] RcvdOffer The pointer to the received offer packet.\r
1137\r
a35dc649
FS
1138 @retval EFI_SUCCESS Cache and parse the packet successfully.\r
1139 @retval Others Operation failed.\r
a3bcde70 1140**/\r
a35dc649 1141EFI_STATUS\r
a3bcde70 1142PxeBcCacheDhcp6Offer (\r
d1050b9d
MK
1143 IN PXEBC_PRIVATE_DATA *Private,\r
1144 IN EFI_DHCP6_PACKET *RcvdOffer\r
a3bcde70
HT
1145 )\r
1146{\r
1147 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
1148 EFI_DHCP6_PACKET *Offer;\r
1149 PXEBC_OFFER_TYPE OfferType;\r
a35dc649 1150 EFI_STATUS Status;\r
a3bcde70
HT
1151\r
1152 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
1153 Offer = &Cache6->Packet.Offer;\r
1154\r
1155 //\r
1156 // Cache the content of DHCPv6 packet firstly.\r
1157 //\r
a35dc649
FS
1158 Status = PxeBcCacheDhcp6Packet (Offer, RcvdOffer);\r
1159 if (EFI_ERROR (Status)) {\r
1160 return Status;\r
1161 }\r
a3bcde70
HT
1162\r
1163 //\r
1164 // Validate the DHCPv6 packet, and parse the options and offer type.\r
1165 //\r
1166 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {\r
a35dc649 1167 return EFI_ABORTED;\r
a3bcde70
HT
1168 }\r
1169\r
1170 //\r
1171 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
1172 //\r
1173 OfferType = Cache6->OfferType;\r
1174 ASSERT (OfferType < PxeOfferTypeMax);\r
1175 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);\r
1176\r
1177 if (IS_PROXY_OFFER (OfferType)) {\r
1178 //\r
1179 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.\r
1180 //\r
1181 Private->IsProxyRecved = TRUE;\r
1182\r
1183 if (OfferType == PxeOfferTypeProxyBinl) {\r
1184 //\r
1185 // Cache all proxy BINL offers.\r
1186 //\r
1187 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
1188 Private->OfferCount[OfferType]++;\r
d1050b9d
MK
1189 } else if (((OfferType == PxeOfferTypeProxyPxe10) || (OfferType == PxeOfferTypeProxyWfm11a)) &&\r
1190 (Private->OfferCount[OfferType] < 1))\r
1191 {\r
a3bcde70
HT
1192 //\r
1193 // Only cache the first PXE10/WFM11a offer, and discard the others.\r
1194 //\r
1195 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
1196 Private->OfferCount[OfferType] = 1;\r
1197 } else {\r
a35dc649 1198 return EFI_ABORTED;\r
a3bcde70
HT
1199 }\r
1200 } else {\r
1201 //\r
1202 // It's a DHCPv6 offer with yiaddr, and cache them all.\r
1203 //\r
1204 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
1205 Private->OfferCount[OfferType]++;\r
1206 }\r
1207\r
1208 Private->OfferNum++;\r
a35dc649
FS
1209\r
1210 return EFI_SUCCESS;\r
a3bcde70
HT
1211}\r
1212\r
a3bcde70
HT
1213/**\r
1214 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.\r
1215\r
1216 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1217\r
1218**/\r
1219VOID\r
1220PxeBcSelectDhcp6Offer (\r
d1050b9d 1221 IN PXEBC_PRIVATE_DATA *Private\r
a3bcde70
HT
1222 )\r
1223{\r
d1050b9d
MK
1224 UINT32 Index;\r
1225 UINT32 OfferIndex;\r
1226 PXEBC_OFFER_TYPE OfferType;\r
a3bcde70
HT
1227\r
1228 Private->SelectIndex = 0;\r
1229\r
1230 if (Private->IsOfferSorted) {\r
1231 //\r
1232 // Select offer by default policy.\r
1233 //\r
1234 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {\r
1235 //\r
1236 // 1. DhcpPxe10 offer\r
1237 //\r
1238 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;\r
a3bcde70
HT
1239 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {\r
1240 //\r
1241 // 2. DhcpWfm11a offer\r
1242 //\r
1243 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;\r
d1050b9d
MK
1244 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&\r
1245 (Private->OfferCount[PxeOfferTypeProxyPxe10] > 0))\r
1246 {\r
a3bcde70
HT
1247 //\r
1248 // 3. DhcpOnly offer and ProxyPxe10 offer.\r
1249 //\r
1250 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
1251 Private->SelectProxyType = PxeOfferTypeProxyPxe10;\r
d1050b9d
MK
1252 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&\r
1253 (Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0))\r
1254 {\r
a3bcde70
HT
1255 //\r
1256 // 4. DhcpOnly offer and ProxyWfm11a offer.\r
1257 //\r
1258 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
1259 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;\r
a3bcde70
HT
1260 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {\r
1261 //\r
1262 // 5. DhcpBinl offer.\r
1263 //\r
1264 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;\r
d1050b9d
MK
1265 } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) &&\r
1266 (Private->OfferCount[PxeOfferTypeProxyBinl] > 0))\r
1267 {\r
a3bcde70
HT
1268 //\r
1269 // 6. DhcpOnly offer and ProxyBinl offer.\r
1270 //\r
1271 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
1272 Private->SelectProxyType = PxeOfferTypeProxyBinl;\r
a3bcde70
HT
1273 } else {\r
1274 //\r
1275 // 7. DhcpOnly offer with bootfilename.\r
1276 //\r
1277 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {\r
1278 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];\r
1279 if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) {\r
1280 Private->SelectIndex = OfferIndex + 1;\r
1281 break;\r
1282 }\r
1283 }\r
1284 }\r
1285 } else {\r
1286 //\r
1287 // Select offer by received order.\r
1288 //\r
1289 for (Index = 0; Index < Private->OfferNum; Index++) {\r
a3bcde70
HT
1290 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;\r
1291\r
1292 if (IS_PROXY_OFFER (OfferType)) {\r
1293 //\r
1294 // Skip proxy offers\r
1295 //\r
1296 continue;\r
1297 }\r
1298\r
1299 if (!Private->IsProxyRecved &&\r
d1050b9d
MK
1300 (OfferType == PxeOfferTypeDhcpOnly) &&\r
1301 (Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL))\r
1302 {\r
a3bcde70
HT
1303 //\r
1304 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.\r
1305 //\r
1306 continue;\r
1307 }\r
1308\r
1309 Private->SelectIndex = Index + 1;\r
1310 break;\r
1311 }\r
1312 }\r
1313}\r
1314\r
a3bcde70
HT
1315/**\r
1316 Handle the DHCPv6 offer packet.\r
1317\r
1318 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1319\r
92ec8772
ZL
1320 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.\r
1321 @retval EFI_NO_RESPONSE No response to the following request packet.\r
1322 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
a35dc649 1323 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.\r
a3bcde70
HT
1324\r
1325**/\r
1326EFI_STATUS\r
1327PxeBcHandleDhcp6Offer (\r
d1050b9d 1328 IN PXEBC_PRIVATE_DATA *Private\r
a3bcde70
HT
1329 )\r
1330{\r
d1050b9d
MK
1331 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
1332 EFI_STATUS Status;\r
1333 PXEBC_OFFER_TYPE OfferType;\r
1334 UINT32 ProxyIndex;\r
1335 UINT32 SelectIndex;\r
1336 UINT32 Index;\r
a3bcde70
HT
1337\r
1338 ASSERT (Private->SelectIndex > 0);\r
d1050b9d 1339 SelectIndex = (UINT32)(Private->SelectIndex - 1);\r
a3bcde70 1340 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);\r
d1050b9d
MK
1341 Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
1342 Status = EFI_SUCCESS;\r
a3bcde70 1343\r
6692d519
ZL
1344 //\r
1345 // First try to cache DNS server address if DHCP6 offer provides.\r
1346 //\r
1347 if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) {\r
1348 Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen));\r
92ec8772
ZL
1349 if (Private->DnsServer == NULL) {\r
1350 return EFI_OUT_OF_RESOURCES;\r
1351 }\r
d1050b9d 1352\r
6692d519
ZL
1353 CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS));\r
1354 }\r
1355\r
a3bcde70
HT
1356 if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
1357 //\r
1358 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
1359 //\r
1360 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) {\r
1361 Status = EFI_NO_RESPONSE;\r
1362 }\r
1363 } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) {\r
a3bcde70
HT
1364 if (Private->IsProxyRecved) {\r
1365 //\r
1366 // DhcpOnly offer is selected, so need try to request bootfilename.\r
1367 //\r
1368 ProxyIndex = 0;\r
1369 if (Private->IsOfferSorted) {\r
1370 //\r
1371 // The proxy offer should be determined if select by default policy.\r
1372 // IsOfferSorted means all offers are labeled by OfferIndex.\r
1373 //\r
1374 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);\r
1375\r
1376 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {\r
1377 //\r
1378 // Try all the cached ProxyBinl offer one by one to request bootfilename.\r
1379 //\r
1380 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {\r
a3bcde70
HT
1381 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];\r
1382 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) {\r
1383 break;\r
1384 }\r
1385 }\r
d1050b9d 1386\r
a3bcde70
HT
1387 if (Index == Private->OfferCount[Private->SelectProxyType]) {\r
1388 Status = EFI_NO_RESPONSE;\r
1389 }\r
1390 } else {\r
1391 //\r
1392 // For other proxy offers (pxe10 or wfm11a), only one is buffered.\r
1393 //\r
1394 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
1395 }\r
1396 } else {\r
1397 //\r
1398 // The proxy offer should not be determined if select by received order.\r
1399 //\r
1400 Status = EFI_NO_RESPONSE;\r
1401\r
1402 for (Index = 0; Index < Private->OfferNum; Index++) {\r
a3bcde70
HT
1403 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;\r
1404\r
1405 if (!IS_PROXY_OFFER (OfferType)) {\r
1406 //\r
1407 // Skip non proxy dhcp offers.\r
1408 //\r
1409 continue;\r
1410 }\r
1411\r
1412 if (OfferType == PxeOfferTypeProxyBinl) {\r
1413 //\r
1414 // Try all the cached ProxyBinl offer one by one to request bootfilename.\r
1415 //\r
1416 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) {\r
1417 continue;\r
1418 }\r
1419 }\r
1420\r
1421 Private->SelectProxyType = OfferType;\r
1422 ProxyIndex = Index;\r
1423 Status = EFI_SUCCESS;\r
1424 break;\r
1425 }\r
1426 }\r
1427\r
d1050b9d 1428 if (!EFI_ERROR (Status) && (Private->SelectProxyType != PxeOfferTypeProxyBinl)) {\r
a3bcde70
HT
1429 //\r
1430 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
1431 //\r
a35dc649 1432 Status = PxeBcCopyDhcp6Proxy (Private, ProxyIndex);\r
a3bcde70
HT
1433 }\r
1434 } else {\r
1435 //\r
5add2c55 1436 // Otherwise, the bootfilename must be included in DhcpOnly offer.\r
a3bcde70
HT
1437 //\r
1438 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
1439 }\r
1440 }\r
1441\r
1442 if (!EFI_ERROR (Status)) {\r
1443 //\r
1444 // All PXE boot information is ready by now.\r
1445 //\r
d1050b9d 1446 Status = PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);\r
a3bcde70
HT
1447 Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;\r
1448 }\r
1449\r
1450 return Status;\r
1451}\r
1452\r
a3bcde70
HT
1453/**\r
1454 Unregister the address by Ip6Config protocol.\r
1455\r
1456 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1457\r
1458**/\r
1459VOID\r
1460PxeBcUnregisterIp6Address (\r
d1050b9d 1461 IN PXEBC_PRIVATE_DATA *Private\r
a3bcde70
HT
1462 )\r
1463{\r
1464 if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) {\r
1465 //\r
1466 // PXE driver change the policy of IP6 driver, it's a chance to recover.\r
1467 // Keep the point and there is no enough requirements to do recovery.\r
1468 //\r
1469 }\r
1470}\r
1471\r
ae97201c
FS
1472/**\r
1473 Check whether IP driver could route the message which will be sent to ServerIp address.\r
f75a7f56 1474\r
ae97201c
FS
1475 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid\r
1476 route is found in IP6 route table, the address will be filed in GatewayAddr and return.\r
1477\r
1478 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1479 @param[in] TimeOutInSecond Timeout value in seconds.\r
1480 @param[out] GatewayAddr Pointer to store the gateway IP address.\r
1481\r
1482 @retval EFI_SUCCESS Found a valid gateway address successfully.\r
1483 @retval EFI_TIMEOUT The operation is time out.\r
5add2c55 1484 @retval Other Unexpected error happened.\r
f75a7f56 1485\r
ae97201c
FS
1486**/\r
1487EFI_STATUS\r
1488PxeBcCheckRouteTable (\r
d1050b9d
MK
1489 IN PXEBC_PRIVATE_DATA *Private,\r
1490 IN UINTN TimeOutInSecond,\r
1491 OUT EFI_IPv6_ADDRESS *GatewayAddr\r
ae97201c
FS
1492 )\r
1493{\r
d1050b9d
MK
1494 EFI_STATUS Status;\r
1495 EFI_IP6_PROTOCOL *Ip6;\r
1496 EFI_IP6_MODE_DATA Ip6ModeData;\r
1497 UINTN Index;\r
1498 EFI_EVENT TimeOutEvt;\r
1499 UINTN RetryCount;\r
1500 BOOLEAN GatewayIsFound;\r
ae97201c
FS
1501\r
1502 ASSERT (GatewayAddr != NULL);\r
1503 ASSERT (Private != NULL);\r
1504\r
1505 Ip6 = Private->Ip6;\r
1506 GatewayIsFound = FALSE;\r
1507 RetryCount = 0;\r
1508 TimeOutEvt = NULL;\r
1509 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));\r
1510\r
1511 while (TRUE) {\r
1512 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);\r
1513 if (EFI_ERROR (Status)) {\r
1514 goto ON_EXIT;\r
1515 }\r
1516\r
1517 //\r
07f986f1 1518 // Find out the gateway address which can route the message which send to ServerIp.\r
ae97201c
FS
1519 //\r
1520 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {\r
1521 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {\r
1522 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);\r
1523 GatewayIsFound = TRUE;\r
1524 break;\r
1525 }\r
1526 }\r
1527\r
1528 if (Ip6ModeData.AddressList != NULL) {\r
1529 FreePool (Ip6ModeData.AddressList);\r
1530 }\r
d1050b9d 1531\r
ae97201c
FS
1532 if (Ip6ModeData.GroupTable != NULL) {\r
1533 FreePool (Ip6ModeData.GroupTable);\r
1534 }\r
d1050b9d 1535\r
ae97201c
FS
1536 if (Ip6ModeData.RouteTable != NULL) {\r
1537 FreePool (Ip6ModeData.RouteTable);\r
1538 }\r
d1050b9d 1539\r
ae97201c
FS
1540 if (Ip6ModeData.NeighborCache != NULL) {\r
1541 FreePool (Ip6ModeData.NeighborCache);\r
1542 }\r
d1050b9d 1543\r
ae97201c
FS
1544 if (Ip6ModeData.PrefixTable != NULL) {\r
1545 FreePool (Ip6ModeData.PrefixTable);\r
1546 }\r
d1050b9d 1547\r
ae97201c
FS
1548 if (Ip6ModeData.IcmpTypeList != NULL) {\r
1549 FreePool (Ip6ModeData.IcmpTypeList);\r
1550 }\r
f75a7f56 1551\r
d1050b9d 1552 if (GatewayIsFound || (RetryCount == TimeOutInSecond)) {\r
ae97201c
FS
1553 break;\r
1554 }\r
f75a7f56 1555\r
ae97201c 1556 RetryCount++;\r
f75a7f56 1557\r
ae97201c
FS
1558 //\r
1559 // Delay 1 second then recheck it again.\r
1560 //\r
1561 if (TimeOutEvt == NULL) {\r
1562 Status = gBS->CreateEvent (\r
1563 EVT_TIMER,\r
1564 TPL_CALLBACK,\r
1565 NULL,\r
1566 NULL,\r
1567 &TimeOutEvt\r
1568 );\r
1569 if (EFI_ERROR (Status)) {\r
1570 goto ON_EXIT;\r
1571 }\r
1572 }\r
1573\r
1574 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);\r
1575 if (EFI_ERROR (Status)) {\r
1576 goto ON_EXIT;\r
1577 }\r
d1050b9d 1578\r
ae97201c
FS
1579 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
1580 Ip6->Poll (Ip6);\r
1581 }\r
1582 }\r
f75a7f56 1583\r
ae97201c
FS
1584ON_EXIT:\r
1585 if (TimeOutEvt != NULL) {\r
1586 gBS->CloseEvent (TimeOutEvt);\r
1587 }\r
f75a7f56 1588\r
ae97201c
FS
1589 if (GatewayIsFound) {\r
1590 Status = EFI_SUCCESS;\r
1591 } else if (RetryCount == TimeOutInSecond) {\r
1592 Status = EFI_TIMEOUT;\r
1593 }\r
1594\r
f75a7f56 1595 return Status;\r
ae97201c 1596}\r
a3bcde70
HT
1597\r
1598/**\r
ae97201c 1599 Register the ready station address and gateway by Ip6Config protocol.\r
a3bcde70
HT
1600\r
1601 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1602 @param[in] Address The pointer to the ready address.\r
1603\r
5add2c55 1604 @retval EFI_SUCCESS Registered the address successfully.\r
a3bcde70
HT
1605 @retval Others Failed to register the address.\r
1606\r
1607**/\r
1608EFI_STATUS\r
1609PxeBcRegisterIp6Address (\r
d1050b9d
MK
1610 IN PXEBC_PRIVATE_DATA *Private,\r
1611 IN EFI_IPv6_ADDRESS *Address\r
a3bcde70
HT
1612 )\r
1613{\r
d1050b9d
MK
1614 EFI_IP6_PROTOCOL *Ip6;\r
1615 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
1616 EFI_IP6_CONFIG_POLICY Policy;\r
1617 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;\r
1618 EFI_IPv6_ADDRESS GatewayAddr;\r
1619 UINTN DataSize;\r
1620 EFI_EVENT MappedEvt;\r
1621 EFI_STATUS Status;\r
1622 BOOLEAN NoGateway;\r
1623 EFI_IPv6_ADDRESS *Ip6Addr;\r
1624 UINTN Index;\r
1625\r
1626 Status = EFI_SUCCESS;\r
1627 MappedEvt = NULL;\r
1628 Ip6Addr = NULL;\r
1629 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
1630 Ip6Cfg = Private->Ip6Cfg;\r
1631 Ip6 = Private->Ip6;\r
1632 NoGateway = FALSE;\r
a3bcde70
HT
1633\r
1634 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
1635 CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));\r
1636\r
ae97201c
FS
1637 Status = Ip6->Configure (Ip6, &Private->Ip6CfgData);\r
1638 if (EFI_ERROR (Status)) {\r
1639 goto ON_EXIT;\r
1640 }\r
1641\r
a3bcde70 1642 //\r
ae97201c 1643 // Retrieve the gateway address from IP6 route table.\r
a3bcde70 1644 //\r
ae97201c 1645 Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);\r
a3bcde70 1646 if (EFI_ERROR (Status)) {\r
07f986f1 1647 NoGateway = TRUE;\r
a3bcde70 1648 }\r
f75a7f56 1649\r
a3bcde70
HT
1650 //\r
1651 // There is no channel between IP6 and PXE driver about address setting,\r
1652 // so it has to set the new address by Ip6ConfigProtocol manually.\r
1653 //\r
1654 Policy = Ip6ConfigPolicyManual;\r
1655 Status = Ip6Cfg->SetData (\r
1656 Ip6Cfg,\r
1657 Ip6ConfigDataTypePolicy,\r
d1050b9d 1658 sizeof (EFI_IP6_CONFIG_POLICY),\r
a3bcde70
HT
1659 &Policy\r
1660 );\r
1661 if (EFI_ERROR (Status)) {\r
1662 //\r
1663 // There is no need to recover later.\r
1664 //\r
1665 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;\r
1666 goto ON_EXIT;\r
1667 }\r
1668\r
a3bcde70
HT
1669 //\r
1670 // Create a notify event to set address flag when DAD if IP6 driver succeeded.\r
1671 //\r
1672 Status = gBS->CreateEvent (\r
1673 EVT_NOTIFY_SIGNAL,\r
1674 TPL_NOTIFY,\r
1675 PxeBcCommonNotify,\r
1676 &Private->IsAddressOk,\r
1677 &MappedEvt\r
1678 );\r
1679 if (EFI_ERROR (Status)) {\r
1680 goto ON_EXIT;\r
1681 }\r
1682\r
bf9f7cea 1683 Private->IsAddressOk = FALSE;\r
d1050b9d
MK
1684 Status = Ip6Cfg->RegisterDataNotify (\r
1685 Ip6Cfg,\r
1686 Ip6ConfigDataTypeManualAddress,\r
1687 MappedEvt\r
1688 );\r
1689 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
1690 goto ON_EXIT;\r
1691 }\r
1692\r
1693 Status = Ip6Cfg->SetData (\r
1694 Ip6Cfg,\r
1695 Ip6ConfigDataTypeManualAddress,\r
d1050b9d 1696 sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS),\r
a3bcde70
HT
1697 &CfgAddr\r
1698 );\r
d1050b9d 1699 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
a3bcde70 1700 goto ON_EXIT;\r
bf9f7cea
FS
1701 } else if (Status == EFI_NOT_READY) {\r
1702 //\r
1703 // Poll the network until the asynchronous process is finished.\r
1704 //\r
1705 while (!Private->IsAddressOk) {\r
1706 Ip6->Poll (Ip6);\r
1707 }\r
d1050b9d 1708\r
bf9f7cea
FS
1709 //\r
1710 // Check whether the IP6 address setting is successed.\r
1711 //\r
1712 DataSize = 0;\r
d1050b9d
MK
1713 Status = Ip6Cfg->GetData (\r
1714 Ip6Cfg,\r
1715 Ip6ConfigDataTypeManualAddress,\r
1716 &DataSize,\r
1717 NULL\r
1718 );\r
1719 if ((Status != EFI_BUFFER_TOO_SMALL) || (DataSize == 0)) {\r
bf9f7cea
FS
1720 Status = EFI_DEVICE_ERROR;\r
1721 goto ON_EXIT;\r
1722 }\r
a3bcde70 1723\r
bf9f7cea
FS
1724 Ip6Addr = AllocatePool (DataSize);\r
1725 if (Ip6Addr == NULL) {\r
1726 return EFI_OUT_OF_RESOURCES;\r
1727 }\r
d1050b9d 1728\r
bf9f7cea
FS
1729 Status = Ip6Cfg->GetData (\r
1730 Ip6Cfg,\r
1731 Ip6ConfigDataTypeManualAddress,\r
1732 &DataSize,\r
d1050b9d 1733 (VOID *)Ip6Addr\r
bf9f7cea
FS
1734 );\r
1735 if (EFI_ERROR (Status)) {\r
1736 Status = EFI_DEVICE_ERROR;\r
1737 goto ON_EXIT;\r
1738 }\r
a3bcde70 1739\r
bf9f7cea
FS
1740 for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) {\r
1741 if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) {\r
1742 break;\r
1743 }\r
1744 }\r
d1050b9d 1745\r
bf9f7cea
FS
1746 if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {\r
1747 Status = EFI_ABORTED;\r
1748 goto ON_EXIT;\r
a3bcde70
HT
1749 }\r
1750 }\r
f75a7f56 1751\r
ae97201c
FS
1752 //\r
1753 // Set the default gateway address back if needed.\r
1754 //\r
07f986f1 1755 if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) {\r
ae97201c
FS
1756 Status = Ip6Cfg->SetData (\r
1757 Ip6Cfg,\r
1758 Ip6ConfigDataTypeGateway,\r
1759 sizeof (EFI_IPv6_ADDRESS),\r
1760 &GatewayAddr\r
1761 );\r
1762 if (EFI_ERROR (Status)) {\r
1763 goto ON_EXIT;\r
1764 }\r
1765 }\r
1766\r
a3bcde70
HT
1767ON_EXIT:\r
1768 if (MappedEvt != NULL) {\r
1769 Ip6Cfg->UnregisterDataNotify (\r
1770 Ip6Cfg,\r
1771 Ip6ConfigDataTypeManualAddress,\r
1772 MappedEvt\r
1773 );\r
1774 gBS->CloseEvent (MappedEvt);\r
1775 }\r
d1050b9d 1776\r
bf9f7cea
FS
1777 if (Ip6Addr != NULL) {\r
1778 FreePool (Ip6Addr);\r
a3bcde70 1779 }\r
d1050b9d 1780\r
a3bcde70
HT
1781 return Status;\r
1782}\r
1783\r
ae97201c
FS
1784/**\r
1785 Set the IP6 policy to Automatic.\r
1786\r
1787 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1788\r
5add2c55
AC
1789 @retval EFI_SUCCESS Switch the IP policy successfully.\r
1790 @retval Others Unexpected error happened.\r
ae97201c
FS
1791\r
1792**/\r
1793EFI_STATUS\r
1794PxeBcSetIp6Policy (\r
d1050b9d 1795 IN PXEBC_PRIVATE_DATA *Private\r
ae97201c
FS
1796 )\r
1797{\r
d1050b9d
MK
1798 EFI_IP6_CONFIG_POLICY Policy;\r
1799 EFI_STATUS Status;\r
1800 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
1801 UINTN DataSize;\r
ae97201c 1802\r
d1050b9d
MK
1803 Ip6Cfg = Private->Ip6Cfg;\r
1804 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
ae97201c
FS
1805\r
1806 //\r
1807 // Get and store the current policy of IP6 driver.\r
1808 //\r
1809 Status = Ip6Cfg->GetData (\r
1810 Ip6Cfg,\r
1811 Ip6ConfigDataTypePolicy,\r
1812 &DataSize,\r
1813 &Private->Ip6Policy\r
1814 );\r
1815 if (EFI_ERROR (Status)) {\r
1816 return Status;\r
1817 }\r
1818\r
1819 if (Private->Ip6Policy == Ip6ConfigPolicyManual) {\r
1820 Policy = Ip6ConfigPolicyAutomatic;\r
1821 Status = Ip6Cfg->SetData (\r
1822 Ip6Cfg,\r
1823 Ip6ConfigDataTypePolicy,\r
d1050b9d 1824 sizeof (EFI_IP6_CONFIG_POLICY),\r
ae97201c
FS
1825 &Policy\r
1826 );\r
1827 if (EFI_ERROR (Status)) {\r
1828 //\r
1829 // There is no need to recover later.\r
1830 //\r
1831 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;\r
1832 }\r
1833 }\r
1834\r
1835 return Status;\r
1836}\r
1837\r
1838/**\r
1839 This function will register the station IP address and flush IP instance to start using the new IP address.\r
f75a7f56 1840\r
ae97201c
FS
1841 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
1842\r
1843 @retval EFI_SUCCESS The new IP address has been configured successfully.\r
1844 @retval Others Failed to configure the address.\r
1845\r
1846**/\r
1847EFI_STATUS\r
1848PxeBcSetIp6Address (\r
d1050b9d 1849 IN PXEBC_PRIVATE_DATA *Private\r
ae97201c
FS
1850 )\r
1851{\r
d1050b9d
MK
1852 EFI_STATUS Status;\r
1853 EFI_DHCP6_PROTOCOL *Dhcp6;\r
f75a7f56 1854\r
ae97201c
FS
1855 Dhcp6 = Private->Dhcp6;\r
1856\r
1857 CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
1858 CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
1859\r
1860 Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);\r
1861 if (EFI_ERROR (Status)) {\r
1862 Dhcp6->Stop (Dhcp6);\r
1863 return Status;\r
1864 }\r
1865\r
1866 Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);\r
1867 if (EFI_ERROR (Status)) {\r
1868 PxeBcUnregisterIp6Address (Private);\r
1869 Dhcp6->Stop (Dhcp6);\r
1870 return Status;\r
1871 }\r
1872\r
1873 AsciiPrint ("\n Station IP address is ");\r
1874 PxeBcShowIp6Addr (&Private->StationIp.v6);\r
1875\r
1876 return EFI_SUCCESS;\r
1877}\r
a3bcde70
HT
1878\r
1879/**\r
1880 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver\r
1881 to intercept events that occurred in the configuration process.\r
1882\r
1883 @param[in] This The pointer to the EFI DHCPv6 Protocol.\r
1884 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().\r
1885 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.\r
1886 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a\r
1887 state transition.\r
1888 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.\r
1889 @param[out] NewPacket The packet that is used to replace the Packet above.\r
1890\r
1891 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.\r
1892 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol\r
1893 driver will continue to wait for more packets.\r
1894 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.\r
1895\r
1896**/\r
1897EFI_STATUS\r
1898EFIAPI\r
1899PxeBcDhcp6CallBack (\r
d1050b9d
MK
1900 IN EFI_DHCP6_PROTOCOL *This,\r
1901 IN VOID *Context,\r
1902 IN EFI_DHCP6_STATE CurrentState,\r
1903 IN EFI_DHCP6_EVENT Dhcp6Event,\r
1904 IN EFI_DHCP6_PACKET *Packet,\r
1905 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL\r
a3bcde70
HT
1906 )\r
1907{\r
d1050b9d
MK
1908 PXEBC_PRIVATE_DATA *Private;\r
1909 EFI_PXE_BASE_CODE_MODE *Mode;\r
1910 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
1911 EFI_DHCP6_PACKET *SelectAd;\r
1912 EFI_STATUS Status;\r
1913 BOOLEAN Received;\r
a3bcde70
HT
1914\r
1915 if ((Dhcp6Event != Dhcp6RcvdAdvertise) &&\r
1916 (Dhcp6Event != Dhcp6SelectAdvertise) &&\r
1917 (Dhcp6Event != Dhcp6SendSolicit) &&\r
1918 (Dhcp6Event != Dhcp6SendRequest) &&\r
d1050b9d
MK
1919 (Dhcp6Event != Dhcp6RcvdReply))\r
1920 {\r
a3bcde70
HT
1921 return EFI_SUCCESS;\r
1922 }\r
1923\r
1924 ASSERT (Packet != NULL);\r
1925\r
d1050b9d
MK
1926 Private = (PXEBC_PRIVATE_DATA *)Context;\r
1927 Mode = Private->PxeBc.Mode;\r
1928 Callback = Private->PxeBcCallback;\r
a3bcde70
HT
1929\r
1930 //\r
5add2c55 1931 // Callback to user when any traffic occurred if has.\r
a3bcde70 1932 //\r
d1050b9d
MK
1933 if ((Dhcp6Event != Dhcp6SelectAdvertise) && (Callback != NULL)) {\r
1934 Received = (BOOLEAN)(Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);\r
1935 Status = Callback->Callback (\r
1936 Callback,\r
1937 Private->Function,\r
1938 Received,\r
1939 Packet->Length,\r
1940 (EFI_PXE_BASE_CODE_PACKET *)&Packet->Dhcp6\r
1941 );\r
a3bcde70
HT
1942 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
1943 return EFI_ABORTED;\r
1944 }\r
1945 }\r
1946\r
1947 Status = EFI_SUCCESS;\r
1948\r
1949 switch (Dhcp6Event) {\r
d1050b9d
MK
1950 case Dhcp6SendSolicit:\r
1951 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
1952 //\r
1953 // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
1954 //\r
1955 Status = EFI_ABORTED;\r
1956 break;\r
1957 }\r
a3bcde70 1958\r
632dcfd6 1959 //\r
d1050b9d 1960 // Record the first Solicate msg time\r
632dcfd6 1961 //\r
d1050b9d
MK
1962 if (Private->SolicitTimes == 0) {\r
1963 CalcElapsedTime (Private);\r
1964 Private->SolicitTimes++;\r
1965 }\r
a3bcde70 1966\r
632dcfd6 1967 //\r
d1050b9d 1968 // Cache the dhcp discover packet to mode data directly.\r
632dcfd6 1969 //\r
d1050b9d 1970 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length);\r
632dcfd6 1971 break;\r
d1050b9d
MK
1972\r
1973 case Dhcp6RcvdAdvertise:\r
1974 Status = EFI_NOT_READY;\r
1975 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
1976 //\r
1977 // Ignore the incoming packets which exceed the maximum length.\r
1978 //\r
1979 break;\r
1980 }\r
1981\r
1982 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
1983 //\r
1984 // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
1985 // the OfferIndex and OfferCount.\r
1986 //\r
1987 PxeBcCacheDhcp6Offer (Private, Packet);\r
1988 }\r
1989\r
1990 break;\r
1991\r
1992 case Dhcp6SendRequest:\r
1993 if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) {\r
1994 //\r
1995 // If the to be sent packet exceeds the maximum length, abort the DHCP process.\r
1996 //\r
1997 Status = EFI_ABORTED;\r
1998 break;\r
1999 }\r
2000\r
a3bcde70 2001 //\r
d1050b9d 2002 // Store the request packet as seed packet for discover.\r
a3bcde70 2003 //\r
d1050b9d
MK
2004 if (Private->Dhcp6Request != NULL) {\r
2005 FreePool (Private->Dhcp6Request);\r
2006 }\r
2007\r
2008 Private->Dhcp6Request = AllocateZeroPool (Packet->Size);\r
2009 if (Private->Dhcp6Request != NULL) {\r
2010 CopyMem (Private->Dhcp6Request, Packet, Packet->Size);\r
2011 }\r
2012\r
2013 break;\r
a3bcde70 2014\r
d1050b9d 2015 case Dhcp6SelectAdvertise:\r
632dcfd6 2016 //\r
d1050b9d
MK
2017 // Select offer by the default policy or by order, and record the SelectIndex\r
2018 // and SelectProxyType.\r
632dcfd6 2019 //\r
d1050b9d 2020 PxeBcSelectDhcp6Offer (Private);\r
f75a7f56 2021\r
d1050b9d
MK
2022 if (Private->SelectIndex == 0) {\r
2023 Status = EFI_ABORTED;\r
2024 } else {\r
2025 ASSERT (NewPacket != NULL);\r
2026 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
2027 *NewPacket = AllocateZeroPool (SelectAd->Size);\r
2028 ASSERT (*NewPacket != NULL);\r
2029 if (*NewPacket == NULL) {\r
2030 return EFI_ABORTED;\r
2031 }\r
a3bcde70 2032\r
d1050b9d
MK
2033 CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
2034 }\r
a3bcde70 2035\r
d1050b9d
MK
2036 break;\r
2037\r
2038 case Dhcp6RcvdReply:\r
2039 //\r
2040 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data\r
2041 // without verification.\r
2042 //\r
2043 ASSERT (Private->SelectIndex != 0);\r
2044 Status = PxeBcCopyDhcp6Ack (Private, Packet, FALSE);\r
2045 if (EFI_ERROR (Status)) {\r
2046 Status = EFI_ABORTED;\r
9f4f29cb 2047 }\r
a3bcde70 2048\r
d1050b9d 2049 break;\r
a3bcde70 2050\r
d1050b9d
MK
2051 default:\r
2052 ASSERT (0);\r
a3bcde70
HT
2053 }\r
2054\r
2055 return Status;\r
2056}\r
2057\r
a3bcde70
HT
2058/**\r
2059 Build and send out the request packet for the bootfile, and parse the reply.\r
2060\r
2061 @param[in] Private The pointer to PxeBc private data.\r
2062 @param[in] Type PxeBc option boot item type.\r
2063 @param[in] Layer The pointer to option boot item layer.\r
2064 @param[in] UseBis Use BIS or not.\r
2065 @param[in] DestIp The pointer to the server address.\r
2066\r
2067 @retval EFI_SUCCESS Successfully discovered the boot file.\r
2068 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
2069 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
2070 @retval Others Failed to discover the boot file.\r
2071\r
2072**/\r
2073EFI_STATUS\r
2074PxeBcDhcp6Discover (\r
d1050b9d
MK
2075 IN PXEBC_PRIVATE_DATA *Private,\r
2076 IN UINT16 Type,\r
2077 IN UINT16 *Layer,\r
2078 IN BOOLEAN UseBis,\r
2079 IN EFI_IP_ADDRESS *DestIp\r
a3bcde70
HT
2080 )\r
2081{\r
d1050b9d
MK
2082 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;\r
2083 EFI_PXE_BASE_CODE_UDP_PORT DestPort;\r
2084 EFI_PXE_BASE_CODE_MODE *Mode;\r
2085 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
2086 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;\r
2087 UINTN DiscoverLen;\r
2088 EFI_DHCP6_PACKET *Request;\r
2089 UINTN RequestLen;\r
2090 EFI_DHCP6_PACKET *Reply;\r
2091 UINT8 *RequestOpt;\r
2092 UINT8 *DiscoverOpt;\r
2093 UINTN ReadSize;\r
2094 UINT16 OpCode;\r
2095 UINT16 OpLen;\r
2096 UINT32 Xid;\r
2097 EFI_STATUS Status;\r
2098\r
2099 PxeBc = &Private->PxeBc;\r
2100 Mode = PxeBc->Mode;\r
2101 Request = Private->Dhcp6Request;\r
2102 SrcPort = PXEBC_BS_DISCOVER_PORT;\r
2103 DestPort = PXEBC_BS_DISCOVER_PORT;\r
2104\r
2105 if (!UseBis && (Layer != NULL)) {\r
a3bcde70
HT
2106 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
2107 }\r
2108\r
2109 if (Request == NULL) {\r
2110 return EFI_DEVICE_ERROR;\r
2111 }\r
2112\r
2113 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
2114 if (Discover == NULL) {\r
2115 return EFI_OUT_OF_RESOURCES;\r
2116 }\r
2117\r
2118 //\r
2119 // Build the discover packet by the cached request packet before.\r
2120 //\r
2121 Xid = NET_RANDOM (NetRandomInitSeed ());\r
2122 Discover->TransactionId = HTONL (Xid);\r
2123 Discover->MessageType = Request->Dhcp6.Header.MessageType;\r
2124 RequestOpt = Request->Dhcp6.Option;\r
2125 DiscoverOpt = Discover->DhcpOptions;\r
2126 DiscoverLen = sizeof (EFI_DHCP6_HEADER);\r
2127 RequestLen = DiscoverLen;\r
2128\r
2129 while (RequestLen < Request->Length) {\r
d1050b9d
MK
2130 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode);\r
2131 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen);\r
2132 if ((OpCode != EFI_DHCP6_IA_TYPE_NA) &&\r
2133 (OpCode != EFI_DHCP6_IA_TYPE_TA))\r
2134 {\r
a3bcde70
HT
2135 //\r
2136 // Copy all the options except IA option.\r
2137 //\r
2138 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
2139 DiscoverOpt += (OpLen + 4);\r
2140 DiscoverLen += (OpLen + 4);\r
2141 }\r
d1050b9d 2142\r
a3bcde70
HT
2143 RequestOpt += (OpLen + 4);\r
2144 RequestLen += (OpLen + 4);\r
2145 }\r
2146\r
2147 Status = PxeBc->UdpWrite (\r
2148 PxeBc,\r
903d1fa9 2149 0,\r
a3bcde70
HT
2150 &Private->ServerIp,\r
2151 &DestPort,\r
2152 NULL,\r
2153 &Private->StationIp,\r
2154 &SrcPort,\r
2155 NULL,\r
2156 NULL,\r
2157 &DiscoverLen,\r
d1050b9d 2158 (VOID *)Discover\r
a3bcde70
HT
2159 );\r
2160 if (EFI_ERROR (Status)) {\r
2fad330f 2161 goto ON_ERROR;\r
a3bcde70
HT
2162 }\r
2163\r
2164 //\r
2165 // Cache the right PXE reply packet here, set valid flag later.\r
2166 // Especially for PXE discover packet, store it into mode data here.\r
2167 //\r
2168 if (Private->IsDoDiscover) {\r
2169 CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen);\r
2170 Reply = &Private->PxeReply.Dhcp6.Packet.Ack;\r
2171 } else {\r
2172 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;\r
2173 }\r
d1050b9d
MK
2174\r
2175 ReadSize = (UINTN)Reply->Size;\r
a3bcde70 2176\r
357af285 2177 //\r
2178 // Start Udp6Read instance\r
2179 //\r
2180 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
2181 if (EFI_ERROR (Status)) {\r
2fad330f 2182 goto ON_ERROR;\r
357af285 2183 }\r
f75a7f56 2184\r
a3bcde70
HT
2185 Status = PxeBc->UdpRead (\r
2186 PxeBc,\r
903d1fa9
FS
2187 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,\r
2188 NULL,\r
a3bcde70
HT
2189 &SrcPort,\r
2190 &Private->ServerIp,\r
2191 &DestPort,\r
2192 NULL,\r
2193 NULL,\r
2194 &ReadSize,\r
d1050b9d 2195 (VOID *)&Reply->Dhcp6\r
a3bcde70 2196 );\r
357af285 2197 //\r
2198 // Stop Udp6Read instance\r
2199 //\r
2200 Private->Udp6Read->Configure (Private->Udp6Read, NULL);\r
a3bcde70 2201 if (EFI_ERROR (Status)) {\r
2fad330f 2202 goto ON_ERROR;\r
a3bcde70
HT
2203 }\r
2204\r
2205 return EFI_SUCCESS;\r
2fad330f
FS
2206\r
2207ON_ERROR:\r
2208 if (Discover != NULL) {\r
2209 FreePool (Discover);\r
2210 }\r
2211\r
2212 return Status;\r
a3bcde70
HT
2213}\r
2214\r
a3bcde70
HT
2215/**\r
2216 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.\r
2217\r
2218 @param[in] Private The pointer to PxeBc private data.\r
2219 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL\r
2220\r
2221 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.\r
2222 @retval Others Failed to finish the S.A.R.R. process.\r
2223\r
2224**/\r
2225EFI_STATUS\r
2226PxeBcDhcp6Sarr (\r
d1050b9d
MK
2227 IN PXEBC_PRIVATE_DATA *Private,\r
2228 IN EFI_DHCP6_PROTOCOL *Dhcp6\r
a3bcde70
HT
2229 )\r
2230{\r
d1050b9d
MK
2231 EFI_PXE_BASE_CODE_MODE *PxeMode;\r
2232 EFI_DHCP6_CONFIG_DATA Config;\r
2233 EFI_DHCP6_MODE_DATA Mode;\r
2234 EFI_DHCP6_RETRANSMISSION *Retransmit;\r
2235 EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM];\r
2236 UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];\r
2237 UINT32 OptCount;\r
2238 EFI_STATUS Status;\r
2239 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
2240 EFI_STATUS TimerStatus;\r
2241 EFI_EVENT Timer;\r
2242 UINT64 GetMappingTimeOut;\r
2243 UINTN DataSize;\r
2244 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;\r
2245\r
2246 Status = EFI_SUCCESS;\r
2247 PxeMode = Private->PxeBc.Mode;\r
2248 Ip6Cfg = Private->Ip6Cfg;\r
2249 Timer = NULL;\r
a3bcde70
HT
2250\r
2251 //\r
2252 // Build option list for the request packet.\r
2253 //\r
d1050b9d
MK
2254 OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer);\r
2255 ASSERT (OptCount > 0);\r
a3bcde70
HT
2256\r
2257 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r
2258 if (Retransmit == NULL) {\r
2259 return EFI_OUT_OF_RESOURCES;\r
2260 }\r
2261\r
2262 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
2263 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
2264\r
2265 Config.OptionCount = OptCount;\r
2266 Config.OptionList = OptList;\r
2267 Config.Dhcp6Callback = PxeBcDhcp6CallBack;\r
2268 Config.CallbackContext = Private;\r
2269 Config.IaInfoEvent = NULL;\r
2270 Config.RapidCommit = FALSE;\r
2271 Config.ReconfigureAccept = FALSE;\r
75dce340 2272 Config.IaDescriptor.IaId = Private->IaId;\r
a3bcde70
HT
2273 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;\r
2274 Config.SolicitRetransmission = Retransmit;\r
2275 Retransmit->Irt = 4;\r
2276 Retransmit->Mrc = 4;\r
2277 Retransmit->Mrt = 32;\r
2278 Retransmit->Mrd = 60;\r
2279\r
2280 //\r
2281 // Configure the DHCPv6 instance for PXE boot.\r
2282 //\r
2283 Status = Dhcp6->Configure (Dhcp6, &Config);\r
ed2bfecb 2284 FreePool (Retransmit);\r
a3bcde70 2285 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
2286 return Status;\r
2287 }\r
2288\r
2289 //\r
2290 // Initialize the record fields for DHCPv6 offer in private data.\r
2291 //\r
2292 Private->IsProxyRecved = FALSE;\r
2293 Private->OfferNum = 0;\r
2294 Private->SelectIndex = 0;\r
2295 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
2296 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
2297\r
a3bcde70
HT
2298 //\r
2299 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
2300 //\r
2301 Status = Dhcp6->Start (Dhcp6);\r
ed2bfecb 2302 if (Status == EFI_NO_MAPPING) {\r
2303 //\r
2304 // IP6 Linklocal address is not available for use, so stop current Dhcp process\r
2305 // and wait for duplicate address detection to finish.\r
2306 //\r
2307 Dhcp6->Stop (Dhcp6);\r
2308\r
2309 //\r
2310 // Get Duplicate Address Detection Transmits count.\r
2311 //\r
2312 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
d1050b9d
MK
2313 Status = Ip6Cfg->GetData (\r
2314 Ip6Cfg,\r
2315 Ip6ConfigDataTypeDupAddrDetectTransmits,\r
2316 &DataSize,\r
2317 &DadXmits\r
2318 );\r
ed2bfecb 2319 if (EFI_ERROR (Status)) {\r
2320 Dhcp6->Configure (Dhcp6, NULL);\r
2321 return Status;\r
2322 }\r
2323\r
2324 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
2325 if (EFI_ERROR (Status)) {\r
2326 Dhcp6->Configure (Dhcp6, NULL);\r
2327 return Status;\r
2328 }\r
2329\r
2330 GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;\r
d1050b9d 2331 Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);\r
ed2bfecb 2332 if (EFI_ERROR (Status)) {\r
2333 gBS->CloseEvent (Timer);\r
2334 Dhcp6->Configure (Dhcp6, NULL);\r
2335 return Status;\r
2336 }\r
2337\r
2338 do {\r
ed2bfecb 2339 TimerStatus = gBS->CheckEvent (Timer);\r
2340 if (!EFI_ERROR (TimerStatus)) {\r
2341 Status = Dhcp6->Start (Dhcp6);\r
2342 }\r
2343 } while (TimerStatus == EFI_NOT_READY);\r
f75a7f56 2344\r
ed2bfecb 2345 gBS->CloseEvent (Timer);\r
2346 }\r
d1050b9d 2347\r
a3bcde70
HT
2348 if (EFI_ERROR (Status)) {\r
2349 if (Status == EFI_ICMP_ERROR) {\r
2350 PxeMode->IcmpErrorReceived = TRUE;\r
2351 }\r
d1050b9d 2352\r
a3bcde70
HT
2353 Dhcp6->Configure (Dhcp6, NULL);\r
2354 return Status;\r
2355 }\r
2356\r
2357 //\r
2358 // Get the acquired IPv6 address and store them.\r
2359 //\r
2360 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);\r
2361 if (EFI_ERROR (Status)) {\r
2362 Dhcp6->Stop (Dhcp6);\r
2363 return Status;\r
2364 }\r
2365\r
bec55c33 2366 ASSERT ((Mode.Ia != NULL) && (Mode.Ia->State == Dhcp6Bound));\r
ae97201c
FS
2367 //\r
2368 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the\r
2369 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when\r
2370 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as\r
f75a7f56 2371 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery\r
ae97201c
FS
2372 // to find a valid router address.\r
2373 //\r
2374 CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
ce22514e
ZL
2375 if (Mode.ClientId != NULL) {\r
2376 FreePool (Mode.ClientId);\r
2377 }\r
d1050b9d 2378\r
ce22514e
ZL
2379 if (Mode.Ia != NULL) {\r
2380 FreePool (Mode.Ia);\r
2381 }\r
d1050b9d 2382\r
a3bcde70
HT
2383 //\r
2384 // Check the selected offer whether BINL retry is needed.\r
2385 //\r
2386 Status = PxeBcHandleDhcp6Offer (Private);\r
2387 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
2388 Dhcp6->Stop (Dhcp6);\r
2389 return Status;\r
2390 }\r
f75a7f56 2391\r
a3bcde70
HT
2392 return EFI_SUCCESS;\r
2393}\r