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