PxeBcDhcp4.c revision 9063c328dff827ef9deb1ce0dde75112c496e072
1/** @file
2  Functions implementation related with DHCPv4 for UefiPxeBc Driver.
3
4  Copyright (c) 2009 - 2012, 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//
21UINT8 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//
34UINT32 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**/
48EFI_DHCP4_PACKET_OPTION *
49PxeBcParseDhcp4Options (
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**/
93VOID
94PxeBcParseVendorOptions (
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**/
227UINT32
228PxeBcBuildDhcp4Options (
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**/
393VOID
394PxeBcSeedDhcp4Packet (
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**/
428VOID
429PxeBcCacheDhcp4Packet (
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**/
450EFI_STATUS
451PxeBcParseDhcp4Packet (
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  //
476  for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
477    Options[Index] = PxeBcParseDhcp4Options (
478                       Offer->Dhcp4.Option,
479                       GET_OPTION_BUFFER_LEN (Offer),
480                       mInterestedDhcp4Tags[Index]
481                       );
482  }
483
484  //
485  // The offer with "yiaddr" is a proxy offer.
486  //
487  if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
488    IsProxyOffer = TRUE;
489  }
490
491  //
492  // The offer with "PXEClient" is a PXE offer.
493  //
494  Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
495  if ((Option != NULL) && (Option->Length >= 9) &&
496      (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
497    IsPxeOffer = TRUE;
498  }
499
500  //
501  // Parse PXE vendor options in this offer, and store the contents/pointers.
502  //
503  Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
504  if (IsPxeOffer && Option != NULL) {
505    PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);
506  }
507
508  //
509  // Check whether bootfilename and serverhostname overloaded, refers to rfc-2132 in details.
510  // If overloaded, parse the buffer as nested DHCPv4 options, or else just parse as bootfilename
511  // and serverhostname option.
512  //
513  Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
514  if (Option != NULL && (Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
515
516    Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = PxeBcParseDhcp4Options (
517                                                (UINT8 *) Offer->Dhcp4.Header.BootFileName,
518                                                sizeof (Offer->Dhcp4.Header.BootFileName),
519                                                PXEBC_DHCP4_TAG_BOOTFILE
520                                                );
521    //
522    // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
523    // terminated string. So force to append null terminated character at the end of string.
524    //
525    if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
526      Ptr8 =  (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
527      Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
528      *Ptr8 =  '\0';
529    }
530
531  } else if ((Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) &&
532            (Offer->Dhcp4.Header.BootFileName[0] != 0)) {
533    //
534    // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
535    // Do not count dhcp option header here, or else will destory the serverhostname.
536    //
537    Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
538                                                (&Offer->Dhcp4.Header.BootFileName[0] -
539                                                OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
540
541  }
542
543  //
544  // Determine offer type of the DHCPv4 packet.
545  //
546  Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
547  if (Option == NULL || Option->Data[0] == 0) {
548    //
549    // It's a Bootp offer.
550    //
551    OfferType = PxeOfferTypeBootp;
552
553    Option    = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
554    if (Option == NULL) {
555      //
556      // If the Bootp offer without bootfilename, discard it.
557      //
558      return EFI_DEVICE_ERROR;
559    }
560  } else {
561
562    if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
563      //
564      // It's a PXE10 offer with PXEClient and discover vendor option.
565      //
566      OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
567    } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
568      //
569      // It's a WFM11a offer with PXEClient and mtftp vendor option.
570      // But multi-cast download is not supported currently, so discard it.
571      //
572      return EFI_DEVICE_ERROR;
573    } else if (IsPxeOffer) {
574      //
575      // It's a BINL offer only with PXEClient.
576      //
577      OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
578    } else {
579      //
580      // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
581      //
582      OfferType = PxeOfferTypeDhcpOnly;
583    }
584  }
585
586  Cache4->OfferType = OfferType;
587
588  return EFI_SUCCESS;
589}
590
591
592/**
593  Cache the DHCPv4 ack packet, and parse it on demand.
594
595  @param[in]  Private             Pointer to PxeBc private data.
596  @param[in]  Ack                 Pointer to the DHCPv4 ack packet.
597  @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.
598
599**/
600VOID
601PxeBcCopyDhcp4Ack (
602  IN PXEBC_PRIVATE_DATA   *Private,
603  IN EFI_DHCP4_PACKET     *Ack,
604  IN BOOLEAN              Verified
605  )
606{
607  EFI_PXE_BASE_CODE_MODE  *Mode;
608
609  Mode = Private->PxeBc.Mode;
610
611  PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
612
613  if (Verified) {
614    //
615    // Parse the ack packet and store it into mode data if needed.
616    //
617    PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
618    CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
619    Mode->DhcpAckReceived = TRUE;
620  }
621}
622
623
624/**
625  Cache the DHCPv4 proxy offer packet according to the received order.
626
627  @param[in]  Private               Pointer to PxeBc private data.
628  @param[in]  OfferIndex            The received order of offer packets.
629
630**/
631VOID
632PxeBcCopyProxyOffer (
633  IN PXEBC_PRIVATE_DATA   *Private,
634  IN UINT32               OfferIndex
635  )
636{
637  EFI_PXE_BASE_CODE_MODE  *Mode;
638  EFI_DHCP4_PACKET        *Offer;
639
640  ASSERT (OfferIndex < Private->OfferNum);
641  ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
642
643  Mode  = Private->PxeBc.Mode;
644  Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
645
646  //
647  // Cache the proxy offer packet and parse it.
648  //
649  PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
650  PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
651
652  //
653  // Store this packet into mode data.
654  //
655  CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
656  Mode->ProxyOfferReceived = TRUE;
657}
658
659
660/**
661  Retry to request bootfile name by the BINL offer.
662
663  @param[in]  Private              Pointer to PxeBc private data.
664  @param[in]  Index                The received order of offer packets.
665
666  @retval     EFI_SUCCESS          Successfully retried to request bootfile name.
667  @retval     EFI_DEVICE_ERROR     Failed to retry bootfile name.
668
669**/
670EFI_STATUS
671PxeBcRetryBinlOffer (
672  IN PXEBC_PRIVATE_DATA     *Private,
673  IN UINT32                 Index
674  )
675{
676  EFI_DHCP4_PACKET          *Offer;
677  EFI_IP_ADDRESS            ServerIp;
678  EFI_STATUS                Status;
679  PXEBC_DHCP4_PACKET_CACHE  *Cache4;
680  EFI_DHCP4_PACKET          *Reply;
681
682  ASSERT (Index < PXEBC_OFFER_MAX_NUM);
683  ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
684          Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);
685
686  Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
687
688  //
689  // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
690  //
691  if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
692    CopyMem (
693      &ServerIp.Addr[0],
694      Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
695      sizeof (EFI_IPv4_ADDRESS)
696      );
697  } else {
698    CopyMem (
699      &ServerIp.Addr[0],
700      &Offer->Dhcp4.Header.ServerAddr,
701      sizeof (EFI_IPv4_ADDRESS)
702      );
703  }
704
705  Private->IsDoDiscover = FALSE;
706  Cache4                = &Private->ProxyOffer.Dhcp4;
707  Reply                 = &Cache4->Packet.Offer;
708
709  //
710  // Send another request packet for bootfile name.
711  //
712  Status = PxeBcDhcp4Discover (
713             Private,
714             0,
715             NULL,
716             FALSE,
717             &ServerIp,
718             0,
719             NULL
720             );
721  if (EFI_ERROR (Status)) {
722    return Status;
723  }
724
725  //
726  // Parse the reply for the last request packet.
727  //
728  Status = PxeBcParseDhcp4Packet (Cache4);
729  if (EFI_ERROR (Status)) {
730    return Status;
731  }
732
733  if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&
734      Cache4->OfferType != PxeOfferTypeProxyWfm11a &&
735      Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
736    //
737    // This BINL ack doesn't have discovery option set or multicast option set
738    // or bootfile name specified.
739    //
740    return EFI_DEVICE_ERROR;
741  }
742
743  //
744  // Store the reply into mode data.
745  //
746  Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
747  CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
748
749  return EFI_SUCCESS;
750}
751
752
753/**
754  Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
755
756  @param[in]  Private               Pointer to PxeBc private data.
757  @param[in]  RcvdOffer             Pointer to the received offer packet.
758
759**/
760VOID
761PxeBcCacheDhcp4Offer (
762  IN PXEBC_PRIVATE_DATA     *Private,
763  IN EFI_DHCP4_PACKET       *RcvdOffer
764  )
765{
766  PXEBC_DHCP4_PACKET_CACHE  *Cache4;
767  EFI_DHCP4_PACKET          *Offer;
768  PXEBC_OFFER_TYPE          OfferType;
769
770  ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
771  Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
772  Offer  = &Cache4->Packet.Offer;
773
774  //
775  // Cache the content of DHCPv4 packet firstly.
776  //
777  PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
778
779  //
780  // Validate the DHCPv4 packet, and parse the options and offer type.
781  //
782  if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
783    return;
784  }
785
786  //
787  // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
788  //
789  OfferType = Cache4->OfferType;
790  ASSERT (OfferType < PxeOfferTypeMax);
791
792  if (OfferType == PxeOfferTypeBootp) {
793    //
794    // It's a Bootp offer, only cache the first one, and discard the others.
795    //
796    if (Private->OfferCount[OfferType] == 0) {
797      Private->OfferIndex[OfferType][0] = Private->OfferNum;
798      Private->OfferCount[OfferType]    = 1;
799    } else {
800      return;
801    }
802  } else {
803    ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
804    if (IS_PROXY_DHCP_OFFER (Offer)) {
805      //
806      // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
807      //
808      Private->IsProxyRecved = TRUE;
809
810      if (OfferType == PxeOfferTypeProxyBinl) {
811        //
812        // Cache all proxy BINL offers.
813        //
814        Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
815        Private->OfferCount[OfferType]++;
816      } else if (Private->OfferCount[OfferType] > 0) {
817        //
818        // Only cache the first PXE10/WFM11a offer, and discard the others.
819        //
820        Private->OfferIndex[OfferType][0] = Private->OfferNum;
821        Private->OfferCount[OfferType]    = 1;
822      } else {
823        return ;
824      }
825    } else {
826      //
827      // It's a DHCPv4 offer with yiaddr, and cache them all.
828      //
829      Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
830      Private->OfferCount[OfferType]++;
831    }
832  }
833
834  Private->OfferNum++;
835}
836
837
838/**
839  Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
840
841  @param[in]  Private             Pointer to PxeBc private data.
842
843**/
844VOID
845PxeBcSelectDhcp4Offer (
846  IN PXEBC_PRIVATE_DATA       *Private
847  )
848{
849  UINT32                      Index;
850  UINT32                      OfferIndex;
851  EFI_DHCP4_PACKET            *Offer;
852
853  Private->SelectIndex = 0;
854
855  if (Private->IsOfferSorted) {
856    //
857    // Select offer by default policy.
858    //
859    if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
860      //
861      // 1. DhcpPxe10 offer
862      //
863      Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
864
865    } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
866      //
867      // 2. DhcpWfm11a offer
868      //
869      Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
870
871    } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
872               Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
873      //
874      // 3. DhcpOnly offer and ProxyPxe10 offer.
875      //
876      Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
877      Private->SelectProxyType = PxeOfferTypeProxyPxe10;
878
879    } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
880               Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
881      //
882      // 4. DhcpOnly offer and ProxyWfm11a offer.
883      //
884      Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
885      Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
886
887    } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
888      //
889      // 5. DhcpBinl offer.
890      //
891      Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
892
893    } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
894               Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
895      //
896      // 6. DhcpOnly offer and ProxyBinl offer.
897      //
898      Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
899      Private->SelectProxyType = PxeOfferTypeProxyBinl;
900
901    } else {
902      //
903      // 7. DhcpOnly offer with bootfilename.
904      //
905      for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
906        OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
907        if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
908          Private->SelectIndex = OfferIndex + 1;
909          break;
910        }
911      }
912      //
913      // 8. Bootp offer with bootfilename.
914      //
915      OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
916      if (Private->SelectIndex == 0 &&
917          Private->OfferCount[PxeOfferTypeBootp] > 0 &&
918          Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
919        Private->SelectIndex = OfferIndex + 1;
920      }
921    }
922  } else {
923    //
924    // Select offer by received order.
925    //
926    for (Index = 0; Index < Private->OfferNum; Index++) {
927
928      Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
929
930      if (IS_PROXY_DHCP_OFFER (Offer)) {
931        //
932        // Skip proxy offers
933        //
934        continue;
935      }
936
937      if (!Private->IsProxyRecved &&
938          Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&
939          Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
940        //
941        // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
942        //
943        continue;
944      }
945
946      //
947      // Record the index of the select offer.
948      //
949      Private->SelectIndex = Index + 1;
950      break;
951    }
952  }
953}
954
955
956/**
957  Handle the DHCPv4 offer packet.
958
959  @param[in]  Private             Pointer to PxeBc private data.
960
961  @retval     EFI_SUCCESS         Handled the DHCPv4 offer packet successfully.
962  @retval     EFI_NO_RESPONSE     No response to the following request packet.
963  @retval     EFI_NOT_FOUND       No boot filename received.
964
965**/
966EFI_STATUS
967PxeBcHandleDhcp4Offer (
968  IN PXEBC_PRIVATE_DATA     *Private
969  )
970{
971  PXEBC_DHCP4_PACKET_CACHE  *Cache4;
972  EFI_DHCP4_PACKET_OPTION   **Options;
973  UINT32                    Index;
974  EFI_DHCP4_PACKET          *Offer;
975  PXEBC_OFFER_TYPE          OfferType;
976  UINT32                    ProxyIndex;
977  UINT32                    SelectIndex;
978  EFI_STATUS                Status;
979  EFI_PXE_BASE_CODE_MODE    *Mode;
980  EFI_DHCP4_PACKET          *Ack;
981
982  ASSERT (Private->SelectIndex > 0);
983  SelectIndex = (UINT32) (Private->SelectIndex - 1);
984  ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
985  Cache4      = &Private->OfferBuffer[SelectIndex].Dhcp4;
986  Options     = Cache4->OptList;
987  Status      = EFI_SUCCESS;
988
989  if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
990    //
991    // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
992    //
993    if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
994      Status = EFI_NO_RESPONSE;
995    }
996  } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
997
998    if (Private->IsProxyRecved) {
999      //
1000      // DhcpOnly offer is selected, so need try to request bootfile name.
1001      //
1002      ProxyIndex = 0;
1003      if (Private->IsOfferSorted) {
1004        //
1005        // The proxy offer should be determined if select by default policy.
1006        // IsOfferSorted means all offers are labeled by OfferIndex.
1007        //
1008        ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
1009        ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
1010
1011        if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
1012          //
1013          // Try all the cached ProxyBinl offer one by one to request bootfile name.
1014          //
1015          for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
1016            ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1017            ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
1018            if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
1019              break;
1020            }
1021          }
1022          if (Index == Private->OfferCount[Private->SelectProxyType]) {
1023            Status = EFI_NO_RESPONSE;
1024          }
1025        } else {
1026          //
1027          // For other proxy offers, only one is buffered.
1028          //
1029          ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
1030        }
1031      } else {
1032        //
1033        // The proxy offer should not be determined if select by received order.
1034        //
1035        Status = EFI_NO_RESPONSE;
1036
1037        for (Index = 0; Index < Private->OfferNum; Index++) {
1038          ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1039          Offer     = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
1040          OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
1041          if (!IS_PROXY_DHCP_OFFER (Offer)) {
1042            //
1043            // Skip non proxy DHCPv4 offers.
1044            //
1045            continue;
1046          }
1047
1048          if (OfferType == PxeOfferTypeProxyBinl) {
1049            //
1050            // Try all the cached ProxyBinl offer one by one to request bootfile name.
1051            //
1052            if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
1053              continue;
1054            }
1055          }
1056
1057          Private->SelectProxyType = OfferType;
1058          ProxyIndex               = Index;
1059          Status                   = EFI_SUCCESS;
1060          break;
1061        }
1062      }
1063
1064      if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
1065        //
1066        // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1067        //
1068        PxeBcCopyProxyOffer (Private, ProxyIndex);
1069      }
1070    } else {
1071      //
1072      //  Othewise, the bootfile name must be included in DhcpOnly offer.
1073      //
1074      if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
1075        Status = EFI_NOT_FOUND;
1076      }
1077    }
1078  }
1079
1080  if (!EFI_ERROR (Status)) {
1081    //
1082    // All PXE boot information is ready by now.
1083    //
1084    Mode  = Private->PxeBc.Mode;
1085    Offer = &Cache4->Packet.Offer;
1086    Ack   = &Private->DhcpAck.Dhcp4.Packet.Ack;
1087    if (Cache4->OfferType == PxeOfferTypeBootp) {
1088      //
1089      // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1090      // should be taken as ack.
1091      //
1092      Ack = Offer;
1093    }
1094
1095    PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
1096    Mode->DhcpDiscoverValid = TRUE;
1097  }
1098
1099  return Status;
1100}
1101
1102
1103/**
1104  EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1105  to intercept events that occurred in the configuration process.
1106
1107  @param[in]  This              Pointer to the EFI DHCPv4 Protocol.
1108  @param[in]  Context           Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1109  @param[in]  CurrentState      The current operational state of the EFI DHCPv4 Protocol driver.
1110  @param[in]  Dhcp4Event        The event that occurs in the current state, which usually means a
1111                                state transition.
1112  @param[in]  Packet            The DHCPv4 packet that is going to be sent or already received.
1113  @param[out] NewPacket         The packet that is used to replace the above Packet.
1114
1115  @retval EFI_SUCCESS           Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1116  @retval EFI_NOT_READY         Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1117                                driver will continue to wait for more DHCPOFFER packets until the
1118                                retry timeout expires.
1119  @retval EFI_ABORTED           Tells the EFI DHCPv4 Protocol driver to abort the current process
1120                                and return to the Dhcp4Init or Dhcp4InitReboot state.
1121
1122**/
1123EFI_STATUS
1124EFIAPI
1125PxeBcDhcp4CallBack (
1126  IN  EFI_DHCP4_PROTOCOL               *This,
1127  IN  VOID                             *Context,
1128  IN  EFI_DHCP4_STATE                  CurrentState,
1129  IN  EFI_DHCP4_EVENT                  Dhcp4Event,
1130  IN  EFI_DHCP4_PACKET                 *Packet            OPTIONAL,
1131  OUT EFI_DHCP4_PACKET                 **NewPacket        OPTIONAL
1132  )
1133{
1134  PXEBC_PRIVATE_DATA                   *Private;
1135  EFI_PXE_BASE_CODE_MODE               *Mode;
1136  EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  *Callback;
1137  EFI_DHCP4_PACKET_OPTION              *MaxMsgSize;
1138  UINT16                               Value;
1139  EFI_STATUS                           Status;
1140  BOOLEAN                              Received;
1141
1142  if ((Dhcp4Event != Dhcp4RcvdOffer) &&
1143      (Dhcp4Event != Dhcp4SelectOffer) &&
1144      (Dhcp4Event != Dhcp4SendDiscover) &&
1145      (Dhcp4Event != Dhcp4RcvdAck)) {
1146    return EFI_SUCCESS;
1147  }
1148
1149  Private   = (PXEBC_PRIVATE_DATA *) Context;
1150  Mode      = Private->PxeBc.Mode;
1151  Callback  = Private->PxeBcCallback;
1152
1153  //
1154  // Override the Maximum DHCP Message Size.
1155  //
1156  MaxMsgSize = PxeBcParseDhcp4Options (
1157                 Packet->Dhcp4.Option,
1158                 GET_OPTION_BUFFER_LEN (Packet),
1159                 PXEBC_DHCP4_TAG_MAXMSG
1160                 );
1161  if (MaxMsgSize != NULL) {
1162    Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);
1163    CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
1164  }
1165
1166  //
1167  // Callback to user if any packets sent or received.
1168  //
1169  if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {
1170    Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
1171    Status = Callback->Callback (
1172                         Callback,
1173                         Private->Function,
1174                         Received,
1175                         Packet->Length,
1176                         (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4
1177                         );
1178    if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1179      return EFI_ABORTED;
1180    }
1181  }
1182
1183  Status = EFI_SUCCESS;
1184
1185  switch (Dhcp4Event) {
1186
1187  case Dhcp4SendDiscover:
1188    //
1189    // Cache the DHCPv4 discover packet to mode data directly.
1190    // It need to check SendGuid as well as Dhcp4SendRequest.
1191    //
1192    CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
1193
1194  case Dhcp4SendRequest:
1195    if (Mode->SendGUID) {
1196      //
1197      // Send the system Guid instead of the MAC address as the hardware address if required.
1198      //
1199      if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {
1200        //
1201        // Zero the Guid to indicate NOT programable if failed to get system Guid.
1202        //
1203        ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1204      }
1205      Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);
1206    }
1207    break;
1208
1209  case Dhcp4RcvdOffer:
1210    Status = EFI_NOT_READY;
1211    if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1212      //
1213      // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1214      // the OfferIndex and OfferCount.
1215      //
1216      PxeBcCacheDhcp4Offer (Private, Packet);
1217    }
1218    break;
1219
1220  case Dhcp4SelectOffer:
1221    //
1222    // Select offer by the default policy or by order, and record the SelectIndex
1223    // and SelectProxyType.
1224    //
1225    PxeBcSelectDhcp4Offer (Private);
1226
1227    if (Private->SelectIndex == 0) {
1228      Status = EFI_ABORTED;
1229    } else {
1230      *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
1231    }
1232    break;
1233
1234  case Dhcp4RcvdAck:
1235    //
1236    // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1237    // without verification.
1238    //
1239    ASSERT (Private->SelectIndex != 0);
1240
1241    PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
1242    break;
1243
1244  default:
1245    break;
1246  }
1247
1248  return Status;
1249}
1250
1251
1252/**
1253  Build and send out the request packet for the bootfile, and parse the reply.
1254
1255  @param[in]  Private               Pointer to PxeBc private data.
1256  @param[in]  Type                  PxeBc option boot item type.
1257  @param[in]  Layer                 Pointer to option boot item layer.
1258  @param[in]  UseBis                Use BIS or not.
1259  @param[in]  DestIp                Pointer to the server address.
1260  @param[in]  IpCount               The total count of the server address.
1261  @param[in]  SrvList               Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1262
1263  @retval     EFI_SUCCESS           Successfully discovered boot file.
1264  @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resource.
1265  @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.
1266  @retval     Others                Failed to discover boot file.
1267
1268**/
1269EFI_STATUS
1270PxeBcDhcp4Discover (
1271  IN  PXEBC_PRIVATE_DATA              *Private,
1272  IN  UINT16                          Type,
1273  IN  UINT16                          *Layer,
1274  IN  BOOLEAN                         UseBis,
1275  IN  EFI_IP_ADDRESS                  *DestIp,
1276  IN  UINT16                          IpCount,
1277  IN  EFI_PXE_BASE_CODE_SRVLIST       *SrvList
1278  )
1279{
1280  EFI_PXE_BASE_CODE_UDP_PORT          Sport;
1281  EFI_PXE_BASE_CODE_MODE              *Mode;
1282  EFI_DHCP4_PROTOCOL                  *Dhcp4;
1283  EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
1284  BOOLEAN                             IsBCast;
1285  EFI_STATUS                          Status;
1286  UINT16                              RepIndex;
1287  UINT16                              SrvIndex;
1288  UINT16                              TryIndex;
1289  EFI_DHCP4_LISTEN_POINT              ListenPoint;
1290  EFI_DHCP4_PACKET                    *Response;
1291  UINT8                               Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1292  EFI_DHCP4_PACKET_OPTION             *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1293  UINT32                              OptCount;
1294  EFI_DHCP4_PACKET_OPTION             *PxeOpt;
1295  PXEBC_OPTION_BOOT_ITEM              *PxeBootItem;
1296  UINT8                               VendorOptLen;
1297  UINT32                              Xid;
1298
1299  Mode      = Private->PxeBc.Mode;
1300  Dhcp4     = Private->Dhcp4;
1301  Status    = EFI_SUCCESS;
1302
1303  ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
1304
1305  //
1306  // Use broadcast if destination address not specified.
1307  //
1308  if (DestIp == NULL) {
1309    Sport   = PXEBC_DHCP4_S_PORT;
1310    IsBCast = TRUE;
1311  } else {
1312    Sport   = PXEBC_BS_DISCOVER_PORT;
1313    IsBCast = FALSE;
1314  }
1315
1316  if (!UseBis && Layer != NULL) {
1317    *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1318  }
1319
1320  //
1321  // Build all the options for the request packet.
1322  //
1323  OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
1324
1325  if (Private->IsDoDiscover) {
1326    //
1327    // Add vendor option of PXE_BOOT_ITEM
1328    //
1329    VendorOptLen      = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
1330    OptList[OptCount] = AllocateZeroPool (VendorOptLen);
1331    if (OptList[OptCount] == NULL) {
1332      return EFI_OUT_OF_RESOURCES;
1333    }
1334
1335    OptList[OptCount]->OpCode     = PXEBC_DHCP4_TAG_VENDOR;
1336    OptList[OptCount]->Length     = (UINT8) (VendorOptLen - 2);
1337    PxeOpt                        = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;
1338    PxeOpt->OpCode                = PXEBC_VENDOR_TAG_BOOT_ITEM;
1339    PxeOpt->Length                = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);
1340    PxeBootItem                   = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;
1341    PxeBootItem->Type             = HTONS (Type);
1342    PxeOpt->Data[PxeOpt->Length]  = PXEBC_DHCP4_TAG_EOP;
1343
1344    if (Layer != NULL) {
1345      PxeBootItem->Layer          = HTONS (*Layer);
1346    }
1347
1348    OptCount++;
1349  }
1350
1351  //
1352  // Build the request packet with seed packet and option list.
1353  //
1354  Status = Dhcp4->Build (
1355                    Dhcp4,
1356                    &Private->SeedPacket,
1357                    0,
1358                    NULL,
1359                    OptCount,
1360                    OptList,
1361                    &Token.Packet
1362                    );
1363  //
1364  // Free the vendor option of PXE_BOOT_ITEM.
1365  //
1366  if (Private->IsDoDiscover) {
1367    FreePool (OptList[OptCount - 1]);
1368  }
1369
1370  if (EFI_ERROR (Status)) {
1371    return Status;
1372  }
1373
1374  if (Mode->SendGUID) {
1375    if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {
1376      //
1377      // Zero the Guid to indicate NOT programable if failed to get system Guid.
1378      //
1379      ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1380    }
1381    Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)  sizeof (EFI_GUID);
1382  }
1383
1384  //
1385  // Set fields of the token for the request packet.
1386  //
1387  Xid                                 = NET_RANDOM (NetRandomInitSeed ());
1388  Token.Packet->Dhcp4.Header.Xid      = HTONL (Xid);
1389  Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));
1390  CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1391
1392  Token.RemotePort = Sport;
1393
1394  if (IsBCast) {
1395    SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
1396  } else {
1397    CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1398  }
1399
1400  CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
1401
1402  if (!IsBCast) {
1403    Token.ListenPointCount            = 1;
1404    Token.ListenPoints                = &ListenPoint;
1405    Token.ListenPoints[0].ListenPort  = PXEBC_BS_DISCOVER_PORT;
1406    CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));
1407    CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));
1408  }
1409
1410  //
1411  // Send out the request packet to discover the bootfile.
1412  //
1413  for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
1414
1415    Token.TimeoutValue                  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
1416    Token.Packet->Dhcp4.Header.Seconds  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
1417
1418    Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
1419    if (Token.Status != EFI_TIMEOUT) {
1420      break;
1421    }
1422  }
1423
1424  if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
1425    //
1426    // No server response our PXE request
1427    //
1428    Status = EFI_TIMEOUT;
1429  }
1430
1431  if (!EFI_ERROR (Status)) {
1432
1433    RepIndex  = 0;
1434    SrvIndex  = 0;
1435    Response  = Token.ResponseList;
1436    //
1437    // Find the right PXE Reply according to server address.
1438    //
1439    while (RepIndex < Token.ResponseCount) {
1440
1441      while (SrvIndex < IpCount) {
1442        if (SrvList[SrvIndex].AcceptAnyResponse) {
1443          break;
1444        }
1445        if ((SrvList[SrvIndex].Type == Type) &&
1446            EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {
1447          break;
1448        }
1449        SrvIndex++;
1450      }
1451
1452      if ((IpCount != SrvIndex) || (IpCount == 0)) {
1453        break;
1454      }
1455
1456      SrvIndex = 0;
1457      RepIndex++;
1458
1459      Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
1460    }
1461
1462    if (RepIndex < Token.ResponseCount) {
1463      //
1464      // Cache the right PXE reply packet here, set valid flag later.
1465      // Especially for PXE discover packet, store it into mode data here.
1466      //
1467      if (Private->IsDoDiscover) {
1468        PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
1469        CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
1470      } else {
1471        PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
1472      }
1473    } else {
1474      //
1475      // Not found the right PXE reply packet.
1476      //
1477      Status = EFI_NOT_FOUND;
1478    }
1479    if (Token.ResponseList != NULL) {
1480      FreePool (Token.ResponseList);
1481    }
1482  }
1483
1484  FreePool (Token.Packet);
1485  return Status;
1486}
1487
1488
1489/**
1490  Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1491
1492  @param[in]  Private           Pointer to PxeBc private data.
1493  @param[in]  Dhcp4             Pointer to the EFI_DHCP4_PROTOCOL
1494
1495  @retval EFI_SUCCESS           The D.O.R.A process successfully finished.
1496  @retval Others                Failed to finish the D.O.R.A process.
1497
1498**/
1499EFI_STATUS
1500PxeBcDhcp4Dora (
1501  IN PXEBC_PRIVATE_DATA        *Private,
1502  IN EFI_DHCP4_PROTOCOL        *Dhcp4
1503  )
1504{
1505  EFI_PXE_BASE_CODE_MODE       *PxeMode;
1506  EFI_DHCP4_CONFIG_DATA        Config;
1507  EFI_DHCP4_MODE_DATA          Mode;
1508  EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1509  UINT8                        Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1510  UINT32                       OptCount;
1511  EFI_STATUS                   Status;
1512
1513  ASSERT (Dhcp4 != NULL);
1514
1515  Status   = EFI_SUCCESS;
1516  PxeMode  = Private->PxeBc.Mode;
1517
1518  //
1519  // Build option list for the request packet.
1520  //
1521  OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1522  ASSERT (OptCount> 0);
1523
1524  ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1525  ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1526
1527  Config.OptionCount      = OptCount;
1528  Config.OptionList       = OptList;
1529  Config.Dhcp4Callback    = PxeBcDhcp4CallBack;
1530  Config.CallbackContext  = Private;
1531  Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1532  Config.DiscoverTimeout  = mPxeDhcpTimeout;
1533
1534  //
1535  // Configure the DHCPv4 instance for PXE boot.
1536  //
1537  Status = Dhcp4->Configure (Dhcp4, &Config);
1538  if (EFI_ERROR (Status)) {
1539    goto ON_EXIT;
1540  }
1541
1542  //
1543  // Initialize the record fields for DHCPv4 offer in private data.
1544  //
1545  Private->IsProxyRecved = FALSE;
1546  Private->OfferNum      = 0;
1547  ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1548  ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1549
1550  //
1551  // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
1552  //
1553  Status = Dhcp4->Start (Dhcp4, NULL);
1554  if (EFI_ERROR (Status)) {
1555    if (Status == EFI_ICMP_ERROR) {
1556      PxeMode->IcmpErrorReceived = TRUE;
1557    }
1558    goto ON_EXIT;
1559  }
1560
1561  //
1562  // Get the acquired IPv4 address and store them.
1563  //
1564  Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1565  if (EFI_ERROR (Status)) {
1566    goto ON_EXIT;
1567  }
1568
1569  ASSERT (Mode.State == Dhcp4Bound);
1570
1571  CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1572  CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1573  CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1574  CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1575  CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1576
1577  Status = PxeBcFlushStaionIp (Private, &Private->StationIp, &Private->SubnetMask);
1578  if (EFI_ERROR (Status)) {
1579    goto ON_EXIT;
1580  }
1581
1582  //
1583  // Check the selected offer whether BINL retry is needed.
1584  //
1585  Status = PxeBcHandleDhcp4Offer (Private);
1586
1587  AsciiPrint ("\n  Station IP address is ");
1588
1589  PxeBcShowIp4Addr (&Private->StationIp.v4);
1590  AsciiPrint ("\n");
1591
1592ON_EXIT:
1593  if (EFI_ERROR (Status)) {
1594    Dhcp4->Stop (Dhcp4);
1595    Dhcp4->Configure (Dhcp4, NULL);
1596  } else {
1597    ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1598    Dhcp4->Configure (Dhcp4, &Config);
1599    Private->IsAddressOk = TRUE;
1600  }
1601
1602  return Status;
1603}
1604