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