]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
Add CONSTRUCTOR to BaseDebugLibSerialPort to call SerialPortInitialize() in the Seria...
[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
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
18\r
19/**\r
20 Parse out a DHCPv6 option by OptTag, and find the position in buffer.\r
21\r
22 @param[in] Buffer The pointer to the option buffer.\r
23 @param[in] Length Length of the option buffer.\r
24 @param[in] OptTag The required option tag.\r
25\r
26 @retval NULL Failed to parse the required option.\r
27 @retval Others The postion of the required option in buffer.\r
28\r
29**/\r
30EFI_DHCP6_PACKET_OPTION *\r
31PxeBcParseDhcp6Options (\r
32 IN UINT8 *Buffer,\r
33 IN UINT32 Length,\r
34 IN UINT16 OptTag\r
35 )\r
36{\r
37 EFI_DHCP6_PACKET_OPTION *Option;\r
38 UINT32 Offset;\r
39\r
40 Option = (EFI_DHCP6_PACKET_OPTION *) Buffer;\r
41 Offset = 0;\r
42\r
43 //\r
44 // OpLen and OpCode here are both stored in network order.\r
45 //\r
46 while (Offset < Length) {\r
47\r
48 if (NTOHS (Option->OpCode) == OptTag) {\r
49\r
50 return Option;\r
51 }\r
52\r
53 Offset += (NTOHS(Option->OpLen) + 4);\r
54 Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset);\r
55 }\r
56\r
57 return NULL;\r
58}\r
59\r
60\r
61/**\r
62 Build the options buffer for the DHCPv6 request packet.\r
63\r
64 @param[in] Private The pointer to PxeBc private data.\r
65 @param[out] OptList The pointer to the option pointer array.\r
66 @param[in] Buffer The pointer to the buffer to contain the option list.\r
67\r
68 @return Index The count of the built-in options.\r
69\r
70**/\r
71UINT32\r
72PxeBcBuildDhcp6Options (\r
73 IN PXEBC_PRIVATE_DATA *Private,\r
74 OUT EFI_DHCP6_PACKET_OPTION **OptList,\r
75 IN UINT8 *Buffer\r
76 )\r
77{\r
78 PXEBC_DHCP6_OPTION_ENTRY OptEnt;\r
79 UINT32 Index;\r
80 UINT16 Value;\r
81\r
82 Index = 0;\r
83 OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer;\r
84\r
85 //\r
86 // Append client option request option\r
87 //\r
88 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ORO);\r
89 OptList[Index]->OpLen = HTONS (4);\r
90 OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;\r
91 OptEnt.Oro->OpCode[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL);\r
92 OptEnt.Oro->OpCode[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM);\r
93 Index++;\r
94 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
95\r
96 //\r
97 // Append client network device interface option\r
98 //\r
99 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_UNDI);\r
852b6341 100 OptList[Index]->OpLen = HTONS ((UINT16)3);\r
a3bcde70
HT
101 OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;\r
102\r
103 if (Private->Nii != NULL) {\r
104 OptEnt.Undi->Type = Private->Nii->Type;\r
105 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
106 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
107 } else {\r
108 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;\r
109 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;\r
110 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;\r
111 }\r
112\r
a3bcde70
HT
113 Index++;\r
114 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
115\r
116 //\r
117 // Append client system architecture option\r
118 //\r
119 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ARCH);\r
120 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH));\r
121 OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data;\r
122 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);\r
123 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
124 Index++;\r
125 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);\r
126\r
127 //\r
128 // Append vendor class option to store the PXE class identifier.\r
129 //\r
130 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS);\r
131 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS));\r
132 OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data;\r
133 OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);\r
134 OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID));\r
135 CopyMem (\r
136 &OptEnt.VendorClass->ClassId,\r
137 DEFAULT_CLASS_ID_DATA,\r
138 sizeof (PXEBC_CLASS_ID)\r
139 );\r
140 PxeBcUintnToAscDecWithFormat (\r
141 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,\r
142 OptEnt.VendorClass->ClassId.ArchitectureType,\r
143 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)\r
144 );\r
145\r
146 if (Private->Nii != NULL) {\r
147 CopyMem (\r
148 OptEnt.VendorClass->ClassId.InterfaceName,\r
149 Private->Nii->StringId,\r
150 sizeof (OptEnt.VendorClass->ClassId.InterfaceName)\r
151 );\r
152 PxeBcUintnToAscDecWithFormat (\r
153 Private->Nii->MajorVer,\r
154 OptEnt.VendorClass->ClassId.UndiMajor,\r
155 sizeof (OptEnt.VendorClass->ClassId.UndiMajor)\r
156 );\r
157 PxeBcUintnToAscDecWithFormat (\r
158 Private->Nii->MinorVer,\r
159 OptEnt.VendorClass->ClassId.UndiMinor,\r
160 sizeof (OptEnt.VendorClass->ClassId.UndiMinor)\r
161 );\r
162 }\r
163\r
164 Index++;\r
165\r
166 return Index;\r
167}\r
168\r
169\r
170/**\r
171 Cache the DHCPv6 packet.\r
172\r
173 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.\r
174 @param[in] Src The pointer to the DHCPv6 packet to be cached.\r
175\r
176**/\r
177VOID\r
178PxeBcCacheDhcp6Packet (\r
179 IN EFI_DHCP6_PACKET *Dst,\r
180 IN EFI_DHCP6_PACKET *Src\r
181 )\r
182{\r
183 ASSERT (Dst->Size >= Src->Length);\r
184\r
185 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);\r
186 Dst->Length = Src->Length;\r
187}\r
188\r
189\r
190/**\r
191 Free all the nodes in the list for boot file.\r
192\r
193 @param[in] Head The pointer to the head of list.\r
194\r
195**/\r
196VOID\r
197PxeBcFreeBootFileOption (\r
198 IN LIST_ENTRY *Head\r
199 )\r
200{\r
201 LIST_ENTRY *Entry;\r
202 LIST_ENTRY *NextEntry;\r
203 PXEBC_DHCP6_OPTION_NODE *Node;\r
204\r
205 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) {\r
206 Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link);\r
207 RemoveEntryList (Entry);\r
208 FreePool (Node);\r
209 }\r
210}\r
211\r
212\r
213/**\r
214 Parse the Boot File URL option.\r
215\r
216 @param[out] FileName The pointer to the boot file name.\r
217 @param[in, out] SrvAddr The pointer to the boot server address.\r
218 @param[in] BootFile The pointer to the boot file URL option data.\r
219 @param[in] Length The length of the boot file URL option data.\r
220\r
221 @retval EFI_ABORTED User cancel operation.\r
222 @retval EFI_SUCCESS Selected the boot menu successfully.\r
223 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.\r
224\r
225**/\r
226EFI_STATUS\r
227PxeBcExtractBootFileUrl (\r
228 OUT UINT8 **FileName,\r
229 IN OUT EFI_IPv6_ADDRESS *SrvAddr,\r
230 IN CHAR8 *BootFile,\r
231 IN UINT16 Length\r
232 )\r
233{\r
234 UINT16 PrefixLen;\r
235 UINT8 *BootFileNamePtr;\r
236 UINT8 *BootFileName;\r
237 UINT16 BootFileNameLen;\r
238 CHAR8 *TmpStr;\r
239 CHAR8 *ServerAddressOption;\r
240 CHAR8 *ServerAddress;\r
241 EFI_STATUS Status;\r
242\r
243 //\r
244 // The format of the Boot File URL option is:\r
245 //\r
246 // 0 1 2 3\r
247 // 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
248 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
249 // | OPT_BOOTFILE_URL | option-len |\r
250 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
251 // | |\r
252 // . bootfile-url (variable length) .\r
253 // | |\r
254 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
255 //\r
256\r
257 //\r
c01fa590 258 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format\r
259 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME\r
a3bcde70
HT
260 // As an example where the BOOTFILE_NAME is the EFI loader and\r
261 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.\r
262 //\r
263 PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX);\r
264\r
265 if (Length <= PrefixLen ||\r
266 CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) {\r
267 return EFI_NOT_FOUND;\r
268 }\r
269\r
270 BootFile = BootFile + PrefixLen;\r
271 Length = (UINT16) (Length - PrefixLen);\r
272\r
273 TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1);\r
274 if (TmpStr == NULL) {\r
275 return EFI_OUT_OF_RESOURCES;\r
276 }\r
277\r
278 CopyMem (TmpStr, BootFile, Length);\r
279 TmpStr[Length] = '\0';\r
280\r
281 //\r
282 // Get the part of SERVER_ADDRESS string.\r
283 //\r
284 ServerAddressOption = TmpStr;\r
285 if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {\r
286 FreePool (TmpStr);\r
287 return EFI_INVALID_PARAMETER;\r
288 }\r
289\r
290 ServerAddressOption ++;\r
291 ServerAddress = ServerAddressOption;\r
292 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
293 ServerAddress++;\r
294 }\r
295\r
296 if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {\r
297 FreePool (TmpStr);\r
298 return EFI_INVALID_PARAMETER;\r
299 }\r
300\r
301 *ServerAddress = '\0';\r
302\r
303 //\r
304 // Convert the string of server address to Ipv6 address format and store it.\r
305 //\r
306 Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);\r
307 if (EFI_ERROR (Status)) {\r
308 FreePool (TmpStr);\r
309 return Status;\r
310 }\r
311\r
312 //\r
313 // Get the part of BOOTFILE_NAME string.\r
314 //\r
315 BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1);\r
316 if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
317 FreePool (TmpStr);\r
318 return EFI_INVALID_PARAMETER;\r
319 }\r
320\r
321 ++BootFileNamePtr;\r
322 BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);\r
323 if (BootFileNameLen != 0 || FileName != NULL) {\r
324 BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen);\r
325 if (BootFileName == NULL) {\r
326 FreePool (TmpStr);\r
327 return EFI_OUT_OF_RESOURCES;\r
328 }\r
329\r
330 CopyMem (BootFileName, BootFileNamePtr, BootFileNameLen);\r
331 BootFileName[BootFileNameLen - 1] = '\0';\r
332 *FileName = BootFileName;\r
333 }\r
334\r
335\r
336 FreePool (TmpStr);\r
337\r
338 return EFI_SUCCESS;\r
339}\r
340\r
341\r
342/**\r
343 Parse the Boot File Parameter option.\r
344\r
345 @param[in] BootFilePara The pointer to boot file parameter option data.\r
346 @param[out] BootFileSize The pointer to the parsed boot file size.\r
347\r
348 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.\r
349 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.\r
350\r
351**/\r
352EFI_STATUS\r
353PxeBcExtractBootFileParam (\r
354 IN CHAR8 *BootFilePara,\r
355 OUT UINT16 *BootFileSize\r
356 )\r
357{\r
358 UINT16 Length;\r
359 UINT8 Index;\r
360 UINT8 Digit;\r
361 UINT32 Size;\r
362\r
363 CopyMem (&Length, BootFilePara, sizeof (UINT16));\r
364 Length = NTOHS (Length);\r
365\r
366 //\r
367 // The BootFile Size should be 1~5 byte ASCII strings\r
368 //\r
369 if (Length < 1 || Length > 5) {\r
370 return EFI_NOT_FOUND;\r
371 }\r
372\r
373 //\r
374 // Extract the value of BootFile Size.\r
375 //\r
376 BootFilePara = BootFilePara + sizeof (UINT16);\r
377 Size = 0;\r
378 for (Index = 0; Index < Length; Index++) {\r
379 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) {\r
380 return EFI_NOT_FOUND;\r
381 }\r
382\r
383 Size = (Size + Digit) * 10;\r
384 }\r
385\r
386 Size = Size / 10;\r
387 if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) {\r
388 return EFI_NOT_FOUND;\r
389 }\r
390\r
391 *BootFileSize = (UINT16) Size;\r
392 return EFI_SUCCESS;\r
393}\r
394\r
395\r
396/**\r
397 Parse the cached DHCPv6 packet, including all the options.\r
398\r
399 @param[in] Cache6 The pointer to a cached DHCPv6 packet.\r
400\r
401 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.\r
402 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.\r
403\r
404**/\r
405EFI_STATUS\r
406PxeBcParseDhcp6Packet (\r
407 IN PXEBC_DHCP6_PACKET_CACHE *Cache6\r
408 )\r
409{\r
410 EFI_DHCP6_PACKET *Offer;\r
411 EFI_DHCP6_PACKET_OPTION **Options;\r
412 EFI_DHCP6_PACKET_OPTION *Option;\r
413 PXEBC_OFFER_TYPE OfferType;\r
414 BOOLEAN IsProxyOffer;\r
415 BOOLEAN IsPxeOffer;\r
416 UINT32 Offset;\r
417 UINT32 Length;\r
418 UINT32 EnterpriseNum;\r
419\r
420 IsProxyOffer = TRUE;\r
421 IsPxeOffer = FALSE;\r
422 Offer = &Cache6->Packet.Offer;\r
423 Options = Cache6->OptList;\r
424\r
425 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));\r
426\r
427 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option);\r
428 Offset = 0;\r
429 Length = GET_DHCP6_OPTION_SIZE (Offer);\r
430\r
431 //\r
432 // OpLen and OpCode here are both stored in network order, since they are from original packet.\r
433 //\r
434 while (Offset < Length) {\r
435\r
436 if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) {\r
437 Options[PXEBC_DHCP6_IDX_IA_NA] = Option;\r
438 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) {\r
439 //\r
440 // The server sends this option to inform the client about an URL to a boot file.\r
441 //\r
442 Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option;\r
443 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) {\r
444 Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;\r
445 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) {\r
446 Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;\r
447 }\r
448\r
449 Offset += (NTOHS (Option->OpLen) + 4);\r
450 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset);\r
451 }\r
452\r
453 //\r
454 // The offer with assigned client address is a proxy offer.\r
455 // An ia_na option, embeded with valid ia_addr option and a status_code of success.\r
456 //\r
457 Option = Options[PXEBC_DHCP6_IDX_IA_NA];\r
458 if (Option != NULL && NTOHS(Option->OpLen) >= 12) {\r
459 Option = PxeBcParseDhcp6Options (\r
460 Option->Data + 12,\r
461 NTOHS (Option->OpLen),\r
462 PXEBC_DHCP6_OPT_STATUS_CODE\r
463 );\r
464 if (Option != NULL && Option->Data[0] == 0) {\r
465 IsProxyOffer = FALSE;\r
466 }\r
467 }\r
468\r
469 //\r
470 // The offer with "PXEClient" is a pxe offer.\r
471 //\r
472 Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];\r
473 EnterpriseNum = PXEBC_DHCP6_ENTERPRISE_NUM;\r
474 if (Option != NULL &&\r
475 NTOHS(Option->OpLen) >= 13 &&\r
476 CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&\r
477 CompareMem (&Option->Data[4], DEFAULT_CLASS_ID_DATA, 9) == 0) {\r
478 IsPxeOffer = TRUE;\r
479 }\r
480\r
481 //\r
482 // Determine offer type of the dhcp6 packet.\r
483 //\r
484 if (IsPxeOffer) {\r
485 //\r
486 // It's a binl offer only with PXEClient.\r
487 //\r
488 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;\r
489 } else {\r
490 //\r
491 // It's a dhcp only offer, which is a pure dhcp6 offer packet.\r
492 //\r
493 OfferType = PxeOfferTypeDhcpOnly;\r
494 }\r
495\r
496 Cache6->OfferType = OfferType;\r
497\r
498 return EFI_SUCCESS;\r
499}\r
500\r
501\r
502/**\r
503 Cache the DHCPv6 ack packet, and parse it on demand.\r
504\r
505 @param[in] Private The pointer to PxeBc private data.\r
506 @param[in] Ack The pointer to the DHCPv6 ack packet.\r
507 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.\r
508\r
509**/\r
510VOID\r
511PxeBcCopyDhcp6Ack (\r
512 IN PXEBC_PRIVATE_DATA *Private,\r
513 IN EFI_DHCP6_PACKET *Ack,\r
514 IN BOOLEAN Verified\r
515 )\r
516{\r
517 EFI_PXE_BASE_CODE_MODE *Mode;\r
518\r
519 Mode = Private->PxeBc.Mode;\r
520\r
521 PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);\r
522\r
523 if (Verified) {\r
524 //\r
525 // Parse the ack packet and store it into mode data if needed.\r
526 //\r
527 PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6);\r
528 CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);\r
529 Mode->DhcpAckReceived = TRUE;\r
530 }\r
531}\r
532\r
533\r
534/**\r
535 Cache the DHCPv6 proxy offer packet according to the received order.\r
536\r
537 @param[in] Private The pointer to PxeBc private data.\r
538 @param[in] OfferIndex The received order of offer packets.\r
539\r
540**/\r
541VOID\r
542PxeBcCopyDhcp6Proxy (\r
543 IN PXEBC_PRIVATE_DATA *Private,\r
544 IN UINT32 OfferIndex\r
545 )\r
546{\r
547 EFI_PXE_BASE_CODE_MODE *Mode;\r
548 EFI_DHCP6_PACKET *Offer;\r
549\r
550 ASSERT (OfferIndex < Private->OfferNum);\r
551 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);\r
552\r
553 Mode = Private->PxeBc.Mode;\r
554 Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer;\r
555\r
556 //\r
557 // Cache the proxy offer packet and parse it.\r
558 //\r
559 PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);\r
560 PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);\r
561\r
562 //\r
563 // Store this packet into mode data.\r
564 //\r
565 CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);\r
566 Mode->ProxyOfferReceived = TRUE;\r
567}\r
568\r
569\r
570/**\r
571 Retry to request bootfile name by the BINL offer.\r
572\r
573 @param[in] Private The pointer to PxeBc private data.\r
574 @param[in] Index The received order of offer packets.\r
575\r
576 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.\r
577 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.\r
578\r
579**/\r
580EFI_STATUS\r
581PxeBcRetryDhcp6Binl (\r
582 IN PXEBC_PRIVATE_DATA *Private,\r
583 IN UINT32 Index\r
584 )\r
585{\r
586 EFI_PXE_BASE_CODE_MODE *Mode;\r
587 PXEBC_DHCP6_PACKET_CACHE *Offer;\r
588 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
589 EFI_IP_ADDRESS ServerIp;\r
590 EFI_STATUS Status;\r
591\r
592 ASSERT (Index < PXEBC_OFFER_MAX_NUM);\r
593 ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl ||\r
594 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl);\r
595\r
596 Mode = Private->PxeBc.Mode;\r
597 Private->IsDoDiscover = FALSE;\r
598 Offer = &Private->OfferBuffer[Index].Dhcp6;\r
599\r
600 ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
601 //\r
602 // Parse out the next server address from the last offer, and store it\r
603 //\r
604 Status = PxeBcExtractBootFileUrl (\r
605 NULL,\r
606 &ServerIp.v6,\r
607 (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
608 NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
609 );\r
610 if (EFI_ERROR (Status)) {\r
611 return Status;\r
612 }\r
613\r
614 //\r
615 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.\r
616 //\r
617 Status = PxeBcDhcp6Discover (\r
618 Private,\r
619 0,\r
620 NULL,\r
621 FALSE,\r
622 &ServerIp\r
623 );\r
624 if (EFI_ERROR (Status)) {\r
625 return Status;\r
626 }\r
627\r
628 Cache6 = &Private->ProxyOffer.Dhcp6;\r
629 Status = PxeBcParseDhcp6Packet (Cache6);\r
630 if (EFI_ERROR (Status)) {\r
631 return Status;\r
632 }\r
633\r
634 if (Cache6->OfferType != PxeOfferTypeProxyPxe10 &&\r
635 Cache6->OfferType != PxeOfferTypeProxyWfm11a &&\r
636 Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
637 //\r
638 // This BINL ack doesn't have discovery option set or multicast option set\r
639 // or bootfile name specified.\r
640 //\r
641 return EFI_DEVICE_ERROR;\r
642 }\r
643\r
644 Mode->ProxyOfferReceived = TRUE;\r
645 CopyMem (\r
646 &Mode->ProxyOffer.Dhcpv6,\r
647 &Cache6->Packet.Offer.Dhcp6,\r
648 Cache6->Packet.Offer.Length\r
649 );\r
650\r
651 return EFI_SUCCESS;\r
652}\r
653\r
654\r
655/**\r
656 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.\r
657\r
658 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
659 @param[in] RcvdOffer The pointer to the received offer packet.\r
660\r
661**/\r
662VOID\r
663PxeBcCacheDhcp6Offer (\r
664 IN PXEBC_PRIVATE_DATA *Private,\r
665 IN EFI_DHCP6_PACKET *RcvdOffer\r
666 )\r
667{\r
668 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
669 EFI_DHCP6_PACKET *Offer;\r
670 PXEBC_OFFER_TYPE OfferType;\r
671\r
672 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;\r
673 Offer = &Cache6->Packet.Offer;\r
674\r
675 //\r
676 // Cache the content of DHCPv6 packet firstly.\r
677 //\r
678 PxeBcCacheDhcp6Packet (Offer, RcvdOffer);\r
679\r
680 //\r
681 // Validate the DHCPv6 packet, and parse the options and offer type.\r
682 //\r
683 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {\r
684 return ;\r
685 }\r
686\r
687 //\r
688 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.\r
689 //\r
690 OfferType = Cache6->OfferType;\r
691 ASSERT (OfferType < PxeOfferTypeMax);\r
692 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);\r
693\r
694 if (IS_PROXY_OFFER (OfferType)) {\r
695 //\r
696 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.\r
697 //\r
698 Private->IsProxyRecved = TRUE;\r
699\r
700 if (OfferType == PxeOfferTypeProxyBinl) {\r
701 //\r
702 // Cache all proxy BINL offers.\r
703 //\r
704 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
705 Private->OfferCount[OfferType]++;\r
706 } else if (Private->OfferCount[OfferType] > 0) {\r
707 //\r
708 // Only cache the first PXE10/WFM11a offer, and discard the others.\r
709 //\r
710 Private->OfferIndex[OfferType][0] = Private->OfferNum;\r
711 Private->OfferCount[OfferType] = 1;\r
712 } else {\r
713 return;\r
714 }\r
715 } else {\r
716 //\r
717 // It's a DHCPv6 offer with yiaddr, and cache them all.\r
718 //\r
719 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;\r
720 Private->OfferCount[OfferType]++;\r
721 }\r
722\r
723 Private->OfferNum++;\r
724}\r
725\r
726\r
727/**\r
728 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.\r
729\r
730 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
731\r
732**/\r
733VOID\r
734PxeBcSelectDhcp6Offer (\r
735 IN PXEBC_PRIVATE_DATA *Private\r
736 )\r
737{\r
738 UINT32 Index;\r
739 UINT32 OfferIndex;\r
740 PXEBC_OFFER_TYPE OfferType;\r
741\r
742 Private->SelectIndex = 0;\r
743\r
744 if (Private->IsOfferSorted) {\r
745 //\r
746 // Select offer by default policy.\r
747 //\r
748 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {\r
749 //\r
750 // 1. DhcpPxe10 offer\r
751 //\r
752 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;\r
753\r
754 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {\r
755 //\r
756 // 2. DhcpWfm11a offer\r
757 //\r
758 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;\r
759\r
760 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
761 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {\r
762 //\r
763 // 3. DhcpOnly offer and ProxyPxe10 offer.\r
764 //\r
765 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
766 Private->SelectProxyType = PxeOfferTypeProxyPxe10;\r
767\r
768 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
769 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {\r
770 //\r
771 // 4. DhcpOnly offer and ProxyWfm11a offer.\r
772 //\r
773 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
774 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;\r
775\r
776 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {\r
777 //\r
778 // 5. DhcpBinl offer.\r
779 //\r
780 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;\r
781\r
782 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&\r
783 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {\r
784 //\r
785 // 6. DhcpOnly offer and ProxyBinl offer.\r
786 //\r
787 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;\r
788 Private->SelectProxyType = PxeOfferTypeProxyBinl;\r
789\r
790 } else {\r
791 //\r
792 // 7. DhcpOnly offer with bootfilename.\r
793 //\r
794 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {\r
795 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];\r
796 if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) {\r
797 Private->SelectIndex = OfferIndex + 1;\r
798 break;\r
799 }\r
800 }\r
801 }\r
802 } else {\r
803 //\r
804 // Select offer by received order.\r
805 //\r
806 for (Index = 0; Index < Private->OfferNum; Index++) {\r
807\r
808 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;\r
809\r
810 if (IS_PROXY_OFFER (OfferType)) {\r
811 //\r
812 // Skip proxy offers\r
813 //\r
814 continue;\r
815 }\r
816\r
817 if (!Private->IsProxyRecved &&\r
818 OfferType == PxeOfferTypeDhcpOnly &&\r
819 Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {\r
820 //\r
821 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.\r
822 //\r
823 continue;\r
824 }\r
825\r
826 Private->SelectIndex = Index + 1;\r
827 break;\r
828 }\r
829 }\r
830}\r
831\r
832\r
833/**\r
834 Handle the DHCPv6 offer packet.\r
835\r
836 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
837\r
838 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.\r
839 @retval EFI_NO_RESPONSE No response to the following request packet.\r
840\r
841**/\r
842EFI_STATUS\r
843PxeBcHandleDhcp6Offer (\r
844 IN PXEBC_PRIVATE_DATA *Private\r
845 )\r
846{\r
847 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
848 EFI_STATUS Status;\r
849 PXEBC_OFFER_TYPE OfferType;\r
850 UINT32 ProxyIndex;\r
851 UINT32 SelectIndex;\r
852 UINT32 Index;\r
853\r
854 ASSERT (Private->SelectIndex > 0);\r
855 SelectIndex = (UINT32) (Private->SelectIndex - 1);\r
856 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);\r
857 Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6;\r
858 Status = EFI_SUCCESS;\r
859\r
860 if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
861 //\r
862 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.\r
863 //\r
864 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) {\r
865 Status = EFI_NO_RESPONSE;\r
866 }\r
867 } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) {\r
868\r
869 if (Private->IsProxyRecved) {\r
870 //\r
871 // DhcpOnly offer is selected, so need try to request bootfilename.\r
872 //\r
873 ProxyIndex = 0;\r
874 if (Private->IsOfferSorted) {\r
875 //\r
876 // The proxy offer should be determined if select by default policy.\r
877 // IsOfferSorted means all offers are labeled by OfferIndex.\r
878 //\r
879 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);\r
880\r
881 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {\r
882 //\r
883 // Try all the cached ProxyBinl offer one by one to request bootfilename.\r
884 //\r
885 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {\r
886\r
887 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];\r
888 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) {\r
889 break;\r
890 }\r
891 }\r
892 if (Index == Private->OfferCount[Private->SelectProxyType]) {\r
893 Status = EFI_NO_RESPONSE;\r
894 }\r
895 } else {\r
896 //\r
897 // For other proxy offers (pxe10 or wfm11a), only one is buffered.\r
898 //\r
899 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];\r
900 }\r
901 } else {\r
902 //\r
903 // The proxy offer should not be determined if select by received order.\r
904 //\r
905 Status = EFI_NO_RESPONSE;\r
906\r
907 for (Index = 0; Index < Private->OfferNum; Index++) {\r
908\r
909 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;\r
910\r
911 if (!IS_PROXY_OFFER (OfferType)) {\r
912 //\r
913 // Skip non proxy dhcp offers.\r
914 //\r
915 continue;\r
916 }\r
917\r
918 if (OfferType == PxeOfferTypeProxyBinl) {\r
919 //\r
920 // Try all the cached ProxyBinl offer one by one to request bootfilename.\r
921 //\r
922 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) {\r
923 continue;\r
924 }\r
925 }\r
926\r
927 Private->SelectProxyType = OfferType;\r
928 ProxyIndex = Index;\r
929 Status = EFI_SUCCESS;\r
930 break;\r
931 }\r
932 }\r
933\r
934 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {\r
935 //\r
936 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.\r
937 //\r
938 PxeBcCopyDhcp6Proxy (Private, ProxyIndex);\r
939 }\r
940 } else {\r
941 //\r
942 // Othewise, the bootfilename must be included in DhcpOnly offer.\r
943 //\r
944 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
945 }\r
946 }\r
947\r
948 if (!EFI_ERROR (Status)) {\r
949 //\r
950 // All PXE boot information is ready by now.\r
951 //\r
952 PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);\r
953 Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;\r
954 }\r
955\r
956 return Status;\r
957}\r
958\r
959\r
960/**\r
961 Unregister the address by Ip6Config protocol.\r
962\r
963 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
964\r
965**/\r
966VOID\r
967PxeBcUnregisterIp6Address (\r
968 IN PXEBC_PRIVATE_DATA *Private\r
969 )\r
970{\r
971 if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) {\r
972 //\r
973 // PXE driver change the policy of IP6 driver, it's a chance to recover.\r
974 // Keep the point and there is no enough requirements to do recovery.\r
975 //\r
976 }\r
977}\r
978\r
979\r
980/**\r
981 Register the ready address by Ip6Config protocol.\r
982\r
983 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
984 @param[in] Address The pointer to the ready address.\r
985\r
986 @retval EFI_SUCCESS Registered the address succesfully.\r
987 @retval Others Failed to register the address.\r
988\r
989**/\r
990EFI_STATUS\r
991PxeBcRegisterIp6Address (\r
992 IN PXEBC_PRIVATE_DATA *Private,\r
993 IN EFI_IPv6_ADDRESS *Address\r
994 )\r
995{\r
996 EFI_IP6_PROTOCOL *Ip6;\r
997 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
998 EFI_IP6_CONFIG_POLICY Policy;\r
999 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;\r
1000 UINTN DataSize;\r
1001 EFI_EVENT TimeOutEvt;\r
1002 EFI_EVENT MappedEvt;\r
1003 EFI_STATUS Status;\r
1004\r
1005 Status = EFI_SUCCESS;\r
1006 TimeOutEvt = NULL;\r
1007 MappedEvt = NULL;\r
1008 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
1009 Ip6Cfg = Private->Ip6Cfg;\r
1010 Ip6 = Private->Ip6;\r
1011\r
1012 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));\r
1013 CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));\r
1014\r
1015 //\r
1016 // Get and store the current policy of IP6 driver.\r
1017 //\r
1018 Status = Ip6Cfg->GetData (\r
1019 Ip6Cfg,\r
1020 Ip6ConfigDataTypePolicy,\r
1021 &DataSize,\r
1022 &Private->Ip6Policy\r
1023 );\r
1024 if (EFI_ERROR (Status)) {\r
1025 goto ON_EXIT;\r
1026 }\r
1027\r
1028 //\r
1029 // There is no channel between IP6 and PXE driver about address setting,\r
1030 // so it has to set the new address by Ip6ConfigProtocol manually.\r
1031 //\r
1032 Policy = Ip6ConfigPolicyManual;\r
1033 Status = Ip6Cfg->SetData (\r
1034 Ip6Cfg,\r
1035 Ip6ConfigDataTypePolicy,\r
1036 sizeof(EFI_IP6_CONFIG_POLICY),\r
1037 &Policy\r
1038 );\r
1039 if (EFI_ERROR (Status)) {\r
1040 //\r
1041 // There is no need to recover later.\r
1042 //\r
1043 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;\r
1044 goto ON_EXIT;\r
1045 }\r
1046\r
1047 //\r
1048 // Create a timer as setting address timeout event since DAD in IP6 driver.\r
1049 //\r
1050 Status = gBS->CreateEvent (\r
1051 EVT_TIMER,\r
1052 TPL_CALLBACK,\r
1053 NULL,\r
1054 NULL,\r
1055 &TimeOutEvt\r
1056 );\r
1057 if (EFI_ERROR (Status)) {\r
1058 goto ON_EXIT;\r
1059 }\r
1060\r
1061 //\r
1062 // Create a notify event to set address flag when DAD if IP6 driver succeeded.\r
1063 //\r
1064 Status = gBS->CreateEvent (\r
1065 EVT_NOTIFY_SIGNAL,\r
1066 TPL_NOTIFY,\r
1067 PxeBcCommonNotify,\r
1068 &Private->IsAddressOk,\r
1069 &MappedEvt\r
1070 );\r
1071 if (EFI_ERROR (Status)) {\r
1072 goto ON_EXIT;\r
1073 }\r
1074\r
1075 Status = Ip6Cfg->RegisterDataNotify (\r
1076 Ip6Cfg,\r
1077 Ip6ConfigDataTypeManualAddress,\r
1078 MappedEvt\r
1079 );\r
1080 if (EFI_ERROR(Status)) {\r
1081 goto ON_EXIT;\r
1082 }\r
1083\r
1084 Status = Ip6Cfg->SetData (\r
1085 Ip6Cfg,\r
1086 Ip6ConfigDataTypeManualAddress,\r
1087 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS),\r
1088 &CfgAddr\r
1089 );\r
1090 if (EFI_ERROR(Status) && Status != EFI_NOT_READY) {\r
1091 goto ON_EXIT;\r
1092 }\r
1093\r
1094 //\r
1095 // Start the 5 secondes timer to wait for setting address.\r
1096 //\r
1097 Status = EFI_NO_MAPPING;\r
1098 gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT);\r
1099\r
1100 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
1101 Ip6->Poll (Ip6);\r
1102 if (Private->IsAddressOk) {\r
1103 Status = EFI_SUCCESS;\r
1104 break;\r
1105 }\r
1106 }\r
1107\r
1108ON_EXIT:\r
1109 if (MappedEvt != NULL) {\r
1110 Ip6Cfg->UnregisterDataNotify (\r
1111 Ip6Cfg,\r
1112 Ip6ConfigDataTypeManualAddress,\r
1113 MappedEvt\r
1114 );\r
1115 gBS->CloseEvent (MappedEvt);\r
1116 }\r
1117 if (TimeOutEvt != NULL) {\r
1118 gBS->CloseEvent (TimeOutEvt);\r
1119 }\r
1120 return Status;\r
1121}\r
1122\r
1123\r
1124/**\r
1125 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver\r
1126 to intercept events that occurred in the configuration process.\r
1127\r
1128 @param[in] This The pointer to the EFI DHCPv6 Protocol.\r
1129 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().\r
1130 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.\r
1131 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a\r
1132 state transition.\r
1133 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.\r
1134 @param[out] NewPacket The packet that is used to replace the Packet above.\r
1135\r
1136 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.\r
1137 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol\r
1138 driver will continue to wait for more packets.\r
1139 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.\r
1140\r
1141**/\r
1142EFI_STATUS\r
1143EFIAPI\r
1144PxeBcDhcp6CallBack (\r
1145 IN EFI_DHCP6_PROTOCOL *This,\r
1146 IN VOID *Context,\r
1147 IN EFI_DHCP6_STATE CurrentState,\r
1148 IN EFI_DHCP6_EVENT Dhcp6Event,\r
1149 IN EFI_DHCP6_PACKET *Packet,\r
1150 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL\r
1151 )\r
1152{\r
1153 PXEBC_PRIVATE_DATA *Private;\r
1154 EFI_PXE_BASE_CODE_MODE *Mode;\r
1155 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
1156 EFI_DHCP6_PACKET *SelectAd;\r
1157 EFI_STATUS Status;\r
1158 BOOLEAN Received;\r
1159\r
1160 if ((Dhcp6Event != Dhcp6RcvdAdvertise) &&\r
1161 (Dhcp6Event != Dhcp6SelectAdvertise) &&\r
1162 (Dhcp6Event != Dhcp6SendSolicit) &&\r
1163 (Dhcp6Event != Dhcp6SendRequest) &&\r
1164 (Dhcp6Event != Dhcp6RcvdReply)) {\r
1165 return EFI_SUCCESS;\r
1166 }\r
1167\r
1168 ASSERT (Packet != NULL);\r
1169\r
1170 Private = (PXEBC_PRIVATE_DATA *) Context;\r
1171 Mode = Private->PxeBc.Mode;\r
1172 Callback = Private->PxeBcCallback;\r
1173\r
1174 //\r
1175 // Callback to user when any traffic ocurred if has.\r
1176 //\r
1177 if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) {\r
1178 Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);\r
1179 Status = Callback->Callback (\r
1180 Callback,\r
1181 Private->Function,\r
1182 Received,\r
1183 Packet->Length,\r
1184 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6\r
1185 );\r
1186 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
1187 return EFI_ABORTED;\r
1188 }\r
1189 }\r
1190\r
1191 Status = EFI_SUCCESS;\r
1192\r
1193 switch (Dhcp6Event) {\r
1194\r
1195 case Dhcp6SendSolicit:\r
1196 //\r
1197 // Cache the dhcp discover packet to mode data directly.\r
1198 //\r
1199 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length);\r
1200 break;\r
1201\r
1202 case Dhcp6RcvdAdvertise:\r
1203 Status = EFI_NOT_READY;\r
1204 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {\r
1205 //\r
1206 // Cache the dhcp offers to OfferBuffer[] for select later, and record\r
1207 // the OfferIndex and OfferCount.\r
1208 //\r
1209 PxeBcCacheDhcp6Offer (Private, Packet);\r
1210 }\r
1211 break;\r
1212\r
1213 case Dhcp6SendRequest:\r
1214 //\r
1215 // Store the request packet as seed packet for discover.\r
1216 //\r
1217 if (Private->Dhcp6Request != NULL) {\r
1218 FreePool (Private->Dhcp6Request);\r
1219 }\r
1220 Private->Dhcp6Request = AllocateZeroPool (Packet->Size);\r
1221 if (Private->Dhcp6Request != NULL) {\r
1222 CopyMem (Private->Dhcp6Request, Packet, Packet->Size);\r
1223 }\r
1224 break;\r
1225\r
1226 case Dhcp6SelectAdvertise:\r
1227 //\r
1228 // Select offer by the default policy or by order, and record the SelectIndex\r
1229 // and SelectProxyType.\r
1230 //\r
1231 PxeBcSelectDhcp6Offer (Private);\r
1232\r
1233 if (Private->SelectIndex == 0) {\r
1234 Status = EFI_ABORTED;\r
1235 } else {\r
1236 ASSERT (NewPacket != NULL);\r
1237 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;\r
1238 *NewPacket = AllocateZeroPool (SelectAd->Size);\r
1239 ASSERT (*NewPacket != NULL);\r
1240 CopyMem (*NewPacket, SelectAd, SelectAd->Size);\r
1241 }\r
1242 break;\r
1243\r
1244 case Dhcp6RcvdReply:\r
1245 //\r
1246 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data\r
1247 // without verification.\r
1248 //\r
1249 ASSERT (Private->SelectIndex != 0);\r
1250 PxeBcCopyDhcp6Ack (Private, Packet, FALSE);\r
1251 break;\r
1252\r
1253 default:\r
1254 ASSERT (0);\r
1255 }\r
1256\r
1257 return Status;\r
1258}\r
1259\r
1260\r
1261/**\r
1262 Build and send out the request packet for the bootfile, and parse the reply.\r
1263\r
1264 @param[in] Private The pointer to PxeBc private data.\r
1265 @param[in] Type PxeBc option boot item type.\r
1266 @param[in] Layer The pointer to option boot item layer.\r
1267 @param[in] UseBis Use BIS or not.\r
1268 @param[in] DestIp The pointer to the server address.\r
1269\r
1270 @retval EFI_SUCCESS Successfully discovered the boot file.\r
1271 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
1272 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
1273 @retval Others Failed to discover the boot file.\r
1274\r
1275**/\r
1276EFI_STATUS\r
1277PxeBcDhcp6Discover (\r
1278 IN PXEBC_PRIVATE_DATA *Private,\r
1279 IN UINT16 Type,\r
1280 IN UINT16 *Layer,\r
1281 IN BOOLEAN UseBis,\r
1282 IN EFI_IP_ADDRESS *DestIp\r
1283 )\r
1284{\r
1285 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;\r
1286 EFI_PXE_BASE_CODE_UDP_PORT DestPort;\r
1287 EFI_PXE_BASE_CODE_MODE *Mode;\r
1288 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
1289 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;\r
1290 UINTN DiscoverLen;\r
1291 EFI_DHCP6_PACKET *Request;\r
1292 UINTN RequestLen;\r
1293 EFI_DHCP6_PACKET *Reply;\r
1294 UINT8 *RequestOpt;\r
1295 UINT8 *DiscoverOpt;\r
1296 UINTN ReadSize;\r
1297 UINT16 OpFlags;\r
1298 UINT16 OpCode;\r
1299 UINT16 OpLen;\r
1300 UINT32 Xid;\r
1301 EFI_STATUS Status;\r
1302\r
1303 PxeBc = &Private->PxeBc;\r
1304 Mode = PxeBc->Mode;\r
1305 Request = Private->Dhcp6Request;\r
1306 SrcPort = PXEBC_BS_DISCOVER_PORT;\r
1307 DestPort = PXEBC_BS_DISCOVER_PORT;\r
1308 OpFlags = 0;\r
1309\r
1310 if (!UseBis && Layer != NULL) {\r
1311 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1312 }\r
1313\r
1314 if (Request == NULL) {\r
1315 return EFI_DEVICE_ERROR;\r
1316 }\r
1317\r
1318 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
1319 if (Discover == NULL) {\r
1320 return EFI_OUT_OF_RESOURCES;\r
1321 }\r
1322\r
1323 //\r
1324 // Build the discover packet by the cached request packet before.\r
1325 //\r
1326 Xid = NET_RANDOM (NetRandomInitSeed ());\r
1327 Discover->TransactionId = HTONL (Xid);\r
1328 Discover->MessageType = Request->Dhcp6.Header.MessageType;\r
1329 RequestOpt = Request->Dhcp6.Option;\r
1330 DiscoverOpt = Discover->DhcpOptions;\r
1331 DiscoverLen = sizeof (EFI_DHCP6_HEADER);\r
1332 RequestLen = DiscoverLen;\r
1333\r
1334 while (RequestLen < Request->Length) {\r
1335 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);\r
1336 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);\r
1337 if (OpCode != EFI_DHCP6_IA_TYPE_NA &&\r
1338 OpCode != EFI_DHCP6_IA_TYPE_TA) {\r
1339 //\r
1340 // Copy all the options except IA option.\r
1341 //\r
1342 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
1343 DiscoverOpt += (OpLen + 4);\r
1344 DiscoverLen += (OpLen + 4);\r
1345 }\r
1346 RequestOpt += (OpLen + 4);\r
1347 RequestLen += (OpLen + 4);\r
1348 }\r
1349\r
1350 Status = PxeBc->UdpWrite (\r
1351 PxeBc,\r
1352 OpFlags,\r
1353 &Private->ServerIp,\r
1354 &DestPort,\r
1355 NULL,\r
1356 &Private->StationIp,\r
1357 &SrcPort,\r
1358 NULL,\r
1359 NULL,\r
1360 &DiscoverLen,\r
1361 (VOID *) Discover\r
1362 );\r
1363 if (EFI_ERROR (Status)) {\r
1364 return Status;\r
1365 }\r
1366\r
1367 //\r
1368 // Cache the right PXE reply packet here, set valid flag later.\r
1369 // Especially for PXE discover packet, store it into mode data here.\r
1370 //\r
1371 if (Private->IsDoDiscover) {\r
1372 CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen);\r
1373 Reply = &Private->PxeReply.Dhcp6.Packet.Ack;\r
1374 } else {\r
1375 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;\r
1376 }\r
1377 ReadSize = (UINTN) Reply->Size;\r
1378\r
1379 Status = PxeBc->UdpRead (\r
1380 PxeBc,\r
1381 OpFlags,\r
1382 &Private->StationIp,\r
1383 &SrcPort,\r
1384 &Private->ServerIp,\r
1385 &DestPort,\r
1386 NULL,\r
1387 NULL,\r
1388 &ReadSize,\r
1389 (VOID *) &Reply->Dhcp6\r
1390 );\r
1391 if (EFI_ERROR (Status)) {\r
1392 return Status;\r
1393 }\r
1394\r
1395 return EFI_SUCCESS;\r
1396}\r
1397\r
1398\r
1399/**\r
1400 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.\r
1401\r
1402 @param[in] Private The pointer to PxeBc private data.\r
1403 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL\r
1404\r
1405 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.\r
1406 @retval Others Failed to finish the S.A.R.R. process.\r
1407\r
1408**/\r
1409EFI_STATUS\r
1410PxeBcDhcp6Sarr (\r
1411 IN PXEBC_PRIVATE_DATA *Private,\r
1412 IN EFI_DHCP6_PROTOCOL *Dhcp6\r
1413 )\r
1414{\r
1415 EFI_PXE_BASE_CODE_MODE *PxeMode;\r
1416 EFI_DHCP6_CONFIG_DATA Config;\r
1417 EFI_DHCP6_MODE_DATA Mode;\r
1418 EFI_DHCP6_RETRANSMISSION *Retransmit;\r
1419 EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM];\r
1420 UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];\r
1421 UINT32 OptCount;\r
1422 EFI_STATUS Status;\r
1423\r
1424 Status = EFI_SUCCESS;\r
1425 PxeMode = Private->PxeBc.Mode;\r
1426\r
1427 //\r
1428 // Build option list for the request packet.\r
1429 //\r
1430 OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer);\r
1431 ASSERT (OptCount> 0);\r
1432\r
1433 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));\r
1434 if (Retransmit == NULL) {\r
1435 return EFI_OUT_OF_RESOURCES;\r
1436 }\r
1437\r
1438 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));\r
1439 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));\r
1440\r
1441 Config.OptionCount = OptCount;\r
1442 Config.OptionList = OptList;\r
1443 Config.Dhcp6Callback = PxeBcDhcp6CallBack;\r
1444 Config.CallbackContext = Private;\r
1445 Config.IaInfoEvent = NULL;\r
1446 Config.RapidCommit = FALSE;\r
1447 Config.ReconfigureAccept = FALSE;\r
1448 Config.IaDescriptor.IaId = 1;\r
1449 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;\r
1450 Config.SolicitRetransmission = Retransmit;\r
1451 Retransmit->Irt = 4;\r
1452 Retransmit->Mrc = 4;\r
1453 Retransmit->Mrt = 32;\r
1454 Retransmit->Mrd = 60;\r
1455\r
1456 //\r
1457 // Configure the DHCPv6 instance for PXE boot.\r
1458 //\r
1459 Status = Dhcp6->Configure (Dhcp6, &Config);\r
1460 if (EFI_ERROR (Status)) {\r
1461 FreePool (Retransmit);\r
1462 return Status;\r
1463 }\r
1464\r
1465 //\r
1466 // Initialize the record fields for DHCPv6 offer in private data.\r
1467 //\r
1468 Private->IsProxyRecved = FALSE;\r
1469 Private->OfferNum = 0;\r
1470 Private->SelectIndex = 0;\r
1471 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
1472 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
1473\r
1474\r
1475 //\r
1476 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
1477 //\r
1478 Status = Dhcp6->Start (Dhcp6);\r
1479 if (EFI_ERROR (Status)) {\r
1480 if (Status == EFI_ICMP_ERROR) {\r
1481 PxeMode->IcmpErrorReceived = TRUE;\r
1482 }\r
1483 Dhcp6->Configure (Dhcp6, NULL);\r
1484 return Status;\r
1485 }\r
1486\r
1487 //\r
1488 // Get the acquired IPv6 address and store them.\r
1489 //\r
1490 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);\r
1491 if (EFI_ERROR (Status)) {\r
1492 Dhcp6->Stop (Dhcp6);\r
1493 return Status;\r
1494 }\r
1495\r
1496 ASSERT (Mode.Ia->State == Dhcp6Bound);\r
1497 CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
1498 CopyMem (&PxeMode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));\r
1499\r
1500 Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);\r
1501 if (EFI_ERROR (Status)) {\r
1502 Dhcp6->Stop (Dhcp6);\r
1503 return Status;\r
1504 }\r
1505\r
1506 Status = PxeBcFlushStaionIp (Private, &Private->StationIp, NULL);\r
1507 if (EFI_ERROR (Status)) {\r
1508 PxeBcUnregisterIp6Address (Private);\r
1509 Dhcp6->Stop (Dhcp6);\r
1510 return Status;\r
1511 }\r
1512\r
1513 //\r
1514 // Check the selected offer whether BINL retry is needed.\r
1515 //\r
1516 Status = PxeBcHandleDhcp6Offer (Private);\r
1517 if (EFI_ERROR (Status)) {\r
1518 PxeBcUnregisterIp6Address (Private);\r
1519 Dhcp6->Stop (Dhcp6);\r
1520 return Status;\r
1521 }\r
1522\r
1523 AsciiPrint ("\n Station IP address is ");\r
1524\r
1525 PxeBcShowIp6Addr (&Private->StationIp.v6);\r
1526\r
1527 return EFI_SUCCESS;\r
1528}\r
1529\r