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