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