PxeBcDhcp4.c revision 0e7f6f50cc7b05a0f6ec541ddce34211794d9c08
1/** @file
2  Functions implementation related with DHCPv4 for UefiPxeBc Driver.
3
4  Copyright (c) 2009 - 2014, 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  // 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 "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**/
621VOID
622PxeBcCopyDhcp4Ack (
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**/
652VOID
653PxeBcCopyProxyOffer (
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**/
691EFI_STATUS
692PxeBcRetryBinlOffer (
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**/
781VOID
782PxeBcCacheDhcp4Offer (
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**/
865VOID
866PxeBcSelectDhcp4Offer (
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**/
987EFI_STATUS
988PxeBcHandleDhcp4Offer (
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**/
1144EFI_STATUS
1145EFIAPI
1146PxeBcDhcp4CallBack (
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**/
1290EFI_STATUS
1291PxeBcDhcp4Discover (
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/**
1511  Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1512
1513  @param[in]  Private           Pointer to PxeBc private data.
1514  @param[in]  Dhcp4             Pointer to the EFI_DHCP4_PROTOCOL
1515
1516  @retval EFI_SUCCESS           The D.O.R.A process successfully finished.
1517  @retval Others                Failed to finish the D.O.R.A process.
1518
1519**/
1520EFI_STATUS
1521PxeBcDhcp4Dora (
1522  IN PXEBC_PRIVATE_DATA        *Private,
1523  IN EFI_DHCP4_PROTOCOL        *Dhcp4
1524  )
1525{
1526  EFI_PXE_BASE_CODE_MODE       *PxeMode;
1527  EFI_DHCP4_CONFIG_DATA        Config;
1528  EFI_DHCP4_MODE_DATA          Mode;
1529  EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1530  UINT8                        Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1531  UINT32                       OptCount;
1532  EFI_STATUS                   Status;
1533
1534  ASSERT (Dhcp4 != NULL);
1535
1536  Status   = EFI_SUCCESS;
1537  PxeMode  = Private->PxeBc.Mode;
1538
1539  //
1540  // Build option list for the request packet.
1541  //
1542  OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1543  ASSERT (OptCount> 0);
1544
1545  ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1546  ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1547
1548  Config.OptionCount      = OptCount;
1549  Config.OptionList       = OptList;
1550  Config.Dhcp4Callback    = PxeBcDhcp4CallBack;
1551  Config.CallbackContext  = Private;
1552  Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1553  Config.DiscoverTimeout  = mPxeDhcpTimeout;
1554
1555  //
1556  // Configure the DHCPv4 instance for PXE boot.
1557  //
1558  Status = Dhcp4->Configure (Dhcp4, &Config);
1559  if (EFI_ERROR (Status)) {
1560    goto ON_EXIT;
1561  }
1562
1563  //
1564  // Initialize the record fields for DHCPv4 offer in private data.
1565  //
1566  Private->IsProxyRecved = FALSE;
1567  Private->OfferNum      = 0;
1568  ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1569  ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1570
1571  //
1572  // Start DHCPv4 D.O.R.A. process to acquire IPv4 address.
1573  //
1574  Status = Dhcp4->Start (Dhcp4, NULL);
1575  if (EFI_ERROR (Status)) {
1576    if (Status == EFI_ICMP_ERROR) {
1577      PxeMode->IcmpErrorReceived = TRUE;
1578    }
1579    goto ON_EXIT;
1580  }
1581
1582  //
1583  // Get the acquired IPv4 address and store them.
1584  //
1585  Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1586  if (EFI_ERROR (Status)) {
1587    goto ON_EXIT;
1588  }
1589
1590  ASSERT (Mode.State == Dhcp4Bound);
1591
1592  CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1593  CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1594  CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1595  CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1596  CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1597
1598  Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
1599  if (EFI_ERROR (Status)) {
1600    goto ON_EXIT;
1601  }
1602
1603  //
1604  // Check the selected offer whether BINL retry is needed.
1605  //
1606  Status = PxeBcHandleDhcp4Offer (Private);
1607
1608  AsciiPrint ("\n  Station IP address is ");
1609
1610  PxeBcShowIp4Addr (&Private->StationIp.v4);
1611  AsciiPrint ("\n");
1612
1613ON_EXIT:
1614  if (EFI_ERROR (Status)) {
1615    Dhcp4->Stop (Dhcp4);
1616    Dhcp4->Configure (Dhcp4, NULL);
1617  } else {
1618    ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1619    Dhcp4->Configure (Dhcp4, &Config);
1620    Private->IsAddressOk = TRUE;
1621  }
1622
1623  return Status;
1624}
1625