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