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