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