1 /** @file
2   Functions implementation related with DHCPv4 for UefiPxeBc Driver.
3 
4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PxeBcImpl.h"
17 
18 //
19 // This is a map from the interested DHCP4 option tags' index to the tag value.
20 //
21 UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
22   PXEBC_DHCP4_TAG_BOOTFILE_LEN,
23   PXEBC_DHCP4_TAG_VENDOR,
24   PXEBC_DHCP4_TAG_OVERLOAD,
25   PXEBC_DHCP4_TAG_MSG_TYPE,
26   PXEBC_DHCP4_TAG_SERVER_ID,
27   PXEBC_DHCP4_TAG_CLASS_ID,
28   PXEBC_DHCP4_TAG_BOOTFILE
29 };
30 
31 //
32 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
33 //
34 UINT32 mPxeDhcpTimeout[4] = {4, 8, 16, 32};
35 
36 
37 /**
38   Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
39 
40   @param[in]  Buffer              Pointer to the option buffer.
41   @param[in]  Length              Length of the option buffer.
42   @param[in]  OptTag              Tag of the required option.
43 
44   @retval     NULL                Failed to find the required option.
45   @retval     Others              The position of the required option.
46 
47 **/
48 EFI_DHCP4_PACKET_OPTION *
PxeBcParseDhcp4Options(IN UINT8 * Buffer,IN UINT32 Length,IN UINT8 OptTag)49 PxeBcParseDhcp4Options (
50   IN UINT8                      *Buffer,
51   IN UINT32                     Length,
52   IN UINT8                      OptTag
53   )
54 {
55   EFI_DHCP4_PACKET_OPTION       *Option;
56   UINT32                        Offset;
57 
58   Option  = (EFI_DHCP4_PACKET_OPTION *) Buffer;
59   Offset  = 0;
60 
61   while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {
62 
63     if (Option->OpCode == OptTag) {
64       //
65       // Found the required option.
66       //
67       return Option;
68     }
69 
70     //
71     // Skip the current option to the next.
72     //
73     if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {
74       Offset++;
75     } else {
76       Offset += Option->Length + 2;
77     }
78 
79     Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);
80   }
81 
82   return NULL;
83 }
84 
85 
86 /**
87   Parse the PXE vender options and extract the information from them.
88 
89   @param[in]  Dhcp4Option        Pointer to vendor options in buffer.
90   @param[in]  VendorOption       Pointer to structure to store information in vendor options.
91 
92 **/
93 VOID
PxeBcParseVendorOptions(IN EFI_DHCP4_PACKET_OPTION * Dhcp4Option,IN PXEBC_VENDOR_OPTION * VendorOption)94 PxeBcParseVendorOptions (
95   IN EFI_DHCP4_PACKET_OPTION    *Dhcp4Option,
96   IN PXEBC_VENDOR_OPTION        *VendorOption
97   )
98 {
99   UINT32                        *BitMap;
100   UINT8                         VendorOptionLen;
101   EFI_DHCP4_PACKET_OPTION       *PxeOption;
102   UINT8                         Offset;
103 
104   BitMap          = VendorOption->BitMap;
105   VendorOptionLen = Dhcp4Option->Length;
106   PxeOption       = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];
107   Offset          = 0;
108 
109   ASSERT (PxeOption != NULL);
110 
111   while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {
112     //
113     // Parse all the interesting PXE vendor options one by one.
114     //
115     switch (PxeOption->OpCode) {
116 
117     case PXEBC_VENDOR_TAG_MTFTP_IP:
118 
119       CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
120       break;
121 
122     case PXEBC_VENDOR_TAG_MTFTP_CPORT:
123 
124       CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
125       break;
126 
127     case PXEBC_VENDOR_TAG_MTFTP_SPORT:
128 
129       CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
130       break;
131 
132     case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
133 
134       VendorOption->MtftpTimeout = *PxeOption->Data;
135       break;
136 
137     case PXEBC_VENDOR_TAG_MTFTP_DELAY:
138 
139       VendorOption->MtftpDelay = *PxeOption->Data;
140       break;
141 
142     case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
143 
144       VendorOption->DiscoverCtrl = *PxeOption->Data;
145       break;
146 
147     case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
148 
149       CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
150       break;
151 
152     case PXEBC_VENDOR_TAG_BOOT_SERVERS:
153 
154       VendorOption->BootSvrLen  = PxeOption->Length;
155       VendorOption->BootSvr     = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;
156       break;
157 
158     case PXEBC_VENDOR_TAG_BOOT_MENU:
159 
160       VendorOption->BootMenuLen = PxeOption->Length;
161       VendorOption->BootMenu    = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;
162       break;
163 
164     case PXEBC_VENDOR_TAG_MENU_PROMPT:
165 
166       VendorOption->MenuPromptLen = PxeOption->Length;
167       VendorOption->MenuPrompt    = (PXEBC_MENU_PROMPT *) PxeOption->Data;
168       break;
169 
170     case PXEBC_VENDOR_TAG_MCAST_ALLOC:
171 
172       CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
173       CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
174       CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
175       break;
176 
177     case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
178 
179       VendorOption->CredTypeLen = PxeOption->Length;
180       VendorOption->CredType    = (UINT32 *) PxeOption->Data;
181       break;
182 
183     case PXEBC_VENDOR_TAG_BOOT_ITEM:
184 
185       CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
186       CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
187       break;
188 
189     default:
190       //
191       // Not interesting PXE vendor options.
192       //
193       break;
194     }
195 
196     //
197     // Set the bit map for the special PXE options.
198     //
199     SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
200 
201     //
202     // Continue to the next option.
203     //
204     if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {
205       Offset++;
206     } else {
207       Offset = (UINT8) (Offset + PxeOption->Length + 2);
208     }
209 
210     PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);
211   }
212 }
213 
214 
215 /**
216   Build the options buffer for the DHCPv4 request packet.
217 
218   @param[in]  Private             Pointer to PxeBc private data.
219   @param[out] OptList             Pointer to the option pointer array.
220   @param[in]  Buffer              Pointer to the buffer to contain the option list.
221   @param[in]  NeedMsgType         If TRUE, it is necessary to include the Msg type option.
222                                   Otherwise, it is not necessary.
223 
224   @return     Index               The count of the built-in options.
225 
226 **/
227 UINT32
PxeBcBuildDhcp4Options(IN PXEBC_PRIVATE_DATA * Private,OUT EFI_DHCP4_PACKET_OPTION ** OptList,IN UINT8 * Buffer,IN BOOLEAN NeedMsgType)228 PxeBcBuildDhcp4Options (
229   IN  PXEBC_PRIVATE_DATA       *Private,
230   OUT EFI_DHCP4_PACKET_OPTION  **OptList,
231   IN  UINT8                    *Buffer,
232   IN  BOOLEAN                  NeedMsgType
233   )
234 {
235   UINT32                       Index;
236   PXEBC_DHCP4_OPTION_ENTRY     OptEnt;
237   UINT16                       Value;
238 
239   Index      = 0;
240   OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;
241 
242   if (NeedMsgType) {
243     //
244     // Append message type.
245     //
246     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MSG_TYPE;
247     OptList[Index]->Length  = 1;
248     OptEnt.Mesg             = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;
249     OptEnt.Mesg->Type       = PXEBC_DHCP4_MSG_TYPE_REQUEST;
250     Index++;
251     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
252 
253     //
254     // Append max message size.
255     //
256     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MAXMSG;
257     OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
258     OptEnt.MaxMesgSize      = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;
259     Value                   = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);
260     CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
261     Index++;
262     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
263   }
264 
265   //
266   // Append parameter request list option.
267   //
268   OptList[Index]->OpCode    = PXEBC_DHCP4_TAG_PARA_LIST;
269   OptList[Index]->Length    = 35;
270   OptEnt.Para               = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;
271   OptEnt.Para->ParaList[0]  = PXEBC_DHCP4_TAG_NETMASK;
272   OptEnt.Para->ParaList[1]  = PXEBC_DHCP4_TAG_TIME_OFFSET;
273   OptEnt.Para->ParaList[2]  = PXEBC_DHCP4_TAG_ROUTER;
274   OptEnt.Para->ParaList[3]  = PXEBC_DHCP4_TAG_TIME_SERVER;
275   OptEnt.Para->ParaList[4]  = PXEBC_DHCP4_TAG_NAME_SERVER;
276   OptEnt.Para->ParaList[5]  = PXEBC_DHCP4_TAG_DNS_SERVER;
277   OptEnt.Para->ParaList[6]  = PXEBC_DHCP4_TAG_HOSTNAME;
278   OptEnt.Para->ParaList[7]  = PXEBC_DHCP4_TAG_BOOTFILE_LEN;
279   OptEnt.Para->ParaList[8]  = PXEBC_DHCP4_TAG_DOMAINNAME;
280   OptEnt.Para->ParaList[9]  = PXEBC_DHCP4_TAG_ROOTPATH;
281   OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;
282   OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;
283   OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;
284   OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;
285   OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;
286   OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;
287   OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;
288   OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;
289   OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;
290   OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;
291   OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;
292   OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;
293   OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;
294   OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;
295   OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;
296   OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;
297   OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;
298   OptEnt.Para->ParaList[27] = 0x80;
299   OptEnt.Para->ParaList[28] = 0x81;
300   OptEnt.Para->ParaList[29] = 0x82;
301   OptEnt.Para->ParaList[30] = 0x83;
302   OptEnt.Para->ParaList[31] = 0x84;
303   OptEnt.Para->ParaList[32] = 0x85;
304   OptEnt.Para->ParaList[33] = 0x86;
305   OptEnt.Para->ParaList[34] = 0x87;
306   Index++;
307   OptList[Index]            = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
308 
309   //
310   // Append UUID/Guid-based client identifier option
311   //
312   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UUID;
313   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);
314   OptEnt.Uuid             = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;
315   OptEnt.Uuid->Type       = 0;
316   Index++;
317   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
318 
319   if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {
320     //
321     // Zero the Guid to indicate NOT programable if failed to get system Guid.
322     //
323     ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
324   }
325 
326   //
327   // Append client network device interface option
328   //
329   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UNDI;
330   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);
331   OptEnt.Undi             = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;
332 
333   if (Private->Nii != NULL) {
334     OptEnt.Undi->Type     = Private->Nii->Type;
335     OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
336     OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
337   } else {
338     OptEnt.Undi->Type     = DEFAULT_UNDI_TYPE;
339     OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
340     OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
341   }
342 
343   Index++;
344   OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
345 
346   //
347   // Append client system architecture option
348   //
349   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_ARCH;
350   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);
351   OptEnt.Arch             = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;
352   Value                   = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
353   CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
354   Index++;
355   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
356 
357   //
358   // Append vendor class identify option
359   //
360   OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_CLASS_ID;
361   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);
362   OptEnt.Clid             = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;
363   CopyMem (
364     OptEnt.Clid,
365     DEFAULT_CLASS_ID_DATA,
366     sizeof (PXEBC_DHCP4_OPTION_CLID)
367     );
368   PxeBcUintnToAscDecWithFormat (
369     EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
370     OptEnt.Clid->ArchitectureType,
371     sizeof (OptEnt.Clid->ArchitectureType)
372     );
373 
374   if (Private->Nii != NULL) {
375     CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
376     PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
377     PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
378   }
379 
380   Index++;
381 
382   return Index;
383 }
384 
385 
386 /**
387   Create a template DHCPv4 packet as a seed.
388 
389   @param[out] Seed           Pointer to the seed packet.
390   @param[in]  Udp4           Pointer to EFI_UDP4_PROTOCOL.
391 
392 **/
393 VOID
PxeBcSeedDhcp4Packet(OUT EFI_DHCP4_PACKET * Seed,IN EFI_UDP4_PROTOCOL * Udp4)394 PxeBcSeedDhcp4Packet (
395   OUT EFI_DHCP4_PACKET       *Seed,
396   IN  EFI_UDP4_PROTOCOL      *Udp4
397   )
398 {
399   EFI_SIMPLE_NETWORK_MODE    Mode;
400   EFI_DHCP4_HEADER           *Header;
401 
402   //
403   // Get IfType and HwAddressSize from SNP mode data.
404   //
405   Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
406 
407   Seed->Size            = sizeof (EFI_DHCP4_PACKET);
408   Seed->Length          = sizeof (Seed->Dhcp4);
409   Header                = &Seed->Dhcp4.Header;
410   ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
411   Header->OpCode        = PXEBC_DHCP4_OPCODE_REQUEST;
412   Header->HwType        = Mode.IfType;
413   Header->HwAddrLen     = (UINT8) Mode.HwAddressSize;
414   CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
415 
416   Seed->Dhcp4.Magik     = PXEBC_DHCP4_MAGIC;
417   Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP;
418 }
419 
420 
421 /**
422   Cache the DHCPv4 packet.
423 
424   @param[in]  Dst          Pointer to the cache buffer for DHCPv4 packet.
425   @param[in]  Src          Pointer to the DHCPv4 packet to be cached.
426 
427 **/
428 VOID
PxeBcCacheDhcp4Packet(IN EFI_DHCP4_PACKET * Dst,IN EFI_DHCP4_PACKET * Src)429 PxeBcCacheDhcp4Packet (
430   IN EFI_DHCP4_PACKET     *Dst,
431   IN EFI_DHCP4_PACKET     *Src
432   )
433 {
434   ASSERT (Dst->Size >= Src->Length);
435 
436   CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
437   Dst->Length = Src->Length;
438 }
439 
440 
441 /**
442   Parse the cached DHCPv4 packet, including all the options.
443 
444   @param[in]  Cache4           Pointer to cached DHCPv4 packet.
445 
446   @retval     EFI_SUCCESS      Parsed the DHCPv4 packet successfully.
447   @retval     EFI_DEVICE_ERROR Failed to parse and invalid packet.
448 
449 **/
450 EFI_STATUS
PxeBcParseDhcp4Packet(IN PXEBC_DHCP4_PACKET_CACHE * Cache4)451 PxeBcParseDhcp4Packet (
452   IN PXEBC_DHCP4_PACKET_CACHE    *Cache4
453   )
454 {
455   EFI_DHCP4_PACKET               *Offer;
456   EFI_DHCP4_PACKET_OPTION        **Options;
457   EFI_DHCP4_PACKET_OPTION        *Option;
458   PXEBC_OFFER_TYPE               OfferType;
459   UINTN                          Index;
460   BOOLEAN                        IsProxyOffer;
461   BOOLEAN                        IsPxeOffer;
462   UINT8                          *Ptr8;
463 
464   IsProxyOffer = FALSE;
465   IsPxeOffer   = FALSE;
466 
467   ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
468   ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));
469 
470   Offer   = &Cache4->Packet.Offer;
471   Options = Cache4->OptList;
472 
473   //
474   // Parse DHCPv4 options in this offer, and store the pointers.
475   // First, try to parse DHCPv4 options from the DHCP optional parameters field.
476   //
477   for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
478     Options[Index] = PxeBcParseDhcp4Options (
479                        Offer->Dhcp4.Option,
480                        GET_OPTION_BUFFER_LEN (Offer),
481                        mInterestedDhcp4Tags[Index]
482                        );
483   }
484   //
485   // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
486   // If yes, try to parse options from the BootFileName field, then ServerName field.
487   //
488   Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
489   if (Option != NULL) {
490     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
491       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
492         if (Options[Index] == NULL) {
493           Options[Index] = PxeBcParseDhcp4Options (
494                              (UINT8 *) Offer->Dhcp4.Header.BootFileName,
495                              sizeof (Offer->Dhcp4.Header.BootFileName),
496                              mInterestedDhcp4Tags[Index]
497                              );
498         }
499       }
500     }
501     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
502       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
503         if (Options[Index] == NULL) {
504           Options[Index] = PxeBcParseDhcp4Options (
505                              (UINT8 *) Offer->Dhcp4.Header.ServerName,
506                              sizeof (Offer->Dhcp4.Header.ServerName),
507                              mInterestedDhcp4Tags[Index]
508                              );
509         }
510       }
511     }
512   }
513 
514   //
515   // The offer with zero "yiaddr" is a proxy offer.
516   //
517   if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
518     IsProxyOffer = TRUE;
519   }
520 
521   //
522   // The offer with "PXEClient" is a PXE offer.
523   //
524   Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
525   if ((Option != NULL) && (Option->Length >= 9) &&
526       (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
527     IsPxeOffer = TRUE;
528   }
529 
530   //
531   // Parse PXE vendor options in this offer, and store the contents/pointers.
532   //
533   Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
534   if (IsPxeOffer && Option != NULL) {
535     PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);
536   }
537 
538   //
539   // Parse PXE boot file name:
540   // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
541   // Otherwise, read from boot file field in DHCP header.
542   //
543   if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
544     //
545     // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
546     // terminated string. So force to append null terminated character at the end of string.
547     //
548     Ptr8 =  (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
549     Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
550     if (*(Ptr8 - 1) != '\0') {
551       *Ptr8 = '\0';
552     }
553   } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {
554     //
555     // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
556     // Do not count dhcp option header here, or else will destroy the serverhostname.
557     //
558     Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
559                                                 (&Offer->Dhcp4.Header.BootFileName[0] -
560                                                 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
561 
562   }
563 
564   //
565   // Determine offer type of the DHCPv4 packet.
566   //
567   Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
568   if (Option == NULL || Option->Data[0] == 0) {
569     //
570     // It's a Bootp offer.
571     //
572     OfferType = PxeOfferTypeBootp;
573 
574     Option    = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
575     if (Option == NULL) {
576       //
577       // If the Bootp offer without bootfilename, discard it.
578       //
579       return EFI_DEVICE_ERROR;
580     }
581   } else {
582 
583     if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
584       //
585       // It's a PXE10 offer with PXEClient and discover vendor option.
586       //
587       OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
588     } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
589       //
590       // It's a WFM11a offer with PXEClient and mtftp vendor option.
591       // But multi-cast download is not supported currently, so discard it.
592       //
593       return EFI_DEVICE_ERROR;
594     } else if (IsPxeOffer) {
595       //
596       // It's a BINL offer only with PXEClient.
597       //
598       OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
599     } else {
600       //
601       // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
602       //
603       OfferType = PxeOfferTypeDhcpOnly;
604     }
605   }
606 
607   Cache4->OfferType = OfferType;
608 
609   return EFI_SUCCESS;
610 }
611 
612 
613 /**
614   Cache the DHCPv4 ack packet, and parse it on demand.
615 
616   @param[in]  Private             Pointer to PxeBc private data.
617   @param[in]  Ack                 Pointer to the DHCPv4 ack packet.
618   @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.
619 
620 **/
621 VOID
PxeBcCopyDhcp4Ack(IN PXEBC_PRIVATE_DATA * Private,IN EFI_DHCP4_PACKET * Ack,IN BOOLEAN Verified)622 PxeBcCopyDhcp4Ack (
623   IN PXEBC_PRIVATE_DATA   *Private,
624   IN EFI_DHCP4_PACKET     *Ack,
625   IN BOOLEAN              Verified
626   )
627 {
628   EFI_PXE_BASE_CODE_MODE  *Mode;
629 
630   Mode = Private->PxeBc.Mode;
631 
632   PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
633 
634   if (Verified) {
635     //
636     // Parse the ack packet and store it into mode data if needed.
637     //
638     PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
639     CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
640     Mode->DhcpAckReceived = TRUE;
641   }
642 }
643 
644 
645 /**
646   Cache the DHCPv4 proxy offer packet according to the received order.
647 
648   @param[in]  Private               Pointer to PxeBc private data.
649   @param[in]  OfferIndex            The received order of offer packets.
650 
651 **/
652 VOID
PxeBcCopyProxyOffer(IN PXEBC_PRIVATE_DATA * Private,IN UINT32 OfferIndex)653 PxeBcCopyProxyOffer (
654   IN PXEBC_PRIVATE_DATA   *Private,
655   IN UINT32               OfferIndex
656   )
657 {
658   EFI_PXE_BASE_CODE_MODE  *Mode;
659   EFI_DHCP4_PACKET        *Offer;
660 
661   ASSERT (OfferIndex < Private->OfferNum);
662   ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
663 
664   Mode  = Private->PxeBc.Mode;
665   Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
666 
667   //
668   // Cache the proxy offer packet and parse it.
669   //
670   PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
671   PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
672 
673   //
674   // Store this packet into mode data.
675   //
676   CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
677   Mode->ProxyOfferReceived = TRUE;
678 }
679 
680 
681 /**
682   Retry to request bootfile name by the BINL offer.
683 
684   @param[in]  Private              Pointer to PxeBc private data.
685   @param[in]  Index                The received order of offer packets.
686 
687   @retval     EFI_SUCCESS          Successfully retried to request bootfile name.
688   @retval     EFI_DEVICE_ERROR     Failed to retry bootfile name.
689 
690 **/
691 EFI_STATUS
PxeBcRetryBinlOffer(IN PXEBC_PRIVATE_DATA * Private,IN UINT32 Index)692 PxeBcRetryBinlOffer (
693   IN PXEBC_PRIVATE_DATA     *Private,
694   IN UINT32                 Index
695   )
696 {
697   EFI_DHCP4_PACKET          *Offer;
698   EFI_IP_ADDRESS            ServerIp;
699   EFI_STATUS                Status;
700   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
701   EFI_DHCP4_PACKET          *Reply;
702 
703   ASSERT (Index < PXEBC_OFFER_MAX_NUM);
704   ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
705           Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);
706 
707   Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
708 
709   //
710   // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
711   //
712   if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
713     CopyMem (
714       &ServerIp.Addr[0],
715       Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
716       sizeof (EFI_IPv4_ADDRESS)
717       );
718   } else {
719     CopyMem (
720       &ServerIp.Addr[0],
721       &Offer->Dhcp4.Header.ServerAddr,
722       sizeof (EFI_IPv4_ADDRESS)
723       );
724   }
725 
726   Private->IsDoDiscover = FALSE;
727   Cache4                = &Private->ProxyOffer.Dhcp4;
728   Reply                 = &Cache4->Packet.Offer;
729 
730   //
731   // Send another request packet for bootfile name.
732   //
733   Status = PxeBcDhcp4Discover (
734              Private,
735              0,
736              NULL,
737              FALSE,
738              &ServerIp,
739              0,
740              NULL
741              );
742   if (EFI_ERROR (Status)) {
743     return Status;
744   }
745 
746   //
747   // Parse the reply for the last request packet.
748   //
749   Status = PxeBcParseDhcp4Packet (Cache4);
750   if (EFI_ERROR (Status)) {
751     return Status;
752   }
753 
754   if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&
755       Cache4->OfferType != PxeOfferTypeProxyWfm11a &&
756       Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
757     //
758     // This BINL ack doesn't have discovery option set or multicast option set
759     // or bootfile name specified.
760     //
761     return EFI_DEVICE_ERROR;
762   }
763 
764   //
765   // Store the reply into mode data.
766   //
767   Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
768   CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
769 
770   return EFI_SUCCESS;
771 }
772 
773 
774 /**
775   Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
776 
777   @param[in]  Private               Pointer to PxeBc private data.
778   @param[in]  RcvdOffer             Pointer to the received offer packet.
779 
780 **/
781 VOID
PxeBcCacheDhcp4Offer(IN PXEBC_PRIVATE_DATA * Private,IN EFI_DHCP4_PACKET * RcvdOffer)782 PxeBcCacheDhcp4Offer (
783   IN PXEBC_PRIVATE_DATA     *Private,
784   IN EFI_DHCP4_PACKET       *RcvdOffer
785   )
786 {
787   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
788   EFI_DHCP4_PACKET          *Offer;
789   PXEBC_OFFER_TYPE          OfferType;
790 
791   ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
792   Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
793   Offer  = &Cache4->Packet.Offer;
794 
795   //
796   // Cache the content of DHCPv4 packet firstly.
797   //
798   PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
799 
800   //
801   // Validate the DHCPv4 packet, and parse the options and offer type.
802   //
803   if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
804     return;
805   }
806 
807   //
808   // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
809   //
810   OfferType = Cache4->OfferType;
811   ASSERT (OfferType < PxeOfferTypeMax);
812 
813   if (OfferType == PxeOfferTypeBootp) {
814     //
815     // It's a Bootp offer, only cache the first one, and discard the others.
816     //
817     if (Private->OfferCount[OfferType] == 0) {
818       Private->OfferIndex[OfferType][0] = Private->OfferNum;
819       Private->OfferCount[OfferType]    = 1;
820     } else {
821       return;
822     }
823   } else {
824     ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
825     if (IS_PROXY_DHCP_OFFER (Offer)) {
826       //
827       // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
828       //
829       Private->IsProxyRecved = TRUE;
830 
831       if (OfferType == PxeOfferTypeProxyBinl) {
832         //
833         // Cache all proxy BINL offers.
834         //
835         Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
836         Private->OfferCount[OfferType]++;
837       } else if (Private->OfferCount[OfferType] > 0) {
838         //
839         // Only cache the first PXE10/WFM11a offer, and discard the others.
840         //
841         Private->OfferIndex[OfferType][0] = Private->OfferNum;
842         Private->OfferCount[OfferType]    = 1;
843       } else {
844         return ;
845       }
846     } else {
847       //
848       // It's a DHCPv4 offer with yiaddr, and cache them all.
849       //
850       Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
851       Private->OfferCount[OfferType]++;
852     }
853   }
854 
855   Private->OfferNum++;
856 }
857 
858 
859 /**
860   Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
861 
862   @param[in]  Private             Pointer to PxeBc private data.
863 
864 **/
865 VOID
PxeBcSelectDhcp4Offer(IN PXEBC_PRIVATE_DATA * Private)866 PxeBcSelectDhcp4Offer (
867   IN PXEBC_PRIVATE_DATA       *Private
868   )
869 {
870   UINT32                      Index;
871   UINT32                      OfferIndex;
872   EFI_DHCP4_PACKET            *Offer;
873 
874   Private->SelectIndex = 0;
875 
876   if (Private->IsOfferSorted) {
877     //
878     // Select offer by default policy.
879     //
880     if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
881       //
882       // 1. DhcpPxe10 offer
883       //
884       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
885 
886     } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
887       //
888       // 2. DhcpWfm11a offer
889       //
890       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
891 
892     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
893                Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
894       //
895       // 3. DhcpOnly offer and ProxyPxe10 offer.
896       //
897       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
898       Private->SelectProxyType = PxeOfferTypeProxyPxe10;
899 
900     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
901                Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
902       //
903       // 4. DhcpOnly offer and ProxyWfm11a offer.
904       //
905       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
906       Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
907 
908     } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
909       //
910       // 5. DhcpBinl offer.
911       //
912       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
913 
914     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
915                Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
916       //
917       // 6. DhcpOnly offer and ProxyBinl offer.
918       //
919       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
920       Private->SelectProxyType = PxeOfferTypeProxyBinl;
921 
922     } else {
923       //
924       // 7. DhcpOnly offer with bootfilename.
925       //
926       for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
927         OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
928         if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
929           Private->SelectIndex = OfferIndex + 1;
930           break;
931         }
932       }
933       //
934       // 8. Bootp offer with bootfilename.
935       //
936       OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
937       if (Private->SelectIndex == 0 &&
938           Private->OfferCount[PxeOfferTypeBootp] > 0 &&
939           Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
940         Private->SelectIndex = OfferIndex + 1;
941       }
942     }
943   } else {
944     //
945     // Select offer by received order.
946     //
947     for (Index = 0; Index < Private->OfferNum; Index++) {
948 
949       Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
950 
951       if (IS_PROXY_DHCP_OFFER (Offer)) {
952         //
953         // Skip proxy offers
954         //
955         continue;
956       }
957 
958       if (!Private->IsProxyRecved &&
959           Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&
960           Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
961         //
962         // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
963         //
964         continue;
965       }
966 
967       //
968       // Record the index of the select offer.
969       //
970       Private->SelectIndex = Index + 1;
971       break;
972     }
973   }
974 }
975 
976 
977 /**
978   Handle the DHCPv4 offer packet.
979 
980   @param[in]  Private             Pointer to PxeBc private data.
981 
982   @retval     EFI_SUCCESS         Handled the DHCPv4 offer packet successfully.
983   @retval     EFI_NO_RESPONSE     No response to the following request packet.
984   @retval     EFI_NOT_FOUND       No boot filename received.
985 
986 **/
987 EFI_STATUS
PxeBcHandleDhcp4Offer(IN PXEBC_PRIVATE_DATA * Private)988 PxeBcHandleDhcp4Offer (
989   IN PXEBC_PRIVATE_DATA     *Private
990   )
991 {
992   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
993   EFI_DHCP4_PACKET_OPTION   **Options;
994   UINT32                    Index;
995   EFI_DHCP4_PACKET          *Offer;
996   PXEBC_OFFER_TYPE          OfferType;
997   UINT32                    ProxyIndex;
998   UINT32                    SelectIndex;
999   EFI_STATUS                Status;
1000   EFI_PXE_BASE_CODE_MODE    *Mode;
1001   EFI_DHCP4_PACKET          *Ack;
1002 
1003   ASSERT (Private->SelectIndex > 0);
1004   SelectIndex = (UINT32) (Private->SelectIndex - 1);
1005   ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
1006   Cache4      = &Private->OfferBuffer[SelectIndex].Dhcp4;
1007   Options     = Cache4->OptList;
1008   Status      = EFI_SUCCESS;
1009 
1010   if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
1011     //
1012     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1013     //
1014     if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
1015       Status = EFI_NO_RESPONSE;
1016     }
1017   } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
1018 
1019     if (Private->IsProxyRecved) {
1020       //
1021       // DhcpOnly offer is selected, so need try to request bootfile name.
1022       //
1023       ProxyIndex = 0;
1024       if (Private->IsOfferSorted) {
1025         //
1026         // The proxy offer should be determined if select by default policy.
1027         // IsOfferSorted means all offers are labeled by OfferIndex.
1028         //
1029         ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
1030         ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
1031 
1032         if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
1033           //
1034           // Try all the cached ProxyBinl offer one by one to request bootfile name.
1035           //
1036           for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
1037             ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1038             ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
1039             if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
1040               break;
1041             }
1042           }
1043           if (Index == Private->OfferCount[Private->SelectProxyType]) {
1044             Status = EFI_NO_RESPONSE;
1045           }
1046         } else {
1047           //
1048           // For other proxy offers, only one is buffered.
1049           //
1050           ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
1051         }
1052       } else {
1053         //
1054         // The proxy offer should not be determined if select by received order.
1055         //
1056         Status = EFI_NO_RESPONSE;
1057 
1058         for (Index = 0; Index < Private->OfferNum; Index++) {
1059           ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1060           Offer     = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
1061           OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
1062           if (!IS_PROXY_DHCP_OFFER (Offer)) {
1063             //
1064             // Skip non proxy DHCPv4 offers.
1065             //
1066             continue;
1067           }
1068 
1069           if (OfferType == PxeOfferTypeProxyBinl) {
1070             //
1071             // Try all the cached ProxyBinl offer one by one to request bootfile name.
1072             //
1073             if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
1074               continue;
1075             }
1076           }
1077 
1078           Private->SelectProxyType = OfferType;
1079           ProxyIndex               = Index;
1080           Status                   = EFI_SUCCESS;
1081           break;
1082         }
1083       }
1084 
1085       if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
1086         //
1087         // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1088         //
1089         PxeBcCopyProxyOffer (Private, ProxyIndex);
1090       }
1091     } else {
1092       //
1093       //  Othewise, the bootfile name must be included in DhcpOnly offer.
1094       //
1095       if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
1096         Status = EFI_NOT_FOUND;
1097       }
1098     }
1099   }
1100 
1101   if (!EFI_ERROR (Status)) {
1102     //
1103     // All PXE boot information is ready by now.
1104     //
1105     Mode  = Private->PxeBc.Mode;
1106     Offer = &Cache4->Packet.Offer;
1107     Ack   = &Private->DhcpAck.Dhcp4.Packet.Ack;
1108     if (Cache4->OfferType == PxeOfferTypeBootp) {
1109       //
1110       // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1111       // should be taken as ack.
1112       //
1113       Ack = Offer;
1114     }
1115 
1116     PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
1117     Mode->DhcpDiscoverValid = TRUE;
1118   }
1119 
1120   return Status;
1121 }
1122 
1123 
1124 /**
1125   EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1126   to intercept events that occurred in the configuration process.
1127 
1128   @param[in]  This              Pointer to the EFI DHCPv4 Protocol.
1129   @param[in]  Context           Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1130   @param[in]  CurrentState      The current operational state of the EFI DHCPv4 Protocol driver.
1131   @param[in]  Dhcp4Event        The event that occurs in the current state, which usually means a
1132                                 state transition.
1133   @param[in]  Packet            The DHCPv4 packet that is going to be sent or already received.
1134   @param[out] NewPacket         The packet that is used to replace the above Packet.
1135 
1136   @retval EFI_SUCCESS           Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1137   @retval EFI_NOT_READY         Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1138                                 driver will continue to wait for more DHCPOFFER packets until the
1139                                 retry timeout expires.
1140   @retval EFI_ABORTED           Tells the EFI DHCPv4 Protocol driver to abort the current process
1141                                 and return to the Dhcp4Init or Dhcp4InitReboot state.
1142 
1143 **/
1144 EFI_STATUS
1145 EFIAPI
PxeBcDhcp4CallBack(IN EFI_DHCP4_PROTOCOL * This,IN VOID * Context,IN EFI_DHCP4_STATE CurrentState,IN EFI_DHCP4_EVENT Dhcp4Event,IN EFI_DHCP4_PACKET * Packet OPTIONAL,OUT EFI_DHCP4_PACKET ** NewPacket OPTIONAL)1146 PxeBcDhcp4CallBack (
1147   IN  EFI_DHCP4_PROTOCOL               *This,
1148   IN  VOID                             *Context,
1149   IN  EFI_DHCP4_STATE                  CurrentState,
1150   IN  EFI_DHCP4_EVENT                  Dhcp4Event,
1151   IN  EFI_DHCP4_PACKET                 *Packet            OPTIONAL,
1152   OUT EFI_DHCP4_PACKET                 **NewPacket        OPTIONAL
1153   )
1154 {
1155   PXEBC_PRIVATE_DATA                   *Private;
1156   EFI_PXE_BASE_CODE_MODE               *Mode;
1157   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  *Callback;
1158   EFI_DHCP4_PACKET_OPTION              *MaxMsgSize;
1159   UINT16                               Value;
1160   EFI_STATUS                           Status;
1161   BOOLEAN                              Received;
1162 
1163   if ((Dhcp4Event != Dhcp4RcvdOffer) &&
1164       (Dhcp4Event != Dhcp4SelectOffer) &&
1165       (Dhcp4Event != Dhcp4SendDiscover) &&
1166       (Dhcp4Event != Dhcp4RcvdAck)) {
1167     return EFI_SUCCESS;
1168   }
1169 
1170   Private   = (PXEBC_PRIVATE_DATA *) Context;
1171   Mode      = Private->PxeBc.Mode;
1172   Callback  = Private->PxeBcCallback;
1173 
1174   //
1175   // Override the Maximum DHCP Message Size.
1176   //
1177   MaxMsgSize = PxeBcParseDhcp4Options (
1178                  Packet->Dhcp4.Option,
1179                  GET_OPTION_BUFFER_LEN (Packet),
1180                  PXEBC_DHCP4_TAG_MAXMSG
1181                  );
1182   if (MaxMsgSize != NULL) {
1183     Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);
1184     CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
1185   }
1186 
1187   //
1188   // Callback to user if any packets sent or received.
1189   //
1190   if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {
1191     Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
1192     Status = Callback->Callback (
1193                          Callback,
1194                          Private->Function,
1195                          Received,
1196                          Packet->Length,
1197                          (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4
1198                          );
1199     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1200       return EFI_ABORTED;
1201     }
1202   }
1203 
1204   Status = EFI_SUCCESS;
1205 
1206   switch (Dhcp4Event) {
1207 
1208   case Dhcp4SendDiscover:
1209     //
1210     // Cache the DHCPv4 discover packet to mode data directly.
1211     // It need to check SendGuid as well as Dhcp4SendRequest.
1212     //
1213     CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
1214 
1215   case Dhcp4SendRequest:
1216     if (Mode->SendGUID) {
1217       //
1218       // Send the system Guid instead of the MAC address as the hardware address if required.
1219       //
1220       if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {
1221         //
1222         // Zero the Guid to indicate NOT programable if failed to get system Guid.
1223         //
1224         ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1225       }
1226       Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);
1227     }
1228     break;
1229 
1230   case Dhcp4RcvdOffer:
1231     Status = EFI_NOT_READY;
1232     if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1233       //
1234       // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1235       // the OfferIndex and OfferCount.
1236       //
1237       PxeBcCacheDhcp4Offer (Private, Packet);
1238     }
1239     break;
1240 
1241   case Dhcp4SelectOffer:
1242     //
1243     // Select offer by the default policy or by order, and record the SelectIndex
1244     // and SelectProxyType.
1245     //
1246     PxeBcSelectDhcp4Offer (Private);
1247 
1248     if (Private->SelectIndex == 0) {
1249       Status = EFI_ABORTED;
1250     } else {
1251       *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
1252     }
1253     break;
1254 
1255   case Dhcp4RcvdAck:
1256     //
1257     // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1258     // without verification.
1259     //
1260     ASSERT (Private->SelectIndex != 0);
1261 
1262     PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
1263     break;
1264 
1265   default:
1266     break;
1267   }
1268 
1269   return Status;
1270 }
1271 
1272 
1273 /**
1274   Build and send out the request packet for the bootfile, and parse the reply.
1275 
1276   @param[in]  Private               Pointer to PxeBc private data.
1277   @param[in]  Type                  PxeBc option boot item type.
1278   @param[in]  Layer                 Pointer to option boot item layer.
1279   @param[in]  UseBis                Use BIS or not.
1280   @param[in]  DestIp                Pointer to the server address.
1281   @param[in]  IpCount               The total count of the server address.
1282   @param[in]  SrvList               Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1283 
1284   @retval     EFI_SUCCESS           Successfully discovered boot file.
1285   @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resource.
1286   @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.
1287   @retval     Others                Failed to discover boot file.
1288 
1289 **/
1290 EFI_STATUS
PxeBcDhcp4Discover(IN PXEBC_PRIVATE_DATA * Private,IN UINT16 Type,IN UINT16 * Layer,IN BOOLEAN UseBis,IN EFI_IP_ADDRESS * DestIp,IN UINT16 IpCount,IN EFI_PXE_BASE_CODE_SRVLIST * SrvList)1291 PxeBcDhcp4Discover (
1292   IN  PXEBC_PRIVATE_DATA              *Private,
1293   IN  UINT16                          Type,
1294   IN  UINT16                          *Layer,
1295   IN  BOOLEAN                         UseBis,
1296   IN  EFI_IP_ADDRESS                  *DestIp,
1297   IN  UINT16                          IpCount,
1298   IN  EFI_PXE_BASE_CODE_SRVLIST       *SrvList
1299   )
1300 {
1301   EFI_PXE_BASE_CODE_UDP_PORT          Sport;
1302   EFI_PXE_BASE_CODE_MODE              *Mode;
1303   EFI_DHCP4_PROTOCOL                  *Dhcp4;
1304   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
1305   BOOLEAN                             IsBCast;
1306   EFI_STATUS                          Status;
1307   UINT16                              RepIndex;
1308   UINT16                              SrvIndex;
1309   UINT16                              TryIndex;
1310   EFI_DHCP4_LISTEN_POINT              ListenPoint;
1311   EFI_DHCP4_PACKET                    *Response;
1312   UINT8                               Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1313   EFI_DHCP4_PACKET_OPTION             *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1314   UINT32                              OptCount;
1315   EFI_DHCP4_PACKET_OPTION             *PxeOpt;
1316   PXEBC_OPTION_BOOT_ITEM              *PxeBootItem;
1317   UINT8                               VendorOptLen;
1318   UINT32                              Xid;
1319 
1320   Mode      = Private->PxeBc.Mode;
1321   Dhcp4     = Private->Dhcp4;
1322   Status    = EFI_SUCCESS;
1323 
1324   ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
1325 
1326   //
1327   // Use broadcast if destination address not specified.
1328   //
1329   if (DestIp == NULL) {
1330     Sport   = PXEBC_DHCP4_S_PORT;
1331     IsBCast = TRUE;
1332   } else {
1333     Sport   = PXEBC_BS_DISCOVER_PORT;
1334     IsBCast = FALSE;
1335   }
1336 
1337   if (!UseBis && Layer != NULL) {
1338     *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1339   }
1340 
1341   //
1342   // Build all the options for the request packet.
1343   //
1344   OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
1345 
1346   if (Private->IsDoDiscover) {
1347     //
1348     // Add vendor option of PXE_BOOT_ITEM
1349     //
1350     VendorOptLen      = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
1351     OptList[OptCount] = AllocateZeroPool (VendorOptLen);
1352     if (OptList[OptCount] == NULL) {
1353       return EFI_OUT_OF_RESOURCES;
1354     }
1355 
1356     OptList[OptCount]->OpCode     = PXEBC_DHCP4_TAG_VENDOR;
1357     OptList[OptCount]->Length     = (UINT8) (VendorOptLen - 2);
1358     PxeOpt                        = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;
1359     PxeOpt->OpCode                = PXEBC_VENDOR_TAG_BOOT_ITEM;
1360     PxeOpt->Length                = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);
1361     PxeBootItem                   = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;
1362     PxeBootItem->Type             = HTONS (Type);
1363     PxeOpt->Data[PxeOpt->Length]  = PXEBC_DHCP4_TAG_EOP;
1364 
1365     if (Layer != NULL) {
1366       PxeBootItem->Layer          = HTONS (*Layer);
1367     }
1368 
1369     OptCount++;
1370   }
1371 
1372   //
1373   // Build the request packet with seed packet and option list.
1374   //
1375   Status = Dhcp4->Build (
1376                     Dhcp4,
1377                     &Private->SeedPacket,
1378                     0,
1379                     NULL,
1380                     OptCount,
1381                     OptList,
1382                     &Token.Packet
1383                     );
1384   //
1385   // Free the vendor option of PXE_BOOT_ITEM.
1386   //
1387   if (Private->IsDoDiscover) {
1388     FreePool (OptList[OptCount - 1]);
1389   }
1390 
1391   if (EFI_ERROR (Status)) {
1392     return Status;
1393   }
1394 
1395   if (Mode->SendGUID) {
1396     if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {
1397       //
1398       // Zero the Guid to indicate NOT programable if failed to get system Guid.
1399       //
1400       ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1401     }
1402     Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)  sizeof (EFI_GUID);
1403   }
1404 
1405   //
1406   // Set fields of the token for the request packet.
1407   //
1408   Xid                                 = NET_RANDOM (NetRandomInitSeed ());
1409   Token.Packet->Dhcp4.Header.Xid      = HTONL (Xid);
1410   Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));
1411   CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1412 
1413   Token.RemotePort = Sport;
1414 
1415   if (IsBCast) {
1416     SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
1417   } else {
1418     CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1419   }
1420 
1421   CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
1422 
1423   if (!IsBCast) {
1424     Token.ListenPointCount            = 1;
1425     Token.ListenPoints                = &ListenPoint;
1426     Token.ListenPoints[0].ListenPort  = PXEBC_BS_DISCOVER_PORT;
1427     CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));
1428     CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));
1429   }
1430 
1431   //
1432   // Send out the request packet to discover the bootfile.
1433   //
1434   for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
1435 
1436     Token.TimeoutValue                  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
1437     Token.Packet->Dhcp4.Header.Seconds  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
1438 
1439     Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
1440     if (Token.Status != EFI_TIMEOUT) {
1441       break;
1442     }
1443   }
1444 
1445   if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
1446     //
1447     // No server response our PXE request
1448     //
1449     Status = EFI_TIMEOUT;
1450   }
1451 
1452   if (!EFI_ERROR (Status)) {
1453 
1454     RepIndex  = 0;
1455     SrvIndex  = 0;
1456     Response  = Token.ResponseList;
1457     //
1458     // Find the right PXE Reply according to server address.
1459     //
1460     while (RepIndex < Token.ResponseCount) {
1461 
1462       while (SrvIndex < IpCount) {
1463         if (SrvList[SrvIndex].AcceptAnyResponse) {
1464           break;
1465         }
1466         if ((SrvList[SrvIndex].Type == Type) &&
1467             EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {
1468           break;
1469         }
1470         SrvIndex++;
1471       }
1472 
1473       if ((IpCount != SrvIndex) || (IpCount == 0)) {
1474         break;
1475       }
1476 
1477       SrvIndex = 0;
1478       RepIndex++;
1479 
1480       Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
1481     }
1482 
1483     if (RepIndex < Token.ResponseCount) {
1484       //
1485       // Cache the right PXE reply packet here, set valid flag later.
1486       // Especially for PXE discover packet, store it into mode data here.
1487       //
1488       if (Private->IsDoDiscover) {
1489         PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
1490         CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
1491       } else {
1492         PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
1493       }
1494     } else {
1495       //
1496       // Not found the right PXE reply packet.
1497       //
1498       Status = EFI_NOT_FOUND;
1499     }
1500     if (Token.ResponseList != NULL) {
1501       FreePool (Token.ResponseList);
1502     }
1503   }
1504 
1505   FreePool (Token.Packet);
1506   return Status;
1507 }
1508 
1509 /**
1510   Switch the Ip4 policy to static.
1511 
1512   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
1513 
1514   @retval     EFI_SUCCESS         The policy is already configured to static.
1515   @retval     Others              Other error as indicated..
1516 
1517 **/
1518 EFI_STATUS
PxeBcSetIp4Policy(IN PXEBC_PRIVATE_DATA * Private)1519 PxeBcSetIp4Policy (
1520   IN PXEBC_PRIVATE_DATA            *Private
1521   )
1522 {
1523   EFI_STATUS                   Status;
1524   EFI_IP4_CONFIG2_PROTOCOL     *Ip4Config2;
1525   EFI_IP4_CONFIG2_POLICY       Policy;
1526   UINTN                        DataSize;
1527 
1528   Ip4Config2 = Private->Ip4Config2;
1529   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
1530   Status = Ip4Config2->GetData (
1531                        Ip4Config2,
1532                        Ip4Config2DataTypePolicy,
1533                        &DataSize,
1534                        &Policy
1535                        );
1536   if (EFI_ERROR (Status)) {
1537     return Status;
1538   }
1539 
1540   if (Policy != Ip4Config2PolicyStatic) {
1541     Policy = Ip4Config2PolicyStatic;
1542     Status= Ip4Config2->SetData (
1543                           Ip4Config2,
1544                           Ip4Config2DataTypePolicy,
1545                           sizeof (EFI_IP4_CONFIG2_POLICY),
1546                           &Policy
1547                           );
1548     if (EFI_ERROR (Status)) {
1549       return Status;
1550     }
1551   }
1552 
1553   return  EFI_SUCCESS;
1554 }
1555 
1556 /**
1557   Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1558 
1559   @param[in]  Private           Pointer to PxeBc private data.
1560   @param[in]  Dhcp4             Pointer to the EFI_DHCP4_PROTOCOL
1561 
1562   @retval EFI_SUCCESS           The D.O.R.A process successfully finished.
1563   @retval Others                Failed to finish the D.O.R.A process.
1564 
1565 **/
1566 EFI_STATUS
PxeBcDhcp4Dora(IN PXEBC_PRIVATE_DATA * Private,IN EFI_DHCP4_PROTOCOL * Dhcp4)1567 PxeBcDhcp4Dora (
1568   IN PXEBC_PRIVATE_DATA        *Private,
1569   IN EFI_DHCP4_PROTOCOL        *Dhcp4
1570   )
1571 {
1572   EFI_PXE_BASE_CODE_MODE       *PxeMode;
1573   EFI_DHCP4_CONFIG_DATA        Config;
1574   EFI_DHCP4_MODE_DATA          Mode;
1575   EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1576   UINT8                        Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1577   UINT32                       OptCount;
1578   EFI_STATUS                   Status;
1579 
1580   ASSERT (Dhcp4 != NULL);
1581 
1582   Status   = EFI_SUCCESS;
1583   PxeMode  = Private->PxeBc.Mode;
1584 
1585   //
1586   // Build option list for the request packet.
1587   //
1588   OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1589   ASSERT (OptCount> 0);
1590 
1591   ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1592   ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1593 
1594   Config.OptionCount      = OptCount;
1595   Config.OptionList       = OptList;
1596   Config.Dhcp4Callback    = PxeBcDhcp4CallBack;
1597   Config.CallbackContext  = Private;
1598   Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1599   Config.DiscoverTimeout  = mPxeDhcpTimeout;
1600 
1601   //
1602   // Configure the DHCPv4 instance for PXE boot.
1603   //
1604   Status = Dhcp4->Configure (Dhcp4, &Config);
1605   if (EFI_ERROR (Status)) {
1606     goto ON_EXIT;
1607   }
1608 
1609   //
1610   // Initialize the record fields for DHCPv4 offer in private data.
1611   //
1612   Private->IsProxyRecved = FALSE;
1613   Private->OfferNum      = 0;
1614   ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1615   ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1616 
1617   //
1618   // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. This may
1619   // have already been done, thus do not leave in error if the return
1620   // code is EFI_ALREADY_STARTED.
1621   //
1622   Status = Dhcp4->Start (Dhcp4, NULL);
1623   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1624     if (Status == EFI_ICMP_ERROR) {
1625       PxeMode->IcmpErrorReceived = TRUE;
1626     }
1627     goto ON_EXIT;
1628   }
1629 
1630   //
1631   // Get the acquired IPv4 address and store them.
1632   //
1633   Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1634   if (EFI_ERROR (Status)) {
1635     goto ON_EXIT;
1636   }
1637 
1638   ASSERT (Mode.State == Dhcp4Bound);
1639 
1640   CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1641   CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1642   CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1643   CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1644   CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1645 
1646   Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
1647   if (EFI_ERROR (Status)) {
1648     goto ON_EXIT;
1649   }
1650 
1651   //
1652   // Check the selected offer whether BINL retry is needed.
1653   //
1654   Status = PxeBcHandleDhcp4Offer (Private);
1655 
1656   AsciiPrint ("\n  Station IP address is ");
1657 
1658   PxeBcShowIp4Addr (&Private->StationIp.v4);
1659   AsciiPrint ("\n");
1660 
1661 ON_EXIT:
1662   if (EFI_ERROR (Status)) {
1663     Dhcp4->Stop (Dhcp4);
1664     Dhcp4->Configure (Dhcp4, NULL);
1665   } else {
1666     ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1667     Dhcp4->Configure (Dhcp4, &Config);
1668     Private->IsAddressOk = TRUE;
1669   }
1670 
1671   return Status;
1672 }
1673